Используете ли вы возможности OpenCL для ускорения расчетов? (и обсуждение применения в торговле) - страница 4

 
Alexey Oreshkin:

Это просто нож в сердце. Никогда не рассматривал видео от  АМД:( Буду думать что делать.

Это реальность для тех, кто считает в double, а не играется в разламывание целочисленных хешей или отработку 4х байтовых блоков картинок.

Плюс осознанный саботаж со стороны NVidia, которая продвигает исключительно свою CUDA в надежде победить. Прям вырезает любые упоминания OpenCL из рекламы и спецификаций своих карт.

Только в 2017 году под напором постоянных запросов "почему не выпускаете OpenCL 2.0?" начали говорить про "будем выпускать OpenCL 2.0 в бета версии".
 
 
Nikolai Semko:


Привет, Николай!

Я думаю, что OpenCL - это большой задел на будущее. Его наиглавнейшее применение - графика. Учитывая мощность которую можно будет получить - это будет трехмерная графика. Визуализация рыночных процессов.

Нужно уже сейчас браться за разработку. В будущем, окупится с лихвой.

 
Renat Fatkhullin:

Это реальность для тех, кто считает в double, а не играется в разламывание целочисленных хешей или отработку 4х байтовых блоков картинок.

Плюс осознанный саботаж со стороны NVidia, которая продвигает исключительно свою CUDA в надежде победить. Прям вырезает любые упоминания OpenCL из рекламы и спецификаций своих карт.

Только в 2017 году под напором постоянных запросов "почему не выпускаете OpenCL 2.0?" начали говорить про "будем выпускать OpenCL 2.0 в бета версии".
ок. благодарю.
Получается что и карты от nvidia - TESLA - тоже не есть хороший выбор ?
 
Alexey Oreshkin:
ок. благодарю.
Получается что и карты от nvidia - TESLA - тоже не есть хороший выбор ?

Еще раз детальнее:

  1. NVidia хочет закопать OpenCL и саботирует его
  2. NVidia до последнего не хочет запускать OpenCL 2.0, чтобы не создавать конкурента постоянно развивающемуся CUDA
  3. NVidia в ритейл секторе игровых карт зарезала double производительность, сконцентрировавшись на float.
  4. NVidia в рамках повышения доходности придумала нишу "профессиональных вычислений", где пытается в разы дороже продавать свои Теслы
  5. AMD наоборот не резала double и в их картах они работают быстро и задешево

Мои тесты тесл и зоопарка NVidia карт показывают, что скорость в финасовых мат вычислениях AMD лучше всего. А NVidia ведет себя отвратительно по отношению к своим пользователеям. Как конкретный потребитель, смысла в "профессиональных" решениях от NVidia не вижу вообще.

Про "ну достаточно финансовую математику перевести в инты и потом все залетает и на нвидии" рассказывать не надо.

 
Renat Fatkhullin:

Еще раз детальнее:

  1. NVidia хочет закопать OpenCL и саботирует его
  2. NVidia до последнего не хочет запускать OpenCL 2.0, чтобы не создавать конкурента постоянно развивающемуся CUDA
  3. NVidia в ритейл секторе игровых карт зарезала double производительность, сконцентрировавшись на float.
  4. NVidia в рамках повышения доходности придумала нишу "профессиональных вычислений", где пытается в разы дороже продавать свои Теслы
  5. AMD наоборот не резала double и в их картах они работают быстро и задешево

Мои тесты тесл и зоопарка NVidia карт показывают, что скорость в финасовых мат вычислениях AMD лучше всего. А NVidia ведет себя отвратительно по отношению к своим пользователеям. Как конкретный потребитель, смысла в "профессиональных" решениях от NVidia не вижу вообще.

Про "ну достаточно финансовую математику перевести в инты и потом все залетает и на нвидии" рассказывать не надо.

Спасибо за ликбез. Склонен в данном вопросе довериться на все 100%

 

Попробуем для разминки решить следующую задачку:

Отправить в кернел массив из двух элементов, поменять значения элементов местами и вернуть обратно.

Первый вариант решения:

//============================================================================================= MQL5 ===
//    LibreOCL v1.002 (MQL5)
//    Главный модуль обработки событий
//    Librecoin(c)2014-2017
//============================================================================================= MQL5 ===
//    REVIEWS
//------------------------------------------------------------------------------------------------------
// Пример программирования OpenCL.
//============================================================================================= MQL5 ===
//    IDEAS
//------------------------------------------------------------------------------------------------------
// Заносим два значения в кернел, меняем местами и возвращаем обратно.
//============================================================================================= MQL5 ===
//    PROPERTY
//------------------------------------------------------------------------------------------------------
#property copyright "Librecoin(c)2017"
#property version   "1.002"
#property strict
//============================================================================================= MQL5 ===
// Код функций для OpenCL
//------------------------------------------------------------------------------------------------------
const string CL_Source=
                        "kernel void Exch(global double *ix)   \r\n"
                        "{                                     \r\n"
                        "  double z;                           \r\n"
                        "  z=ix[0];                            \r\n"
                        "  ix[0]=ix[1];                        \r\n"
                        "  ix[1]=z;                            \r\n"
                        "}                                     \r\n";
//
//============================================================================================= MQL5 ===
// Script program start function  
//------------------------------------------------------------------------------------------------------
void OnStart(){
//----- Исходный массив значений для перестановки
   double x[2]={1111.1,9999.9}; 
//----- Распечатаем исходные значения элементов массива
   Print("x[0]=",x[0]," x[1]=",x[1]);
//----- Хендлы для объектов OpenCL
   int h_CL_Context;                      //Хендл контекста
   int h_CL_Program;                      //Хендл программы
   int h_CL_Kernel;                       //Хендл кернела
   int h_CL_Buffer;                       //Хендл буфера
//----- Создание контекста (среды) для программы OpenCL (выбор девайса)
   ResetLastError();
   {if((h_CL_Context=CLContextCreate(CL_USE_ANY))==INVALID_HANDLE)         //CL_USE_ANY - использовать любое доступное устройство с поддержкой OpenCL
   {
      Print("OpenCL not found, error:",GetLastError());
      return;
   }else{
      Print("OpenCL found, Хендл на контекст OpenCL:",h_CL_Context," Error:",GetLastError());
   }}//if((h_CL_Context=CLContextCreate(CL_USE_ANY))==INVALID_HANDLE)
//----- Создание в контексте программы на основе кода в строке CL_Source
   ResetLastError();
   string BuildLog="";                    //Лог компиляции
   {if((h_CL_Program=CLProgramCreate(h_CL_Context,CL_Source,BuildLog))==INVALID_HANDLE)//В третьем параметре - лог компиляции
   {
      Print("OpenCL program create failed, error:",GetLastError()," BuildLog=",BuildLog);
      CLContextFree(h_CL_Context);
      return;
   }else{
      Print("OpenCL program create, Хендл программы OpenCL:",h_CL_Program," Error:",GetLastError());
   }}//if((h_CL_Program=CLProgramCreate(h_CL_Context,CL_Source,BuildLog))==INVALID_HANDLE)
//----- Создание кернела для расчета значений функции от двух переменных
   ResetLastError();
   {if((h_CL_Kernel=CLKernelCreate(h_CL_Program,"Exch"))==INVALID_HANDLE)//Имя функции ("Exch") должно соответствовать имени в программной строке CL_Source
   {
      Print("OpenCL kernel create failed, error:",GetLastError());
      CLProgramFree(h_CL_Program);
      CLContextFree(h_CL_Context);
      return;
   }else{
      Print("OpenCL kernel create, Хендл кернела OpenCL:",h_CL_Kernel," Error:",GetLastError());
   }}//if((h_CL_Kernel=CLKernelCreate(h_CL_Program,"Exch"))==INVALID_HANDLE)
//----- Создание буфера OpenCL для получения значений функции
   ResetLastError();
   {if((h_CL_Buffer=CLBufferCreate(h_CL_Context,ArraySize(x)*sizeof(double),CL_MEM_READ_WRITE))==INVALID_HANDLE)
   {
      Print("OpenCL buffer create failed, error:",GetLastError());
      CLKernelFree(h_CL_Kernel);
      CLProgramFree(h_CL_Program);
      CLContextFree(h_CL_Context);
      return;
   }else{
      Print("OpenCL buffer create, Хендл буфера OpenCL:",h_CL_Buffer," Error:",GetLastError());
   }}//if((h_CL_Buffer=CLBufferCreate(h_CL_Context,ArraySize(x)*sizeof(double),CL_MEM_READ_WRITE))==INVALID_HANDLE)
//----- Записываем исходные значения в буфер
   Print("В буфер записано ",CLBufferWrite(h_CL_Buffer,x)," элементов");
//----- Передаём значения буфера по хендлу h_CL_Buffer в кернел
   ResetLastError();
   {if(!CLSetKernelArgMem(h_CL_Kernel,0,h_CL_Buffer))
   {
      Print("OpenCL set buffer failed, error:",GetLastError());
      CLBufferFree(h_CL_Buffer);
      CLKernelFree(h_CL_Kernel);
      CLProgramFree(h_CL_Program);
      CLContextFree(h_CL_Context);
      return;
   }else{
      Print("OpenCL set buffer, error:",GetLastError());
   }}//if(CLSetKernelArgMem(h_CL_Kernel,0,h_CL_Buffer))
//----- Запускаем выполнение кернела
   ResetLastError();
   {if(!CLExecute(h_CL_Kernel))
   {
      Print("OpenCL execute failed, error:",GetLastError());
      CLBufferFree(h_CL_Buffer);
      CLKernelFree(h_CL_Kernel);
      CLProgramFree(h_CL_Program);
      CLContextFree(h_CL_Context);
      return;
   }else{
      Print("OpenCL execute, error:",GetLastError());
   }}//if(!CLExecute(h_CL_Kernel))
//----- Считываем полученные значения в массив x
   Print("Из буфера прочитано ",CLBufferRead(h_CL_Buffer,x)," элементов");
//----- Распечатываем полученные значения элементов массива
   Print("x[0]=",x[0]," x[1]=",x[1]);
//----- Удаляем объекты OpenCL
   CLBufferFree(h_CL_Buffer);
   CLKernelFree(h_CL_Kernel);
   CLProgramFree(h_CL_Program);
   CLContextFree(h_CL_Context);
   return;
}//OnStart()

Результат выполнения:

2017.12.11 22:00:59.128 LibreOCL_v1.002 (VTBR-12.17,M1) x[0]=1111.1 x[1]=9999.9
2017.12.11 22:00:59.136 LibreOCL_v1.002 (VTBR-12.17,M1) OpenCL: GPU device 'Pitcairn' selected
2017.12.11 22:00:59.136 LibreOCL_v1.002 (VTBR-12.17,M1) OpenCL found, Хендл на контекст OpenCL:65536 Error:0
2017.12.11 22:00:59.190 LibreOCL_v1.002 (VTBR-12.17,M1) OpenCL program create, Хендл программы OpenCL:65537 Error:0
2017.12.11 22:00:59.191 LibreOCL_v1.002 (VTBR-12.17,M1) OpenCL kernel create, Хендл кернела OpenCL:65538 Error:0
2017.12.11 22:00:59.191 LibreOCL_v1.002 (VTBR-12.17,M1) OpenCL buffer create, Хендл буфера OpenCL:65539 Error:0
2017.12.11 22:00:59.191 LibreOCL_v1.002 (VTBR-12.17,M1) В буфер записано 2 элементов
2017.12.11 22:00:59.191 LibreOCL_v1.002 (VTBR-12.17,M1) OpenCL set buffer, error:0
2017.12.11 22:00:59.191 LibreOCL_v1.002 (VTBR-12.17,M1) OpenCL execute, error:0
2017.12.11 22:00:59.194 LibreOCL_v1.002 (VTBR-12.17,M1) Из буфера прочитано 2 элементов
2017.12.11 22:00:59.194 LibreOCL_v1.002 (VTBR-12.17,M1) x[0]=9999.9 x[1]=1111.1

Обратите внимание на строку использованную при создании программы для кернела и содержащую инструкцию:

CLProgramCreate(h_CL_Context,CL_Source,BuildLog)

Здесь последний параметр строкового типа BuildLog содержит лог компиляции программы отправленной в кернел, если при компиляции обнаружены ошибки.

Например, если мы намеренно внесём ошибку в код функции:

//============================================================================================= MQL5 ===
// Код функций для OpenCL
//------------------------------------------------------------------------------------------------------
const string CL_Source=
                        "kernel void Exch(global double *ix)   \r\n"
                        "{                                     \r\n"
                        "  double z; XXX                          \r\n"
                        "  z=ix[0];                            \r\n"
                        "  ix[0]=ix[1];                        \r\n"
                        "  ix[1]=z;                            \r\n"
                        "}                                     \r\n";

То получим следующий лог:

"C:\Users\User9764\AppData\Local\Temp\OCL82CA.tmp.cl", line 3: error: 
          identifier "XXX" is undefined
    double z; XXX                          
              ^

"C:\Users\User9764\AppData\Local\Temp\OCL82CA.tmp.cl", line 4: error: "z" has
          already been declared in the current scope
    z=ix[0];                            
    ^

"C:\Users\User9764\AppData\Local\Temp\OCL82CA.tmp.cl", line 3: warning: 
          variable "z" was declared but never referenced
    double z; XXX                          
           ^

2 errors detected in the compilation of "C:\Users\User9764\AppData\Local\Temp\OCL82CA.tmp.cl".

Frontend phase failed compilation.

Файлы:
 

Используйте штатный класс COpenCL из /include/OpenCL/OpenCL.mqh и код станет чище, меньше и красивее.


Мы давно уже сделали автоматический перехват OpenCL ошибок и они показываются прямо в терминале во время исполнения:

2017.12.11 22:17:40.749 new (EURUSD,H1) x[0]=1111.1 x[1]=9999.9
2017.12.11 22:17:40.787 new (EURUSD,H1) OpenCL: GPU device 'Hawaii' selected
2017.12.11 22:17:40.787 new (EURUSD,H1) OpenCL found, Хендл на контекст OpenCL:65536 Error:0
2017.12.11 22:17:40.797 new (EURUSD,H1) OpenCL program create failed, error:5105 BuildLog=C:\xxxxxxxxxxxxxxxxxxxxxxxx.cl:3:13: error: use of undeclared identifier 'XXX'
2017.12.11 22:17:40.797 new (EURUSD,H1)   double z; XXX                           
2017.12.11 22:17:40.797 new (EURUSD,H1)             ^
2017.12.11 22:17:40.797 new (EURUSD,H1) 1 error generated.
2017.12.11 22:17:40.797 new (EURUSD,H1) 
2017.12.11 22:17:40.797 new (EURUSD,H1) error: Clang front-end compilation failed!
2017.12.11 22:17:40.797 new (EURUSD,H1) Frontend phase failed compilation.
2017.12.11 22:17:40.797 new (EURUSD,H1) Error: Compiling CL to IR
 

Если забыть про графику и смотреть в сторону бустинга алгоритмов для ТА, то с практической точки зрения, с помощью OC наиболее выгодно ускорять нейронки и тому подобное (множество одновременно независимых вычислений), например всякие легкие эвристики. А в остальных мало выигрыша, т.к. на практике обычно (осмелюсь сказать что свыше 90%) это алгоритмы с малым количеством потоков, которые либо слишком тяжелые (что перегружает ядра ГП), либо слишком легкие - в место ускорения, в итоге получаем замедление, из-за потерь в передаче данных, кстати в эту категорию можно занести индикаторы, как бы странно это не звучало.

Можно, конечно еще OC использовать и для того, чтобы реализовать многопоточность в MQL5, но для этого нужно серъезный резон, т.к. код писать и поддерживать заметно сложнее.

 

на ноутах с неплохой дискретной карточкой (в смысле не встроенной в процессор) тоже норм ускорение

2017.12.12 06:18:46.712 Wavelet (USDJPY,M15)    OpenCL: GPU device 'GeForce 940MX' selected
2017.12.12 06:18:47.349 Wavelet (USDJPY,M15)    time CPU=5734 ms, time GPU=344 ms, CPU/GPU ratio: 16.668605

только оптимизироваться такой бот будет только на 1 агенте, насколько я помню.. т.е. либэ-либэ

 
Renat Fatkhullin:

Используйте штатный класс COpenCL из /include/OpenCL/OpenCL.mqh и код станет чище, меньше и красивее.


Мы давно уже сделали автоматический перехват OpenCL ошибок и они показываются прямо в терминале во время исполнения:


Ренат, для понимания механизмов работы OpenCL я намеренно не собираюсь пока использовать библиотеки, а буду вести работу на уровне встроенных объектов языка MQL. Впоследствии возможно будут использоваться и библиотеки классов.

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