Canvas is cool! - page 19

 
Renat Fatkhullin:

It turns out that I was looking at the web generation frequency, not the output frequency.

These are different numbers, multiples of each other.

It turns out I was calculating the web generation frequency (without output) and output frequency (without generation) a bit wrong

Here is a more correct version.


Results on my processor:

If you take the time purely by generating a frame of 200 smoothed circles without output, it happens at about 500 frames per second.

forming a frame of 200 unsmoothed circles without output - about 1000 fps.

The frequency of the image (canvas) output itself (Update function) is about 650 fps.

You have really worked hard!

Files:
 
Renat Fatkhullin:

Beware of mass conversions of (int)double or (double)int types and mixing int+double in mat operations in general.

This gives the wildest overhead to the processor - just such an expensive assembler command. If you count in double, keep counting in double and don't switch to integer types.

Commands like cvtsi2sd/cvttsd2si are very long. A little tip in the article"The slowest x86 instruction", villain number 2.

Thanks for a very valuable article.


But to be honest, I don't understand why then in this simple script:

#define  Num 1000000 
void OnStart()
  {
    double arr[Num];
    for (int i=0;i<Num;i++) arr[i]=(double) rand()/(1+rand()%100); // инициализируем массив случайными числами double от 0.0 до 32767.0
    
    long sumL=0;
    
    ulong t1=GetMicrosecondCount();
    for (int i=0;i<Num;i++) sumL+=(long)arr[i]; // сумма long
    t1=GetMicrosecondCount()-t1;
    
    double sumD=0;
    
    ulong t2=GetMicrosecondCount();
    for (int i=0;i<Num;i++) sumD+=arr[i];      // сумма double
    t2=GetMicrosecondCount()-t2;  
    
    Print ("Сумма long   = "+ string(sumL)+ ", время суммирования "+string(t1)+" микросекунд");
    Print ("Сумма double = "+ DoubleToString(sumD)+ ", время суммирования "+string(t2)+" микросекунд");   
  }

the sum of long with conversion of double type to long is much faster than the sum of double of the same array without conversion

2019.01.15 22:21:46.410 TestSpeedDoubleAndInt (NZDUSD,M5)       Сумма long   = 849290923,          время суммирования 748  микросекунд
2019.01.15 22:21:46.410 TestSpeedDoubleAndInt (NZDUSD,M5)       Сумма double = 849764484.23059070, время суммирования 1393 микросекунд
 

Firstly, one should look at the assembly code and the result of optimizations of extremely simple cases (supermicrosynthetics has long been misleading). It is easy to run into an ideal case of conveyor implementation.

Secondly, hardly anybody can guarantee how this or that code will compile and how long it will take to execute.

You just have to add one more line/command into the code and the speed changes drastically. The real code/data might well get out of the L1/L2 cache and that's it.

How did it work for you? In theory/super-synthetics it seems that integer commands will help in speed, but in real code it's a drain. Because there is tens/hundreds of times more code, no convectorization, constant jumping from integer to real calculations and optimization is limited.

 
Renat Fatkhullin:


Why is initialization of arrays of any types in MQL4 more than 10 times slower than in MQL5?

 
Реter Konow:

Why is initialization of arrays of any types in MQL4 more than 10 times slower than in MQL5?

Because all arrays there are dynamic and the language is ten times slower.

 
That's a cool answer)).
Ten times slower because ten times slower)).
 

An ultra-fast indicator of hundreds of moving averages, implemented on Canvas.

100 lines MA (period step 10) - time of calculation and displaying on the screen - 4-7 milliseconds


1000 lines MA (period step 1) - time of calculation and displaying - 20-30 milliseconds.


I haven't tested the code too much. There may be bugs. Implemented only for one pixel thick bar (it is forced to this scale). Also screen refresh rate is not optimized. All lines are calculated and fully output at every tick.

#include <Canvas\iCanvas.mqh> //https://www.mql5.com/ru/code/22164
#property indicator_chart_window

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
input int MA=1000;   // максимальный период скользящих средних
input int stepMa=10; // шаг скользящих средних

