Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > Delphi программирование > Общие вопросы Delphi
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 14.01.2016, 12:11   #1
Prok186
Пользователь
 
Регистрация: 19.06.2011
Сообщений: 21
По умолчанию Использование OpenCL в Delphi-коде под Win64

Для ускорения расчётов в небольшой (но определяющей всё быстродействие в целом) части огромной (55тыс строк) программы для научных расчётов, написанной на Delphi XE2 (...XE6), ранее использовались потоки (объект TThread) на CPU. Всё это прекрасно работает. Сейчас возникла идея использовать возможности GPU. Простой, как казалось, путь - подключить модули (заголовочные файлы к OpenCL.dll по сути) - и использовать возможности OpenCL от Khronos Groupe. На просторах Инета вполне такие примеры использования OpenCL в Delphi можно найти.
Вот такой архив, к примеру, можно скачать:
http://gofile.me/2Zesj/fvDY3om0
Там все необходимые файлы (3шт. *.pas) для подключения OpenCL к Delphi и пример расчёта суммы двух векторов длиной по 2048. Сам код, выполняемый на видеоускорителе, написан в виде отдельного файла на языке С - VectorAdd.CL: передаётся на видеокарту прямо в виде строки кода. Работает всё это, но...только при компиляции дельфового проекта под Win32. А мне нужны большие массивы, динамические: компиляция всей научной программы под Win64 просто необходима (используем иногда до 12Гбайт оперативки CPU). И тут начинаются грабли... Где-то тестовые примеры (пока речь только о тестах) работы с GPU через язык OpenCL, скомпилированное под Win64, работают, где-то - нет. Видеокарты пробовали разные: и NVIDIA GeForce 450, 430, и AMD M275.... Операционка Windows 10, 64bit. Видеодрайверы - последние.
Что значит не работает? Либо зависает, либо результат расчёта - нолики вместо чисел. Хотя никаких ошибок при инициализации контекста или запуска расчётного ядра не происходит....
Даже имя видеокарты уже отображается не верно, если компиляция проекта Delphi выполняется под Win64...
-----
Вот мой пример номер 1 - тут уже динамические массивы, длину которых можно менять в основной форме (по умолч. 25000):
http://gofile.me/2Zesj/mcwGFNK1
При компиляции под Win32 работает, а под Win64 - нет!!
-----
Вот развитие этого примера: умножение уже не векторов, а 2-х матриц (размер матрицы и ширина "полосы умножения" задаётся на форме):
http://gofile.me/2Zesj/uUfRtVdN
Работает иногда и при компиляции в Delphi XE2 или XE6 (Seattle не пробовал) под Win64. Иногда глючит - выдаёт нолики вместо результатов.... Компилируешь ВСЁ под Win32- OK.
-------
С чем это может быть связано? Не пригодные для Win64 заголовочные файлы CL.pas, CL_GL.pas? Может, у кого-то есть другие? Или сама видеокарта не может работать с программой под Win64 ??
Но аналогичные программы для GPU, написанные под Visual Studio 2015 на языке C++ AMP, у меня идут...Выкладываю то-же умножение матриц, в цикле - для контроля времени выполнения, и тоже умножить большие матрицы удаётся только в "полосе" - иначе видеокарта виснет:
http://gofile.me/2Zesj/rQ3aw82g
-----
По идее, OpenCL должно корректно работать в проектах Embarcadero:
http://community.embarcadero.com/blo...ng-with-opencl
Но даже если вы здесь скачаете примеры от Mitov Software, они корректно отработают только при компиляции под Win32 (в них есть LOG-файлы и картинки с результатами на выходе). Проверял в среде Delphi XE6

Последний раз редактировалось Prok186; 14.01.2016 в 13:02.
Prok186 вне форума Ответить с цитированием
Старый 15.01.2016, 20:26   #2
wendstor
Пользователь
 
Аватар для wendstor
 
Регистрация: 28.12.2011
Сообщений: 20
По умолчанию

Что то я сомневаюсь в этих ~50 тыс строк) раз не можете толком разобраться в плане ошибки...
1. Изменить OpenCL.dll на OpenCL64.dll в функции LoadOpenCL или завести константу:

Код:
const
  {$IFDEF WIN32}
  DLL_OPENCL = 'OpenCL.dll';
  {$ENDIF}
  {$IFDEF WIN64}
  DLL_OPENCL = 'OpenCL64.dll';
  {$ENDIF}  

...........
function LoadOpenCL: boolean;
begin
  OpenCL_handle:=LoadLibrary(DLL_OPENCL);

