SciRuby/integration

View on GitHub
lib/opencl/integration_host.c

Summary

Maintainability
Test Coverage
// This file contains the host code of the openCL supported integration
#include <stdio.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdlib.h>
#include <limits.h>       //For PATH_MAX

// import OpenCL headers assuming OS is a linux version or MAC
#ifdef __APPLE__
    #include<OpenCL/opencl.h>
#else
    #include<CL/cl.h>
#endif

#define MAX_SOURCE_SIZE (0x100000) // maximum size allowed for the kernel text

// these are the available integration methods
enum methods{
      rectangle,
      trapezoid,
      simpson,
      adaptive_quadrature,
      gauss,
      romberg,
      monte_carlo
};

double opencl_integration(double lower, double upper, int n, char* f,
                        enum methods method, char* path_to_kerne) {

    char* source_str;
    size_t source_size;
    int i = 0;
    double dx = (upper - lower) / n;
    double *results = (double*) malloc(n * sizeof(double));

    // read the corresponding kernel
    FILE* fp;
    sprintf(path_to_kerne, "%s%s", path_to_kerne, "/unidimensional_kernel.cl");
    fp = fopen(path_to_kerne, "r");

    // if the kernel file doesn't exist, stop the execution
    if(fp == 0) {
        printf("kernel file not found\n");
        exit(0);
    }
    
    char *temp_source;
    // allocate memory for kenel code
    temp_source = (char*) malloc(sizeof(char) * MAX_SOURCE_SIZE);
    source_str  = (char*) malloc(sizeof(char) * MAX_SOURCE_SIZE);

    temp_source[0] = '\0';  // make temp_source a null string
    char line[100];
    // read the text of the kernel into temp_source
    while(!feof(fp)) {
        if (fgets(line, 100, fp)) {
            sprintf(temp_source, "%s%s",temp_source, line);
        }
    }

    // create the complete kernel code appending,
    // f()   - integrating function
    sprintf(source_str, "double f(double x){return (%s);}\n%s", f, temp_source);

    // printf("\nfunction----------------------------\n%s\n--------------------------\n", source_str);
    source_size = strlen(source_str);
    fclose(fp);
    free(temp_source);

    cl_platform_id platform_id = NULL;
    cl_device_id device_id     = NULL;   
    cl_uint ret_num_devices;
    cl_uint ret_num_platforms;
    cl_int ret;
    ret = clGetPlatformIDs(1, &platform_id, &ret_num_platforms);
    // CL_DEVICE_TYPE_CPU is being used currently as the testing value
    ret = clGetDeviceIDs( platform_id, CL_DEVICE_TYPE_CPU, 1, &device_id, &ret_num_devices);

    // create kernel
    cl_context context = clCreateContext( NULL, 1, &device_id, NULL, NULL, &ret);
    // create command queue
    cl_command_queue command_queue = clCreateCommandQueue(context, device_id, 0, &ret);    

    // create memory buffers to share memory with kernel program 
    cl_mem lower_obj  = clCreateBuffer(context, CL_MEM_READ_ONLY,  sizeof(double)     , NULL, &ret);
    cl_mem dx_obj     = clCreateBuffer(context, CL_MEM_READ_ONLY,  sizeof(double)     , NULL, &ret);
    cl_mem n_obj      = clCreateBuffer(context, CL_MEM_READ_ONLY,  sizeof(int)       , NULL, &ret);
    cl_mem method_obj = clCreateBuffer(context, CL_MEM_READ_ONLY,  sizeof(int)       , NULL, &ret);
    cl_mem result_obj = clCreateBuffer(context, CL_MEM_WRITE_ONLY, sizeof(double) * n , NULL, &ret);
    //cl_mem epsilon_obj      = clCreateBuffer(context, CL_MEM_READ_ONLY,  sizeof(double)     , NULL, &ret);
    //cl_mem golden_obj       = clCreateBuffer(context, CL_MEM_READ_ONLY,  sizeof(double)     , NULL, &ret);

    // writes the input values into the allocated memory buffers
    ret = clEnqueueWriteBuffer(command_queue, lower_obj,  CL_TRUE, 0, sizeof(double)    , &lower , 0, NULL, NULL);
    ret = clEnqueueWriteBuffer(command_queue, dx_obj   ,  CL_TRUE, 0, sizeof(double)    , &dx    , 0, NULL, NULL);
    ret = clEnqueueWriteBuffer(command_queue, n_obj    ,  CL_TRUE, 0, sizeof(int)      , &n     , 0, NULL, NULL);
    ret = clEnqueueWriteBuffer(command_queue, method_obj, CL_TRUE, 0, sizeof(int)      , &method, 0, NULL, NULL);
    //ret = clEnqueueWriteBuffer(command_queue, epsilon_obj , CL_TRUE, 0, sizeof(double)    , &epsilon       , 0, NULL, NULL);
    //ret = clEnqueueWriteBuffer(command_queue, golden_obj  , CL_TRUE, 0, sizeof(double)    , &golden        , 0, NULL, NULL);

    // create kernel program
    cl_program program = clCreateProgramWithSource(context, 1, (const char **)&source_str, (const size_t *)&source_size, &ret);
    // build the kernel program. Still the code isn't being executed
    // memory buffers haven't involved. Any error at this stage MAY be a syntax error of kernel code
    ret = clBuildProgram(program, 1, &device_id, NULL, NULL, NULL);
    // this gives error message only if the kernel code includes any syntax error
    if(ret == CL_BUILD_PROGRAM_FAILURE)  printf("\nerror while building kernel: %d\n", ret);
    // create the kernel calling the kernel function 'minimize'
    cl_kernel kernel = clCreateKernel(program, "integrate", &ret);

    // set arguments of kernel function
    ret = clSetKernelArg(kernel, 0 , sizeof(cl_mem)    , (void *)&lower_obj);    
    ret = clSetKernelArg(kernel, 1 , sizeof(cl_mem)    , (void *)&dx_obj);    
    ret = clSetKernelArg(kernel, 2 , sizeof(cl_mem)    , (void *)&n_obj);    
    ret = clSetKernelArg(kernel, 3 , sizeof(cl_mem)    , (void *)&method_obj);    
    ret = clSetKernelArg(kernel, 4 , sizeof(cl_mem) * n, (void *)&result_obj);
    //ret = clSetKernelArg(kernel, 9 , sizeof(cl_mem)    , (void *)&epsilon_obj);
    //ret = clSetKernelArg(kernel, 10, sizeof(cl_mem)    , (void *)&golden_obj);

    size_t global_item_size = n;
    // enqueue the jobs and let them to be solved by kernel program
    ret = clEnqueueNDRangeKernel(command_queue, kernel, 1, NULL, &global_item_size, NULL, 0, NULL, NULL);
    
    // retrieve results from the shared memory buffers
    ret = clEnqueueReadBuffer(command_queue, result_obj, CL_TRUE, 0, sizeof(double) * n, results, 0, NULL, NULL);

    // clear the allocated memory
    ret = clFlush(command_queue);
    ret = clFinish(command_queue);
    ret = clReleaseKernel(kernel);
    ret = clReleaseProgram(program);

    ret = clReleaseMemObject(lower_obj);
    ret = clReleaseMemObject(dx_obj);
    ret = clReleaseMemObject(n_obj);
    ret = clReleaseMemObject(method_obj);
    //ret = clReleaseMemObject(epsilon_obj);
    //ret = clReleaseMemObject(golden_obj);

    ret = clReleaseCommandQueue(command_queue);
    ret = clReleaseContext(context);
    free(source_str);

    double final_result = 0;
    for(i = 0; i < n; ++i) {
        final_result += results[i];
    }

    return final_result;
}