Виртуальная машина для ардуино?

Тема в разделе "Флудилка", создана пользователем valeraba, 27 авг 2018.

  1. Airbus

    Airbus Оракул

    А можно глупый вопрос?Практическое применение в конечном устройстве?
     
  2. valeraba

    valeraba Нерд

    Совсем даже не глупый. Побудило меня к созданию ПЛК то, что потребовалось организовать взаимодействие между устройствами по сети.
    Это обстоятельство, потянуло за собой другую смежную задачу, нужно было каким-то образом предобрабатывать полученные значения от других устройств, и только потом давать команду на исполнительные механизмы самого устройства.
    Менять логику устройства каждый раз перешивая бинарник довольно муторное занятие. Напротив, ПЛК по TCP-IP получает новый скрипт буквально за одну секунду, и прямо на горячую (без перезагрузки), принимает его к исполнению.
    Как плюшка, зацикленный или битый скрипт будет просто проигнорирован ПЛК, поэтому можно тут же исправить ошибку и перезалить скрипт.
     
  3. parovoZZ

    parovoZZ Гуру

    мне кажется, что в современном мировосприятии это одно и то же)))
     
  4. valeraba

    valeraba Нерд

    Вещь одна, но технология изготовления разная. Форд неспроста придумал свой конвейер.
     
  5. valeraba

    valeraba Нерд

    Замерил скорость исполнения байт-кода такого вот простейшего сценария мигалки. На выходе получил 43кГц меандр (платформа ESP8266 80МГц).
    [​IMG]
    Не идеальная производительность, но всё же раз в десять лучше чем у Lua и Espruino. Для моих задач вполне хватает.
    http://esp8266freq.blogspot.com/2016/12/esp-speed-compare-in-lua-micropython.html
    https://www.espruino.com/Performance

    Как это выглядит в работе, здесь: http://mgt24.ru/en/home.html#5ba362d917f9911528d00810/1
     
  6. DIYMan

    DIYMan Гуру

    Как печально-то, на самом деле. Либо байт-код - гуано, либо интерпретатор байт-кода - такое же. Имхо.
     
  7. valeraba

    valeraba Нерд

    Всё познаётся в сравнении, найдите лучше ;)
     
  8. DIYMan

    DIYMan Гуру

    Да незачем. Просто мысль вслух высказал, что реально - печально такое.
     
  9. DIYMan

    DIYMan Гуру

    Чой-то решил проверить на Uno, пока тупо сделал так, чтобы понять, от чего отталкиваться:

    Код (C++):
    //--------------------------------------------------------------------------------------------------------------------------------
    void setup()
    {
      Serial.begin(57600);

      pinMode(13,OUTPUT);

      uint16_t passes = 1000;
      uint32_t start = millis();

      for(uint16_t i=0;i<passes;i++)
      {
        digitalWrite(13,HIGH);
        digitalWrite(13,LOW);
      }

      uint32_t end = millis();
      uint32_t elapsed = end - start;

      Serial.print(F("Count passes: "));
      Serial.println(passes);
      Serial.print(F("Elapsed time, ms: "));
      Serial.println(elapsed);
      float hz = (1.0/elapsed)*1000*passes;
      Serial.print(F("Frequency: "));
      Serial.println(hz);


    }
    //--------------------------------------------------------------------------------------------------------------------------------
    void loop()
    {
      // put your main code here, to run repeatedly:

    }
    //--------------------------------------------------------------------------------------------------------------------------------
     
    Выхлоп в мониторе порта:
    Теперь попробую набросать простенький интерпретатор одного блока байт-кода - и глянем, смогу ли из 166кГц получить 43кГц ;)
     
    Mitrandir нравится это.
  10. Mitrandir

    Mitrandir Гуру

    ого какая Uno шустрая

    на Mega2560

    Count passes: 1000
    Elapsed time, ms: 11
    Frequency: 90909.10
     
  11. DIYMan

    DIYMan Гуру

    Погоди, я тут навскидку писал, расчёт частоты надо проверить - вдруг прокосячил. Да не вдруг, а точно - прокосячил, не то считал ;) Короче, щас всё выясним ;) Там же надо частоту меандра посчитать, а не то, что я считал ;)

    Или - таки правильно считал?
    Код (C++):
    float hz = (1.0/elapsed)*1000*passes; // сколько раз за секунду выполнится тело цикла
    Например, у нас 1000 проходов заняло 5 мс. Значит:

    (1.0/5)*1000*1000 = с частотой 200 кГц вызываются две строки
    Код (C++):
        digitalWrite(13,HIGH);
        digitalWrite(13,LOW);
    Так будет понятнее, короче. В любом случае - нам интересны накладные расходы на байткод. Проверяю.
     
    Последнее редактирование: 27 сен 2018
  12. Mitrandir

    Mitrandir Гуру

    так у тебя 6 секунд, у меня 11 в два раза медленнее
     
  13. Mitrandir

    Mitrandir Гуру

    какой?)
     
  14. DIYMan

    DIYMan Гуру

    Щас всё будет, погоди ;)
     
  15. Igor68

    Igor68 Гуру

    Простите, но вот мои 5 копеек:
    Исходя из того, что у локального цикла исполнения (как в Step7):
    1) цикл чтения входов и флагов/параметров в памяти;
    2) цикл исполнения(логика);
    3) цикл записи выходов и флагов/параметров в память.
    1 и 3 для глобальных переменных, а для логики(блока) есть и локальные.
    Примечание: флаги/параметры могут обрабатываться и в цикле 2 без 1 и 2... но не в этом дело.
    Нужен "механизм" подмены новых логических блоков (коррекция на горячую), который подменяет старые только после завершения всех 3-х циклов. А это некое подобие ОС. Можете ли Вы это реализовать на AVR(Arduino). Без этого как правило идея не работает. Как пример OMRON, OWEN и др. Все они сначала тормозят работу программы, потом заливают, и затем запускают... и при этом без инициализации параметров, и то не все/всегда. И ещё среды разработки производят всё-таки компиляцию(какую-то) перед заливкой. Поверьте механизм подмены не так прост.
    Извините!
     
  16. DIYMan

    DIYMan Гуру

    Итак:
    Код (C++):
    //--------------------------------------------------------------------------------------------------------------------------------
    typedef enum
    {
      incrementForBlock,
      endForBlock,
      pinWriteBlock

    } BlockType;
    //--------------------------------------------------------------------------------------------------------------------------------
    uint8_t block[] = {
        incrementForBlock, // это цикл for c инкрементом
        0x03, 0xE8, // 1000 проходов
        1, // шаг инкремента

        // тут тело цикла

          pinWriteBlock, // пишем в пин
          13, // номер пина
          HIGH, // уровень

          pinWriteBlock, // пишем в пин
          13, // номер пина
          LOW, // уровень
     
        // конец тела цикла

        endForBlock // цикл for закончился
    };
    //--------------------------------------------------------------------------------------------------------------------------------
    void executePinWriteBlock(uint8_t* bytecode)
    {
      bytecode++; // пропустили идентификатор блока (pinWriteBlock)

      //Serial.println(*bytecode);
      //Serial.println(*(bytecode+1));
      digitalWrite(*bytecode, *(bytecode+1));
    }
    //--------------------------------------------------------------------------------------------------------------------------------
    void executeIncrementForBlock(uint8_t* bytecode)
    {
      bytecode++; // пропустили идентификатор блока (incrementForBlock)

      uint16_t passes = (*bytecode++ << 8) | (*bytecode++);
      uint8_t increment = *bytecode++;

      Serial.print(F("Passes: ")); Serial.println(passes);
      Serial.print(F("Increment: ")); Serial.println(increment);

      uint32_t start = millis();

      uint8_t* startCode = bytecode;
      bool canExitWhile = false;

      for(uint16_t i=0;i<passes;i+=increment)
      {
        canExitWhile = false;

        while(!canExitWhile) // шаримся по блокам тела цикла
        {
          switch(*startCode)
          {
            case pinWriteBlock:
              executePinWriteBlock(startCode);
              startCode += 3; // пропустили блок
            break;

           case endForBlock:
            //Serial.println("BEGIN");
            startCode = bytecode;
            canExitWhile = true;
           break;

           default:
            //Serial.println("!!!!!");
           break;
          } // switch
     
        } // while

      } // for

      uint32_t end = millis();
      uint32_t elapsed = end - start;

      Serial.print(F("Count passes: "));
      Serial.println(passes);
      Serial.print(F("Elapsed time, ms: "));
      Serial.println(elapsed);
      float hz = (1.0/elapsed)*1000*passes;
      Serial.print(F("Frequency: "));
      Serial.println(hz);

    }
    //--------------------------------------------------------------------------------------------------------------------------------
    void setup()
    {
      Serial.begin(57600);

      pinMode(13,OUTPUT);

      uint16_t passes = 1000;
      uint32_t start = millis();

      for(uint16_t i=0;i<passes;i++)
      {
        digitalWrite(13,HIGH);
        digitalWrite(13,LOW);
      }

      uint32_t end = millis();
      uint32_t elapsed = end - start;

      Serial.print(F("Count passes: "));
      Serial.println(passes);
      Serial.print(F("Elapsed time, ms: "));
      Serial.println(elapsed);
      float hz = (1.0/elapsed)*1000*passes; // сколько раз за секунду выполнится тело цикла
      Serial.print(F("Frequency: "));
      Serial.println(hz);

      Serial.println();
      Serial.println("BYTE CODE TEST: ");
      Serial.println();

      executeIncrementForBlock(block);

    }
    //--------------------------------------------------------------------------------------------------------------------------------
    void loop()
    {
      // put your main code here, to run repeatedly:

    }
    //--------------------------------------------------------------------------------------------------------------------------------
     
    Выхлоп:
    Без байт-кода: ~140кГц (округляем). С байт-кодом: 100кГц. Накладные расходы, очевидно, е, и немалые, но! Во-первых, даже при таком колхозном подходе частота вызова двух строчек
    Код (C++):
        digitalWrite(13,HIGH);
        digitalWrite(13,LOW);
    через байт-код - составляет порядка 100 кГц. Во-вторых: никакой, нет, НИКАКОЙ оптимизации не проводилось, а там - есть где разгуляться, если делать всё строго по теории. Да даже отказаться от вызова функции executePinWriteBlock, заинлайнив её - уже будет быстрее, вангую ;)

    Ессно, данное поделие не претендует на полноценный интерпретатор байт-кода, просто разместил объяву о том, что частота вызова двух строчек в 43кГц (ну пусть 43*2, меандр же) под камнем в 80МГц - это как-то совсем не алё, пмсм. Ну хотя бы пять сотен килогерц, не?

    В моём примере получается соотношение к тактовой 1/160, если подставить это к 80 МГц, то получим 500 кГц, навскидку.

    Где я неправ? Может, чего ступил и неправильно где посчитал (сегодня день заполошный, бошка уже не варит)? И да, строго говоря, отталкиваться от тактовой ядра - не совсем верно, вот тут могу как раз и наколоться, ибо разные блоки МК могут тактироваться по разному.

    Короче, дискуссии - быть, щитаю. Присоединяйтесь ;)

    З.З.Ы. Ещё раз: тестировал на Uno, ибо под рукой что попалось - туда и впихнул. Могу NodeMCU достать, в принципе - и глянуть, чего там будет. Но - там ещё стек Wi-Fi чухается, возможно, именно этим обусловлены столь печальные результаты, приведённые выше, в сообщении #45. Так что, вполне вероятно, что был неправ, и виной не интерпретатор байт-кода - а стек Wi-Fi в ESP, которому надо овердохрена процессорного времени для нормальной работы.

    Кто закачает в NodeMCU и попробует? Мне лень чой-то :)
     
    Последнее редактирование: 27 сен 2018
  17. Mitrandir

    Mitrandir Гуру

    ну у тебя довольно таки узкоспециализированный байт-код. Он ясное дело будет быстрее джавы или луа с питоном
     
  18. DIYMan

    DIYMan Гуру

    Да, ещё раз подчеркну, чтобы не получилось так, что сравнимаем сферических коней в вакууме и тёплое с круглым: речь идёт о том, что сказано с сообщении #45, т.е. простейший пример простейшего байткода, который интерпретатор просто обязан развернуть и выплюнуть, как здрасьте. И да - речь не идёт о Lua и JS - это другая лига.
     
    Mitrandir нравится это.
  19. DIYMan

    DIYMan Гуру

    Вот только вот выше - дополнил, во избежание разночтений ;) Речь не о Lua, питоне или JS - как я понял, в сообщении #45 приведён пример простого байткода под некий интерпретатор, отличный от Lua, питона или JS, не? Речь именно об этом. Если там таки другая лига - сорри, был неправ, ибо в таком случае все проведённые мной сравнения - некорректны.
     
  20. Mitrandir

    Mitrandir Гуру

    Мега 2560

    Count passes: 1000
    Elapsed time, ms: 11
    Frequency: 90909.10

    BYTE CODE TEST:

    Passes: 1000
    Increment: 1
    Count passes: 1000
    Elapsed time, ms: 15
    Frequency: 66666.67