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 }