2 * ompt-general.cpp -- OMPT implementation of interface functions
5 //===----------------------------------------------------------------------===//
7 // The LLVM Compiler Infrastructure
9 // This file is dual licensed under the MIT and the University of Illinois Open
10 // Source Licenses. See LICENSE.txt for details.
12 //===----------------------------------------------------------------------===//
14 /*****************************************************************************
15 * system include files
16 ****************************************************************************/
28 /*****************************************************************************
30 ****************************************************************************/
32 #include "ompt-specific.cpp"
34 /*****************************************************************************
36 ****************************************************************************/
38 #define ompt_get_callback_success 1
39 #define ompt_get_callback_failure 0
41 #define no_tool_present 0
43 #define OMPT_API_ROUTINE static
45 #ifndef OMPT_STR_MATCH
46 #define OMPT_STR_MATCH(haystack, needle) (!strcasecmp(haystack, needle))
49 /*****************************************************************************
51 ****************************************************************************/
54 const char *state_name;
55 ompt_state_t state_id;
61 } kmp_mutex_impl_info_t;
70 /*****************************************************************************
72 ****************************************************************************/
74 ompt_callbacks_active_t ompt_enabled;
76 ompt_state_info_t ompt_state_info[] = {
77 #define ompt_state_macro(state, code) {#state, state},
78 FOREACH_OMPT_STATE(ompt_state_macro)
79 #undef ompt_state_macro
82 kmp_mutex_impl_info_t kmp_mutex_impl_info[] = {
83 #define kmp_mutex_impl_macro(name, id) {#name, name},
84 FOREACH_KMP_MUTEX_IMPL(kmp_mutex_impl_macro)
85 #undef kmp_mutex_impl_macro
88 ompt_callbacks_internal_t ompt_callbacks;
90 static ompt_start_tool_result_t *ompt_start_tool_result = NULL;
92 /*****************************************************************************
93 * forward declarations
94 ****************************************************************************/
96 static ompt_interface_fn_t ompt_fn_lookup(const char *s);
98 OMPT_API_ROUTINE ompt_data_t *ompt_get_thread_data(void);
100 /*****************************************************************************
101 * initialization and finalization (private operations)
102 ****************************************************************************/
104 typedef ompt_start_tool_result_t *(*ompt_start_tool_t)(unsigned int,
109 // While Darwin supports weak symbols, the library that wishes to provide a new
110 // implementation has to link against this runtime which defeats the purpose
111 // of having tools that are agnostic of the underlying runtime implementation.
113 // Fortunately, the linker includes all symbols of an executable in the global
114 // symbol table by default so dlsym() even finds static implementations of
115 // ompt_start_tool. For this to work on Linux, -Wl,--export-dynamic needs to be
116 // passed when building the application which we don't want to rely on.
118 static ompt_start_tool_result_t *ompt_tool_darwin(unsigned int omp_version,
119 const char *runtime_version) {
120 ompt_start_tool_result_t *ret = NULL;
121 // Search symbol in the current address space.
122 ompt_start_tool_t start_tool =
123 (ompt_start_tool_t)dlsym(RTLD_DEFAULT, "ompt_start_tool");
125 ret = start_tool(omp_version, runtime_version);
130 #elif OMPT_HAVE_WEAK_ATTRIBUTE
132 // On Unix-like systems that support weak symbols the following implementation
133 // of ompt_start_tool() will be used in case no tool-supplied implementation of
134 // this function is present in the address space of a process.
136 _OMP_EXTERN OMPT_WEAK_ATTRIBUTE ompt_start_tool_result_t *
137 ompt_start_tool(unsigned int omp_version, const char *runtime_version) {
138 ompt_start_tool_result_t *ret = NULL;
139 // Search next symbol in the current address space. This can happen if the
140 // runtime library is linked before the tool. Since glibc 2.2 strong symbols
141 // don't override weak symbols that have been found before unless the user
142 // sets the environment variable LD_DYNAMIC_WEAK.
143 ompt_start_tool_t next_tool =
144 (ompt_start_tool_t)dlsym(RTLD_NEXT, "ompt_start_tool");
146 ret = next_tool(omp_version, runtime_version);
151 #elif OMPT_HAVE_PSAPI
153 // On Windows, the ompt_tool_windows function is used to find the
154 // ompt_start_tool symbol across all modules loaded by a process. If
155 // ompt_start_tool is found, ompt_start_tool's return value is used to
156 // initialize the tool. Otherwise, NULL is returned and OMPT won't be enabled.
159 #pragma comment(lib, "psapi.lib")
161 // The number of loaded modules to start enumeration with EnumProcessModules()
162 #define NUM_MODULES 128
164 static ompt_start_tool_result_t *
165 ompt_tool_windows(unsigned int omp_version, const char *runtime_version) {
167 DWORD needed, new_size;
169 HANDLE process = GetCurrentProcess();
170 modules = (HMODULE *)malloc(NUM_MODULES * sizeof(HMODULE));
171 ompt_start_tool_t ompt_tool_p = NULL;
174 printf("ompt_tool_windows(): looking for ompt_start_tool\n");
176 if (!EnumProcessModules(process, modules, NUM_MODULES * sizeof(HMODULE),
178 // Regardless of the error reason use the stub initialization function
182 // Check if NUM_MODULES is enough to list all modules
183 new_size = needed / sizeof(HMODULE);
184 if (new_size > NUM_MODULES) {
186 printf("ompt_tool_windows(): resize buffer to %d bytes\n", needed);
188 modules = (HMODULE *)realloc(modules, needed);
189 // If resizing failed use the stub function.
190 if (!EnumProcessModules(process, modules, needed, &needed)) {
195 for (i = 0; i < new_size; ++i) {
196 (FARPROC &)ompt_tool_p = GetProcAddress(modules[i], "ompt_start_tool");
199 TCHAR modName[MAX_PATH];
200 if (GetModuleFileName(modules[i], modName, MAX_PATH))
201 printf("ompt_tool_windows(): ompt_start_tool found in module %s\n",
205 return (*ompt_tool_p)(omp_version, runtime_version);
209 TCHAR modName[MAX_PATH];
210 if (GetModuleFileName(modules[i], modName, MAX_PATH))
211 printf("ompt_tool_windows(): ompt_start_tool not found in module %s\n",
220 #error Activation of OMPT is not supported on this platform.
223 static ompt_start_tool_result_t *
224 ompt_try_start_tool(unsigned int omp_version, const char *runtime_version) {
225 ompt_start_tool_result_t *ret = NULL;
226 ompt_start_tool_t start_tool = NULL;
228 // Cannot use colon to describe a list of absolute paths on Windows
229 const char *sep = ";";
231 const char *sep = ":";
235 // Try in the current address space
236 ret = ompt_tool_darwin(omp_version, runtime_version);
237 #elif OMPT_HAVE_WEAK_ATTRIBUTE
238 ret = ompt_start_tool(omp_version, runtime_version);
239 #elif OMPT_HAVE_PSAPI
240 ret = ompt_tool_windows(omp_version, runtime_version);
242 #error Activation of OMPT is not supported on this platform.
247 // Try tool-libraries-var ICV
248 const char *tool_libs = getenv("OMP_TOOL_LIBRARIES");
250 char *libs = __kmp_str_format("%s", tool_libs);
252 char *fname = __kmp_str_token(libs, sep, &buf);
255 void *h = dlopen(fname, RTLD_LAZY);
257 start_tool = (ompt_start_tool_t)dlsym(h, "ompt_start_tool");
259 HMODULE h = LoadLibrary(fname);
261 start_tool = (ompt_start_tool_t)GetProcAddress(h, "ompt_start_tool");
263 #error Activation of OMPT is not supported on this platform.
265 if (start_tool && (ret = (*start_tool)(omp_version, runtime_version)))
268 fname = __kmp_str_token(NULL, sep, &buf);
270 __kmp_str_free(&libs);
275 void ompt_pre_init() {
276 //--------------------------------------------------
277 // Execute the pre-initialization logic only once.
278 //--------------------------------------------------
279 static int ompt_pre_initialized = 0;
281 if (ompt_pre_initialized)
284 ompt_pre_initialized = 1;
286 //--------------------------------------------------
287 // Use a tool iff a tool is enabled and available.
288 //--------------------------------------------------
289 const char *ompt_env_var = getenv("OMP_TOOL");
290 tool_setting_e tool_setting = omp_tool_error;
292 if (!ompt_env_var || !strcmp(ompt_env_var, ""))
293 tool_setting = omp_tool_unset;
294 else if (OMPT_STR_MATCH(ompt_env_var, "disabled"))
295 tool_setting = omp_tool_disabled;
296 else if (OMPT_STR_MATCH(ompt_env_var, "enabled"))
297 tool_setting = omp_tool_enabled;
300 printf("ompt_pre_init(): tool_setting = %d\n", tool_setting);
302 switch (tool_setting) {
303 case omp_tool_disabled:
307 case omp_tool_enabled:
309 //--------------------------------------------------
310 // Load tool iff specified in environment variable
311 //--------------------------------------------------
312 ompt_start_tool_result =
313 ompt_try_start_tool(__kmp_openmp_version, ompt_get_runtime_version());
315 memset(&ompt_enabled, 0, sizeof(ompt_enabled));
319 fprintf(stderr, "Warning: OMP_TOOL has invalid value \"%s\".\n"
320 " legal values are (NULL,\"\",\"disabled\","
326 printf("ompt_pre_init(): ompt_enabled = %d\n", ompt_enabled);
330 extern "C" int omp_get_initial_device(void);
332 void ompt_post_init() {
333 //--------------------------------------------------
334 // Execute the post-initialization logic only once.
335 //--------------------------------------------------
336 static int ompt_post_initialized = 0;
338 if (ompt_post_initialized)
341 ompt_post_initialized = 1;
343 //--------------------------------------------------
344 // Initialize the tool if so indicated.
345 //--------------------------------------------------
346 if (ompt_start_tool_result) {
347 ompt_enabled.enabled = !!ompt_start_tool_result->initialize(
348 ompt_fn_lookup, omp_get_initial_device(), &(ompt_start_tool_result->tool_data));
350 if (!ompt_enabled.enabled) {
351 // tool not enabled, zero out the bitmap, and done
352 memset(&ompt_enabled, 0, sizeof(ompt_enabled));
356 kmp_info_t *root_thread = ompt_get_thread();
358 ompt_set_thread_state(root_thread, ompt_state_overhead);
360 if (ompt_enabled.ompt_callback_thread_begin) {
361 ompt_callbacks.ompt_callback(ompt_callback_thread_begin)(
362 ompt_thread_initial, __ompt_get_thread_data_internal());
364 ompt_data_t *task_data;
365 __ompt_get_task_info_internal(0, NULL, &task_data, NULL, NULL, NULL);
366 if (ompt_enabled.ompt_callback_task_create) {
367 ompt_callbacks.ompt_callback(ompt_callback_task_create)(
368 NULL, NULL, task_data, ompt_task_initial, 0, NULL);
371 ompt_set_thread_state(root_thread, ompt_state_work_serial);
376 if (ompt_enabled.enabled) {
377 ompt_start_tool_result->finalize(&(ompt_start_tool_result->tool_data));
380 memset(&ompt_enabled, 0, sizeof(ompt_enabled));
383 /*****************************************************************************
384 * interface operations
385 ****************************************************************************/
387 /*****************************************************************************
389 ****************************************************************************/
391 OMPT_API_ROUTINE int ompt_enumerate_states(int current_state, int *next_state,
392 const char **next_state_name) {
393 const static int len = sizeof(ompt_state_info) / sizeof(ompt_state_info_t);
396 for (i = 0; i < len - 1; i++) {
397 if (ompt_state_info[i].state_id == current_state) {
398 *next_state = ompt_state_info[i + 1].state_id;
399 *next_state_name = ompt_state_info[i + 1].state_name;
407 OMPT_API_ROUTINE int ompt_enumerate_mutex_impls(int current_impl,
409 const char **next_impl_name) {
410 const static int len =
411 sizeof(kmp_mutex_impl_info) / sizeof(kmp_mutex_impl_info_t);
413 for (i = 0; i < len - 1; i++) {
414 if (kmp_mutex_impl_info[i].id != current_impl)
416 *next_impl = kmp_mutex_impl_info[i + 1].id;
417 *next_impl_name = kmp_mutex_impl_info[i + 1].name;
423 /*****************************************************************************
425 ****************************************************************************/
427 OMPT_API_ROUTINE ompt_set_result_t ompt_set_callback(ompt_callbacks_t which,
428 ompt_callback_t callback) {
431 #define ompt_event_macro(event_name, callback_type, event_id) \
433 if (ompt_event_implementation_status(event_name)) { \
434 ompt_callbacks.ompt_callback(event_name) = (callback_type)callback; \
435 ompt_enabled.event_name = (callback != 0); \
438 return ompt_event_implementation_status(event_name); \
440 return ompt_set_always;
442 FOREACH_OMPT_EVENT(ompt_event_macro)
444 #undef ompt_event_macro
447 return ompt_set_error;
451 OMPT_API_ROUTINE int ompt_get_callback(ompt_callbacks_t which,
452 ompt_callback_t *callback) {
453 if (!ompt_enabled.enabled)
454 return ompt_get_callback_failure;
458 #define ompt_event_macro(event_name, callback_type, event_id) \
460 if (ompt_event_implementation_status(event_name)) { \
461 ompt_callback_t mycb = \
462 (ompt_callback_t)ompt_callbacks.ompt_callback(event_name); \
463 if (ompt_enabled.event_name && mycb) { \
465 return ompt_get_callback_success; \
468 return ompt_get_callback_failure;
470 FOREACH_OMPT_EVENT(ompt_event_macro)
472 #undef ompt_event_macro
475 return ompt_get_callback_failure;
479 /*****************************************************************************
481 ****************************************************************************/
483 OMPT_API_ROUTINE int ompt_get_parallel_info(int ancestor_level,
484 ompt_data_t **parallel_data,
486 if (!ompt_enabled.enabled)
488 return __ompt_get_parallel_info_internal(ancestor_level, parallel_data,
492 OMPT_API_ROUTINE int ompt_get_state(ompt_wait_id_t *wait_id) {
493 if (!ompt_enabled.enabled)
494 return ompt_state_work_serial;
495 int thread_state = __ompt_get_state_internal(wait_id);
497 if (thread_state == ompt_state_undefined) {
498 thread_state = ompt_state_work_serial;
504 /*****************************************************************************
506 ****************************************************************************/
508 OMPT_API_ROUTINE ompt_data_t *ompt_get_thread_data(void) {
509 if (!ompt_enabled.enabled)
511 return __ompt_get_thread_data_internal();
514 OMPT_API_ROUTINE int ompt_get_task_info(int ancestor_level, int *type,
515 ompt_data_t **task_data,
516 ompt_frame_t **task_frame,
517 ompt_data_t **parallel_data,
519 if (!ompt_enabled.enabled)
521 return __ompt_get_task_info_internal(ancestor_level, type, task_data,
522 task_frame, parallel_data, thread_num);
525 OMPT_API_ROUTINE int ompt_get_task_memory(void **addr, size_t *size,
531 /*****************************************************************************
533 ****************************************************************************/
535 OMPT_API_ROUTINE int ompt_get_num_procs(void) {
536 // copied from kmp_ftn_entry.h (but modified: OMPT can only be called when
537 // runtime is initialized)
538 return __kmp_avail_proc;
541 /*****************************************************************************
543 ****************************************************************************/
545 OMPT_API_ROUTINE int ompt_get_num_places(void) {
546 // copied from kmp_ftn_entry.h (but modified)
547 #if !KMP_AFFINITY_SUPPORTED
550 if (!KMP_AFFINITY_CAPABLE())
552 return __kmp_affinity_num_masks;
556 OMPT_API_ROUTINE int ompt_get_place_proc_ids(int place_num, int ids_size,
558 // copied from kmp_ftn_entry.h (but modified)
559 #if !KMP_AFFINITY_SUPPORTED
563 int tmp_ids[ids_size];
564 if (!KMP_AFFINITY_CAPABLE())
566 if (place_num < 0 || place_num >= (int)__kmp_affinity_num_masks)
568 /* TODO: Is this safe for asynchronous call from signal handler during runtime
570 kmp_affin_mask_t *mask = KMP_CPU_INDEX(__kmp_affinity_masks, place_num);
572 KMP_CPU_SET_ITERATE(i, mask) {
573 if ((!KMP_CPU_ISSET(i, __kmp_affin_fullMask)) ||
574 (!KMP_CPU_ISSET(i, mask))) {
577 if (count < ids_size)
581 if (ids_size >= count) {
582 for (i = 0; i < count; i++) {
590 OMPT_API_ROUTINE int ompt_get_place_num(void) {
591 // copied from kmp_ftn_entry.h (but modified)
592 #if !KMP_AFFINITY_SUPPORTED
595 if (!ompt_enabled.enabled || __kmp_get_gtid() < 0)
600 if (!KMP_AFFINITY_CAPABLE())
602 gtid = __kmp_entry_gtid();
603 thread = __kmp_thread_from_gtid(gtid);
604 if (thread == NULL || thread->th.th_current_place < 0)
606 return thread->th.th_current_place;
610 OMPT_API_ROUTINE int ompt_get_partition_place_nums(int place_nums_size,
612 // copied from kmp_ftn_entry.h (but modified)
613 #if !KMP_AFFINITY_SUPPORTED
616 if (!ompt_enabled.enabled || __kmp_get_gtid() < 0)
619 int i, gtid, place_num, first_place, last_place, start, end;
621 if (!KMP_AFFINITY_CAPABLE())
623 gtid = __kmp_entry_gtid();
624 thread = __kmp_thread_from_gtid(gtid);
627 first_place = thread->th.th_first_place;
628 last_place = thread->th.th_last_place;
629 if (first_place < 0 || last_place < 0)
631 if (first_place <= last_place) {
638 if (end - start <= place_nums_size)
639 for (i = 0, place_num = start; place_num <= end; ++place_num, ++i) {
640 place_nums[i] = place_num;
642 return end - start + 1;
646 /*****************************************************************************
648 ****************************************************************************/
650 OMPT_API_ROUTINE int ompt_get_proc_id(void) {
651 if (!ompt_enabled.enabled || __kmp_get_gtid() < 0)
654 return sched_getcpu();
657 GetCurrentProcessorNumberEx(&pn);
658 return 64 * pn.Group + pn.Number;
664 /*****************************************************************************
666 ****************************************************************************/
669 * Currently unused function
670 OMPT_API_ROUTINE int ompt_get_ompt_version() { return OMPT_VERSION; }
673 /*****************************************************************************
674 * application-facing API
675 ****************************************************************************/
677 /*----------------------------------------------------------------------------
679 ---------------------------------------------------------------------------*/
681 int __kmp_control_tool(uint64_t command, uint64_t modifier, void *arg) {
683 if (ompt_enabled.enabled) {
684 if (ompt_enabled.ompt_callback_control_tool) {
685 return ompt_callbacks.ompt_callback(ompt_callback_control_tool)(
686 command, modifier, arg, OMPT_LOAD_RETURN_ADDRESS(__kmp_entry_gtid()));
695 /*****************************************************************************
697 ****************************************************************************/
699 OMPT_API_ROUTINE uint64_t ompt_get_unique_id(void) {
700 return __ompt_get_unique_id_internal();
703 OMPT_API_ROUTINE void ompt_finalize_tool(void) {
707 /*****************************************************************************
709 ****************************************************************************/
711 OMPT_API_ROUTINE int ompt_get_target_info(uint64_t *device_num,
712 ompt_id_t *target_id,
713 ompt_id_t *host_op_id) {
714 return 0; // thread is not in a target region
717 OMPT_API_ROUTINE int ompt_get_num_devices(void) {
718 return 1; // only one device (the current device) is available
721 /*****************************************************************************
722 * API inquiry for tool
723 ****************************************************************************/
725 static ompt_interface_fn_t ompt_fn_lookup(const char *s) {
727 #define ompt_interface_fn(fn) \
728 fn##_t fn##_f = fn; \
729 if (strcmp(s, #fn) == 0) \
730 return (ompt_interface_fn_t)fn##_f;
732 FOREACH_OMPT_INQUIRY_FN(ompt_interface_fn)
734 return (ompt_interface_fn_t)0;