October 31, 2020

Функции измерения нагрузки ПЛК

Измерение загрузки контроллера можно условно разделить на:

  • измерение нагрузки процессора. Показывает справляется ли вся система в целом: Windows + TwinCAT.
  • Измерение времени исполнения программы в текущем цикле. Укладывается ли текущая ветвь программы в заданное время цикла.
  • Профилирование. Замер времени выполнения отдельных частей программы.

И возвращаясь к теме предыдущего поста: "измерять производительность — это хороший способ узнать, осталось ли что-нибудь за кадром. Иногда это просто любопытство".


Разбор программы


PROGRAM MAIN
VAR
PAYLOAD: UINT := 100;
usage, usageMax: UDINT;
latencyMax, latencyAct: UDINT;
cycleExecTime, cycleTimeSti, cycleExecSti: REAL;
cycleLoad, cycleLoadUser: REAL;
TcSysLatency: TC_SysLatency;
TcCpuUsage: TC_CpuUsage;
CpuCounter: GETCPUCOUNTER;
i: UDINT;
a: LREAL := 3.1415926;
b: LREAL := 2.7182818;
cpustart: UDINT;
Timer: TON := (PT := T#10s);
sti: SYSTEMTASKINFOTYPE;
END_VAR
cycleExecTime := (CpuCounter.cpuCntLoDW - cpustart) / 10000.0;
cycleLoad := sti.lastExecTime / (sti.cycleTime / 100.0);
cycleLoadUser := (CpuCounter.cpuCntLoDW - cpustart) / (sti.cycleTime / 100.0);
CpuCounter();
cpustart := CpuCounter.cpuCntLoDW;
sti := SystemTaskInfoArr[1];
cycleExecSti := sti.lastExecTime / 10000.0;
cycleTimeSti := sti.cycleTime / 10000.0;
TcCpuUsage(START:= TRUE);
TcSysLatency(START:= TRUE);
IF NOT TcSysLatency.BUSY THEN
TcSysLatency(START:= FALSE);
latencyMax := TcSysLatency.MAXIMUM;
latencyAct := TcSysLatency.ACTUAL;
END_IF
Timer(IN := NOT Timer.Q);
IF Timer.Q THEN
usageMax := 0;
END_IF
IF NOT TcCpuUsage.BUSY THEN
TcCpuUsage(START:= FALSE);
usage := TcCpuUsage.USAGE;
usageMax := MAX(usageMax, usage);
END_IF
FOR i := 0 TO PAYLOAD DO
a := a / b;
a := a * b;
END_FOR
CpuCounter();
END_PROGRAM

В программе выше используются функции: TC_SysLatency, TC_CpuUsage, GETCPUCOUNTER. Также используется информация из встроенного глобального массива SystemTaskInfoArr[]. Он предоставляет структуру данных SYSTEMTASKINFOTYPE.

TC_SysLatency пропустим, я по прежнему не вижу в нем смысла. TC_CpuUsage возвращает целое число процентов нагрузки на процессор. Это значение должно совпадать с графиком в System Manager, но это не точно и это было видно выше.

GETCPUCOUNTER работает независимо от счетчика в CPU. Это счетчик 100 наносекундных циклов. Увеличение на единицу соответствует прошедшему времени в 100 нс. Увеличение на 10 соответствует 1 микросекунде. Посмотрим как перевести в миллисекунды с десятичными долями:

52'108'000 наносекунд = 52'108'0 100*нс = 52'108 микросекунд = 52,108 миллисекунд.

LREAL cpuCntMs := (cpuCntLoDW + cpuCntHiDW) / 10000.0

Счетчик можно использовать для профилирования времени выполнения отдельных блоков программы внутри цикла. Можно узнать сколько времени занимает выполнение подпрограммы или функционального блока.

SystemTaskInfoArr[] в том же цикле отдает структуру SYSTEMTASKINFOTYPE. Индексом для массива служит номер текущей задачи. Индекс можно получить с помощью функции GETCURTASKINDEX в этом же цикле и начать его использовать уже в следующей строке программы.

Структура SYSTEMTASKINFOTYPE содержит состояние предыдущего цикла. Эта структура содержит:

  • cycleTimeExceeded — TRUE = время цикла превышено, FALSE = время выполнения в норме. Значение параметра не фиксируется, в каждом цикле оно может быть разным. Всё зависит от времени исполнения предыдущего цикла.
  • cycleTime — максимально возможное время на выполнение цикла. Задается в сотнях наносекунд. Для перевода в миллисекунды, разделите значение cycleTime на 10000.0.
  • lastExecTime — время выполнения программы в предыдущем цикле. Предыдущего, потому что текущий цикл еще только выполняется, вот прямо сейчас, в данный момент. Значение в сотнях наносекунд.
  • cycleCount — номер текущего цикла от момента включения контроллера. Если номер цикла умножить на длительность цикла cycleTime, можно узнать сколько прошло времени с момента включения контроллера.

 

В TwinCAT 3 массив поменял имя на _TaskInfo[], а структура стала более подробной и теперь называется PlcTaskSystemInfo.

No comments

Post a Comment

Note: Only a member of this blog may post a comment.