Надає основані на мові подібній до Java обчислювач та рушій бібліотек. Користувач може створювати та модифікувати функції та їх бібліотеки.
Ліцензія:
GPL
Вступ
Модуль контролеру JavaLikeCalc надає у системі OpenSCADA механізм створення функцій та їх бібліотек на мові подібній до Java. Опис функції на мові подібній до Java зводиться до обв'язки параметрів функції алгоритмом. Крім цього модуль наділено функціями безпосередніх обчислень шляхом створення обчислювальних контролерів.
Безпосередні обчислення забезпечуються створенням контролеру та зв'язуванням його із функцією цього-ж модуля. Для зв'язування функції створюється кадр значень, над яким і виконуються періодичні обчислення.
Модулем реалізуються функції горизонтального резервування, а саме — спільної роботи з віддаленою станцією цього-ж рівня. Окрім синхронізації значень та архівів атрибутів параметрів модулем здійснюється синхронізація значень обчислювальної функції, з метою безударного "підхоплення" алгоритмів.
Параметри функції можуть вільно створюватися, видалятися або модифікуватися. Поточна версія модуля підтримує до 65535 параметрів функції у підсумку із внутрішніми змінними. Вигляд редактору функцій показано на рис.1.
Рис.1. Вигляд редактору функцій.
Після будь-якої зміни програми або конфігурації параметрів здійснюється перекомпіляція програми із повідомленням пов'язаних з функцією об'єктів значень TValCfg. Компілятор мови побудовано із використанням відомого генератору граматики "Bison", який сумісний з не менш відомою утилітою "Yacc".
Мова використовує неявне визначення локальних змінних, яке полягає у визначені нової змінної у випадку привласнення їй значення. Причому тип локальної змінної встановлюється у відповідності з типом значення, що привласнюється. Наприклад, вираз Qr=Q0*Pi+0.01; визначить змінну Qr з типом змінної Q0.
У роботі з різними типами ця мова використовує механізм автоматичного приведення типів у місцях, де подібне приведення є доцільним.
Для коментування ділянок коду у мові передбачено символи "//" та "/* ... */". Все, що йде після "//" до кінця рядку та між "/* ... */", ігнорується компілятором.
У процесі генерації коду компілятор мови здійснює оптимізацію за константам та приведення типів констант до потрібного типу. Під оптимізацією констант мається на увазі виконання обчислень у процесі побудови байт-коду над двома константами та вставка результату у код. Наприклад, вираз y=pi*10; згорнеться у просте привласнення y=31.4159;. Під приведенням типів констант до потрібного типу мається на увазі формування у коді константи, яка виключає приведення типу в процесі виконання. Наприклад, вираз y=x*10, у випадку реального типу змінної x, перетвориться у y=x*10.0.
Вирази привласнення можуть записуватися через символ ',', наприклад:
Мова підтримує виклики зовнішніх та внутрішніх функцій. Ім'я будь-якої функції взагалі сприймається як символ, перевірка на належність якого до тієї або іншої категорії здійснюється у наступній послідовності:
не починається з крапки:
ключові слова (if, else, while, ...);
параметри-атрибути цієї функції;
іменовані-вбудовані постійні (EVAL, pi, e, ...) та постійні-об'єкти (SYS, arguments)
вбудовані функції (sin, cos, ...);
внутрішні, зовнішні функції, функції об'єкту та системних вузлів OpenSCADA (DOM);
зареєстровані раніш автоматичні змінні;
глобальні атрибути параметрів DAQ та властивості змінних;
ключові слова (in, var);
нова автоматична змінна.
починаються з точки:
елементи шляху до властивості та функції об'єкту.
Виклик зовнішньої функції, як і атрибуту системного параметра, записується як адреса до об'єкту динамічного дерева об'єктної моделі системи OpenSCADA у вигляді: "DAQ.JavaLikeCalc.lib_techApp.klapNotLin". Для статичних функцій Ви можете здійснювати динамічне підключення, наступним чином:
Для надання можливості написання користувацьких процедур управління різними компонентами OpenSCADA цим модулем надається реалізація API прекомпіляції користувацьких процедур окремих компонентів OpenSCADA на реалізації подібної до Java мови. Такими компонентами, наприклад, є: Шаблони параметрів підсистеми "Збір даних" та Середовище візуалізації та управління (СВУ).
шістнадцяткові: цифри 0-9, букви a-f або A-F (0x12, 0XAB);
реальні: 345.23, 2.1e5, 3.4E-5, 3e6;
логічні: true, false;
строкові: "hello", без переходу на наступний рядок однак з підтримкою прямої конкатенації строкових констант.
Типи змінних:
ціле: -263...263, EVAL_INT(-9223372036854775807);
реальне: 3.4 * 10308, EVAL_REAL(-1.79E308);
логічне: false, true, EVAL_BOOL(2);
рядок: послідовність символів-байтів (0...255) будь якої довжини, обмеженої об'ємом пам'яті та сховищем у БД; EVAL_STR("<EVAL>").
Вбудовані константи: pi = 3.14159265, e = 2.71828182, EVAL_BOOL(2), EVAL_INT(-9223372036854775807), EVAL_REAL,EVAL(-1.79E308), EVAL_STR("<EVAL>") Атрибути параметрів системи OpenSCADA (починаючи з підсистеми DAQ, у вигляді "{Тип модуля DAQ}.{Контролер}.{Параметр}.{Атрибут}"). Функції об'єктної моделі системи OpenSCADA.
1.2. Операції мови
Операції, підтримувані мовою, представлено у таблиці нижче. Пріоритет операцій зменшується зверху донизу. Операції з однаковим пріоритетом входять до однієї групи кольору.
Символ
Опис
()
Виклик функції.
{}
Програмні блоки.
++
Інкремент (пост та пре).
--
Декремент (пост та пре).
-
Унарний мінус.
!
Логічне заперечення.
~
Побітове заперечення.
*
Множення.
/
Ділення.
%
Залишок від цілочисельного ділення.
+
Складання
-
Віднімання
<<
Поразрядний зсув ліворуч
>>
Поразрядний зсув праворуч
>
Більше
>=
Більше або дорівнює
<
Менше
<=
Менше або дорівнює
==
Дорівнює
!=
Не дорівнює
|
Порозрядне "АБО"
&
Порозрядне "ТАК"
^
Порозрядне "Виключне АБО"
&&
Логічне "ТАК"
||
Логічне "АБО"
?:
Умовна операція "i=(i<0)?0:i;"
=
Привласнення.
+=
Привласнення із складанням.
-=
Привласнення із відніманням.
*=
Привласнення із множенням.
/=
Привласнення із діленням.
1.3. Вбудовані функції мови
Віртуальною машиною мови передбачено наступний набір вбудованих функцій загального призначення:
double max(double x, double x1) — максимальне значення із x та x1;
double min(double x, double x1) — мінімальне значення із x та x1;
string typeof(ElTp vl) — тип значення vl;
string tr(string base) — переклад базового base повідомлення.
Для забезпечення високої швидкості роботи у математичних обчислення модуль надає вбудовані математичні функції, які викликаються на рівні команд віртуальної машини:
double sin(double x) — синус x;
double cos(double x) — косинус x;
double tan(double x) — тангенс x;
double sinh(double x) — синус гіперболічний від x;
double cosh(double x) — косинус гіперболічний від x;
double tanh(double x) — тангенс гіперболічний від x;
double asin(double x) — арксинус від x;
double acos(double x) — арккосинус від x;
double atan(double x) — арктангенс від x;
double rand(double x) — випадкове число від 0 до x;
double lg(double x) — десятковий логарифм від x;
double ln(double x) — натуральний логарифм від x;
double exp(double x) — експонента від x;
double pow(double x, double x1) — зведення x у степінь x1;
double sqrt(double x) — корінь квадратний від x;
double abs(double x) — абсолютне значення від x;
double sign(double x) — знак числа x;
double ceil(double x) — округлення числа x до більшого цілого;
double floor(double x) — округлення числа x до меншого цілого.
1.4. Оператори мови
Загальний перелік операторів мови:
var — оператор ініціалізації змінної; визначення змінної без привласнення значення резервує її зі значенням EVAL, що дозволяє здійснити одноразову ініціалізацію складних типів даних на кшталт об'єкту, через перевірку на "isEVal()";
if — оператор умови "Якщо";
else — оператор умови "Інакше";
while — опис циклу "Поки";
for — опис циклу "Для";
in — роздільник циклу "Для" для перебору властивостей об'єкту;
break — переривання виконання циклу;
continue — продовжити виконання циклу з початку;
function — визначення внутрішньої функції;
using — дозволяє встановити простір видимості функцій часто використовної бібліотеки (using Special.FLibSYS;) для наступного звернення тільки за назвою функції, не має ефекту для об'єктного доступу;
return — переривання функції та повернення результату, який копіюється до атрибуту із ознакою повернення (return 123;); в середині внутрішньої функції здійснюється її завершення з визначеним результатом;
new — створення об'єкту, реалізовано: об'єкт "Object", масив "Array" та регулярні вирази "RegExp";
delete — видалення/звільнення об'єкту або його властивостей, при цьому: внутрішні змінні встановлюються у EVAL_REAL, зовнішні замінюються порожнім об'єктом, а властивості об'єкту очищуються.
1.4.1. Умовні оператори
Мовою модуля підтримуються два типи умов. Перша — це операції умови для використання всередині виразу, друга — глобальна, основана на умовних операторах.
Умова всередині виразу будується на операціях '?' та ':'. У якості прикладу можна записати наступні практичні вирази st_open=(pos>=100)?true:false;, що читається як "Якщо змінна pos більша або дорівнює 100, тоді змінній st_open привласнюється значення true, інакше — false".
Глобальна умова будується на основі умовних операторів "if" та "else". У якості прикладу можна привести той-же вираз, але записаний у інший спосіб if(pos>100) st_open=true; else st_open=false;. Як видно, вираз записано по іншому, але читається так само.
1.4.2. Цикли
Підтримується три типи циклів: while, for та for-in. Синтаксис циклів відповідає мовам програмування: C++, Java та JavaScript.
Цикл while, загалом, записується наступним чином: while({умова}) {тіло циклу};
Цикл for записується наступним чином: for({пре-ініціаліз};{умова};{пост-обчислення}) {тіло циклу};
Цикл for-in записується наступним чином: for({змінна} in {об'єкт}) {тіло циклу};
Де:
{умова} — вираз, який визначає умову; {тіло циклу} — тіло циклу множинного виконання; {пре-ініціаліз} — вираз попередньої ініціалізації змінних циклу; {пост-обчислення} — вираз модифікації параметрів циклу після чергової ітерації; {змінна} — змінна, яка буде містити ім'я властивості об'єкта при переборі; {об'єкт} — об'єкт для якого здійснюється перебір властивостей.
1.4.3. Внутрішні функції
Ця мова підтримує визначення та виклик внутрішніх функцій. Для визначення внутрішньої функції використовується ключове слово "function" та в цілому визначення має синтаксис: function {ім'яФ} ({зм1}, {зм2}, ... {змN}) { {тіло функції} }. Визначення внутрішньої функції всередині іншої недозволене однак дозволено виклик раніш визначеної.
Виклик внутрішньої функції здійснюється у типовий спосіб, як процедура {ім'яФ}({var1}, {var2}, ... {varN}); або як функція {змРез} = {ім'яФ}({зм1}, {зм2}, ... {змN});. Виклик внутрішніх функцій допустимий тільки після їх декларації вище!
Всі змінні, визначені у основному тілі, недоступні всередині внутрішніх функцій і можуть бути передані тільки через двобічні аргументи викликуваної внутрішньої функції. Всі змінні, визначені в середині внутрішньої функції, мають власний простір назв та недоступні із основного тіла або будь якої іншої внутрішньої функції та можуть бути передані тільки в основне тіло через двобічні аргументи або результат викликуваної внутрішньої функції.
Оператор "return" в середині внутрішньої функції здійснює контрольоване її завершення та розташування вказаної змінної або результату виразу як результату викликуваної внутрішньої функції.
Приклад типового визначення та використання внутрішньої функції наведено нижче:
1.4.4. Спеціальні символи строкових змінних
Мовою передбачено підтримку наступних спеціальних символів строкових змінних:
"\n" — перевід рядка;
"\t" — символ табуляції;
"\b" — забій;
"\f" — перевід сторінки;
"\r" — повернення каретки;
"\\" — сам символ '\';
"\041" — символ '!' записаний вісімковим числом;
"\x21" — символ '!' записаний шістнадцятковим числом.
1.5. Об'єкт
Мовою надається підтримка типу даних об'єкт "Object". Об'єкт представляє собою асоціативний контейнер властивостей та функцій. Властивості можуть містити як дані чотирьох базових типів, так і інші об'єкти. Доступ до властивостей об'єкту може здійснюватися за посередництвом запису імен властивостей через точку до об'єкту obj.prop, а також за посередництвом заключення імені властивості у квадратні дужки obj["prop"]. Очевидно, що перший механізм статичний, а другий дозволяє вказувати ім'я властивості через змінну. Видалити властивість об'єкту можна директивою "delete". Створення об'єкту здійснюється за посередництвом ключового слова new: varO = new Object(). Базове визначення об'єкту не містить функцій. Операції копіювання об'єкту насправді роблять посилання на вихідний об'єкт. При видаленні об'єкту здійснюється зменшення лічильника посилань, а при досягнення лічильника посилань нуля об'єкт видаляється фізично.
Різні компоненти можуть довизначати базовий об'єкт особливими властивостями та функціями. Стандартним розширенням об'єкту є масив "Array", який створюється командою varO = new Array(prm1,prm2,prm3,...,prmN). Перелічені через кому параметри поміщаються до масиву у вихідній послідовності. Якщо параметр тільки один тоді масив ініціюється вказаною кількістю порожніх елементів. Особливістю масиву є те, що він працює із властивостями як з індексами та основним механізмом звернення є заключення індексу у квадратні дужки arr[1]. Масив зберігає властивості у власному контейнері одномірного масиву. Цифрові властивості масиву використовуються для доступу безпосередньо до масиву, а символьні працюють як властивості об'єкту. Детальніше про властивості та функції масиву можна прочитати за посиланням.
Об'єкт регулярного виразу "RegExp" створюється командою varO = new RegExp(pat,flg), де pat — шаблон регулярного виразу, а flg — ознаки пошуку. Об'єкт роботи із регулярними виразами оснований на бібліотеці "PCRE". При глобальному пошуку встановлюється атрибут об'єкту "lastIndex", що дозволяє продовжити пошук при наступному виклику функції. У випадку невдалого пошуку атрибут "lastIndex" скидається у нуль. Детальніше про властивості та функції об'єкту регулярного виразу можна прочитати за посиланням.
Для довільного доступу до аргументів функції передбачено об'єкт аргументів, звернутися до якого можна за посередництвом символу "arguments". Цей об'єкт містить властивість "length" з кількістю аргументів у функції та дозволяє звернутися до значень аргументу за посередництвом його номеру або ідентифікатору. Розглянемо перебір аргументів по циклу:
args = new Array();
for(var i=0; i < arguments.length; i++)
args[i] = arguments[i];
Часткові властивості об'єкту мають і базові типи. Властивості та функції базових типів приведено нижче:
Нульовий тип, функції:
bool isEVal(); — Повертає "true".
Логічний тип, функції:
bool isEVal(); — Перевірка значення на "EVAL".
string toString(); — Надання значення у вигляді рядка "true" або "false".
Ціле та реальне число:
Властивості:
MAX_VALUE — максимальне значення;
MIN_VALUE — мінімальне значення;
NaN — недостовірне значення.
Функції:
bool isEVal(); — Перевірка значення на "EVAL".
string toExponential( int numbs = -1 ); — Повернення рядка, відформатованого числа у експоненціальній нотації та кількістю значущих цифр numbs. Якщо numbs відсутній то цифр буде стільки скільки потрібно.
string toFixed( int numbs = 0, int len = 0, bool sign = false ); — Повернення рядку відформатованого числа в нотації з фіксованою точкою та кількістю цифр після десяткової точки numbs з мінімальною довжиною len та обов'язковим знаком sign. Якщо numbs відсутній то кількість цифр після десяткової точки дорівнює нулю.
string toPrecision( int prec = -1 ); — Повернення рядка відформатованого числа з кількістю значущих цифр prec.
string toString( int base = 10, int len = -1, bool sign = false ); — Повернення рядку відформатованого числа цілого типу з базою представлення base (2-36) з мінімальною довжиною len та обов'язковим знаком sign.
Рядок:
Властивості:
int length — довжина рядка.
Функції:
bool isEVal(); — Перевірка значення на "EVAL".
string charAt( int symb ); — Вилучає із рядка символ номер symb, нумерація символів з нуля.
int charCodeAt( int symb ); — Вилучає із рядка код символу symb.
string concat( string val1, string val2, ... ); — Повертає новий рядок сформований шляхом приєднання значень val1 і т.п. до початкового.
int indexOf( string substr, int start ); — Повертає позицію пошукового рядка substr у вихідному рядку починаючи з позиції start. Якщо вихідна позиція не вказана то пошук починається з початку. Якщо шуканого рядка не знайдено то повертається "-1".
int lastIndexOf( string substr, int start ); — Повертає позицію шуканого рядка substr у вихідному рядку починаючи з позиції start, при пошуку з кінця. Якщо вихідна позиція не вказана то пошук починається з кінця. Якщо шуканого рядку не знайдено то повертається "-1".
int search( string pat, string flg = "" ); — Пошук у рядку за шаблоном pat та ознаками шаблону flg. Повертає положення найденого рядку інакше "-1".
var rez = "Java123Script".search("script","i"); // rez = 7
int search( RegExp pat ); — Пошук у рядку за шаблоном "RegExp" pat. Повертає положення найденого підрядку інакше "-1".
var rez = "Java123Script".search(new RegExp("script","i")); // rez = 7
Array match( string pat, string flg = "" ); — Пошук в рядку за шаблоном pat та ознаками шаблону flg. Повертає масив із знайденим підрядком (0) та підвиразами (>1). Атрибут "index" масиву встановлюється у позицію знайденого підрядка. Атрибут "input" встановлюється у початковий рядок.
Array match( TRegExp pat ); — Пошук у рядку за шаблоном "RegExp" pat. Повертає масив зі знайденим підрядком (0) та підвиразами (>1). Атрибут "index" масиву встановлюється у позицію знайденого підрядка. Атрибут "input" встановлюється у початковий рядок.
string slice( int beg, int end ); string substring( int beg, int end ); — Повернення підрядку вилученого з вихідного починаючи з позиції beg та закінчуючи end, нумерація з нуля. Якщо значення початку або кінця негативне, то відлік ведеться з кінця рядку. Якщо кінець не вказано, то кінцем є кінець рядку. Наприклад, конструкція substring(-2) поверне останні два символи рядку.
Array split( string sep, int limit ); — Повернення масиву елементів рядку поділених sep з обмеженням кількості елементів limit.
Array split( RegExp pat, int limit ); — Повертає масив елементів рядку поділених шаблоном "RegExp" pat з обмеженням кількості елементів limit.
real toReal(); — Перетворення поточного рядку у реальне число.
int toInt( int base = 0 ); — Перетворення поточного рядки в ціле число, у відповідності із основою base (от 2 до 36). Якщо основа дорівнює 0 тоді буде враховуватися префіксний запис для визначення основи (123-десяткове; 0123-вісімкове; 0x123-шістнадцяткове).
string parse( int pos, string sep = ".", int off = 0 ); — Виокремлення із вихідного рядку елементу pos для поділювача елементів sep від зміщення off. Результуюче зміщення поміщається назад до off.
string parseLine( int pos, int off = 0 ); — Виокремлення рядку з номером pos від зміщення off. Результуюче зміщення поміщюється назад до off.
string parsePath( int pos, int off = 0 ); — Виділення із початкового шляху елементу pos від зміщення off. Результуюче зміщення поміщюється назад до off.
string path2sep( string sep = "." ); — Перетворення шляху у поточному рядку у рядок з розділювачем sep.
string trim( string cfg = " \n\t\r" ); — Обрізка рядка з початку та кінцю для символів cfg.
Для доступу до системних об'єктів(вузлам) OpenSCADA передбачено відповідний об'єкт, який створюється шляхом простого вказання точки входу "SYS" кореневого об'єкту OpenSCADA, а надалі, через точку вказуються вкладені об'єкти у відповідності з ієрархією. Наприклад, виклик функції запиту через вихідний транспорт здійснюється наступним чином: SYS.Transport.Sockets.out_testModBus.messIO(Special.FLibSYS.strEnc2Bin("15 01 00 00 00 06 01 03 00 00 00 05"));.
1.6. Приклади програми на мові
Приведемо декілька прикладів програм на подібній до Java мові:
//Модель клапану
Qr = Q0 + Q0*Kpr*(Pi-1) + 0.01;
Sr = (S_kl1*l_kl1+S_kl2*l_kl2)/100;
Ftmp = (Pi>2*Po) ? Pi*pow(Q0*0.75/Ti,0.5) : (Po>2*Pi) ? Po*pow(Q0*0.75/To,0.5) : pow(abs(Q0*(pow(Pi,2)-pow(Po,2))/Ti),0.5);
Fi -= (Fi-7260*Sr*sign(Pi-Po)*Ftmp)/(0.01*lo*frq);
Po += 0.27*(Fi-Fo)/(So*lo*Q0*frq);
Po = (Po<0) ? 0 : (Po>100) ? 100 : Po;
To += (abs(Fi)*(Ti*pow(Po/Pi,0.02)-To)+(Fwind+1)*(Twind-To)/Riz)/(Ct*So*lo*Qr*frq);
2. Контролер та його конфігурація
Контролер цього модуля пов'язується з функціями із бібліотек, побудованими за його допомогою, для забезпечення безпосередніх обчислень. Для надання обчислювальних даних у систему OpenSCADA в контролері можуть створюватися параметри. Приклад вкладки конфігурації контролера даного типу зображено на рис.2.
Рис.2. Вкладка конфігурації контролера.
За допомогою цієї вкладки можна встановити:
Стан контролеру, а саме: Статус, "Включений", "Запущений" та ім'я БД, яка містить конфігурацію.
Ідентифікатор, ім'я та опис контролеру.
Стан, в який переводити контролер при завантажені: "Включений" та "Запущений".
Ім'я таблиці для зберігання параметрів.
Адреса обчислювальної функції.
Політика планування обчислення, пріоритет та число ітерацій у одному циклі задачі обчислення.
Вкладка "Обчислення" контролеру(Рис. 3) містить параметри та текст програми, яка безпосередньо виконується контролером. Модулем передбачена обробка низки спеціальних параметрів, доступних в програмі контролеру:
f_frq — Частота обчислення програми контролера, тільки читання.
f_start — Ознака першого виконання програми контролера, запуск, тільки читання.
f_stop — Ознака останнього виконання програми контролера, зупинка, тільки читання.
this — Об'єкт даного контролеру.
Рис.3. Вкладка "Обчислення" контролеру.
3. Параметр контролеру та його конфігурація
Параметр контролера данного модуля виконує функцію надання доступу до результатів обчислення контролера у систему OpenSCADA за посередництвом атрибутів параметрів. Із специфічних полей вкладка конфігурації параметра контролера містить тільки поле перелічення параметрів обчислювальної функції, які треба відобразити.
4. Бібліотеки функцій модуля
Модуль надає механізм для створення бібліотек користувацьких функцій на подібній до Java мові. Приклад вкладки конфігурації бібліотеки зображено на Рис.4. Вкладка містить базові поля: доступність, адреса таблиці БД бібліотеки, дата та час модифікації, ідентифікатор, ім'я та опис.
Рис.4. Вкладка конфігурації бібліотеки.
5. Користувацькі функції модуля
Функція, також як і бібліотека, містить базову вкладку конфігурації, вкладку формування програми та параметрів функції (Рис.1), а також вкладку виконання створеної функції.
6. API користувацького програмування
Деякі об'єкти модуля надають функції користувацького програмування.
Об'єкт "Бібліотека функцій" (SYS.DAQ.JavaLikeCalc["lib_Lfunc"])
ElTp {funcID}(ElTp prm1, ...) — виклик функції "funcID" бібліотеки "Lfunc". Повертає результат викликаної функції. Префікс "lib_" перед ідентифікатором бібліотеки обов'язковий!
Об'єкт "Користувацька функція" (SYS.DAQ.JavaLikeCalc["lib_Lfunc"]["func"])
ElTp call(ElTp prm1, ...) — виклик функції "func" бібліотеки "Lfunc" з параметрами "prm{N}". Повертає результат викликаної функції. Префікс "lib_" перед ідентифікатором бібліотеки обов'язковий!
7. Продуктивність
Вихідний текст процедур на мові цього модуля компілюється у байт-код віртуальної машини, який надалі обчислюється віртуальною машиною. Байт-код це не машинний код і досягнути продуктивності самої апаратної архітектури у віртуальній машині його виконуючої теоретически нереально, якщо звісно код цієї віртуальної машини не виконує сам процесор. Тобто продуктивність виконання байт-коду приблизно на порядок нижче апаратної продуктивності за рахунок накладених витрат команд віртуальної машини, розподілу багатопотокового доступу до даних, прозорого приведення типів та відсутності жорсткої типізації, а також динамічної природи мови та наявності складних типів "Рядок" та "Об'єкт".
28.01.2006: Основание: Первичная оценка производительности виртуальной машины системы OpenSCADA на основе выражения "y=x1+x2", где все переменные глобальные вещественного типа.
Стадия
Действие
K7_1G-0, мкс
1
Инициализация списка регистров
2.3
2
Вход в функцию exec()
3
3
Обход команд
4.4
4
Чтение
9
5
Полное время
10.2
17.07.2013: Основание: Обоснование текущей производительности, оценка и оптимизация. Измерения проводились выборкой минимального времени из пяти вызовов по 1000 исполнений формулы "a -= b*(a-c)" и её сокращений в каждом вызове. Все переменные глобальные вещественного типа.
!> use unified TVariant function setVal() and getVal() = 7.6 (2.7 write only) => fix to 5.0 by prevent default set to string EVAL.
=> full call: 2.5 (0.33)
=> only write const: 2.17 (0.47)
=> only check for type: 1.7 (0.3)
=> pass code: 1.4 (0.11)
Write to function IO is longer then read from local register by other context call and additional checking for NAN and real modification.
Empty
1.29
Infrastructure and measurement method utilization time.
24.04.2016: Reason: Estimate performance of access to low level IO lines on Raspberry Pi GPIO in different ways of JavaLikeCalc language of OpenSCADA. Conditions:Raspberry Pi 3, GPIO40, DAQ.BCM2835 (based on library bcm2835)
Operation
Result, us
Sleep. Lag on sleep in 1ms measured, which mostly limited by the realtime reaction about 100us.
SYS.sleep();
+110
Special.FLibSYS.fnc_tmSleep();
+70
Sleep. Lag on sleep in 100us measured, which performs in the measuring cycle.
SYS.sleep();
+17
Special.FLibSYS.fnc_tmSleep();
+2
Get GPIO pin's level
From an attribute res = BCM2835.pi2.pi2.gpio17;
5.4
By the static accessing function res = DAQ.BCM2835.pi2.pi2.fnc_get(17);
1.6
By the static accessing function with prepare the link function get = "DAQ.BCM2835.pi2.pi2.fnc_get"; for(i = 0; i < 10000; i++) res = get(17);
1.7
By the dynamic accessing function res = SYS.DAQ.BCM2835.pi2.pi2.fnc_get.call(17);
80
By the dynamic accessing function with prepare the end object tO = SYS.DAQ.BCM2835.pi2.pi2.fnc_get; for(i = 0; i < 1000; i++) res = tO.call(17);
14.3
Put GPIO pin's level
To an attribute BCM2835.pi2.pi2.gpio18 = true;
2.1
By the static accessing function DAQ.BCM2835.pi2.pi2.fnc_put(18, true);
1.4
By the static accessing function with prepare the link function put = "DAQ.BCM2835.pi2.pi2.fnc_put"; for(i = 0; i < 10000; i++) put(17, false);
1.5
By the dynamic accessing function SYS.DAQ.BCM2835.pi2.pi2.fnc_put.call(18, true);
79
By the dynamic accessing function with prepare the end object tO = SYS.DAQ.BCM2835.pi2.pi2.fnc_put; for(i = 0; i < 1000; i++) tO.call(18, true);