* sv.po: Update.
[official-gcc.git] / liboffloadmic / plugin / libgomp-plugin-intelmic.cpp
blob57accb441d127951c3a2b25fa218af33ec2f9a9e
1 /* Plugin for offload execution on Intel MIC devices.
3 Copyright (C) 2014-2015 Free Software Foundation, Inc.
5 Contributed by Ilya Verbin <ilya.verbin@intel.com>.
7 This file is part of the GNU Offloading and Multi Processing Library
8 (libgomp).
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.
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.
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.
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/>. */
29 /* Host side part of a libgomp plugin. */
31 #include <stdint.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <utility>
36 #include <vector>
37 #include <map>
38 #include "libgomp-plugin.h"
39 #include "compiler_if_host.h"
40 #include "main_target_image.h"
41 #include "gomp-constants.h"
43 #define LD_LIBRARY_PATH_ENV "LD_LIBRARY_PATH"
44 #define MIC_LD_LIBRARY_PATH_ENV "MIC_LD_LIBRARY_PATH"
45 #define OFFLOAD_ACTIVE_WAIT_ENV "OFFLOAD_ACTIVE_WAIT"
47 #ifdef DEBUG
48 #define TRACE(...) \
49 { \
50 fprintf (stderr, "HOST:\t%s:%s ", __FILE__, __FUNCTION__); \
51 fprintf (stderr, __VA_ARGS__); \
52 fprintf (stderr, "\n"); \
54 #else
55 #define TRACE { }
56 #endif
59 /* Start/end addresses of functions and global variables on a device. */
60 typedef std::vector<addr_pair> AddrVect;
62 /* Addresses for one image and all devices. */
63 typedef std::vector<AddrVect> DevAddrVect;
65 /* Addresses for all images and all devices. */
66 typedef std::map<const void *, DevAddrVect> ImgDevAddrMap;
68 /* Image descriptor needed by __offload_[un]register_image. */
69 struct TargetImageDesc {
70 int64_t size;
71 /* 10 characters is enough for max int value. */
72 char name[sizeof ("lib0000000000.so")];
73 char data[];
76 /* Image descriptors, indexed by a pointer obtained from libgomp. */
77 typedef std::map<const void *, TargetImageDesc *> ImgDescMap;
80 /* Total number of available devices. */
81 static int num_devices;
83 /* Total number of shared libraries with offloading to Intel MIC. */
84 static int num_images;
86 /* Two dimensional array: one key is a pointer to image,
87 second key is number of device. Contains a vector of pointer pairs. */
88 static ImgDevAddrMap *address_table;
90 /* Descriptors of all images, registered in liboffloadmic. */
91 static ImgDescMap *image_descriptors;
93 /* Thread-safe registration of the main image. */
94 static pthread_once_t main_image_is_registered = PTHREAD_ONCE_INIT;
96 static VarDesc vd_host2tgt = {
97 { 1, 1 }, /* dst, src */
98 { 1, 0 }, /* in, out */
99 1, /* alloc_if */
100 1, /* free_if */
101 4, /* align */
102 0, /* mic_offset */
103 { 0, 0, 0, 0, 0, 0, 0, 0 }, /* is_static, is_static_dstn, has_length,
104 is_stack_buf, sink_addr, alloc_disp,
105 is_noncont_src, is_noncont_dst */
106 0, /* offset */
107 0, /* size */
108 1, /* count */
109 0, /* alloc */
110 0, /* into */
111 0 /* ptr */
114 static VarDesc vd_tgt2host = {
115 { 1, 1 }, /* dst, src */
116 { 0, 1 }, /* in, out */
117 1, /* alloc_if */
118 1, /* free_if */
119 4, /* align */
120 0, /* mic_offset */
121 { 0, 0, 0, 0, 0, 0, 0, 0 }, /* is_static, is_static_dstn, has_length,
122 is_stack_buf, sink_addr, alloc_disp,
123 is_noncont_src, is_noncont_dst */
124 0, /* offset */
125 0, /* size */
126 1, /* count */
127 0, /* alloc */
128 0, /* into */
129 0 /* ptr */
133 __attribute__((constructor))
134 static void
135 init (void)
137 const char *ld_lib_path = getenv (LD_LIBRARY_PATH_ENV);
138 const char *mic_lib_path = getenv (MIC_LD_LIBRARY_PATH_ENV);
139 const char *active_wait = getenv (OFFLOAD_ACTIVE_WAIT_ENV);
141 /* Disable active wait by default to avoid useless CPU usage. */
142 if (!active_wait)
143 setenv (OFFLOAD_ACTIVE_WAIT_ENV, "0", 0);
145 if (!ld_lib_path)
146 goto out;
148 /* Add path specified in LD_LIBRARY_PATH to MIC_LD_LIBRARY_PATH, which is
149 required by liboffloadmic. */
150 if (!mic_lib_path)
151 setenv (MIC_LD_LIBRARY_PATH_ENV, ld_lib_path, 1);
152 else
154 size_t len = strlen (mic_lib_path) + strlen (ld_lib_path) + 2;
155 bool use_alloca = len <= 2048;
156 char *mic_lib_path_new = (char *) (use_alloca ? alloca (len)
157 : malloc (len));
158 if (!mic_lib_path_new)
160 fprintf (stderr, "%s: Can't allocate memory\n", __FILE__);
161 exit (1);
164 sprintf (mic_lib_path_new, "%s:%s", mic_lib_path, ld_lib_path);
165 setenv (MIC_LD_LIBRARY_PATH_ENV, mic_lib_path_new, 1);
167 if (!use_alloca)
168 free (mic_lib_path_new);
171 out:
172 address_table = new ImgDevAddrMap;
173 image_descriptors = new ImgDescMap;
174 num_devices = _Offload_number_of_devices ();
177 extern "C" const char *
178 GOMP_OFFLOAD_get_name (void)
180 const char *res = "intelmic";
181 TRACE ("(): return %s", res);
182 return res;
185 extern "C" unsigned int
186 GOMP_OFFLOAD_get_caps (void)
188 unsigned int res = GOMP_OFFLOAD_CAP_OPENMP_400;
189 TRACE ("(): return %x", res);
190 return res;
193 extern "C" enum offload_target_type
194 GOMP_OFFLOAD_get_type (void)
196 enum offload_target_type res = OFFLOAD_TARGET_TYPE_INTEL_MIC;
197 TRACE ("(): return %d", res);
198 return res;
201 extern "C" int
202 GOMP_OFFLOAD_get_num_devices (void)
204 TRACE ("(): return %d", num_devices);
205 return num_devices;
208 static void
209 offload (const char *file, uint64_t line, int device, const char *name,
210 int num_vars, VarDesc *vars, const void **async_data)
212 OFFLOAD ofld = __offload_target_acquire1 (&device, file, line);
213 if (ofld)
215 if (async_data == NULL)
216 __offload_offload1 (ofld, name, 0, num_vars, vars, NULL, 0, NULL, NULL);
217 else
219 OffloadFlags flags;
220 flags.flags = 0;
221 flags.bits.omp_async = 1;
222 __offload_offload3 (ofld, name, 0, num_vars, vars, NULL, 0, NULL,
223 async_data, 0, NULL, flags, NULL);
226 else
228 fprintf (stderr, "%s:%d: Offload target acquire failed\n", file, line);
229 exit (1);
233 static void
234 register_main_image ()
236 /* Do not check the return value, because old versions of liboffloadmic did
237 not have return values. */
238 __offload_register_image (&main_target_image);
240 /* liboffloadmic will call GOMP_PLUGIN_target_task_completion when
241 asynchronous task on target is completed. */
242 __offload_register_task_callback (GOMP_PLUGIN_target_task_completion);
245 /* liboffloadmic loads and runs offload_target_main on all available devices
246 during a first call to offload (). */
247 extern "C" void
248 GOMP_OFFLOAD_init_device (int device)
250 TRACE ("(device = %d)", device);
251 pthread_once (&main_image_is_registered, register_main_image);
252 offload (__FILE__, __LINE__, device, "__offload_target_init_proc", 0, NULL,
253 NULL);
256 extern "C" void
257 GOMP_OFFLOAD_fini_device (int device)
259 TRACE ("(device = %d)", device);
261 /* liboffloadmic will finalize target processes on all available devices. */
262 __offload_unregister_image (&main_target_image);
265 static void
266 get_target_table (int device, int &num_funcs, int &num_vars, void **&table)
268 VarDesc vd1[2] = { vd_tgt2host, vd_tgt2host };
269 vd1[0].ptr = &num_funcs;
270 vd1[0].size = sizeof (num_funcs);
271 vd1[1].ptr = &num_vars;
272 vd1[1].size = sizeof (num_vars);
274 offload (__FILE__, __LINE__, device, "__offload_target_table_p1", 2, vd1,
275 NULL);
277 int table_size = num_funcs + 2 * num_vars;
278 if (table_size > 0)
280 table = new void * [table_size];
282 VarDesc vd2;
283 vd2 = vd_tgt2host;
284 vd2.ptr = table;
285 vd2.size = table_size * sizeof (void *);
287 offload (__FILE__, __LINE__, device, "__offload_target_table_p2", 1, &vd2,
288 NULL);
292 /* Offload TARGET_IMAGE to all available devices and fill address_table with
293 corresponding target addresses. */
295 static void
296 offload_image (const void *target_image)
298 void *image_start = ((void **) target_image)[0];
299 void *image_end = ((void **) target_image)[1];
301 TRACE ("(target_image = %p { %p, %p })",
302 target_image, image_start, image_end);
304 int64_t image_size = (uintptr_t) image_end - (uintptr_t) image_start;
305 TargetImageDesc *image = (TargetImageDesc *) malloc (offsetof (TargetImageDesc, data)
306 + image_size);
307 if (!image)
309 fprintf (stderr, "%s: Can't allocate memory\n", __FILE__);
310 exit (1);
313 image->size = image_size;
314 sprintf (image->name, "lib%010d.so", num_images++);
315 memcpy (image->data, image_start, image->size);
317 TRACE ("() __offload_register_image %s { %p, %d }",
318 image->name, image_start, image->size);
319 /* Do not check the return value, because old versions of liboffloadmic did
320 not have return values. */
321 __offload_register_image (image);
323 /* Receive tables for target_image from all devices. */
324 DevAddrVect dev_table;
325 for (int dev = 0; dev < num_devices; dev++)
327 int num_funcs = 0;
328 int num_vars = 0;
329 void **table = NULL;
331 get_target_table (dev, num_funcs, num_vars, table);
333 AddrVect curr_dev_table;
335 for (int i = 0; i < num_funcs; i++)
337 addr_pair tgt_addr;
338 tgt_addr.start = (uintptr_t) table[i];
339 tgt_addr.end = tgt_addr.start + 1;
340 TRACE ("() func %d:\t0x%llx..0x%llx", i,
341 tgt_addr.start, tgt_addr.end);
342 curr_dev_table.push_back (tgt_addr);
345 for (int i = 0; i < num_vars; i++)
347 addr_pair tgt_addr;
348 tgt_addr.start = (uintptr_t) table[num_funcs+i*2];
349 tgt_addr.end = tgt_addr.start + (uintptr_t) table[num_funcs+i*2+1];
350 TRACE ("() var %d:\t0x%llx..0x%llx", i, tgt_addr.start, tgt_addr.end);
351 curr_dev_table.push_back (tgt_addr);
354 dev_table.push_back (curr_dev_table);
355 delete [] table;
358 address_table->insert (std::make_pair (target_image, dev_table));
359 image_descriptors->insert (std::make_pair (target_image, image));
362 /* Return the libgomp version number we're compatible with. There is
363 no requirement for cross-version compatibility. */
365 extern "C" unsigned
366 GOMP_OFFLOAD_version (void)
368 return GOMP_VERSION;
371 extern "C" int
372 GOMP_OFFLOAD_load_image (int device, const unsigned version,
373 void *target_image, addr_pair **result)
375 TRACE ("(device = %d, target_image = %p)", device, target_image);
377 if (GOMP_VERSION_DEV (version) > GOMP_VERSION_INTEL_MIC)
378 GOMP_PLUGIN_fatal ("Offload data incompatible with intelmic plugin"
379 " (expected %u, received %u)",
380 GOMP_VERSION_INTEL_MIC, GOMP_VERSION_DEV (version));
382 /* If target_image is already present in address_table, then there is no need
383 to offload it. */
384 if (address_table->count (target_image) == 0)
385 offload_image (target_image);
387 AddrVect *curr_dev_table = &(*address_table)[target_image][device];
388 int table_size = curr_dev_table->size ();
389 addr_pair *table = (addr_pair *) malloc (table_size * sizeof (addr_pair));
390 if (table == NULL)
392 fprintf (stderr, "%s: Can't allocate memory\n", __FILE__);
393 exit (1);
396 std::copy (curr_dev_table->begin (), curr_dev_table->end (), table);
397 *result = table;
398 return table_size;
401 extern "C" void
402 GOMP_OFFLOAD_unload_image (int device, unsigned version,
403 const void *target_image)
405 if (GOMP_VERSION_DEV (version) > GOMP_VERSION_INTEL_MIC)
406 return;
408 TRACE ("(device = %d, target_image = %p)", device, target_image);
410 /* liboffloadmic unloads the image from all available devices. */
411 if (image_descriptors->count (target_image) > 0)
413 TargetImageDesc *image_desc = (*image_descriptors)[target_image];
414 __offload_unregister_image (image_desc);
415 free (image_desc);
417 address_table->erase (target_image);
418 image_descriptors->erase (target_image);
422 extern "C" void *
423 GOMP_OFFLOAD_alloc (int device, size_t size)
425 TRACE ("(device = %d, size = %d)", device, size);
427 void *tgt_ptr;
428 VarDesc vd[2] = { vd_host2tgt, vd_tgt2host };
429 vd[0].ptr = &size;
430 vd[0].size = sizeof (size);
431 vd[1].ptr = &tgt_ptr;
432 vd[1].size = sizeof (void *);
434 offload (__FILE__, __LINE__, device, "__offload_target_alloc", 2, vd, NULL);
436 return tgt_ptr;
439 extern "C" void
440 GOMP_OFFLOAD_free (int device, void *tgt_ptr)
442 TRACE ("(device = %d, tgt_ptr = %p)", device, tgt_ptr);
444 VarDesc vd = vd_host2tgt;
445 vd.ptr = &tgt_ptr;
446 vd.size = sizeof (void *);
448 offload (__FILE__, __LINE__, device, "__offload_target_free", 1, &vd, NULL);
451 extern "C" void *
452 GOMP_OFFLOAD_host2dev (int device, void *tgt_ptr, const void *host_ptr,
453 size_t size)
455 TRACE ("(device = %d, tgt_ptr = %p, host_ptr = %p, size = %d)",
456 device, tgt_ptr, host_ptr, size);
457 if (!size)
458 return tgt_ptr;
460 VarDesc vd1[2] = { vd_host2tgt, vd_host2tgt };
461 vd1[0].ptr = &tgt_ptr;
462 vd1[0].size = sizeof (void *);
463 vd1[1].ptr = &size;
464 vd1[1].size = sizeof (size);
466 offload (__FILE__, __LINE__, device, "__offload_target_host2tgt_p1", 2, vd1,
467 NULL);
469 VarDesc vd2 = vd_host2tgt;
470 vd2.ptr = (void *) host_ptr;
471 vd2.size = size;
473 offload (__FILE__, __LINE__, device, "__offload_target_host2tgt_p2", 1, &vd2,
474 NULL);
476 return tgt_ptr;
479 extern "C" void *
480 GOMP_OFFLOAD_dev2host (int device, void *host_ptr, const void *tgt_ptr,
481 size_t size)
483 TRACE ("(device = %d, host_ptr = %p, tgt_ptr = %p, size = %d)",
484 device, host_ptr, tgt_ptr, size);
485 if (!size)
486 return host_ptr;
488 VarDesc vd1[2] = { vd_host2tgt, vd_host2tgt };
489 vd1[0].ptr = &tgt_ptr;
490 vd1[0].size = sizeof (void *);
491 vd1[1].ptr = &size;
492 vd1[1].size = sizeof (size);
494 offload (__FILE__, __LINE__, device, "__offload_target_tgt2host_p1", 2, vd1,
495 NULL);
497 VarDesc vd2 = vd_tgt2host;
498 vd2.ptr = (void *) host_ptr;
499 vd2.size = size;
501 offload (__FILE__, __LINE__, device, "__offload_target_tgt2host_p2", 1, &vd2,
502 NULL);
504 return host_ptr;
507 extern "C" void *
508 GOMP_OFFLOAD_dev2dev (int device, void *dst_ptr, const void *src_ptr,
509 size_t size)
511 TRACE ("(device = %d, dst_ptr = %p, src_ptr = %p, size = %d)",
512 device, dst_ptr, src_ptr, size);
513 if (!size)
514 return dst_ptr;
516 VarDesc vd[3] = { vd_host2tgt, vd_host2tgt, vd_host2tgt };
517 vd[0].ptr = &dst_ptr;
518 vd[0].size = sizeof (void *);
519 vd[1].ptr = &src_ptr;
520 vd[1].size = sizeof (void *);
521 vd[2].ptr = &size;
522 vd[2].size = sizeof (size);
524 offload (__FILE__, __LINE__, device, "__offload_target_tgt2tgt", 3, vd, NULL);
526 return dst_ptr;
529 extern "C" void
530 GOMP_OFFLOAD_async_run (int device, void *tgt_fn, void *tgt_vars,
531 void **, void *async_data)
533 TRACE ("(device = %d, tgt_fn = %p, tgt_vars = %p, async_data = %p)", device,
534 tgt_fn, tgt_vars, async_data);
536 VarDesc vd[2] = { vd_host2tgt, vd_host2tgt };
537 vd[0].ptr = &tgt_fn;
538 vd[0].size = sizeof (void *);
539 vd[1].ptr = &tgt_vars;
540 vd[1].size = sizeof (void *);
542 offload (__FILE__, __LINE__, device, "__offload_target_run", 2, vd,
543 (const void **) async_data);
546 extern "C" void
547 GOMP_OFFLOAD_run (int device, void *tgt_fn, void *tgt_vars, void **)
549 TRACE ("(device = %d, tgt_fn = %p, tgt_vars = %p)", device, tgt_fn, tgt_vars);
551 GOMP_OFFLOAD_async_run (device, tgt_fn, tgt_vars, NULL, NULL);