OpenCL : tests de l'implémentation interne dans MQL5

 

Nous travaillons sur le support natif d'OpenCL directement dans MQL5. Dans quelques versions, il sera disponible publiquement.

Voici un petit exemple de calcul de la fractale de Mandelbrot en OpenCL qui accélère considérablement les calculs par rapport à l'implémentation logicielle. Le calcul en OpenCL est 100 fois plus rapide.


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

Nous travaillons sur le support natif d'OpenCL directement dans MQL5. Dans quelques versions, il sera disponible publiquement.

Voici un petit exemple de calcul de la fractale de Mandelbrot en OpenCL qui accélère considérablement les calculs par rapport à l'implémentation logicielle. Le calcul en OpenCL est 100 fois plus rapide.

Pour pouvoir exécuter le script par vous-même, la bibliothèque de fonctions doit être incluse : CLContextCreate, CLProgramCreate, CLKernelCreate, CLBufferCreate, etc. Qu'est-ce que cette bibliothèque et où puis-je l'obtenir ?

 
tol64:

Afin d'exécuter le script, vous devez inclure une bibliothèque avec des fonctions : CLContextCreate, CLProgramCreate, CLKernelCreate, CLBufferCreate, etc. Qu'est-ce que cette bibliothèque et où puis-je l'obtenir ?

Dans le dossier OpenCL ... Dans un couple de constructions ... :)
 
tol64:

Afin d'exécuter le script, vous devez inclure une bibliothèque avec des fonctions : CLContextCreate, CLProgramCreate, CLKernelCreate, CLBufferCreate, etc. Qu'est-ce que cette bibliothèque et où puis-je l'obtenir ?

Vous n'avez besoin d'aucune bibliothèque ; la prise en charge d'OpenCL dans MQL5 est désormais native.

Il n'y a pas de fichiers DLL supplémentaires dans le terminal. Au chargement, le terminal détecte la présence d'interfaces OpenCL sur le système (elles sont ajoutées par le pilote de la carte vidéo). Tous les fabricants de cartes vidéo (NVIDIA, AMD, Intel) qui fournissent OpenCL sont pris en charge.

Il est important que les pilotes de cartes vidéo soient à jour et que le support des interfaces OpenCL soit activé. Souvent, les pilotes ordinaires fournis avec l'ordinateur ne prennent pas en charge OpenCL ou sont si anciens qu'ils contiennent des erreurs critiques dans la mise en œuvre des bibliothèques OpenCL/CUDA. Il est généralement possible de remédier à ce problème en installant les derniers pilotes depuis le site Web du fabricant.

 
Renat:
Renat, vous devriez écrire un article maintenant - comment utiliser, les caractéristiques, où trouver le bois, etc.
 
Renat:

Nous travaillons sur le support natif d'OpenCL directement dans MQL5. Il sera disponible publiquement dans quelques builds.

Cela signifie-t-il que les agents "vidéo" peuvent être connectés au meta tester ? Opencl sera-t-il, si possible, utilisé dans tous/la plupart des EA ou seulement dans ceux qui seront écrits ("ground up") pour utiliser les cartes vidéo ?
 
Renat:

C'est une excellente nouvelle ! Merci.

LeXpert:
Renat, vous devriez écrire un article maintenant - comment utiliser, les caractéristiques, où obtenir le matériel, etc.

Oui, un article est nécessaire.

 
TheXpert:
Renat, vous devriez simplement écrire un article sur la façon de l'utiliser, ce qu'il a de spécial, où trouver les pilotes et ainsi de suite.

Il y a déjà beaucoup de matériel sur OpenCL sur le web.

Vous pouvez commencer par là :

Toutes les fonctions OpenCL sont utilisées de la même manière dans MQL5, il ne sera donc pas difficile de transférer les descriptions d'autres articles vers le sol de MQL5.

 
joo:

Oui, l'article est nécessaire.

Oui, nous essaierons de couvrir l'utilisation d'OpenCL à la fois dans la documentation et dans les articles.
 
WChas:
Cela signifie-t-il que les agents "vidéo" peuvent être connectés au metatester ? Opencl sera-t-il, si possible, utilisé dans tous/la plupart des EA, ou seulement dans ceux qui seront écrits ("ground up") pour utiliser les cartes vidéo ?

Oui, il sera possible de se brancher - c'est l'intention.

Si les dispositifs OpenCL ne sont pas présents sur l'agent, l'implémentation logicielle fonctionnera automatiquement.

 
Je suis prêt à fournir ma Radeon 6930 si c'est plus rentable que les crypto-monnaies. 2-3 c.u. par jour me conviendraient parfaitement. S'il sera aussi inactif que les processeurs Core i5 i7, je ne suis pas intéressé.