0
votes

I am working on a package for R using C++, Rcpp and OpenCL.

I am having a build failure when loading from a .cl file. However, when I load from a const char * kernel it works.

// code build fails 
  std::ifstream sourceFile("Kernels.cl");
    std::string sourceCode( std::istreambuf_iterator<char(sourceFile), (std::istreambuf_iterator<char>()));

cl::Program::Sources  source(1, std::make_pair(sourceCode.c_str(), sourceCode.length()));  
// code build passes

cl::Program::Sources  source(1, std::make_pair(vadd, strlen(vadd)));
cl::Program program2 = cl::Program(context,source);

Is there an issue with loading OpenCL between rcpp and OpenCL?

Minimal Example( all dealing with an R package): Test.cpp

#define __CL_ENABLE_EXCEPTIONS
/* Modified from https://github.com/HandsOnOpenCL/Exercises-Solutions; Simon McIntosh-Smith and Tom Deakin from the University of Bristol*/

#include < /Users/5kd/Documents/TestExample/src/err_code.h >  
#include < /Users/5kd/Documents/TestExample/src/cl.hpp >
#include < vector >
#include < stdio >
#include < cstdlib >
#include < string >
#include < iostream >
#include < stream >
#include < /Users/5kd/Documents/TestExample/src/Test_Kernels.h >
#ifndef DEVICE
#define DEVICE CL_DEVICE_TYPE_DEFAULT
#endif 


void TestVal1(){
        try{
                cl::Context context(DEVICE);
                cl_int err;
                std::ifstream sourceFile("Test_Kernels.cl");
                std::string sourceCode( std::istreambuf_iterator<char>(sourceFile), (std::istreambuf_iterator<char>()));
                cl::Program::Sources  source1(1, std::make_pair(sourceCode.c_str(), sourceCode.length()));
                cl::Program program1(context,source1 );
                std::vector<cl::Device> devices = context.getInfo<CL_CONTEXT_DEVICES>();
                program1.build(devices);
                Rcpp::Rcout << "pass 1\n";
        }
        catch (cl::Error err) {
                Rcpp::Rcout << "Exception\n";
                 Rcpp::Rcout << "ERROR: "<< err.what() << "("  << err_code(err.err()) << ")"  << "\n";
    }
};
void TestVal2(){
        try{
                cl::Context context(DEVICE);
                cl_int err;
                std::ifstream sourceFile2("vadd.cl");
                std::string sourceCode2( std::istreambuf_iterator<char>(sourceFile2), (std::istreambuf_iterator<char>()));
                cl::Program::Sources  source2(1, std::make_pair(sourceCode2.c_str(), sourceCode2.length()));
                cl::Program program2(context,source2 );
                std::vector<cl::Device> devices = context.getInfo<CL_CONTEXT_DEVICES>();
                program2.build(devices);
                Rcpp::Rcout << "pass 2\n";
        }
        catch (cl::Error err) {
                Rcpp::Rcout << "Exception\n";
                 Rcpp::Rcout << "ERROR: "<< err.what() << "("  << err_code(err.err()) << ")"  << "\n";
    }
};
void TestVal3(){
        try{
                cl::Context context(DEVICE);
                cl_int err;
                cl::Program::Sources source3(1, std::make_pair(VAdd, strlen(VAdd)));
                cl::Program program3(context,source3 );
                std::vector<cl::Device> devices = context.getInfo<CL_CONTEXT_DEVICES>();
                program3.build(devices);
                Rcpp::Rcout << "pass 3\n";
         }
        catch (cl::Error err) {
                Rcpp::Rcout << "Exception\n";
                 Rcpp::Rcout << "ERROR: "<< err.what() << "("  << err_code(err.err()) << ")"  << "\n";
    }
};
SEXP solve_(){
  Test opt;
  int soln = opt.region(5);
  return List::create();
}

int Test::region(int p){
  TestVal1();
  TestVal2();
  TestVal3();

  return(p);
};

Test::Test() {};

Test_Kernels.cl

kernel void vadd2( global const float *a , global const float * b ,global float *c ){

        int index= get_global_id(0);
        c]index] = a[index] + b[index];
}

vadd.cl

