Программирование на видеокартах GPGPU (1184391), страница 9
Текст из файла (страница 9)
Во-вторых, макроопределение CL_CHECK_ERR, возвращающее значениенекоторого заранее неизвестного типа "из-под" пар круглых, а затем фигурных скобок,слишком «авангардно» для компилятора VC 9.0 и не совсем ясно, чем его можно было бызаменить, поэтому проще его не применять вообще. Это касается вызовов функцийclCreateContext(), clCreateCommandQueue() в конструкторе clhelper и функцииclCreateBuffer() в методе createbuffer. При этом нужно добавить определениеиспользуемой при первых двух вызовах величины _err, поскольку в самом конструкторе33этого определения — после игнорирования макроса — уже нет.
В-третьих, лучше всегообъявление и определение функции обратного вызова pfn_notify снабдить пометкойCL_CALLBACK, несущественной везде, кроме Windows, — иначе придётся заменятьчетвёртый параметр в вызове clCreateContext() на NULL, лишаясь возможности узнать окаких-либо неприятностях при создании контекста OpenCL.Ну, и напоследок надо сказать, что для системы Windows код файла clhelper.hpp,являющийся работоспособным во всех системах, кроме неё, должен быть скорректирован вметоде load_program_source() класса clfunction, поскольку без этого возникаеттрудноуловимая ошибка компиляции ядра, которую невозможно обнаружить даже«отдельным» компилятором ядер (например, clcc; см. далее). А всё дело оказывается в том,что при чтении файла в память используется открытие файла в режиме "r", что автоматическиприводит к «проглатыванию» первого из символов пары 0x0D,0x0A, завершающих строкитекста, из-за чего только (!) исходные тексты ядер, созданные под Windows, оказываютсякороче длины файла.
Конец текста ядра в памяти при этом оказывается испорченпосторонними символами и ядро просто не компилируется. Причём — это надо подчеркнуть— никаких ошибок не будет, если ядро содержит только Linux-переводы строк или вообщенаписано в одну строчку (хотя, конечно, самому компилятору ядер всё равно, как разделяютсятекстовые строки, — он всё обрабатывает правильно). Скорректировать процедуру чтенияможно путём изменения режима открытия файла ("rb"), тогда даже ядра из файлов спереводами строк в стиле Windows (0x0D,0x0A) будут загружаться в память правильно.Надо сказать, что компилирование ядер «вслепую» (без контроля возникающих ошибок)оправдано лишь в случаях уже «проверенных» ядер.
В реальной работе нужно быть точноуверенным, что ядра не содержат синтаксических ошибок и компилируются, а для этого полезнопопытаться скомпилировать их отдельно, используя, например, clcc — OpenCL Kernel Compiler(http://sourceforge.net/projects/clcc/), который использует уже установленную накомпьютере реализацию OpenCL, а если их несколько — то любую заданную из них. Типичнаякомандная строка компиляции файла с ядром для заданной платформы и заданного устройствавыглядит так:clcc -p <Платформа> -d <Устройство> <ИмяФайлаСЯдром>Необходимые для этой строки значения идентификаторов платформы и устройства можно узнатьс помощью «справочного» запуска этого компилятора (clcc -i).
Подсказка по имеющимсявозможностям компилятора — clcc -h.Если при этом ядрам понадобятся дополнительные параметры, то их использование возможно спомощью опции --cloptions командной строки. Например, в коде ядра reduction.cl супомянутого выше сайта (http://www.caam.rice.edu/~timwar/HPC12/Examples/OpenCL++/)используется величина dx, нигде в файле ядра не определяемая. Она получает своё значение вхост-программе reduction.cpp перед компиляцией ядра и передаётся в рамках опциикомандной строки при компиляции (например, так: "-Ddx=512").
Такая возможностькомпиляции ядер с немного разными значениями подобного типа параметров является дляOpenCL вполне оправданной, т.к. разные устройства обладают разными характеристиками.Помимо отдельной компиляции ядер надо обязательно проверять все используемые в OpenCLфункции на предмет возможных ошибок при выполнении каждой из них. Это может казатьсяизбыточным, но это лишь отчасти так, и только, если программа компилируется и работает. Еслиже она — в процессе создания, дополнительные сообщения об ошибках, а также возвращаемыефункцией clGetProgramBuildInfo() сведения будут совсем не лишними.34Завершить набор советов уместно ещё одним замечанием.
В Сети легко обнаружить довольномного примеров, которыми можно воспользоваться для освоения любой незнакомой области,важно не забывать, что программы почти всегда содержат ошибки, и не все эти ошибкиобнаружены авторами примеров — просто потому, что у них эти ошибки могли не проявляться.Чаще всего ошибки возникают потому, что пишется программа в одной операционной системе, апроверяется — в другой, при этом должного внимания переносимости кода не уделяется.Например, код из текста достаточно свежей заметки (25 августа 2014) в блоге разработчика (!)библиотек для GPU — фирмы ArrayFire (http://arrayfire.com/generating-ptx-filesfrom-opencl-code/) тоже содержит обсуждавшуюся ранее ошибку: .cl-файл открываетсядля чтения в текстовом режиме ("r"). При этом сохраняемый .ptx-файл открывается длязаписи зачем-то в бинарном режиме ("wb"), хотя его содержимое является чисто текстовым.Если фрагменты кода бездумно «вырезать» прямо из заметки, то, как уже говорилось, подWindows ядро просто не откомпилируется, поскольку будет содержать по два символа концастроки, один из которых при считывании файла в текстовом режиме под Windows простоисчезнет.
Если же воспользоваться версией кода с GitHub, то наличие ошибки в коде (припроверке даже под Windows) будет незаметно, поскольку ядро там содержит по одномусимволу конца строки. Справедливости ради надо сказать, что эта ошибка в тексте заметки —не единственная и не главная: обе версии ядра (CUDA и OpenCL), содержат одинаковуюошибку в операции проверки (неравенство должно быть противоположным!), из-за чегопрограмма, их использующая, не могла бы в принципе работать, но, к счастью, здесь она лишьпреобразует ядро из одного вида в другой, а не запускает его...Дополнительные материалыНеплохая статья-введение в программирование с помощью OpenCL (выдержки из неёиспользовались выше):A Gentle Introduction to OpenCLhttp://www.drdobbs.com/parallel/a-gentle-introduction-to-opencl/231002854Ссылки на реализации OpenCL основными изготовителями видеокарт:OpenCL | NVIDIA Developer Zonehttps://developer.nvidia.com/openclOpenCL™ Zone | AMD — Develop With AMDhttp://developer.amd.com/resources/heterogeneous-computing/opencl-zone/Intel® SDK for OpenCLhttp://software.intel.com/en-us/articles/intel-opencl-sdk/Просто интересные ссылки по теме:Differences between VexCL, Thrust, and Boost.Computehttp://stackoverflow.com/questions/20154179/differences-between-vexcl-thrustand-boost-computeSimulation and Rendering of Fire using CUDAhttps://code.google.com/p/cuda-fire-simulation/Библиотека ViennaCL:http://sourceforge.net/projects/viennacl/358Библиотека OpenCV (Open Source Computer Vision Library)Общие сведенияЭто открытая библиотека, содержащая несколько сотен алгоритмов работы с изображениями.
Длянас она интересна в первую очередь тем, что некоторые её модули (имеется в виду модуль gpu,«умеющий» использовать карты NVIDIA, а с версии 2.4.3 — также модуль ocl, инициированныйфирмой AMD и «задействующий» OpenCL) содержат алгоритмы из различных других модулей иэти алгоритмы используют графическую карту для ускорения работы.
Среди остальныхмодулей (т.е., отдельных статических или динамических библиотек): core (структуры данных,многомерный массив данных Mat, базовые функции, используемые в других модулях), imgproc(обработка изображений: линейная и нелинейная фильтрация, геометрические и цветовыепреобразования, гистограммы и т.п), video (видеоанализ: оценка движения, устранение фона,слежение за объектом), objdetect (обнаружение объектов определённых классов, например, лиц,глаз, а также людей, машин), highgui (интерфейс работы с видео и изображениями) и др.Компиляция и сборка проекта с использованием OpenCVДля добавления возможностей OpenCV к проекту, создаваемому с помощью компилятора VisualC++, удобно иметь переменную окружения, скажем, OPENCV, указывающую на каталог, гдерасположены файлы библиотеки, тогда с помощью $(OPENCV) упрощается указание путей вустановках проекта: для компиляции параметр AdditionalIncludeDirectories должен содержать$(OPENCV)\build\include, для сборки программы параметр AdditionalLibraryDirectoriesдолжен содержать значение $(OPENCV)\build\<Платформа>\<ВерсияСтудии>\lib) ипараметр AdditionalDependencies — список необходимых статических библиотек).
В зависимостиот сложности программы список может включать такие статические библиотеки:opencv_core<ВерсияOpenCV>.lib, opencv_imgproc<ВерсияOpenCV>.lib,opencv_highgui<ВерсияOpenCV>.lib, opencv_ml<ВерсияOpenCV>.lib,opencv_video<ВерсияOpenCV>.lib, opencv_features2d<ВерсияOpenCV>.lib,opencv_calib3d<ВерсияOpenCV>.lib, opencv_objdetect<ВерсияOpenCV>.lib,opencv_contrib<ВерсияOpenCV>.lib, opencv_legacy<ВерсияOpenCV>.lib,opencv_flann<ВерсияOpenCV>.lib.Для работы с графической картой добавляется ещё opencv_gpu<ВерсияOpenCV>.lib.Здесь использованы такие обозначения: <Платформа> — это x86 или x64, <ВерсияСтудии> —vc9, vc10, vc11 или vc12, <ВерсияOpenCV> — три или четыре цифры версии (без точек),например, 2411 для OpenCV v.2.4.11, 230 — для OpenCV v.2.3.0 и т.п.Интересно, что OpenCV v2.3.0 имеет варианты библиотечных файлов только для vc9 и vc10, авот версия OpenCV v2.4.8— уже только для vc10, vc11 и vc12...И, разумеется, для того, чтобы работающая программа могла найти свои динамическиебиблиотеки (.dll), нужно добавить путь к ним в переменную окружения Path (или скопироватьдинамические библиотеки туда, где поиск уже производится, например, в каталог\Windows\system32).36Программирование с использованием OpenCVИмеется два варианта взаимодействия с функциями OpenCV: "старый" (используютсязаголовочные файлы opencv/...) и новый, появившийся со второй версии библиотеки(используются заголовочные файлы opencv2/...).