SCM Repository
View of /branches/vis12-cl/src/lib/cl-target/ocl-support.c
Parent Directory
|
Revision Log
Revision 3133 -
(download)
(as text)
(annotate)
Wed Mar 25 15:25:33 2015 UTC (7 years, 1 month ago) by jhr
File size: 19934 byte(s)
Wed Mar 25 15:25:33 2015 UTC (7 years, 1 month ago) by jhr
File size: 19934 byte(s)
added missing #ifdef
/*! \file ocl-support.c * * \author John Reppy * * \brief This file contains support code for the OpenCL target. It includes functions * that can be used to determine properties of the host machine's OpenCL support. */ /* * COPYRIGHT (c) 2014 The Diderot Project (http://diderot-language.cs.uchicago.edu) * All rights reserved. */ #ifndef DIDEROT_TARGET_CL # define DIDEROT_TARGET_CL #endif #include "Diderot/diderot.h" #include <stdio.h> #include <string.h> #include <stdlib.h> #include <sys/stat.h> #define MAX_PLATFORMS 16 static bool GetDevices (WorldPrefix_t *wrld, unsigned int platIdx, Diderot_PlatformInfo_t *plat); #define CHECK(call) do { \ cl_int __sts = call; \ if (__sts != CL_SUCCESS) { \ biffMsgAddf(wrld->errors, "error at %s:%d: %s\n", \ __FILE__, __LINE__, Diderot_OCLErrorString(__sts)); \ return 0; \ } \ } while (0) Diderot_OCLInfo_t *Diderot_GetCLInfo (WorldPrefix_t *wrld) { cl_platform_id platformIDs[MAX_PLATFORMS]; char buf[512]; // get platform info // get number of OpenCL platforms cl_uint numPlatforms; CHECK(clGetPlatformIDs (MAX_PLATFORMS, platformIDs, &numPlatforms)); Diderot_PlatformInfo_t *plats = NEWVEC(Diderot_PlatformInfo_t, numPlatforms); for (unsigned int i = 0; i < numPlatforms; i++) { clGetPlatformInfo (platformIDs[i], CL_PLATFORM_NAME, sizeof(buf), buf, 0); plats[i].name = NEWSTR(buf); plats[i].id = platformIDs[i]; // get OpenCL version info clGetPlatformInfo (platformIDs[i], CL_PLATFORM_VERSION, sizeof(buf), buf, 0); // get extension info // FIXME: TODO // get device info if (GetDevices (wrld, i, &(plats[i]))) { // free storage for (unsigned int j = 0; j <= i; j++) { free (plats[i].name); } free (plats); return 0; } } Diderot_OCLInfo_t *info = NEW(Diderot_OCLInfo_t); info->numPlatforms = numPlatforms; info->platforms = plats; return info; } static char *GetStringInfo (cl_device_id dev, cl_device_info param) { char buf[1024]; cl_int sts = clGetDeviceInfo (dev, param, sizeof(buf), buf, 0); if (sts != CL_SUCCESS) return 0; else return NEWSTR(buf); } static bool GetDevices (WorldPrefix_t *wrld, unsigned int platIdx, Diderot_PlatformInfo_t *plat) { cl_uint numDevs; char buf[512]; // get number of devices for the platform clGetDeviceIDs (plat->id, CL_DEVICE_TYPE_ALL, 0, 0, &numDevs); if (numDevs == 0) { plat->numDevices = 0; plat->devices = 0; return false; } plat->numDevices = numDevs; plat->devices = NEWVEC(Diderot_DeviceInfo_t, numDevs); cl_device_id *devices = NEWVEC(cl_device_id, numDevs); CHECK(clGetDeviceIDs (plat->id, CL_DEVICE_TYPE_ALL, numDevs, devices, 0)); for (unsigned int i = 0; i < numDevs; i++) { Diderot_DeviceInfo_t *dev = &(plat->devices[i]); dev->index[0] = platIdx; dev->index[1] = i; if ((dev->name = GetStringInfo(devices[i], CL_DEVICE_NAME)) == 0) { biffMsgAdd (wrld->errors, "error getting device name\n"); return true; } if ((dev->vendor = GetStringInfo(devices[i], CL_DEVICE_VENDOR)) == 0) { biffMsgAdd (wrld->errors, "error getting device vendor\n"); return true; } dev->id = devices[i]; CHECK(clGetDeviceInfo ( devices[i], CL_DEVICE_VERSION, sizeof(buf), buf, 0)); if (sscanf (buf, "OpenCL %d.%d", &(dev->majorVersion), &(dev->minorVersion)) != 2) { biffMsgAddf (wrld->errors, "error scanning version string: \"%s\"\n", buf); return true; } CHECK(clGetDeviceInfo ( devices[i], CL_DEVICE_TYPE, sizeof(cl_device_type), &(dev->ty), 0)); CHECK(clGetDeviceInfo ( devices[i], CL_DEVICE_AVAILABLE, sizeof(cl_bool), &(dev->isAvail), 0)); CHECK(clGetDeviceInfo ( devices[i], CL_DEVICE_ADDRESS_BITS, sizeof(cl_uint), &(dev->addrBits), 0)); CHECK(clGetDeviceInfo ( devices[i], CL_DEVICE_ENDIAN_LITTLE, sizeof(cl_bool), &(dev->littleEndian), 0)); CHECK(clGetDeviceInfo ( devices[i], CL_DEVICE_MAX_COMPUTE_UNITS, sizeof(cl_uint), &(dev->numCUs), 0)); CHECK(clGetDeviceInfo ( devices[i], CL_DEVICE_MAX_CONSTANT_ARGS, sizeof(cl_uint), &(dev->maxConstArgs), 0)); CHECK(clGetDeviceInfo ( devices[i], CL_DEVICE_MAX_WORK_ITEM_DIMENSIONS, sizeof(cl_uint), &(dev->maxWIDims), 0)); CHECK(clGetDeviceInfo ( devices[i], CL_DEVICE_MAX_WORK_GROUP_SIZE, sizeof(size_t), &(dev->maxWGSize), 0)); size_t szb = sizeof(size_t) * dev->maxWIDims; dev->maxWISize = (size_t *) CheckedAlloc (szb); CHECK(clGetDeviceInfo (devices[i], CL_DEVICE_MAX_WORK_ITEM_SIZES, szb, dev->maxWISize, 0)); CHECK(clGetDeviceInfo ( devices[i], CL_DEVICE_GLOBAL_MEM_SIZE, sizeof(cl_ulong), &(dev->globalMemSzb), 0)); CHECK(clGetDeviceInfo ( devices[i], CL_DEVICE_LOCAL_MEM_SIZE, sizeof(cl_ulong), &(dev->localMemSzb), 0)); CHECK(clGetDeviceInfo ( devices[i], CL_DEVICE_MAX_PARAMETER_SIZE, sizeof(size_t), &(dev->maxParamSzb), 0)); CHECK(clGetDeviceInfo ( devices[i], CL_DEVICE_MAX_CONSTANT_BUFFER_SIZE, sizeof(cl_ulong), &(dev->maxConstBufSzb), 0)); CHECK(clGetDeviceInfo ( devices[i], CL_DEVICE_MAX_MEM_ALLOC_SIZE, sizeof(cl_ulong), &(dev->maxAllocSzb), 0)); cl_bool imagesSupported; CHECK(clGetDeviceInfo ( devices[i], CL_DEVICE_IMAGE_SUPPORT, sizeof(cl_bool), &imagesSupported, 0)); if (imagesSupported) { CHECK(clGetDeviceInfo ( devices[i], CL_DEVICE_IMAGE2D_MAX_WIDTH, sizeof(size_t), &(dev->maxImg2D[0]), 0)); CHECK(clGetDeviceInfo ( devices[i], CL_DEVICE_IMAGE3D_MAX_DEPTH, sizeof(size_t), &(dev->maxImg2D[1]), 0)); CHECK(clGetDeviceInfo ( devices[i], CL_DEVICE_IMAGE3D_MAX_WIDTH, sizeof(size_t), &(dev->maxImg3D[0]), 0)); CHECK(clGetDeviceInfo ( devices[i], CL_DEVICE_IMAGE3D_MAX_HEIGHT, sizeof(size_t), &(dev->maxImg3D[1]), 0)); CHECK(clGetDeviceInfo ( devices[i], CL_DEVICE_IMAGE3D_MAX_DEPTH, sizeof(size_t), &(dev->maxImg3D[2]), 0)); } else { dev->maxImg2D[0] = dev->maxImg2D[1] = 0; dev->maxImg3D[0] = dev->maxImg3D[1] = dev->maxImg3D[2] = 0; } CHECK(clGetDeviceInfo ( devices[i], CL_DEVICE_PREFERRED_VECTOR_WIDTH_CHAR, sizeof(cl_uint), &(dev->charWid), 0)); CHECK(clGetDeviceInfo ( devices[i], CL_DEVICE_PREFERRED_VECTOR_WIDTH_CHAR, sizeof(cl_uint), &(dev->shortWid), 0)); CHECK(clGetDeviceInfo ( devices[i], CL_DEVICE_PREFERRED_VECTOR_WIDTH_CHAR, sizeof(cl_uint), &(dev->intWid), 0)); CHECK(clGetDeviceInfo ( devices[i], CL_DEVICE_PREFERRED_VECTOR_WIDTH_CHAR, sizeof(cl_uint), &(dev->longWid), 0)); CHECK(clGetDeviceInfo ( devices[i], CL_DEVICE_PREFERRED_VECTOR_WIDTH_CHAR, sizeof(cl_uint), &(dev->floatWid), 0)); CHECK(clGetDeviceInfo ( devices[i], CL_DEVICE_PREFERRED_VECTOR_WIDTH_CHAR, sizeof(cl_uint), &(dev->doubleWid), 0)); // determine the compute-unit width if (Diderot_isCPUDevice(dev)) dev->cuWidth = 1; else if (Diderot_isGPUDevice(dev)) if (strcasecmp("AMD", dev->vendor) == 0) dev->cuWidth = 64; // an AMD wavefront is 64-wide else if (strcasecmp("NVIDIA", dev->vendor) == 0) dev->cuWidth = 32; // an NVIDIA warp is 32-wide else dev->cuWidth = 32; // FIXME: not sure what this should be? else dev->cuWidth = 1; // FIXME: not sure what this should be? } free(devices); return false; } /*! \brief return the device with the given index. */ Diderot_DeviceInfo_t *Diderot_GetDeviceByIndex (Diderot_OCLInfo_t *clinfo, unsigned int platIdx, unsigned int devIdx) { if ((clinfo == 0) || (clinfo->numPlatforms <= platIdx) || (clinfo->platforms[platIdx].numDevices <= devIdx)) return 0; else return &(clinfo->platforms[platIdx].devices[devIdx]); } void Diderot_PrintCLInfo (FILE *outS, Diderot_OCLInfo_t *clinfo) { if (clinfo->numPlatforms == 0) { fprintf(outS, "No OpenCL platforms\n"); return; } fprintf(outS, "OpenCL profile:\n"); for (unsigned int i = 0; i < clinfo->numPlatforms; i++) { Diderot_PlatformInfo_t *plat = &(clinfo->platforms[i]); fprintf (outS, " Platform %d (%s)\n", i, plat->name); for (unsigned int j = 0; j < plat->numDevices; j++) { Diderot_DeviceInfo_t *dev = &(plat->devices[j]); if (dev->isAvail) fprintf (outS, " Device %d.%d (%s):\n", i, j, dev->name); else fprintf (outS, " Device %d.%d (%s): **UNAVAILABLE**\n", i, j, dev->name); fprintf (outS, " Vendor: %s\n", dev->vendor); fprintf (outS, " OpenCL version: %d.%d\n", dev->majorVersion, dev->minorVersion); fprintf (outS, " Type: "); if (Diderot_isCPUDevice(dev)) fprintf (outS, " CPU"); if (Diderot_isGPUDevice(dev)) fprintf (outS, " GPU"); if (dev->ty & CL_DEVICE_TYPE_ACCELERATOR) fprintf (outS, " ACCELERATOR"); if (dev->ty & CL_DEVICE_TYPE_DEFAULT) fprintf (outS, " DEFAULT"); fprintf (outS, "\n"); fprintf (outS, " Address size: %d\n", dev->addrBits); fprintf (outS, " Endianess: %s\n", dev->littleEndian ? "LITTLE" : "BIG"); fprintf (outS, " Num. compute units: %d", dev->numCUs); if (dev->cuWidth > 1) fprintf (outS, " * %d\n", dev->cuWidth); else fprintf (outS, "\n"); fprintf (outS, " Max. dimensions: %d\n", dev->maxWIDims); fprintf (outS, " Max. work group size: %ld\n", (long)(dev->maxWGSize)); fprintf (outS, " Max. work items: "); for (int k = 0; k < dev->maxWIDims; k++) fprintf (outS, "%s%ld", (k > 0) ? " x " : "", (long)(dev->maxWISize[k])); fprintf (outS, "\n"); fprintf (outS, " Global memory size: %ld\n", (long)(dev->globalMemSzb)); fprintf (outS, " Local memory size: %ld\n", (long)(dev->localMemSzb)); fprintf (outS, " Max. parameter size: %ld\n", (long)(dev->maxParamSzb)); fprintf (outS, " Max. allocation size: %ld\n", (long)(dev->maxAllocSzb)); fprintf (outS, " Max. const. buffer size: %ld\n", (long)(dev->maxConstBufSzb)); fprintf (outS, " Max. const. arguments: %d\n", dev->maxConstArgs); fprintf (outS, " Max. 2D image size: %ld x %ld\n", (long)(dev->maxImg2D[0]), (long)(dev->maxImg2D[1])); fprintf (outS, " Max. 3D image size: %ld x %ld x %ld\n", (long)(dev->maxImg3D[0]), (long)(dev->maxImg3D[1]), (long)(dev->maxImg3D[2])); fprintf (outS, " Prefered vector width: char%d, short%d, int%d, long%d\n", dev->charWid, dev->shortWid, dev->intWid, dev->longWid); fprintf (outS, " float%d", dev->floatWid); if (dev->doubleWid > 0) fprintf (outS, ", double%d\n", dev->doubleWid); else fprintf (outS, "\n"); } } } Diderot_DeviceInfo_t *Diderot_DefaultCLDevice (Diderot_OCLInfo_t *clinfo) { if ((clinfo == 0) || (clinfo->numPlatforms == 0)) return 0; // we pick the first GPU device that we find for (unsigned int i = 0; i < clinfo->numPlatforms; i++) { Diderot_PlatformInfo_t *plat = &(clinfo->platforms[i]); for (unsigned int j = 0; j < plat->numDevices; j++) { if (Diderot_isGPUDevice(&(plat->devices[j]))) return &(plat->devices[j]); } } // otherwise we pick a CPU device for (unsigned int i = 0; i < clinfo->numPlatforms; i++) { Diderot_PlatformInfo_t *plat = &(clinfo->platforms[i]); for (unsigned int j = 0; j < plat->numDevices; j++) { if (Diderot_isCPUDevice(&(plat->devices[j]))) return &(plat->devices[j]); } } // otherwise return 0 return 0; } /*! \brief load OpenCL code from a file */ cl_program Diderot_LoadProgramFromSource (WorldPrefix_t *wrld, cl_context cxt, const char *filename, cl_int *sts) { struct stat statbuf; if (stat(filename, &statbuf) < 0) { biffMsgAddf (wrld->errors, "unable to stat OpenCL source file %s\n", filename); *sts = CL_INVALID_PROGRAM; return 0; } char *source = (char *)CheckedAlloc(statbuf.st_size + 1); if (source == 0) { biffMsgAddf (wrld->errors, "unable to allocate memory for OpenCL source\n"); *sts = CL_OUT_OF_HOST_MEMORY; return 0; } FILE *fh = fopen(filename, "r"); if ((fh == 0) || (fread(source, statbuf.st_size, 1, fh) != 1)) { biffMsgAddf (wrld->errors, "unable to read OpenCL source from %s\n", filename); *sts = CL_INVALID_PROGRAM; return 0; } source[statbuf.st_size] = '\0'; fclose (fh); cl_program prog = clCreateProgramWithSource(cxt, 1, (const char **)&source, NULL, sts); free (source); if (*sts != CL_SUCCESS) { biffMsgAddf (wrld->errors, "error creating program: %s\n", Diderot_OCLErrorString(*sts)); return 0; } return prog; } // convert an OpenCL error code to a string // const char *Diderot_OCLErrorString (cl_int sts) { switch (sts) { case CL_SUCCESS: return "Success!"; case CL_DEVICE_NOT_FOUND: return "Device not found."; case CL_DEVICE_NOT_AVAILABLE: return "Device not available"; case CL_COMPILER_NOT_AVAILABLE: return "Compiler not available"; case CL_MEM_OBJECT_ALLOCATION_FAILURE: return "Memory object allocation failure"; case CL_OUT_OF_RESOURCES: return "Out of resources"; case CL_OUT_OF_HOST_MEMORY: return "Out of host memory"; case CL_PROFILING_INFO_NOT_AVAILABLE: return "Profiling information not available"; case CL_MEM_COPY_OVERLAP: return "Memory copy overlap"; case CL_IMAGE_FORMAT_MISMATCH: return "Image format mismatch"; case CL_IMAGE_FORMAT_NOT_SUPPORTED: return "Image format not supported"; case CL_BUILD_PROGRAM_FAILURE: return "Program build failure"; case CL_MAP_FAILURE: return "Map failure"; case CL_INVALID_VALUE: return "Invalid value"; case CL_INVALID_DEVICE_TYPE: return "Invalid device type"; case CL_INVALID_PLATFORM: return "Invalid platform"; case CL_INVALID_DEVICE: return "Invalid device"; case CL_INVALID_CONTEXT: return "Invalid context"; case CL_INVALID_QUEUE_PROPERTIES: return "Invalid queue properties"; case CL_INVALID_COMMAND_QUEUE: return "Invalid command queue"; case CL_INVALID_HOST_PTR: return "Invalid host pointer"; case CL_INVALID_MEM_OBJECT: return "Invalid memory object"; case CL_INVALID_IMAGE_FORMAT_DESCRIPTOR: return "Invalid image format descriptor"; case CL_INVALID_IMAGE_SIZE: return "Invalid image size"; case CL_INVALID_SAMPLER: return "Invalid sampler"; case CL_INVALID_BINARY: return "Invalid binary"; case CL_INVALID_BUILD_OPTIONS: return "Invalid build options"; case CL_INVALID_PROGRAM: return "Invalid program"; case CL_INVALID_PROGRAM_EXECUTABLE: return "Invalid program executable"; case CL_INVALID_KERNEL_NAME: return "Invalid kernel name"; case CL_INVALID_KERNEL_DEFINITION: return "Invalid kernel definition"; case CL_INVALID_KERNEL: return "Invalid kernel"; case CL_INVALID_ARG_INDEX: return "Invalid argument index"; case CL_INVALID_ARG_VALUE: return "Invalid argument value"; case CL_INVALID_ARG_SIZE: return "Invalid argument size"; case CL_INVALID_KERNEL_ARGS: return "Invalid kernel arguments"; case CL_INVALID_WORK_DIMENSION: return "Invalid work dimension"; case CL_INVALID_WORK_GROUP_SIZE: return "Invalid work group size"; case CL_INVALID_WORK_ITEM_SIZE: return "Invalid work item size"; case CL_INVALID_GLOBAL_OFFSET: return "Invalid global offset"; case CL_INVALID_EVENT_WAIT_LIST: return "Invalid event wait list"; case CL_INVALID_EVENT: return "Invalid event"; case CL_INVALID_OPERATION: return "Invalid operation"; case CL_INVALID_GL_OBJECT: return "Invalid OpenGL object"; case CL_INVALID_BUFFER_SIZE: return "Invalid buffer size"; case CL_INVALID_MIP_LEVEL: return "Invalid mip-map level"; case CL_INVALID_GLOBAL_WORK_SIZE: return "Invalid global work size"; case CL_INVALID_PROPERTY: return "Invalid property"; #ifdef CL_INVALID_IMAGE_DESCRIPTOR case CL_INVALID_IMAGE_DESCRIPTOR: return "Invalid image descriptor"; #endif #ifdef CL_INVALID_COMPILER_OPTIONS case CL_INVALID_COMPILER_OPTIONS: return "Invalid compiler options"; #endif #ifdef CL_INVALID_LINKER_OPTIONS case CL_INVALID_LINKER_OPTIONS: return "Invalid linker options"; #endif #ifdef CL_INVALID_LINKER_OPTIONS case CL_INVALID_DEVICE_PARTITION_COUNT: return "Invalid device partition count"; #endif default: return "Unknown error"; } } /* get the OpenCL program binary */ unsigned char *Diderot_OCLGetBinary (WorldPrefix_t *wrld, cl_program prog, size_t *sizeOut) { cl_int sts; size_t sizes[1]; CHECK (clGetProgramInfo (prog, CL_PROGRAM_BINARY_SIZES, sizeof(size_t), sizes, 0)); unsigned char *bufs[1]; bufs[0] = NEWVEC(unsigned char, sizes[0]); CHECK (clGetProgramInfo (prog, CL_PROGRAM_BINARIES, sizes[0], bufs, sizeOut)); return bufs[0]; } bool Diderot_OCLSaveBinary (WorldPrefix_t *wrld, cl_program prog, const char *file) { size_t sizeb; unsigned char *binary = Diderot_OCLGetBinary (wrld, prog, &sizeb); if (binary == 0) { return true; } FILE *outS = fopen (file, "wb"); if (outS == NULL) { return true; } if (fwrite (binary, sizeb, 1, outS) < sizeb) { fclose (outS); return true; } fclose (outS); return false; }
root@smlnj-gforge.cs.uchicago.edu | ViewVC Help |
Powered by ViewVC 1.0.0 |