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