/** * Cellular automata sample main function. * */ int main(int argc, char* argv[]) { /* Wrappers for OpenCL objects. */ CCLContext* ctx; CCLDevice* dev; CCLImage* img1; CCLImage* img2; CCLProgram* prg; CCLKernel* krnl; CCLEvent* evt1; CCLEvent* evt2; /* Other variables. */ CCLEventWaitList ewl = NULL; /* Profiler object. */ CCLProf* prof; /* Output images filename. */ char* filename; /* Selected device, may be given in command line. */ int dev_idx = -1; /* Error handling object (must be NULL). */ GError* err = NULL; /* Does selected device support images? */ cl_bool image_ok; /* Initial sim state. */ cl_uchar4* input_image; /* Simulation states. */ cl_uchar4** output_images; /* RNG seed, may be given in command line. */ unsigned int seed; /* Image file write status. */ int file_write_status; /* Image format. */ cl_image_format image_format = { CL_RGBA, CL_UNSIGNED_INT8 }; /* Thread data. */ struct thread_data td; /* Full kernel path. */ gchar* kernel_path = NULL; /* Global and local worksizes. */ size_t gws[2]; size_t lws[2]; /* Threads. */ GThread* comm_thread; GThread* exec_thread; /* Check arguments. */ if (argc >= 2) { /* Check if a device was specified in the command line. */ dev_idx = atoi(argv[1]); } if (argc >= 3) { /* Check if a RNG seed was specified. */ seed = atoi(argv[2]); } else { seed = (unsigned int) time(NULL); } /* Initialize RNG. */ srand(seed); /* Create random initial state. */ input_image = (cl_uchar4*) malloc(CA_WIDTH * CA_HEIGHT * sizeof(cl_uchar4)); for (cl_uint i = 0; i < CA_WIDTH * CA_HEIGHT; ++i) { cl_uchar state = (rand() & 0x3) ? 0xFF : 0x00; input_image[i] = (cl_uchar4) {{ state, state, state, 0xFF }}; } /* Allocate space for simulation results. */ output_images = (cl_uchar4**) malloc((CA_ITERS + 1) * sizeof(cl_uchar4*)); for (cl_uint i = 0; i < CA_ITERS + 1; ++i) output_images[i] = (cl_uchar4*) malloc(CA_WIDTH * CA_HEIGHT * sizeof(cl_uchar4)); /* Create context using device selected from menu. */ ctx = ccl_context_new_from_menu_full(&dev_idx, &err); HANDLE_ERROR(err); /* Get first device in context. */ dev = ccl_context_get_device(ctx, 0, &err); HANDLE_ERROR(err); /* Ask device if it supports images. */ image_ok = ccl_device_get_info_scalar( dev, CL_DEVICE_IMAGE_SUPPORT, cl_bool, &err); HANDLE_ERROR(err); if (!image_ok) ERROR_MSG_AND_EXIT("Selected device doesn't support images."); /* Create command queues. */ queue_exec = ccl_queue_new(ctx, dev, CL_QUEUE_PROFILING_ENABLE, &err); HANDLE_ERROR(err); queue_comm = ccl_queue_new(ctx, dev, CL_QUEUE_PROFILING_ENABLE, &err); HANDLE_ERROR(err); /* Create 2D image for initial state. */ img1 = ccl_image_new(ctx, CL_MEM_READ_WRITE, &image_format, NULL, &err, "image_type", (cl_mem_object_type) CL_MEM_OBJECT_IMAGE2D, "image_width", (size_t) CA_WIDTH, "image_height", (size_t) CA_HEIGHT, NULL); HANDLE_ERROR(err); /* Create another 2D image for double buffering. */ img2 = ccl_image_new(ctx, CL_MEM_READ_WRITE, &image_format, NULL, &err, "image_type", (cl_mem_object_type) CL_MEM_OBJECT_IMAGE2D, "image_width", (size_t) CA_WIDTH, "image_height", (size_t) CA_HEIGHT, NULL); HANDLE_ERROR(err); /* Get location of kernel file, which should be in the same location * of the bankconf executable. */ kernel_path = ccl_ex_kernelpath_get(kernel_files[0], argv[0]); /* Create program from kernel source and compile it. */ prg = ccl_program_new_from_source_file(ctx, kernel_path, &err); HANDLE_ERROR(err); ccl_program_build(prg, NULL, &err); HANDLE_ERROR(err); /* Get kernel wrapper. */ krnl = ccl_program_get_kernel(prg, "ca", &err); HANDLE_ERROR(err); /* Determine nice local and global worksizes. */ ccl_kernel_suggest_worksizes(krnl, dev, 2, real_ws, gws, lws, &err); HANDLE_ERROR(err); printf("\n * Global work-size: (%d, %d)\n", (int) gws[0], (int) gws[1]); printf(" * Local work-size: (%d, %d)\n", (int) lws[0], (int) lws[1]); /* Create thread communication queues. */ comm_thread_queue = g_async_queue_new(); exec_thread_queue = g_async_queue_new(); host_thread_queue = g_async_queue_new(); /* Setup thread data. */ td.krnl = krnl; td.img1 = img1; td.img2 = img2; td.gws = gws; td.lws = lws; td.output_images = output_images; /* Create threads. */ exec_thread = g_thread_new("exec_thread", exec_func, &td); comm_thread = g_thread_new("comm_thread", comm_func, &td); /* Start profiling. */ prof = ccl_prof_new(); ccl_prof_start(prof); /* Write initial state. */ ccl_image_enqueue_write(img1, queue_comm, CL_TRUE, origin, region, 0, 0, input_image, NULL, &err); HANDLE_ERROR(err); /* Run CA_ITERS iterations of the CA. */ for (cl_uint i = 0; i < CA_ITERS; ++i) { /* Send message to comms thread. */ g_async_queue_push(comm_thread_queue, &go_msg); /* Send message to exec thread. */ g_async_queue_push(exec_thread_queue, &go_msg); /* Get event wrappers from both threads. */ evt1 = (CCLEvent*) g_async_queue_pop(host_thread_queue); evt2 = (CCLEvent*) g_async_queue_pop(host_thread_queue); /* Can't continue until this iteration is over. */ ccl_event_wait_list_add(&ewl, evt1, evt2, NULL); /* Wait for events. */ ccl_event_wait(&ewl, &err); HANDLE_ERROR(err); } /* Send message to comms thread to read last result. */ g_async_queue_push(comm_thread_queue, &go_msg); /* Send stop messages to both threads. */ g_async_queue_push(comm_thread_queue, &stop_msg); g_async_queue_push(exec_thread_queue, &stop_msg); /* Get event wrapper from comms thread. */ evt1 = (CCLEvent*) g_async_queue_pop(host_thread_queue); /* Can't continue until final read is over. */ ccl_event_wait_list_add(&ewl, evt1, NULL); ccl_event_wait(&ewl, &err); HANDLE_ERROR(err); /* Make sure both queues are finished. */ ccl_queue_finish(queue_comm, &err); HANDLE_ERROR(err); ccl_queue_finish(queue_exec, &err); HANDLE_ERROR(err); /* Stop profiling timer and add queues for analysis. */ ccl_prof_stop(prof); ccl_prof_add_queue(prof, "Comms", queue_comm); ccl_prof_add_queue(prof, "Exec", queue_exec); /* Allocate space for base filename. */ filename = (char*) malloc( (strlen(IMAGE_FILE_PREFIX ".png") + IMAGE_FILE_NUM_DIGITS + 1) * sizeof(char)); /* Write results to image files. */ for (cl_uint i = 0; i < CA_ITERS; ++i) { /* Determine next filename. */ sprintf(filename, "%s%0" G_STRINGIFY(IMAGE_FILE_NUM_DIGITS) "d.png", IMAGE_FILE_PREFIX, i); /* Save next image. */ file_write_status = stbi_write_png(filename, CA_WIDTH, CA_HEIGHT, 4, output_images[i], CA_WIDTH * sizeof(cl_uchar4)); /* Give feedback if unable to save image. */ if (!file_write_status) { ERROR_MSG_AND_EXIT("Unable to save image in file."); } } /* Process profiling info. */ ccl_prof_calc(prof, &err); HANDLE_ERROR(err); /* Print profiling info. */ ccl_prof_print_summary(prof); /* Save profiling info. */ ccl_prof_export_info_file(prof, "prof.tsv", &err); HANDLE_ERROR(err); /* Destroy threads. */ g_thread_join(exec_thread); g_thread_join(comm_thread); /* Destroy thread communication queues. */ g_async_queue_unref(comm_thread_queue); g_async_queue_unref(exec_thread_queue); g_async_queue_unref(host_thread_queue); /* Release host buffers. */ free(filename); free(input_image); for (cl_uint i = 0; i < CA_ITERS + 1; ++i) free(output_images[i]); free(output_images); /* Release wrappers. */ ccl_image_destroy(img1); ccl_image_destroy(img2); ccl_program_destroy(prg); ccl_queue_destroy(queue_comm); ccl_queue_destroy(queue_exec); ccl_context_destroy(ctx); /* Destroy profiler. */ ccl_prof_destroy(prof); /* Check all wrappers have been destroyed. */ g_assert(ccl_wrapper_memcheck()); /* Terminate. */ return 0; }
/** * Kernel info main function. * * @param[in] argc Number of command line arguments. * @param[in] argv Command line arguments. * @return ::CCL_SUCCESS if program returns with no error, or another * ::CCLErrorCode value otherwise. * */ int main(int argc, char *argv[]) { /* ***************** */ /* Program variables */ /* ***************** */ /* Function and program return status. */ int status; /* Error management. */ GError *err = NULL; /* Context wrapper. */ CCLContext* ctx = NULL; /* Program wrapper. */ CCLProgram* prg = NULL; /* Kernel wrapper. */ CCLKernel* krnl = NULL; /* Device wrapper. */ CCLDevice* dev = NULL; /* Device filters. */ CCLDevSelFilters filters = NULL; /* Default device index. */ cl_int dev_idx = -1; /* OpenCL version. */ double ocl_ver; /* Kernel workgroup info variables. */ size_t k_wg_size; size_t k_pref_wg_size_mult; size_t* k_compile_wg_size; cl_ulong k_loc_mem_size; cl_ulong k_priv_mem_size; /* ************************** */ /* Parse command line options */ /* ************************** */ /* If version was requested, output version and exit. */ if ((argc == 2) && (g_strcmp0("--version", argv[1]) == 0)) { ccl_common_version_print("ccl_kerninfo"); exit(0); } ccl_if_err_create_goto(err, CCL_ERROR, (argc < 3) || (argc > 4), CCL_ERROR_ARGS, error_handler, "Usage: %s <program_file> <kernel_name> [device_index]\n", argv[0]); if (argc == 4) dev_idx = atoi(argv[3]); /* ********************************************* */ /* Initialize OpenCL variables and build program */ /* ********************************************* */ /* Select a context/device. */ ccl_devsel_add_dep_filter( &filters, ccl_devsel_dep_menu, (dev_idx == -1) ? NULL : (void*) &dev_idx); ctx = ccl_context_new_from_filters(&filters, &err); ccl_if_err_goto(err, error_handler); /* Get program which contains kernel. */ prg = ccl_program_new_from_source_file(ctx, argv[1], &err); ccl_if_err_goto(err, error_handler); /* Build program. */ ccl_program_build(prg, NULL, &err); ccl_if_err_goto(err, error_handler); /* Get kernel */ krnl = ccl_program_get_kernel(prg, argv[2], &err); ccl_if_err_goto(err, error_handler); /* Get the device. */ dev = ccl_context_get_device(ctx, 0, &err); ccl_if_err_goto(err, error_handler); /* Check platform OpenCL version. */ ocl_ver = ccl_kernel_get_opencl_version(krnl, &err); ccl_if_err_goto(err, error_handler); /* *************************** */ /* Get and print kernel info */ /* *************************** */ g_printf("\n ======================== Static Kernel Information =======================\n\n"); k_wg_size = ccl_kernel_get_workgroup_info_scalar( krnl, dev, CL_KERNEL_WORK_GROUP_SIZE, size_t, &err); ccl_if_err_goto(err, error_handler); g_printf(" Maximum workgroup size : %lu\n", (unsigned long) k_wg_size); /* Only show info about CL_KERNEL_PREFERRED_WORK_GROUP_SIZE_MULTIPLE * if OpenCL version of the underlying platform is >= 1.1. */ if (ocl_ver >= 110) { k_pref_wg_size_mult = ccl_kernel_get_workgroup_info_scalar(krnl, dev, CL_KERNEL_PREFERRED_WORK_GROUP_SIZE_MULTIPLE, size_t, &err); ccl_if_err_goto(err, error_handler); g_printf(" Preferred multiple of workgroup size : %lu\n", (unsigned long) k_pref_wg_size_mult); } k_compile_wg_size = ccl_kernel_get_workgroup_info_array(krnl, dev, CL_KERNEL_COMPILE_WORK_GROUP_SIZE, size_t*, &err); ccl_if_err_goto(err, error_handler); g_printf(" WG size in __attribute__ qualifier : (%lu, %lu, %lu)\n", (unsigned long) k_compile_wg_size[0], (unsigned long) k_compile_wg_size[1], (unsigned long) k_compile_wg_size[2]); k_loc_mem_size = ccl_kernel_get_workgroup_info_scalar(krnl, dev, CL_KERNEL_LOCAL_MEM_SIZE, cl_ulong, &err); ccl_if_err_goto(err, error_handler); g_printf(" Local memory used by kernel : %lu bytes\n", (unsigned long) k_loc_mem_size); k_priv_mem_size = ccl_kernel_get_workgroup_info_scalar(krnl, dev, CL_KERNEL_PRIVATE_MEM_SIZE, cl_ulong, &err); ccl_if_err_goto(err, error_handler); g_printf(" Min. private mem. used by each workitem : %lu bytes\n", (unsigned long) k_priv_mem_size); g_printf("\n"); /* ************** */ /* Error handling */ /* ************** */ /* If we get here, no need for error checking, jump to cleanup. */ g_assert(err == NULL); status = CCL_SUCCESS; goto cleanup; error_handler: /* If we got here there was an error, verify that it is so. */ g_assert(err != NULL); g_fprintf(stderr, "%s\n", err->message); status = (err->domain == CCL_ERROR) ? err->code : CCL_ERROR_OTHER; g_error_free(err); cleanup: /* *********** */ /* Free stuff! */ /* *********** */ if (prg != NULL) ccl_program_destroy(prg); if (ctx != NULL) ccl_context_destroy(ctx); /* Confirm that memory allocated by wrappers has been properly * freed. */ g_return_val_if_fail(ccl_wrapper_memcheck(), CCL_ERROR_OTHER); /* Return status. */ return status; }
/** * Tests creation, getting info from and destruction of * program wrapper objects. * */ static void create_info_destroy_test() { /* Test variables. */ CCLContext* ctx = NULL; CCLProgram* prg = NULL; CCLProgram* prg2 = NULL; CCLKernel* krnl = NULL; CCLWrapperInfo* info = NULL; CCLDevice* d = NULL; CCLQueue* cq = NULL; size_t gws; size_t lws; cl_uint a_h[CCL_TEST_PROGRAM_BUF_SIZE]; cl_uint b_h[CCL_TEST_PROGRAM_BUF_SIZE]; cl_uint c_h[CCL_TEST_PROGRAM_BUF_SIZE]; cl_uint d_h ; CCLBuffer* a_w; CCLBuffer* b_w; CCLBuffer* c_w; CCLEvent* evt_w1; CCLEvent* evt_w2; CCLEvent* evt_kr; CCLEvent* evt_r1; CCLEventWaitList ewl = NULL; GError* err = NULL; gchar* tmp_dir_name; gchar* tmp_file_prefix; /* Get a temp. dir. */ tmp_dir_name = g_dir_make_tmp("test_program_XXXXXX", &err); g_assert_no_error(err); /* Get a temp file prefix. */ tmp_file_prefix = g_strdup_printf("%s%c%s", tmp_dir_name, G_DIR_SEPARATOR, CCL_TEST_PROGRAM_SUM_FILENAME); /* Create a temporary kernel file. */ g_file_set_contents( tmp_file_prefix, CCL_TEST_PROGRAM_SUM_CONTENT, -1, &err); g_assert_no_error(err); /* Create a context with devices from first available platform. */ ctx = ccl_test_context_new(&err); g_assert_no_error(err); /* Create a new program from kernel file. */ prg = ccl_program_new_from_source_file( ctx, tmp_file_prefix, &err); g_assert_no_error(err); ccl_program_destroy(prg); const char* file_pref = (const char*) tmp_file_prefix; prg = ccl_program_new_from_source_files(ctx, 1, &file_pref, &err); g_assert_no_error(err); g_free(tmp_file_prefix); /* Get some program info, compare it with expected info. */ info = ccl_program_get_info(prg, CL_PROGRAM_CONTEXT, &err); g_assert_no_error(err); g_assert(*((cl_context*) info->value) == ccl_context_unwrap(ctx)); /* Get number of devices from program info, check that this is the * same value as the number of devices in context. */ info = ccl_program_get_info(prg, CL_PROGRAM_NUM_DEVICES, &err); g_assert_no_error(err); g_assert_cmpuint(*((cl_uint*) info->value), ==, ccl_context_get_num_devices(ctx, &err)); g_assert_no_error(err); /* Get program source from program info, check that it is the * same as the passed source. */ info = ccl_program_get_info(prg, CL_PROGRAM_SOURCE, &err); g_assert_no_error(err); g_assert_cmpstr((char*) info->value, ==, CCL_TEST_PROGRAM_SUM_CONTENT); /* Get first device in context (and in program). */ d = ccl_context_get_device(ctx, 0, &err); g_assert_no_error(err); /* Check that no build was performed yet. */ info = ccl_program_get_build_info( prg, d, CL_PROGRAM_BUILD_STATUS, &err); g_assert_no_error(err); g_assert_cmpint(*((cl_build_status*) info->value), ==, CL_BUILD_NONE); /* **** BUILD PROGRAM **** */ ccl_program_build(prg, NULL, &err); g_assert_no_error(err); /* Get some program build info, compare it with expected values. */ info = ccl_program_get_build_info( prg, d, CL_PROGRAM_BUILD_STATUS, &err); g_assert_no_error(err); g_assert((*((cl_build_status*) info->value) == CL_BUILD_SUCCESS) || (*((cl_build_status*) info->value) == CL_BUILD_IN_PROGRESS)); /* Get the build log, check that no error occurs. */ info = ccl_program_get_build_info(prg, d, CL_PROGRAM_BUILD_LOG, &err); g_assert_no_error(err); /* Get kernel wrapper object. */ krnl = ccl_program_get_kernel( prg, CCL_TEST_PROGRAM_SUM, &err); g_assert_no_error(err); /* Get some kernel info, compare it with expected info. */ /* Get kernel function name from kernel info, compare it with the * expected value. */ info = ccl_kernel_get_info(krnl, CL_KERNEL_FUNCTION_NAME, &err); g_assert_no_error(err); g_assert_cmpstr( (gchar*) info->value, ==, CCL_TEST_PROGRAM_SUM); /* Check if the kernel context is the same as the initial context * and the program context. */ info = ccl_kernel_get_info(krnl, CL_KERNEL_CONTEXT, &err); g_assert_no_error(err); g_assert(*((cl_context*) info->value) == ccl_context_unwrap(ctx)); info = ccl_kernel_get_info(krnl, CL_KERNEL_PROGRAM, &err); g_assert_no_error(err); g_assert(*((cl_program*) info->value) == ccl_program_unwrap(prg)); #ifndef OPENCL_STUB #ifdef CL_VERSION_1_2 cl_kernel_arg_address_qualifier kaaq; char* kernel_arg_type_name; char* kernel_arg_name; cl_uint ocl_ver; /* Get OpenCL version of program's underlying platform. */ ocl_ver = ccl_program_get_opencl_version(prg, &err); g_assert_no_error(err); /* If platform supports kernel argument queries, get kernel argument * information and compare it with expected info. */ if (ocl_ver >= 120) { /* First kernel argument. */ kaaq = ccl_kernel_get_arg_info_scalar(krnl, 0, CL_KERNEL_ARG_ADDRESS_QUALIFIER, cl_kernel_arg_address_qualifier, &err); g_assert((err == NULL) || (err->code == CCL_ERROR_INFO_UNAVAILABLE_OCL)); if (err == NULL) { g_assert_cmphex(kaaq, ==, CL_KERNEL_ARG_ADDRESS_GLOBAL); } else {