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 #include <fstream>
 26 #include <functional>
 27 #define shared_cpp
 28 
 29 #include "shared.h"
 30 
 31 #define INFO 0
 32 
 33 #include <cstring>
 34 
 35 void Hex::ascii(std::ostream &s, char c) {
 36     if (::iscntrl(c)) {
 37         if (c == '\a') {
 38             s << "\\a ";
 39         } else if (c == '\r') {
 40             s << "\\r ";
 41         } else if (c == '\n') {
 42             s << "\\n ";
 43         } else if (c == '\t') {
 44             s << "\\t ";
 45         } else {
 46             s << "?? ";
 47         }
 48     } else {
 49         s << c << "  ";
 50     }
 51 }
 52 
 53 void Hex::hex(std::ostream &s, char c) {
 54     s << std::hex << std::setw(2) << std::setfill('0') << std::uppercase << (c & 0xff) << " ";
 55 }
 56 
 57 void Hex::bytes(std::ostream &s, char *p, size_t len, std::function<void(std::ostream &)> prefix) {
 58     for (int i = 0; i < len; i++) {
 59         if ((i % 16) == 0) {
 60             if (i > 0) {
 61                 s << "  ";
 62                 for (int c = i - 16; c < i; c++) {
 63                     ascii(s, p[c]);
 64                 }
 65             }
 66             s << std::endl;
 67             prefix(s);
 68             s << std::hex << std::setw(6) << std::setfill('0') << i << " ";
 69         }
 70         hex(s, p[i]);
 71     }
 72 
 73     if ((len % 16) == 0) {
 74         s << "  ";
 75         for (int c = len - 16; c < len; c++) {
 76             ascii(s, p[c]);
 77         }
 78     } else {
 79         for (int v = len % 16; v < 16; v++) {
 80             s << "   ";
 81         }
 82         s << "  ";
 83         for (int c = len - (len % 16); c < len; c++) {
 84             ascii(s, p[c]);
 85         }
 86     }
 87 }
 88 
 89 void strutil::replaceInPlace(std::string &subject, const std::string &search,
 90                              const std::string &replace) {
 91     size_t pos = 0;
 92     while ((pos = subject.find(search, pos)) != std::string::npos) {
 93         subject.replace(pos, search.length(), replace);
 94         pos += replace.length();
 95     }
 96 }
 97 
 98 
 99 bool strutil::endsWith(const std::string &str, const std::string &suffix) {
100     return str.size() >= suffix.size() && 0 == str.compare(str.size() - suffix.size(), suffix.size(), suffix);
101 }
102 
103 char *strutil::clone(char *name) {
104     size_t len = ::strlen(name);
105     char *buf = new char[len + 1];
106     memcpy(buf, name, len);
107     buf[len] = '\0';
108     return buf;
109 }
110 
111 void hexdump(void *ptr, int buflen) {
112     auto *buf = static_cast<unsigned char *>(ptr);
113     int i, j;
114     for (i = 0; i < buflen; i += 16) {
115         printf("%06x: ", i);
116         for (j = 0; j < 16; j++)
117             if (i + j < buflen)
118                 printf("%02x ", buf[i + j]);
119             else
120                 printf("   ");
121         printf(" ");
122         for (j = 0; j < 16; j++)
123             if (i + j < buflen)
124                 printf("%c", isprint(buf[i + j]) ? buf[i + j] : '.');
125         printf("\n");
126     }
127 }
128 
129 void Sled::show(std::ostream &out, void *argArray) {
130     ArgSled argSled(static_cast<ArgArray_s *>(argArray));
131     for (int i = 0; i < argSled.argc(); i++) {
132         KernelArg *arg = argSled.arg(i);
133         switch (arg->variant) {
134             case '&': {
135                 out << "Buf: of " << arg->value.buffer.sizeInBytes << " bytes " << std::endl;
136                 break;
137             }
138             case 'B': {
139                 out << "S8:" << arg->value.s8 << std::endl;
140                 break;
141             }
142             case 'Z': {
143                 out << "Z:" << arg->value.z1 << std::endl;
144                 break;
145             }
146             case 'C': {
147                 out << "U16:" << arg->value.u16 << std::endl;
148                 break;
149             }
150             case 'S': {
151                 out << "S16:" << arg->value.s16 << std::endl;
152                 break;
153             }
154             case 'I': {
155                 out << "S32:" << arg->value.s32 << std::endl;
156                 break;
157             }
158             case 'F': {
159                 out << "F32:" << arg->value.f32 << std::endl;
160                 break;
161             }
162             case 'J': {
163                 out << "S64:" << arg->value.s64 << std::endl;
164                 break;
165             }
166             case 'D': {
167                 out << "F64:" << arg->value.f64 << std::endl;
168                 break;
169             }
170             default: {
171                 std::cerr << "unexpected variant (shared.cpp) '" << static_cast<char>(arg->variant) << "'" << std::endl;
172                 exit(1);
173             }
174         }
175     }
176     out << "schema len = " << argSled.schemaLen() << std::endl;
177 
178     out << "schema = " << argSled.schema() << std::endl;
179 }
180 
181 
182 extern "C" void showDeviceInfo(long backendHandle) {
183         std::cout << "DEBUG through backendHandle to backend.showDeviceInfo()" << std::endl;
184     if (INFO) {
185         std::cout << "trampolining through backendHandle to backend.showDeviceInfo()" << std::endl;
186     }
187     auto *backend = reinterpret_cast<Backend *>(backendHandle);
188     backend->showDeviceInfo();
189 }
190 
191 extern "C" void computeStart(long backendHandle) {
192     if (INFO) {
193         std::cout << "trampolining through backendHandle to backend.computeStart()" << std::endl;
194     }
195     auto *backend = reinterpret_cast<Backend *>(backendHandle);
196     backend->computeStart();
197 }
198 
199 extern "C" void computeEnd(long backendHandle) {
200     if (INFO) {
201         std::cout << "trampolining through backendHandle to backend.computeEnd()" << std::endl;
202     }
203     auto *backend = reinterpret_cast<Backend *>(backendHandle);
204     backend->computeEnd();
205 }
206 
207 extern "C" void releaseBackend(long backendHandle) {
208     auto *backend = reinterpret_cast<Backend *>(backendHandle);
209     delete backend;
210 }
211 
212 extern "C" long compile(long backendHandle, int len, char *source) {
213     if (INFO) {
214         std::cout << "trampolining through backendHandle to backend.compile() "
215                 << std::hex << backendHandle << std::dec << std::endl;
216     }
217     auto *backend = reinterpret_cast<Backend *>(backendHandle);
218     long compilationUnitHandle = reinterpret_cast<long>(backend->compile(len, source));
219     if (INFO) {
220         std::cout << "compilationUnitHandle = " << std::hex << compilationUnitHandle << std::dec << std::endl;
221     }
222     return compilationUnitHandle;
223 }
224 
225 extern "C" long getKernel(long compilationUnitHandle, int nameLen, char *name) {
226     if (INFO) {
227         std::cout << "trampolining through programHandle to compilationUnit.getKernel()"
228                 << std::hex << compilationUnitHandle << std::dec << std::endl;
229     }
230     auto compilationUnit = reinterpret_cast<Backend::CompilationUnit *>(compilationUnitHandle);
231     return reinterpret_cast<long>(compilationUnit->getKernel(nameLen, name));
232 }
233 
234 extern "C" long ndrange(long kernelHandle, void *argArray) {
235     if (INFO) {
236         std::cout << "trampolining through kernelHandle to kernel.ndrange(...) " << std::endl;
237     }
238     auto kernel = reinterpret_cast<Backend::CompilationUnit::Kernel *>(kernelHandle);
239     kernel->ndrange(argArray);
240     return (long) 0;
241 }
242 
243 extern "C" void releaseKernel(long kernelHandle) {
244     if (INFO) {
245         std::cout << "trampolining through to releaseKernel " << std::endl;
246     }
247     auto kernel = reinterpret_cast<Backend::CompilationUnit::Kernel *>(kernelHandle);
248     delete kernel;
249 }
250 
251 extern "C" void releaseCompilationUnit(long compilationUnitHandle) {
252     if (INFO) {
253         std::cout << "trampolining through to releaseCompilationUnit " << std::endl;
254     }
255     auto compilationUnit = reinterpret_cast<Backend::CompilationUnit *>(compilationUnitHandle);
256     delete compilationUnit;
257 }
258 
259 extern "C" bool compilationUnitOK(long compilationUnitHandle) {
260     if (INFO) {
261         std::cout << "trampolining through to compilationUnitHandleOK " << std::endl;
262     }
263     auto compilationUnit = reinterpret_cast<Backend::CompilationUnit *>(compilationUnitHandle);
264     return compilationUnit->compilationUnitOK();
265 }
266 
267 extern "C" bool getBufferFromDeviceIfDirty(long backendHandle, long memorySegmentHandle, long memorySegmentLength) {
268     if (INFO) {
269         std::cout << "trampolining through to getBuffer " << std::endl;
270     }
271     auto backend = reinterpret_cast<Backend *>(backendHandle);
272     auto memorySegment = reinterpret_cast<void *>(memorySegmentHandle);
273     return backend->getBufferFromDeviceIfDirty(memorySegment, memorySegmentLength);
274 }
275 
276 
277 Backend::Config::Config(int configBits):BasicConfig(configBits) {
278 
279 }
280 
281 Backend::Config::~Config() = default;
282 
283 Backend::Queue::Queue(Backend *backend)
284     : backend(backend) {
285 }
286 
287 Backend::Queue::~Queue() = default;
288 
289 Text::Text(size_t len, char *text, bool isCopy)
290     : len(len), text(text), isCopy(isCopy) {
291     // std::cout << "in Text len="<<len<<" isCopy="<<isCopy << std::endl;
292 }
293 
294 Text::Text(char *text, bool isCopy)
295     : len(std::strlen(text)), text(text), isCopy(isCopy) {
296     // std::cout << "in Text len="<<len<<" isCopy="<<isCopy << std::endl;
297 }
298 
299 Text::Text(size_t len)
300     : len(len), text(len > 0 ? new char[len] : nullptr), isCopy(true) {
301     //  std::cout << "in Text len="<<len<<" isCopy="<<isCopy << std::endl;
302 }
303 
304 void Text::write(const std::string &filename) const {
305     std::ofstream out;
306     out.open(filename, std::ofstream::trunc);
307     out.write(text, len);
308     out.close();
309 }
310 
311 void Text::read(const std::string &filename) {
312     if (isCopy && text) {
313         delete[] text;
314     }
315     text = nullptr;
316     isCopy = false;
317     // std::cout << "reading from " << filename << std::endl;
318 
319     std::ifstream ptxStream;
320     ptxStream.open(filename);
321 
322 
323     ptxStream.seekg(0, std::ios::end);
324     len = ptxStream.tellg();
325     ptxStream.seekg(0, std::ios::beg);
326 
327     if (len > 0) {
328         text = new char[len];
329         isCopy = true;
330         //std::cerr << "about to read  " << len << std::endl;
331         ptxStream.read(text, len);
332         ptxStream.close();
333         //std::cerr << "read  " << len << std::endl;
334         text[len - 1] = '\0';
335         //std::cerr << "read text " << text << std::endl;
336     }
337 }
338 
339 Text::~Text() {
340     if (isCopy && text) {
341         delete[] text;
342     }
343     text = nullptr;
344     isCopy = false;
345     len = 0;
346 }
347 
348 Log::Log(const size_t len)
349     : Text(len) {
350 }
351 
352 Log::Log(char *text)
353     : Text(text, false) {
354 }
355 
356 long Backend::CompilationUnit::Kernel::ndrange(void *argArray) {
357     if (compilationUnit->backend->config->traceCalls) {
358         std::cout << "dispatchContext(\"" << name << "\"){" << std::endl;
359     }
360     ArgSled argSled(static_cast<ArgArray_s *>(argArray));
361     auto *profilableQueue = dynamic_cast<ProfilableQueue *>(compilationUnit->backend->queue);
362     if (profilableQueue != nullptr) {
363         profilableQueue->marker(ProfilableQueue::EnterKernelDispatchBits, name);
364     }
365     if (compilationUnit->backend->config->trace) {
366         Sled::show(std::cout, argArray);
367     }
368       KernelArg *argDispatchContext  = argSled.arg(0);
369     DispatchContext *dispatchContext =  static_cast<DispatchContext *>(argDispatchContext->value.buffer.memorySegment);
370     // Now arg[0] is the dispatchContext so we will extract it immediately
371     for (int i = 1; i < argSled.argc(); i++) {
372 
373         KernelArg *arg = argSled.arg(i);
374    //      std::cout << "in argsled loop id = "<< i<< " and arg->idx = " << arg->idx << std::endl;
375         switch (arg->variant) {
376             case '&': {
377                 bool readAccessor  = arg->value.buffer.access == RO_BYTE || arg->value.buffer.access == RW_BYTE || arg->value.buffer.access == UNKNOWN_BYTE;
378                 if (compilationUnit->backend->config->trace) {
379                     std::cout << "arg[" << i << "] = " << std::hex << (int) (arg->value.buffer.access);
380                     switch (arg->value.buffer.access) {
381                         case RO_BYTE:
382                             std::cout << " RO";
383                             break;
384                         case WO_BYTE:
385                             std::cout << " WO";
386                             break;
387                         case RW_BYTE:
388                             std::cout << " RW";
389                             break;
390                     }
391                     std::cout << std::endl;
392                 }
393 
394                 BufferState *bufferState = BufferState::of(arg);
395 
396                 Buffer *buffer = compilationUnit->backend->getOrCreateBuffer(bufferState);
397 
398                 bool kernelReadsFromThisArg =  arg->value.buffer.access == RW_BYTE
399                                             || arg->value.buffer.access == RO_BYTE;
400 
401                 bool copyToDevice = readAccessor;
402                 if (!compilationUnit->backend->config->alwaysCopy) {
403                     copyToDevice = (bufferState->state == BufferState::NEW_STATE)
404                                      || ((bufferState->state == BufferState::HOST_OWNED));
405                 }
406 
407                 if (compilationUnit->backend->config->showWhy) {
408                     std::cout << "config.alwaysCopy=" << compilationUnit->backend->config->alwaysCopy
409                             << " | arg.RW=" << (arg->value.buffer.access == RW_BYTE)
410                             << " | arg.RO=" << (arg->value.buffer.access == RO_BYTE)
411                             << " | kernel.needsToRead=" << kernelReadsFromThisArg
412                             << " | Buffer state = " << BufferState::stateNames[bufferState->state]
413                             << " so "
414                             << std::endl;
415                 }
416                 if (copyToDevice) {
417                     compilationUnit->backend->queue->copyToDevice(buffer);
418                     bufferState->state = BufferState::DEVICE_OWNED;
419                     if (compilationUnit->backend->config->traceCopies) {
420                         std::cout << "copying arg " << arg->idx-1 << " host->device " << std::endl;
421                     }
422                 } else {
423                     if (compilationUnit->backend->config->traceSkippedCopies) {
424                         std::cout << "NOT copying arg " << arg->idx-1 << " host->device " << std::endl;
425                     }
426                 }
427                 setArg(arg, buffer);
428                 if (compilationUnit->backend->config->trace) {
429                     std::cout << "set buffer arg " << arg->idx-1 << std::endl;
430                 }
431                 break;
432             }
433             case 'B':
434             case 'S':
435             case 'C':
436             case 'I':
437             case 'F':
438             case 'J':
439             case 'D': {
440                 setArg(arg);
441                 if (compilationUnit->backend->config->trace) {
442                     std::cerr << "set " << arg->variant << " " << arg->idx-1 << std::endl;
443                 }
444                 break;
445             }
446             default: {
447                 std::cerr << "unexpected variant setting args in OpenCLKernel::dispatchContext " << (char) arg->variant <<
448                         std::endl;
449                 exit(1);
450             }
451         }
452     }
453 
454     if (dispatchContext == nullptr) {
455         std::cerr << "Looks like we received a kernel dispatch with zero args kernel='" << name << "'" << std::endl;
456         exit(1);
457     }
458 
459     if (compilationUnit->backend->config->trace) {
460         std::cout << "dispatchContext = <" << dispatchContext->gsx << "," << dispatchContext->gsy << "," << dispatchContext->gsz << ">" << std::endl;
461     }
462 
463     compilationUnit->backend->queue->dispatch(dispatchContext, this);
464 
465     for (int i = 1; i < argSled.argc(); i++) {
466         // note i above = 1... we never need to copy back the KernelContext fix this for DispatchContext
467         KernelArg *arg = argSled.arg(i);
468     //       std::cout << "out argsled loop id = "<< i<< " and arg->idx = " << arg->idx << std::endl;
469         if (arg->variant == '&') {
470             BufferState *bufferState = BufferState::of(arg);
471 
472             bool kernelWroteToThisArg = (arg->value.buffer.access == WO_BYTE) || (arg->value.buffer.access == RW_BYTE);
473             if (compilationUnit->backend->config->showWhy) {
474                 std::cout <<
475                         "config.alwaysCopy=" << compilationUnit->backend->config->alwaysCopy
476                         << " | arg.WO=" << (arg->value.buffer.access == WO_BYTE)
477                         << " | arg.RW=" << (arg->value.buffer.access == RW_BYTE)
478                         << " | kernel.wroteToThisArg=" << kernelWroteToThisArg
479                         << "Buffer state = " << BufferState::stateNames[bufferState->state]
480                         << " so "
481                         << std::endl;
482             }
483 
484             auto *buffer = static_cast<Buffer *>(bufferState->vendorPtr);
485             if (kernelWroteToThisArg && compilationUnit->backend->config->alwaysCopy) {
486                 compilationUnit->backend->queue->copyFromDevice(buffer);
487                 bufferState->state = BufferState::HOST_OWNED;
488                 if (compilationUnit->backend->config->traceCopies || compilationUnit->backend->config->traceEnqueues) {
489                     std::cout << "copying arg " << arg->idx-1 << " device->host " << std::endl;
490                 }
491             } else {
492                 if (compilationUnit->backend->config->traceSkippedCopies) {
493                     std::cout << "NOT copying arg " << arg->idx-1 << " device->host " << std::endl;
494                 }
495             }
496         }
497     }
498     if (profilableQueue != nullptr) {
499         profilableQueue->marker(Backend::ProfilableQueue::LeaveKernelDispatchBits, name);
500     }
501     compilationUnit->backend->queue->wait();
502     compilationUnit->backend->queue->release();
503     if (compilationUnit->backend->config->traceCalls) {
504         std::cout << "\"" << name << "\"}" << std::endl;
505     }
506     return 0;
507 }