OpenCL: внутренние тесты реализации в MQL5

 

Мы ведем работу над нативной поддержкой OpenCL прямо в MQL5. Через пару билдов будет доступно публично.

Вот небольшой рабочий пример расчета фрактала Мандельброта в OpenCL, который кардинально ускоряет расчеты по сравнению с софтверной реализацией. Расчет на OpenCL получился в 100 раз быстрее.


//+------------------------------------------------------------------+
//|                                                     ocl_test.mq5 |
//|                        Copyright 2012, MetaQuotes Software Corp. |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2012, MetaQuotes Software Corp."
#property link      "http://www.mql5.com"
#property version   "1.00"
//+------------------------------------------------------------------+
//| Код функции OpenCL                                               |
//+------------------------------------------------------------------+
const string cl_src=
      "__kernel void MFractal(                                    \r\n"
      "                       float x0,                           \r\n"
      "                       float y0,                           \r\n"
      "                       float x1,                           \r\n"
      "                       float y1,                           \r\n"
      "                       uint  max,                          \r\n"
      "              __global uint *out)                          \r\n"
      "  {                                                        \r\n"
      "   size_t  w = get_global_size(0);                         \r\n"
      "   size_t  h = get_global_size(1);                         \r\n"
      "   size_t gx = get_global_id(0);                           \r\n"
      "   size_t gy = get_global_id(1);                           \r\n"
      "   float dx = x0 + gx * (x1-x0) / (float) w;               \r\n"
      "   float dy = y0 + gy * (y1-y0) / (float)h;                \r\n"
      "   float x  = 0;                                           \r\n"
      "   float y  = 0;                                           \r\n"
      "   float xx = 0;                                           \r\n"
      "   float yy = 0;                                           \r\n"
      "   float xy = 0;                                           \r\n"
      "   uint i = 0;                                             \r\n"
      "   while ((xx+yy)<4 && i<max)                              \r\n"
      "     {                                                     \r\n"
      "      xx = x*x;                                            \r\n"
      "      yy = y*y;                                            \r\n"
      "      xy = x*y;                                            \r\n"
      "      y = xy+xy+dy;                                        \r\n"
      "      x = xx-yy+dx;                                        \r\n"
      "      i++;                                                 \r\n"
      "     }                                                     \r\n"
      "   if(i==max)                                              \r\n"
      "      out[w*gy+gx] = 0;                                    \r\n"
      "   else                                                    \r\n"
      "      out[w*gy+gx] = (uint)((float)0xFFFFFF/(float)max)*i; \r\n"
      "  }                                                        \r\n";
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
#define SIZE_X 512
#define SIZE_Y 512
//+------------------------------------------------------------------+
//| Заголовок BMP файла                                              |
//+------------------------------------------------------------------+
struct BitmapHeader
  {
   ushort            type;
   uint              size;
   uint              reserv;
   uint              offbits;
   uint              imgSSize;
   uint              imgWidth;
   uint              imgHeight;
   ushort            imgPlanes;
   ushort            imgBitCount;
   uint              imgCompression;
   uint              imgSizeImage;
   uint              imgXPelsPerMeter;
   uint              imgYPelsPerMeter;
   uint              imgClrUsed;
   uint              imgClrImportant;
  };
//+------------------------------------------------------------------+
//| Запись битмапа в файл                                            |
//+------------------------------------------------------------------+
bool SaveBitmapToFile(const string filename,uint &bitmap[],const BitmapHeader &info)
  {
//--- откроем файл
   int file=FileOpen(filename,FILE_WRITE|FILE_BIN);
   if(file==INVALID_HANDLE)
     {
      Print(__FUNCTION__," error opening '",filename,"'");
      return(false);
     }
//--- запишем заголовок и само тело
   if(FileWriteStruct(file,info)==sizeof(info))
     {
      if(FileWriteArray(file,bitmap)==ArraySize(bitmap))
        {
         FileClose(file);
         return(true);
        }
     }
//--- неудачно получилось, удалим файл от греха подальше
   FileClose(file);
   FileDelete(filename);
   Print(__FUNCTION__," error writting '",filename,"'");
//--- вернем ошибку
   return(false);
  }
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
//--- инициализируем OpenCL объекты
   int cl_ctx=CLContextCreate();
   int cl_prg=CLProgramCreate(cl_ctx,cl_src);
   int cl_krn=CLKernelCreate(cl_prg,"MFractal");
   int cl_mem=CLBufferCreate(cl_ctx,SIZE_X*SIZE_Y*sizeof(float),CL_MEM_READ_WRITE);
//--- подготовимся к выполению
   float x0       =-2;
   float y0       =-0.5;
   float x1       =-1;
   float y1       = 0.5;
   uint  max      = 20000;
   uint  offset[2]={0,0};
   uint  work  [2]={SIZE_X,SIZE_Y};
//--- выставляем неизменяемые параметры функции OpenCL
   CLSetKernelArg(cl_krn,4,max);
   CLSetKernelArgMem(cl_krn,5,cl_mem);
//--- подготовим буфер для вывода пикселей
   uint buf[];  
   ArrayResize(buf,SIZE_X*SIZE_Y);
//--- подготовим заголовок
   BitmapHeader info;
   ZeroMemory(info);
   info.type          =0x4d42;
   info.size          =sizeof(info)+SIZE_X*SIZE_Y*4;
   info.offbits       =sizeof(info);
   info.imgSSize      =40;
   info.imgWidth      =SIZE_X;
   info.imgHeight     =SIZE_Y;
   info.imgPlanes     =1;
   info.imgBitCount   =32;
   info.imgCompression=0;                // BI_RGB
   info.imgSizeImage  =SIZE_X*SIZE_Y*4;   