__kernel void vadd(
   __global float* a,
   __global float* b,
   __global float* c,
   const unsigned int count)
{
   int i = get_global_id(0);
   if(i < count)  {
       c[i] = a[i] + b[i];
   }
 }

Test_Kernels.h

const char * VAdd =" kernel void vadd( global const  float *a, global const float *b, global float* c){ int i = get_global_id(0);  c[i] = a[i] + b[i];         }";

    }

RcppExports.cpp

#include <RcppEigen.h>
#include <Rcpp.h>

using namespace Rcpp;

// solve_
SEXP solve_();
RcppExport SEXP TestExample_solve_() {
BEGIN_RCPP
    SEXP __sexp_result;
    {
        Rcpp::RNGScope __rngScope;
        SEXP __result = solve_();
        PROTECT(__sexp_result = Rcpp::wrap(__result));
    }
    UNPROTECT(1);
    return __sexp_result;
END_RCPP
}

RcppExports.R

solve_ <- function() {
    .Call('TestExample_solve_', PACKAGE = 'TestExample')
}

Test_solve.R

Test_solve <- function() {

  opt_ <- get_Test_opts()

  .Call('TestExample_solve_', PACKAGE = 'TestExample')
}

Main running: Test.R

require(RcppEigen)
require(Matrix)
require(TestExample)


t <- Test_solve()

Build Using: R CMD build TestExample R CMD INSTALL TestExample.tar.gz Run: R -f Test.R

Output from my run:
> require(RcppEigen)
Loading required package: RcppEigen
> require(Matrix)
Loading required package: Matrix
> require(TestExample)
Loading required package: TestExample
Loading required package: Rcpp
> 
> 
> t <- Test_solve()

Exception
ERROR: clBuildProgram(CL_BUILD_PROGRAM_FAILURE)
Exception
ERROR: clBuildProgram(CL_BUILD_PROGRAM_FAILURE)
pass 3
1
Can you bring this as a minimal example to rcpp-devel? Charles Determan may be able to help you, not sure he'll spot it here. I only played with OpenCL indirectly via (Rcpp)ArrayFire. - Dirk Eddelbuettel
I can try and bring a minimal example but most what I am working on can't be shown. - Kirsten
Understood, many of us are in a similar situation. That does not stop most of us from being able to mock the full issue with a small yet salient reproducible example. - Dirk Eddelbuettel
Thank you so much for fast replay! - Kirsten
A minimal reproducible example would be useful. Right now the only people able to answer your question are those that have encountered it before. Those that are willing to investigate are left out. - Ralf Stubner

1 Answers

1
votes

I don't see an relation to Rcpp, since I am able to reproduce the compilation errors using a plain C++ program:

#define __CL_ENABLE_EXCEPTIONS

#include <CL/cl.hpp>
#include <iostream>
#include <fstream>

void TestVal1(){
  try{
    cl::Context context(CL_DEVICE_TYPE_DEFAULT);
    std::ifstream sourceFile("Test_Kernels.cl");
    std::string sourceCode( std::istreambuf_iterator<char>(sourceFile), (std::istreambuf_iterator<char>()));
    cl::Program::Sources  source1(1, std::make_pair(sourceCode.c_str(), sourceCode.length()));
    cl::Program program1(context, source1);
    std::vector<cl::Device> devices = context.getInfo<CL_CONTEXT_DEVICES>();
    program1.build(devices);
    std::cout << "pass 1\n";
  }
  catch (cl::Error err) {
    std::cout << "Exception\n";
    std::cout << "ERROR: "<< err.what() << "("  << err.err() << ")"  << "\n";
  }
}
void TestVal2(){
  try{
    cl::Context context(CL_DEVICE_TYPE_DEFAULT);
    std::ifstream sourceFile("vadd.cl");
    std::string sourceCode( std::istreambuf_iterator<char>(sourceFile), (std::istreambuf_iterator<char>()));
    cl::Program::Sources  source2(1, std::make_pair(sourceCode.c_str(), sourceCode.length()));
    cl::Program program2(context, source2);
    std::vector<cl::Device> devices = context.getInfo<CL_CONTEXT_DEVICES>();
    program2.build(devices);
    std::cout << "pass 2\n";
  }
  catch (cl::Error err) {
    std::cout << "Exception\n";
    std::cout << "ERROR: "<< err.what() << "("  << err.err() << ")"  << "\n";
  }
}
void TestVal3(){
  try{
    cl::Context context(CL_DEVICE_TYPE_DEFAULT);
    const char * VAdd =" kernel void vadd( global const  float *a, global const float *b, global float* c){ int i = get_global_id(0);  c[i] = a[i] + b[i];         }";
    cl::Program::Sources source3(1, std::make_pair(VAdd, strlen(VAdd)));
    cl::Program program3(context, source3);
    std::vector<cl::Device> devices = context.getInfo<CL_CONTEXT_DEVICES>();
    program3.build(devices);
    std::cout << "pass 3\n";
  }
  catch (cl::Error err) {
    std::cout << "Exception\n";
    std::cout << "ERROR: "<< err.what() << "("  << err.err() << ")"  << "\n";
  }
}

