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 #pragma once
 27 
 28 #include <iostream>
 29 #include <map>
 30 #include <vector>
 31 #include <cstdio>
 32 #include <cstring>
 33 #include <unistd.h>
 34 #include <sys/time.h>
 35 #include <iostream>
 36 #include <iomanip>
 37 #include <bitset>
 38 #include <stack>
 39 #include <functional>
 40 
 41 #include "config.h"
 42 
 43 #ifdef __APPLE__
 44 #define SNPRINTF snprintf
 45 #else
 46 #include <malloc.h>
 47 #if defined (_WIN32)
 48 #include "windows.h"
 49 #define SNPRINTF _snprintf
 50 #else
 51 #define SNPRINTF  snprintf
 52 #endif
 53 #endif
 54 
 55 #define ceil_div(x, y) ((x + y - 1) / y)
 56 namespace strutil {
 57     void replaceInPlace(std::string &subject, const std::string &search, const std::string &replace);
 58 
 59     bool endsWith(const std::string &str, const std::string &suffix);
 60 
 61     char *clone(char *name);
 62 };
 63 
 64 class Hex {
 65 public:
 66     static void ascii(std::ostream &s, char c);
 67 
 68     static void hex(std::ostream &s, char c);
 69 
 70     static void bytes(std::ostream &s, char *p, size_t len, std::function<void(std::ostream &)> prefix);
 71 };
 72 
 73 typedef char s8_t;
 74 typedef char byte;
 75 typedef char boolean;
 76 typedef char z1_t;
 77 typedef unsigned char u8_t;
 78 typedef short s16_t;
 79 typedef unsigned short u16_t;
 80 typedef unsigned int u32_t;
 81 typedef int s32_t;
 82 typedef float f32_t;
 83 typedef double f64_t;
 84 typedef long s64_t;
 85 typedef unsigned long u64_t;
 86 
 87 extern void hexdump(void *ptr, int buflen);
 88 
 89 class Text {
 90 public:
 91     size_t len;
 92     char *text;
 93     bool isCopy;
 94 
 95     Text(size_t len, char *text, bool isCopy);
 96 
 97     Text(char *text, bool isCopy);
 98 
 99     explicit Text(size_t len);
100 
101     void write(const std::string &filename) const;
102 
103     void read(const std::string &filename);
104 
105     virtual ~Text();
106 };
107 
108 class Log : public Text {
109 public:
110     explicit Log(size_t len);
111 
112     explicit Log(char *text);
113 
114     ~Log() override = default;
115 };
116 
117 #define UNKNOWN_BYTE 0
118 #define RO_BYTE (1<<1)
119 #define WO_BYTE (1<<2)
120 #define RW_BYTE (RO_BYTE|WO_BYTE)
121 
122 struct Buffer_s {
123     void *memorySegment; // Address of a Buffer/MemorySegment
124     long sizeInBytes;    // The size of the memory segment in bytes
125     u8_t access;         // see hat/buffer/ArgArray.java  UNKNOWN_BYTE=0, RO_BYTE =1<<1,WO_BYTE =1<<2,RW_BYTE =RO_BYTE|WO_BYTE;
126 };
127 
128 union Value_u {
129     boolean z1; // 'Z'
130     u8_t s8; // 'B'
131     u16_t u16; // 'C'
132     s16_t s16; // 'S'
133     u16_t x16; // 'C' or 'S'   // this is never used
134     s32_t s32; // 'I'
135     s32_t x32; // 'I' or 'F'   // this is never used
136     f32_t f32; // 'F'
137     f64_t f64; // 'D'
138     s64_t s64; // 'J'
139     s64_t x64; // 'D' or 'J'   // this is never used
140     Buffer_s buffer; // '&'
141 };
142 
143 struct KernelArg {
144     u32_t idx; // 0..argc
145     u8_t variant; // which variant 'I','Z','S','J','F', '&' implies Buffer/MemorySegment
146     u8_t pad8[8];
147     Value_u value;
148     u8_t pad6[6];
149 
150     size_t size() const {
151         size_t sz;
152         switch (variant) {
153             case 'I':
154             case 'F':
155                 sz = sizeof(u32_t);
156                 break;
157             case 'S':
158             case 'C':
159                 sz = sizeof(u16_t);
160                 break;
161             case 'D':
162             case 'J':
163                 return sizeof(u64_t);
164             case 'B':
165                 return sizeof(u8_t);
166             default:
167                 std::cerr << "Bad variant " << variant << "arg::size" << std::endl;
168                 exit(1);
169         }
170         return sz;
171     }
172 };
173 
174 struct BufferState {
175     static constexpr long MAGIC = 0x4a71facebffab175;   // This magic number is a delimiter to
176                                                         // check the length of the buffer as follows:
177                                                         // *(bufferStart+(bufferLen - sizeof(bufferState)) == MAGIC
178     static constexpr int NO_STATE = 0;
179     static constexpr int NEW_STATE = 1;
180     static constexpr int HOST_OWNED = 2;
181     static constexpr int DEVICE_OWNED = 3;
182     static constexpr int DEVICE_VALID_HOST_HAS_COPY = 4;
183     const static char *stateNames[]; // See below for out of line definition
184 
185     long magic1;
186     void *ptr;
187     long length;
188     int bits;
189     mutable int state;
190     void *vendorPtr;
191     long magic2;
192 
193     bool ok() const {
194         return ((magic1 == MAGIC) && (magic2 == MAGIC));
195     }
196 
197     void setState(int newState) {
198         state = newState;
199     }
200 
201     int getState() const {
202         return state;
203     }
204 
205     void dump(const char *msg) const {
206         if (ok()) {
207             printf("{%s,ptr:%016lx,length: %016lx,  state:%08x, vendorPtr:%016lx}\n", msg, (long) ptr, length, state,
208                    (long) vendorPtr);
209         } else {
210             printf("%s bad magic \n", msg);
211             printf("(magic1:%016lx,", magic1);
212             printf("{%s, ptr:%016lx, length: %016lx,  state:%08x, vendorPtr:%016lx}", msg, (long) ptr, length, state,
213                    (long) vendorPtr);
214             printf("magic2:%016lx)\n", magic2);
215         }
216     }
217 
218     static BufferState *of(void *ptr, size_t sizeInBytes) {
219         return reinterpret_cast<BufferState *>(static_cast<char *>(ptr) + sizeInBytes - sizeof(BufferState));
220     }
221 
222     static BufferState *of(const KernelArg *arg) {
223         // access?
224         BufferState *bufferState = of(
225             arg->value.buffer.memorySegment,
226             arg->value.buffer.sizeInBytes
227         );
228 
229         // Sanity check the buffers
230         // These sanity check finds errors passing memory segments which are not Buffers
231         if (bufferState->ptr != arg->value.buffer.memorySegment) {
232              std::cerr << "Error:  Unexpected initial state for buffer "
233                             << " idx=" << arg->idx
234                             << " bufferState->ptr=0x"<<std::hex<<((long)bufferState->ptr)<<std::dec
235                               << " bufferState->length=0x"<<std::hex<<((long)bufferState->length)<<std::dec
236                             << " arg->value.buffer.memorySegment=0x"<<std::hex<<((long)arg->value.buffer.memorySegment)<<std::dec
237                             << " state=" << bufferState->state << " '"
238                             << stateNames[bufferState->state] << "'"
239                             << " vendorPtr" << bufferState->vendorPtr << std::endl;
240             std::cerr << "The ptr (bufferState->ptr) does not appear to be a arg->value.buffer.memorySegment" << std::endl;
241 
242             // This is A bit brutal to stop the VM? We can throw an exception and handle it in the Java side?
243             std::exit(1);
244         }
245 
246         if ((bufferState->vendorPtr == nullptr) && (bufferState->state != NEW_STATE)) {
247             std::cerr << "Warning:  Unexpected initial state for buffer "
248                     << " idx=" << arg->idx
249                     << " state=" << bufferState->state << " '"
250                     << stateNames[bufferState->state] << "'"
251                     << " vendorPtr" << bufferState->vendorPtr << std::endl;
252             // This is A bit brutal to stop the VM? We can throw an exception and handle it in the Java side?
253             //std::exit(1);
254         }
255         // End of sanity checks
256         return bufferState;
257     }
258 };
259 
260 #ifdef shared_cpp
261 const char *BufferState::stateNames[] = {
262     "NO_STATE",
263     "NEW_STATE",
264     "HOST_OWNED",
265     "DEVICE_OWNED",
266     "DEVICE_VALID_HOST_HAS_COPY"
267 };
268 #endif
269 
270 struct ArgArray_s {
271     u32_t argc;
272     u8_t pad12[12];
273     KernelArg argv[0/*argc*/];
274 };
275 
276 class ArgSled {
277 private:
278     ArgArray_s *argArray;
279 
280 public:
281     int argc() const {
282         return argArray->argc;
283     }
284 
285     KernelArg *arg(int n) const {
286         KernelArg *a = (argArray->argv + n);
287         return a;
288     }
289 
290     void hexdumpArg(int n) const {
291         hexdump(arg(n), sizeof(KernelArg));
292     }
293 
294     void dumpArg(int n) const {
295         KernelArg *a = arg(n);
296         int idx = (int) a->idx;
297         std::cout << "arg[" << idx << "]";
298         char variant = (char) a->variant;
299         switch (variant) {
300             case 'F':
301                 std::cout << " f32 " << a->value.f32 << std::endl;
302                 break;
303             case 'I':
304                 std::cout << " s32 " << a->value.s32 << std::endl;
305                 break;
306             case 'D':
307                 std::cout << " f64 " << a->value.f64 << std::endl;
308                 break;
309             case 'J':
310                 std::cout << " s64 " << a->value.s64 << std::endl;
311                 break;
312             case 'C':
313                 std::cout << " u16 " << a->value.u16 << std::endl;
314                 break;
315             case 'S':
316                 std::cout << " s16 " << a->value.s32 << std::endl;
317                 break;
318             case 'Z':
319                 std::cout << " z1 " << a->value.z1 << std::endl;
320                 break;
321             case '&':
322                 std::cout << " buffer {"
323                         << " void *address = 0x" << std::hex << (long) a->value.buffer.memorySegment << std::dec
324                         << ", long bytesSize= 0x" << std::hex << (long) a->value.buffer.sizeInBytes << std::dec
325                         << ", char access= 0x" << std::hex << (unsigned char) a->value.buffer.access << std::dec
326                         << "}" << std::endl;
327                 break;
328             default:
329                 std::cout << (char) variant << std::endl;
330                 break;
331         }
332     }
333 
334     void *afterArgsPtrPtr() const {
335         KernelArg *a = arg(argc());
336         return (void *) a;
337     }
338 
339     int *schemaLenPtr() const {
340         int *schemaLenP = (int *) ((char *) afterArgsPtrPtr() /*+ sizeof(void *) */);
341         return schemaLenP;
342     }
343 
344     int schemaLen() const {
345         return *schemaLenPtr();
346     }
347 
348     char *schema() const {
349         int *schemaLenP = ((int *) ((char *) afterArgsPtrPtr() /*+ sizeof(void *)*/) + 1);
350         return (char *) schemaLenP;
351     }
352 
353     explicit ArgSled(ArgArray_s *argArray)
354         : argArray(argArray) {
355     }
356 };
357 
358 
359 class Timer {
360     struct timeval startTV, endTV;
361 
362 public:
363     unsigned long elapsed_us{};
364 
365     Timer(): startTV(), endTV() {
366     }
367 
368     void start() {
369         gettimeofday(&startTV, nullptr);
370     }
371 
372     unsigned long end() {
373         gettimeofday(&endTV, nullptr);
374         elapsed_us = (endTV.tv_sec - startTV.tv_sec) * 1000000; // sec to us
375         elapsed_us += (endTV.tv_usec - startTV.tv_usec);
376         return elapsed_us;
377     }
378 };
379 
380 
381 //extern void hexdump(void *ptr, int buflen);
382 
383 class Sled {
384 public:
385     static void show(std::ostream &out, void *argArray);
386 };
387 
388 class DispatchContext {
389 public:
390     int type;
391     int dimensions;
392     // global sizes
393     int gsx;
394     int gsy;
395     int gsz;
396     // local size
397     int lsx;
398     int lsy;
399     int lsz;
400     // Block sizes
401     int bsx;
402     int bsy;
403     int bsz;
404     // Tile Size
405     int tlx;
406     int tly;
407     int tlz;
408     // Warp sizes
409     int wsx;
410     int wsy;
411     int wsz;
412 };
413 /*
414 class KernelContext {
415 public:
416     int type;
417     // Dimensions of the kernel (1D, 2D or 3D)
418     int dimensions;
419     // global sizes
420     int gsx;
421     int gsy;
422     int gsz;
423     // local size
424     int lsx;
425     int lsy;
426     int lsz;
427     // Block sizes
428     int bsx;
429     int bsy;
430     int bsz;
431     // Tile Size
432     int tlx;
433     int tly;
434     int tlz;
435     // Warp sizes
436     int wsx;
437     int wsy;
438     int wsz;
439     // global index
440     int gix;
441     int giy;
442     int giz;
443     // local index
444     int lix;
445     int liy;
446     int liz;
447     // Group index
448     int bix;
449     int biy;
450     int biz;
451 }; */
452 
453 class Backend {
454 public:
455     class Config final : public BasicConfig {
456     public:
457         explicit Config(int mode);
458 
459         ~Config() override;
460     };
461 
462     class Buffer {
463     public:
464         Backend *backend;
465         BufferState *bufferState;
466 
467         Buffer(Backend *backend, BufferState *bufferState)
468             : backend(backend), bufferState(bufferState) {
469         }
470 
471         virtual ~Buffer() = default;
472     };
473 
474     class CompilationUnit {
475     public:
476         class Kernel {
477         public:
478             char *name;
479 
480             CompilationUnit *compilationUnit;
481 
482             virtual bool setArg(KernelArg *arg, Buffer *openCLBuffer) = 0;
483 
484             virtual bool setArg(KernelArg *arg) = 0;
485 
486             virtual long ndrange(void *argArray) final;
487 
488             Kernel(CompilationUnit *compilationUnit, char *name)
489                 : name(strutil::clone(name)), compilationUnit(compilationUnit) {
490             }
491 
492             virtual ~Kernel() {
493                 delete[] name;
494             }
495         };
496 
497     public:
498         Backend *backend;
499         char *src;
500         char *log;
501         bool ok;
502 
503         virtual Kernel *getKernel(int nameLen, char *name) = 0;
504 
505         virtual bool compilationUnitOK() final {
506             return ok;
507         }
508 
509         CompilationUnit(Backend *backend, char *src, char *log, bool ok)
510             : backend(backend), src(src), log(log), ok(ok) {
511         }
512 
513         virtual ~CompilationUnit() {
514             delete[] src;
515             delete[] log;
516         };
517     };
518 
519     class Queue {
520     public:
521         Backend *backend;
522 
523         explicit Queue(Backend *backend);
524 
525         virtual void wait() = 0;
526 
527         virtual void release() = 0;
528 
529         virtual void computeStart() = 0;
530 
531         virtual void computeEnd() = 0;
532 
533         virtual void copyToDevice(Buffer *buffer) =0;
534 
535         virtual void copyFromDevice(Buffer *buffer) =0;
536 
537         virtual void dispatch(DispatchContext *dispatchContext, CompilationUnit::Kernel *kernel) = 0;
538 
539         virtual ~Queue();
540     };
541 
542     class ProfilableQueue : public Queue {
543     public:
544         static constexpr int START_BIT_IDX = 20;
545         static constexpr int CopyToDeviceBits = 1 << START_BIT_IDX;
546         static constexpr int CopyFromDeviceBits = 1 << 21;
547         static constexpr int NDRangeBits = 1 << 22;
548         static constexpr int StartComputeBits = 1 << 23;
549         static constexpr int EndComputeBits = 1 << 24;
550         static constexpr int EnterKernelDispatchBits = 1 << 25;
551         static constexpr int LeaveKernelDispatchBits = 1 << 26;
552         static constexpr int HasConstCharPtrArgBits = 1 << 27;
553         static constexpr int hasIntArgBits = 1 << 28;
554         static constexpr int END_BIT_IDX = 27;
555 
556         size_t eventMax;
557         size_t eventc;
558         int *eventInfoBits;
559         const char **eventInfoConstCharPtrArgs;
560 
561         virtual void showEvents(int width) = 0;
562 
563         virtual void inc(int bits) = 0;
564 
565         virtual void inc(int bits, const char *arg) = 0;
566 
567         virtual void marker(int bits) = 0;
568 
569         virtual void marker(int bits, const char *arg) = 0;
570 
571 
572         virtual void markAsStartComputeAndInc() = 0;
573 
574         virtual void markAsEndComputeAndInc() = 0;
575 
576         virtual void markAsEnterKernelDispatchAndInc() = 0;
577 
578         virtual void markAsLeaveKernelDispatchAndInc() = 0;
579 
580         ProfilableQueue(Backend *backend, int eventMax)
581             : Queue(backend),
582               eventMax(eventMax),
583               eventInfoBits(new int[eventMax]),
584               eventInfoConstCharPtrArgs(new const char *[eventMax]),
585               eventc(0) {
586         }
587 
588         ~ProfilableQueue() override {
589             delete[]eventInfoBits;
590             delete[]eventInfoConstCharPtrArgs;
591         }
592     };
593 
594     Config *config;
595     Queue *queue;
596 
597     Backend(Config *config, Queue *queue)
598         : config(config), queue(queue) {
599     }
600 
601     virtual Buffer *getOrCreateBuffer(BufferState *bufferState) = 0;
602 
603     virtual void shortDeviceInfo() = 0;
604 
605     virtual void showDeviceInfo() = 0;
606 
607     virtual void computeStart() = 0;
608 
609     virtual void computeEnd() = 0;
610 
611     virtual CompilationUnit *compile(int len, char *source) = 0;
612 
613     virtual bool getBufferFromDeviceIfDirty(void *memorySegment, long memorySegmentLength) = 0;
614 
615     virtual ~Backend() = default;
616 };
617 
618 template<typename T>
619 T *bufferOf(const char *name) {
620     size_t lenIncludingBufferState = sizeof(T);
621     size_t lenExcludingBufferState = lenIncludingBufferState - sizeof(BufferState);
622     T *buffer = reinterpret_cast<T *>(new unsigned char[lenIncludingBufferState]);
623     auto *bufferState = reinterpret_cast<BufferState *>(reinterpret_cast<char *>(buffer) + lenExcludingBufferState);
624     bufferState->magic1 = bufferState->magic2 = BufferState::MAGIC;
625     bufferState->ptr = buffer;
626     bufferState->length = sizeof(T) - sizeof(BufferState);
627     bufferState->state = BufferState::NEW_STATE;
628     bufferState->vendorPtr = nullptr;
629     bufferState->dump(name);
630     return buffer;
631 }