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
canon.c
/*
* This file is part of cf4ocl (C Framework for OpenCL).
*
* cf4ocl is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* cf4ocl is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with cf4ocl. If not, see <http://www.gnu.org/licenses/>.
* */
/*
* Description
* -----------
*
* Cannonical example of how to use _cf4ocl_. Performs an element-wise sum of
* two vectors, also adding a constant.
*
* Optional command-line arguments:
*
* 1. Device index
* 2. Buffer size
*
* */
#include <cf4ocl2.h>
#include <assert.h>
/* Kernel source string, will be hardwired in this location during the build
* process, before compilation. The kernel source is available in canon.cl. */
#define KERNEL_SRC \
@canon_KERNEL_SRC@
/* Kernel name. */
#define KERNEL_NAME "sum"
/* Default buffer size. Final size can be specified as a command-line option. */
#define DEF_BUF_N 16;
/* Error handling macros. */
#define ERROR_MSG_AND_EXIT(msg) \
do { fprintf(stderr, "\n%s\n", msg); exit(EXIT_FAILURE); } while(0)
#define HANDLE_ERROR(err) \
if (err != NULL) { ERROR_MSG_AND_EXIT(err->message); }
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. */
/* Export profiling info. */
ccl_prof_export_info_file(prof, "out.tsv", &err);
HANDLE_ERROR(err);
/* Destroy profiler object. */
/* Destroy host buffers. */
free(a_host);
free(b_host);
free(c_host);
/* Destroy wrappers. */
/* Confirm that memory allocated by wrappers has been properly freed. */
/* Bye. */
return ret_val;
}