Caratteristiche del linguaggio mql5, sottigliezze e tecniche - pagina 84

 
Alain Verleyen:

Puoi fornire il codice di riferimento per dimostrarlo?

#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(1 e7, Str)));
  BENCH(Print(Bench2(1 e7, Str)));
  BENCH(Print(Bench3(1 e7, Str)));
}


Risultato(rilascio)

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


E questo è ciò che si ottiene quando lo si esegue in modalità di profiling

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

Sfortunatamente, non ci si può fidare del profiler in questo caso.

 
fxsaber:


Risultato ( rilascio )


HH E questo è ciò che ottengo, se lo eseguo in modalità di profiling

Non solo è impossibile credere al profiler in questo caso, ma Bench1 gira 10 volte più velocemente che nella versione Release!

Grazie per questo.

Risultato ( rilascio )

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

Testato con Expert Advisor per strategia.

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)

Un altro 2 volte più veloce (ma non più di 10 volte più veloce, il che è certamente dovuto all'ottimizzazione del compilatore).

File:
170952.mq5  6 kb
 
Alain Verleyen:

Testato con un consulente strategico.

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)

È ancora 2 volte più veloce (ma non più di 10 volte più veloce, il che è ovviamente dovuto all'ottimizzazione del compilatore).

Si misura il tempo ancora per generare tick, non solo il calcolo di OnTick.

Qui c'è solo la misura 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;
  }  
}


Panchina1

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


Panchina3

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


Di un fattore tre. Non si può ottenere 10 volte più veloce a causa delle chiamate multiple alla funzione BenchX. StringToDouble2 stesso è infatti 10 volte più veloce.

 
fxsaber:

Si misura il tempo ancora per generare i tick, non solo per calcolare OnTick.

...

Hai ragione.

Sono davvero sorpreso che sia 10 volte più veloce, ma la tua funzione può essere usata solo quando sai che la stringa contiene un valore doppio valido.

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

 
Aleksey Vyazmikin:

Grazie, ma questo script salva anche in modo errato.

Sul mio monitor, la limitazione sul lato destro è segnata da una linea verticale, e lo screenshot è ben oltre quella linea.

Citerò la risposta del servicedesk:

In questo caso, la guida ChartScreenShot dovrebbe essere presa alla lettera

align_mode=ALIGN_RIGHT

[Modalità di output di uno screenshot stretto. Il valore dell'enumerazione ENUM_ALIGN_MODE. ALIGN_RIGHT indica l'allineamento al bordo destro (uscita dalla fine). ALIGN_LEFT specifica l'allineamento a sinistra.

Significa che quando si specifica l'allineamento ALIGN_RIGHT il grafico verrà fatto scorrere forzatamente verso il bordo destro, il che equivale a eseguire il comando

ChartNavigate(0,CHART_END,0);

Questo comportamento è stato stabilito molti anni fa (quindi storicamente) quando non c'era ancora la funzione ChartNavigate(). Impostando align_mode=ALIGN_RIGHT si garantiva che esattamente il bordo destro del grafico sarebbe stato rimosso.

Quando è stata aggiunta la funzione ChartNavigate(), il comportamento della funzione ChartScreenShot non è stato cambiato.

Quindi, se vuoi ottenere l'effetto desiderato (il grafico non verrà fatto scorrere verso il bordo destro) - usa il valore ALIGN_LEFT per il parametro align_mode.

 
Alain Verleyen:

la vostra funzione può essere usata solo quando sapete che la stringa contiene un valore doppio valido.

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

Corretto, ora funziona come l'originale

#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("");
  }
}
 

Se si rimuove la const evidenziata, il tempo di esecuzione della funzione raddoppia. Questo dimostra che il compilatore non crea sempre un codice ottimale e ha bisogno di questo tipo di suggerimenti.

 
fxsaber:

Se rimuoviamo la cost marcata, il tempo di esecuzione della funzione raddoppierà. Indica che il compilatore non crea sempre un codice ottimale e ha bisogno di questo tipo di suggerimenti.

Interessante, grazie.

Per favore non modificare il tuo codice una volta che hai già ricevuto una risposta, non ho ricevuto la notifica che l'hai aggiornato.

 
fxsaber:

Se rimuoviamo la cost marcata, il tempo di esecuzione della funzione raddoppierà. Indica che il compilatore non crea sempre un codice ottimale e ha bisogno di questo tipo di suggerimenti.

Molto interessante...
Qualche idea sul perché questo accade?

Qual è il meccanismo?

 

Per determinare la larghezza di uno screenshot preso con MQL5 che includa tutte le barre per un certo periodo, viene offerta la soluzione seguente.

Una particolarità si è rivelata essere il fatto che la larghezza dello screenshot deve essere corretta a diverse approssimazioni del grafico.

I "coefficienti" effettivi si sono rivelati diversi (per me in particolare) per la variante con e senza la scala.

 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           - степень приближение экрана
Motivazione: