1 //---------------------------------------------------------------------------//
2 // Copyright (c) 2013 Kyle Lutz <kyle.r.lutz@gmail.com>
4 // Distributed under the Boost Software License, Version 1.0
5 // See accompanying file LICENSE_1_0.txt or copy at
6 // http://www.boost.org/LICENSE_1_0.txt
8 // See http://boostorg.github.com/compute for more information.
9 //---------------------------------------------------------------------------//
11 #define BOOST_TEST_MODULE TestProgram
12 #include <boost/test/unit_test.hpp>
14 // disable the automatic kernel compilation debug messages. this allows the
15 // test for program to check that compilation error exceptions are properly
16 // thrown when invalid kernel code is passed to program::build().
17 #undef BOOST_COMPUTE_DEBUG_KERNEL_COMPILATION
19 #include <boost/compute/exception/program_build_failure.hpp>
20 #include <boost/compute/kernel.hpp>
21 #include <boost/compute/system.hpp>
22 #include <boost/compute/program.hpp>
23 #include <boost/compute/utility/source.hpp>
26 #include "context_setup.hpp"
28 namespace compute
= boost::compute
;
31 "__kernel void foo(__global float *x, const uint n) { }\n"
32 "__kernel void bar(__global int *x, __global int *y) { }\n";
35 BOOST_AUTO_TEST_CASE(get_program_info
)
38 boost::compute::program program
=
39 boost::compute::program::create_with_source(source
, context
);
45 #ifndef BOOST_COMPUTE_USE_OFFLINE_CACHE
46 BOOST_CHECK(program
.source().empty() == false);
48 BOOST_CHECK(program
.get_context() == context
);
51 BOOST_AUTO_TEST_CASE(program_source
)
53 // create program from source
54 boost::compute::program program
=
55 boost::compute::program::create_with_source(source
, context
);
57 BOOST_CHECK_EQUAL(std::string(source
), program
.source());
60 BOOST_AUTO_TEST_CASE(program_multiple_sources
)
62 std::vector
<std::string
> sources
;
63 sources
.push_back("__kernel void foo(__global int* x) { }\n");
64 sources
.push_back("__kernel void bar(__global float* y) { }\n");
66 // create program from sources
67 boost::compute::program program
=
68 boost::compute::program::create_with_source(sources
, context
);
71 boost::compute::kernel foo
= program
.create_kernel("foo");
72 boost::compute::kernel bar
= program
.create_kernel("bar");
75 BOOST_AUTO_TEST_CASE(program_source_no_file
)
77 // create program from a non-existant source file
78 // and verifies it throws.
79 BOOST_CHECK_THROW(boost::compute::program program
=
80 boost::compute::program::create_with_source_file
81 (std::string(), context
),
82 std::ios_base::failure
);
85 BOOST_AUTO_TEST_CASE(create_kernel
)
87 boost::compute::program program
=
88 boost::compute::program::create_with_source(source
, context
);
91 boost::compute::kernel foo
= program
.create_kernel("foo");
92 boost::compute::kernel bar
= program
.create_kernel("bar");
94 // try to create a kernel that doesn't exist
95 BOOST_CHECK_THROW(program
.create_kernel("baz"), boost::compute::opencl_error
);
98 BOOST_AUTO_TEST_CASE(create_with_binary
)
100 // create program from source
101 boost::compute::program source_program
=
102 boost::compute::program::create_with_source(source
, context
);
103 source_program
.build();
105 // create kernels in source program
106 boost::compute::kernel source_foo_kernel
= source_program
.create_kernel("foo");
107 boost::compute::kernel source_bar_kernel
= source_program
.create_kernel("bar");
109 // check source kernels
110 BOOST_CHECK_EQUAL(source_foo_kernel
.name(), std::string("foo"));
111 BOOST_CHECK_EQUAL(source_bar_kernel
.name(), std::string("bar"));
114 std::vector
<unsigned char> binary
= source_program
.binary();
116 // create program from binary
117 boost::compute::program binary_program
=
118 boost::compute::program::create_with_binary(binary
, context
);
119 binary_program
.build();
121 // create kernels in binary program
122 boost::compute::kernel binary_foo_kernel
= binary_program
.create_kernel("foo");
123 boost::compute::kernel binary_bar_kernel
= binary_program
.create_kernel("bar");
125 // check binary kernels
126 BOOST_CHECK_EQUAL(binary_foo_kernel
.name(), std::string("foo"));
127 BOOST_CHECK_EQUAL(binary_bar_kernel
.name(), std::string("bar"));
130 #ifdef BOOST_COMPUTE_CL_VERSION_2_1
131 BOOST_AUTO_TEST_CASE(create_with_il
)
133 REQUIRES_OPENCL_VERSION(2, 1);
135 size_t device_address_space_size
= device
.address_bits();
136 std::string
file_path(BOOST_COMPUTE_TEST_DATA_PATH
);
137 if(device_address_space_size
== 64)
139 file_path
+= "/program.spirv64";
143 file_path
+= "/program.spirv32";
146 // create program from il
147 boost::compute::program il_program
;
148 BOOST_CHECK_NO_THROW(
149 il_program
= boost::compute::program::create_with_il_file(
153 BOOST_CHECK_NO_THROW(il_program
.build());
155 // create kernel (to check if program was loaded correctly)
156 BOOST_CHECK_NO_THROW(il_program
.create_kernel("foobar"));
159 BOOST_AUTO_TEST_CASE(get_program_il_binary
)
161 REQUIRES_OPENCL_VERSION(2, 1);
163 size_t device_address_space_size
= device
.address_bits();
164 std::string
file_path(BOOST_COMPUTE_TEST_DATA_PATH
);
165 if(device_address_space_size
== 64)
167 file_path
+= "/program.spirv64";
171 file_path
+= "/program.spirv32";
174 // create program from il
175 boost::compute::program il_program
;
176 BOOST_CHECK_NO_THROW(
177 il_program
= boost::compute::program::create_with_il_file(
181 BOOST_CHECK_NO_THROW(il_program
.build());
183 std::vector
<unsigned char> il_binary
;
184 BOOST_CHECK_NO_THROW(il_binary
= il_program
.il_binary());
186 // create program from loaded il binary
187 BOOST_CHECK_NO_THROW(
188 il_program
= boost::compute::program::create_with_il(il_binary
, context
)
190 BOOST_CHECK_NO_THROW(il_program
.build());
192 // create kernel (to check if program was loaded correctly)
193 BOOST_CHECK_NO_THROW(il_program
.create_kernel("foobar"));
196 BOOST_AUTO_TEST_CASE(get_program_il_binary_empty
)
198 REQUIRES_OPENCL_VERSION(2, 1);
200 boost::compute::program program
;
201 BOOST_CHECK_NO_THROW(
202 program
= boost::compute::program::create_with_source(source
, context
)
204 BOOST_CHECK_NO_THROW(program
.build());
206 std::vector
<unsigned char> il_binary
;
207 il_binary
= program
.il_binary();
208 BOOST_CHECK(il_binary
.empty());
210 #endif // BOOST_COMPUTE_CL_VERSION_2_1
212 BOOST_AUTO_TEST_CASE(create_with_source_doctest
)
214 //! [create_with_source]
215 std::string source
= "__kernel void foo(__global int *data) { }";
217 boost::compute::program foo_program
=
218 boost::compute::program::create_with_source(source
, context
);
219 //! [create_with_source]
224 #ifdef BOOST_COMPUTE_CL_VERSION_1_2
225 BOOST_AUTO_TEST_CASE(compile_and_link
)
227 REQUIRES_OPENCL_VERSION(1,2);
229 if(!supports_compile_program(device
) || !supports_link_program(device
)) {
233 // create the library program
234 const char library_source
[] = BOOST_COMPUTE_STRINGIZE_SOURCE(
235 // for some reason the apple opencl compilers complains if a prototype
236 // for the square() function is not available, so we add it here
239 // generic square function definition
240 T
square(T x
) { return x
* x
; }
243 compute::program library_program
=
244 compute::program::create_with_source(library_source
, context
);
246 library_program
.compile("-DT=int");
248 // create the kernel program
249 const char kernel_source
[] = BOOST_COMPUTE_STRINGIZE_SOURCE(
250 // forward declare square function
251 extern int square(int);
253 // square kernel definition
254 __kernel
void square_kernel(__global
int *x
)
260 compute::program square_program
=
261 compute::program::create_with_source(kernel_source
, context
);
263 square_program
.compile();
266 std::vector
<compute::program
> programs
;
267 programs
.push_back(library_program
);
268 programs
.push_back(square_program
);
270 compute::program linked_program
=
271 compute::program::link(programs
, context
);
273 // create the square kernel
274 compute::kernel square_kernel
=
275 linked_program
.create_kernel("square_kernel");
276 BOOST_CHECK_EQUAL(square_kernel
.name(), "square_kernel");
279 BOOST_AUTO_TEST_CASE(compile_and_link_with_headers
)
281 REQUIRES_OPENCL_VERSION(1,2);
283 if(!supports_compile_program(device
) || !supports_link_program(device
)) {
287 // create the header programs
288 const char square_header_source
[] = BOOST_COMPUTE_STRINGIZE_SOURCE(
289 T
square(T x
) { return x
* x
; }
291 const char div2_header_source
[] = BOOST_COMPUTE_STRINGIZE_SOURCE(
292 T
div2(T x
) { return x
/ 2; }
295 compute::program square_header_program
=
296 compute::program::create_with_source(square_header_source
, context
);
297 compute::program div2_header_program
=
298 compute::program::create_with_source(div2_header_source
, context
);
300 // create the kernel program
301 const char kernel_source
[] =
302 "#include \"square.h\"\n"
303 "#include \"div2.h\"\n"
304 "__kernel void squareby2_kernel(__global int *x)"
306 " x[0] = div2(square(x[0]));"
309 compute::program square_program
=
310 compute::program::create_with_source(kernel_source
, context
);
312 std::vector
<std::pair
<std::string
, compute::program
> > header_programs
;
313 header_programs
.push_back(std::make_pair("square.h", square_header_program
));
314 header_programs
.push_back(std::make_pair("div2.h", div2_header_program
));
316 square_program
.compile("-DT=int", header_programs
);
319 std::vector
<compute::program
> programs
;
320 programs
.push_back(square_program
);
322 compute::program linked_program
=
323 compute::program::link(programs
, context
);
325 // create the square kernel
326 compute::kernel square_kernel
=
327 linked_program
.create_kernel("squareby2_kernel");
328 BOOST_CHECK_EQUAL(square_kernel
.name(), "squareby2_kernel");
330 #endif // BOOST_COMPUTE_CL_VERSION_1_2
332 BOOST_AUTO_TEST_CASE(build_log
)
334 const char invalid_source
[] =
335 "__kernel void foo(__global int *input) { !@#$%^&*() }";
337 compute::program invalid_program
=
338 compute::program::create_with_source(invalid_source
, context
);
341 invalid_program
.build();
343 // should not get here
346 catch(compute::opencl_error
&){
347 std::string log
= invalid_program
.build_log();
348 BOOST_CHECK(!log
.empty());
352 BOOST_AUTO_TEST_CASE(program_build_exception
)
354 const char invalid_source
[] =
355 "__kernel void foo(__global int *input) { !@#$%^&*() }";
357 compute::program invalid_program
=
358 compute::program::create_with_source(invalid_source
, context
);
360 BOOST_CHECK_THROW(invalid_program
.build(),
361 compute::program_build_failure
);
364 // POCL bug: https://github.com/pocl/pocl/issues/577
365 if(pocl_bug_issue_577(device
))
368 compute::program::create_with_source(invalid_source
, context
);
370 invalid_program
.build();
372 // should not get here
375 catch(compute::program_build_failure
& e
){
376 BOOST_CHECK(e
.build_log() == invalid_program
.build_log());
380 // should not get here
385 BOOST_AUTO_TEST_CASE(build_with_source_exception
)
387 const char invalid_source
[] =
388 "__kernel void foo(__global int *input) { !@#$%^&*() }";
390 BOOST_CHECK_THROW(compute::program::build_with_source(invalid_source
, context
),
391 compute::program_build_failure
);
394 BOOST_AUTO_TEST_CASE(build_with_source_file_exception
)
396 std::string
file_path(BOOST_COMPUTE_TEST_DATA_PATH
"/invalid_program.cl");
397 BOOST_CHECK_THROW(compute::program::build_with_source_file(file_path
, context
),
398 compute::program_build_failure
);
401 BOOST_AUTO_TEST_SUITE_END()