Новая версия платформы MetaTrader 5 build 4230: больше встроенных приложений и расширение поддержки ONNX - страница 24

 

Ilyas #:

Что же Вы, то используете 3 параметр, то нет:

Пытался разобраться, как бесплатно (без физического перераспределения) понизить размерность массива, если reserve_size не был ранее задан.


Работаю с большим количеством тиков. Как это делать экономно по памяти?

input datetime inFrom = D'2021.01.01';

bool IsMyTick( const MqlTick &Tick )
{
  return(!(Tick.time_msc % 10));
}

int FilterTicks( MqlTick &Ticks[] )
{
  const int Size = ArraySize(Ticks);
  int Amount = 0;  
  
  for (int i = 0; i < Size; i++)
    if (IsMyTick(Ticks[i]))
      Ticks[Amount++] = Ticks[i];
      
  return(ArrayResize(Ticks, Amount));
}

class TICKS_ARRAY
{
public:
  MqlTick Ticks[];
};

double Tester( const TICKS_ARRAY &TicksArray[] )
{
  return(0);
}

void OnStart()
{
  const string Symbols[] = {"EURUSD", "GBPUSD", "AUDUSD"};
  
  TICKS_ARRAY TicksArray[];
  
  for (uint i = ArrayResize(TicksArray, ArraySize(Symbols)); (bool)i--;)
  {
    CopyTicksRange(Symbols[i], TicksArray[i].Ticks, COPY_TICKS_ALL, inFrom * 1000);    
    
    FilterTicks(TicksArray[i].Ticks);
  }
  
  Tester(TicksArray);
}


Выделил проблемный участок кода.

 
fxsaber #:
Так зачем физически перестраивать при понижении размерности? Нужно же только счетчик количества элементов массива уменьшить!

Тогда кусок памяти не освободится.

Если хотите работать быстро, то используйте указанный мною метод ведения рядом собственного счетчика рабочих записей в массиве.

 
b4240, отсутствие ошибки компиляции.
class B {};

void f( const B& ) {}

void OnStart()
{
  const B* bPtr = NULL;
  
  f(bPtr); // OK
}
Строка для поискаOshibka 097.
 
fxsaber #:

ЗЫ Чтобы сохранить старое поведение в песочнице, приходится использовать такой костыль.

Спасибо, пригодилось.

 

b4240, получил замедление в 1.5 раза своих расчетов после перехода с объектов на их указатели.


Более-менее лаконично удалось воспроизвести на таком примере.

class TICKS_ARRAY
{
public:
  MqlTick Ticks[];
};

template <typename T>
int Func( const T &TicksArray[] )
{
  const ulong StartTime = GetMicrosecondCount();
  
  int ResCount = 0;
  
  const int Amount = ArraySize(TicksArray);

  int Count = 0;
  
  int Size[];
  bool Res[];
  int Pos[];

  ArrayResize(Pos, Amount);
  ArrayInitialize(Pos, 0);
      
  for (uint i = ArrayResize(Res, ArrayResize(Size, Amount)); (bool)i--;)
  {
    Size[i] = ArraySize(TicksArray[i].Ticks);
    
    if (Res[i] = Size[i])
      Count++;
  }
 
  while (Count)
  {
    uint Index;
      
    for (uint i = Amount; (bool)i--;)
//    for (int i = 0; i < Amount; i++) // Почему-то ускоряет выполнение.
      if (Res[i])
      {
        ResCount += (bool)TicksArray[i].Ticks[Pos[i]].time_msc;
        Index = i;
      }
      
    if (!(Res[Index] = (++Pos[Index] != Size[Index])))
      Count--;
  }

  Print(__FUNCSIG__ + ": " + (string)(GetMicrosecondCount() - StartTime) + " mcs."); // Замер времени выполнения.
  
  return(ResCount);
}

void OnStart()
{
  TICKS_ARRAY TicksArray[];      // Массив тиковых массивов.
  const TICKS_ARRAY* PtrArray[]; // Массив указателей на объекты тиковых массивов.
  
  // Заполнили массив объектов.
  for (uint i = ArrayResize(TicksArray, 20); (bool)i--;)
    ArrayResize(TicksArray[i].Ticks, 1e6);
    
  // Заполнили массив указателей.
  for (uint i = ArrayResize(PtrArray, ArraySize(TicksArray)); (bool)i--;)
    PtrArray[i] = &TicksArray[i];

  Func(PtrArray); // Разогрев
  Print("Bench...");
  
  Print(Func(TicksArray)); // int Func<TICKS_ARRAY>(const TICKS_ARRAY&[]):    892808 mcs.
  Print(Func(PtrArray));   // int Func<TICKS_ARRAY*>(const TICKS_ARRAY*&[]): 1543152 mcs.
}

Не может же быть такого, чтобы в тяжелых расчетах нужно было бы отказываться от использования указателей?!

Строка для поискаOshibka 098.

 
fxsaber #:

b4240, получил замедление в 1.5 раза своих расчетов после перехода с объектов на их указатели.


Более-менее лаконично удалось воспроизвести на таком примере.

Не может же быть такого, чтобы в тяжелых расчетах нужно было бы отказываться от использования указателей?!

