C++ OpenCL helper object/function

I’m not sure this is the correct forum, please move if it isn’t.

I have created this C++ helper object and function that I thought might be of use for anyone using the C++ bindings. Basically the helper queries for all of the platforms and devices in the system and filters them using specified criteria. The platform, device, context, and command queue for each device is placed in a vector array and returned for use in the calling program. My goal was to have an easy way to check and find only those devices that my program can use and have them in an easily accessible place. Right now the only filtering it does is on the device type (cl_device_type) and OpenCL version (CL_DEVICE_OPENCL_C_VERSION), but the function can be easily modified for more filters.

My questions are, is this helpful, and I’m I doing this correctly (should probably have more error checking)? Any comments and help would be most appreciated.

Here is the clInitDevices helper object/function (I use linux so that is what I tested it on, YMMV):

// Jason Grimes - 8/30/2010 University of Alaska, GINA program.
// This class holds all of objects needed for OpenCL to communicate with a
// device.
class clDeviceList
  {
  public:
  clDeviceList() { }
  clDeviceList( cl::Platform* newPlatform, std::vector<cl::Device>* newDevice,
      cl_device_type nDevType ) :
      clPlatform( *newPlatform ),
      clDevice( *newDevice )
    {
    cl_context_properties clProperties[] =
      {
      CL_CONTEXT_PLATFORM,
      (cl_context_properties)clPlatform(),
      0, 0, 0
      };

    clContext = cl::Context( (cl_device_type)nDevType, clProperties, NULL,
        NULL, NULL );
    clQueue = cl::CommandQueue( clContext, clDevice[0], 0, NULL );
    }

  const cl::Platform &getPlatform() const { return clPlatform; }
  const std::vector<cl::Device> &getDevice() const { return clDevice; }
  const cl::Context &getContext() const { return clContext; }
  const cl::CommandQueue &getQueue() const { return clQueue; }

  private:
  cl::Platform clPlatform;               // Holds this OpenCL Platform
  std::vector<cl::Device> clDevice;      // Holds this OpenCL Device
  cl::Context clContext;                 // Holds this OpenCL Context
  cl::CommandQueue clQueue;              // Holds this OpenCL Command Queue
  };

// A function to initialize OpenCL devices and to filter them by OpenCL 
// version and device type. 
std::vector<clDeviceList*> clInitDevices( cl_device_type nDevType,
      const std::string clVersionCompare )
  {
  std::vector<cl::Platform> clPlatforms;         // Platforms 
  std::vector<clDeviceList*> clDevices;          // OpenCL Devices
  cl::STRING_CLASS clVersion;                    // OpenCL version string

  // Get all platforms on the system
  cl::Platform::get( &clPlatforms );

  // Check each platform ...
  std::vector<cl::Device> clDeviceTemp;  // temp holding array
  for( unsigned int cnt=0; cnt < clPlatforms.size(); cnt++ )
    {
    // Process OpenCL platforms and devices, match to params 
    clPlatforms[cnt].getInfo( (cl_platform_info) CL_PLATFORM_VERSION,
       &clVersion );

    // Add compatable devices into devices vector
    try
      {
      clPlatforms[cnt].getDevices( (cl_device_type)nDevType, &clDeviceTemp );
      }
    catch( cl::Error error )
      {
      if( error.err() == -1 )
        std::cout << "Device not found" << std::endl;
      }

    for( unsigned int cnt2=0; cnt2 < clDeviceTemp.size(); cnt2++ )
      {
      std::vector<cl::Device> devtemp;  // Temp array will only have 1 entry
      devtemp.push_back( clDeviceTemp[cnt2] );
      devtemp[0].getInfo( (cl_device_info)CL_DEVICE_OPENCL_C_VERSION,
          &clVersion );

      if( clVersion.find( clVersionCompare ) != std::string::npos )
        clDevices.push_back( new clDeviceList( &clPlatforms[cnt],
            &devtemp, nDevType ));
      }
    }
  return clDevices;
  }

Here is some example code that demonstrates how to use the clInitDevices object/function.

//  Jason Grimes - 8/30/2010 University of Alaska, GINA program.
// Get information about installed OpenCL installed devices
// ---------------------------------------------------------------------------
// Use - openclinfo { -gpu } or { -cpu }
// openclinfo defaults to -all and reports on all of the devices in the system
// -gpu will list only gpu devices
// -cpu will list only cpu devices
// -ver #.# list only devices that are valid for the specified OpenCL version
// ---------------------------------------------------------------------------
// Compiled with the following g++ command:
// g++ openclinfo.cpp -o openclinfo -I /usr/include/CL -lOpenCL -Wall
//

// Defines
#define __CL_ENABLE_EXCEPTIONS
//#define __NO_STD_STRING

// Includes
#include <iostream>
#include <string>
#include <vector>
#include <cl.hpp>
#include <cstdio>
#include <cstdlib>
#include "opencl_devs.hpp"

