/* Tom Gall (tom.gall@linaro.org / tom_gall@mac.com) * Copyright Linaro 2014 * Released under the terms and conditions of the license documented in the LICENSE file */ #include #include #include "sqlite3.h" //#include "sqlite3ext.h" #include "opencl-sqlite.h" #define SEARCH_KERNEL_FUNC "x1_search_kernel" int opencl_init( opencl_sqlite_context *s, sqlite3 *db, size_t data_size, size_t results_size, char *filename) { cl_platform_id platform; cl_device_id device; cl_int i, err; FILE *program_handle; char *program_buffer, *program_log; size_t program_size, log_size, read_return; s->db = db; s->data_cpu = malloc(sizeof (opencl_data)); s->data_size = data_size; s->data_cpu->d = malloc (data_size); s->data_gpu = malloc(sizeof (opencl_data_gpu)); s->data_gpu->d = NULL; s->results_cpu = malloc(sizeof (opencl_results)); s->results_size = results_size; s->results_cpu->r = NULL; s->results_gpu = malloc(sizeof (opencl_gpu_results)); /* Identify a platform */ err = clGetPlatformIDs(1, &platform, NULL); if(err < 0) { perror("ERROR: Couldn't find any platforms."); exit(1); } /* Access a device */ #ifdef USE_CPU err = clGetDeviceIDs(platform, CL_DEVICE_TYPE_CPU, 1, &device, NULL); #else err = clGetDeviceIDs(platform, CL_DEVICE_TYPE_GPU, 1, &device, NULL); #endif if(err < 0) { perror("ERROR: Couldn't find any devices."); exit(1); } /* Create the context */ s->context = clCreateContext(NULL, 1, &device, NULL, NULL, &err); if(err < 0) { perror("ERROR: Couldn't create a context."); exit(1); } err=clRetainContext(s->context); if(err < 0) { perror("ERROR: Couldn't retain context."); exit(1); } /* Read program file and place content into buffer * loop here across useful cl routines that we'll have */ program_handle = fopen(filename, "r"); if(program_handle == NULL) { perror("Couldn't find cl file \n"); exit(1); } fseek(program_handle, 0, SEEK_END); program_size = ftell(program_handle); rewind(program_handle); program_buffer = (char*)malloc(program_size + 1); program_buffer[program_size] = '\0'; read_return = fread(program_buffer, sizeof(char), program_size, program_handle); fclose(program_handle); /* Create program from file */ s->program = clCreateProgramWithSource(s->context, 1, (const char**)&program_buffer, &program_size, &err); if(err < 0) { perror("Couldn't create the program"); exit(1); } free(program_buffer); /* Build program */ err = clBuildProgram(s->program, 0, NULL, NULL, NULL, NULL); if(err < 0) { /* Find size of log and print to std output */ clGetProgramBuildInfo(s->program, device, CL_PROGRAM_BUILD_LOG, 0, NULL, &log_size); program_log = (char*) malloc(log_size + 1); program_log[log_size] = '\0'; clGetProgramBuildInfo(s->program, device, CL_PROGRAM_BUILD_LOG, log_size + 1, program_log, NULL); printf("%s\n", program_log); free(program_log); exit(1); } /* Create kernel for the all the added cl functions * TODO : evolve this in a loop */ s->kernel = clCreateKernel(s->program, SEARCH_KERNEL_FUNC, &err); if(err < 0) { perror("Couldn't create the kernel "); exit(1); } /* Create a CL command queue for the device*/ s->queue = clCreateCommandQueue(s->context, device, CL_QUEUE_PROFILING_ENABLE, &err); if(err < 0) { perror("Couldn't create the command queue"); exit(1); } return OPENCL_SUCCESS; } int opencl_release(opencl_sqlite_context *s) { return OPENCL_SUCCESS; } int opencl_cleanup(opencl_sqlite_context *s) { clReleaseKernel(s->kernel); clReleaseCommandQueue(s->queue); clReleaseProgram(s->program); clReleaseContext(s->context); return OPENCL_SUCCESS; } /* * The point of this code is to get at the data in the database so we can work with it. * Likely to be replaced at some point by going completely to shards by column which * is the most efficient when passing into an OpenCL kernel. */ int opencl_prepare_data(opencl_sqlite_context *s, const char* sql_stmt, int * columnSettings) { sqlite3_stmt *stmt; sqlite3_value *val; int columns, offset=0, type, stride=0; opencl_data *data = s->data_cpu; int i = strlen(sql_stmt); sqlite3_prepare_v2(s->db, sql_stmt, i, &stmt, NULL); // first determine the size of a row i = sqlite3_step(stmt); // no row? bail if(i != SQLITE_ROW) return OPENCL_ERR_STMT; columns = sqlite3_column_count(stmt); data->columns = columns; // walk one row for(i = 0; i < columns; i++) { val = sqlite3_column_value(stmt, i); // Handling just the 32 bit cases for now // will support armv8, other 64 bit hardware eventually type = sqlite3_value_type(val); switch (type) { case SQLITE_INTEGER: data->types[i] = OPENCL_INT; data->offsets[i] = offset; offset += sizeof(int); break; case SQLITE_FLOAT: data->types[i] = OPENCL_FLOAT; data->offsets[i] = offset; offset += sizeof(float); break; default: perror("Unsupported data type detected\n"); return OPENCL_ERR_TYPE; } } // set row stride to the current offset for ( i = 0; i < columns; i++ ) { if (columnSettings[i]) stride+=4; } s->data_cpu->stride = stride; int rows = 0; char *d = (char*)s->data_cpu->d; void *p; int rowoffset=0; do { for(i = 0; i < columns; i++) { if (columnSettings[i]) { p = d + rows * stride + rowoffset; switch(data->types[i]) { case OPENCL_INT : ((int *)p)[0] = sqlite3_column_int(stmt, i); break; case OPENCL_INT64 : ((long long *)p)[0] = sqlite3_column_int64(stmt, i); break; case OPENCL_FLOAT : ((float *)p)[0] = (float)sqlite3_column_double(stmt, i); break; case OPENCL_DOUBLE : ((double *)p)[0] = sqlite3_column_double(stmt, i); break; default: fprintf(stderr, "column %i, datatype is not supported (yet)\n", i); return OPENCL_ERR_TYPE; } rowoffset+=4; } } rows++; rowoffset = 0; } while(sqlite3_step(stmt) == SQLITE_ROW); data->rows = rows; sqlite3_finalize(stmt); return OPENCL_SUCCESS; } int opencl_shard_data(opencl_sqlite_context *s, opencl_data_shard *shard, int column) { int rows = 0; int rowoffset=0; cl_int error=0; opencl_data *data = s->data_cpu; int *d = (int*)s->data_cpu->d; rows = data -> rows; shard->type = s->data_cpu->types[column]; shard->rows = rows; int *v = malloc(rows * sizeof(int)); int *cpu_map=v; //shard->d = clCreateBuffer(s->context, CL_MEM_ALLOC_HOST_PTR | CL_MEM_READ_ONLY, rows * sizeof(int), NULL, NULL); //int *destination = clEnqueueMapBuffer(s->queue, shard->d, CL_TRUE, CL_MAP_READ, 0, rows * sizeof(int), 0, NULL, NULL, &error); char *p =(char *) (d + column); do { //*destination = *((int *)p); *v = *((int *)p); /* switch(data->types[i]) { case OPENCL_INT : break; case OPENCL_INT64 : break; case OPENCL_FLOAT : break; case OPENCL_DOUBLE : break; default: return OPENCL_ERR_TYPE; }*/ // destination++; v++; p += data->stride; rows--; } while(rows); shard->d = clCreateBuffer(s->context, CL_MEM_COPY_HOST_PTR | CL_MEM_READ_ONLY, s->data_cpu->rows * sizeof(int), cpu_map, NULL); // clEnqueueUnmapMemObject(s->queue, shard->d, destination, 0, NULL, NULL); return OPENCL_SUCCESS; }