//--- создаём объект для вывода графики
   ObjectCreate(0,"x",OBJ_BITMAP_LABEL,0,0,0);
   ObjectSetInteger(0,"x",OBJPROP_XDISTANCE,0);
   ObjectSetInteger(0,"x",OBJPROP_YDISTANCE,50);
//--- рендерим пока не остоновят снаружи
   while(!IsStopped())
     {
      uint x=GetTickCount();
      //--- выставляем плавающие параметры
      CLSetKernelArg(cl_krn,0,x0);
      CLSetKernelArg(cl_krn,1,y0);
      CLSetKernelArg(cl_krn,2,x1);
      CLSetKernelArg(cl_krn,3,y1);
      //--- рендерим кадр
      CLExecute(cl_krn,2,offset,work);                  
      //--- забираем данные кадра
      CLBufferRead(cl_mem,buf);
      //--- выведем время рендера
      Comment(GetTickCount()-x);
      //--- сохраняем кадр в памяти и рисуем его
      SaveBitmapToFile("Mandelbrot.bmp",buf,info);
      ObjectSetString(0,"x",OBJPROP_BMPFILE,NULL);
      ObjectSetString(0,"x",OBJPROP_BMPFILE,"\\Files\\Mandelbrot.bmp");
      ChartRedraw();
      //--- небольшая задержка и обновление параметров для следующего кадра
      Sleep(10);
      x0+=0.001f;
      x1-=0.001f;
      y0+=0.001f;
      y1-=0.001f;
     }
//--- удаляем объекты OpenCL
   CLBufferFree(cl_mem);
   CLKernelFree(cl_krn);
   CLProgramFree(cl_prg);
   CLContextFree(cl_ctx);
  }
//+------------------------------------------------------------------+
OpenCL: Мост в параллельные миры
OpenCL: Мост в параллельные миры
  • 2012.05.16
  • Sceptic Philozoff
  • www.mql5.com
В конце января 2012 года компания-разработчик терминала MetaTrader 5 анонсировала нативную поддержку OpenCL в MQL5. В статье на конкретном примере изложены основы программирования на OpenCL в среде MQL5 и приведены несколько примеров "наивной" оптимизации программы по быстродействию.
 
Renat:

Мы ведем работу над нативной поддержкой OpenCL прямо в MQL5. Через пару билдов будет доступно публично.

Вот небольшой рабочий пример расчета фрактала Мандельброта в OpenCL, который кардинально ускоряет расчеты по сравнению с софтверной реализацией. Расчет на OpenCL получился в 100 раз быстрее.

А чтобы у себя запустить скрипт нужно подключить библиотеку с функциями: CLContextCreate, CLProgramCreate, CLKernelCreate, CLBufferCreate и т.д. Что это за библиотека и где можно её взять?

 
tol64:

А чтобы у себя запустить скрипт нужно подключить библиотеку с функциями: CLContextCreate, CLProgramCreate, CLKernelCreate, CLBufferCreate и т.д. Что это за библиотека и где можно её взять?

В папке OpenCL  ... через пару билдов.. :)
 
tol64:

А чтобы у себя запустить скрипт нужно подключить библиотеку с функциями: CLContextCreate, CLProgramCreate, CLKernelCreate, CLBufferCreate и т.д. Что это за библиотека и где можно её взять?

Не нужны никакие библиотеки, поддержка OpenCL в MQL5 теперь нативная.

Никаких дополнительных DLL файлов в составе терминала нет. При загрузке терминал определяет наличие OpenCL интерфейсов в системе (их добавляет драйвер видеокарты). Поддерживаются все производители видеокарт (NVIDIA, AMD, Intel), которые предоставляют OpenCL.

Важно чтобы драйвера видеокарт были современными с включенной поддержкой OpenCL интерфейсов. Зачастую штатные драйвера в комплектах с компьютером идут или без поддержки OpenCL или настолько старые, что содержат в себе критические ошибки реализации OpenCL/CUDA библиотек. Все это обычно лечится установкой последних драйверов с сайта производителя.

 
Renat:
Ренат, вам бы сейчас статейку запилить -- как пользоваться, особенности, где дрова брать и т.п.
 
Renat:

Мы ведем работу над нативной поддержкой OpenCL прямо в MQL5. Через пару билдов будет доступно публично.

Это означает, что к метатестеру можно подключать "видео" агентов? Opencl будет, по возможности, использоваться во всех/большинстве экспертов либо только в тех, которые будут написаны ("заточены") под использование видеокарт?
 
Renat:

Отличная новость! Спасибо.

TheXpert:
Ренат, вам бы сейчас статейку запилить -- как пользоваться, особенности, где дрова брать и т.п.

Да, статься необходима.

 
TheXpert:
Ренат, вам бы сейчас статейку запилить -- как пользоваться, особенности, где дрова брать и т.п.

По OpenCL уже много материалов в сети.

Можно начать отсюда:

Все OpenCL функции используются один в один на MQL5, так что не будет проблем с переносом описаний из других статей на почву MQL5.

 
joo:

Да, статься необходима.

Да, мы постараемся расписать использование OpenCL как в документации, так и в статьях.
 
WChas:
Это означает, что к метатестеру можно подключать "видео" агентов? Opencl будет, по возможности, использоваться во всех/большинстве экспертов либо только в тех, которые будут написаны ("заточены") под использование видеокарт?

Да, можно будет подключать - именно на это и нацеленность.

Если OpenCL устройств не будет на агенте, то автоматически будет работать софтверная реализация.

 
Готов предоставить свою Radeon 6930, если она будет выгоднее работать чем на криптовалюте. 2-3 у.е в день меня устроят на ней. Если она будет также простаивать как и процессоры Core i5 i7, имхо не интересно
Причина обращения: