OpenCL: internal implementation tests in MQL5

 

We are working on native OpenCL support directly in MQL5. In a couple of builds it will be available publicly.

Here is a small working example of calculation of the Mandelbrot fractal in OpenCL which dramatically speeds up calculations as compared to the software implementation. The calculation in OpenCL is 100 times faster.


//+------------------------------------------------------------------+
//|                                                     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.001 f;
      x1-=0.001 f;
      y0+=0.001 f;
      y1-=0.001 f;
     }
//--- удаляем объекты 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:

We are working on native OpenCL support directly in MQL5. In a couple of builds it will be available publicly.

Here is a small working example of calculation of the Mandelbrot fractal in OpenCL which dramatically speeds up calculations as compared to the software implementation. The calculation in OpenCL is 100 times faster.

To be able to run the script on your own, the library with functions must be included: CLContextCreate, CLProgramCreate, CLKernelCreate, CLBufferCreate, etc. What is this library and where can I get it?

 
tol64:

In order to run the script, you need to include a library with functions: CLContextCreate, CLProgramCreate, CLKernelCreate, CLBufferCreate, etc. What is this library and where can I get it?

In the OpenCL folder ... In a couple of builds ... :)
 
tol64:

In order to run the script, you need to include a library with functions: CLContextCreate, CLProgramCreate, CLKernelCreate, CLBufferCreate, etc. What is this library and where can I get it?

You do not need any libraries; OpenCL support in MQL5 is now native.

There are no additional DLL files in the terminal. Upon loading, the terminal detects the presence of OpenCL interfaces on the system (they are added by the video card driver). All video card manufacturers (NVIDIA, AMD, Intel) that provide OpenCL are supported.

It is important that video card drivers be up-to-date with OpenCL interfaces support enabled. Often, bundled drivers with computers either do not have OpenCL support or are so old that they contain critical errors in the implementation of OpenCL/CUDA libraries. This can usually be remedied by installing the latest drivers from the manufacturer's website.

 
Renat:
Renat, you should write an article now - how to use, features, where to get the wood, etc.
 
Renat:

We are working on native OpenCL support directly in MQL5. It will be available publicly in a couple of builds.

Does this mean that "video" agents can be connected to the meta tester? Opencl will, if possible, be used in all/most EAs or only in those which will be written ("ground up") to use video cards?
 
Renat:

That's great news! Thank you.

TheXpert:
Renat, you should write an article now - how to use, features, where to get the hardware, etc.

Yes, an article is needed.

 
TheXpert:
Renat, you should just write an article on how to use it, what is special about it, where to get the drivers and so on.

There are already a lot of materials on OpenCL on the web.

You can start from here:

All OpenCL functions are used equally in MQL5, so it won't be a problem to transfer descriptions from other articles to MQL5 soil.

 
joo:

Yes, the article is necessary.

Yes, we will try to cover the use of OpenCL both in the documentation and in the articles.
 
WChas:
Does this mean that "video" agents can be connected to the metatester? Will Opencl, if possible, be used in all/most EAs, or only in those which will be written ("ground up") to use video cards?

Yes, it will be possible to plug in - that is the intention.

If OpenCL devices will not be on the agent, the software implementation will automatically work.

 
I'm willing to provide my Radeon 6930 if it's more profitable than cryptocurrency. 2-3 c.u. a day would suit me fine on it. If it will be as idle as a Core i5 i7 processor, imho not interested
Reason: