Многопоточность в МТ5 - страница 4

 
Graff:
технология распараллеливания работает, дает результаты - значит нужно ее использовать.

У Вас в гараже 3 автомобиля. Вы один. Сможете одновременно управлять тремя автомобилями?

 
Graff:
технология распараллеливания работает, дает результаты - значит нужно ее использовать.

К сожалению, она не работает в общем виде для универсальных (99% всех обычных) задач.

Насколько я вижу вокруг (мне эта тема давно интересна), все GPU тесты строятся на узкоспециализированных задачах, чтобы поразить публику. Я не уверен, что даже через пару поколений GPU получится конкурировать с CPU в универсальных задачах. Слишком разная у них идеология.

 
AlexSTAL:

У Вас в гараже 3 автомобиля. Вы один. Сможете одновременно управлять тремя автомобилями?

Ваше сравнение не применимо. Не хотите - не используйте. Если кто-то может - значит и у других есть возможность. 
 
Graff:
Ваше сравнение не применимо. Не хотите - не используйте. Если кто-то может - значит и у других есть возможность. 

Так и нужно было Вам в исходном посте писать об этом...

 
Renat:

К сожалению, она не работает в общем виде для универсальных (99% всех обычных) задач.

Насколько я вижу вокруг (мне эта тема давно интересна), все GPU тесты строятся на узкоспециализированных задачах, чтобы поразить публику. Я не уверен, что даже через пару поколений GPU получится конкурировать с CPU в универсальных задачах. Слишком разная у них идеология.

Технология новая, в процессе развития, перспективная. Я не говорю переписывать весть МТ5 с использованием ОпенЦЛ, было бы не плохо переписать хотябы самую простую часть и содействовать разрабочикам в написании кода на МКЛ5 с использованием ОпенЦЛ.

Кусочек кода от автора:

   __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"
"            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"
"   }//--------------------------------------------   \r\n"

 

   int calcOCL() {
      ulong startTime = GetTickCount();
      CL_STATUS status;
      cl_mem data_buf;
      data_buf = ctx.CreateBuffer(CL_MEM_ALLOC_HOST_PTR,CL_MEM_READ_WRITE,m_SizeX*m_SizeY,FLOAT,status);
      if (status!=CL_SUCCESS) {
         Alert("CreateBuffer: ", EnumToString(status));
         return (-1);
      }
      float x0 = -2;
      float y0 = -0.5;
      float x1 = -1;
      float y1 =  0.5;
      uint  max = iterations;
      
      
      kernel.SetArg(0,x0);
      kernel.SetArg(1,y0);
      kernel.SetArg(2,x1);
      kernel.SetArg(3,y1);
      kernel.SetArg(4,max);
      kernel.SetArg(5,data_buf);
      
      uint offset[2] =  {0,0};
      uint work  [2];  work[0]= m_SizeX; work[1]= m_SizeY;
      uint group [2];  group [0] = wgs; group [1] = 1; 
      
      status = queue.NDRange(kernel, 2, offset, work, group);
      oclFlush(queue);
      
      for (int y=0;y<m_SizeY;y++) {
         status = queue.ReadBuffer(data_buf,true,y*m_SizeX,m_SizeX,Line[y].Pixel);
         if (status!=CL_SUCCESS) {
            Alert("ReadBuffer: ", EnumToString(status));
            break;
         }
      }
      oclFinish(queue);
      
      data_buf.Release();
      queue.Release();
      uint endTime = GetTickCount();
      return (int)(endTime-startTime);
   }
   
   uint calcMQL() {
      uint startTime = GetTickCount();
      float x0 = -2;
      float y0 = -0.5;
      float x1 = -1;
      float y1 =  0.5;
      uint  max = iterations;
      uint  w = m_SizeX;
      uint  h = m_SizeY;
      
      for (uint gy =0;gy<h;gy++) {
         for (uint gx =0;gx<w;gx++) {
            float dx = x0 + gx * (x1-x0) / w;
            float dy = y0 + gy * (y1-y0) / h;

            float x  = 0;
            float y  = 0;
            float xx = 0;
            float yy = 0;
            float xy = 0;
            uint i = 0;
            while ((xx+yy)<4 && i<max) {
               xx = x*x;
               yy = y*y;
               xy = x*y;
               y = xy+xy+dy;
               x = xx-yy+dx;
               i++;
            }

            if (i == max) {
               Line[gy].Pixel[gx]=0;
            } else {
               Line[gy].Pixel[gx] = (int) (((float)i/max)*0xFFFFFF);
                 }
         }
      }
      uint endTime = GetTickCount();
      return (int)(endTime-startTime);
   }
};

 

 

Я быстренько набросал код с выводом в BMP файл. Убрал "классовую" работу с битмапом, заменив на простой массив.

Вот что получилось:

//+------------------------------------------------------------------+
//|                                                   Mandelbrot.mq5 |
//|                        Copyright 2010, MetaQuotes Software Corp. |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2010, MetaQuotes Software Corp."
#property link      "http://www.mql5.com"
#property version   "1.00"
#property script_show_inputs

input uint ExtWidth     =512;
input uint ExtHeight    =512;
input uint ExtIterations=20000;

//+------------------------------------------------------------------+
//| Заголовок 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[],uint width,uint height)
  {
//--- откроем файл
   int file=FileOpen(filename,FILE_WRITE|FILE_BIN);
   if(file==INVALID_HANDLE)
     {
      Print(__FUNCTION__," error opening '",filename,"'");
      return(false);
     }
//--- подготовим заголовок
   BitmapHeader info;

   ZeroMemory(info);
   info.type          =0x4d42;
   info.size          =sizeof(info)+width*height*4;
   info.offbits       =sizeof(info);

   info.imgSSize      =40;
   info.imgWidth      =width;
   info.imgHeight     =height;
   info.imgPlanes     =1;
   info.imgBitCount   =32;
   info.imgCompression=0;                // BI_RGB
   info.imgSizeImage  =width*height*4;
//--- запишем заголовок и само тело
   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);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
uint calcMQL(uint &bitmap[],uint w,uint h,uint max)
  {
   uint  startTime=GetTickCount();
   float x0 = -2;
   float y0 = -0.5;
   float x1 = -1;
   float y1 =  0.5;

   uint  scanline=0;
//---
   for(uint gy=0;gy<h;gy++)
     {
      for(uint gx=0;gx<w;gx++)
        {
         float dx = x0 + gx * (x1-x0) / w;
         float dy = y0 + gy * (y1-y0) / h;

         float x  = 0;
         float y  = 0;
         float xx = 0;
         float yy = 0;
         float xy = 0;
         uint  i=0;
         
         while((xx+yy)<4 && i<max)
           {
            xx = x*x;
            yy = y*y;
            xy = x*y;
            y  = xy+xy+dy;
            x  = xx-yy+dx;
            i++;
           }

         if(i==max)
           {
            //Line[gy].Pixel[gx]=0;
            bitmap[scanline]=0;
           }
         else
           {
            //Line[gy].Pixel[gx]=(int)(((float)i/max)*0xFFFFFF);
            bitmap[scanline]=(int)(((float)i/max)*0xFFFFFF);
           }
         scanline++;
        }
     }
//---
   return(GetTickCount()-startTime);
  }
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
   int bitmap[];
//--- распределим массив
   ArrayResize(bitmap,ExtWidth*ExtWidth,0);
//--- расчитаем фрактал
   uint res=calcMQL(bitmap,ExtWidth,ExtHeight,ExtIterations);
   Print("Time: ",res," ms");
//--- запишем на диск BMP файл
   SaveBitmapToFile("Mandelbrot.bmp",bitmap,ExtWidth,ExtHeight);
//---
  }
//+------------------------------------------------------------------+

Файл mandelbrot.bmp кладется в /Files.


На моем Intel Xeon X5680 3.33GHz строит картинку за 7863 ms.


95% всего времени отрисовка проводит в цикле прокрутки итераций (20 000):

         while((xx+yy)<4 && i<max)
           {
            xx = x*x;
            yy = y*y;
            xy = x*y;
            y  = xy+xy+dy;
            x  = xx-yy+dx;
            i++;
           }
Фактически задача сводится к максимально быстрой математике.


Файлы:
 

Причем после перевода всех float в double, получилось ожидаемое ускорение - время расчета 5491 ms вместо 7863 ms на float.

Код приложен.

Файлы:
 
Renat:

Причем после перевода всех float в double, получилось ожидаемое ускорение - время расчета 5491 ms вместо 7863 ms на float.

Код приложен.

На моем выдало 2011.06.05 18:36:37 Mandelbrot_double (EURUSD,M5) Time: 6427 ms
 
Renat:

На моем Intel Xeon X5680 3.33GHz строит картинку за 7863 ms.
95% всего времени отрисовка проводит в цикле прокрутки итераций (20 000):

Фактически задача сводится к максимально быстрой математике.

На моей видеокарте, которую уже несколько лет не выпускают тест быстрее выполняется в 5 с лишним раз, а стоит она.... ничего она не стоит уже.
 
joo:
На моей видеокарте, которую уже несколько лет не выпускают тест быстрее выполняется в 5 с лишним раз, а стоит она.... ничего она не стоит уже.

Я думаю, что скоро автор выложит свои наработки в публичный доступ вместе со статьей. Это даст возможность любому разработчику подключать CUDA/OpenCL расчеты в свои программы.

Со своей стороны мы будем и дальше работать над ускорением базового MQL5 кода.

Причина обращения: