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