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