1 /* 2 * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 #include "opencl_backend.h" 27 OpenCLBackend::OpenCLBuffer * OpenCLBackend::getOrCreateBuffer(BufferState *bufferState) { 28 OpenCLBuffer *openclBuffer = nullptr; 29 if (bufferState->vendorPtr == 0L || bufferState->state == BufferState::NEW_STATE){ 30 openclBuffer = new OpenCLBuffer(this, bufferState); 31 if (config->trace){ 32 std::cout << "We allocated arg buffer "<<std::endl; 33 } 34 }else{ 35 if (config->trace){ 36 std::cout << "Were reusing buffer buffer "<<std::endl; 37 } 38 openclBuffer= static_cast<OpenCLBuffer*>(bufferState->vendorPtr); 39 } 40 return openclBuffer; 41 } 42 bool OpenCLBackend::getBufferFromDeviceIfDirty(void *memorySegment, long memorySegmentLength) { 43 if (config->traceCalls){ 44 std::cout << "getBufferFromDeviceIfDirty(" <<std::hex << (long)memorySegment << "," << std::dec<< memorySegmentLength <<"){"<<std::endl; 45 } 46 if (config->minimizeCopies){ 47 BufferState * bufferState = BufferState::of(memorySegment,memorySegmentLength); 48 if (bufferState->state == BufferState::DEVICE_OWNED){ 49 queue->copyFromDevice(static_cast<Backend::Buffer *>(bufferState->vendorPtr)); 50 if (config->traceEnqueues | config->traceCopies){ 51 std::cout << "copying buffer from device (from java access) "<< std::endl; 52 } 53 queue->wait(); 54 queue->release(); 55 }else{ 56 std::cout << "HOW DID WE GET HERE 1 attempting to get buffer but buffer is not device dirty"<<std::endl; 57 std::exit(1); 58 } 59 }else{ 60 std::cerr << "HOW DID WE GET HERE ? java side should avoid calling getBufferFromDeviceIfDirty as we are not minimising buffers!"<<std::endl; 61 std::exit(1); 62 } 63 if (config->traceCalls){ 64 std::cout << "}getBufferFromDeviceIfDirty()"<<std::endl; 65 } 66 return true; 67 } 68 69 OpenCLBackend::OpenCLBackend(int configBits ) 70 : Backend(new Config(configBits), new OpenCLQueue(this)) { 71 72 cl_int status; 73 cl_uint platformc = 0; 74 if ((status = clGetPlatformIDs(0, NULL, &platformc)) != CL_SUCCESS) { 75 std::cerr << "clGetPlatformIDs (to get count) failed " << errorMsg(status)<<std::endl; 76 std::exit(1); 77 return; 78 } 79 80 if (config->platform >= platformc){ 81 std::cerr << "We only have "<<platformc<<" platform"<<((platformc>1)?"s":"")<<" (platform[0]-platform["<<(platformc-1)<<"] inclusive) you requested platform["<<config->platform<<"]"<< std::endl; 82 std::exit(1); 83 return; 84 } 85 cl_platform_id *platforms = new cl_platform_id[platformc]; 86 if ((status = clGetPlatformIDs(platformc, platforms, NULL)) != CL_SUCCESS) { 87 std::cerr << "clGetPlatformIDs failed " << errorMsg(status)<<std::endl; 88 std::exit(1); 89 return; 90 } 91 cl_uint devicec = 0; 92 platform_id = platforms[config->platform]; 93 if ((status = clGetDeviceIDs(platform_id, CL_DEVICE_TYPE_ALL, 0, NULL, &devicec)) != CL_SUCCESS) { 94 if (status != CL_SUCCESS){ 95 std::cerr << "clGetDeviceIDs (to get count) failed " << errorMsg(status)<<std::endl; 96 } 97 delete[] platforms; 98 return; 99 } 100 if (config->device >= devicec){ 101 std::cerr << "Platform["<<config->platform<<"] only has "<<devicec<<" device"<<((devicec>1)?"s":"")<<" (device[0]-device["<<(devicec-1)<<"] inclusive) and you requested device["<<config->device<<"]"<< std::endl; 102 std::cerr << "No device available " << errorMsg(CL_DEVICE_NOT_AVAILABLE)<<std::endl; 103 delete[] platforms; 104 std::exit(1); 105 return; 106 } 107 108 if (devicec == 0) { 109 status = CL_DEVICE_NOT_AVAILABLE; 110 std::cerr << "No device available " << errorMsg(status)<<std::endl; 111 delete[] platforms; 112 return; 113 } 114 cl_device_id *device_ids = new cl_device_id[devicec]; // compute device id 115 if ((status = clGetDeviceIDs(platform_id, CL_DEVICE_TYPE_ALL, devicec, device_ids, NULL)) != CL_SUCCESS) { 116 std::cerr << "clGetDeviceIDs failed " << errorMsg(status)<<std::endl; 117 delete[] platforms; 118 delete[] device_ids; 119 return; 120 } 121 if ((context = clCreateContext(nullptr, 1, &device_ids[config->device], NULL, NULL, &status)) == NULL || status != CL_SUCCESS) { 122 std::cerr << "clCreateContext failed " << errorMsg(status)<<std::endl; 123 delete[] platforms; 124 delete[] device_ids; 125 return; 126 } 127 128 cl_command_queue_properties queue_props = CL_QUEUE_PROFILING_ENABLE; 129 auto openCLQueue = dynamic_cast<OpenCLQueue *>(queue); 130 if ((openCLQueue->command_queue = clCreateCommandQueue(context, device_ids[config->device], queue_props, &status)) == NULL || 131 status != CL_SUCCESS) { 132 std::cerr << "clCreateCommandQueue failed " << errorMsg(status)<<std::endl; 133 clReleaseContext(context); 134 delete[] platforms; 135 delete[] device_ids; 136 return; 137 } 138 139 device_id = device_ids[config->device]; 140 delete[] device_ids; 141 delete[] platforms; 142 143 } 144 145 OpenCLBackend::~OpenCLBackend() { 146 clReleaseContext(context); 147 148 } 149 150 void OpenCLBackend::computeStart() { 151 if (config->trace){ 152 std::cout <<"compute start" <<std::endl; 153 } 154 queue->computeStart(); 155 } 156 void OpenCLBackend::computeEnd() { 157 queue->computeEnd(); 158 queue->wait(); 159 160 if (config->profile){ 161 auto openCLQueue = dynamic_cast<OpenCLQueue *>(queue); 162 openCLQueue->showEvents(100); 163 } 164 queue->release(); 165 if (config->trace){ 166 std::cout <<"compute end" <<std::endl; 167 } 168 } 169 OpenCLBackend::OpenCLProgram *OpenCLBackend::compileProgram(OpenCLSource &openclSource){ 170 return compileProgram(&openclSource); 171 } 172 OpenCLBackend::OpenCLProgram *OpenCLBackend::compileProgram(OpenCLSource *openclSource){ 173 return compileProgram(openclSource->len, openclSource->text); 174 } 175 176 OpenCLBackend::OpenCLProgram *OpenCLBackend::compileProgram(int len, char *text){ 177 return dynamic_cast<OpenCLProgram *>(compile(len, text)); 178 } 179 180 Backend::CompilationUnit *OpenCLBackend::compile(int len, char *source){ 181 size_t srcLen = ::strlen(source); 182 char *src = new char[srcLen + 1]; 183 ::strncpy(src, source, srcLen); 184 src[srcLen] = '\0'; 185 if(config->trace){ 186 std::cout << "native compiling " << src << std::endl; 187 } 188 cl_int status; 189 cl_program program; 190 if ((program = clCreateProgramWithSource(context, 1, (const char **) &src, nullptr, &status)) == nullptr || 191 status != CL_SUCCESS) { 192 std::cerr << "clCreateProgramWithSource failed" << std::endl; 193 delete[] src; 194 return 0; 195 } 196 197 cl_int buildStatus = clBuildProgram(program, 0, nullptr, nullptr, nullptr, nullptr); 198 if (buildStatus != CL_SUCCESS) { 199 std::cerr << "buildStatus =failed" << std::endl; 200 } 201 size_t logLen = 0; 202 OpenCLProgram *openclProgram = nullptr; 203 if ((status = clGetProgramBuildInfo(program, device_id, CL_PROGRAM_BUILD_LOG, 0, nullptr, &logLen)) != CL_SUCCESS) { 204 std::cerr << "clGetBuildInfo (getting log size) failed" << std::endl; 205 //openclProgram->buildInfo = new Backend::CompilationUnit::BuildInfo(openclProgram, src, nullptr, false); 206 openclProgram= new OpenCLProgram(this, src,nullptr,buildStatus==CL_SUCCESS,program); 207 } else { 208 cl_build_status buildStatus; 209 clGetProgramBuildInfo(program, device_id, CL_PROGRAM_BUILD_STATUS, sizeof(buildStatus), &buildStatus, nullptr); 210 if (logLen > 0) { 211 char *log = new char[logLen + 1]; 212 if ((status = clGetProgramBuildInfo(program, device_id, CL_PROGRAM_BUILD_LOG, logLen + 1, (void *) log, 213 nullptr)) != CL_SUCCESS) { 214 std::cerr << "clGetBuildInfo (getting log) failed" << std::endl; 215 delete[] log; 216 log = nullptr; 217 } else { 218 log[logLen] = '\0'; 219 if (logLen > 1) { 220 std::cerr << "logLen = " << logLen << " log = " << log << std::endl; 221 } 222 } 223 openclProgram= new OpenCLProgram(this, src,log,buildStatus==CL_SUCCESS,program); 224 225 } else { 226 openclProgram= new OpenCLProgram(this, src, nullptr, buildStatus==CL_SUCCESS, program); 227 } 228 } 229 return openclProgram; 230 } 231 232 233 const char *OpenCLBackend::errorMsg(cl_int status) { 234 static struct { 235 cl_int code; 236 const char *msg; 237 } error_table[] = { 238 {CL_SUCCESS, "success"}, 239 {CL_DEVICE_NOT_FOUND, "device not found",}, 240 {CL_DEVICE_NOT_AVAILABLE, "device not available",}, 241 {CL_COMPILER_NOT_AVAILABLE, "compiler not available",}, 242 {CL_MEM_OBJECT_ALLOCATION_FAILURE, "mem object allocation failure",}, 243 {CL_OUT_OF_RESOURCES, "out of resources",}, 244 {CL_OUT_OF_HOST_MEMORY, "out of host memory",}, 245 {CL_PROFILING_INFO_NOT_AVAILABLE, "profiling not available",}, 246 {CL_MEM_COPY_OVERLAP, "memcopy overlaps",}, 247 {CL_IMAGE_FORMAT_MISMATCH, "image format mismatch",}, 248 {CL_IMAGE_FORMAT_NOT_SUPPORTED, "image format not supported",}, 249 {CL_BUILD_PROGRAM_FAILURE, "build program failed",}, 250 {CL_MAP_FAILURE, "map failed",}, 251 {CL_INVALID_VALUE, "invalid value",}, 252 {CL_INVALID_DEVICE_TYPE, "invalid device type",}, 253 {CL_INVALID_PLATFORM, "invlaid platform",}, 254 {CL_INVALID_DEVICE, "invalid device",}, 255 {CL_INVALID_CONTEXT, "invalid context",}, 256 {CL_INVALID_QUEUE_PROPERTIES, "invalid queue properties",}, 257 {CL_INVALID_COMMAND_QUEUE, "invalid command queue",}, 258 {CL_INVALID_HOST_PTR, "invalid host ptr",}, 259 {CL_INVALID_MEM_OBJECT, "invalid mem object",}, 260 {CL_INVALID_IMAGE_FORMAT_DESCRIPTOR, "invalid image format descriptor ",}, 261 {CL_INVALID_IMAGE_SIZE, "invalid image size",}, 262 {CL_INVALID_SAMPLER, "invalid sampler",}, 263 {CL_INVALID_BINARY, "invalid binary",}, 264 {CL_INVALID_BUILD_OPTIONS, "invalid build options",}, 265 {CL_INVALID_PROGRAM, "invalid program ",}, 266 {CL_INVALID_PROGRAM_EXECUTABLE, "invalid program executable",}, 267 {CL_INVALID_KERNEL_NAME, "invalid kernel name",}, 268 {CL_INVALID_KERNEL_DEFINITION, "invalid definition",}, 269 {CL_INVALID_KERNEL, "invalid kernel",}, 270 {CL_INVALID_ARG_INDEX, "invalid arg index",}, 271 {CL_INVALID_ARG_VALUE, "invalid arg value",}, 272 {CL_INVALID_ARG_SIZE, "invalid arg size",}, 273 {CL_INVALID_KERNEL_ARGS, "invalid kernel args",}, 274 {CL_INVALID_WORK_DIMENSION, "invalid work dimension",}, 275 {CL_INVALID_WORK_GROUP_SIZE, "invalid work group size",}, 276 {CL_INVALID_WORK_ITEM_SIZE, "invalid work item size",}, 277 {CL_INVALID_GLOBAL_OFFSET, "invalid global offset",}, 278 {CL_INVALID_EVENT_WAIT_LIST, "invalid event wait list",}, 279 {CL_INVALID_EVENT, "invalid event",}, 280 {CL_INVALID_OPERATION, "invalid operation",}, 281 {CL_INVALID_GL_OBJECT, "invalid gl object",}, 282 {CL_INVALID_BUFFER_SIZE, "invalid buffer size",}, 283 {CL_INVALID_MIP_LEVEL, "invalid mip level",}, 284 {CL_INVALID_GLOBAL_WORK_SIZE, "invalid global work size",}, 285 {-9999, "enqueueNdRangeKernel Illegal read or write to a buffer",}, 286 {0, NULL}, 287 }; 288 for (int i = 0; error_table[i].msg != NULL; i++) { 289 if (error_table[i].code == status) { 290 //std::cerr << " clerror '" << error_table[i].msg << "'" << std::endl; 291 return error_table[i].msg; 292 } 293 } 294 static char unknown[256]; 295 #if defined (_WIN32) 296 _snprintf 297 #else 298 snprintf 299 #endif 300 (unknown, sizeof(unknown), "unmapped string for error %d", status); 301 return unknown; 302 } 303 304 305 extern "C" long getBackend(int configBits) { 306 std::cerr << "Opencl Driver =" << std::hex<< configBits <<std::dec<< std::endl; 307 308 return reinterpret_cast<long>(new OpenCLBackend(configBits)); 309 } 310 311 312 void __checkOpenclErrors(cl_int status, const char *file, const int line) { 313 if (CL_SUCCESS != status) { 314 std::cerr << "Opencl Driver API error = " << status << " from file " << file << " line " << line << std::endl; 315 exit(-1); 316 } 317 } 318 319 OpenCLSource::OpenCLSource() 320 : Text(0L) { 321 } 322 OpenCLSource::OpenCLSource(size_t len) 323 : Text(len) { 324 } 325 OpenCLSource::OpenCLSource(char *text) 326 : Text(text, false) { 327 }