1 /* 2 * ompt-specific.cpp -- OMPT internal 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 // include files 15 //****************************************************************************** 16 17 #include "kmp.h" 18 #include "ompt-specific.h" 19 20 #if KMP_OS_UNIX 21 #include <dlfcn.h> 22 #endif 23 24 #if KMP_OS_WINDOWS 25 #define THREAD_LOCAL __declspec(thread) 26 #else 27 #define THREAD_LOCAL __thread 28 #endif 29 30 #define OMPT_WEAK_ATTRIBUTE KMP_WEAK_ATTRIBUTE_INTERNAL 31 32 //****************************************************************************** 33 // macros 34 //****************************************************************************** 35 36 #define LWT_FROM_TEAM(team) (team)->t.ompt_serialized_team_info 37 38 #define OMPT_THREAD_ID_BITS 16 39 40 //****************************************************************************** 41 // private operations 42 //****************************************************************************** 43 44 //---------------------------------------------------------- 45 // traverse the team and task hierarchy 46 // note: __ompt_get_teaminfo and __ompt_get_task_info_object 47 // traverse the hierarchy similarly and need to be 48 // kept consistent 49 //---------------------------------------------------------- 50 51 ompt_team_info_t *__ompt_get_teaminfo(int depth, int *size) { 52 kmp_info_t *thr = ompt_get_thread(); 53 54 if (thr) { 55 kmp_team *team = thr->th.th_team; 56 if (team == NULL) 57 return NULL; 58 59 ompt_lw_taskteam_t *next_lwt = LWT_FROM_TEAM(team), *lwt = NULL; 60 61 while (depth > 0) { 62 // next lightweight team (if any) 63 if (lwt) 64 lwt = lwt->parent; 65 66 // next heavyweight team (if any) after 67 // lightweight teams are exhausted 68 if (!lwt && team) { 69 if (next_lwt) { 70 lwt = next_lwt; 71 next_lwt = NULL; 72 } else { 73 team = team->t.t_parent; 74 if (team) { 75 next_lwt = LWT_FROM_TEAM(team); 76 } 77 } 78 } 79 80 depth--; 81 } 82 83 if (lwt) { 84 // lightweight teams have one task 85 if (size) 86 *size = 1; 87 88 // return team info for lightweight team 89 return &lwt->ompt_team_info; 90 } else if (team) { 91 // extract size from heavyweight team 92 if (size) 93 *size = team->t.t_nproc; 94 95 // return team info for heavyweight team 96 return &team->t.ompt_team_info; 97 } 98 } 99 100 return NULL; 101 } 102 103 ompt_task_info_t *__ompt_get_task_info_object(int depth) { 104 ompt_task_info_t *info = NULL; 105 kmp_info_t *thr = ompt_get_thread(); 106 107 if (thr) { 108 kmp_taskdata_t *taskdata = thr->th.th_current_task; 109 ompt_lw_taskteam_t *lwt = NULL, 110 *next_lwt = LWT_FROM_TEAM(taskdata->td_team); 111 112 while (depth > 0) { 113 // next lightweight team (if any) 114 if (lwt) 115 lwt = lwt->parent; 116 117 // next heavyweight team (if any) after 118 // lightweight teams are exhausted 119 if (!lwt && taskdata) { 120 if (next_lwt) { 121 lwt = next_lwt; 122 next_lwt = NULL; 123 } else { 124 taskdata = taskdata->td_parent; 125 if (taskdata) { 126 next_lwt = LWT_FROM_TEAM(taskdata->td_team); 127 } 128 } 129 } 130 depth--; 131 } 132 133 if (lwt) { 134 info = &lwt->ompt_task_info; 135 } else if (taskdata) { 136 info = &taskdata->ompt_task_info; 137 } 138 } 139 140 return info; 141 } 142 143 ompt_task_info_t *__ompt_get_scheduling_taskinfo(int depth) { 144 ompt_task_info_t *info = NULL; 145 kmp_info_t *thr = ompt_get_thread(); 146 147 if (thr) { 148 kmp_taskdata_t *taskdata = thr->th.th_current_task; 149 150 ompt_lw_taskteam_t *lwt = NULL, 151 *next_lwt = LWT_FROM_TEAM(taskdata->td_team); 152 153 while (depth > 0) { 154 // next lightweight team (if any) 155 if (lwt) 156 lwt = lwt->parent; 157 158 // next heavyweight team (if any) after 159 // lightweight teams are exhausted 160 if (!lwt && taskdata) { 161 // first try scheduling parent (for explicit task scheduling) 162 if (taskdata->ompt_task_info.scheduling_parent) { 163 taskdata = taskdata->ompt_task_info.scheduling_parent; 164 } else if (next_lwt) { 165 lwt = next_lwt; 166 next_lwt = NULL; 167 } else { 168 // then go for implicit tasks 169 taskdata = taskdata->td_parent; 170 if (taskdata) { 171 next_lwt = LWT_FROM_TEAM(taskdata->td_team); 172 } 173 } 174 } 175 depth--; 176 } 177 178 if (lwt) { 179 info = &lwt->ompt_task_info; 180 } else if (taskdata) { 181 info = &taskdata->ompt_task_info; 182 } 183 } 184 185 return info; 186 } 187 188 //****************************************************************************** 189 // interface operations 190 //****************************************************************************** 191 192 //---------------------------------------------------------- 193 // thread support 194 //---------------------------------------------------------- 195 196 ompt_data_t *__ompt_get_thread_data_internal() { 197 if (__kmp_get_gtid() >= 0) { 198 kmp_info_t *thread = ompt_get_thread(); 199 if (thread == NULL) 200 return NULL; 201 return &(thread->th.ompt_thread_info.thread_data); 202 } 203 return NULL; 204 } 205 206 //---------------------------------------------------------- 207 // state support 208 //---------------------------------------------------------- 209 210 void __ompt_thread_assign_wait_id(void *variable) { 211 kmp_info_t *ti = ompt_get_thread(); 212 213 if (ti) 214 ti->th.ompt_thread_info.wait_id = (ompt_wait_id_t)(uintptr_t)variable; 215 } 216 217 int __ompt_get_state_internal(ompt_wait_id_t *omp_wait_id) { 218 kmp_info_t *ti = ompt_get_thread(); 219 220 if (ti) { 221 if (omp_wait_id) 222 *omp_wait_id = ti->th.ompt_thread_info.wait_id; 223 return ti->th.ompt_thread_info.state; 224 } 225 return ompt_state_undefined; 226 } 227 228 //---------------------------------------------------------- 229 // parallel region support 230 //---------------------------------------------------------- 231 232 int __ompt_get_parallel_info_internal(int ancestor_level, 233 ompt_data_t **parallel_data, 234 int *team_size) { 235 if (__kmp_get_gtid() >= 0) { 236 ompt_team_info_t *info; 237 if (team_size) { 238 info = __ompt_get_teaminfo(ancestor_level, team_size); 239 } else { 240 info = __ompt_get_teaminfo(ancestor_level, NULL); 241 } 242 if (parallel_data) { 243 *parallel_data = info ? &(info->parallel_data) : NULL; 244 } 245 return info ? 2 : 0; 246 } else { 247 return 0; 248 } 249 } 250 251 //---------------------------------------------------------- 252 // lightweight task team support 253 //---------------------------------------------------------- 254 255 void __ompt_lw_taskteam_init(ompt_lw_taskteam_t *lwt, kmp_info_t *thr, int gtid, 256 ompt_data_t *ompt_pid, void *codeptr) { 257 // initialize parallel_data with input, return address to parallel_data on 258 // exit 259 lwt->ompt_team_info.parallel_data = *ompt_pid; 260 lwt->ompt_team_info.master_return_address = codeptr; 261 lwt->ompt_task_info.task_data.value = 0; 262 lwt->ompt_task_info.frame.enter_frame = ompt_data_none; 263 lwt->ompt_task_info.frame.exit_frame = ompt_data_none; 264 lwt->ompt_task_info.scheduling_parent = NULL; 265 lwt->heap = 0; 266 lwt->parent = 0; 267 } 268 269 void __ompt_lw_taskteam_link(ompt_lw_taskteam_t *lwt, kmp_info_t *thr, 270 int on_heap, bool always) { 271 ompt_lw_taskteam_t *link_lwt = lwt; 272 if (always || 273 thr->th.th_team->t.t_serialized > 274 1) { // we already have a team, so link the new team and swap values 275 if (on_heap) { // the lw_taskteam cannot stay on stack, allocate it on heap 276 link_lwt = 277 (ompt_lw_taskteam_t *)__kmp_allocate(sizeof(ompt_lw_taskteam_t)); 278 } 279 link_lwt->heap = on_heap; 280 281 // would be swap in the (on_stack) case. 282 ompt_team_info_t tmp_team = lwt->ompt_team_info; 283 link_lwt->ompt_team_info = *OMPT_CUR_TEAM_INFO(thr); 284 *OMPT_CUR_TEAM_INFO(thr) = tmp_team; 285 286 // link the taskteam into the list of taskteams: 287 ompt_lw_taskteam_t *my_parent = 288 thr->th.th_team->t.ompt_serialized_team_info; 289 link_lwt->parent = my_parent; 290 thr->th.th_team->t.ompt_serialized_team_info = link_lwt; 291 #if OMPD_SUPPORT 292 if (ompd_state & OMPD_ENABLE_BP) { 293 ompd_bp_parallel_begin(); 294 } 295 #endif 296 297 ompt_task_info_t tmp_task = lwt->ompt_task_info; 298 link_lwt->ompt_task_info = *OMPT_CUR_TASK_INFO(thr); 299 *OMPT_CUR_TASK_INFO(thr) = tmp_task; 300 } else { 301 // this is the first serialized team, so we just store the values in the 302 // team and drop the taskteam-object 303 *OMPT_CUR_TEAM_INFO(thr) = lwt->ompt_team_info; 304 #if OMPD_SUPPORT 305 if (ompd_state & OMPD_ENABLE_BP) { 306 ompd_bp_parallel_begin(); 307 } 308 #endif 309 *OMPT_CUR_TASK_INFO(thr) = lwt->ompt_task_info; 310 } 311 } 312 313 void __ompt_lw_taskteam_unlink(kmp_info_t *thr) { 314 ompt_lw_taskteam_t *lwtask = thr->th.th_team->t.ompt_serialized_team_info; 315 if (lwtask) { 316 ompt_task_info_t tmp_task = lwtask->ompt_task_info; 317 lwtask->ompt_task_info = *OMPT_CUR_TASK_INFO(thr); 318 *OMPT_CUR_TASK_INFO(thr) = tmp_task; 319 #if OMPD_SUPPORT 320 if (ompd_state & OMPD_ENABLE_BP) { 321 ompd_bp_parallel_end(); 322 } 323 #endif 324 thr->th.th_team->t.ompt_serialized_team_info = lwtask->parent; 325 326 ompt_team_info_t tmp_team = lwtask->ompt_team_info; 327 lwtask->ompt_team_info = *OMPT_CUR_TEAM_INFO(thr); 328 *OMPT_CUR_TEAM_INFO(thr) = tmp_team; 329 330 if (lwtask->heap) { 331 __kmp_free(lwtask); 332 lwtask = NULL; 333 } 334 } 335 // return lwtask; 336 } 337 338 //---------------------------------------------------------- 339 // task support 340 //---------------------------------------------------------- 341 342 int __ompt_get_task_info_internal(int ancestor_level, int *type, 343 ompt_data_t **task_data, 344 ompt_frame_t **task_frame, 345 ompt_data_t **parallel_data, 346 int *thread_num) { 347 if (__kmp_get_gtid() < 0) 348 return 0; 349 350 if (ancestor_level < 0) 351 return 0; 352 353 // copied from __ompt_get_scheduling_taskinfo 354 ompt_task_info_t *info = NULL; 355 ompt_team_info_t *team_info = NULL; 356 kmp_info_t *thr = ompt_get_thread(); 357 int level = ancestor_level; 358 359 if (thr) { 360 kmp_taskdata_t *taskdata = thr->th.th_current_task; 361 if (taskdata == NULL) 362 return 0; 363 kmp_team *team = thr->th.th_team, *prev_team = NULL; 364 if (team == NULL) 365 return 0; 366 ompt_lw_taskteam_t *lwt = NULL, 367 *next_lwt = LWT_FROM_TEAM(taskdata->td_team); 368 369 while (ancestor_level > 0) { 370 // next lightweight team (if any) 371 if (lwt) 372 lwt = lwt->parent; 373 374 // next heavyweight team (if any) after 375 // lightweight teams are exhausted 376 if (!lwt && taskdata) { 377 // first try scheduling parent (for explicit task scheduling) 378 if (taskdata->ompt_task_info.scheduling_parent) { 379 taskdata = taskdata->ompt_task_info.scheduling_parent; 380 } else if (next_lwt) { 381 lwt = next_lwt; 382 next_lwt = NULL; 383 } else { 384 // then go for implicit tasks 385 taskdata = taskdata->td_parent; 386 if (team == NULL) 387 return 0; 388 prev_team = team; 389 team = team->t.t_parent; 390 if (taskdata) { 391 next_lwt = LWT_FROM_TEAM(taskdata->td_team); 392 } 393 } 394 } 395 ancestor_level--; 396 } 397 398 if (lwt) { 399 info = &lwt->ompt_task_info; 400 team_info = &lwt->ompt_team_info; 401 if (type) { 402 *type = ompt_task_implicit; 403 } 404 } else if (taskdata) { 405 info = &taskdata->ompt_task_info; 406 team_info = &team->t.ompt_team_info; 407 if (type) { 408 if (taskdata->td_parent) { 409 *type = (taskdata->td_flags.tasktype ? ompt_task_explicit 410 : ompt_task_implicit) | 411 TASK_TYPE_DETAILS_FORMAT(taskdata); 412 } else { 413 *type = ompt_task_initial; 414 } 415 } 416 } 417 if (task_data) { 418 *task_data = info ? &info->task_data : NULL; 419 } 420 if (task_frame) { 421 // OpenMP spec asks for the scheduling task to be returned. 422 *task_frame = info ? &info->frame : NULL; 423 } 424 if (parallel_data) { 425 *parallel_data = team_info ? &(team_info->parallel_data) : NULL; 426 } 427 if (thread_num) { 428 if (level == 0) 429 *thread_num = __kmp_get_tid(); 430 else if (lwt) 431 *thread_num = 0; 432 else if (!prev_team) { 433 // The innermost parallel region contains at least one explicit task. 434 // The task at level > 0 is either an implicit task that 435 // corresponds to the mentioned region or one of the explicit tasks 436 // nested inside the same region. Note that the task isn't the 437 // innermost explicit tasks (because of condition level > 0). 438 // Since the task at this level still belongs to the innermost parallel 439 // region, thread_num is determined the same way as for level==0. 440 *thread_num = __kmp_get_tid(); 441 } else 442 *thread_num = prev_team->t.t_master_tid; 443 // *thread_num = team->t.t_master_tid; 444 } 445 return info ? 2 : 0; 446 } 447 return 0; 448 } 449 450 int __ompt_get_task_memory_internal(void **addr, size_t *size, int blocknum) { 451 if (blocknum != 0) 452 return 0; // support only a single block 453 454 kmp_info_t *thr = ompt_get_thread(); 455 if (!thr) 456 return 0; 457 458 kmp_taskdata_t *taskdata = thr->th.th_current_task; 459 kmp_task_t *task = KMP_TASKDATA_TO_TASK(taskdata); 460 461 if (taskdata->td_flags.tasktype != TASK_EXPLICIT) 462 return 0; // support only explicit task 463 464 void *ret_addr; 465 int64_t ret_size = taskdata->td_size_alloc - sizeof(kmp_taskdata_t); 466 467 // kmp_task_t->data1 is an optional member 468 if (taskdata->td_flags.destructors_thunk) 469 ret_addr = &task->data1 + 1; 470 else 471 ret_addr = &task->part_id + 1; 472 473 ret_size -= (char *)(ret_addr) - (char *)(task); 474 if (ret_size < 0) 475 return 0; 476 477 *addr = ret_addr; 478 *size = (size_t)ret_size; 479 return 1; 480 } 481 482 //---------------------------------------------------------- 483 // team support 484 //---------------------------------------------------------- 485 486 void __ompt_team_assign_id(kmp_team_t *team, ompt_data_t ompt_pid) { 487 team->t.ompt_team_info.parallel_data = ompt_pid; 488 } 489 490 //---------------------------------------------------------- 491 // misc 492 //---------------------------------------------------------- 493 494 static uint64_t __ompt_get_unique_id_internal() { 495 static uint64_t thread = 1; 496 static THREAD_LOCAL uint64_t ID = 0; 497 if (ID == 0) { 498 uint64_t new_thread = KMP_TEST_THEN_INC64((kmp_int64 *)&thread); 499 ID = new_thread << (sizeof(uint64_t) * 8 - OMPT_THREAD_ID_BITS); 500 } 501 return ++ID; 502 } 503 504 ompt_sync_region_t __ompt_get_barrier_kind(enum barrier_type bt, 505 kmp_info_t *thr) { 506 if (bt == bs_forkjoin_barrier) 507 return ompt_sync_region_barrier_implicit; 508 509 if (bt != bs_plain_barrier) 510 return ompt_sync_region_barrier_implementation; 511 512 if (!thr->th.th_ident) 513 return ompt_sync_region_barrier; 514 515 kmp_int32 flags = thr->th.th_ident->flags; 516 517 if ((flags & KMP_IDENT_BARRIER_EXPL) != 0) 518 return ompt_sync_region_barrier_explicit; 519 520 if ((flags & KMP_IDENT_BARRIER_IMPL) != 0) 521 return ompt_sync_region_barrier_implicit; 522 523 return ompt_sync_region_barrier_implementation; 524 } 525