Странное поведение millis()

hedin
Offline
Зарегистрирован: 10.08.2015

Добрый день!

Хотел посчитать разницу выполнения по времени двух вариантов вычислений.  Т.е. берем перед вычислениями (в цикле многократно, чтобы время "ощутить")    , вызываем millis(), затем цикл с функцией и далее опять вызываем millis () -  смотрим разницу времен = бинго :) 

Однако на вывод разница времен попадала почему-то нулевая. После мЫшления над разными возм. причинами взял совсем простую уж прогу (занимается подсчетом времени выполнения цикла и выводом результатов по Serial

#define MAXSTEP 100000L
void setup() {
  // put your setup code here, to run once:
 
    Serial.begin( 9600 ) ;
    while (!Serial) {
        ; // wait for serial port to connect. Needed for native USB port only
     }
 }

void loop() {

  unsigned char incomingByte = 0 ;
  long i; double x;
  unsigned long millis_begin , millis_end ;

    millis_begin = millis() ;
    for ( i=0 ; i < MAXSTEP ; i ++ ) {
       x = sin ( (float)(  x + 1.) ) ;
    }
    millis_end = millis() ;
    Serial.println ( i ) ;
   // Serial.println ( x) ;      ----------- ВОТ ЭТО ВАЖНО! не включена строка эта
    Serial.println( millis_begin ) ;
    Serial.println( millis_end ) ;
     
       // read the incoming byte:
    while( incomingByte = Serial.read () != 'y' ) {
       ;  // Это просто чтоб ждало ввода "y" для следующего оборота loop() а не фигачило изо всех сил
    }
    delay(1000);
 }

На печать выводится при запуске этого варианта:

100000
0
0

Т.е. время както не затрачено на выполнение цикла :)

Включаем в проге строчку с печатью "x" (и больше ниче не трогаем! )

#define MAXSTEP 100000L
void setup() {
  // put your setup code here, to run once:
 
    Serial.begin( 9600 ) ;
    while (!Serial) {
        ; // wait for serial port to connect. Needed for native USB port only
     }
 }

void loop() {

  unsigned char incomingByte = 0 ;
  long i; double x;
  unsigned long millis_begin , millis_end ;

    millis_begin = millis() ;
    for ( i=0 ; i < MAXSTEP ; i ++ ) {
       x = sin ( (float)(  x + 1.) ) ;
    }
    millis_end = millis() ;
    Serial.println ( i ) ;
    Serial.println ( x) ;      ----------- ВОТ ЭТО ВАЖНО! теперь включили вывод для "x"
    Serial.println( millis_begin ) ;
    Serial.println( millis_end ) ;
     
       // read the incoming byte:
    while( incomingByte = Serial.read () != 'y' ) {
       ;  // Это просто чтоб ждало ввода "y" для следующего оборота loop() а не фигачило изо всех сил
    }
    delay(1000);
 }

На выводе при запуске имеем:

100000
0.93
0
11764
То есть бац -  и тут же millis() выдал для времени выполнения какое-то осмысленное уже число....

Что на самом деле происходит, почему какаято левая совершенно (не имеющая отношения к millis вообще строка все так меняет???

MagicianT
Offline
Зарегистрирован: 03.10.2015

Poprobyi:

 unsigned char incomingByte = 0 ;
  long i; 
 volatile double x;
  unsigned long millis_begin , millis_end ;

    millis_begin = millis() ;
    for ( i=0 ; i < MAXSTEP ; i ++ ) {
       x = sin ( (float)(  x + 1.) ) ;
    }

 

hedin
Offline
Зарегистрирован: 10.08.2015

ОК, сработало (с вариантом без печатания "x" ) !  Спасибо.

Правда, глубинный смысл произошедшего остался неясен - ведь millis() как бы не связан с x-ом.... И остальные переменные  вроде объявляюются как неволатильные - и ниче плохого от этого не происходит..
Вариант, что без объявления "volatile"  цикл пролетается слишком быстро (как бы не вычисляя ниче) вроде не проходит - я там задавал MAXSTEP до миллиона - а разница времен оставалась одинаково никакой, что миллион, что тысяча степов.  И "i" ведь тоже печатался правильный - то есть по идее цикл хотя бы на уровне  i++ что-то делал - время на миллионе шагов какое-никакое бы должно уйти.

MagicianT
Offline
Зарегистрирован: 03.10.2015

hedin пишет:

 то есть по идее цикл хотя бы на уровне  i++ что-то делал - время на миллионе шагов какое-никакое бы должно уйти.

Неверное предположение, gcc++  компилер делает оптимизацию кода, и если нету "волатиле" и переменная нигде не используется - все идет "в топку" , т. е. выбрасывается.  Просто знайте , что программа редко работает как написано на C++, существует несколько уровнеи оптимизации, и компилированный до ассемблера код может сильно отличаться.
 

 

hedin
Offline
Зарегистрирован: 10.08.2015

Спасибо, познавательно вышло.   В первоначальной программке сравнения вычислений тоже переменная, которой присваивалось значение функции, не использовалось - после объявления волатильной сразу время выполнения образовалось, вполне пропорциональное количеству шагов цикла.  Кстати, не думал , что такая мелкофигня, как Атмега 328 так быстро на самом деле считает простую, правда, арифметику.. На 286 по воспоминаниям , как бы не медлееннее считалось.

Arhat109-2
Offline
Зарегистрирован: 24.09.2015

Извините, а с чего она должна "медленее" считать? Теже 16 мегагерц, та же регистровая арифметика .. ваще-то.

А имея значительно больше регистров код вычислений может быть куда как производительней. Но, чтобы получить "весь кайф", надо помнить что микропроцессор .. байтовый. В лучшем случае, 16-и разрядный. А соответственно, убирать по максиуму long, unsigned long, особенно из параметров функций (uint16 против uint32 экономит по 6 байт на параметр при каждом вызове). Из-за чего и сделал себе 8 и 16 разрядные delay(), millis() и micros() .. чего и вам настоятельно рекомендую. Для больших интервалов .. считайте секундами, минутами и часами .. :)