Раз уже в прошлой заметке зашла речь о проекте RWTH - Mindstorms NXT Toolbox for MATLAB, то следует рассказать об одном интересном исследовании проведенном в рамках этого проекта. |
На самом деле автор данных материалов делал исследование с целью измерить какие трюки, уловки он смог бы применять в своих программах на языке Not eXactly C, чтобы его роботы были более быстрыми, имели меньшее время реакции на события и т.п. Для этого он создал набор тестов. измеряющие производительность стандартного NXT firmware.
Эти тесты включали в себя следующие проверки:
- сколько выполняются математические операции умножение и сложение, как для данных типа
int
, так и дляlong
- преимущество битовых сдвигов (только для расширенной версии FW, поставляемой с NXC), тоже для отдельно для
int
иlong
- как быстро работает пустой цикл (ну т.е. в нем все равно будут операции инкремента и сравнения)
- сколько занимают вызовы стандартных функций
CurrentTick()
иMotorTachoCount()
- насколько быстр вычисление позиции элемента в одномерных массивах
- имеет ли смысл использовать inline ассемблерный код, вместо использования стандартной операции инкремента (++)
Итак, в ходе экспериментов выяснилось:
- нет никакого выигрыша в производительности между использованием типов данных
int
иlong
- в течении секунды выполняется примерно 5200 операций сложения или умножения. Причем, с точки зрения производительности одна операция умножения занимает практически столько же сколько операция сложения! Для людей знающих, как выполняются двоичные операции на процессоре, это будет довольно интересный и заслуживающий внимания факт. Автор делает предположение, что это может быть из-за внутреннего ограничения выполняемого NXT firmware, определяющего сколько процессорных "тиков" может использовать каждая задача.
- операции битовых сдвигов (
<<
>>
) медленнее больше, чем в два раза, других операций. Не используйте сдвигов - замените их арифметическими операциями:x*2^n
- для левых сдвигов,x/2^n
- для правых (естественно, 2^n лучше сразу рассчитать и значение вставить в код). - пустой цикл не выполняется быстрее
- вычисление позиции элемента в массиве соизмеримо по скорости с математическими операциями
- ассемблерная inline вставка для выполнения инкремента по производительности абсолютно равна операции ++
- подтвердилось ожидание того, что увеличение количества параллельных выполняющихся задач уменьшает производительность остальных. Т.е. если мы стартуем какую-то дополнительную задачу помимо main, то процессору нужно теперь тратить время на работу обеих задач, а значит производительность основной задачи упадет в два раза.
- функция
Wait()
не помогает значительно освобождать ресурсы процессора. Иными словами, если в дополнительной задаче сделать задержку в 100 миллисекунд, т.е. задача будет выполнятся всего 10 раз в секунду, то это не приведет к росту производительности основной задачи - она также будет в два раза медленнее. Похоже внутренняя реализация операцииWait()
по прежнему тратит время на вычисление, а не прошли ли это 100 мс. В то время как в "настоящих" операционных системах, ядро ОС ответственно за уведомление задачи, что "время сна" закончилось.
В общем, очень интересные получились результаты, позволяющие на некоторые вещи в программировании LEGO роботов взглянуть c новой стороны.
Также данный NXC-файл будет полезен тем, кто только изучает язык Not eXactly C, чтобы почерпнуть из него много новой информации, полезной в будущем.
А кто-нибудь сможет провести аналогичные эксперименты на Robolab, leJOS и RobotC? У них ведь свои собственные firmware - как ведут они себя с точки зрения производительности.
Думаю, у языков со своими firmware результаты буду совсем другие. Не случайно количество тиков в пустом цикле в RobotC точно больше 5200 (сам измерял).
ОтветитьУдалитьНа самом деле все еще интереснее. Я взял свой блок (NXT2.0 std FW 1.31), скомпилировал PerformanceChk2.nxc, результаты которого представлены в этой статье и получил, что скорость работы на самом деле больше, чем в два раза больше - 12000 матем. операций против 5200, заявленных в прошлом.
Удалить10000 циклов пустых на robotC требуют лишь 129 миллисекунд, если переменную заменить на тип лонг то уже 169 миллисекунд, а если переменную цикла заменить на флоат то уже 209)
ОтветитьУдалить