int main(){
  TestVal1();
  TestVal2();
  TestVal3();
}

I both cases there where simple syntax errors in the kernels. Using

kernel void vadd2( global const float *a , global const float * b ,global float *c ){

        int index= get_global_id(0);
        c[index] = a[index] + b[index]; // [ instead of ]
}

and

__kernel void vadd(
   __global float* a,
   __global float* b,
   __global float* c,
   const unsigned int count)
{
   int i = get_global_id(0);
   if(i < count)  {
       c[i] = a[i] + b[i];
   }
} // missing

the example builds and runs fine, also from Rcpp:

#define __CL_ENABLE_EXCEPTIONS

#include <Rcpp.h>
#include <CL/cl.hpp>
#include <fstream>

void TestVal1(){
  try{
    cl::Context context(CL_DEVICE_TYPE_DEFAULT);
    std::ifstream sourceFile("Test_Kernels.cl");
    std::string sourceCode( std::istreambuf_iterator<char>(sourceFile), (std::istreambuf_iterator<char>()));
    cl::Program::Sources  source1(1, std::make_pair(sourceCode.c_str(), sourceCode.length()));
    cl::Program program1(context,source1 );
    std::vector<cl::Device> devices = context.getInfo<CL_CONTEXT_DEVICES>();
    program1.build(devices);
    Rcpp::Rcout << "pass 1\n";
  }
  catch (cl::Error err) {
    Rcpp::Rcout << "Exception\n";
    Rcpp::Rcout << "ERROR: "<< err.what() << "("  << err.err() << ")"  << "\n";
  }
}
void TestVal2(){
  try{
    cl::Context context(CL_DEVICE_TYPE_DEFAULT);
    std::ifstream sourceFile2("vadd.cl");
    std::string sourceCode2( std::istreambuf_iterator<char>(sourceFile2), (std::istreambuf_iterator<char>()));
    cl::Program::Sources  source2(1, std::make_pair(sourceCode2.c_str(), sourceCode2.length()));
    cl::Program program2(context,source2 );
    std::vector<cl::Device> devices = context.getInfo<CL_CONTEXT_DEVICES>();
    program2.build(devices);
    Rcpp::Rcout << "pass 2\n";
  }
  catch (cl::Error err) {
    Rcpp::Rcout << "Exception\n";
    Rcpp::Rcout << "ERROR: "<< err.what() << "("  << err.err() << ")"  << "\n";
  }
}
void TestVal3(){
  try{
    cl::Context context(CL_DEVICE_TYPE_DEFAULT);
    const char * VAdd =" kernel void vadd( global const  float *a, global const float *b, global float* c){ int i = get_global_id(0);  c[i] = a[i] + b[i];         }";
    cl::Program::Sources source3(1, std::make_pair(VAdd, strlen(VAdd)));
    cl::Program program3(context,source3 );
    std::vector<cl::Device> devices = context.getInfo<CL_CONTEXT_DEVICES>();
    program3.build(devices);
    Rcpp::Rcout << "pass 3\n";
  }
  catch (cl::Error err) {
    Rcpp::Rcout << "Exception\n";
    Rcpp::Rcout << "ERROR: "<< err.what() << "("  << err.err() << ")"  << "\n";
  }
}

// [[Rcpp::export]]
void tests(){
  TestVal1();
  TestVal2();
  TestVal3();
}

To compile and run this file I use:

Sys.setenv(PKG_LIBS = "-lOpenCL")
Rcpp::sourceCpp("kernel_test.cpp")
tests()