cf4ocl (C Framework for OpenCL)  v2.1.0
Object-oriented framework for developing and benchmarking OpenCL projects in C/C++
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
ccl_program_wrapper.c
Go to the documentation of this file.
1 /*
2  * This file is part of cf4ocl (C Framework for OpenCL).
3  *
4  * cf4ocl is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU Lesser General Public License as
6  * published by the Free Software Foundation, either version 3 of the
7  * License, or (at your option) any later version.
8  *
9  * cf4ocl is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with cf4ocl. If not, see
16  * <http://www.gnu.org/licenses/>.
17  * */
18 
29 #include "ccl_program_wrapper.h"
30 #include "_ccl_abstract_dev_container_wrapper.h"
31 #include "_ccl_defs.h"
32 
33 /* Valid file name characters. */
34 #define CCL_VALIDFILECHARS "abcdefghijklmnopqrstuvwxyzABCDEFGH" \
35  "IJKLMNOPQRSTUVWXYZ0123456789_."
36 
42 struct ccl_program {
43 
48  CCLDevContainer base;
49 
54  GHashTable* binaries;
55 
60  GHashTable* krnls;
61 
66  GHashTable* build_logs;
67 
72  gchar* build_logs_concat;
73 
74 };
75 
81 
86  unsigned char* data;
87 
92  size_t size;
93 };
94 
103 static void ccl_program_clear_build_logs(CCLProgram* prg) {
104 
105  /* Make sure prg is not NULL. */
106  g_return_if_fail(prg != NULL);
107 
108  /* If the build logs table was created... */
109  if (prg->build_logs != NULL) {
110 
111  /*...free it and the included logs. */
112  g_hash_table_destroy(prg->build_logs);
113 
114  /* Set to NULL to allow reuse. */
115  prg->build_logs = NULL;
116 
117  }
118 }
119 
129 static void ccl_program_release_fields(CCLProgram* prg) {
130 
131  /* Make sure prg wrapper object is not NULL. */
132  g_return_if_fail(prg != NULL);
133 
134  /* Release devices. */
135  ccl_dev_container_release_devices((CCLDevContainer*) prg);
136 
137  /* If the kernels table was created...*/
138  if (prg->krnls != NULL) {
139 
140  /* ...free the kernel table and reduce reference count of
141  * kernels in table (this is done automatically by the
142  * ccl_kernel_destroy() function passed as a destructor
143  * parameter during table creation). */
144  g_hash_table_destroy(prg->krnls);
145 
146  }
147 
148  /* If the binaries table was created... */
149  if (prg->binaries != NULL) {
150 
151  /*...free it and the included binaries. */
152  g_hash_table_destroy(prg->binaries);
153 
154  }
155 
156  /* Destroy table of build logs. */
157  ccl_program_clear_build_logs(prg);
158 
159  /* If there is a concatenated build log... */
160  if (prg->build_logs_concat != NULL) {
161 
162  /*...free it. */
163  g_free(prg->build_logs_concat);
164 
165  }
166 
167 }
168 
182 static CCLWrapperInfo* ccl_program_get_cldevices(
183  CCLDevContainer* devcon, CCLErr** err) {
184 
185  return ccl_program_get_info(devcon, CL_PROGRAM_DEVICES, err);
186 }
187 
198 static CCLProgramBinary* ccl_program_binary_new(
199  unsigned char* data, size_t size) {
200 
201  CCLProgramBinary* pbin = g_slice_new(CCLProgramBinary);
202 
203  pbin->data = data;
204  pbin->size = size;
205 
206  return pbin;
207 
208 }
209 
218 static void ccl_program_binary_destroy(CCLProgramBinary* pbin) {
219 
220  /* Make sure pbin is not NULL. */
221  g_return_if_fail(pbin != NULL);
222 
223  if (pbin->size > 0)
224  g_free(pbin->data);
225  g_slice_free(CCLProgramBinary, pbin);
226 
227 }
228 
235 #define ccl_program_binary_new_empty() ccl_program_binary_new(NULL, 0)
236 
259 CCL_EXPORT
260 CCLProgram* ccl_program_new_wrap(cl_program program) {
261 
262  return (CCLProgram*) ccl_wrapper_new(
263  CCL_PROGRAM, (void*) program, sizeof(CCLProgram));
264 
265 }
266 
275 CCL_EXPORT
277 
278  ccl_wrapper_unref((CCLWrapper*) prg, sizeof(CCLProgram),
279  (ccl_wrapper_release_fields) ccl_program_release_fields,
280  (ccl_wrapper_release_cl_object) clReleaseProgram, NULL);
281 
282 }
283 
297 CCL_EXPORT
299  const char* filename, CCLErr** err) {
300 
301  return ccl_program_new_from_source_files(ctx, 1, &(filename), err);
302 
303 }
304 
319 CCL_EXPORT
321  cl_uint count, const char** filenames, CCLErr** err) {
322 
323  /* Make sure ctx is not NULL. */
324  g_return_val_if_fail(ctx != NULL, NULL);
325  /* Make sure err is NULL or it is not set. */
326  g_return_val_if_fail(err == NULL || *err == NULL, NULL);
327  /* Make sure filenames is not NULL. */
328  g_return_val_if_fail(filenames != NULL, NULL);
329  /* Make sure count > 0. */
330  g_return_val_if_fail(count > 0, NULL);
331 
332  /* Error reporting object. */
333  CCLErr* err_internal = NULL;
334  /* Program wrapper object to return. */
335  CCLProgram* prg = NULL;
336  /* Source files contents. */
337  gchar** strings = NULL;
338 
339  /* Allocate space for the specified number of source file
340  * strings. */
341  strings = g_slice_alloc0(count * sizeof(gchar*));
342 
343  /* Read source files contents. */
344  for (cl_uint i = 0; i < count; ++i) {
345 
346  g_file_get_contents(
347  filenames[i], &strings[i], NULL, &err_internal);
348  ccl_if_err_propagate_goto(err, err_internal, error_handler);
349 
350  }
351 
352  /* Create program from sources. */
353  prg = ccl_program_new_from_sources(ctx, count,
354  (const char**) strings, NULL, &err_internal);
355  ccl_if_err_propagate_goto(err, err_internal, error_handler);
356 
357  /* If we got here, everything is OK. */
358  g_assert(err == NULL || *err == NULL);
359  goto finish;
360 
361 error_handler:
362 
363  /* If we got here there was an error, verify that it is so. */
364  g_assert(err == NULL || *err != NULL);
365 
366 finish:
367 
368  /* Free stuff. */
369  if (strings != NULL) {
370  for (cl_uint i = 0; i < count; ++i) {
371  if (strings[i] != NULL) {
372  g_free(strings[i]);
373  }
374  }
375  g_slice_free1(count * sizeof(gchar*), strings);
376  }
377 
378  /* Return prg. */
379  return prg;
380 
381 }
382 
397 CCL_EXPORT
399  const char* string, CCLErr** err) {
400 
401  return ccl_program_new_from_sources(ctx, 1, &string, NULL, err);
402 }
403 
422 CCL_EXPORT
424  cl_uint count, const char** strings, const size_t* lengths,
425  CCLErr** err) {
426 
427  /* Make sure ctx is not NULL. */
428  g_return_val_if_fail(ctx != NULL, NULL);
429  /* Make sure err is NULL or it is not set. */
430  g_return_val_if_fail(err == NULL || *err == NULL, NULL);
431 
432  cl_int ocl_status;
433  cl_program program = NULL;
434  CCLProgram* prg = NULL;
435 
436  /* Build program from sources. */
437  program = clCreateProgramWithSource(
438  ccl_context_unwrap(ctx), count, strings, lengths, &ocl_status);
440  CL_SUCCESS != ocl_status, ocl_status, error_handler,
441  "%s: unable to create cl_program with source (OpenCL error %d: %s).",
442  CCL_STRD, ocl_status, ccl_err(ocl_status));
443 
444  /* Wrap OpenCL program object. */
445  prg = ccl_program_new_wrap(program);
446 
447  /* If we got here, everything is OK. */
448  g_assert(err == NULL || *err == NULL);
449  goto finish;
450 
451 error_handler:
452 
453  /* If we got here there was an error, verify that it is so. */
454  g_assert(err == NULL || *err != NULL);
455 
456 finish:
457 
458  /* Return prg. */
459  return prg;
460 
461 }
462 
481 CCL_EXPORT
483  CCLDevice* dev, const char* filename, cl_int *binary_status,
484  CCLErr** err) {
485 
487  ctx, 1, &(dev), &(filename), binary_status, err);
488 }
489 
509 CCL_EXPORT
511  cl_uint num_devices, CCLDevice* const* devs, const char** filenames,
512  cl_int *binary_status, CCLErr** err) {
513 
514  /* Make sure err is NULL or it is not set. */
515  g_return_val_if_fail(err == NULL || *err == NULL, NULL);
516  /* Make sure ctx is not NULL. */
517  g_return_val_if_fail(ctx != NULL, NULL);
518  /* Make sure devs is not NULL. */
519  g_return_val_if_fail(devs != NULL, NULL);
520  /* Make sure filenames is not NULL. */
521  g_return_val_if_fail(filenames != NULL, NULL);
522  /* Make sure num_devices > 0. */
523  g_return_val_if_fail(num_devices > 0, NULL);
524 
525  CCLErr* err_internal = NULL;
526  CCLProgramBinary** bins = NULL;
527  CCLProgram* prg = NULL;
528 
529  /* Open files and create binaries. */
530  bins = g_slice_alloc0(num_devices * sizeof(CCLProgramBinary*));
531  for (cl_uint i = 0; i < num_devices; ++i) {
532  bins[i] = ccl_program_binary_new_empty();
533  g_file_get_contents(filenames[i], (char**) &bins[i]->data,
534  &bins[i]->size, &err_internal);
535  ccl_if_err_propagate_goto(err, err_internal, error_handler);
536  }
537 
538  /* Create program. */
540  ctx, num_devices, devs, bins, binary_status, &err_internal);
541  ccl_if_err_propagate_goto(err, err_internal, error_handler);
542 
543  /* If we got here, everything is OK. */
544  g_assert(err == NULL || *err == NULL);
545  goto finish;
546 
547 error_handler:
548 
549  /* If we got here there was an error, verify that it is so. */
550  g_assert(err == NULL || *err != NULL);
551 
552 finish:
553 
554  /* Free stuff if necessary. */
555  if (bins != NULL) {
556  for (cl_uint i = 0; i < num_devices; ++i) {
557  if (bins[i] != NULL) {
558  ccl_program_binary_destroy(bins[i]);
559  }
560  }
561  g_slice_free1(num_devices * sizeof(CCLProgramBinary*), bins);
562  }
563 
564  /* Return prg. */
565  return prg;
566 
567 }
568 
587 CCL_EXPORT
589  CCLProgramBinary* binary, cl_int *binary_status, CCLErr** err) {
590 
591  return ccl_program_new_from_binaries(ctx, 1, &dev, &binary,
592  binary_status, err);
593 }
594 
614 CCL_EXPORT
616  cl_uint num_devices, CCLDevice* const* devs, CCLProgramBinary** bins,
617  cl_int *binary_status, CCLErr** err) {
618 
619  /* Make sure err is NULL or it is not set. */
620  g_return_val_if_fail(err == NULL || *err == NULL, NULL);
621  /* Make sure ctx is not NULL. */
622  g_return_val_if_fail(ctx != NULL, NULL);
623  /* Make sure devs is not NULL. */
624  g_return_val_if_fail(devs != NULL, NULL);
625  /* Make sure num_devices > 0. */
626  g_return_val_if_fail(num_devices > 0, NULL);
627 
628  cl_int ocl_status;
629  CCLProgram* prg = NULL;
630  cl_program program = NULL;
631  cl_device_id* device_list = NULL;
632  size_t* lengths = NULL;
633  unsigned char** bins_raw = NULL;
634 
635  /* Unwrap devices, binaries and lengths. */
636  device_list = g_slice_alloc(num_devices * sizeof(cl_device_id));
637  lengths = g_slice_alloc(num_devices * sizeof(size_t));
638  bins_raw = g_slice_alloc(num_devices * sizeof(unsigned char*));
639  for (guint i = 0; i < num_devices; ++i) {
640  device_list[i] = ccl_device_unwrap(devs[i]);
641  lengths[i] = bins[i]->size;
642  bins_raw[i] = (unsigned char*) bins[i]->data;
643  }
644 
645  /* Create program. */
646  program = clCreateProgramWithBinary(ccl_context_unwrap(ctx),
647  num_devices, device_list, lengths,
648  (const unsigned char**) bins_raw,
649  binary_status, &ocl_status);
651  CL_SUCCESS != ocl_status, ocl_status, error_handler,
652  "%s: unable to create cl_program from binaries (OpenCL error %d: %s).",
653  CCL_STRD, ocl_status, ccl_err(ocl_status));
654 
655  /* Wrap OpenCL program object. */
656  prg = ccl_program_new_wrap(program);
657 
658  /* If we got here, everything is OK. */
659  g_assert(err == NULL || *err == NULL);
660  goto finish;
661 
662 error_handler:
663 
664  /* If we got here there was an error, verify that it is so. */
665  g_assert(err == NULL || *err != NULL);
666 
667 finish:
668 
669  /* Free stuff if necessary. */
670  if (device_list != NULL)
671  g_slice_free1(num_devices * sizeof(cl_device_id), device_list);
672  if (lengths != NULL)
673  g_slice_free1(num_devices * sizeof(size_t), lengths);
674  if (bins_raw != NULL)
675  g_slice_free1(num_devices * sizeof(unsigned char*), bins_raw);
676 
677  /* Return prg. */
678  return prg;
679 
680 }
681 
700 CCL_EXPORT
702  cl_uint num_devices, CCLDevice* const* devs, const char *kernel_names,
703  CCLErr** err) {
704 
705  /* Make sure ctx is not NULL. */
706  g_return_val_if_fail(ctx != NULL, NULL);
707  /* Make sure err is NULL or it is not set. */
708  g_return_val_if_fail(err == NULL || *err == NULL, NULL);
709  /* Make sure num_devices > 0. */
710  g_return_val_if_fail(num_devices > 0, NULL);
711 
712  /* OpenCL function return status. */
713  cl_int ocl_status;
714  /* OpenCL program object. */
715  cl_program program = NULL;
716  /* Program wrapper object. */
717  CCLProgram* prg = NULL;
718  /* List of cl_device_id objects. */
719  cl_device_id* device_list = NULL;
720  /* OpenCL version of underlying platform. */
721  cl_uint ocl_ver;
722  /* Internal error handling object. */
723  CCLErr* err_internal = NULL;
724 
725 #ifndef CL_VERSION_1_2
726 
727  /* Mark unused variables to avoid compiler warnings. */
728  CCL_UNUSED(program);
729  CCL_UNUSED(devs);
730  CCL_UNUSED(kernel_names);
731  CCL_UNUSED(ocl_status);
732  CCL_UNUSED(ocl_ver);
733  CCL_UNUSED(err_internal);
734 
735  /* If cf4ocl was not compiled with support for OpenCL >= 1.2, always throw
736  * error. */
737  ccl_if_err_create_goto(*err, CCL_ERROR, TRUE,
738  CCL_ERROR_UNSUPPORTED_OCL, error_handler,
739  "%s: Program creation from built-in kernels requires cf4ocl to be "
740  "deployed with support for OpenCL version 1.2 or newer.",
741  CCL_STRD);
742 
743 #else
744 
745  /* Check that context platform is >= OpenCL 1.2 */
746  ocl_ver = ccl_context_get_opencl_version(ctx, &err_internal);
747  ccl_if_err_propagate_goto(err, err_internal, error_handler);
748 
749  /* If OpenCL version is not >= 1.2, throw error. */
750  ccl_if_err_create_goto(*err, CCL_ERROR, ocl_ver < 120,
751  CCL_ERROR_UNSUPPORTED_OCL, error_handler,
752  "%s: Program creation with built-in kernels requires OpenCL " \
753  "version 1.2 or newer.", CCL_STRD);
754 
755  /* Unwrap devices. */
756  device_list = g_slice_alloc(num_devices * sizeof(cl_device_id));
757  for (guint i = 0; i < num_devices; ++i) {
758  device_list[i] = ccl_device_unwrap(devs[i]);
759  }
760 
761  /* Create program. */
762  program = clCreateProgramWithBuiltInKernels(
763  ccl_context_unwrap(ctx), num_devices, device_list, kernel_names,
764  &ocl_status);
765 
766  /* Create kernel from built-in kernels. */
768  CL_SUCCESS != ocl_status, ocl_status, error_handler,
769  "%s: unable to create cl_program from built-in kernels "
770  "(OpenCL error %d: %s).",
771  CCL_STRD, ocl_status, ccl_err(ocl_status));
772 
773  /* Wrap OpenCL program object. */
774  prg = ccl_program_new_wrap(program);
775 
776 #endif
777 
778  /* If we got here, everything is OK. */
779  g_assert(err == NULL || *err == NULL);
780  goto finish;
781 
782 error_handler:
783 
784  /* If we got here there was an error, verify that it is so. */
785  g_assert(err == NULL || *err != NULL);
786 
787 finish:
788 
789  /* Free stuff if necessary. */
790  if (device_list != NULL)
791  g_slice_free1(num_devices * sizeof(cl_device_id), device_list);
792 
793  /* Return prg. */
794  return prg;
795 
796 }
797 
817 CCL_EXPORT
819  CCLProgram* prg, const char* options, CCLErr** err) {
820 
821  return ccl_program_build_full(
822  prg, 0, NULL, options, NULL, NULL, err);
823 }
824 
849 CCL_EXPORT
851  cl_uint num_devices, CCLDevice* const* devs, const char *options,
852  ccl_program_callback pfn_notify, void *user_data, CCLErr** err) {
853 
854  /* Make sure prg is not NULL. */
855  g_return_val_if_fail(prg != NULL, CL_FALSE);
856  /* Make sure err is NULL or it is not set. */
857  g_return_val_if_fail(err == NULL || *err == NULL, CL_FALSE);
858 
859  /* Array of unwrapped devices. */
860  cl_device_id* cl_devices = NULL;
861  /* Status of OpenCL function call. */
862  cl_int ocl_status;
863  /* Result of function call. */
864  cl_bool result;
865 
866  /* Clear build logs cache. */
867  ccl_program_clear_build_logs(prg);
868 
869  /* Check if its necessary to unwrap devices. */
870  if ((devs != NULL) && (num_devices > 0)) {
871  cl_devices = g_slice_alloc0(sizeof(cl_device_id) * num_devices);
872  /* Unwrap devices. */
873  for (guint i = 0; i < num_devices; ++i)
874  cl_devices[i] = ccl_device_unwrap(devs[i]);
875  }
876 
877  /* Build program. */
878  ocl_status = clBuildProgram(ccl_program_unwrap(prg),
879  num_devices, cl_devices, options, pfn_notify, user_data);
880 
881  /* Check for any other errors. */
883  CL_SUCCESS != ocl_status, ocl_status, error_handler,
884  "%s: unable to build program (OpenCL error %d: %s).",
885  CCL_STRD, ocl_status, ccl_err(ocl_status));
886 
887  /* If we got here, everything is OK. */
888  g_assert(err == NULL || *err == NULL);
889  result = CL_TRUE;
890  goto finish;
891 
892 error_handler:
893 
894  /* If we got here there was an error, verify that it is so. */
895  g_assert(err == NULL || *err != NULL);
896 
897  /* Bad result. */
898  result = CL_FALSE;
899 
900 finish:
901 
902  /* Check if necessary to release array of unwrapped devices. */
903  if (cl_devices != NULL) {
904  g_slice_free1(sizeof(cl_device_id) * num_devices, cl_devices);
905  }
906 
907  /* Return result of function call. */
908  return result;
909 
910 }
911 
927 CCL_EXPORT
928 const char* ccl_program_get_build_log(CCLProgram* prg, CCLErr** err) {
929 
930  /* Make sure prg is not NULL. */
931  g_return_val_if_fail(prg != NULL, NULL);
932  /* Make sure err is NULL or it is not set. */
933  g_return_val_if_fail((err) == NULL || *(err) == NULL, NULL);
934 
935  /* Counter. */
936  cl_uint i = 0;
937  /* Number of devices in program. */
938  cl_uint num_devs = 0;
939  /* Current device. */
940  CCLDevice* dev = NULL;
941  /* Name of current device. */
942  char* dev_name;
943  /* Build log for current device.*/
944  const char* build_log;
945  /* Internal error handling object. */
946  CCLErr* err_internal = NULL;
947 
948  /* Complete build log string object. */
949  GString* build_log_obj = g_string_new("");
950 
951  /* Clear any previously obtained concatenated build log. */
952  if (prg->build_logs_concat) {
953  g_free(prg->build_logs_concat);
954  prg->build_logs_concat = NULL;
955  }
956 
957  /* How many devices in program? */
958  num_devs = ccl_program_get_num_devices(prg, &err_internal);
959  ccl_if_err_propagate_goto(err, err_internal, error_handler);
960 
961  /* For each device in program: */
962  for (i = 0; i < num_devs; i++) {
963 
964  /* Get the respective device wrapper. */
965  dev = ccl_program_get_device(prg, i, &err_internal);
966  ccl_if_err_propagate_goto(err, err_internal, error_handler);
967 
968  /* Is it a valid device? */
969  if (dev) {
970 
971  /* If so, get its name. */
972  dev_name = ccl_device_get_info_array(
973  dev, CL_DEVICE_NAME, char*, &err_internal);
974  ccl_if_err_propagate_goto(err, err_internal, error_handler);
975 
976  /* Get the respective build log. */
978  prg, dev, &err_internal);
979  ccl_if_err_propagate_goto(err, err_internal, error_handler);
980 
981  /* Append build log to string of concatenated build logs. */
982  g_string_append_printf(build_log_obj, "\n### Build log "
983  "for device '%s'\n\n%s\n\n", dev_name,
984  build_log != NULL ? build_log : "Not available");
985  }
986  }
987 
988  /* Add the newly concatenated build log. */
989  prg->build_logs_concat = build_log_obj->str;
990 
991  /* Release the string object (but not the underlying character array). */
992  g_string_free(build_log_obj, FALSE);
993 
994  /* If we got here, everything is OK. */
995  g_assert(err == NULL || *err == NULL);
996  goto finish;
997 
998 error_handler:
999 
1000  /* If we got here there was an error, verify that it is so. */
1001  g_assert(err == NULL || *err != NULL);
1002 
1003 finish:
1004 
1005  /* Return concatenated build log. */
1006  return (const char*) prg->build_logs_concat;
1007 }
1008 
1021 CCL_EXPORT
1023  CCLProgram* prg, CCLDevice* dev, CCLErr** err) {
1024 
1025  /* Make sure prg is not NULL. */
1026  g_return_val_if_fail(prg != NULL, NULL);
1027  /* Make sure dev is not NULL. */
1028  g_return_val_if_fail(dev != NULL, NULL);
1029  /* Make sure err is NULL or it is not set. */
1030  g_return_val_if_fail(err == NULL || *err == NULL, NULL);
1031 
1032  /* Build log for current device.*/
1033  char* build_log_dev = NULL;
1034  /* Error reporting object. */
1035  CCLErr* err_internal = NULL;
1036 
1037  /* Is build log for this device already in cache? */
1038  if ((prg->build_logs == NULL) || ((build_log_dev = (char*)
1039  g_hash_table_lookup(prg->build_logs, (gconstpointer) dev)) == NULL)) {
1040 
1041  /* Build log for the specified device is not in cache, get it. */
1042  build_log_dev = ccl_program_get_build_info_array(
1043  prg, dev, CL_PROGRAM_BUILD_LOG, char*, &err_internal);
1044  ccl_if_err_propagate_goto(err, err_internal, error_handler);
1045 
1046  /* If build log is not empty, keep it in build logs cache. */
1047  if ((build_log_dev != NULL) && (strlen(build_log_dev) > 0)) {
1048 
1049  /* Check if build logs cache is initialized, if not, initialize
1050  * it. */
1051  if (!prg->build_logs) {
1052  prg->build_logs = g_hash_table_new(
1053  g_direct_hash, g_direct_equal);
1054  }
1055 
1056  /* Keep build log for current device in build logs cache. Previous
1057  * logs are freed automatically. */
1058  g_hash_table_insert(prg->build_logs,
1059  (gpointer) dev,
1060  (gpointer) build_log_dev);
1061 
1062  }
1063  }
1064 
1065  /* If we got here, everything is OK. */
1066  g_assert(err == NULL || *err == NULL);
1067  goto finish;
1068 
1069 error_handler:
1070 
1071  /* If we got here there was an error, verify that it is so. */
1072  g_assert(err == NULL || *err != NULL);
1073 
1074 finish:
1075 
1076  /* Return build log for the specified device, if it exists. */
1077  return build_log_dev;
1078 
1079 }
1080 
1114 CCL_EXPORT
1115 cl_bool ccl_program_compile(CCLProgram* prg, cl_uint num_devices,
1116  CCLDevice* const* devs, const char* options, cl_uint num_input_headers,
1117  CCLProgram** prg_input_headers, const char** header_include_names,
1118  ccl_program_callback pfn_notify, void* user_data, CCLErr** err) {
1119 
1120  /* Make sure prg is not NULL. */
1121  g_return_val_if_fail(prg != NULL, CL_FALSE);
1122  /* Make sure err is NULL or it is not set. */
1123  g_return_val_if_fail(err == NULL || *err == NULL, CL_FALSE);
1124 
1125  /* Array of unwrapped devices. */
1126  cl_device_id* cl_devices = NULL;
1127  /* Array of unwrapped programs (input headers). */
1128  cl_program* input_headers = NULL;
1129  /* Status of OpenCL function call. */
1130  cl_int ocl_status;
1131  /* Result of function call. */
1132  cl_bool result;
1133  /* OpenCL version of underlying platform. */
1134  cl_uint ocl_ver;
1135  /* Internal error handling object. */
1136  CCLErr* err_internal = NULL;
1137 
1138 #ifndef CL_VERSION_1_2
1139 
1140  /* Mark unused variables to avoid compiler warnings. */
1141  CCL_UNUSED(err_internal);
1142  CCL_UNUSED(ocl_ver);
1143  CCL_UNUSED(ocl_status);
1144  CCL_UNUSED(devs);
1145  CCL_UNUSED(options);
1146  CCL_UNUSED(prg_input_headers);
1147  CCL_UNUSED(header_include_names);
1148  CCL_UNUSED(pfn_notify);
1149  CCL_UNUSED(user_data);
1150 
1151  /* If cf4ocl was not compiled with support for OpenCL >= 1.2, always throw
1152  * error. */
1153  ccl_if_err_create_goto(*err, CCL_ERROR, TRUE,
1154  CCL_ERROR_UNSUPPORTED_OCL, error_handler,
1155  "%s: Program compilation requires cf4ocl to be deployed with support "
1156  "for OpenCL version 1.2 or newer.",
1157  CCL_STRD);
1158 
1159 #else
1160 
1161  /* Check that context platform is >= OpenCL 1.2 */
1162  ocl_ver = ccl_program_get_opencl_version(prg, &err_internal);
1163  ccl_if_err_propagate_goto(err, err_internal, error_handler);
1164 
1165  /* If OpenCL version is not >= 1.2, throw error. */
1166  ccl_if_err_create_goto(*err, CCL_ERROR, ocl_ver < 120,
1167  CCL_ERROR_UNSUPPORTED_OCL, error_handler,
1168  "%s: Program compilation requires OpenCL version 1.2 or newer.",
1169  CCL_STRD);
1170 
1171  /* Clear build logs cache. */
1172  ccl_program_clear_build_logs(prg);
1173 
1174  /* Check if its necessary to unwrap devices. */
1175  if ((devs != NULL) && (num_devices > 0)) {
1176  cl_devices = g_slice_alloc0(sizeof(cl_device_id) * num_devices);
1177  /* Unwrap devices. */
1178  for (guint i = 0; i < num_devices; ++i)
1179  cl_devices[i] = ccl_device_unwrap(devs[i]);
1180  }
1181 
1182  /* Check if its necessary to unwrap programs (input headers). */
1183  if ((prg_input_headers != NULL) && (num_input_headers > 0)) {
1184  input_headers =
1185  g_slice_alloc0(sizeof(cl_program) * num_input_headers);
1186  /* Unwrap program objects. */
1187  for (guint i = 0; i < num_input_headers; ++i)
1188  input_headers[i] = ccl_program_unwrap(prg_input_headers[i]);
1189  }
1190 
1191  /* Compile program. */
1192  ocl_status = clCompileProgram(ccl_program_unwrap(prg), num_devices,
1193  (const cl_device_id*) cl_devices, options, num_input_headers,
1194  (const cl_program*) input_headers, header_include_names,
1195  pfn_notify, user_data);
1196 
1197  /* Check for errors. */
1199  CL_SUCCESS != ocl_status, ocl_status, error_handler,
1200  "%s: unable to compile program (OpenCL error %d: %s).",
1201  CCL_STRD, ocl_status, ccl_err(ocl_status));
1202 
1203 #endif
1204 
1205  /* If we got here, everything is OK. */
1206  g_assert(err == NULL || *err == NULL);
1207  result = CL_TRUE;
1208  goto finish;
1209 
1210 error_handler:
1211 
1212  /* If we got here there was an error, verify that it is so. */
1213  g_assert(err == NULL || *err != NULL);
1214 
1215  /* Bad result. */
1216  result = CL_FALSE;
1217 
1218 finish:
1219 
1220  /* Check if necessary to release array of unwrapped devices. */
1221  if (cl_devices != NULL) {
1222  g_slice_free1(sizeof(cl_device_id) * num_devices, cl_devices);
1223  }
1224  /* Check if necessary to release array of input headers (programs). */
1225  if (input_headers != NULL) {
1226  g_slice_free1(
1227  sizeof(cl_program) * num_input_headers, input_headers);
1228  }
1229 
1230  /* Return result of function call. */
1231  return result;
1232 
1233 }
1234 
1265 CCL_EXPORT
1266 CCLProgram* ccl_program_link(CCLContext* ctx, cl_uint num_devices,
1267  CCLDevice* const* devs, const char* options, cl_uint num_input_programs,
1268  CCLProgram** input_prgs, ccl_program_callback pfn_notify,
1269  void* user_data, CCLErr** err) {
1270 
1271  /* Make sure ctx is not NULL. */
1272  g_return_val_if_fail(ctx != NULL, CL_FALSE);
1273  /* Make sure err is NULL or it is not set. */
1274  g_return_val_if_fail(err == NULL || *err == NULL, CL_FALSE);
1275 
1276  /* Array of unwrapped devices. */
1277  cl_device_id* cl_devices = NULL;
1278  /* Array of unwrapped input programs. */
1279  cl_program* input_programs = NULL;
1280  /* Status of OpenCL function call. */
1281  cl_int ocl_status;
1282  /* Program wrapper object to create. */
1283  CCLProgram* prg = NULL;
1284  /* OpenCL program object to create and wrap. */
1285  cl_program program = NULL;
1286  /* OpenCL version of underlying platform. */
1287  cl_uint ocl_ver;
1288  /* Internal error handling object. */
1289  CCLErr* err_internal = NULL;
1290 
1291 #ifndef CL_VERSION_1_2
1292 
1293  /* Mark unused variables to avoid compiler warnings. */
1294  CCL_UNUSED(err_internal);
1295  CCL_UNUSED(ocl_ver);
1296  CCL_UNUSED(program);
1297  CCL_UNUSED(ocl_status);
1298  CCL_UNUSED(devs);
1299  CCL_UNUSED(options);
1300  CCL_UNUSED(input_prgs);
1301  CCL_UNUSED(pfn_notify);
1302  CCL_UNUSED(user_data);
1303 
1304  /* If cf4ocl was not compiled with support for OpenCL >= 1.2, always throw
1305  * error. */
1306  ccl_if_err_create_goto(*err, CCL_ERROR, TRUE,
1307  CCL_ERROR_UNSUPPORTED_OCL, error_handler,
1308  "%s: Program linking requires cf4ocl to be deployed with support "
1309  "for OpenCL version 1.2 or newer.",
1310  CCL_STRD);
1311 
1312 #else
1313 
1314  /* Check that context platform is >= OpenCL 1.2 */
1315  ocl_ver = ccl_context_get_opencl_version(ctx, &err_internal);
1316  ccl_if_err_propagate_goto(err, err_internal, error_handler);
1317 
1318  /* If OpenCL version is not >= 1.2, throw error. */
1319  ccl_if_err_create_goto(*err, CCL_ERROR, ocl_ver < 120,
1320  CCL_ERROR_UNSUPPORTED_OCL, error_handler,
1321  "%s: Program linking requires OpenCL version 1.2 or newer.",
1322  CCL_STRD);
1323 
1324  /* Check if its necessary to unwrap devices. */
1325  if ((devs != NULL) && (num_devices > 0)) {
1326  cl_devices = g_slice_alloc0(sizeof(cl_device_id) * num_devices);
1327  /* Unwrap devices. */
1328  for (guint i = 0; i < num_devices; ++i)
1329  cl_devices[i] = ccl_device_unwrap(devs[i]);
1330  }
1331 
1332  /* Check if its necessary to unwrap input programs. */
1333  if ((input_prgs != NULL) && (num_input_programs > 0)) {
1334  input_programs =
1335  g_slice_alloc0(sizeof(cl_program) * num_input_programs);
1336  /* Unwrap program objects. */
1337  for (guint i = 0; i < num_input_programs; ++i)
1338  input_programs[i] = ccl_program_unwrap(input_prgs[i]);
1339  }
1340 
1341  /* Link program. */
1342  program = clLinkProgram(ccl_context_unwrap(ctx), num_devices,
1343  (const cl_device_id*) cl_devices, options, num_input_programs,
1344  (const cl_program*) input_programs, pfn_notify, user_data,
1345  &ocl_status);
1346 
1347  /* Check for errors. */
1349  CL_SUCCESS != ocl_status, ocl_status, error_handler,
1350  "%s: unable to link program (OpenCL error %d: %s).",
1351  CCL_STRD, ocl_status, ccl_err(ocl_status));
1352 
1353  /* Wrap OpenCL program object. */
1354  prg = ccl_program_new_wrap(program);
1355 
1356 #endif
1357 
1358  /* If we got here, everything is OK. */
1359  g_assert(err == NULL || *err == NULL);
1360  goto finish;
1361 
1362 error_handler:
1363 
1364  /* If we got here there was an error, verify that it is so. */
1365  g_assert(err == NULL || *err != NULL);
1366 
1367 finish:
1368 
1369  /* Check if necessary to release array of unwrapped devices. */
1370  if (cl_devices != NULL) {
1371  g_slice_free1(sizeof(cl_device_id) * num_devices, cl_devices);
1372  }
1373  /* Check if necessary to release array of input programs. */
1374  if (input_programs != NULL) {
1375  g_slice_free1(
1376  sizeof(cl_program) * num_input_programs, input_programs);
1377  }
1378 
1379  /* Return linked program wrapper. */
1380  return prg;
1381 
1382 }
1383 
1384 
1403 CCL_EXPORT
1405 
1406  /* Make sure number prg is not NULL. */
1407  g_return_val_if_fail(prg != NULL, 0);
1408  /* Make sure err is NULL or it is not set. */
1409  g_return_val_if_fail(err == NULL || *err == NULL, 0);
1410 
1411  cl_context context;
1412  CCLContext* ctx;
1413  CCLErr* err_internal = NULL;
1414  cl_uint ocl_ver;
1415 
1416  /* Get cl_context object for this program. */
1417  context = ccl_program_get_info_scalar(
1418  prg, CL_PROGRAM_CONTEXT, cl_context, &err_internal);
1419  ccl_if_err_propagate_goto(err, err_internal, error_handler);
1420 
1421  /* Get context wrapper. */
1422  ctx = ccl_context_new_wrap(context);
1423 
1424  /* Get OpenCL version. */
1425  ocl_ver = ccl_context_get_opencl_version(ctx, &err_internal);
1426  ccl_if_err_propagate_goto(err, err_internal, error_handler);
1427 
1428  /* Unref. the context wrapper. */
1429  ccl_context_unref(ctx);
1430 
1431  /* If we got here, everything is OK. */
1432  g_assert(err == NULL || *err == NULL);
1433  goto finish;
1434 
1435 error_handler:
1436 
1437  /* If we got here there was an error, verify that it is so. */
1438  g_assert(err == NULL || *err != NULL);
1439  ocl_ver = 0;
1440 
1441 finish:
1442 
1443  /* Return event wrapper. */
1444  return ocl_ver;
1445 
1446 }
1447 
1469 CCL_EXPORT
1471  CCLProgram* prg, const char* kernel_name, CCLErr** err) {
1472 
1473  /* Make sure err is NULL or it is not set. */
1474  g_return_val_if_fail((err) == NULL || *(err) == NULL, NULL);
1475  /* Make sure prg is not NULL. */
1476  g_return_val_if_fail(prg != NULL, NULL);
1477  /* Make sure kernel_name is not NULL. */
1478  g_return_val_if_fail(kernel_name != NULL, NULL);
1479 
1480  /* Internal error reporting object. */
1481  CCLErr* err_internal = NULL;
1482  /* Kernel wrapper object. */
1483  CCLKernel* krnl = NULL;
1484 
1485  /* If kernels table is not yet initialized, then
1486  * initialize it. */
1487  if (prg->krnls == NULL) {
1488  prg->krnls = g_hash_table_new_full(g_str_hash, g_str_equal,
1489  NULL, (GDestroyNotify) ccl_kernel_destroy);
1490  }
1491 
1492  /* Check if requested kernel is already present in the kernels
1493  * table. */
1494  if (g_hash_table_contains(
1495  prg->krnls, kernel_name)) {
1496 
1497  /* If so, retrieve it from there. */
1498  krnl = g_hash_table_lookup(
1499  prg->krnls, kernel_name);
1500 
1501  } else {
1502 
1503  /* Otherwise, get it from OpenCL program object.*/
1504  krnl = ccl_kernel_new(prg, kernel_name, &err_internal);
1505  ccl_if_err_propagate_goto(err, err_internal, error_handler);
1506 
1507  /* Keep new kernel wrapper in table. */
1508  g_hash_table_insert(prg->krnls, (gpointer) kernel_name, krnl);
1509 
1510  }
1511 
1512  /* If we got here, everything is OK. */
1513  g_assert(err == NULL || *err == NULL);
1514  goto finish;
1515 
1516 error_handler:
1517 
1518  /* If we got here there was an error, verify that it is so. */
1519  g_assert(err == NULL || *err != NULL);
1520 
1521 finish:
1522 
1523  /* Return kernel wrapper. */
1524  return krnl;
1525 
1526 }
1527 
1571 CCL_EXPORT
1573  const char* kernel_name, CCLQueue* cq, cl_uint work_dim,
1574  const size_t* global_work_offset, const size_t* global_work_size,
1575  const size_t* local_work_size, CCLEventWaitList* evt_wait_lst,
1576  CCLErr** err, ...) {
1577 
1578  /* Event wrapper. */
1579  CCLEvent* evt;
1580  /* The va_list, which represents the variable argument list. */
1581  va_list args_va;
1582  /* Array of arguments, to be created from the va_list. */
1583  void** args_array = NULL;
1584  /* Number of arguments. */
1585  guint num_args = 0;
1586  /* Aux. arg. when cycling through the va_list. */
1587  void* aux_arg;
1588 
1589  /* Initialize the va_list. */
1590  va_start(args_va, err);
1591 
1592  /* Get first argument. */
1593  aux_arg = va_arg(args_va, void*);
1594 
1595  /* Check if any arguments are given, and if so, populate array
1596  * of arguments. */
1597  if (aux_arg != NULL) {
1598 
1599  /* 1. Determine number of arguments. */
1600 
1601  while (aux_arg != NULL) {
1602  num_args++;
1603  aux_arg = va_arg(args_va, void*);
1604  }
1605  va_end(args_va);
1606 
1607  /* 2. Populate array of arguments. */
1608 
1609  args_array = g_slice_alloc((num_args + 1) * sizeof(void*));
1610  va_start(args_va, err);
1611 
1612  for (guint i = 0; i < num_args; ++i) {
1613  aux_arg = va_arg(args_va, void*);
1614  args_array[i] = aux_arg;
1615  }
1616  va_end(args_va);
1617  args_array[num_args] = NULL;
1618 
1619  }
1620 
1621  /* Enqueue kernel using the array of arguments version of this
1622  * function. */
1623  evt = ccl_program_enqueue_kernel_v(prg, kernel_name, cq, work_dim,
1624  global_work_offset, global_work_size, local_work_size,
1625  evt_wait_lst, args_array, err);
1626 
1627  /* If any arguments are given... */
1628  if (num_args > 0) {
1629 
1630  /* Free the array of arguments. */
1631  g_slice_free1((num_args + 1) * sizeof(void*), args_array);
1632 
1633  }
1634 
1635  /* Return the event. */
1636  return evt;
1637 
1638 }
1639 
1682 CCL_EXPORT
1684  const char* kernel_name, CCLQueue* cq, cl_uint work_dim,
1685  const size_t* global_work_offset, const size_t* global_work_size,
1686  const size_t* local_work_size, CCLEventWaitList* evt_wait_lst,
1687  void** args, CCLErr** err) {
1688 
1689  /* Make sure err is NULL or it is not set. */
1690  g_return_val_if_fail((err) == NULL || *(err) == NULL, NULL);
1691 
1692  CCLEvent* evt;
1693  CCLKernel* krnl;
1694 
1695  krnl = ccl_program_get_kernel(prg, kernel_name, err);
1696  if (krnl == NULL) return NULL;
1697 
1698  evt = ccl_kernel_set_args_and_enqueue_ndrange_v(krnl, cq, work_dim,
1699  global_work_offset, global_work_size, local_work_size,
1700  evt_wait_lst, args, err);
1701  return evt;
1702 }
1703 
1715 static void ccl_program_load_binaries(CCLProgram* prg, CCLErr** err) {
1716 
1717  /* Make sure err is NULL or it is not set. */
1718  g_return_if_fail((err) == NULL || *(err) == NULL);
1719 
1720  /* Make sure prg is not NULL. */
1721  g_return_if_fail(prg != NULL);
1722 
1723  /* Make sure binaries table is initialized. */
1724  g_return_if_fail(prg->binaries != NULL);
1725 
1726  cl_uint num_devices;
1727  cl_device_id* devices;
1728  size_t* binary_sizes;
1729  CCLWrapperInfo* info;
1730  unsigned char** bins_raw;
1731  CCLErr* err_internal = NULL;
1732  cl_int ocl_status;
1733 
1734  /* Get number of program devices. */
1735  info = ccl_program_get_info(prg, CL_PROGRAM_NUM_DEVICES, &err_internal);
1736  ccl_if_err_propagate_goto(err, err_internal, error_handler);
1737  num_devices = *((cl_uint*) info->value);
1738 
1739  /* Get program devices. */
1740  info = ccl_program_get_info(prg, CL_PROGRAM_DEVICES, &err_internal);
1741  ccl_if_err_propagate_goto(err, err_internal, error_handler);
1742  devices = (cl_device_id*) info->value;
1743 
1744  /* Get binary sizes. */
1745  info = ccl_program_get_info(prg, CL_PROGRAM_BINARY_SIZES, &err_internal);
1746  ccl_if_err_propagate_goto(err, err_internal, error_handler);
1747  binary_sizes = (size_t*) info->value;
1748 
1749  /* Allocate memory for binaries. */
1750  bins_raw = g_slice_alloc0(num_devices * sizeof(unsigned char*));
1751  for (guint i = 0; i < num_devices; i++) {
1752  if (binary_sizes[i] > 0) {
1753  bins_raw[i] = g_malloc(binary_sizes[i]);
1754  }
1755  }
1756 
1757  /* Get binaries. */
1758  ocl_status = clGetProgramInfo(ccl_program_unwrap(prg),
1759  CL_PROGRAM_BINARIES, num_devices * sizeof(unsigned char*),
1760  bins_raw, NULL);
1762  CL_SUCCESS != ocl_status, ocl_status, error_handler,
1763  "%s: unable to get binaries from program (OpenCL error %d: %s).",
1764  CCL_STRD, ocl_status, ccl_err(ocl_status));
1765 
1766  /* Fill binaries table, associating each device with a
1767  * CCLProgramBinary* object containing the binary and its size. */
1768  for (guint i = 0; i < num_devices; ++i) {
1769 
1770  CCLProgramBinary* bin = ccl_program_binary_new_empty();
1771  bin->size = binary_sizes[i];
1772  bin->data = bins_raw[i];
1773 
1774  g_hash_table_replace(prg->binaries, devices[i], bin);
1775  }
1776 
1777  /* Free memory allocated for binary array. */
1778  g_slice_free1(num_devices * sizeof(unsigned char*), bins_raw);
1779 
1780  /* If we got here, everything is OK. */
1781  g_assert(err == NULL || *err == NULL);
1782  return;
1783 
1784 error_handler:
1785 
1786  /* If we got here there was an error, verify that it is so. */
1787  g_assert(err == NULL || *err != NULL);
1788  return;
1789 
1790 }
1791 
1805 CCL_EXPORT
1807  CCLProgram* prg, CCLDevice* dev, CCLErr** err) {
1808 
1809  /* Make sure err is NULL or it is not set. */
1810  g_return_val_if_fail((err) == NULL || *(err) == NULL, NULL);
1811  /* Make sure prg is not NULL. */
1812  g_return_val_if_fail(prg != NULL, NULL);
1813  /* Make sure dev is not NULL. */
1814  g_return_val_if_fail(dev != NULL, NULL);
1815 
1816  /* Internal error handling object. */
1817  CCLErr* err_internal = NULL;
1818  /* Binary code object. */
1819  CCLProgramBinary* binary = NULL;
1820 
1821  /* Check if binaries table is initialized. */
1822  if (prg->binaries == NULL) {
1823 
1824  /* Initialize binaries table. */
1825  prg->binaries = g_hash_table_new_full(
1826  g_direct_hash, g_direct_equal, NULL,
1827  (GDestroyNotify) ccl_program_binary_destroy);
1828 
1829  /* Load binaries. */
1830  ccl_program_load_binaries(prg, &err_internal);
1831  ccl_if_err_propagate_goto(err, err_internal, error_handler);
1832  }
1833 
1834  /* Check if given device exists in the list of program devices. */
1835  if (g_hash_table_contains(prg->binaries, ccl_device_unwrap(dev))) {
1836 
1837  /* It exists, get it. */
1838  binary = g_hash_table_lookup(
1839  prg->binaries, ccl_device_unwrap(dev));
1840 
1841  /* If NULL, then perform a new binary fetch on the CL program
1842  * object... */
1843  ccl_program_load_binaries(prg, &err_internal);
1844  ccl_if_err_propagate_goto(err, err_internal, error_handler);
1845 
1846  /* ...and get it again. If it's NULL it's because binary isn't
1847  * compiled for given device. */
1848  binary = g_hash_table_lookup(
1849  prg->binaries, ccl_device_unwrap(dev));
1850 
1851  } else {
1852 
1853  /* Device does not exist in list of program devices. */
1854  ccl_if_err_create_goto(*err, CCL_ERROR, TRUE,
1856  error_handler, "%s: device is not part of program devices.",
1857  CCL_STRD);
1858  }
1859 
1860  /* If we got here, everything is OK. */
1861  g_assert(err == NULL || *err == NULL);
1862  goto finish;
1863 
1864 error_handler:
1865 
1866  /* If we got here there was an error, verify that it is so. */
1867  g_assert(err == NULL || *err != NULL);
1868 
1869 finish:
1870 
1871  /* Return kernel wrapper. */
1872  return binary;
1873 }
1874 
1889 CCL_EXPORT
1891  const char* filename, CCLErr** err) {
1892 
1893  /* Make sure err is NULL or it is not set. */
1894  g_return_val_if_fail((err) == NULL || *(err) == NULL, CL_FALSE);
1895  /* Make sure prg is not NULL. */
1896  g_return_val_if_fail(prg != NULL, CL_FALSE);
1897  /* Make sure filename is not NULL. */
1898  g_return_val_if_fail(filename != NULL, CL_FALSE);
1899 
1900  /* OpenCL function status. */
1901  cl_bool status;
1902  /* Internal error handling object. */
1903  CCLErr* err_internal = NULL;
1904  /* The binary code object. */
1905  CCLProgramBinary* binary = NULL;
1906 
1907  /* Get the binary code object for the specified device and check
1908  * for associated errors. */
1909  binary = ccl_program_get_binary(prg, dev, &err_internal);
1910  ccl_if_err_propagate_goto(err, err_internal, error_handler);
1911 
1912  ccl_if_err_create_goto(*err, CCL_ERROR, binary->size == 0,
1913  CCL_ERROR_INVALID_DATA, error_handler,
1914  "%s: binary for given device has size 0.", CCL_STRD);
1915 
1916  /* Save binary code to specified file. */
1917  g_file_set_contents(filename, (const gchar*) binary->data,
1918  binary->size, &err_internal);
1919  ccl_if_err_propagate_goto(err, err_internal, error_handler);
1920 
1921  /* If we got here, everything is OK. */
1922  g_assert(err == NULL || *err == NULL);
1923  status = CL_TRUE;
1924  goto finish;
1925 
1926 error_handler:
1927 
1928  /* If we got here there was an error, verify that it is so. */
1929  g_assert(err == NULL || *err != NULL);
1930 
1931  status = CL_FALSE;
1932 
1933 finish:
1934 
1935  /* Return function status. */
1936  return status;
1937 }
1938 
1971 CCL_EXPORT
1973  const char* file_prefix, const char* file_suffix, char*** filenames,
1974  CCLErr** err) {
1975 
1976  /* Make sure err is NULL or it is not set. */
1977  g_return_val_if_fail((err) == NULL || *(err) == NULL, CL_FALSE);
1978  /* Make sure prg is not NULL. */
1979  g_return_val_if_fail(prg != NULL, CL_FALSE);
1980  /* Make sure file prefix and suffix are not NULL. */
1981  g_return_val_if_fail(
1982  (file_prefix != NULL) && (file_suffix != NULL), CL_FALSE);
1983 
1984  /* Internal error handling object. */
1985  CCLErr* err_internal = NULL;
1986  /* Number of devices. */
1987  guint num_devices;
1988  /* OpenCL function return status. */
1989  cl_bool status;
1990 
1991  /* Get number of devices. */
1992  num_devices = ccl_program_get_num_devices(prg, &err_internal);
1993  ccl_if_err_propagate_goto(err, err_internal, error_handler);
1994 
1995  /* Allocate space for filenames. */
1996  if (filenames != NULL)
1997  *filenames = g_malloc((num_devices + 1) * sizeof(char**));
1998 
1999  /* Allocate space for*/
2000  /* Cycle through each device. */
2001  for (guint i = 0; i < num_devices; ++i) {
2002 
2003  /* Save binaries, one per device. */
2004 
2005  /* Device wrapper object. */
2006  CCLDevice* dev = NULL;
2007  /* Variable part of filename. */
2008  gchar* file_middle = NULL;
2009  /* Complete filename. */
2010  gchar* filename;
2011 
2012  /* Get next device associated with program. */
2013  dev = ccl_program_get_device(prg, i, &err_internal);
2014  ccl_if_err_propagate_goto(err, err_internal, error_handler);
2015 
2016  /* Determine the variable part of current filename. */
2017  file_middle = g_strdup(
2019  dev, CL_DEVICE_NAME, char*, &err_internal));
2020  ccl_if_err_propagate_goto(err, err_internal, error_handler);
2021 
2022  g_strcanon(file_middle, CCL_VALIDFILECHARS, '_');
2023 
2024  /* Determine complete filename of current file. */
2025  filename = g_strdup_printf("%s%s_%02d%s",
2026  file_prefix, file_middle, i, file_suffix);
2027 
2028  /* Save current binary to file. */
2029  ccl_program_save_binary(prg, dev, filename, &err_internal);
2030  ccl_if_err_propagate_goto(err, err_internal, error_handler);
2031 
2032  /* Keep filename or free it, depending if the filenames
2033  * variable is NULL or not. */
2034  if (filenames != NULL) {
2035  (*filenames)[i] = filename;
2036  } else {
2037  g_free(filename);
2038  }
2039 
2040  /* Free middle filename variable. */
2041  g_free(file_middle);
2042  }
2043 
2044  /* Signal the end of the array with NULL, so it can be freed with GLib's
2045  * g_strfreev() function or with its cf4ocl wrapper, ccl_strv_clear(). */
2046  if (filenames != NULL)
2047  (*filenames)[num_devices] = NULL;
2048 
2049  /* If we got here, everything is OK. */
2050  g_assert(err == NULL || *err == NULL);
2051  status = CL_TRUE;
2052  goto finish;
2053 
2054 error_handler:
2055 
2056  /* If we got here there was an error, verify that it is so. */
2057  g_assert(err == NULL || *err != NULL);
2058 
2059  status = CL_FALSE;
2060 
2061 finish:
2062 
2063  /* Return function status. */
2064  return status;
2065 
2066 }
2067 
2080 CCL_EXPORT
2082  CCLProgram* prg, cl_uint index, CCLErr** err) {
2083 
2084  return ccl_dev_container_get_device(
2085  (CCLDevContainer*) prg, ccl_program_get_cldevices, index, err);
2086 }
2087 
2099 CCL_EXPORT
2101 
2102  return ccl_dev_container_get_num_devices(
2103  (CCLDevContainer*) prg, ccl_program_get_cldevices, err);
2104 
2105 }
2106 
2122 CCL_EXPORT
2124  CCLErr** err) {
2125 
2126  return ccl_dev_container_get_all_devices((CCLDevContainer*) prg,
2127  ccl_program_get_cldevices, err);
2128 
2129 }
2130 
void ccl_kernel_destroy(CCLKernel *krnl)
Decrements the reference count of the kernel wrapper object.
Invalid data passed to a function or returned from function.
Definition: ccl_common.h:304
CCLEvent * ccl_kernel_set_args_and_enqueue_ndrange_v(CCLKernel *krnl, CCLQueue *cq, cl_uint work_dim, const size_t *global_work_offset, const size_t *global_work_size, const size_t *local_work_size, CCLEventWaitList *evt_wait_lst, void **args, CCLErr **err)
Set kernel arguments and enqueue it for execution on a device.
#define CCL_OCL_ERROR
Resolves to error category identifying string, in this case an error in the OpenCL library...
Definition: ccl_common.h:324
const char * ccl_program_get_device_build_log(CCLProgram *prg, CCLDevice *dev, CCLErr **err)
Get build log for most recent build, compile or link for the specified device.
CCLDevice *const * ccl_program_get_all_devices(CCLProgram *prg, CCLErr **err)
Get all device wrappers in program.
CCLEvent * ccl_program_enqueue_kernel(CCLProgram *prg, const char *kernel_name, CCLQueue *cq, cl_uint work_dim, const size_t *global_work_offset, const size_t *global_work_size, const size_t *local_work_size, CCLEventWaitList *evt_wait_lst, CCLErr **err,...)
Enqueues a program kernel function for execution on a device.
CCLEvent * ccl_program_enqueue_kernel_v(CCLProgram *prg, const char *kernel_name, CCLQueue *cq, cl_uint work_dim, const size_t *global_work_offset, const size_t *global_work_size, const size_t *local_work_size, CCLEventWaitList *evt_wait_lst, void **args, CCLErr **err)
Enqueues a program kernel function for execution on a device.
#define ccl_if_err_create_goto(err, quark, error_condition, error_code, label, msg,...)
If error is detected (error_code != no_error_code), create an error object (CCLErr) and go to the spe...
Definition: _ccl_defs.h:91
#define ccl_context_unwrap(ctx)
Get the OpenCL context object.
GPtrArray * CCLEventWaitList
A list of event objects on which enqueued commands can wait.
Useful definitions used internally by cf4ocl.
CCLProgram * ccl_program_new_from_binary_file(CCLContext *ctx, CCLDevice *dev, const char *filename, cl_int *binary_status, CCLErr **err)
Create a new program wrapper object from a file containing binary code executable on a specific devic...
CCLProgram * ccl_program_new_from_built_in_kernels(CCLContext *ctx, cl_uint num_devices, CCLDevice *const *devs, const char *kernel_names, CCLErr **err)
Create a new program wrapper object from device built-in kernels.
The context wrapper class.
#define ccl_if_err_propagate_goto(err_dest, err_src, label)
Same as ccl_if_err_goto(), but rethrows error in a source CCLErr object to a new destination CCLErr o...
Definition: _ccl_defs.h:120
CCLProgram * ccl_program_new_from_source(CCLContext *ctx, const char *string, CCLErr **err)
Create a new program wrapper object from a null-terminated source string.
Command queue wrapper class.
const char * ccl_err(int code)
Convert OpenCL error code to a readable string.
Definition: ccl_errors.c:118
CCLContext * ccl_context_new_wrap(cl_context context)
Get the context wrapper for the given OpenCL context.
cl_uint ccl_context_get_opencl_version(CCLContext *ctx, CCLErr **err)
Get the OpenCL version of the platform associated with this context.
cl_uint ccl_program_get_opencl_version(CCLProgram *prg, CCLErr **err)
Get the OpenCL version of the platform associated with this program.
CCLProgram * ccl_program_new_wrap(cl_program program)
Get the program wrapper for the given OpenCL program.
CCLProgramBinary * ccl_program_get_binary(CCLProgram *prg, CCLDevice *dev, CCLErr **err)
Get the program binary object for the specified device.
CCLProgram * ccl_program_new_from_binaries(CCLContext *ctx, cl_uint num_devices, CCLDevice *const *devs, CCLProgramBinary **bins, cl_int *binary_status, CCLErr **err)
Create a new program wrapper object from a list of binary code strings executable on the given device...
Base class for wrappers which contain devices, i.e., CCLPlatform, CCLProgram and CCLContext.
#define CCL_ERROR
Resolves to error category identifying string, in this case an error in cf4ocl.
Definition: ccl_common.h:320
#define ccl_program_get_info(prg, param_name, err)
Get a CCLWrapperInfo program information object.
The requested OpenCL device was not found.
Definition: ccl_common.h:308
Definition of a wrapper class and its methods for OpenCL program objects.
cl_bool ccl_program_build(CCLProgram *prg, const char *options, CCLErr **err)
Utility function which builds (compiles and links) a program executable from the program source or bi...
Event wrapper class.
Base class for all OpenCL wrappers.
cl_bool ccl_program_save_all_binaries(CCLProgram *prg, const char *file_prefix, const char *file_suffix, char ***filenames, CCLErr **err)
Save the program binaries for all associated devices to files, one file per device.
#define ccl_device_unwrap(dev)
Get the OpenCL device_id object.
#define ccl_context_unref(ctx)
Alias to ccl_context_destroy().
#define CCL_UNUSED(x)
Macro to avoid warning in unused variables.
Definition: ccl_common.h:86
#define ccl_device_get_info_array(dev, param_name, param_type, err)
Macro which returns an array device information value.
const char * ccl_program_get_build_log(CCLProgram *prg, CCLErr **err)
Get a general build log of most recent build, compile or link, for all devices.
CCLProgram * ccl_program_new_from_source_file(CCLContext *ctx, const char *filename, CCLErr **err)
Create a new program wrapper object from a source file.
CCLProgram * ccl_program_link(CCLContext *ctx, cl_uint num_devices, CCLDevice *const *devs, const char *options, cl_uint num_input_programs, CCLProgram **input_prgs, ccl_program_callback pfn_notify, void *user_data, CCLErr **err)
Link a set of compiled programs and create an executable program wrapper.
Program wrapper class.
void * value
Object information.
CCLProgram * ccl_program_new_from_binary(CCLContext *ctx, CCLDevice *dev, CCLProgramBinary *binary, cl_int *binary_status, CCLErr **err)
Create a new program wrapper object from binary code executable on a specific device.
CCLProgram * ccl_program_new_from_source_files(CCLContext *ctx, cl_uint count, const char **filenames, CCLErr **err)
Create a new program wrapper object from several source files.
void(* ccl_program_callback)(cl_program program, void *user_data)
Prototype of callback functions for program build, compile and link.
CCLProgram * ccl_program_new_from_binary_files(CCLContext *ctx, cl_uint num_devices, CCLDevice *const *devs, const char **filenames, cl_int *binary_status, CCLErr **err)
Create a new program wrapper object from files containing binary code executable on the given device ...
Kernel wrapper class.
cl_bool ccl_program_compile(CCLProgram *prg, cl_uint num_devices, CCLDevice *const *devs, const char *options, cl_uint num_input_headers, CCLProgram **prg_input_headers, const char **header_include_names, ccl_program_callback pfn_notify, void *user_data, CCLErr **err)
Compile a program's source code.
Class which represents information about a wrapped OpenCL object.
#define ccl_program_unwrap(prg)
Get the OpenCL program object.
#define ccl_program_get_build_info_array(prg, dev, param_name, param_type, err)
Macro which returns an array program build information value.
GError CCLErr
Error handling class.
Definition: ccl_common.h:291
cl_bool ccl_program_save_binary(CCLProgram *prg, CCLDevice *dev, const char *filename, CCLErr **err)
Save the program binary code for a specified device to a file.
CCLDevice * ccl_program_get_device(CCLProgram *prg, cl_uint index, CCLErr **err)
Get CCLDevice wrapper at given index.
CCLKernel * ccl_program_get_kernel(CCLProgram *prg, const char *kernel_name, CCLErr **err)
Get the kernel wrapper object for the given program kernel function.
cl_bool ccl_program_build_full(CCLProgram *prg, cl_uint num_devices, CCLDevice *const *devs, const char *options, ccl_program_callback pfn_notify, void *user_data, CCLErr **err)
Builds (compiles and links) a program executable from the program source or binary.
void ccl_program_destroy(CCLProgram *prg)
Decrements the reference count of the program wrapper object.
Class which represents a binary object associated with a program and a device.
Program object.
Definition: ccl_common.h:108
CCLProgram * ccl_program_new_from_sources(CCLContext *ctx, cl_uint count, const char **strings, const size_t *lengths, CCLErr **err)
Create a new program wrapper object from several source code strings.
#define ccl_program_get_info_scalar(prg, param_name, param_type, err)
Macro which returns a scalar program information value.
Device wrapper class.
The operation is not supported by the version of the selected OpenCL platform.
Definition: ccl_common.h:311
cl_uint ccl_program_get_num_devices(CCLProgram *prg, CCLErr **err)
Return number of devices in program.
CCLKernel * ccl_kernel_new(CCLProgram *prg, const char *kernel_name, CCLErr **err)
Create a new kernel wrapper object.