1 /***************************************************************************** 2 * system include files 3 ****************************************************************************/ 4 5 #include <assert.h> 6 7 #include <stdint.h> 8 #include <stdio.h> 9 #include <stdlib.h> 10 #include <string.h> 11 #if KMP_OS_UNIX 12 #include <dlfcn.h> 13 #endif 14 15 /***************************************************************************** 16 * ompt include files 17 ****************************************************************************/ 18 19 #include "ompt-specific.cpp" 20 21 /***************************************************************************** 22 * macros 23 ****************************************************************************/ 24 25 #define ompt_get_callback_success 1 26 #define ompt_get_callback_failure 0 27 28 #define no_tool_present 0 29 30 #define OMPT_API_ROUTINE static 31 32 #ifndef OMPT_STR_MATCH 33 #define OMPT_STR_MATCH(haystack, needle) (!strcasecmp(haystack, needle)) 34 #endif 35 36 /***************************************************************************** 37 * types 38 ****************************************************************************/ 39 40 typedef struct { 41 const char *state_name; 42 omp_state_t state_id; 43 } omp_state_info_t; 44 45 typedef struct { 46 const char *name; 47 ompt_mutex_impl_t id; 48 } ompt_mutex_impl_info_t; 49 50 enum tool_setting_e { 51 omp_tool_error, 52 omp_tool_unset, 53 omp_tool_disabled, 54 omp_tool_enabled 55 }; 56 57 /***************************************************************************** 58 * global variables 59 ****************************************************************************/ 60 61 ompt_callbacks_active_t ompt_enabled; 62 63 omp_state_info_t omp_state_info[] = { 64 #define omp_state_macro(state, code) {#state, state}, 65 FOREACH_OMP_STATE(omp_state_macro) 66 #undef omp_state_macro 67 }; 68 69 ompt_mutex_impl_info_t ompt_mutex_impl_info[] = { 70 #define ompt_mutex_impl_macro(name, id) {#name, name}, 71 FOREACH_OMPT_MUTEX_IMPL(ompt_mutex_impl_macro) 72 #undef ompt_mutex_impl_macro 73 }; 74 75 ompt_callbacks_internal_t ompt_callbacks; 76 77 static ompt_start_tool_result_t *ompt_start_tool_result = NULL; 78 79 /***************************************************************************** 80 * forward declarations 81 ****************************************************************************/ 82 83 static ompt_interface_fn_t ompt_fn_lookup(const char *s); 84 85 OMPT_API_ROUTINE ompt_data_t *ompt_get_thread_data(void); 86 87 /***************************************************************************** 88 * initialization and finalization (private operations) 89 ****************************************************************************/ 90 91 /* On Unix-like systems that support weak symbols the following implementation 92 * of ompt_start_tool() will be used in case no tool-supplied implementation of 93 * this function is present in the address space of a process. 94 * 95 * On Windows, the ompt_tool_windows function is used to find the 96 * ompt_tool symbol across all modules loaded by a process. If ompt_tool is 97 * found, ompt_tool's return value is used to initialize the tool. Otherwise, 98 * NULL is returned and OMPT won't be enabled */ 99 100 typedef ompt_start_tool_result_t *(*ompt_start_tool_t)(unsigned int, 101 const char *); 102 103 #if KMP_OS_UNIX 104 105 #if OMPT_HAVE_WEAK_ATTRIBUTE 106 _OMP_EXTERN __attribute__((weak)) 107 #elif defined KMP_DYNAMIC_LIB 108 _OMP_EXTERN 109 #warning Activation of OMPT is might fail for tools statically linked into the application. 110 #else 111 #error Activation of OMPT is not supported on this platform. 112 #endif 113 ompt_start_tool_result_t * 114 ompt_start_tool(unsigned int omp_version, const char *runtime_version) { 115 #ifdef KMP_DYNAMIC_LIB 116 ompt_start_tool_result_t *ret = NULL; 117 // Try next symbol in the address space 118 ompt_start_tool_t next_tool = 119 (ompt_start_tool_t)dlsym(RTLD_NEXT, "ompt_start_tool"); 120 if (next_tool) 121 ret = (next_tool)(omp_version, runtime_version); 122 return ret; 123 #else 124 #if OMPT_DEBUG 125 printf("ompt_start_tool() is called from the RTL\n"); 126 #endif 127 return NULL; 128 #endif 129 } 130 131 #elif OMPT_HAVE_PSAPI 132 133 #include <psapi.h> 134 #pragma comment(lib, "psapi.lib") 135 #define ompt_start_tool ompt_tool_windows 136 137 // The number of loaded modules to start enumeration with EnumProcessModules() 138 #define NUM_MODULES 128 139 140 static ompt_start_tool_result_t * 141 ompt_tool_windows(unsigned int omp_version, const char *runtime_version) { 142 int i; 143 DWORD needed, new_size; 144 HMODULE *modules; 145 HANDLE process = GetCurrentProcess(); 146 modules = (HMODULE *)malloc(NUM_MODULES * sizeof(HMODULE)); 147 ompt_start_tool_t ompt_tool_p = NULL; 148 149 #if OMPT_DEBUG 150 printf("ompt_tool_windows(): looking for ompt_start_tool\n"); 151 #endif 152 if (!EnumProcessModules(process, modules, NUM_MODULES * sizeof(HMODULE), 153 &needed)) { 154 // Regardless of the error reason use the stub initialization function 155 free(modules); 156 return NULL; 157 } 158 // Check if NUM_MODULES is enough to list all modules 159 new_size = needed / sizeof(HMODULE); 160 if (new_size > NUM_MODULES) { 161 #if OMPT_DEBUG 162 printf("ompt_tool_windows(): resize buffer to %d bytes\n", needed); 163 #endif 164 modules = (HMODULE *)realloc(modules, needed); 165 // If resizing failed use the stub function. 166 if (!EnumProcessModules(process, modules, needed, &needed)) { 167 free(modules); 168 return NULL; 169 } 170 } 171 for (i = 0; i < new_size; ++i) { 172 (FARPROC &)ompt_tool_p = GetProcAddress(modules[i], "ompt_start_tool"); 173 if (ompt_tool_p) { 174 #if OMPT_DEBUG 175 TCHAR modName[MAX_PATH]; 176 if (GetModuleFileName(modules[i], modName, MAX_PATH)) 177 printf("ompt_tool_windows(): ompt_start_tool found in module %s\n", 178 modName); 179 #endif 180 free(modules); 181 return (*ompt_tool_p)(omp_version, runtime_version); 182 } 183 #if OMPT_DEBUG 184 else { 185 TCHAR modName[MAX_PATH]; 186 if (GetModuleFileName(modules[i], modName, MAX_PATH)) 187 printf("ompt_tool_windows(): ompt_start_tool not found in module %s\n", 188 modName); 189 } 190 #endif 191 } 192 free(modules); 193 return NULL; 194 } 195 #else 196 #error Either __attribute__((weak)) or psapi.dll are required for OMPT support 197 #endif // OMPT_HAVE_WEAK_ATTRIBUTE 198 199 static ompt_start_tool_result_t * 200 ompt_try_start_tool(unsigned int omp_version, const char *runtime_version) { 201 ompt_start_tool_result_t *ret = NULL; 202 ompt_start_tool_t start_tool = NULL; 203 #if KMP_OS_WINDOWS 204 // Cannot use colon to describe a list of absolute paths on Windows 205 const char *sep = ";"; 206 #else 207 const char *sep = ":"; 208 #endif 209 210 // Try in the current address space 211 if ((ret = ompt_start_tool(omp_version, runtime_version))) 212 return ret; 213 214 // Try tool-libraries-var ICV 215 const char *tool_libs = getenv("OMP_TOOL_LIBRARIES"); 216 if (tool_libs) { 217 const char *libs = __kmp_str_format("%s", tool_libs); 218 char *buf; 219 char *fname = __kmp_str_token(CCAST(char *, libs), sep, &buf); 220 while (fname) { 221 #if KMP_OS_UNIX 222 void *h = dlopen(fname, RTLD_LAZY); 223 if (h) { 224 start_tool = (ompt_start_tool_t)dlsym(h, "ompt_start_tool"); 225 #elif KMP_OS_WINDOWS 226 HMODULE h = LoadLibrary(fname); 227 if (h) { 228 start_tool = (ompt_start_tool_t)GetProcAddress(h, "ompt_start_tool"); 229 #else 230 #error Activation of OMPT is not supported on this platform. 231 #endif 232 if (start_tool && (ret = (*start_tool)(omp_version, runtime_version))) 233 break; 234 } 235 fname = __kmp_str_token(NULL, sep, &buf); 236 } 237 __kmp_str_free(&libs); 238 } 239 return ret; 240 } 241 242 void ompt_pre_init() { 243 //-------------------------------------------------- 244 // Execute the pre-initialization logic only once. 245 //-------------------------------------------------- 246 static int ompt_pre_initialized = 0; 247 248 if (ompt_pre_initialized) 249 return; 250 251 ompt_pre_initialized = 1; 252 253 //-------------------------------------------------- 254 // Use a tool iff a tool is enabled and available. 255 //-------------------------------------------------- 256 const char *ompt_env_var = getenv("OMP_TOOL"); 257 tool_setting_e tool_setting = omp_tool_error; 258 259 if (!ompt_env_var || !strcmp(ompt_env_var, "")) 260 tool_setting = omp_tool_unset; 261 else if (OMPT_STR_MATCH(ompt_env_var, "disabled")) 262 tool_setting = omp_tool_disabled; 263 else if (OMPT_STR_MATCH(ompt_env_var, "enabled")) 264 tool_setting = omp_tool_enabled; 265 266 #if OMPT_DEBUG 267 printf("ompt_pre_init(): tool_setting = %d\n", tool_setting); 268 #endif 269 switch (tool_setting) { 270 case omp_tool_disabled: 271 break; 272 273 case omp_tool_unset: 274 case omp_tool_enabled: 275 276 //-------------------------------------------------- 277 // Load tool iff specified in environment variable 278 //-------------------------------------------------- 279 ompt_start_tool_result = 280 ompt_try_start_tool(__kmp_openmp_version, ompt_get_runtime_version()); 281 282 memset(&ompt_enabled, 0, sizeof(ompt_enabled)); 283 break; 284 285 case omp_tool_error: 286 fprintf(stderr, "Warning: OMP_TOOL has invalid value \"%s\".\n" 287 " legal values are (NULL,\"\",\"disabled\"," 288 "\"enabled\").\n", 289 ompt_env_var); 290 break; 291 } 292 #if OMPT_DEBUG 293 printf("ompt_pre_init(): ompt_enabled = %d\n", ompt_enabled); 294 #endif 295 } 296 297 void ompt_post_init() { 298 //-------------------------------------------------- 299 // Execute the post-initialization logic only once. 300 //-------------------------------------------------- 301 static int ompt_post_initialized = 0; 302 303 if (ompt_post_initialized) 304 return; 305 306 ompt_post_initialized = 1; 307 308 //-------------------------------------------------- 309 // Initialize the tool if so indicated. 310 //-------------------------------------------------- 311 if (ompt_start_tool_result) { 312 ompt_enabled.enabled = !!ompt_start_tool_result->initialize( 313 ompt_fn_lookup, &(ompt_start_tool_result->tool_data)); 314 315 ompt_thread_t *root_thread = ompt_get_thread(); 316 317 ompt_set_thread_state(root_thread, omp_state_overhead); 318 319 if (ompt_enabled.ompt_callback_thread_begin) { 320 ompt_callbacks.ompt_callback(ompt_callback_thread_begin)( 321 ompt_thread_initial, __ompt_get_thread_data_internal()); 322 } 323 ompt_data_t *task_data; 324 __ompt_get_task_info_internal(0, NULL, &task_data, NULL, NULL, NULL); 325 if (ompt_enabled.ompt_callback_task_create) { 326 ompt_callbacks.ompt_callback(ompt_callback_task_create)( 327 NULL, NULL, task_data, ompt_task_initial, 0, NULL); 328 } 329 330 ompt_set_thread_state(root_thread, omp_state_work_serial); 331 } 332 } 333 334 void ompt_fini() { 335 if (ompt_enabled.enabled) { 336 ompt_start_tool_result->finalize(&(ompt_start_tool_result->tool_data)); 337 } 338 339 memset(&ompt_enabled, 0, sizeof(ompt_enabled)); 340 } 341 342 /***************************************************************************** 343 * interface operations 344 ****************************************************************************/ 345 346 /***************************************************************************** 347 * state 348 ****************************************************************************/ 349 350 OMPT_API_ROUTINE int ompt_enumerate_states(int current_state, int *next_state, 351 const char **next_state_name) { 352 const static int len = sizeof(omp_state_info) / sizeof(omp_state_info_t); 353 int i = 0; 354 355 for (i = 0; i < len - 1; i++) { 356 if (omp_state_info[i].state_id == current_state) { 357 *next_state = omp_state_info[i + 1].state_id; 358 *next_state_name = omp_state_info[i + 1].state_name; 359 return 1; 360 } 361 } 362 363 return 0; 364 } 365 366 OMPT_API_ROUTINE int ompt_enumerate_mutex_impls(int current_impl, 367 int *next_impl, 368 const char **next_impl_name) { 369 const static int len = 370 sizeof(ompt_mutex_impl_info) / sizeof(ompt_mutex_impl_info_t); 371 int i = 0; 372 for (i = 0; i < len - 1; i++) { 373 if (ompt_mutex_impl_info[i].id != current_impl) 374 continue; 375 *next_impl = ompt_mutex_impl_info[i + 1].id; 376 *next_impl_name = ompt_mutex_impl_info[i + 1].name; 377 return 1; 378 } 379 return 0; 380 } 381 382 /***************************************************************************** 383 * callbacks 384 ****************************************************************************/ 385 386 OMPT_API_ROUTINE int ompt_set_callback(ompt_callbacks_t which, 387 ompt_callback_t callback) { 388 switch (which) { 389 390 #define ompt_event_macro(event_name, callback_type, event_id) \ 391 case event_name: \ 392 if (ompt_event_implementation_status(event_name)) { \ 393 ompt_callbacks.ompt_callback(event_name) = (callback_type)callback; \ 394 ompt_enabled.event_name = 1; \ 395 } \ 396 return ompt_event_implementation_status(event_name); 397 398 FOREACH_OMPT_EVENT(ompt_event_macro) 399 400 #undef ompt_event_macro 401 402 default: 403 return ompt_set_error; 404 } 405 } 406 407 OMPT_API_ROUTINE int ompt_get_callback(ompt_callbacks_t which, 408 ompt_callback_t *callback) { 409 switch (which) { 410 411 #define ompt_event_macro(event_name, callback_type, event_id) \ 412 case event_name: \ 413 if (ompt_event_implementation_status(event_name)) { \ 414 ompt_callback_t mycb = \ 415 (ompt_callback_t)ompt_callbacks.ompt_callback(event_name); \ 416 if (mycb) { \ 417 *callback = mycb; \ 418 return ompt_get_callback_success; \ 419 } \ 420 } \ 421 return ompt_get_callback_failure; 422 423 FOREACH_OMPT_EVENT(ompt_event_macro) 424 425 #undef ompt_event_macro 426 427 default: 428 return ompt_get_callback_failure; 429 } 430 } 431 432 /***************************************************************************** 433 * parallel regions 434 ****************************************************************************/ 435 436 OMPT_API_ROUTINE int ompt_get_parallel_info(int ancestor_level, 437 ompt_data_t **parallel_data, 438 int *team_size) { 439 return __ompt_get_parallel_info_internal(ancestor_level, parallel_data, 440 team_size); 441 } 442 443 OMPT_API_ROUTINE omp_state_t ompt_get_state(ompt_wait_id_t *wait_id) { 444 omp_state_t thread_state = __ompt_get_state_internal(wait_id); 445 446 if (thread_state == omp_state_undefined) { 447 thread_state = omp_state_work_serial; 448 } 449 450 return thread_state; 451 } 452 453 /***************************************************************************** 454 * tasks 455 ****************************************************************************/ 456 457 OMPT_API_ROUTINE ompt_data_t *ompt_get_thread_data(void) { 458 return __ompt_get_thread_data_internal(); 459 } 460 461 OMPT_API_ROUTINE int ompt_get_task_info(int ancestor_level, int *type, 462 ompt_data_t **task_data, 463 ompt_frame_t **task_frame, 464 ompt_data_t **parallel_data, 465 int *thread_num) { 466 return __ompt_get_task_info_internal(ancestor_level, type, task_data, 467 task_frame, parallel_data, thread_num); 468 } 469 470 /***************************************************************************** 471 * places 472 ****************************************************************************/ 473 474 OMPT_API_ROUTINE int ompt_get_num_places(void) { 475 // copied from kmp_ftn_entry.h (but modified) 476 #if !KMP_AFFINITY_SUPPORTED 477 return 0; 478 #else 479 if (!KMP_AFFINITY_CAPABLE()) 480 return 0; 481 return __kmp_affinity_num_masks; 482 #endif 483 } 484 485 OMPT_API_ROUTINE int ompt_get_place_proc_ids(int place_num, int ids_size, 486 int *ids) { 487 // copied from kmp_ftn_entry.h (but modified) 488 #if !KMP_AFFINITY_SUPPORTED 489 return 0; 490 #else 491 int i, count; 492 int tmp_ids[ids_size]; 493 if (!KMP_AFFINITY_CAPABLE()) 494 return 0; 495 if (place_num < 0 || place_num >= (int)__kmp_affinity_num_masks) 496 return 0; 497 /* TODO: Is this safe for asynchronous call from signal handler during runtime 498 * shutdown? */ 499 kmp_affin_mask_t *mask = KMP_CPU_INDEX(__kmp_affinity_masks, place_num); 500 count = 0; 501 KMP_CPU_SET_ITERATE(i, mask) { 502 if ((!KMP_CPU_ISSET(i, __kmp_affin_fullMask)) || 503 (!KMP_CPU_ISSET(i, mask))) { 504 continue; 505 } 506 if (count < ids_size) 507 tmp_ids[count] = i; 508 count++; 509 } 510 if (ids_size >= count) { 511 for (i = 0; i < count; i++) { 512 ids[i] = tmp_ids[i]; 513 } 514 } 515 return count; 516 #endif 517 } 518 519 OMPT_API_ROUTINE int ompt_get_place_num(void) { 520 // copied from kmp_ftn_entry.h (but modified) 521 #if !KMP_AFFINITY_SUPPORTED 522 return -1; 523 #else 524 int gtid; 525 kmp_info_t *thread; 526 if (!KMP_AFFINITY_CAPABLE()) 527 return -1; 528 gtid = __kmp_entry_gtid(); 529 thread = __kmp_thread_from_gtid(gtid); 530 if (thread == NULL || thread->th.th_current_place < 0) 531 return -1; 532 return thread->th.th_current_place; 533 #endif 534 } 535 536 OMPT_API_ROUTINE int ompt_get_partition_place_nums(int place_nums_size, 537 int *place_nums) { 538 // copied from kmp_ftn_entry.h (but modified) 539 #if !KMP_AFFINITY_SUPPORTED 540 return 0; 541 #else 542 int i, gtid, place_num, first_place, last_place, start, end; 543 kmp_info_t *thread; 544 if (!KMP_AFFINITY_CAPABLE()) 545 return 0; 546 gtid = __kmp_entry_gtid(); 547 thread = __kmp_thread_from_gtid(gtid); 548 if (thread == NULL) 549 return 0; 550 first_place = thread->th.th_first_place; 551 last_place = thread->th.th_last_place; 552 if (first_place < 0 || last_place < 0) 553 return 0; 554 if (first_place <= last_place) { 555 start = first_place; 556 end = last_place; 557 } else { 558 start = last_place; 559 end = first_place; 560 } 561 if (end - start <= place_nums_size) 562 for (i = 0, place_num = start; place_num <= end; ++place_num, ++i) { 563 place_nums[i] = place_num; 564 } 565 return end - start; 566 #endif 567 } 568 569 /***************************************************************************** 570 * places 571 ****************************************************************************/ 572 573 OMPT_API_ROUTINE int ompt_get_proc_id(void) { 574 #if KMP_OS_LINUX 575 return sched_getcpu(); 576 #else 577 return -1; 578 #endif 579 } 580 581 /***************************************************************************** 582 * compatability 583 ****************************************************************************/ 584 585 OMPT_API_ROUTINE int ompt_get_ompt_version() { return OMPT_VERSION; } 586 587 /***************************************************************************** 588 * application-facing API 589 ****************************************************************************/ 590 591 /*---------------------------------------------------------------------------- 592 | control 593 ---------------------------------------------------------------------------*/ 594 595 int __kmp_control_tool(uint64_t command, uint64_t modifier, void *arg) { 596 597 if (ompt_enabled.enabled) { 598 if (ompt_enabled.ompt_callback_control_tool) { 599 return ompt_callbacks.ompt_callback(ompt_callback_control_tool)( 600 command, modifier, arg, OMPT_LOAD_RETURN_ADDRESS(__kmp_entry_gtid())); 601 } else { 602 return -1; 603 } 604 } else { 605 return -2; 606 } 607 } 608 609 /***************************************************************************** 610 * misc 611 ****************************************************************************/ 612 613 OMPT_API_ROUTINE uint64_t ompt_get_unique_id(void) { 614 return __ompt_get_unique_id_internal(); 615 } 616 617 /***************************************************************************** 618 * Target 619 ****************************************************************************/ 620 621 OMPT_API_ROUTINE int ompt_get_target_info(uint64_t *device_num, 622 ompt_id_t *target_id, 623 ompt_id_t *host_op_id) { 624 return 0; // thread is not in a target region 625 } 626 627 OMPT_API_ROUTINE int ompt_get_num_devices(void) { 628 return 1; // only one device (the current device) is available 629 } 630 631 /***************************************************************************** 632 * API inquiry for tool 633 ****************************************************************************/ 634 635 static ompt_interface_fn_t ompt_fn_lookup(const char *s) { 636 637 #define ompt_interface_fn(fn) \ 638 fn##_t fn##_f = fn; \ 639 if (strcmp(s, #fn) == 0) \ 640 return (ompt_interface_fn_t)fn##_f; 641 642 FOREACH_OMPT_INQUIRY_FN(ompt_interface_fn) 643 644 return (ompt_interface_fn_t)0; 645 } 646