LLVM OpenMP* Runtime Library
ompt-general.cpp
1 /*
2  * ompt-general.cpp -- OMPT implementation of interface functions
3  */
4 
5 //===----------------------------------------------------------------------===//
6 //
7 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
8 // See https://llvm.org/LICENSE.txt for license information.
9 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
10 //
11 //===----------------------------------------------------------------------===//
12 
13 /*****************************************************************************
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 }