offload_target_main.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380
  1. /* Plugin for offload execution on Intel MIC devices.
  2. Copyright (C) 2014-2016 Free Software Foundation, Inc.
  3. Contributed by Ilya Verbin <ilya.verbin@intel.com>.
  4. This file is part of the GNU Offloading and Multi Processing Library
  5. (libgomp).
  6. Libgomp is free software; you can redistribute it and/or modify it
  7. under the terms of the GNU General Public License as published by
  8. the Free Software Foundation; either version 3, or (at your option)
  9. any later version.
  10. Libgomp is distributed in the hope that it will be useful, but WITHOUT ANY
  11. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  12. FOR A PARTICULAR PURPOSE. See the GNU General Public License for
  13. more details.
  14. Under Section 7 of GPL version 3, you are granted additional
  15. permissions described in the GCC Runtime Library Exception, version
  16. 3.1, as published by the Free Software Foundation.
  17. You should have received a copy of the GNU General Public License and
  18. a copy of the GCC Runtime Library Exception along with this program;
  19. see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
  20. <http://www.gnu.org/licenses/>. */
  21. /* Target side part of a libgomp plugin. */
  22. #include <stdint.h>
  23. #include <stdio.h>
  24. #include <stdlib.h>
  25. #include "compiler_if_target.h"
  26. #ifdef DEBUG
  27. #define TRACE(...) \
  28. { \
  29. fprintf (stderr, "TARGET:\t%s:%s ", __FILE__, __FUNCTION__); \
  30. fprintf (stderr, __VA_ARGS__); \
  31. fprintf (stderr, "\n"); \
  32. }
  33. #else
  34. #define TRACE { }
  35. #endif
  36. static VarDesc vd_host2tgt = {
  37. { 1, 1 }, /* dst, src */
  38. { 1, 0 }, /* in, out */
  39. 1, /* alloc_if */
  40. 1, /* free_if */
  41. 4, /* align */
  42. 0, /* mic_offset */
  43. { 0, 0, 0, 0, 0, 0, 0, 0 }, /* is_static, is_static_dstn, has_length,
  44. is_stack_buf, sink_addr, alloc_disp,
  45. is_noncont_src, is_noncont_dst */
  46. 0, /* offset */
  47. 0, /* size */
  48. 1, /* count */
  49. 0, /* alloc */
  50. 0, /* into */
  51. 0 /* ptr */
  52. };
  53. static VarDesc vd_tgt2host = {
  54. { 1, 1 }, /* dst, src */
  55. { 0, 1 }, /* in, out */
  56. 1, /* alloc_if */
  57. 1, /* free_if */
  58. 4, /* align */
  59. 0, /* mic_offset */
  60. { 0, 0, 0, 0, 0, 0, 0, 0 }, /* is_static, is_static_dstn, has_length,
  61. is_stack_buf, sink_addr, alloc_disp,
  62. is_noncont_src, is_noncont_dst */
  63. 0, /* offset */
  64. 0, /* size */
  65. 1, /* count */
  66. 0, /* alloc */
  67. 0, /* into */
  68. 0 /* ptr */
  69. };
  70. /* Pointer to the descriptor of the last loaded shared library. */
  71. static void *last_loaded_library = NULL;
  72. /* Pointer and size of the variable, used in __offload_target_host2tgt_p[12]
  73. and __offload_target_tgt2host_p[12]. */
  74. static void *last_var_ptr = NULL;
  75. static int last_var_size = 0;
  76. /* Override the corresponding functions from libgomp. */
  77. extern "C" int
  78. omp_is_initial_device (void) __GOMP_NOTHROW
  79. {
  80. return 0;
  81. }
  82. extern "C" int32_t
  83. omp_is_initial_device_ (void)
  84. {
  85. return omp_is_initial_device ();
  86. }
  87. /* Dummy function needed for the initialization of target process during the
  88. first call to __offload_offload1. */
  89. static void
  90. __offload_target_init_proc (OFFLOAD ofldt)
  91. {
  92. TRACE ("");
  93. }
  94. /* Collect addresses of the offload functions and of the global variables from
  95. the library descriptor and send them to host.
  96. Part 1: Send num_funcs and num_vars to host. */
  97. static void
  98. __offload_target_table_p1 (OFFLOAD ofldt)
  99. {
  100. void ***lib_descr = (void ***) last_loaded_library;
  101. if (lib_descr == NULL)
  102. {
  103. TRACE ("");
  104. fprintf (stderr, "Error! No shared libraries loaded on target.\n");
  105. return;
  106. }
  107. void **func_table_begin = lib_descr[0];
  108. void **func_table_end = lib_descr[1];
  109. void **var_table_begin = lib_descr[2];
  110. void **var_table_end = lib_descr[3];
  111. /* The func table contains only addresses, the var table contains addresses
  112. and corresponding sizes. */
  113. int num_funcs = func_table_end - func_table_begin;
  114. int num_vars = (var_table_end - var_table_begin) / 2;
  115. TRACE ("(num_funcs = %d, num_vars = %d)", num_funcs, num_vars);
  116. VarDesc vd[2] = { vd_tgt2host, vd_tgt2host };
  117. vd[0].ptr = &num_funcs;
  118. vd[0].size = sizeof (num_funcs);
  119. vd[1].ptr = &num_vars;
  120. vd[1].size = sizeof (num_vars);
  121. __offload_target_enter (ofldt, 2, vd, NULL);
  122. __offload_target_leave (ofldt);
  123. }
  124. /* Part 2: Send the table with addresses to host. */
  125. static void
  126. __offload_target_table_p2 (OFFLOAD ofldt)
  127. {
  128. void ***lib_descr = (void ***) last_loaded_library;
  129. void **func_table_begin = lib_descr[0];
  130. void **func_table_end = lib_descr[1];
  131. void **var_table_begin = lib_descr[2];
  132. void **var_table_end = lib_descr[3];
  133. int num_funcs = func_table_end - func_table_begin;
  134. int num_vars = (var_table_end - var_table_begin) / 2;
  135. int table_size = (num_funcs + 2 * num_vars) * sizeof (void *);
  136. void **table = (void **) malloc (table_size);
  137. TRACE ("(table_size = %d)", table_size);
  138. VarDesc vd = vd_tgt2host;
  139. vd.ptr = table;
  140. vd.size = table_size;
  141. __offload_target_enter (ofldt, 1, &vd, NULL);
  142. void **p;
  143. int i = 0;
  144. for (p = func_table_begin; p < func_table_end; p++, i++)
  145. table[i] = *p;
  146. for (p = var_table_begin; p < var_table_end; p++, i++)
  147. table[i] = *p;
  148. __offload_target_leave (ofldt);
  149. free (table);
  150. }
  151. /* Allocate size bytes and send a pointer to the allocated memory to host. */
  152. static void
  153. __offload_target_alloc (OFFLOAD ofldt)
  154. {
  155. size_t size = 0;
  156. void *ptr = NULL;
  157. VarDesc vd[2] = { vd_host2tgt, vd_tgt2host };
  158. vd[0].ptr = &size;
  159. vd[0].size = sizeof (size);
  160. vd[1].ptr = &ptr;
  161. vd[1].size = sizeof (void *);
  162. __offload_target_enter (ofldt, 2, vd, NULL);
  163. ptr = malloc (size);
  164. TRACE ("(size = %d): ptr = %p", size, ptr);
  165. __offload_target_leave (ofldt);
  166. }
  167. /* Free the memory space pointed to by ptr. */
  168. static void
  169. __offload_target_free (OFFLOAD ofldt)
  170. {
  171. void *ptr = 0;
  172. VarDesc vd = vd_host2tgt;
  173. vd.ptr = &ptr;
  174. vd.size = sizeof (void *);
  175. __offload_target_enter (ofldt, 1, &vd, NULL);
  176. TRACE ("(ptr = %p)", ptr);
  177. free (ptr);
  178. __offload_target_leave (ofldt);
  179. }
  180. /* Receive var_size bytes from host and store to var_ptr.
  181. Part 1: Receive var_ptr and var_size from host. */
  182. static void
  183. __offload_target_host2tgt_p1 (OFFLOAD ofldt)
  184. {
  185. void *var_ptr = NULL;
  186. size_t var_size = 0;
  187. VarDesc vd[2] = { vd_host2tgt, vd_host2tgt };
  188. vd[0].ptr = &var_ptr;
  189. vd[0].size = sizeof (void *);
  190. vd[1].ptr = &var_size;
  191. vd[1].size = sizeof (var_size);
  192. __offload_target_enter (ofldt, 2, vd, NULL);
  193. TRACE ("(var_ptr = %p, var_size = %d)", var_ptr, var_size);
  194. last_var_ptr = var_ptr;
  195. last_var_size = var_size;
  196. __offload_target_leave (ofldt);
  197. }
  198. /* Part 2: Receive the data from host. */
  199. static void
  200. __offload_target_host2tgt_p2 (OFFLOAD ofldt)
  201. {
  202. TRACE ("(last_var_ptr = %p, last_var_size = %d)",
  203. last_var_ptr, last_var_size);
  204. VarDesc vd = vd_host2tgt;
  205. vd.ptr = last_var_ptr;
  206. vd.size = last_var_size;
  207. __offload_target_enter (ofldt, 1, &vd, NULL);
  208. __offload_target_leave (ofldt);
  209. }
  210. /* Send var_size bytes from var_ptr to host.
  211. Part 1: Receive var_ptr and var_size from host. */
  212. static void
  213. __offload_target_tgt2host_p1 (OFFLOAD ofldt)
  214. {
  215. void *var_ptr = NULL;
  216. size_t var_size = 0;
  217. VarDesc vd[2] = { vd_host2tgt, vd_host2tgt };
  218. vd[0].ptr = &var_ptr;
  219. vd[0].size = sizeof (void *);
  220. vd[1].ptr = &var_size;
  221. vd[1].size = sizeof (var_size);
  222. __offload_target_enter (ofldt, 2, vd, NULL);
  223. TRACE ("(var_ptr = %p, var_size = %d)", var_ptr, var_size);
  224. last_var_ptr = var_ptr;
  225. last_var_size = var_size;
  226. __offload_target_leave (ofldt);
  227. }
  228. /* Part 2: Send the data to host. */
  229. static void
  230. __offload_target_tgt2host_p2 (OFFLOAD ofldt)
  231. {
  232. TRACE ("(last_var_ptr = %p, last_var_size = %d)",
  233. last_var_ptr, last_var_size);
  234. VarDesc vd = vd_tgt2host;
  235. vd.ptr = last_var_ptr;
  236. vd.size = last_var_size;
  237. __offload_target_enter (ofldt, 1, &vd, NULL);
  238. __offload_target_leave (ofldt);
  239. }
  240. /* Copy SIZE bytes from SRC_PTR to DST_PTR. */
  241. static void
  242. __offload_target_tgt2tgt (OFFLOAD ofldt)
  243. {
  244. void *src_ptr = NULL;
  245. void *dst_ptr = NULL;
  246. size_t size = 0;
  247. VarDesc vd[3] = { vd_host2tgt, vd_host2tgt, vd_host2tgt };
  248. vd[0].ptr = &dst_ptr;
  249. vd[0].size = sizeof (void *);
  250. vd[1].ptr = &src_ptr;
  251. vd[1].size = sizeof (void *);
  252. vd[2].ptr = &size;
  253. vd[2].size = sizeof (size);
  254. __offload_target_enter (ofldt, 3, vd, NULL);
  255. TRACE ("(dst_ptr = %p, src_ptr = %p, size = %d)", dst_ptr, src_ptr, size);
  256. memcpy (dst_ptr, src_ptr, size);
  257. __offload_target_leave (ofldt);
  258. }
  259. /* Call offload function by the address fn_ptr and pass vars_ptr to it. */
  260. static void
  261. __offload_target_run (OFFLOAD ofldt)
  262. {
  263. void *fn_ptr;
  264. void *vars_ptr;
  265. VarDesc vd[2] = { vd_host2tgt, vd_host2tgt };
  266. vd[0].ptr = &fn_ptr;
  267. vd[0].size = sizeof (void *);
  268. vd[1].ptr = &vars_ptr;
  269. vd[1].size = sizeof (void *);
  270. __offload_target_enter (ofldt, 2, vd, NULL);
  271. TRACE ("(fn_ptr = %p, vars_ptr = %p)", fn_ptr, vars_ptr);
  272. void (*fn)(void *) = (void (*)(void *)) fn_ptr;
  273. fn (vars_ptr);
  274. __offload_target_leave (ofldt);
  275. }
  276. /* This should be called from every library with offloading. */
  277. extern "C" void
  278. target_register_lib (const void *target_table)
  279. {
  280. TRACE ("(target_table = %p { %p, %p, %p, %p })", target_table,
  281. ((void **) target_table)[0], ((void **) target_table)[1],
  282. ((void **) target_table)[2], ((void **) target_table)[3]);
  283. last_loaded_library = (void *) target_table;
  284. }
  285. /* Use __offload_target_main from liboffload. */
  286. int
  287. main (int argc, char **argv)
  288. {
  289. __offload_target_main ();
  290. return 0;
  291. }
  292. /* Register offload_target_main's functions in the liboffload. */
  293. struct Entry {
  294. const char *name;
  295. void *func;
  296. };
  297. #define REGISTER(f) \
  298. extern "C" const Entry __offload_target_##f##_$entry \
  299. __attribute__ ((section(".OffloadEntryTable."))) = { \
  300. "__offload_target_"#f, \
  301. (void *) __offload_target_##f \
  302. }
  303. REGISTER (init_proc);
  304. REGISTER (table_p1);
  305. REGISTER (table_p2);
  306. REGISTER (alloc);
  307. REGISTER (free);
  308. REGISTER (host2tgt_p1);
  309. REGISTER (host2tgt_p2);
  310. REGISTER (tgt2host_p1);
  311. REGISTER (tgt2host_p2);
  312. REGISTER (tgt2tgt);
  313. REGISTER (run);
  314. #undef REGISTER