]> git.ipfire.org Git - thirdparty/gcc.git/blame - liboffloadmic/plugin/libgomp-plugin-intelmic.cpp
gcc/
[thirdparty/gcc.git] / liboffloadmic / plugin / libgomp-plugin-intelmic.cpp
CommitLineData
30cc6b51 1/* Plugin for offload execution on Intel MIC devices.
2
5f74ee59 3 Copyright (C) 2014-2015 Free Software Foundation, Inc.
30cc6b51 4
5 Contributed by Ilya Verbin <ilya.verbin@intel.com>.
6
c35c9a62 7 This file is part of the GNU Offloading and Multi Processing Library
8 (libgomp).
30cc6b51 9
10 Libgomp is free software; you can redistribute it and/or modify it
11 under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 3, or (at your option)
13 any later version.
14
15 Libgomp is distributed in the hope that it will be useful, but WITHOUT ANY
16 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17 FOR A PARTICULAR PURPOSE. See the GNU General Public License for
18 more details.
19
20 Under Section 7 of GPL version 3, you are granted additional
21 permissions described in the GCC Runtime Library Exception, version
22 3.1, as published by the Free Software Foundation.
23
24 You should have received a copy of the GNU General Public License and
25 a copy of the GCC Runtime Library Exception along with this program;
26 see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
27 <http://www.gnu.org/licenses/>. */
28
29/* Host side part of a libgomp plugin. */
30
31#include <stdint.h>
32#include <stdio.h>
33#include <stdlib.h>
34#include <string.h>
35#include <utility>
36#include <vector>
0d8c703d 37#include <map>
ca4c3545 38#include "libgomp-plugin.h"
30cc6b51 39#include "compiler_if_host.h"
40#include "main_target_image.h"
5f74ee59 41#include "gomp-constants.h"
30cc6b51 42
43#define LD_LIBRARY_PATH_ENV "LD_LIBRARY_PATH"
44#define MIC_LD_LIBRARY_PATH_ENV "MIC_LD_LIBRARY_PATH"
b30bdf28 45#define OFFLOAD_ACTIVE_WAIT_ENV "OFFLOAD_ACTIVE_WAIT"
30cc6b51 46
47#ifdef DEBUG
48#define TRACE(...) \
49{ \
50fprintf (stderr, "HOST:\t%s:%s ", __FILE__, __FUNCTION__); \
51fprintf (stderr, __VA_ARGS__); \
52fprintf (stderr, "\n"); \
53}
54#else
55#define TRACE { }
56#endif
57
58
0d8c703d 59/* Start/end addresses of functions and global variables on a device. */
60typedef std::vector<addr_pair> AddrVect;
61
62/* Addresses for one image and all devices. */
63typedef std::vector<AddrVect> DevAddrVect;
64
65/* Addresses for all images and all devices. */
70046055 66typedef std::map<const void *, DevAddrVect> ImgDevAddrMap;
0d8c703d 67
68
69/* Total number of available devices. */
70static int num_devices;
71
72/* Total number of shared libraries with offloading to Intel MIC. */
73static int num_images;
74
75/* Two dimensional array: one key is a pointer to image,
76 second key is number of device. Contains a vector of pointer pairs. */
77static ImgDevAddrMap *address_table;
78
79/* Thread-safe registration of the main image. */
80static pthread_once_t main_image_is_registered = PTHREAD_ONCE_INIT;
81
30cc6b51 82static VarDesc vd_host2tgt = {
83 { 1, 1 }, /* dst, src */
84 { 1, 0 }, /* in, out */
85 1, /* alloc_if */
86 1, /* free_if */
87 4, /* align */
88 0, /* mic_offset */
89 { 0, 0, 0, 0, 0, 0, 0, 0 }, /* is_static, is_static_dstn, has_length,
90 is_stack_buf, sink_addr, alloc_disp,
91 is_noncont_src, is_noncont_dst */
92 0, /* offset */
93 0, /* size */
94 1, /* count */
95 0, /* alloc */
96 0, /* into */
97 0 /* ptr */
98};
99
100static VarDesc vd_tgt2host = {
101 { 1, 1 }, /* dst, src */
102 { 0, 1 }, /* in, out */
103 1, /* alloc_if */
104 1, /* free_if */
105 4, /* align */
106 0, /* mic_offset */
107 { 0, 0, 0, 0, 0, 0, 0, 0 }, /* is_static, is_static_dstn, has_length,
108 is_stack_buf, sink_addr, alloc_disp,
109 is_noncont_src, is_noncont_dst */
110 0, /* offset */
111 0, /* size */
112 1, /* count */
113 0, /* alloc */
114 0, /* into */
115 0 /* ptr */
116};
117
118
30cc6b51 119__attribute__((constructor))
120static void
0d8c703d 121init (void)
30cc6b51 122{
123 const char *ld_lib_path = getenv (LD_LIBRARY_PATH_ENV);
124 const char *mic_lib_path = getenv (MIC_LD_LIBRARY_PATH_ENV);
b30bdf28 125 const char *active_wait = getenv (OFFLOAD_ACTIVE_WAIT_ENV);
126
127 /* Disable active wait by default to avoid useless CPU usage. */
128 if (!active_wait)
129 setenv (OFFLOAD_ACTIVE_WAIT_ENV, "0", 0);
30cc6b51 130
131 if (!ld_lib_path)
0d8c703d 132 goto out;
30cc6b51 133
b30bdf28 134 /* Add path specified in LD_LIBRARY_PATH to MIC_LD_LIBRARY_PATH, which is
135 required by liboffloadmic. */
30cc6b51 136 if (!mic_lib_path)
137 setenv (MIC_LD_LIBRARY_PATH_ENV, ld_lib_path, 1);
138 else
139 {
140 size_t len = strlen (mic_lib_path) + strlen (ld_lib_path) + 2;
141 bool use_alloca = len <= 2048;
142 char *mic_lib_path_new = (char *) (use_alloca ? alloca (len)
143 : malloc (len));
144 if (!mic_lib_path_new)
145 {
146 fprintf (stderr, "%s: Can't allocate memory\n", __FILE__);
147 exit (1);
148 }
149
150 sprintf (mic_lib_path_new, "%s:%s", mic_lib_path, ld_lib_path);
151 setenv (MIC_LD_LIBRARY_PATH_ENV, mic_lib_path_new, 1);
152
153 if (!use_alloca)
154 free (mic_lib_path_new);
155 }
0d8c703d 156
157out:
158 address_table = new ImgDevAddrMap;
159 num_devices = _Offload_number_of_devices ();
30cc6b51 160}
161
ca4c3545 162extern "C" const char *
163GOMP_OFFLOAD_get_name (void)
164{
165 const char *res = "intelmic";
166 TRACE ("(): return %s", res);
167 return res;
168}
169
170extern "C" unsigned int
171GOMP_OFFLOAD_get_caps (void)
172{
173 unsigned int res = GOMP_OFFLOAD_CAP_OPENMP_400;
174 TRACE ("(): return %x", res);
175 return res;
176}
177
30cc6b51 178extern "C" enum offload_target_type
179GOMP_OFFLOAD_get_type (void)
180{
181 enum offload_target_type res = OFFLOAD_TARGET_TYPE_INTEL_MIC;
182 TRACE ("(): return %d", res);
183 return res;
184}
185
186extern "C" int
187GOMP_OFFLOAD_get_num_devices (void)
188{
0d8c703d 189 TRACE ("(): return %d", num_devices);
190 return num_devices;
30cc6b51 191}
192
193static void
194offload (const char *file, uint64_t line, int device, const char *name,
195 int num_vars, VarDesc *vars, VarDesc2 *vars2)
196{
197 OFFLOAD ofld = __offload_target_acquire1 (&device, file, line);
198 if (ofld)
199 __offload_offload1 (ofld, name, 0, num_vars, vars, vars2, 0, NULL, NULL);
200 else
201 {
202 fprintf (stderr, "%s:%d: Offload target acquire failed\n", file, line);
203 exit (1);
204 }
205}
206
207static void
208register_main_image ()
209{
210 __offload_register_image (&main_target_image);
211}
212
0d8c703d 213/* liboffloadmic loads and runs offload_target_main on all available devices
214 during a first call to offload (). */
30cc6b51 215extern "C" void
216GOMP_OFFLOAD_init_device (int device)
217{
218 TRACE ("");
219 pthread_once (&main_image_is_registered, register_main_image);
220 offload (__FILE__, __LINE__, device, "__offload_target_init_proc", 0,
221 NULL, NULL);
222}
223
ca4c3545 224extern "C" void
225GOMP_OFFLOAD_fini_device (int device)
226{
227 TRACE ("");
228 /* Unreachable for GOMP_OFFLOAD_CAP_OPENMP_400. */
229 abort ();
230}
231
30cc6b51 232static void
233get_target_table (int device, int &num_funcs, int &num_vars, void **&table)
234{
235 VarDesc vd1[2] = { vd_tgt2host, vd_tgt2host };
236 vd1[0].ptr = &num_funcs;
237 vd1[0].size = sizeof (num_funcs);
238 vd1[1].ptr = &num_vars;
239 vd1[1].size = sizeof (num_vars);
240 VarDesc2 vd1g[2] = { { "num_funcs", 0 }, { "num_vars", 0 } };
241
242 offload (__FILE__, __LINE__, device, "__offload_target_table_p1", 2,
243 vd1, vd1g);
244
245 int table_size = num_funcs + 2 * num_vars;
246 if (table_size > 0)
247 {
248 table = new void * [table_size];
249
250 VarDesc vd2;
251 vd2 = vd_tgt2host;
252 vd2.ptr = table;
253 vd2.size = table_size * sizeof (void *);
254 VarDesc2 vd2g = { "table", 0 };
255
256 offload (__FILE__, __LINE__, device, "__offload_target_table_p2", 1,
257 &vd2, &vd2g);
258 }
259}
260
0d8c703d 261/* Offload TARGET_IMAGE to all available devices and fill address_table with
262 corresponding target addresses. */
263
30cc6b51 264static void
70046055 265offload_image (const void *target_image)
30cc6b51 266{
267 struct TargetImage {
268 int64_t size;
269 /* 10 characters is enough for max int value. */
270 char name[sizeof ("lib0000000000.so")];
271 char data[];
272 } __attribute__ ((packed));
273
0d8c703d 274 void *image_start = ((void **) target_image)[0];
275 void *image_end = ((void **) target_image)[1];
30cc6b51 276
0d8c703d 277 TRACE ("(target_image = %p { %p, %p })",
278 target_image, image_start, image_end);
30cc6b51 279
280 int64_t image_size = (uintptr_t) image_end - (uintptr_t) image_start;
281 TargetImage *image
282 = (TargetImage *) malloc (sizeof (int64_t) + sizeof ("lib0000000000.so")
283 + image_size);
284 if (!image)
285 {
286 fprintf (stderr, "%s: Can't allocate memory\n", __FILE__);
287 exit (1);
288 }
289
290 image->size = image_size;
0d8c703d 291 sprintf (image->name, "lib%010d.so", num_images++);
30cc6b51 292 memcpy (image->data, image_start, image->size);
293
294 TRACE ("() __offload_register_image %s { %p, %d }",
295 image->name, image_start, image->size);
296 __offload_register_image (image);
297
0d8c703d 298 /* Receive tables for target_image from all devices. */
299 DevAddrVect dev_table;
300 for (int dev = 0; dev < num_devices; dev++)
30cc6b51 301 {
0d8c703d 302 int num_funcs = 0;
303 int num_vars = 0;
304 void **table = NULL;
30cc6b51 305
0d8c703d 306 get_target_table (dev, num_funcs, num_vars, table);
30cc6b51 307
0d8c703d 308 AddrVect curr_dev_table;
30cc6b51 309
0d8c703d 310 for (int i = 0; i < num_funcs; i++)
311 {
312 addr_pair tgt_addr;
313 tgt_addr.start = (uintptr_t) table[i];
314 tgt_addr.end = tgt_addr.start + 1;
315 TRACE ("() func %d:\t0x%llx..0x%llx", i,
316 tgt_addr.start, tgt_addr.end);
317 curr_dev_table.push_back (tgt_addr);
318 }
30cc6b51 319
0d8c703d 320 for (int i = 0; i < num_vars; i++)
321 {
322 addr_pair tgt_addr;
323 tgt_addr.start = (uintptr_t) table[num_funcs+i*2];
324 tgt_addr.end = tgt_addr.start + (uintptr_t) table[num_funcs+i*2+1];
325 TRACE ("() var %d:\t0x%llx..0x%llx", i, tgt_addr.start, tgt_addr.end);
326 curr_dev_table.push_back (tgt_addr);
327 }
30cc6b51 328
0d8c703d 329 dev_table.push_back (curr_dev_table);
30cc6b51 330 }
331
0d8c703d 332 address_table->insert (std::make_pair (target_image, dev_table));
333
334 free (image);
30cc6b51 335}
336
d3d8e632 337/* Return the libgomp version number we're compatible with. There is
338 no requirement for cross-version compatibility. */
339
340extern "C" unsigned
341GOMP_OFFLOAD_version (void)
342{
343 return GOMP_VERSION;
344}
345
30cc6b51 346extern "C" int
d3d8e632 347GOMP_OFFLOAD_load_image (int device, const unsigned version,
348 void *target_image, addr_pair **result)
30cc6b51 349{
0d8c703d 350 TRACE ("(device = %d, target_image = %p)", device, target_image);
30cc6b51 351
d3d8e632 352 if (GOMP_VERSION_DEV (version) > GOMP_VERSION_INTEL_MIC)
353 GOMP_PLUGIN_fatal ("Offload data incompatible with intelmic plugin"
354 " (expected %u, received %u)",
355 GOMP_VERSION_INTEL_MIC, GOMP_VERSION_DEV (version));
356
0d8c703d 357 /* If target_image is already present in address_table, then there is no need
358 to offload it. */
359 if (address_table->count (target_image) == 0)
360 offload_image (target_image);
30cc6b51 361
0d8c703d 362 AddrVect *curr_dev_table = &(*address_table)[target_image][device];
363 int table_size = curr_dev_table->size ();
364 addr_pair *table = (addr_pair *) malloc (table_size * sizeof (addr_pair));
365 if (table == NULL)
366 {
367 fprintf (stderr, "%s: Can't allocate memory\n", __FILE__);
368 exit (1);
369 }
30cc6b51 370
0d8c703d 371 std::copy (curr_dev_table->begin (), curr_dev_table->end (), table);
372 *result = table;
30cc6b51 373 return table_size;
374}
375
0d8c703d 376extern "C" void
d3d8e632 377GOMP_OFFLOAD_unload_image (int device, unsigned version,
378 const void *target_image)
0d8c703d 379{
d3d8e632 380 if (GOMP_VERSION_DEV (version) > GOMP_VERSION_INTEL_MIC)
381 return;
382
0d8c703d 383 TRACE ("(device = %d, target_image = %p)", device, target_image);
384
385 /* TODO: Currently liboffloadmic doesn't support __offload_unregister_image
386 for libraries. */
387
388 address_table->erase (target_image);
389}
390
30cc6b51 391extern "C" void *
392GOMP_OFFLOAD_alloc (int device, size_t size)
393{
394 TRACE ("(size = %d)", size);
395
396 void *tgt_ptr;
397 VarDesc vd1[2] = { vd_host2tgt, vd_tgt2host };
398 vd1[0].ptr = &size;
399 vd1[0].size = sizeof (size);
400 vd1[1].ptr = &tgt_ptr;
401 vd1[1].size = sizeof (void *);
402 VarDesc2 vd1g[2] = { { "size", 0 }, { "tgt_ptr", 0 } };
403
404 offload (__FILE__, __LINE__, device, "__offload_target_alloc", 2, vd1, vd1g);
405
406 return tgt_ptr;
407}
408
409extern "C" void
410GOMP_OFFLOAD_free (int device, void *tgt_ptr)
411{
412 TRACE ("(tgt_ptr = %p)", tgt_ptr);
413
414 VarDesc vd1 = vd_host2tgt;
415 vd1.ptr = &tgt_ptr;
416 vd1.size = sizeof (void *);
417 VarDesc2 vd1g = { "tgt_ptr", 0 };
418
419 offload (__FILE__, __LINE__, device, "__offload_target_free", 1, &vd1, &vd1g);
420}
421
422extern "C" void *
423GOMP_OFFLOAD_host2dev (int device, void *tgt_ptr, const void *host_ptr,
424 size_t size)
425{
426 TRACE ("(tgt_ptr = %p, host_ptr = %p, size = %d)", tgt_ptr, host_ptr, size);
427 if (!size)
428 return tgt_ptr;
429
430 VarDesc vd1[2] = { vd_host2tgt, vd_host2tgt };
431 vd1[0].ptr = &tgt_ptr;
432 vd1[0].size = sizeof (void *);
433 vd1[1].ptr = &size;
434 vd1[1].size = sizeof (size);
435 VarDesc2 vd1g[2] = { { "tgt_ptr", 0 }, { "size", 0 } };
436
437 offload (__FILE__, __LINE__, device, "__offload_target_host2tgt_p1", 2,
438 vd1, vd1g);
439
440 VarDesc vd2 = vd_host2tgt;
441 vd2.ptr = (void *) host_ptr;
442 vd2.size = size;
443 VarDesc2 vd2g = { "var", 0 };
444
445 offload (__FILE__, __LINE__, device, "__offload_target_host2tgt_p2", 1,
446 &vd2, &vd2g);
447
448 return tgt_ptr;
449}
450
451extern "C" void *
452GOMP_OFFLOAD_dev2host (int device, void *host_ptr, const void *tgt_ptr,
453 size_t size)
454{
455 TRACE ("(host_ptr = %p, tgt_ptr = %p, size = %d)", host_ptr, tgt_ptr, size);
456 if (!size)
457 return host_ptr;
458
459 VarDesc vd1[2] = { vd_host2tgt, vd_host2tgt };
460 vd1[0].ptr = &tgt_ptr;
461 vd1[0].size = sizeof (void *);
462 vd1[1].ptr = &size;
463 vd1[1].size = sizeof (size);
464 VarDesc2 vd1g[2] = { { "tgt_ptr", 0 }, { "size", 0 } };
465
466 offload (__FILE__, __LINE__, device, "__offload_target_tgt2host_p1", 2,
467 vd1, vd1g);
468
469 VarDesc vd2 = vd_tgt2host;
470 vd2.ptr = (void *) host_ptr;
471 vd2.size = size;
472 VarDesc2 vd2g = { "var", 0 };
473
474 offload (__FILE__, __LINE__, device, "__offload_target_tgt2host_p2", 1,
475 &vd2, &vd2g);
476
477 return host_ptr;
478}
479
43895be5 480extern "C" void *
481GOMP_OFFLOAD_dev2dev (int device, void *dst_ptr, const void *src_ptr,
482 size_t size)
483{
484 TRACE ("(dst_ptr = %p, src_ptr = %p, size = %d)", dst_ptr, src_ptr, size);
485 if (!size)
486 return dst_ptr;
487
488 VarDesc vd1[3] = { vd_host2tgt, vd_host2tgt, vd_host2tgt };
489 vd1[0].ptr = &dst_ptr;
490 vd1[0].size = sizeof (void *);
491 vd1[1].ptr = &src_ptr;
492 vd1[1].size = sizeof (void *);
493 vd1[2].ptr = &size;
494 vd1[2].size = sizeof (size);
495 VarDesc2 vd1g[3] = { { "dst_ptr", 0 }, { "src_ptr", 0 }, { "size", 0 } };
496
497 offload (__FILE__, __LINE__, device, "__offload_target_tgt2tgt", 3, vd1,
498 vd1g);
499
500 return dst_ptr;
501}
502
30cc6b51 503extern "C" void
504GOMP_OFFLOAD_run (int device, void *tgt_fn, void *tgt_vars)
505{
506 TRACE ("(tgt_fn = %p, tgt_vars = %p)", tgt_fn, tgt_vars);
507
508 VarDesc vd1[2] = { vd_host2tgt, vd_host2tgt };
509 vd1[0].ptr = &tgt_fn;
510 vd1[0].size = sizeof (void *);
511 vd1[1].ptr = &tgt_vars;
512 vd1[1].size = sizeof (void *);
513 VarDesc2 vd1g[2] = { { "tgt_fn", 0 }, { "tgt_vars", 0 } };
514
515 offload (__FILE__, __LINE__, device, "__offload_target_run", 2, vd1, vd1g);
516}