Example #1
0
/**
 * 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;

}
Example #2
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;

}
Example #3
0
/**
 * 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 {