@Quark_Hell
C++ программист

Какие есть хорошие уроки по OpenCL в C++?

Пытаясь ускорить свои вычисления я обратил внимание на отдыхающую видеокарту (задача стоит умножать огромное количество матриц в очень сжатые сроки). Но нигде не смог найти внятного и хорошего урока по нему. Разве что одна статья на хабре. Но даже с ней возникли проблемы. Почему-то у меня в проекте просто нет всяких __kernel, __global и т.д.,хотя OpenCL вроде как подключён и я могу работать с именем пространств cl.

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

Кто-то знает хорошие уроки, где рассказывается про работу с OpenCL от устоновки в студию до написания проектов с его использованием?
  • Вопрос задан
  • 219 просмотров
Пригласить эксперта
Ответы на вопрос 2
@BulatZiganshin
в статье описан официальный API OpenCL, ваша либа предоставляет для него более высокоуровневую обёртку (ака wrapper).

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

в целом по opencl есть книги, курсы, есть куча разборов именно задачи умножения матриц (ибо классика). вы пробовали гуглить, желательно на английском?

для более детального обсуждения могу предложить группу https://t.me/parallelcoding
Ответ написан
@rPman
Большая часть проблем - это установка необходимых библиотек для поддержки opencl, даже на linux у меня были конфликты (решаемые) когда на машину одновременно устанавливались intel opencl, nvidia driver проприетарный и amd rocm

начни от сюда

Удостоверься что у тебя все установлено под твою видеокарту (не помогу с windows, там с интервалом раз в 3-4 года много что меняется именно в среде gpu-computing, не мудрено что все готовые сборки нейронных сетей типа SD или GPT для pytorch таскают с собой гигабайты готовых предустановленных окружений.
----------

Про c++ враппер, год назад я пробовал устанавливать и использовать различные врапперы (я так понял они все на одном и том же основаны, так как вот такой изврат ...getInfo<CL_DEVICE_NAME>() сложно не заметить) и спотыкался на банальном запуске примеров из документации.

Плюнул, и разобрался с https://man.opencl.org/ нагуглив любой минимальный пример, хоть этот древний

Так вот главная рекомендация банальна и тупа - проверяй сообщение об ошибке каждого метода, сэкономишь тьму времени на отладке (а отладка cl грустная, так как все значения скрыты, структуры косвенные)
Я написал себе макрос и хелпер
/* макрос, помогающий обрабатывать ошибки opencl методов и автоматическое завершение работы при любой ошибке, с корректным освобождением ресурсов
  Использовать так CL_RET = clMethod....
  при возникновении ошибки сгенерирует исключение, в котором будет содержаться текущие имя файла и строка
 */
/* если нужно в сообщении об ошибке сообщать имя файла исходников и номер строки */
/**/#define CL_RET main_cl.error(__FILE__,__LINE__)
/* если нужно в сообщении об ошибке сообщать имя файла исходников и номер строки но проигнорировать один код ошибки */
/**/#define CL_RET_IGNORE(id) main_cl.error(__FILE__,__LINE__,id)
/* код ошибки не будет содержать имени файла и строки */
//**/#define CL_RET main_cl


/* класс-обертка над стандартными операциями по инициализации OpenCL, обработка ошибок и т.п. */
class CLHelper
{
	public:
	/* хранится последнее значение кода ошибки метода, перед которым поставили макрос CL_RET */
	cl_int ret;
	/* последнее значение имни файла исходников места последнего вызова макроса CL_RET */
	char* file=NULL;
	/* последнее значение строчки файла исходников места последнего вызова макроса CL_RET */
	int line;
	cl_int ignore_ret;
	/* код фиксации текущего имени файла и строки, вызывается в макросе CL_RET */
	inline CLHelper& error(const char* _file,const int _line,cl_int _ignore_ret=-999999)
	{
		file=const_cast<char*>(_file);
		line=_line;
		ignore_ret=_ignore_ret;
		return *this;
	}
	/* подмена оператора = для красивого использования CL_RET */
	inline void operator=(cl_int _ret)
	{
		ret=_ret;
		if(ret==CL_SUCCESS||(ignore_ret!=-999999&&ret==ignore_ret)) return;
		//std::string msg=std::to_string("OpenCL error in ")+std::string(file)+":"+std::to_string(line);
		std::string msg="OpenCL error ";
		if(file!=NULL)
		{
			msg+="in ";
			msg+=file;
			msg+=":"+std::to_string(line)+" ret=";
		}
		msg+=ret_str(ret);
		throw std::runtime_error(msg);
	}
...
}

трансляция кода ошибки в строку
кусок кода вывода подробного сообщения об ошибке компиляции .cl файла с kernel
CL_RET_IGNORE(CL_BUILD_PROGRAM_FAILURE) = clBuildProgram(program, 1, &device_id, NULL, NULL, NULL);
    if(main_cl.ret==CL_BUILD_PROGRAM_FAILURE)
    {
    	size_t build_log_len;
    	CL_RET = clGetProgramBuildInfo(program, device_id, CL_PROGRAM_BUILD_LOG, 0, NULL, &build_log_len);
    	char buff_erro[build_log_len];
        CL_RET = clGetProgramBuildInfo(program, device_id, CL_PROGRAM_BUILD_LOG, build_log_len, buff_erro, NULL);
        std::cerr << buff_erro;
    	CL_RET = CL_BUILD_PROGRAM_FAILURE; // компиляция завершена с ошибкой но чтобы вывести лог компиляции выход отложили
    }


Использовать так
CL_RET = clGetPlatformIDs(MAX_PLATFORMS, platforms_id, &ret_num_platform);

или так
program = clCreateProgramWithSource(context, 1, (const char **)&cstr, (const size_t *)&source_size, &ret);
CL_RET=ret;

будет вызвано исключение с подробным сообщением об ошибке и его месте в коде

соединять c-style код с c++ std не сложно, в случае с opencl тебе и так придется так или иначе выходить за рамки абстракций и опускаться до работы с буферами памяти... так зачем лишние прослойки
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы