Leinwand ist cool! - Seite 19

 
Renat Fatkhullin:

Es stellte sich heraus, dass ich auf die Frequenz der Netzgenerierung und nicht auf die Ausgangsfrequenz geachtet hatte.

Es handelt sich um verschiedene Zahlen, die ein Vielfaches voneinander sind.

Es stellte sich heraus, dass ich die Häufigkeit der Netzgenerierung (ohne Ausgabe) und die Häufigkeit der Ausgabe (ohne Generierung) ein wenig falsch berechnet hatte

Hier ist eine korrektere Version.


Ergebnisse auf meinem Prozessor:

Nimmt man die reine Zeit, indem man ein Bild mit 200 geglätteten Kreisen ohne Ausgabe erzeugt, geschieht dies mit etwa 500 Bildern pro Sekunde.

einen Frame mit 200 ungeglätteten Kreisen ohne Ausgabe bilden - etwa 1000 fps.

Die Frequenz der Bildausgabe (Leinwand) selbst (Aktualisierungsfunktion) beträgt etwa 650 fps.

Sie haben wirklich hart gearbeitet!

Dateien:
 
Renat Fatkhullin:

Hüten Sie sich vor Massenkonvertierungen der Typen (int)double oder (double)int und der Vermischung von int+double in Mat-Operationen im Allgemeinen.

Das gibt dem Prozessor den wildesten Overhead - eben einen solchen teuren Assembler-Befehl. Wenn Sie in Double zählen, zählen Sie weiter in Double und wechseln Sie nicht zu Integer-Typen.

Befehle wie cvtsi2sd/cvttsd2si sind sehr lang. Ein kleiner Tipp im Artikel"Der langsamste x86-Befehl", Schurke Nummer 2.

Vielen Dank für diesen sehr wertvollen Artikel.


Aber um ehrlich zu sein, verstehe ich nicht, warum dann in diesem einfachen Skript:

#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)+" микросекунд");   
  }

die Summe von long mit Umwandlung von double in long ist viel schneller als die Summe von double des gleichen Arrays ohne Umwandlung

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 микросекунд
 

Erstens sollte man sich den Assemblercode und das Ergebnis von Optimierungen für extrem einfache Fälle ansehen (die Supermikrosynthetik ist schon lange irreführend). Es ist leicht, einen idealen Fall von Förderanlagen zu finden.

Zweitens kann kaum jemand garantieren, wie dieser oder jener Code kompiliert wird und wie lange er zur Ausführung braucht.

Man muss nur eine weitere Zeile/Befehl in den Code einfügen und die Geschwindigkeit ändert sich drastisch. Der eigentliche Code/die eigentlichen Daten könnten durchaus aus dem L1/L2-Cache kommen, und das war's.

Wie hat es bei Ihnen funktioniert? In der Theorie / Super-Synthetik scheint es, dass Integer-Befehle in der Geschwindigkeit helfen, aber in der realen Code ist es ein Drain. Denn es gibt zehn- bis hundertmal mehr Code, keine Konvektorisierung, ständige Sprünge von ganzzahligen zu reellen Berechnungen und die Optimierung ist begrenzt.

 
Renat Fatkhullin:


Warum ist die Initialisierung von Arrays beliebigen Typs in MQL4 mehr als 10 Mal langsamer als in MQL5?

 
Реter Konow:

Warum ist die Initialisierung von Arrays beliebigen Typs in MQL4 mehr als 10 Mal langsamer als in MQL5?

Denn dort sind alle Arrays dynamisch und die Sprache ist zehnmal langsamer.

 
Das ist eine coole Antwort)).
Zehnmal langsamer, weil zehnmal langsamer)).
 

Ein ultraschneller Indikator mit Hunderten von gleitenden Durchschnitten, implementiert auf Canvas.

100 MA-Zeilen (Periodenschritt 10) - Zeit der Berechnung und Anzeige auf dem Bildschirm - 4-7 Millisekunden


1000 Zeilen MA (Periodenschritt 1) - Zeit der Berechnung und Anzeige - 20-30 Millisekunden.


Ich habe den Code nicht allzu sehr getestet. Es kann Fehler geben. Nur für einen Pixel dicken Balken implementiert (er wird zu diesem Maßstab gezwungen). Auch die Bildwiederholfrequenz ist nicht optimiert. Alle Zeilen werden berechnet und bei jedem Tick vollständig ausgegeben.

#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));
  }
//+------------------------------------------------------------------+
Dateien:
MultiMA.mq5  9 kb
[Gelöscht]  
Nikolai Semko:

Ein ultraschneller Indikator mit Hunderten von gleitenden Durchschnitten, implementiert auf Canvas.

100 MA-Zeilen (Periodenschritt 10) - Zeit der Berechnung und Anzeige auf dem Bildschirm - 4-7 Millisekunden


1000 MA-Zeilen (Periodenschritt 1) - Zeit für Berechnung und Anzeige - 20-30 Millisekunden


cool, mit Standardindikatoren wäre alles tot

 
Maxim Dmitrievsky:

cool, die Standard-Indikatoren hätten das alles aufgehängt.

und dann wäre da noch eine Meile Code...

vielleicht kann sogar das nur mit einer Vorlage gemacht werden. Ich weiß nicht, ob die Anzahl der Indikatorlinien im Körper eines Indikators begrenzt ist.

 
Nikolai Semko:

...

Die Begrenzung der Anzahl von Indikatorzeilen im Körper eines Indikators ist nicht bekannt.

Es gibt eine Grenze. Es können bis zu 512 Anzeigepuffer erstellt werden >>>https://www.mql5.com/ru/docs/indicators

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