diff options
Diffstat (limited to 'gdb/testsuite/lib')
-rw-r--r-- | gdb/testsuite/lib/cl_util.c | 519 | ||||
-rw-r--r-- | gdb/testsuite/lib/cl_util.h | 88 | ||||
-rw-r--r-- | gdb/testsuite/lib/opencl.exp | 83 | ||||
-rw-r--r-- | gdb/testsuite/lib/opencl_hostapp.c | 168 | ||||
-rw-r--r-- | gdb/testsuite/lib/opencl_kernel.cl | 5 |
5 files changed, 863 insertions, 0 deletions
diff --git a/gdb/testsuite/lib/cl_util.c b/gdb/testsuite/lib/cl_util.c new file mode 100644 index 0000000..5b731b2 --- /dev/null +++ b/gdb/testsuite/lib/cl_util.c @@ -0,0 +1,519 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2010 Free Software Foundation, Inc. + + This program 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. + + This program 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 this program. If not, see <http://www.gnu.org/licenses/>. + + Contributed by Ken Werner <ken.werner@de.ibm.com> */ + +/* Utility macros and functions for OpenCL applications. */ + +#include "cl_util.h" + +#include <stdlib.h> +#include <errno.h> +#include <sys/stat.h> +#include <string.h> + +const char *get_clerror_string (int errcode) +{ + switch (errcode) + { + case CL_SUCCESS: + return "CL_SUCCESS"; + case CL_DEVICE_NOT_FOUND: + return "CL_DEVICE_NOT_FOUND"; + case CL_DEVICE_NOT_AVAILABLE: + return "CL_DEVICE_NOT_AVAILABLE"; + case CL_COMPILER_NOT_AVAILABLE: + return "CL_COMPILER_NOT_AVAILABLE"; + case CL_MEM_OBJECT_ALLOCATION_FAILURE: + return "CL_MEM_OBJECT_ALLOCATION_FAILURE"; + case CL_OUT_OF_RESOURCES: + return "CL_OUT_OF_RESOURCES"; + case CL_OUT_OF_HOST_MEMORY: + return "CL_OUT_OF_HOST_MEMORY"; + case CL_PROFILING_INFO_NOT_AVAILABLE: + return "CL_PROFILING_INFO_NOT_AVAILABLE"; + case CL_MEM_COPY_OVERLAP: + return "CL_MEM_COPY_OVERLAP"; + case CL_IMAGE_FORMAT_MISMATCH: + return "CL_IMAGE_FORMAT_MISMATCH"; + case CL_IMAGE_FORMAT_NOT_SUPPORTED: + return "CL_IMAGE_FORMAT_NOT_SUPPORTED"; + case CL_BUILD_PROGRAM_FAILURE: + return "CL_BUILD_PROGRAM_FAILURE"; + case CL_MAP_FAILURE: + return "CL_MAP_FAILURE"; + case CL_INVALID_VALUE: + return "CL_INVALID_VALUE"; + case CL_INVALID_DEVICE_TYPE: + return "CL_INVALID_DEVICE_TYPE"; + case CL_INVALID_PLATFORM: + return "CL_INVALID_PLATFORM"; + case CL_INVALID_DEVICE: + return "CL_INVALID_DEVICE"; + case CL_INVALID_CONTEXT: + return "CL_INVALID_CONTEXT"; + case CL_INVALID_QUEUE_PROPERTIES: + return "CL_INVALID_QUEUE_PROPERTIES"; + case CL_INVALID_COMMAND_QUEUE: + return "CL_INVALID_COMMAND_QUEUE"; + case CL_INVALID_HOST_PTR: + return "CL_INVALID_HOST_PTR"; + case CL_INVALID_MEM_OBJECT: + return "CL_INVALID_MEM_OBJECT"; + case CL_INVALID_IMAGE_FORMAT_DESCRIPTOR: + return "CL_INVALID_IMAGE_FORMAT_DESCRIPTOR"; + case CL_INVALID_IMAGE_SIZE: + return "CL_INVALID_IMAGE_SIZE"; + case CL_INVALID_SAMPLER: + return "CL_INVALID_SAMPLER"; + case CL_INVALID_BINARY: + return "CL_INVALID_BINARY"; + case CL_INVALID_BUILD_OPTIONS: + return "CL_INVALID_BUILD_OPTIONS"; + case CL_INVALID_PROGRAM: + return "CL_INVALID_PROGRAM"; + case CL_INVALID_PROGRAM_EXECUTABLE: + return "CL_INVALID_PROGRAM_EXECUTABLE"; + case CL_INVALID_KERNEL_NAME: + return "CL_INVALID_KERNEL_NAME"; + case CL_INVALID_KERNEL_DEFINITION: + return "CL_INVALID_KERNEL_DEFINITION"; + case CL_INVALID_KERNEL: + return "CL_INVALID_KERNEL"; + case CL_INVALID_ARG_INDEX: + return "CL_INVALID_ARG_INDEX"; + case CL_INVALID_ARG_VALUE: + return "CL_INVALID_ARG_VALUE"; + case CL_INVALID_ARG_SIZE: + return "CL_INVALID_ARG_SIZE"; + case CL_INVALID_KERNEL_ARGS: + return "CL_INVALID_KERNEL_ARGS"; + case CL_INVALID_WORK_DIMENSION: + return "CL_INVALID_WORK_DIMENSION"; + case CL_INVALID_WORK_GROUP_SIZE: + return "CL_INVALID_WORK_GROUP_SIZE"; + case CL_INVALID_WORK_ITEM_SIZE: + return "CL_INVALID_WORK_ITEM_SIZE"; + case CL_INVALID_GLOBAL_OFFSET: + return "CL_INVALID_GLOBAL_OFFSET"; + case CL_INVALID_EVENT_WAIT_LIST: + return "CL_INVALID_EVENT_WAIT_LIST"; + case CL_INVALID_EVENT: + return "CL_INVALID_EVENT"; + case CL_INVALID_OPERATION: + return "CL_INVALID_OPERATION"; + case CL_INVALID_GL_OBJECT: + return "CL_INVALID_GL_OBJECT"; + case CL_INVALID_BUFFER_SIZE: + return "CL_INVALID_BUFFER_SIZE"; + case CL_INVALID_MIP_LEVEL: + return "CL_INVALID_MIP_LEVEL"; +#ifndef CL_PLATFORM_NVIDIA + case CL_INVALID_GLOBAL_WORK_SIZE: + return "CL_INVALID_GLOBAL_WORK_SIZE"; +#endif + default: + return "Unknown"; + }; +} + + +void print_clinfo () +{ + char *s = NULL; + size_t len; + unsigned i, j; + cl_uint platform_count; + cl_platform_id *platforms; + + /* Determine number of OpenCL Platforms available. */ + clGetPlatformIDs (0, NULL, &platform_count); + printf ("number of OpenCL Platforms available:\t%d\n", platform_count); + /* Get platforms. */ + platforms + = (cl_platform_id*) malloc (sizeof (cl_platform_id) * platform_count); + if (platforms == NULL) + { + fprintf (stderr, "malloc failed\n"); + exit (EXIT_FAILURE); + } + clGetPlatformIDs (platform_count, platforms, NULL); + + /* Querying platforms. */ + for (i = 0; i < platform_count; i++) + { + cl_device_id *devices; + cl_uint device_count; + cl_device_id default_dev; + printf (" OpenCL Platform: %d\n", i); + +#define PRINT_PF_INFO(PARM)\ + clGetPlatformInfo (platforms[i], PARM, 0, NULL, &len); \ + s = realloc (s, len); \ + clGetPlatformInfo (platforms[i], PARM, len, s, NULL); \ + printf (" %-36s%s\n", #PARM ":", s); + + PRINT_PF_INFO (CL_PLATFORM_PROFILE) + PRINT_PF_INFO (CL_PLATFORM_VERSION) + PRINT_PF_INFO (CL_PLATFORM_NAME) + PRINT_PF_INFO (CL_PLATFORM_VENDOR) + PRINT_PF_INFO (CL_PLATFORM_EXTENSIONS) +#undef PRINT_PF_INFO + + clGetDeviceIDs (platforms[i], CL_DEVICE_TYPE_DEFAULT, 1, &default_dev, + NULL); + clGetDeviceInfo (default_dev, CL_DEVICE_NAME, 0, NULL, &len); + s = realloc (s, len); + clGetDeviceInfo (default_dev, CL_DEVICE_NAME, len, s, NULL); + printf (" CL_DEVICE_TYPE_DEFAULT: %s\n", s); + + /* Determine number of devices. */ + clGetDeviceIDs (platforms[i], CL_DEVICE_TYPE_ALL, 0, NULL, &device_count); + printf ("\n number of OpenCL Devices available: %d\n", device_count); + /* Get devices. */ + devices = (cl_device_id*) malloc (sizeof (cl_device_id) * device_count); + if (devices == NULL) + { + fprintf (stderr, "malloc failed\n"); + exit (EXIT_FAILURE); + } + clGetDeviceIDs (platforms[i], CL_DEVICE_TYPE_ALL, device_count, devices, + NULL); + + /* Querying devices. */ + for (j = 0; j < device_count; j++) + { + cl_device_type dtype; + cl_device_mem_cache_type mctype; + cl_device_local_mem_type mtype; + cl_device_fp_config fpcfg; + cl_device_exec_capabilities xcap; + cl_command_queue_properties qprops; + cl_bool clbool; + cl_uint cluint; + cl_ulong clulong; + size_t sizet; + size_t workitem_size[3]; + printf (" OpenCL Device: %d\n", j); + +#define PRINT_DEV_INFO(PARM)\ + clGetDeviceInfo (devices[j], PARM, 0, NULL, &len); \ + s = realloc (s, len); \ + clGetDeviceInfo (devices[j], PARM, len, s, NULL); \ + printf (" %-41s%s\n", #PARM ":", s); + + PRINT_DEV_INFO (CL_DEVICE_NAME) + PRINT_DEV_INFO (CL_DRIVER_VERSION) + PRINT_DEV_INFO (CL_DEVICE_VENDOR) + clGetDeviceInfo (devices[j], CL_DEVICE_VENDOR_ID, sizeof (cluint), + &cluint, NULL); + printf (" CL_DEVICE_VENDOR_ID: %d\n", cluint); + + clGetDeviceInfo (devices[j], CL_DEVICE_TYPE, sizeof (dtype), &dtype, NULL); + if (dtype & CL_DEVICE_TYPE_CPU) + printf (" CL_DEVICE_TYPE: CL_DEVICE_TYPE_CPU\n"); + if (dtype & CL_DEVICE_TYPE_GPU) + printf (" CL_DEVICE_TYPE: CL_DEVICE_TYPE_GPU\n"); + if (dtype & CL_DEVICE_TYPE_ACCELERATOR) + printf (" CL_DEVICE_TYPE: CL_DEVICE_TYPE_ACCELERATOR\n"); + if (dtype & CL_DEVICE_TYPE_DEFAULT) + printf (" CL_DEVICE_TYPE: CL_DEVICE_TYPE_DEFAULT\n"); + + clGetDeviceInfo (devices[j], CL_DEVICE_MAX_CLOCK_FREQUENCY, sizeof (cluint), &cluint, NULL); + printf (" CL_DEVICE_MAX_CLOCK_FREQUENCY: %d\n", cluint); + + PRINT_DEV_INFO (CL_DEVICE_PROFILE) + PRINT_DEV_INFO (CL_DEVICE_EXTENSIONS) + + clGetDeviceInfo (devices[j], CL_DEVICE_AVAILABLE, sizeof (clbool), &clbool, NULL); + if (clbool == CL_TRUE) + printf (" CL_DEVICE_AVAILABLE: CL_TRUE\n"); + else + printf (" CL_DEVICE_AVAILABLE: CL_FALSE\n"); + clGetDeviceInfo (devices[j], CL_DEVICE_ENDIAN_LITTLE, sizeof (clbool), &clbool, NULL); + if (clbool == CL_TRUE) + printf (" CL_DEVICE_ENDIAN_LITTLE: CL_TRUE\n"); + else + printf (" CL_DEVICE_ENDIAN_LITTLE: CL_FALSE\n"); + + clGetDeviceInfo (devices[j], CL_DEVICE_MAX_COMPUTE_UNITS, sizeof (cluint), &cluint, NULL); + printf (" CL_DEVICE_MAX_COMPUTE_UNITS: %d\n", cluint); + clGetDeviceInfo (devices[j], CL_DEVICE_MAX_WORK_GROUP_SIZE, sizeof (sizet), &sizet, NULL); + printf (" CL_DEVICE_MAX_WORK_GROUP_SIZE: %d\n", sizet); + clGetDeviceInfo (devices[j], CL_DEVICE_MAX_WORK_ITEM_DIMENSIONS, sizeof (cluint), &cluint, NULL); + printf (" CL_DEVICE_MAX_WORK_ITEM_DIMENSIONS: %d\n", cluint); + clGetDeviceInfo (devices[j], CL_DEVICE_MAX_WORK_ITEM_SIZES, sizeof (workitem_size), &workitem_size, NULL); + printf (" CL_DEVICE_MAX_WORK_ITEM_SIZES: %d / %d / %d\n", workitem_size[0], workitem_size[1], workitem_size[2]); + + clGetDeviceInfo (devices[j], CL_DEVICE_ADDRESS_BITS, sizeof (cluint), &cluint, NULL); + printf (" CL_DEVICE_ADDRESS_BITS: %d\n", cluint); + + clGetDeviceInfo (devices[j], CL_DEVICE_MAX_MEM_ALLOC_SIZE, sizeof (clulong), &clulong, NULL); + printf (" CL_DEVICE_MAX_MEM_ALLOC_SIZE: %llu\n", clulong); + clGetDeviceInfo (devices[j], CL_DEVICE_MEM_BASE_ADDR_ALIGN, sizeof (cluint), &cluint, NULL); + printf (" CL_DEVICE_MEM_BASE_ADDR_ALIGN: %d\n", cluint); + clGetDeviceInfo(devices[j], CL_DEVICE_MIN_DATA_TYPE_ALIGN_SIZE, sizeof (cluint), &cluint, NULL); + printf (" CL_DEVICE_MIN_DATA_TYPE_ALIGN_SIZE: %d\n", cluint); + clGetDeviceInfo(devices[j], CL_DEVICE_MAX_PARAMETER_SIZE, sizeof (sizet), &sizet, NULL); + printf (" CL_DEVICE_MAX_PARAMETER_SIZE: %d\n", sizet); + clGetDeviceInfo(devices[j], CL_DEVICE_GLOBAL_MEM_SIZE, sizeof (clulong), &clulong, NULL); + printf (" CL_DEVICE_GLOBAL_MEM_SIZE: %llu\n", clulong); + + clGetDeviceInfo (devices[j], CL_DEVICE_GLOBAL_MEM_CACHE_TYPE, sizeof (mctype), &mctype, NULL); + if (mctype & CL_NONE) + printf (" CL_DEVICE_GLOBAL_MEM_CACHE_TYPE: CL_NONE\n"); + if (mctype & CL_READ_ONLY_CACHE) + printf (" CL_DEVICE_GLOBAL_MEM_CACHE_TYPE: CL_READ_ONLY_CACHE\n"); + if (mctype & CL_READ_WRITE_CACHE) + printf (" CL_DEVICE_GLOBAL_MEM_CACHE_TYPE: CL_READ_WRITE_CACHE\n"); + + clGetDeviceInfo (devices[j], CL_DEVICE_GLOBAL_MEM_CACHE_SIZE, sizeof (clulong), &clulong, NULL); + printf (" CL_DEVICE_GLOBAL_MEM_CACHE_SIZE: %llu\n", clulong); + clGetDeviceInfo (devices[j], CL_DEVICE_GLOBAL_MEM_CACHELINE_SIZE, sizeof (cluint), &cluint, NULL); + printf (" CL_DEVICE_GLOBAL_MEM_CACHELINE_SIZE: %d\n", cluint); + + clGetDeviceInfo (devices[j], CL_DEVICE_LOCAL_MEM_TYPE, sizeof (mtype), &mtype, NULL); + if (mtype & CL_LOCAL) + printf (" CL_DEVICE_LOCAL_MEM_TYPE: CL_LOCAL\n"); + if (mtype & CL_GLOBAL) + printf (" CL_DEVICE_LOCAL_MEM_TYPE: CL_GLOBAL\n"); + + clGetDeviceInfo (devices[j], CL_DEVICE_MIN_DATA_TYPE_ALIGN_SIZE, sizeof (cluint), &cluint, NULL); + printf (" CL_DEVICE_MIN_DATA_TYPE_ALIGN_SIZE: %d\n", cluint); + clGetDeviceInfo (devices[j], CL_DEVICE_MEM_BASE_ADDR_ALIGN, sizeof (cluint), &cluint, NULL); + printf (" CL_DEVICE_MEM_BASE_ADDR_ALIGN: %d\n", cluint); + clGetDeviceInfo (devices[j], CL_DEVICE_PREFERRED_VECTOR_WIDTH_CHAR, sizeof (cluint), &cluint, NULL); + printf (" CL_DEVICE_PREFERRED_VECTOR_WIDTH_CHAR: %d\n", cluint); + clGetDeviceInfo (devices[j], CL_DEVICE_PREFERRED_VECTOR_WIDTH_SHORT, sizeof (cluint), &cluint, NULL); + printf (" CL_DEVICE_PREFERRED_VECTOR_WIDTH_SHORT: %d\n", cluint); + clGetDeviceInfo (devices[j], CL_DEVICE_PREFERRED_VECTOR_WIDTH_INT, sizeof (cluint), &cluint, NULL); + printf (" CL_DEVICE_PREFERRED_VECTOR_WIDTH_INT: %d\n", cluint); + clGetDeviceInfo (devices[j], CL_DEVICE_PREFERRED_VECTOR_WIDTH_LONG, sizeof (cluint), &cluint, NULL); + printf (" CL_DEVICE_PREFERRED_VECTOR_WIDTH_LONG: %d\n", cluint); + clGetDeviceInfo (devices[j], CL_DEVICE_PREFERRED_VECTOR_WIDTH_FLOAT, sizeof (cluint), &cluint, NULL); + printf (" CL_DEVICE_PREFERRED_VECTOR_WIDTH_FLOAT: %d\n", cluint); + clGetDeviceInfo (devices[j], CL_DEVICE_PREFERRED_VECTOR_WIDTH_DOUBLE, sizeof (cluint), &cluint, NULL); + printf (" CL_DEVICE_PREFERRED_VECTOR_WIDTH_DOUBLE: %d\n", cluint); + + clGetDeviceInfo (devices[j], CL_DEVICE_SINGLE_FP_CONFIG, sizeof (fpcfg), &fpcfg, NULL); + if (fpcfg & CL_FP_DENORM) + printf (" CL_DEVICE_SINGLE_FP_CONFIG: CL_FP_DENORM\n"); + if (fpcfg & CL_FP_INF_NAN) + printf (" CL_DEVICE_SINGLE_FP_CONFIG: CL_FP_INF_NAN\n"); + if (fpcfg & CL_FP_ROUND_TO_NEAREST) + printf (" CL_DEVICE_SINGLE_FP_CONFIG: CL_FP_ROUND_TO_NEAREST\n"); + if (fpcfg & CL_FP_ROUND_TO_ZERO) + printf (" CL_DEVICE_SINGLE_FP_CONFIG: CL_FP_ROUND_TO_ZERO\n"); + + clGetDeviceInfo (devices[j], CL_DEVICE_EXECUTION_CAPABILITIES, sizeof (xcap), &xcap, NULL); + if (xcap & CL_EXEC_KERNEL ) + printf (" CL_DEVICE_EXECUTION_CAPABILITIES: CL_EXEC_KERNEL\n"); + if (xcap & CL_EXEC_NATIVE_KERNEL) + printf (" CL_DEVICE_EXECUTION_CAPABILITIES: CL_EXEC_NATIVE_KERNEL\n"); + + clGetDeviceInfo (devices[j], CL_DEVICE_QUEUE_PROPERTIES, sizeof (qprops), &qprops, NULL); + if (qprops & CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE) + printf (" CL_DEVICE_QUEUE_PROPERTIES: CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE\n"); + if (qprops & CL_QUEUE_PROFILING_ENABLE) + printf (" CL_DEVICE_QUEUE_PROPERTIES: CL_QUEUE_PROFILING_ENABLE\n"); + + clGetDeviceInfo (devices[j], CL_DEVICE_PROFILING_TIMER_RESOLUTION, sizeof (sizet), &sizet, NULL); + printf (" CL_DEVICE_PROFILING_TIMER_RESOLUTION: %d\n", sizet); + + clGetDeviceInfo (devices[j], CL_DEVICE_COMPILER_AVAILABLE, sizeof (clbool), &clbool, NULL); + if (clbool == CL_TRUE) + printf (" CL_DEVICE_COMPILER_AVAILABLE: CL_TRUE\n"); + else + printf (" CL_DEVICE_COMPILER_AVAILABLE: CL_FALSE\n"); + clGetDeviceInfo (devices[j], CL_DEVICE_ERROR_CORRECTION_SUPPORT, sizeof (clbool), &clbool, NULL); + if (clbool == CL_TRUE) + printf (" CL_DEVICE_ERROR_CORRECTION_SUPPORT: CL_TRUE\n"); + else + printf (" CL_DEVICE_ERROR_CORRECTION_SUPPORT: CL_FALSE\n"); + + clGetDeviceInfo (devices[j], CL_DEVICE_IMAGE_SUPPORT, sizeof (clbool), &clbool, NULL); + if (clbool == CL_FALSE) + { + printf (" CL_DEVICE_IMAGE_SUPPORT: CL_FALSE\n"); + } + else + { + printf (" CL_DEVICE_IMAGE_SUPPORT: CL_TRUE\n"); + clGetDeviceInfo (devices[j], CL_DEVICE_MAX_SAMPLERS, sizeof (cluint), &cluint, NULL); + printf (" CL_DEVICE_MAX_SAMPLERS: %d\n", cluint); + clGetDeviceInfo (devices[j], CL_DEVICE_MAX_READ_IMAGE_ARGS, sizeof (cluint), &cluint, NULL); + printf (" CL_DEVICE_MAX_READ_IMAGE_ARGS: %d\n", cluint); + clGetDeviceInfo (devices[j], CL_DEVICE_MAX_WRITE_IMAGE_ARGS, sizeof (cluint), &cluint, NULL); + printf (" CL_DEVICE_MAX_WRITE_IMAGE_ARGS: %d\n", cluint); + clGetDeviceInfo (devices[j], CL_DEVICE_IMAGE2D_MAX_WIDTH, sizeof (sizet), &sizet, NULL); + printf (" CL_DEVICE_IMAGE2D_MAX_WIDTH: %d\n", sizet); + clGetDeviceInfo (devices[j], CL_DEVICE_IMAGE2D_MAX_HEIGHT, sizeof (sizet), &sizet, NULL); + printf (" CL_DEVICE_IMAGE2D_MAX_HEIGHT: %d\n", sizet); + clGetDeviceInfo (devices[j], CL_DEVICE_IMAGE3D_MAX_WIDTH, sizeof (sizet), &sizet, NULL); + printf (" CL_DEVICE_IMAGE3D_MAX_WIDTH: %d\n", sizet); + clGetDeviceInfo (devices[j], CL_DEVICE_IMAGE3D_MAX_HEIGHT, sizeof (sizet), &sizet, NULL); + printf (" CL_DEVICE_IMAGE3D_MAX_HEIGHT: %d\n", sizet); + clGetDeviceInfo (devices[j], CL_DEVICE_IMAGE3D_MAX_DEPTH, sizeof (sizet), &sizet, NULL); + printf (" CL_DEVICE_IMAGE3D_MAX_DEPTH: %d\n", sizet); + } +#undef PRINT_DEV_INFO + } /* devices */ + free (devices); + } /* platforms */ + free (s); + free (platforms); +} + + +const char * +read_file (const char * const filename, size_t *size) +{ + char *buf = NULL; + FILE *fd; + struct stat st; + if (stat (filename, &st) == -1) + { + /* Check if the file exists. */ + if (errno == ENOENT) + return buf; + perror ("stat failed"); + exit (EXIT_FAILURE); + } + buf = (char *) malloc (st.st_size); + if (buf == NULL) + { + fprintf (stderr, "malloc failed\n"); + exit (EXIT_FAILURE); + } + fd = fopen (filename, "r"); + if (fd == NULL) + { + perror ("fopen failed"); + free (buf); + exit (EXIT_FAILURE); + } + if (fread (buf, st.st_size, 1, fd) != 1) + { + fprintf (stderr, "fread failed\n"); + free (buf); + fclose (fd); + exit (EXIT_FAILURE); + } + fclose (fd); + *size = st.st_size; + return buf; +} + + +void +save_program_binaries (cl_program program) +{ + cl_device_id *devices; + cl_uint device_count; + size_t *sizes; + unsigned char **binaries; + unsigned i, j; + + /* Query the amount of devices for the given program. */ + CHK (clGetProgramInfo (program, CL_PROGRAM_NUM_DEVICES, sizeof (cl_uint), + &device_count, NULL)); + + /* Get the sizes of the binaries. */ + sizes = (size_t*) malloc (sizeof (size_t) * device_count); + if (sizes == NULL) + { + fprintf (stderr, "malloc failed\n"); + exit (EXIT_FAILURE); + } + CHK (clGetProgramInfo (program, CL_PROGRAM_BINARY_SIZES, sizeof (sizes), + sizes, NULL)); + + /* Get the binaries. */ + binaries + = (unsigned char **) malloc (sizeof (unsigned char *) * device_count); + if (binaries == NULL) + { + fprintf (stderr, "malloc failed\n"); + exit (EXIT_FAILURE); + } + for (i = 0; i < device_count; i++) + { + binaries[i] = (unsigned char *) malloc (sizes[i]); + if (binaries[i] == NULL) + { + fprintf (stderr, "malloc failed\n"); + exit (EXIT_FAILURE); + } + } + CHK (clGetProgramInfo (program, CL_PROGRAM_BINARIES, sizeof (binaries), + binaries, NULL)); + + /* Get the devices for the given program to extract the file names. */ + devices = (cl_device_id*) malloc (sizeof (cl_device_id) * device_count); + if (devices == NULL) + { + fprintf (stderr, "malloc failed\n"); + exit (EXIT_FAILURE); + } + CHK (clGetProgramInfo (program, CL_PROGRAM_DEVICES, sizeof (devices), + devices, NULL)); + + for (i = 0; i < device_count; i++) + { + FILE *fd; + char *dev_name = NULL; + size_t len; + CHK (clGetDeviceInfo (devices[i], CL_DEVICE_NAME, 0, NULL, &len)); + dev_name = malloc (len); + if (dev_name == NULL) + { + fprintf (stderr, "malloc failed\n"); + exit (EXIT_FAILURE); + } + CHK (clGetDeviceInfo (devices[i], CL_DEVICE_NAME, len, dev_name, NULL)); + /* Convert spaces to underscores. */ + for (j = 0; j < strlen (dev_name); j++) + { + if (dev_name[j] == ' ') + dev_name[j] = '_'; + } + + /* Save the binaries. */ + printf ("saving program binary for device: %s\n", dev_name); + /* Save binaries[i]. */ + fd = fopen (dev_name, "w"); + if (fd == NULL) + { + perror ("fopen failed"); + exit (EXIT_FAILURE); + } + if (fwrite (binaries[i], sizes[i], 1, fd) != 1) + { + fprintf (stderr, "fwrite failed\n"); + for (j = i; j < device_count; j++) + free (binaries[j]); + fclose (fd); + exit (EXIT_FAILURE); + } + fclose (fd); + free (binaries[i]); + free (dev_name); + free (sizes); + } + free (devices); + free (binaries); +} diff --git a/gdb/testsuite/lib/cl_util.h b/gdb/testsuite/lib/cl_util.h new file mode 100644 index 0000000..acdbc5d --- /dev/null +++ b/gdb/testsuite/lib/cl_util.h @@ -0,0 +1,88 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2010 Free Software Foundation, Inc. + + This program 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. + + This program 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 this program. If not, see <http://www.gnu.org/licenses/>. + + Contributed by Ken Werner <ken.werner@de.ibm.com> */ + +/* Utility macros and functions for OpenCL applications. */ + +#ifndef CL_UTIL_H +#define CL_UTIL_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef __APPLE__ +#include <OpenCL/opencl.h> +#else +#include <CL/cl.h> +#endif +#include <stdio.h> + +/* Executes the given OpenCL function and checks its return value. + In case of failure (rc != CL_SUCCESS) an error string will be + printed to stderr and the program will be terminated. This Macro + is only intended for OpenCL routines which return cl_int. */ + +#define CHK(func)\ +{\ + int rc = (func);\ + CHK_ERR (#func, rc);\ +} + +/* Macro that checks an OpenCL error code. In case of failure + (err != CL_SUCCESS) an error string will be printed to stderr + including the prefix and the program will be terminated. This + Macro is only intended to use in conjunction with OpenCL routines + which take a pointer to a cl_int as an argument to place their + error code. */ + +#define CHK_ERR(prefix, err)\ +if (err != CL_SUCCESS)\ + {\ + fprintf (stderr, "CHK_ERR (%s, %d)\n", prefix, err);\ + fprintf (stderr, "%s:%d error: %s\n", __FILE__, __LINE__,\ + get_clerror_string (err));\ + exit (EXIT_FAILURE);\ + }; + +/* Return a pointer to a string that describes the error code specified + by the errcode argument. */ + +extern const char *get_clerror_string (int errcode); + +/* Prints OpenCL information to stdout. */ + +extern void print_clinfo (); + +/* Reads a given file into the memory and returns a pointer to the data or NULL + if the file does not exist. FILENAME specifies the location of the file to + be read. SIZE is an output parameter that returns the size of the file in + bytes. */ + +extern const char *read_file (const char * const filename, size_t *size); + +/* Saves all program binaries of the given OpenCL PROGRAM. The file + names are extracted from the devices. */ + +extern void save_program_binaries (cl_program program); + +#ifdef __cplusplus +} +#endif + +#endif /* CL_UTIL_H */ diff --git a/gdb/testsuite/lib/opencl.exp b/gdb/testsuite/lib/opencl.exp new file mode 100644 index 0000000..33d3688 --- /dev/null +++ b/gdb/testsuite/lib/opencl.exp @@ -0,0 +1,83 @@ +# Copyright 2010 Free Software Foundation, Inc. +# +# This program 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. +# +# This program 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 this program. If not, see <http://www.gnu.org/licenses/>. +# +# Contributed by Ken Werner <ken.werner@de.ibm.com>. +# +# Support library for testing OpenCL GDB features + +# Compile OpenCL programs using a generic host app. +proc gdb_compile_opencl_hostapp {clsource executable options} { + global srcdir objdir subdir + set src "${srcdir}/lib/cl_util.c ${srcdir}/lib/opencl_hostapp.c" + set binfile ${objdir}/${subdir}/${executable} + set compile_flags [concat additional_flags=-I${srcdir}/lib/ additional_flags=-DCL_SOURCE=$clsource] + set options_opencl [concat {debug} $compile_flags $options [list libs=-lOpenCL]] + return [gdb_compile ${src} ${binfile} "executable" ${options_opencl}] +} + +# Run a test on the target to check if it supports OpenCL. Return 0 if so, 1 if +# it does not. +proc skip_opencl_tests {} { + global skip_opencl_tests_saved srcdir objdir subdir gdb_prompt + + # Use the cached value, if it exists. Cache value per "board" to handle + # runs with multiple options (e.g. unix/{-m32,-64}) correctly. + set me "skip_opencl_tests" + set board [target_info name] + if [info exists skip_opencl_tests_saved($board)] { + verbose "$me: returning saved $skip_opencl_tests_saved($board)" 2 + return $skip_opencl_tests_saved($board) + } + + # Set up, compile, and execute an OpenCL program. Include the current + # process ID in the file name of the executable to prevent conflicts with + # invocations for multiple testsuites. + set clprogram [remote_download target ${srcdir}/lib/opencl_kernel.cl] + set executable opencltest[pid].x + + verbose "$me: compiling OpenCL test app" 2 + set compile_flags {debug nowarnings quiet} + + if { [gdb_compile_opencl_hostapp "${clprogram}" "${executable}" "" ] != "" } { + verbose "$me: compiling OpenCL binary failed, returning 1" 2 + return [set skip_opencl_tests_saved($board) 1] + } + + # Compilation succeeded so now run it via gdb. + clean_restart "$executable" + gdb_run_cmd + gdb_expect 30 { + -re ".*Program exited normally.*${gdb_prompt} $" { + verbose -log "\n$me: OpenCL support detected" + set skip_opencl_tests_saved($board) 0 + } + -re ".*Program exited with code.*${gdb_prompt} $" { + verbose -log "\n$me: OpenCL support not detected" + set skip_opencl_tests_saved($board) 1 + } + default { + verbose -log "\n$me OpenCL support not detected (default case)" + set skip_opencl_tests_saved($board) 1 + } + } + gdb_exit + remote_file build delete $executable + + # Delete the OpenCL program source file. + remote_file target delete ${clprogram} + + verbose "$me: returning $skip_opencl_tests_saved($board)" 2 + return $skip_opencl_tests_saved($board) +} diff --git a/gdb/testsuite/lib/opencl_hostapp.c b/gdb/testsuite/lib/opencl_hostapp.c new file mode 100644 index 0000000..4bc9658 --- /dev/null +++ b/gdb/testsuite/lib/opencl_hostapp.c @@ -0,0 +1,168 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2010 Free Software Foundation, Inc. + + This program 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. + + This program 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 this program. If not, see <http://www.gnu.org/licenses/>. + + Contributed by Ken Werner <ken.werner@de.ibm.com> */ + +/* Simple OpenCL application that executes a kernel on the default device + in a data parallel fashion. The filename of the OpenCL program source + should be specified using the CL_SOURCE define. The name of the kernel + routine is expected to be "testkernel". */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <CL/cl.h> +#include "cl_util.h" + +#ifndef CL_SOURCE +#error "Please specify the OpenCL source file using the CL_SOURCE define" +#endif + +#define STRINGIFY(S) _STRINGIFY(S) +#define _STRINGIFY(S) #S + +#define SIZE 16 + +int +main () +{ + int err, i; + cl_platform_id platform; + cl_device_id device; + cl_context context; + cl_context_properties context_props[3]; + cl_command_queue queue; + cl_program program; + cl_kernel kernel; + cl_mem buffer; + + size_t len; + const char *program_source = NULL; + char *device_extensions = NULL; + char kernel_build_opts[256]; + size_t size = sizeof (cl_int) * SIZE; + const size_t global_work_size[] = {SIZE, 0, 0}; /* size of each dimension */ + cl_int *data; + + /* In order to see which devices the OpenCL implementation on your platform + provides you may issue a call to the print_clinfo () fuction. */ + + /* Initialize the data the OpenCl program operates on. */ + data = (cl_int*) calloc (1, size); + if (data == NULL) + { + fprintf (stderr, "calloc failed\n"); + exit (EXIT_FAILURE); + } + + /* Pick the first platform. */ + CHK (clGetPlatformIDs (1, &platform, NULL)); + /* Get the default device and create context. */ + CHK (clGetDeviceIDs (platform, CL_DEVICE_TYPE_DEFAULT, 1, &device, NULL)); + context_props[0] = CL_CONTEXT_PLATFORM; + context_props[1] = (cl_context_properties) platform; + context_props[2] = 0; + context = clCreateContext (context_props, 1, &device, NULL, NULL, &err); + CHK_ERR ("clCreateContext", err); + queue = clCreateCommandQueue (context, device, 0, &err); + CHK_ERR ("clCreateCommandQueue", err); + + /* Query OpenCL extensions of that device. */ + CHK (clGetDeviceInfo (device, CL_DEVICE_EXTENSIONS, 0, NULL, &len)); + device_extensions = (char *) malloc (len); + CHK (clGetDeviceInfo (device, CL_DEVICE_EXTENSIONS, len, device_extensions, + NULL)); + strcpy (kernel_build_opts, "-Werror -cl-opt-disable"); + if (strstr (device_extensions, "cl_khr_fp64") != NULL) + strcpy (kernel_build_opts + strlen (kernel_build_opts), + " -D HAVE_cl_khr_fp64"); + if (strstr (device_extensions, "cl_khr_fp16") != NULL) + strcpy (kernel_build_opts + strlen (kernel_build_opts), + " -D HAVE_cl_khr_fp16"); + + /* Read the OpenCL kernel source into the main memory. */ + program_source = read_file (STRINGIFY (CL_SOURCE), &len); + if (program_source == NULL) + { + fprintf (stderr, "file does not exist: %s\n", STRINGIFY (CL_SOURCE)); + exit (EXIT_FAILURE); + } + + /* Build the OpenCL kernel. */ + program = clCreateProgramWithSource (context, 1, &program_source, + &len, &err); + free ((void*) program_source); + CHK_ERR ("clCreateProgramWithSource", err); + err = clBuildProgram (program, 0, NULL, kernel_build_opts, NULL, + NULL); + if (err != CL_SUCCESS) + { + size_t len; + char *clbuild_log = NULL; + CHK (clGetProgramBuildInfo (program, device, CL_PROGRAM_BUILD_LOG, 0, + NULL, &len)); + clbuild_log = malloc (len); + if (clbuild_log) + { + CHK (clGetProgramBuildInfo (program, device, CL_PROGRAM_BUILD_LOG, + len, clbuild_log, NULL)); + fprintf (stderr, "clBuildProgram failed with:\n%s\n", clbuild_log); + free (clbuild_log); + } + exit (EXIT_FAILURE); + } + + /* In some cases it might be handy to save the OpenCL program binaries to do + further analysis on them. In order to do so you may call the following + function: save_program_binaries (program);. */ + + kernel = clCreateKernel (program, "testkernel", &err); + CHK_ERR ("clCreateKernel", err); + + /* Setup the input data for the kernel. */ + buffer = clCreateBuffer (context, CL_MEM_USE_HOST_PTR, size, data, &err); + CHK_ERR ("clCreateBuffer", err); + + /* Execute the kernel (data parallel). */ + CHK (clSetKernelArg (kernel, 0, sizeof (buffer), &buffer)); + CHK (clEnqueueNDRangeKernel (queue, kernel, 1, NULL, global_work_size, NULL, + 0, NULL, NULL)); + + /* Fetch the results (blocking). */ + CHK (clEnqueueReadBuffer (queue, buffer, CL_TRUE, 0, size, data, 0, NULL, + NULL)); + + /* Compare the results. */ + for (i = 0; i < SIZE; i++) + { + if (data[i] != 0x1) + { + fprintf (stderr, "error: data[%d]: %d != 0x1\n", i, data[i]); + exit (EXIT_FAILURE); + } + } + + /* Cleanup. */ + CHK (clReleaseMemObject (buffer)); + CHK (clReleaseKernel (kernel)); + CHK (clReleaseProgram (program)); + CHK (clReleaseCommandQueue (queue)); + CHK (clReleaseContext (context)); + free (data); + + return 0; +} diff --git a/gdb/testsuite/lib/opencl_kernel.cl b/gdb/testsuite/lib/opencl_kernel.cl new file mode 100644 index 0000000..32cba64 --- /dev/null +++ b/gdb/testsuite/lib/opencl_kernel.cl @@ -0,0 +1,5 @@ +/* OpenCL kernel for testing purposes. */ +__kernel void testkernel (__global int *data) +{ + data[get_global_id(0)] = 0x1; +} |