2. Изменить size_t на NativeInt или

Код:
uses
  {$IFDEF WINDOWS}
  Windows, System.SysUtils;
  {$ENDIF}

  {$IFDEF WIN32}
  size_t     = longword;
  {$ENDIF}
  {$IFDEF WIN64}
  size_t     = NativeInt;
  {$ENDIF}
Ссылка

Последний раз редактировалось Arigato; 20.11.2018 в 10:06.
wendstor вне форума Ответить с цитированием
Старый 19.01.2016, 20:40   #3
Prok186
Пользователь
 
Регистрация: 19.06.2011
Сообщений: 21
По умолчанию

Цитата:
Сообщение от wendstor Посмотреть сообщение
Что то я сомневаюсь в этих ~50 тыс строк) раз не можете толком разобраться в плане ошибки...
1. Изменить OpenCL.dll на OpenCL64.dll в функции LoadOpenCL или завести константу:
...
2. Изменить size_t на NativeInt или
...
Напрасно сомневаетесь
На самом деле, уже разобрался: заголовочный файл к OpenCL.dll переписал, выкинул ненужное мне, работает под Win32 и под Win64 - пример выложу на днях!
С использованием не той DLL (32bit vs 64bit) ошибка маловероятна: DLL под Win32 к приложению, скомпелированному в Delphi как Win64, просто не подключилась бы, и наоборот. За подсказку с NativeInt - спасибо, использую. Но пока и без неё всё работает (size_t я задавал как int64)... Остался вопрос про выравнивание информации, передаваемой в OpenCL функции, по границе 16 байт. Про это в ряде примеров пишут с тремя восклицательными... Вручную подбирать размеры массивов, или достаточно директивы {$A16} ?
===
Пример уже готов. Вот ссылка для скачивания: http://gofile.me/2Zesj/C0f3wb1o
Прежние ссылки (пост выше) на некорректно работающие примеры удалил!!
Там в папке:
1) Полезная утилита GPU_Caps_Viewer_Setup_v1.25.0.0.exe для контроля состояния видеокарты, особенно, если нажать кнопку "More GPU Info".
2) OpenCL1_2_Delphi.zip - файл с примером от чехов (Университет Брно, насколько помню) использования OpenCL в Delphi, 2013год. У меня этот пример не всегда корректно работал при компиляции под Win64 (не на всех видео-картах). Но там хороший заголовочный файл CL.pas - его можно чуть доработать с учётом замечания про NativeInt в предыдущих постах, и использовать вместо моего "укороченного" MyOpenCL.pas - см.ниже.
---
3) Вложенная папка с моим вариантом программы-теста. Она самодостаточна: больше ничего не надо, ну разве что последние версии видео-драйверов установить. Тест сделан под Delphi XE2 (работает и под XE6). Причём работает, по крайней мере у меня, при компиляции под Win32, и что более важно- под Win64. Всего 2 файла:
--> MyOpenCL.pas: заголовочный; я его урезал - убрал ненужные мне функции, которые в принципе можно взять из файла чехов CL.pas + учёл полезное замечание про NativeInt выше;
--> FMain.pas : тестовая программа. Выделяет на GPU память (создаёт буферы) под 16 массивов (квадратных матриц из cl_Float, размер стороны которых задаётся на основной форме, по умолчанию 1200) и под ещё один массив, того же размера, куда пишется результат несложных вычислений на GPU. Потом запускается итерационный цикл (количество итераций - для проверки времени работы - задаётся тоже на форме, по умолчанию - 12). Внутри каждой итерации 16 массивов заполняются данными, затем запускается ещё и внутренний цикл: 30 проходов вызова расчётного ядра на GPU. Такая структура тестовой программы больше всего подходит под наши научные задачи (вычислит. гидродинамика), но пока это лишь тест. В тесте есть несложная проверка правильности вычислений - для одного из элементов матрицы-результата, поскольку НЕ все драйверы видеокарт (особенно старые) могут диагностировать Kernel Error.
--> программа на С для ядра - текстовый файл ProgramGPU.CL (должен лежать рядом с MyFirstOpenCL.exe !!): там можно глянуть, что делается с одномерными массивами на GPU. Она прямо передаётся в виде строки на GPU, там копилируется и линкуется - ну как обычно в OpenCL.
Нужная DLL для OpenCL - под Win64 или Win32 - подключится из системных папок Windows автоматически, в зависимости от компиляции.
----
4) Можете на своём сетапе запустить прямо готовый MyFirstOpenCL.exe (это версия 64bit !!) с параметрами:
--> размер стороны матрицы = 3200; лезут 17 таких матриц на видеокарту от 1Gb и выше; если не влезут (часть видео-памяти уже занята чем-то) - возможны ошибки, которые диагностируются НЕ всем драйверами видеокарт, а только новыми;
--> количество итераций (внешний цикл) = 12.
---
5) У меня для указанного примера время счёта вышло:
NVIDIA GT-430 (1Gb, 96core, 700MHz core) - 3мин 37сек;
NVIDIA GTS-450 (1Gb, 192core, 810MHz core) - 1мин 36сек;
NVIDIA GTX-570 (1.28Gb, 480core, 732MHz core) - 42.5сек;
AMD Radeon R9 M275X (2Gb, 640core, 925MHz core) - 1мин 27сек - настольный моноблок ASUS 2702.
----
Может кто-то попробовать MyFirstOpenCL.exe на своих видеокартах???
Запустить, нажать верхнюю кнопку на форме, установить размер матрицы 3200 (если 1200 отработает корректно), выбрать платформу-девайс, нажать нижнюю кнопку на форме. Записать время счёта: оно выдаётся в итоговом окне.
Нам сейчас на работу надо будет покупать новую карту именно для расчётов...денег более 60тр вряд ли выделят... AMD конечно подешевле, но... Такие сопоставительные тесты на задачах, приближенных к нашим, были бы полезны!! Были бы полезны и замечания участников форума по тестовой программе.

