OpenCL: testes internos de implementação em MQL5

 

Estamos a trabalhar no suporte nativo OpenCL directamente na MQL5. Num par de construções estará disponível ao público.

Eis um pequeno exemplo de trabalho de cálculo do Mandelbrot fractal em OpenCL que acelera drasticamente os cálculos em comparação com a implementação do software. O cálculo em OpenCL é 100 vezes mais 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 a trabalhar no suporte nativo OpenCL directamente na MQL5. Num par de construções estará disponível ao público.

Eis um pequeno exemplo de trabalho de cálculo do Mandelbrot fractal em OpenCL que acelera drasticamente os cálculos em comparação com a implementação do software. O cálculo em OpenCL é 100 vezes mais rápido.

Para poder executar o guião por si próprio, a biblioteca com funções deve ser incluída: CLContextCreate, CLProgramCreate, CLKernelCreate, CLBufferCreate, etc. O que é esta biblioteca e onde a posso obter?

 
tol64:

Para executar o guião, é necessário incluir uma biblioteca com funções: CLContextCreate, CLProgramCreate, CLKernelCreate, CLBufferCreate, etc. O que é esta biblioteca e onde a posso obter?

Na pasta do OpenCL ... Num par de construções ... :)
 
tol64:

Para executar o guião, é necessário incluir uma biblioteca com funções: CLContextCreate, CLProgramCreate, CLKernelCreate, CLBufferCreate, etc. O que é esta biblioteca e onde a posso obter?

Não precisa de bibliotecas; o suporte OpenCL em MQL5 é agora nativo.

Não existem ficheiros DLL adicionais no terminal. Ao carregar, o terminal detecta a presença de interfaces OpenCL no sistema (elas são adicionadas pelo condutor da placa de vídeo). Todos os fabricantes de placas de vídeo (NVIDIA, AMD, Intel) que fornecem OpenCL são suportados.

É importante que os controladores de placas de vídeo estejam actualizados com o suporte de interfaces OpenCL activado. Muitas vezes, os controladores agrupados com computadores ou não têm suporte OpenCL ou são tão antigos que contêm erros críticos na implementação de bibliotecas OpenCL/CUDA. Isto pode normalmente ser remediado instalando os últimos condutores do website do fabricante.

 
Renat:
Renat, deve escrever agora um artigo - como usar, características, onde obter a madeira, etc.
 
Renat:

Estamos a trabalhar no suporte nativo OpenCL directamente na MQL5. Estará disponível publicamente num par de construções.

Isto significa que os agentes "vídeo" podem ser ligados ao meta-ensaio? Opencl será, se possível, utilizado em todas/mais EAs ou apenas naquelas que serão escritas ("ground up") para utilizar placas de vídeo?
 
Renat:

Isso são óptimas notícias! Obrigado.

TheXpert:
Renat, deve escrever agora um artigo - como usar, características, onde obter o hardware, etc.

Sim, é necessário um artigo.

 
TheXpert:
Renat, deve apenas escrever um artigo sobre como utilizá-lo, o que tem de especial, onde obter os condutores e assim por diante.

Já existem muitos materiais sobre OpenCL na web.

Pode começar a partir daqui:

Todas as funções OpenCL são utilizadas igualmente na MQL5, pelo que não será um problema transferir descrições de outros artigos para o solo MQL5.

 
joo:

Sim, o artigo é necessário.

Sim, tentaremos cobrir a utilização do OpenCL tanto na documentação como nos artigos.
 
WChas:
Isto significa que os agentes "vídeo" podem ser ligados ao metatenuador? A Opencl, se possível, será utilizada em todos os EAs/mais EAs, ou apenas naqueles que serão escritos ("ground up") para utilizar placas de vídeo?

Sim, será possível ligar a ficha - é essa a intenção.

Se os dispositivos OpenCL não estiverem no agente, a implementação do software funcionará automaticamente.

 
Estou disposto a fornecer o meu Radeon 6930 se ele for mais rentável do que a moeda criptográfica. 2-3 c.u. um dia serviria perfeitamente para mim. Se for tão ocioso como um processador Core i5 i7, imho não estou interessado