/** * @internal * * @brief Tests buffer fill. * */ static void fill_test() { /* Test variables. */ CCLPlatforms * ps; CCLPlatform * p; CCLContext * ctx = NULL; CCLDevice * d = NULL; CCLBuffer * b = NULL; CCLQueue * q; cl_char8 h[CCL_TEST_BUFFER_SIZE]; cl_char8 pattern = {{ 1, -1, 5, 4, -12, 3, 7, -20 }}; size_t buf_size = sizeof(cl_char8) * CCL_TEST_BUFFER_SIZE; CCLErr * err = NULL; /* Get a context which supports OpenCL 1.2, if possible. */ ps = ccl_platforms_new(&err); g_assert_no_error(err); for (guint i = 0; i < ccl_platforms_count(ps); ++i) { p = ccl_platforms_get(ps, i); cl_uint ocl_ver = ccl_platform_get_opencl_version(p, &err); if (ocl_ver >= 120) { ctx = ccl_context_new_from_devices( ccl_platform_get_num_devices(p, NULL), ccl_platform_get_all_devices(p, NULL), &err); g_assert_no_error(err); break; } } /* If not possible to find a 1.2 or better context, finish this * test. */ if (ctx == NULL) { g_test_message("'%s' test not performed because no platform " \ "with OpenCL 1.2 support was found", CCL_STRD); ccl_platforms_destroy(ps); return; } /* Get first device in context. */ d = ccl_context_get_device(ctx, 0, &err); g_assert_no_error(err); /* Create a command queue. */ q = ccl_queue_new(ctx, d, 0, &err); g_assert_no_error(err); /* Create regular buffer. */ b = ccl_buffer_new(ctx, CL_MEM_READ_WRITE, buf_size, NULL, &err); g_assert_no_error(err); /* Fill buffer with pattern. */ ccl_buffer_enqueue_fill( b, q, &pattern, sizeof(cl_char8), 0, buf_size, NULL, &err); g_assert_no_error(err); /* Read data back to host. */ ccl_buffer_enqueue_read(b, q, CL_TRUE, 0, buf_size, h, NULL, &err); g_assert_no_error(err); /* Check data is OK. */ for (guint i = 0; i < CCL_TEST_BUFFER_SIZE; ++i) for (guint j = 0; j < 8; ++j) g_assert_cmpuint(h[i].s[j], ==, pattern.s[j]); /* Free stuff. */ ccl_buffer_destroy(b); ccl_queue_destroy(q); ccl_context_destroy(ctx); ccl_platforms_destroy(ps); /* Confirm that memory allocated by wrappers has been properly * freed. */ g_assert(ccl_wrapper_memcheck()); }
/** * @internal * * @brief Tests the ccl_buffer_new_from_region() function. * */ static void create_from_region_test() { /* Test variables. */ CCLContext * ctx = NULL; CCLDevice * dev = NULL; CCLQueue * cq = NULL; CCLBuffer * buf = NULL; CCLBuffer * subbuf = NULL; CCLEvent * evt = NULL; CCLEventWaitList ewl = NULL; CCLErr * err = NULL; cl_ulong * hbuf; cl_ulong * hsubbuf; cl_uint min_align; size_t siz_buf; size_t siz_subbuf; /* Get the test context with the pre-defined device. */ ctx = ccl_test_context_new(&err); g_assert_no_error(err); /* Get first device in context. */ dev = ccl_context_get_device(ctx, 0, &err); g_assert_no_error(err); /* Get minimum alignment for sub-buffer in bits. */ min_align = ccl_device_get_info_scalar( dev, CL_DEVICE_MEM_BASE_ADDR_ALIGN, cl_uint, &err); g_assert_no_error(err); /* Determine buffer and sub-buffer sizes (divide by 64 because its * the number of bits in cl_ulong). */ siz_subbuf = sizeof(cl_ulong) * min_align / 64; siz_buf = 4 * siz_subbuf; /* Allocate memory for host buffer and host sub-buffer. */ hbuf = g_slice_alloc(siz_buf); hsubbuf = g_slice_alloc(siz_subbuf); /* Initialize initial host buffer. */ for (cl_uint i = 0; i < siz_buf / sizeof(cl_ulong); ++i) hbuf[i] = g_test_rand_int(); /* Create a command queue. */ cq = ccl_queue_new(ctx, dev, 0, &err); g_assert_no_error(err); /* Create a regular buffer, put some data in it. */ buf = ccl_buffer_new( ctx, CL_MEM_READ_WRITE | CL_MEM_COPY_HOST_PTR, siz_buf, hbuf, &err); g_assert_no_error(err); /* Create sub-buffer from indexes 16 to 31 (16 positions) of * original buffer. */ subbuf = ccl_buffer_new_from_region( buf, 0, siz_subbuf, siz_subbuf, &err); g_assert_no_error(err); /* Get data in sub-buffer to a new host buffer. */ evt = ccl_buffer_enqueue_read( subbuf, cq, CL_FALSE, 0, siz_subbuf, hsubbuf, NULL, &err); g_assert_no_error(err); /* Wait for read to be complete. */ ccl_event_wait(ccl_ewl(&ewl, evt, NULL), &err); g_assert_no_error(err); /* Check that expected values were successfully read. */ for (cl_uint i = 0; i < siz_subbuf / sizeof(cl_ulong); ++i) g_assert_cmpuint( hsubbuf[i], ==, hbuf[i + siz_subbuf / sizeof(cl_ulong)]); /* Destroy stuff. */ ccl_buffer_destroy(buf); ccl_buffer_destroy(subbuf); ccl_queue_destroy(cq); ccl_context_destroy(ctx); g_slice_free1(siz_buf, hbuf); g_slice_free1(siz_subbuf, hsubbuf); /* Confirm that memory allocated by wrappers has been properly * freed. */ g_assert(ccl_wrapper_memcheck()); }
/** * @internal * * @brief Tests basic read/write operations from/to buffer objects. * */ static void read_write_test() { /* Test variables. */ CCLContext * ctx = NULL; CCLDevice * d = NULL; CCLBuffer * b = NULL; CCLQueue * q; cl_uint h_in[CCL_TEST_BUFFER_SIZE]; cl_uint h_out[CCL_TEST_BUFFER_SIZE]; size_t buf_size = sizeof(cl_uint) * CCL_TEST_BUFFER_SIZE; CCLErr * err = NULL; /* Create a host array, put some stuff in it. */ for (guint i = 0; i < CCL_TEST_BUFFER_SIZE; ++i) h_in[i] = g_test_rand_int(); /* Get the test context with the pre-defined device. */ ctx = ccl_test_context_new(&err); g_assert_no_error(err); /* Get first device in context. */ d = ccl_context_get_device(ctx, 0, &err); g_assert_no_error(err); /* Create a command queue. */ q = ccl_queue_new(ctx, d, 0, &err); g_assert_no_error(err); /* Create regular buffer and write data from the host buffer. */ b = ccl_buffer_new( ctx, CL_MEM_READ_WRITE | CL_MEM_COPY_HOST_PTR, buf_size, h_in, &err); g_assert_no_error(err); /* Read data back to host. */ ccl_buffer_enqueue_read( b, q, CL_TRUE, 0, buf_size, (void *) h_out, NULL, &err); g_assert_no_error(err); /* Check data is OK. */ for (guint i = 0; i < CCL_TEST_BUFFER_SIZE; ++i) g_assert_cmpuint(h_in[i], ==, h_out[i]); /* Set some other data in host array. */ for (guint i = 0; i < CCL_TEST_BUFFER_SIZE; ++i) h_in[i] = g_test_rand_int(); /* Write it explicitly to buffer. */ ccl_buffer_enqueue_write( b, q, CL_TRUE, 0, buf_size, (void *) h_in, NULL, &err); g_assert_no_error(err); /* Read new data to host. */ ccl_buffer_enqueue_read( b, q, CL_TRUE, 0, buf_size, (void *) h_out, NULL, &err); g_assert_no_error(err); /* Check data is OK. */ for (guint i = 0; i < CCL_TEST_BUFFER_SIZE; ++i) g_assert_cmpuint(h_in[i], ==, h_out[i]); /* Free stuff. */ ccl_buffer_destroy(b); ccl_queue_destroy(q); ccl_context_destroy(ctx); /* Confirm that memory allocated by wrappers has been properly * freed. */ g_assert(ccl_wrapper_memcheck()); }
/** * @internal * * @brief Tests copy operations from one buffer to another. * */ static void copy_test() { /* Test variables. */ CCLContext * ctx = NULL; CCLDevice * d = NULL; CCLBuffer * b1 = NULL; CCLBuffer * b2 = NULL; CCLQueue * q; cl_long h1[CCL_TEST_BUFFER_SIZE]; cl_long h2[CCL_TEST_BUFFER_SIZE]; size_t buf_size = sizeof(cl_long) * CCL_TEST_BUFFER_SIZE; CCLErr * err = NULL; /* Create a host array, put some stuff in it. */ for (guint i = 0; i < CCL_TEST_BUFFER_SIZE; ++i) h1[i] = g_test_rand_int(); /* Get the test context with the pre-defined device. */ ctx = ccl_test_context_new(&err); g_assert_no_error(err); /* Get first device in context. */ d = ccl_context_get_device(ctx, 0, &err); g_assert_no_error(err); /* Create a command queue. */ q = ccl_queue_new(ctx, d, 0, &err); g_assert_no_error(err); /* Create regular buffer and write data from the host buffer. */ b1 = ccl_buffer_new( ctx, CL_MEM_READ_WRITE | CL_MEM_COPY_HOST_PTR, buf_size, h1, &err); g_assert_no_error(err); /* Create another buffer, double the size. */ b2 = ccl_buffer_new(ctx, CL_MEM_READ_WRITE, 2 * buf_size, NULL, &err); g_assert_no_error(err); /* Copy data from first buffer to second buffer, using an offset on * the second buffer. */ ccl_buffer_enqueue_copy( b1, b2, q, 0, buf_size / 2, buf_size, NULL, &err); g_assert_no_error(err); /* Read data back to host from the second buffer. */ ccl_buffer_enqueue_read( b2, q, CL_TRUE, buf_size / 2, buf_size, h2, NULL, &err); g_assert_no_error(err); /* Check data is OK. */ for (guint i = 0; i < CCL_TEST_BUFFER_SIZE; ++i) g_assert_cmpuint(h1[i], ==, h2[i]); /* Free stuff. */ ccl_buffer_destroy(b1); ccl_buffer_destroy(b2); ccl_queue_destroy(q); ccl_context_destroy(ctx); /* Confirm that memory allocated by wrappers has been properly * freed. */ g_assert(ccl_wrapper_memcheck()); }
/** * Canonical example main function. * */ int main(int argc, char** argv) { /* Number of elements in buffer. */ size_t buf_n = DEF_BUF_N; /* Device selected specified in the command line. */ int dev_idx = -1; /* Program return value. */ int ret_val; /* Check if a device was specified in the command line. */ if (argc >= 2) { dev_idx = atoi(argv[1]); } /* Check if a new buffer size was specified in the command line. */ if (argc >= 3) { buf_n = atoi(argv[2]); } /* Wrappers. */ CCLContext* ctx = NULL; CCLProgram* prg = NULL; CCLDevice* dev = NULL; CCLQueue* queue = NULL; CCLKernel* krnl = NULL; CCLBuffer* a_dev; CCLBuffer* b_dev; CCLBuffer* c_dev; CCLEvent* evt_write1; CCLEvent* evt_write2; CCLEvent* evt_exec; CCLEventWaitList ewl = NULL; /* Profiler. */ CCLProf* prof; /* Global and local worksizes. */ size_t gws = 0; size_t lws = 0; /* Host buffers. */ cl_uint* a_host = NULL; cl_uint* b_host = NULL; cl_uint* c_host = NULL; cl_uint d_host; /* Error reporting object. */ CCLErr* err = NULL; /* Check results flag. */ cl_bool check_result; /* Create a context with device selected from menu. */ ctx = ccl_context_new_from_menu_full(&dev_idx, &err); HANDLE_ERROR(err); /* Get the selected device. */ dev = ccl_context_get_device(ctx, 0, &err); HANDLE_ERROR(err); /* Create a new program from kernel source. */ prg = ccl_program_new_from_source(ctx, KERNEL_SRC, &err); HANDLE_ERROR(err); /* Build program. */ ccl_program_build(prg, NULL, &err); HANDLE_ERROR(err); /* Create a command queue. */ queue = ccl_queue_new(ctx, dev, CL_QUEUE_PROFILING_ENABLE, &err); HANDLE_ERROR(err); /* Get kernel object. */ krnl = ccl_program_get_kernel(prg, KERNEL_NAME, &err); HANDLE_ERROR(err); /* Get worksizes. */ lws = ccl_kernel_suggest_worksizes(krnl, dev, 1, &buf_n, &gws, &lws, &err); HANDLE_ERROR(err); /* Show worksizes. */ printf("\n"); printf(" * Global worksize: %d\n", (int) gws); printf(" * Local worksize : %d\n", (int) lws); /* Initialize host buffers. */ a_host = (cl_uint*) malloc(sizeof(cl_uint) * buf_n); b_host = (cl_uint*) malloc(sizeof(cl_uint) * buf_n); c_host = (cl_uint*) malloc(sizeof(cl_uint) * buf_n); /* Fill host buffers. */ for (cl_uint i = 0; i < buf_n; ++i) { a_host[i] = i; b_host[i] = buf_n - i; } d_host = buf_n / 4; /* Create device buffers. */ a_dev = ccl_buffer_new(ctx, CL_MEM_READ_ONLY, buf_n * sizeof(cl_uint), NULL, &err); HANDLE_ERROR(err); b_dev = ccl_buffer_new(ctx, CL_MEM_READ_ONLY, buf_n * sizeof(cl_uint), NULL, &err); HANDLE_ERROR(err); c_dev = ccl_buffer_new(ctx, CL_MEM_WRITE_ONLY, buf_n * sizeof(cl_uint), NULL, &err); HANDLE_ERROR(err); /* Copy host data to device buffers without waiting for transfer * to terminate before continuing host program. */ evt_write1 = ccl_buffer_enqueue_write(a_dev, queue, CL_FALSE, 0, buf_n * sizeof(cl_uint), a_host, NULL, &err); HANDLE_ERROR(err); evt_write2 = ccl_buffer_enqueue_write(b_dev, queue, CL_FALSE, 0, buf_n * sizeof(cl_uint), b_host, NULL, &err); HANDLE_ERROR(err); /* Initialize event wait list and add the two transfer events. */ ccl_event_wait_list_add(&ewl, evt_write1, evt_write2, NULL); /* Execute program kernel, waiting for the two transfer events * to terminate (this will empty the event wait list). */ evt_exec = ccl_program_enqueue_kernel(prg, KERNEL_NAME, queue, 1, NULL, &gws, &lws, &ewl, &err, /* Kernel arguments. */ a_dev, b_dev, c_dev, ccl_arg_priv(d_host, cl_uint), ccl_arg_priv(buf_n, cl_uint), NULL); HANDLE_ERROR(err); /* Add the kernel termination event to the wait list. */ ccl_event_wait_list_add(&ewl, evt_exec, NULL); /* Sync. queue for events in wait list (just the execute event in * this case) to terminate before going forward... */ ccl_enqueue_barrier(queue, &ewl, &err); HANDLE_ERROR(err); /* Read back results from host waiting for transfer to terminate * before continuing host program. */ ccl_buffer_enqueue_read(c_dev, queue, CL_TRUE, 0, buf_n * sizeof(cl_uint), c_host, NULL, &err); HANDLE_ERROR(err); /* Check results are as expected (not available with OpenCL stub). */ check_result = CL_TRUE; for (cl_uint i = 0; i < buf_n; ++i) { if(c_host[i] != a_host[i] + b_host[i] + d_host) { check_result = CL_FALSE; break; } } if (check_result) { fprintf(stdout, " * Kernel execution produced the expected results.\n"); ret_val = EXIT_SUCCESS; } else { fprintf(stderr, " * Kernel execution failed to produce the expected results.\n"); ret_val = EXIT_FAILURE; } /* Perform profiling. */ prof = ccl_prof_new(); ccl_prof_add_queue(prof, "queue1", queue); ccl_prof_calc(prof, &err); HANDLE_ERROR(err); /* Show profiling info. */ ccl_prof_print_summary(prof); /* Export profiling info. */ ccl_prof_export_info_file(prof, "out.tsv", &err); HANDLE_ERROR(err); /* Destroy profiler object. */ ccl_prof_destroy(prof); /* Destroy host buffers. */ free(a_host); free(b_host); free(c_host); /* Destroy wrappers. */ ccl_buffer_destroy(a_dev); ccl_buffer_destroy(b_dev); ccl_buffer_destroy(c_dev); ccl_queue_destroy(queue); ccl_program_destroy(prg); ccl_context_destroy(ctx); /* Confirm that memory allocated by wrappers has been properly freed. */ assert(ccl_wrapper_memcheck()); /* Bye. */ return ret_val; }