Последний раз редактировалось Prok186; 20.01.2016 в 16:45.
Prok186 вне форума Ответить с цитированием
Старый 10.02.2016, 20:12   #4
Prok186
Пользователь
 
Регистрация: 19.06.2011
Сообщений: 21
По умолчанию

А пока тут вяло шло тестирование видеокарт... уже переписал часть "трудоёмкого" кода в своей основной (не тестовой уже) программе на OpenCL, 3 кернела. Сравнительно быстро всё отладил. Предварительный итог: время счёта на задачах (сутками считаются - гидродинамика) уже сократилось почти в 4 раза.
Поменял у себя на работе видео-карту на GeForce GTX-980ti - зверь! :up:
Кстати, фирме Khronos стало видимо стыдно, и она 05 февраля 2016г (!!!) выложила файлы поддержки OpenCL и CUDA (заодно, чтобы не мелочиться) для Delphi. Тут можно скачать: http://sourceforge.net/p/glscene/cod.../ParallelAPIs/ , для OpenCL хватит CL.pas, CL_Platform.pas, CL.inc. Но мне проще использовать для OpenCL.dll свой заголовочник, кот. уже выкладывал в посте 1.
Итак. Чтобы не быть голословным, выкладываю во вложенной папке (см. ссылку для скачивания в 1-м посте), или прямо ссылку на вложенную папку - http://gofile.me/2Zesj/TOT6JHm0
Там, во-первых, новый работающий пример: выкинул всё написанное чехами, всё переписал заново, более осмысленно. Две программы-Kernel (так для пробы, используется в тесте первая), контроль погрешности - сравнение расчётов CPU vs GPU, использование в Kernel функции-atomic. Но Header-файл пока оставил свой, а не брал заголовочник, выложенный Khronos. Ещё там же в отдельной по-папке - 2 картинки-скана TIF с моими вопросами по работе новой видяхи GTX-980ti. Гляньте, плиз: почему такую частоту памяти видяхи показывает Caps-Viewer? :smirk:
И наконец, в папке OpenCL_Demo2016 есть под-папка с моими 3-мя Kernel для не тествых, а рельных расчётов- последний длинный вчера дописал и опробовал - можете полюбопытствовать! Вряд ли они кому-то понадобятся в таком виде, но вот как примеры для OpenCL (для любого языка программы на хосте - хоть Delphi, хоть JAVA)...могут быть полезны участникам форума.
====
ПыСы. Посоветуйте, коллеги, на каком форуме активно обсуждается написание самих Kernel для OpenCL (программки на языке, похожем на C99, которые компилирует сам драйвер видео-карты). Или здесь подскажите, как разбивать для Kernel'a большую программу на модули (хотя это в принципе есть в моём новом примере - уже вроде осилил), и главное - как обмениваться между этими модулями (процедурами) данными: только через их списки параметров? Через всю цепочку процедур этот список тащить до той, где они действительно нужны??? Писать весь расчётный модуль одним "монолитом" без разбивки на модули - не кашерно, сами понимаете. А мне сейчас надо запихнуть на GPU код в несколько тысяч строк...

Последний раз редактировалось Prok186; 10.02.2016 в 20:35.
Prok186 вне форума Ответить с цитированием
Старый 11.11.2018, 00:40   #5
ekvi
 
Регистрация: 11.11.2018
Сообщений: 4
По умолчанию

Всем добрый день!
prok12 пишет: "огромной (55тыс строк) программы для научных расчётов, написанной на Delphi". У меня ситуация аналогичная: более 20 тыс. операторов на Паскале, и тоже захотелось использовать видеокарту для ускорения оптимизации оптических систем. Понятно, что переписывать такой объём на C++ или C# уже духу не хватит.
Своей работой Владимир Анатольевич (prok12) воодушевил и меня. У меня установлена ВК GTX 1060, Visual Studio 2015 и NVidia C, пример с kernel работает с double, но всё это - на Си++ и без оконный интерфейс (консольный).
OpenCL тем и привлёк, что позволяет, не меняя оконного интерфейса, использовать видеокарту.
Однако меня смущает, что OpenCL 1.2 обрабатывает только float-числа, обеспечивающие точность грубее 10^-7, поскольку для оптики требуется точность 10^-16 и выше.
Не подскажете, как с помощью библиотеки OpenCL обрабатывать double-числа?

Последний раз редактировалось ekvi; 11.11.2018 в 01:09. Причина: уточнение вопроса
ekvi вне форума Ответить с цитированием
Старый 18.11.2018, 05:52   #6
Qaplok
Новичок
Джуниор
 
Регистрация: 18.09.2012
Сообщений: 2
По умолчанию

[QUOTE=ekvi;.....
Однако меня смущает, что OpenCL 1.2 обрабатывает только float-числа, обеспечивающие точность грубее 10^-7, поскольку для оптики требуется точность 10^-16 и выше.
Не подскажете, как с помощью библиотеки OpenCL обрабатывать double-числа?[/QUOTE]
Доброго времени суток. Вроде там в файлах было описание переменных а-ля cl_real = real и т.п. - наверное можно таким образом и Extended добавить.
Qaplok вне форума Ответить с цитированием
Старый 18.11.2018, 11:24   #7
p51x
Старожил
 
Регистрация: 15.02.2010
Сообщений: 15,695
По умолчанию

OpenCL 1.2 обрабатывает даблы, более ранние требовали включения расширения. Только надо еще карточку с поддержкой.
p51x вне форума Ответить с цитированием
Старый 18.11.2018, 13:21   #8
Pavia
Лис
Старожил
 
Аватар для Pavia
 
Регистрация: 18.09.2015
Сообщений: 2,409
По умолчанию

Цитата:
Сообщение от p51x Посмотреть сообщение
Только надо еще карточку с поддержкой.
OpenCL создавался под большим влиянием интела. Поэтому полноценная поддержка Double осуществляется только на их CPU.
На GPU у вас 2-3 варианта
1) либо Double совсем не поддерживается.
2) либо поддерживается минимум функций.
3) либо средний.
Хорошо поставленный вопрос это уже половина ответа. | Каков вопрос, таков ответ.
У дзен программиста программа делает то что он хотел, а не то что он написал .
Pavia вне форума Ответить с цитированием
Старый 20.11.2018, 11:53   #9
ekvi
 
Регистрация: 11.11.2018
Сообщений: 4
По умолчанию

Спасибо всем, откликнувшимся!
У меня CPU - Intel - подспудно и была надежда на их поддержку. Но, поскольку $ всем застит сознание, надежда эта была очень слабой.
Поэтому сейчас пытаюсь подобраться к параллельному программированию ... через Embarcaldero (Дельфи 10). Но, к сожалению, и там - опора на Windows, "надёжную, как весь гражданский флот" ...
ekvi вне форума Ответить с цитированием
Старый 20.11.2018, 12:12   #10
ekvi
 
Регистрация: 11.11.2018
Сообщений: 4
По умолчанию

