OpenCL: pruebas de implementación interna en MQL5

 

Estamos trabajando en el soporte nativo de OpenCL directamente en MQL5. En un par de construcciones estará disponible públicamente.

A continuación se muestra un pequeño ejemplo de cálculo del fractal de Mandelbrot en OpenCL que acelera drásticamente los cálculos en comparación con la implementación de software. El cálculo en OpenCL es 100 veces más rápido.


//+------------------------------------------------------------------+
//|                                                     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:

Estamos trabajando en el soporte nativo de OpenCL directamente en MQL5. En un par de construcciones estará disponible públicamente.

A continuación se muestra un pequeño ejemplo de trabajo de cálculo del fractal de Mandelbrot en OpenCL que acelera drásticamente los cálculos en comparación con la implementación de software. El cálculo en OpenCL es 100 veces más rápido.

Para poder ejecutar el script por su cuenta, es necesario incluir la biblioteca con las funciones: CLContextCreate, CLProgramCreate, CLKernelCreate, CLBufferCreate, etc. ¿Qué es esta biblioteca y dónde puedo conseguirla?

 
tol64:

Para ejecutar el script, es necesario incluir una biblioteca con funciones: CLContextCreate, CLProgramCreate, CLKernelCreate, CLBufferCreate, etc. ¿Qué es esta biblioteca y dónde puedo conseguirla?

En la carpeta OpenCL... En un par de construcciones ... :)
 
tol64:

Para ejecutar el script, es necesario incluir una biblioteca con funciones: CLContextCreate, CLProgramCreate, CLKernelCreate, CLBufferCreate, etc. ¿Qué es esta biblioteca y dónde puedo conseguirla?

No necesitas ninguna librería; el soporte de OpenCL en MQL5 es ahora nativo.

No hay archivos DLL adicionales en el terminal. Al cargarse, el terminal detecta la presencia de interfaces OpenCL en el sistema (las añade el controlador de la tarjeta de vídeo). Todos los fabricantes de tarjetas de vídeo (NVIDIA, AMD, Intel) que proporcionan OpenCL son compatibles.

Es importante que los controladores de la tarjeta de vídeo estén actualizados con el soporte de las interfaces OpenCL activado. A menudo, los controladores habituales que vienen con el ordenador no tienen soporte para OpenCL o son tan antiguos que contienen errores críticos en la implementación de las bibliotecas OpenCL/CUDA. Por lo general, esto se puede remediar instalando los últimos controladores desde el sitio web del fabricante.

 
Renat:
Renat, deberías escribir un artículo ahora - cómo usar, características, dónde conseguir la madera, etc.
 
Renat:

Estamos trabajando en el soporte nativo de OpenCL directamente en MQL5. Estará disponible públicamente en un par de construcciones.

¿Significa esto que los agentes de "vídeo" pueden conectarse al meta tester? ¿Opencl se utilizará, si es posible, en todos o la mayoría de los EAs o sólo en aquellos que se escriban ("ground up") para utilizar tarjetas de vídeo?
 
Renat:

¡Es una gran noticia! Gracias.

TheXpert:
Renat, deberías escribir un artículo ahora - cómo usar, características, dónde conseguir el hardware, etc.

Sí, se necesita un artículo.

 
TheXpert:
Renat, deberías escribir un artículo sobre cómo usarlo, qué tiene de especial, dónde conseguir los drivers, etc.

Ya hay mucho material sobre OpenCL en la web.

Puedes empezar desde aquí:

Todas las funciones OpenCL se utilizan por igual en MQL5, por lo que no será un problema transferir las descripciones de otros artículos al suelo de MQL5.

 
joo:

Sí, el artículo es necesario.

Sí, intentaremos cubrir el uso de OpenCL tanto en la documentación como en los artículos.
 
WChas:
¿Significa esto que los agentes de "vídeo" pueden conectarse al metatester? ¿Se utilizará Opencl, si es posible, en todos o en la mayoría de los EA, o sólo en los que se escriban ("desde cero") para utilizar tarjetas de vídeo?

Sí, se podrá conectar, esa es la intención.

Si los dispositivos OpenCL no están en el agente, la implementación de software funcionará automáticamente.

 
Estoy dispuesto a proporcionar mi Radeon 6930 si es más rentable que la criptomoneda. 2-3 c.u. al día me vendrían bien. Si va a ser tan inactivo como los procesadores Core i5 i7, imho no está interesado