2015-01-20 Paolo Carlini <paolo.carlini@oracle.com>
[official-gcc.git] / liboffloadmic / plugin / libgomp-plugin-intelmic.cpp
blob3e7a95860b65cd40084d126e072117bcb21c92eb
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
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 "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"
44 #ifdef DEBUG
45 #define TRACE(...) \
46 { \
47 fprintf (stderr, "HOST:\t%s:%s ", __FILE__, __FUNCTION__); \
48 fprintf (stderr, __VA_ARGS__); \
49 fprintf (stderr, "\n"); \
51 #else
52 #define TRACE { }
53 #endif
56 static VarDesc vd_host2tgt = {
57 { 1, 1 }, /* dst, src */
58 { 1, 0 }, /* in, out */
59 1, /* alloc_if */
60 1, /* free_if */
61 4, /* align */
62 0, /* mic_offset */
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 */
66 0, /* offset */
67 0, /* size */
68 1, /* count */
69 0, /* alloc */
70 0, /* into */
71 0 /* ptr */
74 static VarDesc vd_tgt2host = {
75 { 1, 1 }, /* dst, src */
76 { 0, 1 }, /* in, out */
77 1, /* alloc_if */
78 1, /* free_if */
79 4, /* align */
80 0, /* mic_offset */
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 */
84 0, /* offset */
85 0, /* size */
86 1, /* count */
87 0, /* alloc */
88 0, /* into */
89 0 /* ptr */
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
97 target images. */
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))
107 static void
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);
113 if (!ld_lib_path)
114 return;
116 if (!mic_lib_path)
117 setenv (MIC_LD_LIBRARY_PATH_ENV, ld_lib_path, 1);
118 else
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)
123 : malloc (len));
124 if (!mic_lib_path_new)
126 fprintf (stderr, "%s: Can't allocate memory\n", __FILE__);
127 exit (1);
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);
133 if (!use_alloca)
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);
143 return 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);
151 return 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);
159 return res;
162 extern "C" int
163 GOMP_OFFLOAD_get_num_devices (void)
165 int res = _Offload_number_of_devices ();
166 TRACE ("(): return %d", res);
167 return res;
170 /* This should be called from every shared library with offloading. */
171 extern "C" void
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));
176 num_libraries++;
179 static void
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);
184 if (ofld)
185 __offload_offload1 (ofld, name, 0, num_vars, vars, vars2, 0, NULL, NULL);
186 else
188 fprintf (stderr, "%s:%d: Offload target acquire failed\n", file, line);
189 exit (1);
193 static void
194 register_main_image ()
196 __offload_register_image (&main_target_image);
199 /* Load offload_target_main on target. */
200 extern "C" void
201 GOMP_OFFLOAD_init_device (int device)
203 TRACE ("");
204 pthread_once (&main_image_is_registered, register_main_image);
205 offload (__FILE__, __LINE__, device, "__offload_target_init_proc", 0,
206 NULL, NULL);
209 extern "C" void
210 GOMP_OFFLOAD_fini_device (int device)
212 TRACE ("");
213 /* Unreachable for GOMP_OFFLOAD_CAP_OPENMP_400. */
214 abort ();
217 static void
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,
228 vd1, vd1g);
230 int table_size = num_funcs + 2 * num_vars;
231 if (table_size > 0)
233 table = new void * [table_size];
235 VarDesc vd2;
236 vd2 = vd_tgt2host;
237 vd2.ptr = table;
238 vd2.size = table_size * sizeof (void *);
239 VarDesc2 vd2g = { "table", 0 };
241 offload (__FILE__, __LINE__, device, "__offload_target_table_p2", 1,
242 &vd2, &vd2g);
246 static void
247 load_lib_and_get_table (int device, int lib_num, mapping_table *&table,
248 int &table_size)
250 struct TargetImage {
251 int64_t size;
252 /* 10 characters is enough for max int value. */
253 char name[sizeof ("lib0000000000.so")];
254 char data[];
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;
272 TargetImage *image
273 = (TargetImage *) malloc (sizeof (int64_t) + sizeof ("lib0000000000.so")
274 + image_size);
275 if (!image)
277 fprintf (stderr, "%s: Can't allocate memory\n", __FILE__);
278 exit (1);
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);
293 free (image);
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__);
306 exit (1);
308 if (host_num_vars != tgt_num_vars)
310 fprintf (stderr, "%s: Can't map target variables\n", __FILE__);
311 exit (1);
314 table = (mapping_table *) realloc (table, (table_size + host_num_funcs
315 + host_num_vars)
316 * sizeof (mapping_table));
317 if (table == NULL)
319 fprintf (stderr, "%s: Can't allocate memory\n", __FILE__);
320 exit (1);
323 for (int i = 0; i < host_num_funcs; i++)
325 mapping_table t;
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)
339 mapping_table t;
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;
352 delete [] tgt_table;
355 extern "C" int
356 GOMP_OFFLOAD_get_table (int device, void *result)
358 TRACE ("(num_libraries = %d)", num_libraries);
360 mapping_table *table = NULL;
361 int table_size = 0;
363 for (int i = 0; i < num_libraries; i++)
364 load_lib_and_get_table (device, i, table, table_size);
366 *(void **) result = table;
367 return table_size;
370 extern "C" void *
371 GOMP_OFFLOAD_alloc (int device, size_t size)
373 TRACE ("(size = %d)", size);
375 void *tgt_ptr;
376 VarDesc vd1[2] = { vd_host2tgt, vd_tgt2host };
377 vd1[0].ptr = &size;
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);
385 return tgt_ptr;
388 extern "C" void
389 GOMP_OFFLOAD_free (int device, void *tgt_ptr)
391 TRACE ("(tgt_ptr = %p)", tgt_ptr);
393 VarDesc vd1 = vd_host2tgt;
394 vd1.ptr = &tgt_ptr;
395 vd1.size = sizeof (void *);
396 VarDesc2 vd1g = { "tgt_ptr", 0 };
398 offload (__FILE__, __LINE__, device, "__offload_target_free", 1, &vd1, &vd1g);
401 extern "C" void *
402 GOMP_OFFLOAD_host2dev (int device, void *tgt_ptr, const void *host_ptr,
403 size_t size)
405 TRACE ("(tgt_ptr = %p, host_ptr = %p, size = %d)", tgt_ptr, host_ptr, size);
406 if (!size)
407 return tgt_ptr;
409 VarDesc vd1[2] = { vd_host2tgt, vd_host2tgt };
410 vd1[0].ptr = &tgt_ptr;
411 vd1[0].size = sizeof (void *);
412 vd1[1].ptr = &size;
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,
417 vd1, vd1g);
419 VarDesc vd2 = vd_host2tgt;
420 vd2.ptr = (void *) host_ptr;
421 vd2.size = size;
422 VarDesc2 vd2g = { "var", 0 };
424 offload (__FILE__, __LINE__, device, "__offload_target_host2tgt_p2", 1,
425 &vd2, &vd2g);
427 return tgt_ptr;
430 extern "C" void *
431 GOMP_OFFLOAD_dev2host (int device, void *host_ptr, const void *tgt_ptr,
432 size_t size)
434 TRACE ("(host_ptr = %p, tgt_ptr = %p, size = %d)", host_ptr, tgt_ptr, size);
435 if (!size)
436 return host_ptr;
438 VarDesc vd1[2] = { vd_host2tgt, vd_host2tgt };
439 vd1[0].ptr = &tgt_ptr;
440 vd1[0].size = sizeof (void *);
441 vd1[1].ptr = &size;
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,
446 vd1, vd1g);
448 VarDesc vd2 = vd_tgt2host;
449 vd2.ptr = (void *) host_ptr;
450 vd2.size = size;
451 VarDesc2 vd2g = { "var", 0 };
453 offload (__FILE__, __LINE__, device, "__offload_target_tgt2host_p2", 1,
454 &vd2, &vd2g);
456 return host_ptr;
459 extern "C" void
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);