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_abstract_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 
30 #include "ccl_abstract_wrapper.h"
31 #include "_ccl_abstract_wrapper.h"
32 #include "_ccl_kernel_wrapper.h"
33 #include "_ccl_defs.h"
34 
35 /* Generic function pointer for OpenCL clget**Info() functions. */
36 typedef cl_int (*ccl_wrapper_info_fp)(void);
37 
38 /* Table of all existing wrappers. */
39 static GHashTable* wrappers = NULL;
40 /* Define lock for synchronizing access to table of all existing wrappers. */
41 G_LOCK_DEFINE(wrappers);
42 
43 /* Wrapper names ordered by their enum type. */
44 static const char* ccl_class_names[] = {"Buffer", "Context", "Device", "Event",
45  "Image", "Kernel", "Platform", "Program", "Sampler", "Queue", "None", NULL};
46 
47 /* Information functions. They must be in the same order as defined in the
48  * CCLInfo enum. */
49 static const ccl_wrapper_info_fp info_funs[] = {
50  (ccl_wrapper_info_fp) clGetContextInfo,
51  (ccl_wrapper_info_fp) clGetDeviceInfo,
52  (ccl_wrapper_info_fp) clGetEventInfo,
53  (ccl_wrapper_info_fp) clGetEventProfilingInfo,
54  (ccl_wrapper_info_fp) clGetImageInfo,
55  (ccl_wrapper_info_fp) clGetKernelInfo,
56 #ifdef CL_VERSION_1_2
57  (ccl_wrapper_info_fp) ccl_kernel_get_arg_info_adapter,
58 #else
59  NULL,
60 #endif
61  (ccl_wrapper_info_fp) clGetKernelWorkGroupInfo,
62 #ifdef CL_VERSION_2_1
63  NULL /* clKernelSubGroupInfo - not implemented yet. */,
64 #else
65  NULL,
66 #endif
67  (ccl_wrapper_info_fp) clGetMemObjectInfo,
68  (ccl_wrapper_info_fp) clGetPlatformInfo,
69  (ccl_wrapper_info_fp) clGetProgramInfo,
70  (ccl_wrapper_info_fp) clGetProgramBuildInfo,
71  (ccl_wrapper_info_fp) clGetSamplerInfo,
72  (ccl_wrapper_info_fp) clGetCommandQueueInfo,
73 #ifdef CL_VERSION_2_0
74  NULL /* clGetPipeInfo - not implemented yet. */
75 #else
76  NULL,
77 #endif
78 };
79 
84 
89  GHashTable* table;
90 
95  GSList* old_info;
96 
102  GMutex mutex;
103 
104 };
105 
106 /* ********************************* */
107 /* ****** Protected methods ******** */
108 /* ********************************* */
109 
122 CCLWrapper* ccl_wrapper_new(CCLClass class, void* cl_object, size_t size) {
123 
124  /* Make sure OpenCL object is not NULL. */
125  g_return_val_if_fail(cl_object != NULL, NULL);
126 
127  /* The new wrapper object. */
128  CCLWrapper* w;
129 
130  /* Lock access to table of all existing wrappers. */
131  G_LOCK(wrappers);
132 
133  /* If table of all existing wrappers is not yet initialized,
134  * initialize it. */
135  if (wrappers == NULL) {
136  wrappers = g_hash_table_new_full(
137  g_direct_hash, g_direct_equal, NULL, NULL);
138  }
139 
140  /* Check if requested wrapper already exists, and get it if so. */
141  w = g_hash_table_lookup(wrappers, cl_object);
142 
143  if (w == NULL) {
144 
145  /* Wrapper doesn't yet exist, create it. */
146  w = (CCLWrapper*) g_slice_alloc0(size);
147  w->class = class;
148  w->cl_object = cl_object;
149 
150  /* Initialize info table. */
151  w->info = g_slice_new0(struct ccl_wrapper_info_table);
152  g_mutex_init(&w->info->mutex);
153 
154  /* Insert newly created wrapper in table of all existing
155  * wrappers. */
156  g_hash_table_insert(wrappers, cl_object, w);
157 
158  }
159 
160  /* Increase reference count of wrapper. */
161  ccl_wrapper_ref(w);
162 
163  /* Unlock access to table of all existing wrappers. */
164  G_UNLOCK(wrappers);
165 
166  /* Return requested wrapper. */
167  return w;
168 }
169 
189 cl_bool ccl_wrapper_unref(CCLWrapper* wrapper, size_t size,
190  ccl_wrapper_release_fields rel_fields_fun,
191  ccl_wrapper_release_cl_object rel_cl_fun, CCLErr** err) {
192 
193  /* Make sure wrapper object is not NULL. */
194  g_return_val_if_fail(wrapper != NULL, CL_FALSE);
195 
196  /* Make sure err is NULL or it is not set. */
197  g_return_val_if_fail(err == NULL || *err == NULL, CL_FALSE);
198 
199  /* Flag which indicates if wrapper was destroyed or not. */
200  cl_bool destroyed = CL_FALSE;
201 
202  /* OpenCL status flag. */
203  cl_int ocl_status;
204 
205 #ifdef CCL_DEBUG_OBJ_LIFETIME
206 
207  /* Log destruction/unreferencing of wrapper. */
208  g_debug("Destroy/unref. CCL%s(%p)",
209  ccl_wrapper_get_class_name(wrapper), (void*) wrapper->cl_object);
210 
211 #endif
212 
213  /* Decrement reference count and check if it reaches 0. */
214  if (g_atomic_int_dec_and_test(&wrapper->ref_count)) {
215 
216  /* Ref. count reached 0, so wrapper will be destroyed. */
217  destroyed = CL_TRUE;
218 
219  /* Release the OpenCL wrapped object. */
220  if (rel_cl_fun != NULL) {
221  ocl_status = rel_cl_fun(wrapper->cl_object);
222  if (ocl_status != CL_SUCCESS) {
223  g_set_error(err, CCL_OCL_ERROR, ocl_status,
224  "%s: unable to create release OpenCL object "
225  "(OpenCL error %d: %s).",
226  CCL_STRD, ocl_status, ccl_err(ocl_status));
227  }
228  }
229 
230  /* Destroy table containing wrapped object information. */
231  if (wrapper->info->table != NULL) {
232  g_hash_table_destroy(wrapper->info->table);
233  }
234  if (wrapper->info->old_info != NULL) {
235  g_slist_free_full(wrapper->info->old_info,
236  (GDestroyNotify) ccl_wrapper_info_destroy);
237  }
238  g_mutex_clear(&wrapper->info->mutex);
239  g_slice_free(struct ccl_wrapper_info_table, wrapper->info);
240 
241  /* Remove wrapper from static table, release static table if
242  * empty. */
243  G_LOCK(wrappers);
244  g_hash_table_remove(wrappers, wrapper->cl_object);
245  if (g_hash_table_size(wrappers) == 0) {
246  g_hash_table_destroy(wrappers);
247  wrappers = NULL;
248  }
249  G_UNLOCK(wrappers);
250 
251  /* Destroy remaining wrapper fields. */
252  if (rel_fields_fun != NULL)
253  rel_fields_fun(wrapper);
254 
255  /* Destroy wrapper. */
256  g_slice_free1(size, wrapper);
257 
258  }
259 
260  /* Return flag indicating if wrapper was destroyed. */
261  return destroyed;
262 
263 }
264 
277 void ccl_wrapper_add_info(CCLWrapper* wrapper, cl_uint param_name,
278  CCLWrapperInfo* info) {
279 
280  /* Make sure wrapper is not NULL. */
281  g_return_if_fail(wrapper != NULL);
282  /* Make sure info is not NULL. */
283  g_return_if_fail(info != NULL);
284 
285  /* Lock access to info table. */
286  g_mutex_lock(&wrapper->info->mutex);
287 
288  /* If information table is not yet initialized, then
289  * initialize it. */
290  if (wrapper->info->table == NULL) {
291  wrapper->info->table = g_hash_table_new_full(
292  g_direct_hash, g_direct_equal,
293  NULL, (GDestroyNotify) ccl_wrapper_info_destroy);
294  }
295 
296  /* Check if information with same key as already present in
297  * table... */
298  if (g_hash_table_contains(
299  wrapper->info->table, GUINT_TO_POINTER(param_name))) {
300 
301  /* ...if so, move this information to the old information
302  * table. */
303 
304  /* Get existing information... */
305  CCLWrapperInfo* info_old =
306  (CCLWrapperInfo*) g_hash_table_lookup(
307  wrapper->info->table, GUINT_TO_POINTER(param_name));
308 
309  /* ...and put it in table of old information. */
310  wrapper->info->old_info =
311  g_slist_prepend(wrapper->info->old_info, info_old);
312 
313  /* Remove old info from info table without destroying it. */
314  g_hash_table_steal(
315  wrapper->info->table, GUINT_TO_POINTER(param_name));
316 
317  }
318 
319  /* Keep new information in information table. */
320  g_hash_table_insert(wrapper->info->table,
321  GUINT_TO_POINTER(param_name), info);
322 
323  /* Unlock access to info table. */
324  g_mutex_unlock(&wrapper->info->mutex);
325 
326 }
327 
337 CCLWrapperInfo* ccl_wrapper_info_new(size_t size) {
338 
339  CCLWrapperInfo* info = g_slice_new(CCLWrapperInfo);
340 
341  if (size > 0)
342  info->value = g_slice_alloc0(size);
343  else
344  info->value = NULL;
345  info->size = size;
346 
347  return info;
348 
349 }
350 
359 void ccl_wrapper_info_destroy(CCLWrapperInfo* info) {
360 
361  /* Make sure info is not NULL. */
362  g_return_if_fail(info != NULL);
363 
364  if (info->size > 0)
365  g_slice_free1(info->size, info->value);
366  g_slice_free(CCLWrapperInfo, info);
367 
368 }
369 
370 /* ********************************* */
371 /* ******** Public methods ********* */
372 /* ********************************* */
373 
381 CCL_EXPORT
382 void ccl_wrapper_ref(CCLWrapper* wrapper) {
383 
384  /* Make sure wrapper object is not NULL. */
385  g_return_if_fail(wrapper != NULL);
386 
387  /* Increment wrapper reference count. */
388  g_atomic_int_inc(&wrapper->ref_count);
389 
390 #ifdef CCL_DEBUG_OBJ_LIFETIME
391 
392  /* Log creation/referencing of wrapper. */
393  g_debug("New/ref. CCL%s(%p)",
394  ccl_wrapper_get_class_name(wrapper), (void*) wrapper->cl_object);
395 
396 #endif
397 
398 }
399 
409 CCL_EXPORT
411 
412  /* Make sure wrapper is not NULL. */
413  g_return_val_if_fail(wrapper != NULL, -1);
414 
415  /* Return reference count. */
416  return wrapper->ref_count;
417 
418 }
419 
428 CCL_EXPORT
430 
431  /* Make sure wrapper is not NULL. */
432  g_return_val_if_fail(wrapper != NULL, NULL);
433 
434  /* Return the OpenCL wrapped object. */
435  return wrapper->cl_object;
436 }
437 
462 CCL_EXPORT
464  CCLWrapper* wrapper2, cl_uint param_name, size_t min_size,
465  CCLInfo info_type, cl_bool use_cache, CCLErr** err) {
466 
467  /* Make sure err is NULL or it is not set. */
468  g_return_val_if_fail((err) == NULL || *(err) == NULL, NULL);
469 
470  /* Make sure wrapper1 is not NULL. */
471  g_return_val_if_fail(wrapper1 != NULL, NULL);
472 
473  /* Make sure info_type has a valid value. */
474  g_return_val_if_fail((info_type >= 0) && (info_type < CCL_INFO_END), NULL);
475 
476  /* Information object. */
477  CCLWrapperInfo* info = NULL;
478 
479  /* Does info table cache contain requested information? */
480  gboolean contains;
481 
482  /* Information function to use. */
483  ccl_wrapper_info_fp info_fun = info_funs[info_type];
484 
485  /* Check if info table cache contains requested information. */
486  g_mutex_lock(&wrapper1->info->mutex);
487  contains = wrapper1->info->table != NULL
488  ? g_hash_table_contains(
489  wrapper1->info->table, GUINT_TO_POINTER(param_name))
490  : FALSE;
491  g_mutex_unlock(&wrapper1->info->mutex);
492 
493  /* Check if it is required to query OpenCL object, i.e. if info
494  * table cache is not to be used or info table cache does not
495  * contain requested info. */
496  if ((!use_cache) || (!contains)) {
497 
498  /* Let's query OpenCL object.*/
499  cl_int ocl_status;
500  /* Size of device information in bytes. */
501  size_t size_ret = 0;
502 
503  /* Get size of information. */
504  ocl_status = (wrapper2 == NULL)
505  ? ((ccl_wrapper_info_fp1) info_fun)(wrapper1->cl_object,
506  param_name, 0, NULL, &size_ret)
507  : ((ccl_wrapper_info_fp2) info_fun)(wrapper1->cl_object,
508  wrapper2->cl_object, param_name, 0, NULL, &size_ret);
509 
510  /* Avoid bug in Apple OpenCL implementation. */
511 #if defined(__APPLE__) || defined(__MACOSX)
512  if ((ocl_status == CL_INVALID_VALUE)
513  && (info_fun == (ccl_wrapper_info_fp) clGetEventProfilingInfo))
514  ocl_status = CL_SUCCESS;
515 #endif
516 
518  CL_SUCCESS != ocl_status, ocl_status, error_handler,
519  "%s: get info [size] (OpenCL error %d: %s).",
520  CCL_STRD, ocl_status, ccl_err(ocl_status));
521  ccl_if_err_create_goto(*err, CCL_ERROR, size_ret == 0,
522  CCL_ERROR_INFO_UNAVAILABLE_OCL, error_handler,
523  "%s: the requested info is unavailable (info size is 0).",
524  CCL_STRD);
525 
526  /* Allocate memory for information. */
527  info = ccl_wrapper_info_new(size_ret);
528 
529  /* Get information. */
530  ocl_status = (wrapper2 == NULL)
531  ? ((ccl_wrapper_info_fp1) info_fun)(wrapper1->cl_object,
532  param_name, size_ret, info->value, NULL)
533  : ((ccl_wrapper_info_fp2) info_fun)(wrapper1->cl_object,
534  wrapper2->cl_object, param_name, size_ret, info->value,
535  NULL);
537  CL_SUCCESS != ocl_status, ocl_status, error_handler,
538  "%s: get context info [info] (OpenCL error %d: %s).",
539  CCL_STRD, ocl_status, ccl_err(ocl_status));
540 
541  /* Keep information in information table. */
542  ccl_wrapper_add_info(wrapper1, param_name, info);
543 
544  } else {
545 
546  /* Requested info is already present in the info table,
547  * retrieve it from there. */
548  g_mutex_lock(&wrapper1->info->mutex);
549  info = g_hash_table_lookup(
550  wrapper1->info->table, GUINT_TO_POINTER(param_name));
551  g_mutex_unlock(&wrapper1->info->mutex);
552 
553  }
554 
555  /* If we got here, everything is OK. */
556  g_assert(err == NULL || *err == NULL);
557  goto finish;
558 
559 error_handler:
560  /* If we got here there was an error, verify that it is so. */
561  g_assert(err == NULL || *err != NULL);
562 
563  /* In case of error, return an all-zeros info if min_size is > 0. */
564  if (min_size > 0) {
565  if (info != NULL) ccl_wrapper_info_destroy(info);
566  info = ccl_wrapper_info_new(min_size);
567  ccl_wrapper_add_info(wrapper1, param_name, info);
568  }
569 
570 finish:
571 
572  /* Return the requested information. */
573  return info;
574 }
575 
599 CCL_EXPORT
601  CCLWrapper* wrapper2, cl_uint param_name, size_t min_size,
602  CCLInfo info_type, cl_bool use_cache, CCLErr** err) {
603 
604  /* Make sure err is NULL or it is not set. */
605  g_return_val_if_fail(err == NULL || *err == NULL, NULL);
606 
607  /* Make sure wrapper1 is not NULL. */
608  g_return_val_if_fail(wrapper1 != NULL, NULL);
609 
610  /* Make sure info_type has a valid value. */
611  g_return_val_if_fail((info_type >= 0) && (info_type < CCL_INFO_END), NULL);
612 
613  /* Get information object. */
614  CCLWrapperInfo* diw = ccl_wrapper_get_info(wrapper1, wrapper2,
615  param_name, min_size, info_type, use_cache, err);
616 
617  /* Return value if information object is not NULL. */
618  return diw != NULL ? diw->value : NULL;
619 }
620 
641 size_t CCL_EXPORT ccl_wrapper_get_info_size(CCLWrapper* wrapper1,
642  CCLWrapper* wrapper2, cl_uint param_name, size_t min_size,
643  CCLInfo info_type, cl_bool use_cache, CCLErr** err) {
644 
645  /* Make sure err is NULL or it is not set. */
646  g_return_val_if_fail(err == NULL || *err == NULL, 0);
647 
648  /* Make sure wrapper1 is not NULL. */
649  g_return_val_if_fail(wrapper1 != NULL, 0);
650 
651  /* Make sure info_type has a valid value. */
652  g_return_val_if_fail((info_type >= 0) && (info_type < CCL_INFO_END), 0);
653 
654  /* Get information object. */
655  CCLWrapperInfo* diw = ccl_wrapper_get_info(wrapper1, wrapper2,
656  param_name, min_size, info_type, use_cache, err);
657 
658  /* Return value if information object is not NULL. */
659  return diw != NULL ? diw->size : 0;
660 }
661 
674 CCL_EXPORT
676 
677  /* Check return variable. */
678  cl_bool check;
679 
680 #ifndef NDEBUG
681 
682  /* Iterator over existing wrappers. */
683  GHashTableIter iter;
684 
685  /* Current wrapper. */
686  CCLWrapper* obj = NULL;
687 
688  /* Current wrapper address. */
689  gpointer addr;
690 
691  /* Log string. */
692  GString* logstr = NULL;
693 
694 #endif
695 
696  /* Lock access to wrappers variable. */
697  G_LOCK(wrappers);
698 
699  /* Check if wrappers variable is set. */
700  check = (wrappers == NULL);
701 
702 #ifndef NDEBUG
703 
704  /* In debug mode, log existing wrappers. */
705  if (check) {
706 
707  /* Wrappers table is empty. */
708  g_debug("Wrappers table is empty");
709 
710  } else {
711 
712  /* Wrappers table is not empty, list them. */
713 
714  /* Initialize iterator. */
715  g_hash_table_iter_init(&iter, wrappers);
716 
717  /* Initialize log string. */
718  logstr = g_string_new("");
719  g_string_append_printf(logstr,
720  "There are %u wrappers in table: ", g_hash_table_size(wrappers));
721 
722  /* Iterate over existing wrappers... */
723  while(g_hash_table_iter_next(&iter, &addr, (gpointer) &obj)) {
724 
725  /*...and add their name and address to log string. */
726  g_string_append_printf(logstr, "\n%s(%p) ",
727  ccl_wrapper_get_class_name(obj), addr);
728 
729  }
730 
731  /* Log existing wrappers.*/
732  g_debug("%s\n", logstr->str);
733 
734  /* Release string. */
735  g_string_free(logstr, TRUE);
736 
737  }
738 
739 #endif
740 
741  /* Unlock access to wrappers variable. */
742  G_UNLOCK(wrappers);
743 
744  /* Return check. */
745  return check;
746 }
747 
755 CCL_EXPORT
756 const char* ccl_wrapper_get_class_name(CCLWrapper* wrapper) {
757 
758  /* Make sure wrapper is not NULL. */
759  g_return_val_if_fail(wrapper != NULL, NULL);
760 
761  /* Make sure class enum value is within bounds. */
762  g_return_val_if_fail(
763  (wrapper->class >= 0) && (wrapper->class < CCL_NONE), NULL);
764 
765  /* Return wrapper class name. */
766  return ccl_class_names[wrapper->class];
767 
768 }
int ccl_wrapper_ref_count(CCLWrapper *wrapper)
Returns the wrapper object reference count.
Information about wrapped OpenCL objects.
#define CCL_OCL_ERROR
Resolves to error category identifying string, in this case an error in the OpenCL library...
Definition: ccl_common.h:324
enum ccl_info CCLInfo
Type of information to obtain using ccl_wrapper_get_info(), ccl_wrapper_get_info_value() and ccl_wrap...
#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
Useful definitions used internally by cf4ocl.
size_t ccl_wrapper_get_info_size(CCLWrapper *wrapper1, CCLWrapper *wrapper2, cl_uint param_name, size_t min_size, CCLInfo info_type, cl_bool use_cache, CCLErr **err)
Get information size.
Enumeration termination marker.
Definition: ccl_common.h:159
const char * ccl_err(int code)
Convert OpenCL error code to a readable string.
Definition: ccl_errors.c:118
enum ccl_class CCLClass
Class or type of wrapped OpenCL object.
void ccl_wrapper_ref(CCLWrapper *wrapper)
Increase the reference count of the wrapper object.
This header provides the prototype of the ccl_kernel_get_arg_info_adapter() function.
#define CCL_ERROR
Resolves to error category identifying string, in this case an error in cf4ocl.
Definition: ccl_common.h:320
CCLWrapperInfo * ccl_wrapper_get_info(CCLWrapper *wrapper1, CCLWrapper *wrapper2, cl_uint param_name, size_t min_size, CCLInfo info_type, cl_bool use_cache, CCLErr **err)
Get information about any wrapped OpenCL object.
Base class for all OpenCL wrappers.
size_t size
Size in bytes of object information.
const char * ccl_wrapper_get_class_name(CCLWrapper *wrapper)
Get wrapper class or type name.
Object information is unavailable.
Definition: ccl_common.h:313
Definition of an abstract wrapper class and its methods for OpenCL objects.
void * value
Object information.
void * ccl_wrapper_get_info_value(CCLWrapper *wrapper1, CCLWrapper *wrapper2, cl_uint param_name, size_t min_size, CCLInfo info_type, cl_bool use_cache, CCLErr **err)
Get pointer to information value.
Class which represents information about a wrapped OpenCL object.
GError CCLErr
Error handling class.
Definition: ccl_common.h:291
No object, enumeration termination marker.
Definition: ccl_common.h:114
cl_bool ccl_wrapper_memcheck()
Debug function which checks if memory allocated by wrappers has been properly freed.
void * ccl_wrapper_unwrap(CCLWrapper *wrapper)
Get the wrapped OpenCL object.