Caractéristiques du langage mql5, subtilités et techniques - page 84

 
Alain Verleyen:

Pouvez-vous fournir le code de référence pour le démontrer ?

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


Résultat(Libération)

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


Et voici ce que vous obtenez lorsque vous l'exécutez en mode profilage

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

Malheureusement, on ne peut pas faire confiance au profileur dans ce cas.

 
fxsaber:


Résultat ( Release )


HH Et voici ce que j'obtiens, si je l'exécute en mode de profilage

Non seulement il est impossible de croire le profileur dans ce cas, mais Bench1 s'exécute 10 fois plus vite que dans la version Release !

Merci pour cela.

Résultat ( Release )

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

Testé avec Expert Advisor par stratégie.

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)

Encore 2 fois plus rapide (mais pas plus de 10 fois plus rapide, ce qui est certainement dû à l'optimisation du compilateur).

Dossiers :
170952.mq5  6 kb
 
Alain Verleyen:

Testé avec un conseiller en stratégie.

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)

Il est encore 2 fois plus rapide (mais pas plus de 10 fois plus rapide, ce qui est évidemment dû à l'optimisation du compilateur).

Vous mesurez le temps restant pour générer des ticks, et pas seulement le calcul de OnTick.

Voici seulement la mesure 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


Par un facteur de trois. Vous ne pouvez pas obtenir une vitesse 10 fois plus rapide grâce à des appels multiples à la fonction BenchX. StringToDouble2 lui-même est en effet 10 fois plus rapide.

 
fxsaber:

Vous mesurez le temps nécessaire pour générer des ticks, et pas seulement pour calculer OnTick.

...

Vous avez raison.

Je suis vraiment surpris que ce soit 10 fois plus rapide, mais votre fonction ne peut être utilisée que lorsque vous savez que la chaîne contient une valeur double valide.

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

 
Aleksey Vyazmikin:

Merci, mais ce script enregistre également de manière incorrecte.

Sur mon écran, la limitation sur le côté droit est marquée par une ligne verticale, et la capture d'écran est bien au-delà de cette ligne.

Je vais citer la réponse du servicedesk :

Dans ce cas, l'aide ChartScreenShot doit être prise au pied de la lettre.

align_mode=ALIGN_RIGHT

[Mode de sortie d'une capture d'écran étroite. La valeur de l'énumération ENUM_ALIGN_MODE. ALIGN_RIGHT indique un alignement sur le bord droit (sortie par la fin). ALIGN_LEFT spécifie l'alignement à gauche.

Cela signifie que lorsque vous spécifiez l'alignement ALIGN_RIGHT, le graphique défilera de force vers le bord droit, ce qui équivaut à l'exécution de la commande

ChartNavigate(0,CHART_END,0);

Ce comportement a été établi il y a de nombreuses années (donc historiquement) lorsqu'il n'y avait pas encore de fonction ChartNavigate(). La définition de align_mode=ALIGN_RIGHT garantissait que le bord droit du graphique serait supprimé.

Lorsque la fonction ChartNavigate() a été ajoutée, le comportement de la fonction ChartScreenShot n'a pas été modifié.

Par conséquent, si vous souhaitez obtenir l'effet souhaité (le graphique ne défilera pas vers le bord droit), utilisez la valeur ALIGN_LEFT pour le paramètre align_mode.

 
Alain Verleyen:

votre fonction ne peut être utilisée que lorsque vous savez que la chaîne de caractères contient une valeur double valide.

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

Corrigé, maintenant il fonctionne comme l'original

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

Si vous supprimez la constante mise en évidence, le temps d'exécution de la fonction sera doublé. Cela montre que le compilateur ne crée pas toujours un code optimal et qu'il a besoin de ce genre d'indications.

 
fxsaber:

Si nous supprimons la mention const, le temps d'exécution de la fonction sera doublé. Cela indique que le compilateur ne crée pas toujours un code optimal et qu'il a besoin de ce genre d'indications.

Intéressant, merci.

Veuillez ne pas modifier votre code une fois que vous avez déjà reçu une réponse, je n'ai pas reçu la notification que vous l'avez mis à jour.

 
fxsaber:

Si nous supprimons la mention const, le temps d'exécution de la fonction sera doublé. Cela indique que le compilateur ne crée pas toujours un code optimal et qu'il a besoin de ce genre d'indications.

Très intéressant...
Vous savez pourquoi cela se produit ?

Quel est le mécanisme ?

 

Pour déterminer la largeur d'une capture d'écran prise avec MQL5 qui inclurait toutes les barres pour une certaine période, la solution ci-dessous est proposée.

Une particularité s'est avérée être le fait que la largeur de la capture d'écran doit être corrigée à différentes approximations du graphique.

Les "coefficients" réels se sont avérés différents (pour moi spécifiquement) pour la variante avec et sans l'échelle.

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