GCC Code Coverage Report


Directory: src/
File: src/LB_numThreads/omptool.c
Date: 2026-09-15 07:37:49
Exec Total Coverage
Lines: 268 408 65.7%
Functions: 22 24 91.7%
Branches: 151 370 40.8%

Line Branch Exec Source
1 /*********************************************************************************/
2 /* Copyright 2009-2026 Barcelona Supercomputing Center */
3 /* */
4 /* This file is part of the DLB library. */
5 /* */
6 /* DLB is free software: you can redistribute it and/or modify */
7 /* it under the terms of the GNU Lesser General Public License as published by */
8 /* the Free Software Foundation, either version 3 of the License, or */
9 /* (at your option) any later version. */
10 /* */
11 /* DLB is distributed in the hope that it will be useful, */
12 /* but WITHOUT ANY WARRANTY; without even the implied warranty of */
13 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
14 /* GNU Lesser General Public License for more details. */
15 /* */
16 /* You should have received a copy of the GNU Lesser General Public License */
17 /* along with DLB. If not, see <https://www.gnu.org/licenses/>. */
18 /*********************************************************************************/
19
20 /* Configure second tool with:
21 * DLB_TOOL_LIBRARIES
22 * DLB_TOOL_VERBOSE_INIT
23 */
24 #define OMPT_MULTIPLEX_TOOL_NAME "DLB"
25 #include "LB_numThreads/ompt-multiplex.h"
26
27 #include "LB_numThreads/omptool.h"
28
29 #include "LB_numThreads/omp-tools.h"
30 #include "LB_numThreads/omptm_omp5.h"
31 #include "LB_numThreads/omptm_free_agents.h"
32 #include "LB_numThreads/omptm_role_shift.h"
33 #include "LB_core/spd.h"
34 #include "apis/dlb.h"
35 #include "apis/dlb_errors.h"
36 #include "support/debug.h"
37 #include "support/dlb_common.h"
38 #include "support/mask_utils.h"
39 #include "support/tracing.h"
40 #include "talp/talp_openmp.h"
41
42 #include <inttypes.h>
43 #include <unistd.h>
44 #include <string.h>
45 #include <stdbool.h>
46 #include <sys/syscall.h>
47
48
49 static omptool_callback_funcs_t omptool_funcs = {0};
50 static omptool_event_funcs_t talp_funcs = {0};
51 static omptool_event_funcs_t omptm_funcs = {0};
52 static ompt_set_callback_t set_callback_fn = NULL;
53
54
55 /*********************************************************************************/
56 /* Init & Finalize */
57 /*********************************************************************************/
58
59 4 static void omptool__init(pid_t process_id, const options_t *options) {
60
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
4 if (talp_funcs.init) {
61 2 talp_funcs.init(process_id, options);
62 }
63
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
4 if (omptm_funcs.init) {
64 2 omptm_funcs.init(process_id, options);
65 }
66 4 }
67
68 4 static void omptool__finalize(void) {
69
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
4 if (talp_funcs.finalize) {
70 2 talp_funcs.finalize();
71 }
72
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
4 if (omptm_funcs.finalize) {
73 2 omptm_funcs.finalize();
74 }
75 4 }
76
77
78 /*********************************************************************************/
79 /* "Callbacks" from MPI and DLB API */
80 /*********************************************************************************/
81
82 22 void omptool__into_blocking_call(void) {
83
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 20 times.
22 if (talp_funcs.into_mpi) {
84 2 talp_funcs.into_mpi();
85 }
86
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 20 times.
22 if (omptm_funcs.into_mpi) {
87 2 omptm_funcs.into_mpi();
88 }
89 22 }
90
91 22 void omptool__outof_blocking_call(void) {
92
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 20 times.
22 if (omptm_funcs.outof_mpi) {
93 2 omptm_funcs.outof_mpi();
94 }
95
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 20 times.
22 if (talp_funcs.outof_mpi) {
96 2 talp_funcs.outof_mpi();
97 }
98 22 }
99
100 4 void omptool__lend_from_api(void) {
101
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
4 if (omptm_funcs.lend_from_api) {
102 2 omptm_funcs.lend_from_api();
103 }
104 4 }
105
106
107 /*********************************************************************************/
108 /* OpenMP callbacks */
109 /*********************************************************************************/
110
111 4 static void omptool_callback__thread_begin(
112 ompt_thread_t thread_type,
113 ompt_data_t *thread_data) {
114
115 4 spd_enter_dlb(thread_spd);
116
117
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 verbose(VB_OMPT, "native-thread-begin event");
118
119
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
4 if (talp_funcs.thread_begin) {
120 2 talp_funcs.thread_begin(thread_type);
121 }
122
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
4 if (omptm_funcs.thread_begin) {
123 2 omptm_funcs.thread_begin(thread_type);
124 }
125 4 }
126
127 4 static void omptool_callback__thread_end(
128 ompt_data_t *thread_data) {
129
130
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 verbose(VB_OMPT, "native-thread-end event");
131
132
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
4 if (talp_funcs.thread_end) {
133 2 talp_funcs.thread_end();
134 }
135
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
4 if (omptm_funcs.thread_end) {
136 2 omptm_funcs.thread_end();
137 }
138 4 }
139
140
141 /* Parallel data storage from level 1 will be reused, other levels will be
142 * allocated on demand */
143 static omptool_parallel_data_t omptool_parallel_data_level1 = {.level = 1};
144
145 12 static void omptool_callback__parallel_begin(
146 ompt_data_t *encountering_task_data,
147 const ompt_frame_t *encountering_task_frame,
148 ompt_data_t *parallel_data,
149 unsigned int requested_parallelism,
150 int flags,
151 const void *codeptr_ra) {
152
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 4 times.
12 if (flags & ompt_parallel_team) {
153 /* Obtain the nesting level of the generating parallel region and save
154 * some info in parallel_data */
155 8 omptool_parallel_data_t *omptool_parallel_data = NULL;
156
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 4 times.
8 if (encountering_task_frame->exit_frame.ptr == NULL) {
157 /* No exit frame means inital task, so this parallel is level 1 */
158 4 omptool_parallel_data = &omptool_parallel_data_level1;
159
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 } else if (encountering_task_data->value > 0) {
160 /* Allocate new data */
161 4 void *new_data = NULL;
162
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 if (posix_memalign(&new_data, DLB_CACHE_LINE, sizeof(omptool_parallel_data_t)) == 0) {
163 4 omptool_parallel_data = new_data;
164 4 *omptool_parallel_data = (omptool_parallel_data_t) {
165 4 .level = encountering_task_data->value + 1,
166 };
167 } else {
168 fatal("Memory allocation error in %s", __func__);
169 }
170 }
171
172
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 ensure(omptool_parallel_data != NULL, "Unhandled case in %s",__func__);
173
174 8 omptool_parallel_data->codeptr_ra = codeptr_ra;
175 8 omptool_parallel_data->requested_parallelism = requested_parallelism;
176 8 parallel_data->ptr = omptool_parallel_data;
177
178
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 4 times.
8 if (omptool_parallel_data->level == 1) {
179
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 verbose(VB_OMPT, "parallel-begin event");
180 } else {
181
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 verbose(VB_OMPT, "parallel-begin event: nesting level %u",
182 omptool_parallel_data->level);
183 }
184
185 /* Finally, invoke TALP or OMPTM if needed */
186
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 4 times.
8 if (talp_funcs.parallel_begin) {
187 4 talp_funcs.parallel_begin(omptool_parallel_data);
188 }
189
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 4 times.
8 if (omptm_funcs.parallel_begin) {
190 4 omptm_funcs.parallel_begin(omptool_parallel_data);
191 }
192 } else {
193 /* ompt_parallel_league ? not supported */
194 }
195 12 }
196
197 8 static void omptool_callback__parallel_end(
198 ompt_data_t *parallel_data,
199 ompt_data_t *encountering_task_data,
200 int flags,
201 const void *codeptr_ra) {
202
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
8 if (flags & ompt_parallel_team) {
203 8 omptool_parallel_data_t *omptool_parallel_data = parallel_data->ptr;
204
205
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 4 times.
8 if (omptool_parallel_data->level == 1) {
206
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 verbose(VB_OMPT, "parallel-end event");
207 } else {
208
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 verbose(VB_OMPT, "parallel-end event: nesting level %u",
209 omptool_parallel_data->level);
210 }
211
212
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 4 times.
8 if (talp_funcs.parallel_end) {
213 4 talp_funcs.parallel_end(omptool_parallel_data);
214 }
215
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 4 times.
8 if (omptm_funcs.parallel_end) {
216 4 omptm_funcs.parallel_end(omptool_parallel_data);
217 }
218
219 /* Deallocate if needed */
220
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 4 times.
8 if (omptool_parallel_data->level > 1) {
221 4 free(parallel_data->ptr);
222 }
223
224 instrument_event(BINDINGS_EVENT, sched_getcpu()+1, EVENT_BEGIN);
225 }
226 8 }
227
228 4 static void omptool_callback__task_create(
229 ompt_data_t *encountering_task_data,
230 const ompt_frame_t *encountering_task_frame,
231 ompt_data_t *new_task_data,
232 int flags,
233 int has_dependences,
234 const void *codeptr_ra) {
235
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 if (flags & ompt_task_explicit) {
236 /* Pass nesting level */
237 4 new_task_data->value = encountering_task_data->value;
238
239
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 verbose(VB_OMPT, "task-create event");
240
241
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
4 if (talp_funcs.task_create) {
242 2 talp_funcs.task_create();
243 }
244
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
4 if (omptm_funcs.task_create) {
245 2 omptm_funcs.task_create();
246 }
247 }
248 4 }
249
250 8 static void omptool_callback__task_schedule(
251 ompt_data_t *prior_task_data,
252 ompt_task_status_t prior_task_status,
253 ompt_data_t *next_task_data) {
254
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 4 times.
8 if (prior_task_status == ompt_task_complete) {
255
256
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 verbose(VB_OMPT, "task-schedule event: task complete");
257
258
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
4 if (talp_funcs.task_complete) {
259 2 talp_funcs.task_complete();
260 }
261
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
4 if (omptm_funcs.task_complete) {
262 2 omptm_funcs.task_complete();
263 }
264
265 instrument_event(BINDINGS_EVENT, 0, EVENT_END);
266
267
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 } else if (prior_task_status == ompt_task_switch) {
268
269
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 verbose(VB_OMPT, "task-schedule event: task switch");
270
271
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
4 if (talp_funcs.task_switch) {
272 2 talp_funcs.task_switch();
273 }
274
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
4 if (omptm_funcs.task_switch) {
275 2 omptm_funcs.task_switch();
276 }
277
278 instrument_event(BINDINGS_EVENT, sched_getcpu()+1, EVENT_BEGIN);
279 }
280 8 }
281
282 8 static void omptool_callback__implicit_task(
283 ompt_scope_endpoint_t endpoint,
284 ompt_data_t *parallel_data,
285 ompt_data_t *task_data,
286 unsigned int actual_parallelism,
287 unsigned int index,
288 int flags) {
289
290
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
8 if (flags & ompt_task_implicit) {
291
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
8 if (endpoint == ompt_scope_begin
292
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
8 && parallel_data != NULL
293
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
16 && parallel_data->ptr != NULL) {
294
295 8 omptool_parallel_data_t *omptool_parallel_data = parallel_data->ptr;
296
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
8 if (index == 0) {
297 8 omptool_parallel_data->actual_parallelism = actual_parallelism;
298 }
299
300 /* Pass nesting level to implicit task */
301 8 task_data->value = omptool_parallel_data->level;
302
303
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 verbose(VB_OMPT, "implicit-task-begin event: into parallel function");
304
305
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 4 times.
8 if (talp_funcs.into_parallel_function) {
306 4 talp_funcs.into_parallel_function(omptool_parallel_data, index);
307 }
308
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 4 times.
8 if (omptm_funcs.into_parallel_function) {
309 4 omptm_funcs.into_parallel_function(omptool_parallel_data, index);
310 }
311
312 instrument_event(BINDINGS_EVENT, sched_getcpu()+1, EVENT_BEGIN);
313 }
314 else if (endpoint == ompt_scope_end) {
315 /* Note: parallel_data is NULL */
316
317 verbose(VB_OMPT, "implicit-task-end event");
318
319 if (index == 0) {
320 /* The primary thread state is already controlled in the parallel-end event */
321 } else {
322 /* This event is emitted differently across OpenMP implementations.
323 *
324 * In LLVM (tested with earlier versions until 19), team-worker threads are
325 * typically suspended during the implicit barrier at the end of a parallel
326 * region, and this event is not triggered until they resume at the start of
327 * the next parallel region.
328 *
329 * Cray PE (testing with versions 8.3 - 8.5, based on LLVM 17) invokes this
330 * event for each team-worker thread, but sometimes after the primary thread
331 * has already triggered the parallel-end event. This can introduce race
332 * conditions that cause the timing metrics to be attributed to different states,
333 * potentially leading to inconsistent efficiency results.
334 */
335 if (talp_funcs.outof_parallel_function) {
336 talp_funcs.outof_parallel_function();
337 }
338 if (omptm_funcs.outof_parallel_function) {
339 omptm_funcs.outof_parallel_function();
340 }
341
342 instrument_event(BINDINGS_EVENT, 0, EVENT_END);
343 }
344 }
345 }
346 else if (flags & ompt_task_initial) {
347 if (endpoint == ompt_scope_begin) {
348 verbose(VB_OMPT, "initial-task-begin event");
349 } else if (endpoint == ompt_scope_end) {
350 verbose(VB_OMPT, "initial-task-end event");
351 }
352 }
353 8 }
354
355
356 12 static inline void into_parallel_implicit_barrier(omptool_parallel_data_t *data) {
357
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 6 times.
12 if (talp_funcs.into_parallel_implicit_barrier) {
358 6 talp_funcs.into_parallel_implicit_barrier(data);
359 }
360
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 6 times.
12 if (omptm_funcs.into_parallel_implicit_barrier) {
361 6 omptm_funcs.into_parallel_implicit_barrier(data);
362 }
363
364 instrument_event(BINDINGS_EVENT, 0, EVENT_END);
365 12 }
366
367 static inline void into_parallel_sync(omptool_parallel_data_t *data) {
368 if (talp_funcs.into_parallel_sync) {
369 talp_funcs.into_parallel_sync(data);
370 }
371 if (omptm_funcs.into_parallel_sync) {
372 omptm_funcs.into_parallel_sync(data);
373 }
374 }
375
376 static inline void outof_parallel_sync(omptool_parallel_data_t *data) {
377 if (talp_funcs.outof_parallel_sync) {
378 talp_funcs.outof_parallel_sync(data);
379 }
380 if (omptm_funcs.outof_parallel_sync) {
381 omptm_funcs.outof_parallel_sync(data);
382 }
383 }
384
385 /* Warning: Newer LLVM versions already use the new
386 * `ompt_sync_region_barrier_implicit_parallel` enum, but older versions and
387 * Cray runtimes still use the deprecated `ompt_sync_region_barrier_implicit`.
388 * This enum value is also used for implicit barriers in a **single** region,
389 * but we can still identify the implicit barrier of a parallel region
390 * comparing the codeptr_ra, which will be NULL for all team-worker threads,
391 * and equal to the codeptr_ra from parallel_begin for the primary thread.
392 */
393 12 static void omptool_callback__sync_region(
394 ompt_sync_region_t kind,
395 ompt_scope_endpoint_t endpoint,
396 ompt_data_t *parallel_data,
397 ompt_data_t *task_data,
398 const void *codeptr_ra) {
399
2/4
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
12 if (parallel_data != NULL && parallel_data->ptr != NULL) {
400 12 omptool_parallel_data_t *data = parallel_data->ptr;
401
2/10
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 4 times.
✗ Branch 9 not taken.
12 switch (kind) {
402 8 case ompt_sync_region_barrier_implicit:
403 /* deprecated enum, includes implicit barriers from parallel,
404 * single, workshare, etc. */
405
2/4
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
8 if (codeptr_ra == NULL || codeptr_ra == data->codeptr_ra) {
406
407 /* Note: Cray OpenMP still uses this enum, but apparently
408 * only for parallel region with no tasks */
409
410 /* implicit barrier in parallel region only if codeptr_ra is NULL
411 * or equal to parallel region's */
412
413
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
8 if (endpoint == ompt_scope_begin) {
414
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 verbose(VB_OMPT, "implicit-barrier-begin event: "
415 "end of parallel function (deprecated enum)");
416 8 into_parallel_implicit_barrier(data);
417 }
418 else if (endpoint == ompt_scope_end) {
419 verbose(VB_OMPT, "implicit-barrier-end event: "
420 "end of parallel function (deprecated enum)");
421 }
422
423 } else {
424
425 /* other implicit barriers */
426
427 if (endpoint == ompt_scope_begin) {
428 verbose(VB_OMPT, "implicit-barrier-begin event: sync region");
429 into_parallel_sync(data);
430 } else if (endpoint == ompt_scope_end) {
431 verbose(VB_OMPT, "implicit-barrier-end event: sync region");
432 outof_parallel_sync(data);
433 }
434 }
435 8 break;
436
437 case ompt_sync_region_barrier_explicit:
438 if (endpoint == ompt_scope_begin) {
439 verbose(VB_OMPT, "explicit-barrier-begin event");
440 into_parallel_sync(data);
441 } else if (endpoint == ompt_scope_end) {
442 verbose(VB_OMPT, "explicit-barrier-end event");
443 outof_parallel_sync(data);
444 }
445 break;
446
447 case ompt_sync_region_barrier_implementation:
448 verbose(VB_OMPT, "Implementation-Specific Barrier event");
449 if (endpoint == ompt_scope_begin) {
450 into_parallel_sync(data);
451 } else if (endpoint == ompt_scope_end) {
452 outof_parallel_sync(data);
453 }
454 break;
455
456 case ompt_sync_region_taskwait:
457 if (endpoint == ompt_scope_begin) {
458 verbose(VB_OMPT, "taskwait-begin event");
459 into_parallel_sync(data);
460 } else if (endpoint == ompt_scope_end) {
461 verbose(VB_OMPT, "taskwait-end event");
462 outof_parallel_sync(data);
463 }
464 break;
465
466 case ompt_sync_region_taskgroup:
467 if (endpoint == ompt_scope_begin) {
468 verbose(VB_OMPT, "taskgroup-begin event");
469 into_parallel_sync(data);
470 } else if (endpoint == ompt_scope_end) {
471 verbose(VB_OMPT, "taskgroup-end event");
472 outof_parallel_sync(data);
473 }
474 break;
475
476 case ompt_sync_region_barrier_implicit_workshare:
477 if (endpoint == ompt_scope_begin) {
478 verbose(VB_OMPT, "implicit-barrier-begin event: workshare");
479 into_parallel_sync(data);
480 } else if (endpoint == ompt_scope_end) {
481 verbose(VB_OMPT, "implicit-barrier-end event: workshare");
482 outof_parallel_sync(data);
483 }
484 break;
485
486 case ompt_sync_region_barrier_teams:
487 if (endpoint == ompt_scope_begin) {
488 verbose(VB_OMPT, "implicit-barrier-begin event: teams");
489 into_parallel_sync(data);
490 } else if (endpoint == ompt_scope_end) {
491 verbose(VB_OMPT, "implicit-barrier-end event: teams");
492 outof_parallel_sync(data);
493 }
494 break;
495
496 case ompt_sync_region_reduction:
497 /* For now we don't do anything with reductions */
498 break;
499
500 4 case ompt_sync_region_barrier_implicit_parallel:
501 /* new enum in OMP 5.1 */
502
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 if (endpoint == ompt_scope_begin) {
503
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 verbose(VB_OMPT, "implicit-barrier-begin event: end of parallel function");
504 4 into_parallel_implicit_barrier(data);
505 }
506 else if (endpoint == ompt_scope_end) {
507 verbose(VB_OMPT, "implicit-barrier-end event: end of parallel function");
508 }
509 4 break;
510
511 default:
512 break;
513 }
514 }
515 12 }
516
517
518 /*********************************************************************************/
519 /* Function pointers setup */
520 /*********************************************************************************/
521
522 /* For testing purposes only, override function pointers */
523 static const omptool_event_funcs_t *test_talp_funcs = NULL;
524 static const omptool_event_funcs_t *test_omptm_funcs = NULL;
525 1 void omptool_testing__setup_event_fn_ptrs(
526 const omptool_event_funcs_t *talp_fns,
527 const omptool_event_funcs_t *omptm_fns) {
528 1 test_talp_funcs = talp_fns;
529 1 test_omptm_funcs = omptm_fns;
530 1 }
531
532 4 static void setup_omp_fn_ptrs(omptm_version_t omptm_version, bool talp_openmp) {
533
534 /* talp_funcs */
535
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
4 if (talp_openmp) {
536
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 verbose(VB_OMPT, "Enabling OMPT support for TALP");
537
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (test_talp_funcs) {
538 2 talp_funcs = *test_talp_funcs;
539 } else {
540 talp_funcs = talp_events_vtable;
541 }
542 } else {
543 2 talp_funcs = (const omptool_event_funcs_t) {};
544 }
545
546 /* omptm_funcs */
547
2/5
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
4 switch(omptm_version) {
548 2 case OMPTM_NONE:
549 2 omptm_funcs = (const omptool_event_funcs_t) {};
550 2 break;
551 2 case OMPTM_OMP5:
552
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 verbose(VB_OMPT, "Enabling OMPT support for OpenMP 5.0");
553
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (test_omptm_funcs) {
554 2 omptm_funcs = *test_omptm_funcs;
555 } else {
556 omptm_funcs = omptm_omp5_events_vtable;
557 }
558 2 break;
559 case OMPTM_FREE_AGENTS:
560 verbose(VB_OMPT, "Enabling experimental support with free agent threads");
561 if (test_omptm_funcs) {
562 omptm_funcs = *test_omptm_funcs;
563 } else {
564 omptm_funcs = omptm_free_agents_events_vtable;
565 }
566 break;
567 case OMPTM_ROLE_SHIFT:
568 verbose(VB_OMPT, "Enabling experimental support with role shift threads");
569 if (test_omptm_funcs) {
570 omptm_funcs = *test_omptm_funcs;
571 } else {
572 omptm_funcs = omptm_role_shift_events_vtable;
573 }
574 break;
575 }
576
577 /* The following callbacks are centralized and always registered, even if both
578 * omptm and talp are disabled. It is deciced this way to allow event tracing and
579 * debugging events entry via verbose messages. */
580 4 omptool_funcs = (const omptool_callback_funcs_t) {
581 .thread_begin = omptool_callback__thread_begin,
582 .thread_end = omptool_callback__thread_end,
583 .parallel_begin = omptool_callback__parallel_begin,
584 .parallel_end = omptool_callback__parallel_end,
585 .task_create = omptool_callback__task_create,
586 .task_schedule = omptool_callback__task_schedule,
587 .implicit_task = omptool_callback__implicit_task,
588 .sync_region = omptool_callback__sync_region,
589 };
590
591 /* The following function is a custom callback and it's only used in the
592 * experimental role-shift thread manager */
593
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (omptm_version == OMPTM_ROLE_SHIFT) {
594 omptool_funcs.thread_role_shift = omptm_role_shift__thread_role_shift;
595 }
596 4 }
597
598 32 static inline int set_ompt_callback(ompt_callbacks_t event, ompt_callback_t callback) {
599 32 int error = 1;
600
1/7
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 32 times.
✗ Branch 7 not taken.
32 switch (set_callback_fn(event, callback)) {
601 case ompt_set_error:
602 verbose(VB_OMPT, "OMPT set callback %d failed.", event);
603 break;
604 case ompt_set_never:
605 verbose(VB_OMPT, "OMPT set callback %d returned 'never'. The event was "
606 "registered but it will never occur or the callback will never "
607 "be invoked at runtime.", event);
608 break;
609 case ompt_set_impossible:
610 verbose(VB_OMPT, "OMPT set callback %d returned 'impossible'. The event "
611 "may occur but the tracing of it is not possible.", event);
612 break;
613 case ompt_set_sometimes:
614 verbose(VB_OMPT, "OMPT set callback %d returned 'sometimes'. The event "
615 "may occur and the callback will be invoked at runtime, but "
616 "only for an implementation-defined subset of associated event "
617 "occurrences.", event);
618 error = 0;
619 break;
620 case ompt_set_sometimes_paired:
621 verbose(VB_OMPT, "OMPT set callback %d returned 'sometimes paired'. "
622 "The event may occur and the callback will be invoked at "
623 "runtime, but only for an implementation-defined subset of "
624 "associated event occurrences. If any callback is invoked "
625 "with a begin_scope endpoint, it will be invoked also later "
626 "with and end_scope endpoint.", event);
627 error = 0;
628 break;
629 32 case ompt_set_always:
630 32 error = 0;
631 32 break;
632 default:
633 fatal("Unsupported return code at set_ompt_callback, "
634 "please file a bug report.");
635 }
636 32 return error;
637 }
638
639 4 static int set_ompt_callbacks(ompt_function_lookup_t lookup, omptm_version_t omptm_version,
640 bool talp_openmp) {
641
642 /* Populate global structs */
643 4 setup_omp_fn_ptrs(omptm_version, talp_openmp);
644
645 4 int error = 0;
646 4 set_callback_fn = (ompt_set_callback_t)lookup("ompt_set_callback");
647
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 if (set_callback_fn) {
648
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 if (omptool_funcs.thread_begin) {
649 4 error += set_ompt_callback(
650 ompt_callback_thread_begin,
651 4 (ompt_callback_t)omptool_funcs.thread_begin);
652 }
653
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 if (omptool_funcs.thread_end) {
654 4 error += set_ompt_callback(
655 ompt_callback_thread_end,
656 4 (ompt_callback_t)omptool_funcs.thread_end);
657 }
658
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (omptool_funcs.thread_role_shift) {
659 error += set_ompt_callback(
660 ompt_callback_thread_role_shift,
661 (ompt_callback_t)omptool_funcs.thread_role_shift);
662 }
663
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 if (omptool_funcs.parallel_begin) {
664 4 error += set_ompt_callback(
665 ompt_callback_parallel_begin,
666 4 (ompt_callback_t)omptool_funcs.parallel_begin);
667 }
668
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 if (omptool_funcs.parallel_end) {
669 4 error += set_ompt_callback(
670 ompt_callback_parallel_end,
671 4 (ompt_callback_t)omptool_funcs.parallel_end);
672 }
673
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 if (omptool_funcs.task_create) {
674 4 error += set_ompt_callback(
675 ompt_callback_task_create,
676 4 (ompt_callback_t)omptool_funcs.task_create);
677 }
678
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 if (omptool_funcs.task_schedule) {
679 4 error += set_ompt_callback(
680 ompt_callback_task_schedule,
681 4 (ompt_callback_t)omptool_funcs.task_schedule);
682 }
683
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 if (omptool_funcs.implicit_task) {
684 4 error += set_ompt_callback(
685 ompt_callback_implicit_task,
686 4 (ompt_callback_t)omptool_funcs.implicit_task);
687 }
688
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 if (omptool_funcs.sync_region) {
689 4 error += set_ompt_callback(
690 ompt_callback_sync_region,
691 4 (ompt_callback_t)omptool_funcs.sync_region);
692 }
693 } else {
694 error = 1;
695 verbose(VB_OMPT, "Could not look up function \"ompt_set_callback\"");
696 }
697
698
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 if (!error) {
699
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 verbose(VB_OMPT, "OMPT callbacks successfully registered");
700 }
701
702 4 return error;
703 }
704
705 4 static void unset_ompt_callbacks(void) {
706
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 if (set_callback_fn) {
707
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 if (omptool_funcs.thread_begin) {
708 4 set_callback_fn(ompt_callback_thread_begin, NULL);
709 }
710
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 if (omptool_funcs.thread_end) {
711 4 set_callback_fn(ompt_callback_thread_end, NULL);
712 }
713
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (omptool_funcs.thread_role_shift) {
714 set_callback_fn(ompt_callback_thread_role_shift, NULL);
715 }
716
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 if (omptool_funcs.parallel_begin) {
717 4 set_callback_fn(ompt_callback_parallel_begin, NULL);
718 }
719
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 if (omptool_funcs.parallel_end) {
720 4 set_callback_fn(ompt_callback_parallel_end, NULL);
721 }
722
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 if (omptool_funcs.task_create) {
723 4 set_callback_fn(ompt_callback_task_create, NULL);
724 }
725
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 if (omptool_funcs.task_schedule) {
726 4 set_callback_fn(ompt_callback_task_schedule, NULL);
727 }
728
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 if (omptool_funcs.implicit_task) {
729 4 set_callback_fn(ompt_callback_implicit_task, NULL);
730 }
731
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 if (omptool_funcs.sync_region) {
732 4 set_callback_fn(ompt_callback_sync_region, NULL);
733 }
734 }
735 4 }
736
737
738 /*********************************************************************************/
739 /* OMPT start tool */
740 /*********************************************************************************/
741
742 static bool dlb_initialized_through_ompt = false;
743 static bool omptool_initialized = false;
744 static const char *openmp_runtime_version;
745
746 4 static int omptool_initialize(ompt_function_lookup_t lookup, int initial_device_num,
747 ompt_data_t *tool_data) {
748
749 4 spd_enter_dlb(thread_spd);
750
751 /* Parse options and get the required fields */
752 options_t options;
753 4 options_init(&options, NULL);
754 4 debug_init(&options);
755
756 /* Print OMPT version and variables*/
757 4 const char *omp_policy_str = getenv("OMP_WAIT_POLICY");
758
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 verbose(VB_OMPT, "Detected OpenMP runtime: %s", openmp_runtime_version);
759
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 verbose(VB_OMPT, "Environment variables of interest:");
760
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 verbose(VB_OMPT, " OMP_WAIT_POLICY: %s", omp_policy_str);
761
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 if (strncmp(openmp_runtime_version, "Intel", 5) == 0 ||
762
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 strncmp(openmp_runtime_version, "LLVM", 4) == 0) {
763 verbose(VB_OMPT, " KMP_LIBRARY: %s", getenv("KMP_LIBRARY"));
764 verbose(VB_OMPT, " KMP_BLOCKTIME: %s", getenv("KMP_BLOCKTIME"));
765 }
766 /* when GCC implements OMPT: else if "gomp", print GOMP_SPINCOUNT */
767
768
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
4 verbose(VB_OMPT, "DLB with OMPT support is %s", options.ompt ? "ENABLED" : "DISABLED");
769
770 /* Enable OMPT only if requested */
771
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 if (options.ompt) {
772
773 /* Disable --ompt-thread-manager if no LeWI or DROM */
774
3/4
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
4 if (!(options.lewi || options.drom)) {
775 2 options.omptm_version = OMPTM_NONE;
776 }
777
778 /* Emit warning if OMP_WAIT_POLICY is not "passive" */
779
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
4 if (options.lewi &&
780
2/4
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
2 options.omptm_version == OMPTM_OMP5 &&
781 (!omp_policy_str || strcasecmp(omp_policy_str, "passive") != 0)) {
782 2 warning("OMP_WAIT_POLICY value it not \"passive\". Even though the default "
783 "value may be \"passive\", setting it explicitly is recommended "
784 "since it modifies other runtime related environment variables");
785 }
786
787 /* Hint to infer LeWI mode */
788 4 thread_spd->dlb_initialized_via_ompt = true;
789
790 4 int err = 0;
791
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 if (options.preinit_pid == 0) {
792 /* Force init */
793 cpu_set_t process_mask;
794 4 sched_getaffinity(0, sizeof(process_mask), &process_mask);
795 4 err = DLB_Init(0, &process_mask, NULL);
796
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 if (err == DLB_SUCCESS) {
797 4 dlb_initialized_through_ompt = true;
798 } else if (err != DLB_ERR_INIT) {
799 warning("DLB_Init failed: %s", DLB_Strerror(err));
800 }
801 } else {
802 /* Initialize DLB only if ompt is enabled, and
803 * remember if succeeded to finalize it when ompt_finalize is invoked. */
804 err = DLB_Init(0, NULL, NULL);
805 if (err == DLB_SUCCESS) {
806 dlb_initialized_through_ompt = true;
807 } else {
808 verbose(VB_OMPT, "DLB_Init: %s", DLB_Strerror(err));
809 }
810 }
811
812
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 verbose(VB_OMPT, "Initializing OMPT module");
813
814 /* Register OMPT callbacks */
815 4 bool talp_openmp = options.talp & (TALP_COMPONENT_DEFAULT | TALP_COMPONENT_OPENMP);
816 4 err = set_ompt_callbacks(lookup, options.omptm_version, talp_openmp);
817
818 /* If callbacks are successfully registered, initialize modules
819 * and return a non-zero value to activate the tool */
820
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 if (!err) {
821 4 omptool__init(thread_spd->id, &options);
822 4 options_finalize(&options);
823 /* we save the thread ID that initialized OMPT */
824 4 tool_data->value = syscall(SYS_gettid);
825 4 omptool_initialized = true;
826 4 return 1;
827 }
828
829 /* Otherwise, finalize DLB if init succeeded */
830 if (dlb_initialized_through_ompt) {
831 DLB_Finalize();
832 dlb_initialized_through_ompt = false;
833 }
834
835 warning("DLB could not register itself as OpenMP tool");
836 if (options.talp & TALP_COMPONENT_OPENMP) {
837 warning("TALP: Failed to load OpenMP component");
838 }
839 }
840
841 options_finalize(&options);
842
843 return 0;
844 }
845
846 4 static void omptool_finalize(ompt_data_t *tool_data) {
847
848 /* Protect finalization against forks and other double calls */
849
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 if (tool_data->value == (uint64_t)syscall(SYS_gettid)
850
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 && omptool_initialized) {
851
852
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 verbose(VB_OMPT, "Finalizing OMPT module");
853
854 /* Finalize DLB if needed */
855
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 if (dlb_initialized_through_ompt) {
856 4 DLB_Finalize();
857 }
858
859 /* Disable OMPT callbacks */
860 4 unset_ompt_callbacks();
861
862 /* Finalize modules */
863 4 omptool__finalize();
864
865 4 omptool_initialized = false;
866 4 dlb_initialized_through_ompt = false;
867 }
868 4 }
869
870
871 #ifndef OMPT_MULTIPLEX_H
872 DLB_EXPORT_SYMBOL
873 #endif
874 1 ompt_start_tool_result_t* ompt_start_tool(unsigned int omp_version, const char *runtime_version) {
875 1 openmp_runtime_version = runtime_version;
876 static ompt_start_tool_result_t tool = {
877 .initialize = omptool_initialize,
878 .finalize = omptool_finalize,
879 .tool_data = {0}
880 };
881 1 return &tool;
882 }
883