Características da linguagem mql5, subtilezas e técnicas - página 84

 
Alain Verleyen:

Você pode fornecer o código de referência para demonstrar isso?

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


Resultado(Lançamento)

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 isto é o que se obtém quando se corre em modo de perfil.

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

Infelizmente, não se pode confiar no profiler neste caso.

 
fxsaber:


Resultado ( Lançamento )


HH E isto é o que eu recebo, se o correr em modo de perfil.

Não só é impossível confiar no profiler neste caso, como o Bench1 corre 10 vezes mais rápido do que no Release-version!

Obrigado por isso.

Resultado ( Lançamento )

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

Testado com o Expert Advisor por estratégia.

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)

Mais 2 vezes mais rápido (mas não mais de 10 vezes mais rápido, o que certamente se deve à otimização do compilador).

Arquivos anexados:
170952.mq5  6 kb
 
Alain Verleyen:

Testado com um conselheiro de estratégia.

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 vezes mais rápido ainda (mas não mais de 10 vezes mais rápido, o que obviamente se deve à otimização do compilador).

Você mede o tempo ainda para gerar ticks, não apenas o cálculo do OnTick.

Aqui está apenas a medição 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;
  }  
}


Bancada1

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


Bancada3

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


Por um factor de três. Você não pode obter 10 vezes mais rápido devido a múltiplas chamadas para a função BenchX. O próprio StringToDouble2 é de facto 10 vezes mais rápido.

 
fxsaber:

Você mede o tempo ainda para gerar carrapatos, não apenas para calcular o OnTick.

...

Tens razão.

Estou realmente surpreso que seja 10x mais rápido, mas a sua função só pode ser usada quando você sabe que a string contém um valor duplo válido.

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

 
Aleksey Vyazmikin:

Obrigado, mas este script também salva incorretamente.

No meu monitor, a limitação do lado direito é marcada com uma linha vertical, e a imagem da tela está muito além dessa linha.

Vou citar a resposta do servicedesk:

Neste caso, a ajuda ChartScreenShot deve ser tomada literalmente

align_mode=ALIGN_RIGHT

[em] Modo de uma saída de tela estreita. O valor da enumeração ENUM_ALIGN_MODE. ALIGN_RIGHT indica alinhamento para a borda direita (saída do fim). ALIGN_LEFT especifica o alinhamento à esquerda.

Isso significa que quando você especifica o alinhamento ALIGN_RIGHT o gráfico será rolado à força para a borda direita, o que é equivalente a executar o comando

ChartNavigate(0,CHART_END,0);

Este comportamento foi estabelecido há muitos anos (historicamente) quando ainda não existia a função ChartNavigate(). Definir align_mode=ALIGN_RIGHT garantiu que exatamente a borda direita do gráfico seria removida.

Quando a função ChartNavigate() foi adicionada, o comportamento da função ChartScreenShot não foi alterado.

Portanto, se você quiser obter o efeito desejado (o gráfico não será rolado para a borda direita), use o valor ALIGN_LEFT para o parâmetro align_mode.

 
Alain Verleyen:

a sua função só pode ser usada quando você sabe que a string contém um valor duplo válido.

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

Corrigido, agora funciona como o 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("");
  }
}
 

Se você remover a constante destacada, o tempo de execução da função irá dobrar. Isto mostra que o compilador nem sempre cria o código ideal e precisa deste tipo de dicas.

 
fxsaber:

Se removermos a constante marcada, o tempo de execução da função irá duplicar. Ele indica que o compilador nem sempre cria um código ideal e precisa deste tipo de dicas.

Interessante, obrigado.

Por favor, não edite o seu código depois de já ter recebido uma resposta, não recebi a notificação de que o actualizou.

 
fxsaber:

Se removermos a constante marcada, o tempo de execução da função irá duplicar. Ele indica que o compilador nem sempre cria um código ideal e precisa deste tipo de dicas.

Muito interessante...
Alguma ideia sobre o porquê de isto acontecer?

Qual é o mecanismo?

 

Para determinar a largura de uma imagem tirada com MQL5 que incluiria todas as barras por um determinado período, é oferecida a solução abaixo.

Uma peculiaridade acabou por ser o facto de a largura da imagem da tela ter de ser corrigida em diferentes aproximações do gráfico.

Os "coeficientes" reais revelaram-se diferentes (para mim especificamente) para a variante com e sem a escala.

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