OpenCL: interne Implementierungstests in MQL5

 

Wir arbeiten an nativer OpenCL-Unterstützung direkt in MQL5. In ein paar Jahren wird sie öffentlich zugänglich sein.

Hier ist ein kleines Arbeitsbeispiel für die Berechnung des Mandelbrot-Fraktals in OpenCL, das die Berechnungen im Vergleich zur Software-Implementierung drastisch beschleunigt. Die Berechnung in OpenCL ist 100 Mal schneller.


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

Wir arbeiten an nativer OpenCL-Unterstützung direkt in MQL5. In ein paar Jahren wird sie öffentlich zugänglich sein.

Hier ist ein kleines Arbeitsbeispiel für die Berechnung des Mandelbrot-Fraktals in OpenCL, das die Berechnungen im Vergleich zur Software-Implementierung drastisch beschleunigt. Die Berechnung in OpenCL ist 100 Mal schneller.

Um das Skript selbst ausführen zu können, muss die Bibliothek mit den Funktionen enthalten sein: CLContextCreate, CLProgramCreate, CLKernelCreate, CLBufferCreate, usw. Was ist diese Bibliothek und wo kann ich sie bekommen?

 
tol64:

Um das Skript ausführen zu können, müssen Sie eine Bibliothek mit Funktionen einbinden: CLContextCreate, CLProgramCreate, CLKernelCreate, CLBufferCreate, usw. Was ist diese Bibliothek und wo kann ich sie bekommen?

Im Ordner OpenCL ... In einer Reihe von Builds ... :)
 
tol64:

Um das Skript ausführen zu können, müssen Sie eine Bibliothek mit Funktionen einbinden: CLContextCreate, CLProgramCreate, CLKernelCreate, CLBufferCreate, usw. Was ist diese Bibliothek und wo kann ich sie bekommen?

Sie benötigen keine Bibliotheken; die OpenCL-Unterstützung in MQL5 ist jetzt nativ.

Im Terminal sind keine zusätzlichen DLL-Dateien vorhanden. Beim Laden erkennt das Terminal das Vorhandensein von OpenCL-Schnittstellen auf dem System (sie werden vom Grafikkartentreiber hinzugefügt). Alle Grafikkartenhersteller (NVIDIA, AMD, Intel), die OpenCL anbieten, werden unterstützt.

Es ist wichtig, dass die Grafikkartentreiber auf dem neuesten Stand sind und die OpenCL-Schnittstellen unterstützen. Häufig verfügen die mit den Computern gebündelten Treiber entweder nicht über OpenCL-Unterstützung oder sind so alt, dass sie kritische Fehler bei der Implementierung von OpenCL/CUDA-Bibliotheken enthalten. Dies kann in der Regel durch die Installation der neuesten Treiber von der Website des Herstellers behoben werden.

 
Renat:
Renat, du solltest jetzt einen Artikel schreiben - wie man es benutzt, welche Eigenschaften es hat, wo man das Holz bekommt, usw.
 
Renat:

Wir arbeiten an nativer OpenCL-Unterstützung direkt in MQL5. Sie wird in ein paar Jahren öffentlich verfügbar sein.

Bedeutet dies, dass "Video"-Agenten mit dem Meta-Tester verbunden werden können? Wird Opencl, wenn möglich, in allen/den meisten EAs verwendet oder nur in denen, die von Grund auf für die Verwendung von Grafikkarten geschrieben werden?
 
Renat:

Das ist eine großartige Nachricht! Ich danke Ihnen.

TheXpert:
Renat, du solltest jetzt einen Artikel schreiben - wie man es benutzt, welche Funktionen es hat, wo man die Hardware bekommt, usw.

Ja, ein Artikel ist erforderlich.

 
TheXpert:
Renat, du solltest einfach einen Artikel darüber schreiben, wie man ihn benutzt, was das Besondere an ihm ist, wo man die Treiber bekommt und so weiter.

Es gibt bereits eine Menge Material über OpenCL im Internet.

Sie können von hier aus starten:

Alle OpenCL-Funktionen werden in MQL5 gleichermaßen verwendet, so dass es kein Problem sein wird, Beschreibungen aus anderen Artikeln auf MQL5-Boden zu übertragen.

 
joo:

Ja, der Artikel ist notwendig.

Ja, wir werden versuchen, die Verwendung von OpenCL sowohl in der Dokumentation als auch in den Artikeln zu behandeln.
 
WChas:
Bedeutet dies, dass "Video"-Agenten mit dem Metatester verbunden werden können? Wird Opencl, wenn möglich, in allen/den meisten EAs verwendet, oder nur in denen, die von Grund auf für die Verwendung von Grafikkarten geschrieben werden?

Ja, es wird möglich sein, sich anzuschließen - das ist die Absicht.

Wenn keine OpenCL-Geräte auf dem Agenten vorhanden sind, funktioniert die Software-Implementierung automatisch.

 
Ich bin bereit, mein Radeon 6930 zur Verfügung zu stellen, wenn es profitabler ist als Kryptowährung. 2-3 c.u. pro Tag würden mir gut passen. Wenn es so träge wie Core i5 i7 Prozessoren sein wird, imho nicht interessiert