1 /* Plugin for offload execution on Intel MIC devices.
3 Copyright (C) 2014 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"
42 #define LD_LIBRARY_PATH_ENV "LD_LIBRARY_PATH"
43 #define MIC_LD_LIBRARY_PATH_ENV "MIC_LD_LIBRARY_PATH"
48 fprintf (stderr, "HOST:\t%s:%s ", __FILE__, __FUNCTION__); \
49 fprintf (stderr, __VA_ARGS__); \
50 fprintf (stderr, "\n"); \
57 /* Start/end addresses of functions and global variables on a device. */
58 typedef std::vector
<addr_pair
> AddrVect
;
60 /* Addresses for one image and all devices. */
61 typedef std::vector
<AddrVect
> DevAddrVect
;
63 /* Addresses for all images and all devices. */
64 typedef std::map
<void *, DevAddrVect
> ImgDevAddrMap
;
67 /* Total number of available devices. */
68 static int num_devices
;
70 /* Total number of shared libraries with offloading to Intel MIC. */
71 static int num_images
;
73 /* Two dimensional array: one key is a pointer to image,
74 second key is number of device. Contains a vector of pointer pairs. */
75 static ImgDevAddrMap
*address_table
;
77 /* Thread-safe registration of the main image. */
78 static pthread_once_t main_image_is_registered
= PTHREAD_ONCE_INIT
;
80 static VarDesc vd_host2tgt
= {
81 { 1, 1 }, /* dst, src */
82 { 1, 0 }, /* in, out */
87 { 0, 0, 0, 0, 0, 0, 0, 0 }, /* is_static, is_static_dstn, has_length,
88 is_stack_buf, sink_addr, alloc_disp,
89 is_noncont_src, is_noncont_dst */
98 static VarDesc vd_tgt2host
= {
99 { 1, 1 }, /* dst, src */
100 { 0, 1 }, /* in, out */
105 { 0, 0, 0, 0, 0, 0, 0, 0 }, /* is_static, is_static_dstn, has_length,
106 is_stack_buf, sink_addr, alloc_disp,
107 is_noncont_src, is_noncont_dst */
117 /* Add path specified in LD_LIBRARY_PATH to MIC_LD_LIBRARY_PATH, which is
118 required by liboffloadmic. */
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
);
130 setenv (MIC_LD_LIBRARY_PATH_ENV
, ld_lib_path
, 1);
133 size_t len
= strlen (mic_lib_path
) + strlen (ld_lib_path
) + 2;
134 bool use_alloca
= len
<= 2048;
135 char *mic_lib_path_new
= (char *) (use_alloca
? alloca (len
)
137 if (!mic_lib_path_new
)
139 fprintf (stderr
, "%s: Can't allocate memory\n", __FILE__
);
143 sprintf (mic_lib_path_new
, "%s:%s", mic_lib_path
, ld_lib_path
);
144 setenv (MIC_LD_LIBRARY_PATH_ENV
, mic_lib_path_new
, 1);
147 free (mic_lib_path_new
);
151 address_table
= new ImgDevAddrMap
;
152 num_devices
= _Offload_number_of_devices ();
155 extern "C" const char *
156 GOMP_OFFLOAD_get_name (void)
158 const char *res
= "intelmic";
159 TRACE ("(): return %s", res
);
163 extern "C" unsigned int
164 GOMP_OFFLOAD_get_caps (void)
166 unsigned int res
= GOMP_OFFLOAD_CAP_OPENMP_400
;
167 TRACE ("(): return %x", res
);
171 extern "C" enum offload_target_type
172 GOMP_OFFLOAD_get_type (void)
174 enum offload_target_type res
= OFFLOAD_TARGET_TYPE_INTEL_MIC
;
175 TRACE ("(): return %d", res
);
180 GOMP_OFFLOAD_get_num_devices (void)
182 TRACE ("(): return %d", num_devices
);
187 offload (const char *file
, uint64_t line
, int device
, const char *name
,
188 int num_vars
, VarDesc
*vars
, VarDesc2
*vars2
)
190 OFFLOAD ofld
= __offload_target_acquire1 (&device
, file
, line
);
192 __offload_offload1 (ofld
, name
, 0, num_vars
, vars
, vars2
, 0, NULL
, NULL
);
195 fprintf (stderr
, "%s:%d: Offload target acquire failed\n", file
, line
);
201 register_main_image ()
203 __offload_register_image (&main_target_image
);
206 /* liboffloadmic loads and runs offload_target_main on all available devices
207 during a first call to offload (). */
209 GOMP_OFFLOAD_init_device (int device
)
212 pthread_once (&main_image_is_registered
, register_main_image
);
213 offload (__FILE__
, __LINE__
, device
, "__offload_target_init_proc", 0,
218 GOMP_OFFLOAD_fini_device (int device
)
221 /* Unreachable for GOMP_OFFLOAD_CAP_OPENMP_400. */
226 get_target_table (int device
, int &num_funcs
, int &num_vars
, void **&table
)
228 VarDesc vd1
[2] = { vd_tgt2host
, vd_tgt2host
};
229 vd1
[0].ptr
= &num_funcs
;
230 vd1
[0].size
= sizeof (num_funcs
);
231 vd1
[1].ptr
= &num_vars
;
232 vd1
[1].size
= sizeof (num_vars
);
233 VarDesc2 vd1g
[2] = { { "num_funcs", 0 }, { "num_vars", 0 } };
235 offload (__FILE__
, __LINE__
, device
, "__offload_target_table_p1", 2,
238 int table_size
= num_funcs
+ 2 * num_vars
;
241 table
= new void * [table_size
];
246 vd2
.size
= table_size
* sizeof (void *);
247 VarDesc2 vd2g
= { "table", 0 };
249 offload (__FILE__
, __LINE__
, device
, "__offload_target_table_p2", 1,
254 /* Offload TARGET_IMAGE to all available devices and fill address_table with
255 corresponding target addresses. */
258 offload_image (void *target_image
)
262 /* 10 characters is enough for max int value. */
263 char name
[sizeof ("lib0000000000.so")];
265 } __attribute__ ((packed
));
267 void *image_start
= ((void **) target_image
)[0];
268 void *image_end
= ((void **) target_image
)[1];
270 TRACE ("(target_image = %p { %p, %p })",
271 target_image
, image_start
, image_end
);
273 int64_t image_size
= (uintptr_t) image_end
- (uintptr_t) image_start
;
275 = (TargetImage
*) malloc (sizeof (int64_t) + sizeof ("lib0000000000.so")
279 fprintf (stderr
, "%s: Can't allocate memory\n", __FILE__
);
283 image
->size
= image_size
;
284 sprintf (image
->name
, "lib%010d.so", num_images
++);
285 memcpy (image
->data
, image_start
, image
->size
);
287 TRACE ("() __offload_register_image %s { %p, %d }",
288 image
->name
, image_start
, image
->size
);
289 __offload_register_image (image
);
291 /* Receive tables for target_image from all devices. */
292 DevAddrVect dev_table
;
293 for (int dev
= 0; dev
< num_devices
; dev
++)
299 get_target_table (dev
, num_funcs
, num_vars
, table
);
301 AddrVect curr_dev_table
;
303 for (int i
= 0; i
< num_funcs
; i
++)
306 tgt_addr
.start
= (uintptr_t) table
[i
];
307 tgt_addr
.end
= tgt_addr
.start
+ 1;
308 TRACE ("() func %d:\t0x%llx..0x%llx", i
,
309 tgt_addr
.start
, tgt_addr
.end
);
310 curr_dev_table
.push_back (tgt_addr
);
313 for (int i
= 0; i
< num_vars
; i
++)
316 tgt_addr
.start
= (uintptr_t) table
[num_funcs
+i
*2];
317 tgt_addr
.end
= tgt_addr
.start
+ (uintptr_t) table
[num_funcs
+i
*2+1];
318 TRACE ("() var %d:\t0x%llx..0x%llx", i
, tgt_addr
.start
, tgt_addr
.end
);
319 curr_dev_table
.push_back (tgt_addr
);
322 dev_table
.push_back (curr_dev_table
);
325 address_table
->insert (std::make_pair (target_image
, dev_table
));
331 GOMP_OFFLOAD_load_image (int device
, void *target_image
, addr_pair
**result
)
333 TRACE ("(device = %d, target_image = %p)", device
, target_image
);
335 /* If target_image is already present in address_table, then there is no need
337 if (address_table
->count (target_image
) == 0)
338 offload_image (target_image
);
340 AddrVect
*curr_dev_table
= &(*address_table
)[target_image
][device
];
341 int table_size
= curr_dev_table
->size ();
342 addr_pair
*table
= (addr_pair
*) malloc (table_size
* sizeof (addr_pair
));
345 fprintf (stderr
, "%s: Can't allocate memory\n", __FILE__
);
349 std::copy (curr_dev_table
->begin (), curr_dev_table
->end (), table
);
355 GOMP_OFFLOAD_unload_image (int device
, void *target_image
)
357 TRACE ("(device = %d, target_image = %p)", device
, target_image
);
359 /* TODO: Currently liboffloadmic doesn't support __offload_unregister_image
362 address_table
->erase (target_image
);
366 GOMP_OFFLOAD_alloc (int device
, size_t size
)
368 TRACE ("(size = %d)", size
);
371 VarDesc vd1
[2] = { vd_host2tgt
, vd_tgt2host
};
373 vd1
[0].size
= sizeof (size
);
374 vd1
[1].ptr
= &tgt_ptr
;
375 vd1
[1].size
= sizeof (void *);
376 VarDesc2 vd1g
[2] = { { "size", 0 }, { "tgt_ptr", 0 } };
378 offload (__FILE__
, __LINE__
, device
, "__offload_target_alloc", 2, vd1
, vd1g
);
384 GOMP_OFFLOAD_free (int device
, void *tgt_ptr
)
386 TRACE ("(tgt_ptr = %p)", tgt_ptr
);
388 VarDesc vd1
= vd_host2tgt
;
390 vd1
.size
= sizeof (void *);
391 VarDesc2 vd1g
= { "tgt_ptr", 0 };
393 offload (__FILE__
, __LINE__
, device
, "__offload_target_free", 1, &vd1
, &vd1g
);
397 GOMP_OFFLOAD_host2dev (int device
, void *tgt_ptr
, const void *host_ptr
,
400 TRACE ("(tgt_ptr = %p, host_ptr = %p, size = %d)", tgt_ptr
, host_ptr
, size
);
404 VarDesc vd1
[2] = { vd_host2tgt
, vd_host2tgt
};
405 vd1
[0].ptr
= &tgt_ptr
;
406 vd1
[0].size
= sizeof (void *);
408 vd1
[1].size
= sizeof (size
);
409 VarDesc2 vd1g
[2] = { { "tgt_ptr", 0 }, { "size", 0 } };
411 offload (__FILE__
, __LINE__
, device
, "__offload_target_host2tgt_p1", 2,
414 VarDesc vd2
= vd_host2tgt
;
415 vd2
.ptr
= (void *) host_ptr
;
417 VarDesc2 vd2g
= { "var", 0 };
419 offload (__FILE__
, __LINE__
, device
, "__offload_target_host2tgt_p2", 1,
426 GOMP_OFFLOAD_dev2host (int device
, void *host_ptr
, const void *tgt_ptr
,
429 TRACE ("(host_ptr = %p, tgt_ptr = %p, size = %d)", host_ptr
, tgt_ptr
, size
);
433 VarDesc vd1
[2] = { vd_host2tgt
, vd_host2tgt
};
434 vd1
[0].ptr
= &tgt_ptr
;
435 vd1
[0].size
= sizeof (void *);
437 vd1
[1].size
= sizeof (size
);
438 VarDesc2 vd1g
[2] = { { "tgt_ptr", 0 }, { "size", 0 } };
440 offload (__FILE__
, __LINE__
, device
, "__offload_target_tgt2host_p1", 2,
443 VarDesc vd2
= vd_tgt2host
;
444 vd2
.ptr
= (void *) host_ptr
;
446 VarDesc2 vd2g
= { "var", 0 };
448 offload (__FILE__
, __LINE__
, device
, "__offload_target_tgt2host_p2", 1,
455 GOMP_OFFLOAD_run (int device
, void *tgt_fn
, void *tgt_vars
)
457 TRACE ("(tgt_fn = %p, tgt_vars = %p)", tgt_fn
, tgt_vars
);
459 VarDesc vd1
[2] = { vd_host2tgt
, vd_host2tgt
};
460 vd1
[0].ptr
= &tgt_fn
;
461 vd1
[0].size
= sizeof (void *);
462 vd1
[1].ptr
= &tgt_vars
;
463 vd1
[1].size
= sizeof (void *);
464 VarDesc2 vd1g
[2] = { { "tgt_fn", 0 }, { "tgt_vars", 0 } };
466 offload (__FILE__
, __LINE__
, device
, "__offload_target_run", 2, vd1
, vd1g
);