double  Close[];
long Total;
int Ma;
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int OnInit()
  {
   ChartSetInteger(0,CHART_EVENT_MOUSE_MOVE,true);
   ChartSetInteger(0,CHART_SCALE,0,0);
   ChartSetInteger(0,CHART_FOREGROUND,true);
   CopyClose(_Symbol,_Period,(int)W.Right_bar,W.BarsInWind+Ma-1,Close);
   Total=SeriesInfoInteger(_Symbol,_Period,SERIES_BARS_COUNT);
   if (Total<(MA+W.BarsInWind)) Ma=(int)Total-1-W.BarsInWind; else Ma=MA;
   if (Ma<=0) Ma=1;
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,const int prev_calculated,const int begin,const double &price[])
  {
   CopyClose(_Symbol,_Period,(int)W.Right_bar,W.BarsInWind+Ma-1,Close);
   Print("Время формирования кадра = "+(string)(nMA()/1000)+" миллискунд");
   return(rates_total);
  }
//+------------------------------------------------------------------+
//| ChartEvent function                                              |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
  {
   if(id==CHARTEVENT_CHART_CHANGE)
     {
      ChartSetInteger(0,CHART_SCALE,0,0);
      CopyClose(_Symbol,_Period,(int)W.Right_bar,W.BarsInWind+Ma-1,Close);
      Print("Время формирования кадра = "+(string)(nMA()/1000)+" миллискунд");
     }
  }
//+------------------------------------------------------------------+

ulong nMA()
  {
   ulong t=GetMicrosecondCount();
   int preY=0;
   Canvas.Erase();
   double S=0;
   for(int i=0;i<Ma; i++) S+=Close[i];

   for(int Per=Ma;Per>0;)
     {
      double s=S;
      uint Clr=Grad((double)Per/Ma);
      for(int x=0; x<W.BarsInWind;x++)
        {
         int Y=(int)(Canvas.Y(s/Per)-0.5);
         if(x>0) if(fabs(Y-preY)>1) Canvas.Line(x-1,preY,x,Y,Clr);
         else Canvas.PixelSet(x,Y,Clr);
         if((Ma+x)<ArraySize(Close)) s=s-Close[x+Ma-Per]+Close[Ma+x]; else break;
         preY=Y;
        }
      for(int j=0; j<stepMa; j++) if(Per>0){ S=S-Close[Ma-Per]; Per--;} else break;
     }
   Canvas.Update();
   return GetMicrosecondCount()-t;
  }
//+------------------------------------------------------------------+
uint Grad(double p)
  {
   static uint Col[6]={0xFF0000FF,0xFFFF00FF,0xFFFF0000,0xFFFFFF00,0xFF00FF00,0xFF00FFFF};
   if(p>0.9999) return Col[5];
   if(p<0.0001) return Col[0];
   p=p*5;
   int n=(int)p;
   double k=p-n;
   argb c1,c2;
   c1.clr=Col[n];
   c2.clr=Col[n+1];
   return ARGB(255,c1.c[2]+uchar(k*(c2.c[2]-c1.c[2])+0.5),
                   c1.c[1]+uchar(k*(c2.c[1]-c1.c[1])+0.5),
                   c1.c[0]+uchar(k*(c2.c[0]-c1.c[0])+0.5));
  }
//+------------------------------------------------------------------+
Files:
MultiMA.mq5  9 kb
 
Nikolai Semko:

An ultra-fast indicator of hundreds of moving averages, implemented on Canvas.

100 lines MA (period step 10) - time of calculation and displaying on the screen - 4-7 milliseconds


1000 MA lines (period step 1) - time for calculation and display - 20-30 milliseconds


cool, with standard indicators everything would be dead

 
Maxim Dmitrievsky:

cool, the standard indicators would have hung it all up.

and then there'd be a mile of code...

maybe even that can only be done with a template. I don't know about the limitation of the number of indicator lines in the body of one indicator.

 
Nikolai Semko:

...

Not aware of the limitation on the number of indicator lines in the body of one indicator.

There is a limit. Up to 512 indicator buffers can be made >>>https://www.mql5.com/ru/docs/indicators

Документация по MQL5: Технические индикаторы
Документация по MQL5: Технические индикаторы
  • www.mql5.com
Все функции типа iMA, iAC, iMACD, iIchimoku и т.п., создают в глобальном кеше клиентского терминала копию соответствующего технического индикатора. Если копия индикатора с этими параметрами уже существует, то новая копия не создается, а увеличивается счетчик ссылок на данную копию. Эти функции возвращают хэндл соответствующей копии индикатора...