LLVM OpenMP* Runtime Library
ompt-general.cpp
1 /*
2  * ompt-general.cpp -- OMPT implementation of interface functions
3  */
4 
5 //===----------------------------------------------------------------------===//
6 //
7 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
8 // See https://llvm.org/LICENSE.txt for license information.
9 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #include "kmp_utils.h"
14 
15 /*****************************************************************************
16  * system include files
17  ****************************************************************************/
18 #include <assert.h>
19 
20 #include <stdint.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #if KMP_OS_UNIX
25 #include <dlfcn.h>
26 #endif
27 
28 /*****************************************************************************
29  * ompt include files
30  ****************************************************************************/
31 
32 #include "ompt-specific.cpp"
33 
34 /*****************************************************************************
35  * macros
36  ****************************************************************************/
37 
38 #define ompt_get_callback_success 1
39 #define ompt_get_callback_failure 0
40 
41 #define no_tool_present 0
42 
43 #define OMPT_API_ROUTINE static
44 
45 #ifndef OMPT_STR_MATCH
46 #define OMPT_STR_MATCH(haystack, needle) (!strcasecmp(haystack, needle))
47 #endif
48 
49 // prints for an enabled OMP_TOOL_VERBOSE_INIT.
50 // In the future a prefix could be added in the first define, the second define
51 // omits the prefix to allow for continued lines. Example: "PREFIX: Start
52 // tool... Success." instead of "PREFIX: Start tool... PREFIX: Success."
53 #define OMPT_VERBOSE_INIT_PRINT(...) \
54  if (verbose_init) \
55  fprintf(verbose_file, __VA_ARGS__)
56 #define OMPT_VERBOSE_INIT_CONTINUED_PRINT(...) \
57  if (verbose_init) \
58  fprintf(verbose_file, __VA_ARGS__)
59 
60 static FILE *verbose_file;
61 static int verbose_init;
62 
63 /*****************************************************************************
64  * types
65  ****************************************************************************/
66 
67 typedef struct {
68  const char *state_name;
69  ompt_state_t state_id;
70 } ompt_state_info_t;
71 
72 typedef struct {
73  const char *name;
74  kmp_mutex_impl_t id;
75 } kmp_mutex_impl_info_t;
76 
77 enum tool_setting_e {
78  omp_tool_error,
79  omp_tool_unset,
80  omp_tool_disabled,
81  omp_tool_enabled
82 };
83 
84 /*****************************************************************************
85  * global variables
86  ****************************************************************************/
87 
88 ompt_callbacks_active_t ompt_enabled;
89 
90 ompt_state_info_t ompt_state_info[] = {
91 #define ompt_state_macro(state, code) {#state, state},
92  FOREACH_OMPT_STATE(ompt_state_macro)
93 #undef ompt_state_macro
94 };
95 
96 kmp_mutex_impl_info_t kmp_mutex_impl_info[] = {
97 #define kmp_mutex_impl_macro(name, id) {#name, name},
98  FOREACH_KMP_MUTEX_IMPL(kmp_mutex_impl_macro)
99 #undef kmp_mutex_impl_macro
100 };
101 
102 ompt_callbacks_internal_t ompt_callbacks;
103 
104 static ompt_start_tool_result_t *ompt_start_tool_result = NULL;
105 
106 #if KMP_OS_WINDOWS
107 static HMODULE ompt_tool_module = NULL;
108 static HMODULE ompt_archer_module = NULL;
109 #define OMPT_DLCLOSE(Lib) FreeLibrary(Lib)
110 #else
111 static void *ompt_tool_module = NULL;
112 static void *ompt_archer_module = NULL;
113 #define OMPT_DLCLOSE(Lib) dlclose(Lib)
114 #endif
115 
117 static ompt_start_tool_result_t *libomptarget_ompt_result = NULL;
118 
119 /*****************************************************************************
120  * forward declarations
121  ****************************************************************************/
122 
123 static ompt_interface_fn_t ompt_fn_lookup(const char *s);
124 
125 OMPT_API_ROUTINE ompt_data_t *ompt_get_thread_data(void);
126 
127 /*****************************************************************************
128  * initialization and finalization (private operations)
129  ****************************************************************************/
130 
131 typedef ompt_start_tool_result_t *(*ompt_start_tool_t)(unsigned int,
132  const char *);
133 
134 #if KMP_OS_DARWIN
135 
136 // While Darwin supports weak symbols, the library that wishes to provide a new
137 // implementation has to link against this runtime which defeats the purpose
138 // of having tools that are agnostic of the underlying runtime implementation.
139 //
140 // Fortunately, the linker includes all symbols of an executable in the global
141 // symbol table by default so dlsym() even finds static implementations of
142 // ompt_start_tool. For this to work on Linux, -Wl,--export-dynamic needs to be
143 // passed when building the application which we don't want to rely on.
144 
145 static ompt_start_tool_result_t *ompt_tool_darwin(unsigned int omp_version,
146  const char *runtime_version) {
147  ompt_start_tool_result_t *ret = NULL;
148  // Search symbol in the current address space.
149  ompt_start_tool_t start_tool =
150  (ompt_start_tool_t)dlsym(RTLD_DEFAULT, "ompt_start_tool");
151  if (start_tool) {
152  ret = start_tool(omp_version, runtime_version);
153  }
154  return ret;
155 }
156 
157 #elif OMPT_HAVE_WEAK_ATTRIBUTE
158 
159 // On Unix-like systems that support weak symbols the following implementation
160 // of ompt_start_tool() will be used in case no tool-supplied implementation of
161 // this function is present in the address space of a process.
162 
163 _OMP_EXTERN OMPT_WEAK_ATTRIBUTE ompt_start_tool_result_t *
164 ompt_start_tool(unsigned int omp_version, const char *runtime_version) {
165  ompt_start_tool_result_t *ret = NULL;
166  // Search next symbol in the current address space. This can happen if the
167  // runtime library is linked before the tool. Since glibc 2.2 strong symbols
168  // don't override weak symbols that have been found before unless the user
169  // sets the environment variable LD_DYNAMIC_WEAK.
170  ompt_start_tool_t next_tool =
171  (ompt_start_tool_t)dlsym(RTLD_NEXT, "ompt_start_tool");
172  if (next_tool) {
173  ret = next_tool(omp_version, runtime_version);
174  }
175  return ret;
176 }
177 
178 #elif OMPT_HAVE_PSAPI
179 
180 // On Windows, the ompt_tool_windows function is used to find the
181 // ompt_start_tool symbol across all modules loaded by a process. If
182 // ompt_start_tool is found, ompt_start_tool's return value is used to
183 // initialize the tool. Otherwise, NULL is returned and OMPT won't be enabled.
184 
185 #include <psapi.h>
186 #pragma comment(lib, "psapi.lib")
187 
188 // The number of loaded modules to start enumeration with EnumProcessModules()
189 #define NUM_MODULES 128
190 
191 static ompt_start_tool_result_t *
192 ompt_tool_windows(unsigned int omp_version, const char *runtime_version) {
193  int i;
194  DWORD needed, new_size;
195  HMODULE *modules;
196  HANDLE process = GetCurrentProcess();
197  modules = (HMODULE *)malloc(NUM_MODULES * sizeof(HMODULE));
198  ompt_start_tool_t ompt_tool_p = NULL;
199 
200 #if OMPT_DEBUG
201  printf("ompt_tool_windows(): looking for ompt_start_tool\n");
202 #endif
203  if (!EnumProcessModules(process, modules, NUM_MODULES * sizeof(HMODULE),
204  &needed)) {
205  // Regardless of the error reason use the stub initialization function
206  free(modules);
207  return NULL;
208  }
209  // Check if NUM_MODULES is enough to list all modules
210  new_size = needed / sizeof(HMODULE);
211  if (new_size > NUM_MODULES) {
212 #if OMPT_DEBUG
213  printf("ompt_tool_windows(): resize buffer to %d bytes\n", needed);
214 #endif
215  modules = (HMODULE *)realloc(modules, needed);
216  // If resizing failed use the stub function.
217  if (!EnumProcessModules(process, modules, needed, &needed)) {
218  free(modules);
219  return NULL;
220  }
221  }
222  for (i = 0; i < new_size; ++i) {
223  (FARPROC &)ompt_tool_p = GetProcAddress(modules[i], "ompt_start_tool");
224  if (ompt_tool_p) {
225 #if OMPT_DEBUG
226  TCHAR modName[MAX_PATH];
227  if (GetModuleFileName(modules[i], modName, MAX_PATH))
228  printf("ompt_tool_windows(): ompt_start_tool found in module %s\n",
229  modName);
230 #endif
231  free(modules);
232  return (*ompt_tool_p)(omp_version, runtime_version);
233  }
234 #if OMPT_DEBUG
235  else {
236  TCHAR modName[MAX_PATH];
237  if (GetModuleFileName(modules[i], modName, MAX_PATH))
238  printf("ompt_tool_windows(): ompt_start_tool not found in module %s\n",
239  modName);
240  }
241 #endif
242  }
243  free(modules);
244  return NULL;
245 }
246 #else
247 #error Activation of OMPT is not supported on this platform.
248 #endif
249 
250 static ompt_start_tool_result_t *
251 ompt_try_start_tool(unsigned int omp_version, const char *runtime_version) {
252  ompt_start_tool_result_t *ret = NULL;
253  ompt_start_tool_t start_tool = NULL;
254 #if KMP_OS_WINDOWS
255  // Cannot use colon to describe a list of absolute paths on Windows
256  const char *sep = ";";
257 #else
258  const char *sep = ":";
259 #endif
260 
261  OMPT_VERBOSE_INIT_PRINT("----- START LOGGING OF TOOL REGISTRATION -----\n");
262  OMPT_VERBOSE_INIT_PRINT("Search for OMP tool in current address space... ");
263 
264 #if KMP_OS_DARWIN
265  // Try in the current address space
266  ret = ompt_tool_darwin(omp_version, runtime_version);
267 #elif OMPT_HAVE_WEAK_ATTRIBUTE
268  ret = ompt_start_tool(omp_version, runtime_version);
269 #elif OMPT_HAVE_PSAPI
270  ret = ompt_tool_windows(omp_version, runtime_version);
271 #else
272 #error Activation of OMPT is not supported on this platform.
273 #endif
274  if (ret) {
275  OMPT_VERBOSE_INIT_CONTINUED_PRINT("Success.\n");
276  OMPT_VERBOSE_INIT_PRINT(
277  "Tool was started and is using the OMPT interface.\n");
278  OMPT_VERBOSE_INIT_PRINT("----- END LOGGING OF TOOL REGISTRATION -----\n");
279  return ret;
280  }
281 
282  // Try tool-libraries-var ICV
283  OMPT_VERBOSE_INIT_CONTINUED_PRINT("Failed.\n");
284  const char *tool_libs = getenv("OMP_TOOL_LIBRARIES");
285  if (tool_libs) {
286  OMPT_VERBOSE_INIT_PRINT("Searching tool libraries...\n");
287  OMPT_VERBOSE_INIT_PRINT("OMP_TOOL_LIBRARIES = %s\n", tool_libs);
288  char *libs = __kmp_str_format("%s", tool_libs);
289  char *buf;
290  char *fname = __kmp_str_token(libs, sep, &buf);
291  // Reset dl-error
292  dlerror();
293 
294  while (fname) {
295 #if KMP_OS_UNIX
296  OMPT_VERBOSE_INIT_PRINT("Opening %s... ", fname);
297  void *h = dlopen(fname, RTLD_LAZY);
298  if (!h) {
299  OMPT_VERBOSE_INIT_CONTINUED_PRINT("Failed: %s\n", dlerror());
300  } else {
301  OMPT_VERBOSE_INIT_CONTINUED_PRINT("Success. \n");
302  OMPT_VERBOSE_INIT_PRINT("Searching for ompt_start_tool in %s... ",
303  fname);
304  dlerror(); // Clear any existing error
305  start_tool = (ompt_start_tool_t)dlsym(h, "ompt_start_tool");
306  if (!start_tool) {
307  char *error = dlerror();
308  if (error != NULL) {
309  OMPT_VERBOSE_INIT_CONTINUED_PRINT("Failed: %s\n", error);
310  } else {
311  OMPT_VERBOSE_INIT_CONTINUED_PRINT("Failed: %s\n",
312  "ompt_start_tool = NULL");
313  }
314  } else
315 #elif KMP_OS_WINDOWS
316  OMPT_VERBOSE_INIT_PRINT("Opening %s... ", fname);
317  HMODULE h = LoadLibrary(fname);
318  if (!h) {
319  OMPT_VERBOSE_INIT_CONTINUED_PRINT("Failed: Error %u\n",
320  (unsigned)GetLastError());
321  } else {
322  OMPT_VERBOSE_INIT_CONTINUED_PRINT("Success. \n");
323  OMPT_VERBOSE_INIT_PRINT("Searching for ompt_start_tool in %s... ",
324  fname);
325  start_tool = (ompt_start_tool_t)GetProcAddress(h, "ompt_start_tool");
326  if (!start_tool) {
327  OMPT_VERBOSE_INIT_CONTINUED_PRINT("Failed: Error %u\n",
328  (unsigned)GetLastError());
329  } else
330 #else
331 #error Activation of OMPT is not supported on this platform.
332 #endif
333  { // if (start_tool)
334  ret = (*start_tool)(omp_version, runtime_version);
335  if (ret) {
336  OMPT_VERBOSE_INIT_CONTINUED_PRINT("Success.\n");
337  OMPT_VERBOSE_INIT_PRINT(
338  "Tool was started and is using the OMPT interface.\n");
339  ompt_tool_module = h;
340  break;
341  }
342  OMPT_VERBOSE_INIT_CONTINUED_PRINT(
343  "Found but not using the OMPT interface.\n");
344  OMPT_VERBOSE_INIT_PRINT("Continuing search...\n");
345  }
346  OMPT_DLCLOSE(h);
347  }
348  fname = __kmp_str_token(NULL, sep, &buf);
349  }
350  __kmp_str_free(&libs);
351  } else {
352  OMPT_VERBOSE_INIT_PRINT("No OMP_TOOL_LIBRARIES defined.\n");
353  }
354 
355  // usable tool found in tool-libraries
356  if (ret) {
357  OMPT_VERBOSE_INIT_PRINT("----- END LOGGING OF TOOL REGISTRATION -----\n");
358  return ret;
359  }
360 
361 #if KMP_OS_UNIX
362  { // Non-standard: load archer tool if application is built with TSan
363  const char *fname = "libarcher.so";
364  OMPT_VERBOSE_INIT_PRINT(
365  "...searching tool libraries failed. Using archer tool.\n");
366  OMPT_VERBOSE_INIT_PRINT("Opening %s... ", fname);
367  void *h = dlopen(fname, RTLD_LAZY);
368  if (h) {
369  OMPT_VERBOSE_INIT_CONTINUED_PRINT("Success.\n");
370  OMPT_VERBOSE_INIT_PRINT("Searching for ompt_start_tool in %s... ", fname);
371  start_tool = (ompt_start_tool_t)dlsym(h, "ompt_start_tool");
372  if (start_tool) {
373  ret = (*start_tool)(omp_version, runtime_version);
374  if (ret) {
375  OMPT_VERBOSE_INIT_CONTINUED_PRINT("Success.\n");
376  OMPT_VERBOSE_INIT_PRINT(
377  "Tool was started and is using the OMPT interface.\n");
378  OMPT_VERBOSE_INIT_PRINT(
379  "----- END LOGGING OF TOOL REGISTRATION -----\n");
380  ompt_archer_module = h;
381  return ret;
382  }
383  OMPT_VERBOSE_INIT_CONTINUED_PRINT(
384  "Found but not using the OMPT interface.\n");
385  } else {
386  OMPT_VERBOSE_INIT_CONTINUED_PRINT("Failed: %s\n", dlerror());
387  }
388  OMPT_DLCLOSE(h);
389  }
390  }
391 #endif
392  OMPT_VERBOSE_INIT_PRINT("No OMP tool loaded.\n");
393  OMPT_VERBOSE_INIT_PRINT("----- END LOGGING OF TOOL REGISTRATION -----\n");
394  return ret;
395 }
396 
397 void ompt_pre_init() {
398  //--------------------------------------------------
399  // Execute the pre-initialization logic only once.
400  //--------------------------------------------------
401  static int ompt_pre_initialized = 0;
402 
403  if (ompt_pre_initialized)
404  return;
405 
406  ompt_pre_initialized = 1;
407 
408  //--------------------------------------------------
409  // Use a tool iff a tool is enabled and available.
410  //--------------------------------------------------
411  const char *ompt_env_var = getenv("OMP_TOOL");
412  tool_setting_e tool_setting = omp_tool_error;
413 
414  if (!ompt_env_var || !strcmp(ompt_env_var, ""))
415  tool_setting = omp_tool_unset;
416  else if (OMPT_STR_MATCH(ompt_env_var, "disabled"))
417  tool_setting = omp_tool_disabled;
418  else if (OMPT_STR_MATCH(ompt_env_var, "enabled"))
419  tool_setting = omp_tool_enabled;
420 
421  const char *ompt_env_verbose_init = getenv("OMP_TOOL_VERBOSE_INIT");
422  // possible options: disabled | stdout | stderr | <filename>
423  // if set, not empty and not disabled -> prepare for logging
424  if (ompt_env_verbose_init && strcmp(ompt_env_verbose_init, "") &&
425  !OMPT_STR_MATCH(ompt_env_verbose_init, "disabled")) {
426  verbose_init = 1;
427  if (OMPT_STR_MATCH(ompt_env_verbose_init, "STDERR"))
428  verbose_file = stderr;
429  else if (OMPT_STR_MATCH(ompt_env_verbose_init, "STDOUT"))
430  verbose_file = stdout;
431  else
432  verbose_file = fopen(ompt_env_verbose_init, "w");
433  } else
434  verbose_init = 0;
435 
436 #if OMPT_DEBUG
437  printf("ompt_pre_init(): tool_setting = %d\n", tool_setting);
438 #endif
439  switch (tool_setting) {
440  case omp_tool_disabled:
441  OMPT_VERBOSE_INIT_PRINT("OMP tool disabled. \n");
442  break;
443 
444  case omp_tool_unset:
445  case omp_tool_enabled:
446 
447  //--------------------------------------------------
448  // Load tool iff specified in environment variable
449  //--------------------------------------------------
450  ompt_start_tool_result =
451  ompt_try_start_tool(__kmp_openmp_version, ompt_get_runtime_version());
452 
453  memset(&ompt_enabled, 0, sizeof(ompt_enabled));
454  break;
455 
456  case omp_tool_error:
457  fprintf(stderr,
458  "Warning: OMP_TOOL has invalid value \"%s\".\n"
459  " legal values are (NULL,\"\",\"disabled\","
460  "\"enabled\").\n",
461  ompt_env_var);
462  break;
463  }
464  if (verbose_init && verbose_file != stderr && verbose_file != stdout)
465  fclose(verbose_file);
466 #if OMPT_DEBUG
467  printf("ompt_pre_init(): ompt_enabled = %d\n", ompt_enabled.enabled);
468 #endif
469 }
470 
471 extern "C" int omp_get_initial_device(void);
472 
473 void ompt_post_init() {
474  //--------------------------------------------------
475  // Execute the post-initialization logic only once.
476  //--------------------------------------------------
477  static int ompt_post_initialized = 0;
478 
479  if (ompt_post_initialized)
480  return;
481 
482  ompt_post_initialized = 1;
483 
484  //--------------------------------------------------
485  // Initialize the tool if so indicated.
486  //--------------------------------------------------
487  if (ompt_start_tool_result) {
488  ompt_enabled.enabled = !!ompt_start_tool_result->initialize(
489  ompt_fn_lookup, omp_get_initial_device(),
490  &(ompt_start_tool_result->tool_data));
491 
492  if (!ompt_enabled.enabled) {
493  // tool not enabled, zero out the bitmap, and done
494  memset(&ompt_enabled, 0, sizeof(ompt_enabled));
495  return;
496  }
497 
498  kmp_info_t *root_thread = ompt_get_thread();
499 
500  ompt_set_thread_state(root_thread, ompt_state_overhead);
501  __ompt_task_init(root_thread->th.th_current_task, 0);
502 
503  if (ompt_enabled.ompt_callback_thread_begin) {
504  ompt_callbacks.ompt_callback(ompt_callback_thread_begin)(
505  ompt_thread_initial, __ompt_get_thread_data_internal());
506  }
507  ompt_data_t *task_data = nullptr;
508  ompt_data_t *parallel_data = nullptr;
509  __ompt_get_task_info_internal(0, NULL, &task_data, NULL, &parallel_data,
510  NULL);
511  if (ompt_enabled.ompt_callback_implicit_task) {
512  ompt_callbacks.ompt_callback(ompt_callback_implicit_task)(
513  ompt_scope_begin, parallel_data, task_data, 1, 1, ompt_task_initial);
514  }
515 
516  ompt_set_thread_state(root_thread, ompt_state_work_serial);
517  }
518 }
519 
520 void ompt_fini() {
521  if (ompt_enabled.enabled) {
522  if (ompt_start_tool_result && ompt_start_tool_result->finalize) {
523  ompt_start_tool_result->finalize(&(ompt_start_tool_result->tool_data));
524  }
525  if (libomptarget_ompt_result && libomptarget_ompt_result->finalize) {
526  libomptarget_ompt_result->finalize(NULL);
527  }
528  }
529 
530  if (ompt_archer_module)
531  OMPT_DLCLOSE(ompt_archer_module);
532  if (ompt_tool_module)
533  OMPT_DLCLOSE(ompt_tool_module);
534  memset(&ompt_enabled, 0, sizeof(ompt_enabled));
535 }
536 
537 /*****************************************************************************
538  * interface operations
539  ****************************************************************************/
540 
541 /*****************************************************************************
542  * state
543  ****************************************************************************/
544 
545 OMPT_API_ROUTINE int ompt_enumerate_states(int current_state, int *next_state,
546  const char **next_state_name) {
547  const static int len = sizeof(ompt_state_info) / sizeof(ompt_state_info_t);
548  int i = 0;
549 
550  for (i = 0; i < len - 1; i++) {
551  if (ompt_state_info[i].state_id == current_state) {
552  *next_state = ompt_state_info[i + 1].state_id;
553  *next_state_name = ompt_state_info[i + 1].state_name;
554  return 1;
555  }
556  }
557 
558  return 0;
559 }
560 
561 OMPT_API_ROUTINE int ompt_enumerate_mutex_impls(int current_impl,
562  int *next_impl,
563  const char **next_impl_name) {
564  const static int len =
565  sizeof(kmp_mutex_impl_info) / sizeof(kmp_mutex_impl_info_t);
566  int i = 0;
567  for (i = 0; i < len - 1; i++) {
568  if (kmp_mutex_impl_info[i].id != current_impl)
569  continue;
570  *next_impl = kmp_mutex_impl_info[i + 1].id;
571  *next_impl_name = kmp_mutex_impl_info[i + 1].name;
572  return 1;
573  }
574  return 0;
575 }
576 
577 /*****************************************************************************
578  * callbacks
579  ****************************************************************************/
580 
581 OMPT_API_ROUTINE ompt_set_result_t ompt_set_callback(ompt_callbacks_t which,
582  ompt_callback_t callback) {
583  switch (which) {
584 
585 #define ompt_event_macro(event_name, callback_type, event_id) \
586  case event_name: \
587  ompt_callbacks.ompt_callback(event_name) = (callback_type)callback; \
588  ompt_enabled.event_name = (callback != 0); \
589  if (callback) \
590  return ompt_event_implementation_status(event_name); \
591  else \
592  return ompt_set_always;
593 
594  FOREACH_OMPT_EVENT(ompt_event_macro)
595 
596 #undef ompt_event_macro
597 
598  default:
599  return ompt_set_error;
600  }
601 }
602 
603 OMPT_API_ROUTINE int ompt_get_callback(ompt_callbacks_t which,
604  ompt_callback_t *callback) {
605  if (!ompt_enabled.enabled)
606  return ompt_get_callback_failure;
607 
608  switch (which) {
609 
610 #define ompt_event_macro(event_name, callback_type, event_id) \
611  case event_name: { \
612  ompt_callback_t mycb = \
613  (ompt_callback_t)ompt_callbacks.ompt_callback(event_name); \
614  if (ompt_enabled.event_name && mycb) { \
615  *callback = mycb; \
616  return ompt_get_callback_success; \
617  } \
618  return ompt_get_callback_failure; \
619  }
620 
621  FOREACH_OMPT_EVENT(ompt_event_macro)
622 
623 #undef ompt_event_macro
624 
625  default:
626  return ompt_get_callback_failure;
627  }
628 }
629 
630 /*****************************************************************************
631  * parallel regions
632  ****************************************************************************/
633 
634 OMPT_API_ROUTINE int ompt_get_parallel_info(int ancestor_level,
635  ompt_data_t **parallel_data,
636  int *team_size) {
637  if (!ompt_enabled.enabled)
638  return 0;
639  return __ompt_get_parallel_info_internal(ancestor_level, parallel_data,
640  team_size);
641 }
642 
643 OMPT_API_ROUTINE int ompt_get_state(ompt_wait_id_t *wait_id) {
644  if (!ompt_enabled.enabled)
645  return ompt_state_work_serial;
646  int thread_state = __ompt_get_state_internal(wait_id);
647 
648  if (thread_state == ompt_state_undefined) {
649  thread_state = ompt_state_work_serial;
650  }
651 
652  return thread_state;
653 }
654 
655 /*****************************************************************************
656  * tasks
657  ****************************************************************************/
658 
659 OMPT_API_ROUTINE ompt_data_t *ompt_get_thread_data(void) {
660  if (!ompt_enabled.enabled)
661  return NULL;
662  return __ompt_get_thread_data_internal();
663 }
664 
665 OMPT_API_ROUTINE int ompt_get_task_info(int ancestor_level, int *type,
666  ompt_data_t **task_data,
667  ompt_frame_t **task_frame,
668  ompt_data_t **parallel_data,
669  int *thread_num) {
670  if (!ompt_enabled.enabled)
671  return 0;
672  return __ompt_get_task_info_internal(ancestor_level, type, task_data,
673  task_frame, parallel_data, thread_num);
674 }
675 
676 OMPT_API_ROUTINE int ompt_get_task_memory(void **addr, size_t *size,
677  int block) {
678  return __ompt_get_task_memory_internal(addr, size, block);
679 }
680 
681 /*****************************************************************************
682  * num_procs
683  ****************************************************************************/
684 
685 OMPT_API_ROUTINE int ompt_get_num_procs(void) {
686  // copied from kmp_ftn_entry.h (but modified: OMPT can only be called when
687  // runtime is initialized)
688  return __kmp_avail_proc;
689 }
690 
691 /*****************************************************************************
692  * places
693  ****************************************************************************/
694 
695 OMPT_API_ROUTINE int ompt_get_num_places(void) {
696 // copied from kmp_ftn_entry.h (but modified)
697 #if !KMP_AFFINITY_SUPPORTED
698  return 0;
699 #else
700  if (!KMP_AFFINITY_CAPABLE())
701  return 0;
702  return __kmp_affinity.num_masks;
703 #endif
704 }
705 
706 OMPT_API_ROUTINE int ompt_get_place_proc_ids(int place_num, int ids_size,
707  int *ids) {
708 // copied from kmp_ftn_entry.h (but modified)
709 #if !KMP_AFFINITY_SUPPORTED
710  return 0;
711 #else
712  int i, count;
713  SimpleVLA<int> tmp_ids(ids_size);
714  for (int j = 0; j < ids_size; j++)
715  tmp_ids[j] = 0;
716  if (!KMP_AFFINITY_CAPABLE())
717  return 0;
718  if (place_num < 0 || place_num >= (int)__kmp_affinity.num_masks)
719  return 0;
720  /* TODO: Is this safe for asynchronous call from signal handler during runtime
721  * shutdown? */
722  kmp_affin_mask_t *mask = KMP_CPU_INDEX(__kmp_affinity.masks, place_num);
723  count = 0;
724  KMP_CPU_SET_ITERATE(i, mask) {
725  if ((!KMP_CPU_ISSET(i, __kmp_affin_fullMask)) ||
726  (!KMP_CPU_ISSET(i, mask))) {
727  continue;
728  }
729  if (count < ids_size)
730  tmp_ids[count] = i;
731  count++;
732  }
733  if (ids_size >= count) {
734  for (i = 0; i < count; i++) {
735  ids[i] = tmp_ids[i];
736  }
737  }
738  return count;
739 #endif
740 }
741 
742 OMPT_API_ROUTINE int ompt_get_place_num(void) {
743 // copied from kmp_ftn_entry.h (but modified)
744 #if !KMP_AFFINITY_SUPPORTED
745  return -1;
746 #else
747  if (!ompt_enabled.enabled || __kmp_get_gtid() < 0)
748  return -1;
749 
750  int gtid;
751  kmp_info_t *thread;
752  if (!KMP_AFFINITY_CAPABLE())
753  return -1;
754  gtid = __kmp_entry_gtid();
755  thread = __kmp_thread_from_gtid(gtid);
756  if (thread == NULL || thread->th.th_current_place < 0)
757  return -1;
758  return thread->th.th_current_place;
759 #endif
760 }
761 
762 OMPT_API_ROUTINE int ompt_get_partition_place_nums(int place_nums_size,
763  int *place_nums) {
764 // copied from kmp_ftn_entry.h (but modified)
765 #if !KMP_AFFINITY_SUPPORTED
766  return 0;
767 #else
768  if (!ompt_enabled.enabled || __kmp_get_gtid() < 0)
769  return 0;
770 
771  int i, gtid, place_num, first_place, last_place, start, end;
772  kmp_info_t *thread;
773  if (!KMP_AFFINITY_CAPABLE())
774  return 0;
775  gtid = __kmp_entry_gtid();
776  thread = __kmp_thread_from_gtid(gtid);
777  if (thread == NULL)
778  return 0;
779  first_place = thread->th.th_first_place;
780  last_place = thread->th.th_last_place;
781  if (first_place < 0 || last_place < 0)
782  return 0;
783  if (first_place <= last_place) {
784  start = first_place;
785  end = last_place;
786  } else {
787  start = last_place;
788  end = first_place;
789  }
790  if (end - start <= place_nums_size)
791  for (i = 0, place_num = start; place_num <= end; ++place_num, ++i) {
792  place_nums[i] = place_num;
793  }
794  return end - start + 1;
795 #endif
796 }
797 
798 /*****************************************************************************
799  * places
800  ****************************************************************************/
801 
802 OMPT_API_ROUTINE int ompt_get_proc_id(void) {
803  if (!ompt_enabled.enabled || __kmp_get_gtid() < 0)
804  return -1;
805 #if KMP_HAVE_SCHED_GETCPU
806  return sched_getcpu();
807 #elif KMP_OS_WINDOWS
808  PROCESSOR_NUMBER pn;
809  GetCurrentProcessorNumberEx(&pn);
810  return 64 * pn.Group + pn.Number;
811 #else
812  return -1;
813 #endif
814 }
815 
816 /*****************************************************************************
817  * compatability
818  ****************************************************************************/
819 
820 /*
821  * Currently unused function
822 OMPT_API_ROUTINE int ompt_get_ompt_version() { return OMPT_VERSION; }
823 */
824 
825 /*****************************************************************************
826  * application-facing API
827  ****************************************************************************/
828 
829 /*----------------------------------------------------------------------------
830  | control
831  ---------------------------------------------------------------------------*/
832 
833 int __kmp_control_tool(uint64_t command, uint64_t modifier, void *arg) {
834 
835  if (ompt_enabled.enabled) {
836  if (ompt_enabled.ompt_callback_control_tool) {
837  return ompt_callbacks.ompt_callback(ompt_callback_control_tool)(
838  command, modifier, arg, OMPT_LOAD_RETURN_ADDRESS(__kmp_entry_gtid()));
839  } else {
840  return -1;
841  }
842  } else {
843  return -2;
844  }
845 }
846 
847 /*****************************************************************************
848  * misc
849  ****************************************************************************/
850 
851 OMPT_API_ROUTINE uint64_t ompt_get_unique_id(void) {
852  return __ompt_get_unique_id_internal();
853 }
854 
855 OMPT_API_ROUTINE void ompt_finalize_tool(void) { __kmp_internal_end_atexit(); }
856 
857 /*****************************************************************************
858  * Target
859  ****************************************************************************/
860 
861 OMPT_API_ROUTINE int ompt_get_target_info(uint64_t *device_num,
862  ompt_id_t *target_id,
863  ompt_id_t *host_op_id) {
864  return 0; // thread is not in a target region
865 }
866 
867 OMPT_API_ROUTINE int ompt_get_num_devices(void) {
868  return 1; // only one device (the current device) is available
869 }
870 
871 /*****************************************************************************
872  * API inquiry for tool
873  ****************************************************************************/
874 
875 static ompt_interface_fn_t ompt_fn_lookup(const char *s) {
876 
877 #define ompt_interface_fn(fn) \
878  fn##_t fn##_f = fn; \
879  if (strcmp(s, #fn) == 0) \
880  return (ompt_interface_fn_t)fn##_f;
881 
882  FOREACH_OMPT_INQUIRY_FN(ompt_interface_fn)
883 
884 #undef ompt_interface_fn
885 
886  return NULL;
887 }
888 
889 static ompt_data_t *ompt_get_task_data() { return __ompt_get_task_data(); }
890 
891 static ompt_data_t *ompt_get_target_task_data() {
892  return __ompt_get_target_task_data();
893 }
894 
896 static ompt_interface_fn_t ompt_libomp_target_fn_lookup(const char *s) {
897 #define provide_fn(fn) \
898  if (strcmp(s, #fn) == 0) \
899  return (ompt_interface_fn_t)fn;
900 
901  provide_fn(ompt_get_callback);
902  provide_fn(ompt_get_task_data);
903  provide_fn(ompt_get_target_task_data);
904 #undef provide_fn
905 
906 #define ompt_interface_fn(fn, type, code) \
907  if (strcmp(s, #fn) == 0) \
908  return (ompt_interface_fn_t)ompt_callbacks.ompt_callback(fn);
909 
910  FOREACH_OMPT_DEVICE_EVENT(ompt_interface_fn)
911  FOREACH_OMPT_EMI_EVENT(ompt_interface_fn)
912  FOREACH_OMPT_NOEMI_EVENT(ompt_interface_fn)
913 #undef ompt_interface_fn
914 
915  return (ompt_interface_fn_t)0;
916 }
917 
920 _OMP_EXTERN void ompt_libomp_connect(ompt_start_tool_result_t *result) {
921  OMPT_VERBOSE_INIT_PRINT("libomp --> OMPT: Enter ompt_libomp_connect\n");
922 
923  // Ensure libomp callbacks have been added if not already
924  __ompt_force_initialization();
925 
926  if (ompt_enabled.enabled && result) {
927  OMPT_VERBOSE_INIT_PRINT("libomp --> OMPT: Connecting with libomptarget\n");
928  // Pass in the libomp lookup function so that the already registered
929  // functions can be extracted and assigned to the callbacks in
930  // libomptarget
931  result->initialize(ompt_libomp_target_fn_lookup,
932  /* initial_device_num */ 0, /* tool_data */ nullptr);
933  // Track the object provided by libomptarget so that the finalizer can be
934  // called during OMPT finalization
935  libomptarget_ompt_result = result;
936  }
937  OMPT_VERBOSE_INIT_PRINT("libomp --> OMPT: Exit ompt_libomp_connect\n");
938 }