Как быстрее "делать ноги" с Iskra JS или тайная сила "compile";

Тема в разделе "Iskra JS, Espruino, Йодо", создана пользователем sys, 1 июн 2017.

  1. sys

    sys Злобный Буратино Модератор

    Часть1.
    Задача: найти способ самого быстрого переключения значений на пинах Iskra JS.

    Итак, проведем тесты пяти способов и засечем время за которое Iskra JS сможет включить и выключить 4 пина 1000 раз.

    Способ 1
    примитивный
    Код (Javascript):
    function test() {
      var cnt = 1000;
      var ft = Date.now();

      for (var i=0;i<cnt;i++) {
        digitalWrite(P6, 1);
        digitalWrite(P6, 0);
        digitalWrite(P8, 1);
        digitalWrite(P8, 0);
        digitalWrite(P10, 1);
        digitalWrite(P10, 0);
        digitalWrite(P12, 1);
        digitalWrite(P12, 0);
      }
      print(Date.now()-ft);
    }
    function start_test(){
      pinMode(P6, "output");
      pinMode(P8, "output");
      pinMode(P10, "output");
      pinMode(P12, "output");
      test();
    }
    start_test();

    Время выполнения: 773 мс

    ------------------------------------------

    Способ 2
    упаковка в массив
    http://www.espruino.com/Reference#l__global_digitalWrite
    Код (Javascript):
    function test() {
      var cnt = 1000;
      var ft = Date.now();

      for (var i=0;i<cnt;i++) {
        digitalWrite([P12,P12,P10,P10,P8,P8,P6,P6],0b01010101);
      }
      print(Date.now()-ft);
    }
    function start_test(){
      pinMode(P6, "output");
      pinMode(P8, "output");
      pinMode(P10, "output");
      pinMode(P12, "output");
      test();
    }
    start_test();

    Время выполнения: 437 мс
    Примечание: компиляция с использованием массива в digitalWrite на данный момент пока не поддерживается...
    ------------------------------------------

    Способ 3
    как и способ 1, но с предварительной компиляцией функции в нативный код с помощью строки "compiled";
    https://www.espruino.com/Compilation
    Код (Javascript):
    function test() {
      "compiled";
      var cnt = 1000;
      var ft = Date.now();

      for (var i=0;i<cnt;i++) {
        digitalWrite(P6, 1);
        digitalWrite(P6, 0);
        digitalWrite(P8, 1);
        digitalWrite(P8, 0);
        digitalWrite(P10, 1);
        digitalWrite(P10, 0);
        digitalWrite(P12, 1);
        digitalWrite(P12, 0);
      }
      print(Date.now()-ft);
    }
    function start_test(){
      pinMode(P6, "output");
      pinMode(P8, "output");
      pinMode(P10, "output");
      pinMode(P12, "output");
      test();
    }
    start_test();

    Время выполнения: 338 мс

    ------------------------------------------

    Способ 4
    запись в регистры с помощью функции poke32. Внимание, использовать осторожно!
    http://www.espruino.com/Reference#l__global_poke32
    Код (Javascript):
     function test() {
      var pP6 = 0|P6.getInfo().out_addr;
      var pP8 = 0|P8.getInfo().out_addr;
      var pP10 = 0|P10.getInfo().out_addr;
      var pP12 = 0|P12.getInfo().out_addr;
      var cnt = 1000;
      var ft = Date.now();

      for (var i=0;i<cnt;i++) {
        poke32(pP6, 1);
        poke32(pP6, 0);
        poke32(pP8, 1);
        poke32(pP8, 0);
        poke32(pP10, 1);
        poke32(pP10, 0);
        poke32(pP12, 1);
        poke32(pP12, 0);
      }
      print(Date.now()-ft);
    }

    function start_test(){
      pinMode(P6, "output");
      pinMode(P8, "output");
      pinMode(P10, "output");
      pinMode(P12, "output");
      test();
    }

    start_test();

    Время выполнения: 659 мс

    ------------------------------------------

    Способ 5
    как и способ 4, но с предварительной компиляцией функции в нативный код с помощью строки "compiled";
    https://www.espruino.com/Compilation
    Код (Javascript):
     function test() {
      "compiled";
      var pP6 = 0|P6.getInfo().out_addr;
      var pP8 = 0|P8.getInfo().out_addr;
      var pP10 = 0|P10.getInfo().out_addr;
      var pP12 = 0|P12.getInfo().out_addr;
      var cnt = 1000;
      var ft = Date.now();

      for (var i=0;i<cnt;i++) {
        poke32(pP6, 1);
        poke32(pP6, 0);
        poke32(pP8, 1);
        poke32(pP8, 0);
        poke32(pP10, 1);
        poke32(pP10, 0);
        poke32(pP12, 1);
        poke32(pP12, 0);
      }
      print(Date.now()-ft);
    }

    function start_test(){
      pinMode(P6, "output");
      pinMode(P8, "output");
      pinMode(P10, "output");
      pinMode(P12, "output");
      test();
    }

    start_test();

    Время выполнения: 0.62 мс = 620 мкс !!!

    ------------------------------------------

    Я думаю, победителя представлять не надо :)

    P.S. Работоспособность проверялась с помощью пьезопищалки ака зуммер на P12
    P.P.S. В данном опусе не учитываются некоторые способы оптимизации кода, о которых я напишу далее...
     
    Последнее редактирование: 4 июн 2017
    Konkery, arkadyf, Morgan и 3 другим нравится это.
  2. sys

    sys Злобный Буратино Модератор

    Часть 2.
    Хочу поделиться еще несколькими тонкостями по некоторой оптимизации кода, также позволяющей получить некоторый прирост скорости... И вообще советую прочитать заметки о производительности https://www.espruino.com/Performance , лично я подчерпнул от туда много полезного ;)
    ---------------------------------

    Итак, начнем пожалуй со способа 1 из предыдущего поста. Его можно было ускорить, если не использовать в цикле длинные имена digitalWrite, а переопределить их с самого начала на что-нибудь короткое (всего из того же performance):
    Код (Javascript):
    unction test() {
       var cnt = 1000;
       var ft = Date.now();
       var d=digitalWrite;

       for (var i=0;i<cnt;i++) {
        d(P6, 1);
        d(P6, 0);
        d(P8, 1);
        d(P8, 0);
        d(P10, 1);
        d(P10, 0);
        d(P12, 1);
        d(P12, 0);
      }
      print(Date.now()-ft);
    }

    function start_test(){
      pinMode(P6, "output");
      pinMode(P8, "output");
      pinMode(P10, "output");
      pinMode(P12, "output");
      test();
    }

    start_test();
     
    Время исполнения: 652 мс (на 121 мс быстрее оригинала)
    Этот же способ с компиляцей ( "compiled"; ): 208 мс (быстрее способа 3 на 130 мс)

    ---------------------------------

    Есть еще способ ускориться используя привязку https://www.espruino.com/Reference#l_Function_bind
    Код (Javascript):
    function test() {
      var cnt = 1000;
      var ft = Date.now();
      var p1 = P6.write.bind(P6);
      var p2 = P8.write.bind(P8);
      var p3 = P10.write.bind(P10);
      var p4 = P12.write.bind(P12);
      for (var i=0;i<cnt;i++) {
        p1(1);
        p1(0);
        p2(1);
        p2(0);
        p3(1);
        p3(0);
        p4(1);
        p4(0);
      }
      print(Date.now()-ft);
    }

    function start_test(){
      pinMode(P6, "output");
      pinMode(P8, "output");
      pinMode(P10, "output");
      pinMode(P12, "output");
      test();
    }

    start_test();

    Время выполнения: 476 мс
    То же самое с компиляцей ( "compiled"; ): 126 мс (прирост в 350 мс)

    ---------------------------------

    Так же дает небольшой прирост в 20-30 мс явное определение режима работы пина pinMode() https://www.espruino.com/Reference#l__global_pinMode (используется в тестах), чтобы не заставлять работать автоматику. Проверить можно следующим кодом
    Код (Javascript):
    function test() {
      "compiled";
      var cnt = 1000;
      var ft = Date.now();
      var p1 = P6.write.bind(P6);
      var p2 = P8.write.bind(P8);
      var p3 = P10.write.bind(P10);
      var p4 = P12.write.bind(P12);

      for (var i=0;i<cnt;i++) {
        p1(1);
        p1(0);
        p2(1);
        p2(0);
        p3(1);
        p3(0);
        p4(1);
        p4(0);
      }
      print(Date.now()-ft);
    }

    function start_test(){
      pinMode(P6, "output");
      pinMode(P8, "output");
      pinMode(P10, "output");
      pinMode(P12, "output");
      test();
    }

    test();
    setTimeout('start_test()',1000);
     
    Последнее редактирование: 4 июн 2017
    caracal, acos, arkadyf и ещё 1-му нравится это.
  3. sys

    sys Злобный Буратино Модератор

    updated :)
     
  4. ИгорьК

    ИгорьК Гуру

    Хорошая работа.
     
  5. caracal

    caracal Нерд

    Супер! Спасибо)