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