OpenCL:MQL5での内部実装テスト

 

MQL5で直接OpenCLの ネイティブサポートに 取り組んでいます。数回のビルドで一般に公開される予定です。

ここでは、OpenCLによるマンデルブロフラクタル計算の小さな実用例を紹介します。この計算では、ソフトウェア実装に比べて計算が劇的に高速化されます。OpenCLでの計算が100倍速くなる。


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

MQL5で直接OpenCLのネイティブサポートに取り組んでいます。数回のビルドで一般に公開される予定です。

ここでは、OpenCLによるマンデルブロフラクタル計算の小さな実用例を紹介します。この計算では、ソフトウェア実装に比べて計算が劇的に高速化されます。OpenCLでの計算が100倍速くなる。

スクリプトを自分で実行できるようにするためには、関数を含むライブラリが必要です。CLContextCreateCLProgramCreateCLKernelCreateCLBufferCreate など。このライブラリーは何ですか、どこで手に入りますか?

 
tol64:

スクリプトを実行するためには、関数を含むライブラリが必要です。CLContextCreateCLProgramCreateCLKernelCreateCLBufferCreate など。このライブラリーは何ですか、どこで手に入りますか?

OpenCL フォルダに ...数回のビルドで・・・。:)
 
tol64:

スクリプトを実行するためには、関数を含むライブラリが必要です。CLContextCreateCLProgramCreateCLKernelCreateCLBufferCreate など。このライブラリーは何ですか、どこで手に入りますか?

ライブラリは不要で、MQL5でのOpenCLサポートはネイティブになりました。

ターミナルには、追加のDLLファイルはありません。ロード時に、端末はシステム上のOpenCLインターフェイスの存在を検出します(それらはビデオカードドライバーによって追加されます)。OpenCLを提供するすべてのビデオカードメーカー(NVIDIA、AMD、Intel)に対応しています。

ビデオカードのドライバーは、OpenCLインターフェースのサポートが有効になっている最新のものを使用することが重要です。コンピュータに付属する通常のドライバは、OpenCLをサポートしていないか、非常に古いもので、OpenCL/CUDAライブラリの実装に重大なエラーが 含まれていることがよくあるのです。これは通常、メーカーのウェブサイトから最新のドライバをインストールすることで改善されます。

 
Renat:
レナート、今すぐ記事を書けよ - 使い方、特徴、木材の入手先など。
 
Renat:

MQL5で直接OpenCLのネイティブサポートに取り組んでいます。数回のビルドで一般に公開される予定です。

メタテスターに「ビデオ」エージェントが接続できるということでしょうか。Openclは、可能であれば、すべて/ほとんどのEAで使用されるのでしょうか、それとも、ビデオカードを使用するように書かれた(「グランドアップ」)ものだけに使用されるのでしょうか?
 
Renat:

それは素晴らしいニュースですね。ありがとうございます。

TheXpert です。
レナート 今すぐ記事を書いてください - 使い方、特徴、ハードの入手先など。

そうです、記事が必要なのです。

 
TheXpert:
レナートさん、使い方はもちろん、何が特別なのか、ドライバはどこで手に入るのか、などなど、とにかく記事を書いてください。

OpenCLについては、すでにWeb上で多くの資料が公開されています。

ここからスタートすることができます。

MQL5では全てのOpenCL関数が同等に使用されますので、他の記事からMQL5の土壌に記述を移すことは問題ありません。

 
joo:

そう、記事は必要なのです。

はい、ドキュメントと記事の両方でOpenCLの利用を カバーするようにします。
 
WChas:
ビデオ」エージェントがメーテーターに接続できるということでしょうか。Openclは、可能であれば、すべての/ほとんどのEAで使用されるのでしょうか、それとも、ビデオカードを使用するように書かれた(「グランドアップ」)ものだけで使用されるのでしょうか?

そうですね、プラグインが可能になる--そのつもりです。

OpenCLデバイスがエージェント上にない場合、ソフトウェア実装が自動的に動作します。

 
暗号通貨より儲かるなら、私のRadeon 6930を提供してもいいんだけど。1日2~3c.u.なら、それで十分だと思います。Core i5 i7 プロセッサのようにアイドル状態になるのであれば、興味はない。
理由: