エラー、バグ、質問 - ページ 2667

 
つまり、私が説明したバグは開発者の興味を惹かないということですね、わかりました...。
 
MT5のバグ(ビルド2345)長い間、プロファイラーが 動作しているのに、結果がどこにも表示されないことが理解できなかった。
スクリプトプロジェクトのプロファイラーは、最適化が無効な場合にのみ結果を表示し、最適化が有効な場合は、すべてが実行され、動作しますが、結果が得られないことが判明しました。
 
Sergey Dzyublik:
MT5(ビルド2345)のバグで、プロファイラが 起動して動作しているのに結果が表示されないのが理解できなかった。
スクリプトプロジェクトのプロファイラーは、最適化が無効な場合にのみ結果を表示し、最適化が有効な場合は、すべてが実行され、動作しますが、結果は得られませんことが判明しました。

プロファイラがすべての指標で機能しない(最適化なし)。フォーラムに2回書き、開発者にPMでコードを送りましたが、返事がありません。

 
MT5(ビルド2345)でプロファイラーを操作してみました。
大雑把に言うと、最適化 モードで1.7倍のドローダウンという、スピードが違うのに最終的に同じ結果を出す2つのアルゴリズムが不思議だったんです。

#include <stl_vector.mqh>

// TickCounts: 850
vector<int>::move test_vector_move_return_assign_by_index(int n){
   vector<int> v(n);
   for(int i = 0; i < n; i++){
      v[i].UNREF  = i;
   }
   return v;
};

// TickCounts: 1450
vector<int>::move test_vector_move_return_push_back(int n){
   vector<int> v;
   // lazy implementation  
   v.reserve(n);                      
   for(int i = 0; i < n; i++){
      v.push_back(i);
   }
   return v;
};


void OnStart()
{
   for(int i = 0; i < 20000; i++){
       vector<int> v_int_move = test_vector_move_return_assign_by_index(1000);
   }
   
   for(int i = 0; i < 20000; i++){
      vector<int> v_int_move = test_vector_move_return_push_back(1000);
   }
}


その結果、MT5プロファイラの実用的な経験を積み、その動作に関する多くのバグを検出することができました。
開発者がこの情報に興味を持つかどうかは不明であり、バグのローカライズに何時間もかける気もないため、検出された問題点についての簡単な情報のみを提供することにする。

1) 異なるアルゴリズムの速度を比較する方法がない。
そのため、最適化を行った場合と行わなかった場合の両方で、他のアルゴリズムよりも3倍速いアルゴリズムが、プロファイラでは最も遅く表示されることがあります。
どうやらプロファイラのオーバーヘッドのようなものがあり、それがアルゴリズムの実行時間に影響を与えているようで、この場合、プロファイラでアルゴリズムの性能速度を比較する意味がありません。

2) 画面上のヒストグラムのツールチップに表示されるCountの値が間違っている。
プロファイラによると、この関数は80K回起動され、期待された20K回ではありませんでした。同時に、行によってカウントが数倍、ある行では3倍、別の行では2倍になっています。

3) 画面上のヒストグラムのツールチップに表示される「時間」の値が間違っている。
プロファイラで99.90%の確率で条件に入ったと表示されても、実際には20K回の通過のうち1回しか発生しないケースもあります。

 

バグというより観察ですねー。


mt 5 build 2340。

昨日、Data Directoryを開いたとき、IndicatorsフォルダがExpertsフォルダに移動していることに気がつきませんでした。その後、mt5を無効にし、本日有効にしたところ、何事もなかったかのようにNavigatorからインジケータも使用できるようになりました。しかし、Data Folderを再び開くと空のIndicatorsフォルダが表示され、そこに何らかのインジケータを移動させてもNavigatorには表示されません。ナビゲーターに表示されなくなります。IndicatorsフォルダーをMQL5Indicatorsに戻すと解決します。

 

MT5 (build 2347) ArrayResizeを使用して配列に要素を1つずつ追加する際に、あらかじめメモリが確保されている場合、なぜこのような大きなオーバーヘッドが発生するのでしょうか?

#define  K 1000
#define  M (1000 * K)

#define    SpeedTest(test_count,msg,EX)        {uint mss=GetTickCount(); ulong count=test_count;for(ulong ii=0;ii<count&&!_StopFlag;ii++){EX;} \
                                              printf("%-60s: loops=%i ms=%u",msg,count,GetTickCount()-mss);}
                                              
class A{
public:
   int data;
};

struct B{
   int data;
};

template<typename T>
void test1(const int test_count, const int array_size){
   SpeedTest(
   test_count,"Test Class ArrayResize all",
   {
      T class_array[];
      for(int i = 1; i <= array_size; i++){
         ArrayResize(class_array, array_size);
      }
   }
   )
};

template<typename T>
void test2(const int test_count, const int array_size){
   SpeedTest(
   test_count,"Test Class ArrayResize one by one with reserved memory",
   {
      T class_array[];
      ArrayResize(class_array, 1, array_size - 1);
      for(int i = 2; i <= array_size; i++){
         ArrayResize(class_array, i);
      }
   }
   )
};

