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. */
37 #include "libgomp-plugin.h"
38 #include "compiler_if_host.h"
39 #include "main_target_image.h"
41 #define LD_LIBRARY_PATH_ENV "LD_LIBRARY_PATH"
42 #define MIC_LD_LIBRARY_PATH_ENV "MIC_LD_LIBRARY_PATH"
47 fprintf (stderr, "HOST:\t%s:%s ", __FILE__, __FUNCTION__); \
48 fprintf (stderr, __VA_ARGS__); \
49 fprintf (stderr, "\n"); \
56 static VarDesc vd_host2tgt
= {
57 { 1, 1 }, /* dst, src */
58 { 1, 0 }, /* in, out */
63 { 0, 0, 0, 0, 0, 0, 0, 0 }, /* is_static, is_static_dstn, has_length,
64 is_stack_buf, sink_addr, alloc_disp,
65 is_noncont_src, is_noncont_dst */
74 static VarDesc vd_tgt2host
= {
75 { 1, 1 }, /* dst, src */
76 { 0, 1 }, /* in, out */
81 { 0, 0, 0, 0, 0, 0, 0, 0 }, /* is_static, is_static_dstn, has_length,
82 is_stack_buf, sink_addr, alloc_disp,
83 is_noncont_src, is_noncont_dst */
93 /* Total number of shared libraries with offloading to Intel MIC. */
94 static int num_libraries
;
96 /* Pointers to the descriptors, containing pointers to host-side tables and to
98 static std::vector
< std::pair
<void *, void *> > lib_descrs
;
100 /* Thread-safe registration of the main image. */
101 static pthread_once_t main_image_is_registered
= PTHREAD_ONCE_INIT
;
104 /* Add path specified in LD_LIBRARY_PATH to MIC_LD_LIBRARY_PATH, which is
105 required by liboffloadmic. */
106 __attribute__((constructor
))
108 set_mic_lib_path (void)
110 const char *ld_lib_path
= getenv (LD_LIBRARY_PATH_ENV
);
111 const char *mic_lib_path
= getenv (MIC_LD_LIBRARY_PATH_ENV
);
117 setenv (MIC_LD_LIBRARY_PATH_ENV
, ld_lib_path
, 1);
120 size_t len
= strlen (mic_lib_path
) + strlen (ld_lib_path
) + 2;
121 bool use_alloca
= len
<= 2048;
122 char *mic_lib_path_new
= (char *) (use_alloca
? alloca (len
)
124 if (!mic_lib_path_new
)
126 fprintf (stderr
, "%s: Can't allocate memory\n", __FILE__
);
130 sprintf (mic_lib_path_new
, "%s:%s", mic_lib_path
, ld_lib_path
);
131 setenv (MIC_LD_LIBRARY_PATH_ENV
, mic_lib_path_new
, 1);
134 free (mic_lib_path_new
);
138 extern "C" const char *
139 GOMP_OFFLOAD_get_name (void)
141 const char *res
= "intelmic";
142 TRACE ("(): return %s", res
);
146 extern "C" unsigned int
147 GOMP_OFFLOAD_get_caps (void)
149 unsigned int res
= GOMP_OFFLOAD_CAP_OPENMP_400
;
150 TRACE ("(): return %x", res
);
154 extern "C" enum offload_target_type
155 GOMP_OFFLOAD_get_type (void)
157 enum offload_target_type res
= OFFLOAD_TARGET_TYPE_INTEL_MIC
;
158 TRACE ("(): return %d", res
);
163 GOMP_OFFLOAD_get_num_devices (void)
165 int res
= _Offload_number_of_devices ();
166 TRACE ("(): return %d", res
);
170 /* This should be called from every shared library with offloading. */
172 GOMP_OFFLOAD_register_image (void *host_table
, void *target_image
)
174 TRACE ("(host_table = %p, target_image = %p)", host_table
, target_image
);
175 lib_descrs
.push_back (std::make_pair (host_table
, target_image
));
180 offload (const char *file
, uint64_t line
, int device
, const char *name
,
181 int num_vars
, VarDesc
*vars
, VarDesc2
*vars2
)
183 OFFLOAD ofld
= __offload_target_acquire1 (&device
, file
, line
);
185 __offload_offload1 (ofld
, name
, 0, num_vars
, vars
, vars2
, 0, NULL
, NULL
);
188 fprintf (stderr
, "%s:%d: Offload target acquire failed\n", file
, line
);
194 register_main_image ()
196 __offload_register_image (&main_target_image
);
199 /* Load offload_target_main on target. */
201 GOMP_OFFLOAD_init_device (int device
)
204 pthread_once (&main_image_is_registered
, register_main_image
);
205 offload (__FILE__
, __LINE__
, device
, "__offload_target_init_proc", 0,
210 GOMP_OFFLOAD_fini_device (int device
)
213 /* Unreachable for GOMP_OFFLOAD_CAP_OPENMP_400. */
218 get_target_table (int device
, int &num_funcs
, int &num_vars
, void **&table
)
220 VarDesc vd1
[2] = { vd_tgt2host
, vd_tgt2host
};
221 vd1
[0].ptr
= &num_funcs
;
222 vd1
[0].size
= sizeof (num_funcs
);
223 vd1
[1].ptr
= &num_vars
;
224 vd1
[1].size
= sizeof (num_vars
);
225 VarDesc2 vd1g
[2] = { { "num_funcs", 0 }, { "num_vars", 0 } };
227 offload (__FILE__
, __LINE__
, device
, "__offload_target_table_p1", 2,
230 int table_size
= num_funcs
+ 2 * num_vars
;
233 table
= new void * [table_size
];
238 vd2
.size
= table_size
* sizeof (void *);
239 VarDesc2 vd2g
= { "table", 0 };
241 offload (__FILE__
, __LINE__
, device
, "__offload_target_table_p2", 1,
247 load_lib_and_get_table (int device
, int lib_num
, mapping_table
*&table
,
252 /* 10 characters is enough for max int value. */
253 char name
[sizeof ("lib0000000000.so")];
255 } __attribute__ ((packed
));
257 void ***host_table_descr
= (void ***) lib_descrs
[lib_num
].first
;
258 void **host_func_start
= host_table_descr
[0];
259 void **host_func_end
= host_table_descr
[1];
260 void **host_var_start
= host_table_descr
[2];
261 void **host_var_end
= host_table_descr
[3];
263 void **target_image_descr
= (void **) lib_descrs
[lib_num
].second
;
264 void *image_start
= target_image_descr
[0];
265 void *image_end
= target_image_descr
[1];
267 TRACE ("() host_table_descr { %p, %p, %p, %p }", host_func_start
,
268 host_func_end
, host_var_start
, host_var_end
);
269 TRACE ("() target_image_descr { %p, %p }", image_start
, image_end
);
271 int64_t image_size
= (uintptr_t) image_end
- (uintptr_t) image_start
;
273 = (TargetImage
*) malloc (sizeof (int64_t) + sizeof ("lib0000000000.so")
277 fprintf (stderr
, "%s: Can't allocate memory\n", __FILE__
);
281 image
->size
= image_size
;
282 sprintf (image
->name
, "lib%010d.so", lib_num
);
283 memcpy (image
->data
, image_start
, image
->size
);
285 TRACE ("() __offload_register_image %s { %p, %d }",
286 image
->name
, image_start
, image
->size
);
287 __offload_register_image (image
);
289 int tgt_num_funcs
= 0;
290 int tgt_num_vars
= 0;
291 void **tgt_table
= NULL
;
292 get_target_table (device
, tgt_num_funcs
, tgt_num_vars
, tgt_table
);
295 /* The func table contains only addresses, the var table contains addresses
296 and corresponding sizes. */
297 int host_num_funcs
= host_func_end
- host_func_start
;
298 int host_num_vars
= (host_var_end
- host_var_start
) / 2;
299 TRACE ("() host_num_funcs = %d, tgt_num_funcs = %d",
300 host_num_funcs
, tgt_num_funcs
);
301 TRACE ("() host_num_vars = %d, tgt_num_vars = %d",
302 host_num_vars
, tgt_num_vars
);
303 if (host_num_funcs
!= tgt_num_funcs
)
305 fprintf (stderr
, "%s: Can't map target functions\n", __FILE__
);
308 if (host_num_vars
!= tgt_num_vars
)
310 fprintf (stderr
, "%s: Can't map target variables\n", __FILE__
);
314 table
= (mapping_table
*) realloc (table
, (table_size
+ host_num_funcs
316 * sizeof (mapping_table
));
319 fprintf (stderr
, "%s: Can't allocate memory\n", __FILE__
);
323 for (int i
= 0; i
< host_num_funcs
; i
++)
326 t
.host_start
= (uintptr_t) host_func_start
[i
];
327 t
.host_end
= t
.host_start
+ 1;
328 t
.tgt_start
= (uintptr_t) tgt_table
[i
];
329 t
.tgt_end
= t
.tgt_start
+ 1;
331 TRACE ("() lib %d, func %d:\t0x%llx -- 0x%llx",
332 lib_num
, i
, t
.host_start
, t
.tgt_start
);
334 table
[table_size
++] = t
;
337 for (int i
= 0; i
< host_num_vars
* 2; i
+= 2)
340 t
.host_start
= (uintptr_t) host_var_start
[i
];
341 t
.host_end
= t
.host_start
+ (uintptr_t) host_var_start
[i
+1];
342 t
.tgt_start
= (uintptr_t) tgt_table
[tgt_num_funcs
+i
];
343 t
.tgt_end
= t
.tgt_start
+ (uintptr_t) tgt_table
[tgt_num_funcs
+i
+1];
345 TRACE ("() lib %d, var %d:\t0x%llx (%d) -- 0x%llx (%d)", lib_num
, i
/2,
346 t
.host_start
, t
.host_end
- t
.host_start
,
347 t
.tgt_start
, t
.tgt_end
- t
.tgt_start
);
349 table
[table_size
++] = t
;
356 GOMP_OFFLOAD_get_table (int device
, void *result
)
358 TRACE ("(num_libraries = %d)", num_libraries
);
360 mapping_table
*table
= NULL
;
363 for (int i
= 0; i
< num_libraries
; i
++)
364 load_lib_and_get_table (device
, i
, table
, table_size
);
366 *(void **) result
= table
;
371 GOMP_OFFLOAD_alloc (int device
, size_t size
)
373 TRACE ("(size = %d)", size
);
376 VarDesc vd1
[2] = { vd_host2tgt
, vd_tgt2host
};
378 vd1
[0].size
= sizeof (size
);
379 vd1
[1].ptr
= &tgt_ptr
;
380 vd1
[1].size
= sizeof (void *);
381 VarDesc2 vd1g
[2] = { { "size", 0 }, { "tgt_ptr", 0 } };
383 offload (__FILE__
, __LINE__
, device
, "__offload_target_alloc", 2, vd1
, vd1g
);
389 GOMP_OFFLOAD_free (int device
, void *tgt_ptr
)
391 TRACE ("(tgt_ptr = %p)", tgt_ptr
);
393 VarDesc vd1
= vd_host2tgt
;
395 vd1
.size
= sizeof (void *);
396 VarDesc2 vd1g
= { "tgt_ptr", 0 };
398 offload (__FILE__
, __LINE__
, device
, "__offload_target_free", 1, &vd1
, &vd1g
);
402 GOMP_OFFLOAD_host2dev (int device
, void *tgt_ptr
, const void *host_ptr
,
405 TRACE ("(tgt_ptr = %p, host_ptr = %p, size = %d)", tgt_ptr
, host_ptr
, size
);
409 VarDesc vd1
[2] = { vd_host2tgt
, vd_host2tgt
};
410 vd1
[0].ptr
= &tgt_ptr
;
411 vd1
[0].size
= sizeof (void *);
413 vd1
[1].size
= sizeof (size
);
414 VarDesc2 vd1g
[2] = { { "tgt_ptr", 0 }, { "size", 0 } };
416 offload (__FILE__
, __LINE__
, device
, "__offload_target_host2tgt_p1", 2,
419 VarDesc vd2
= vd_host2tgt
;
420 vd2
.ptr
= (void *) host_ptr
;
422 VarDesc2 vd2g
= { "var", 0 };
424 offload (__FILE__
, __LINE__
, device
, "__offload_target_host2tgt_p2", 1,
431 GOMP_OFFLOAD_dev2host (int device
, void *host_ptr
, const void *tgt_ptr
,
434 TRACE ("(host_ptr = %p, tgt_ptr = %p, size = %d)", host_ptr
, tgt_ptr
, size
);
438 VarDesc vd1
[2] = { vd_host2tgt
, vd_host2tgt
};
439 vd1
[0].ptr
= &tgt_ptr
;
440 vd1
[0].size
= sizeof (void *);
442 vd1
[1].size
= sizeof (size
);
443 VarDesc2 vd1g
[2] = { { "tgt_ptr", 0 }, { "size", 0 } };
445 offload (__FILE__
, __LINE__
, device
, "__offload_target_tgt2host_p1", 2,
448 VarDesc vd2
= vd_tgt2host
;
449 vd2
.ptr
= (void *) host_ptr
;
451 VarDesc2 vd2g
= { "var", 0 };
453 offload (__FILE__
, __LINE__
, device
, "__offload_target_tgt2host_p2", 1,
460 GOMP_OFFLOAD_run (int device
, void *tgt_fn
, void *tgt_vars
)
462 TRACE ("(tgt_fn = %p, tgt_vars = %p)", tgt_fn
, tgt_vars
);
464 VarDesc vd1
[2] = { vd_host2tgt
, vd_host2tgt
};
465 vd1
[0].ptr
= &tgt_fn
;
466 vd1
[0].size
= sizeof (void *);
467 vd1
[1].ptr
= &tgt_vars
;
468 vd1
[1].size
= sizeof (void *);
469 VarDesc2 vd1g
[2] = { { "tgt_fn", 0 }, { "tgt_vars", 0 } };
471 offload (__FILE__
, __LINE__
, device
, "__offload_target_run", 2, vd1
, vd1g
);