Строка для поискаOshibka 098.

К сожалению, безопасность не бывает бесплатной.

Мы постоянно в поиске более быстрых решений и идеи у нас есть, в данный момент прорабатываем решение.

 

Указатели требуют дополнительной проверки безопасности, что дает оверхед. Это основа управляемого языка.

Не надо использовать хакерские методы в циклах for - так вы портите компилятору шаблон оптимизации циклов/векторизации и в рабочих условиях получаете код хуже. При этом надо учитывать, что есть немалый шанс самообмана на усеченной синтетике бенчмарков, где некоторые хакерские методы могут показать фейковое улучшение.

 

А что означает эта ошибка и как с ней бороться (перевести я смог :))? Только сейчас заметил в 4240. Раньше все ок работало...

compiler limit reached: immediate string length 65600 exceeds 65535 characters  Executables Code.mqh    2904    2

Такое ограничение останется?

Это может быть связано с моим железом? Я недавно настройки VM подкручивал, правда все в сторону увеличения памяти и CPU...

Terminal        MetaTrader 5 x64 build 4242 started for MetaQuotes Software Corp.
Windows 11 build 22000, 12 x Apple Silicon, 28 / 31 Gb memory, 178 / 255 Gb disk, touchable, UAC, GMT+3

 
Ilyas #:

Мы постоянно в поиске более быстрых решений и идеи у нас есть, в данный момент прорабатываем решение.

К сожалению, объекты в указатели преобразовать можно, а в обратном направлении - нет.


У меня получилось ускорить указатели, добавив двухстороннее "преобразование".

class TICKS_ARRAY
{
public:
  MqlTick Ticks[];
};

template <typename T>
int Func( T &TicksArray[] )
{  
  int ResCount = 0;
  
  const int Amount = ArraySize(TicksArray);

  int Count = 0;
  
  int Size[];
  bool Res[];
  int Pos[];

  ArrayResize(Pos, Amount);
  ArrayInitialize(Pos, 0);
      
  for (uint i = ArrayResize(Res, ArrayResize(Size, Amount)); (bool)i--;)
  {
    Size[i] = ArraySize(TicksArray[i].Ticks);
    
    if (Res[i] = Size[i])
      Count++;
  }
 
  while (Count)
  {
    uint Index;
      
    for (int i = 0; i < Amount; i++)
      if (Res[i])
      {
        ResCount += (bool)TicksArray[i].Ticks[Pos[i]].time_msc;
        Index = i;
      }
      
    if (!(Res[Index] = (++Pos[Index] != Size[Index])))
      Count--;
  }
  
  return(ResCount);
}

// "Преобразует" указатели в объекты и обратно.
int Hack( TICKS_ARRAY* &PtrArray[] )
{
  TICKS_ARRAY TicksArray[];
  const int Size = ArrayResize(TicksArray, ArraySize(PtrArray));
  
  for (int i = 0; i < Size; i++)
    ArraySwap(TicksArray[i].Ticks, PtrArray[i].Ticks);

  const int Res = Func(TicksArray);
  
  for (int i = 0; i < Size; i++)
    ArraySwap(TicksArray[i].Ticks, PtrArray[i].Ticks);
    
  return(Res);
}

#define BENCH(A)                                                              \
  {                                                                           \
    const ulong StartTime = GetMicrosecondCount();                            \
    A;                                                                        \
    Print(#A + ": " + (string)(GetMicrosecondCount() - StartTime) + " mcs."); \
  } 

void OnStart()
{
  TICKS_ARRAY TicksArray[]; // Массив тиковых массивов.
  TICKS_ARRAY* PtrArray[];  // Массив указателей на объекты тиковых массивов.
  
  // Заполнили массив объектов.
  for (uint i = ArrayResize(TicksArray, 20); (bool)i--;)
    ArrayResize(TicksArray[i].Ticks, 1e6);
    
  // Заполнили массив указателей.
  for (uint i = ArrayResize(PtrArray, ArraySize(TicksArray)); (bool)i--;)
    PtrArray[i] = &TicksArray[i];

  Func(PtrArray); // Разогрев
  Print("Bench...");
    
  BENCH(Func(TicksArray)); // Func(TicksArray): 599315 mcs.
  BENCH(Func(PtrArray));   // Func(PtrArray): 1105295 mcs.
  
  BENCH(Hack(PtrArray));   // Hack(PtrArray): 599608 mcs. 
}

С указателями скорость стала такой же, как с объектами!


Получилась хорошая демонстрация, что соответствующее улучшение компилятора может дать существенный рост производительности. В данном случае почти в два раза при использовании указателей.

 

Просьба рассмотреть возможность файловых операций не только в песочнице (Read/Write: MQL5\Files\*.*), но и в тестерном кеше (Read: Tester\cache\*.tst, *.opt).

  • FileLoad.
  • FileIsExist.
  • FileFindFirst.
  • FileFindNext.
  • FileFindClose.
  • FileSelectDialog.


Библиотеки чтения tst/opt-форматов.


Сейчас для чтения этих файлов приходится подключать WinAPI, либо делать mklink, чтобы Маркет-продукты наделить доп. функционалом.

Строка для поиска: Uluchshenie 089.
Причина обращения: