Home My Page Projects Code Snippets Project Openings diderot
Summary Activity Tracker Tasks SCM

SCM Repository

[diderot] View of /branches/vis12-cl/src/lib/cl-target/ocl-support.c
ViewVC logotype

View of /branches/vis12-cl/src/lib/cl-target/ocl-support.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3121 - (download) (as text) (annotate)
Tue Mar 24 08:58:26 2015 UTC (4 years, 3 months ago) by jhr
File size: 18377 byte(s)
  fix typo
/*! \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";
        default: return "Unknown error";
    }

}

root@smlnj-gforge.cs.uchicago.edu
ViewVC Help
Powered by ViewVC 1.0.0