LLVM OpenMP
kmp_csupport.cpp
Go to the documentation of this file.
1/*
2 * kmp_csupport.cpp -- kfront linkage support for OpenMP.
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#define __KMP_IMP
14#include "omp.h" /* extern "C" declarations of user-visible routines */
15#include "kmp.h"
16#include "kmp_error.h"
17#include "kmp_i18n.h"
18#include "kmp_itt.h"
19#include "kmp_lock.h"
20#include "kmp_stats.h"
21#include "kmp_utils.h"
22#include "ompt-specific.h"
23
24#define MAX_MESSAGE 512
25
26// flags will be used in future, e.g. to implement openmp_strict library
27// restrictions
28
29/*!
30 * @ingroup STARTUP_SHUTDOWN
31 * @param loc in source location information
32 * @param flags in for future use (currently ignored)
33 *
34 * Initialize the runtime library. This call is optional; if it is not made then
35 * it will be implicitly called by attempts to use other library functions.
36 */
38 // By default __kmpc_begin() is no-op.
39 char *env;
40 if ((env = getenv("KMP_INITIAL_THREAD_BIND")) != NULL &&
44 KC_TRACE(10, ("__kmpc_begin: middle initialization called\n"));
45 } else if (__kmp_ignore_mppbeg() == FALSE) {
46 // By default __kmp_ignore_mppbeg() returns TRUE.
48 KC_TRACE(10, ("__kmpc_begin: called\n"));
49 }
50}
51
52/*!
53 * @ingroup STARTUP_SHUTDOWN
54 * @param loc source location information
55 *
56 * Shutdown the runtime library. This is also optional, and even if called will
57 * not do anything unless the `KMP_IGNORE_MPPEND` environment variable is set to
58 * zero.
59 */
61 // By default, __kmp_ignore_mppend() returns TRUE which makes __kmpc_end()
62 // call no-op. However, this can be overridden with KMP_IGNORE_MPPEND
63 // environment variable. If KMP_IGNORE_MPPEND is 0, __kmp_ignore_mppend()
64 // returns FALSE and __kmpc_end() will unregister this root (it can cause
65 // library shut down).
66 if (__kmp_ignore_mppend() == FALSE) {
67 KC_TRACE(10, ("__kmpc_end: called\n"));
68 KA_TRACE(30, ("__kmpc_end\n"));
69
71 }
72#if KMP_OS_WINDOWS && OMPT_SUPPORT
73 // Normal exit process on Windows does not allow worker threads of the final
74 // parallel region to finish reporting their events, so shutting down the
75 // library here fixes the issue at least for the cases where __kmpc_end() is
76 // placed properly.
77 if (ompt_enabled.enabled)
79#endif
80}
81
82/*!
83@ingroup THREAD_STATES
84@param loc Source location information.
85@return The global thread index of the active thread.
86
87This function can be called in any context.
88
89If the runtime has ony been entered at the outermost level from a
90single (necessarily non-OpenMP<sup>*</sup>) thread, then the thread number is
91that which would be returned by omp_get_thread_num() in the outermost
92active parallel construct. (Or zero if there is no active parallel
93construct, since the primary thread is necessarily thread zero).
94
95If multiple non-OpenMP threads all enter an OpenMP construct then this
96will be a unique thread identifier among all the threads created by
97the OpenMP runtime (but the value cannot be defined in terms of
98OpenMP thread ids returned by omp_get_thread_num()).
99*/
102
103 KC_TRACE(10, ("__kmpc_global_thread_num: T#%d\n", gtid));
104
105 return gtid;
106}
107
108/*!
109@ingroup THREAD_STATES
110@param loc Source location information.
111@return The number of threads under control of the OpenMP<sup>*</sup> runtime
112
113This function can be called in any context.
114It returns the total number of threads under the control of the OpenMP runtime.
115That is not a number that can be determined by any OpenMP standard calls, since
116the library may be called from more than one non-OpenMP thread, and this
117reflects the total over all such calls. Similarly the runtime maintains
118underlying threads even when they are not active (since the cost of creating
119and destroying OS threads is high), this call counts all such threads even if
120they are not waiting for work.
121*/
123 KC_TRACE(10,
124 ("__kmpc_global_num_threads: num_threads = %d\n", __kmp_all_nth));
125
126 return TCR_4(__kmp_all_nth);
127}
128
129/*!
130@ingroup THREAD_STATES
131@param loc Source location information.
132@return The thread number of the calling thread in the innermost active parallel
133construct.
134*/
136 KC_TRACE(10, ("__kmpc_bound_thread_num: called\n"));
138}
139
140/*!
141@ingroup THREAD_STATES
142@param loc Source location information.
143@return The number of threads in the innermost active parallel construct.
144*/
146 KC_TRACE(10, ("__kmpc_bound_num_threads: called\n"));
147
148 return __kmp_entry_thread()->th.th_team->t.t_nproc;
149}
150
151/*!
152 * @ingroup DEPRECATED
153 * @param loc location description
154 *
155 * This function need not be called. It always returns TRUE.
156 */
158#ifndef KMP_DEBUG
159
160 return TRUE;
161
162#else
163
164 const char *semi2;
165 const char *semi3;
166 int line_no;
167
168 if (__kmp_par_range == 0) {
169 return TRUE;
170 }
171 semi2 = loc->psource;
172 if (semi2 == NULL) {
173 return TRUE;
174 }
175 semi2 = strchr(semi2, ';');
176 if (semi2 == NULL) {
177 return TRUE;
178 }
179 semi2 = strchr(semi2 + 1, ';');
180 if (semi2 == NULL) {
181 return TRUE;
182 }
183 if (__kmp_par_range_filename[0]) {
184 const char *name = semi2 - 1;
185 while ((name > loc->psource) && (*name != '/') && (*name != ';')) {
186 name--;
187 }
188 if ((*name == '/') || (*name == ';')) {
189 name++;
190 }
191 if (strncmp(__kmp_par_range_filename, name, semi2 - name)) {
192 return __kmp_par_range < 0;
193 }
194 }
195 semi3 = strchr(semi2 + 1, ';');
196 if (__kmp_par_range_routine[0]) {
197 if ((semi3 != NULL) && (semi3 > semi2) &&
198 (strncmp(__kmp_par_range_routine, semi2 + 1, semi3 - semi2 - 1))) {
199 return __kmp_par_range < 0;
200 }
201 }
202 if (KMP_SSCANF(semi3 + 1, "%d", &line_no) == 1) {
203 if ((line_no >= __kmp_par_range_lb) && (line_no <= __kmp_par_range_ub)) {
204 return __kmp_par_range > 0;
205 }
206 return __kmp_par_range < 0;
207 }
208 return TRUE;
209
210#endif /* KMP_DEBUG */
211}
212
213/*!
214@ingroup THREAD_STATES
215@param loc Source location information.
216@return 1 if this thread is executing inside an active parallel region, zero if
217not.
218*/
220 return __kmp_entry_thread()->th.th_root->r.r_active;
221}
222
223/*!
224@ingroup PARALLEL
225@param loc source location information
226@param global_tid global thread number
227@param num_threads number of threads requested for this parallel construct
228
229Set the number of threads to be used by the next fork spawned by this thread.
230This call is only required if the parallel construct has a `num_threads` clause.
231*/
233 kmp_int32 num_threads) {
234 KA_TRACE(20, ("__kmpc_push_num_threads: enter T#%d num_threads=%d\n",
235 global_tid, num_threads));
236 __kmp_assert_valid_gtid(global_tid);
237 __kmp_push_num_threads(loc, global_tid, num_threads);
238}
239
241 kmp_int32 num_threads, int severity,
242 const char *message) {
243 __kmp_push_num_threads(loc, global_tid, num_threads);
244 __kmp_set_strict_num_threads(loc, global_tid, severity, message);
245}
246
247/*!
248@ingroup PARALLEL
249@param loc source location information
250@param global_tid global thread number
251@param list_length number of entries in the num_threads_list array
252@param num_threads_list array of numbers of threads requested for this parallel
253construct and subsequent nested parallel constructs
254
255Set the number of threads to be used by the next fork spawned by this thread,
256and some nested forks as well.
257This call is only required if the parallel construct has a `num_threads` clause
258that has a list of integers as the argument.
259*/
261 kmp_uint32 list_length,
262 kmp_int32 *num_threads_list) {
263 KA_TRACE(20, ("__kmpc_push_num_threads_list: enter T#%d num_threads_list=",
264 global_tid));
265 KA_TRACE(20, ("%d", num_threads_list[0]));
266#ifdef KMP_DEBUG
267 for (kmp_uint32 i = 1; i < list_length; ++i)
268 KA_TRACE(20, (", %d", num_threads_list[i]));
269#endif
270 KA_TRACE(20, ("/n"));
271
272 __kmp_assert_valid_gtid(global_tid);
273 __kmp_push_num_threads_list(loc, global_tid, list_length, num_threads_list);
274}
275
277 kmp_uint32 list_length,
278 kmp_int32 *num_threads_list,
279 int severity, const char *message) {
280 __kmp_push_num_threads_list(loc, global_tid, list_length, num_threads_list);
281 __kmp_set_strict_num_threads(loc, global_tid, severity, message);
282}
283
285 KA_TRACE(20, ("__kmpc_pop_num_threads: enter\n"));
286 /* the num_threads are automatically popped */
287}
288
290 kmp_int32 proc_bind) {
291 KA_TRACE(20, ("__kmpc_push_proc_bind: enter T#%d proc_bind=%d\n", global_tid,
292 proc_bind));
293 __kmp_assert_valid_gtid(global_tid);
294 __kmp_push_proc_bind(loc, global_tid, (kmp_proc_bind_t)proc_bind);
295}
296
297/*!
298@ingroup PARALLEL
299@param loc source location information
300@param argc total number of arguments in the ellipsis
301@param microtask pointer to callback routine consisting of outlined parallel
302construct
303@param ... pointers to shared variables that aren't global
304
305Do the actual fork and call the microtask in the relevant number of threads.
306*/
308 int gtid = __kmp_entry_gtid();
309
310#if (KMP_STATS_ENABLED)
311 // If we were in a serial region, then stop the serial timer, record
312 // the event, and start parallel region timer
313 stats_state_e previous_state = KMP_GET_THREAD_STATE();
314 if (previous_state == stats_state_e::SERIAL_REGION) {
315 KMP_EXCHANGE_PARTITIONED_TIMER(OMP_parallel_overhead);
316 } else {
317 KMP_PUSH_PARTITIONED_TIMER(OMP_parallel_overhead);
318 }
319 int inParallel = __kmpc_in_parallel(loc);
320 if (inParallel) {
321 KMP_COUNT_BLOCK(OMP_NESTED_PARALLEL);
322 } else {
323 KMP_COUNT_BLOCK(OMP_PARALLEL);
324 }
325#endif
326
327 // maybe to save thr_state is enough here
328 {
329 va_list ap;
330 va_start(ap, microtask);
331
332#if OMPT_SUPPORT
333 ompt_frame_t *ompt_frame;
334 if (ompt_enabled.enabled) {
335 kmp_info_t *master_th = __kmp_threads[gtid];
336 ompt_frame = &master_th->th.th_current_task->ompt_task_info.frame;
337 ompt_frame->enter_frame.ptr = OMPT_GET_FRAME_ADDRESS(0);
338 }
339 OMPT_STORE_RETURN_ADDRESS(gtid);
340#endif
341
342#if INCLUDE_SSC_MARKS
343 SSC_MARK_FORKING();
344#endif
346 VOLATILE_CAST(microtask_t) microtask, // "wrapped" task
348 kmp_va_addr_of(ap));
349#if INCLUDE_SSC_MARKS
350 SSC_MARK_JOINING();
351#endif
352 __kmp_join_call(loc, gtid
353#if OMPT_SUPPORT
354 ,
356#endif
357 );
358
359 va_end(ap);
360
361#if OMPT_SUPPORT
362 if (ompt_enabled.enabled) {
363 ompt_frame->enter_frame = ompt_data_none;
364 }
365#endif
366 }
367
368#if KMP_STATS_ENABLED
369 if (previous_state == stats_state_e::SERIAL_REGION) {
370 KMP_EXCHANGE_PARTITIONED_TIMER(OMP_serial);
371 KMP_SET_THREAD_STATE(previous_state);
372 } else {
374 }
375#endif // KMP_STATS_ENABLED
376}
377
378/*!
379@ingroup PARALLEL
380@param loc source location information
381@param microtask pointer to callback routine consisting of outlined parallel
382construct
383@param cond condition for running in parallel
384@param args struct of pointers to shared variables that aren't global
385
386Perform a fork only if the condition is true.
387*/
389 kmp_int32 cond, void *args) {
390 int gtid = __kmp_entry_gtid();
391 if (cond) {
392 if (args)
394 else
396 } else {
398
399#if OMPT_SUPPORT
400 void *exit_frame_ptr;
401#endif
402
403 if (args)
405 /*npr=*/0,
406 /*argc=*/1, &args
407#if OMPT_SUPPORT
408 ,
409 &exit_frame_ptr
410#endif
411 );
412 else
414 /*npr=*/0,
415 /*argc=*/0,
416 /*args=*/nullptr
417#if OMPT_SUPPORT
418 ,
419 &exit_frame_ptr
420#endif
421 );
422
424 }
425}
426
427/*!
428@ingroup PARALLEL
429@param loc source location information
430@param global_tid global thread number
431@param num_teams number of teams requested for the teams construct
432@param num_threads number of threads per team requested for the teams construct
433
434Set the number of teams to be used by the teams construct.
435This call is only required if the teams construct has a `num_teams` clause
436or a `thread_limit` clause (or both).
437*/
439 kmp_int32 num_teams, kmp_int32 num_threads) {
440 KA_TRACE(20,
441 ("__kmpc_push_num_teams: enter T#%d num_teams=%d num_threads=%d\n",
442 global_tid, num_teams, num_threads));
443 __kmp_assert_valid_gtid(global_tid);
444 __kmp_push_num_teams(loc, global_tid, num_teams, num_threads);
445}
446
447/*!
448@ingroup PARALLEL
449@param loc source location information
450@param global_tid global thread number
451@param thread_limit limit on number of threads which can be created within the
452current task
453
454Set the thread_limit for the current task
455This call is there to support `thread_limit` clause on the `target` construct
456*/
458 kmp_int32 thread_limit) {
459 __kmp_assert_valid_gtid(global_tid);
460 kmp_info_t *thread = __kmp_threads[global_tid];
461 if (thread_limit > 0)
462 thread->th.th_current_task->td_icvs.task_thread_limit = thread_limit;
463}
464
465/*!
466@ingroup PARALLEL
467@param loc source location information
468@param global_tid global thread number
469@param num_teams_lb lower bound on number of teams requested for the teams
470construct
471@param num_teams_ub upper bound on number of teams requested for the teams
472construct
473@param num_threads number of threads per team requested for the teams construct
474
475Set the number of teams to be used by the teams construct. The number of initial
476teams cretaed will be greater than or equal to the lower bound and less than or
477equal to the upper bound.
478This call is only required if the teams construct has a `num_teams` clause
479or a `thread_limit` clause (or both).
480*/
482 kmp_int32 num_teams_lb, kmp_int32 num_teams_ub,
483 kmp_int32 num_threads) {
484 KA_TRACE(20, ("__kmpc_push_num_teams_51: enter T#%d num_teams_lb=%d"
485 " num_teams_ub=%d num_threads=%d\n",
486 global_tid, num_teams_lb, num_teams_ub, num_threads));
487 __kmp_assert_valid_gtid(global_tid);
488 __kmp_push_num_teams_51(loc, global_tid, num_teams_lb, num_teams_ub,
489 num_threads);
490}
491
492/*!
493@ingroup PARALLEL
494@param loc source location information
495@param argc total number of arguments in the ellipsis
496@param microtask pointer to callback routine consisting of outlined teams
497construct
498@param ... pointers to shared variables that aren't global
499
500Do the actual fork and call the microtask in the relevant number of threads.
501*/
503 ...) {
504 int gtid = __kmp_entry_gtid();
505 kmp_info_t *this_thr = __kmp_threads[gtid];
506 va_list ap;
507 va_start(ap, microtask);
508
509#if KMP_STATS_ENABLED
510 KMP_COUNT_BLOCK(OMP_TEAMS);
511 stats_state_e previous_state = KMP_GET_THREAD_STATE();
512 if (previous_state == stats_state_e::SERIAL_REGION) {
513 KMP_EXCHANGE_PARTITIONED_TIMER(OMP_teams_overhead);
514 } else {
515 KMP_PUSH_PARTITIONED_TIMER(OMP_teams_overhead);
516 }
517#endif
518
519 // remember teams entry point and nesting level
520 this_thr->th.th_teams_microtask = microtask;
521 this_thr->th.th_teams_level =
522 this_thr->th.th_team->t.t_level; // AC: can be >0 on host
523
524#if OMPT_SUPPORT
525 kmp_team_t *parent_team = this_thr->th.th_team;
526 int tid = __kmp_tid_from_gtid(gtid);
527 if (ompt_enabled.enabled) {
528 parent_team->t.t_implicit_task_taskdata[tid]
529 .ompt_task_info.frame.enter_frame.ptr = OMPT_GET_FRAME_ADDRESS(0);
530 }
531 OMPT_STORE_RETURN_ADDRESS(gtid);
532#endif
533
534 // check if __kmpc_push_num_teams called, set default number of teams
535 // otherwise
536 if (this_thr->th.th_teams_size.nteams == 0) {
537 __kmp_push_num_teams(loc, gtid, 0, 0);
538 }
539 KMP_DEBUG_ASSERT(this_thr->th.th_set_nproc >= 1);
540 KMP_DEBUG_ASSERT(this_thr->th.th_teams_size.nteams >= 1);
541 KMP_DEBUG_ASSERT(this_thr->th.th_teams_size.nth >= 1);
542
544 loc, gtid, fork_context_intel, argc,
547 __kmp_join_call(loc, gtid
548#if OMPT_SUPPORT
549 ,
551#endif
552 );
553
554 // Pop current CG root off list
555 KMP_DEBUG_ASSERT(this_thr->th.th_cg_roots);
556 kmp_cg_root_t *tmp = this_thr->th.th_cg_roots;
557 this_thr->th.th_cg_roots = tmp->up;
558 KA_TRACE(100, ("__kmpc_fork_teams: Thread %p popping node %p and moving up"
559 " to node %p. cg_nthreads was %d\n",
560 this_thr, tmp, this_thr->th.th_cg_roots, tmp->cg_nthreads));
562 int i = tmp->cg_nthreads--;
563 if (i == 1) { // check is we are the last thread in CG (not always the case)
564 __kmp_free(tmp);
565 }
566 // Restore current task's thread_limit from CG root
567 KMP_DEBUG_ASSERT(this_thr->th.th_cg_roots);
568 this_thr->th.th_current_task->td_icvs.thread_limit =
569 this_thr->th.th_cg_roots->cg_thread_limit;
570
571 this_thr->th.th_teams_microtask = NULL;
572 this_thr->th.th_teams_level = 0;
573 memset(&this_thr->th.th_teams_size, 0, sizeof(kmp_teams_size_t));
574 va_end(ap);
575#if KMP_STATS_ENABLED
576 if (previous_state == stats_state_e::SERIAL_REGION) {
577 KMP_EXCHANGE_PARTITIONED_TIMER(OMP_serial);
578 KMP_SET_THREAD_STATE(previous_state);
579 } else {
581 }
582#endif // KMP_STATS_ENABLED
583}
584
585// I don't think this function should ever have been exported.
586// The __kmpc_ prefix was misapplied. I'm fairly certain that no generated
587// openmp code ever called it, but it's been exported from the RTL for so
588// long that I'm afraid to remove the definition.
589int __kmpc_invoke_task_func(int gtid) { return __kmp_invoke_task_func(gtid); }
590
591/*!
592@ingroup PARALLEL
593@param loc source location information
594@param global_tid global thread number
595
596Enter a serialized parallel construct. This interface is used to handle a
597conditional parallel region, like this,
598@code
599#pragma omp parallel if (condition)
600@endcode
601when the condition is false.
602*/
604 // The implementation is now in kmp_runtime.cpp so that it can share static
605 // functions with kmp_fork_call since the tasks to be done are similar in
606 // each case.
607 __kmp_assert_valid_gtid(global_tid);
608#if OMPT_SUPPORT
609 OMPT_STORE_RETURN_ADDRESS(global_tid);
610#endif
611 __kmp_serialized_parallel(loc, global_tid);
612}
613
614/*!
615@ingroup PARALLEL
616@param loc source location information
617@param global_tid global thread number
618
619Leave a serialized parallel construct.
620*/
623 kmp_info_t *this_thr;
624 kmp_team_t *serial_team;
625
626 KC_TRACE(10,
627 ("__kmpc_end_serialized_parallel: called by T#%d\n", global_tid));
628
629 /* skip all this code for autopar serialized loops since it results in
630 unacceptable overhead */
631 if (loc != NULL && (loc->flags & KMP_IDENT_AUTOPAR))
632 return;
633
634 // Not autopar code
635 __kmp_assert_valid_gtid(global_tid);
638
640
641 this_thr = __kmp_threads[global_tid];
642 serial_team = this_thr->th.th_serial_team;
643
644 kmp_task_team_t *task_team = this_thr->th.th_task_team;
645 // we need to wait for the proxy tasks before finishing the thread
646 if (task_team != NULL && (task_team->tt.tt_found_proxy_tasks ||
648 __kmp_task_team_wait(this_thr, serial_team USE_ITT_BUILD_ARG(NULL));
649
650 KMP_MB();
651 KMP_DEBUG_ASSERT(serial_team);
652 KMP_ASSERT(serial_team->t.t_serialized);
653 KMP_DEBUG_ASSERT(this_thr->th.th_team == serial_team);
654 KMP_DEBUG_ASSERT(serial_team != this_thr->th.th_root->r.r_root_team);
655 KMP_DEBUG_ASSERT(serial_team->t.t_threads);
656 KMP_DEBUG_ASSERT(serial_team->t.t_threads[0] == this_thr);
657
658#if OMPT_SUPPORT
659 if (ompt_enabled.enabled &&
660 this_thr->th.ompt_thread_info.state != ompt_state_overhead) {
661 OMPT_CUR_TASK_INFO(this_thr)->frame.exit_frame = ompt_data_none;
662 if (ompt_enabled.ompt_callback_implicit_task) {
663 ompt_callbacks.ompt_callback(ompt_callback_implicit_task)(
664 ompt_scope_end, NULL, OMPT_CUR_TASK_DATA(this_thr), 1,
665 OMPT_CUR_TASK_INFO(this_thr)->thread_num, ompt_task_implicit);
666 }
667
668 // reset clear the task id only after unlinking the task
669 ompt_data_t *parent_task_data;
670 __ompt_get_task_info_internal(1, NULL, &parent_task_data, NULL, NULL, NULL);
671
672 if (ompt_enabled.ompt_callback_parallel_end) {
673 ompt_callbacks.ompt_callback(ompt_callback_parallel_end)(
674 &(serial_team->t.ompt_team_info.parallel_data), parent_task_data,
675 ompt_parallel_invoker_program | ompt_parallel_team,
676 OMPT_LOAD_RETURN_ADDRESS(global_tid));
677 }
679 this_thr->th.ompt_thread_info.state = ompt_state_overhead;
680 }
681#endif
682
683 /* If necessary, pop the internal control stack values and replace the team
684 * values */
685 top = serial_team->t.t_control_stack_top;
686 if (top && top->serial_nesting_level == serial_team->t.t_serialized) {
687 copy_icvs(&serial_team->t.t_threads[0]->th.th_current_task->td_icvs, top);
688 serial_team->t.t_control_stack_top = top->next;
689 __kmp_free(top);
690 }
691
692 /* pop dispatch buffers stack */
693 KMP_DEBUG_ASSERT(serial_team->t.t_dispatch->th_disp_buffer);
694 {
695 dispatch_private_info_t *disp_buffer =
696 serial_team->t.t_dispatch->th_disp_buffer;
697 serial_team->t.t_dispatch->th_disp_buffer =
698 serial_team->t.t_dispatch->th_disp_buffer->next;
699 __kmp_free(disp_buffer);
700 }
701
702 /* pop the task team stack */
703 if (serial_team->t.t_serialized > 1) {
704 __kmp_pop_task_team_node(this_thr, serial_team);
705 }
706
707 this_thr->th.th_def_allocator = serial_team->t.t_def_allocator; // restore
708
709 --serial_team->t.t_serialized;
710 if (serial_team->t.t_serialized == 0) {
711
712 /* return to the parallel section */
713
714#if KMP_ARCH_X86 || KMP_ARCH_X86_64
715 if (__kmp_inherit_fp_control && serial_team->t.t_fp_control_saved) {
716 __kmp_clear_x87_fpu_status_word();
717 __kmp_load_x87_fpu_control_word(&serial_team->t.t_x87_fpu_control_word);
718 __kmp_load_mxcsr(&serial_team->t.t_mxcsr);
719 }
720#endif /* KMP_ARCH_X86 || KMP_ARCH_X86_64 */
721
723#if OMPD_SUPPORT
724 if (ompd_state & OMPD_ENABLE_BP)
725 ompd_bp_parallel_end();
726#endif
727
728 this_thr->th.th_team = serial_team->t.t_parent;
729 this_thr->th.th_info.ds.ds_tid = serial_team->t.t_master_tid;
730
731 /* restore values cached in the thread */
732 this_thr->th.th_team_nproc = serial_team->t.t_parent->t.t_nproc; /* JPH */
733 this_thr->th.th_team_master =
734 serial_team->t.t_parent->t.t_threads[0]; /* JPH */
735 this_thr->th.th_team_serialized = this_thr->th.th_team->t.t_serialized;
736
737 /* TODO the below shouldn't need to be adjusted for serialized teams */
738 this_thr->th.th_dispatch =
739 &this_thr->th.th_team->t.t_dispatch[serial_team->t.t_master_tid];
740
741 KMP_ASSERT(this_thr->th.th_current_task->td_flags.executing == 0);
742 this_thr->th.th_current_task->td_flags.executing = 1;
743
745 // Restore task state from serial team structure
746 KMP_DEBUG_ASSERT(serial_team->t.t_primary_task_state == 0 ||
747 serial_team->t.t_primary_task_state == 1);
748 this_thr->th.th_task_state =
749 (kmp_uint8)serial_team->t.t_primary_task_state;
750 // Copy the task team from the new child / old parent team to the thread.
751 this_thr->th.th_task_team =
752 this_thr->th.th_team->t.t_task_team[this_thr->th.th_task_state];
753 KA_TRACE(20,
754 ("__kmpc_end_serialized_parallel: T#%d restoring task_team %p / "
755 "team %p\n",
756 global_tid, this_thr->th.th_task_team, this_thr->th.th_team));
757 }
758#if KMP_AFFINITY_SUPPORTED
759 if (this_thr->th.th_team->t.t_level == 0 && __kmp_affinity.flags.reset) {
760 __kmp_reset_root_init_mask(global_tid);
761 }
762#endif
763 } else {
765 KA_TRACE(20, ("__kmpc_end_serialized_parallel: T#%d decreasing nesting "
766 "depth of serial team %p to %d\n",
767 global_tid, serial_team, serial_team->t.t_serialized));
768 }
769 }
770
771 serial_team->t.t_level--;
773 __kmp_pop_parallel(global_tid, NULL);
774#if OMPT_SUPPORT
775 if (ompt_enabled.enabled)
776 this_thr->th.ompt_thread_info.state =
777 ((this_thr->th.th_team_serialized) ? ompt_state_work_serial
778 : ompt_state_work_parallel);
779#endif
780}
781
782/*!
783@ingroup SYNCHRONIZATION
784@param loc source location information.
785
786Execute <tt>flush</tt>. This is implemented as a full memory fence. (Though
787depending on the memory ordering convention obeyed by the compiler
788even that may not be necessary).
789*/
791 KC_TRACE(10, ("__kmpc_flush: called\n"));
792
793 /* need explicit __mf() here since use volatile instead in library */
794 KMP_MFENCE(); /* Flush all pending memory write invalidates. */
795
796#if OMPT_SUPPORT && OMPT_OPTIONAL
797 if (ompt_enabled.ompt_callback_flush) {
798 ompt_callbacks.ompt_callback(ompt_callback_flush)(
800 }
801#endif
802}
803
804/* -------------------------------------------------------------------------- */
805/*!
806@ingroup SYNCHRONIZATION
807@param loc source location information
808@param global_tid thread id.
809
810Execute a barrier.
811*/
813 KMP_COUNT_BLOCK(OMP_BARRIER);
814 KC_TRACE(10, ("__kmpc_barrier: called T#%d\n", global_tid));
815 __kmp_assert_valid_gtid(global_tid);
816
819
821
823 if (loc == 0) {
824 KMP_WARNING(ConstructIdentInvalid); // ??? What does it mean for the user?
825 }
826 __kmp_check_barrier(global_tid, ct_barrier, loc);
827 }
828
829#if OMPT_SUPPORT
830 ompt_frame_t *ompt_frame;
831 if (ompt_enabled.enabled) {
832 __ompt_get_task_info_internal(0, NULL, NULL, &ompt_frame, NULL, NULL);
833 if (ompt_frame->enter_frame.ptr == NULL)
834 ompt_frame->enter_frame.ptr = OMPT_GET_FRAME_ADDRESS(0);
835 }
836 OMPT_STORE_RETURN_ADDRESS(global_tid);
837#endif
838 __kmp_threads[global_tid]->th.th_ident = loc;
839 // TODO: explicit barrier_wait_id:
840 // this function is called when 'barrier' directive is present or
841 // implicit barrier at the end of a worksharing construct.
842 // 1) better to add a per-thread barrier counter to a thread data structure
843 // 2) set to 0 when a new team is created
844 // 4) no sync is required
845
846 __kmp_barrier(bs_plain_barrier, global_tid, FALSE, 0, NULL, NULL);
847#if OMPT_SUPPORT && OMPT_OPTIONAL
848 if (ompt_enabled.enabled) {
849 ompt_frame->enter_frame = ompt_data_none;
850 }
851#endif
852}
853
854/* The BARRIER for a MASTER section is always explicit */
855/*!
856@ingroup WORK_SHARING
857@param loc source location information.
858@param global_tid global thread number .
859@return 1 if this thread should execute the <tt>master</tt> block, 0 otherwise.
860*/
862 int status = 0;
863
864 KC_TRACE(10, ("__kmpc_master: called T#%d\n", global_tid));
865 __kmp_assert_valid_gtid(global_tid);
866
869
871
872 if (KMP_MASTER_GTID(global_tid)) {
873 KMP_COUNT_BLOCK(OMP_MASTER);
874 KMP_PUSH_PARTITIONED_TIMER(OMP_master);
875 status = 1;
876 }
877
878#if OMPT_SUPPORT && OMPT_OPTIONAL
879 if (status) {
880 if (ompt_enabled.ompt_callback_masked) {
881 kmp_info_t *this_thr = __kmp_threads[global_tid];
882 kmp_team_t *team = this_thr->th.th_team;
883
884 int tid = __kmp_tid_from_gtid(global_tid);
885 ompt_callbacks.ompt_callback(ompt_callback_masked)(
886 ompt_scope_begin, &(team->t.ompt_team_info.parallel_data),
887 &(team->t.t_implicit_task_taskdata[tid].ompt_task_info.task_data),
889 }
890 }
891#endif
892
894#if KMP_USE_DYNAMIC_LOCK
895 if (status)
896 __kmp_push_sync(global_tid, ct_master, loc, NULL, 0);
897 else
898 __kmp_check_sync(global_tid, ct_master, loc, NULL, 0);
899#else
900 if (status)
901 __kmp_push_sync(global_tid, ct_master, loc, NULL);
902 else
903 __kmp_check_sync(global_tid, ct_master, loc, NULL);
904#endif
905 }
906
907 return status;
908}
909
910/*!
911@ingroup WORK_SHARING
912@param loc source location information.
913@param global_tid global thread number .
914
915Mark the end of a <tt>master</tt> region. This should only be called by the
916thread that executes the <tt>master</tt> region.
917*/
919 KC_TRACE(10, ("__kmpc_end_master: called T#%d\n", global_tid));
920 __kmp_assert_valid_gtid(global_tid);
923
924#if OMPT_SUPPORT && OMPT_OPTIONAL
925 kmp_info_t *this_thr = __kmp_threads[global_tid];
926 kmp_team_t *team = this_thr->th.th_team;
927 if (ompt_enabled.ompt_callback_masked) {
928 int tid = __kmp_tid_from_gtid(global_tid);
929 ompt_callbacks.ompt_callback(ompt_callback_masked)(
930 ompt_scope_end, &(team->t.ompt_team_info.parallel_data),
931 &(team->t.t_implicit_task_taskdata[tid].ompt_task_info.task_data),
933 }
934#endif
935
937 if (KMP_MASTER_GTID(global_tid))
938 __kmp_pop_sync(global_tid, ct_master, loc);
939 }
940}
941
942/*!
943@ingroup WORK_SHARING
944@param loc source location information.
945@param global_tid global thread number.
946@param filter result of evaluating filter clause on thread global_tid, or zero
947if no filter clause present
948@return 1 if this thread should execute the <tt>masked</tt> block, 0 otherwise.
949*/
951 int status = 0;
952 int tid;
953 KC_TRACE(10, ("__kmpc_masked: called T#%d\n", global_tid));
954 __kmp_assert_valid_gtid(global_tid);
955
958
960
961 tid = __kmp_tid_from_gtid(global_tid);
962 if (tid == filter) {
963 KMP_COUNT_BLOCK(OMP_MASKED);
964 KMP_PUSH_PARTITIONED_TIMER(OMP_masked);
965 status = 1;
966 }
967
968#if OMPT_SUPPORT && OMPT_OPTIONAL
969 if (status) {
970 if (ompt_enabled.ompt_callback_masked) {
971 kmp_info_t *this_thr = __kmp_threads[global_tid];
972 kmp_team_t *team = this_thr->th.th_team;
973 ompt_callbacks.ompt_callback(ompt_callback_masked)(
974 ompt_scope_begin, &(team->t.ompt_team_info.parallel_data),
975 &(team->t.t_implicit_task_taskdata[tid].ompt_task_info.task_data),
977 }
978 }
979#endif
980
982#if KMP_USE_DYNAMIC_LOCK
983 if (status)
984 __kmp_push_sync(global_tid, ct_masked, loc, NULL, 0);
985 else
986 __kmp_check_sync(global_tid, ct_masked, loc, NULL, 0);
987#else
988 if (status)
989 __kmp_push_sync(global_tid, ct_masked, loc, NULL);
990 else
991 __kmp_check_sync(global_tid, ct_masked, loc, NULL);
992#endif
993 }
994
995 return status;
996}
997
998/*!
999@ingroup WORK_SHARING
1000@param loc source location information.
1001@param global_tid global thread number .
1002
1003Mark the end of a <tt>masked</tt> region. This should only be called by the
1004thread that executes the <tt>masked</tt> region.
1005*/
1007 KC_TRACE(10, ("__kmpc_end_masked: called T#%d\n", global_tid));
1008 __kmp_assert_valid_gtid(global_tid);
1010
1011#if OMPT_SUPPORT && OMPT_OPTIONAL
1012 kmp_info_t *this_thr = __kmp_threads[global_tid];
1013 kmp_team_t *team = this_thr->th.th_team;
1014 if (ompt_enabled.ompt_callback_masked) {
1015 int tid = __kmp_tid_from_gtid(global_tid);
1016 ompt_callbacks.ompt_callback(ompt_callback_masked)(
1017 ompt_scope_end, &(team->t.ompt_team_info.parallel_data),
1018 &(team->t.t_implicit_task_taskdata[tid].ompt_task_info.task_data),
1020 }
1021#endif
1022
1024 __kmp_pop_sync(global_tid, ct_masked, loc);
1025 }
1026}
1027
1028/*!
1029@ingroup WORK_SHARING
1030@param loc source location information.
1031@param gtid global thread number.
1032
1033Start execution of an <tt>ordered</tt> construct.
1034*/
1036 int cid = 0;
1037 kmp_info_t *th;
1039
1040 KC_TRACE(10, ("__kmpc_ordered: called T#%d\n", gtid));
1042
1045
1047
1048#if USE_ITT_BUILD
1049 __kmp_itt_ordered_prep(gtid);
1050// TODO: ordered_wait_id
1051#endif /* USE_ITT_BUILD */
1052
1053 th = __kmp_threads[gtid];
1054
1055#if OMPT_SUPPORT && OMPT_OPTIONAL
1056 kmp_team_t *team;
1057 ompt_wait_id_t lck;
1058 void *codeptr_ra;
1059 OMPT_STORE_RETURN_ADDRESS(gtid);
1060 if (ompt_enabled.enabled) {
1061 team = __kmp_team_from_gtid(gtid);
1062 lck = (ompt_wait_id_t)(uintptr_t)&team->t.t_ordered.dt.t_value;
1063 /* OMPT state update */
1064 th->th.ompt_thread_info.wait_id = lck;
1065 th->th.ompt_thread_info.state = ompt_state_wait_ordered;
1066
1067 /* OMPT event callback */
1068 codeptr_ra = OMPT_LOAD_RETURN_ADDRESS(gtid);
1069 if (ompt_enabled.ompt_callback_mutex_acquire) {
1070 ompt_callbacks.ompt_callback(ompt_callback_mutex_acquire)(
1071 ompt_mutex_ordered, omp_lock_hint_none, kmp_mutex_impl_spin, lck,
1072 codeptr_ra);
1073 }
1074 }
1075#endif
1076
1077 if (th->th.th_dispatch->th_deo_fcn != 0)
1078 (*th->th.th_dispatch->th_deo_fcn)(&gtid, &cid, loc);
1079 else
1080 __kmp_parallel_deo(&gtid, &cid, loc);
1081
1082#if OMPT_SUPPORT && OMPT_OPTIONAL
1083 if (ompt_enabled.enabled) {
1084 /* OMPT state update */
1085 th->th.ompt_thread_info.state = ompt_state_work_parallel;
1086 th->th.ompt_thread_info.wait_id = 0;
1087
1088 /* OMPT event callback */
1089 if (ompt_enabled.ompt_callback_mutex_acquired) {
1090 ompt_callbacks.ompt_callback(ompt_callback_mutex_acquired)(
1091 ompt_mutex_ordered, (ompt_wait_id_t)(uintptr_t)lck, codeptr_ra);
1092 }
1093 }
1094#endif
1095
1096#if USE_ITT_BUILD
1097 __kmp_itt_ordered_start(gtid);
1098#endif /* USE_ITT_BUILD */
1099}
1100
1101/*!
1102@ingroup WORK_SHARING
1103@param loc source location information.
1104@param gtid global thread number.
1105
1106End execution of an <tt>ordered</tt> construct.
1107*/
1109 int cid = 0;
1110 kmp_info_t *th;
1111
1112 KC_TRACE(10, ("__kmpc_end_ordered: called T#%d\n", gtid));
1114
1115#if USE_ITT_BUILD
1116 __kmp_itt_ordered_end(gtid);
1117// TODO: ordered_wait_id
1118#endif /* USE_ITT_BUILD */
1119
1120 th = __kmp_threads[gtid];
1121
1122 if (th->th.th_dispatch->th_dxo_fcn != 0)
1123 (*th->th.th_dispatch->th_dxo_fcn)(&gtid, &cid, loc);
1124 else
1125 __kmp_parallel_dxo(&gtid, &cid, loc);
1126
1127#if OMPT_SUPPORT && OMPT_OPTIONAL
1128 OMPT_STORE_RETURN_ADDRESS(gtid);
1129 if (ompt_enabled.ompt_callback_mutex_released) {
1130 ompt_callbacks.ompt_callback(ompt_callback_mutex_released)(
1131 ompt_mutex_ordered,
1132 (ompt_wait_id_t)(uintptr_t)&__kmp_team_from_gtid(gtid)
1133 ->t.t_ordered.dt.t_value,
1134 OMPT_LOAD_RETURN_ADDRESS(gtid));
1135 }
1136#endif
1137}
1138
1139#if KMP_USE_DYNAMIC_LOCK
1140
1141static __forceinline void
1142__kmp_init_indirect_csptr(kmp_critical_name *crit, ident_t const *loc,
1143 kmp_int32 gtid, kmp_indirect_locktag_t tag) {
1144 // Pointer to the allocated indirect lock is written to crit, while indexing
1145 // is ignored.
1146 void *idx;
1147 kmp_indirect_lock_t **lck;
1148 lck = (kmp_indirect_lock_t **)crit;
1149 kmp_indirect_lock_t *ilk = __kmp_allocate_indirect_lock(&idx, gtid, tag);
1150 KMP_I_LOCK_FUNC(ilk, init)(ilk->lock);
1151 KMP_SET_I_LOCK_LOCATION(ilk, loc);
1152 KMP_SET_I_LOCK_FLAGS(ilk, kmp_lf_critical_section);
1153 KA_TRACE(20,
1154 ("__kmp_init_indirect_csptr: initialized indirect lock #%d\n", tag));
1155#if USE_ITT_BUILD
1156 __kmp_itt_critical_creating(ilk->lock, loc);
1157#endif
1158 int status = KMP_COMPARE_AND_STORE_PTR(lck, nullptr, ilk);
1159 if (status == 0) {
1160#if USE_ITT_BUILD
1161 __kmp_itt_critical_destroyed(ilk->lock);
1162#endif
1163 // We don't really need to destroy the unclaimed lock here since it will be
1164 // cleaned up at program exit.
1165 // KMP_D_LOCK_FUNC(&idx, destroy)((kmp_dyna_lock_t *)&idx);
1166 }
1167 KMP_DEBUG_ASSERT(*lck != NULL);
1168}
1169
1170// Fast-path acquire tas lock
1171#define KMP_ACQUIRE_TAS_LOCK(lock, gtid) \
1172 { \
1173 kmp_tas_lock_t *l = (kmp_tas_lock_t *)lock; \
1174 kmp_int32 tas_free = KMP_LOCK_FREE(tas); \
1175 kmp_int32 tas_busy = KMP_LOCK_BUSY(gtid + 1, tas); \
1176 if (KMP_ATOMIC_LD_RLX(&l->lk.poll) != tas_free || \
1177 !__kmp_atomic_compare_store_acq(&l->lk.poll, tas_free, tas_busy)) { \
1178 kmp_uint32 spins; \
1179 KMP_FSYNC_PREPARE(l); \
1180 KMP_INIT_YIELD(spins); \
1181 kmp_backoff_t backoff = __kmp_spin_backoff_params; \
1182 do { \
1183 if (TCR_4(__kmp_nth) > \
1184 (__kmp_avail_proc ? __kmp_avail_proc : __kmp_xproc)) { \
1185 KMP_YIELD(TRUE); \
1186 } else { \
1187 KMP_YIELD_SPIN(spins); \
1188 } \
1189 __kmp_spin_backoff(&backoff); \
1190 } while ( \
1191 KMP_ATOMIC_LD_RLX(&l->lk.poll) != tas_free || \
1192 !__kmp_atomic_compare_store_acq(&l->lk.poll, tas_free, tas_busy)); \
1193 } \
1194 KMP_FSYNC_ACQUIRED(l); \
1195 }
1196
1197// Fast-path test tas lock
1198#define KMP_TEST_TAS_LOCK(lock, gtid, rc) \
1199 { \
1200 kmp_tas_lock_t *l = (kmp_tas_lock_t *)lock; \
1201 kmp_int32 tas_free = KMP_LOCK_FREE(tas); \
1202 kmp_int32 tas_busy = KMP_LOCK_BUSY(gtid + 1, tas); \
1203 rc = KMP_ATOMIC_LD_RLX(&l->lk.poll) == tas_free && \
1204 __kmp_atomic_compare_store_acq(&l->lk.poll, tas_free, tas_busy); \
1205 }
1206
1207// Fast-path release tas lock
1208#define KMP_RELEASE_TAS_LOCK(lock, gtid) \
1209 { KMP_ATOMIC_ST_REL(&((kmp_tas_lock_t *)lock)->lk.poll, KMP_LOCK_FREE(tas)); }
1210
1211#if KMP_USE_FUTEX
1212
1213#include <sys/syscall.h>
1214#include <unistd.h>
1215#ifndef FUTEX_WAIT
1216#define FUTEX_WAIT 0
1217#endif
1218#ifndef FUTEX_WAKE
1219#define FUTEX_WAKE 1
1220#endif
1221
1222// Fast-path acquire futex lock
1223#define KMP_ACQUIRE_FUTEX_LOCK(lock, gtid) \
1224 { \
1225 kmp_futex_lock_t *ftx = (kmp_futex_lock_t *)lock; \
1226 kmp_int32 gtid_code = (gtid + 1) << 1; \
1227 KMP_MB(); \
1228 KMP_FSYNC_PREPARE(ftx); \
1229 kmp_int32 poll_val; \
1230 while ((poll_val = KMP_COMPARE_AND_STORE_RET32( \
1231 &(ftx->lk.poll), KMP_LOCK_FREE(futex), \
1232 KMP_LOCK_BUSY(gtid_code, futex))) != KMP_LOCK_FREE(futex)) { \
1233 kmp_int32 cond = KMP_LOCK_STRIP(poll_val) & 1; \
1234 if (!cond) { \
1235 if (!KMP_COMPARE_AND_STORE_RET32(&(ftx->lk.poll), poll_val, \
1236 poll_val | \
1237 KMP_LOCK_BUSY(1, futex))) { \
1238 continue; \
1239 } \
1240 poll_val |= KMP_LOCK_BUSY(1, futex); \
1241 } \
1242 kmp_int32 rc; \
1243 if ((rc = syscall(__NR_futex, &(ftx->lk.poll), FUTEX_WAIT, poll_val, \
1244 NULL, NULL, 0)) != 0) { \
1245 continue; \
1246 } \
1247 gtid_code |= 1; \
1248 } \
1249 KMP_FSYNC_ACQUIRED(ftx); \
1250 }
1251
1252// Fast-path test futex lock
1253#define KMP_TEST_FUTEX_LOCK(lock, gtid, rc) \
1254 { \
1255 kmp_futex_lock_t *ftx = (kmp_futex_lock_t *)lock; \
1256 if (KMP_COMPARE_AND_STORE_ACQ32(&(ftx->lk.poll), KMP_LOCK_FREE(futex), \
1257 KMP_LOCK_BUSY(gtid + 1 << 1, futex))) { \
1258 KMP_FSYNC_ACQUIRED(ftx); \
1259 rc = TRUE; \
1260 } else { \
1261 rc = FALSE; \
1262 } \
1263 }
1264
1265// Fast-path release futex lock
1266#define KMP_RELEASE_FUTEX_LOCK(lock, gtid) \
1267 { \
1268 kmp_futex_lock_t *ftx = (kmp_futex_lock_t *)lock; \
1269 KMP_MB(); \
1270 KMP_FSYNC_RELEASING(ftx); \
1271 kmp_int32 poll_val = \
1272 KMP_XCHG_FIXED32(&(ftx->lk.poll), KMP_LOCK_FREE(futex)); \
1273 if (KMP_LOCK_STRIP(poll_val) & 1) { \
1274 syscall(__NR_futex, &(ftx->lk.poll), FUTEX_WAKE, \
1275 KMP_LOCK_BUSY(1, futex), NULL, NULL, 0); \
1276 } \
1277 KMP_MB(); \
1278 KMP_YIELD_OVERSUB(); \
1279 }
1280
1281#endif // KMP_USE_FUTEX
1282
1283#else // KMP_USE_DYNAMIC_LOCK
1284
1286 ident_t const *loc,
1287 kmp_int32 gtid) {
1289
1290 // Because of the double-check, the following load doesn't need to be volatile
1292
1293 if (lck == NULL) {
1294 void *idx;
1295
1296 // Allocate & initialize the lock.
1297 // Remember alloc'ed locks in table in order to free them in __kmp_cleanup()
1301#if USE_ITT_BUILD
1302 __kmp_itt_critical_creating(lck);
1303// __kmp_itt_critical_creating() should be called *before* the first usage
1304// of underlying lock. It is the only place where we can guarantee it. There
1305// are chances the lock will destroyed with no usage, but it is not a
1306// problem, because this is not real event seen by user but rather setting
1307// name for object (lock). See more details in kmp_itt.h.
1308#endif /* USE_ITT_BUILD */
1309
1310 // Use a cmpxchg instruction to slam the start of the critical section with
1311 // the lock pointer. If another thread beat us to it, deallocate the lock,
1312 // and use the lock that the other thread allocated.
1313 int status = KMP_COMPARE_AND_STORE_PTR(lck_pp, 0, lck);
1314
1315 if (status == 0) {
1316// Deallocate the lock and reload the value.
1317#if USE_ITT_BUILD
1318 __kmp_itt_critical_destroyed(lck);
1319// Let ITT know the lock is destroyed and the same memory location may be reused
1320// for another purpose.
1321#endif /* USE_ITT_BUILD */
1323 __kmp_user_lock_free(&idx, gtid, lck);
1324 lck = (kmp_user_lock_p)TCR_PTR(*lck_pp);
1325 KMP_DEBUG_ASSERT(lck != NULL);
1326 }
1327 }
1328 return lck;
1329}
1330
1331#endif // KMP_USE_DYNAMIC_LOCK
1332
1333/*!
1334@ingroup WORK_SHARING
1335@param loc source location information.
1336@param global_tid global thread number.
1337@param crit identity of the critical section. This could be a pointer to a lock
1338associated with the critical section, or some other suitably unique value.
1339
1340Enter code protected by a `critical` construct.
1341This function blocks until the executing thread can enter the critical section.
1342*/
1345#if KMP_USE_DYNAMIC_LOCK
1346#if OMPT_SUPPORT && OMPT_OPTIONAL
1347 OMPT_STORE_RETURN_ADDRESS(global_tid);
1348#endif // OMPT_SUPPORT
1349 __kmpc_critical_with_hint(loc, global_tid, crit, omp_lock_hint_none);
1350#else
1351 KMP_COUNT_BLOCK(OMP_CRITICAL);
1352#if OMPT_SUPPORT && OMPT_OPTIONAL
1353 ompt_state_t prev_state = ompt_state_undefined;
1355#endif
1357
1358 KC_TRACE(10, ("__kmpc_critical: called T#%d\n", global_tid));
1359 __kmp_assert_valid_gtid(global_tid);
1360
1361 // TODO: add THR_OVHD_STATE
1362
1363 KMP_PUSH_PARTITIONED_TIMER(OMP_critical_wait);
1365
1366 if ((__kmp_user_lock_kind == lk_tas) &&
1367 (sizeof(lck->tas.lk.poll) <= OMP_CRITICAL_SIZE)) {
1369 }
1370#if KMP_USE_FUTEX
1371 else if ((__kmp_user_lock_kind == lk_futex) &&
1372 (sizeof(lck->futex.lk.poll) <= OMP_CRITICAL_SIZE)) {
1374 }
1375#endif
1376 else { // ticket, queuing or drdpa
1378 }
1379
1381 __kmp_push_sync(global_tid, ct_critical, loc, lck);
1382
1383 // since the critical directive binds to all threads, not just the current
1384 // team we have to check this even if we are in a serialized team.
1385 // also, even if we are the uber thread, we still have to conduct the lock,
1386 // as we have to contend with sibling threads.
1387
1388#if USE_ITT_BUILD
1389 __kmp_itt_critical_acquiring(lck);
1390#endif /* USE_ITT_BUILD */
1391#if OMPT_SUPPORT && OMPT_OPTIONAL
1392 OMPT_STORE_RETURN_ADDRESS(gtid);
1393 void *codeptr_ra = NULL;
1394 if (ompt_enabled.enabled) {
1395 ti = __kmp_threads[global_tid]->th.ompt_thread_info;
1396 /* OMPT state update */
1397 prev_state = ti.state;
1398 ti.wait_id = (ompt_wait_id_t)(uintptr_t)lck;
1399 ti.state = ompt_state_wait_critical;
1400
1401 /* OMPT event callback */
1402 codeptr_ra = OMPT_LOAD_RETURN_ADDRESS(gtid);
1403 if (ompt_enabled.ompt_callback_mutex_acquire) {
1404 ompt_callbacks.ompt_callback(ompt_callback_mutex_acquire)(
1405 ompt_mutex_critical, omp_lock_hint_none, __ompt_get_mutex_impl_type(),
1406 (ompt_wait_id_t)(uintptr_t)lck, codeptr_ra);
1407 }
1408 }
1409#endif
1410 // Value of 'crit' should be good for using as a critical_id of the critical
1411 // section directive.
1413
1414#if USE_ITT_BUILD
1415 __kmp_itt_critical_acquired(lck);
1416#endif /* USE_ITT_BUILD */
1417#if OMPT_SUPPORT && OMPT_OPTIONAL
1418 if (ompt_enabled.enabled) {
1419 /* OMPT state update */
1420 ti.state = prev_state;
1421 ti.wait_id = 0;
1422
1423 /* OMPT event callback */
1424 if (ompt_enabled.ompt_callback_mutex_acquired) {
1425 ompt_callbacks.ompt_callback(ompt_callback_mutex_acquired)(
1426 ompt_mutex_critical, (ompt_wait_id_t)(uintptr_t)lck, codeptr_ra);
1427 }
1428 }
1429#endif
1431
1432 KMP_PUSH_PARTITIONED_TIMER(OMP_critical);
1433 KA_TRACE(15, ("__kmpc_critical: done T#%d\n", global_tid));
1434#endif // KMP_USE_DYNAMIC_LOCK
1435}
1436
1437#if KMP_USE_DYNAMIC_LOCK
1438
1439// Converts the given hint to an internal lock implementation
1440static __forceinline kmp_dyna_lockseq_t __kmp_map_hint_to_lock(uintptr_t hint) {
1441#if KMP_USE_TSX
1442#define KMP_TSX_LOCK(seq) lockseq_##seq
1443#else
1444#define KMP_TSX_LOCK(seq) __kmp_user_lock_seq
1445#endif
1446
1447#if KMP_ARCH_X86 || KMP_ARCH_X86_64
1448#define KMP_CPUINFO_RTM (__kmp_cpuinfo.flags.rtm)
1449#else
1450#define KMP_CPUINFO_RTM 0
1451#endif
1452
1453 // Hints that do not require further logic
1454 if (hint & kmp_lock_hint_hle)
1455 return KMP_TSX_LOCK(hle);
1456 if (hint & kmp_lock_hint_rtm)
1457 return KMP_CPUINFO_RTM ? KMP_TSX_LOCK(rtm_queuing) : __kmp_user_lock_seq;
1458 if (hint & kmp_lock_hint_adaptive)
1459 return KMP_CPUINFO_RTM ? KMP_TSX_LOCK(adaptive) : __kmp_user_lock_seq;
1460
1461 // Rule out conflicting hints first by returning the default lock
1462 if ((hint & omp_lock_hint_contended) && (hint & omp_lock_hint_uncontended))
1463 return __kmp_user_lock_seq;
1464 if ((hint & omp_lock_hint_speculative) &&
1465 (hint & omp_lock_hint_nonspeculative))
1466 return __kmp_user_lock_seq;
1467
1468 // Do not even consider speculation when it appears to be contended
1469 if (hint & omp_lock_hint_contended)
1470 return lockseq_queuing;
1471
1472 // Uncontended lock without speculation
1473 if ((hint & omp_lock_hint_uncontended) && !(hint & omp_lock_hint_speculative))
1474 return lockseq_tas;
1475
1476 // Use RTM lock for speculation
1477 if (hint & omp_lock_hint_speculative)
1478 return KMP_CPUINFO_RTM ? KMP_TSX_LOCK(rtm_spin) : __kmp_user_lock_seq;
1479
1480 return __kmp_user_lock_seq;
1481}
1482
1483#if OMPT_SUPPORT && OMPT_OPTIONAL
1484#if KMP_USE_DYNAMIC_LOCK
1485static kmp_mutex_impl_t
1486__ompt_get_mutex_impl_type(void *user_lock, kmp_indirect_lock_t *ilock = 0) {
1487 if (user_lock) {
1488 switch (KMP_EXTRACT_D_TAG(user_lock)) {
1489 case 0:
1490 break;
1491#if KMP_USE_FUTEX
1492 case locktag_futex:
1493 return kmp_mutex_impl_queuing;
1494#endif
1495 case locktag_tas:
1496 return kmp_mutex_impl_spin;
1497#if KMP_USE_TSX
1498 case locktag_hle:
1499 case locktag_rtm_spin:
1500 return kmp_mutex_impl_speculative;
1501#endif
1502 default:
1503 return kmp_mutex_impl_none;
1504 }
1505 ilock = KMP_LOOKUP_I_LOCK(user_lock);
1506 }
1507 KMP_ASSERT(ilock);
1508 switch (ilock->type) {
1509#if KMP_USE_TSX
1510 case locktag_adaptive:
1511 case locktag_rtm_queuing:
1512 return kmp_mutex_impl_speculative;
1513#endif
1514 case locktag_nested_tas:
1515 return kmp_mutex_impl_spin;
1516#if KMP_USE_FUTEX
1517 case locktag_nested_futex:
1518#endif
1519 case locktag_ticket:
1520 case locktag_queuing:
1521 case locktag_drdpa:
1522 case locktag_nested_ticket:
1523 case locktag_nested_queuing:
1524 case locktag_nested_drdpa:
1525 return kmp_mutex_impl_queuing;
1526 default:
1527 return kmp_mutex_impl_none;
1528 }
1529}
1530#else
1531// For locks without dynamic binding
1532static kmp_mutex_impl_t __ompt_get_mutex_impl_type() {
1533 switch (__kmp_user_lock_kind) {
1534 case lk_tas:
1535 return kmp_mutex_impl_spin;
1536#if KMP_USE_FUTEX
1537 case lk_futex:
1538#endif
1539 case lk_ticket:
1540 case lk_queuing:
1541 case lk_drdpa:
1542 return kmp_mutex_impl_queuing;
1543#if KMP_USE_TSX
1544 case lk_hle:
1545 case lk_rtm_queuing:
1546 case lk_rtm_spin:
1547 case lk_adaptive:
1548 return kmp_mutex_impl_speculative;
1549#endif
1550 default:
1551 return kmp_mutex_impl_none;
1552 }
1553}
1554#endif // KMP_USE_DYNAMIC_LOCK
1555#endif // OMPT_SUPPORT && OMPT_OPTIONAL
1556
1557/*!
1558@ingroup WORK_SHARING
1559@param loc source location information.
1560@param global_tid global thread number.
1561@param crit identity of the critical section. This could be a pointer to a lock
1562associated with the critical section, or some other suitably unique value.
1563@param hint the lock hint.
1564
1565Enter code protected by a `critical` construct with a hint. The hint value is
1566used to suggest a lock implementation. This function blocks until the executing
1567thread can enter the critical section unless the hint suggests use of
1568speculative execution and the hardware supports it.
1569*/
1571 kmp_critical_name *crit, uint32_t hint) {
1572 KMP_COUNT_BLOCK(OMP_CRITICAL);
1574#if OMPT_SUPPORT && OMPT_OPTIONAL
1575 ompt_state_t prev_state = ompt_state_undefined;
1577 // This is the case, if called from __kmpc_critical:
1578 void *codeptr = OMPT_LOAD_RETURN_ADDRESS(global_tid);
1579 if (!codeptr)
1580 codeptr = OMPT_GET_RETURN_ADDRESS(0);
1581#endif
1582
1583 KC_TRACE(10, ("__kmpc_critical: called T#%d\n", global_tid));
1584 __kmp_assert_valid_gtid(global_tid);
1585
1586 kmp_dyna_lock_t *lk = (kmp_dyna_lock_t *)crit;
1587 // Check if it is initialized.
1588 KMP_PUSH_PARTITIONED_TIMER(OMP_critical_wait);
1589 kmp_dyna_lockseq_t lockseq = __kmp_map_hint_to_lock(hint);
1590 if (*lk == 0) {
1591 if (KMP_IS_D_LOCK(lockseq)) {
1593 (volatile kmp_int32 *)&((kmp_base_tas_lock_t *)crit)->poll, 0,
1594 KMP_GET_D_TAG(lockseq));
1595 } else {
1596 __kmp_init_indirect_csptr(crit, loc, global_tid, KMP_GET_I_TAG(lockseq));
1597 }
1598 }
1599 // Branch for accessing the actual lock object and set operation. This
1600 // branching is inevitable since this lock initialization does not follow the
1601 // normal dispatch path (lock table is not used).
1602 if (KMP_EXTRACT_D_TAG(lk) != 0) {
1603 lck = (kmp_user_lock_p)lk;
1605 __kmp_push_sync(global_tid, ct_critical, loc, lck,
1606 __kmp_map_hint_to_lock(hint));
1607 }
1608#if USE_ITT_BUILD
1609 __kmp_itt_critical_acquiring(lck);
1610#endif
1611#if OMPT_SUPPORT && OMPT_OPTIONAL
1612 if (ompt_enabled.enabled) {
1613 ti = __kmp_threads[global_tid]->th.ompt_thread_info;
1614 /* OMPT state update */
1615 prev_state = ti.state;
1616 ti.wait_id = (ompt_wait_id_t)(uintptr_t)lck;
1617 ti.state = ompt_state_wait_critical;
1618
1619 /* OMPT event callback */
1620 if (ompt_enabled.ompt_callback_mutex_acquire) {
1621 ompt_callbacks.ompt_callback(ompt_callback_mutex_acquire)(
1622 ompt_mutex_critical, (unsigned int)hint,
1623 __ompt_get_mutex_impl_type(crit), (ompt_wait_id_t)(uintptr_t)lck,
1624 codeptr);
1625 }
1626 }
1627#endif
1628#if KMP_USE_INLINED_TAS
1629 if (lockseq == lockseq_tas && !__kmp_env_consistency_check) {
1630 KMP_ACQUIRE_TAS_LOCK(lck, global_tid);
1631 } else
1632#elif KMP_USE_INLINED_FUTEX
1633 if (lockseq == lockseq_futex && !__kmp_env_consistency_check) {
1634 KMP_ACQUIRE_FUTEX_LOCK(lck, global_tid);
1635 } else
1636#endif
1637 {
1638 KMP_D_LOCK_FUNC(lk, set)(lk, global_tid);
1639 }
1640 } else {
1641 kmp_indirect_lock_t *ilk = *((kmp_indirect_lock_t **)lk);
1642 lck = ilk->lock;
1644 __kmp_push_sync(global_tid, ct_critical, loc, lck,
1645 __kmp_map_hint_to_lock(hint));
1646 }
1647#if USE_ITT_BUILD
1648 __kmp_itt_critical_acquiring(lck);
1649#endif
1650#if OMPT_SUPPORT && OMPT_OPTIONAL
1651 if (ompt_enabled.enabled) {
1652 ti = __kmp_threads[global_tid]->th.ompt_thread_info;
1653 /* OMPT state update */
1654 prev_state = ti.state;
1655 ti.wait_id = (ompt_wait_id_t)(uintptr_t)lck;
1656 ti.state = ompt_state_wait_critical;
1657
1658 /* OMPT event callback */
1659 if (ompt_enabled.ompt_callback_mutex_acquire) {
1660 ompt_callbacks.ompt_callback(ompt_callback_mutex_acquire)(
1661 ompt_mutex_critical, (unsigned int)hint,
1662 __ompt_get_mutex_impl_type(0, ilk), (ompt_wait_id_t)(uintptr_t)lck,
1663 codeptr);
1664 }
1665 }
1666#endif
1667 KMP_I_LOCK_FUNC(ilk, set)(lck, global_tid);
1668 }
1670
1671#if USE_ITT_BUILD
1672 __kmp_itt_critical_acquired(lck);
1673#endif /* USE_ITT_BUILD */
1674#if OMPT_SUPPORT && OMPT_OPTIONAL
1675 if (ompt_enabled.enabled) {
1676 /* OMPT state update */
1677 ti.state = prev_state;
1678 ti.wait_id = 0;
1679
1680 /* OMPT event callback */
1681 if (ompt_enabled.ompt_callback_mutex_acquired) {
1682 ompt_callbacks.ompt_callback(ompt_callback_mutex_acquired)(
1683 ompt_mutex_critical, (ompt_wait_id_t)(uintptr_t)lck, codeptr);
1684 }
1685 }
1686#endif
1687
1688 KMP_PUSH_PARTITIONED_TIMER(OMP_critical);
1689 KA_TRACE(15, ("__kmpc_critical: done T#%d\n", global_tid));
1690} // __kmpc_critical_with_hint
1691
1692#endif // KMP_USE_DYNAMIC_LOCK
1693
1694/*!
1695@ingroup WORK_SHARING
1696@param loc source location information.
1697@param global_tid global thread number .
1698@param crit identity of the critical section. This could be a pointer to a lock
1699associated with the critical section, or some other suitably unique value.
1700
1701Leave a critical section, releasing any lock that was held during its execution.
1702*/
1706
1707 KC_TRACE(10, ("__kmpc_end_critical: called T#%d\n", global_tid));
1708
1709#if KMP_USE_DYNAMIC_LOCK
1710 int locktag = KMP_EXTRACT_D_TAG(crit);
1711 if (locktag) {
1713 KMP_ASSERT(lck != NULL);
1715 __kmp_pop_sync(global_tid, ct_critical, loc);
1716 }
1717#if USE_ITT_BUILD
1718 __kmp_itt_critical_releasing(lck);
1719#endif
1720#if KMP_USE_INLINED_TAS
1721 if (locktag == locktag_tas && !__kmp_env_consistency_check) {
1722 KMP_RELEASE_TAS_LOCK(lck, global_tid);
1723 } else
1724#elif KMP_USE_INLINED_FUTEX
1725 if (locktag == locktag_futex && !__kmp_env_consistency_check) {
1726 KMP_RELEASE_FUTEX_LOCK(lck, global_tid);
1727 } else
1728#endif
1729 {
1730 KMP_D_LOCK_FUNC(lck, unset)((kmp_dyna_lock_t *)lck, global_tid);
1731 }
1732 } else {
1733 kmp_indirect_lock_t *ilk =
1734 (kmp_indirect_lock_t *)TCR_PTR(*((kmp_indirect_lock_t **)crit));
1735 KMP_ASSERT(ilk != NULL);
1736 lck = ilk->lock;
1738 __kmp_pop_sync(global_tid, ct_critical, loc);
1739 }
1740#if USE_ITT_BUILD
1741 __kmp_itt_critical_releasing(lck);
1742#endif
1743 KMP_I_LOCK_FUNC(ilk, unset)(lck, global_tid);
1744 }
1745
1746#else // KMP_USE_DYNAMIC_LOCK
1747
1748 if ((__kmp_user_lock_kind == lk_tas) &&
1749 (sizeof(lck->tas.lk.poll) <= OMP_CRITICAL_SIZE)) {
1751 }
1752#if KMP_USE_FUTEX
1753 else if ((__kmp_user_lock_kind == lk_futex) &&
1754 (sizeof(lck->futex.lk.poll) <= OMP_CRITICAL_SIZE)) {
1756 }
1757#endif
1758 else { // ticket, queuing or drdpa
1760 }
1761
1762 KMP_ASSERT(lck != NULL);
1763
1765 __kmp_pop_sync(global_tid, ct_critical, loc);
1766
1767#if USE_ITT_BUILD
1768 __kmp_itt_critical_releasing(lck);
1769#endif /* USE_ITT_BUILD */
1770 // Value of 'crit' should be good for using as a critical_id of the critical
1771 // section directive.
1773
1774#endif // KMP_USE_DYNAMIC_LOCK
1775
1776#if OMPT_SUPPORT && OMPT_OPTIONAL
1777 /* OMPT release event triggers after lock is released; place here to trigger
1778 * for all #if branches */
1779 OMPT_STORE_RETURN_ADDRESS(global_tid);
1780 if (ompt_enabled.ompt_callback_mutex_released) {
1781 ompt_callbacks.ompt_callback(ompt_callback_mutex_released)(
1782 ompt_mutex_critical, (ompt_wait_id_t)(uintptr_t)lck,
1783 OMPT_LOAD_RETURN_ADDRESS(global_tid));
1784 }
1785#endif
1786
1788 KA_TRACE(15, ("__kmpc_end_critical: done T#%d\n", global_tid));
1789}
1790
1791/*!
1792@ingroup SYNCHRONIZATION
1793@param loc source location information
1794@param global_tid thread id.
1795@return one if the thread should execute the master block, zero otherwise
1796
1797Start execution of a combined barrier and master. The barrier is executed inside
1798this function.
1799*/
1801 int status;
1802 KC_TRACE(10, ("__kmpc_barrier_master: called T#%d\n", global_tid));
1803 __kmp_assert_valid_gtid(global_tid);
1804
1807
1809
1811 __kmp_check_barrier(global_tid, ct_barrier, loc);
1812
1813#if OMPT_SUPPORT
1814 ompt_frame_t *ompt_frame;
1815 if (ompt_enabled.enabled) {
1816 __ompt_get_task_info_internal(0, NULL, NULL, &ompt_frame, NULL, NULL);
1817 if (ompt_frame->enter_frame.ptr == NULL)
1818 ompt_frame->enter_frame.ptr = OMPT_GET_FRAME_ADDRESS(0);
1819 }
1820 OMPT_STORE_RETURN_ADDRESS(global_tid);
1821#endif
1822#if USE_ITT_NOTIFY
1823 __kmp_threads[global_tid]->th.th_ident = loc;
1824#endif
1825 status = __kmp_barrier(bs_plain_barrier, global_tid, TRUE, 0, NULL, NULL);
1826#if OMPT_SUPPORT && OMPT_OPTIONAL
1827 if (ompt_enabled.enabled) {
1828 ompt_frame->enter_frame = ompt_data_none;
1829 }
1830#endif
1831
1832 return (status != 0) ? 0 : 1;
1833}
1834
1835/*!
1836@ingroup SYNCHRONIZATION
1837@param loc source location information
1838@param global_tid thread id.
1839
1840Complete the execution of a combined barrier and master. This function should
1841only be called at the completion of the <tt>master</tt> code. Other threads will
1842still be waiting at the barrier and this call releases them.
1843*/
1845 KC_TRACE(10, ("__kmpc_end_barrier_master: called T#%d\n", global_tid));
1846 __kmp_assert_valid_gtid(global_tid);
1848}
1849
1850/*!
1851@ingroup SYNCHRONIZATION
1852@param loc source location information
1853@param global_tid thread id.
1854@return one if the thread should execute the master block, zero otherwise
1855
1856Start execution of a combined barrier and master(nowait) construct.
1857The barrier is executed inside this function.
1858There is no equivalent "end" function, since the
1859*/
1861 kmp_int32 ret;
1862 KC_TRACE(10, ("__kmpc_barrier_master_nowait: called T#%d\n", global_tid));
1863 __kmp_assert_valid_gtid(global_tid);
1864
1867
1869
1871 if (loc == 0) {
1872 KMP_WARNING(ConstructIdentInvalid); // ??? What does it mean for the user?
1873 }
1874 __kmp_check_barrier(global_tid, ct_barrier, loc);
1875 }
1876
1877#if OMPT_SUPPORT
1878 ompt_frame_t *ompt_frame;
1879 if (ompt_enabled.enabled) {
1880 __ompt_get_task_info_internal(0, NULL, NULL, &ompt_frame, NULL, NULL);
1881 if (ompt_frame->enter_frame.ptr == NULL)
1882 ompt_frame->enter_frame.ptr = OMPT_GET_FRAME_ADDRESS(0);
1883 }
1884 OMPT_STORE_RETURN_ADDRESS(global_tid);
1885#endif
1886#if USE_ITT_NOTIFY
1887 __kmp_threads[global_tid]->th.th_ident = loc;
1888#endif
1889 __kmp_barrier(bs_plain_barrier, global_tid, FALSE, 0, NULL, NULL);
1890#if OMPT_SUPPORT && OMPT_OPTIONAL
1891 if (ompt_enabled.enabled) {
1892 ompt_frame->enter_frame = ompt_data_none;
1893 }
1894#endif
1895
1896 ret = __kmpc_master(loc, global_tid);
1897
1899 /* there's no __kmpc_end_master called; so the (stats) */
1900 /* actions of __kmpc_end_master are done here */
1901 if (ret) {
1902 /* only one thread should do the pop since only */
1903 /* one did the push (see __kmpc_master()) */
1904 __kmp_pop_sync(global_tid, ct_master, loc);
1905 }
1906 }
1907
1908 return (ret);
1909}
1910
1911/* The BARRIER for a SINGLE process section is always explicit */
1912/*!
1913@ingroup WORK_SHARING
1914@param loc source location information
1915@param global_tid global thread number
1916@return One if this thread should execute the single construct, zero otherwise.
1917
1918Test whether to execute a <tt>single</tt> construct.
1919There are no implicit barriers in the two "single" calls, rather the compiler
1920should introduce an explicit barrier if it is required.
1921*/
1922
1924 __kmp_assert_valid_gtid(global_tid);
1925 kmp_int32 rc = __kmp_enter_single(global_tid, loc, TRUE);
1926
1927 if (rc) {
1928 // We are going to execute the single statement, so we should count it.
1929 KMP_COUNT_BLOCK(OMP_SINGLE);
1930 KMP_PUSH_PARTITIONED_TIMER(OMP_single);
1931 }
1932
1933#if OMPT_SUPPORT && OMPT_OPTIONAL
1934 kmp_info_t *this_thr = __kmp_threads[global_tid];
1935 kmp_team_t *team = this_thr->th.th_team;
1936 int tid = __kmp_tid_from_gtid(global_tid);
1937
1938 if (ompt_enabled.enabled) {
1939 if (rc) {
1940 if (ompt_enabled.ompt_callback_work) {
1941 ompt_callbacks.ompt_callback(ompt_callback_work)(
1942 ompt_work_single_executor, ompt_scope_begin,
1943 &(team->t.ompt_team_info.parallel_data),
1944 &(team->t.t_implicit_task_taskdata[tid].ompt_task_info.task_data),
1946 }
1947 } else {
1948 if (ompt_enabled.ompt_callback_work) {
1949 ompt_callbacks.ompt_callback(ompt_callback_work)(
1950 ompt_work_single_other, ompt_scope_begin,
1951 &(team->t.ompt_team_info.parallel_data),
1952 &(team->t.t_implicit_task_taskdata[tid].ompt_task_info.task_data),
1954 ompt_callbacks.ompt_callback(ompt_callback_work)(
1955 ompt_work_single_other, ompt_scope_end,
1956 &(team->t.ompt_team_info.parallel_data),
1957 &(team->t.t_implicit_task_taskdata[tid].ompt_task_info.task_data),
1959 }
1960 }
1961 }
1962#endif
1963
1964 return rc;
1965}
1966
1967/*!
1968@ingroup WORK_SHARING
1969@param loc source location information
1970@param global_tid global thread number
1971
1972Mark the end of a <tt>single</tt> construct. This function should
1973only be called by the thread that executed the block of code protected
1974by the `single` construct.
1975*/
1977 __kmp_assert_valid_gtid(global_tid);
1978 __kmp_exit_single(global_tid);
1980
1981#if OMPT_SUPPORT && OMPT_OPTIONAL
1982 kmp_info_t *this_thr = __kmp_threads[global_tid];
1983 kmp_team_t *team = this_thr->th.th_team;
1984 int tid = __kmp_tid_from_gtid(global_tid);
1985
1986 if (ompt_enabled.ompt_callback_work) {
1987 ompt_callbacks.ompt_callback(ompt_callback_work)(
1988 ompt_work_single_executor, ompt_scope_end,
1989 &(team->t.ompt_team_info.parallel_data),
1990 &(team->t.t_implicit_task_taskdata[tid].ompt_task_info.task_data), 1,
1992 }
1993#endif
1994}
1995
1996/*!
1997@ingroup WORK_SHARING
1998@param loc Source location
1999@param global_tid Global thread id
2000
2001Mark the end of a statically scheduled loop.
2002*/
2005 KE_TRACE(10, ("__kmpc_for_static_fini called T#%d\n", global_tid));
2006
2007#if OMPT_SUPPORT && OMPT_OPTIONAL
2008 if (ompt_enabled.ompt_callback_work) {
2009 ompt_work_t ompt_work_type = ompt_work_loop_static;
2010 ompt_team_info_t *team_info = __ompt_get_teaminfo(0, NULL);
2012 // Determine workshare type
2013 if (loc != NULL) {
2014 if ((loc->flags & KMP_IDENT_WORK_LOOP) != 0) {
2015 ompt_work_type = ompt_work_loop_static;
2016 } else if ((loc->flags & KMP_IDENT_WORK_SECTIONS) != 0) {
2017 ompt_work_type = ompt_work_sections;
2018 } else if ((loc->flags & KMP_IDENT_WORK_DISTRIBUTE) != 0) {
2019 ompt_work_type = ompt_work_distribute;
2020 } else {
2021 // use default set above.
2022 // a warning about this case is provided in __kmpc_for_static_init
2023 }
2024 KMP_DEBUG_ASSERT(ompt_work_type);
2025 }
2026 ompt_callbacks.ompt_callback(ompt_callback_work)(
2027 ompt_work_type, ompt_scope_end, &(team_info->parallel_data),
2028 &(task_info->task_data), 0, OMPT_GET_RETURN_ADDRESS(0));
2029 }
2030#endif
2032 __kmp_pop_workshare(global_tid, ct_pdo, loc);
2033}
2034
2035// User routines which take C-style arguments (call by value)
2036// different from the Fortran equivalent routines
2037
2039 // !!!!! TODO: check the per-task binding
2041}
2042
2044 if (arg > (kmp_int64)INT_MAX)
2045 arg = INT_MAX;
2046 else if (arg < (kmp_int64)INT_MIN)
2047 arg = INT_MIN;
2049}
2050
2052 kmp_info_t *thread;
2053
2054 /* For the thread-private implementation of the internal controls */
2055 thread = __kmp_entry_thread();
2056
2058
2059 set__dynamic(thread, flag ? true : false);
2060}
2061
2063 kmp_info_t *thread;
2064
2065 /* For the thread-private internal controls implementation */
2066 thread = __kmp_entry_thread();
2067
2069
2071}
2072
2073void ompc_set_max_active_levels(int max_active_levels) {
2074 /* TO DO */
2075 /* we want per-task implementation of this internal control */
2076
2077 /* For the per-thread internal controls implementation */
2078 __kmp_set_max_active_levels(__kmp_entry_gtid(), max_active_levels);
2079}
2080
2081void ompc_set_schedule(omp_sched_t kind, int modifier) {
2082 // !!!!! TODO: check the per-task binding
2084}
2085
2089
2093
2094/* OpenMP 5.0 Affinity Format API */
2102
2103size_t KMP_EXPAND_NAME(ompc_get_affinity_format)(char *buffer, size_t size) {
2104 size_t format_size;
2105 if (!__kmp_init_serial) {
2107 }
2108 format_size = KMP_STRLEN(__kmp_affinity_format);
2109 if (buffer && size) {
2111 format_size + 1);
2112 }
2113 return format_size;
2114}
2115
2116void KMP_EXPAND_NAME(ompc_display_affinity)(char const *format) {
2117 int gtid;
2118 if (!TCR_4(__kmp_init_middle)) {
2120 }
2122 gtid = __kmp_get_gtid();
2123#if KMP_AFFINITY_SUPPORTED
2124 if (__kmp_threads[gtid]->th.th_team->t.t_level == 0 &&
2125 __kmp_affinity.flags.reset) {
2127 }
2128#endif
2129 __kmp_aux_display_affinity(gtid, format);
2130}
2131
2132size_t KMP_EXPAND_NAME(ompc_capture_affinity)(char *buffer, size_t buf_size,
2133 char const *format) {
2134 int gtid;
2135 size_t num_required;
2136 kmp_str_buf_t capture_buf;
2137 if (!TCR_4(__kmp_init_middle)) {
2139 }
2141 gtid = __kmp_get_gtid();
2142#if KMP_AFFINITY_SUPPORTED
2143 if (__kmp_threads[gtid]->th.th_team->t.t_level == 0 &&
2144 __kmp_affinity.flags.reset) {
2146 }
2147#endif
2148 __kmp_str_buf_init(&capture_buf);
2149 num_required = __kmp_aux_capture_affinity(gtid, format, &capture_buf);
2150 if (buffer && buf_size) {
2151 __kmp_strncpy_truncate(buffer, buf_size, capture_buf.str,
2152 capture_buf.used + 1);
2153 }
2154 __kmp_str_buf_free(&capture_buf);
2155 return num_required;
2156}
2157
2158void kmpc_set_stacksize(int arg) {
2159 // __kmp_aux_set_stacksize initializes the library if needed
2161}
2162
2163void kmpc_set_stacksize_s(size_t arg) {
2164 // __kmp_aux_set_stacksize initializes the library if needed
2166}
2167
2168void kmpc_set_blocktime(int arg) {
2169 int gtid, tid, bt = arg;
2170 kmp_info_t *thread;
2171
2172 gtid = __kmp_entry_gtid();
2173 tid = __kmp_tid_from_gtid(gtid);
2174 thread = __kmp_thread_from_gtid(gtid);
2175
2177 __kmp_aux_set_blocktime(bt, thread, tid);
2178}
2179
2180void kmpc_set_library(int arg) {
2181 // __kmp_user_set_library initializes the library if needed
2183}
2184
2185void kmpc_set_defaults(char const *str) {
2186 // __kmp_aux_set_defaults initializes the library if needed
2188}
2189
2191 // ignore after initialization because some teams have already
2192 // allocated dispatch buffers
2194 arg <= KMP_MAX_DISP_NUM_BUFF) {
2196 }
2197}
2198
2199int kmpc_set_affinity_mask_proc(int proc, void **mask) {
2200#if defined(KMP_STUB) || !KMP_AFFINITY_SUPPORTED
2201 return -1;
2202#else
2203 if (!TCR_4(__kmp_init_middle)) {
2205 }
2207 return __kmp_aux_set_affinity_mask_proc(proc, mask);
2208#endif
2209}
2210
2212#if defined(KMP_STUB) || !KMP_AFFINITY_SUPPORTED
2213 return -1;
2214#else
2215 if (!TCR_4(__kmp_init_middle)) {
2217 }
2219 return __kmp_aux_unset_affinity_mask_proc(proc, mask);
2220#endif
2221}
2222
2223int kmpc_get_affinity_mask_proc(int proc, void **mask) {
2224#if defined(KMP_STUB) || !KMP_AFFINITY_SUPPORTED
2225 return -1;
2226#else
2227 if (!TCR_4(__kmp_init_middle)) {
2229 }
2231 return __kmp_aux_get_affinity_mask_proc(proc, mask);
2232#endif
2233}
2234
2235/* -------------------------------------------------------------------------- */
2236/*!
2237@ingroup THREADPRIVATE
2238@param loc source location information
2239@param gtid global thread number
2240@param cpy_size size of the cpy_data buffer
2241@param cpy_data pointer to data to be copied
2242@param cpy_func helper function to call for copying data
2243@param didit flag variable: 1=single thread; 0=not single thread
2244
2245__kmpc_copyprivate implements the interface for the private data broadcast
2246needed for the copyprivate clause associated with a single region in an
2247OpenMP<sup>*</sup> program (both C and Fortran).
2248All threads participating in the parallel region call this routine.
2249One of the threads (called the single thread) should have the <tt>didit</tt>
2250variable set to 1 and all other threads should have that variable set to 0.
2251All threads pass a pointer to a data buffer (cpy_data) that they have built.
2252
2253The OpenMP specification forbids the use of nowait on the single region when a
2254copyprivate clause is present. However, @ref __kmpc_copyprivate implements a
2255barrier internally to avoid race conditions, so the code generation for the
2256single region should avoid generating a barrier after the call to @ref
2257__kmpc_copyprivate.
2258
2259The <tt>gtid</tt> parameter is the global thread id for the current thread.
2260The <tt>loc</tt> parameter is a pointer to source location information.
2261
2262Internal implementation: The single thread will first copy its descriptor
2263address (cpy_data) to a team-private location, then the other threads will each
2264call the function pointed to by the parameter cpy_func, which carries out the
2265copy by copying the data using the cpy_data buffer.
2266
2267The cpy_func routine used for the copy and the contents of the data area defined
2268by cpy_data and cpy_size may be built in any fashion that will allow the copy
2269to be done. For instance, the cpy_data buffer can hold the actual data to be
2270copied or it may hold a list of pointers to the data. The cpy_func routine must
2271interpret the cpy_data buffer appropriately.
2272
2273The interface to cpy_func is as follows:
2274@code
2275void cpy_func( void *destination, void *source )
2276@endcode
2277where void *destination is the cpy_data pointer for the thread being copied to
2278and void *source is the cpy_data pointer for the thread being copied from.
2279*/
2280void __kmpc_copyprivate(ident_t *loc, kmp_int32 gtid, size_t cpy_size,
2281 void *cpy_data, void (*cpy_func)(void *, void *),
2282 kmp_int32 didit) {
2283 void **data_ptr;
2284 KC_TRACE(10, ("__kmpc_copyprivate: called T#%d\n", gtid));
2286
2287 KMP_MB();
2288
2289 data_ptr = &__kmp_team_from_gtid(gtid)->t.t_copypriv_data;
2290
2292 if (loc == 0) {
2293 KMP_WARNING(ConstructIdentInvalid);
2294 }
2295 }
2296
2297 // ToDo: Optimize the following two barriers into some kind of split barrier
2298
2299 if (didit)
2300 *data_ptr = cpy_data;
2301
2302#if OMPT_SUPPORT
2303 ompt_frame_t *ompt_frame;
2304 if (ompt_enabled.enabled) {
2305 __ompt_get_task_info_internal(0, NULL, NULL, &ompt_frame, NULL, NULL);
2306 if (ompt_frame->enter_frame.ptr == NULL)
2307 ompt_frame->enter_frame.ptr = OMPT_GET_FRAME_ADDRESS(0);
2308 }
2309 OMPT_STORE_RETURN_ADDRESS(gtid);
2310#endif
2311/* This barrier is not a barrier region boundary */
2312#if USE_ITT_NOTIFY
2313 __kmp_threads[gtid]->th.th_ident = loc;
2314#endif
2315 __kmp_barrier(bs_plain_barrier, gtid, FALSE, 0, NULL, NULL);
2316
2317 if (!didit)
2318 (*cpy_func)(cpy_data, *data_ptr);
2319
2320 // Consider next barrier a user-visible barrier for barrier region boundaries
2321 // Nesting checks are already handled by the single construct checks
2322 {
2323#if OMPT_SUPPORT
2324 OMPT_STORE_RETURN_ADDRESS(gtid);
2325#endif
2326#if USE_ITT_NOTIFY
2327 __kmp_threads[gtid]->th.th_ident = loc; // TODO: check if it is needed (e.g.
2328// tasks can overwrite the location)
2329#endif
2330 __kmp_barrier(bs_plain_barrier, gtid, FALSE, 0, NULL, NULL);
2331#if OMPT_SUPPORT && OMPT_OPTIONAL
2332 if (ompt_enabled.enabled) {
2333 ompt_frame->enter_frame = ompt_data_none;
2334 }
2335#endif
2336 }
2337}
2338
2339/* --------------------------------------------------------------------------*/
2340/*!
2341@ingroup THREADPRIVATE
2342@param loc source location information
2343@param gtid global thread number
2344@param cpy_data pointer to the data to be saved/copied or 0
2345@return the saved pointer to the data
2346
2347__kmpc_copyprivate_light is a lighter version of __kmpc_copyprivate:
2348__kmpc_copyprivate_light only saves the pointer it's given (if it's not 0, so
2349coming from single), and returns that pointer in all calls (for single thread
2350it's not needed). This version doesn't do any actual data copying. Data copying
2351has to be done somewhere else, e.g. inline in the generated code. Due to this,
2352this function doesn't have any barrier at the end of the function, like
2353__kmpc_copyprivate does, so generated code needs barrier after copying of all
2354data was done.
2355*/
2356void *__kmpc_copyprivate_light(ident_t *loc, kmp_int32 gtid, void *cpy_data) {
2357 void **data_ptr;
2358
2359 KC_TRACE(10, ("__kmpc_copyprivate_light: called T#%d\n", gtid));
2360
2361 KMP_MB();
2362
2363 data_ptr = &__kmp_team_from_gtid(gtid)->t.t_copypriv_data;
2364
2366 if (loc == 0) {
2367 KMP_WARNING(ConstructIdentInvalid);
2368 }
2369 }
2370
2371 // ToDo: Optimize the following barrier
2372
2373 if (cpy_data)
2374 *data_ptr = cpy_data;
2375
2376#if OMPT_SUPPORT
2377 ompt_frame_t *ompt_frame;
2378 if (ompt_enabled.enabled) {
2379 __ompt_get_task_info_internal(0, NULL, NULL, &ompt_frame, NULL, NULL);
2380 if (ompt_frame->enter_frame.ptr == NULL)
2381 ompt_frame->enter_frame.ptr = OMPT_GET_FRAME_ADDRESS(0);
2382 OMPT_STORE_RETURN_ADDRESS(gtid);
2383 }
2384#endif
2385/* This barrier is not a barrier region boundary */
2386#if USE_ITT_NOTIFY
2387 __kmp_threads[gtid]->th.th_ident = loc;
2388#endif
2389 __kmp_barrier(bs_plain_barrier, gtid, FALSE, 0, NULL, NULL);
2390
2391 return *data_ptr;
2392}
2393
2394/* -------------------------------------------------------------------------- */
2395
2396#define INIT_LOCK __kmp_init_user_lock_with_checks
2397#define INIT_NESTED_LOCK __kmp_init_nested_user_lock_with_checks
2398#define ACQUIRE_LOCK __kmp_acquire_user_lock_with_checks
2399#define ACQUIRE_LOCK_TIMED __kmp_acquire_user_lock_with_checks_timed
2400#define ACQUIRE_NESTED_LOCK __kmp_acquire_nested_user_lock_with_checks
2401#define ACQUIRE_NESTED_LOCK_TIMED \
2402 __kmp_acquire_nested_user_lock_with_checks_timed
2403#define RELEASE_LOCK __kmp_release_user_lock_with_checks
2404#define RELEASE_NESTED_LOCK __kmp_release_nested_user_lock_with_checks
2405#define TEST_LOCK __kmp_test_user_lock_with_checks
2406#define TEST_NESTED_LOCK __kmp_test_nested_user_lock_with_checks
2407#define DESTROY_LOCK __kmp_destroy_user_lock_with_checks
2408#define DESTROY_NESTED_LOCK __kmp_destroy_nested_user_lock_with_checks
2409
2410// TODO: Make check abort messages use location info & pass it into
2411// with_checks routines
2412
2413#if KMP_USE_DYNAMIC_LOCK
2414
2415// internal lock initializer
2416static __forceinline void __kmp_init_lock_with_hint(ident_t *loc, void **lock,
2417 kmp_dyna_lockseq_t seq) {
2418 if (KMP_IS_D_LOCK(seq)) {
2419 KMP_INIT_D_LOCK(lock, seq);
2420#if USE_ITT_BUILD
2421 __kmp_itt_lock_creating((kmp_user_lock_p)lock, NULL);
2422#endif
2423 } else {
2424 KMP_INIT_I_LOCK(lock, seq);
2425#if USE_ITT_BUILD
2426 kmp_indirect_lock_t *ilk = KMP_LOOKUP_I_LOCK(lock);
2427 __kmp_itt_lock_creating(ilk->lock, loc);
2428#endif
2429 }
2430}
2431
2432// internal nest lock initializer
2433static __forceinline void
2434__kmp_init_nest_lock_with_hint(ident_t *loc, void **lock,
2435 kmp_dyna_lockseq_t seq) {
2436#if KMP_USE_TSX
2437 // Don't have nested lock implementation for speculative locks
2438 if (seq == lockseq_hle || seq == lockseq_rtm_queuing ||
2439 seq == lockseq_rtm_spin || seq == lockseq_adaptive)
2440 seq = __kmp_user_lock_seq;
2441#endif
2442 switch (seq) {
2443 case lockseq_tas:
2444 seq = lockseq_nested_tas;
2445 break;
2446#if KMP_USE_FUTEX
2447 case lockseq_futex:
2448 seq = lockseq_nested_futex;
2449 break;
2450#endif
2451 case lockseq_ticket:
2452 seq = lockseq_nested_ticket;
2453 break;
2454 case lockseq_queuing:
2455 seq = lockseq_nested_queuing;
2456 break;
2457 case lockseq_drdpa:
2458 seq = lockseq_nested_drdpa;
2459 break;
2460 default:
2461 seq = lockseq_nested_queuing;
2462 }
2463 KMP_INIT_I_LOCK(lock, seq);
2464#if USE_ITT_BUILD
2465 kmp_indirect_lock_t *ilk = KMP_LOOKUP_I_LOCK(lock);
2466 __kmp_itt_lock_creating(ilk->lock, loc);
2467#endif
2468}
2469
2470/* initialize the lock with a hint */
2471void __kmpc_init_lock_with_hint(ident_t *loc, kmp_int32 gtid, void **user_lock,
2472 uintptr_t hint) {
2474 if (__kmp_env_consistency_check && user_lock == NULL) {
2475 KMP_FATAL(LockIsUninitialized, "omp_init_lock_with_hint");
2476 }
2477
2478 __kmp_init_lock_with_hint(loc, user_lock, __kmp_map_hint_to_lock(hint));
2479
2480#if OMPT_SUPPORT && OMPT_OPTIONAL
2481 // This is the case, if called from omp_init_lock_with_hint:
2482 void *codeptr = OMPT_LOAD_RETURN_ADDRESS(gtid);
2483 if (!codeptr)
2484 codeptr = OMPT_GET_RETURN_ADDRESS(0);
2485 if (ompt_enabled.ompt_callback_lock_init) {
2486 ompt_callbacks.ompt_callback(ompt_callback_lock_init)(
2487 ompt_mutex_lock, (omp_lock_hint_t)hint,
2488 __ompt_get_mutex_impl_type(user_lock),
2489 (ompt_wait_id_t)(uintptr_t)user_lock, codeptr);
2490 }
2491#endif
2492}
2493
2494/* initialize the lock with a hint */
2496 void **user_lock, uintptr_t hint) {
2498 if (__kmp_env_consistency_check && user_lock == NULL) {
2499 KMP_FATAL(LockIsUninitialized, "omp_init_nest_lock_with_hint");
2500 }
2501
2502 __kmp_init_nest_lock_with_hint(loc, user_lock, __kmp_map_hint_to_lock(hint));
2503
2504#if OMPT_SUPPORT && OMPT_OPTIONAL
2505 // This is the case, if called from omp_init_lock_with_hint:
2506 void *codeptr = OMPT_LOAD_RETURN_ADDRESS(gtid);
2507 if (!codeptr)
2508 codeptr = OMPT_GET_RETURN_ADDRESS(0);
2509 if (ompt_enabled.ompt_callback_lock_init) {
2510 ompt_callbacks.ompt_callback(ompt_callback_lock_init)(
2511 ompt_mutex_nest_lock, (omp_lock_hint_t)hint,
2512 __ompt_get_mutex_impl_type(user_lock),
2513 (ompt_wait_id_t)(uintptr_t)user_lock, codeptr);
2514 }
2515#endif
2516}
2517
2518#endif // KMP_USE_DYNAMIC_LOCK
2519
2520/* initialize the lock */
2521void __kmpc_init_lock(ident_t *loc, kmp_int32 gtid, void **user_lock) {
2522#if KMP_USE_DYNAMIC_LOCK
2523
2525 if (__kmp_env_consistency_check && user_lock == NULL) {
2526 KMP_FATAL(LockIsUninitialized, "omp_init_lock");
2527 }
2528 __kmp_init_lock_with_hint(loc, user_lock, __kmp_user_lock_seq);
2529
2530#if OMPT_SUPPORT && OMPT_OPTIONAL
2531 // This is the case, if called from omp_init_lock_with_hint:
2532 void *codeptr = OMPT_LOAD_RETURN_ADDRESS(gtid);
2533 if (!codeptr)
2534 codeptr = OMPT_GET_RETURN_ADDRESS(0);
2535 if (ompt_enabled.ompt_callback_lock_init) {
2536 ompt_callbacks.ompt_callback(ompt_callback_lock_init)(
2537 ompt_mutex_lock, omp_lock_hint_none,
2538 __ompt_get_mutex_impl_type(user_lock),
2539 (ompt_wait_id_t)(uintptr_t)user_lock, codeptr);
2540 }
2541#endif
2542
2543#else // KMP_USE_DYNAMIC_LOCK
2544
2545 static char const *const func = "omp_init_lock";
2548
2550 if (user_lock == NULL) {
2551 KMP_FATAL(LockIsUninitialized, func);
2552 }
2553 }
2554
2556
2557 if ((__kmp_user_lock_kind == lk_tas) &&
2558 (sizeof(lck->tas.lk.poll) <= OMP_LOCK_T_SIZE)) {
2559 lck = (kmp_user_lock_p)user_lock;
2560 }
2561#if KMP_USE_FUTEX
2562 else if ((__kmp_user_lock_kind == lk_futex) &&
2563 (sizeof(lck->futex.lk.poll) <= OMP_LOCK_T_SIZE)) {
2564 lck = (kmp_user_lock_p)user_lock;
2565 }
2566#endif
2567 else {
2568 lck = __kmp_user_lock_allocate(user_lock, gtid, 0);
2569 }
2570 INIT_LOCK(lck);
2572
2573#if OMPT_SUPPORT && OMPT_OPTIONAL
2574 // This is the case, if called from omp_init_lock_with_hint:
2575 void *codeptr = OMPT_LOAD_RETURN_ADDRESS(gtid);
2576 if (!codeptr)
2577 codeptr = OMPT_GET_RETURN_ADDRESS(0);
2578 if (ompt_enabled.ompt_callback_lock_init) {
2579 ompt_callbacks.ompt_callback(ompt_callback_lock_init)(
2580 ompt_mutex_lock, omp_lock_hint_none, __ompt_get_mutex_impl_type(),
2581 (ompt_wait_id_t)(uintptr_t)user_lock, codeptr);
2582 }
2583#endif
2584
2585#if USE_ITT_BUILD
2586 __kmp_itt_lock_creating(lck);
2587#endif /* USE_ITT_BUILD */
2588
2589#endif // KMP_USE_DYNAMIC_LOCK
2590} // __kmpc_init_lock
2591
2592/* initialize the lock */
2593void __kmpc_init_nest_lock(ident_t *loc, kmp_int32 gtid, void **user_lock) {
2594#if KMP_USE_DYNAMIC_LOCK
2595
2597 if (__kmp_env_consistency_check && user_lock == NULL) {
2598 KMP_FATAL(LockIsUninitialized, "omp_init_nest_lock");
2599 }
2600 __kmp_init_nest_lock_with_hint(loc, user_lock, __kmp_user_lock_seq);
2601
2602#if OMPT_SUPPORT && OMPT_OPTIONAL
2603 // This is the case, if called from omp_init_lock_with_hint:
2604 void *codeptr = OMPT_LOAD_RETURN_ADDRESS(gtid);
2605 if (!codeptr)
2606 codeptr = OMPT_GET_RETURN_ADDRESS(0);
2607 if (ompt_enabled.ompt_callback_lock_init) {
2608 ompt_callbacks.ompt_callback(ompt_callback_lock_init)(
2609 ompt_mutex_nest_lock, omp_lock_hint_none,
2610 __ompt_get_mutex_impl_type(user_lock),
2611 (ompt_wait_id_t)(uintptr_t)user_lock, codeptr);
2612 }
2613#endif
2614
2615#else // KMP_USE_DYNAMIC_LOCK
2616
2617 static char const *const func = "omp_init_nest_lock";
2620
2622 if (user_lock == NULL) {
2623 KMP_FATAL(LockIsUninitialized, func);
2624 }
2625 }
2626
2628
2629 if ((__kmp_user_lock_kind == lk_tas) &&
2630 (sizeof(lck->tas.lk.poll) + sizeof(lck->tas.lk.depth_locked) <=
2632 lck = (kmp_user_lock_p)user_lock;
2633 }
2634#if KMP_USE_FUTEX
2635 else if ((__kmp_user_lock_kind == lk_futex) &&
2636 (sizeof(lck->futex.lk.poll) + sizeof(lck->futex.lk.depth_locked) <=
2638 lck = (kmp_user_lock_p)user_lock;
2639 }
2640#endif
2641 else {
2642 lck = __kmp_user_lock_allocate(user_lock, gtid, 0);
2643 }
2644
2647
2648#if OMPT_SUPPORT && OMPT_OPTIONAL
2649 // This is the case, if called from omp_init_lock_with_hint:
2650 void *codeptr = OMPT_LOAD_RETURN_ADDRESS(gtid);
2651 if (!codeptr)
2652 codeptr = OMPT_GET_RETURN_ADDRESS(0);
2653 if (ompt_enabled.ompt_callback_lock_init) {
2654 ompt_callbacks.ompt_callback(ompt_callback_lock_init)(
2655 ompt_mutex_nest_lock, omp_lock_hint_none, __ompt_get_mutex_impl_type(),
2656 (ompt_wait_id_t)(uintptr_t)user_lock, codeptr);
2657 }
2658#endif
2659
2660#if USE_ITT_BUILD
2661 __kmp_itt_lock_creating(lck);
2662#endif /* USE_ITT_BUILD */
2663
2664#endif // KMP_USE_DYNAMIC_LOCK
2665} // __kmpc_init_nest_lock
2666
2667void __kmpc_destroy_lock(ident_t *loc, kmp_int32 gtid, void **user_lock) {
2668#if KMP_USE_DYNAMIC_LOCK
2669
2670#if USE_ITT_BUILD
2672 if (KMP_EXTRACT_D_TAG(user_lock) == 0) {
2673 lck = ((kmp_indirect_lock_t *)KMP_LOOKUP_I_LOCK(user_lock))->lock;
2674 } else {
2675 lck = (kmp_user_lock_p)user_lock;
2676 }
2677 __kmp_itt_lock_destroyed(lck);
2678#endif
2679#if OMPT_SUPPORT && OMPT_OPTIONAL
2680 // This is the case, if called from omp_init_lock_with_hint:
2681 void *codeptr = OMPT_LOAD_RETURN_ADDRESS(gtid);
2682 if (!codeptr)
2683 codeptr = OMPT_GET_RETURN_ADDRESS(0);
2684 if (ompt_enabled.ompt_callback_lock_destroy) {
2685 ompt_callbacks.ompt_callback(ompt_callback_lock_destroy)(
2686 ompt_mutex_lock, (ompt_wait_id_t)(uintptr_t)user_lock, codeptr);
2687 }
2688#endif
2689 KMP_D_LOCK_FUNC(user_lock, destroy)((kmp_dyna_lock_t *)user_lock);
2690#else
2692
2693 if ((__kmp_user_lock_kind == lk_tas) &&
2694 (sizeof(lck->tas.lk.poll) <= OMP_LOCK_T_SIZE)) {
2695 lck = (kmp_user_lock_p)user_lock;
2696 }
2697#if KMP_USE_FUTEX
2698 else if ((__kmp_user_lock_kind == lk_futex) &&
2699 (sizeof(lck->futex.lk.poll) <= OMP_LOCK_T_SIZE)) {
2700 lck = (kmp_user_lock_p)user_lock;
2701 }
2702#endif
2703 else {
2704 lck = __kmp_lookup_user_lock(user_lock, "omp_destroy_lock");
2705 }
2706
2707#if OMPT_SUPPORT && OMPT_OPTIONAL
2708 // This is the case, if called from omp_init_lock_with_hint:
2709 void *codeptr = OMPT_LOAD_RETURN_ADDRESS(gtid);
2710 if (!codeptr)
2711 codeptr = OMPT_GET_RETURN_ADDRESS(0);
2712 if (ompt_enabled.ompt_callback_lock_destroy) {
2713 ompt_callbacks.ompt_callback(ompt_callback_lock_destroy)(
2714 ompt_mutex_lock, (ompt_wait_id_t)(uintptr_t)user_lock, codeptr);
2715 }
2716#endif
2717
2718#if USE_ITT_BUILD
2719 __kmp_itt_lock_destroyed(lck);
2720#endif /* USE_ITT_BUILD */
2722
2723 if ((__kmp_user_lock_kind == lk_tas) &&
2724 (sizeof(lck->tas.lk.poll) <= OMP_LOCK_T_SIZE)) {
2725 ;
2726 }
2727#if KMP_USE_FUTEX
2728 else if ((__kmp_user_lock_kind == lk_futex) &&
2729 (sizeof(lck->futex.lk.poll) <= OMP_LOCK_T_SIZE)) {
2730 ;
2731 }
2732#endif
2733 else {
2734 __kmp_user_lock_free(user_lock, gtid, lck);
2735 }
2736#endif // KMP_USE_DYNAMIC_LOCK
2737} // __kmpc_destroy_lock
2738
2739/* destroy the lock */
2740void __kmpc_destroy_nest_lock(ident_t *loc, kmp_int32 gtid, void **user_lock) {
2741#if KMP_USE_DYNAMIC_LOCK
2742
2743#if USE_ITT_BUILD
2744 kmp_indirect_lock_t *ilk = KMP_LOOKUP_I_LOCK(user_lock);
2745 __kmp_itt_lock_destroyed(ilk->lock);
2746#endif
2747#if OMPT_SUPPORT && OMPT_OPTIONAL
2748 // This is the case, if called from omp_init_lock_with_hint:
2749 void *codeptr = OMPT_LOAD_RETURN_ADDRESS(gtid);
2750 if (!codeptr)
2751 codeptr = OMPT_GET_RETURN_ADDRESS(0);
2752 if (ompt_enabled.ompt_callback_lock_destroy) {
2753 ompt_callbacks.ompt_callback(ompt_callback_lock_destroy)(
2754 ompt_mutex_nest_lock, (ompt_wait_id_t)(uintptr_t)user_lock, codeptr);
2755 }
2756#endif
2757 KMP_D_LOCK_FUNC(user_lock, destroy)((kmp_dyna_lock_t *)user_lock);
2758
2759#else // KMP_USE_DYNAMIC_LOCK
2760
2762
2763 if ((__kmp_user_lock_kind == lk_tas) &&
2764 (sizeof(lck->tas.lk.poll) + sizeof(lck->tas.lk.depth_locked) <=
2766 lck = (kmp_user_lock_p)user_lock;
2767 }
2768#if KMP_USE_FUTEX
2769 else if ((__kmp_user_lock_kind == lk_futex) &&
2770 (sizeof(lck->futex.lk.poll) + sizeof(lck->futex.lk.depth_locked) <=
2772 lck = (kmp_user_lock_p)user_lock;
2773 }
2774#endif
2775 else {
2776 lck = __kmp_lookup_user_lock(user_lock, "omp_destroy_nest_lock");
2777 }
2778
2779#if OMPT_SUPPORT && OMPT_OPTIONAL
2780 // This is the case, if called from omp_init_lock_with_hint:
2781 void *codeptr = OMPT_LOAD_RETURN_ADDRESS(gtid);
2782 if (!codeptr)
2783 codeptr = OMPT_GET_RETURN_ADDRESS(0);
2784 if (ompt_enabled.ompt_callback_lock_destroy) {
2785 ompt_callbacks.ompt_callback(ompt_callback_lock_destroy)(
2786 ompt_mutex_nest_lock, (ompt_wait_id_t)(uintptr_t)user_lock, codeptr);
2787 }
2788#endif
2789
2790#if USE_ITT_BUILD
2791 __kmp_itt_lock_destroyed(lck);
2792#endif /* USE_ITT_BUILD */
2793
2795
2796 if ((__kmp_user_lock_kind == lk_tas) &&
2797 (sizeof(lck->tas.lk.poll) + sizeof(lck->tas.lk.depth_locked) <=
2799 ;
2800 }
2801#if KMP_USE_FUTEX
2802 else if ((__kmp_user_lock_kind == lk_futex) &&
2803 (sizeof(lck->futex.lk.poll) + sizeof(lck->futex.lk.depth_locked) <=
2805 ;
2806 }
2807#endif
2808 else {
2809 __kmp_user_lock_free(user_lock, gtid, lck);
2810 }
2811#endif // KMP_USE_DYNAMIC_LOCK
2812} // __kmpc_destroy_nest_lock
2813
2814void __kmpc_set_lock(ident_t *loc, kmp_int32 gtid, void **user_lock) {
2815 KMP_COUNT_BLOCK(OMP_set_lock);
2816#if KMP_USE_DYNAMIC_LOCK
2817 int tag = KMP_EXTRACT_D_TAG(user_lock);
2818#if USE_ITT_BUILD
2819 __kmp_itt_lock_acquiring(
2821 user_lock); // itt function will get to the right lock object.
2822#endif
2823#if OMPT_SUPPORT && OMPT_OPTIONAL
2824 // This is the case, if called from omp_init_lock_with_hint:
2825 void *codeptr = OMPT_LOAD_RETURN_ADDRESS(gtid);
2826 if (!codeptr)
2827 codeptr = OMPT_GET_RETURN_ADDRESS(0);
2828 if (ompt_enabled.ompt_callback_mutex_acquire) {
2829 ompt_callbacks.ompt_callback(ompt_callback_mutex_acquire)(
2830 ompt_mutex_lock, omp_lock_hint_none,
2831 __ompt_get_mutex_impl_type(user_lock),
2832 (ompt_wait_id_t)(uintptr_t)user_lock, codeptr);
2833 }
2834#endif
2835#if KMP_USE_INLINED_TAS
2836 if (tag == locktag_tas && !__kmp_env_consistency_check) {
2837 KMP_ACQUIRE_TAS_LOCK(user_lock, gtid);
2838 } else
2839#elif KMP_USE_INLINED_FUTEX
2840 if (tag == locktag_futex && !__kmp_env_consistency_check) {
2841 KMP_ACQUIRE_FUTEX_LOCK(user_lock, gtid);
2842 } else
2843#endif
2844 {
2845 __kmp_direct_set[tag]((kmp_dyna_lock_t *)user_lock, gtid);
2846 }
2847#if USE_ITT_BUILD
2848 __kmp_itt_lock_acquired((kmp_user_lock_p)user_lock);
2849#endif
2850#if OMPT_SUPPORT && OMPT_OPTIONAL
2851 if (ompt_enabled.ompt_callback_mutex_acquired) {
2852 ompt_callbacks.ompt_callback(ompt_callback_mutex_acquired)(
2853 ompt_mutex_lock, (ompt_wait_id_t)(uintptr_t)user_lock, codeptr);
2854 }
2855#endif
2856
2857#else // KMP_USE_DYNAMIC_LOCK
2858
2860
2861 if ((__kmp_user_lock_kind == lk_tas) &&
2862 (sizeof(lck->tas.lk.poll) <= OMP_LOCK_T_SIZE)) {
2863 lck = (kmp_user_lock_p)user_lock;
2864 }
2865#if KMP_USE_FUTEX
2866 else if ((__kmp_user_lock_kind == lk_futex) &&
2867 (sizeof(lck->futex.lk.poll) <= OMP_LOCK_T_SIZE)) {
2868 lck = (kmp_user_lock_p)user_lock;
2869 }
2870#endif
2871 else {
2872 lck = __kmp_lookup_user_lock(user_lock, "omp_set_lock");
2873 }
2874
2875#if USE_ITT_BUILD
2876 __kmp_itt_lock_acquiring(lck);
2877#endif /* USE_ITT_BUILD */
2878#if OMPT_SUPPORT && OMPT_OPTIONAL
2879 // This is the case, if called from omp_init_lock_with_hint:
2880 void *codeptr = OMPT_LOAD_RETURN_ADDRESS(gtid);
2881 if (!codeptr)
2882 codeptr = OMPT_GET_RETURN_ADDRESS(0);
2883 if (ompt_enabled.ompt_callback_mutex_acquire) {
2884 ompt_callbacks.ompt_callback(ompt_callback_mutex_acquire)(
2885 ompt_mutex_lock, omp_lock_hint_none, __ompt_get_mutex_impl_type(),
2886 (ompt_wait_id_t)(uintptr_t)lck, codeptr);
2887 }
2888#endif
2889
2890 ACQUIRE_LOCK(lck, gtid);
2891
2892#if USE_ITT_BUILD
2893 __kmp_itt_lock_acquired(lck);
2894#endif /* USE_ITT_BUILD */
2895
2896#if OMPT_SUPPORT && OMPT_OPTIONAL
2897 if (ompt_enabled.ompt_callback_mutex_acquired) {
2898 ompt_callbacks.ompt_callback(ompt_callback_mutex_acquired)(
2899 ompt_mutex_lock, (ompt_wait_id_t)(uintptr_t)lck, codeptr);
2900 }
2901#endif
2902
2903#endif // KMP_USE_DYNAMIC_LOCK
2904}
2905
2906void __kmpc_set_nest_lock(ident_t *loc, kmp_int32 gtid, void **user_lock) {
2907#if KMP_USE_DYNAMIC_LOCK
2908
2909#if USE_ITT_BUILD
2910 __kmp_itt_lock_acquiring((kmp_user_lock_p)user_lock);
2911#endif
2912#if OMPT_SUPPORT && OMPT_OPTIONAL
2913 // This is the case, if called from omp_init_lock_with_hint:
2914 void *codeptr = OMPT_LOAD_RETURN_ADDRESS(gtid);
2915 if (!codeptr)
2916 codeptr = OMPT_GET_RETURN_ADDRESS(0);
2917 if (ompt_enabled.enabled) {
2918 if (ompt_enabled.ompt_callback_mutex_acquire) {
2919 ompt_callbacks.ompt_callback(ompt_callback_mutex_acquire)(
2920 ompt_mutex_nest_lock, omp_lock_hint_none,
2921 __ompt_get_mutex_impl_type(user_lock),
2922 (ompt_wait_id_t)(uintptr_t)user_lock, codeptr);
2923 }
2924 }
2925#endif
2926 int acquire_status =
2927 KMP_D_LOCK_FUNC(user_lock, set)((kmp_dyna_lock_t *)user_lock, gtid);
2928 (void)acquire_status;
2929#if USE_ITT_BUILD
2930 __kmp_itt_lock_acquired((kmp_user_lock_p)user_lock);
2931#endif
2932
2933#if OMPT_SUPPORT && OMPT_OPTIONAL
2934 if (ompt_enabled.enabled) {
2935 if (acquire_status == KMP_LOCK_ACQUIRED_FIRST) {
2936 if (ompt_enabled.ompt_callback_mutex_acquired) {
2937 // lock_first
2938 ompt_callbacks.ompt_callback(ompt_callback_mutex_acquired)(
2939 ompt_mutex_nest_lock, (ompt_wait_id_t)(uintptr_t)user_lock,
2940 codeptr);
2941 }
2942 } else {
2943 if (ompt_enabled.ompt_callback_nest_lock) {
2944 // lock_next
2945 ompt_callbacks.ompt_callback(ompt_callback_nest_lock)(
2946 ompt_scope_begin, (ompt_wait_id_t)(uintptr_t)user_lock, codeptr);
2947 }
2948 }
2949 }
2950#endif
2951
2952#else // KMP_USE_DYNAMIC_LOCK
2953 int acquire_status;
2955
2956 if ((__kmp_user_lock_kind == lk_tas) &&
2957 (sizeof(lck->tas.lk.poll) + sizeof(lck->tas.lk.depth_locked) <=
2959 lck = (kmp_user_lock_p)user_lock;
2960 }
2961#if KMP_USE_FUTEX
2962 else if ((__kmp_user_lock_kind == lk_futex) &&
2963 (sizeof(lck->futex.lk.poll) + sizeof(lck->futex.lk.depth_locked) <=
2965 lck = (kmp_user_lock_p)user_lock;
2966 }
2967#endif
2968 else {
2969 lck = __kmp_lookup_user_lock(user_lock, "omp_set_nest_lock");
2970 }
2971
2972#if USE_ITT_BUILD
2973 __kmp_itt_lock_acquiring(lck);
2974#endif /* USE_ITT_BUILD */
2975#if OMPT_SUPPORT && OMPT_OPTIONAL
2976 // This is the case, if called from omp_init_lock_with_hint:
2977 void *codeptr = OMPT_LOAD_RETURN_ADDRESS(gtid);
2978 if (!codeptr)
2979 codeptr = OMPT_GET_RETURN_ADDRESS(0);
2980 if (ompt_enabled.enabled) {
2981 if (ompt_enabled.ompt_callback_mutex_acquire) {
2982 ompt_callbacks.ompt_callback(ompt_callback_mutex_acquire)(
2983 ompt_mutex_nest_lock, omp_lock_hint_none,
2984 __ompt_get_mutex_impl_type(), (ompt_wait_id_t)(uintptr_t)lck,
2985 codeptr);
2986 }
2987 }
2988#endif
2989
2990 ACQUIRE_NESTED_LOCK(lck, gtid, &acquire_status);
2991
2992#if USE_ITT_BUILD
2993 __kmp_itt_lock_acquired(lck);
2994#endif /* USE_ITT_BUILD */
2995
2996#if OMPT_SUPPORT && OMPT_OPTIONAL
2997 if (ompt_enabled.enabled) {
2998 if (acquire_status == KMP_LOCK_ACQUIRED_FIRST) {
2999 if (ompt_enabled.ompt_callback_mutex_acquired) {
3000 // lock_first
3001 ompt_callbacks.ompt_callback(ompt_callback_mutex_acquired)(
3002 ompt_mutex_nest_lock, (ompt_wait_id_t)(uintptr_t)lck, codeptr);
3003 }
3004 } else {
3005 if (ompt_enabled.ompt_callback_nest_lock) {
3006 // lock_next
3007 ompt_callbacks.ompt_callback(ompt_callback_nest_lock)(
3008 ompt_scope_begin, (ompt_wait_id_t)(uintptr_t)lck, codeptr);
3009 }
3010 }
3011 }
3012#endif
3013
3014#endif // KMP_USE_DYNAMIC_LOCK
3015}
3016
3017void __kmpc_unset_lock(ident_t *loc, kmp_int32 gtid, void **user_lock) {
3018#if KMP_USE_DYNAMIC_LOCK
3019
3020 int tag = KMP_EXTRACT_D_TAG(user_lock);
3021#if USE_ITT_BUILD
3022 __kmp_itt_lock_releasing((kmp_user_lock_p)user_lock);
3023#endif
3024#if KMP_USE_INLINED_TAS
3025 if (tag == locktag_tas && !__kmp_env_consistency_check) {
3026 KMP_RELEASE_TAS_LOCK(user_lock, gtid);
3027 } else
3028#elif KMP_USE_INLINED_FUTEX
3029 if (tag == locktag_futex && !__kmp_env_consistency_check) {
3030 KMP_RELEASE_FUTEX_LOCK(user_lock, gtid);
3031 } else
3032#endif
3033 {
3034 __kmp_direct_unset[tag]((kmp_dyna_lock_t *)user_lock, gtid);
3035 }
3036
3037#if OMPT_SUPPORT && OMPT_OPTIONAL
3038 // This is the case, if called from omp_init_lock_with_hint:
3039 void *codeptr = OMPT_LOAD_RETURN_ADDRESS(gtid);
3040 if (!codeptr)
3041 codeptr = OMPT_GET_RETURN_ADDRESS(0);
3042 if (ompt_enabled.ompt_callback_mutex_released) {
3043 ompt_callbacks.ompt_callback(ompt_callback_mutex_released)(
3044 ompt_mutex_lock, (ompt_wait_id_t)(uintptr_t)user_lock, codeptr);
3045 }
3046#endif
3047
3048#else // KMP_USE_DYNAMIC_LOCK
3049
3051
3052 /* Can't use serial interval since not block structured */
3053 /* release the lock */
3054
3055 if ((__kmp_user_lock_kind == lk_tas) &&
3056 (sizeof(lck->tas.lk.poll) <= OMP_LOCK_T_SIZE)) {
3057#if KMP_OS_LINUX && \
3058 (KMP_ARCH_X86 || KMP_ARCH_X86_64 || KMP_ARCH_ARM || KMP_ARCH_AARCH64)
3059// "fast" path implemented to fix customer performance issue
3060#if USE_ITT_BUILD
3061 __kmp_itt_lock_releasing((kmp_user_lock_p)user_lock);
3062#endif /* USE_ITT_BUILD */
3063 TCW_4(((kmp_user_lock_p)user_lock)->tas.lk.poll, 0);
3064 KMP_MB();
3065
3066#if OMPT_SUPPORT && OMPT_OPTIONAL
3067 // This is the case, if called from omp_init_lock_with_hint:
3068 void *codeptr = OMPT_LOAD_RETURN_ADDRESS(gtid);
3069 if (!codeptr)
3070 codeptr = OMPT_GET_RETURN_ADDRESS(0);
3071 if (ompt_enabled.ompt_callback_mutex_released) {
3072 ompt_callbacks.ompt_callback(ompt_callback_mutex_released)(
3073 ompt_mutex_lock, (ompt_wait_id_t)(uintptr_t)lck, codeptr);
3074 }
3075#endif
3076
3077 return;
3078#else
3079 lck = (kmp_user_lock_p)user_lock;
3080#endif
3081 }
3082#if KMP_USE_FUTEX
3083 else if ((__kmp_user_lock_kind == lk_futex) &&
3084 (sizeof(lck->futex.lk.poll) <= OMP_LOCK_T_SIZE)) {
3085 lck = (kmp_user_lock_p)user_lock;
3086 }
3087#endif
3088 else {
3089 lck = __kmp_lookup_user_lock(user_lock, "omp_unset_lock");
3090 }
3091
3092#if USE_ITT_BUILD
3093 __kmp_itt_lock_releasing(lck);
3094#endif /* USE_ITT_BUILD */
3095
3096 RELEASE_LOCK(lck, gtid);
3097
3098#if OMPT_SUPPORT && OMPT_OPTIONAL
3099 // This is the case, if called from omp_init_lock_with_hint:
3100 void *codeptr = OMPT_LOAD_RETURN_ADDRESS(gtid);
3101 if (!codeptr)
3102 codeptr = OMPT_GET_RETURN_ADDRESS(0);
3103 if (ompt_enabled.ompt_callback_mutex_released) {
3104 ompt_callbacks.ompt_callback(ompt_callback_mutex_released)(
3105 ompt_mutex_lock, (ompt_wait_id_t)(uintptr_t)lck, codeptr);
3106 }
3107#endif
3108
3109#endif // KMP_USE_DYNAMIC_LOCK
3110}
3111
3112/* release the lock */
3113void __kmpc_unset_nest_lock(ident_t *loc, kmp_int32 gtid, void **user_lock) {
3114#if KMP_USE_DYNAMIC_LOCK
3115
3116#if USE_ITT_BUILD
3117 __kmp_itt_lock_releasing((kmp_user_lock_p)user_lock);
3118#endif
3119 int release_status =
3120 KMP_D_LOCK_FUNC(user_lock, unset)((kmp_dyna_lock_t *)user_lock, gtid);
3121 (void)release_status;
3122
3123#if OMPT_SUPPORT && OMPT_OPTIONAL
3124 // This is the case, if called from omp_init_lock_with_hint:
3125 void *codeptr = OMPT_LOAD_RETURN_ADDRESS(gtid);
3126 if (!codeptr)
3127 codeptr = OMPT_GET_RETURN_ADDRESS(0);
3128 if (ompt_enabled.enabled) {
3129 if (release_status == KMP_LOCK_RELEASED) {
3130 if (ompt_enabled.ompt_callback_mutex_released) {
3131 // release_lock_last
3132 ompt_callbacks.ompt_callback(ompt_callback_mutex_released)(
3133 ompt_mutex_nest_lock, (ompt_wait_id_t)(uintptr_t)user_lock,
3134 codeptr);
3135 }
3136 } else if (ompt_enabled.ompt_callback_nest_lock) {
3137 // release_lock_prev
3138 ompt_callbacks.ompt_callback(ompt_callback_nest_lock)(
3139 ompt_scope_end, (ompt_wait_id_t)(uintptr_t)user_lock, codeptr);
3140 }
3141 }
3142#endif
3143
3144#else // KMP_USE_DYNAMIC_LOCK
3145
3147
3148 /* Can't use serial interval since not block structured */
3149
3150 if ((__kmp_user_lock_kind == lk_tas) &&
3151 (sizeof(lck->tas.lk.poll) + sizeof(lck->tas.lk.depth_locked) <=
3153#if KMP_OS_LINUX && \
3154 (KMP_ARCH_X86 || KMP_ARCH_X86_64 || KMP_ARCH_ARM || KMP_ARCH_AARCH64)
3155 // "fast" path implemented to fix customer performance issue
3156 kmp_tas_lock_t *tl = (kmp_tas_lock_t *)user_lock;
3157#if USE_ITT_BUILD
3158 __kmp_itt_lock_releasing((kmp_user_lock_p)user_lock);
3159#endif /* USE_ITT_BUILD */
3160
3161#if OMPT_SUPPORT && OMPT_OPTIONAL
3162 int release_status = KMP_LOCK_STILL_HELD;
3163#endif
3164
3165 if (--(tl->lk.depth_locked) == 0) {
3166 TCW_4(tl->lk.poll, 0);
3167#if OMPT_SUPPORT && OMPT_OPTIONAL
3168 release_status = KMP_LOCK_RELEASED;
3169#endif
3170 }
3171 KMP_MB();
3172
3173#if OMPT_SUPPORT && OMPT_OPTIONAL
3174 // This is the case, if called from omp_init_lock_with_hint:
3175 void *codeptr = OMPT_LOAD_RETURN_ADDRESS(gtid);
3176 if (!codeptr)
3177 codeptr = OMPT_GET_RETURN_ADDRESS(0);
3178 if (ompt_enabled.enabled) {
3179 if (release_status == KMP_LOCK_RELEASED) {
3180 if (ompt_enabled.ompt_callback_mutex_released) {
3181 // release_lock_last
3182 ompt_callbacks.ompt_callback(ompt_callback_mutex_released)(
3183 ompt_mutex_nest_lock, (ompt_wait_id_t)(uintptr_t)lck, codeptr);
3184 }
3185 } else if (ompt_enabled.ompt_callback_nest_lock) {
3186 // release_lock_previous
3187 ompt_callbacks.ompt_callback(ompt_callback_nest_lock)(
3188 ompt_mutex_scope_end, (ompt_wait_id_t)(uintptr_t)lck, codeptr);
3189 }
3190 }
3191#endif
3192
3193 return;
3194#else
3195 lck = (kmp_user_lock_p)user_lock;
3196#endif
3197 }
3198#if KMP_USE_FUTEX
3199 else if ((__kmp_user_lock_kind == lk_futex) &&
3200 (sizeof(lck->futex.lk.poll) + sizeof(lck->futex.lk.depth_locked) <=
3202 lck = (kmp_user_lock_p)user_lock;
3203 }
3204#endif
3205 else {
3206 lck = __kmp_lookup_user_lock(user_lock, "omp_unset_nest_lock");
3207 }
3208
3209#if USE_ITT_BUILD
3210 __kmp_itt_lock_releasing(lck);
3211#endif /* USE_ITT_BUILD */
3212
3213 int release_status;
3214 release_status = RELEASE_NESTED_LOCK(lck, gtid);
3215#if OMPT_SUPPORT && OMPT_OPTIONAL
3216 // This is the case, if called from omp_init_lock_with_hint:
3217 void *codeptr = OMPT_LOAD_RETURN_ADDRESS(gtid);
3218 if (!codeptr)
3219 codeptr = OMPT_GET_RETURN_ADDRESS(0);
3220 if (ompt_enabled.enabled) {
3221 if (release_status == KMP_LOCK_RELEASED) {
3222 if (ompt_enabled.ompt_callback_mutex_released) {
3223 // release_lock_last
3224 ompt_callbacks.ompt_callback(ompt_callback_mutex_released)(
3225 ompt_mutex_nest_lock, (ompt_wait_id_t)(uintptr_t)lck, codeptr);
3226 }
3227 } else if (ompt_enabled.ompt_callback_nest_lock) {
3228 // release_lock_previous
3229 ompt_callbacks.ompt_callback(ompt_callback_nest_lock)(
3230 ompt_mutex_scope_end, (ompt_wait_id_t)(uintptr_t)lck, codeptr);
3231 }
3232 }
3233#endif
3234
3235#endif // KMP_USE_DYNAMIC_LOCK
3236}
3237
3238/* try to acquire the lock */
3239int __kmpc_test_lock(ident_t *loc, kmp_int32 gtid, void **user_lock) {
3240 KMP_COUNT_BLOCK(OMP_test_lock);
3241
3242#if KMP_USE_DYNAMIC_LOCK
3243 int rc;
3244 int tag = KMP_EXTRACT_D_TAG(user_lock);
3245#if USE_ITT_BUILD
3246 __kmp_itt_lock_acquiring((kmp_user_lock_p)user_lock);
3247#endif
3248#if OMPT_SUPPORT && OMPT_OPTIONAL
3249 // This is the case, if called from omp_init_lock_with_hint:
3250 void *codeptr = OMPT_LOAD_RETURN_ADDRESS(gtid);
3251 if (!codeptr)
3252 codeptr = OMPT_GET_RETURN_ADDRESS(0);
3253 if (ompt_enabled.ompt_callback_mutex_acquire) {
3254 ompt_callbacks.ompt_callback(ompt_callback_mutex_acquire)(
3255 ompt_mutex_test_lock, omp_lock_hint_none,
3256 __ompt_get_mutex_impl_type(user_lock),
3257 (ompt_wait_id_t)(uintptr_t)user_lock, codeptr);
3258 }
3259#endif
3260#if KMP_USE_INLINED_TAS
3261 if (tag == locktag_tas && !__kmp_env_consistency_check) {
3262 KMP_TEST_TAS_LOCK(user_lock, gtid, rc);
3263 } else
3264#elif KMP_USE_INLINED_FUTEX
3265 if (tag == locktag_futex && !__kmp_env_consistency_check) {
3266 KMP_TEST_FUTEX_LOCK(user_lock, gtid, rc);
3267 } else
3268#endif
3269 {
3270 rc = __kmp_direct_test[tag]((kmp_dyna_lock_t *)user_lock, gtid);
3271 }
3272 if (rc) {
3273#if USE_ITT_BUILD
3274 __kmp_itt_lock_acquired((kmp_user_lock_p)user_lock);
3275#endif
3276#if OMPT_SUPPORT && OMPT_OPTIONAL
3277 if (ompt_enabled.ompt_callback_mutex_acquired) {
3278 ompt_callbacks.ompt_callback(ompt_callback_mutex_acquired)(
3279 ompt_mutex_test_lock, (ompt_wait_id_t)(uintptr_t)user_lock, codeptr);
3280 }
3281#endif
3282 return FTN_TRUE;
3283 } else {
3284#if USE_ITT_BUILD
3285 __kmp_itt_lock_cancelled((kmp_user_lock_p)user_lock);
3286#endif
3287 return FTN_FALSE;
3288 }
3289
3290#else // KMP_USE_DYNAMIC_LOCK
3291
3293 int rc;
3294
3295 if ((__kmp_user_lock_kind == lk_tas) &&
3296 (sizeof(lck->tas.lk.poll) <= OMP_LOCK_T_SIZE)) {
3297 lck = (kmp_user_lock_p)user_lock;
3298 }
3299#if KMP_USE_FUTEX
3300 else if ((__kmp_user_lock_kind == lk_futex) &&
3301 (sizeof(lck->futex.lk.poll) <= OMP_LOCK_T_SIZE)) {
3302 lck = (kmp_user_lock_p)user_lock;
3303 }
3304#endif
3305 else {
3306 lck = __kmp_lookup_user_lock(user_lock, "omp_test_lock");
3307 }
3308
3309#if USE_ITT_BUILD
3310 __kmp_itt_lock_acquiring(lck);
3311#endif /* USE_ITT_BUILD */
3312#if OMPT_SUPPORT && OMPT_OPTIONAL
3313 // This is the case, if called from omp_init_lock_with_hint:
3314 void *codeptr = OMPT_LOAD_RETURN_ADDRESS(gtid);
3315 if (!codeptr)
3316 codeptr = OMPT_GET_RETURN_ADDRESS(0);
3317 if (ompt_enabled.ompt_callback_mutex_acquire) {
3318 ompt_callbacks.ompt_callback(ompt_callback_mutex_acquire)(
3319 ompt_mutex_test_lock, omp_lock_hint_none, __ompt_get_mutex_impl_type(),
3320 (ompt_wait_id_t)(uintptr_t)lck, codeptr);
3321 }
3322#endif
3323
3324 rc = TEST_LOCK(lck, gtid);
3325#if USE_ITT_BUILD
3326 if (rc) {
3327 __kmp_itt_lock_acquired(lck);
3328 } else {
3329 __kmp_itt_lock_cancelled(lck);
3330 }
3331#endif /* USE_ITT_BUILD */
3332#if OMPT_SUPPORT && OMPT_OPTIONAL
3333 if (rc && ompt_enabled.ompt_callback_mutex_acquired) {
3334 ompt_callbacks.ompt_callback(ompt_callback_mutex_acquired)(
3335 ompt_mutex_test_lock, (ompt_wait_id_t)(uintptr_t)lck, codeptr);
3336 }
3337#endif
3338
3339 return (rc ? FTN_TRUE : FTN_FALSE);
3340
3341 /* Can't use serial interval since not block structured */
3342
3343#endif // KMP_USE_DYNAMIC_LOCK
3344}
3345
3346/* try to acquire the lock */
3347int __kmpc_test_nest_lock(ident_t *loc, kmp_int32 gtid, void **user_lock) {
3348#if KMP_USE_DYNAMIC_LOCK
3349 int rc;
3350#if USE_ITT_BUILD
3351 __kmp_itt_lock_acquiring((kmp_user_lock_p)user_lock);
3352#endif
3353#if OMPT_SUPPORT && OMPT_OPTIONAL
3354 // This is the case, if called from omp_init_lock_with_hint:
3355 void *codeptr = OMPT_LOAD_RETURN_ADDRESS(gtid);
3356 if (!codeptr)
3357 codeptr = OMPT_GET_RETURN_ADDRESS(0);
3358 if (ompt_enabled.ompt_callback_mutex_acquire) {
3359 ompt_callbacks.ompt_callback(ompt_callback_mutex_acquire)(
3360 ompt_mutex_test_nest_lock, omp_lock_hint_none,
3361 __ompt_get_mutex_impl_type(user_lock),
3362 (ompt_wait_id_t)(uintptr_t)user_lock, codeptr);
3363 }
3364#endif
3365 rc = KMP_D_LOCK_FUNC(user_lock, test)((kmp_dyna_lock_t *)user_lock, gtid);
3366#if USE_ITT_BUILD
3367 if (rc) {
3368 __kmp_itt_lock_acquired((kmp_user_lock_p)user_lock);
3369 } else {
3370 __kmp_itt_lock_cancelled((kmp_user_lock_p)user_lock);
3371 }
3372#endif
3373#if OMPT_SUPPORT && OMPT_OPTIONAL
3374 if (ompt_enabled.enabled && rc) {
3375 if (rc == 1) {
3376 if (ompt_enabled.ompt_callback_mutex_acquired) {
3377 // lock_first
3378 ompt_callbacks.ompt_callback(ompt_callback_mutex_acquired)(
3379 ompt_mutex_test_nest_lock, (ompt_wait_id_t)(uintptr_t)user_lock,
3380 codeptr);
3381 }
3382 } else {
3383 if (ompt_enabled.ompt_callback_nest_lock) {
3384 // lock_next
3385 ompt_callbacks.ompt_callback(ompt_callback_nest_lock)(
3386 ompt_scope_begin, (ompt_wait_id_t)(uintptr_t)user_lock, codeptr);
3387 }
3388 }
3389 }
3390#endif
3391 return rc;
3392
3393#else // KMP_USE_DYNAMIC_LOCK
3394
3396 int rc;
3397
3398 if ((__kmp_user_lock_kind == lk_tas) &&
3399 (sizeof(lck->tas.lk.poll) + sizeof(lck->tas.lk.depth_locked) <=
3401 lck = (kmp_user_lock_p)user_lock;
3402 }
3403#if KMP_USE_FUTEX
3404 else if ((__kmp_user_lock_kind == lk_futex) &&
3405 (sizeof(lck->futex.lk.poll) + sizeof(lck->futex.lk.depth_locked) <=
3407 lck = (kmp_user_lock_p)user_lock;
3408 }
3409#endif
3410 else {
3411 lck = __kmp_lookup_user_lock(user_lock, "omp_test_nest_lock");
3412 }
3413
3414#if USE_ITT_BUILD
3415 __kmp_itt_lock_acquiring(lck);
3416#endif /* USE_ITT_BUILD */
3417
3418#if OMPT_SUPPORT && OMPT_OPTIONAL
3419 // This is the case, if called from omp_init_lock_with_hint:
3420 void *codeptr = OMPT_LOAD_RETURN_ADDRESS(gtid);
3421 if (!codeptr)
3422 codeptr = OMPT_GET_RETURN_ADDRESS(0);
3423 if (ompt_enabled.enabled) &&
3424 ompt_enabled.ompt_callback_mutex_acquire) {
3425 ompt_callbacks.ompt_callback(ompt_callback_mutex_acquire)(
3426 ompt_mutex_test_nest_lock, omp_lock_hint_none,
3427 __ompt_get_mutex_impl_type(), (ompt_wait_id_t)(uintptr_t)lck,
3428 codeptr);
3429 }
3430#endif
3431
3432 rc = TEST_NESTED_LOCK(lck, gtid);
3433#if USE_ITT_BUILD
3434 if (rc) {
3435 __kmp_itt_lock_acquired(lck);
3436 } else {
3437 __kmp_itt_lock_cancelled(lck);
3438 }
3439#endif /* USE_ITT_BUILD */
3440#if OMPT_SUPPORT && OMPT_OPTIONAL
3441 if (ompt_enabled.enabled && rc) {
3442 if (rc == 1) {
3443 if (ompt_enabled.ompt_callback_mutex_acquired) {
3444 // lock_first
3445 ompt_callbacks.ompt_callback(ompt_callback_mutex_acquired)(
3446 ompt_mutex_test_nest_lock, (ompt_wait_id_t)(uintptr_t)lck, codeptr);
3447 }
3448 } else {
3449 if (ompt_enabled.ompt_callback_nest_lock) {
3450 // lock_next
3451 ompt_callbacks.ompt_callback(ompt_callback_nest_lock)(
3452 ompt_mutex_scope_begin, (ompt_wait_id_t)(uintptr_t)lck, codeptr);
3453 }
3454 }
3455 }
3456#endif
3457 return rc;
3458
3459 /* Can't use serial interval since not block structured */
3460
3461#endif // KMP_USE_DYNAMIC_LOCK
3462}
3463
3464// Interface to fast scalable reduce methods routines
3465
3466// keep the selected method in a thread local structure for cross-function
3467// usage: will be used in __kmpc_end_reduce* functions;
3468// another solution: to re-determine the method one more time in
3469// __kmpc_end_reduce* functions (new prototype required then)
3470// AT: which solution is better?
3471#define __KMP_SET_REDUCTION_METHOD(gtid, rmethod) \
3472 ((__kmp_threads[(gtid)]->th.th_local.packed_reduction_method) = (rmethod))
3473
3474#define __KMP_GET_REDUCTION_METHOD(gtid) \
3475 (__kmp_threads[(gtid)]->th.th_local.packed_reduction_method)
3476
3477// description of the packed_reduction_method variable: look at the macros in
3478// kmp.h
3479
3480// used in a critical section reduce block
3481static __forceinline void
3484
3485 // this lock was visible to a customer and to the threading profile tool as a
3486 // serial overhead span (although it's used for an internal purpose only)
3487 // why was it visible in previous implementation?
3488 // should we keep it visible in new reduce block?
3490
3491#if KMP_USE_DYNAMIC_LOCK
3492
3493 kmp_dyna_lock_t *lk = (kmp_dyna_lock_t *)crit;
3494 // Check if it is initialized.
3495 if (*lk == 0) {
3496 if (KMP_IS_D_LOCK(__kmp_user_lock_seq)) {
3498 KMP_GET_D_TAG(__kmp_user_lock_seq));
3499 } else {
3500 __kmp_init_indirect_csptr(crit, loc, global_tid,
3501 KMP_GET_I_TAG(__kmp_user_lock_seq));
3502 }
3503 }
3504 // Branch for accessing the actual lock object and set operation. This
3505 // branching is inevitable since this lock initialization does not follow the
3506 // normal dispatch path (lock table is not used).
3507 if (KMP_EXTRACT_D_TAG(lk) != 0) {
3508 lck = (kmp_user_lock_p)lk;
3509 KMP_DEBUG_ASSERT(lck != NULL);
3511 __kmp_push_sync(global_tid, ct_critical, loc, lck, __kmp_user_lock_seq);
3512 }
3513 KMP_D_LOCK_FUNC(lk, set)(lk, global_tid);
3514 } else {
3515 kmp_indirect_lock_t *ilk = *((kmp_indirect_lock_t **)lk);
3516 lck = ilk->lock;
3517 KMP_DEBUG_ASSERT(lck != NULL);
3519 __kmp_push_sync(global_tid, ct_critical, loc, lck, __kmp_user_lock_seq);
3520 }
3521 KMP_I_LOCK_FUNC(ilk, set)(lck, global_tid);
3522 }
3523
3524#else // KMP_USE_DYNAMIC_LOCK
3525
3526 // We know that the fast reduction code is only emitted by Intel compilers
3527 // with 32 byte critical sections. If there isn't enough space, then we
3528 // have to use a pointer.
3531 } else {
3533 }
3534 KMP_DEBUG_ASSERT(lck != NULL);
3535
3537 __kmp_push_sync(global_tid, ct_critical, loc, lck);
3538
3540
3541#endif // KMP_USE_DYNAMIC_LOCK
3542}
3543
3544// used in a critical section reduce block
3545static __forceinline void
3548
3550
3551#if KMP_USE_DYNAMIC_LOCK
3552
3553 if (KMP_IS_D_LOCK(__kmp_user_lock_seq)) {
3556 __kmp_pop_sync(global_tid, ct_critical, loc);
3557 KMP_D_LOCK_FUNC(lck, unset)((kmp_dyna_lock_t *)lck, global_tid);
3558 } else {
3559 kmp_indirect_lock_t *ilk =
3560 (kmp_indirect_lock_t *)TCR_PTR(*((kmp_indirect_lock_t **)crit));
3562 __kmp_pop_sync(global_tid, ct_critical, loc);
3563 KMP_I_LOCK_FUNC(ilk, unset)(ilk->lock, global_tid);
3564 }
3565
3566#else // KMP_USE_DYNAMIC_LOCK
3567
3568 // We know that the fast reduction code is only emitted by Intel compilers
3569 // with 32 byte critical sections. If there isn't enough space, then we have
3570 // to use a pointer.
3571 if (__kmp_base_user_lock_size > 32) {
3572 lck = *((kmp_user_lock_p *)crit);
3573 KMP_ASSERT(lck != NULL);
3574 } else {
3576 }
3577
3579 __kmp_pop_sync(global_tid, ct_critical, loc);
3580
3582
3583#endif // KMP_USE_DYNAMIC_LOCK
3584} // __kmp_end_critical_section_reduce_block
3585
3586static __forceinline int
3588 int *task_state) {
3589 kmp_team_t *team;
3590
3591 // Check if we are inside the teams construct?
3592 if (th->th.th_teams_microtask) {
3593 *team_p = team = th->th.th_team;
3594 if (team->t.t_level == th->th.th_teams_level) {
3595 // This is reduction at teams construct.
3596 KMP_DEBUG_ASSERT(!th->th.th_info.ds.ds_tid); // AC: check that tid == 0
3597 // Let's swap teams temporarily for the reduction.
3598 th->th.th_info.ds.ds_tid = team->t.t_master_tid;
3599 th->th.th_team = team->t.t_parent;
3600 th->th.th_team_nproc = th->th.th_team->t.t_nproc;
3601 th->th.th_task_team = th->th.th_team->t.t_task_team[0];
3602 *task_state = th->th.th_task_state;
3603 th->th.th_task_state = 0;
3604
3605 return 1;
3606 }
3607 }
3608 return 0;
3609}
3610
3611static __forceinline void
3613 // Restore thread structure swapped in __kmp_swap_teams_for_teams_reduction.
3614 th->th.th_info.ds.ds_tid = 0;
3615 th->th.th_team = team;
3616 th->th.th_team_nproc = team->t.t_nproc;
3617 th->th.th_task_team = team->t.t_task_team[task_state];
3618 __kmp_type_convert(task_state, &(th->th.th_task_state));
3619}
3620
3621/* 2.a.i. Reduce Block without a terminating barrier */
3622/*!
3623@ingroup SYNCHRONIZATION
3624@param loc source location information
3625@param global_tid global thread number
3626@param num_vars number of items (variables) to be reduced
3627@param reduce_size size of data in bytes to be reduced
3628@param reduce_data pointer to data to be reduced
3629@param reduce_func callback function providing reduction operation on two
3630operands and returning result of reduction in lhs_data
3631@param lck pointer to the unique lock data structure
3632@result 1 for the primary thread, 0 for all other team threads, 2 for all team
3633threads if atomic reduction needed
3634
3635The nowait version is used for a reduce clause with the nowait argument.
3636*/
3639 size_t reduce_size, void *reduce_data,
3640 void (*reduce_func)(void *lhs_data, void *rhs_data),
3642
3643 KMP_COUNT_BLOCK(REDUCE_nowait);
3644 int retval = 0;
3645 PACKED_REDUCTION_METHOD_T packed_reduction_method;
3646 kmp_info_t *th;
3647 kmp_team_t *team;
3648 int teams_swapped = 0, task_state;
3649 KA_TRACE(10, ("__kmpc_reduce_nowait() enter: called T#%d\n", global_tid));
3650 __kmp_assert_valid_gtid(global_tid);
3651
3652 // why do we need this initialization here at all?
3653 // Reduction clause can not be used as a stand-alone directive.
3654
3655 // do not call __kmp_serial_initialize(), it will be called by
3656 // __kmp_parallel_initialize() if needed
3657 // possible detection of false-positive race by the threadchecker ???
3660
3662
3663// check correctness of reduce block nesting
3664#if KMP_USE_DYNAMIC_LOCK
3666 __kmp_push_sync(global_tid, ct_reduce, loc, NULL, 0);
3667#else
3669 __kmp_push_sync(global_tid, ct_reduce, loc, NULL);
3670#endif
3671
3672 th = __kmp_thread_from_gtid(global_tid);
3673 teams_swapped = __kmp_swap_teams_for_teams_reduction(th, &team, &task_state);
3674
3675 // packed_reduction_method value will be reused by __kmp_end_reduce* function,
3676 // the value should be kept in a variable
3677 // the variable should be either a construct-specific or thread-specific
3678 // property, not a team specific property
3679 // (a thread can reach the next reduce block on the next construct, reduce
3680 // method may differ on the next construct)
3681 // an ident_t "loc" parameter could be used as a construct-specific property
3682 // (what if loc == 0?)
3683 // (if both construct-specific and team-specific variables were shared,
3684 // then unness extra syncs should be needed)
3685 // a thread-specific variable is better regarding two issues above (next
3686 // construct and extra syncs)
3687 // a thread-specific "th_local.reduction_method" variable is used currently
3688 // each thread executes 'determine' and 'set' lines (no need to execute by one
3689 // thread, to avoid unness extra syncs)
3690
3691 packed_reduction_method = __kmp_determine_reduction_method(
3692 loc, global_tid, num_vars, reduce_size, reduce_data, reduce_func, lck);
3693 __KMP_SET_REDUCTION_METHOD(global_tid, packed_reduction_method);
3694
3695 OMPT_REDUCTION_DECL(th, global_tid);
3696 if (packed_reduction_method == critical_reduce_block) {
3697
3699
3701 retval = 1;
3702
3703 } else if (packed_reduction_method == empty_reduce_block) {
3704
3706
3707 // usage: if team size == 1, no synchronization is required ( Intel
3708 // platforms only )
3709 retval = 1;
3710
3711 } else if (packed_reduction_method == atomic_reduce_block) {
3712
3713 retval = 2;
3714
3715 // all threads should do this pop here (because __kmpc_end_reduce_nowait()
3716 // won't be called by the code gen)
3717 // (it's not quite good, because the checking block has been closed by
3718 // this 'pop',
3719 // but atomic operation has not been executed yet, will be executed
3720 // slightly later, literally on next instruction)
3722 __kmp_pop_sync(global_tid, ct_reduce, loc);
3723
3724 } else if (TEST_REDUCTION_METHOD(packed_reduction_method,
3726
3727// AT: performance issue: a real barrier here
3728// AT: (if primary thread is slow, other threads are blocked here waiting for
3729// the primary thread to come and release them)
3730// AT: (it's not what a customer might expect specifying NOWAIT clause)
3731// AT: (specifying NOWAIT won't result in improvement of performance, it'll
3732// be confusing to a customer)
3733// AT: another implementation of *barrier_gather*nowait() (or some other design)
3734// might go faster and be more in line with sense of NOWAIT
3735// AT: TO DO: do epcc test and compare times
3736
3737// this barrier should be invisible to a customer and to the threading profile
3738// tool (it's neither a terminating barrier nor customer's code, it's
3739// used for an internal purpose)
3740#if OMPT_SUPPORT
3741 // JP: can this barrier potentially leed to task scheduling?
3742 // JP: as long as there is a barrier in the implementation, OMPT should and
3743 // will provide the barrier events
3744 // so we set-up the necessary frame/return addresses.
3745 ompt_frame_t *ompt_frame;
3746 if (ompt_enabled.enabled) {
3747 __ompt_get_task_info_internal(0, NULL, NULL, &ompt_frame, NULL, NULL);
3748 if (ompt_frame->enter_frame.ptr == NULL)
3749 ompt_frame->enter_frame.ptr = OMPT_GET_FRAME_ADDRESS(0);
3750 }
3751 OMPT_STORE_RETURN_ADDRESS(global_tid);
3752#endif
3753#if USE_ITT_NOTIFY
3754 __kmp_threads[global_tid]->th.th_ident = loc;
3755#endif
3756 retval =
3757 __kmp_barrier(UNPACK_REDUCTION_BARRIER(packed_reduction_method),
3758 global_tid, FALSE, reduce_size, reduce_data, reduce_func);
3759 retval = (retval != 0) ? (0) : (1);
3760#if OMPT_SUPPORT && OMPT_OPTIONAL
3761 if (ompt_enabled.enabled) {
3762 ompt_frame->enter_frame = ompt_data_none;
3763 }
3764#endif
3765
3766 // all other workers except primary thread should do this pop here
3767 // ( none of other workers will get to __kmpc_end_reduce_nowait() )
3769 if (retval == 0) {
3770 __kmp_pop_sync(global_tid, ct_reduce, loc);
3771 }
3772 }
3773
3774 } else {
3775
3776 // should never reach this block
3777 KMP_ASSERT(0); // "unexpected method"
3778 }
3779 if (teams_swapped) {
3780 __kmp_restore_swapped_teams(th, team, task_state);
3781 }
3782 KA_TRACE(
3783 10,
3784 ("__kmpc_reduce_nowait() exit: called T#%d: method %08x, returns %08x\n",
3785 global_tid, packed_reduction_method, retval));
3786
3787 return retval;
3788}
3789
3790/*!
3791@ingroup SYNCHRONIZATION
3792@param loc source location information
3793@param global_tid global thread id.
3794@param lck pointer to the unique lock data structure
3795
3796Finish the execution of a reduce nowait.
3797*/
3800
3801 PACKED_REDUCTION_METHOD_T packed_reduction_method;
3802
3803 KA_TRACE(10, ("__kmpc_end_reduce_nowait() enter: called T#%d\n", global_tid));
3804 __kmp_assert_valid_gtid(global_tid);
3805
3806 packed_reduction_method = __KMP_GET_REDUCTION_METHOD(global_tid);
3807
3808 OMPT_REDUCTION_DECL(__kmp_thread_from_gtid(global_tid), global_tid);
3809
3810 if (packed_reduction_method == critical_reduce_block) {
3811
3814
3815 } else if (packed_reduction_method == empty_reduce_block) {
3816
3817 // usage: if team size == 1, no synchronization is required ( on Intel
3818 // platforms only )
3819
3821
3822 } else if (packed_reduction_method == atomic_reduce_block) {
3823
3824 // neither primary thread nor other workers should get here
3825 // (code gen does not generate this call in case 2: atomic reduce block)
3826 // actually it's better to remove this elseif at all;
3827 // after removal this value will checked by the 'else' and will assert
3828
3829 } else if (TEST_REDUCTION_METHOD(packed_reduction_method,
3831
3832 // only primary thread gets here
3833 // OMPT: tree reduction is annotated in the barrier code
3834
3835 } else {
3836
3837 // should never reach this block
3838 KMP_ASSERT(0); // "unexpected method"
3839 }
3840
3842 __kmp_pop_sync(global_tid, ct_reduce, loc);
3843
3844 KA_TRACE(10, ("__kmpc_end_reduce_nowait() exit: called T#%d: method %08x\n",
3845 global_tid, packed_reduction_method));
3846
3847 return;
3848}
3849
3850/* 2.a.ii. Reduce Block with a terminating barrier */
3851
3852/*!
3853@ingroup SYNCHRONIZATION
3854@param loc source location information
3855@param global_tid global thread number
3856@param num_vars number of items (variables) to be reduced
3857@param reduce_size size of data in bytes to be reduced
3858@param reduce_data pointer to data to be reduced
3859@param reduce_func callback function providing reduction operation on two
3860operands and returning result of reduction in lhs_data
3861@param lck pointer to the unique lock data structure
3862@result 1 for the primary thread, 0 for all other team threads, 2 for all team
3863threads if atomic reduction needed
3864
3865A blocking reduce that includes an implicit barrier.
3866*/
3868 size_t reduce_size, void *reduce_data,
3869 void (*reduce_func)(void *lhs_data, void *rhs_data),
3871 KMP_COUNT_BLOCK(REDUCE_wait);
3872 int retval = 0;
3873 PACKED_REDUCTION_METHOD_T packed_reduction_method;
3874 kmp_info_t *th;
3875 kmp_team_t *team;
3876 int teams_swapped = 0, task_state;
3877
3878 KA_TRACE(10, ("__kmpc_reduce() enter: called T#%d\n", global_tid));
3879 __kmp_assert_valid_gtid(global_tid);
3880
3881 // why do we need this initialization here at all?
3882 // Reduction clause can not be a stand-alone directive.
3883
3884 // do not call __kmp_serial_initialize(), it will be called by
3885 // __kmp_parallel_initialize() if needed
3886 // possible detection of false-positive race by the threadchecker ???
3889
3891
3892// check correctness of reduce block nesting
3893#if KMP_USE_DYNAMIC_LOCK
3895 __kmp_push_sync(global_tid, ct_reduce, loc, NULL, 0);
3896#else
3898 __kmp_push_sync(global_tid, ct_reduce, loc, NULL);
3899#endif
3900
3901 th = __kmp_thread_from_gtid(global_tid);
3902 teams_swapped = __kmp_swap_teams_for_teams_reduction(th, &team, &task_state);
3903
3904 packed_reduction_method = __kmp_determine_reduction_method(
3905 loc, global_tid, num_vars, reduce_size, reduce_data, reduce_func, lck);
3906 __KMP_SET_REDUCTION_METHOD(global_tid, packed_reduction_method);
3907
3908 OMPT_REDUCTION_DECL(th, global_tid);
3909
3910 if (packed_reduction_method == critical_reduce_block) {
3911
3914 retval = 1;
3915
3916 } else if (packed_reduction_method == empty_reduce_block) {
3917
3919 // usage: if team size == 1, no synchronization is required ( Intel
3920 // platforms only )
3921 retval = 1;
3922
3923 } else if (packed_reduction_method == atomic_reduce_block) {
3924
3925 retval = 2;
3926
3927 } else if (TEST_REDUCTION_METHOD(packed_reduction_method,
3929
3930// case tree_reduce_block:
3931// this barrier should be visible to a customer and to the threading profile
3932// tool (it's a terminating barrier on constructs if NOWAIT not specified)
3933#if OMPT_SUPPORT
3934 ompt_frame_t *ompt_frame;
3935 if (ompt_enabled.enabled) {
3936 __ompt_get_task_info_internal(0, NULL, NULL, &ompt_frame, NULL, NULL);
3937 if (ompt_frame->enter_frame.ptr == NULL)
3938 ompt_frame->enter_frame.ptr = OMPT_GET_FRAME_ADDRESS(0);
3939 }
3940 OMPT_STORE_RETURN_ADDRESS(global_tid);
3941#endif
3942#if USE_ITT_NOTIFY
3943 __kmp_threads[global_tid]->th.th_ident =
3944 loc; // needed for correct notification of frames
3945#endif
3946 retval =
3947 __kmp_barrier(UNPACK_REDUCTION_BARRIER(packed_reduction_method),
3948 global_tid, TRUE, reduce_size, reduce_data, reduce_func);
3949 retval = (retval != 0) ? (0) : (1);
3950#if OMPT_SUPPORT && OMPT_OPTIONAL
3951 if (ompt_enabled.enabled) {
3952 ompt_frame->enter_frame = ompt_data_none;
3953 }
3954#endif
3955
3956 // all other workers except primary thread should do this pop here
3957 // (none of other workers except primary will enter __kmpc_end_reduce())
3959 if (retval == 0) { // 0: all other workers; 1: primary thread
3960 __kmp_pop_sync(global_tid, ct_reduce, loc);
3961 }
3962 }
3963
3964 } else {
3965
3966 // should never reach this block
3967 KMP_ASSERT(0); // "unexpected method"
3968 }
3969 if (teams_swapped) {
3970 __kmp_restore_swapped_teams(th, team, task_state);
3971 }
3972
3973 KA_TRACE(10,
3974 ("__kmpc_reduce() exit: called T#%d: method %08x, returns %08x\n",
3975 global_tid, packed_reduction_method, retval));
3976 return retval;
3977}
3978
3979/*!
3980@ingroup SYNCHRONIZATION
3981@param loc source location information
3982@param global_tid global thread id.
3983@param lck pointer to the unique lock data structure
3984
3985Finish the execution of a blocking reduce.
3986The <tt>lck</tt> pointer must be the same as that used in the corresponding
3987start function.
3988*/
3991
3992 PACKED_REDUCTION_METHOD_T packed_reduction_method;
3993 kmp_info_t *th;
3994 kmp_team_t *team;
3995 int teams_swapped = 0, task_state;
3996
3997 KA_TRACE(10, ("__kmpc_end_reduce() enter: called T#%d\n", global_tid));
3998 __kmp_assert_valid_gtid(global_tid);
3999
4000 th = __kmp_thread_from_gtid(global_tid);
4001 teams_swapped = __kmp_swap_teams_for_teams_reduction(th, &team, &task_state);
4002
4003 packed_reduction_method = __KMP_GET_REDUCTION_METHOD(global_tid);
4004
4005 // this barrier should be visible to a customer and to the threading profile
4006 // tool (it's a terminating barrier on constructs if NOWAIT not specified)
4007 OMPT_REDUCTION_DECL(th, global_tid);
4008
4009 if (packed_reduction_method == critical_reduce_block) {
4011
4013
4014// TODO: implicit barrier: should be exposed
4015#if OMPT_SUPPORT
4016 ompt_frame_t *ompt_frame;
4017 if (ompt_enabled.enabled) {
4018 __ompt_get_task_info_internal(0, NULL, NULL, &ompt_frame, NULL, NULL);
4019 if (ompt_frame->enter_frame.ptr == NULL)
4020 ompt_frame->enter_frame.ptr = OMPT_GET_FRAME_ADDRESS(0);
4021 }
4022 OMPT_STORE_RETURN_ADDRESS(global_tid);
4023#endif
4024#if USE_ITT_NOTIFY
4025 __kmp_threads[global_tid]->th.th_ident = loc;
4026#endif
4027 __kmp_barrier(bs_plain_barrier, global_tid, FALSE, 0, NULL, NULL);
4028#if OMPT_SUPPORT && OMPT_OPTIONAL
4029 if (ompt_enabled.enabled) {
4030 ompt_frame->enter_frame = ompt_data_none;
4031 }
4032#endif
4033
4034 } else if (packed_reduction_method == empty_reduce_block) {
4035
4037
4038// usage: if team size==1, no synchronization is required (Intel platforms only)
4039
4040// TODO: implicit barrier: should be exposed
4041#if OMPT_SUPPORT
4042 ompt_frame_t *ompt_frame;
4043 if (ompt_enabled.enabled) {
4044 __ompt_get_task_info_internal(0, NULL, NULL, &ompt_frame, NULL, NULL);
4045 if (ompt_frame->enter_frame.ptr == NULL)
4046 ompt_frame->enter_frame.ptr = OMPT_GET_FRAME_ADDRESS(0);
4047 }
4048 OMPT_STORE_RETURN_ADDRESS(global_tid);
4049#endif
4050#if USE_ITT_NOTIFY
4051 __kmp_threads[global_tid]->th.th_ident = loc;
4052#endif
4053 __kmp_barrier(bs_plain_barrier, global_tid, FALSE, 0, NULL, NULL);
4054#if OMPT_SUPPORT && OMPT_OPTIONAL
4055 if (ompt_enabled.enabled) {
4056 ompt_frame->enter_frame = ompt_data_none;
4057 }
4058#endif
4059
4060 } else if (packed_reduction_method == atomic_reduce_block) {
4061
4062#if OMPT_SUPPORT
4063 ompt_frame_t *ompt_frame;
4064 if (ompt_enabled.enabled) {
4065 __ompt_get_task_info_internal(0, NULL, NULL, &ompt_frame, NULL, NULL);
4066 if (ompt_frame->enter_frame.ptr == NULL)
4067 ompt_frame->enter_frame.ptr = OMPT_GET_FRAME_ADDRESS(0);
4068 }
4069 OMPT_STORE_RETURN_ADDRESS(global_tid);
4070#endif
4071// TODO: implicit barrier: should be exposed
4072#if USE_ITT_NOTIFY
4073 __kmp_threads[global_tid]->th.th_ident = loc;
4074#endif
4075 __kmp_barrier(bs_plain_barrier, global_tid, FALSE, 0, NULL, NULL);
4076#if OMPT_SUPPORT && OMPT_OPTIONAL
4077 if (ompt_enabled.enabled) {
4078 ompt_frame->enter_frame = ompt_data_none;
4079 }
4080#endif
4081
4082 } else if (TEST_REDUCTION_METHOD(packed_reduction_method,
4084
4085 // only primary thread executes here (primary releases all other workers)
4086 __kmp_end_split_barrier(UNPACK_REDUCTION_BARRIER(packed_reduction_method),
4087 global_tid);
4088
4089 } else {
4090
4091 // should never reach this block
4092 KMP_ASSERT(0); // "unexpected method"
4093 }
4094 if (teams_swapped) {
4095 __kmp_restore_swapped_teams(th, team, task_state);
4096 }
4097
4099 __kmp_pop_sync(global_tid, ct_reduce, loc);
4100
4101 KA_TRACE(10, ("__kmpc_end_reduce() exit: called T#%d: method %08x\n",
4102 global_tid, packed_reduction_method));
4103
4104 return;
4105}
4106
4107#undef __KMP_GET_REDUCTION_METHOD
4108#undef __KMP_SET_REDUCTION_METHOD
4109
4110/* end of interface to fast scalable reduce routines */
4111
4113
4114 kmp_int32 gtid;
4115 kmp_info_t *thread;
4116
4117 gtid = __kmp_get_gtid();
4118 if (gtid < 0) {
4119 return 0;
4120 }
4121 thread = __kmp_thread_from_gtid(gtid);
4122 return thread->th.th_current_task->td_task_id;
4123
4124} // __kmpc_get_taskid
4125
4127
4128 kmp_int32 gtid;
4129 kmp_info_t *thread;
4130 kmp_taskdata_t *parent_task;
4131
4132 gtid = __kmp_get_gtid();
4133 if (gtid < 0) {
4134 return 0;
4135 }
4136 thread = __kmp_thread_from_gtid(gtid);
4137 parent_task = thread->th.th_current_task->td_parent;
4138 return (parent_task == NULL ? 0 : parent_task->td_task_id);
4139
4140} // __kmpc_get_parent_taskid
4141
4142/*!
4143@ingroup WORK_SHARING
4144@param loc source location information.
4145@param gtid global thread number.
4146@param num_dims number of associated doacross loops.
4147@param dims info on loops bounds.
4148
4149Initialize doacross loop information.
4150Expect compiler send us inclusive bounds,
4151e.g. for(i=2;i<9;i+=2) lo=2, up=8, st=2.
4152*/
4153void __kmpc_doacross_init(ident_t *loc, int gtid, int num_dims,
4154 const struct kmp_dim *dims) {
4156 int j, idx;
4157 kmp_int64 last, trace_count;
4158 kmp_info_t *th = __kmp_threads[gtid];
4159 kmp_team_t *team = th->th.th_team;
4160 kmp_uint32 *flags;
4161 kmp_disp_t *pr_buf = th->th.th_dispatch;
4162 dispatch_shared_info_t *sh_buf;
4163
4164 KA_TRACE(
4165 20,
4166 ("__kmpc_doacross_init() enter: called T#%d, num dims %d, active %d\n",
4167 gtid, num_dims, !team->t.t_serialized));
4168 KMP_DEBUG_ASSERT(dims != NULL);
4169 KMP_DEBUG_ASSERT(num_dims > 0);
4170
4171 if (team->t.t_serialized) {
4172 KA_TRACE(20, ("__kmpc_doacross_init() exit: serialized team\n"));
4173 return; // no dependencies if team is serialized
4174 }
4175 KMP_DEBUG_ASSERT(team->t.t_nproc > 1);
4176 idx = pr_buf->th_doacross_buf_idx++; // Increment index of shared buffer for
4177 // the next loop
4178 sh_buf = &team->t.t_disp_buffer[idx % __kmp_dispatch_num_buffers];
4179
4180 // Save bounds info into allocated private buffer
4181 KMP_DEBUG_ASSERT(pr_buf->th_doacross_info == NULL);
4183 th, sizeof(kmp_int64) * (4 * num_dims + 1));
4184 KMP_DEBUG_ASSERT(pr_buf->th_doacross_info != NULL);
4185 pr_buf->th_doacross_info[0] =
4186 (kmp_int64)num_dims; // first element is number of dimensions
4187 // Save also address of num_done in order to access it later without knowing
4188 // the buffer index
4189 pr_buf->th_doacross_info[1] = (kmp_int64)&sh_buf->doacross_num_done;
4190 pr_buf->th_doacross_info[2] = dims[0].lo;
4191 pr_buf->th_doacross_info[3] = dims[0].up;
4192 pr_buf->th_doacross_info[4] = dims[0].st;
4193 last = 5;
4194 for (j = 1; j < num_dims; ++j) {
4195 kmp_int64
4196 range_length; // To keep ranges of all dimensions but the first dims[0]
4197 if (dims[j].st == 1) { // most common case
4198 // AC: should we care of ranges bigger than LLONG_MAX? (not for now)
4199 range_length = dims[j].up - dims[j].lo + 1;
4200 } else {
4201 if (dims[j].st > 0) {
4202 KMP_DEBUG_ASSERT(dims[j].up > dims[j].lo);
4203 range_length = (kmp_uint64)(dims[j].up - dims[j].lo) / dims[j].st + 1;
4204 } else { // negative increment
4205 KMP_DEBUG_ASSERT(dims[j].lo > dims[j].up);
4206 range_length =
4207 (kmp_uint64)(dims[j].lo - dims[j].up) / (-dims[j].st) + 1;
4208 }
4209 }
4210 pr_buf->th_doacross_info[last++] = range_length;
4211 pr_buf->th_doacross_info[last++] = dims[j].lo;
4212 pr_buf->th_doacross_info[last++] = dims[j].up;
4213 pr_buf->th_doacross_info[last++] = dims[j].st;
4214 }
4215
4216 // Compute total trip count.
4217 // Start with range of dims[0] which we don't need to keep in the buffer.
4218 if (dims[0].st == 1) { // most common case
4219 trace_count = dims[0].up - dims[0].lo + 1;
4220 } else if (dims[0].st > 0) {
4221 KMP_DEBUG_ASSERT(dims[0].up > dims[0].lo);
4222 trace_count = (kmp_uint64)(dims[0].up - dims[0].lo) / dims[0].st + 1;
4223 } else { // negative increment
4224 KMP_DEBUG_ASSERT(dims[0].lo > dims[0].up);
4225 trace_count = (kmp_uint64)(dims[0].lo - dims[0].up) / (-dims[0].st) + 1;
4226 }
4227 for (j = 1; j < num_dims; ++j) {
4228 trace_count *= pr_buf->th_doacross_info[4 * j + 1]; // use kept ranges
4229 }
4230 KMP_DEBUG_ASSERT(trace_count > 0);
4231
4232 // Check if shared buffer is not occupied by other loop (idx -
4233 // __kmp_dispatch_num_buffers)
4234 if (idx != sh_buf->doacross_buf_idx) {
4235 // Shared buffer is occupied, wait for it to be free
4236 __kmp_wait_4((volatile kmp_uint32 *)&sh_buf->doacross_buf_idx, idx,
4237 __kmp_eq_4, NULL);
4238 }
4239#if KMP_32_BIT_ARCH
4240 // Check if we are the first thread. After the CAS the first thread gets 0,
4241 // others get 1 if initialization is in progress, allocated pointer otherwise.
4242 // Treat pointer as volatile integer (value 0 or 1) until memory is allocated.
4244 (volatile kmp_int32 *)&sh_buf->doacross_flags, NULL, 1);
4245#else
4247 (volatile kmp_int64 *)&sh_buf->doacross_flags, NULL, 1LL);
4248#endif
4249 if (flags == NULL) {
4250 // we are the first thread, allocate the array of flags
4251 size_t size =
4252 (size_t)trace_count / 8 + 8; // in bytes, use single bit per iteration
4253 flags = (kmp_uint32 *)__kmp_thread_calloc(th, size, 1);
4254 KMP_MB();
4255 sh_buf->doacross_flags = flags;
4256 } else if (flags == (kmp_uint32 *)1) {
4257#if KMP_32_BIT_ARCH
4258 // initialization is still in progress, need to wait
4259 while (*(volatile kmp_int32 *)&sh_buf->doacross_flags == 1)
4260#else
4261 while (*(volatile kmp_int64 *)&sh_buf->doacross_flags == 1LL)
4262#endif
4263 KMP_YIELD(TRUE);
4264 KMP_MB();
4265 } else {
4266 KMP_MB();
4267 }
4268 KMP_DEBUG_ASSERT(sh_buf->doacross_flags > (kmp_uint32 *)1); // check ptr value
4269 pr_buf->th_doacross_flags =
4270 sh_buf->doacross_flags; // save private copy in order to not
4271 // touch shared buffer on each iteration
4272 KA_TRACE(20, ("__kmpc_doacross_init() exit: T#%d\n", gtid));
4273}
4274
4275void __kmpc_doacross_wait(ident_t *loc, int gtid, const kmp_int64 *vec) {
4277 kmp_int64 shft;
4278 size_t num_dims, i;
4280 kmp_int64 iter_number; // iteration number of "collapsed" loop nest
4281 kmp_info_t *th = __kmp_threads[gtid];
4282 kmp_team_t *team = th->th.th_team;
4283 kmp_disp_t *pr_buf;
4284 kmp_int64 lo, up, st;
4285
4286 KA_TRACE(20, ("__kmpc_doacross_wait() enter: called T#%d\n", gtid));
4287 if (team->t.t_serialized) {
4288 KA_TRACE(20, ("__kmpc_doacross_wait() exit: serialized team\n"));
4289 return; // no dependencies if team is serialized
4290 }
4291
4292 // calculate sequential iteration number and check out-of-bounds condition
4293 pr_buf = th->th.th_dispatch;
4294 KMP_DEBUG_ASSERT(pr_buf->th_doacross_info != NULL);
4295 num_dims = (size_t)pr_buf->th_doacross_info[0];
4296 lo = pr_buf->th_doacross_info[2];
4297 up = pr_buf->th_doacross_info[3];
4298 st = pr_buf->th_doacross_info[4];
4299#if OMPT_SUPPORT && OMPT_OPTIONAL
4300 SimpleVLA<ompt_dependence_t> deps(num_dims);
4301#endif
4302 if (st == 1) { // most common case
4303 if (vec[0] < lo || vec[0] > up) {
4304 KA_TRACE(20, ("__kmpc_doacross_wait() exit: T#%d iter %lld is out of "
4305 "bounds [%lld,%lld]\n",
4306 gtid, vec[0], lo, up));
4307 return;
4308 }
4309 iter_number = vec[0] - lo;
4310 } else if (st > 0) {
4311 if (vec[0] < lo || vec[0] > up) {
4312 KA_TRACE(20, ("__kmpc_doacross_wait() exit: T#%d iter %lld is out of "
4313 "bounds [%lld,%lld]\n",
4314 gtid, vec[0], lo, up));
4315 return;
4316 }
4317 iter_number = (kmp_uint64)(vec[0] - lo) / st;
4318 } else { // negative increment
4319 if (vec[0] > lo || vec[0] < up) {
4320 KA_TRACE(20, ("__kmpc_doacross_wait() exit: T#%d iter %lld is out of "
4321 "bounds [%lld,%lld]\n",
4322 gtid, vec[0], lo, up));
4323 return;
4324 }
4325 iter_number = (kmp_uint64)(lo - vec[0]) / (-st);
4326 }
4327#if OMPT_SUPPORT && OMPT_OPTIONAL
4328 deps[0].variable.value = iter_number;
4329 deps[0].dependence_type = ompt_dependence_type_sink;
4330#endif
4331 for (i = 1; i < num_dims; ++i) {
4332 kmp_int64 iter, ln;
4333 size_t j = i * 4;
4334 ln = pr_buf->th_doacross_info[j + 1];
4335 lo = pr_buf->th_doacross_info[j + 2];
4336 up = pr_buf->th_doacross_info[j + 3];
4337 st = pr_buf->th_doacross_info[j + 4];
4338 if (st == 1) {
4339 if (vec[i] < lo || vec[i] > up) {
4340 KA_TRACE(20, ("__kmpc_doacross_wait() exit: T#%d iter %lld is out of "
4341 "bounds [%lld,%lld]\n",
4342 gtid, vec[i], lo, up));
4343 return;
4344 }
4345 iter = vec[i] - lo;
4346 } else if (st > 0) {
4347 if (vec[i] < lo || vec[i] > up) {
4348 KA_TRACE(20, ("__kmpc_doacross_wait() exit: T#%d iter %lld is out of "
4349 "bounds [%lld,%lld]\n",
4350 gtid, vec[i], lo, up));
4351 return;
4352 }
4353 iter = (kmp_uint64)(vec[i] - lo) / st;
4354 } else { // st < 0
4355 if (vec[i] > lo || vec[i] < up) {
4356 KA_TRACE(20, ("__kmpc_doacross_wait() exit: T#%d iter %lld is out of "
4357 "bounds [%lld,%lld]\n",
4358 gtid, vec[i], lo, up));
4359 return;
4360 }
4361 iter = (kmp_uint64)(lo - vec[i]) / (-st);
4362 }
4363 iter_number = iter + ln * iter_number;
4364#if OMPT_SUPPORT && OMPT_OPTIONAL
4365 deps[i].variable.value = iter;
4366 deps[i].dependence_type = ompt_dependence_type_sink;
4367#endif
4368 }
4369 shft = iter_number % 32; // use 32-bit granularity
4370 iter_number >>= 5; // divided by 32
4371 flag = 1 << shft;
4372 while ((flag & pr_buf->th_doacross_flags[iter_number]) == 0) {
4373 KMP_YIELD(TRUE);
4374 }
4375 KMP_MB();
4376#if OMPT_SUPPORT && OMPT_OPTIONAL
4377 if (ompt_enabled.ompt_callback_dependences) {
4378 ompt_callbacks.ompt_callback(ompt_callback_dependences)(
4379 &(OMPT_CUR_TASK_INFO(th)->task_data), deps, (kmp_uint32)num_dims);
4380 }
4381#endif
4382 KA_TRACE(20,
4383 ("__kmpc_doacross_wait() exit: T#%d wait for iter %lld completed\n",
4384 gtid, (iter_number << 5) + shft));
4385}
4386
4387void __kmpc_doacross_post(ident_t *loc, int gtid, const kmp_int64 *vec) {
4389 kmp_int64 shft;
4390 size_t num_dims, i;
4392 kmp_int64 iter_number; // iteration number of "collapsed" loop nest
4393 kmp_info_t *th = __kmp_threads[gtid];
4394 kmp_team_t *team = th->th.th_team;
4395 kmp_disp_t *pr_buf;
4396 kmp_int64 lo, st;
4397
4398 KA_TRACE(20, ("__kmpc_doacross_post() enter: called T#%d\n", gtid));
4399 if (team->t.t_serialized) {
4400 KA_TRACE(20, ("__kmpc_doacross_post() exit: serialized team\n"));
4401 return; // no dependencies if team is serialized
4402 }
4403
4404 // calculate sequential iteration number (same as in "wait" but no
4405 // out-of-bounds checks)
4406 pr_buf = th->th.th_dispatch;
4407 KMP_DEBUG_ASSERT(pr_buf->th_doacross_info != NULL);
4408 num_dims = (size_t)pr_buf->th_doacross_info[0];
4409 lo = pr_buf->th_doacross_info[2];
4410 st = pr_buf->th_doacross_info[4];
4411#if OMPT_SUPPORT && OMPT_OPTIONAL
4412 SimpleVLA<ompt_dependence_t> deps(num_dims);
4413#endif
4414 if (st == 1) { // most common case
4415 iter_number = vec[0] - lo;
4416 } else if (st > 0) {
4417 iter_number = (kmp_uint64)(vec[0] - lo) / st;
4418 } else { // negative increment
4419 iter_number = (kmp_uint64)(lo - vec[0]) / (-st);
4420 }
4421#if OMPT_SUPPORT && OMPT_OPTIONAL
4422 deps[0].variable.value = iter_number;
4423 deps[0].dependence_type = ompt_dependence_type_source;
4424#endif
4425 for (i = 1; i < num_dims; ++i) {
4426 kmp_int64 iter, ln;
4427 size_t j = i * 4;
4428 ln = pr_buf->th_doacross_info[j + 1];
4429 lo = pr_buf->th_doacross_info[j + 2];
4430 st = pr_buf->th_doacross_info[j + 4];
4431 if (st == 1) {
4432 iter = vec[i] - lo;
4433 } else if (st > 0) {
4434 iter = (kmp_uint64)(vec[i] - lo) / st;
4435 } else { // st < 0
4436 iter = (kmp_uint64)(lo - vec[i]) / (-st);
4437 }
4438 iter_number = iter + ln * iter_number;
4439#if OMPT_SUPPORT && OMPT_OPTIONAL
4440 deps[i].variable.value = iter;
4441 deps[i].dependence_type = ompt_dependence_type_source;
4442#endif
4443 }
4444#if OMPT_SUPPORT && OMPT_OPTIONAL
4445 if (ompt_enabled.ompt_callback_dependences) {
4446 ompt_callbacks.ompt_callback(ompt_callback_dependences)(
4447 &(OMPT_CUR_TASK_INFO(th)->task_data), deps, (kmp_uint32)num_dims);
4448 }
4449#endif
4450 shft = iter_number % 32; // use 32-bit granularity
4451 iter_number >>= 5; // divided by 32
4452 flag = 1 << shft;
4453 KMP_MB();
4454 if ((flag & pr_buf->th_doacross_flags[iter_number]) == 0)
4455 KMP_TEST_THEN_OR32(&pr_buf->th_doacross_flags[iter_number], flag);
4456 KA_TRACE(20, ("__kmpc_doacross_post() exit: T#%d iter %lld posted\n", gtid,
4457 (iter_number << 5) + shft));
4458}
4459
4462 kmp_int32 num_done;
4463 kmp_info_t *th = __kmp_threads[gtid];
4464 kmp_team_t *team = th->th.th_team;
4465 kmp_disp_t *pr_buf = th->th.th_dispatch;
4466
4467 KA_TRACE(20, ("__kmpc_doacross_fini() enter: called T#%d\n", gtid));
4468 if (team->t.t_serialized) {
4469 KA_TRACE(20, ("__kmpc_doacross_fini() exit: serialized team %p\n", team));
4470 return; // nothing to do
4471 }
4472 num_done =
4474 if (num_done == th->th.th_team_nproc) {
4475 // we are the last thread, need to free shared resources
4476 int idx = pr_buf->th_doacross_buf_idx - 1;
4477 dispatch_shared_info_t *sh_buf =
4478 &team->t.t_disp_buffer[idx % __kmp_dispatch_num_buffers];
4480 (kmp_int64)&sh_buf->doacross_num_done);
4481 KMP_DEBUG_ASSERT(num_done == sh_buf->doacross_num_done);
4482 KMP_DEBUG_ASSERT(idx == sh_buf->doacross_buf_idx);
4484 sh_buf->doacross_flags = NULL;
4485 sh_buf->doacross_num_done = 0;
4486 sh_buf->doacross_buf_idx +=
4487 __kmp_dispatch_num_buffers; // free buffer for future re-use
4488 }
4489 // free private resources (need to keep buffer index forever)
4490 pr_buf->th_doacross_flags = NULL;
4491 __kmp_thread_free(th, (void *)pr_buf->th_doacross_info);
4492 pr_buf->th_doacross_info = NULL;
4493 KA_TRACE(20, ("__kmpc_doacross_fini() exit: T#%d\n", gtid));
4494}
4495
4496/* OpenMP 5.1 Memory Management routines */
4497void *omp_alloc(size_t size, omp_allocator_handle_t allocator) {
4498 return __kmp_alloc(__kmp_entry_gtid(), 0, size, allocator);
4499}
4500
4501void *omp_aligned_alloc(size_t align, size_t size,
4502 omp_allocator_handle_t allocator) {
4503 return __kmp_alloc(__kmp_entry_gtid(), align, size, allocator);
4504}
4505
4506void *omp_calloc(size_t nmemb, size_t size, omp_allocator_handle_t allocator) {
4507 return __kmp_calloc(__kmp_entry_gtid(), 0, nmemb, size, allocator);
4508}
4509
4510void *omp_aligned_calloc(size_t align, size_t nmemb, size_t size,
4511 omp_allocator_handle_t allocator) {
4512 return __kmp_calloc(__kmp_entry_gtid(), align, nmemb, size, allocator);
4513}
4514
4515void *omp_realloc(void *ptr, size_t size, omp_allocator_handle_t allocator,
4516 omp_allocator_handle_t free_allocator) {
4517 return __kmp_realloc(__kmp_entry_gtid(), ptr, size, allocator,
4518 free_allocator);
4519}
4520
4521void omp_free(void *ptr, omp_allocator_handle_t allocator) {
4522 ___kmpc_free(__kmp_entry_gtid(), ptr, allocator);
4523}
4524/* end of OpenMP 5.1 Memory Management routines */
4525
4526void *omp_get_dyn_gprivate_ptr(size_t offset, omp_access_t access_group) {
4527 return NULL;
4528}
4529
4530void *omp_get_dyn_gprivate_nofb_ptr(size_t offset, omp_access_t access_group) {
4531 return NULL;
4532}
4533
4534size_t omp_get_dyn_gprivate_size(omp_access_t access_group) { return 0; }
4535
4537 return omp_null_mem_space;
4538}
4539
4541 if (!__kmp_init_serial) {
4543 }
4544 return __kmp_target_offload;
4545}
4546
4548 if (!__kmp_init_serial) {
4549 return 1; // Can't pause if runtime is not initialized
4550 }
4552}
4553
4554void __kmpc_error(ident_t *loc, int severity, const char *message) {
4555 if (!__kmp_init_serial)
4557
4558 KMP_ASSERT(severity == severity_warning || severity == severity_fatal);
4559
4560#if OMPT_SUPPORT
4561 if (ompt_enabled.enabled && ompt_enabled.ompt_callback_error) {
4562 ompt_callbacks.ompt_callback(ompt_callback_error)(
4563 (ompt_severity_t)severity, message, KMP_STRLEN(message),
4565 }
4566#endif // OMPT_SUPPORT
4567
4568 char *src_loc;
4569 if (loc && loc->psource) {
4570 kmp_str_loc_t str_loc = __kmp_str_loc_init(loc->psource, false);
4571 src_loc =
4572 __kmp_str_format("%s:%d:%d", str_loc.file, str_loc.line, str_loc.col);
4573 __kmp_str_loc_free(&str_loc);
4574 } else {
4575 src_loc = __kmp_str_format("unknown");
4576 }
4577
4578 if (severity == severity_warning)
4579 KMP_WARNING(UserDirectedWarning, src_loc, message);
4580 else
4581 KMP_FATAL(UserDirectedError, src_loc, message);
4582
4583 __kmp_str_free(&src_loc);
4584}
4585
4586// Mark begin of scope directive.
4587void __kmpc_scope(ident_t *loc, kmp_int32 gtid, void *reserved) {
4588// reserved is for extension of scope directive and not used.
4589#if OMPT_SUPPORT && OMPT_OPTIONAL
4590 if (ompt_enabled.enabled && ompt_enabled.ompt_callback_work) {
4591 kmp_team_t *team = __kmp_threads[gtid]->th.th_team;
4592 int tid = __kmp_tid_from_gtid(gtid);
4593 ompt_callbacks.ompt_callback(ompt_callback_work)(
4594 ompt_work_scope, ompt_scope_begin,
4595 &(team->t.ompt_team_info.parallel_data),
4596 &(team->t.t_implicit_task_taskdata[tid].ompt_task_info.task_data), 1,
4598 }
4599#endif // OMPT_SUPPORT && OMPT_OPTIONAL
4600}
4601
4602// Mark end of scope directive
4603void __kmpc_end_scope(ident_t *loc, kmp_int32 gtid, void *reserved) {
4604// reserved is for extension of scope directive and not used.
4605#if OMPT_SUPPORT && OMPT_OPTIONAL
4606 if (ompt_enabled.enabled && ompt_enabled.ompt_callback_work) {
4607 kmp_team_t *team = __kmp_threads[gtid]->th.th_team;
4608 int tid = __kmp_tid_from_gtid(gtid);
4609 ompt_callbacks.ompt_callback(ompt_callback_work)(
4610 ompt_work_scope, ompt_scope_end,
4611 &(team->t.ompt_team_info.parallel_data),
4612 &(team->t.t_implicit_task_taskdata[tid].ompt_task_info.task_data), 1,
4614 }
4615#endif // OMPT_SUPPORT && OMPT_OPTIONAL
4616}
4617
4618#ifdef KMP_USE_VERSION_SYMBOLS
4619// For GOMP compatibility there are two versions of each omp_* API.
4620// One is the plain C symbol and one is the Fortran symbol with an appended
4621// underscore. When we implement a specific ompc_* version of an omp_*
4622// function, we want the plain GOMP versioned symbol to alias the ompc_* version
4623// instead of the Fortran versions in kmp_ftn_entry.h
4624extern "C" {
4625// Have to undef these from omp.h so they aren't translated into
4626// their ompc counterparts in the KMP_VERSION_OMPC_SYMBOL macros below
4627#ifdef omp_set_affinity_format
4628#undef omp_set_affinity_format
4629#endif
4630#ifdef omp_get_affinity_format
4631#undef omp_get_affinity_format
4632#endif
4633#ifdef omp_display_affinity
4634#undef omp_display_affinity
4635#endif
4636#ifdef omp_capture_affinity
4637#undef omp_capture_affinity
4638#endif
4640 "OMP_5.0");
4642 "OMP_5.0");
4644 "OMP_5.0");
4646 "OMP_5.0");
4647} // extern "C"
4648#endif
uint8_t kmp_uint8
int test()
A simple pure header implementation of VLA that aims to replace uses of actual VLA,...
Definition kmp_utils.h:26
int64_t kmp_int64
Definition common.h:10
@ KMP_IDENT_WORK_LOOP
To mark a static loop in OMPT callbacks.
Definition kmp.h:197
@ KMP_IDENT_WORK_SECTIONS
To mark a sections directive in OMPT callbacks.
Definition kmp.h:199
@ KMP_IDENT_AUTOPAR
Entry point generated by auto-parallelization.
Definition kmp.h:182
@ KMP_IDENT_WORK_DISTRIBUTE
To mark a distribute construct in OMPT callbacks.
Definition kmp.h:201
kmp_int32 __kmpc_ok_to_fork(ident_t *loc)
void __kmpc_fork_teams(ident_t *loc, kmp_int32 argc, kmpc_micro microtask,...)
void __kmpc_fork_call_if(ident_t *loc, kmp_int32 argc, kmpc_micro microtask, kmp_int32 cond, void *args)
void __kmpc_push_num_threads(ident_t *loc, kmp_int32 global_tid, kmp_int32 num_threads)
void __kmpc_set_thread_limit(ident_t *loc, kmp_int32 global_tid, kmp_int32 thread_limit)
void __kmpc_serialized_parallel(ident_t *loc, kmp_int32 global_tid)
void __kmpc_push_num_threads_list(ident_t *loc, kmp_int32 global_tid, kmp_uint32 list_length, kmp_int32 *num_threads_list)
void __kmpc_push_num_teams(ident_t *loc, kmp_int32 global_tid, kmp_int32 num_teams, kmp_int32 num_threads)
void __kmpc_fork_call(ident_t *loc, kmp_int32 argc, kmpc_micro microtask,...)
void __kmpc_end_serialized_parallel(ident_t *loc, kmp_int32 global_tid)
void(* kmpc_micro)(kmp_int32 *global_tid, kmp_int32 *bound_tid,...)
The type for a microtask which gets passed to __kmpc_fork_call().
Definition kmp.h:1764
void __kmpc_push_num_teams_51(ident_t *loc, kmp_int32 global_tid, kmp_int32 num_teams_lb, kmp_int32 num_teams_ub, kmp_int32 num_threads)
void __kmpc_begin(ident_t *loc, kmp_int32 flags)
void __kmpc_end(ident_t *loc)
void __kmpc_end_reduce(ident_t *loc, kmp_int32 global_tid, kmp_critical_name *lck)
void __kmpc_end_barrier_master(ident_t *loc, kmp_int32 global_tid)
kmp_int32 __kmpc_barrier_master_nowait(ident_t *loc, kmp_int32 global_tid)
void __kmpc_end_reduce_nowait(ident_t *loc, kmp_int32 global_tid, kmp_critical_name *lck)
kmp_int32 __kmpc_reduce(ident_t *loc, kmp_int32 global_tid, kmp_int32 num_vars, size_t reduce_size, void *reduce_data, void(*reduce_func)(void *lhs_data, void *rhs_data), kmp_critical_name *lck)
void __kmpc_barrier(ident_t *loc, kmp_int32 global_tid)
void __kmpc_flush(ident_t *loc)
kmp_int32 __kmpc_barrier_master(ident_t *loc, kmp_int32 global_tid)
kmp_int32 __kmpc_reduce_nowait(ident_t *loc, kmp_int32 global_tid, kmp_int32 num_vars, size_t reduce_size, void *reduce_data, void(*reduce_func)(void *lhs_data, void *rhs_data), kmp_critical_name *lck)
void __kmpc_copyprivate(ident_t *loc, kmp_int32 gtid, size_t cpy_size, void *cpy_data, void(*cpy_func)(void *, void *), kmp_int32 didit)
void * __kmpc_copyprivate_light(ident_t *loc, kmp_int32 gtid, void *cpy_data)
kmp_int32 __kmpc_global_num_threads(ident_t *loc)
kmp_int32 __kmpc_global_thread_num(ident_t *loc)
kmp_int32 __kmpc_in_parallel(ident_t *loc)
kmp_int32 __kmpc_bound_thread_num(ident_t *loc)
kmp_int32 __kmpc_bound_num_threads(ident_t *loc)
void __kmpc_end_ordered(ident_t *loc, kmp_int32 gtid)
void __kmpc_end_critical(ident_t *loc, kmp_int32 global_tid, kmp_critical_name *crit)
void __kmpc_for_static_fini(ident_t *loc, kmp_int32 global_tid)
void __kmpc_end_masked(ident_t *loc, kmp_int32 global_tid)
kmp_int32 __kmpc_master(ident_t *loc, kmp_int32 global_tid)
kmp_int32 __kmpc_single(ident_t *loc, kmp_int32 global_tid)
void __kmpc_doacross_init(ident_t *loc, int gtid, int num_dims, const struct kmp_dim *dims)
void __kmpc_end_master(ident_t *loc, kmp_int32 global_tid)
void __kmpc_end_single(ident_t *loc, kmp_int32 global_tid)
void __kmpc_ordered(ident_t *loc, kmp_int32 gtid)
kmp_int32 __kmpc_masked(ident_t *loc, kmp_int32 global_tid, kmp_int32 filter)
void __kmpc_critical(ident_t *loc, kmp_int32 global_tid, kmp_critical_name *crit)
__itt_string_handle * name
Definition ittnotify.h:3305
void
Definition ittnotify.h:3324
void const char const char int ITT_FORMAT __itt_group_sync x void const char ITT_FORMAT __itt_group_sync s void ITT_FORMAT __itt_group_sync p void ITT_FORMAT p void ITT_FORMAT p no args __itt_suppress_mode_t unsigned int mask
void const char const char int ITT_FORMAT __itt_group_sync x void const char ITT_FORMAT __itt_group_sync s void ITT_FORMAT __itt_group_sync p void ITT_FORMAT p void ITT_FORMAT p no args __itt_suppress_mode_t unsigned int void size_t size
void const char const char int ITT_FORMAT __itt_group_sync x void const char ITT_FORMAT __itt_group_sync s void ITT_FORMAT __itt_group_sync p void ITT_FORMAT p void ITT_FORMAT p no args __itt_suppress_mode_t unsigned int void size_t ITT_FORMAT d void ITT_FORMAT p void ITT_FORMAT p __itt_model_site __itt_model_site_instance ITT_FORMAT p __itt_model_task __itt_model_task_instance ITT_FORMAT p void ITT_FORMAT p void ITT_FORMAT p void size_t ITT_FORMAT d void ITT_FORMAT p const wchar_t ITT_FORMAT s const char ITT_FORMAT s const char ITT_FORMAT s const char ITT_FORMAT s no args void ITT_FORMAT p size_t ITT_FORMAT d no args const wchar_t const wchar_t ITT_FORMAT s __itt_heap_function void size_t int ITT_FORMAT d __itt_heap_function void ITT_FORMAT p __itt_heap_function void void size_t int ITT_FORMAT d no args no args unsigned int ITT_FORMAT u const __itt_domain __itt_id ITT_FORMAT lu const __itt_domain __itt_id __itt_id __itt_string_handle ITT_FORMAT p const __itt_domain __itt_id ITT_FORMAT p const __itt_domain __itt_id __itt_timestamp __itt_timestamp ITT_FORMAT lu const __itt_domain __itt_id __itt_id __itt_string_handle ITT_FORMAT p const __itt_domain ITT_FORMAT p const __itt_domain __itt_string_handle unsigned long long ITT_FORMAT lu const __itt_domain __itt_string_handle unsigned long long ITT_FORMAT lu const __itt_domain __itt_id __itt_string_handle __itt_metadata_type size_t void ITT_FORMAT p const __itt_domain __itt_id __itt_string_handle const wchar_t size_t ITT_FORMAT lu const __itt_domain __itt_id __itt_relation __itt_id ITT_FORMAT p const wchar_t int ITT_FORMAT __itt_group_mark d int
struct kmp_disp kmp_disp_t
void * omp_memspace_handle_t
Definition kmp.h:1055
int __kmp_pause_resource(kmp_pause_status_t level)
void * omp_allocator_handle_t
Definition kmp.h:1073
#define __kmp_free(ptr)
Definition kmp.h:3749
void __kmp_aux_set_defaults(char const *str, size_t len)
void __kmp_set_schedule(int gtid, kmp_sched_t new_sched, int chunk)
union kmp_task_team kmp_task_team_t
Definition kmp.h:243
@ ct_reduce
Definition kmp.h:1693
@ ct_critical
Definition kmp.h:1689
@ ct_master
Definition kmp.h:1692
@ ct_barrier
Definition kmp.h:1694
@ ct_masked
Definition kmp.h:1695
@ ct_pdo
Definition kmp.h:1685
void __kmp_teams_master(int gtid)
#define UNPACK_REDUCTION_BARRIER(packed_reduction_method)
Definition kmp.h:553
struct kmp_teams_size kmp_teams_size_t
kmp_pause_status_t
Definition kmp.h:4538
size_t KMP_EXPAND_NAME ompc_get_affinity_format(char *buffer, size_t size)
void __kmp_pop_task_team_node(kmp_info_t *thread, kmp_team_t *team)
struct dispatch_shared_info dispatch_shared_info_t
int __kmp_barrier(enum barrier_type bt, int gtid, int is_split, size_t reduce_size, void *reduce_data, void(*reduce)(void *, void *))
struct KMP_ALIGN_CACHE dispatch_private_info dispatch_private_info_t
void ___kmpc_free(int gtid, void *ptr, omp_allocator_handle_t al)
void __kmp_push_num_teams_51(ident_t *loc, int gtid, int num_teams_lb, int num_teams_ub, int num_threads)
#define __kmp_assign_root_init_mask()
Definition kmp.h:3949
int __kmp_dflt_max_active_levels
static kmp_team_t * __kmp_team_from_gtid(int gtid)
Definition kmp.h:3632
kmp_tasking_mode_t __kmp_tasking_mode
char * __kmp_affinity_format
void * __kmp_alloc(int gtid, size_t align, size_t sz, omp_allocator_handle_t al)
void * __kmp_calloc(int gtid, size_t align, size_t nmemb, size_t sz, omp_allocator_handle_t al)
@ fork_context_intel
Called from Intel generated code.
Definition kmp.h:4058
void __kmp_exit_single(int gtid)
int __kmp_get_team_size(int gtid, int level)
kmp_uint32 __kmp_eq_4(kmp_uint32 value, kmp_uint32 checker)
volatile int __kmp_all_nth
kmp_target_offload_kind_t __kmp_target_offload
void __kmp_parallel_dxo(int *gtid_ref, int *cid_ref, ident_t *loc_ref)
KMP_EXPORT void __kmpc_critical_with_hint(ident_t *, kmp_int32 global_tid, kmp_critical_name *, uint32_t hint)
void __kmp_push_num_threads(ident_t *loc, int gtid, int num_threads)
@ severity_warning
Definition kmp.h:4628
@ severity_fatal
Definition kmp.h:4629
#define set__dynamic(xthread, xval)
Definition kmp.h:2410
#define __kmp_entry_gtid()
Definition kmp.h:3594
void __kmp_internal_end_library(int gtid)
struct kmp_internal_control kmp_internal_control_t
void __kmp_set_max_active_levels(int gtid, int new_max_active_levels)
static int __kmp_tid_from_gtid(int gtid)
Definition kmp.h:3612
void __kmp_internal_end_thread(int gtid)
void __kmp_push_num_threads_list(ident_t *loc, int gtid, kmp_uint32 list_length, int *num_threads_list)
void __kmp_user_set_library(enum library_type arg)
KMP_EXPORT void __kmpc_init_nest_lock_with_hint(ident_t *loc, kmp_int32 gtid, void **user_lock, uintptr_t hint)
int __kmp_gtid_get_specific(void)
volatile int __kmp_init_middle
void __kmp_set_num_threads(int new_nth, int gtid)
PACKED_REDUCTION_METHOD_T __kmp_determine_reduction_method(ident_t *loc, kmp_int32 global_tid, kmp_int32 num_vars, size_t reduce_size, void *reduce_data, void(*reduce_func)(void *lhs_data, void *rhs_data), kmp_critical_name *lck)
void * __kmp_realloc(int gtid, void *ptr, size_t sz, omp_allocator_handle_t al, omp_allocator_handle_t free_al)
void __kmp_end_split_barrier(enum barrier_type bt, int gtid)
int PACKED_REDUCTION_METHOD_T
Definition kmp.h:568
int __kmp_enter_single(int gtid, ident_t *id_ref, int push_ws)
void KMP_EXPAND_NAME ompc_display_affinity(char const *format)
struct kmp_cg_root kmp_cg_root_t
static kmp_info_t * __kmp_entry_thread()
Definition kmp.h:3724
int __kmp_get_ancestor_thread_num(int gtid, int level)
#define __kmp_thread_malloc(th, size)
Definition kmp.h:3769
omp_memspace_handle_t const omp_null_mem_space
void __kmp_middle_initialize(void)
static void copy_icvs(kmp_internal_control_t *dst, kmp_internal_control_t *src)
Definition kmp.h:2205
kmp_info_t ** __kmp_threads
#define TEST_REDUCTION_METHOD(packed_reduction_method, which_reduction_block)
Definition kmp.h:556
static void __kmp_reset_root_init_mask(int gtid)
Definition kmp.h:3950
void __kmp_parallel_deo(int *gtid_ref, int *cid_ref, ident_t *loc_ref)
int __kmp_dispatch_num_buffers
union kmp_team kmp_team_t
Definition kmp.h:241
#define set__max_active_levels(xthread, xval)
Definition kmp.h:2421
#define KMP_MASTER_GTID(gtid)
Definition kmp.h:1335
void __kmp_parallel_initialize(void)
#define KMP_YIELD(cond)
Definition kmp.h:1603
int(* launch_t)(int gtid)
Definition kmp.h:3102
int __kmp_ignore_mppbeg(void)
volatile int __kmp_init_parallel
enum kmp_sched kmp_sched_t
void __kmp_aux_set_stacksize(size_t arg)
static const size_t KMP_AFFINITY_FORMAT_SIZE
Definition kmp.h:951
#define TRUE
Definition kmp.h:1341
#define FALSE
Definition kmp.h:1340
void __kmp_push_num_teams(ident_t *loc, int gtid, int num_teams, int num_threads)
size_t __kmp_aux_capture_affinity(int gtid, const char *format, kmp_str_buf_t *buffer)
@ tskm_immediate_exec
Definition kmp.h:2438
int __kmp_fork_call(ident_t *loc, int gtid, enum fork_context_e fork_context, kmp_int32 argc, microtask_t microtask, launch_t invoker, kmp_va_list ap)
int __kmp_env_consistency_check
omp_sched_t
Definition kmp.h:4489
void __kmp_aux_display_affinity(int gtid, const char *format)
void __kmp_push_proc_bind(ident_t *loc, int gtid, kmp_proc_bind_t proc_bind)
int __kmp_invoke_task_func(int gtid)
size_t KMP_EXPAND_NAME ompc_capture_affinity(char *buffer, size_t buf_size, char const *format)
void __kmp_set_strict_num_threads(ident_t *loc, int gtid, int sev, const char *msg)
#define __kmp_thread_calloc(th, nelem, elsize)
Definition kmp.h:3771
void __kmp_save_internal_controls(kmp_info_t *thread)
@ bs_plain_barrier
Definition kmp.h:2153
int __kmp_invoke_teams_master(int gtid)
static void __kmp_aux_convert_blocktime(int *bt)
Definition kmp.h:3478
#define __kmp_get_gtid()
Definition kmp.h:3593
void __kmp_serial_initialize(void)
kmp_uint32 __kmp_wait_4(kmp_uint32 volatile *spinner, kmp_uint32 checker, kmp_uint32(*pred)(kmp_uint32, kmp_uint32), void *obj)
void __kmp_resume_if_soft_paused()
KMP_EXPORT void __kmpc_init_lock_with_hint(ident_t *loc, kmp_int32 gtid, void **user_lock, uintptr_t hint)
static void __kmp_assert_valid_gtid(kmp_int32 gtid)
Definition kmp.h:3637
void __kmp_serialized_parallel(ident_t *id, kmp_int32 gtid)
void __kmp_pop_current_task_from_thread(kmp_info_t *this_thr)
void __kmp_internal_begin(void)
kmp_proc_bind_t
Definition kmp.h:930
static kmp_info_t * __kmp_thread_from_gtid(int gtid)
Definition kmp.h:3627
void KMP_EXPAND_NAME ompc_set_affinity_format(char const *format)
#define KMP_MIN_DISP_NUM_BUFF
Definition kmp.h:1307
library_type
Definition kmp.h:487
volatile int __kmp_init_serial
@ empty_reduce_block
Definition kmp.h:522
@ critical_reduce_block
Definition kmp.h:519
@ tree_reduce_block
Definition kmp.h:521
@ atomic_reduce_block
Definition kmp.h:520
#define KMP_MAX_DISP_NUM_BUFF
Definition kmp.h:1309
int __kmp_invoke_microtask(microtask_t pkfn, int gtid, int npr, int argc, void *argv[])
static void __kmp_type_convert(T1 src, T2 *dest)
Definition kmp.h:4879
void __kmp_join_call(ident_t *loc, int gtid, int exit_teams=0)
int __kmp_ignore_mppend(void)
struct kmp_taskdata kmp_taskdata_t
Definition kmp.h:242
union KMP_ALIGN_CACHE kmp_info kmp_info_t
void __kmp_task_team_wait(kmp_info_t *this_thr, kmp_team_t *team, int wait=1)
void __kmp_aux_set_blocktime(int arg, kmp_info_t *thread, int tid)
#define __kmp_thread_free(th, ptr)
Definition kmp.h:3775
KMP_ARCH_X86 KMP_ARCH_X86 KMP_ARCH_X86 KMP_ARCH_X86 KMP_ARCH_X86 KMP_ARCH_X86 KMP_ARCH_X86 KMP_ARCH_X86 KMP_ARCH_X86<<, 2i, 1, KMP_ARCH_X86) ATOMIC_CMPXCHG(fixed2, shr, kmp_int16, 16, > KMP_ARCH_X86 KMP_ARCH_X86 kmp_uint32
void kmpc_set_num_threads_8(kmp_int64 arg)
static kmp_user_lock_p __kmp_get_critical_section_ptr(kmp_critical_name *crit, ident_t const *loc, kmp_int32 gtid)
void ompc_set_dynamic(int flag)
int kmpc_unset_affinity_mask_proc(int proc, void **mask)
#define __KMP_GET_REDUCTION_METHOD(gtid)
void __kmpc_unset_nest_lock(ident_t *loc, kmp_int32 gtid, void **user_lock)
void * omp_aligned_calloc(size_t align, size_t nmemb, size_t size, omp_allocator_handle_t allocator)
void __kmpc_destroy_nest_lock(ident_t *loc, kmp_int32 gtid, void **user_lock)
void __kmpc_doacross_post(ident_t *loc, int gtid, const kmp_int64 *vec)
void * omp_calloc(size_t nmemb, size_t size, omp_allocator_handle_t allocator)
void kmpc_set_disp_num_buffers(int arg)
#define INIT_NESTED_LOCK
void * omp_get_dyn_gprivate_nofb_ptr(size_t offset, omp_access_t access_group)
static __forceinline int __kmp_swap_teams_for_teams_reduction(kmp_info_t *th, kmp_team_t **team_p, int *task_state)
int ompc_get_ancestor_thread_num(int level)
#define DESTROY_LOCK
void kmpc_set_stacksize_s(size_t arg)
void __kmpc_push_num_threads_strict(ident_t *loc, kmp_int32 global_tid, kmp_int32 num_threads, int severity, const char *message)
void __kmpc_scope(ident_t *loc, kmp_int32 gtid, void *reserved)
size_t omp_get_dyn_gprivate_size(omp_access_t access_group)
static __forceinline void __kmp_end_critical_section_reduce_block(ident_t *loc, kmp_int32 global_tid, kmp_critical_name *crit)
int kmpc_set_affinity_mask_proc(int proc, void **mask)
void kmpc_set_library(int arg)
#define TEST_LOCK
void __kmpc_set_nest_lock(ident_t *loc, kmp_int32 gtid, void **user_lock)
void __kmpc_push_num_threads_list_strict(ident_t *loc, kmp_int32 global_tid, kmp_uint32 list_length, kmp_int32 *num_threads_list, int severity, const char *message)
void kmpc_set_stacksize(int arg)
#define DESTROY_NESTED_LOCK
void ompc_set_schedule(omp_sched_t kind, int modifier)
void __kmpc_error(ident_t *loc, int severity, const char *message)
void * omp_aligned_alloc(size_t align, size_t size, omp_allocator_handle_t allocator)
void kmpc_set_blocktime(int arg)
#define __KMP_SET_REDUCTION_METHOD(gtid, rmethod)
void kmpc_set_defaults(char const *str)
void __kmpc_end_scope(ident_t *loc, kmp_int32 gtid, void *reserved)
void * omp_get_dyn_gprivate_ptr(size_t offset, omp_access_t access_group)
void __kmpc_init_lock(ident_t *loc, kmp_int32 gtid, void **user_lock)
void omp_free(void *ptr, omp_allocator_handle_t allocator)
void __kmpc_set_lock(ident_t *loc, kmp_int32 gtid, void **user_lock)
void * omp_realloc(void *ptr, size_t size, omp_allocator_handle_t allocator, omp_allocator_handle_t free_allocator)
kmp_uint64 __kmpc_get_taskid()
int ompc_get_team_size(int level)
int kmpc_get_affinity_mask_proc(int proc, void **mask)
void __kmpc_doacross_fini(ident_t *loc, int gtid)
#define RELEASE_NESTED_LOCK
int __kmpc_test_nest_lock(ident_t *loc, kmp_int32 gtid, void **user_lock)
void __kmpc_destroy_lock(ident_t *loc, kmp_int32 gtid, void **user_lock)
static __forceinline void __kmp_restore_swapped_teams(kmp_info_t *th, kmp_team_t *team, int task_state)
void __kmpc_pop_num_threads(ident_t *loc, kmp_int32 global_tid)
int __kmpc_invoke_task_func(int gtid)
void __kmpc_unset_lock(ident_t *loc, kmp_int32 gtid, void **user_lock)
void __kmpc_push_proc_bind(ident_t *loc, kmp_int32 global_tid, kmp_int32 proc_bind)
void __kmpc_init_nest_lock(ident_t *loc, kmp_int32 gtid, void **user_lock)
#define ACQUIRE_NESTED_LOCK
#define INIT_LOCK
void ompc_set_nested(int flag)
#define ACQUIRE_LOCK
static __forceinline void __kmp_enter_critical_section_reduce_block(ident_t *loc, kmp_int32 global_tid, kmp_critical_name *crit)
void ompc_set_max_active_levels(int max_active_levels)
kmp_uint64 __kmpc_get_parent_taskid()
void ompc_set_num_threads(int arg)
omp_memspace_handle_t omp_get_dyn_gprivate_memspace(omp_access_t access_group)
void * omp_alloc(size_t size, omp_allocator_handle_t allocator)
#define TEST_NESTED_LOCK
#define RELEASE_LOCK
void __kmpc_doacross_wait(ident_t *loc, int gtid, const kmp_int64 *vec)
int __kmpc_get_target_offload(void)
int __kmpc_pause_resource(kmp_pause_status_t level)
int __kmpc_test_lock(ident_t *loc, kmp_int32 gtid, void **user_lock)
#define KE_TRACE(d, x)
Definition kmp_debug.h:161
#define KA_TRACE(d, x)
Definition kmp_debug.h:157
#define KMP_ASSERT(cond)
Definition kmp_debug.h:59
#define KC_TRACE(d, x)
Definition kmp_debug.h:159
#define KMP_DEBUG_ASSERT(cond)
Definition kmp_debug.h:61
unsigned long long kmp_uint64
void __kmp_push_sync(int gtid, enum cons_type ct, ident_t const *ident, kmp_user_lock_p lck)
void __kmp_check_sync(int gtid, enum cons_type ct, ident_t const *ident, kmp_user_lock_p lck)
enum cons_type __kmp_pop_workshare(int gtid, enum cons_type ct, ident_t const *ident)
void __kmp_pop_sync(int gtid, enum cons_type ct, ident_t const *ident)
void __kmp_check_barrier(int gtid, enum cons_type ct, ident_t const *ident)
void __kmp_pop_parallel(int gtid, ident_t const *ident)
static volatile kmp_i18n_cat_status_t status
Definition kmp_i18n.cpp:48
static kmp_bootstrap_lock_t lock
Definition kmp_i18n.cpp:57
#define KMP_WARNING(...)
Definition kmp_i18n.h:144
#define KMP_FATAL(...)
Definition kmp_i18n.h:146
#define USE_ITT_BUILD_ARG(x)
Definition kmp_itt.h:346
size_t __kmp_base_user_lock_size
enum kmp_lock_kind __kmp_user_lock_kind
kmp_user_lock_p __kmp_user_lock_allocate(void **user_lock, kmp_int32 gtid, kmp_lock_flags_t flags)
void __kmp_user_lock_free(void **user_lock, kmp_int32 gtid, kmp_user_lock_p lck)
kmp_user_lock_p __kmp_lookup_user_lock(void **user_lock, char const *func)
struct kmp_base_tas_lock kmp_base_tas_lock_t
Definition kmp_lock.h:135
#define INTEL_CRITICAL_SIZE
Definition kmp_lock.h:65
#define OMP_NEST_LOCK_T_SIZE
Definition kmp_lock.h:58
#define KMP_CHECK_USER_LOCK_INIT()
Definition kmp_lock.h:990
static void __kmp_release_user_lock_with_checks(kmp_user_lock_p lck, kmp_int32 gtid)
Definition kmp_lock.h:718
union kmp_user_lock * kmp_user_lock_p
Definition kmp_lock.h:623
static int __kmp_acquire_user_lock_with_checks(kmp_user_lock_p lck, kmp_int32 gtid)
Definition kmp_lock.h:675
#define KMP_LOCK_RELEASED
Definition kmp_lock.h:164
@ lk_ticket
Definition kmp_lock.h:597
@ lk_drdpa
Definition kmp_lock.h:599
@ lk_queuing
Definition kmp_lock.h:598
@ lk_tas
Definition kmp_lock.h:588
static void __kmp_destroy_user_lock_with_checks(kmp_user_lock_p lck)
Definition kmp_lock.h:742
static void __kmp_init_user_lock_with_checks(kmp_user_lock_p lck)
Definition kmp_lock.h:726
#define kmp_lf_critical_section
Definition kmp_lock.h:70
static void __kmp_set_user_lock_location(kmp_user_lock_p lck, const ident_t *loc)
Definition kmp_lock.h:892
#define OMP_LOCK_T_SIZE
Definition kmp_lock.h:57
#define KMP_LOCK_ACQUIRED_FIRST
Definition kmp_lock.h:166
union kmp_tas_lock kmp_tas_lock_t
Definition kmp_lock.h:143
#define OMP_CRITICAL_SIZE
Definition kmp_lock.h:64
#define KMP_LOCK_STILL_HELD
Definition kmp_lock.h:165
#define KMP_COMPARE_AND_STORE_RET64(p, cv, sv)
Definition kmp_os.h:867
void(* microtask_t)(int *gtid, int *npr,...)
Definition kmp_os.h:1189
#define FTN_TRUE
Definition kmp_os.h:1182
#define KMP_TEST_THEN_OR32(p, v)
Definition kmp_os.h:788
#define KMP_TEST_THEN_INC32(p)
Definition kmp_os.h:729
#define KMP_COMPARE_AND_STORE_RET32(p, cv, sv)
Definition kmp_os.h:834
#define TCR_PTR(a)
Definition kmp_os.h:1170
#define KMP_VERSION_OMPC_SYMBOL(apic_name, api_name, ver_num, ver_str)
Definition kmp_os.h:449
#define VOLATILE_CAST(x)
Definition kmp_os.h:1194
#define CCAST(type, var)
Definition kmp_os.h:293
#define KMP_MB()
Definition kmp_os.h:1070
#define FTN_FALSE
Definition kmp_os.h:1186
#define kmp_va_addr_of(ap)
Definition kmp_os.h:232
#define TCR_4(a)
Definition kmp_os.h:1141
#define KMP_MFENCE()
Definition kmp_os.h:1103
#define KMP_COMPARE_AND_STORE_ACQ32(p, cv, sv)
Definition kmp_os.h:818
#define TCW_4(a, b)
Definition kmp_os.h:1142
unsigned long kmp_uintptr_t
Definition kmp_os.h:206
#define KMP_EXPAND_NAME(api_name)
Definition kmp_os.h:447
#define KMP_COMPARE_AND_STORE_PTR(p, cv, sv)
Definition kmp_os.h:824
#define KMP_SSCANF
static void __kmp_strncpy_truncate(char *buffer, size_t buf_size, char const *src, size_t src_size)
#define KMP_STRLEN
Functions for collecting statistics.
#define KMP_PUSH_PARTITIONED_TIMER(name)
Definition kmp_stats.h:1014
#define KMP_GET_THREAD_STATE()
Definition kmp_stats.h:1017
#define KMP_POP_PARTITIONED_TIMER()
Definition kmp_stats.h:1015
#define KMP_COUNT_BLOCK(n)
Definition kmp_stats.h:1001
#define KMP_SET_THREAD_STATE(state_name)
Definition kmp_stats.h:1016
kmp_str_loc_t __kmp_str_loc_init(char const *psource, bool init_fname)
Definition kmp_str.cpp:347
void __kmp_str_buf_free(kmp_str_buf_t *buffer)
Definition kmp_str.cpp:123
char * __kmp_str_format(char const *format,...)
Definition kmp_str.cpp:448
int __kmp_str_match_true(char const *data)
Definition kmp_str.cpp:552
void __kmp_str_loc_free(kmp_str_loc_t *loc)
Definition kmp_str.cpp:393
#define args
void __kmp_str_free(char **str)
Definition kmp_str.cpp:494
struct kmp_str_loc kmp_str_loc_t
Definition kmp_str.h:101
struct kmp_str_buf kmp_str_buf_t
Definition kmp_str.h:39
#define __kmp_str_buf_init(b)
Definition kmp_str.h:41
#define i
Definition kmp_stub.cpp:88
#define omp_get_affinity_format
Definition kmp_stub.cpp:39
#define omp_set_affinity_format
Definition kmp_stub.cpp:38
#define omp_display_affinity
Definition kmp_stub.cpp:40
#define omp_capture_affinity
Definition kmp_stub.cpp:41
void microtask(int *global_tid, int *bound_tid)
int32_t kmp_int32
omp_lock_t lck
Definition omp_lock.c:7
void func(int *num_exec)
void init(int &A, int val)
ompt_callbacks_active_t ompt_enabled
return ret
ompt_callbacks_internal_t ompt_callbacks
#define OMPT_GET_RETURN_ADDRESS(level)
#define OMPT_GET_FRAME_ADDRESS(level)
ompt_team_info_t * __ompt_get_teaminfo(int depth, int *size)
int __ompt_get_task_info_internal(int ancestor_level, int *type, ompt_data_t **task_data, ompt_frame_t **task_frame, ompt_data_t **parallel_data, int *thread_num)
ompt_task_info_t * __ompt_get_task_info_object(int depth)
void __ompt_lw_taskteam_unlink(kmp_info_t *thr)
ompt_data_t * __ompt_get_thread_data_internal()
#define OMPT_REDUCTION_BEGIN
#define OMPT_REDUCTION_DECL(this_thr, gtid)
#define OMPT_REDUCTION_END
static id loc
volatile int flag
kmp_int32 doacross_num_done
Definition kmp.h:2077
volatile kmp_int32 doacross_buf_idx
Definition kmp.h:2075
volatile kmp_uint32 * doacross_flags
Definition kmp.h:2076
std::atomic< kmp_int32 > poll
Definition kmp_lock.h:130
kmp_int32 depth_locked
Definition kmp_lock.h:131
kmp_int32 tt_found_proxy_tasks
Definition kmp.h:2861
kmp_int32 tt_hidden_helper_task_encountered
Definition kmp.h:2866
kmp_int32 cg_nthreads
Definition kmp.h:2925
struct kmp_cg_root * up
Definition kmp.h:2926
kmp_int64 up
Definition kmp.h:4455
kmp_int64 lo
Definition kmp.h:4454
kmp_int64 st
Definition kmp.h:4456
kmp_int32 th_doacross_buf_idx
Definition kmp.h:2100
volatile kmp_uint32 * th_doacross_flags
Definition kmp.h:2101
kmp_int64 * th_doacross_info
Definition kmp.h:2102
struct kmp_internal_control * next
Definition kmp.h:2202
int serial_nesting_level
Definition kmp.h:2183
char * str
Definition kmp_str.h:34
char * file
Definition kmp_str.h:96
kmp_taskdata_t * td_parent
Definition kmp.h:2761
kmp_int32 td_task_id
Definition kmp.h:2756
ompt_data_t task_data
ompt_data_t parallel_data
ompt_wait_id_t wait_id
ompt_state_t state
kmp_critical_name crit
kmp_base_tas_lock_t lk
Definition kmp_lock.h:138
kmp_base_task_team_t tt
Definition kmp.h:2877
kmp_base_team_t t
Definition kmp.h:3227