C++ Library Extensions 2022.12.09
To help learn modern C++ programming
cpg_opencl_sycl.hpp
Go to the documentation of this file.
1/*
2 Author: Thomas Kim 김창희
3 First Edit: Jan. 25, 2022
4*/
5
6#ifndef _CPG_OPENCL_SYCL_HPP
7#define _CPG_OPENCL_SYCL_HPP
8
9#ifndef NOMINMAX
10#define NOMINMAX
11#endif
12
13#include "cpg_types.hpp"
14
15#ifndef __SYCL_INTERNAL_API
16 #define __SYCL_INTERNAL_API
17#endif
18
19#include <cl/sycl.hpp>
20#include <tbb/tbb.h>
21#include <regex>
22
24{
25 namespace cgt = cpg::types;
26
27 using device_info = sycl::info::device;
28 using access = sycl::access::mode;
29
30 namespace hidden
31 {
32 template<typename = int>
33 std::string file_contents(const char* fileName)
34 {
35 std::ifstream kernelFile(fileName, std::ios::in);
36
37 if (!kernelFile.is_open())
38 {
39 std::cout << "Failed to open file for reading: "
40 << fileName << std::endl;
41
42 return "";
43 }
44
45 std::ostringstream oss;
46 oss << kernelFile.rdbuf();
47 std::string srcStdStr = oss.str();
48
49 if(srcStdStr.back() != '\n') srcStdStr.push_back('\n');
50
51 if(srcStdStr[0] == (char)0xEF && srcStdStr[1] == (char)0xBB && srcStdStr[2] == (char)0xBF)
52 return std::string( &srcStdStr[3] );
53 else
54 return srcStdStr;
55 }
56
57 template<typename StringType>
58 auto count_lines(StringType& src)
59 {
60 std::size_t lines = 0;
61
62 for(auto c: src) if(c == '\n') ++lines;
63
64 return lines;
65 }
66
67 template<typename FileNameType, typename CountType, std::size_t N,
68 typename StringType>
69 auto error_line_file_name(std::array<FileNameType, N> const&
70 file_names, std::array<CountType, N> const& line_counts, StringType error_line_str)
71 {
72 std::size_t error_line = std::stoll(error_line_str);
73 std::size_t error_file_index = 0;
74
75 for(std::size_t i = 1; i < N; ++i)
76 {
77 if(line_counts[i-1] < error_line &&
78 error_line <= line_counts[i])
79 {
80 error_line -= line_counts[i-1];
81 error_file_index = i; break;
82 }
83 }
84
85 std::ostringstream oss;
86 oss << error_line;
87
88 return std::tuple{ oss.str(), file_names[error_file_index] };
89 }
90
91 template<typename CharType>
92 std::basic_string<CharType> replace_string(std::basic_string<CharType> target,
93 std::basic_string<CharType> const& str_find, std::basic_string<CharType> const& str_replace)
94 {
95 auto pos = target.find(str_find);
96
97 if(pos != std::basic_string<CharType>::npos)
98 return target.replace(pos, str_find.size(), str_replace);
99 else
100 return target;
101 }
102
103 template<typename FileNameType, typename CountType, std::size_t N,
104 typename StringType>
105 auto parse_error_message(std::array<FileNameType, N> const&
106 file_names, std::array<CountType, N> const& line_counts, StringType error_msg)
107 {
108 // 1:11:5: error:, 1:20:5: warning:
109 std::regex pattern{ R"((\d+):(\d+):(\d+):)" };
110
111 auto result = error_msg;
112
113 for(std::sregex_iterator p{error_msg.begin(), error_msg.end(), pattern};
114 p != std::sregex_iterator{}; ++p)
115 {
116 auto& m = *p;
117
118 auto [line, filename] = error_line_file_name(file_names, line_counts, m[2].str());
119
120 std::ostringstream oss;
121 oss<<"[" << filename <<"] "
122 << line <<":"
123 << m[3].str()<<":";
124
125 result = replace_string(result, m.str(), oss.str());
126 }
127
128 return result;
129 }
130
131 template<typename... OpenCLFiles>
132 cl_program CreateProgram(cl_context context, cl_device_id device, OpenCLFiles... opencl_files)
133 {
134 cl_int errNum;
135 cl_program program;
136
137 constexpr std::size_t FileCount = sizeof...(opencl_files);
138
139 std::array src_files{ opencl_files... };
140
141 std::array std_file_contents { file_contents(opencl_files) ... };
142
143 auto srcStr = cgt::for_stallion<FileCount>(
144 [&std_file_contents]<auto... i>( cgt::sequence<i...>)
145 {
146 return std::array{ std_file_contents[i].c_str()... };
147 } );
148
149 program =
150 clCreateProgramWithSource(context, FileCount, srcStr.data(), NULL, NULL);
151
152 if(program == NULL)
153 {
154 std::cout << "Failed to create CL program from source." << std::endl;
155 return NULL;
156 }
157
158 errNum = clBuildProgram(program, 0, NULL, NULL, NULL, NULL);
159
160 if (errNum != CL_SUCCESS)
161 {
162 std::size_t N;
163
164 auto line_counts =
165 cgt::for_stallion<FileCount>([&std_file_contents]<auto... i>(cgt::sequence<i...>)
166 {
167 return std::array{ count_lines(std_file_contents[i])... };
168 });
169
170 for(std::size_t i = 1; i < FileCount; ++i)
171 line_counts[i] += line_counts[i-1];
172
173 // https://www.khronos.org/registry/OpenCL//sdk/2.2/docs/man/html/clGetProgramBuildInfo.html
174 clGetProgramBuildInfo(program, device, CL_PROGRAM_BUILD_LOG, 0, nullptr, &N);
175
176 std::string buildLog(N, ' ');
177
178 clGetProgramBuildInfo(program, device, CL_PROGRAM_BUILD_LOG, N, buildLog.data(), NULL);
179
180 buildLog = parse_error_message(src_files, line_counts, buildLog);
181
182 std::cout << buildLog;
183
184 clReleaseProgram(program);
185
186 return NULL;
187 }
188 else
189 return program;
190 }
191
192 }
193 // end of namespace hidden
194
195 template<typename SycleQueue, typename... OpenCLFiles>
196 auto create_program(SycleQueue& queue, OpenCLFiles... opencl_files)
197 {
198 auto context = queue.get_context();
199 auto device = queue.get_device();
200
201 auto program = cgt::raii_create_object(
202 hidden::CreateProgram(context.get(), device.get(),
203 opencl_files...), clReleaseProgram);
204
205 if(program)
206 clBuildProgram(program.get(), 0, nullptr, nullptr, nullptr, nullptr);
207
208 return program;
209 }
210
211 template<typename ProgramType>
212 auto create_kernel(ProgramType& program, const char* kernel_name)
213 {
215 clCreateKernel(program.get(), kernel_name, nullptr), clReleaseKernel);
216 }
217
218 auto sycl_kernel(auto& opencl_kernel, auto& queue)
219 {
220 return sycl::kernel{ opencl_kernel.get(), queue.get_context() };
221 }
222}
223// end of namespace cpg::sycl
224#endif // end of file _CPG_OPENCL_SYCL_HPP
auto & cout
auto & endl
auto count_lines(StringType &src)
cl_program CreateProgram(cl_context context, cl_device_id device, OpenCLFiles... opencl_files)
auto parse_error_message(std::array< FileNameType, N > const &file_names, std::array< CountType, N > const &line_counts, StringType error_msg)
std::basic_string< CharType > replace_string(std::basic_string< CharType > target, std::basic_string< CharType > const &str_find, std::basic_string< CharType > const &str_replace)
std::string file_contents(const char *fileName)
auto error_line_file_name(std::array< FileNameType, N > const &file_names, std::array< CountType, N > const &line_counts, StringType error_line_str)
auto sycl_kernel(auto &opencl_kernel, auto &queue)
auto create_program(SycleQueue &queue, OpenCLFiles... opencl_files)
sycl::access::mode access
auto create_kernel(ProgramType &program, const char *kernel_name)
sycl::info::device device_info
auto raii_create_object(PointerType object_ptr, FuncType func)
Definition: cpg_types.hpp:934
std::integer_sequence< std::common_type_t< std::remove_cvref_t< decltype(Indices)>... >, Indices... > sequence
Definition: cpg_types.hpp:2665