/* * This file is part of oclkit. * * oclkit 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. * * oclkit 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 Foobar. If not, see . */ #include #include #include #include #include #include "ocl.h" struct OclPlatform { cl_platform_id platform; cl_context context; cl_uint num_devices; cl_device_id *devices; cl_command_queue *cmd_queues; int own_queues; }; static const char* opencl_error_msgs[] = { "CL_SUCCESS", "CL_DEVICE_NOT_FOUND", "CL_DEVICE_NOT_AVAILABLE", "CL_COMPILER_NOT_AVAILABLE", "CL_MEM_OBJECT_ALLOCATION_FAILURE", "CL_OUT_OF_RESOURCES", "CL_OUT_OF_HOST_MEMORY", "CL_PROFILING_INFO_NOT_AVAILABLE", "CL_MEM_COPY_OVERLAP", "CL_IMAGE_FORMAT_MISMATCH", "CL_IMAGE_FORMAT_NOT_SUPPORTED", "CL_BUILD_PROGRAM_FAILURE", "CL_MAP_FAILURE", "CL_MISALIGNED_SUB_BUFFER_OFFSET", "CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST", /* next IDs start at 30! */ "CL_INVALID_VALUE", "CL_INVALID_DEVICE_TYPE", "CL_INVALID_PLATFORM", "CL_INVALID_DEVICE", "CL_INVALID_CONTEXT", "CL_INVALID_QUEUE_PROPERTIES", "CL_INVALID_COMMAND_QUEUE", "CL_INVALID_HOST_PTR", "CL_INVALID_MEM_OBJECT", "CL_INVALID_IMAGE_FORMAT_DESCRIPTOR", "CL_INVALID_IMAGE_SIZE", "CL_INVALID_SAMPLER", "CL_INVALID_BINARY", "CL_INVALID_BUILD_OPTIONS", "CL_INVALID_PROGRAM", "CL_INVALID_PROGRAM_EXECUTABLE", "CL_INVALID_KERNEL_NAME", "CL_INVALID_KERNEL_DEFINITION", "CL_INVALID_KERNEL", "CL_INVALID_ARG_INDEX", "CL_INVALID_ARG_VALUE", "CL_INVALID_ARG_SIZE", "CL_INVALID_KERNEL_ARGS", "CL_INVALID_WORK_DIMENSION", "CL_INVALID_WORK_GROUP_SIZE", "CL_INVALID_WORK_ITEM_SIZE", "CL_INVALID_GLOBAL_OFFSET", "CL_INVALID_EVENT_WAIT_LIST", "CL_INVALID_EVENT", "CL_INVALID_OPERATION", "CL_INVALID_GL_OBJECT", "CL_INVALID_BUFFER_SIZE", "CL_INVALID_MIP_LEVEL", "CL_INVALID_GLOBAL_WORK_SIZE" }; const char* ocl_strerr (int error) { int index = 0; if (error >= -14) index = -error; else if (error <= -30 && error >= -64) index = -error-15; return opencl_error_msgs[index]; } static void transfer_error (cl_int src, cl_int *dst) { if (dst != NULL) *dst = src; } char * ocl_read_program (const char *filename) { FILE *fp; char *buffer; size_t length; size_t buffer_length; if ((fp = fopen(filename, "r")) == NULL) return NULL; fseek (fp, 0, SEEK_END); length = ftell (fp); rewind (fp); buffer = malloc (length + 1); buffer[length] = '\0'; if (buffer == NULL) { fclose(fp); return NULL; } buffer_length = fread (buffer, 1, length, fp); fclose(fp); if (buffer_length != length) { free (buffer); buffer = NULL; } return buffer; } OclPlatform * ocl_new (unsigned platform, cl_device_type type) { OclPlatform *ocl; cl_int errcode; cl_uint num_platforms; cl_platform_id *platforms; ocl = malloc (sizeof(OclPlatform)); OCL_CHECK_ERROR (clGetPlatformIDs (0, NULL, &num_platforms)); platforms = malloc (sizeof (cl_platform_id) * num_platforms); if (platform >= num_platforms) { fprintf (stderr, "invalid platform %i out of %i platforms\n", platform, num_platforms); goto ocl_new_cleanup; } OCL_CHECK_ERROR (clGetPlatformIDs (num_platforms, platforms, NULL)); ocl->platform = platforms[platform]; OCL_CHECK_ERROR (clGetDeviceIDs (ocl->platform, type, 0, NULL, &ocl->num_devices)); ocl->devices = malloc (ocl->num_devices * sizeof(cl_device_id)); OCL_CHECK_ERROR (clGetDeviceIDs (ocl->platform, type, ocl->num_devices, ocl->devices, NULL)); ocl->context = clCreateContext (NULL, ocl->num_devices, ocl->devices, NULL, NULL, &errcode); OCL_CHECK_ERROR (errcode); ocl->own_queues = 0; free (platforms); return ocl; ocl_new_cleanup: free (ocl); free (platforms); return NULL; } OclPlatform * ocl_new_with_queues (unsigned platform, cl_device_type type, cl_command_queue_properties queue_properties) { OclPlatform *ocl; cl_int errcode; ocl = ocl_new (platform, type); if (ocl == NULL) return NULL; ocl->own_queues = 1; ocl->cmd_queues = malloc (ocl->num_devices * sizeof(cl_command_queue)); for (cl_uint i = 0; i < ocl->num_devices; i++) { ocl->cmd_queues[i] = clCreateCommandQueue (ocl->context, ocl->devices[i], queue_properties, &errcode); OCL_CHECK_ERROR (errcode); } return ocl; } void ocl_print_usage (void) { printf ("oclkit options\n" " --ocl-platform\tIndex of platform, starting with 0, to use\n" " --ocl-type\tDevice type: gpu, cpu or accelerator\n"); } int ocl_read_args (int argc, const char **argv, unsigned int *platform, cl_device_type *type) { int c; static struct option options[] = { { "ocl-platform", required_argument, NULL, 'p' }, { "ocl-type", required_argument, NULL, 't' }, { "help", no_argument, NULL, 'h' }, { NULL, 0, NULL, 0 } }; while (1) { int index = 0; c = getopt_long (argc, (char **) argv, "p:d:t:h", options, &index); if (c == -1) break; switch (c) { case 'h': ocl_print_usage (); return -1; case 'p': *platform = atoi (optarg); break; case 't': { int n = strlen (optarg); n = n > 10 ? 10 : n; /* for accelerator */ if (!strncmp (optarg, "gpu", n)) *type = CL_DEVICE_TYPE_GPU; else if (!strncmp (optarg, "cpu", n)) *type = CL_DEVICE_TYPE_CPU; else if (!strncmp (optarg, "accelerator", n)) *type = CL_DEVICE_TYPE_ACCELERATOR; } break; default: abort (); } } return 0; } OclPlatform * ocl_new_from_args (int argc, const char **argv, cl_command_queue_properties queue_properties) { unsigned platform = 0; cl_device_type type = CL_DEVICE_TYPE_GPU; if (ocl_read_args (argc, argv, &platform, &type)) return NULL; return ocl_new_with_queues (platform, type, queue_properties); } void ocl_free (OclPlatform *ocl) { if (ocl == NULL) return; if (ocl->own_queues) { for (cl_uint i = 0; i < ocl->num_devices; i++) OCL_CHECK_ERROR (clReleaseCommandQueue (ocl->cmd_queues[i])); free (ocl->cmd_queues); } OCL_CHECK_ERROR (clReleaseContext (ocl->context)); free (ocl->devices); free (ocl); } char * ocl_get_platform_info (OclPlatform *ocl, cl_platform_info param) { size_t size; char *result; OCL_CHECK_ERROR (clGetPlatformInfo (ocl->platform, param, 0, NULL, &size)); result = malloc (size); OCL_CHECK_ERROR (clGetPlatformInfo (ocl->platform, param, size, result, NULL)); return result; } cl_program ocl_create_program_from_source (OclPlatform *ocl, const char *source, const char *options, cl_int *errcode) { cl_int tmp_err; cl_program program; program = clCreateProgramWithSource (ocl->context, 1, (const char **) &source, NULL, &tmp_err); if (tmp_err != CL_SUCCESS) { transfer_error (tmp_err, errcode); return NULL; } tmp_err = clBuildProgram (program, ocl->num_devices, ocl->devices, options, NULL, NULL); if (tmp_err != CL_SUCCESS) { size_t log_size; char* log; transfer_error (tmp_err, errcode); OCL_CHECK_ERROR (clGetProgramBuildInfo (program, ocl->devices[0], CL_PROGRAM_BUILD_LOG, 0, NULL, &log_size)); log = malloc (log_size * sizeof(char)); OCL_CHECK_ERROR (clGetProgramBuildInfo (program, ocl->devices[0], CL_PROGRAM_BUILD_LOG, log_size, log, NULL)); fprintf (stderr, "\n** Error building program. Build log:\n%s\n", log); free (log); return NULL; } *errcode = CL_SUCCESS; return program; } cl_program ocl_create_program_from_file (OclPlatform *ocl, const char *filename, const char *options, cl_int *errcode) { char *source; cl_program program; source = ocl_read_program (filename); if (source == NULL) return NULL; program = ocl_create_program_from_source (ocl, source, options, errcode); free(source); return program; } cl_context ocl_get_context (OclPlatform *ocl) { assert (ocl != NULL); return ocl->context; } int ocl_get_num_devices (OclPlatform *ocl) { assert (ocl != NULL); return ocl->num_devices; } cl_device_id * ocl_get_devices (OclPlatform *ocl) { assert (ocl != NULL); return ocl->devices; } cl_command_queue * ocl_get_cmd_queues (OclPlatform *ocl) { assert (ocl != NULL); return ocl->cmd_queues; } void ocl_get_event_times (cl_event event, cl_ulong *start, cl_ulong *end, cl_ulong *queued, cl_ulong *submitted) { if (queued != NULL) OCL_CHECK_ERROR (clGetEventProfilingInfo (event, CL_PROFILING_COMMAND_QUEUED, sizeof (cl_ulong), queued, NULL)); if (submitted != NULL) OCL_CHECK_ERROR (clGetEventProfilingInfo (event, CL_PROFILING_COMMAND_SUBMIT, sizeof (cl_ulong), submitted, NULL)); if (start != NULL) OCL_CHECK_ERROR (clGetEventProfilingInfo (event, CL_PROFILING_COMMAND_START, sizeof (cl_ulong), start, NULL)); if (end != NULL) OCL_CHECK_ERROR (clGetEventProfilingInfo (event, CL_PROFILING_COMMAND_END, sizeof (cl_ulong), end, NULL)); }