Особенности языка mql5, тонкости и приёмы работы - страница 84

 
Alain Verleyen:

Can you provide the benchmark code to demonstrate that ?

#define BENCH(A)                                                              \
{                                                                             \
  const ulong StartTime = GetMicrosecondCount();                              \
  A;                                                                          \
  Print("Time[" + #A + "] = " + (string)(GetMicrosecondCount() - StartTime)); \
}

double Bench1( const int Size, const string Str )
{
  double Tmp = 0;
  
  for (int i = 0; i < Size; i++)
    Tmp += (double)Str;

  return(Tmp);
}

double Bench2( const int Size, const string Str )
{
  double Tmp = 0;;
  
  for (int i = 0; i < Size; i++)
    Tmp += StringToDouble(Str);

  return(Tmp);
}

double Bench3( const int Size, const string Str )
{
  double Tmp = 0;
  
  for (int i = 0; i < Size; i++)
    Tmp += StringToDouble2(Str); // https://www.mql5.com/ru/forum/170952/page83#comment_7121066

  return(Tmp);
}

void OnStart()
{  
  const string Str = "123.456";
  
  BENCH(Print(Bench1(1e7, Str)));
  BENCH(Print(Bench2(1e7, Str)));
  BENCH(Print(Bench3(1e7, Str)));
}


Result (Release)

1234559999.924436
Time[Print(Bench1(1e7,Str))] = 1656182
1234559999.924436
Time[Print(Bench2(1e7,Str))] = 1639179
1234559999.924436
Time[Print(Bench3(1e7,Str))] = 147382


ЗЫ А вот такое получается, если запустить в режиме профилирования

1234559999.924436
Time[Print(Bench1(1e7,Str))] = 1757705
1234559999.924436
Time[Print(Bench2(1e7,Str))] = 1877177
1234559999.924436
Time[Print(Bench3(1e7,Str))] = 4578266

К сожалению, профайлеру верить нельзя в данном случае.

 
fxsaber :


Result ( Release )


ЗЫ А вот такое получается, если запустить в режиме профилирования

Мало того, про профайлеру верить нельзя в данном случае, так еще Bench1 выполняется в 10 раз быстрее, чем в Release-варианте!

Благодарю.

Результат ( выпуск )

Time [Bench1( 1 e7,Str)] = 1680754
Time [Bench2( 1 e7,Str)] = 1646789
Time [Bench3( 1 e7,Str)] = 143408     more then 10 times faster !!! 

Протестировано с помощью советника по стратегии.

2018.04.16 14:24:28.049    Core 1    OnTester result 39725470 (µs bench1)
2018.04.16 14:26:14.629    Core 1    OnTester result 39270950 (µs bench2)
2018.04.16 14:27:13.566    Core 1    OnTester result 20467067 (µs bench3)

Еще в 2 раза быстрее (но не более 10 раз, что, безусловно, связано с оптимизацией компилятора).

Файлы:
170952.mq5  6 kb
 
Alain Verleyen:

Протестировано с помощью советника по стратегии.

2018.04.16 14:24:28.049    Core 1    OnTester result 39725470 (µs bench1)
2018.04.16 14:26:14.629    Core 1    OnTester result 39270950 (µs bench2)
2018.04.16 14:27:13.566    Core 1    OnTester result 20467067 (µs bench3)

Еще в 2 раза быстрее (но не более 10 раз, что, безусловно, связано с оптимизацией компилятора).

Вы замеряете время еще на генерацию тиков, а не только вычисление OnTick.

Вот замер только OnTick

#define PROFILER_OnTick // Замеряет чистое время выполнения всех OnTick - немного замедляет общую работу
#include <TesterBenchmark.mqh> // https://www.mql5.com/ru/code/18804

input int bench=1;// between 1 and 3

void OnTick()
{
  static const string Str = "123.456";

  switch(bench)
  {
    // https://www.mql5.com/ru/forum/170952/page84#comment_7121207
    case 1 : Bench1(1, Str); break;
    case 2 : Bench2(1, Str); break;
    case 3 : Bench3(1, Str); break;
  }  
}


Bench1

i = 0 Pass = 0 OnTester = 3.729 s.: OnTick Profiler: Count = 7197033, Interval = 1.895 s., 3796990.9 unit/sec , Agent = C:\Program Files\Alpari Limited MT5\Tester\Agent-127.0.0.1-3000 build = 1795
i = 1 Pass = 1 OnTester = 3.843 s.: OnTick Profiler: Count = 7197033, Interval = 1.950 s., 3690523.1 unit/sec , Agent = C:\Program Files\Alpari Limited MT5\Tester\Agent-127.0.0.1-3000 build = 1795


Bench3

i = 0 Pass = 0 OnTester = 2.280 s.: OnTick Profiler: Count = 7197033, Interval = 0.631 s., 11404799.6 unit/sec , Agent = C:\Program Files\Alpari Limited MT5\Tester\Agent-127.0.0.1-3000 build = 1795
i = 1 Pass = 1 OnTester = 2.340 s.: OnTick Profiler: Count = 7197033, Interval = 0.640 s., 11242184.6 unit/sec , Agent = C:\Program Files\Alpari Limited MT5\Tester\Agent-127.0.0.1-3000 build = 1795


В три раза. В 10 раз ускорения не получается, поскольку множественный вызов BenchX-функции. Сама StringToDouble2, действительно, в 10 раз быстрее.

 
fxsaber :

Вы замеряете время еще на генерацию тиков, а не только вычисление OnTick.

...

Ты прав.

Я действительно удивлен, что он в 10 раз быстрее, однако ваша функция может использоваться только тогда, когда вы знаете, что строка содержит действительное двойное значение.

2018.04.16 17: 14: 16.183 170952_180416 (EURUSD, H1) StringToDouble2 (abcdef) = 5456784.0

 
Aleksey Vyazmikin:

Спасибо, но этот скрипт сохраняет так же не верно.

На мониторе у меня ограничение с правой стороны отмечено вертикальной линией, а скрин ушел далеко за эту линию.

Процитирую ответ из сервисдеска:

В данном случае справку по ChartScreenShot нужно понимать буквально

align_mode=ALIGN_RIGHT

[in]  Режим вывода узкого скриншота. Значение перечисления ENUM_ALIGN_MODE. ALIGN_RIGHT означает выравнивание по правой границе (вывод с конца). ALIGN_LEFT задает выравнивание по левой границе.

Это означает, что при указании выравнивания ALIGN_RIGHT график будет принудительно проскроллен к правой границе, что равносильно выполнению команды

ChartNavigate(0,CHART_END,0);

Такое поведение было заложено много лет назад (так исторически сложилось), когда еще не было функции ChartNavigate(). Установка align_mode=ALIGN_RIGHT гарантировала, что будет снят именно правый край графика.

И когда добавили функцию ChartNavigate() поведение функции ChartScreenShot менять не стали.

Поэтому, если хотите получить желаемый эффект (не проматывать график к правому краю)  - используйте для параметра align_mode значение ALIGN_LEFT.

 
Alain Verleyen:

ваша функция может использоваться только тогда, когда вы знаете, что строка содержит действительное двойное значение.

2018.04.16 17: 14: 16.183 170952_180416 (EURUSD, H1) StringToDouble2 (abcdef) = 5456784.0

Исправил, теперь работает, как и оригинал

#define PRINT(A) Print(#A + " = " + (string)(A))

void OnStart()
{    
  const string Str[] = {"123.456", "-asdf1234", "12as", ".34 a", "..23", "1.."};

  for (int i = 0; i < ArraySize(Str); i++)
  {
    PRINT(Str[i]);
    
    PRINT((double)Str[i]);
    PRINT(StringToDouble2(Str[i])); // https://www.mql5.com/ru/forum/170952/page83#comment_7121066
    
    Print("");
  }
}
 

Если убрать выделенный const, то время выполнения функции увеличится в два раза. Это говорит о том, что компилятор не всегда создает оптимальный код, и ему требуются такого рода подсказки.

 
fxsaber :

Если убрать выделенный const, то время выполнения функции увеличится в два раза. Это говорит о том, что компилятор не всегда создает оптимальный код, и ему требуются такого рода подсказки.

Интересно, спасибо.

Пожалуйста, не редактируйте свой код, как только вы уже получите ответ, я не получил уведомление, которое вы его обновили.

 
fxsaber:

Если убрать выделенный const, то время выполнения функции увеличится в два раза. Это говорит о том, что компилятор не всегда создает оптимальный код, и ему требуются такого рода подсказки.

Очень интересно...
А есть мысли, почему так происходит?

Каков механизм?

 

Для определения ширины скриншота, снимаемого с экрана с помощью MQL5, который включал бы полностью бары за определенный период, предлагается решение, представленное ниже.

Особенностью оказалось то обстоятельство, что при разном приближении чарта необходимо делать коррекцию ширины скриншота.

Фактические "коэффициенты" получились разными (конкретно у меня) для варианта со шкалой и без.

 if (Use_Shakala==false)
 
 {
   ChartSetInteger(0,CHART_SHOW_PRICE_SCALE ,0);//Показывать или нет ценовую шкалу
   int TotalPixel=(int)ChartGetInteger(0,CHART_WIDTH_IN_PIXELS);   // Ширина графика в пикселях
   int WidthBar=int(1<<ChartGetInteger(0,CHART_SCALE));            // сколько пикселей между барами
   int FirstBar=(int)ChartGetInteger(0,CHART_FIRST_VISIBLE_BAR);   // номер первого (левого) бара на экране
   int VisibleBars=(int)ChartGetInteger(0,CHART_VISIBLE_BARS);     // количество видимых баров на экране
   int BarNr= FirstBar-(Shift_Start-Shift_Stop)*(-1);              // номер искомого бара, допустим на 12 баров правее самого левого бара 
   int LeftPixelOfBar=((FirstBar-BarNr)>=VisibleBars || FirstBar<BarNr)?(-1):((FirstBar-BarNr)*WidthBar);  // левый пиксель искомого бара, если бара нет на экране тогда -1
   int RightPixelOfBar =(LeftPixelOfBar<0)?(-1):LeftPixelOfBar+WidthBar-1;                                 //правый пиксель искомого бара, если бара нет на экране тогда -1
   if (RightPixelOfBar>=TotalPixel) RightPixelOfBar=TotalPixel-1;  // проверяем не за пределами ли экрана 

      if (Zoom==0)ZoomX=6;
      if (Zoom==1)ZoomX=5;
      if (Zoom==2)ZoomX=5;
      if (Zoom==3)ZoomX=4;
      if (Zoom==4)ZoomX=2;
      if (Zoom==5)ZoomX=0;

  pp=WidthBar*((Shift_Start-Shift_Stop)*(-1)+2)+ZoomX;
}

  if (Use_Shakala==true)
  {
   ChartSetInteger(0,CHART_SHOW_PRICE_SCALE ,1);//Показывать или нет ценовую шкалу
   int TotalPixel=(int)ChartGetInteger(0,CHART_WIDTH_IN_PIXELS);   // Ширина графика в пикселях
   int WidthBar=int(1<<ChartGetInteger(0,CHART_SCALE));            // сколько пикселей между барами
   int FirstBar=(int)ChartGetInteger(0,CHART_FIRST_VISIBLE_BAR);   // номер первого (левого) бара на экране
   int VisibleBars=(int)ChartGetInteger(0,CHART_WIDTH_IN_BARS);     // количество видимых баров на экране
   int BarNr= FirstBar-(Shift_Start-Shift_Stop)*(-1);              // номер искомого бара, допустим на 12 баров правее самого левого бара 
   int LeftPixelOfBar=((FirstBar-BarNr)>=VisibleBars || FirstBar<BarNr)?(-1):((FirstBar-BarNr)*WidthBar);  // левый пиксель искомого бара, если бара нет на экране тогда -1
   int RightPixelOfBar =(LeftPixelOfBar<0)?(-1):LeftPixelOfBar+WidthBar-1;                                 //правый пиксель искомого бара, если бара нет на экране тогда -1
   if (RightPixelOfBar>=TotalPixel) RightPixelOfBar=TotalPixel-1;  // проверяем не за пределами ли экрана 

      if (Zoom==0)ZoomX=1;
      if (Zoom==1)ZoomX=1;
      if (Zoom==2)ZoomX=1;
      if (Zoom==3)ZoomX=3;
      if (Zoom==4)ZoomX=2;
      if (Zoom==5)ZoomX=0;    
  pp=WidthBar*((Shift_Start-Shift_Stop)*(-1)+2-0.5)+ZoomX+Schkala;
  
  }
//pp 		 - ширина скриншота
//Shift_Start    - номер левого бара, который целиком должен попасть на скрин
//Shift_Stop     - номер правого бара, который целиком должен попасть на скрин
//Schkala        - ширина цифровой шкалы по методу fxsaber
//Zoom           - степень приближение экрана
Причина обращения: