November 5, 2019

InvokeRpcMethod — вызов удаленного метода

С помощью ADS можно не только передавать данные, но и вызывать методы ПЛК задачи.

TcAdsClient client = new TcAdsClient();
client.Connect(new AmsAddress("5.28.214.97.1.1", AmsPort.R0_RTS + 1));
short result = -1;
var args = new object[]{ result, (short)1, (short)2 };
try {
    result = (short)client.InvokeRpcMethod("MAIN.fbBox", "M_FuncPub", args);
}
catch { }


PROGRAM / ACTION


Проверим странное...
...оно не работает. Нет такого символа
Value cannot be null.
Parameter name: symbol
Работоспособность не зависит от размещения атрибута: что внутри экшена, что над объявлением программы, что и там, и здесь. Результат отрицательный.


FB


Action

Опять нестандартное. И оно тоже не работает.
The RPC method 'A_Func01' is not supported on symbol 'MAIN.fbBox!
Кстати, опечатка в сообщении эксепшена — не хватает кавычки.


Method

Для метода, ожидаемо, работает. Причем, внезапно, вызов метода работает даже когда Runtime в состоянии Stop. Иначе говоря, когда порт создан (851), но ПЛК задача еще не запущена.

Команда __NEW при RPC вызовах также работает, даже в состоянии "стоп", и по прежнему выжирает память роутера. Контроль памяти роутера описан в New, Delete и память роутера. Поэтому если память выделяется внутри RPC метода, а освобождается в другом месте — получится Ахтунг и протечка памяти!

Итоги:
  • Уровень доступа метода не влияет на доступность извне. Любой из PUBLIC, PRIVATE, PROTECTED, INTERNAL доступен для внешнего вызова.
  • Вызов требует наличия всех параметров объявленных в ФБ как VAR_INPUT
  • Точки останова внутри методов не срабатывают при RPC вызовах.


Насколько быстро?


Тестировать будем на CX9020, x32, TwinCAT 3.1.4022.25 и на десктопе Core i7-3630QM x64 TwinCAT 3.1.4024.0. Для интереса сравним производительность относительно обычного чтения символа.

results[i] = (uint)client.InvokeRpcMethod("MAIN.fbBox", "M_FuncPub", args);
// VS
results[i] = (uint)client.ReadSymbol("MAIN.CycleCount", typeof(uint), false);


Будем последовательно и синхронно читать по 1000 значений за раз. В случае с InvokeRpcMethod соответственно вызывать метод и получать результат. Результатом же чтения будет номер текущего цикла ПЛК задачи. При последовательном и многократном чтении, получим массив номеров циклов. Сравнивая два соседних значения и умножая разницу на время цикла ПЛК задачи, получим время затраченное на чтение.

Начну с обычного чтения ReadSymbol. По горизонтали — номер выборки. По вертикали — время в миллисекундах, затраченное на чтение символа. Цветом обозначено время цикла ПЛК-задачи. Первым будет CX9020, вторая картинка — десктоп:

ReadSymbol, CX9020



ReadSymbol, десктоп Core i7 x64


Даже "на глаз" видно, что десктоп справляется "стабильнее" и быстрее. К тому же, в случае десктопа все происходит на локалхосте и нет сетевых прослоек, привносящих дополнительные лаги. Краткий вывод: для циклов от 4 миллисекунд данные возвращаются стабильно. Меньше 4мс могут быть задержки (видимо запросы попадают на границу цикла).

Кроме этого есть запросы с нулевым временем выполнения. Это озорует роутер. При отправке запросов чаще, чем время одного цикла, роутер делает вид, что значение еще не изменилось и быстро шлет обратный ответ с тем же, старым значением. Ну и отлично.

Теперь про RPC запросы. Порядок контроллеров прежний:

RPC, CX9020



RPC, десктоп Core i7 x64


RPC выполняется дольше чем запрос данных одной переменной. Это ожидаемо, так как нужно принять запрос с аргументами, выполнить код, и только затем отправить ответ. 3-4-5 циклов, в зависимости от того, куда упадет запрос относительно границы кванта системного времени.

Правило 4мс по прежнему работает.


Выводы


RPC-запрос может легко выполнить код, который нарушит экосистему рантайма. Например, может вызвать утечку памяти и т. п. В то же время можно попытаться организовать автоматическую систему юнит-тестирования, так как RPC вызовы работают даже на приостановленном рантайме.

Если же необходимо реализовать контурные режимы или передавать данные чаще чем раз в 4мс, то необходимо реализовать промежуточный буфер и отправлять несколько значений за раз, используя обычные функции для работы с переменными ReadAny, WriteSymbol, etc.


PS: Инструменты


Для проведения тестирования и рисования результатов, иногда достаточно обычного экселя (Excel), что и было использовано:




No comments

Post a Comment

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