キャンバスがカッコいい! - ページ 19

 
Renat Fatkhullin:

出力周波数ではなく、ウェブの生成周波数を見ていたことが判明したのです。

これらは異なる数字で、お互いの倍数である。

ウェブの生成頻度(出力なし)と出力頻度(生成なし)の計算を少し間違えていたことが判明しました

以下は、より正しいバージョンです。


私のプロセッサーでの結果。

出力せずに200個の平滑化した円を1フレーム生成して純粋に時間をかけると、1秒間に約500フレームで発生します。

出力なしで200個の非平滑化円形のフレームを形成する - 約1000fps。

画像(キャンバス)の出力自体(Update機能)の周波数は、1秒間に約650フレームです。

本当によく頑張りましたね。

ファイル:
 
Renat Fatkhullin:

(int)double型や(double)int型の大量変換や、一般的なmat演算でのint+doubleの混在に注意すること。

これは、プロセッサに乱暴なオーバーヘッドを与えるもので、まさにそんな高価なアセンブラコマンドです。doubleでカウントしている場合は、doubleでカウントし続け、整数型に切り替えないようにします。

cvtsi2sd/cvttsd2si のようなコマンドは非常に長いです。x86で一番遅い命令」の記事中の悪役ナンバー2に ちょっとしたヒントがあります。

とても貴重な記事をありがとうございました。


しかし、正直なところ、このシンプルなスクリプトでなぜそうなるのか理解できない。

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

double 型を long 型に変換した long 型の合計は,変換せずに同じ配列の double 型の合計よりもずっと高速です.

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

まず、アセンブリコードと、極めて単純なケースの最適化の 結果を見るべきである(スーパーマイクロシンセティクスは長い間、誤解を招いてきた)。コンベア実装の理想的なケースにぶつかりやすいのです。

第二に、このコードがどのようにコンパイルされ、どれだけの時間をかけて実行されるかを保証できる人はほとんどいない。

コードに1行/1コマンドを加えるだけで、スピードが劇的に変わるのです。本当の コード/データは、L1/L2キャッシュから出るかもしれないし、それだけかもしれない。

どのような効果があったのでしょうか?理論的/超合理的には、整数コマンドはスピードに役立つと思われますが、実際のコードでは消耗品です。数十倍・数百倍のコードがあるため、対流がなく、整数計算から実数計算へのジャンプが絶えず、最適化には限界があります。

 
Renat Fatkhullin:


MQL4で任意の型の配列の初期 化が、MQL5に比べて10倍以上遅いのはなぜですか?

 
Реter Konow:

MQL4で任意の型の配列の初期 化が、MQL5に比べて10倍以上遅いのはなぜですか?

なぜなら、そこではすべての配列が動的であり、言語が10倍遅くなるからです。

 
かっこいい答えですね))。
10倍遅いから10倍遅い))。
 

数百本の移動平均線をCanvasで実装した超高速インジケーターです。

100 MAライン(ピリオドステップ10)-計算と画面表示の時間-4-7ミリ秒


1000行MA(期間ステップ1)-計算と表示の時間-20-30ミリ秒。


あまりコードのテストはしていないのですが。バグがあるかもしれません。1ピクセルの太さのバーに対してのみ実装される(このスケールに強制的に合わせられる)。また、画面のリフレッシュレートも最適化されていません。すべての行を計算し、1ティックごとに完全に出力します。

#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));
  }
//+------------------------------------------------------------------+
ファイル:
MultiMA.mq5  9 kb
 
Nikolai Semko:

数百本の移動平均線をCanvasで実装した超高速インジケーターです。

100ラインMA(ピリオドステップ10)-計算と画面表示の時間-4-7ミリ秒


1000 MAライン(期間ステップ1)-計算と表示のための時間-20-30ミリ秒


標準的なインジケータでは、すべてが死んでしまう。

 
Maxim Dmitrievsky:

クールに、標準的なインジケーターはすべて掛けていたはずです。

そして、1マイルのコードがある...

それもテンプレートでなければできないことかもしれません。1つのインジケーター本体に表示されるインジケーターラインの 数の制限についてはわかりません。

 
Nikolai Semko:

...

1つのインジケーター本体に表示されるインジケーターの行 数の制限を意識していない。

限界はある。最大512個のインジケーターバッファを作成可能 >>https://www.mql5.com/ru/docs/indicators

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