test_program.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401
  1. //---------------------------------------------------------------------------//
  2. // Copyright (c) 2013 Kyle Lutz <kyle.r.lutz@gmail.com>
  3. //
  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
  7. //
  8. // See http://boostorg.github.com/compute for more information.
  9. //---------------------------------------------------------------------------//
  10. #define BOOST_TEST_MODULE TestProgram
  11. #include <boost/test/unit_test.hpp>
  12. // disable the automatic kernel compilation debug messages. this allows the
  13. // test for program to check that compilation error exceptions are properly
  14. // thrown when invalid kernel code is passed to program::build().
  15. #undef BOOST_COMPUTE_DEBUG_KERNEL_COMPILATION
  16. #include <boost/compute/exception/program_build_failure.hpp>
  17. #include <boost/compute/kernel.hpp>
  18. #include <boost/compute/system.hpp>
  19. #include <boost/compute/program.hpp>
  20. #include <boost/compute/utility/source.hpp>
  21. #include "quirks.hpp"
  22. #include "context_setup.hpp"
  23. namespace compute = boost::compute;
  24. const char source[] =
  25. "__kernel void foo(__global float *x, const uint n) { }\n"
  26. "__kernel void bar(__global int *x, __global int *y) { }\n";
  27. BOOST_AUTO_TEST_CASE(get_program_info)
  28. {
  29. // create program
  30. boost::compute::program program =
  31. boost::compute::program::create_with_source(source, context);
  32. // build program
  33. program.build();
  34. // check program info
  35. #ifndef BOOST_COMPUTE_USE_OFFLINE_CACHE
  36. BOOST_CHECK(program.source().empty() == false);
  37. #endif
  38. BOOST_CHECK(program.get_context() == context);
  39. }
  40. BOOST_AUTO_TEST_CASE(program_source)
  41. {
  42. // create program from source
  43. boost::compute::program program =
  44. boost::compute::program::create_with_source(source, context);
  45. BOOST_CHECK_EQUAL(std::string(source), program.source());
  46. }
  47. BOOST_AUTO_TEST_CASE(program_multiple_sources)
  48. {
  49. std::vector<std::string> sources;
  50. sources.push_back("__kernel void foo(__global int* x) { }\n");
  51. sources.push_back("__kernel void bar(__global float* y) { }\n");
  52. // create program from sources
  53. boost::compute::program program =
  54. boost::compute::program::create_with_source(sources, context);
  55. program.build();
  56. boost::compute::kernel foo = program.create_kernel("foo");
  57. boost::compute::kernel bar = program.create_kernel("bar");
  58. }
  59. BOOST_AUTO_TEST_CASE(program_source_no_file)
  60. {
  61. // create program from a non-existant source file
  62. // and verifies it throws.
  63. BOOST_CHECK_THROW(boost::compute::program program =
  64. boost::compute::program::create_with_source_file
  65. (std::string(), context),
  66. std::ios_base::failure);
  67. }
  68. BOOST_AUTO_TEST_CASE(create_kernel)
  69. {
  70. boost::compute::program program =
  71. boost::compute::program::create_with_source(source, context);
  72. program.build();
  73. boost::compute::kernel foo = program.create_kernel("foo");
  74. boost::compute::kernel bar = program.create_kernel("bar");
  75. // try to create a kernel that doesn't exist
  76. BOOST_CHECK_THROW(program.create_kernel("baz"), boost::compute::opencl_error);
  77. }
  78. BOOST_AUTO_TEST_CASE(create_with_binary)
  79. {
  80. // create program from source
  81. boost::compute::program source_program =
  82. boost::compute::program::create_with_source(source, context);
  83. source_program.build();
  84. // create kernels in source program
  85. boost::compute::kernel source_foo_kernel = source_program.create_kernel("foo");
  86. boost::compute::kernel source_bar_kernel = source_program.create_kernel("bar");
  87. // check source kernels
  88. BOOST_CHECK_EQUAL(source_foo_kernel.name(), std::string("foo"));
  89. BOOST_CHECK_EQUAL(source_bar_kernel.name(), std::string("bar"));
  90. // get binary
  91. std::vector<unsigned char> binary = source_program.binary();
  92. // create program from binary
  93. boost::compute::program binary_program =
  94. boost::compute::program::create_with_binary(binary, context);
  95. binary_program.build();
  96. // create kernels in binary program
  97. boost::compute::kernel binary_foo_kernel = binary_program.create_kernel("foo");
  98. boost::compute::kernel binary_bar_kernel = binary_program.create_kernel("bar");
  99. // check binary kernels
  100. BOOST_CHECK_EQUAL(binary_foo_kernel.name(), std::string("foo"));
  101. BOOST_CHECK_EQUAL(binary_bar_kernel.name(), std::string("bar"));
  102. }
  103. #ifdef BOOST_COMPUTE_CL_VERSION_2_1
  104. BOOST_AUTO_TEST_CASE(create_with_il)
  105. {
  106. REQUIRES_OPENCL_VERSION(2, 1);
  107. size_t device_address_space_size = device.address_bits();
  108. std::string file_path(BOOST_COMPUTE_TEST_DATA_PATH);
  109. if(device_address_space_size == 64)
  110. {
  111. file_path += "/program.spirv64";
  112. }
  113. else
  114. {
  115. file_path += "/program.spirv32";
  116. }
  117. // create program from il
  118. boost::compute::program il_program;
  119. BOOST_CHECK_NO_THROW(
  120. il_program = boost::compute::program::create_with_il_file(
  121. file_path, context
  122. )
  123. );
  124. BOOST_CHECK_NO_THROW(il_program.build());
  125. // create kernel (to check if program was loaded correctly)
  126. BOOST_CHECK_NO_THROW(il_program.create_kernel("foobar"));
  127. }
  128. BOOST_AUTO_TEST_CASE(get_program_il_binary)
  129. {
  130. REQUIRES_OPENCL_VERSION(2, 1);
  131. size_t device_address_space_size = device.address_bits();
  132. std::string file_path(BOOST_COMPUTE_TEST_DATA_PATH);
  133. if(device_address_space_size == 64)
  134. {
  135. file_path += "/program.spirv64";
  136. }
  137. else
  138. {
  139. file_path += "/program.spirv32";
  140. }
  141. // create program from il
  142. boost::compute::program il_program;
  143. BOOST_CHECK_NO_THROW(
  144. il_program = boost::compute::program::create_with_il_file(
  145. file_path, context
  146. )
  147. );
  148. BOOST_CHECK_NO_THROW(il_program.build());
  149. std::vector<unsigned char> il_binary;
  150. BOOST_CHECK_NO_THROW(il_binary = il_program.il_binary());
  151. // create program from loaded il binary
  152. BOOST_CHECK_NO_THROW(
  153. il_program = boost::compute::program::create_with_il(il_binary, context)
  154. );
  155. BOOST_CHECK_NO_THROW(il_program.build());
  156. // create kernel (to check if program was loaded correctly)
  157. BOOST_CHECK_NO_THROW(il_program.create_kernel("foobar"));
  158. }
  159. BOOST_AUTO_TEST_CASE(get_program_il_binary_empty)
  160. {
  161. REQUIRES_OPENCL_VERSION(2, 1);
  162. boost::compute::program program;
  163. BOOST_CHECK_NO_THROW(
  164. program = boost::compute::program::create_with_source(source, context)
  165. );
  166. BOOST_CHECK_NO_THROW(program.build());
  167. std::vector<unsigned char> il_binary;
  168. il_binary = program.il_binary();
  169. BOOST_CHECK(il_binary.empty());
  170. }
  171. #endif // BOOST_COMPUTE_CL_VERSION_2_1
  172. BOOST_AUTO_TEST_CASE(create_with_source_doctest)
  173. {
  174. //! [create_with_source]
  175. std::string source = "__kernel void foo(__global int *data) { }";
  176. boost::compute::program foo_program =
  177. boost::compute::program::create_with_source(source, context);
  178. //! [create_with_source]
  179. foo_program.build();
  180. }
  181. #ifdef BOOST_COMPUTE_CL_VERSION_1_2
  182. BOOST_AUTO_TEST_CASE(compile_and_link)
  183. {
  184. REQUIRES_OPENCL_VERSION(1,2);
  185. if(!supports_compile_program(device) || !supports_link_program(device)) {
  186. return;
  187. }
  188. // create the library program
  189. const char library_source[] = BOOST_COMPUTE_STRINGIZE_SOURCE(
  190. // for some reason the apple opencl compilers complains if a prototype
  191. // for the square() function is not available, so we add it here
  192. T square(T);
  193. // generic square function definition
  194. T square(T x) { return x * x; }
  195. );
  196. compute::program library_program =
  197. compute::program::create_with_source(library_source, context);
  198. library_program.compile("-DT=int");
  199. // create the kernel program
  200. const char kernel_source[] = BOOST_COMPUTE_STRINGIZE_SOURCE(
  201. // forward declare square function
  202. extern int square(int);
  203. // square kernel definition
  204. __kernel void square_kernel(__global int *x)
  205. {
  206. x[0] = square(x[0]);
  207. }
  208. );
  209. compute::program square_program =
  210. compute::program::create_with_source(kernel_source, context);
  211. square_program.compile();
  212. // link the programs
  213. std::vector<compute::program> programs;
  214. programs.push_back(library_program);
  215. programs.push_back(square_program);
  216. compute::program linked_program =
  217. compute::program::link(programs, context);
  218. // create the square kernel
  219. compute::kernel square_kernel =
  220. linked_program.create_kernel("square_kernel");
  221. BOOST_CHECK_EQUAL(square_kernel.name(), "square_kernel");
  222. }
  223. BOOST_AUTO_TEST_CASE(compile_and_link_with_headers)
  224. {
  225. REQUIRES_OPENCL_VERSION(1,2);
  226. if(!supports_compile_program(device) || !supports_link_program(device)) {
  227. return;
  228. }
  229. // create the header programs
  230. const char square_header_source[] = BOOST_COMPUTE_STRINGIZE_SOURCE(
  231. T square(T x) { return x * x; }
  232. );
  233. const char div2_header_source[] = BOOST_COMPUTE_STRINGIZE_SOURCE(
  234. T div2(T x) { return x / 2; }
  235. );
  236. compute::program square_header_program =
  237. compute::program::create_with_source(square_header_source, context);
  238. compute::program div2_header_program =
  239. compute::program::create_with_source(div2_header_source, context);
  240. // create the kernel program
  241. const char kernel_source[] =
  242. "#include \"square.h\"\n"
  243. "#include \"div2.h\"\n"
  244. "__kernel void squareby2_kernel(__global int *x)"
  245. "{"
  246. " x[0] = div2(square(x[0]));"
  247. "}";
  248. compute::program square_program =
  249. compute::program::create_with_source(kernel_source, context);
  250. std::vector<std::pair<std::string, compute::program> > header_programs;
  251. header_programs.push_back(std::make_pair("square.h", square_header_program));
  252. header_programs.push_back(std::make_pair("div2.h", div2_header_program));
  253. square_program.compile("-DT=int", header_programs);
  254. // link program
  255. std::vector<compute::program> programs;
  256. programs.push_back(square_program);
  257. compute::program linked_program =
  258. compute::program::link(programs, context);
  259. // create the square kernel
  260. compute::kernel square_kernel =
  261. linked_program.create_kernel("squareby2_kernel");
  262. BOOST_CHECK_EQUAL(square_kernel.name(), "squareby2_kernel");
  263. }
  264. #endif // BOOST_COMPUTE_CL_VERSION_1_2
  265. BOOST_AUTO_TEST_CASE(build_log)
  266. {
  267. const char invalid_source[] =
  268. "__kernel void foo(__global int *input) { !@#$%^&*() }";
  269. compute::program invalid_program =
  270. compute::program::create_with_source(invalid_source, context);
  271. try {
  272. invalid_program.build();
  273. // should not get here
  274. BOOST_CHECK(false);
  275. }
  276. catch(compute::opencl_error&){
  277. std::string log = invalid_program.build_log();
  278. BOOST_CHECK(!log.empty());
  279. }
  280. }
  281. BOOST_AUTO_TEST_CASE(program_build_exception)
  282. {
  283. const char invalid_source[] =
  284. "__kernel void foo(__global int *input) { !@#$%^&*() }";
  285. compute::program invalid_program =
  286. compute::program::create_with_source(invalid_source, context);
  287. BOOST_CHECK_THROW(invalid_program.build(),
  288. compute::program_build_failure);
  289. try {
  290. // POCL bug: https://github.com/pocl/pocl/issues/577
  291. if(pocl_bug_issue_577(device))
  292. {
  293. invalid_program =
  294. compute::program::create_with_source(invalid_source, context);
  295. }
  296. invalid_program.build();
  297. // should not get here
  298. BOOST_CHECK(false);
  299. }
  300. catch(compute::program_build_failure& e){
  301. BOOST_CHECK(e.build_log() == invalid_program.build_log());
  302. }
  303. catch(...)
  304. {
  305. // should not get here
  306. BOOST_CHECK(false);
  307. }
  308. }
  309. BOOST_AUTO_TEST_CASE(build_with_source_exception)
  310. {
  311. const char invalid_source[] =
  312. "__kernel void foo(__global int *input) { !@#$%^&*() }";
  313. BOOST_CHECK_THROW(compute::program::build_with_source(invalid_source, context),
  314. compute::program_build_failure);
  315. }
  316. BOOST_AUTO_TEST_CASE(build_with_source_file_exception)
  317. {
  318. std::string file_path(BOOST_COMPUTE_TEST_DATA_PATH "/invalid_program.cl");
  319. BOOST_CHECK_THROW(compute::program::build_with_source_file(file_path, context),
  320. compute::program_build_failure);
  321. }
  322. BOOST_AUTO_TEST_SUITE_END()