Чтобы не быть голословным, приведу фрагмент кода (здесь float = double - это определено в основном модуле проекта ROS#):
Код:
// kn-weight of the spectrLine
procedure ppCalcSpot(kn:float); // canvas:TCanvas);
// в этой процедуре - чистый параллелизм. Но его надо обустроить:
// выделить для каждого потока и свою память, и свои команды (алгоритмы)
var
 j: integer;
 dw,ro,s1,s2: float;
 sur,suw: array of float; // returning dates
begin 
 SetLength(sur,mn0);
 SetLength(suw,mn0);
 TParallel.For(4,0,mn0-1, // kernCount = 4
 procedure(j:Int64)
 begin
   px:=0;
   py:=y0^[j];
   pz:=z0^[j];
   pu:=ui;
   pv:=vi;
   pw:=wi;
   sln:=py*pv+pz*pw; // учет наклона вх зрачка для SNL
   for i:=0 to ns-1 do
   begin
    rs:=rrs^[i];
    exct:=ex^[i];
    pop:=nCurr^[i];
    nu:=eCurr^[i];
    px:=ll^[i]-px;
    if (abs(exct) < eps) then
    begin      // sfera
      a:=pu*px-pv*py-pw*pz;
      c:=(px-a*pu)*2-(sqr(a)-sqr(px)-sqr(py)-sqr(pz))/rs;
      d:=sqr(pu)-c/rs;
      if (d > 0) then
      begin
        f:=sqrt(d);
        zt:=pu+f;
        if (zt <> 0) then
        begin
          a:=a+c/(pu+f);
          sln:=sln+pop*a;
          px:=a*pu-px;
          py:=a*pv+py;
          pz:=a*pw+pz;
          sq:=1+sqr(nu)*(d-1);
          if (sq > 0) then
          begin
            c:=sqrt(sq)-nu*f;
            a:=-c/rs;
            pu:=nu*pu+a*px+c;
            pv:=nu*pv+a*py;
            pw:=nu*pw+a*pz;
          end;
        end;
      end;
    end
    else
    begin // AS
      e:=exct/rs;
      a:=px*pu-py*pv-pz*pw;
      g:=a*pu-px;
      c:=sqr(px)+sqr(py)+sqr(pz)-sqr(a);
	    d:=(2+e*g)*g-c/rs;
      sr:=sqr(pu)+(d+e*c*sqr(pu))/rs;
	    if (sr > 0) then
      begin
        b:=sqrt(sr);
        a:=a-d/(b+pu*(1+e*g));
        px:=a*pu-px;
        py:=a*pv+py;
        pz:=a*pw+pz;
        sln:=sln+pop*a;
        sr:=1+e*(sqr(py)+sqr(pz))/rs;
        if (sr > 0) then
        begin
          d:=sqrt(sr);
          b:=b/d;
          sr:=1+sqr(nu)*(sqr(b)-1);
          if (sr > 0) then
          begin
            g:=(sqrt(sr)-nu*b)/d;
            a:=-g/rs;
            pu:=nu*pu+a*px*(1-exct)+g;
            pv:=nu*pv+py*a;
            pw:=nu*pw+pz*a;
          end;
        end;
      end;
    end;
   end;
   sur[j]:=sqr(py-yc)+sqr(pz-zc);
   suw[j]:=sqr(sln-optPath0);
 end);

 for j:=0 to mn0-1 do // sum results:
 begin
   dw:=suw[j];
   if (abs(dw) > swam) then
    swam:=abs(dw);
   swa:=swa+sqr(dw);
   sro:=sro+sur[j];
   ro:=sqrt(sur[j]);
   if (ro > maxro) then
     maxro:=ro; // radius!!!
   if (ro <= rAiry) then
     sAry:=sAry+kn;
 end;
 sro:=sro*kn;
 swa:=swa*kn;
 snum:=snum+kn*mn0;
end;
В C# для данного фрагмента команда TParallel.For работает и даёт 4х-кратное ускорение при 4х ядрах. Но в Дельфи - только 20-50% - "Слабак!" - сказал бы Харитонов.
Кстати, в проекте Linzik автор, использовавший GPU (видеокарту), также получил лишь 4.5х ускорение. И это, по-видимому, - предел для подобного рода алгоритмов (на NVIDEA CUDA C мне не удалось даже уровнять последовательные и параллельные результаты).
Поэтому код целесообразнее рассыпать по ядрам CPU. Хотя и здесь Winda волынит: контроль загрузки ядер показывает - они загружены только на 60 - 80 %.

Последний раз редактировалось ekvi; 20.11.2018 в 12:32. Причина: уточнение сообщения
ekvi вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск


Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Использование Delphi DLL в PHP коде Adult_Master Общие вопросы Delphi 5 27.10.2015 18:17
Embarcadero C++, C OpenCL DARTS C++ Builder 1 07.02.2013 22:18
Использование функций в коде программы vl@d0s Общие вопросы C/C++ 6 14.12.2010 22:59
использование SQL запросов в коде VBA b00s Microsoft Office Access 3 26.04.2008 13:40