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
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)
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
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. */
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"
50 fprintf (stderr, "HOST:\t%s:%s ", __FILE__, __FUNCTION__); \
51 fprintf (stderr, __VA_ARGS__); \
52 fprintf (stderr, "\n"); \
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
;
69 /* Total number of available devices. */
70 static int num_devices
;
72 /* Total number of shared libraries with offloading to Intel MIC. */
73 static int num_images
;
75 /* Two dimensional array: one key is a pointer to image,
76 second key is number of device. Contains a vector of pointer pairs. */
77 static ImgDevAddrMap
*address_table
;
79 /* Thread-safe registration of the main image. */
80 static pthread_once_t main_image_is_registered
= PTHREAD_ONCE_INIT
;
82 static VarDesc vd_host2tgt
= {
83 { 1, 1 }, /* dst, src */
84 { 1, 0 }, /* in, out */
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 */
100 static VarDesc vd_tgt2host
= {
101 { 1, 1 }, /* dst, src */
102 { 0, 1 }, /* in, out */
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 */
119 __attribute__((constructor
))
123 const char *ld_lib_path
= getenv (LD_LIBRARY_PATH_ENV
);
124 const char *mic_lib_path
= getenv (MIC_LD_LIBRARY_PATH_ENV
);
125 const char *active_wait
= getenv (OFFLOAD_ACTIVE_WAIT_ENV
);
127 /* Disable active wait by default to avoid useless CPU usage. */
129 setenv (OFFLOAD_ACTIVE_WAIT_ENV
, "0", 0);
134 /* Add path specified in LD_LIBRARY_PATH to MIC_LD_LIBRARY_PATH, which is
135 required by liboffloadmic. */
137 setenv (MIC_LD_LIBRARY_PATH_ENV
, ld_lib_path
, 1);
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
)
144 if (!mic_lib_path_new
)
146 fprintf (stderr
, "%s: Can't allocate memory\n", __FILE__
);
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);
154 free (mic_lib_path_new
);
158 address_table
= new ImgDevAddrMap
;
159 num_devices
= _Offload_number_of_devices ();
162 extern "C" const char *
163 GOMP_OFFLOAD_get_name (void)
165 const char *res
= "intelmic";
166 TRACE ("(): return %s", res
);
170 extern "C" unsigned int
171 GOMP_OFFLOAD_get_caps (void)
173 unsigned int res
= GOMP_OFFLOAD_CAP_OPENMP_400
;
174 TRACE ("(): return %x", res
);
178 extern "C" enum offload_target_type
179 GOMP_OFFLOAD_get_type (void)
181 enum offload_target_type res
= OFFLOAD_TARGET_TYPE_INTEL_MIC
;
182 TRACE ("(): return %d", res
);
187 GOMP_OFFLOAD_get_num_devices (void)
189 TRACE ("(): return %d", num_devices
);
194 offload (const char *file
, uint64_t line
, int device
, const char *name
,
195 int num_vars
, VarDesc
*vars
, VarDesc2
*vars2
)
197 OFFLOAD ofld
= __offload_target_acquire1 (&device
, file
, line
);
199 __offload_offload1 (ofld
, name
, 0, num_vars
, vars
, vars2
, 0, NULL
, NULL
);
202 fprintf (stderr
, "%s:%d: Offload target acquire failed\n", file
, line
);
208 register_main_image ()
210 __offload_register_image (&main_target_image
);
213 /* liboffloadmic loads and runs offload_target_main on all available devices
214 during a first call to offload (). */
216 GOMP_OFFLOAD_init_device (int device
)
219 pthread_once (&main_image_is_registered
, register_main_image
);
220 offload (__FILE__
, __LINE__
, device
, "__offload_target_init_proc", 0,
225 GOMP_OFFLOAD_fini_device (int device
)
228 /* Unreachable for GOMP_OFFLOAD_CAP_OPENMP_400. */
233 get_target_table (int device
, int &num_funcs
, int &num_vars
, void **&table
)
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 } };
242 offload (__FILE__
, __LINE__
, device
, "__offload_target_table_p1", 2,
245 int table_size
= num_funcs
+ 2 * num_vars
;
248 table
= new void * [table_size
];
253 vd2
.size
= table_size
* sizeof (void *);
254 VarDesc2 vd2g
= { "table", 0 };
256 offload (__FILE__
, __LINE__
, device
, "__offload_target_table_p2", 1,
261 /* Offload TARGET_IMAGE to all available devices and fill address_table with
262 corresponding target addresses. */
265 offload_image (const void *target_image
)
269 /* 10 characters is enough for max int value. */
270 char name
[sizeof ("lib0000000000.so")];
272 } __attribute__ ((packed
));
274 void *image_start
= ((void **) target_image
)[0];
275 void *image_end
= ((void **) target_image
)[1];
277 TRACE ("(target_image = %p { %p, %p })",
278 target_image
, image_start
, image_end
);
280 int64_t image_size
= (uintptr_t) image_end
- (uintptr_t) image_start
;
282 = (TargetImage
*) malloc (sizeof (int64_t) + sizeof ("lib0000000000.so")
286 fprintf (stderr
, "%s: Can't allocate memory\n", __FILE__
);
290 image
->size
= image_size
;
291 sprintf (image
->name
, "lib%010d.so", num_images
++);
292 memcpy (image
->data
, image_start
, image
->size
);
294 TRACE ("() __offload_register_image %s { %p, %d }",
295 image
->name
, image_start
, image
->size
);
296 __offload_register_image (image
);
298 /* Receive tables for target_image from all devices. */
299 DevAddrVect dev_table
;
300 for (int dev
= 0; dev
< num_devices
; dev
++)
306 get_target_table (dev
, num_funcs
, num_vars
, table
);
308 AddrVect curr_dev_table
;
310 for (int i
= 0; i
< num_funcs
; i
++)
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
);
320 for (int i
= 0; i
< num_vars
; i
++)
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
);
329 dev_table
.push_back (curr_dev_table
);
332 address_table
->insert (std::make_pair (target_image
, dev_table
));
337 /* Return the libgomp version number we're compatible with. There is
338 no requirement for cross-version compatibility. */
341 GOMP_OFFLOAD_version (void)
347 GOMP_OFFLOAD_load_image (int device
, const unsigned version
,
348 void *target_image
, addr_pair
**result
)
350 TRACE ("(device = %d, target_image = %p)", device
, target_image
);
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
));
357 /* If target_image is already present in address_table, then there is no need
359 if (address_table
->count (target_image
) == 0)
360 offload_image (target_image
);
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
));
367 fprintf (stderr
, "%s: Can't allocate memory\n", __FILE__
);
371 std::copy (curr_dev_table
->begin (), curr_dev_table
->end (), table
);
377 GOMP_OFFLOAD_unload_image (int device
, unsigned version
,
378 const void *target_image
)
380 if (GOMP_VERSION_DEV (version
) > GOMP_VERSION_INTEL_MIC
)
383 TRACE ("(device = %d, target_image = %p)", device
, target_image
);
385 /* TODO: Currently liboffloadmic doesn't support __offload_unregister_image
388 address_table
->erase (target_image
);
392 GOMP_OFFLOAD_alloc (int device
, size_t size
)
394 TRACE ("(size = %d)", size
);
397 VarDesc vd1
[2] = { vd_host2tgt
, vd_tgt2host
};
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 } };
404 offload (__FILE__
, __LINE__
, device
, "__offload_target_alloc", 2, vd1
, vd1g
);
410 GOMP_OFFLOAD_free (int device
, void *tgt_ptr
)
412 TRACE ("(tgt_ptr = %p)", tgt_ptr
);
414 VarDesc vd1
= vd_host2tgt
;
416 vd1
.size
= sizeof (void *);
417 VarDesc2 vd1g
= { "tgt_ptr", 0 };
419 offload (__FILE__
, __LINE__
, device
, "__offload_target_free", 1, &vd1
, &vd1g
);
423 GOMP_OFFLOAD_host2dev (int device
, void *tgt_ptr
, const void *host_ptr
,
426 TRACE ("(tgt_ptr = %p, host_ptr = %p, size = %d)", tgt_ptr
, host_ptr
, size
);
430 VarDesc vd1
[2] = { vd_host2tgt
, vd_host2tgt
};
431 vd1
[0].ptr
= &tgt_ptr
;
432 vd1
[0].size
= sizeof (void *);
434 vd1
[1].size
= sizeof (size
);
435 VarDesc2 vd1g
[2] = { { "tgt_ptr", 0 }, { "size", 0 } };
437 offload (__FILE__
, __LINE__
, device
, "__offload_target_host2tgt_p1", 2,
440 VarDesc vd2
= vd_host2tgt
;
441 vd2
.ptr
= (void *) host_ptr
;
443 VarDesc2 vd2g
= { "var", 0 };
445 offload (__FILE__
, __LINE__
, device
, "__offload_target_host2tgt_p2", 1,
452 GOMP_OFFLOAD_dev2host (int device
, void *host_ptr
, const void *tgt_ptr
,
455 TRACE ("(host_ptr = %p, tgt_ptr = %p, size = %d)", host_ptr
, tgt_ptr
, size
);
459 VarDesc vd1
[2] = { vd_host2tgt
, vd_host2tgt
};
460 vd1
[0].ptr
= &tgt_ptr
;
461 vd1
[0].size
= sizeof (void *);
463 vd1
[1].size
= sizeof (size
);
464 VarDesc2 vd1g
[2] = { { "tgt_ptr", 0 }, { "size", 0 } };
466 offload (__FILE__
, __LINE__
, device
, "__offload_target_tgt2host_p1", 2,
469 VarDesc vd2
= vd_tgt2host
;
470 vd2
.ptr
= (void *) host_ptr
;
472 VarDesc2 vd2g
= { "var", 0 };
474 offload (__FILE__
, __LINE__
, device
, "__offload_target_tgt2host_p2", 1,
481 GOMP_OFFLOAD_dev2dev (int device
, void *dst_ptr
, const void *src_ptr
,
484 TRACE ("(dst_ptr = %p, src_ptr = %p, size = %d)", dst_ptr
, src_ptr
, size
);
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 *);
494 vd1
[2].size
= sizeof (size
);
495 VarDesc2 vd1g
[3] = { { "dst_ptr", 0 }, { "src_ptr", 0 }, { "size", 0 } };
497 offload (__FILE__
, __LINE__
, device
, "__offload_target_tgt2tgt", 3, vd1
,
504 GOMP_OFFLOAD_run (int device
, void *tgt_fn
, void *tgt_vars
)
506 TRACE ("(tgt_fn = %p, tgt_vars = %p)", tgt_fn
, tgt_vars
);
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 } };
515 offload (__FILE__
, __LINE__
, device
, "__offload_target_run", 2, vd1
, vd1g
);