PDA

Просмотр полной версии : Модель памяти CoDeSys / ОВЕН ПЛК



Владимир Ситников
08.06.2016, 10:30
Интересно следующее:
1) Есть ли документация на модель памяти (https://en.wikipedia.org/wiki/Memory_model_(programming)) КДС и/или ОВЕН ПЛК. Судя по всему, нет.
2) Есть ли защита от word tearing. Например, разные задачи выполняются одновременно и пишут в смежные AT% ячейки памяти (или вообще в соседние биты).
3) out of order writes / happens-before / data race. Грубо говоря, разрешено ли компилятору менять порядок записи переменных.

Даже ПЛК110 (с учётом PRU) выполняет как минимум две задачи, и обработка PRU не влияет на основной цикл (http://www.owen.ru/forum/showthread.php?t=22169&p=197630&viewfull=1#post197630) => значит должна быть какая-то синхронизация между PRU и механизмом обработки входов-выходов.



Как бы я предупреждал. Заведите себе тему и в ней рубитесь.

К сути:
ЦАП на ПЛК работает не через библиотеки, а через Конфигурацию ПЛК. В соответствующий канал записывается значение переменной, в заданном диапазоне.
Про считывание входов, опрос и изменение во время цикла.`
1. К PLCOpen отсылать не буду, но книжку Петрова или Минаева полистать стоит. Есть думаю и другие достойные книги.
2. Нужно понимать особенности работы ПЛК. Опрос области памяти входов - выполнение цикла - запись области памяти выходов - сервисное время - опрос области памяти входов. ПЛК работает так и только так. Классически. Именно по этому Вы обращаетесь не к физической памяти контроллера, а к области памяти AT%...
3. А вот записываются значения физических входов в память входов, и управление физическими выходами из памяти выходов в независимости от цикла ПЛК.

Говоря простыми словами - после того как контроллер считал область памяти входов и ушел в выполнение цикла (а он может быть и в секундах - никто не запрещает) - изменение физических входов восприниматься не будет. И уже только закончив цикл и снова перейдя к чтению области памяти входов контроллер возьмет последнее записанное в эту область памяти значение, которое за это время могло измениться 100 раз.
При этом совершенно не важно сколько у Вас процессоров - 1 или 1000. Если Вы работаете с AT% - Вы всегда берете значение из области памяти входов.

Для задач, где требуется реагировать на изменение значения входов даже когда программа выполняет цикл - прерывания. Но это совсем другая история.



2. Нужно понимать особенности работы ПЛК. Опрос области памяти входов - выполнение цикла - запись области памяти выходов - сервисное время - опрос области памяти входов. ПЛК работает так и только так. Классически. Именно по этому Вы обращаетесь не к физической памяти контроллера, а к области памяти AT%...

Вопрос "что произойдёт, если две одновременно выполняющиеся задачи обратятся к одной/смежной области AT% всё равно открыт".
Например, одна задача запишет первый бит, вторая -- второй. А CPU вряд ли умеет отдельные биты в памяти менять. Наверняка наслоение какое-нибудь пойдёт.
Аналогично с чтением: один меняет биты, а второй читает WORD'ы -- word tearing в полный рост.


Говоря простыми словами - после того как контроллер считал область памяти входов и ушел в выполнение цикла (а он может быть и в секундах - никто не запрещает) - изменение физических входов восприниматься не будет
Если так окажется, что на ПЛК 2 ядра, и в каждый момент на каком-то из ядер выполняется хотя бы одна программа. Внимание, вопрос: в какой момент времени переносятся данные из "физической памяти" в "AT% память" и обратно? Или этот момент разный для разных ядер?

Ну, легко говорить, когда всего одно ядро (тут более-менее понятно, что есть цикл, есть пользовательское и системное время). А когда ядер несколько, то может возникнуть ситуация, что в каждый момент кто-то выполняется, и где там "цикл" неясно.

Николаев Андрей
08.06.2016, 11:56
Спасибо за понимание и что открыли отдельную тему.
Первые три вопроса требуют пояснения, я, видите ли не программист.
Модель памяти не может иметь финальный вид, так как пользователь при добавлении в конфигурации ПЛК определенных параметров и создает эту самую модель памяти. Про то, как она адресуется и как делается выравнивание в карте есть описание в РП, в разделе добавления сетевого обмена.
Могут ли разные подзадачи обращаться к одной области памяти? Могут. И для чтения и для записи. В физический выход пойдет та, которая была записана последней в интервале между передачей из области памяти в физические выходы. Так же как и в PLC_PRG Вы можете 1000 раз изменять значение переменной, но в память будет записано последнее. Это же ПЛК.

Конечно же есть зависимость на уровне кода CPU что и когда делается. Когда PRU опрашивается, когда значения в ЦАПы записываются или входы опрашиваются и записываются в области памяти. А так же когда ОС вызвать, когда в ОС вызвать систему исполнения CODESYS, когда в системе исполнения вызвать PLC_PRG и другие подпрограммы, как и когда просматривать не сработали ли прерывания, в какой момент времени производится инициация и контроль сетевого обмена по 5 интерфейсам, и еще пара сотен процессов.
Вот только если Вы покупаете ПЛК - Вам не надо думать об этом. Вы знаете область памяти и к ней обращаетесь. Вы вызываете прерывания по заданному принципу... в любых ПЛК любых производителей... независимо от архитектуры CPU. В этом и есть тайный смысл ПЛК.
Всем желающим об этом подумать есть промПК, Arduino и прочие ругательные для меня слова, где Вы можете все это самолично учитывать и настраивать. Хотя нет, на ардуино тоже уже CDS положили :)
Но это уже никак не относится к ОВЕН ПЛК. Как и вопросы многоядерности. Возможно их лучше обсуждать на профильных форумах.

ASo
08.06.2016, 13:17
Интересно следующее:
1) Есть ли документация на модель памяти (https://en.wikipedia.org/wiki/Memory_model_(programming)) КДС и/или ОВЕН ПЛК. Судя по всему, нет.
2) Есть ли защита от word tearing. Например, разные задачи выполняются одновременно и пишут в смежные AT% ячейки памяти (или вообще в соседние биты).
3) out of order writes / happens-before / data race. Грубо говоря, разрешено ли компилятору менять порядок записи переменных.

Повторяю еще раз.
Стандарт МЭК..... создан не для профессиональных программистов, а для технологов, которых обучили (начальному уровню) программирования.
Именно поэтому ST - это Паскаль, а не Си. Именно поэтому из языка убраны все прибамбамсеты, которые позволяют "удалить гланды через черный ход".
Исходите из этой парадигмы.

Владимир Ситников
08.06.2016, 13:36
Повторяю еще раз.
Стандарт МЭК..... создан не для профессиональных программистов, а для технологов, которых обучили (начальному уровню) программирования.
Именно поэтому ST - это Паскаль, а не Си. Именно поэтому из языка убраны все прибамбамсеты, которые позволяют "удалить гланды через черный ход".
Исходите из этой парадигмы.

Я вашу мысль прекрасно понимаю, но против законов физики не попрёшь.

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

"убраны прибамбасы" это каким образом? Понятно, что "malloc/free" в стандарте специально нет. Но то, что именно может увидеть операция чтения из памяти -- этот вопрос за скобки не вынесешь.
Даже на многоядерных ПЛК всё равно делают один-единственный цикл? Честно говоря, не вяжется. И не вяжется с утверждением, что "PRU задачи не влияют на цикл ПЛК".


В КДС 3.5 можно включить warning, чтобы оно ругалось, если обнаружит, что "разные задачи обращаются к одной и той же области AT%" (или что-то типа того, но сходу не получается найти).
Это жжж не спроста -- значит, какая-то опасность есть.

Владимир Ситников
08.06.2016, 13:53
Спасибо за понимание и что открыли отдельную тему.
Первые три вопроса требуют пояснения, я, видите ли не программист.
Это и программистам тяжело даётся, поэтому норм.

Если просто, то модель памяти отвечает на один вопрос: "что может вернуть операция чтения?"
Вопрос звучит просто, но реально всё именно к нему сводится. Есть какая-то программа, и вопрос "что может вернуть конкретная операция чтения".

При этом, программистов не волнует как именно делаются (или не делаются) операции записи. Ведь, главное в том, что именно мы можем прочитать.
В тривиальном случае (если чтений вообще нет), компилятор может смело выкинуть весь код и никто об этом не узнает (чтений-то нет!)

Если грубо, то вопрос, например, в том "есть ли гарантия, что при изменении ячейки памяти в одной задаче другие увидят это прямо сразу, или вообще могут не увидеть, или только в следующем запуске и т.п.".

"2) Есть ли защита от word tearing"

Word tearing (http://shipilev.net/blog/2014/jmm-pragmatics/#_part_ii_word_tearing).

Как правило, процессоры не могут менять отдельные биты в памяти, а только целые байты/слова и т.п.
При этом, операция "изменить бит" превращается в 3 операции: загрузить байт, изменить, записать байт назад.

Если две задачи делают такое "примерно в одно время со смежными битами", то запросто может возникнуть ситуация, что "записать байт назад" запишет байт без учёта, что "только что бит в этой области изменила другая задача".

Аналогичная проблема может быть, например, при работе с соседними элементами массива.


"3) out of order writes / happens-before"

Если грубо, то "задача A обновила пару ячеек памяти, в какой момент изменения станут видны задаче Б?"
Или ещё вопрос: "задача X записала массив из 10 значений, и в ячейку AT%готово записала 1. Задача Y прочитала значение 1 из ячейки AT%готово. Верно ли, что задача Y может смело читать оставшиеся 10 ячеек и в них будут актуальные данные?"

Если подробно, то читать можно тут: http://shipilev.net/blog/2014/jmm-pragmatics/#_part_iii_sc_drf

2 часа видео (на русском) на эту тему: https://www.youtube.com/watch?v=noDnSV7NCtw, https://www.youtube.com/watch?v=Ky1_5mabd18

capzap
08.06.2016, 15:57
что на этой картинке компилятор может смело выкинуть?

Владимир Ситников
08.06.2016, 17:34
что на этой картинке компилятор может смело выкинуть?

Была бы модель памяти -- можно было бы ответить. Без неё остаётся лишь гадать и ставить эксперименты над реальным железом, специально провоцируя проблемные многопоточные выполнения.

Не забываем, что "то, что разрешено по спецификации" и "то, что умеет делать компилятор" это разные вещи. Я не говорю, что компилятор обязан всё-всё-всё оптимизировать.
Я говорю про то, что хорошо бы иметь понимание того, что именно запрещено и разрешено делать компилятору (и железу).

Целесообразно ли учить компилятор предвычислению такого цикла -- вопрос. С другой стороны, операцию "avg=ARDINST()" можно было бы и вынести из цикла (оптимизация loop invariant code motion (https://en.wikipedia.org/wiki/Loop-invariant_code_motion) часто даёт хороший прирост производительности).

Кстати, когда я говорю "компилятор", в эту же категорию попадает и CPU.
Смотрите: почти у каждого CPU есть store buffer (место, где хранятся команды на запись, которые уже обработаны в CPU, но ещё не записаны в память. Память обычно тормозная, поэтому store buffer имеет смысл). В итоге может оказаться, что одна команда записи ещё не закончилась, а другая команда уже началась. Если компилятор не будет генерировать специальные упорядочивающие команды, то CPU может переупорядочивать выполняемые инструкции (с точностью до модели памяти конкретного процессора).

Если бы все ассемблерные команды выполнялись ровно в том порядке как они написаны, то программы работали бы на порядок медленнее. Смысл переупорядочивания как раз в том, чтобы сделать такие правила, которые не выносят мозг программистам, и, в то же время, позволяют эффективно параллелить выполнение.

ASo
08.06.2016, 19:25
Если бы все ассемблерные команды выполнялись ровно в том порядке как они написаны, то программы работали бы на порядок медленнее. Смысл переупорядочивания как раз в том, чтобы сделать такие правила, которые не выносят мозг программистам, и, в то же время, позволяют эффективно параллелить выполнение. Вы узнали, что такое суперскалярность и спекулятивное вычисление?????

А по сути - зачем вам "модель памяти", если воспользоваться ей по крайней мере на ПЛК производства ОВЕН Вы не можете???

Владимир Ситников
08.06.2016, 19:57
Вы узнали, что такое суперскалярность и спекулятивное вычисление?????

Простите, но очень сильно складывается ощущение, что вы пишете в духе "не читал, но осуждаю".
Скорее всего, вы не понимаете суть вопроса, а имеете лишь поверхностное знание о спекулятивном выполнении.

Модель памяти как раз и нужна, для того, чтобы понять "что имеет право, а что не имеет право" делать компилятор/железо.


А по сути - зачем вам "модель памяти", если воспользоваться ей по крайней мере на ПЛК производства ОВЕН Вы не можете???

Почему? Лично у меня многоядерный ПЛК производства ОВЕН. Буду ли я на нём заниматься непотребством? Вряд ли.
Но знать какие гарантии даёт платформа при обращении к одной и той же области памяти в целом полезно. Как без этого программировать?

Посмотрите, capzap прекрасный вопрос задал. MM как раз и позволяет отвечать на такого сорта вопросы. Вот, только складывается ощущение, что MM нигде не зафиксировано. Т.е. на уровне "интуиции" и plug&pray.

capzap
08.06.2016, 20:05
так может не зафиксировано потому что нет этого. Получение начальног адреса может и в этом коде компилятор выносит за цикл, это действительно ни как не проверить, но переменная zero ни где не используется,кроме как внутри цикла и по логике компилятор бы её удалил в языках на ПК, а здесь будет продолжать делать приращение, потому что запрос значения или запись могут произойти через указатель, который в свою очередь может быть создан динамически,а у семена еще и панель может обратиться, про которую компилятор точно не знает

ASo
08.06.2016, 20:14
Скорее всего, вы не понимаете суть вопроса, а имеете лишь поверхностное знание о спекулятивном выполнении.
Вы с инженером-системотехником по образованию разговариваете.

Модель памяти как раз и нужна, для того, чтобы понять "что имеет право, а что не имеет право" делать компилятор/железо.Стандарт МЭК.... разработан именно для того, чтобы технолог-программист этого не знал и об этом не задумывался.

Почему? Лично у меня многоядерный ПЛК производства ОВЕН.Модель такого ПЛК приведите пожалуйста.

Владимир Ситников
08.06.2016, 20:20
так может не зафиксировано потому что нет этого
Нет чего?

Какая-то модель есть. В самом простом смысле уже много раз разбирали, что "сколько раз выходные переменные не меняй, всё равно будет видно лишь последнее значение".


потому что запрос значения или запись могут произойти через указатель, который в свою очередь может быть создан динамически,
Если локальную переменную (не та, которая in, а простую) ФБ могут изменить извне, это действительно печаль.
Как панель может обратиться ко внутренней переменной -- ума не приложу. Тоже через указатели? Как-то уже совсем невероятно.

Владимир Ситников
08.06.2016, 20:29
Вы с инженером-системотехником по образованию разговариваете.
Хорошо, принято.


Стандарт МЭК.... разработан именно для того, чтобы технолог-программист этого не знал и об этом не задумывался.
Да, с благими целями создаются стандарты.
К сожалению, если компилятор и железо слепо следует программе, то программа выполняется слишком медленно.
Т.е. даже для однопоточных программ нужны какие-то допущения, чтобы компилятор и процессор могли выполнять код так, как будет быстрее.

Я к чему: абстракции текут (https://en.wikipedia.org/wiki/Leaky_abstraction), и в многопоточных приложениях от синхронизации никуда не уйти.
Как вариант -- сказать, что "при одновременной работе со смежными областями памяти может быть что угодно" (== undefined behavior), и это тоже вариант "модели памяти".
Упрощает ли он жизнь программисту? Едва ли.
Так ли работает КДС? -- фиг знает.

Если бы В.Филоненко сказал "для выполнения IO задачи на всех ядрах, в том числе, на PRU приостанавливаются, выполняется ввод-вывод, и потом возобновляются программы", то это бы объясняло как именно синхронизируется IO и PRU/цикл.
Но, В.Филоненко сказал, что "PRU вообще в realtime работает, и не влияет на цикл".


Модель такого ПЛК приведите пожалуйста.
ПЛК110-24-32.К-М02

capzap
08.06.2016, 20:32
в семене ФБ делится на сам ФБ с логикой и блок данных из объявленных переменных, в КДС это как раз о чем Вы говорили. В степе можно обращаться из вне к адресу этого блока данных и делать с ним что хочется, в КДС это можно только через указатель

ASo
08.06.2016, 20:40
ПЛК110-24-32.К-М02
И? Вы готовы утверждать, что в этом ПЛК истинно многозадачная среда исполнения?

Владимир Ситников
08.06.2016, 21:20
И? Вы готовы утверждать, что в этом ПЛК истинно многозадачная среда исполнения?

Владислав утверждает, что да, многозадачная среда.

1. Программы на PRU выполняются отдельно, и никак не влияют на цикл ПЛК и др. функционал.
2. В примере цикл PRU - 1 мкс (0,5МГц частота импульсов), на 1 МГц рассчитывалась схемотехника быстрых I/O.
3. Для примера при цикле 1 мкс можно выполнить приблизительно 20-50 пользовательских лог. блоков (в зависимости от их сложности). Цикл можно менять как в меньшую, так и в большую сторону, в т.ч. динамически.

Натурных экспериментов, чтобы подтвердить/опровергнуть эти слова не ставил.

ASo
08.06.2016, 21:24
Понятно....
При чем тут PRU и "классический" функционал КДС??????

Владимир Ситников
08.06.2016, 21:48
Понятно....
При чем тут PRU и "классический" функционал КДС??????

Чего не знаю, того не знаю.

Если серьёзно, то и PRU и КДС могут работать с fast DI/DO -- т.е. возможны гонки (data races).
Ну, я же про PRU с первого сообщения говорю. Если оно совсем не в кассу, можно было так и сказать. Я ж не такой дурак, как может показаться. Читать умею. Но сейчас всё выглядит так, что PRU выполняется одновременно с циклом, значит возможны потенциальные конфликты за память/входы/выходы.

Ещё потенциально смежный вопрос -- 20us таймер. Ещё одна возможность выполнять задачу "чаще цикла".
Там тоже вопросы "что можно, а что нельзя" делать в этой задаче на обработку 20us таймера.

ASo
08.06.2016, 21:52
Блиннннннн....
PRU не имеет к "классическому" функционалу КДС никакого отношения! Рассматривайте его, как сопроцессор ввода-вывода (некая аналогия - сопроцессор плавающей точки в архитектуре i86).
Сразу с этого начинали бы - и не морочили людям голову.

Владимир Ситников
08.06.2016, 21:58
Блиннннннн....
PRU не имеет к "классическому" функционалу КДС никакого отношения! Рассматривайте его, как сопроцессор ввода-вывода (некая аналогия - сопроцессор плавающей точки в архитектуре i86).
Сразу с этого начинали бы - и не морочили людям голову.

Да понимаю я, что PRU это сопроцессор. И прекрасно понимаю, что там отдельный компилятор и заливатор кода (я его запускал, но до железа дело не дошло).
Но к функционалу КДС это PRU имеет отношение самое простое: с помощью библиотеки PruAccessLib.lib идёт общение между "основным циклом и PRU".

И, да, вопрос не только про PRU.