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