1 /* Definition of available OpenCL devices.
2
3 Copyright (c) 2011 Universidad Rey Juan Carlos and
4 2012-2018 Pekka Jääskeläinen
5
6 Permission is hereby granted, free of charge, to any person obtaining a copy
7 of this software and associated documentation files (the "Software"), to deal
8 in the Software without restriction, including without limitation the rights
9 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 copies of the Software, and to permit persons to whom the Software is
11 furnished to do so, subject to the following conditions:
12
13 The above copyright notice and this permission notice shall be included in
14 all copies or substantial portions of the Software.
15
16 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 THE SOFTWARE.
23 */
24
25 #define _GNU_SOURCE
26
27 #include <string.h>
28 #include <ctype.h>
29
30 #ifdef __linux__
31 #include <limits.h>
32 #include <signal.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <sys/types.h>
36 #include <ucontext.h>
37 #endif
38
39 #ifndef _WIN32
40 # include <unistd.h>
41 #else
42 # include "vccompat.hpp"
43 #endif
44
45 #include "common.h"
46 #include "devices.h"
47 #include "pocl_cache.h"
48 #include "pocl_debug.h"
49 #include "pocl_runtime_config.h"
50 #include "pocl_shared.h"
51 #include "pocl_tracing.h"
52 #include "pocl_util.h"
53
54 #ifdef ENABLE_LLVM
55 #include "pocl_llvm.h"
56 #endif
57
58 #ifdef BUILD_BASIC
59 #include "basic/basic.h"
60 #endif
61 #ifdef BUILD_PTHREAD
62 #include "pthread/pocl-pthread.h"
63 #endif
64
65 #ifdef TCE_AVAILABLE
66 #include "tce/ttasim/ttasim.h"
67 #endif
68
69 #ifdef BUILD_HSA
70 #include "hsa/pocl-hsa.h"
71 #endif
72
73 #ifdef BUILD_CUDA
74 #include "cuda/pocl-cuda.h"
75 #endif
76
77 #if defined(BUILD_ACCEL)
78 #include "accel/accel.h"
79 #endif
80
81 #define MAX_DEV_NAME_LEN 64
82
83 #ifndef PATH_MAX
84 #define PATH_MAX 4096
85 #endif
86
87 #ifdef HAVE_DLFCN_H
88 #if defined(__APPLE__)
89 #define _DARWIN_C_SOURCE
90 #endif
91 #include <dlfcn.h>
92 #endif
93
94 /* the enabled devices */
95 static struct _cl_device_id* pocl_devices = NULL;
96 unsigned int pocl_num_devices = 0;
97
98 #ifdef ENABLE_LOADABLE_DRIVERS
99 #define INIT_DEV(ARG) NULL
100 #else
101 #define INIT_DEV(ARG) pocl_##ARG##_init_device_ops
102 #endif
103
104 /* Init function prototype */
105 typedef void (*init_device_ops)(struct pocl_device_ops*);
106
107 /* All init function for device operations available to pocl */
108 static init_device_ops pocl_devices_init_ops[] = {
109 #ifdef BUILD_BASIC
110 INIT_DEV (basic),
111 #endif
112 #ifdef BUILD_PTHREAD
113 INIT_DEV (pthread),
114 #endif
115 #ifdef TCE_AVAILABLE
116 INIT_DEV (ttasim),
117 #endif
118 #ifdef BUILD_HSA
119 INIT_DEV (hsa),
120 #endif
121 #ifdef BUILD_CUDA
122 INIT_DEV (cuda),
123 #endif
124 #ifdef BUILD_ACCEL
125 INIT_DEV (accel),
126 #endif
127 };
128
129 #define POCL_NUM_DEVICE_TYPES (sizeof(pocl_devices_init_ops) / sizeof((pocl_devices_init_ops)[0]))
130
131 char pocl_device_types[POCL_NUM_DEVICE_TYPES][30] = {
132 #ifdef BUILD_BASIC
133 "basic",
134 #endif
135 #ifdef BUILD_PTHREAD
136 "pthread",
137 #endif
138 #ifdef TCE_AVAILABLE
139 "ttasim",
140 #endif
141 #ifdef BUILD_HSA
142 "hsa",
143 #endif
144 #ifdef BUILD_CUDA
145 "cuda",
146 #endif
147 #ifdef BUILD_ACCEL
148 "accel",
149 #endif
150 };
151
152 static struct pocl_device_ops pocl_device_ops[POCL_NUM_DEVICE_TYPES];
153
154 extern pocl_lock_t pocl_runtime_config_lock;
155 extern pocl_lock_t pocl_context_handling_lock;
156
157 int pocl_offline_compile = 0;
158
159 // first setup
160 static unsigned first_init_done = 0;
161 static unsigned init_in_progress = 0;
162 static unsigned device_count[POCL_NUM_DEVICE_TYPES];
163
164 // after calling drivers uninit, we may have to re-init the devices.
165 static unsigned devices_active = 0;
166
167 static pocl_lock_t pocl_init_lock = POCL_LOCK_INITIALIZER;
168
169 #ifdef ENABLE_LOADABLE_DRIVERS
170
171 static void *pocl_device_handles[POCL_NUM_DEVICE_TYPES];
172
173 #ifndef _WIN32
174 #define POCL_PATH_SEPARATOR "/"
175 #else
176 #define POCL_PATH_SEPARATOR "\\"
177 #endif
178
179 static void
get_pocl_device_lib_path(char * result,char * device_name,int absolute_path)180 get_pocl_device_lib_path (char *result, char *device_name, int absolute_path)
181 {
182 Dl_info info;
183 if (absolute_path && dladdr ((void *)get_pocl_device_lib_path, &info))
184 {
185 char const *soname = info.dli_fname;
186 strcpy (result, soname);
187 char *last_slash = strrchr (result, POCL_PATH_SEPARATOR[0]);
188 *(++last_slash) = '\0';
189 if (strlen (result) > 0)
190 {
191 #ifdef ENABLE_POCL_BUILDING
192 if (pocl_get_bool_option ("POCL_BUILDING", 0))
193 {
194 strcat (result, "devices");
195 strcat (result, POCL_PATH_SEPARATOR);
196 if (strncmp(device_name, "ttasim", 6) == 0)
197 {
198 strcat (result, "tce");
199 }
200 else
201 {
202 strcat (result, device_name);
203 }
204 strcat (result, POCL_PATH_SEPARATOR);
205 }
206 else
207 #endif
208 {
209 strcat (result, POCL_INSTALL_PRIVATE_LIBDIR_REL);
210 }
211 strcat (result, POCL_PATH_SEPARATOR);
212 strcat (result, "libpocl-devices-");
213 strcat (result, device_name);
214 strcat (result, ".so");
215 }
216 }
217 else
218 {
219 strcat (result, "libpocl-devices-");
220 strcat (result, device_name);
221 strcat (result, ".so");
222 }
223 }
224 #endif
225
226 /**
227 * Get the number of specified devices from environment
228 */
pocl_device_get_env_count(const char * dev_type)229 int pocl_device_get_env_count(const char *dev_type)
230 {
231 const char *dev_env = getenv(POCL_DEVICES_ENV);
232 char *ptr, *saveptr = NULL, *tofree, *token;
233 unsigned int dev_count = 0;
234 if (dev_env == NULL)
235 {
236 return -1;
237 }
238 ptr = tofree = strdup(dev_env);
239 while ((token = strtok_r (ptr, " ", &saveptr)) != NULL)
240 {
241 if(strcmp(token, dev_type) == 0)
242 dev_count++;
243 ptr = NULL;
244 }
245 POCL_MEM_FREE(tofree);
246
247 return dev_count;
248 }
249
250 unsigned int
pocl_get_devices(cl_device_type device_type,cl_device_id * devices,unsigned int num_devices)251 pocl_get_devices (cl_device_type device_type, cl_device_id *devices,
252 unsigned int num_devices)
253 {
254 unsigned int i, dev_added = 0;
255
256 for (i = 0; i < pocl_num_devices; ++i)
257 {
258 if (!pocl_offline_compile && (pocl_devices[i].available == CL_FALSE))
259 continue;
260
261 if (device_type == CL_DEVICE_TYPE_DEFAULT)
262 {
263 devices[dev_added] = &pocl_devices[i];
264 ++dev_added;
265 break;
266 }
267
268 if (pocl_devices[i].type & device_type)
269 {
270 if (dev_added < num_devices)
271 {
272 devices[dev_added] = &pocl_devices[i];
273 ++dev_added;
274 }
275 else
276 {
277 break;
278 }
279 }
280 }
281 return dev_added;
282 }
283
284 unsigned int
pocl_get_device_type_count(cl_device_type device_type)285 pocl_get_device_type_count(cl_device_type device_type)
286 {
287 unsigned int count = 0;
288 unsigned int i;
289
290 for (i = 0; i < pocl_num_devices; ++i)
291 {
292 if (!pocl_offline_compile && (pocl_devices[i].available == CL_FALSE))
293 continue;
294
295 if (device_type == CL_DEVICE_TYPE_DEFAULT)
296 return 1;
297
298 if (pocl_devices[i].type & device_type)
299 {
300 ++count;
301 }
302 }
303
304 return count;
305 }
306
307
308 static inline void
str_toupper(char * out,const char * in)309 str_toupper(char *out, const char *in)
310 {
311 int i;
312
313 for (i = 0; in[i] != '\0'; i++)
314 out[i] = toupper(in[i]);
315 out[i] = '\0';
316 }
317
318 cl_int
pocl_uninit_devices()319 pocl_uninit_devices ()
320 {
321 cl_int retval = CL_SUCCESS;
322
323 POCL_LOCK (pocl_init_lock);
324 if ((!devices_active) || (pocl_num_devices == 0))
325 goto FINISH;
326
327 POCL_MSG_PRINT_GENERAL ("UNINIT all devices\n");
328
329 unsigned i, j, dev_index;
330
331 dev_index = 0;
332 cl_device_id d;
333 for (i = 0; i < POCL_NUM_DEVICE_TYPES; ++i)
334 {
335 if (pocl_devices_init_ops[i] == NULL)
336 continue;
337 assert (pocl_device_ops[i].init);
338 for (j = 0; j < device_count[i]; ++j)
339 {
340 d = &pocl_devices[dev_index];
341 if (d->available == 0)
342 continue;
343 if (d->ops->reinit == NULL || d->ops->uninit == NULL)
344 continue;
345 cl_int ret = d->ops->uninit (j, d);
346 if (ret != CL_SUCCESS)
347 {
348 retval = ret;
349 goto FINISH;
350 }
351 #ifdef ENABLE_LOADABLE_DRIVERS
352 if (pocl_device_handles[i] != NULL)
353 {
354 dlclose (pocl_device_handles[i]);
355 }
356 #endif
357 ++dev_index;
358 }
359 }
360
361 FINISH:
362 devices_active = 0;
363 POCL_UNLOCK (pocl_init_lock);
364
365 return retval;
366 }
367
368 static cl_int
pocl_reinit_devices()369 pocl_reinit_devices ()
370 {
371 assert (first_init_done);
372 cl_int retval = CL_SUCCESS;
373
374 if (devices_active)
375 return retval;
376
377 if (pocl_num_devices == 0)
378 return CL_DEVICE_NOT_FOUND;
379
380 POCL_MSG_WARN ("REINIT all devices\n");
381
382 unsigned i, j, dev_index;
383
384 dev_index = 0;
385 cl_device_id d;
386 /* Init infos for each probed devices */
387 for (i = 0; i < POCL_NUM_DEVICE_TYPES; ++i)
388 {
389 assert (pocl_device_ops[i].init);
390 for (j = 0; j < device_count[i]; ++j)
391 {
392 d = &pocl_devices[dev_index];
393 if (d->available == 0)
394 continue;
395 if (d->ops->reinit == NULL || d->ops->uninit == NULL)
396 continue;
397 cl_int ret = d->ops->reinit (j, d);
398 if (ret != CL_SUCCESS)
399 {
400 retval = ret;
401 goto FINISH;
402 }
403
404 ++dev_index;
405 }
406 }
407
408 FINISH:
409
410 devices_active = 1;
411 return retval;
412 }
413
414 cl_int
pocl_init_devices()415 pocl_init_devices ()
416 {
417 int errcode = CL_SUCCESS;
418
419 /* This is a workaround to a nasty problem with libhwloc: When
420 initializing basic, it calls libhwloc to query device info.
421 In case libhwloc has the OpenCL plugin installed, it initializes
422 it and it leads to initializing pocl again which leads to an
423 infinite loop. This only protects against recursive calls of
424 pocl_init_devices(), so must be done without pocl_init_lock held. */
425 if (init_in_progress)
426 return CL_SUCCESS; /* debatable, but what else can we do ? */
427
428 POCL_LOCK (pocl_init_lock);
429 init_in_progress = 1;
430
431 if (first_init_done)
432 {
433 if (!devices_active)
434 {
435 POCL_MSG_PRINT_GENERAL ("FIRST INIT done; REINIT all devices\n");
436 pocl_reinit_devices (); // TODO err check
437 }
438 errcode = pocl_num_devices ? CL_SUCCESS : CL_DEVICE_NOT_FOUND;
439 goto ERROR;
440 }
441 else
442 {
443 POCL_INIT_LOCK (pocl_runtime_config_lock);
444 POCL_INIT_LOCK (pocl_context_handling_lock);
445 }
446
447 /* first time initialization */
448 unsigned i, j, dev_index;
449 char env_name[1024];
450 char dev_name[MAX_DEV_NAME_LEN] = { 0 };
451
452 /* Set a global debug flag, so we don't have to call pocl_get_bool_option
453 * everytime we use the debug macros */
454 #ifdef POCL_DEBUG_MESSAGES
455 const char* debug = pocl_get_string_option ("POCL_DEBUG", "0");
456 pocl_debug_messages_setup (debug);
457 pocl_stderr_is_a_tty = isatty(fileno(stderr));
458 #endif
459
460 POCL_GOTO_ERROR_ON ((pocl_cache_init_topdir ()), CL_DEVICE_NOT_FOUND,
461 "Cache directory initialization failed");
462
463 pocl_event_tracing_init ();
464
465 #ifdef HAVE_SLEEP
466 int delay = pocl_get_int_option ("POCL_STARTUP_DELAY", 0);
467 if (delay > 0)
468 sleep (delay);
469 #endif
470
471
472 #ifdef __linux__
473
474 #ifdef ENABLE_HOST_CPU_DEVICES
475 if (pocl_get_bool_option ("POCL_SIGFPE_HANDLER", 1))
476 {
477 pocl_install_sigfpe_handler ();
478 }
479 #endif
480
481 if (pocl_get_bool_option ("POCL_SIGUSR2_HANDLER", 0))
482 {
483 pocl_install_sigusr2_handler ();
484 }
485 #endif
486
487 pocl_offline_compile = pocl_get_bool_option ("POCL_OFFLINE_COMPILE", 0);
488
489 /* Init operations */
490 for (i = 0; i < POCL_NUM_DEVICE_TYPES; ++i)
491 {
492 #ifdef ENABLE_LOADABLE_DRIVERS
493 if (pocl_devices_init_ops[i] == NULL)
494 {
495 char device_library[PATH_MAX] = "";
496 char init_device_ops_name[MAX_DEV_NAME_LEN + 21] = "";
497 get_pocl_device_lib_path (device_library, pocl_device_types[i], 1);
498 pocl_device_handles[i] = dlopen (device_library, RTLD_LAZY);
499 if (pocl_device_handles[i] == NULL)
500 {
501 POCL_MSG_WARN ("Loading %s failed: %s\n", device_library,
502 dlerror ());
503
504 /* Try again with just the *.so filename */
505 device_library[0] = 0;
506 get_pocl_device_lib_path (device_library,
507 pocl_device_types[i], 0);
508 pocl_device_handles[i] = dlopen (device_library, RTLD_LAZY);
509 if (pocl_device_handles[i] == NULL)
510 {
511 POCL_MSG_WARN ("Loading %s failed: %s\n", device_library,
512 dlerror ());
513 device_count[i] = 0;
514 continue;
515 }
516 else
517 {
518 POCL_MSG_WARN ("Fallback loading %s succeeded\n",
519 device_library);
520 }
521 }
522 strcat (init_device_ops_name, "pocl_");
523 strcat (init_device_ops_name, pocl_device_types[i]);
524 strcat (init_device_ops_name, "_init_device_ops");
525 pocl_devices_init_ops[i] = (init_device_ops)dlsym (
526 pocl_device_handles[i], init_device_ops_name);
527 if (pocl_devices_init_ops[i] != NULL)
528 {
529 pocl_devices_init_ops[i](&pocl_device_ops[i]);
530 }
531 else
532 {
533 POCL_MSG_ERR ("Loading symbol %s from %s failed: %s\n",
534 init_device_ops_name, device_library,
535 dlerror ());
536 device_count[i] = 0;
537 continue;
538 }
539 }
540 else
541 {
542 pocl_device_handles[i] = NULL;
543 }
544 #else
545 assert (pocl_devices_init_ops[i] != NULL);
546 #endif
547 pocl_devices_init_ops[i](&pocl_device_ops[i]);
548 assert(pocl_device_ops[i].device_name != NULL);
549
550 /* Probe and add the result to the number of probed devices */
551 assert(pocl_device_ops[i].probe);
552 device_count[i] = pocl_device_ops[i].probe(&pocl_device_ops[i]);
553 pocl_num_devices += device_count[i];
554 }
555
556 const char *dev_env = pocl_get_string_option (POCL_DEVICES_ENV, NULL);
557 POCL_GOTO_ERROR_ON ((pocl_num_devices == 0), CL_DEVICE_NOT_FOUND,
558 "no devices found. %s=%s\n", POCL_DEVICES_ENV, dev_env);
559
560 pocl_devices = (struct _cl_device_id*) calloc(pocl_num_devices, sizeof(struct _cl_device_id));
561 POCL_GOTO_ERROR_ON ((pocl_devices == NULL), CL_OUT_OF_HOST_MEMORY,
562 "Can not allocate memory for devices\n");
563
564 dev_index = 0;
565 /* Init infos for each probed devices */
566 for (i = 0; i < POCL_NUM_DEVICE_TYPES; ++i)
567 {
568 if (pocl_devices_init_ops[i] == NULL)
569 continue;
570 str_toupper (dev_name, pocl_device_ops[i].device_name);
571 assert(pocl_device_ops[i].init);
572 for (j = 0; j < device_count[i]; ++j)
573 {
574 cl_device_id dev = &pocl_devices[dev_index];
575 dev->ops = &pocl_device_ops[i];
576 dev->dev_id = dev_index;
577 /* The default value for the global memory space identifier is
578 the same as the device id. The device instance can then override
579 it to point to some other device's global memory id in case of
580 a shared global memory. */
581 dev->global_mem_id = dev_index;
582 POCL_INIT_OBJECT (dev);
583 dev->driver_version = POCL_VERSION_FULL;
584 if (dev->version == NULL)
585 dev->version = "OpenCL 2.0 pocl";
586 dev->short_name = strdup (dev->ops->device_name);
587
588 /* Check if there are device-specific parameters set in the
589 POCL_DEVICEn_PARAMETERS env. */
590 POCL_GOTO_ERROR_ON (
591 (snprintf (env_name, 1024, "POCL_%s%d_PARAMETERS", dev_name, j)
592 < 0),
593 CL_OUT_OF_HOST_MEMORY, "Unable to generate the env string.");
594 errcode = pocl_devices[dev_index].ops->init (
595 j, &pocl_devices[dev_index], getenv (env_name));
596 POCL_GOTO_ERROR_ON ((errcode != CL_SUCCESS), CL_DEVICE_NOT_AVAILABLE,
597 "Device %i / %s initialization failed!", j,
598 dev_name);
599
600 ++dev_index;
601 }
602 }
603
604 first_init_done = 1;
605 devices_active = 1;
606 ERROR:
607 init_in_progress = 0;
608 POCL_UNLOCK (pocl_init_lock);
609 return errcode;
610 }
611