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 
502  if (ompt_enabled.ompt_callback_thread_begin) {
503  ompt_callbacks.ompt_callback(ompt_callback_thread_begin)(
504  ompt_thread_initial, __ompt_get_thread_data_internal());
505  }
506  ompt_data_t *task_data = nullptr;
507  ompt_data_t *parallel_data = nullptr;
508  __ompt_get_task_info_internal(0, NULL, &task_data, NULL, &parallel_data,
509  NULL);
510  if (ompt_enabled.ompt_callback_implicit_task) {
511  ompt_callbacks.ompt_callback(ompt_callback_implicit_task)(
512  ompt_scope_begin, parallel_data, task_data, 1, 1, ompt_task_initial);
513  }
514 
515  ompt_set_thread_state(root_thread, ompt_state_work_serial);
516  }
517 }
518 
519 void ompt_fini() {
520  if (ompt_enabled.enabled) {
521  if (ompt_start_tool_result && ompt_start_tool_result->finalize) {
522  ompt_start_tool_result->finalize(&(ompt_start_tool_result->tool_data));
523  }
524  if (libomptarget_ompt_result && libomptarget_ompt_result->finalize) {
525  libomptarget_ompt_result->finalize(NULL);
526  }
527  }
528 
529  if (ompt_archer_module)
530  OMPT_DLCLOSE(ompt_archer_module);
531  if (ompt_tool_module)
532  OMPT_DLCLOSE(ompt_tool_module);
533  memset(&ompt_enabled, 0, sizeof(ompt_enabled));
534 }
535 
536 /*****************************************************************************
537  * interface operations
538  ****************************************************************************/
539 
540 /*****************************************************************************
541  * state
542  ****************************************************************************/
543 
544 OMPT_API_ROUTINE int ompt_enumerate_states(int current_state, int *next_state,
545  const char **next_state_name) {
546  const static int len = sizeof(ompt_state_info) / sizeof(ompt_state_info_t);
547  int i = 0;
548 
549  for (i = 0; i < len - 1; i++) {
550  if (ompt_state_info[i].state_id == current_state) {
551  *next_state = ompt_state_info[i + 1].state_id;
552  *next_state_name = ompt_state_info[i + 1].state_name;
553  return 1;
554  }
555  }
556 
557  return 0;
558 }
559 
560 OMPT_API_ROUTINE int ompt_enumerate_mutex_impls(int current_impl,
561  int *next_impl,
562  const char **next_impl_name) {
563  const static int len =
564  sizeof(kmp_mutex_impl_info) / sizeof(kmp_mutex_impl_info_t);
565  int i = 0;
566  for (i = 0; i < len - 1; i++) {
567  if (kmp_mutex_impl_info[i].id != current_impl)
568  continue;
569  *next_impl = kmp_mutex_impl_info[i + 1].id;
570  *next_impl_name = kmp_mutex_impl_info[i + 1].name;
571  return 1;
572  }
573  return 0;
574 }
575 
576 /*****************************************************************************
577  * callbacks
578  ****************************************************************************/
579 
580 OMPT_API_ROUTINE ompt_set_result_t ompt_set_callback(ompt_callbacks_t which,
581  ompt_callback_t callback) {
582  switch (which) {
583 
584 #define ompt_event_macro(event_name, callback_type, event_id) \
585  case event_name: \
586  ompt_callbacks.ompt_callback(event_name) = (callback_type)callback; \
587  ompt_enabled.event_name = (callback != 0); \
588  if (callback) \
589  return ompt_event_implementation_status(event_name); \
590  else \
591  return ompt_set_always;
592 
593  FOREACH_OMPT_EVENT(ompt_event_macro)
594 
595 #undef ompt_event_macro
596 
597  default:
598  return ompt_set_error;
599  }
600 }
601 
602 OMPT_API_ROUTINE int ompt_get_callback(ompt_callbacks_t which,
603  ompt_callback_t *callback) {
604  if (!ompt_enabled.enabled)
605  return ompt_get_callback_failure;
606 
607  switch (which) {
608 
609 #define ompt_event_macro(event_name, callback_type, event_id) \
610  case event_name: { \
611  ompt_callback_t mycb = \
612  (ompt_callback_t)ompt_callbacks.ompt_callback(event_name); \
613  if (ompt_enabled.event_name && mycb) { \
614  *callback = mycb; \
615  return ompt_get_callback_success; \
616  } \
617  return ompt_get_callback_failure; \
618  }
619 
620  FOREACH_OMPT_EVENT(ompt_event_macro)
621 
622 #undef ompt_event_macro
623 
624  default:
625  return ompt_get_callback_failure;
626  }
627 }
628 
629 /*****************************************************************************
630  * parallel regions
631  ****************************************************************************/
632 
633 OMPT_API_ROUTINE int ompt_get_parallel_info(int ancestor_level,
634  ompt_data_t **parallel_data,
635  int *team_size) {
636  if (!ompt_enabled.enabled)
637  return 0;
638  return __ompt_get_parallel_info_internal(ancestor_level, parallel_data,
639  team_size);
640 }
641 
642 OMPT_API_ROUTINE int ompt_get_state(ompt_wait_id_t *wait_id) {
643  if (!ompt_enabled.enabled)
644  return ompt_state_work_serial;
645  int thread_state = __ompt_get_state_internal(wait_id);
646 
647  if (thread_state == ompt_state_undefined) {
648  thread_state = ompt_state_work_serial;
649  }
650 
651  return thread_state;
652 }
653 
654 /*****************************************************************************
655  * tasks
656  ****************************************************************************/
657 
658 OMPT_API_ROUTINE ompt_data_t *ompt_get_thread_data(void) {
659  if (!ompt_enabled.enabled)
660  return NULL;
661  return __ompt_get_thread_data_internal();
662 }
663 
664 OMPT_API_ROUTINE int ompt_get_task_info(int ancestor_level, int *type,
665  ompt_data_t **task_data,
666  ompt_frame_t **task_frame,
667  ompt_data_t **parallel_data,
668  int *thread_num) {
669  if (!ompt_enabled.enabled)
670  return 0;
671  return __ompt_get_task_info_internal(ancestor_level, type, task_data,
672  task_frame, parallel_data, thread_num);
673 }
674 
675 OMPT_API_ROUTINE int ompt_get_task_memory(void **addr, size_t *size,
676  int block) {
677  return __ompt_get_task_memory_internal(addr, size, block);
678 }
679 
680 /*****************************************************************************
681  * num_procs
682  ****************************************************************************/
683 
684 OMPT_API_ROUTINE int ompt_get_num_procs(void) {
685  // copied from kmp_ftn_entry.h (but modified: OMPT can only be called when
686  // runtime is initialized)
687  return __kmp_avail_proc;
688 }
689 
690 /*****************************************************************************
691  * places
692  ****************************************************************************/
693 
694 OMPT_API_ROUTINE int ompt_get_num_places(void) {
695 // copied from kmp_ftn_entry.h (but modified)
696 #if !KMP_AFFINITY_SUPPORTED
697  return 0;
698 #else
699  if (!KMP_AFFINITY_CAPABLE())
700  return 0;
701  return __kmp_affinity.num_masks;
702 #endif
703 }
704 
705 OMPT_API_ROUTINE int ompt_get_place_proc_ids(int place_num, int ids_size,
706  int *ids) {
707 // copied from kmp_ftn_entry.h (but modified)
708 #if !KMP_AFFINITY_SUPPORTED
709  return 0;
710 #else
711  int i, count;
712  SimpleVLA<int> tmp_ids(ids_size);
713  for (int j = 0; j < ids_size; j++)
714  tmp_ids[j] = 0;
715  if (!KMP_AFFINITY_CAPABLE())
716  return 0;
717  if (place_num < 0 || place_num >= (int)__kmp_affinity.num_masks)
718  return 0;
719  /* TODO: Is this safe for asynchronous call from signal handler during runtime
720  * shutdown? */
721  kmp_affin_mask_t *mask = KMP_CPU_INDEX(__kmp_affinity.masks, place_num);
722  count = 0;
723  KMP_CPU_SET_ITERATE(i, mask) {
724  if ((!KMP_CPU_ISSET(i, __kmp_affin_fullMask)) ||
725  (!KMP_CPU_ISSET(i, mask))) {
726  continue;
727  }
728  if (count < ids_size)
729  tmp_ids[count] = i;
730  count++;
731  }
732  if (ids_size >= count) {
733  for (i = 0; i < count; i++) {
734  ids[i] = tmp_ids[i];
735  }
736  }
737  return count;
738 #endif
739 }
740 
741 OMPT_API_ROUTINE int ompt_get_place_num(void) {
742 // copied from kmp_ftn_entry.h (but modified)
743 #if !KMP_AFFINITY_SUPPORTED
744  return -1;
745 #else
746  if (!ompt_enabled.enabled || __kmp_get_gtid() < 0)
747  return -1;
748 
749  int gtid;
750  kmp_info_t *thread;
751  if (!KMP_AFFINITY_CAPABLE())
752  return -1;
753  gtid = __kmp_entry_gtid();
754  thread = __kmp_thread_from_gtid(gtid);
755  if (thread == NULL || thread->th.th_current_place < 0)
756  return -1;
757  return thread->th.th_current_place;
758 #endif
759 }
760 
761 OMPT_API_ROUTINE int ompt_get_partition_place_nums(int place_nums_size,
762  int *place_nums) {
763 // copied from kmp_ftn_entry.h (but modified)
764 #if !KMP_AFFINITY_SUPPORTED
765  return 0;
766 #else
767  if (!ompt_enabled.enabled || __kmp_get_gtid() < 0)
768  return 0;
769 
770  int i, gtid, place_num, first_place, last_place, start, end;
771  kmp_info_t *thread;
772  if (!KMP_AFFINITY_CAPABLE())
773  return 0;
774  gtid = __kmp_entry_gtid();
775  thread = __kmp_thread_from_gtid(gtid);
776  if (thread == NULL)
777  return 0;
778  first_place = thread->th.th_first_place;
779  last_place = thread->th.th_last_place;
780  if (first_place < 0 || last_place < 0)
781  return 0;
782  if (first_place <= last_place) {
783  start = first_place;
784  end = last_place;
785  } else {
786  start = last_place;
787  end = first_place;
788  }
789  if (end - start <= place_nums_size)
790  for (i = 0, place_num = start; place_num <= end; ++place_num, ++i) {
791  place_nums[i] = place_num;
792  }
793  return end - start + 1;
794 #endif
795 }
796 
797 /*****************************************************************************
798  * places
799  ****************************************************************************/
800 
801 OMPT_API_ROUTINE int ompt_get_proc_id(void) {
802  if (!ompt_enabled.enabled || __kmp_get_gtid() < 0)
803  return -1;
804 #if KMP_HAVE_SCHED_GETCPU
805  return sched_getcpu();
806 #elif KMP_OS_WINDOWS
807  PROCESSOR_NUMBER pn;
808  GetCurrentProcessorNumberEx(&pn);
809  return 64 * pn.Group + pn.Number;
810 #else
811  return -1;
812 #endif
813 }
814 
815 /*****************************************************************************
816  * compatability
817  ****************************************************************************/
818 
819 /*
820  * Currently unused function
821 OMPT_API_ROUTINE int ompt_get_ompt_version() { return OMPT_VERSION; }
822 */
823 
824 /*****************************************************************************
825  * application-facing API
826  ****************************************************************************/
827 
828 /*----------------------------------------------------------------------------
829  | control
830  ---------------------------------------------------------------------------*/
831 
832 int __kmp_control_tool(uint64_t command, uint64_t modifier, void *arg) {
833 
834  if (ompt_enabled.enabled) {
835  if (ompt_enabled.ompt_callback_control_tool) {
836  return ompt_callbacks.ompt_callback(ompt_callback_control_tool)(
837  command, modifier, arg, OMPT_LOAD_RETURN_ADDRESS(__kmp_entry_gtid()));
838  } else {
839  return -1;
840  }
841  } else {
842  return -2;
843  }
844 }
845 
846 /*****************************************************************************
847  * misc
848  ****************************************************************************/
849 
850 OMPT_API_ROUTINE uint64_t ompt_get_unique_id(void) {
851  return __ompt_get_unique_id_internal();
852 }
853 
854 OMPT_API_ROUTINE void ompt_finalize_tool(void) { __kmp_internal_end_atexit(); }
855 
856 /*****************************************************************************
857  * Target
858  ****************************************************************************/
859 
860 OMPT_API_ROUTINE int ompt_get_target_info(uint64_t *device_num,
861  ompt_id_t *target_id,
862  ompt_id_t *host_op_id) {
863  return 0; // thread is not in a target region
864 }
865 
866 OMPT_API_ROUTINE int ompt_get_num_devices(void) {
867  return 1; // only one device (the current device) is available
868 }
869 
870 /*****************************************************************************
871  * API inquiry for tool
872  ****************************************************************************/
873 
874 static ompt_interface_fn_t ompt_fn_lookup(const char *s) {
875 
876 #define ompt_interface_fn(fn) \
877  fn##_t fn##_f = fn; \
878  if (strcmp(s, #fn) == 0) \
879  return (ompt_interface_fn_t)fn##_f;
880 
881  FOREACH_OMPT_INQUIRY_FN(ompt_interface_fn)
882 
883 #undef ompt_interface_fn
884 
885  return NULL;
886 }
887 
888 static ompt_data_t *ompt_get_task_data() { return __ompt_get_task_data(); }
889 
890 static ompt_data_t *ompt_get_target_task_data() {
891  return __ompt_get_target_task_data();
892 }
893 
895 static ompt_interface_fn_t ompt_libomp_target_fn_lookup(const char *s) {
896 #define provide_fn(fn) \
897  if (strcmp(s, #fn) == 0) \
898  return (ompt_interface_fn_t)fn;
899 
900  provide_fn(ompt_get_callback);
901  provide_fn(ompt_get_task_data);
902  provide_fn(ompt_get_target_task_data);
903 #undef provide_fn
904 
905 #define ompt_interface_fn(fn, type, code) \
906  if (strcmp(s, #fn) == 0) \
907  return (ompt_interface_fn_t)ompt_callbacks.ompt_callback(fn);
908 
909  FOREACH_OMPT_DEVICE_EVENT(ompt_interface_fn)
910  FOREACH_OMPT_EMI_EVENT(ompt_interface_fn)
911  FOREACH_OMPT_NOEMI_EVENT(ompt_interface_fn)
912 #undef ompt_interface_fn
913 
914  return (ompt_interface_fn_t)0;
915 }
916 
919 _OMP_EXTERN void ompt_libomp_connect(ompt_start_tool_result_t *result) {
920  OMPT_VERBOSE_INIT_PRINT("libomp --> OMPT: Enter ompt_libomp_connect\n");
921 
922  // Ensure libomp callbacks have been added if not already
923  __ompt_force_initialization();
924 
925  if (ompt_enabled.enabled && result) {
926  OMPT_VERBOSE_INIT_PRINT("libomp --> OMPT: Connecting with libomptarget\n");
927  // Pass in the libomp lookup function so that the already registered
928  // functions can be extracted and assigned to the callbacks in
929  // libomptarget
930  result->initialize(ompt_libomp_target_fn_lookup,
931  /* initial_device_num */ 0, /* tool_data */ nullptr);
932  // Track the object provided by libomptarget so that the finalizer can be
933  // called during OMPT finalization
934  libomptarget_ompt_result = result;
935  }
936  OMPT_VERBOSE_INIT_PRINT("libomp --> OMPT: Exit ompt_libomp_connect\n");
937 }