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_target.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" enum offload_target_type
139 GOMP_OFFLOAD_get_type (void)
141 enum offload_target_type res
= OFFLOAD_TARGET_TYPE_INTEL_MIC
;
142 TRACE ("(): return %d", res
);
147 GOMP_OFFLOAD_get_num_devices (void)
149 int res
= _Offload_number_of_devices ();
150 TRACE ("(): return %d", res
);
154 /* This should be called from every shared library with offloading. */
156 GOMP_OFFLOAD_register_image (void *host_table
, void *target_image
)
158 TRACE ("(host_table = %p, target_image = %p)", host_table
, target_image
);
159 lib_descrs
.push_back (std::make_pair (host_table
, target_image
));
164 offload (const char *file
, uint64_t line
, int device
, const char *name
,
165 int num_vars
, VarDesc
*vars
, VarDesc2
*vars2
)
167 OFFLOAD ofld
= __offload_target_acquire1 (&device
, file
, line
);
169 __offload_offload1 (ofld
, name
, 0, num_vars
, vars
, vars2
, 0, NULL
, NULL
);
172 fprintf (stderr
, "%s:%d: Offload target acquire failed\n", file
, line
);
178 register_main_image ()
180 __offload_register_image (&main_target_image
);
183 /* Load offload_target_main on target. */
185 GOMP_OFFLOAD_init_device (int device
)
188 pthread_once (&main_image_is_registered
, register_main_image
);
189 offload (__FILE__
, __LINE__
, device
, "__offload_target_init_proc", 0,
194 get_target_table (int device
, int &num_funcs
, int &num_vars
, void **&table
)
196 VarDesc vd1
[2] = { vd_tgt2host
, vd_tgt2host
};
197 vd1
[0].ptr
= &num_funcs
;
198 vd1
[0].size
= sizeof (num_funcs
);
199 vd1
[1].ptr
= &num_vars
;
200 vd1
[1].size
= sizeof (num_vars
);
201 VarDesc2 vd1g
[2] = { { "num_funcs", 0 }, { "num_vars", 0 } };
203 offload (__FILE__
, __LINE__
, device
, "__offload_target_table_p1", 2,
206 int table_size
= num_funcs
+ 2 * num_vars
;
209 table
= new void * [table_size
];
214 vd2
.size
= table_size
* sizeof (void *);
215 VarDesc2 vd2g
= { "table", 0 };
217 offload (__FILE__
, __LINE__
, device
, "__offload_target_table_p2", 1,
223 load_lib_and_get_table (int device
, int lib_num
, mapping_table
*&table
,
228 /* 10 characters is enough for max int value. */
229 char name
[sizeof ("lib0000000000.so")];
231 } __attribute__ ((packed
));
233 void ***host_table_descr
= (void ***) lib_descrs
[lib_num
].first
;
234 void **host_func_start
= host_table_descr
[0];
235 void **host_func_end
= host_table_descr
[1];
236 void **host_var_start
= host_table_descr
[2];
237 void **host_var_end
= host_table_descr
[3];
239 void **target_image_descr
= (void **) lib_descrs
[lib_num
].second
;
240 void *image_start
= target_image_descr
[0];
241 void *image_end
= target_image_descr
[1];
243 TRACE ("() host_table_descr { %p, %p, %p, %p }", host_func_start
,
244 host_func_end
, host_var_start
, host_var_end
);
245 TRACE ("() target_image_descr { %p, %p }", image_start
, image_end
);
247 int64_t image_size
= (uintptr_t) image_end
- (uintptr_t) image_start
;
249 = (TargetImage
*) malloc (sizeof (int64_t) + sizeof ("lib0000000000.so")
253 fprintf (stderr
, "%s: Can't allocate memory\n", __FILE__
);
257 image
->size
= image_size
;
258 sprintf (image
->name
, "lib%010d.so", lib_num
);
259 memcpy (image
->data
, image_start
, image
->size
);
261 TRACE ("() __offload_register_image %s { %p, %d }",
262 image
->name
, image_start
, image
->size
);
263 __offload_register_image (image
);
265 int tgt_num_funcs
= 0;
266 int tgt_num_vars
= 0;
267 void **tgt_table
= NULL
;
268 get_target_table (device
, tgt_num_funcs
, tgt_num_vars
, tgt_table
);
271 /* The func table contains only addresses, the var table contains addresses
272 and corresponding sizes. */
273 int host_num_funcs
= host_func_end
- host_func_start
;
274 int host_num_vars
= (host_var_end
- host_var_start
) / 2;
275 TRACE ("() host_num_funcs = %d, tgt_num_funcs = %d",
276 host_num_funcs
, tgt_num_funcs
);
277 TRACE ("() host_num_vars = %d, tgt_num_vars = %d",
278 host_num_vars
, tgt_num_vars
);
279 if (host_num_funcs
!= tgt_num_funcs
)
281 fprintf (stderr
, "%s: Can't map target functions\n", __FILE__
);
284 if (host_num_vars
!= tgt_num_vars
)
286 fprintf (stderr
, "%s: Can't map target variables\n", __FILE__
);
290 table
= (mapping_table
*) realloc (table
, (table_size
+ host_num_funcs
292 * sizeof (mapping_table
));
295 fprintf (stderr
, "%s: Can't allocate memory\n", __FILE__
);
299 for (int i
= 0; i
< host_num_funcs
; i
++)
302 t
.host_start
= (uintptr_t) host_func_start
[i
];
303 t
.host_end
= t
.host_start
+ 1;
304 t
.tgt_start
= (uintptr_t) tgt_table
[i
];
305 t
.tgt_end
= t
.tgt_start
+ 1;
307 TRACE ("() lib %d, func %d:\t0x%llx -- 0x%llx",
308 lib_num
, i
, t
.host_start
, t
.tgt_start
);
310 table
[table_size
++] = t
;
313 for (int i
= 0; i
< host_num_vars
* 2; i
+= 2)
316 t
.host_start
= (uintptr_t) host_var_start
[i
];
317 t
.host_end
= t
.host_start
+ (uintptr_t) host_var_start
[i
+1];
318 t
.tgt_start
= (uintptr_t) tgt_table
[tgt_num_funcs
+i
];
319 t
.tgt_end
= t
.tgt_start
+ (uintptr_t) tgt_table
[tgt_num_funcs
+i
+1];
321 TRACE ("() lib %d, var %d:\t0x%llx (%d) -- 0x%llx (%d)", lib_num
, i
/2,
322 t
.host_start
, t
.host_end
- t
.host_start
,
323 t
.tgt_start
, t
.tgt_end
- t
.tgt_start
);
325 table
[table_size
++] = t
;
332 GOMP_OFFLOAD_get_table (int device
, void *result
)
334 TRACE ("(num_libraries = %d)", num_libraries
);
336 mapping_table
*table
= NULL
;
339 for (int i
= 0; i
< num_libraries
; i
++)
340 load_lib_and_get_table (device
, i
, table
, table_size
);
342 *(void **) result
= table
;
347 GOMP_OFFLOAD_alloc (int device
, size_t size
)
349 TRACE ("(size = %d)", size
);
352 VarDesc vd1
[2] = { vd_host2tgt
, vd_tgt2host
};
354 vd1
[0].size
= sizeof (size
);
355 vd1
[1].ptr
= &tgt_ptr
;
356 vd1
[1].size
= sizeof (void *);
357 VarDesc2 vd1g
[2] = { { "size", 0 }, { "tgt_ptr", 0 } };
359 offload (__FILE__
, __LINE__
, device
, "__offload_target_alloc", 2, vd1
, vd1g
);
365 GOMP_OFFLOAD_free (int device
, void *tgt_ptr
)
367 TRACE ("(tgt_ptr = %p)", tgt_ptr
);
369 VarDesc vd1
= vd_host2tgt
;
371 vd1
.size
= sizeof (void *);
372 VarDesc2 vd1g
= { "tgt_ptr", 0 };
374 offload (__FILE__
, __LINE__
, device
, "__offload_target_free", 1, &vd1
, &vd1g
);
378 GOMP_OFFLOAD_host2dev (int device
, void *tgt_ptr
, const void *host_ptr
,
381 TRACE ("(tgt_ptr = %p, host_ptr = %p, size = %d)", tgt_ptr
, host_ptr
, size
);
385 VarDesc vd1
[2] = { vd_host2tgt
, vd_host2tgt
};
386 vd1
[0].ptr
= &tgt_ptr
;
387 vd1
[0].size
= sizeof (void *);
389 vd1
[1].size
= sizeof (size
);
390 VarDesc2 vd1g
[2] = { { "tgt_ptr", 0 }, { "size", 0 } };
392 offload (__FILE__
, __LINE__
, device
, "__offload_target_host2tgt_p1", 2,
395 VarDesc vd2
= vd_host2tgt
;
396 vd2
.ptr
= (void *) host_ptr
;
398 VarDesc2 vd2g
= { "var", 0 };
400 offload (__FILE__
, __LINE__
, device
, "__offload_target_host2tgt_p2", 1,
407 GOMP_OFFLOAD_dev2host (int device
, void *host_ptr
, const void *tgt_ptr
,
410 TRACE ("(host_ptr = %p, tgt_ptr = %p, size = %d)", host_ptr
, tgt_ptr
, size
);
414 VarDesc vd1
[2] = { vd_host2tgt
, vd_host2tgt
};
415 vd1
[0].ptr
= &tgt_ptr
;
416 vd1
[0].size
= sizeof (void *);
418 vd1
[1].size
= sizeof (size
);
419 VarDesc2 vd1g
[2] = { { "tgt_ptr", 0 }, { "size", 0 } };
421 offload (__FILE__
, __LINE__
, device
, "__offload_target_tgt2host_p1", 2,
424 VarDesc vd2
= vd_tgt2host
;
425 vd2
.ptr
= (void *) host_ptr
;
427 VarDesc2 vd2g
= { "var", 0 };
429 offload (__FILE__
, __LINE__
, device
, "__offload_target_tgt2host_p2", 1,
436 GOMP_OFFLOAD_run (int device
, void *tgt_fn
, void *tgt_vars
)
438 TRACE ("(tgt_fn = %p, tgt_vars = %p)", tgt_fn
, tgt_vars
);
440 VarDesc vd1
[2] = { vd_host2tgt
, vd_host2tgt
};
441 vd1
[0].ptr
= &tgt_fn
;
442 vd1
[0].size
= sizeof (void *);
443 vd1
[1].ptr
= &tgt_vars
;
444 vd1
[1].size
= sizeof (void *);
445 VarDesc2 vd1g
[2] = { { "tgt_fn", 0 }, { "tgt_vars", 0 } };
447 offload (__FILE__
, __LINE__
, device
, "__offload_target_run", 2, vd1
, vd1g
);