xref: /freebsd/contrib/llvm-project/openmp/runtime/src/ompt-general.cpp (revision 700637cbb5e582861067a11aaca4d053546871d2)
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 
116 /// Used to track the initializer and the finalizer provided by libomptarget
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 
ompt_tool_darwin(unsigned int omp_version,const char * runtime_version)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 *
ompt_start_tool(unsigned int omp_version,const char * runtime_version)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 *
ompt_tool_windows(unsigned int omp_version,const char * runtime_version)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 *
ompt_try_start_tool(unsigned int omp_version,const char * runtime_version)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 
895 /// Lookup function to query libomp callbacks registered by the tool
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 
918 /// This function is called by the libomptarget connector to assign
919 /// callbacks already registered with libomp.
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 }
939