void OnStart()
{
  const int test_count = 5*K;
  const int array_size = 5*K;  
  
  test1<int>(test_count, array_size);            // Avg time: 100
  test2<int>(test_count, array_size);            // Avg time: 190
  test1<int>(test_count, array_size);
  test2<int>(test_count, array_size);
  test1<int>(test_count, array_size);
  test2<int>(test_count, array_size);
  test1<int>(test_count, array_size);
  test2<int>(test_count, array_size);
  
printf("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");
  test1<A>(test_count, array_size);              // Avg time: 810
  test2<A>(test_count, array_size);              // Avg time: 1460
  test1<A>(test_count, array_size);
  test2<A>(test_count, array_size);
  test1<A>(test_count, array_size);
  test2<A>(test_count, array_size);
  test1<A>(test_count, array_size);
  test2<A>(test_count, array_size);
  
printf("BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB");
  test1<B>(test_count, array_size);              // Avg time: 110
  test2<B>(test_count, array_size);              // Avg time: 770
  test1<B>(test_count, array_size);
  test2<B>(test_count, array_size);
  test1<B>(test_count, array_size);
  test2<B>(test_count, array_size);
  test1<B>(test_count, array_size);
  test2<B>(test_count, array_size);
}

ArrayResizeによる内部予約アルゴリズムの改良をご検討ください。

例えば、クラスであれば、コンストラクタの呼び出し以外に、何らかの「リストへの内部登録」を行うことが想定される。
そして、ArrayResizeによる予約の枠内で、直接のメモリ確保とは別に、処理の最適化を図ることができるのです。
- 隣接して作成された要素からデータを取得する(例:仮想関数 テーブルへのポインタ)。
- まだ作成されていないクラスの「内部登録」のために、事前に実行またはスペースを確保する。

 
Sergey Dzyublik:

MT5 (build 2347) ArrayResizeを使用して配列に要素を1つずつ追加する際に、あらかじめメモリが確保されている場合、なぜこのような大きなオーバーヘッドが発生するのでしょうか?

それさえも、どうにもならない。

      ArrayResize(class_array, 1, array_size - 1);
      for(int i = 0; i < array_size; i++){
//         ArrayResize(class_array, i);
         ArrayResize(class_array, i, array_size - 1);

ただ、意味がないんです。スピードアップするどころか、減速しているだけです。


ZZZ 不思議なことに、『ドキュメント』の例の 結果が0になっている。

--- Test Fast: ArrayResize(arr,100000,100000)
1. ArraySize(arr)=100000 Time=0 ms
2. ArraySize(arr)=200000 Time=0 ms
3. ArraySize(arr)=300000 Time=0 ms
---- Test Slow: ArrayResize(slow,100000)
1. ArraySize(slow)=100000 Time=0 ms
2. ArraySize(slow)=200000 Time=0 ms
Документация по MQL5: Операции с массивами / ArrayResize
Документация по MQL5: Операции с массивами / ArrayResize
  • www.mql5.com
При успешном выполнении функция возвращает количество всех элементов, содержащихся в массиве после изменения размера; в противном случае возвращает -1 и массив не меняет размеры. Если ArrayResize() применена к статическому массиву, таймсерии или индикаторному буферу, то размер массива остается прежним – такие массивы не могут быть...
 
Sergey Dzyublik :
MT5 (build 2345)でプロファイラを使用した場合、動作しました。
大雑把に言うと、最終的に同じ結果を出す2つのアルゴリズムが異なる速度で動いているのが不思議だったのですが、最適化モードでは ドローダウンが1.7倍.


...

残念ながら、この長時間プロファイラでは、重要なプロジェクトには使えません。すでに報告しようとしたのですが、開発者からは何の関心も示されませんでした。
 
Sergey Dzyublik :

MT5 (build 2347) ArrayResizeを使用して配列に要素を1つずつ追加する際に、あらかじめメモリが確保されている場合、なぜこのような大きなオーバーヘッドが発生するのでしょうか?

比較するならば、そうあるべきでしょう。

 void test1 ( const int test_count, const int array_size){
   SpeedTest(
   test_count,"Test Class ArrayResize all",
   {
      T class_array[];
       for ( int i = 0 ; i < array_size; i++){
         ArrayResize (class_array,  i );
      }
   }
   )
 
Alain Verleyen:

比較するならば、そうあるべきでしょう。

私の方では、比較対象は想定内のものでした。
配列に配置される要素の数はわかっているので、一度にすべて作成するのではなく、作成されない要素用にメモリを確保しています。
問題は、メモリを確保して配列の要素を 一つずつ作成していくと、一度に作成するよりも何倍も時間がかかってしまうことです。
つまり、構造物の場合は7倍も遅くなるわけです。
また、classとintデータ型では2倍遅くなる。

これは非常に大きな違いであり、開発者が望めば排除できるものだと思います。