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         dlerror(); // Clear any existing error
350         start_tool = (ompt_start_tool_t)dlsym(h, "ompt_start_tool");
351         if (!start_tool) {
352           char *error = dlerror();
353           if (error != NULL) {
354             OMPT_VERBOSE_INIT_CONTINUED_PRINT("Failed: %s\n", error);
355           } else {
356             OMPT_VERBOSE_INIT_CONTINUED_PRINT("Failed: %s\n",
357                                               "ompt_start_tool = NULL");
358           }
359         } else
360 #elif KMP_OS_WINDOWS
361       OMPT_VERBOSE_INIT_PRINT("Opening %s... ", fname);
362       HMODULE h = LoadLibrary(fname);
363       if (!h) {
364         OMPT_VERBOSE_INIT_CONTINUED_PRINT("Failed: Error %u\n", GetLastError());
365       } else {
366         OMPT_VERBOSE_INIT_CONTINUED_PRINT("Success. \n");
367         OMPT_VERBOSE_INIT_PRINT("Searching for ompt_start_tool in %s... ",
368                                 fname);
369         start_tool = (ompt_start_tool_t)GetProcAddress(h, "ompt_start_tool");
370         if (!start_tool) {
371           OMPT_VERBOSE_INIT_CONTINUED_PRINT("Failed: Error %u\n",
372                                             GetLastError());
373         } else
374 #else
375 #error Activation of OMPT is not supported on this platform.
376 #endif
377         { // if (start_tool)
378           ret = (*start_tool)(omp_version, runtime_version);
379           if (ret) {
380             OMPT_VERBOSE_INIT_CONTINUED_PRINT("Success.\n");
381             OMPT_VERBOSE_INIT_PRINT(
382                 "Tool was started and is using the OMPT interface.\n");
383             ompt_tool_module = h;
384             break;
385           }
386           OMPT_VERBOSE_INIT_CONTINUED_PRINT(
387               "Found but not using the OMPT interface.\n");
388           OMPT_VERBOSE_INIT_PRINT("Continuing search...\n");
389         }
390         OMPT_DLCLOSE(h);
391       }
392       fname = __kmp_str_token(NULL, sep, &buf);
393     }
394     __kmp_str_free(&libs);
395   } else {
396     OMPT_VERBOSE_INIT_PRINT("No OMP_TOOL_LIBRARIES defined.\n");
397   }
398 
399   // usable tool found in tool-libraries
400   if (ret) {
401     OMPT_VERBOSE_INIT_PRINT("----- END LOGGING OF TOOL REGISTRATION -----\n");
402     return ret;
403   }
404 
405 #if KMP_OS_UNIX
406   { // Non-standard: load archer tool if application is built with TSan
407     const char *fname = "libarcher.so";
408     OMPT_VERBOSE_INIT_PRINT(
409         "...searching tool libraries failed. Using archer tool.\n");
410     OMPT_VERBOSE_INIT_PRINT("Opening %s... ", fname);
411     void *h = dlopen(fname, RTLD_LAZY);
412     if (h) {
413       OMPT_VERBOSE_INIT_CONTINUED_PRINT("Success.\n");
414       OMPT_VERBOSE_INIT_PRINT("Searching for ompt_start_tool in %s... ", fname);
415       start_tool = (ompt_start_tool_t)dlsym(h, "ompt_start_tool");
416       if (start_tool) {
417         ret = (*start_tool)(omp_version, runtime_version);
418         if (ret) {
419           OMPT_VERBOSE_INIT_CONTINUED_PRINT("Success.\n");
420           OMPT_VERBOSE_INIT_PRINT(
421               "Tool was started and is using the OMPT interface.\n");
422           OMPT_VERBOSE_INIT_PRINT(
423               "----- END LOGGING OF TOOL REGISTRATION -----\n");
424           return ret;
425         }
426         OMPT_VERBOSE_INIT_CONTINUED_PRINT(
427             "Found but not using the OMPT interface.\n");
428       } else {
429         OMPT_VERBOSE_INIT_CONTINUED_PRINT("Failed: %s\n", dlerror());
430       }
431     }
432   }
433 #endif
434   OMPT_VERBOSE_INIT_PRINT("No OMP tool loaded.\n");
435   OMPT_VERBOSE_INIT_PRINT("----- END LOGGING OF TOOL REGISTRATION -----\n");
436   return ret;
437 }
438 
439 void ompt_pre_init() {
440   //--------------------------------------------------
441   // Execute the pre-initialization logic only once.
442   //--------------------------------------------------
443   static int ompt_pre_initialized = 0;
444 
445   if (ompt_pre_initialized)
446     return;
447 
448   ompt_pre_initialized = 1;
449 
450   //--------------------------------------------------
451   // Use a tool iff a tool is enabled and available.
452   //--------------------------------------------------
453   const char *ompt_env_var = getenv("OMP_TOOL");
454   tool_setting_e tool_setting = omp_tool_error;
455 
456   if (!ompt_env_var || !strcmp(ompt_env_var, ""))
457     tool_setting = omp_tool_unset;
458   else if (OMPT_STR_MATCH(ompt_env_var, "disabled"))
459     tool_setting = omp_tool_disabled;
460   else if (OMPT_STR_MATCH(ompt_env_var, "enabled"))
461     tool_setting = omp_tool_enabled;
462 
463   const char *ompt_env_verbose_init = getenv("OMP_TOOL_VERBOSE_INIT");
464   // possible options: disabled | stdout | stderr | <filename>
465   // if set, not empty and not disabled -> prepare for logging
466   if (ompt_env_verbose_init && strcmp(ompt_env_verbose_init, "") &&
467       !OMPT_STR_MATCH(ompt_env_verbose_init, "disabled")) {
468     verbose_init = 1;
469     if (OMPT_STR_MATCH(ompt_env_verbose_init, "STDERR"))
470       verbose_file = stderr;
471     else if (OMPT_STR_MATCH(ompt_env_verbose_init, "STDOUT"))
472       verbose_file = stdout;
473     else
474       verbose_file = fopen(ompt_env_verbose_init, "w");
475   } else
476     verbose_init = 0;
477 
478 #if OMPT_DEBUG
479   printf("ompt_pre_init(): tool_setting = %d\n", tool_setting);
480 #endif
481   switch (tool_setting) {
482   case omp_tool_disabled:
483     OMPT_VERBOSE_INIT_PRINT("OMP tool disabled. \n");
484     break;
485 
486   case omp_tool_unset:
487   case omp_tool_enabled:
488 
489     //--------------------------------------------------
490     // Load tool iff specified in environment variable
491     //--------------------------------------------------
492     ompt_start_tool_result =
493         ompt_try_start_tool(__kmp_openmp_version, ompt_get_runtime_version());
494 
495     memset(&ompt_enabled, 0, sizeof(ompt_enabled));
496     break;
497 
498   case omp_tool_error:
499     fprintf(stderr,
500             "Warning: OMP_TOOL has invalid value \"%s\".\n"
501             "  legal values are (NULL,\"\",\"disabled\","
502             "\"enabled\").\n",
503             ompt_env_var);
504     break;
505   }
506   if (verbose_init && verbose_file != stderr && verbose_file != stdout)
507     fclose(verbose_file);
508 #if OMPT_DEBUG
509   printf("ompt_pre_init(): ompt_enabled = %d\n", ompt_enabled);
510 #endif
511 }
512 
513 extern "C" int omp_get_initial_device(void);
514 
515 void ompt_post_init() {
516   //--------------------------------------------------
517   // Execute the post-initialization logic only once.
518   //--------------------------------------------------
519   static int ompt_post_initialized = 0;
520 
521   if (ompt_post_initialized)
522     return;
523 
524   ompt_post_initialized = 1;
525 
526   //--------------------------------------------------
527   // Initialize the tool if so indicated.
528   //--------------------------------------------------
529   if (ompt_start_tool_result) {
530     ompt_enabled.enabled = !!ompt_start_tool_result->initialize(
531         ompt_fn_lookup, omp_get_initial_device(),
532         &(ompt_start_tool_result->tool_data));
533 
534     if (!ompt_enabled.enabled) {
535       // tool not enabled, zero out the bitmap, and done
536       memset(&ompt_enabled, 0, sizeof(ompt_enabled));
537       return;
538     }
539 
540     kmp_info_t *root_thread = ompt_get_thread();
541 
542     ompt_set_thread_state(root_thread, ompt_state_overhead);
543 
544     if (ompt_enabled.ompt_callback_thread_begin) {
545       ompt_callbacks.ompt_callback(ompt_callback_thread_begin)(
546           ompt_thread_initial, __ompt_get_thread_data_internal());
547     }
548     ompt_data_t *task_data;
549     ompt_data_t *parallel_data;
550     __ompt_get_task_info_internal(0, NULL, &task_data, NULL, &parallel_data,
551                                   NULL);
552     if (ompt_enabled.ompt_callback_implicit_task) {
553       ompt_callbacks.ompt_callback(ompt_callback_implicit_task)(
554           ompt_scope_begin, parallel_data, task_data, 1, 1, ompt_task_initial);
555     }
556 
557     ompt_set_thread_state(root_thread, ompt_state_work_serial);
558   }
559 }
560 
561 void ompt_fini() {
562   if (ompt_enabled.enabled
563 #if OMPD_SUPPORT
564       && ompt_start_tool_result && ompt_start_tool_result->finalize
565 #endif
566   ) {
567     ompt_start_tool_result->finalize(&(ompt_start_tool_result->tool_data));
568   }
569 
570   if (ompt_tool_module)
571     OMPT_DLCLOSE(ompt_tool_module);
572   memset(&ompt_enabled, 0, sizeof(ompt_enabled));
573 }
574 
575 /*****************************************************************************
576  * interface operations
577  ****************************************************************************/
578 
579 /*****************************************************************************
580  * state
581  ****************************************************************************/
582 
583 OMPT_API_ROUTINE int ompt_enumerate_states(int current_state, int *next_state,
584                                            const char **next_state_name) {
585   const static int len = sizeof(ompt_state_info) / sizeof(ompt_state_info_t);
586   int i = 0;
587 
588   for (i = 0; i < len - 1; i++) {
589     if (ompt_state_info[i].state_id == current_state) {
590       *next_state = ompt_state_info[i + 1].state_id;
591       *next_state_name = ompt_state_info[i + 1].state_name;
592       return 1;
593     }
594   }
595 
596   return 0;
597 }
598 
599 OMPT_API_ROUTINE int ompt_enumerate_mutex_impls(int current_impl,
600                                                 int *next_impl,
601                                                 const char **next_impl_name) {
602   const static int len =
603       sizeof(kmp_mutex_impl_info) / sizeof(kmp_mutex_impl_info_t);
604   int i = 0;
605   for (i = 0; i < len - 1; i++) {
606     if (kmp_mutex_impl_info[i].id != current_impl)
607       continue;
608     *next_impl = kmp_mutex_impl_info[i + 1].id;
609     *next_impl_name = kmp_mutex_impl_info[i + 1].name;
610     return 1;
611   }
612   return 0;
613 }
614 
615 /*****************************************************************************
616  * callbacks
617  ****************************************************************************/
618 
619 OMPT_API_ROUTINE ompt_set_result_t ompt_set_callback(ompt_callbacks_t which,
620                                                      ompt_callback_t callback) {
621   switch (which) {
622 
623 #define ompt_event_macro(event_name, callback_type, event_id)                  \
624   case event_name:                                                             \
625     ompt_callbacks.ompt_callback(event_name) = (callback_type)callback;        \
626     ompt_enabled.event_name = (callback != 0);                                 \
627     if (callback)                                                              \
628       return ompt_event_implementation_status(event_name);                     \
629     else                                                                       \
630       return ompt_set_always;
631 
632     FOREACH_OMPT_HOST_EVENT(ompt_event_macro)
633 
634 #undef ompt_event_macro
635 
636 #define ompt_event_macro(event_name, callback_type, event_id)                  \
637   case event_name:                                                             \
638     ompt_target_callbacks.ompt_callback(event_name) = (callback_type)callback; \
639     ompt_target_enabled.event_name = (callback != 0);                          \
640     if (callback)                                                              \
641       return ompt_event_implementation_status(event_name);                     \
642     else                                                                       \
643       return ompt_set_always;
644 
645     FOREACH_OMPT_51_TARGET_EVENT(ompt_event_macro)
646 
647 #undef ompt_event_macro
648 
649 #define ompt_event_macro(event_name, callback_type, event_id)                  \
650   case event_name:                                                             \
651     ompt_callbacks_noemi.ompt_callback(event_name) = (callback_type)callback;  \
652     ompt_target_enabled.ompt_emi_event(event_name) = (callback != 0);          \
653     if (callback) {                                                            \
654       ompt_target_callbacks.ompt_emi_callback(event_name) =                    \
655           (ompt_emi_callback_type(event_name))(&ompt_emi_wrapper(event_name)); \
656       return ompt_event_implementation_status(event_name);                     \
657     } else {                                                                   \
658       ompt_target_callbacks.ompt_emi_callback(event_name) = NULL;              \
659       return ompt_set_always;                                                  \
660     }
661 
662     FOREACH_OMPT_NOEMI_EVENT(ompt_event_macro)
663 
664 #undef ompt_event_macro
665 
666   default:
667     return ompt_set_error;
668   }
669 }
670 
671 OMPT_API_ROUTINE int ompt_get_callback(ompt_callbacks_t which,
672                                        ompt_callback_t *callback) {
673   if (!ompt_enabled.enabled)
674     return ompt_get_callback_failure;
675 
676   switch (which) {
677 
678 #define ompt_event_macro(event_name, callback_type, event_id)                  \
679   case event_name: {                                                           \
680     ompt_callback_t mycb =                                                     \
681         (ompt_callback_t)ompt_callbacks.ompt_callback(event_name);             \
682     if (ompt_enabled.event_name && mycb) {                                     \
683       *callback = mycb;                                                        \
684       return ompt_get_callback_success;                                        \
685     }                                                                          \
686     return ompt_get_callback_failure;                                          \
687   }
688 
689     FOREACH_OMPT_HOST_EVENT(ompt_event_macro)
690 
691 #undef ompt_event_macro
692 
693 #define ompt_event_macro(event_name, callback_type, event_id)                  \
694   case event_name: {                                                           \
695     ompt_callback_t mycb =                                                     \
696         (ompt_callback_t)ompt_target_callbacks.ompt_callback(event_name);      \
697     if (ompt_target_enabled.event_name && mycb) {                              \
698       *callback = mycb;                                                        \
699       return ompt_get_callback_success;                                        \
700     }                                                                          \
701     return ompt_get_callback_failure;                                          \
702   }
703 
704     FOREACH_OMPT_DEVICE_EVENT(ompt_event_macro)
705 
706 #undef ompt_event_macro
707 
708 #define ompt_event_macro(event_name, callback_type, event_id)                  \
709   case ompt_emi_event(event_name): {                                           \
710     ompt_callback_t mycb =                                                     \
711         (ompt_callback_t)ompt_target_callbacks.ompt_emi_callback(event_name);  \
712     if (ompt_target_enabled.ompt_emi_event(event_name) &&                      \
713         mycb != (ompt_callback_t)(&ompt_emi_wrapper(event_name))) {            \
714       *callback = mycb;                                                        \
715       return ompt_get_callback_success;                                        \
716     }                                                                          \
717     return ompt_get_callback_failure;                                          \
718   }
719 
720     FOREACH_OMPT_NOEMI_EVENT(ompt_event_macro)
721 
722 #undef ompt_event_macro
723 
724 #define ompt_event_macro(event_name, callback_type, event_id)                  \
725   case event_name: {                                                           \
726     ompt_callback_t mycb =                                                     \
727         (ompt_callback_t)ompt_callbacks_noemi.ompt_callback(event_name);       \
728     ompt_callback_t wrapper =                                                  \
729         (ompt_callback_t)ompt_target_callbacks.ompt_emi_callback(event_name);  \
730     if (ompt_target_enabled.ompt_emi_event(event_name) &&                      \
731         wrapper == (ompt_callback_t)(&ompt_emi_wrapper(event_name))) {         \
732       *callback = mycb;                                                        \
733       return ompt_get_callback_success;                                        \
734     }                                                                          \
735     return ompt_get_callback_failure;                                          \
736   }
737 
738     FOREACH_OMPT_NOEMI_EVENT(ompt_event_macro)
739 
740 #undef ompt_event_macro
741 
742   default:
743     return ompt_get_callback_failure;
744   }
745 }
746 
747 /*****************************************************************************
748  * parallel regions
749  ****************************************************************************/
750 
751 OMPT_API_ROUTINE int ompt_get_parallel_info(int ancestor_level,
752                                             ompt_data_t **parallel_data,
753                                             int *team_size) {
754   if (!ompt_enabled.enabled)
755     return 0;
756   return __ompt_get_parallel_info_internal(ancestor_level, parallel_data,
757                                            team_size);
758 }
759 
760 OMPT_API_ROUTINE int ompt_get_state(ompt_wait_id_t *wait_id) {
761   if (!ompt_enabled.enabled)
762     return ompt_state_work_serial;
763   int thread_state = __ompt_get_state_internal(wait_id);
764 
765   if (thread_state == ompt_state_undefined) {
766     thread_state = ompt_state_work_serial;
767   }
768 
769   return thread_state;
770 }
771 
772 /*****************************************************************************
773  * tasks
774  ****************************************************************************/
775 
776 OMPT_API_ROUTINE ompt_data_t *ompt_get_thread_data(void) {
777   if (!ompt_enabled.enabled)
778     return NULL;
779   return __ompt_get_thread_data_internal();
780 }
781 
782 OMPT_API_ROUTINE int ompt_get_task_info(int ancestor_level, int *type,
783                                         ompt_data_t **task_data,
784                                         ompt_frame_t **task_frame,
785                                         ompt_data_t **parallel_data,
786                                         int *thread_num) {
787   if (!ompt_enabled.enabled)
788     return 0;
789   return __ompt_get_task_info_internal(ancestor_level, type, task_data,
790                                        task_frame, parallel_data, thread_num);
791 }
792 
793 OMPT_API_ROUTINE int ompt_get_task_memory(void **addr, size_t *size,
794                                           int block) {
795   return __ompt_get_task_memory_internal(addr, size, block);
796 }
797 
798 /*****************************************************************************
799  * num_procs
800  ****************************************************************************/
801 
802 OMPT_API_ROUTINE int ompt_get_num_procs(void) {
803   // copied from kmp_ftn_entry.h (but modified: OMPT can only be called when
804   // runtime is initialized)
805   return __kmp_avail_proc;
806 }
807 
808 /*****************************************************************************
809  * places
810  ****************************************************************************/
811 
812 OMPT_API_ROUTINE int ompt_get_num_places(void) {
813 // copied from kmp_ftn_entry.h (but modified)
814 #if !KMP_AFFINITY_SUPPORTED
815   return 0;
816 #else
817   if (!KMP_AFFINITY_CAPABLE())
818     return 0;
819   return __kmp_affinity_num_masks;
820 #endif
821 }
822 
823 OMPT_API_ROUTINE int ompt_get_place_proc_ids(int place_num, int ids_size,
824                                              int *ids) {
825 // copied from kmp_ftn_entry.h (but modified)
826 #if !KMP_AFFINITY_SUPPORTED
827   return 0;
828 #else
829   int i, count;
830   int tmp_ids[ids_size];
831   for (int j = 0; j < ids_size; j++)
832     tmp_ids[j] = 0;
833   if (!KMP_AFFINITY_CAPABLE())
834     return 0;
835   if (place_num < 0 || place_num >= (int)__kmp_affinity_num_masks)
836     return 0;
837   /* TODO: Is this safe for asynchronous call from signal handler during runtime
838    * shutdown? */
839   kmp_affin_mask_t *mask = KMP_CPU_INDEX(__kmp_affinity_masks, place_num);
840   count = 0;
841   KMP_CPU_SET_ITERATE(i, mask) {
842     if ((!KMP_CPU_ISSET(i, __kmp_affin_fullMask)) ||
843         (!KMP_CPU_ISSET(i, mask))) {
844       continue;
845     }
846     if (count < ids_size)
847       tmp_ids[count] = i;
848     count++;
849   }
850   if (ids_size >= count) {
851     for (i = 0; i < count; i++) {
852       ids[i] = tmp_ids[i];
853     }
854   }
855   return count;
856 #endif
857 }
858 
859 OMPT_API_ROUTINE int ompt_get_place_num(void) {
860 // copied from kmp_ftn_entry.h (but modified)
861 #if !KMP_AFFINITY_SUPPORTED
862   return -1;
863 #else
864   if (!ompt_enabled.enabled || __kmp_get_gtid() < 0)
865     return -1;
866 
867   int gtid;
868   kmp_info_t *thread;
869   if (!KMP_AFFINITY_CAPABLE())
870     return -1;
871   gtid = __kmp_entry_gtid();
872   thread = __kmp_thread_from_gtid(gtid);
873   if (thread == NULL || thread->th.th_current_place < 0)
874     return -1;
875   return thread->th.th_current_place;
876 #endif
877 }
878 
879 OMPT_API_ROUTINE int ompt_get_partition_place_nums(int place_nums_size,
880                                                    int *place_nums) {
881 // copied from kmp_ftn_entry.h (but modified)
882 #if !KMP_AFFINITY_SUPPORTED
883   return 0;
884 #else
885   if (!ompt_enabled.enabled || __kmp_get_gtid() < 0)
886     return 0;
887 
888   int i, gtid, place_num, first_place, last_place, start, end;
889   kmp_info_t *thread;
890   if (!KMP_AFFINITY_CAPABLE())
891     return 0;
892   gtid = __kmp_entry_gtid();
893   thread = __kmp_thread_from_gtid(gtid);
894   if (thread == NULL)
895     return 0;
896   first_place = thread->th.th_first_place;
897   last_place = thread->th.th_last_place;
898   if (first_place < 0 || last_place < 0)
899     return 0;
900   if (first_place <= last_place) {
901     start = first_place;
902     end = last_place;
903   } else {
904     start = last_place;
905     end = first_place;
906   }
907   if (end - start <= place_nums_size)
908     for (i = 0, place_num = start; place_num <= end; ++place_num, ++i) {
909       place_nums[i] = place_num;
910     }
911   return end - start + 1;
912 #endif
913 }
914 
915 /*****************************************************************************
916  * places
917  ****************************************************************************/
918 
919 OMPT_API_ROUTINE int ompt_get_proc_id(void) {
920   if (!ompt_enabled.enabled || __kmp_get_gtid() < 0)
921     return -1;
922 #if KMP_OS_LINUX
923   return sched_getcpu();
924 #elif KMP_OS_WINDOWS
925   PROCESSOR_NUMBER pn;
926   GetCurrentProcessorNumberEx(&pn);
927   return 64 * pn.Group + pn.Number;
928 #else
929   return -1;
930 #endif
931 }
932 
933 /*****************************************************************************
934  * compatability
935  ****************************************************************************/
936 
937 /*
938  * Currently unused function
939 OMPT_API_ROUTINE int ompt_get_ompt_version() { return OMPT_VERSION; }
940 */
941 
942 /*****************************************************************************
943  * application-facing API
944  ****************************************************************************/
945 
946 /*----------------------------------------------------------------------------
947  | control
948  ---------------------------------------------------------------------------*/
949 
950 int __kmp_control_tool(uint64_t command, uint64_t modifier, void *arg) {
951 
952   if (ompt_enabled.enabled) {
953     if (ompt_enabled.ompt_callback_control_tool) {
954       return ompt_callbacks.ompt_callback(ompt_callback_control_tool)(
955           command, modifier, arg, OMPT_LOAD_RETURN_ADDRESS(__kmp_entry_gtid()));
956     } else {
957       return -1;
958     }
959   } else {
960     return -2;
961   }
962 }
963 
964 /*****************************************************************************
965  * misc
966  ****************************************************************************/
967 
968 OMPT_API_ROUTINE uint64_t ompt_get_unique_id(void) {
969   return __ompt_get_unique_id_internal();
970 }
971 
972 OMPT_API_ROUTINE void ompt_finalize_tool(void) { __kmp_internal_end_atexit(); }
973 
974 /*****************************************************************************
975  * Target
976  ****************************************************************************/
977 
978 OMPT_API_ROUTINE int ompt_get_target_info(uint64_t *device_num,
979                                           ompt_id_t *target_id,
980                                           ompt_id_t *host_op_id) {
981   return 0; // thread is not in a target region
982 }
983 
984 OMPT_API_ROUTINE int ompt_get_num_devices(void) {
985   return 1; // only one device (the current device) is available
986 }
987 
988 /*****************************************************************************
989  * API inquiry for tool
990  ****************************************************************************/
991 
992 static ompt_interface_fn_t ompt_fn_lookup(const char *s) {
993 
994 #define ompt_interface_fn(fn)                                                  \
995   fn##_t fn##_f = fn;                                                          \
996   if (strcmp(s, #fn) == 0)                                                     \
997     return (ompt_interface_fn_t)fn##_f;
998 
999   FOREACH_OMPT_INQUIRY_FN(ompt_interface_fn)
1000 
1001   return NULL;
1002 }
1003