// Main
int main( int argc, char **argv )
  {
  cl_device_type mode = CL_DEVICE_TYPE_ALL;  // Default type query mode/text
  std::string mode_name = "CL_DEVICE_TYPE_ALL";
  std::string clversion = "1.";              // Default OpenCL version check

  // Parse command line args
  if( argc > 1 )
    {
    for( int cnt=1; cnt<argc; cnt++ )
      {
      std::string args( argv[cnt] );
      if( args.compare( "-cpu" ) == 0 )
        {
        mode = CL_DEVICE_TYPE_CPU; // type CPU mode
        mode_name = "CL_DEVICE_TYPE_CPU";
        }
      if( args.compare( "-gpu" ) == 0 )
        {
        mode = CL_DEVICE_TYPE_GPU; // type GPU mode
        mode_name = "CL_DEVICE_TYPE_GPU";
        }
      if( args.compare( "-ver" ) == 0 )
        {
        cnt++;
        clversion = argv[cnt]; // set the version number to check
        }
      }
    }

  if( argc > 4 )
    {
    std::cout << std::endl;
    std::cout << "Usage - openclinfo {-gpu or -cpu} {-ver #.#}" << std::endl;
    std::cout << "openclinfo defaults to -all and reports on all of the" <<
        " devices in the system, version defaults to 1.#" << std::endl;
    std::cout << "-gpu will list only gpu devices" << std::endl;
    std::cout << "-cpu will list only cpu devices" << std::endl;
    std::cout << "-ver #.# will list only devices with that OpenCL version"
        << std::endl;
    std::cout << "Example: openclinfo -gpu -ver 1.0" << std::endl << std::endl;
    }

  // Initialize the OpenCL interface
  std::vector<clDeviceList*> myopencl =
      clInitDevices( (cl_device_type)mode, clversion );

  if( myopencl.size() == 0 )
    {
    std::cout << "This system does not have an OpenCL compatable device "
       << std::endl;
    std::cout << "that has the following profile:" << std::endl << std::endl;
    std::cout << "Type - " << mode_name << std::endl;
    std::cout << "OpenCL Version - " << clversion << std::endl;
    return 0;
    }

  // Report on the valid devices:
  std::cout << std::endl << "Found " <<  myopencl.size() << " Devices"
      << std::endl << std::endl;

  std::string name;            // Name of Device
  std::string extensions;      // The Extensions the Device Supports
  std::string openclver;       // The OpenCL Version the Device Supports
  for( unsigned int cnt=0; cnt<myopencl.size(); cnt++ )
    {
    std::cout << "Device - " << cnt << std::endl;

    myopencl[cnt]->getDevice()[0].getInfo( (cl_device_info)CL_DEVICE_NAME,
         &name );
    myopencl[cnt]->getDevice()[0].getInfo(
        (cl_device_info)CL_DEVICE_OPENCL_C_VERSION, &openclver );
    myopencl[cnt]->getDevice()[0].getInfo( (cl_device_info)CL_DEVICE_EXTENSIONS,
         &extensions );

    std::cout << "Name - " << name << std::endl;
    std::cout << "OpenCL Version - " << openclver << std::endl;
    std::cout << "Extensions - " << extensions << std::endl;
    std::cout << std::endl;
    }
  }

I changed the code slightly so that I no longer keep the device in a vector array. I think it’s a lot cleaner now just change all of the “getDevice()[0]” to “getDevice()” in the example code and it should work.

// Jason Grimes - 8/30/2010 University of Alaska, GINA program.
// This class holds all of objects needed for OpenCL to communicate with a
// device.
class clDeviceList
  {
  public:
  clDeviceList() { }
  clDeviceList( cl::Platform* newPlatform, cl::Device* newDevice,
      cl_device_type nDevType ) :
      clPlatform( *newPlatform ),
      clDevice( *newDevice )
    {
    cl_context_properties clProperties[] =
      {
      CL_CONTEXT_PLATFORM,
      (cl_context_properties)clPlatform(),
      0, 0, 0
      };

    clContext = cl::Context( (cl_device_type)nDevType, clProperties, NULL,
        NULL, NULL );
    clQueue = cl::CommandQueue( clContext, clDevice, 0, NULL );
    }

  const cl::Platform &getPlatform() const { return clPlatform; }
  const cl::Device &getDevice() const { return clDevice; }
  const cl::Context &getContext() const { return clContext; }
  const cl::CommandQueue &getQueue() const { return clQueue; }

  private:
  cl::Platform clPlatform;               // Holds this OpenCL Platform
  cl::Device clDevice;                   // Holds this OpenCL Device
  cl::Context clContext;                 // Holds this OpenCL Context
  cl::CommandQueue clQueue;              // Holds this OpenCL Command Queue
  };

// A function to initialize OpenCL devices and to filter them by OpenCL 
// version and device type. 
std::vector<clDeviceList*> clInitDevices( cl_device_type nDevType,
      const std::string clVersionCompare )
  {
  std::vector<cl::Platform> clPlatforms;         // Platforms 
  std::vector<clDeviceList*> clDevices;          // OpenCL Devices
  cl::STRING_CLASS clVersion;                    // OpenCL version string

  // Get all platforms on the system
  cl::Platform::get( &clPlatforms );

  // Check each platform ...
  std::vector<cl::Device> clDeviceTemp;  // temp holding array
  for( unsigned int cnt=0; cnt < clPlatforms.size(); cnt++ )
    {
    // Process OpenCL platforms and devices, match to params 
    clPlatforms[cnt].getInfo( (cl_platform_info) CL_PLATFORM_VERSION,
       &clVersion );

    // Add compatable devices into devices vector
    try
      {
      clPlatforms[cnt].getDevices( (cl_device_type)nDevType, &clDeviceTemp );
      }
    catch( cl::Error error )
      {
      if( error.err() == -1 )
        continue;
      }

    for( unsigned int cnt2=0; cnt2 < clDeviceTemp.size(); cnt2++ )
      {
      clDeviceTemp[cnt2].getInfo( (cl_device_info)CL_DEVICE_OPENCL_C_VERSION,
          &clVersion );

      if( clVersion.find( clVersionCompare ) != std::string::npos )
        clDevices.push_back( new clDeviceList( &clPlatforms[cnt],
            &clDeviceTemp[cnt2], nDevType ));
      }
    }
  return clDevices;
  }

Grimm