Ошибки, баги, вопросы - страница 2667

 

Это скорее не баг, а замечание! 


мт 5 билд 2340.

Вчера открыв Каталог данных не заметил как папка Indicators переместилась в папку Experts. Потом выключил мт5 и уже сегодня включил, индикаторы также можно использовать из Навигатора, как ни в чем не бывало. Но, если обратно открыть Каталог данных то там появится пустая папка Indicators и если уже в нее кинуть какой-то индикатор. То он уже не появится в Навигаторе. Возврат папки Indicators обратно в MQL5\Indicators решает проблему. 

 

МТ5 (build 2347) Почему такой большой overhead при добавлении по одному элементу в массив с помощью ArrayResize, если память для них была заранее зарезервирована?

#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:

МТ5 (build 2347) Почему такой большой overhead при добавлении по одному элементу в массив с помощью ArrayResize, если память для них была заранее зарезервирована?

Даже такое не помогает.

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

Ерунда какая-то. Вместо ускорения тормоза.


ЗЫ Странно, результат выполнения примера из Документации нулевой.

--- 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 :
Поработал с профайлером в МТ5 (build 2345),
грубо говоря, интересовало почему два алгоритма, дающих в конечном итоге один и тот же результат, выполняются с разной скоростью, просадка в 1.7 раза в режиме оптимизации .


...

К сожалению, это долгое время профилировщик бесполезен для любого важного проекта. Я уже пытался сообщить об этом, но не было никакого интереса со стороны разработчиков.
 
Sergey Dzyublik :

МТ5 (build 2347) Почему такой большой overhead при добавлении по одному элементу в массив с помощью ArrayResize, если память для них была заранее зарезервирована?

Если вы хотите сравнить, это должно быть:

 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 раз медленнее.
А для типов данных класс и int - в два раза медленнее.

Это очень большая разница, которую, как мне кажется, при желании разработчики могут устранить.

 
Sergey Dzyublik:

Проблема в том, что если резервирую память, а создаю элементы массива по одному, то это требует в разы больше времени, чем просто создать все сразу.

Не заметил этого в коде. Тогда объяснимо, т.к. там только один if срабатывает, где если размер не поменялся, выходим.

 
fxsaber:

Не заметил этого в коде. Тогда объяснимо, т.к. там только один if срабатывает, где если размер не поменялся, выходим.

Пояснение относительно приведенного выше кода #26666

test1, создает все элементы стразу при первом вызове, остальные вызовы ArrayResize идут в "холостую".
Общее количество вызовов ArrayResize == array_size:

      T class_array[];
      for(int i = 1; i <= array_size; i++){
         ArrayResize(class_array, array_size);
      }


test2, создает один элемент и резервирует место еще для array_size-1 элемент, остальные вызовы ArrayResize идут для создании +1 элемента в массиве из ранее зарезервированной памяти.
Общее количество вызовов ArrayResize == array_size:

      T class_array[];
      ArrayResize(class_array, 1, array_size - 1);
      for(int i = 2; i <= array_size; i++){
         ArrayResize(class_array, i);
      }

* в изначальном коде была ошибка (разница +- один элемент). Код обновлен.
Вопрос остается открытым: почему алгоритм test2 медленнее test1 для структур в 7 раз, а для классов и int - в 2 раза?

 
Sergey Dzyublik :

С моей стороны сравнивалось то, что должно было быть.
Мне известно сколько элементов будет помещено в массив и вместо того, что бы создавать их все сразу - резервирую память под несозданные.
Проблема в том, что если резервирую память, а создаю элементы массива по одному, то это требует в разы больше времени, чем просто создать все сразу.
Так для стуктур - это в 7 раз медленнее.
А для типов данных класс и int - в два раза медленнее.

Это очень большая разница, которую, как мне кажется, при желании разработчики могут устранить.

Хорошо в этом случае, я согласен, что должны быть только меньшие накладные расходы.

Но, на мой взгляд, проблема скорее в том, как вы сравниваете. Цикл в test1, скорее всего, оптимизирован и удален компилятором, и, возможно, даже следующим:

 for ( ulong ii= 0 ;ii<count&&! _StopFlag ;ii++)

Попробуйте профилировщик, и вы увидите только небольшую разницу.

 

Нет оптимизации компилятора с помощью профилировщика.