LLVM OpenMP* Runtime Library
kmp_tasking.cpp
1/*
2 * kmp_tasking.cpp -- OpenMP 3.0 tasking support.
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#include "kmp.h"
14#include "kmp_i18n.h"
15#include "kmp_itt.h"
16#include "kmp_stats.h"
17#include "kmp_wait_release.h"
18#include "kmp_taskdeps.h"
19
20#if OMPT_SUPPORT
21#include "ompt-specific.h"
22#endif
23
24#if ENABLE_LIBOMPTARGET
25static void (*tgt_target_nowait_query)(void **);
26
27void __kmp_init_target_task() {
28 *(void **)(&tgt_target_nowait_query) = KMP_DLSYM("__tgt_target_nowait_query");
29}
30#endif
31
32/* forward declaration */
33static void __kmp_enable_tasking(kmp_task_team_t *task_team,
34 kmp_info_t *this_thr);
35static void __kmp_alloc_task_deque(kmp_info_t *thread,
36 kmp_thread_data_t *thread_data);
37static int __kmp_realloc_task_threads_data(kmp_info_t *thread,
38 kmp_task_team_t *task_team);
39static void __kmp_bottom_half_finish_proxy(kmp_int32 gtid, kmp_task_t *ptask);
40
41// returns 1 if new task is allowed to execute, 0 otherwise
42// checks Task Scheduling constraint (if requested) and
43// mutexinoutset dependencies if any
44static bool __kmp_task_is_allowed(int gtid, const kmp_int32 is_constrained,
45 const kmp_taskdata_t *tasknew,
46 const kmp_taskdata_t *taskcurr) {
47 if (is_constrained && (tasknew->td_flags.tiedness == TASK_TIED)) {
48 // Check if the candidate obeys the Task Scheduling Constraints (TSC)
49 // only descendant of all deferred tied tasks can be scheduled, checking
50 // the last one is enough, as it in turn is the descendant of all others
51 kmp_taskdata_t *current = taskcurr->td_last_tied;
52 KMP_DEBUG_ASSERT(current != NULL);
53 // check if the task is not suspended on barrier
54 if (current->td_flags.tasktype == TASK_EXPLICIT ||
55 current->td_taskwait_thread > 0) { // <= 0 on barrier
56 kmp_int32 level = current->td_level;
57 kmp_taskdata_t *parent = tasknew->td_parent;
58 while (parent != current && parent->td_level > level) {
59 // check generation up to the level of the current task
60 parent = parent->td_parent;
61 KMP_DEBUG_ASSERT(parent != NULL);
62 }
63 if (parent != current)
64 return false;
65 }
66 }
67 // Check mutexinoutset dependencies, acquire locks
68 kmp_depnode_t *node = tasknew->td_depnode;
69 if (UNLIKELY(node && (node->dn.mtx_num_locks > 0))) {
70 for (int i = 0; i < node->dn.mtx_num_locks; ++i) {
71 KMP_DEBUG_ASSERT(node->dn.mtx_locks[i] != NULL);
72 if (__kmp_test_lock(node->dn.mtx_locks[i], gtid))
73 continue;
74 // could not get the lock, release previous locks
75 for (int j = i - 1; j >= 0; --j)
76 __kmp_release_lock(node->dn.mtx_locks[j], gtid);
77 return false;
78 }
79 // negative num_locks means all locks acquired successfully
80 node->dn.mtx_num_locks = -node->dn.mtx_num_locks;
81 }
82 return true;
83}
84
85// __kmp_realloc_task_deque:
86// Re-allocates a task deque for a particular thread, copies the content from
87// the old deque and adjusts the necessary data structures relating to the
88// deque. This operation must be done with the deque_lock being held
89static void __kmp_realloc_task_deque(kmp_info_t *thread,
90 kmp_thread_data_t *thread_data) {
91 kmp_int32 size = TASK_DEQUE_SIZE(thread_data->td);
92 KMP_DEBUG_ASSERT(TCR_4(thread_data->td.td_deque_ntasks) == size);
93 kmp_int32 new_size = 2 * size;
94
95 KE_TRACE(10, ("__kmp_realloc_task_deque: T#%d reallocating deque[from %d to "
96 "%d] for thread_data %p\n",
97 __kmp_gtid_from_thread(thread), size, new_size, thread_data));
98
99 kmp_taskdata_t **new_deque =
100 (kmp_taskdata_t **)__kmp_allocate(new_size * sizeof(kmp_taskdata_t *));
101
102 int i, j;
103 for (i = thread_data->td.td_deque_head, j = 0; j < size;
104 i = (i + 1) & TASK_DEQUE_MASK(thread_data->td), j++)
105 new_deque[j] = thread_data->td.td_deque[i];
106
107 __kmp_free(thread_data->td.td_deque);
108
109 thread_data->td.td_deque_head = 0;
110 thread_data->td.td_deque_tail = size;
111 thread_data->td.td_deque = new_deque;
112 thread_data->td.td_deque_size = new_size;
113}
114
115static kmp_task_pri_t *__kmp_alloc_task_pri_list() {
116 kmp_task_pri_t *l = (kmp_task_pri_t *)__kmp_allocate(sizeof(kmp_task_pri_t));
117 kmp_thread_data_t *thread_data = &l->td;
118 __kmp_init_bootstrap_lock(&thread_data->td.td_deque_lock);
119 thread_data->td.td_deque_last_stolen = -1;
120 KE_TRACE(20, ("__kmp_alloc_task_pri_list: T#%d allocating deque[%d] "
121 "for thread_data %p\n",
122 __kmp_get_gtid(), INITIAL_TASK_DEQUE_SIZE, thread_data));
123 thread_data->td.td_deque = (kmp_taskdata_t **)__kmp_allocate(
124 INITIAL_TASK_DEQUE_SIZE * sizeof(kmp_taskdata_t *));
125 thread_data->td.td_deque_size = INITIAL_TASK_DEQUE_SIZE;
126 return l;
127}
128
129// The function finds the deque of priority tasks with given priority, or
130// allocates a new deque and put it into sorted (high -> low) list of deques.
131// Deques of non-default priority tasks are shared between all threads in team,
132// as opposed to per-thread deques of tasks with default priority.
133// The function is called under the lock task_team->tt.tt_task_pri_lock.
134static kmp_thread_data_t *
135__kmp_get_priority_deque_data(kmp_task_team_t *task_team, kmp_int32 pri) {
136 kmp_thread_data_t *thread_data;
137 kmp_task_pri_t *lst = task_team->tt.tt_task_pri_list;
138 if (lst->priority == pri) {
139 // Found queue of tasks with given priority.
140 thread_data = &lst->td;
141 } else if (lst->priority < pri) {
142 // All current priority queues contain tasks with lower priority.
143 // Allocate new one for given priority tasks.
144 kmp_task_pri_t *list = __kmp_alloc_task_pri_list();
145 thread_data = &list->td;
146 list->priority = pri;
147 list->next = lst;
148 task_team->tt.tt_task_pri_list = list;
149 } else { // task_team->tt.tt_task_pri_list->priority > pri
150 kmp_task_pri_t *next_queue = lst->next;
151 while (next_queue && next_queue->priority > pri) {
152 lst = next_queue;
153 next_queue = lst->next;
154 }
155 // lst->priority > pri && (next == NULL || pri >= next->priority)
156 if (next_queue == NULL) {
157 // No queue with pri priority, need to allocate new one.
158 kmp_task_pri_t *list = __kmp_alloc_task_pri_list();
159 thread_data = &list->td;
160 list->priority = pri;
161 list->next = NULL;
162 lst->next = list;
163 } else if (next_queue->priority == pri) {
164 // Found queue of tasks with given priority.
165 thread_data = &next_queue->td;
166 } else { // lst->priority > pri > next->priority
167 // insert newly allocated between existed queues
168 kmp_task_pri_t *list = __kmp_alloc_task_pri_list();
169 thread_data = &list->td;
170 list->priority = pri;
171 list->next = next_queue;
172 lst->next = list;
173 }
174 }
175 return thread_data;
176}
177
178// __kmp_push_priority_task: Add a task to the team's priority task deque
179static kmp_int32 __kmp_push_priority_task(kmp_int32 gtid, kmp_info_t *thread,
180 kmp_taskdata_t *taskdata,
181 kmp_task_team_t *task_team,
182 kmp_int32 pri) {
183 kmp_thread_data_t *thread_data = NULL;
184 KA_TRACE(20,
185 ("__kmp_push_priority_task: T#%d trying to push task %p, pri %d.\n",
186 gtid, taskdata, pri));
187
188 // Find task queue specific to priority value
189 kmp_task_pri_t *lst = task_team->tt.tt_task_pri_list;
190 if (UNLIKELY(lst == NULL)) {
191 __kmp_acquire_bootstrap_lock(&task_team->tt.tt_task_pri_lock);
192 if (task_team->tt.tt_task_pri_list == NULL) {
193 // List of queues is still empty, allocate one.
194 kmp_task_pri_t *list = __kmp_alloc_task_pri_list();
195 thread_data = &list->td;
196 list->priority = pri;
197 list->next = NULL;
198 task_team->tt.tt_task_pri_list = list;
199 } else {
200 // Other thread initialized a queue. Check if it fits and get thread_data.
201 thread_data = __kmp_get_priority_deque_data(task_team, pri);
202 }
203 __kmp_release_bootstrap_lock(&task_team->tt.tt_task_pri_lock);
204 } else {
205 if (lst->priority == pri) {
206 // Found queue of tasks with given priority.
207 thread_data = &lst->td;
208 } else {
209 __kmp_acquire_bootstrap_lock(&task_team->tt.tt_task_pri_lock);
210 thread_data = __kmp_get_priority_deque_data(task_team, pri);
211 __kmp_release_bootstrap_lock(&task_team->tt.tt_task_pri_lock);
212 }
213 }
214 KMP_DEBUG_ASSERT(thread_data);
215
216 __kmp_acquire_bootstrap_lock(&thread_data->td.td_deque_lock);
217 // Check if deque is full
218 if (TCR_4(thread_data->td.td_deque_ntasks) >=
219 TASK_DEQUE_SIZE(thread_data->td)) {
220 if (__kmp_enable_task_throttling &&
221 __kmp_task_is_allowed(gtid, __kmp_task_stealing_constraint, taskdata,
222 thread->th.th_current_task)) {
223 __kmp_release_bootstrap_lock(&thread_data->td.td_deque_lock);
224 KA_TRACE(20, ("__kmp_push_priority_task: T#%d deque is full; returning "
225 "TASK_NOT_PUSHED for task %p\n",
226 gtid, taskdata));
227 return TASK_NOT_PUSHED;
228 } else {
229 // expand deque to push the task which is not allowed to execute
230 __kmp_realloc_task_deque(thread, thread_data);
231 }
232 }
233 KMP_DEBUG_ASSERT(TCR_4(thread_data->td.td_deque_ntasks) <
234 TASK_DEQUE_SIZE(thread_data->td));
235 // Push taskdata.
236 thread_data->td.td_deque[thread_data->td.td_deque_tail] = taskdata;
237 // Wrap index.
238 thread_data->td.td_deque_tail =
239 (thread_data->td.td_deque_tail + 1) & TASK_DEQUE_MASK(thread_data->td);
240 TCW_4(thread_data->td.td_deque_ntasks,
241 TCR_4(thread_data->td.td_deque_ntasks) + 1); // Adjust task count
242 KMP_FSYNC_RELEASING(thread->th.th_current_task); // releasing self
243 KMP_FSYNC_RELEASING(taskdata); // releasing child
244 KA_TRACE(20, ("__kmp_push_priority_task: T#%d returning "
245 "TASK_SUCCESSFULLY_PUSHED: task=%p ntasks=%d head=%u tail=%u\n",
246 gtid, taskdata, thread_data->td.td_deque_ntasks,
247 thread_data->td.td_deque_head, thread_data->td.td_deque_tail));
248 __kmp_release_bootstrap_lock(&thread_data->td.td_deque_lock);
249 task_team->tt.tt_num_task_pri++; // atomic inc
250 return TASK_SUCCESSFULLY_PUSHED;
251}
252
253// __kmp_push_task: Add a task to the thread's deque
254static kmp_int32 __kmp_push_task(kmp_int32 gtid, kmp_task_t *task) {
255 kmp_info_t *thread = __kmp_threads[gtid];
256 kmp_taskdata_t *taskdata = KMP_TASK_TO_TASKDATA(task);
257
258 // If we encounter a hidden helper task, and the current thread is not a
259 // hidden helper thread, we have to give the task to any hidden helper thread
260 // starting from its shadow one.
261 if (UNLIKELY(taskdata->td_flags.hidden_helper &&
262 !KMP_HIDDEN_HELPER_THREAD(gtid))) {
263 kmp_int32 shadow_gtid = KMP_GTID_TO_SHADOW_GTID(gtid);
264 __kmpc_give_task(task, __kmp_tid_from_gtid(shadow_gtid));
265 // Signal the hidden helper threads.
266 __kmp_hidden_helper_worker_thread_signal();
267 return TASK_SUCCESSFULLY_PUSHED;
268 }
269
270 kmp_task_team_t *task_team = thread->th.th_task_team;
271 kmp_int32 tid = __kmp_tid_from_gtid(gtid);
272 kmp_thread_data_t *thread_data;
273
274 KA_TRACE(20,
275 ("__kmp_push_task: T#%d trying to push task %p.\n", gtid, taskdata));
276
277 if (UNLIKELY(taskdata->td_flags.tiedness == TASK_UNTIED)) {
278 // untied task needs to increment counter so that the task structure is not
279 // freed prematurely
280 kmp_int32 counter = 1 + KMP_ATOMIC_INC(&taskdata->td_untied_count);
281 KMP_DEBUG_USE_VAR(counter);
282 KA_TRACE(
283 20,
284 ("__kmp_push_task: T#%d untied_count (%d) incremented for task %p\n",
285 gtid, counter, taskdata));
286 }
287
288 // The first check avoids building task_team thread data if serialized
289 if (UNLIKELY(taskdata->td_flags.task_serial)) {
290 KA_TRACE(20, ("__kmp_push_task: T#%d team serialized; returning "
291 "TASK_NOT_PUSHED for task %p\n",
292 gtid, taskdata));
293 return TASK_NOT_PUSHED;
294 }
295
296 // Now that serialized tasks have returned, we can assume that we are not in
297 // immediate exec mode
298 KMP_DEBUG_ASSERT(__kmp_tasking_mode != tskm_immediate_exec);
299 if (UNLIKELY(!KMP_TASKING_ENABLED(task_team))) {
300 __kmp_enable_tasking(task_team, thread);
301 }
302 KMP_DEBUG_ASSERT(TCR_4(task_team->tt.tt_found_tasks) == TRUE);
303 KMP_DEBUG_ASSERT(TCR_PTR(task_team->tt.tt_threads_data) != NULL);
304
305 if (taskdata->td_flags.priority_specified && task->data2.priority > 0 &&
306 __kmp_max_task_priority > 0) {
307 int pri = KMP_MIN(task->data2.priority, __kmp_max_task_priority);
308 return __kmp_push_priority_task(gtid, thread, taskdata, task_team, pri);
309 }
310
311 // Find tasking deque specific to encountering thread
312 thread_data = &task_team->tt.tt_threads_data[tid];
313
314 // No lock needed since only owner can allocate. If the task is hidden_helper,
315 // we don't need it either because we have initialized the dequeue for hidden
316 // helper thread data.
317 if (UNLIKELY(thread_data->td.td_deque == NULL)) {
318 __kmp_alloc_task_deque(thread, thread_data);
319 }
320
321 int locked = 0;
322 // Check if deque is full
323 if (TCR_4(thread_data->td.td_deque_ntasks) >=
324 TASK_DEQUE_SIZE(thread_data->td)) {
325 if (__kmp_enable_task_throttling &&
326 __kmp_task_is_allowed(gtid, __kmp_task_stealing_constraint, taskdata,
327 thread->th.th_current_task)) {
328 KA_TRACE(20, ("__kmp_push_task: T#%d deque is full; returning "
329 "TASK_NOT_PUSHED for task %p\n",
330 gtid, taskdata));
331 return TASK_NOT_PUSHED;
332 } else {
333 __kmp_acquire_bootstrap_lock(&thread_data->td.td_deque_lock);
334 locked = 1;
335 if (TCR_4(thread_data->td.td_deque_ntasks) >=
336 TASK_DEQUE_SIZE(thread_data->td)) {
337 // expand deque to push the task which is not allowed to execute
338 __kmp_realloc_task_deque(thread, thread_data);
339 }
340 }
341 }
342 // Lock the deque for the task push operation
343 if (!locked) {
344 __kmp_acquire_bootstrap_lock(&thread_data->td.td_deque_lock);
345 // Need to recheck as we can get a proxy task from thread outside of OpenMP
346 if (TCR_4(thread_data->td.td_deque_ntasks) >=
347 TASK_DEQUE_SIZE(thread_data->td)) {
348 if (__kmp_enable_task_throttling &&
349 __kmp_task_is_allowed(gtid, __kmp_task_stealing_constraint, taskdata,
350 thread->th.th_current_task)) {
351 __kmp_release_bootstrap_lock(&thread_data->td.td_deque_lock);
352 KA_TRACE(20, ("__kmp_push_task: T#%d deque is full on 2nd check; "
353 "returning TASK_NOT_PUSHED for task %p\n",
354 gtid, taskdata));
355 return TASK_NOT_PUSHED;
356 } else {
357 // expand deque to push the task which is not allowed to execute
358 __kmp_realloc_task_deque(thread, thread_data);
359 }
360 }
361 }
362 // Must have room since no thread can add tasks but calling thread
363 KMP_DEBUG_ASSERT(TCR_4(thread_data->td.td_deque_ntasks) <
364 TASK_DEQUE_SIZE(thread_data->td));
365
366 thread_data->td.td_deque[thread_data->td.td_deque_tail] =
367 taskdata; // Push taskdata
368 // Wrap index.
369 thread_data->td.td_deque_tail =
370 (thread_data->td.td_deque_tail + 1) & TASK_DEQUE_MASK(thread_data->td);
371 TCW_4(thread_data->td.td_deque_ntasks,
372 TCR_4(thread_data->td.td_deque_ntasks) + 1); // Adjust task count
373 KMP_FSYNC_RELEASING(thread->th.th_current_task); // releasing self
374 KMP_FSYNC_RELEASING(taskdata); // releasing child
375 KA_TRACE(20, ("__kmp_push_task: T#%d returning TASK_SUCCESSFULLY_PUSHED: "
376 "task=%p ntasks=%d head=%u tail=%u\n",
377 gtid, taskdata, thread_data->td.td_deque_ntasks,
378 thread_data->td.td_deque_head, thread_data->td.td_deque_tail));
379
380 __kmp_release_bootstrap_lock(&thread_data->td.td_deque_lock);
381
382 return TASK_SUCCESSFULLY_PUSHED;
383}
384
385// __kmp_pop_current_task_from_thread: set up current task from called thread
386// when team ends
387//
388// this_thr: thread structure to set current_task in.
389void __kmp_pop_current_task_from_thread(kmp_info_t *this_thr) {
390 KF_TRACE(10, ("__kmp_pop_current_task_from_thread(enter): T#%d "
391 "this_thread=%p, curtask=%p, "
392 "curtask_parent=%p\n",
393 0, this_thr, this_thr->th.th_current_task,
394 this_thr->th.th_current_task->td_parent));
395
396 this_thr->th.th_current_task = this_thr->th.th_current_task->td_parent;
397
398 KF_TRACE(10, ("__kmp_pop_current_task_from_thread(exit): T#%d "
399 "this_thread=%p, curtask=%p, "
400 "curtask_parent=%p\n",
401 0, this_thr, this_thr->th.th_current_task,
402 this_thr->th.th_current_task->td_parent));
403}
404
405// __kmp_push_current_task_to_thread: set up current task in called thread for a
406// new team
407//
408// this_thr: thread structure to set up
409// team: team for implicit task data
410// tid: thread within team to set up
411void __kmp_push_current_task_to_thread(kmp_info_t *this_thr, kmp_team_t *team,
412 int tid) {
413 // current task of the thread is a parent of the new just created implicit
414 // tasks of new team
415 KF_TRACE(10, ("__kmp_push_current_task_to_thread(enter): T#%d this_thread=%p "
416 "curtask=%p "
417 "parent_task=%p\n",
418 tid, this_thr, this_thr->th.th_current_task,
419 team->t.t_implicit_task_taskdata[tid].td_parent));
420
421 KMP_DEBUG_ASSERT(this_thr != NULL);
422
423 if (tid == 0) {
424 if (this_thr->th.th_current_task != &team->t.t_implicit_task_taskdata[0]) {
425 team->t.t_implicit_task_taskdata[0].td_parent =
426 this_thr->th.th_current_task;
427 this_thr->th.th_current_task = &team->t.t_implicit_task_taskdata[0];
428 }
429 } else {
430 team->t.t_implicit_task_taskdata[tid].td_parent =
431 team->t.t_implicit_task_taskdata[0].td_parent;
432 this_thr->th.th_current_task = &team->t.t_implicit_task_taskdata[tid];
433 }
434
435 KF_TRACE(10, ("__kmp_push_current_task_to_thread(exit): T#%d this_thread=%p "
436 "curtask=%p "
437 "parent_task=%p\n",
438 tid, this_thr, this_thr->th.th_current_task,
439 team->t.t_implicit_task_taskdata[tid].td_parent));
440}
441
442// __kmp_task_start: bookkeeping for a task starting execution
443//
444// GTID: global thread id of calling thread
445// task: task starting execution
446// current_task: task suspending
447static void __kmp_task_start(kmp_int32 gtid, kmp_task_t *task,
448 kmp_taskdata_t *current_task) {
449 kmp_taskdata_t *taskdata = KMP_TASK_TO_TASKDATA(task);
450 kmp_info_t *thread = __kmp_threads[gtid];
451
452 KA_TRACE(10,
453 ("__kmp_task_start(enter): T#%d starting task %p: current_task=%p\n",
454 gtid, taskdata, current_task));
455
456 KMP_DEBUG_ASSERT(taskdata->td_flags.tasktype == TASK_EXPLICIT);
457
458 // mark currently executing task as suspended
459 // TODO: GEH - make sure root team implicit task is initialized properly.
460 // KMP_DEBUG_ASSERT( current_task -> td_flags.executing == 1 );
461 current_task->td_flags.executing = 0;
462
463 // An untied task is never itself part of the set of tied tasks the thread is
464 // bound to, so it inherits the innermost enclosing tied task from the task it
465 // suspends. This has to happen before the task becomes the current task: the
466 // task scheduling constraint reads td_last_tied off th_current_task, so
467 // anything scheduled from this task (at a nested taskwait, or from
468 // __kmp_release_deps() once it completes) would otherwise observe the NULL
469 // left behind by __kmp_task_alloc(). The chain is OK because implicit and
470 // tied tasks point at themselves.
471 if (UNLIKELY(taskdata->td_flags.tiedness == TASK_UNTIED)) {
472 taskdata->td_last_tied = current_task->td_last_tied;
473 KMP_DEBUG_ASSERT(taskdata->td_last_tied);
474 }
475
476 // mark starting task as executing and as current task
477 thread->th.th_current_task = taskdata;
478
479 KMP_DEBUG_ASSERT(taskdata->td_flags.started == 0 ||
480 taskdata->td_flags.tiedness == TASK_UNTIED);
481 KMP_DEBUG_ASSERT(taskdata->td_flags.executing == 0 ||
482 taskdata->td_flags.tiedness == TASK_UNTIED);
483 taskdata->td_flags.started = 1;
484 taskdata->td_flags.executing = 1;
485 KMP_DEBUG_ASSERT(taskdata->td_flags.complete == 0);
486 KMP_DEBUG_ASSERT(taskdata->td_flags.freed == 0);
487
488 // GEH TODO: shouldn't we pass some sort of location identifier here?
489 // APT: yes, we will pass location here.
490 // need to store current thread state (in a thread or taskdata structure)
491 // before setting work_state, otherwise wrong state is set after end of task
492
493 KA_TRACE(10, ("__kmp_task_start(exit): T#%d task=%p\n", gtid, taskdata));
494
495 return;
496}
497
498#if OMPT_SUPPORT
499//------------------------------------------------------------------------------
500
501// __ompt_task_start:
502// Build and trigger task-begin event
503static inline void __ompt_task_start(kmp_task_t *task,
504 kmp_taskdata_t *current_task,
505 kmp_int32 gtid) {
506 kmp_taskdata_t *taskdata = KMP_TASK_TO_TASKDATA(task);
507 ompt_task_status_t status = ompt_task_switch;
508 if (__kmp_threads[gtid]->th.ompt_thread_info.ompt_task_yielded) {
509 status = ompt_task_yield;
510 __kmp_threads[gtid]->th.ompt_thread_info.ompt_task_yielded = 0;
511 }
512 /* let OMPT know that we're about to run this task */
513 if (ompt_enabled.ompt_callback_task_schedule) {
514 ompt_callbacks.ompt_callback(ompt_callback_task_schedule)(
515 &(current_task->ompt_task_info.task_data), status,
516 &(taskdata->ompt_task_info.task_data));
517 }
518 taskdata->ompt_task_info.scheduling_parent = current_task;
519}
520
521// __ompt_task_finish:
522// Build and trigger final task-schedule event
523static inline void __ompt_task_finish(kmp_task_t *task,
524 kmp_taskdata_t *resumed_task,
525 ompt_task_status_t status) {
526 if (ompt_enabled.ompt_callback_task_schedule) {
527 kmp_taskdata_t *taskdata = KMP_TASK_TO_TASKDATA(task);
528 if (__kmp_omp_cancellation && taskdata->td_taskgroup &&
529 taskdata->td_taskgroup->cancel_request == cancel_taskgroup) {
530 status = ompt_task_cancel;
531 }
532
533 /* let OMPT know that we're returning to the callee task */
534 ompt_callbacks.ompt_callback(ompt_callback_task_schedule)(
535 &(taskdata->ompt_task_info.task_data), status,
536 (resumed_task ? &(resumed_task->ompt_task_info.task_data) : NULL));
537 }
538}
539#endif
540
541template <bool ompt>
542static void __kmpc_omp_task_begin_if0_template(ident_t *loc_ref, kmp_int32 gtid,
543 kmp_task_t *task,
544 void *frame_address,
545 void *return_address) {
546 kmp_taskdata_t *taskdata = KMP_TASK_TO_TASKDATA(task);
547 kmp_taskdata_t *current_task = __kmp_threads[gtid]->th.th_current_task;
548
549 KA_TRACE(10, ("__kmpc_omp_task_begin_if0(enter): T#%d loc=%p task=%p "
550 "current_task=%p\n",
551 gtid, loc_ref, taskdata, current_task));
552
553 if (UNLIKELY(taskdata->td_flags.tiedness == TASK_UNTIED)) {
554 // untied task needs to increment counter so that the task structure is not
555 // freed prematurely
556 kmp_int32 counter = 1 + KMP_ATOMIC_INC(&taskdata->td_untied_count);
557 KMP_DEBUG_USE_VAR(counter);
558 KA_TRACE(20, ("__kmpc_omp_task_begin_if0: T#%d untied_count (%d) "
559 "incremented for task %p\n",
560 gtid, counter, taskdata));
561 }
562
563 taskdata->td_flags.task_serial =
564 1; // Execute this task immediately, not deferred.
565 __kmp_task_start(gtid, task, current_task);
566
567#if OMPT_SUPPORT
568 if (ompt) {
569 if (current_task->ompt_task_info.frame.enter_frame.ptr == NULL) {
570 current_task->ompt_task_info.frame.enter_frame.ptr =
571 taskdata->ompt_task_info.frame.exit_frame.ptr = frame_address;
572 current_task->ompt_task_info.frame.enter_frame_flags =
573 taskdata->ompt_task_info.frame.exit_frame_flags =
574 OMPT_FRAME_FLAGS_APP;
575 }
576 if (ompt_enabled.ompt_callback_task_create) {
577 ompt_task_info_t *parent_info = &(current_task->ompt_task_info);
578 ompt_callbacks.ompt_callback(ompt_callback_task_create)(
579 &(parent_info->task_data), &(parent_info->frame),
580 &(taskdata->ompt_task_info.task_data),
581 TASK_TYPE_DETAILS_FORMAT(taskdata), 0, return_address);
582 }
583 __ompt_task_start(task, current_task, gtid);
584 }
585#endif // OMPT_SUPPORT
586
587 KA_TRACE(10, ("__kmpc_omp_task_begin_if0(exit): T#%d loc=%p task=%p,\n", gtid,
588 loc_ref, taskdata));
589}
590
591#if OMPT_SUPPORT
592OMPT_NOINLINE
593static void __kmpc_omp_task_begin_if0_ompt(ident_t *loc_ref, kmp_int32 gtid,
594 kmp_task_t *task,
595 void *frame_address,
596 void *return_address) {
597 __kmpc_omp_task_begin_if0_template<true>(loc_ref, gtid, task, frame_address,
598 return_address);
599}
600#endif // OMPT_SUPPORT
601
602// __kmpc_omp_task_begin_if0: report that a given serialized task has started
603// execution
604//
605// loc_ref: source location information; points to beginning of task block.
606// gtid: global thread number.
607// task: task thunk for the started task.
608#ifdef __s390x__
609// This is required for OMPT_GET_FRAME_ADDRESS(1) to compile on s390x.
610// In order for it to work correctly, the caller also needs to be compiled with
611// backchain. If a caller is compiled without backchain,
612// OMPT_GET_FRAME_ADDRESS(1) will produce an incorrect value, but will not
613// crash.
614__attribute__((target("backchain")))
615#endif
616void __kmpc_omp_task_begin_if0(ident_t *loc_ref, kmp_int32 gtid,
617 kmp_task_t *task) {
618#if OMPT_SUPPORT
619 if (UNLIKELY(ompt_enabled.enabled)) {
620 OMPT_STORE_RETURN_ADDRESS(gtid);
621 __kmpc_omp_task_begin_if0_ompt(loc_ref, gtid, task,
622 OMPT_GET_FRAME_ADDRESS(1),
623 OMPT_LOAD_RETURN_ADDRESS(gtid));
624 return;
625 }
626#endif
627 __kmpc_omp_task_begin_if0_template<false>(loc_ref, gtid, task, NULL, NULL);
628}
629
630#ifdef TASK_UNUSED
631// __kmpc_omp_task_begin: report that a given task has started execution
632// NEVER GENERATED BY COMPILER, DEPRECATED!!!
633void __kmpc_omp_task_begin(ident_t *loc_ref, kmp_int32 gtid, kmp_task_t *task) {
634 kmp_taskdata_t *current_task = __kmp_threads[gtid]->th.th_current_task;
635
636 KA_TRACE(
637 10,
638 ("__kmpc_omp_task_begin(enter): T#%d loc=%p task=%p current_task=%p\n",
639 gtid, loc_ref, KMP_TASK_TO_TASKDATA(task), current_task));
640
641 __kmp_task_start(gtid, task, current_task);
642
643 KA_TRACE(10, ("__kmpc_omp_task_begin(exit): T#%d loc=%p task=%p,\n", gtid,
644 loc_ref, KMP_TASK_TO_TASKDATA(task)));
645 return;
646}
647#endif // TASK_UNUSED
648
649// __kmp_free_task: free the current task space and the space for shareds
650//
651// gtid: Global thread ID of calling thread
652// taskdata: task to free
653// thread: thread data structure of caller
654static void __kmp_free_task(kmp_int32 gtid, kmp_taskdata_t *taskdata,
655 kmp_info_t *thread) {
656 KA_TRACE(30, ("__kmp_free_task: T#%d freeing data from task %p\n", gtid,
657 taskdata));
658
659 // Check to make sure all flags and counters have the correct values
660 KMP_DEBUG_ASSERT(taskdata->td_flags.tasktype == TASK_EXPLICIT);
661 KMP_DEBUG_ASSERT(taskdata->td_flags.executing == 0);
662 KMP_DEBUG_ASSERT(taskdata->td_flags.complete == 1);
663 KMP_DEBUG_ASSERT(taskdata->td_flags.freed == 0);
664 KMP_DEBUG_ASSERT(taskdata->td_allocated_child_tasks == 0 ||
665 taskdata->td_flags.task_serial == 1);
666 KMP_DEBUG_ASSERT(taskdata->td_incomplete_child_tasks == 0);
667 kmp_task_t *task = KMP_TASKDATA_TO_TASK(taskdata);
668 // Clear data to not be re-used later by mistake.
669 task->data1.destructors = NULL;
670 task->data2.priority = 0;
671
672 taskdata->td_flags.freed = 1;
673// deallocate the taskdata and shared variable blocks associated with this task
674#if USE_FAST_MEMORY
675 __kmp_fast_free(thread, taskdata);
676#else /* ! USE_FAST_MEMORY */
677 __kmp_thread_free(thread, taskdata);
678#endif
679
680 KA_TRACE(20, ("__kmp_free_task: T#%d freed task %p\n", gtid, taskdata));
681}
682
683// __kmp_free_task_and_ancestors: free the current task and ancestors without
684// children
685//
686// gtid: Global thread ID of calling thread
687// taskdata: task to free
688// thread: thread data structure of caller
689static void __kmp_free_task_and_ancestors(kmp_int32 gtid,
690 kmp_taskdata_t *taskdata,
691 kmp_info_t *thread) {
692 // Proxy tasks must always be allowed to free their parents
693 // because they can be run in background even in serial mode.
694 kmp_int32 team_serial =
695 (taskdata->td_flags.team_serial || taskdata->td_flags.tasking_ser) &&
696 !taskdata->td_flags.proxy;
697 KMP_DEBUG_ASSERT(taskdata->td_flags.tasktype == TASK_EXPLICIT);
698
699 kmp_int32 children = KMP_ATOMIC_DEC(&taskdata->td_allocated_child_tasks) - 1;
700 KMP_DEBUG_ASSERT(children >= 0);
701
702 // Now, go up the ancestor tree to see if any ancestors can now be freed.
703 while (children == 0) {
704 kmp_taskdata_t *parent_taskdata = taskdata->td_parent;
705
706 KA_TRACE(20, ("__kmp_free_task_and_ancestors(enter): T#%d task %p complete "
707 "and freeing itself\n",
708 gtid, taskdata));
709
710 // --- Deallocate my ancestor task ---
711 __kmp_free_task(gtid, taskdata, thread);
712
713 taskdata = parent_taskdata;
714
715 if (team_serial)
716 return;
717 // Stop checking ancestors at implicit task instead of walking up ancestor
718 // tree to avoid premature deallocation of ancestors.
719 if (taskdata->td_flags.tasktype == TASK_IMPLICIT) {
720 if (taskdata->td_dephash) { // do we need to cleanup dephash?
721 int children = KMP_ATOMIC_LD_ACQ(&taskdata->td_incomplete_child_tasks);
722 kmp_tasking_flags_t flags_old = taskdata->td_flags;
723 if (children == 0 && flags_old.complete == 1) {
724 kmp_tasking_flags_t flags_new = flags_old;
725 flags_new.complete = 0;
726 if (KMP_COMPARE_AND_STORE_ACQ32(
727 RCAST(kmp_int32 *, &taskdata->td_flags),
728 *RCAST(kmp_int32 *, &flags_old),
729 *RCAST(kmp_int32 *, &flags_new))) {
730 KA_TRACE(100, ("__kmp_free_task_and_ancestors: T#%d cleans "
731 "dephash of implicit task %p\n",
732 gtid, taskdata));
733 // cleanup dephash of finished implicit task
734 __kmp_dephash_free_entries(thread, taskdata->td_dephash);
735 }
736 }
737 }
738 return;
739 }
740 // Predecrement simulated by "- 1" calculation
741 children = KMP_ATOMIC_DEC(&taskdata->td_allocated_child_tasks) - 1;
742 KMP_DEBUG_ASSERT(children >= 0);
743 }
744
745 KA_TRACE(
746 20, ("__kmp_free_task_and_ancestors(exit): T#%d task %p has %d children; "
747 "not freeing it yet\n",
748 gtid, taskdata, children));
749}
750
751// Only need to keep track of child task counts if any of the following:
752// 1. team parallel and tasking not serialized;
753// 2. it is a proxy or detachable or hidden helper task
754// 3. the children counter of its parent task is greater than 0.
755// The reason for the 3rd one is for serialized team that found detached task,
756// hidden helper task, T. In this case, the execution of T is still deferred,
757// and it is also possible that a regular task depends on T. In this case, if we
758// don't track the children, task synchronization will be broken.
759static bool __kmp_track_children_task(kmp_taskdata_t *taskdata) {
760 kmp_tasking_flags_t flags = taskdata->td_flags;
761 bool ret = !(flags.team_serial || flags.tasking_ser);
762 ret = ret || flags.proxy == TASK_PROXY ||
763 flags.detachable == TASK_DETACHABLE || flags.hidden_helper;
764 ret = ret ||
765 KMP_ATOMIC_LD_ACQ(&taskdata->td_parent->td_incomplete_child_tasks) > 0;
766 return ret;
767}
768
769// __kmp_task_finish: bookkeeping to do when a task finishes execution
770//
771// gtid: global thread ID for calling thread
772// task: task to be finished
773// resumed_task: task to be resumed. (may be NULL if task is serialized)
774//
775// template<ompt>: effectively ompt_enabled.enabled!=0
776// the version with ompt=false is inlined, allowing to optimize away all ompt
777// code in this case
778template <bool ompt>
779static void __kmp_task_finish(kmp_int32 gtid, kmp_task_t *task,
780 kmp_taskdata_t *resumed_task) {
781 kmp_taskdata_t *taskdata = KMP_TASK_TO_TASKDATA(task);
782 kmp_info_t *thread = __kmp_threads[gtid];
783 kmp_task_team_t *task_team =
784 thread->th.th_task_team; // might be NULL for serial teams...
785#if KMP_DEBUG
786 kmp_int32 children = 0;
787#endif
788 KA_TRACE(10, ("__kmp_task_finish(enter): T#%d finishing task %p and resuming "
789 "task %p\n",
790 gtid, taskdata, resumed_task));
791
792 KMP_DEBUG_ASSERT(taskdata->td_flags.tasktype == TASK_EXPLICIT);
793
794 if (UNLIKELY(taskdata->td_flags.tiedness == TASK_UNTIED)) {
795 // untied task needs to check the counter so that the task structure is not
796 // freed prematurely
797 kmp_int32 counter = KMP_ATOMIC_DEC(&taskdata->td_untied_count) - 1;
798 KA_TRACE(
799 20,
800 ("__kmp_task_finish: T#%d untied_count (%d) decremented for task %p\n",
801 gtid, counter, taskdata));
802 if (counter > 0) {
803 // untied task is not done, to be continued possibly by other thread, do
804 // not free it now
805 if (resumed_task == NULL) {
806 KMP_DEBUG_ASSERT(taskdata->td_flags.task_serial);
807 resumed_task = taskdata->td_parent; // In a serialized task, the resumed
808 // task is the parent
809 }
810 thread->th.th_current_task = resumed_task; // restore current_task
811 resumed_task->td_flags.executing = 1; // resume previous task
812 KA_TRACE(10, ("__kmp_task_finish(exit): T#%d partially done task %p, "
813 "resuming task %p\n",
814 gtid, taskdata, resumed_task));
815 return;
816 }
817 }
818
819 // bookkeeping for resuming task:
820 // GEH - note tasking_ser => task_serial
821 KMP_DEBUG_ASSERT(
822 (taskdata->td_flags.tasking_ser || taskdata->td_flags.task_serial) ==
823 taskdata->td_flags.task_serial);
824 if (taskdata->td_flags.task_serial) {
825 if (resumed_task == NULL) {
826 resumed_task = taskdata->td_parent; // In a serialized task, the resumed
827 // task is the parent
828 }
829 } else {
830 KMP_DEBUG_ASSERT(resumed_task !=
831 NULL); // verify that resumed task is passed as argument
832 }
833
834 /* If the tasks' destructor thunk flag has been set, we need to invoke the
835 destructor thunk that has been generated by the compiler. The code is
836 placed here, since at this point other tasks might have been released
837 hence overlapping the destructor invocations with some other work in the
838 released tasks. The OpenMP spec is not specific on when the destructors
839 are invoked, so we should be free to choose. */
840 if (UNLIKELY(taskdata->td_flags.destructors_thunk)) {
841 kmp_routine_entry_t destr_thunk = task->data1.destructors;
842 KMP_ASSERT(destr_thunk);
843 destr_thunk(gtid, task);
844 }
845
846 KMP_DEBUG_ASSERT(taskdata->td_flags.complete == 0);
847 KMP_DEBUG_ASSERT(taskdata->td_flags.started == 1);
848 KMP_DEBUG_ASSERT(taskdata->td_flags.freed == 0);
849
850 bool completed = true;
851 if (UNLIKELY(taskdata->td_flags.detachable == TASK_DETACHABLE)) {
852 if (taskdata->td_allow_completion_event.type ==
853 KMP_EVENT_ALLOW_COMPLETION) {
854 // event hasn't been fulfilled yet. Try to detach task.
855 __kmp_acquire_tas_lock(&taskdata->td_allow_completion_event.lock, gtid);
856 if (taskdata->td_allow_completion_event.type ==
857 KMP_EVENT_ALLOW_COMPLETION) {
858 // task finished execution
859 KMP_DEBUG_ASSERT(taskdata->td_flags.executing == 1);
860 taskdata->td_flags.executing = 0; // suspend the finishing task
861
862#if OMPT_SUPPORT
863 // For a detached task, which is not completed, we switch back
864 // the omp_fulfill_event signals completion
865 // locking is necessary to avoid a race with ompt_task_late_fulfill
866 if (ompt)
867 __ompt_task_finish(task, resumed_task, ompt_task_detach);
868#endif
869
870 // no access to taskdata after this point!
871 // __kmp_fulfill_event might free taskdata at any time from now
872
873 taskdata->td_flags.proxy = TASK_PROXY; // proxify!
874 completed = false;
875 }
876 __kmp_release_tas_lock(&taskdata->td_allow_completion_event.lock, gtid);
877 }
878 }
879
880 // Tasks with valid target async handles must be re-enqueued.
881 if (taskdata->td_target_data.async_handle != NULL) {
882 // Note: no need to translate gtid to its shadow. If the current thread is a
883 // hidden helper one, then the gtid is already correct. Otherwise, hidden
884 // helper threads are disabled, and gtid refers to a OpenMP thread.
885#if OMPT_SUPPORT
886 if (ompt) {
887 __ompt_task_finish(task, resumed_task, ompt_task_switch);
888 }
889#endif
890 __kmpc_give_task(task, __kmp_tid_from_gtid(gtid));
891 if (KMP_HIDDEN_HELPER_THREAD(gtid))
892 __kmp_hidden_helper_worker_thread_signal();
893 completed = false;
894 }
895
896 if (completed) {
897 taskdata->td_flags.complete = 1; // mark the task as completed
898
899#if OMPT_SUPPORT
900 // This is not a detached task, we are done here
901 if (ompt)
902 __ompt_task_finish(task, resumed_task, ompt_task_complete);
903#endif
904 // TODO: What would be the balance between the conditions in the function
905 // and an atomic operation?
906 if (__kmp_track_children_task(taskdata)) {
907 __kmp_release_deps(gtid, taskdata);
908 // Predecrement simulated by "- 1" calculation
909#if KMP_DEBUG
910 children = -1 +
911#endif
912 KMP_ATOMIC_DEC(&taskdata->td_parent->td_incomplete_child_tasks);
913 KMP_DEBUG_ASSERT(children >= 0);
914 if (taskdata->td_taskgroup)
915 KMP_ATOMIC_DEC(&taskdata->td_taskgroup->count);
916 } else if (task_team && (task_team->tt.tt_found_proxy_tasks ||
917 task_team->tt.tt_hidden_helper_task_encountered)) {
918 // if we found proxy or hidden helper tasks there could exist a dependency
919 // chain with the proxy task as origin
920 __kmp_release_deps(gtid, taskdata);
921 }
922 // td_flags.executing must be marked as 0 after __kmp_release_deps has been
923 // called. Othertwise, if a task is executed immediately from the
924 // release_deps code, the flag will be reset to 1 again by this same
925 // function
926 KMP_DEBUG_ASSERT(taskdata->td_flags.executing == 1);
927 taskdata->td_flags.executing = 0; // suspend the finishing task
928
929 // Decrement the counter of hidden helper tasks to be executed.
930 if (taskdata->td_flags.hidden_helper) {
931 // Hidden helper tasks can only be executed by hidden helper threads.
932 KMP_ASSERT(KMP_HIDDEN_HELPER_THREAD(gtid));
933 KMP_ATOMIC_DEC(&__kmp_unexecuted_hidden_helper_tasks);
934 }
935 }
936
937 KA_TRACE(
938 20, ("__kmp_task_finish: T#%d finished task %p, %d incomplete children\n",
939 gtid, taskdata, children));
940
941 // Free this task and then ancestor tasks if they have no children.
942 // Restore th_current_task first as suggested by John:
943 // johnmc: if an asynchronous inquiry peers into the runtime system
944 // it doesn't see the freed task as the current task.
945 thread->th.th_current_task = resumed_task;
946 if (completed)
947 __kmp_free_task_and_ancestors(gtid, taskdata, thread);
948
949 // TODO: GEH - make sure root team implicit task is initialized properly.
950 // KMP_DEBUG_ASSERT( resumed_task->td_flags.executing == 0 );
951 resumed_task->td_flags.executing = 1; // resume previous task
952
953 KA_TRACE(
954 10, ("__kmp_task_finish(exit): T#%d finished task %p, resuming task %p\n",
955 gtid, taskdata, resumed_task));
956
957 return;
958}
959
960template <bool ompt>
961static void __kmpc_omp_task_complete_if0_template(ident_t *loc_ref,
962 kmp_int32 gtid,
963 kmp_task_t *task) {
964 KA_TRACE(10, ("__kmpc_omp_task_complete_if0(enter): T#%d loc=%p task=%p\n",
965 gtid, loc_ref, KMP_TASK_TO_TASKDATA(task)));
966 KMP_DEBUG_ASSERT(gtid >= 0);
967 // this routine will provide task to resume
968 __kmp_task_finish<ompt>(gtid, task, NULL);
969
970 KA_TRACE(10, ("__kmpc_omp_task_complete_if0(exit): T#%d loc=%p task=%p\n",
971 gtid, loc_ref, KMP_TASK_TO_TASKDATA(task)));
972
973#if OMPT_SUPPORT
974 if (ompt) {
975 ompt_frame_t *ompt_frame;
976 __ompt_get_task_info_internal(0, NULL, NULL, &ompt_frame, NULL, NULL);
977 ompt_frame->enter_frame = ompt_data_none;
978 ompt_frame->enter_frame_flags = OMPT_FRAME_FLAGS_RUNTIME;
979 }
980#endif
981
982 return;
983}
984
985#if OMPT_SUPPORT
986OMPT_NOINLINE
987void __kmpc_omp_task_complete_if0_ompt(ident_t *loc_ref, kmp_int32 gtid,
988 kmp_task_t *task) {
989 __kmpc_omp_task_complete_if0_template<true>(loc_ref, gtid, task);
990}
991#endif // OMPT_SUPPORT
992
993// __kmpc_omp_task_complete_if0: report that a task has completed execution
994//
995// loc_ref: source location information; points to end of task block.
996// gtid: global thread number.
997// task: task thunk for the completed task.
998void __kmpc_omp_task_complete_if0(ident_t *loc_ref, kmp_int32 gtid,
999 kmp_task_t *task) {
1000#if OMPT_SUPPORT
1001 if (UNLIKELY(ompt_enabled.enabled)) {
1002 __kmpc_omp_task_complete_if0_ompt(loc_ref, gtid, task);
1003 return;
1004 }
1005#endif
1006 __kmpc_omp_task_complete_if0_template<false>(loc_ref, gtid, task);
1007}
1008
1009#ifdef TASK_UNUSED
1010// __kmpc_omp_task_complete: report that a task has completed execution
1011// NEVER GENERATED BY COMPILER, DEPRECATED!!!
1012void __kmpc_omp_task_complete(ident_t *loc_ref, kmp_int32 gtid,
1013 kmp_task_t *task) {
1014 KA_TRACE(10, ("__kmpc_omp_task_complete(enter): T#%d loc=%p task=%p\n", gtid,
1015 loc_ref, KMP_TASK_TO_TASKDATA(task)));
1016
1017 __kmp_task_finish<false>(gtid, task,
1018 NULL); // Not sure how to find task to resume
1019
1020 KA_TRACE(10, ("__kmpc_omp_task_complete(exit): T#%d loc=%p task=%p\n", gtid,
1021 loc_ref, KMP_TASK_TO_TASKDATA(task)));
1022 return;
1023}
1024#endif // TASK_UNUSED
1025
1026// __kmp_init_implicit_task: Initialize the appropriate fields in the implicit
1027// task for a given thread
1028//
1029// loc_ref: reference to source location of parallel region
1030// this_thr: thread data structure corresponding to implicit task
1031// team: team for this_thr
1032// tid: thread id of given thread within team
1033// set_curr_task: TRUE if need to push current task to thread
1034// NOTE: Routine does not set up the implicit task ICVS. This is assumed to
1035// have already been done elsewhere.
1036// TODO: Get better loc_ref. Value passed in may be NULL
1037void __kmp_init_implicit_task(ident_t *loc_ref, kmp_info_t *this_thr,
1038 kmp_team_t *team, int tid, int set_curr_task) {
1039 kmp_taskdata_t *task = &team->t.t_implicit_task_taskdata[tid];
1040
1041 KF_TRACE(
1042 10,
1043 ("__kmp_init_implicit_task(enter): T#:%d team=%p task=%p, reinit=%s\n",
1044 tid, team, task, set_curr_task ? "TRUE" : "FALSE"));
1045
1046 task->td_task_id = KMP_GEN_TASK_ID();
1047 task->td_team = team;
1048 // task->td_parent = NULL; // fix for CQ230101 (broken parent task info
1049 // in debugger)
1050 task->td_ident = loc_ref;
1051 task->td_taskwait_ident = NULL;
1052 task->td_taskwait_counter = 0;
1053 task->td_taskwait_thread = 0;
1054
1055 task->td_flags.tiedness = TASK_TIED;
1056 task->td_flags.tasktype = TASK_IMPLICIT;
1057 task->td_flags.proxy = TASK_FULL;
1058
1059 // All implicit tasks are executed immediately, not deferred
1060 task->td_flags.task_serial = 1;
1061 task->td_flags.tasking_ser = (__kmp_tasking_mode == tskm_immediate_exec);
1062 task->td_flags.team_serial = (team->t.t_serialized) ? 1 : 0;
1063
1064 task->td_flags.started = 1;
1065 task->td_flags.executing = 1;
1066 task->td_flags.complete = 0;
1067 task->td_flags.freed = 0;
1068
1069 task->td_depnode = NULL;
1070 task->td_last_tied = task;
1071 task->td_allow_completion_event.type = KMP_EVENT_UNINITIALIZED;
1072
1073 if (set_curr_task) { // only do this init first time thread is created
1074 KMP_ATOMIC_ST_REL(&task->td_incomplete_child_tasks, 0);
1075 // Not used: don't need to deallocate implicit task
1076 KMP_ATOMIC_ST_REL(&task->td_allocated_child_tasks, 0);
1077 task->td_taskgroup = NULL; // An implicit task does not have taskgroup
1078 task->td_dephash = NULL;
1079 __kmp_push_current_task_to_thread(this_thr, team, tid);
1080 } else {
1081 KMP_DEBUG_ASSERT(task->td_incomplete_child_tasks == 0);
1082 KMP_DEBUG_ASSERT(task->td_allocated_child_tasks == 0);
1083 }
1084
1085#if OMPT_SUPPORT
1086 if (UNLIKELY(ompt_enabled.enabled))
1087 __ompt_task_init(task, tid);
1088#endif
1089
1090 KF_TRACE(10, ("__kmp_init_implicit_task(exit): T#:%d team=%p task=%p\n", tid,
1091 team, task));
1092}
1093
1094// __kmp_finish_implicit_task: Release resources associated to implicit tasks
1095// at the end of parallel regions. Some resources are kept for reuse in the next
1096// parallel region.
1097//
1098// thread: thread data structure corresponding to implicit task
1099void __kmp_finish_implicit_task(kmp_info_t *thread) {
1100 kmp_taskdata_t *task = thread->th.th_current_task;
1101#if ENABLE_LIBOMPTARGET
1102 // Give an opportunity to the offload runtime to synchronize any unfinished
1103 // target async regions before finishing the implicit task
1104 if (UNLIKELY(kmp_target_sync_cb != NULL))
1105 (*kmp_target_sync_cb)(NULL, thread->th.th_info.ds.ds_gtid,
1106 KMP_TASKDATA_TO_TASK(task), NULL);
1107#endif // ENABLE_LIBOMPTARGET
1108 if (task->td_dephash) {
1109 int children;
1110 task->td_flags.complete = 1;
1111 children = KMP_ATOMIC_LD_ACQ(&task->td_incomplete_child_tasks);
1112 kmp_tasking_flags_t flags_old = task->td_flags;
1113 if (children == 0 && flags_old.complete == 1) {
1114 kmp_tasking_flags_t flags_new = flags_old;
1115 flags_new.complete = 0;
1116 if (KMP_COMPARE_AND_STORE_ACQ32(RCAST(kmp_int32 *, &task->td_flags),
1117 *RCAST(kmp_int32 *, &flags_old),
1118 *RCAST(kmp_int32 *, &flags_new))) {
1119 KA_TRACE(100, ("__kmp_finish_implicit_task: T#%d cleans "
1120 "dephash of implicit task %p\n",
1121 thread->th.th_info.ds.ds_gtid, task));
1122 __kmp_dephash_free_entries(thread, task->td_dephash);
1123 }
1124 }
1125 }
1126}
1127
1128// __kmp_free_implicit_task: Release resources associated to implicit tasks
1129// when these are destroyed regions
1130//
1131// thread: thread data structure corresponding to implicit task
1132void __kmp_free_implicit_task(kmp_info_t *thread) {
1133 kmp_taskdata_t *task = thread->th.th_current_task;
1134 if (task && task->td_dephash) {
1135 __kmp_dephash_free(thread, task->td_dephash);
1136 task->td_dephash = NULL;
1137 }
1138}
1139
1140// Round up a size to a power of two specified by val: Used to insert padding
1141// between structures co-allocated using a single malloc() call
1142static size_t __kmp_round_up_to_val(size_t size, size_t val) {
1143 if (size & (val - 1)) {
1144 size &= ~(val - 1);
1145 if (size <= KMP_SIZE_T_MAX - val) {
1146 size += val; // Round up if there is no overflow.
1147 }
1148 }
1149 return size;
1150} // __kmp_round_up_to_va
1151
1152// __kmp_task_alloc: Allocate the taskdata and task data structures for a task
1153//
1154// loc_ref: source location information
1155// gtid: global thread number.
1156// flags: include tiedness & task type (explicit vs. implicit) of the ''new''
1157// task encountered. Converted from kmp_int32 to kmp_tasking_flags_t in routine.
1158// sizeof_kmp_task_t: Size in bytes of kmp_task_t data structure including
1159// private vars accessed in task.
1160// sizeof_shareds: Size in bytes of array of pointers to shared vars accessed
1161// in task.
1162// task_entry: Pointer to task code entry point generated by compiler.
1163// returns: a pointer to the allocated kmp_task_t structure (task).
1164kmp_task_t *__kmp_task_alloc(ident_t *loc_ref, kmp_int32 gtid,
1165 kmp_tasking_flags_t *flags,
1166 size_t sizeof_kmp_task_t, size_t sizeof_shareds,
1167 kmp_routine_entry_t task_entry) {
1168 kmp_task_t *task;
1169 kmp_taskdata_t *taskdata;
1170 kmp_info_t *thread = __kmp_threads[gtid];
1171 kmp_team_t *team = thread->th.th_team;
1172 kmp_taskdata_t *parent_task = thread->th.th_current_task;
1173 size_t shareds_offset;
1174
1175 if (UNLIKELY(!TCR_4(__kmp_init_middle)))
1176 __kmp_middle_initialize();
1177
1178 if (flags->hidden_helper) {
1179 if (__kmp_enable_hidden_helper) {
1180 if (!TCR_4(__kmp_init_hidden_helper))
1181 __kmp_hidden_helper_initialize();
1182 } else {
1183 // If the hidden helper task is not enabled, reset the flag to FALSE.
1184 flags->hidden_helper = FALSE;
1185 }
1186 }
1187
1188 KA_TRACE(10, ("__kmp_task_alloc(enter): T#%d loc=%p, flags=(0x%x) "
1189 "sizeof_task=%ld sizeof_shared=%ld entry=%p\n",
1190 gtid, loc_ref, *((kmp_int32 *)flags), sizeof_kmp_task_t,
1191 sizeof_shareds, task_entry));
1192
1193 KMP_DEBUG_ASSERT(parent_task);
1194 if (parent_task->td_flags.final) {
1195 if (flags->merged_if0) {
1196 }
1197 flags->final = 1;
1198 }
1199
1200 if (flags->tiedness == TASK_UNTIED && !team->t.t_serialized) {
1201 // Untied task encountered causes the TSC algorithm to check entire deque of
1202 // the victim thread. If no untied task encountered, then checking the head
1203 // of the deque should be enough.
1204 KMP_CHECK_UPDATE(thread->th.th_task_team->tt.tt_untied_task_encountered, 1);
1205 }
1206
1207 // Detachable tasks are not proxy tasks yet but could be in the future. Doing
1208 // the tasking setup
1209 // when that happens is too late.
1210 if (UNLIKELY(flags->proxy == TASK_PROXY ||
1211 flags->detachable == TASK_DETACHABLE || flags->hidden_helper)) {
1212 if (flags->proxy == TASK_PROXY) {
1213 flags->tiedness = TASK_UNTIED;
1214 flags->merged_if0 = 1;
1215 }
1216 /* are we running in a sequential parallel or tskm_immediate_exec... we need
1217 tasking support enabled */
1218 if ((thread->th.th_task_team) == NULL) {
1219 /* This should only happen if the team is serialized
1220 setup a task team and propagate it to the thread */
1221 KMP_DEBUG_ASSERT(team->t.t_serialized);
1222 KA_TRACE(30,
1223 ("T#%d creating task team in __kmp_task_alloc for proxy task\n",
1224 gtid));
1225 __kmp_task_team_setup(thread, team);
1226 thread->th.th_task_team = team->t.t_task_team[thread->th.th_task_state];
1227 }
1228 kmp_task_team_t *task_team = thread->th.th_task_team;
1229
1230 /* tasking must be enabled now as the task might not be pushed */
1231 if (!KMP_TASKING_ENABLED(task_team)) {
1232 KA_TRACE(
1233 30,
1234 ("T#%d enabling tasking in __kmp_task_alloc for proxy task\n", gtid));
1235 __kmp_enable_tasking(task_team, thread);
1236 kmp_int32 tid = thread->th.th_info.ds.ds_tid;
1237 kmp_thread_data_t *thread_data = &task_team->tt.tt_threads_data[tid];
1238 // No lock needed since only owner can allocate
1239 if (thread_data->td.td_deque == NULL) {
1240 __kmp_alloc_task_deque(thread, thread_data);
1241 }
1242 }
1243
1244 if ((flags->proxy == TASK_PROXY || flags->detachable == TASK_DETACHABLE) &&
1245 task_team->tt.tt_found_proxy_tasks == FALSE)
1246 TCW_4(task_team->tt.tt_found_proxy_tasks, TRUE);
1247 if (flags->hidden_helper &&
1248 task_team->tt.tt_hidden_helper_task_encountered == FALSE)
1249 TCW_4(task_team->tt.tt_hidden_helper_task_encountered, TRUE);
1250 }
1251
1252 // Calculate shared structure offset including padding after kmp_task_t struct
1253 // to align pointers in shared struct
1254 shareds_offset = sizeof(kmp_taskdata_t) + sizeof_kmp_task_t;
1255 shareds_offset = __kmp_round_up_to_val(shareds_offset, sizeof(kmp_uint64));
1256
1257 // Allocate a kmp_taskdata_t block and a kmp_task_t block.
1258 KA_TRACE(30, ("__kmp_task_alloc: T#%d First malloc size: %ld\n", gtid,
1259 shareds_offset));
1260 KA_TRACE(30, ("__kmp_task_alloc: T#%d Second malloc size: %ld\n", gtid,
1261 sizeof_shareds));
1262
1263 // Avoid double allocation here by combining shareds with taskdata
1264#if USE_FAST_MEMORY
1265 taskdata = (kmp_taskdata_t *)__kmp_fast_allocate(thread, shareds_offset +
1266 sizeof_shareds);
1267#else /* ! USE_FAST_MEMORY */
1268 taskdata = (kmp_taskdata_t *)__kmp_thread_malloc(thread, shareds_offset +
1269 sizeof_shareds);
1270#endif /* USE_FAST_MEMORY */
1271
1272 task = KMP_TASKDATA_TO_TASK(taskdata);
1273
1274// Make sure task & taskdata are aligned appropriately
1275#if KMP_ARCH_X86 || KMP_ARCH_PPC64 || KMP_ARCH_S390X || !KMP_HAVE_QUAD
1276 KMP_DEBUG_ASSERT((((kmp_uintptr_t)taskdata) & (sizeof(double) - 1)) == 0);
1277 KMP_DEBUG_ASSERT((((kmp_uintptr_t)task) & (sizeof(double) - 1)) == 0);
1278#else
1279 KMP_DEBUG_ASSERT((((kmp_uintptr_t)taskdata) & (sizeof(_Quad) - 1)) == 0);
1280 KMP_DEBUG_ASSERT((((kmp_uintptr_t)task) & (sizeof(_Quad) - 1)) == 0);
1281#endif
1282 if (sizeof_shareds > 0) {
1283 // Avoid double allocation here by combining shareds with taskdata
1284 task->shareds = &((char *)taskdata)[shareds_offset];
1285 // Make sure shareds struct is aligned to pointer size
1286 KMP_DEBUG_ASSERT((((kmp_uintptr_t)task->shareds) & (sizeof(void *) - 1)) ==
1287 0);
1288 } else {
1289 task->shareds = NULL;
1290 }
1291 task->routine = task_entry;
1292 task->part_id = 0; // AC: Always start with 0 part id
1293
1294 taskdata->td_task_id = KMP_GEN_TASK_ID();
1295 taskdata->td_team = thread->th.th_team;
1296 taskdata->td_alloc_thread = thread;
1297 taskdata->td_parent = parent_task;
1298 taskdata->td_level = parent_task->td_level + 1; // increment nesting level
1299 KMP_ATOMIC_ST_RLX(&taskdata->td_untied_count, 0);
1300 taskdata->td_ident = loc_ref;
1301 taskdata->td_taskwait_ident = NULL;
1302 taskdata->td_taskwait_counter = 0;
1303 taskdata->td_taskwait_thread = 0;
1304 KMP_DEBUG_ASSERT(taskdata->td_parent != NULL);
1305 // avoid copying icvs for proxy tasks
1306 if (flags->proxy == TASK_FULL)
1307 copy_icvs(&taskdata->td_icvs, &taskdata->td_parent->td_icvs);
1308
1309 taskdata->td_flags = *flags;
1310 taskdata->td_task_team = thread->th.th_task_team;
1311 taskdata->td_size_alloc = shareds_offset + sizeof_shareds;
1312 taskdata->td_flags.tasktype = TASK_EXPLICIT;
1313 // If it is hidden helper task, we need to set the team and task team
1314 // correspondingly.
1315 if (flags->hidden_helper) {
1316 kmp_info_t *shadow_thread = __kmp_threads[KMP_GTID_TO_SHADOW_GTID(gtid)];
1317 taskdata->td_team = shadow_thread->th.th_team;
1318 taskdata->td_task_team = shadow_thread->th.th_task_team;
1319 }
1320
1321 // GEH - TODO: fix this to copy parent task's value of tasking_ser flag
1322 taskdata->td_flags.tasking_ser = (__kmp_tasking_mode == tskm_immediate_exec);
1323
1324 // GEH - TODO: fix this to copy parent task's value of team_serial flag
1325 taskdata->td_flags.team_serial = (team->t.t_serialized) ? 1 : 0;
1326
1327 // GEH - Note we serialize the task if the team is serialized to make sure
1328 // implicit parallel region tasks are not left until program termination to
1329 // execute. Also, it helps locality to execute immediately.
1330
1331 taskdata->td_flags.task_serial =
1332 (parent_task->td_flags.final || taskdata->td_flags.team_serial ||
1333 taskdata->td_flags.tasking_ser || flags->merged_if0);
1334
1335 taskdata->td_flags.started = 0;
1336 taskdata->td_flags.executing = 0;
1337 taskdata->td_flags.complete = 0;
1338 taskdata->td_flags.freed = 0;
1339 KMP_ATOMIC_ST_RLX(&taskdata->td_incomplete_child_tasks, 0);
1340 // start at one because counts current task and children
1341 KMP_ATOMIC_ST_RLX(&taskdata->td_allocated_child_tasks, 1);
1342 taskdata->td_taskgroup =
1343 parent_task->td_taskgroup; // task inherits taskgroup from the parent task
1344 taskdata->td_dephash = NULL;
1345 taskdata->td_depnode = NULL;
1346 taskdata->td_target_data.async_handle = NULL;
1347 if (flags->tiedness == TASK_UNTIED)
1348 taskdata->td_last_tied = NULL; // will be set when the task is scheduled
1349 else
1350 taskdata->td_last_tied = taskdata;
1351 taskdata->td_allow_completion_event.type = KMP_EVENT_UNINITIALIZED;
1352#if OMPT_SUPPORT
1353 if (UNLIKELY(ompt_enabled.enabled))
1354 __ompt_task_init(taskdata, gtid);
1355#endif
1356 // TODO: What would be the balance between the conditions in the function and
1357 // an atomic operation?
1358 if (__kmp_track_children_task(taskdata)) {
1359 KMP_ATOMIC_INC(&parent_task->td_incomplete_child_tasks);
1360 if (parent_task->td_taskgroup)
1361 KMP_ATOMIC_INC(&parent_task->td_taskgroup->count);
1362 // Only need to keep track of allocated child tasks for explicit tasks since
1363 // implicit not deallocated
1364 if (taskdata->td_parent->td_flags.tasktype == TASK_EXPLICIT) {
1365 KMP_ATOMIC_INC(&taskdata->td_parent->td_allocated_child_tasks);
1366 }
1367 if (flags->hidden_helper) {
1368 taskdata->td_flags.task_serial = FALSE;
1369 // Increment the number of hidden helper tasks to be executed
1370 KMP_ATOMIC_INC(&__kmp_unexecuted_hidden_helper_tasks);
1371 }
1372 }
1373
1374 KA_TRACE(20, ("__kmp_task_alloc(exit): T#%d created task %p parent=%p\n",
1375 gtid, taskdata, taskdata->td_parent));
1376
1377 return task;
1378}
1379
1380kmp_task_t *__kmpc_omp_task_alloc(ident_t *loc_ref, kmp_int32 gtid,
1381 kmp_int32 flags, size_t sizeof_kmp_task_t,
1382 size_t sizeof_shareds,
1383 kmp_routine_entry_t task_entry) {
1384 kmp_task_t *retval;
1385 kmp_tasking_flags_t *input_flags = (kmp_tasking_flags_t *)&flags;
1386 __kmp_assert_valid_gtid(gtid);
1387 input_flags->native = FALSE;
1388 // __kmp_task_alloc() sets up all other runtime flags
1389 KA_TRACE(10, ("__kmpc_omp_task_alloc(enter): T#%d loc=%p, flags=(%s %s %s) "
1390 "sizeof_task=%ld sizeof_shared=%ld entry=%p\n",
1391 gtid, loc_ref, input_flags->tiedness ? "tied " : "untied",
1392 input_flags->proxy ? "proxy" : "",
1393 input_flags->detachable ? "detachable" : "", sizeof_kmp_task_t,
1394 sizeof_shareds, task_entry));
1395
1396 retval = __kmp_task_alloc(loc_ref, gtid, input_flags, sizeof_kmp_task_t,
1397 sizeof_shareds, task_entry);
1398
1399 KA_TRACE(20, ("__kmpc_omp_task_alloc(exit): T#%d retval %p\n", gtid, retval));
1400
1401 return retval;
1402}
1403
1404kmp_task_t *__kmpc_omp_target_task_alloc(ident_t *loc_ref, kmp_int32 gtid,
1405 kmp_int32 flags,
1406 size_t sizeof_kmp_task_t,
1407 size_t sizeof_shareds,
1408 kmp_routine_entry_t task_entry,
1409 kmp_int64 device_id) {
1410 auto &input_flags = reinterpret_cast<kmp_tasking_flags_t &>(flags);
1411 // target task is untied defined in the specification
1412 input_flags.tiedness = TASK_UNTIED;
1413 input_flags.target = 1;
1414
1415 if (__kmp_enable_hidden_helper)
1416 input_flags.hidden_helper = TRUE;
1417
1418 return __kmpc_omp_task_alloc(loc_ref, gtid, flags, sizeof_kmp_task_t,
1419 sizeof_shareds, task_entry);
1420}
1421
1435kmp_int32
1437 kmp_task_t *new_task, kmp_int32 naffins,
1438 kmp_task_affinity_info_t *affin_list) {
1439 if (naffins > 0)
1440 KMP_DEBUG_ASSERT(affin_list != NULL);
1441
1442 for (kmp_int32 i = 0; i < naffins; ++i) {
1443 KA_TRACE(30, ("__kmpc_omp_reg_task_with_affinity: T#%d aff[%d] "
1444 "base_addr=0x%llx len=%zu flags={%d,%d,%d}\n",
1445 gtid, i, (unsigned long long)affin_list[i].base_addr,
1446 affin_list[i].len, (int)affin_list[i].flags.flag1,
1447 (int)affin_list[i].flags.flag2,
1448 (int)affin_list[i].flags.reserved));
1449 }
1450
1451 return 0;
1452}
1453
1454// __kmp_invoke_task: invoke the specified task
1455//
1456// gtid: global thread ID of caller
1457// task: the task to invoke
1458// current_task: the task to resume after task invocation
1459#ifdef __s390x__
1460__attribute__((target("backchain")))
1461#endif
1462static void
1463__kmp_invoke_task(kmp_int32 gtid, kmp_task_t *task,
1464 kmp_taskdata_t *current_task) {
1465 kmp_taskdata_t *taskdata = KMP_TASK_TO_TASKDATA(task);
1466 kmp_info_t *thread;
1467 int discard = 0 /* false */;
1468 KA_TRACE(
1469 30, ("__kmp_invoke_task(enter): T#%d invoking task %p, current_task=%p\n",
1470 gtid, taskdata, current_task));
1471 KMP_DEBUG_ASSERT(task);
1472 if (UNLIKELY(taskdata->td_flags.proxy == TASK_PROXY &&
1473 taskdata->td_flags.complete == 1)) {
1474 // This is a proxy task that was already completed but it needs to run
1475 // its bottom-half finish
1476 KA_TRACE(
1477 30,
1478 ("__kmp_invoke_task: T#%d running bottom finish for proxy task %p\n",
1479 gtid, taskdata));
1480
1481 __kmp_bottom_half_finish_proxy(gtid, task);
1482
1483 KA_TRACE(30, ("__kmp_invoke_task(exit): T#%d completed bottom finish for "
1484 "proxy task %p, resuming task %p\n",
1485 gtid, taskdata, current_task));
1486
1487 return;
1488 }
1489
1490#if OMPT_SUPPORT
1491 // For untied tasks, the first task executed only calls __kmpc_omp_task and
1492 // does not execute code.
1493 ompt_thread_info_t oldInfo;
1494 if (UNLIKELY(ompt_enabled.enabled)) {
1495 // Store the threads states and restore them after the task
1496 thread = __kmp_threads[gtid];
1497 oldInfo = thread->th.ompt_thread_info;
1498 thread->th.ompt_thread_info.wait_id = 0;
1499 thread->th.ompt_thread_info.state = (thread->th.th_team_serialized)
1500 ? ompt_state_work_serial
1501 : ompt_state_work_parallel;
1502 taskdata->ompt_task_info.frame.exit_frame.ptr = OMPT_GET_FRAME_ADDRESS(0);
1503 }
1504#endif
1505
1506 // Proxy tasks are not handled by the runtime. They are forced untied, but
1507 // skipping __kmp_task_start() also means they never become the thread's
1508 // current task, so nothing ever reads their td_last_tied.
1509 if (taskdata->td_flags.proxy != TASK_PROXY) {
1510 __kmp_task_start(gtid, task, current_task); // OMPT only if not discarded
1511 }
1512
1513 // TODO: cancel tasks if the parallel region has also been cancelled
1514 // TODO: check if this sequence can be hoisted above __kmp_task_start
1515 // if cancellation has been enabled for this run ...
1516 if (UNLIKELY(__kmp_omp_cancellation)) {
1517 thread = __kmp_threads[gtid];
1518 kmp_team_t *this_team = thread->th.th_team;
1519 kmp_taskgroup_t *taskgroup = taskdata->td_taskgroup;
1520 if ((taskgroup && taskgroup->cancel_request) ||
1521 (this_team->t.t_cancel_request == cancel_parallel)) {
1522#if OMPT_SUPPORT && OMPT_OPTIONAL
1523 ompt_data_t *task_data;
1524 if (UNLIKELY(ompt_enabled.ompt_callback_cancel)) {
1525 __ompt_get_task_info_internal(0, NULL, &task_data, NULL, NULL, NULL);
1526 ompt_callbacks.ompt_callback(ompt_callback_cancel)(
1527 task_data,
1528 ((taskgroup && taskgroup->cancel_request) ? ompt_cancel_taskgroup
1529 : ompt_cancel_parallel) |
1530 ompt_cancel_discarded_task,
1531 NULL);
1532 }
1533#endif
1534 KMP_COUNT_BLOCK(TASK_cancelled);
1535 // this task belongs to a task group and we need to cancel it
1536 discard = 1 /* true */;
1537 }
1538 }
1539
1540 // Invoke the task routine and pass in relevant data.
1541 // Thunks generated by gcc take a different argument list.
1542 if (!discard) {
1543#if KMP_STATS_ENABLED
1544 KMP_COUNT_BLOCK(TASK_executed);
1545 switch (KMP_GET_THREAD_STATE()) {
1546 case FORK_JOIN_BARRIER:
1547 KMP_PUSH_PARTITIONED_TIMER(OMP_task_join_bar);
1548 break;
1549 case PLAIN_BARRIER:
1550 KMP_PUSH_PARTITIONED_TIMER(OMP_task_plain_bar);
1551 break;
1552 case TASKYIELD:
1553 KMP_PUSH_PARTITIONED_TIMER(OMP_task_taskyield);
1554 break;
1555 case TASKWAIT:
1556 KMP_PUSH_PARTITIONED_TIMER(OMP_task_taskwait);
1557 break;
1558 case TASKGROUP:
1559 KMP_PUSH_PARTITIONED_TIMER(OMP_task_taskgroup);
1560 break;
1561 default:
1562 KMP_PUSH_PARTITIONED_TIMER(OMP_task_immediate);
1563 break;
1564 }
1565#endif // KMP_STATS_ENABLED
1566
1567// OMPT task begin
1568#if OMPT_SUPPORT
1569 if (UNLIKELY(ompt_enabled.enabled))
1570 __ompt_task_start(task, current_task, gtid);
1571#endif
1572#if OMPT_SUPPORT && OMPT_OPTIONAL
1573 if (UNLIKELY(ompt_enabled.ompt_callback_dispatch &&
1574 taskdata->ompt_task_info.dispatch_chunk.iterations > 0)) {
1575 ompt_data_t instance = ompt_data_none;
1576 instance.ptr = &(taskdata->ompt_task_info.dispatch_chunk);
1577 ompt_team_info_t *team_info = __ompt_get_teaminfo(0, NULL);
1578 ompt_callbacks.ompt_callback(ompt_callback_dispatch)(
1579 &(team_info->parallel_data), &(taskdata->ompt_task_info.task_data),
1580 ompt_dispatch_taskloop_chunk, instance);
1581 taskdata->ompt_task_info.dispatch_chunk = {0, 0};
1582 }
1583#endif // OMPT_SUPPORT && OMPT_OPTIONAL
1584
1585#if OMPD_SUPPORT
1586 if (ompd_state & OMPD_ENABLE_BP)
1587 ompd_bp_task_begin();
1588#endif
1589
1590#if USE_ITT_BUILD && USE_ITT_NOTIFY
1591 kmp_uint64 cur_time;
1592 kmp_int32 kmp_itt_count_task =
1593 __kmp_forkjoin_frames_mode == 3 && !taskdata->td_flags.task_serial &&
1594 current_task->td_flags.tasktype == TASK_IMPLICIT;
1595 if (kmp_itt_count_task) {
1596 thread = __kmp_threads[gtid];
1597 // Time outer level explicit task on barrier for adjusting imbalance time
1598 if (thread->th.th_bar_arrive_time)
1599 cur_time = __itt_get_timestamp();
1600 else
1601 kmp_itt_count_task = 0; // thread is not on a barrier - skip timing
1602 }
1603 KMP_FSYNC_ACQUIRED(taskdata); // acquired self (new task)
1604#endif
1605
1606#if ENABLE_LIBOMPTARGET
1607 if (taskdata->td_target_data.async_handle != NULL) {
1608 // If we have a valid target async handle, that means that we have already
1609 // executed the task routine once. We must query for the handle completion
1610 // instead of re-executing the routine.
1611 KMP_ASSERT(tgt_target_nowait_query);
1612 tgt_target_nowait_query(&taskdata->td_target_data.async_handle);
1613 } else
1614#endif
1615 if (task->routine != NULL) {
1616#ifdef KMP_GOMP_COMPAT
1617 if (taskdata->td_flags.native) {
1618 ((void (*)(void *))(*(task->routine)))(task->shareds);
1619 } else
1620#endif /* KMP_GOMP_COMPAT */
1621 {
1622 (*(task->routine))(gtid, task);
1623 }
1624 }
1625 KMP_POP_PARTITIONED_TIMER();
1626
1627#if USE_ITT_BUILD && USE_ITT_NOTIFY
1628 if (kmp_itt_count_task) {
1629 // Barrier imbalance - adjust arrive time with the task duration
1630 thread->th.th_bar_arrive_time += (__itt_get_timestamp() - cur_time);
1631 }
1632 KMP_FSYNC_CANCEL(taskdata); // destroy self (just executed)
1633 KMP_FSYNC_RELEASING(taskdata->td_parent); // releasing parent
1634#endif
1635 }
1636
1637#if OMPD_SUPPORT
1638 if (ompd_state & OMPD_ENABLE_BP)
1639 ompd_bp_task_end();
1640#endif
1641
1642 // Proxy tasks are not handled by the runtime
1643 if (taskdata->td_flags.proxy != TASK_PROXY) {
1644#if OMPT_SUPPORT
1645 if (UNLIKELY(ompt_enabled.enabled)) {
1646 thread->th.ompt_thread_info = oldInfo;
1647 if (taskdata->td_flags.tiedness == TASK_TIED) {
1648 taskdata->ompt_task_info.frame.exit_frame = ompt_data_none;
1649 }
1650 __kmp_task_finish<true>(gtid, task, current_task);
1651 } else
1652#endif
1653 __kmp_task_finish<false>(gtid, task, current_task);
1654 }
1655#if OMPT_SUPPORT
1656 else if (UNLIKELY(ompt_enabled.enabled && taskdata->td_flags.target)) {
1657 __ompt_task_finish(task, current_task, ompt_task_switch);
1658 }
1659#endif
1660
1661 KA_TRACE(
1662 30,
1663 ("__kmp_invoke_task(exit): T#%d completed task %p, resuming task %p\n",
1664 gtid, taskdata, current_task));
1665 return;
1666}
1667
1668// __kmpc_omp_task_parts: Schedule a thread-switchable task for execution
1669//
1670// loc_ref: location of original task pragma (ignored)
1671// gtid: Global Thread ID of encountering thread
1672// new_task: task thunk allocated by __kmp_omp_task_alloc() for the ''new task''
1673// Returns:
1674// TASK_CURRENT_NOT_QUEUED (0) if did not suspend and queue current task to
1675// be resumed later.
1676// TASK_CURRENT_QUEUED (1) if suspended and queued the current task to be
1677// resumed later.
1678kmp_int32 __kmpc_omp_task_parts(ident_t *loc_ref, kmp_int32 gtid,
1679 kmp_task_t *new_task) {
1680 kmp_taskdata_t *new_taskdata = KMP_TASK_TO_TASKDATA(new_task);
1681
1682 KA_TRACE(10, ("__kmpc_omp_task_parts(enter): T#%d loc=%p task=%p\n", gtid,
1683 loc_ref, new_taskdata));
1684
1685#if OMPT_SUPPORT
1686 kmp_taskdata_t *parent;
1687 if (UNLIKELY(ompt_enabled.enabled)) {
1688 parent = new_taskdata->td_parent;
1689 if (ompt_enabled.ompt_callback_task_create) {
1690 ompt_callbacks.ompt_callback(ompt_callback_task_create)(
1691 &(parent->ompt_task_info.task_data), &(parent->ompt_task_info.frame),
1692 &(new_taskdata->ompt_task_info.task_data),
1693 TASK_TYPE_DETAILS_FORMAT(new_taskdata), 0,
1694 OMPT_GET_RETURN_ADDRESS(0));
1695 }
1696 }
1697#endif
1698
1699 /* Should we execute the new task or queue it? For now, let's just always try
1700 to queue it. If the queue fills up, then we'll execute it. */
1701
1702 if (__kmp_push_task(gtid, new_task) == TASK_NOT_PUSHED) // if cannot defer
1703 { // Execute this task immediately
1704 kmp_taskdata_t *current_task = __kmp_threads[gtid]->th.th_current_task;
1705 new_taskdata->td_flags.task_serial = 1;
1706 __kmp_invoke_task(gtid, new_task, current_task);
1707 }
1708
1709 KA_TRACE(
1710 10,
1711 ("__kmpc_omp_task_parts(exit): T#%d returning TASK_CURRENT_NOT_QUEUED: "
1712 "loc=%p task=%p, return: TASK_CURRENT_NOT_QUEUED\n",
1713 gtid, loc_ref, new_taskdata));
1714
1715#if OMPT_SUPPORT
1716 if (UNLIKELY(ompt_enabled.enabled)) {
1717 parent->ompt_task_info.frame.enter_frame = ompt_data_none;
1718 parent->ompt_task_info.frame.enter_frame_flags = OMPT_FRAME_FLAGS_RUNTIME;
1719 }
1720#endif
1721 return TASK_CURRENT_NOT_QUEUED;
1722}
1723
1724// __kmp_omp_task: Schedule a non-thread-switchable task for execution
1725//
1726// gtid: Global Thread ID of encountering thread
1727// new_task:non-thread-switchable task thunk allocated by __kmp_omp_task_alloc()
1728// serialize_immediate: if TRUE then if the task is executed immediately its
1729// execution will be serialized
1730// Returns:
1731// TASK_CURRENT_NOT_QUEUED (0) if did not suspend and queue current task to
1732// be resumed later.
1733// TASK_CURRENT_QUEUED (1) if suspended and queued the current task to be
1734// resumed later.
1735kmp_int32 __kmp_omp_task(kmp_int32 gtid, kmp_task_t *new_task,
1736 bool serialize_immediate) {
1737 kmp_taskdata_t *new_taskdata = KMP_TASK_TO_TASKDATA(new_task);
1738
1739 /* Should we execute the new task or queue it? For now, let's just always try
1740 to queue it. If the queue fills up, then we'll execute it. */
1741 if (new_taskdata->td_flags.proxy == TASK_PROXY ||
1742 __kmp_push_task(gtid, new_task) == TASK_NOT_PUSHED) // if cannot defer
1743 { // Execute this task immediately
1744 kmp_taskdata_t *current_task = __kmp_threads[gtid]->th.th_current_task;
1745 if (serialize_immediate)
1746 new_taskdata->td_flags.task_serial = 1;
1747 __kmp_invoke_task(gtid, new_task, current_task);
1748 } else if (__kmp_dflt_blocktime != KMP_MAX_BLOCKTIME &&
1749 __kmp_wpolicy_passive) {
1750 kmp_info_t *this_thr = __kmp_threads[gtid];
1751 kmp_team_t *team = this_thr->th.th_team;
1752 kmp_int32 nthreads = this_thr->th.th_team_nproc;
1753 for (int i = 0; i < nthreads; ++i) {
1754 kmp_info_t *thread = team->t.t_threads[i];
1755 if (thread == this_thr)
1756 continue;
1757 if (thread->th.th_sleep_loc != NULL) {
1758 __kmp_null_resume_wrapper(thread);
1759 break; // awake one thread at a time
1760 }
1761 }
1762 }
1763 return TASK_CURRENT_NOT_QUEUED;
1764}
1765
1766// __kmpc_omp_task: Wrapper around __kmp_omp_task to schedule a
1767// non-thread-switchable task from the parent thread only!
1768//
1769// loc_ref: location of original task pragma (ignored)
1770// gtid: Global Thread ID of encountering thread
1771// new_task: non-thread-switchable task thunk allocated by
1772// __kmp_omp_task_alloc()
1773// Returns:
1774// TASK_CURRENT_NOT_QUEUED (0) if did not suspend and queue current task to
1775// be resumed later.
1776// TASK_CURRENT_QUEUED (1) if suspended and queued the current task to be
1777// resumed later.
1778kmp_int32 __kmpc_omp_task(ident_t *loc_ref, kmp_int32 gtid,
1779 kmp_task_t *new_task) {
1780 kmp_int32 res;
1781 KMP_SET_THREAD_STATE_BLOCK(EXPLICIT_TASK);
1782
1783#if KMP_DEBUG || OMPT_SUPPORT
1784 kmp_taskdata_t *new_taskdata = KMP_TASK_TO_TASKDATA(new_task);
1785#endif
1786 KA_TRACE(10, ("__kmpc_omp_task(enter): T#%d loc=%p task=%p\n", gtid, loc_ref,
1787 new_taskdata));
1788 __kmp_assert_valid_gtid(gtid);
1789
1790#if OMPT_SUPPORT
1791 kmp_taskdata_t *parent = NULL;
1792 if (UNLIKELY(ompt_enabled.enabled)) {
1793 if (!new_taskdata->td_flags.started) {
1794 OMPT_STORE_RETURN_ADDRESS(gtid);
1795 parent = new_taskdata->td_parent;
1796 if (!parent->ompt_task_info.frame.enter_frame.ptr) {
1797 parent->ompt_task_info.frame.enter_frame.ptr =
1798 OMPT_GET_FRAME_ADDRESS(0);
1799 }
1800 if (ompt_enabled.ompt_callback_task_create) {
1801 ompt_callbacks.ompt_callback(ompt_callback_task_create)(
1802 &(parent->ompt_task_info.task_data),
1803 &(parent->ompt_task_info.frame),
1804 &(new_taskdata->ompt_task_info.task_data),
1805 TASK_TYPE_DETAILS_FORMAT(new_taskdata), 0,
1806 OMPT_LOAD_RETURN_ADDRESS(gtid));
1807 }
1808 } else {
1809 // We are scheduling the continuation of an UNTIED task.
1810 // Scheduling back to the parent task.
1811 __ompt_task_finish(new_task,
1812 new_taskdata->ompt_task_info.scheduling_parent,
1813 ompt_task_switch);
1814 new_taskdata->ompt_task_info.frame.exit_frame = ompt_data_none;
1815 }
1816 }
1817#endif
1818
1819 res = __kmp_omp_task(gtid, new_task, true);
1820
1821 KA_TRACE(10, ("__kmpc_omp_task(exit): T#%d returning "
1822 "TASK_CURRENT_NOT_QUEUED: loc=%p task=%p\n",
1823 gtid, loc_ref, new_taskdata));
1824#if OMPT_SUPPORT
1825 if (UNLIKELY(ompt_enabled.enabled && parent != NULL)) {
1826 parent->ompt_task_info.frame.enter_frame = ompt_data_none;
1827 }
1828#endif
1829 return res;
1830}
1831
1832// __kmp_omp_taskloop_task: Wrapper around __kmp_omp_task to schedule
1833// a taskloop task with the correct OMPT return address
1834//
1835// loc_ref: location of original task pragma (ignored)
1836// gtid: Global Thread ID of encountering thread
1837// new_task: non-thread-switchable task thunk allocated by
1838// __kmp_omp_task_alloc()
1839// codeptr_ra: return address for OMPT callback
1840// Returns:
1841// TASK_CURRENT_NOT_QUEUED (0) if did not suspend and queue current task to
1842// be resumed later.
1843// TASK_CURRENT_QUEUED (1) if suspended and queued the current task to be
1844// resumed later.
1845kmp_int32 __kmp_omp_taskloop_task(ident_t *loc_ref, kmp_int32 gtid,
1846 kmp_task_t *new_task, void *codeptr_ra) {
1847 kmp_int32 res;
1848 KMP_SET_THREAD_STATE_BLOCK(EXPLICIT_TASK);
1849
1850#if KMP_DEBUG || OMPT_SUPPORT
1851 kmp_taskdata_t *new_taskdata = KMP_TASK_TO_TASKDATA(new_task);
1852#endif
1853 KA_TRACE(10, ("__kmpc_omp_task(enter): T#%d loc=%p task=%p\n", gtid, loc_ref,
1854 new_taskdata));
1855
1856#if OMPT_SUPPORT
1857 kmp_taskdata_t *parent = NULL;
1858 if (UNLIKELY(ompt_enabled.enabled && !new_taskdata->td_flags.started)) {
1859 parent = new_taskdata->td_parent;
1860 if (!parent->ompt_task_info.frame.enter_frame.ptr)
1861 parent->ompt_task_info.frame.enter_frame.ptr = OMPT_GET_FRAME_ADDRESS(0);
1862 if (ompt_enabled.ompt_callback_task_create) {
1863 ompt_callbacks.ompt_callback(ompt_callback_task_create)(
1864 &(parent->ompt_task_info.task_data), &(parent->ompt_task_info.frame),
1865 &(new_taskdata->ompt_task_info.task_data),
1866 TASK_TYPE_DETAILS_FORMAT(new_taskdata), 0, codeptr_ra);
1867 }
1868 }
1869#endif
1870
1871 res = __kmp_omp_task(gtid, new_task, true);
1872
1873 KA_TRACE(10, ("__kmpc_omp_task(exit): T#%d returning "
1874 "TASK_CURRENT_NOT_QUEUED: loc=%p task=%p\n",
1875 gtid, loc_ref, new_taskdata));
1876#if OMPT_SUPPORT
1877 if (UNLIKELY(ompt_enabled.enabled && parent != NULL)) {
1878 parent->ompt_task_info.frame.enter_frame = ompt_data_none;
1879 }
1880#endif
1881 return res;
1882}
1883
1884template <bool ompt>
1885static kmp_int32 __kmpc_omp_taskwait_template(ident_t *loc_ref, kmp_int32 gtid,
1886 void *frame_address,
1887 void *return_address) {
1888 kmp_taskdata_t *taskdata = nullptr;
1889 kmp_info_t *thread;
1890 int thread_finished = FALSE;
1891 KMP_SET_THREAD_STATE_BLOCK(TASKWAIT);
1892
1893 KA_TRACE(10, ("__kmpc_omp_taskwait(enter): T#%d loc=%p\n", gtid, loc_ref));
1894 KMP_DEBUG_ASSERT(gtid >= 0);
1895
1896 if (__kmp_tasking_mode != tskm_immediate_exec) {
1897 thread = __kmp_threads[gtid];
1898 taskdata = thread->th.th_current_task;
1899
1900#if OMPT_SUPPORT && OMPT_OPTIONAL
1901 ompt_data_t *my_task_data;
1902 ompt_data_t *my_parallel_data;
1903
1904 if (ompt) {
1905 my_task_data = &(taskdata->ompt_task_info.task_data);
1906 my_parallel_data = OMPT_CUR_TEAM_DATA(thread);
1907
1908 taskdata->ompt_task_info.frame.enter_frame.ptr = frame_address;
1909
1910 if (ompt_enabled.ompt_callback_sync_region) {
1911 ompt_callbacks.ompt_callback(ompt_callback_sync_region)(
1912 ompt_sync_region_taskwait, ompt_scope_begin, my_parallel_data,
1913 my_task_data, return_address);
1914 }
1915
1916 if (ompt_enabled.ompt_callback_sync_region_wait) {
1917 ompt_callbacks.ompt_callback(ompt_callback_sync_region_wait)(
1918 ompt_sync_region_taskwait, ompt_scope_begin, my_parallel_data,
1919 my_task_data, return_address);
1920 }
1921 }
1922#endif // OMPT_SUPPORT && OMPT_OPTIONAL
1923
1924#if ENABLE_LIBOMPTARGET
1925 // Give an opportunity to the offload runtime to make progress and create
1926 // any necessary proxy tasks
1927 if (UNLIKELY(kmp_target_sync_cb))
1928 (*kmp_target_sync_cb)(loc_ref, gtid, KMP_TASKDATA_TO_TASK(taskdata),
1929 NULL);
1930#endif // ENABLE_LIBOMPTARGET
1931
1932// Debugger: The taskwait is active. Store location and thread encountered the
1933// taskwait.
1934#if USE_ITT_BUILD
1935// Note: These values are used by ITT events as well.
1936#endif /* USE_ITT_BUILD */
1937 taskdata->td_taskwait_counter += 1;
1938 taskdata->td_taskwait_ident = loc_ref;
1939 taskdata->td_taskwait_thread = gtid + 1;
1940
1941#if USE_ITT_BUILD
1942 void *itt_sync_obj = NULL;
1943#if USE_ITT_NOTIFY
1944 KMP_ITT_TASKWAIT_STARTING(itt_sync_obj);
1945#endif /* USE_ITT_NOTIFY */
1946#endif /* USE_ITT_BUILD */
1947
1948 bool must_wait =
1949 !taskdata->td_flags.team_serial && !taskdata->td_flags.final;
1950
1951 must_wait = must_wait || (thread->th.th_task_team != NULL &&
1952 thread->th.th_task_team->tt.tt_found_proxy_tasks);
1953 // If hidden helper thread is encountered, we must enable wait here.
1954 must_wait =
1955 must_wait ||
1956 (__kmp_enable_hidden_helper && thread->th.th_task_team != NULL &&
1957 thread->th.th_task_team->tt.tt_hidden_helper_task_encountered);
1958
1959 if (must_wait) {
1960 kmp_flag_32<false, false> flag(
1961 RCAST(std::atomic<kmp_uint32> *,
1962 &(taskdata->td_incomplete_child_tasks)),
1963 0U);
1964 while (KMP_ATOMIC_LD_ACQ(&taskdata->td_incomplete_child_tasks) != 0) {
1965 flag.execute_tasks(thread, gtid, FALSE,
1966 &thread_finished USE_ITT_BUILD_ARG(itt_sync_obj),
1967 __kmp_task_stealing_constraint);
1968 }
1969 }
1970#if USE_ITT_BUILD
1971 KMP_ITT_TASKWAIT_FINISHED(itt_sync_obj);
1972 KMP_FSYNC_ACQUIRED(taskdata); // acquire self - sync with children
1973#endif /* USE_ITT_BUILD */
1974
1975 // Debugger: The taskwait is completed. Location remains, but thread is
1976 // negated.
1977 taskdata->td_taskwait_thread = -taskdata->td_taskwait_thread;
1978
1979#if OMPT_SUPPORT && OMPT_OPTIONAL
1980 if (ompt) {
1981 if (ompt_enabled.ompt_callback_sync_region_wait) {
1982 ompt_callbacks.ompt_callback(ompt_callback_sync_region_wait)(
1983 ompt_sync_region_taskwait, ompt_scope_end, my_parallel_data,
1984 my_task_data, return_address);
1985 }
1986 if (ompt_enabled.ompt_callback_sync_region) {
1987 ompt_callbacks.ompt_callback(ompt_callback_sync_region)(
1988 ompt_sync_region_taskwait, ompt_scope_end, my_parallel_data,
1989 my_task_data, return_address);
1990 }
1991 taskdata->ompt_task_info.frame.enter_frame = ompt_data_none;
1992 }
1993#endif // OMPT_SUPPORT && OMPT_OPTIONAL
1994 }
1995
1996 KA_TRACE(10, ("__kmpc_omp_taskwait(exit): T#%d task %p finished waiting, "
1997 "returning TASK_CURRENT_NOT_QUEUED\n",
1998 gtid, taskdata));
1999
2000 return TASK_CURRENT_NOT_QUEUED;
2001}
2002
2003#if OMPT_SUPPORT && OMPT_OPTIONAL
2004OMPT_NOINLINE
2005static kmp_int32 __kmpc_omp_taskwait_ompt(ident_t *loc_ref, kmp_int32 gtid,
2006 void *frame_address,
2007 void *return_address) {
2008 return __kmpc_omp_taskwait_template<true>(loc_ref, gtid, frame_address,
2009 return_address);
2010}
2011#endif // OMPT_SUPPORT && OMPT_OPTIONAL
2012
2013// __kmpc_omp_taskwait: Wait until all tasks generated by the current task are
2014// complete
2015kmp_int32 __kmpc_omp_taskwait(ident_t *loc_ref, kmp_int32 gtid) {
2016#if OMPT_SUPPORT && OMPT_OPTIONAL
2017 if (UNLIKELY(ompt_enabled.enabled)) {
2018 OMPT_STORE_RETURN_ADDRESS(gtid);
2019 return __kmpc_omp_taskwait_ompt(loc_ref, gtid, OMPT_GET_FRAME_ADDRESS(0),
2020 OMPT_LOAD_RETURN_ADDRESS(gtid));
2021 }
2022#endif
2023 return __kmpc_omp_taskwait_template<false>(loc_ref, gtid, NULL, NULL);
2024}
2025
2026// __kmpc_omp_taskyield: switch to a different task
2027kmp_int32 __kmpc_omp_taskyield(ident_t *loc_ref, kmp_int32 gtid, int end_part) {
2028 kmp_taskdata_t *taskdata = NULL;
2029 kmp_info_t *thread;
2030 int thread_finished = FALSE;
2031
2032 KMP_COUNT_BLOCK(OMP_TASKYIELD);
2033 KMP_SET_THREAD_STATE_BLOCK(TASKYIELD);
2034
2035 KA_TRACE(10, ("__kmpc_omp_taskyield(enter): T#%d loc=%p end_part = %d\n",
2036 gtid, loc_ref, end_part));
2037 __kmp_assert_valid_gtid(gtid);
2038
2039 if (__kmp_tasking_mode != tskm_immediate_exec && __kmp_init_parallel) {
2040 thread = __kmp_threads[gtid];
2041 taskdata = thread->th.th_current_task;
2042// Should we model this as a task wait or not?
2043// Debugger: The taskwait is active. Store location and thread encountered the
2044// taskwait.
2045#if USE_ITT_BUILD
2046// Note: These values are used by ITT events as well.
2047#endif /* USE_ITT_BUILD */
2048 taskdata->td_taskwait_counter += 1;
2049 taskdata->td_taskwait_ident = loc_ref;
2050 taskdata->td_taskwait_thread = gtid + 1;
2051
2052#if USE_ITT_BUILD
2053 void *itt_sync_obj = NULL;
2054#if USE_ITT_NOTIFY
2055 KMP_ITT_TASKWAIT_STARTING(itt_sync_obj);
2056#endif /* USE_ITT_NOTIFY */
2057#endif /* USE_ITT_BUILD */
2058 if (!taskdata->td_flags.team_serial) {
2059 kmp_task_team_t *task_team = thread->th.th_task_team;
2060 if (task_team != NULL) {
2061 if (KMP_TASKING_ENABLED(task_team)) {
2062#if OMPT_SUPPORT
2063 if (UNLIKELY(ompt_enabled.enabled))
2064 thread->th.ompt_thread_info.ompt_task_yielded = 1;
2065#endif
2066 __kmp_execute_tasks_32(
2067 thread, gtid, (kmp_flag_32<> *)NULL, FALSE,
2068 &thread_finished USE_ITT_BUILD_ARG(itt_sync_obj),
2069 __kmp_task_stealing_constraint);
2070#if OMPT_SUPPORT
2071 if (UNLIKELY(ompt_enabled.enabled))
2072 thread->th.ompt_thread_info.ompt_task_yielded = 0;
2073#endif
2074 }
2075 }
2076 }
2077#if USE_ITT_BUILD
2078 KMP_ITT_TASKWAIT_FINISHED(itt_sync_obj);
2079#endif /* USE_ITT_BUILD */
2080
2081 // Debugger: The taskwait is completed. Location remains, but thread is
2082 // negated.
2083 taskdata->td_taskwait_thread = -taskdata->td_taskwait_thread;
2084 }
2085
2086 KA_TRACE(10, ("__kmpc_omp_taskyield(exit): T#%d task %p resuming, "
2087 "returning TASK_CURRENT_NOT_QUEUED\n",
2088 gtid, taskdata));
2089
2090 return TASK_CURRENT_NOT_QUEUED;
2091}
2092
2093// Task Reduction implementation
2094//
2095// Note: initial implementation didn't take into account the possibility
2096// to specify omp_orig for initializer of the UDR (user defined reduction).
2097// Corrected implementation takes into account the omp_orig object.
2098// Compiler is free to use old implementation if omp_orig is not specified.
2099
2108typedef struct kmp_taskred_flags {
2110 unsigned lazy_priv : 1;
2111 unsigned reserved31 : 31;
2113
2117typedef struct kmp_task_red_input {
2120 // three compiler-generated routines (init, fini are optional):
2126
2130typedef struct kmp_taskred_data {
2136 // three compiler-generated routines (init, fini are optional):
2142
2148typedef struct kmp_taskred_input {
2152 // three compiler-generated routines (init, fini are optional):
2162template <typename T> void __kmp_assign_orig(kmp_taskred_data_t &item, T &src);
2163template <>
2164void __kmp_assign_orig<kmp_task_red_input_t>(kmp_taskred_data_t &item,
2165 kmp_task_red_input_t &src) {
2166 item.reduce_orig = NULL;
2167}
2168template <>
2169void __kmp_assign_orig<kmp_taskred_input_t>(kmp_taskred_data_t &item,
2170 kmp_taskred_input_t &src) {
2171 if (src.reduce_orig != NULL) {
2172 item.reduce_orig = src.reduce_orig;
2173 } else {
2174 item.reduce_orig = src.reduce_shar;
2175 } // non-NULL reduce_orig means new interface used
2176}
2177
2178template <typename T> void __kmp_call_init(kmp_taskred_data_t &item, size_t j);
2179template <>
2180void __kmp_call_init<kmp_task_red_input_t>(kmp_taskred_data_t &item,
2181 size_t offset) {
2182 ((void (*)(void *))item.reduce_init)((char *)(item.reduce_priv) + offset);
2183}
2184template <>
2185void __kmp_call_init<kmp_taskred_input_t>(kmp_taskred_data_t &item,
2186 size_t offset) {
2187 ((void (*)(void *, void *))item.reduce_init)(
2188 (char *)(item.reduce_priv) + offset, item.reduce_orig);
2189}
2190
2191template <typename T>
2192void *__kmp_task_reduction_init(int gtid, int num, T *data) {
2193 __kmp_assert_valid_gtid(gtid);
2194 kmp_info_t *thread = __kmp_threads[gtid];
2195 kmp_taskgroup_t *tg = thread->th.th_current_task->td_taskgroup;
2196 kmp_uint32 nth = thread->th.th_team_nproc;
2197 kmp_taskred_data_t *arr;
2198
2199 // check input data just in case
2200 KMP_ASSERT(tg != NULL);
2201 KMP_ASSERT(data != NULL);
2202 KMP_ASSERT(num > 0);
2203 if (nth == 1 && !__kmp_enable_hidden_helper) {
2204 KA_TRACE(10, ("__kmpc_task_reduction_init: T#%d, tg %p, exiting nth=1\n",
2205 gtid, tg));
2206 return (void *)tg;
2207 }
2208 KA_TRACE(10, ("__kmpc_task_reduction_init: T#%d, taskgroup %p, #items %d\n",
2209 gtid, tg, num));
2210 arr = (kmp_taskred_data_t *)__kmp_thread_malloc(
2211 thread, num * sizeof(kmp_taskred_data_t));
2212 for (int i = 0; i < num; ++i) {
2213 size_t size = data[i].reduce_size - 1;
2214 // round the size up to cache line per thread-specific item
2215 size += CACHE_LINE - size % CACHE_LINE;
2216 KMP_ASSERT(data[i].reduce_comb != NULL); // combiner is mandatory
2217 arr[i].reduce_shar = data[i].reduce_shar;
2218 arr[i].reduce_size = size;
2219 arr[i].flags = data[i].flags;
2220 arr[i].reduce_comb = data[i].reduce_comb;
2221 arr[i].reduce_init = data[i].reduce_init;
2222 arr[i].reduce_fini = data[i].reduce_fini;
2223 __kmp_assign_orig<T>(arr[i], data[i]);
2224 if (!arr[i].flags.lazy_priv) {
2225 // allocate cache-line aligned block and fill it with zeros
2226 arr[i].reduce_priv = __kmp_allocate(nth * size);
2227 arr[i].reduce_pend = (char *)(arr[i].reduce_priv) + nth * size;
2228 if (arr[i].reduce_init != NULL) {
2229 // initialize all thread-specific items
2230 for (size_t j = 0; j < nth; ++j) {
2231 __kmp_call_init<T>(arr[i], j * size);
2232 }
2233 }
2234 } else {
2235 // only allocate space for pointers now,
2236 // objects will be lazily allocated/initialized if/when requested
2237 // note that __kmp_allocate zeroes the allocated memory
2238 arr[i].reduce_priv = __kmp_allocate(nth * sizeof(void *));
2239 }
2240 }
2241 tg->reduce_data = (void *)arr;
2242 tg->reduce_num_data = num;
2243 return (void *)tg;
2244}
2245
2260void *__kmpc_task_reduction_init(int gtid, int num, void *data) {
2261 return __kmp_task_reduction_init(gtid, num, (kmp_task_red_input_t *)data);
2262}
2263
2276void *__kmpc_taskred_init(int gtid, int num, void *data) {
2277 return __kmp_task_reduction_init(gtid, num, (kmp_taskred_input_t *)data);
2278}
2279
2280// Copy task reduction data (except for shared pointers).
2281template <typename T>
2282void __kmp_task_reduction_init_copy(kmp_info_t *thr, int num, T *data,
2283 kmp_taskgroup_t *tg, void *reduce_data) {
2284 kmp_taskred_data_t *arr;
2285 KA_TRACE(20, ("__kmp_task_reduction_init_copy: Th %p, init taskgroup %p,"
2286 " from data %p\n",
2287 thr, tg, reduce_data));
2288 arr = (kmp_taskred_data_t *)__kmp_thread_malloc(
2289 thr, num * sizeof(kmp_taskred_data_t));
2290 // threads will share private copies, thunk routines, sizes, flags, etc.:
2291 KMP_MEMCPY(arr, reduce_data, num * sizeof(kmp_taskred_data_t));
2292 for (int i = 0; i < num; ++i) {
2293 arr[i].reduce_shar = data[i].reduce_shar; // init unique shared pointers
2294 }
2295 tg->reduce_data = (void *)arr;
2296 tg->reduce_num_data = num;
2297}
2298
2308void *__kmpc_task_reduction_get_th_data(int gtid, void *tskgrp, void *data) {
2309 __kmp_assert_valid_gtid(gtid);
2310 kmp_info_t *thread = __kmp_threads[gtid];
2311 kmp_int32 nth = thread->th.th_team_nproc;
2312 if (nth == 1)
2313 return data; // nothing to do
2314
2315 kmp_taskgroup_t *tg = (kmp_taskgroup_t *)tskgrp;
2316 if (tg == NULL)
2317 tg = thread->th.th_current_task->td_taskgroup;
2318 KMP_ASSERT(tg != NULL);
2319 kmp_taskred_data_t *arr;
2320 kmp_int32 num;
2321 kmp_int32 tid = thread->th.th_info.ds.ds_tid;
2322
2323 KMP_ASSERT(data != NULL);
2324 while (tg != NULL) {
2325 arr = (kmp_taskred_data_t *)(tg->reduce_data);
2326 num = tg->reduce_num_data;
2327 for (int i = 0; i < num; ++i) {
2328 if (!arr[i].flags.lazy_priv) {
2329 if (data == arr[i].reduce_shar ||
2330 (data >= arr[i].reduce_priv && data < arr[i].reduce_pend))
2331 return (char *)(arr[i].reduce_priv) + tid * arr[i].reduce_size;
2332 } else {
2333 // check shared location first
2334 void **p_priv = (void **)(arr[i].reduce_priv);
2335 if (data == arr[i].reduce_shar)
2336 goto found;
2337 // check if we get some thread specific location as parameter
2338 for (int j = 0; j < nth; ++j)
2339 if (data == p_priv[j])
2340 goto found;
2341 continue; // not found, continue search
2342 found:
2343 if (p_priv[tid] == NULL) {
2344 // allocate thread specific object lazily
2345 p_priv[tid] = __kmp_allocate(arr[i].reduce_size);
2346 if (arr[i].reduce_init != NULL) {
2347 if (arr[i].reduce_orig != NULL) { // new interface
2348 ((void (*)(void *, void *))arr[i].reduce_init)(
2349 p_priv[tid], arr[i].reduce_orig);
2350 } else { // old interface (single parameter)
2351 ((void (*)(void *))arr[i].reduce_init)(p_priv[tid]);
2352 }
2353 }
2354 }
2355 return p_priv[tid];
2356 }
2357 }
2358 KMP_ASSERT(tg->parent);
2359 tg = tg->parent;
2360 }
2361 KMP_ASSERT2(0, "Unknown task reduction item");
2362 return NULL; // ERROR, this line never executed
2363}
2364
2365// Finalize task reduction.
2366// Called from __kmpc_end_taskgroup()
2367static void __kmp_task_reduction_fini(kmp_info_t *th, kmp_taskgroup_t *tg) {
2368 kmp_int32 nth = th->th.th_team_nproc;
2369 KMP_DEBUG_ASSERT(
2370 nth > 1 ||
2371 __kmp_enable_hidden_helper); // should not be called if nth == 1 unless we
2372 // are using hidden helper threads
2373 kmp_taskred_data_t *arr = (kmp_taskred_data_t *)tg->reduce_data;
2374 kmp_int32 num = tg->reduce_num_data;
2375 for (int i = 0; i < num; ++i) {
2376 void *sh_data = arr[i].reduce_shar;
2377 void (*f_fini)(void *) = (void (*)(void *))(arr[i].reduce_fini);
2378 void (*f_comb)(void *, void *) =
2379 (void (*)(void *, void *))(arr[i].reduce_comb);
2380 if (!arr[i].flags.lazy_priv) {
2381 void *pr_data = arr[i].reduce_priv;
2382 size_t size = arr[i].reduce_size;
2383 for (int j = 0; j < nth; ++j) {
2384 void *priv_data = (char *)pr_data + j * size;
2385 f_comb(sh_data, priv_data); // combine results
2386 if (f_fini)
2387 f_fini(priv_data); // finalize if needed
2388 }
2389 } else {
2390 void **pr_data = (void **)(arr[i].reduce_priv);
2391 for (int j = 0; j < nth; ++j) {
2392 if (pr_data[j] != NULL) {
2393 f_comb(sh_data, pr_data[j]); // combine results
2394 if (f_fini)
2395 f_fini(pr_data[j]); // finalize if needed
2396 __kmp_free(pr_data[j]);
2397 }
2398 }
2399 }
2400 __kmp_free(arr[i].reduce_priv);
2401 }
2402 __kmp_thread_free(th, arr);
2403 tg->reduce_data = NULL;
2404 tg->reduce_num_data = 0;
2405}
2406
2407// Cleanup task reduction data for parallel or worksharing,
2408// do not touch task private data other threads still working with.
2409// Called from __kmpc_end_taskgroup()
2410static void __kmp_task_reduction_clean(kmp_info_t *th, kmp_taskgroup_t *tg) {
2411 __kmp_thread_free(th, tg->reduce_data);
2412 tg->reduce_data = NULL;
2413 tg->reduce_num_data = 0;
2414}
2415
2416template <typename T>
2417void *__kmp_task_reduction_modifier_init(ident_t *loc, int gtid, int is_ws,
2418 int num, T *data) {
2419 __kmp_assert_valid_gtid(gtid);
2420 kmp_info_t *thr = __kmp_threads[gtid];
2421 kmp_int32 nth = thr->th.th_team_nproc;
2422 __kmpc_taskgroup(loc, gtid); // form new taskgroup first
2423 if (nth == 1) {
2424 KA_TRACE(10,
2425 ("__kmpc_reduction_modifier_init: T#%d, tg %p, exiting nth=1\n",
2426 gtid, thr->th.th_current_task->td_taskgroup));
2427 return (void *)thr->th.th_current_task->td_taskgroup;
2428 }
2429 kmp_team_t *team = thr->th.th_team;
2430 void *reduce_data;
2431 kmp_taskgroup_t *tg;
2432 reduce_data = KMP_ATOMIC_LD_RLX(&team->t.t_tg_reduce_data[is_ws]);
2433 if (reduce_data == NULL &&
2434 __kmp_atomic_compare_store(&team->t.t_tg_reduce_data[is_ws], reduce_data,
2435 (void *)1)) {
2436 // single thread enters this block to initialize common reduction data
2437 KMP_DEBUG_ASSERT(reduce_data == NULL);
2438 // first initialize own data, then make a copy other threads can use
2439 tg = (kmp_taskgroup_t *)__kmp_task_reduction_init<T>(gtid, num, data);
2440 reduce_data = __kmp_thread_malloc(thr, num * sizeof(kmp_taskred_data_t));
2441 KMP_MEMCPY(reduce_data, tg->reduce_data, num * sizeof(kmp_taskred_data_t));
2442 // fini counters should be 0 at this point
2443 KMP_DEBUG_ASSERT(KMP_ATOMIC_LD_RLX(&team->t.t_tg_fini_counter[0]) == 0);
2444 KMP_DEBUG_ASSERT(KMP_ATOMIC_LD_RLX(&team->t.t_tg_fini_counter[1]) == 0);
2445 KMP_ATOMIC_ST_REL(&team->t.t_tg_reduce_data[is_ws], reduce_data);
2446 } else {
2447 while (
2448 (reduce_data = KMP_ATOMIC_LD_ACQ(&team->t.t_tg_reduce_data[is_ws])) ==
2449 (void *)1) { // wait for task reduction initialization
2450 KMP_CPU_PAUSE();
2451 }
2452 KMP_DEBUG_ASSERT(reduce_data > (void *)1); // should be valid pointer here
2453 tg = thr->th.th_current_task->td_taskgroup;
2454 __kmp_task_reduction_init_copy<T>(thr, num, data, tg, reduce_data);
2455 }
2456 return tg;
2457}
2458
2475void *__kmpc_task_reduction_modifier_init(ident_t *loc, int gtid, int is_ws,
2476 int num, void *data) {
2477 return __kmp_task_reduction_modifier_init(loc, gtid, is_ws, num,
2478 (kmp_task_red_input_t *)data);
2479}
2480
2495void *__kmpc_taskred_modifier_init(ident_t *loc, int gtid, int is_ws, int num,
2496 void *data) {
2497 return __kmp_task_reduction_modifier_init(loc, gtid, is_ws, num,
2498 (kmp_taskred_input_t *)data);
2499}
2500
2509void __kmpc_task_reduction_modifier_fini(ident_t *loc, int gtid, int is_ws) {
2510 __kmpc_end_taskgroup(loc, gtid);
2511}
2512
2513// __kmpc_taskgroup: Start a new taskgroup
2514void __kmpc_taskgroup(ident_t *loc, int gtid) {
2515 __kmp_assert_valid_gtid(gtid);
2516 kmp_info_t *thread = __kmp_threads[gtid];
2517 kmp_taskdata_t *taskdata = thread->th.th_current_task;
2518 kmp_taskgroup_t *tg_new =
2519 (kmp_taskgroup_t *)__kmp_thread_malloc(thread, sizeof(kmp_taskgroup_t));
2520 KA_TRACE(10, ("__kmpc_taskgroup: T#%d loc=%p group=%p\n", gtid, loc, tg_new));
2521 KMP_ATOMIC_ST_RLX(&tg_new->count, 0);
2522 KMP_ATOMIC_ST_RLX(&tg_new->cancel_request, cancel_noreq);
2523 tg_new->parent = taskdata->td_taskgroup;
2524 tg_new->reduce_data = NULL;
2525 tg_new->reduce_num_data = 0;
2526 tg_new->gomp_data = NULL;
2527 taskdata->td_taskgroup = tg_new;
2528
2529#if OMPT_SUPPORT && OMPT_OPTIONAL
2530 if (UNLIKELY(ompt_enabled.ompt_callback_sync_region)) {
2531 void *codeptr = OMPT_LOAD_RETURN_ADDRESS(gtid);
2532 if (!codeptr)
2533 codeptr = OMPT_GET_RETURN_ADDRESS(0);
2534 kmp_team_t *team = thread->th.th_team;
2535 ompt_data_t my_task_data = taskdata->ompt_task_info.task_data;
2536 // FIXME: I think this is wrong for lwt!
2537 ompt_data_t my_parallel_data = team->t.ompt_team_info.parallel_data;
2538
2539 ompt_callbacks.ompt_callback(ompt_callback_sync_region)(
2540 ompt_sync_region_taskgroup, ompt_scope_begin, &(my_parallel_data),
2541 &(my_task_data), codeptr);
2542 }
2543#endif
2544}
2545
2546// __kmpc_end_taskgroup: Wait until all tasks generated by the current task
2547// and its descendants are complete
2548void __kmpc_end_taskgroup(ident_t *loc, int gtid) {
2549 __kmp_assert_valid_gtid(gtid);
2550 kmp_info_t *thread = __kmp_threads[gtid];
2551 kmp_taskdata_t *taskdata = thread->th.th_current_task;
2552 kmp_taskgroup_t *taskgroup = taskdata->td_taskgroup;
2553 int thread_finished = FALSE;
2554
2555#if OMPT_SUPPORT && OMPT_OPTIONAL
2556 kmp_team_t *team;
2557 ompt_data_t my_task_data;
2558 ompt_data_t my_parallel_data;
2559 void *codeptr = nullptr;
2560 if (UNLIKELY(ompt_enabled.enabled)) {
2561 team = thread->th.th_team;
2562 my_task_data = taskdata->ompt_task_info.task_data;
2563 // FIXME: I think this is wrong for lwt!
2564 my_parallel_data = team->t.ompt_team_info.parallel_data;
2565 codeptr = OMPT_LOAD_RETURN_ADDRESS(gtid);
2566 if (!codeptr)
2567 codeptr = OMPT_GET_RETURN_ADDRESS(0);
2568 }
2569#endif
2570
2571 KA_TRACE(10, ("__kmpc_end_taskgroup(enter): T#%d loc=%p\n", gtid, loc));
2572 KMP_DEBUG_ASSERT(taskgroup != NULL);
2573 KMP_SET_THREAD_STATE_BLOCK(TASKGROUP);
2574
2575 if (__kmp_tasking_mode != tskm_immediate_exec) {
2576 // mark task as waiting not on a barrier
2577 taskdata->td_taskwait_counter += 1;
2578 taskdata->td_taskwait_ident = loc;
2579 taskdata->td_taskwait_thread = gtid + 1;
2580#if USE_ITT_BUILD
2581 // For ITT the taskgroup wait is similar to taskwait until we need to
2582 // distinguish them
2583 void *itt_sync_obj = NULL;
2584#if USE_ITT_NOTIFY
2585 KMP_ITT_TASKWAIT_STARTING(itt_sync_obj);
2586#endif /* USE_ITT_NOTIFY */
2587#endif /* USE_ITT_BUILD */
2588
2589#if OMPT_SUPPORT && OMPT_OPTIONAL
2590 if (UNLIKELY(ompt_enabled.ompt_callback_sync_region_wait)) {
2591 ompt_callbacks.ompt_callback(ompt_callback_sync_region_wait)(
2592 ompt_sync_region_taskgroup, ompt_scope_begin, &(my_parallel_data),
2593 &(my_task_data), codeptr);
2594 }
2595#endif
2596
2597#if ENABLE_LIBOMPTARGET
2598 // Give an opportunity to the offload runtime to make progress and create
2599 // any necessary proxy tasks
2600 if (UNLIKELY(kmp_target_sync_cb))
2601 (*kmp_target_sync_cb)(loc, gtid, KMP_TASKDATA_TO_TASK(taskdata), NULL);
2602#endif // ENABLE_LIBOMPTARGET
2603
2604 if (!taskdata->td_flags.team_serial ||
2605 (thread->th.th_task_team != NULL &&
2606 (thread->th.th_task_team->tt.tt_found_proxy_tasks ||
2607 thread->th.th_task_team->tt.tt_hidden_helper_task_encountered))) {
2608 kmp_flag_32<false, false> flag(
2609 RCAST(std::atomic<kmp_uint32> *, &(taskgroup->count)), 0U);
2610 while (KMP_ATOMIC_LD_ACQ(&taskgroup->count) != 0) {
2611 flag.execute_tasks(thread, gtid, FALSE,
2612 &thread_finished USE_ITT_BUILD_ARG(itt_sync_obj),
2613 __kmp_task_stealing_constraint);
2614 }
2615 }
2616 taskdata->td_taskwait_thread = -taskdata->td_taskwait_thread; // end waiting
2617
2618#if OMPT_SUPPORT && OMPT_OPTIONAL
2619 if (UNLIKELY(ompt_enabled.ompt_callback_sync_region_wait)) {
2620 ompt_callbacks.ompt_callback(ompt_callback_sync_region_wait)(
2621 ompt_sync_region_taskgroup, ompt_scope_end, &(my_parallel_data),
2622 &(my_task_data), codeptr);
2623 }
2624#endif
2625
2626#if USE_ITT_BUILD
2627 KMP_ITT_TASKWAIT_FINISHED(itt_sync_obj);
2628 KMP_FSYNC_ACQUIRED(taskdata); // acquire self - sync with descendants
2629#endif /* USE_ITT_BUILD */
2630 }
2631 KMP_DEBUG_ASSERT(taskgroup->count == 0);
2632
2633 if (taskgroup->reduce_data != NULL &&
2634 !taskgroup->gomp_data) { // need to reduce?
2635 int cnt;
2636 void *reduce_data;
2637 kmp_team_t *t = thread->th.th_team;
2638 kmp_taskred_data_t *arr = (kmp_taskred_data_t *)taskgroup->reduce_data;
2639 // check if <priv> data of the first reduction variable shared for the team
2640 void *priv0 = arr[0].reduce_priv;
2641 if ((reduce_data = KMP_ATOMIC_LD_ACQ(&t->t.t_tg_reduce_data[0])) != NULL &&
2642 ((kmp_taskred_data_t *)reduce_data)[0].reduce_priv == priv0) {
2643 // finishing task reduction on parallel
2644 cnt = KMP_ATOMIC_INC(&t->t.t_tg_fini_counter[0]);
2645 if (cnt == thread->th.th_team_nproc - 1) {
2646 // we are the last thread passing __kmpc_reduction_modifier_fini()
2647 // finalize task reduction:
2648 __kmp_task_reduction_fini(thread, taskgroup);
2649 // cleanup fields in the team structure:
2650 // TODO: is relaxed store enough here (whole barrier should follow)?
2651 __kmp_thread_free(thread, reduce_data);
2652 KMP_ATOMIC_ST_REL(&t->t.t_tg_reduce_data[0], NULL);
2653 KMP_ATOMIC_ST_REL(&t->t.t_tg_fini_counter[0], 0);
2654 } else {
2655 // we are not the last thread passing __kmpc_reduction_modifier_fini(),
2656 // so do not finalize reduction, just clean own copy of the data
2657 __kmp_task_reduction_clean(thread, taskgroup);
2658 }
2659 } else if ((reduce_data = KMP_ATOMIC_LD_ACQ(&t->t.t_tg_reduce_data[1])) !=
2660 NULL &&
2661 ((kmp_taskred_data_t *)reduce_data)[0].reduce_priv == priv0) {
2662 // finishing task reduction on worksharing
2663 cnt = KMP_ATOMIC_INC(&t->t.t_tg_fini_counter[1]);
2664 if (cnt == thread->th.th_team_nproc - 1) {
2665 // we are the last thread passing __kmpc_reduction_modifier_fini()
2666 __kmp_task_reduction_fini(thread, taskgroup);
2667 // cleanup fields in team structure:
2668 // TODO: is relaxed store enough here (whole barrier should follow)?
2669 __kmp_thread_free(thread, reduce_data);
2670 KMP_ATOMIC_ST_REL(&t->t.t_tg_reduce_data[1], NULL);
2671 KMP_ATOMIC_ST_REL(&t->t.t_tg_fini_counter[1], 0);
2672 } else {
2673 // we are not the last thread passing __kmpc_reduction_modifier_fini(),
2674 // so do not finalize reduction, just clean own copy of the data
2675 __kmp_task_reduction_clean(thread, taskgroup);
2676 }
2677 } else {
2678 // finishing task reduction on taskgroup
2679 __kmp_task_reduction_fini(thread, taskgroup);
2680 }
2681 }
2682 // Restore parent taskgroup for the current task
2683 taskdata->td_taskgroup = taskgroup->parent;
2684 __kmp_thread_free(thread, taskgroup);
2685
2686 KA_TRACE(10, ("__kmpc_end_taskgroup(exit): T#%d task %p finished waiting\n",
2687 gtid, taskdata));
2688
2689#if OMPT_SUPPORT && OMPT_OPTIONAL
2690 if (UNLIKELY(ompt_enabled.ompt_callback_sync_region)) {
2691 ompt_callbacks.ompt_callback(ompt_callback_sync_region)(
2692 ompt_sync_region_taskgroup, ompt_scope_end, &(my_parallel_data),
2693 &(my_task_data), codeptr);
2694 }
2695#endif
2696}
2697
2698static kmp_task_t *__kmp_get_priority_task(kmp_int32 gtid,
2699 kmp_task_team_t *task_team,
2700 kmp_int32 is_constrained) {
2701 kmp_task_t *task = NULL;
2702 kmp_taskdata_t *taskdata;
2703 kmp_taskdata_t *current;
2704 kmp_thread_data_t *thread_data;
2705 int ntasks = task_team->tt.tt_num_task_pri;
2706 if (ntasks == 0) {
2707 KA_TRACE(
2708 20, ("__kmp_get_priority_task(exit #1): T#%d No tasks to get\n", gtid));
2709 return NULL;
2710 }
2711 do {
2712 // decrement num_tasks to "reserve" one task to get for execution
2713 if (__kmp_atomic_compare_store(&task_team->tt.tt_num_task_pri, ntasks,
2714 ntasks - 1))
2715 break;
2716 ntasks = task_team->tt.tt_num_task_pri;
2717 } while (ntasks > 0);
2718 if (ntasks == 0) {
2719 KA_TRACE(20, ("__kmp_get_priority_task(exit #2): T#%d No tasks to get\n",
2720 __kmp_get_gtid()));
2721 return NULL;
2722 }
2723 // We got a "ticket" to get a "reserved" priority task
2724 int deque_ntasks;
2725 kmp_task_pri_t *list = task_team->tt.tt_task_pri_list;
2726 do {
2727 KMP_ASSERT(list != NULL);
2728 thread_data = &list->td;
2729 __kmp_acquire_bootstrap_lock(&thread_data->td.td_deque_lock);
2730 deque_ntasks = thread_data->td.td_deque_ntasks;
2731 if (deque_ntasks == 0) {
2732 __kmp_release_bootstrap_lock(&thread_data->td.td_deque_lock);
2733 KA_TRACE(20, ("__kmp_get_priority_task: T#%d No tasks to get from %p\n",
2734 __kmp_get_gtid(), thread_data));
2735 list = list->next;
2736 }
2737 } while (deque_ntasks == 0);
2738 KMP_DEBUG_ASSERT(deque_ntasks);
2739 int target = thread_data->td.td_deque_head;
2740 current = __kmp_threads[gtid]->th.th_current_task;
2741 taskdata = thread_data->td.td_deque[target];
2742 if (__kmp_task_is_allowed(gtid, is_constrained, taskdata, current)) {
2743 // Bump head pointer and Wrap.
2744 thread_data->td.td_deque_head =
2745 (target + 1) & TASK_DEQUE_MASK(thread_data->td);
2746 } else {
2747 if (!task_team->tt.tt_untied_task_encountered) {
2748 // The TSC does not allow to steal victim task
2749 __kmp_release_bootstrap_lock(&thread_data->td.td_deque_lock);
2750 KA_TRACE(20, ("__kmp_get_priority_task(exit #3): T#%d could not get task "
2751 "from %p: task_team=%p ntasks=%d head=%u tail=%u\n",
2752 gtid, thread_data, task_team, deque_ntasks, target,
2753 thread_data->td.td_deque_tail));
2754 task_team->tt.tt_num_task_pri++; // atomic inc, restore value
2755 return NULL;
2756 }
2757 int i;
2758 // walk through the deque trying to steal any task
2759 taskdata = NULL;
2760 for (i = 1; i < deque_ntasks; ++i) {
2761 target = (target + 1) & TASK_DEQUE_MASK(thread_data->td);
2762 taskdata = thread_data->td.td_deque[target];
2763 if (__kmp_task_is_allowed(gtid, is_constrained, taskdata, current)) {
2764 break; // found task to execute
2765 } else {
2766 taskdata = NULL;
2767 }
2768 }
2769 if (taskdata == NULL) {
2770 // No appropriate candidate found to execute
2771 __kmp_release_bootstrap_lock(&thread_data->td.td_deque_lock);
2772 KA_TRACE(
2773 10, ("__kmp_get_priority_task(exit #4): T#%d could not get task from "
2774 "%p: task_team=%p ntasks=%d head=%u tail=%u\n",
2775 gtid, thread_data, task_team, deque_ntasks,
2776 thread_data->td.td_deque_head, thread_data->td.td_deque_tail));
2777 task_team->tt.tt_num_task_pri++; // atomic inc, restore value
2778 return NULL;
2779 }
2780 int prev = target;
2781 for (i = i + 1; i < deque_ntasks; ++i) {
2782 // shift remaining tasks in the deque left by 1
2783 target = (target + 1) & TASK_DEQUE_MASK(thread_data->td);
2784 thread_data->td.td_deque[prev] = thread_data->td.td_deque[target];
2785 prev = target;
2786 }
2787 KMP_DEBUG_ASSERT(
2788 thread_data->td.td_deque_tail ==
2789 (kmp_uint32)((target + 1) & TASK_DEQUE_MASK(thread_data->td)));
2790 thread_data->td.td_deque_tail = target; // tail -= 1 (wrapped))
2791 }
2792 thread_data->td.td_deque_ntasks = deque_ntasks - 1;
2793 __kmp_release_bootstrap_lock(&thread_data->td.td_deque_lock);
2794 task = KMP_TASKDATA_TO_TASK(taskdata);
2795 return task;
2796}
2797
2798// __kmp_remove_my_task: remove a task from my own deque
2799static kmp_task_t *__kmp_remove_my_task(kmp_info_t *thread, kmp_int32 gtid,
2800 kmp_task_team_t *task_team,
2801 kmp_int32 is_constrained) {
2802 kmp_task_t *task;
2803 kmp_taskdata_t *taskdata;
2804 kmp_thread_data_t *thread_data;
2805 kmp_uint32 tail;
2806
2807 KMP_DEBUG_ASSERT(__kmp_tasking_mode != tskm_immediate_exec);
2808 KMP_DEBUG_ASSERT(task_team->tt.tt_threads_data !=
2809 NULL); // Caller should check this condition
2810
2811 thread_data = &task_team->tt.tt_threads_data[__kmp_tid_from_gtid(gtid)];
2812
2813 KA_TRACE(10, ("__kmp_remove_my_task(enter): T#%d ntasks=%d head=%u tail=%u\n",
2814 gtid, thread_data->td.td_deque_ntasks,
2815 thread_data->td.td_deque_head, thread_data->td.td_deque_tail));
2816
2817 if (TCR_4(thread_data->td.td_deque_ntasks) == 0) {
2818 KA_TRACE(10,
2819 ("__kmp_remove_my_task(exit #1): T#%d No tasks to remove: "
2820 "ntasks=%d head=%u tail=%u\n",
2821 gtid, thread_data->td.td_deque_ntasks,
2822 thread_data->td.td_deque_head, thread_data->td.td_deque_tail));
2823 return NULL;
2824 }
2825
2826 __kmp_acquire_bootstrap_lock(&thread_data->td.td_deque_lock);
2827
2828 if (TCR_4(thread_data->td.td_deque_ntasks) == 0) {
2829 __kmp_release_bootstrap_lock(&thread_data->td.td_deque_lock);
2830 KA_TRACE(10,
2831 ("__kmp_remove_my_task(exit #2): T#%d No tasks to remove: "
2832 "ntasks=%d head=%u tail=%u\n",
2833 gtid, thread_data->td.td_deque_ntasks,
2834 thread_data->td.td_deque_head, thread_data->td.td_deque_tail));
2835 return NULL;
2836 }
2837
2838 tail = (thread_data->td.td_deque_tail - 1) &
2839 TASK_DEQUE_MASK(thread_data->td); // Wrap index.
2840 taskdata = thread_data->td.td_deque[tail];
2841
2842 if (!__kmp_task_is_allowed(gtid, is_constrained, taskdata,
2843 thread->th.th_current_task)) {
2844 // The TSC does not allow to steal victim task
2845 __kmp_release_bootstrap_lock(&thread_data->td.td_deque_lock);
2846 KA_TRACE(10,
2847 ("__kmp_remove_my_task(exit #3): T#%d TSC blocks tail task: "
2848 "ntasks=%d head=%u tail=%u\n",
2849 gtid, thread_data->td.td_deque_ntasks,
2850 thread_data->td.td_deque_head, thread_data->td.td_deque_tail));
2851 return NULL;
2852 }
2853
2854 thread_data->td.td_deque_tail = tail;
2855 TCW_4(thread_data->td.td_deque_ntasks, thread_data->td.td_deque_ntasks - 1);
2856
2857 __kmp_release_bootstrap_lock(&thread_data->td.td_deque_lock);
2858
2859 KA_TRACE(10, ("__kmp_remove_my_task(exit #4): T#%d task %p removed: "
2860 "ntasks=%d head=%u tail=%u\n",
2861 gtid, taskdata, thread_data->td.td_deque_ntasks,
2862 thread_data->td.td_deque_head, thread_data->td.td_deque_tail));
2863
2864 task = KMP_TASKDATA_TO_TASK(taskdata);
2865 return task;
2866}
2867
2868// __kmp_steal_task: remove a task from another thread's deque
2869// Assume that calling thread has already checked existence of
2870// task_team thread_data before calling this routine.
2871static kmp_task_t *__kmp_steal_task(kmp_int32 victim_tid, kmp_int32 gtid,
2872 kmp_task_team_t *task_team,
2873 std::atomic<kmp_int32> *unfinished_threads,
2874 int *thread_finished,
2875 kmp_int32 is_constrained) {
2876 kmp_task_t *task;
2877 kmp_taskdata_t *taskdata;
2878 kmp_taskdata_t *current;
2879 kmp_thread_data_t *victim_td, *threads_data;
2880 kmp_int32 target;
2881 kmp_info_t *victim_thr;
2882
2883 KMP_DEBUG_ASSERT(__kmp_tasking_mode != tskm_immediate_exec);
2884
2885 threads_data = task_team->tt.tt_threads_data;
2886 KMP_DEBUG_ASSERT(threads_data != NULL); // Caller should check this condition
2887 KMP_DEBUG_ASSERT(victim_tid >= 0);
2888 KMP_DEBUG_ASSERT(victim_tid < task_team->tt.tt_max_threads);
2889
2890 victim_td = &threads_data[victim_tid];
2891 victim_thr = victim_td->td.td_thr;
2892 (void)victim_thr; // Use in TRACE messages which aren't always enabled.
2893
2894 KA_TRACE(10, ("__kmp_steal_task(enter): T#%d try to steal from T#%d: "
2895 "task_team=%p ntasks=%d head=%u tail=%u\n",
2896 gtid, __kmp_gtid_from_thread(victim_thr), task_team,
2897 victim_td->td.td_deque_ntasks, victim_td->td.td_deque_head,
2898 victim_td->td.td_deque_tail));
2899
2900 if (TCR_4(victim_td->td.td_deque_ntasks) == 0) {
2901 KA_TRACE(10, ("__kmp_steal_task(exit #1): T#%d could not steal from T#%d: "
2902 "task_team=%p ntasks=%d head=%u tail=%u\n",
2903 gtid, __kmp_gtid_from_thread(victim_thr), task_team,
2904 victim_td->td.td_deque_ntasks, victim_td->td.td_deque_head,
2905 victim_td->td.td_deque_tail));
2906 return NULL;
2907 }
2908
2909 __kmp_acquire_bootstrap_lock(&victim_td->td.td_deque_lock);
2910
2911 int ntasks = TCR_4(victim_td->td.td_deque_ntasks);
2912 // Check again after we acquire the lock
2913 if (ntasks == 0) {
2914 __kmp_release_bootstrap_lock(&victim_td->td.td_deque_lock);
2915 KA_TRACE(10, ("__kmp_steal_task(exit #2): T#%d could not steal from T#%d: "
2916 "task_team=%p ntasks=%d head=%u tail=%u\n",
2917 gtid, __kmp_gtid_from_thread(victim_thr), task_team, ntasks,
2918 victim_td->td.td_deque_head, victim_td->td.td_deque_tail));
2919 return NULL;
2920 }
2921
2922 KMP_DEBUG_ASSERT(victim_td->td.td_deque != NULL);
2923 current = __kmp_threads[gtid]->th.th_current_task;
2924 taskdata = victim_td->td.td_deque[victim_td->td.td_deque_head];
2925 if (__kmp_task_is_allowed(gtid, is_constrained, taskdata, current)) {
2926 // Bump head pointer and Wrap.
2927 victim_td->td.td_deque_head =
2928 (victim_td->td.td_deque_head + 1) & TASK_DEQUE_MASK(victim_td->td);
2929 } else {
2930 if (!task_team->tt.tt_untied_task_encountered) {
2931 // The TSC does not allow to steal victim task
2932 __kmp_release_bootstrap_lock(&victim_td->td.td_deque_lock);
2933 KA_TRACE(10, ("__kmp_steal_task(exit #3): T#%d could not steal from "
2934 "T#%d: task_team=%p ntasks=%d head=%u tail=%u\n",
2935 gtid, __kmp_gtid_from_thread(victim_thr), task_team, ntasks,
2936 victim_td->td.td_deque_head, victim_td->td.td_deque_tail));
2937 return NULL;
2938 }
2939 int i;
2940 // walk through victim's deque trying to steal any task
2941 target = victim_td->td.td_deque_head;
2942 taskdata = NULL;
2943 for (i = 1; i < ntasks; ++i) {
2944 target = (target + 1) & TASK_DEQUE_MASK(victim_td->td);
2945 taskdata = victim_td->td.td_deque[target];
2946 if (__kmp_task_is_allowed(gtid, is_constrained, taskdata, current)) {
2947 break; // found victim task
2948 } else {
2949 taskdata = NULL;
2950 }
2951 }
2952 if (taskdata == NULL) {
2953 // No appropriate candidate to steal found
2954 __kmp_release_bootstrap_lock(&victim_td->td.td_deque_lock);
2955 KA_TRACE(10, ("__kmp_steal_task(exit #4): T#%d could not steal from "
2956 "T#%d: task_team=%p ntasks=%d head=%u tail=%u\n",
2957 gtid, __kmp_gtid_from_thread(victim_thr), task_team, ntasks,
2958 victim_td->td.td_deque_head, victim_td->td.td_deque_tail));
2959 return NULL;
2960 }
2961 int prev = target;
2962 for (i = i + 1; i < ntasks; ++i) {
2963 // shift remaining tasks in the deque left by 1
2964 target = (target + 1) & TASK_DEQUE_MASK(victim_td->td);
2965 victim_td->td.td_deque[prev] = victim_td->td.td_deque[target];
2966 prev = target;
2967 }
2968 KMP_DEBUG_ASSERT(
2969 victim_td->td.td_deque_tail ==
2970 (kmp_uint32)((target + 1) & TASK_DEQUE_MASK(victim_td->td)));
2971 victim_td->td.td_deque_tail = target; // tail -= 1 (wrapped))
2972 }
2973 if (*thread_finished) {
2974 // We need to un-mark this victim as a finished victim. This must be done
2975 // before releasing the lock, or else other threads (starting with the
2976 // primary thread victim) might be prematurely released from the barrier!!!
2977#if KMP_DEBUG
2978 kmp_int32 count =
2979#endif
2980 KMP_ATOMIC_INC(unfinished_threads);
2981 KA_TRACE(
2982 20,
2983 ("__kmp_steal_task: T#%d inc unfinished_threads to %d: task_team=%p\n",
2984 gtid, count + 1, task_team));
2985 *thread_finished = FALSE;
2986 }
2987 TCW_4(victim_td->td.td_deque_ntasks, ntasks - 1);
2988
2989 __kmp_release_bootstrap_lock(&victim_td->td.td_deque_lock);
2990
2991 KMP_COUNT_BLOCK(TASK_stolen);
2992 KA_TRACE(10,
2993 ("__kmp_steal_task(exit #5): T#%d stole task %p from T#%d: "
2994 "task_team=%p ntasks=%d head=%u tail=%u\n",
2995 gtid, taskdata, __kmp_gtid_from_thread(victim_thr), task_team,
2996 ntasks, victim_td->td.td_deque_head, victim_td->td.td_deque_tail));
2997
2998 task = KMP_TASKDATA_TO_TASK(taskdata);
2999 return task;
3000}
3001
3002// __kmp_execute_tasks_template: Choose and execute tasks until either the
3003// condition is statisfied (return true) or there are none left (return false).
3004//
3005// final_spin is TRUE if this is the spin at the release barrier.
3006// thread_finished indicates whether the thread is finished executing all
3007// the tasks it has on its deque, and is at the release barrier.
3008// spinner is the location on which to spin.
3009// spinner == NULL means only execute a single task and return.
3010// checker is the value to check to terminate the spin.
3011template <class C>
3012static inline int __kmp_execute_tasks_template(
3013 kmp_info_t *thread, kmp_int32 gtid, C *flag, int final_spin,
3014 int *thread_finished USE_ITT_BUILD_ARG(void *itt_sync_obj),
3015 kmp_int32 is_constrained) {
3016 kmp_task_team_t *task_team = thread->th.th_task_team;
3017 kmp_thread_data_t *threads_data;
3018 kmp_task_t *task;
3019 kmp_info_t *other_thread;
3020 kmp_taskdata_t *current_task = thread->th.th_current_task;
3021 std::atomic<kmp_int32> *unfinished_threads;
3022 kmp_int32 nthreads, victim_tid = -2, use_own_tasks = 1, new_victim = 0,
3023 tid = thread->th.th_info.ds.ds_tid;
3024
3025 KMP_DEBUG_ASSERT(__kmp_tasking_mode != tskm_immediate_exec);
3026 KMP_DEBUG_ASSERT(thread == __kmp_threads[gtid]);
3027
3028 if (task_team == NULL || current_task == NULL)
3029 return FALSE;
3030
3031 KA_TRACE(15, ("__kmp_execute_tasks_template(enter): T#%d final_spin=%d "
3032 "*thread_finished=%d\n",
3033 gtid, final_spin, *thread_finished));
3034
3035 thread->th.th_reap_state = KMP_NOT_SAFE_TO_REAP;
3036 threads_data = (kmp_thread_data_t *)TCR_PTR(task_team->tt.tt_threads_data);
3037
3038 KMP_DEBUG_ASSERT(threads_data != NULL);
3039
3040 nthreads = task_team->tt.tt_nproc;
3041 unfinished_threads = &(task_team->tt.tt_unfinished_threads);
3042 KMP_DEBUG_ASSERT(*unfinished_threads >= 0);
3043
3044 while (1) { // Outer loop keeps trying to find tasks in case of single thread
3045 // getting tasks from target constructs
3046 while (1) { // Inner loop to find a task and execute it
3047#if ENABLE_LIBOMPTARGET
3048 // Give an opportunity to the offload runtime to make progress
3049 if (UNLIKELY(kmp_target_sync_cb))
3050 (*kmp_target_sync_cb)(NULL, gtid, KMP_TASKDATA_TO_TASK(current_task),
3051 NULL);
3052#endif // ENABLE_LIBOMPTARGET
3053
3054 task = NULL;
3055 if (task_team->tt.tt_num_task_pri) { // get priority task first
3056 task = __kmp_get_priority_task(gtid, task_team, is_constrained);
3057 }
3058 if (task == NULL && use_own_tasks) { // check own queue next
3059 task = __kmp_remove_my_task(thread, gtid, task_team, is_constrained);
3060 }
3061 if ((task == NULL) && (nthreads > 1)) { // Steal a task finally
3062 int asleep = 1;
3063 use_own_tasks = 0;
3064 // Try to steal from the last place I stole from successfully.
3065 if (victim_tid == -2) { // haven't stolen anything yet
3066 victim_tid = threads_data[tid].td.td_deque_last_stolen;
3067 if (victim_tid !=
3068 -1) // if we have a last stolen from victim, get the thread
3069 other_thread = threads_data[victim_tid].td.td_thr;
3070 }
3071 if (victim_tid != -1) { // found last victim
3072 asleep = 0;
3073 } else if (!new_victim) { // no recent steals and we haven't already
3074 // used a new victim; select a random thread
3075 do { // Find a different thread to steal work from.
3076 // Pick a random thread. Initial plan was to cycle through all the
3077 // threads, and only return if we tried to steal from every thread,
3078 // and failed. Arch says that's not such a great idea.
3079 victim_tid = __kmp_get_random(thread) % (nthreads - 1);
3080 if (victim_tid >= tid) {
3081 ++victim_tid; // Adjusts random distribution to exclude self
3082 }
3083 // Found a potential victim
3084 other_thread = threads_data[victim_tid].td.td_thr;
3085 // There is a slight chance that __kmp_enable_tasking() did not wake
3086 // up all threads waiting at the barrier. If victim is sleeping,
3087 // then wake it up. Since we were going to pay the cache miss
3088 // penalty for referencing another thread's kmp_info_t struct
3089 // anyway,
3090 // the check shouldn't cost too much performance at this point. In
3091 // extra barrier mode, tasks do not sleep at the separate tasking
3092 // barrier, so this isn't a problem.
3093 asleep = 0;
3094 if ((__kmp_tasking_mode == tskm_task_teams) &&
3095 (__kmp_dflt_blocktime != KMP_MAX_BLOCKTIME) &&
3096 (TCR_PTR(CCAST(void *, other_thread->th.th_sleep_loc)) !=
3097 NULL)) {
3098 asleep = 1;
3099 __kmp_null_resume_wrapper(other_thread);
3100 // A sleeping thread should not have any tasks on it's queue.
3101 // There is a slight possibility that it resumes, steals a task
3102 // from another thread, which spawns more tasks, all in the time
3103 // that it takes this thread to check => don't write an assertion
3104 // that the victim's queue is empty. Try stealing from a
3105 // different thread.
3106 }
3107 } while (asleep);
3108 }
3109
3110 if (!asleep) {
3111 // We have a victim to try to steal from
3112 task =
3113 __kmp_steal_task(victim_tid, gtid, task_team, unfinished_threads,
3114 thread_finished, is_constrained);
3115 }
3116 if (task != NULL) { // set last stolen to victim
3117 if (threads_data[tid].td.td_deque_last_stolen != victim_tid) {
3118 threads_data[tid].td.td_deque_last_stolen = victim_tid;
3119 // The pre-refactored code did not try more than 1 successful new
3120 // vicitm, unless the last one generated more local tasks;
3121 // new_victim keeps track of this
3122 new_victim = 1;
3123 }
3124 } else { // No tasks found; unset last_stolen
3125 KMP_CHECK_UPDATE(threads_data[tid].td.td_deque_last_stolen, -1);
3126 victim_tid = -2; // no successful victim found
3127 }
3128 }
3129
3130 if (task == NULL)
3131 break; // break out of tasking loop
3132
3133// Found a task; execute it
3134#if USE_ITT_BUILD && USE_ITT_NOTIFY
3135 if (__itt_sync_create_ptr || KMP_ITT_DEBUG) {
3136 if (itt_sync_obj == NULL) { // we are at fork barrier where we could not
3137 // get the object reliably
3138 itt_sync_obj = __kmp_itt_barrier_object(gtid, bs_forkjoin_barrier);
3139 }
3140 __kmp_itt_task_starting(itt_sync_obj);
3141 }
3142#endif /* USE_ITT_BUILD && USE_ITT_NOTIFY */
3143 __kmp_invoke_task(gtid, task, current_task);
3144#if USE_ITT_BUILD
3145 if (itt_sync_obj != NULL)
3146 __kmp_itt_task_finished(itt_sync_obj);
3147#endif /* USE_ITT_BUILD */
3148 // If this thread is only partway through the barrier and the condition is
3149 // met, then return now, so that the barrier gather/release pattern can
3150 // proceed. If this thread is in the last spin loop in the barrier,
3151 // waiting to be released, we know that the termination condition will not
3152 // be satisfied, so don't waste any cycles checking it.
3153 if (flag == NULL || (!final_spin && flag->done_check())) {
3154 KA_TRACE(
3155 15,
3156 ("__kmp_execute_tasks_template: T#%d spin condition satisfied\n",
3157 gtid));
3158 return TRUE;
3159 }
3160 if (thread->th.th_task_team == NULL) {
3161 break;
3162 }
3163 KMP_YIELD(__kmp_library == library_throughput); // Yield before next task
3164 // If execution of a stolen task results in more tasks being placed on our
3165 // run queue, reset use_own_tasks
3166 if (!use_own_tasks && TCR_4(threads_data[tid].td.td_deque_ntasks) != 0) {
3167 KA_TRACE(20, ("__kmp_execute_tasks_template: T#%d stolen task spawned "
3168 "other tasks, restart\n",
3169 gtid));
3170 use_own_tasks = 1;
3171 new_victim = 0;
3172 }
3173 }
3174
3175 // The task source has been exhausted. If in final spin loop of barrier,
3176 // check if termination condition is satisfied. The work queue may be empty
3177 // but there might be proxy tasks still executing.
3178 if (final_spin &&
3179 KMP_ATOMIC_LD_ACQ(&current_task->td_incomplete_child_tasks) == 0) {
3180 // First, decrement the #unfinished threads, if that has not already been
3181 // done. This decrement might be to the spin location, and result in the
3182 // termination condition being satisfied.
3183 if (!*thread_finished) {
3184#if KMP_DEBUG
3185 kmp_int32 count = -1 +
3186#endif
3187 KMP_ATOMIC_DEC(unfinished_threads);
3188 KA_TRACE(20, ("__kmp_execute_tasks_template: T#%d dec "
3189 "unfinished_threads to %d task_team=%p\n",
3190 gtid, count, task_team));
3191 *thread_finished = TRUE;
3192 }
3193
3194 // It is now unsafe to reference thread->th.th_team !!!
3195 // Decrementing task_team->tt.tt_unfinished_threads can allow the primary
3196 // thread to pass through the barrier, where it might reset each thread's
3197 // th.th_team field for the next parallel region. If we can steal more
3198 // work, we know that this has not happened yet.
3199 if (flag != NULL && flag->done_check()) {
3200 KA_TRACE(
3201 15,
3202 ("__kmp_execute_tasks_template: T#%d spin condition satisfied\n",
3203 gtid));
3204 return TRUE;
3205 }
3206 }
3207
3208 // If this thread's task team is NULL, primary thread has recognized that
3209 // there are no more tasks; bail out
3210 if (thread->th.th_task_team == NULL) {
3211 KA_TRACE(15,
3212 ("__kmp_execute_tasks_template: T#%d no more tasks\n", gtid));
3213 return FALSE;
3214 }
3215
3216 // Check the flag again to see if it has already done in case to be trapped
3217 // into infinite loop when a if0 task depends on a hidden helper task
3218 // outside any parallel region. Detached tasks are not impacted in this case
3219 // because the only thread executing this function has to execute the proxy
3220 // task so it is in another code path that has the same check.
3221 if (flag == NULL || (!final_spin && flag->done_check())) {
3222 KA_TRACE(15,
3223 ("__kmp_execute_tasks_template: T#%d spin condition satisfied\n",
3224 gtid));
3225 return TRUE;
3226 }
3227
3228 // We could be getting tasks from target constructs; if this is the only
3229 // thread, keep trying to execute tasks from own queue
3230 if (nthreads == 1 &&
3231 KMP_ATOMIC_LD_ACQ(&current_task->td_incomplete_child_tasks))
3232 use_own_tasks = 1;
3233 else {
3234 KA_TRACE(15,
3235 ("__kmp_execute_tasks_template: T#%d can't find work\n", gtid));
3236 return FALSE;
3237 }
3238 }
3239}
3240
3241template <bool C, bool S>
3242int __kmp_execute_tasks_32(
3243 kmp_info_t *thread, kmp_int32 gtid, kmp_flag_32<C, S> *flag, int final_spin,
3244 int *thread_finished USE_ITT_BUILD_ARG(void *itt_sync_obj),
3245 kmp_int32 is_constrained) {
3246 return __kmp_execute_tasks_template(
3247 thread, gtid, flag, final_spin,
3248 thread_finished USE_ITT_BUILD_ARG(itt_sync_obj), is_constrained);
3249}
3250
3251template <bool C, bool S>
3252int __kmp_execute_tasks_64(
3253 kmp_info_t *thread, kmp_int32 gtid, kmp_flag_64<C, S> *flag, int final_spin,
3254 int *thread_finished USE_ITT_BUILD_ARG(void *itt_sync_obj),
3255 kmp_int32 is_constrained) {
3256 return __kmp_execute_tasks_template(
3257 thread, gtid, flag, final_spin,
3258 thread_finished USE_ITT_BUILD_ARG(itt_sync_obj), is_constrained);
3259}
3260
3261template <bool C, bool S>
3262int __kmp_atomic_execute_tasks_64(
3263 kmp_info_t *thread, kmp_int32 gtid, kmp_atomic_flag_64<C, S> *flag,
3264 int final_spin, int *thread_finished USE_ITT_BUILD_ARG(void *itt_sync_obj),
3265 kmp_int32 is_constrained) {
3266 return __kmp_execute_tasks_template(
3267 thread, gtid, flag, final_spin,
3268 thread_finished USE_ITT_BUILD_ARG(itt_sync_obj), is_constrained);
3269}
3270
3271int __kmp_execute_tasks_oncore(
3272 kmp_info_t *thread, kmp_int32 gtid, kmp_flag_oncore *flag, int final_spin,
3273 int *thread_finished USE_ITT_BUILD_ARG(void *itt_sync_obj),
3274 kmp_int32 is_constrained) {
3275 return __kmp_execute_tasks_template(
3276 thread, gtid, flag, final_spin,
3277 thread_finished USE_ITT_BUILD_ARG(itt_sync_obj), is_constrained);
3278}
3279
3280template int
3281__kmp_execute_tasks_32<false, false>(kmp_info_t *, kmp_int32,
3282 kmp_flag_32<false, false> *, int,
3283 int *USE_ITT_BUILD_ARG(void *), kmp_int32);
3284
3285template int __kmp_execute_tasks_64<false, true>(kmp_info_t *, kmp_int32,
3286 kmp_flag_64<false, true> *,
3287 int,
3288 int *USE_ITT_BUILD_ARG(void *),
3289 kmp_int32);
3290
3291template int __kmp_execute_tasks_64<true, false>(kmp_info_t *, kmp_int32,
3292 kmp_flag_64<true, false> *,
3293 int,
3294 int *USE_ITT_BUILD_ARG(void *),
3295 kmp_int32);
3296
3297template int __kmp_atomic_execute_tasks_64<false, true>(
3298 kmp_info_t *, kmp_int32, kmp_atomic_flag_64<false, true> *, int,
3299 int *USE_ITT_BUILD_ARG(void *), kmp_int32);
3300
3301template int __kmp_atomic_execute_tasks_64<true, false>(
3302 kmp_info_t *, kmp_int32, kmp_atomic_flag_64<true, false> *, int,
3303 int *USE_ITT_BUILD_ARG(void *), kmp_int32);
3304
3305// __kmp_enable_tasking: Allocate task team and resume threads sleeping at the
3306// next barrier so they can assist in executing enqueued tasks.
3307// First thread in allocates the task team atomically.
3308static void __kmp_enable_tasking(kmp_task_team_t *task_team,
3309 kmp_info_t *this_thr) {
3310 kmp_thread_data_t *threads_data;
3311 int nthreads, i, is_init_thread;
3312
3313 KA_TRACE(10, ("__kmp_enable_tasking(enter): T#%d\n",
3314 __kmp_gtid_from_thread(this_thr)));
3315
3316 KMP_DEBUG_ASSERT(task_team != NULL);
3317 KMP_DEBUG_ASSERT(this_thr->th.th_team != NULL);
3318
3319 nthreads = task_team->tt.tt_nproc;
3320 KMP_DEBUG_ASSERT(nthreads > 0);
3321 KMP_DEBUG_ASSERT(nthreads == this_thr->th.th_team->t.t_nproc);
3322
3323 // Allocate or increase the size of threads_data if necessary
3324 is_init_thread = __kmp_realloc_task_threads_data(this_thr, task_team);
3325
3326 if (!is_init_thread) {
3327 // Some other thread already set up the array.
3328 KA_TRACE(
3329 20,
3330 ("__kmp_enable_tasking(exit): T#%d: threads array already set up.\n",
3331 __kmp_gtid_from_thread(this_thr)));
3332 return;
3333 }
3334 threads_data = (kmp_thread_data_t *)TCR_PTR(task_team->tt.tt_threads_data);
3335 KMP_DEBUG_ASSERT(threads_data != NULL);
3336
3337 if (__kmp_tasking_mode == tskm_task_teams &&
3338 (__kmp_dflt_blocktime != KMP_MAX_BLOCKTIME)) {
3339 // Release any threads sleeping at the barrier, so that they can steal
3340 // tasks and execute them. In extra barrier mode, tasks do not sleep
3341 // at the separate tasking barrier, so this isn't a problem.
3342 for (i = 0; i < nthreads; i++) {
3343 void *sleep_loc;
3344 kmp_info_t *thread = threads_data[i].td.td_thr;
3345
3346 if (i == this_thr->th.th_info.ds.ds_tid) {
3347 continue;
3348 }
3349 // Since we haven't locked the thread's suspend mutex lock at this
3350 // point, there is a small window where a thread might be putting
3351 // itself to sleep, but hasn't set the th_sleep_loc field yet.
3352 // To work around this, __kmp_execute_tasks_template() periodically checks
3353 // see if other threads are sleeping (using the same random mechanism that
3354 // is used for task stealing) and awakens them if they are.
3355 if ((sleep_loc = TCR_PTR(CCAST(void *, thread->th.th_sleep_loc))) !=
3356 NULL) {
3357 KF_TRACE(50, ("__kmp_enable_tasking: T#%d waking up thread T#%d\n",
3358 __kmp_gtid_from_thread(this_thr),
3359 __kmp_gtid_from_thread(thread)));
3360 __kmp_null_resume_wrapper(thread);
3361 } else {
3362 KF_TRACE(50, ("__kmp_enable_tasking: T#%d don't wake up thread T#%d\n",
3363 __kmp_gtid_from_thread(this_thr),
3364 __kmp_gtid_from_thread(thread)));
3365 }
3366 }
3367 }
3368
3369 KA_TRACE(10, ("__kmp_enable_tasking(exit): T#%d\n",
3370 __kmp_gtid_from_thread(this_thr)));
3371}
3372
3373/* // TODO: Check the comment consistency
3374 * Utility routines for "task teams". A task team (kmp_task_t) is kind of
3375 * like a shadow of the kmp_team_t data struct, with a different lifetime.
3376 * After a child * thread checks into a barrier and calls __kmp_release() from
3377 * the particular variant of __kmp_<barrier_kind>_barrier_gather(), it can no
3378 * longer assume that the kmp_team_t structure is intact (at any moment, the
3379 * primary thread may exit the barrier code and free the team data structure,
3380 * and return the threads to the thread pool).
3381 *
3382 * This does not work with the tasking code, as the thread is still
3383 * expected to participate in the execution of any tasks that may have been
3384 * spawned my a member of the team, and the thread still needs access to all
3385 * to each thread in the team, so that it can steal work from it.
3386 *
3387 * Enter the existence of the kmp_task_team_t struct. It employs a reference
3388 * counting mechanism, and is allocated by the primary thread before calling
3389 * __kmp_<barrier_kind>_release, and then is release by the last thread to
3390 * exit __kmp_<barrier_kind>_release at the next barrier. I.e. the lifetimes
3391 * of the kmp_task_team_t structs for consecutive barriers can overlap
3392 * (and will, unless the primary thread is the last thread to exit the barrier
3393 * release phase, which is not typical). The existence of such a struct is
3394 * useful outside the context of tasking.
3395 *
3396 * We currently use the existence of the threads array as an indicator that
3397 * tasks were spawned since the last barrier. If the structure is to be
3398 * useful outside the context of tasking, then this will have to change, but
3399 * not setting the field minimizes the performance impact of tasking on
3400 * barriers, when no explicit tasks were spawned (pushed, actually).
3401 */
3402
3403static kmp_task_team_t *__kmp_free_task_teams =
3404 NULL; // Free list for task_team data structures
3405// Lock for task team data structures
3406kmp_bootstrap_lock_t __kmp_task_team_lock =
3407 KMP_BOOTSTRAP_LOCK_INITIALIZER(__kmp_task_team_lock);
3408
3409// __kmp_alloc_task_deque:
3410// Allocates a task deque for a particular thread, and initialize the necessary
3411// data structures relating to the deque. This only happens once per thread
3412// per task team since task teams are recycled. No lock is needed during
3413// allocation since each thread allocates its own deque.
3414static void __kmp_alloc_task_deque(kmp_info_t *thread,
3415 kmp_thread_data_t *thread_data) {
3416 __kmp_init_bootstrap_lock(&thread_data->td.td_deque_lock);
3417 KMP_DEBUG_ASSERT(thread_data->td.td_deque == NULL);
3418
3419 // Initialize last stolen task field to "none"
3420 thread_data->td.td_deque_last_stolen = -1;
3421
3422 KMP_DEBUG_ASSERT(TCR_4(thread_data->td.td_deque_ntasks) == 0);
3423 KMP_DEBUG_ASSERT(thread_data->td.td_deque_head == 0);
3424 KMP_DEBUG_ASSERT(thread_data->td.td_deque_tail == 0);
3425
3426 KE_TRACE(
3427 10,
3428 ("__kmp_alloc_task_deque: T#%d allocating deque[%d] for thread_data %p\n",
3429 __kmp_gtid_from_thread(thread), INITIAL_TASK_DEQUE_SIZE, thread_data));
3430 // Allocate space for task deque, and zero the deque
3431 // Cannot use __kmp_thread_calloc() because threads not around for
3432 // kmp_reap_task_team( ).
3433 thread_data->td.td_deque = (kmp_taskdata_t **)__kmp_allocate(
3434 INITIAL_TASK_DEQUE_SIZE * sizeof(kmp_taskdata_t *));
3435 thread_data->td.td_deque_size = INITIAL_TASK_DEQUE_SIZE;
3436}
3437
3438// __kmp_free_task_deque:
3439// Deallocates a task deque for a particular thread. Happens at library
3440// deallocation so don't need to reset all thread data fields.
3441static void __kmp_free_task_deque(kmp_thread_data_t *thread_data) {
3442 if (thread_data->td.td_deque != NULL) {
3443 __kmp_acquire_bootstrap_lock(&thread_data->td.td_deque_lock);
3444 TCW_4(thread_data->td.td_deque_ntasks, 0);
3445 __kmp_free(thread_data->td.td_deque);
3446 thread_data->td.td_deque = NULL;
3447 __kmp_release_bootstrap_lock(&thread_data->td.td_deque_lock);
3448 }
3449}
3450
3451// __kmp_realloc_task_threads_data:
3452// Allocates a threads_data array for a task team, either by allocating an
3453// initial array or enlarging an existing array. Only the first thread to get
3454// the lock allocs or enlarges the array and re-initializes the array elements.
3455// That thread returns "TRUE", the rest return "FALSE".
3456// Assumes that the new array size is given by task_team -> tt.tt_nproc.
3457// The current size is given by task_team -> tt.tt_max_threads.
3458static int __kmp_realloc_task_threads_data(kmp_info_t *thread,
3459 kmp_task_team_t *task_team) {
3460 kmp_thread_data_t **threads_data_p;
3461 kmp_int32 nthreads, maxthreads;
3462 int is_init_thread = FALSE;
3463
3464 if (TCR_4(task_team->tt.tt_found_tasks)) {
3465 // Already reallocated and initialized.
3466 return FALSE;
3467 }
3468
3469 threads_data_p = &task_team->tt.tt_threads_data;
3470 nthreads = task_team->tt.tt_nproc;
3471 maxthreads = task_team->tt.tt_max_threads;
3472
3473 // All threads must lock when they encounter the first task of the implicit
3474 // task region to make sure threads_data fields are (re)initialized before
3475 // used.
3476 __kmp_acquire_bootstrap_lock(&task_team->tt.tt_threads_lock);
3477
3478 if (!TCR_4(task_team->tt.tt_found_tasks)) {
3479 // first thread to enable tasking
3480 kmp_team_t *team = thread->th.th_team;
3481 int i;
3482
3483 is_init_thread = TRUE;
3484 if (maxthreads < nthreads) {
3485
3486 if (*threads_data_p != NULL) {
3487 kmp_thread_data_t *old_data = *threads_data_p;
3488 kmp_thread_data_t *new_data = NULL;
3489
3490 KE_TRACE(
3491 10,
3492 ("__kmp_realloc_task_threads_data: T#%d reallocating "
3493 "threads data for task_team %p, new_size = %d, old_size = %d\n",
3494 __kmp_gtid_from_thread(thread), task_team, nthreads, maxthreads));
3495 // Reallocate threads_data to have more elements than current array
3496 // Cannot use __kmp_thread_realloc() because threads not around for
3497 // kmp_reap_task_team( ). Note all new array entries are initialized
3498 // to zero by __kmp_allocate().
3499 new_data = (kmp_thread_data_t *)__kmp_allocate(
3500 nthreads * sizeof(kmp_thread_data_t));
3501 // copy old data to new data
3502 KMP_MEMCPY_S((void *)new_data, nthreads * sizeof(kmp_thread_data_t),
3503 (void *)old_data, maxthreads * sizeof(kmp_thread_data_t));
3504
3505 // Install the new data and free the old data
3506 (*threads_data_p) = new_data;
3507 __kmp_free(old_data);
3508 } else {
3509 KE_TRACE(10, ("__kmp_realloc_task_threads_data: T#%d allocating "
3510 "threads data for task_team %p, size = %d\n",
3511 __kmp_gtid_from_thread(thread), task_team, nthreads));
3512 // Make the initial allocate for threads_data array, and zero entries
3513 // Cannot use __kmp_thread_calloc() because threads not around for
3514 // kmp_reap_task_team( ).
3515 *threads_data_p = (kmp_thread_data_t *)__kmp_allocate(
3516 nthreads * sizeof(kmp_thread_data_t));
3517 }
3518 task_team->tt.tt_max_threads = nthreads;
3519 } else {
3520 // If array has (more than) enough elements, go ahead and use it
3521 KMP_DEBUG_ASSERT(*threads_data_p != NULL);
3522 }
3523
3524 // initialize threads_data pointers back to thread_info structures
3525 for (i = 0; i < nthreads; i++) {
3526 kmp_thread_data_t *thread_data = &(*threads_data_p)[i];
3527 thread_data->td.td_thr = team->t.t_threads[i];
3528
3529 if (thread_data->td.td_deque_last_stolen >= nthreads) {
3530 // The last stolen field survives across teams / barrier, and the number
3531 // of threads may have changed. It's possible (likely?) that a new
3532 // parallel region will exhibit the same behavior as previous region.
3533 thread_data->td.td_deque_last_stolen = -1;
3534 }
3535 }
3536
3537 KMP_MB();
3538 TCW_SYNC_4(task_team->tt.tt_found_tasks, TRUE);
3539 }
3540
3541 __kmp_release_bootstrap_lock(&task_team->tt.tt_threads_lock);
3542 return is_init_thread;
3543}
3544
3545// __kmp_free_task_threads_data:
3546// Deallocates a threads_data array for a task team, including any attached
3547// tasking deques. Only occurs at library shutdown.
3548static void __kmp_free_task_threads_data(kmp_task_team_t *task_team) {
3549 __kmp_acquire_bootstrap_lock(&task_team->tt.tt_threads_lock);
3550 if (task_team->tt.tt_threads_data != NULL) {
3551 int i;
3552 for (i = 0; i < task_team->tt.tt_max_threads; i++) {
3553 __kmp_free_task_deque(&task_team->tt.tt_threads_data[i]);
3554 }
3555 __kmp_free(task_team->tt.tt_threads_data);
3556 task_team->tt.tt_threads_data = NULL;
3557 }
3558 __kmp_release_bootstrap_lock(&task_team->tt.tt_threads_lock);
3559}
3560
3561// __kmp_free_task_pri_list:
3562// Deallocates tasking deques used for priority tasks.
3563// Only occurs at library shutdown.
3564static void __kmp_free_task_pri_list(kmp_task_team_t *task_team) {
3565 __kmp_acquire_bootstrap_lock(&task_team->tt.tt_task_pri_lock);
3566 if (task_team->tt.tt_task_pri_list != NULL) {
3567 kmp_task_pri_t *list = task_team->tt.tt_task_pri_list;
3568 while (list != NULL) {
3569 kmp_task_pri_t *next = list->next;
3570 __kmp_free_task_deque(&list->td);
3571 __kmp_free(list);
3572 list = next;
3573 }
3574 task_team->tt.tt_task_pri_list = NULL;
3575 }
3576 __kmp_release_bootstrap_lock(&task_team->tt.tt_task_pri_lock);
3577}
3578
3579static inline void __kmp_task_team_init(kmp_task_team_t *task_team,
3580 kmp_team_t *team) {
3581 int team_nth = team->t.t_nproc;
3582 // Only need to init if task team is isn't active or team size changed
3583 if (!task_team->tt.tt_active || team_nth != task_team->tt.tt_nproc) {
3584 TCW_4(task_team->tt.tt_found_tasks, FALSE);
3585 TCW_4(task_team->tt.tt_found_proxy_tasks, FALSE);
3586 TCW_4(task_team->tt.tt_hidden_helper_task_encountered, FALSE);
3587 TCW_4(task_team->tt.tt_nproc, team_nth);
3588 KMP_ATOMIC_ST_REL(&task_team->tt.tt_unfinished_threads, team_nth);
3589 TCW_4(task_team->tt.tt_active, TRUE);
3590 }
3591}
3592
3593// __kmp_allocate_task_team:
3594// Allocates a task team associated with a specific team, taking it from
3595// the global task team free list if possible. Also initializes data
3596// structures.
3597static kmp_task_team_t *__kmp_allocate_task_team(kmp_info_t *thread,
3598 kmp_team_t *team) {
3599 kmp_task_team_t *task_team = NULL;
3600
3601 KA_TRACE(20, ("__kmp_allocate_task_team: T#%d entering; team = %p\n",
3602 (thread ? __kmp_gtid_from_thread(thread) : -1), team));
3603
3604 if (TCR_PTR(__kmp_free_task_teams) != NULL) {
3605 // Take a task team from the task team pool
3606 __kmp_acquire_bootstrap_lock(&__kmp_task_team_lock);
3607 if (__kmp_free_task_teams != NULL) {
3608 task_team = __kmp_free_task_teams;
3609 TCW_PTR(__kmp_free_task_teams, task_team->tt.tt_next);
3610 task_team->tt.tt_next = NULL;
3611 }
3612 __kmp_release_bootstrap_lock(&__kmp_task_team_lock);
3613 }
3614
3615 if (task_team == NULL) {
3616 KE_TRACE(10, ("__kmp_allocate_task_team: T#%d allocating "
3617 "task team for team %p\n",
3618 __kmp_gtid_from_thread(thread), team));
3619 // Allocate a new task team if one is not available. Cannot use
3620 // __kmp_thread_malloc because threads not around for kmp_reap_task_team.
3621 task_team = (kmp_task_team_t *)__kmp_allocate(sizeof(kmp_task_team_t));
3622 __kmp_init_bootstrap_lock(&task_team->tt.tt_threads_lock);
3623 __kmp_init_bootstrap_lock(&task_team->tt.tt_task_pri_lock);
3624#if USE_ITT_BUILD && USE_ITT_NOTIFY && KMP_DEBUG
3625 // suppress race conditions detection on synchronization flags in debug mode
3626 // this helps to analyze library internals eliminating false positives
3627 __itt_suppress_mark_range(
3628 __itt_suppress_range, __itt_suppress_threading_errors,
3629 &task_team->tt.tt_found_tasks, sizeof(task_team->tt.tt_found_tasks));
3630 __itt_suppress_mark_range(__itt_suppress_range,
3631 __itt_suppress_threading_errors,
3632 CCAST(kmp_uint32 *, &task_team->tt.tt_active),
3633 sizeof(task_team->tt.tt_active));
3634#endif /* USE_ITT_BUILD && USE_ITT_NOTIFY && KMP_DEBUG */
3635 // Note: __kmp_allocate zeroes returned memory, othewise we would need:
3636 // task_team->tt.tt_threads_data = NULL;
3637 // task_team->tt.tt_max_threads = 0;
3638 // task_team->tt.tt_next = NULL;
3639 }
3640
3641 __kmp_task_team_init(task_team, team);
3642
3643 KA_TRACE(20, ("__kmp_allocate_task_team: T#%d exiting; task_team = %p "
3644 "unfinished_threads init'd to %d\n",
3645 (thread ? __kmp_gtid_from_thread(thread) : -1), task_team,
3646 KMP_ATOMIC_LD_RLX(&task_team->tt.tt_unfinished_threads)));
3647 return task_team;
3648}
3649
3650// __kmp_free_task_team:
3651// Frees the task team associated with a specific thread, and adds it
3652// to the global task team free list.
3653void __kmp_free_task_team(kmp_info_t *thread, kmp_task_team_t *task_team) {
3654 KA_TRACE(20, ("__kmp_free_task_team: T#%d task_team = %p\n",
3655 thread ? __kmp_gtid_from_thread(thread) : -1, task_team));
3656
3657 // Put task team back on free list
3658 __kmp_acquire_bootstrap_lock(&__kmp_task_team_lock);
3659
3660 KMP_DEBUG_ASSERT(task_team->tt.tt_next == NULL);
3661 task_team->tt.tt_next = __kmp_free_task_teams;
3662 TCW_PTR(__kmp_free_task_teams, task_team);
3663
3664 __kmp_release_bootstrap_lock(&__kmp_task_team_lock);
3665}
3666
3667// __kmp_reap_task_teams:
3668// Free all the task teams on the task team free list.
3669// Should only be done during library shutdown.
3670// Cannot do anything that needs a thread structure or gtid since they are
3671// already gone.
3672void __kmp_reap_task_teams(void) {
3673 kmp_task_team_t *task_team;
3674
3675 if (TCR_PTR(__kmp_free_task_teams) != NULL) {
3676 // Free all task_teams on the free list
3677 __kmp_acquire_bootstrap_lock(&__kmp_task_team_lock);
3678 while ((task_team = __kmp_free_task_teams) != NULL) {
3679 __kmp_free_task_teams = task_team->tt.tt_next;
3680 task_team->tt.tt_next = NULL;
3681
3682 // Free threads_data if necessary
3683 if (task_team->tt.tt_threads_data != NULL) {
3684 __kmp_free_task_threads_data(task_team);
3685 }
3686 if (task_team->tt.tt_task_pri_list != NULL) {
3687 __kmp_free_task_pri_list(task_team);
3688 }
3689 __kmp_free(task_team);
3690 }
3691 __kmp_release_bootstrap_lock(&__kmp_task_team_lock);
3692 }
3693}
3694
3695// View the array of two task team pointers as a pair of pointers:
3696// 1) a single task_team pointer
3697// 2) next pointer for stack
3698// Serial teams can create a stack of task teams for nested serial teams.
3699void __kmp_push_task_team_node(kmp_info_t *thread, kmp_team_t *team) {
3700 KMP_DEBUG_ASSERT(team->t.t_nproc == 1);
3701 kmp_task_team_list_t *current =
3702 (kmp_task_team_list_t *)(&team->t.t_task_team[0]);
3703 kmp_task_team_list_t *node =
3704 (kmp_task_team_list_t *)__kmp_allocate(sizeof(kmp_task_team_list_t));
3705 node->task_team = current->task_team;
3706 node->next = current->next;
3707 thread->th.th_task_team = current->task_team = NULL;
3708 current->next = node;
3709}
3710
3711// Serial team pops a task team off the stack
3712void __kmp_pop_task_team_node(kmp_info_t *thread, kmp_team_t *team) {
3713 KMP_DEBUG_ASSERT(team->t.t_nproc == 1);
3714 kmp_task_team_list_t *current =
3715 (kmp_task_team_list_t *)(&team->t.t_task_team[0]);
3716 if (current->task_team) {
3717 __kmp_free_task_team(thread, current->task_team);
3718 }
3719 kmp_task_team_list_t *next = current->next;
3720 if (next) {
3721 current->task_team = next->task_team;
3722 current->next = next->next;
3723 KMP_DEBUG_ASSERT(next != current);
3724 __kmp_free(next);
3725 thread->th.th_task_team = current->task_team;
3726 }
3727}
3728
3729// __kmp_wait_to_unref_task_teams:
3730// Some threads could still be in the fork barrier release code, possibly
3731// trying to steal tasks. Wait for each thread to unreference its task team.
3732void __kmp_wait_to_unref_task_teams(void) {
3733 kmp_info_t *thread;
3734 kmp_uint32 spins;
3735 kmp_uint64 time;
3736 int done;
3737
3738 KMP_INIT_YIELD(spins);
3739 KMP_INIT_BACKOFF(time);
3740
3741 for (;;) {
3742 done = TRUE;
3743
3744 // TODO: GEH - this may be is wrong because some sync would be necessary
3745 // in case threads are added to the pool during the traversal. Need to
3746 // verify that lock for thread pool is held when calling this routine.
3747 for (thread = CCAST(kmp_info_t *, __kmp_thread_pool); thread != NULL;
3748 thread = thread->th.th_next_pool) {
3749#if KMP_OS_WINDOWS
3750 DWORD exit_val;
3751#endif
3752 if (TCR_PTR(thread->th.th_task_team) == NULL) {
3753 KA_TRACE(10, ("__kmp_wait_to_unref_task_team: T#%d task_team == NULL\n",
3754 __kmp_gtid_from_thread(thread)));
3755 continue;
3756 }
3757#if KMP_OS_WINDOWS
3758 // TODO: GEH - add this check for Linux* OS / OS X* as well?
3759 if (!__kmp_is_thread_alive(thread, &exit_val)) {
3760 thread->th.th_task_team = NULL;
3761 continue;
3762 }
3763#endif
3764
3765 done = FALSE; // Because th_task_team pointer is not NULL for this thread
3766
3767 KA_TRACE(10, ("__kmp_wait_to_unref_task_team: Waiting for T#%d to "
3768 "unreference task_team\n",
3769 __kmp_gtid_from_thread(thread)));
3770
3771 if (__kmp_dflt_blocktime != KMP_MAX_BLOCKTIME) {
3772 void *sleep_loc;
3773 // If the thread is sleeping, awaken it.
3774 if ((sleep_loc = TCR_PTR(CCAST(void *, thread->th.th_sleep_loc))) !=
3775 NULL) {
3776 KA_TRACE(
3777 10,
3778 ("__kmp_wait_to_unref_task_team: T#%d waking up thread T#%d\n",
3779 __kmp_gtid_from_thread(thread), __kmp_gtid_from_thread(thread)));
3780 __kmp_null_resume_wrapper(thread);
3781 }
3782 }
3783 }
3784 if (done) {
3785 break;
3786 }
3787
3788 // If oversubscribed or have waited a bit, yield.
3789 KMP_YIELD_OVERSUB_ELSE_SPIN(spins, time);
3790 }
3791}
3792
3793// __kmp_task_team_setup: Create a task_team for the current team, but use
3794// an already created, unused one if it already exists.
3795void __kmp_task_team_setup(kmp_info_t *this_thr, kmp_team_t *team) {
3796 KMP_DEBUG_ASSERT(__kmp_tasking_mode != tskm_immediate_exec);
3797
3798 // For the serial and root teams, setup the first task team pointer to point
3799 // to task team. The other pointer is a stack of task teams from previous
3800 // serial levels.
3801 if (team == this_thr->th.th_serial_team ||
3802 team == this_thr->th.th_root->r.r_root_team) {
3803 KMP_DEBUG_ASSERT(team->t.t_nproc == 1);
3804 if (team->t.t_task_team[0] == NULL) {
3805 team->t.t_task_team[0] = __kmp_allocate_task_team(this_thr, team);
3806 KA_TRACE(
3807 20, ("__kmp_task_team_setup: Primary T#%d created new task_team %p"
3808 " for serial/root team %p\n",
3809 __kmp_gtid_from_thread(this_thr), team->t.t_task_team[0], team));
3810
3811 } else
3812 __kmp_task_team_init(team->t.t_task_team[0], team);
3813 return;
3814 }
3815
3816 // If this task_team hasn't been created yet, allocate it. It will be used in
3817 // the region after the next.
3818 // If it exists, it is the current task team and shouldn't be touched yet as
3819 // it may still be in use.
3820 if (team->t.t_task_team[this_thr->th.th_task_state] == NULL) {
3821 team->t.t_task_team[this_thr->th.th_task_state] =
3822 __kmp_allocate_task_team(this_thr, team);
3823 KA_TRACE(20, ("__kmp_task_team_setup: Primary T#%d created new task_team %p"
3824 " for team %d at parity=%d\n",
3825 __kmp_gtid_from_thread(this_thr),
3826 team->t.t_task_team[this_thr->th.th_task_state], team->t.t_id,
3827 this_thr->th.th_task_state));
3828 }
3829
3830 // After threads exit the release, they will call sync, and then point to this
3831 // other task_team; make sure it is allocated and properly initialized. As
3832 // threads spin in the barrier release phase, they will continue to use the
3833 // previous task_team struct(above), until they receive the signal to stop
3834 // checking for tasks (they can't safely reference the kmp_team_t struct,
3835 // which could be reallocated by the primary thread).
3836 int other_team = 1 - this_thr->th.th_task_state;
3837 KMP_DEBUG_ASSERT(other_team >= 0 && other_team < 2);
3838 if (team->t.t_task_team[other_team] == NULL) { // setup other team as well
3839 team->t.t_task_team[other_team] = __kmp_allocate_task_team(this_thr, team);
3840 KA_TRACE(20, ("__kmp_task_team_setup: Primary T#%d created second new "
3841 "task_team %p for team %d at parity=%d\n",
3842 __kmp_gtid_from_thread(this_thr),
3843 team->t.t_task_team[other_team], team->t.t_id, other_team));
3844 } else { // Leave the old task team struct in place for the upcoming region;
3845 // adjust as needed
3846 kmp_task_team_t *task_team = team->t.t_task_team[other_team];
3847 __kmp_task_team_init(task_team, team);
3848 // if team size has changed, the first thread to enable tasking will
3849 // realloc threads_data if necessary
3850 KA_TRACE(20, ("__kmp_task_team_setup: Primary T#%d reset next task_team "
3851 "%p for team %d at parity=%d\n",
3852 __kmp_gtid_from_thread(this_thr),
3853 team->t.t_task_team[other_team], team->t.t_id, other_team));
3854 }
3855
3856 // For regular thread, task enabling should be called when the task is going
3857 // to be pushed to a dequeue. However, for the hidden helper thread, we need
3858 // it ahead of time so that some operations can be performed without race
3859 // condition.
3860 if (this_thr == __kmp_hidden_helper_main_thread) {
3861 for (int i = 0; i < 2; ++i) {
3862 kmp_task_team_t *task_team = team->t.t_task_team[i];
3863 if (KMP_TASKING_ENABLED(task_team)) {
3864 continue;
3865 }
3866 __kmp_enable_tasking(task_team, this_thr);
3867 for (int j = 0; j < task_team->tt.tt_nproc; ++j) {
3868 kmp_thread_data_t *thread_data = &task_team->tt.tt_threads_data[j];
3869 if (thread_data->td.td_deque == NULL) {
3870 __kmp_alloc_task_deque(__kmp_hidden_helper_threads[j], thread_data);
3871 }
3872 }
3873 }
3874 }
3875}
3876
3877// __kmp_task_team_sync: Propagation of task team data from team to threads
3878// which happens just after the release phase of a team barrier. This may be
3879// called by any thread. This is not called for serial or root teams.
3880void __kmp_task_team_sync(kmp_info_t *this_thr, kmp_team_t *team) {
3881 KMP_DEBUG_ASSERT(__kmp_tasking_mode != tskm_immediate_exec);
3882 KMP_DEBUG_ASSERT(team != this_thr->th.th_serial_team);
3883 KMP_DEBUG_ASSERT(team != this_thr->th.th_root->r.r_root_team);
3884
3885 // Toggle the th_task_state field, to switch which task_team this thread
3886 // refers to
3887 this_thr->th.th_task_state = (kmp_uint8)(1 - this_thr->th.th_task_state);
3888
3889 // It is now safe to propagate the task team pointer from the team struct to
3890 // the current thread.
3891 TCW_PTR(this_thr->th.th_task_team,
3892 team->t.t_task_team[this_thr->th.th_task_state]);
3893 KA_TRACE(20,
3894 ("__kmp_task_team_sync: Thread T#%d task team switched to task_team "
3895 "%p from Team #%d (parity=%d)\n",
3896 __kmp_gtid_from_thread(this_thr), this_thr->th.th_task_team,
3897 team->t.t_id, this_thr->th.th_task_state));
3898}
3899
3900// __kmp_task_team_wait: Primary thread waits for outstanding tasks after the
3901// barrier gather phase. Only called by the primary thread.
3902//
3903// wait is a flag that defaults to 1 (see kmp.h), but waiting can be turned off
3904// by passing in 0 optionally as the last argument. When wait is zero, primary
3905// thread does not wait for unfinished_threads to reach 0.
3906void __kmp_task_team_wait(
3907 kmp_info_t *this_thr,
3908 kmp_team_t *team USE_ITT_BUILD_ARG(void *itt_sync_obj), int wait) {
3909 kmp_task_team_t *task_team = team->t.t_task_team[this_thr->th.th_task_state];
3910
3911 KMP_DEBUG_ASSERT(__kmp_tasking_mode != tskm_immediate_exec);
3912 KMP_DEBUG_ASSERT(task_team == this_thr->th.th_task_team);
3913
3914 if ((task_team != NULL) && KMP_TASKING_ENABLED(task_team)) {
3915 if (wait) {
3916 KA_TRACE(20, ("__kmp_task_team_wait: Primary T#%d waiting for all tasks "
3917 "(for unfinished_threads to reach 0) on task_team = %p\n",
3918 __kmp_gtid_from_thread(this_thr), task_team));
3919 // Worker threads may have dropped through to release phase, but could
3920 // still be executing tasks. Wait here for tasks to complete. To avoid
3921 // memory contention, only primary thread checks termination condition.
3922 kmp_flag_32<false, false> flag(
3923 RCAST(std::atomic<kmp_uint32> *,
3924 &task_team->tt.tt_unfinished_threads),
3925 0U);
3926 flag.wait(this_thr, TRUE USE_ITT_BUILD_ARG(itt_sync_obj));
3927 }
3928 // Deactivate the old task team, so that the worker threads will stop
3929 // referencing it while spinning.
3930 KA_TRACE(
3931 20,
3932 ("__kmp_task_team_wait: Primary T#%d deactivating task_team %p: "
3933 "setting active to false, setting local and team's pointer to NULL\n",
3934 __kmp_gtid_from_thread(this_thr), task_team));
3935 TCW_SYNC_4(task_team->tt.tt_found_proxy_tasks, FALSE);
3936 TCW_SYNC_4(task_team->tt.tt_hidden_helper_task_encountered, FALSE);
3937 KMP_CHECK_UPDATE(task_team->tt.tt_untied_task_encountered, 0);
3938 TCW_SYNC_4(task_team->tt.tt_active, FALSE);
3939 KMP_MB();
3940
3941 TCW_PTR(this_thr->th.th_task_team, NULL);
3942 }
3943}
3944
3945// __kmp_tasking_barrier:
3946// This routine is called only when __kmp_tasking_mode == tskm_extra_barrier.
3947// Internal function to execute all tasks prior to a regular barrier or a join
3948// barrier. It is a full barrier itself, which unfortunately turns regular
3949// barriers into double barriers and join barriers into 1 1/2 barriers.
3950void __kmp_tasking_barrier(kmp_team_t *team, kmp_info_t *thread, int gtid) {
3951 std::atomic<kmp_uint32> *spin = RCAST(
3952 std::atomic<kmp_uint32> *,
3953 &team->t.t_task_team[thread->th.th_task_state]->tt.tt_unfinished_threads);
3954 int flag = FALSE;
3955 KMP_DEBUG_ASSERT(__kmp_tasking_mode == tskm_extra_barrier);
3956
3957#if USE_ITT_BUILD
3958 KMP_FSYNC_SPIN_INIT(spin, NULL);
3959#endif /* USE_ITT_BUILD */
3960 kmp_flag_32<false, false> spin_flag(spin, 0U);
3961 while (!spin_flag.execute_tasks(thread, gtid, TRUE,
3962 &flag USE_ITT_BUILD_ARG(NULL), 0)) {
3963#if USE_ITT_BUILD
3964 // TODO: What about itt_sync_obj??
3965 KMP_FSYNC_SPIN_PREPARE(RCAST(void *, spin));
3966#endif /* USE_ITT_BUILD */
3967
3968 if (TCR_4(__kmp_global.g.g_done)) {
3969 if (__kmp_global.g.g_abort)
3970 __kmp_abort_thread();
3971 break;
3972 }
3973 KMP_YIELD(TRUE);
3974 }
3975#if USE_ITT_BUILD
3976 KMP_FSYNC_SPIN_ACQUIRED(RCAST(void *, spin));
3977#endif /* USE_ITT_BUILD */
3978}
3979
3980// __kmp_give_task puts a task into a given thread queue if:
3981// - the queue for that thread was created
3982// - there's space in that queue
3983// Because of this, __kmp_push_task needs to check if there's space after
3984// getting the lock
3985static bool __kmp_give_task(kmp_info_t *thread, kmp_int32 tid, kmp_task_t *task,
3986 kmp_int32 pass) {
3987 kmp_taskdata_t *taskdata = KMP_TASK_TO_TASKDATA(task);
3988 kmp_task_team_t *task_team = taskdata->td_task_team;
3989
3990 KA_TRACE(20, ("__kmp_give_task: trying to give task %p to thread %d.\n",
3991 taskdata, tid));
3992
3993 // If task_team is NULL something went really bad...
3994 KMP_DEBUG_ASSERT(task_team != NULL);
3995
3996 bool result = false;
3997 kmp_thread_data_t *thread_data = &task_team->tt.tt_threads_data[tid];
3998
3999 if (thread_data->td.td_deque == NULL) {
4000 // There's no queue in this thread, go find another one
4001 // We're guaranteed that at least one thread has a queue
4002 KA_TRACE(30,
4003 ("__kmp_give_task: thread %d has no queue while giving task %p.\n",
4004 tid, taskdata));
4005 return result;
4006 }
4007
4008 if (TCR_4(thread_data->td.td_deque_ntasks) >=
4009 TASK_DEQUE_SIZE(thread_data->td)) {
4010 KA_TRACE(
4011 30,
4012 ("__kmp_give_task: queue is full while giving task %p to thread %d.\n",
4013 taskdata, tid));
4014
4015 // if this deque is bigger than the pass ratio give a chance to another
4016 // thread
4017 if (TASK_DEQUE_SIZE(thread_data->td) / INITIAL_TASK_DEQUE_SIZE >= pass)
4018 return result;
4019
4020 __kmp_acquire_bootstrap_lock(&thread_data->td.td_deque_lock);
4021 if (TCR_4(thread_data->td.td_deque_ntasks) >=
4022 TASK_DEQUE_SIZE(thread_data->td)) {
4023 // expand deque to push the task which is not allowed to execute
4024 __kmp_realloc_task_deque(thread, thread_data);
4025 }
4026
4027 } else {
4028
4029 __kmp_acquire_bootstrap_lock(&thread_data->td.td_deque_lock);
4030
4031 if (TCR_4(thread_data->td.td_deque_ntasks) >=
4032 TASK_DEQUE_SIZE(thread_data->td)) {
4033 KA_TRACE(30, ("__kmp_give_task: queue is full while giving task %p to "
4034 "thread %d.\n",
4035 taskdata, tid));
4036
4037 // if this deque is bigger than the pass ratio give a chance to another
4038 // thread
4039 if (TASK_DEQUE_SIZE(thread_data->td) / INITIAL_TASK_DEQUE_SIZE >= pass)
4040 goto release_and_exit;
4041
4042 __kmp_realloc_task_deque(thread, thread_data);
4043 }
4044 }
4045
4046 // lock is held here, and there is space in the deque
4047
4048 thread_data->td.td_deque[thread_data->td.td_deque_tail] = taskdata;
4049 // Wrap index.
4050 thread_data->td.td_deque_tail =
4051 (thread_data->td.td_deque_tail + 1) & TASK_DEQUE_MASK(thread_data->td);
4052 TCW_4(thread_data->td.td_deque_ntasks,
4053 TCR_4(thread_data->td.td_deque_ntasks) + 1);
4054
4055 result = true;
4056 KA_TRACE(30, ("__kmp_give_task: successfully gave task %p to thread %d.\n",
4057 taskdata, tid));
4058
4059release_and_exit:
4060 __kmp_release_bootstrap_lock(&thread_data->td.td_deque_lock);
4061
4062 return result;
4063}
4064
4065#define PROXY_TASK_FLAG 0x40000000
4066/* The finish of the proxy tasks is divided in two pieces:
4067 - the top half is the one that can be done from a thread outside the team
4068 - the bottom half must be run from a thread within the team
4069
4070 In order to run the bottom half the task gets queued back into one of the
4071 threads of the team. Once the td_incomplete_child_task counter of the parent
4072 is decremented the threads can leave the barriers. So, the bottom half needs
4073 to be queued before the counter is decremented. The top half is therefore
4074 divided in two parts:
4075 - things that can be run before queuing the bottom half
4076 - things that must be run after queuing the bottom half
4077
4078 This creates a second race as the bottom half can free the task before the
4079 second top half is executed. To avoid this we use the
4080 td_incomplete_child_task of the proxy task to synchronize the top and bottom
4081 half. */
4082static void __kmp_first_top_half_finish_proxy(kmp_taskdata_t *taskdata) {
4083 KMP_DEBUG_ASSERT(taskdata->td_flags.tasktype == TASK_EXPLICIT);
4084 KMP_DEBUG_ASSERT(taskdata->td_flags.proxy == TASK_PROXY);
4085 KMP_DEBUG_ASSERT(taskdata->td_flags.complete == 0);
4086 KMP_DEBUG_ASSERT(taskdata->td_flags.freed == 0);
4087
4088 taskdata->td_flags.complete = 1; // mark the task as completed
4089
4090 if (taskdata->td_taskgroup)
4091 KMP_ATOMIC_DEC(&taskdata->td_taskgroup->count);
4092
4093 // Create an imaginary children for this task so the bottom half cannot
4094 // release the task before we have completed the second top half
4095 KMP_ATOMIC_OR(&taskdata->td_incomplete_child_tasks, PROXY_TASK_FLAG);
4096}
4097
4098static void __kmp_second_top_half_finish_proxy(kmp_taskdata_t *taskdata) {
4099#if KMP_DEBUG
4100 kmp_int32 children = 0;
4101 // Predecrement simulated by "- 1" calculation
4102 children = -1 +
4103#endif
4104 KMP_ATOMIC_DEC(&taskdata->td_parent->td_incomplete_child_tasks);
4105 KMP_DEBUG_ASSERT(children >= 0);
4106
4107 // Remove the imaginary children
4108 KMP_ATOMIC_AND(&taskdata->td_incomplete_child_tasks, ~PROXY_TASK_FLAG);
4109}
4110
4111static void __kmp_bottom_half_finish_proxy(kmp_int32 gtid, kmp_task_t *ptask) {
4112 kmp_taskdata_t *taskdata = KMP_TASK_TO_TASKDATA(ptask);
4113 kmp_info_t *thread = __kmp_threads[gtid];
4114
4115 KMP_DEBUG_ASSERT(taskdata->td_flags.proxy == TASK_PROXY);
4116 KMP_DEBUG_ASSERT(taskdata->td_flags.complete ==
4117 1); // top half must run before bottom half
4118
4119 // We need to wait to make sure the top half is finished
4120 // Spinning here should be ok as this should happen quickly
4121 while ((KMP_ATOMIC_LD_ACQ(&taskdata->td_incomplete_child_tasks) &
4122 PROXY_TASK_FLAG) > 0)
4123 ;
4124
4125 __kmp_release_deps(gtid, taskdata);
4126 __kmp_free_task_and_ancestors(gtid, taskdata, thread);
4127}
4128
4137void __kmpc_proxy_task_completed(kmp_int32 gtid, kmp_task_t *ptask) {
4138 KMP_DEBUG_ASSERT(ptask != NULL);
4139 kmp_taskdata_t *taskdata = KMP_TASK_TO_TASKDATA(ptask);
4140 KA_TRACE(
4141 10, ("__kmp_proxy_task_completed(enter): T#%d proxy task %p completing\n",
4142 gtid, taskdata));
4143 __kmp_assert_valid_gtid(gtid);
4144 KMP_DEBUG_ASSERT(taskdata->td_flags.proxy == TASK_PROXY);
4145
4146 __kmp_first_top_half_finish_proxy(taskdata);
4147 __kmp_second_top_half_finish_proxy(taskdata);
4148 __kmp_bottom_half_finish_proxy(gtid, ptask);
4149
4150 KA_TRACE(10,
4151 ("__kmp_proxy_task_completed(exit): T#%d proxy task %p completing\n",
4152 gtid, taskdata));
4153}
4154
4155void __kmpc_give_task(kmp_task_t *ptask, kmp_int32 start = 0) {
4156 KMP_DEBUG_ASSERT(ptask != NULL);
4157 kmp_taskdata_t *taskdata = KMP_TASK_TO_TASKDATA(ptask);
4158
4159 // Enqueue task to complete bottom half completion from a thread within the
4160 // corresponding team
4161 kmp_team_t *team = taskdata->td_team;
4162 kmp_int32 nthreads = team->t.t_nproc;
4163 kmp_info_t *thread;
4164
4165 // This should be similar to start_k = __kmp_get_random( thread ) % nthreads
4166 // but we cannot use __kmp_get_random here
4167 kmp_int32 start_k = start % nthreads;
4168 kmp_int32 pass = 1;
4169 kmp_int32 k = start_k;
4170
4171 do {
4172 // For now we're just linearly trying to find a thread
4173 thread = team->t.t_threads[k];
4174 k = (k + 1) % nthreads;
4175
4176 // we did a full pass through all the threads
4177 if (k == start_k)
4178 pass = pass << 1;
4179
4180 } while (!__kmp_give_task(thread, k, ptask, pass));
4181
4182 if (__kmp_dflt_blocktime != KMP_MAX_BLOCKTIME && __kmp_wpolicy_passive) {
4183 // awake at least one thread to execute given task
4184 for (int i = 0; i < nthreads; ++i) {
4185 thread = team->t.t_threads[i];
4186 if (thread->th.th_sleep_loc != NULL) {
4187 __kmp_null_resume_wrapper(thread);
4188 break;
4189 }
4190 }
4191 }
4192}
4193
4201void __kmpc_proxy_task_completed_ooo(kmp_task_t *ptask) {
4202 KMP_DEBUG_ASSERT(ptask != NULL);
4203 kmp_taskdata_t *taskdata = KMP_TASK_TO_TASKDATA(ptask);
4204
4205 KA_TRACE(
4206 10,
4207 ("__kmp_proxy_task_completed_ooo(enter): proxy task completing ooo %p\n",
4208 taskdata));
4209
4210 KMP_DEBUG_ASSERT(taskdata->td_flags.proxy == TASK_PROXY);
4211
4212 __kmp_first_top_half_finish_proxy(taskdata);
4213
4214 __kmpc_give_task(ptask);
4215
4216 __kmp_second_top_half_finish_proxy(taskdata);
4217
4218 KA_TRACE(
4219 10,
4220 ("__kmp_proxy_task_completed_ooo(exit): proxy task completing ooo %p\n",
4221 taskdata));
4222}
4223
4224kmp_event_t *__kmpc_task_allow_completion_event(ident_t *loc_ref, int gtid,
4225 kmp_task_t *task) {
4226 kmp_taskdata_t *td = KMP_TASK_TO_TASKDATA(task);
4227 if (td->td_allow_completion_event.type == KMP_EVENT_UNINITIALIZED) {
4228 td->td_allow_completion_event.type = KMP_EVENT_ALLOW_COMPLETION;
4229 td->td_allow_completion_event.ed.task = task;
4230 __kmp_init_tas_lock(&td->td_allow_completion_event.lock);
4231 }
4232 return &td->td_allow_completion_event;
4233}
4234
4235void __kmp_fulfill_event(kmp_event_t *event) {
4236 if (event->type == KMP_EVENT_ALLOW_COMPLETION) {
4237 kmp_task_t *ptask = event->ed.task;
4238 kmp_taskdata_t *taskdata = KMP_TASK_TO_TASKDATA(ptask);
4239 bool detached = false;
4240 int gtid = __kmp_get_gtid();
4241
4242 // The associated task might have completed or could be completing at this
4243 // point.
4244 // We need to take the lock to avoid races
4245 __kmp_acquire_tas_lock(&event->lock, gtid);
4246 if (taskdata->td_flags.proxy == TASK_PROXY) {
4247 detached = true;
4248 } else {
4249#if OMPT_SUPPORT
4250 // The OMPT event must occur under mutual exclusion,
4251 // otherwise the tool might access ptask after free
4252 if (UNLIKELY(ompt_enabled.enabled))
4253 __ompt_task_finish(ptask, NULL, ompt_task_early_fulfill);
4254#endif
4255 }
4256 event->type = KMP_EVENT_UNINITIALIZED;
4257 __kmp_release_tas_lock(&event->lock, gtid);
4258
4259 if (detached) {
4260#if OMPT_SUPPORT
4261 // We free ptask afterwards and know the task is finished,
4262 // so locking is not necessary
4263 if (UNLIKELY(ompt_enabled.enabled))
4264 __ompt_task_finish(ptask, NULL, ompt_task_late_fulfill);
4265#endif
4266 // If the task detached complete the proxy task
4267 if (gtid >= 0) {
4268 kmp_team_t *team = taskdata->td_team;
4269 kmp_info_t *thread = __kmp_get_thread();
4270 if (thread->th.th_team == team) {
4271 __kmpc_proxy_task_completed(gtid, ptask);
4272 return;
4273 }
4274 }
4275
4276 // fallback
4278 }
4279 }
4280}
4281
4282// __kmp_task_dup_alloc: Allocate the taskdata and make a copy of source task
4283// for taskloop
4284//
4285// thread: allocating thread
4286// task_src: pointer to source task to be duplicated
4287// taskloop_recur: used only when dealing with taskgraph,
4288// indicating whether we need to update task->td_task_id
4289// returns: a pointer to the allocated kmp_task_t structure (task).
4290kmp_task_t *__kmp_task_dup_alloc(kmp_info_t *thread, kmp_task_t *task_src) {
4291 kmp_task_t *task;
4292 kmp_taskdata_t *taskdata;
4293 kmp_taskdata_t *taskdata_src = KMP_TASK_TO_TASKDATA(task_src);
4294 kmp_taskdata_t *parent_task = taskdata_src->td_parent; // same parent task
4295 size_t shareds_offset;
4296 size_t task_size;
4297
4298 KA_TRACE(10, ("__kmp_task_dup_alloc(enter): Th %p, source task %p\n", thread,
4299 task_src));
4300 KMP_DEBUG_ASSERT(taskdata_src->td_flags.proxy ==
4301 TASK_FULL); // it should not be proxy task
4302 KMP_DEBUG_ASSERT(taskdata_src->td_flags.tasktype == TASK_EXPLICIT);
4303 task_size = taskdata_src->td_size_alloc;
4304
4305 // Allocate a kmp_taskdata_t block and a kmp_task_t block.
4306 KA_TRACE(30, ("__kmp_task_dup_alloc: Th %p, malloc size %ld\n", thread,
4307 task_size));
4308#if USE_FAST_MEMORY
4309 taskdata = (kmp_taskdata_t *)__kmp_fast_allocate(thread, task_size);
4310#else
4311 taskdata = (kmp_taskdata_t *)__kmp_thread_malloc(thread, task_size);
4312#endif /* USE_FAST_MEMORY */
4313 KMP_MEMCPY(taskdata, taskdata_src, task_size);
4314
4315 task = KMP_TASKDATA_TO_TASK(taskdata);
4316
4317 // Initialize new task (only specific fields not affected by memcpy)
4318 taskdata->td_task_id = KMP_GEN_TASK_ID();
4319 if (task->shareds != NULL) { // need setup shareds pointer
4320 shareds_offset = (char *)task_src->shareds - (char *)taskdata_src;
4321 task->shareds = &((char *)taskdata)[shareds_offset];
4322 KMP_DEBUG_ASSERT((((kmp_uintptr_t)task->shareds) & (sizeof(void *) - 1)) ==
4323 0);
4324 }
4325 taskdata->td_alloc_thread = thread;
4326 taskdata->td_parent = parent_task;
4327 // task inherits the taskgroup from the parent task
4328 taskdata->td_taskgroup = parent_task->td_taskgroup;
4329 // tied task needs to initialize the td_last_tied at creation,
4330 // untied one does this when it is scheduled for execution
4331 if (taskdata->td_flags.tiedness == TASK_TIED)
4332 taskdata->td_last_tied = taskdata;
4333
4334 // Only need to keep track of child task counts if team parallel and tasking
4335 // not serialized
4336 if (!(taskdata->td_flags.team_serial || taskdata->td_flags.tasking_ser)) {
4337 KMP_ATOMIC_INC(&parent_task->td_incomplete_child_tasks);
4338 if (parent_task->td_taskgroup)
4339 KMP_ATOMIC_INC(&parent_task->td_taskgroup->count);
4340 // Only need to keep track of allocated child tasks for explicit tasks since
4341 // implicit not deallocated
4342 if (taskdata->td_parent->td_flags.tasktype == TASK_EXPLICIT)
4343 KMP_ATOMIC_INC(&taskdata->td_parent->td_allocated_child_tasks);
4344 }
4345
4346 KA_TRACE(20,
4347 ("__kmp_task_dup_alloc(exit): Th %p, created task %p, parent=%p\n",
4348 thread, taskdata, taskdata->td_parent));
4349#if OMPT_SUPPORT
4350 if (UNLIKELY(ompt_enabled.enabled))
4351 __ompt_task_init(taskdata, thread->th.th_info.ds.ds_gtid);
4352#endif
4353 return task;
4354}
4355
4356// Routine optionally generated by the compiler for setting the lastprivate flag
4357// and calling needed constructors for private/firstprivate objects
4358// (used to form taskloop tasks from pattern task)
4359// Parameters: dest task, src task, lastprivate flag.
4360typedef void (*p_task_dup_t)(kmp_task_t *, kmp_task_t *, kmp_int32);
4361
4362KMP_BUILD_ASSERT(sizeof(long) == 4 || sizeof(long) == 8);
4363
4364// class to encapsulate manipulating loop bounds in a taskloop task.
4365// this abstracts away the Intel vs GOMP taskloop interface for setting/getting
4366// the loop bound variables.
4367class kmp_taskloop_bounds_t {
4368 kmp_task_t *task;
4369 const kmp_taskdata_t *taskdata;
4370 size_t lower_offset;
4371 size_t upper_offset;
4372
4373public:
4374 kmp_taskloop_bounds_t(kmp_task_t *_task, kmp_uint64 *lb, kmp_uint64 *ub)
4375 : task(_task), taskdata(KMP_TASK_TO_TASKDATA(task)),
4376 lower_offset((char *)lb - (char *)task),
4377 upper_offset((char *)ub - (char *)task) {
4378 KMP_DEBUG_ASSERT((char *)lb > (char *)_task);
4379 KMP_DEBUG_ASSERT((char *)ub > (char *)_task);
4380 }
4381 kmp_taskloop_bounds_t(kmp_task_t *_task, const kmp_taskloop_bounds_t &bounds)
4382 : task(_task), taskdata(KMP_TASK_TO_TASKDATA(_task)),
4383 lower_offset(bounds.lower_offset), upper_offset(bounds.upper_offset) {}
4384 size_t get_lower_offset() const { return lower_offset; }
4385 size_t get_upper_offset() const { return upper_offset; }
4386 kmp_uint64 get_lb() const {
4387 kmp_int64 retval;
4388#if defined(KMP_GOMP_COMPAT)
4389 // Intel task just returns the lower bound normally
4390 if (!taskdata->td_flags.native) {
4391 retval = *(kmp_int64 *)((char *)task + lower_offset);
4392 } else {
4393 // GOMP task has to take into account the sizeof(long)
4394 if (taskdata->td_size_loop_bounds == 4) {
4395 kmp_int32 *lb = RCAST(kmp_int32 *, task->shareds);
4396 retval = (kmp_int64)*lb;
4397 } else {
4398 kmp_int64 *lb = RCAST(kmp_int64 *, task->shareds);
4399 retval = (kmp_int64)*lb;
4400 }
4401 }
4402#else
4403 (void)taskdata;
4404 retval = *(kmp_int64 *)((char *)task + lower_offset);
4405#endif // defined(KMP_GOMP_COMPAT)
4406 return retval;
4407 }
4408 kmp_uint64 get_ub() const {
4409 kmp_int64 retval;
4410#if defined(KMP_GOMP_COMPAT)
4411 // Intel task just returns the upper bound normally
4412 if (!taskdata->td_flags.native) {
4413 retval = *(kmp_int64 *)((char *)task + upper_offset);
4414 } else {
4415 // GOMP task has to take into account the sizeof(long)
4416 if (taskdata->td_size_loop_bounds == 4) {
4417 kmp_int32 *ub = RCAST(kmp_int32 *, task->shareds) + 1;
4418 retval = (kmp_int64)*ub;
4419 } else {
4420 kmp_int64 *ub = RCAST(kmp_int64 *, task->shareds) + 1;
4421 retval = (kmp_int64)*ub;
4422 }
4423 }
4424#else
4425 retval = *(kmp_int64 *)((char *)task + upper_offset);
4426#endif // defined(KMP_GOMP_COMPAT)
4427 return retval;
4428 }
4429 void set_lb(kmp_uint64 lb) {
4430#if defined(KMP_GOMP_COMPAT)
4431 // Intel task just sets the lower bound normally
4432 if (!taskdata->td_flags.native) {
4433 *(kmp_uint64 *)((char *)task + lower_offset) = lb;
4434 } else {
4435 // GOMP task has to take into account the sizeof(long)
4436 if (taskdata->td_size_loop_bounds == 4) {
4437 kmp_uint32 *lower = RCAST(kmp_uint32 *, task->shareds);
4438 *lower = (kmp_uint32)lb;
4439 } else {
4440 kmp_uint64 *lower = RCAST(kmp_uint64 *, task->shareds);
4441 *lower = (kmp_uint64)lb;
4442 }
4443 }
4444#else
4445 *(kmp_uint64 *)((char *)task + lower_offset) = lb;
4446#endif // defined(KMP_GOMP_COMPAT)
4447 }
4448 void set_ub(kmp_uint64 ub) {
4449#if defined(KMP_GOMP_COMPAT)
4450 // Intel task just sets the upper bound normally
4451 if (!taskdata->td_flags.native) {
4452 *(kmp_uint64 *)((char *)task + upper_offset) = ub;
4453 } else {
4454 // GOMP task has to take into account the sizeof(long)
4455 if (taskdata->td_size_loop_bounds == 4) {
4456 kmp_uint32 *upper = RCAST(kmp_uint32 *, task->shareds) + 1;
4457 *upper = (kmp_uint32)ub;
4458 } else {
4459 kmp_uint64 *upper = RCAST(kmp_uint64 *, task->shareds) + 1;
4460 *upper = (kmp_uint64)ub;
4461 }
4462 }
4463#else
4464 *(kmp_uint64 *)((char *)task + upper_offset) = ub;
4465#endif // defined(KMP_GOMP_COMPAT)
4466 }
4467};
4468
4469// __kmp_taskloop_linear: Start tasks of the taskloop linearly
4470//
4471// loc Source location information
4472// gtid Global thread ID
4473// task Pattern task, exposes the loop iteration range
4474// lb Pointer to loop lower bound in task structure
4475// ub Pointer to loop upper bound in task structure
4476// st Loop stride
4477// ub_glob Global upper bound (used for lastprivate check)
4478// num_tasks Number of tasks to execute
4479// grainsize Number of loop iterations per task
4480// extras Number of chunks with grainsize+1 iterations
4481// last_chunk Reduction of grainsize for last task
4482// tc Iterations count
4483// task_dup Tasks duplication routine
4484// codeptr_ra Return address for OMPT events
4485void __kmp_taskloop_linear(ident_t *loc, int gtid, kmp_task_t *task,
4486 kmp_uint64 *lb, kmp_uint64 *ub, kmp_int64 st,
4487 kmp_uint64 ub_glob, kmp_uint64 num_tasks,
4488 kmp_uint64 grainsize, kmp_uint64 extras,
4489 kmp_int64 last_chunk, kmp_uint64 tc,
4490#if OMPT_SUPPORT
4491 void *codeptr_ra,
4492#endif
4493 void *task_dup) {
4494 KMP_COUNT_BLOCK(OMP_TASKLOOP);
4495 KMP_TIME_PARTITIONED_BLOCK(OMP_taskloop_scheduling);
4496 p_task_dup_t ptask_dup = (p_task_dup_t)task_dup;
4497 // compiler provides global bounds here
4498 kmp_taskloop_bounds_t task_bounds(task, lb, ub);
4499 kmp_uint64 lower = task_bounds.get_lb();
4500 kmp_uint64 upper = task_bounds.get_ub();
4501 kmp_uint64 i;
4502 kmp_info_t *thread = __kmp_threads[gtid];
4503 kmp_taskdata_t *current_task = thread->th.th_current_task;
4504 kmp_task_t *next_task;
4505 kmp_int32 lastpriv = 0;
4506
4507 KMP_DEBUG_ASSERT(tc == num_tasks * grainsize +
4508 (last_chunk < 0 ? last_chunk : extras));
4509 KMP_DEBUG_ASSERT(num_tasks > extras);
4510 KMP_DEBUG_ASSERT(num_tasks > 0);
4511 KA_TRACE(20, ("__kmp_taskloop_linear: T#%d: %lld tasks, grainsize %lld, "
4512 "extras %lld, last_chunk %lld, i=%lld,%lld(%d)%lld, dup %p\n",
4513 gtid, num_tasks, grainsize, extras, last_chunk, lower, upper,
4514 ub_glob, st, task_dup));
4515
4516 // Launch num_tasks tasks, assign grainsize iterations each task
4517 for (i = 0; i < num_tasks; ++i) {
4518 kmp_uint64 chunk_minus_1;
4519 if (extras == 0) {
4520 chunk_minus_1 = grainsize - 1;
4521 } else {
4522 chunk_minus_1 = grainsize;
4523 --extras; // first extras iterations get bigger chunk (grainsize+1)
4524 }
4525 upper = lower + st * chunk_minus_1;
4526 if (upper > *ub) {
4527 upper = *ub;
4528 }
4529 if (i == num_tasks - 1) {
4530 // schedule the last task, set lastprivate flag if needed
4531 if (st == 1) { // most common case
4532 KMP_DEBUG_ASSERT(upper == *ub);
4533 if (upper == ub_glob)
4534 lastpriv = 1;
4535 } else if (st > 0) { // positive loop stride
4536 KMP_DEBUG_ASSERT((kmp_uint64)st > *ub - upper);
4537 if ((kmp_uint64)st > ub_glob - upper)
4538 lastpriv = 1;
4539 } else { // negative loop stride
4540 KMP_DEBUG_ASSERT(upper + st < *ub);
4541 if (upper - ub_glob < (kmp_uint64)(-st))
4542 lastpriv = 1;
4543 }
4544 }
4545
4546 next_task = __kmp_task_dup_alloc(thread, task); // allocate new task
4547
4548 kmp_taskdata_t *next_taskdata = KMP_TASK_TO_TASKDATA(next_task);
4549 kmp_taskloop_bounds_t next_task_bounds =
4550 kmp_taskloop_bounds_t(next_task, task_bounds);
4551
4552 // adjust task-specific bounds
4553 next_task_bounds.set_lb(lower);
4554 if (next_taskdata->td_flags.native) {
4555 next_task_bounds.set_ub(upper + (st > 0 ? 1 : -1));
4556 } else {
4557 next_task_bounds.set_ub(upper);
4558 }
4559 if (ptask_dup != NULL) // set lastprivate flag, construct firstprivates,
4560 // etc.
4561 ptask_dup(next_task, task, lastpriv);
4562 KA_TRACE(40,
4563 ("__kmp_taskloop_linear: T#%d; task #%llu: task %p: lower %lld, "
4564 "upper %lld stride %lld, (offsets %p %p)\n",
4565 gtid, i, next_task, lower, upper, st,
4566 next_task_bounds.get_lower_offset(),
4567 next_task_bounds.get_upper_offset()));
4568#if OMPT_SUPPORT
4569 __kmp_omp_taskloop_task(NULL, gtid, next_task,
4570 codeptr_ra); // schedule new task
4571#if OMPT_OPTIONAL
4572 if (ompt_enabled.ompt_callback_dispatch) {
4573 OMPT_GET_DISPATCH_CHUNK(next_taskdata->ompt_task_info.dispatch_chunk,
4574 lower, upper, st);
4575 }
4576#endif // OMPT_OPTIONAL
4577#else
4578 __kmp_omp_task(gtid, next_task, true); // schedule new task
4579#endif
4580 lower = upper + st; // adjust lower bound for the next iteration
4581 }
4582 // free the pattern task and exit
4583 __kmp_task_start(gtid, task, current_task); // make internal bookkeeping
4584 // do not execute the pattern task, just do internal bookkeeping
4585 __kmp_task_finish<false>(gtid, task, current_task);
4586}
4587
4588// Structure to keep taskloop parameters for auxiliary task
4589// kept in the shareds of the task structure.
4590typedef struct __taskloop_params {
4591 kmp_task_t *task;
4592 kmp_uint64 *lb;
4593 kmp_uint64 *ub;
4594 void *task_dup;
4595 kmp_int64 st;
4596 kmp_uint64 ub_glob;
4597 kmp_uint64 num_tasks;
4598 kmp_uint64 grainsize;
4599 kmp_uint64 extras;
4600 kmp_int64 last_chunk;
4601 kmp_uint64 tc;
4602 kmp_uint64 num_t_min;
4603#if OMPT_SUPPORT
4604 void *codeptr_ra;
4605#endif
4606} __taskloop_params_t;
4607
4608void __kmp_taskloop_recur(ident_t *, int, kmp_task_t *, kmp_uint64 *,
4609 kmp_uint64 *, kmp_int64, kmp_uint64, kmp_uint64,
4610 kmp_uint64, kmp_uint64, kmp_int64, kmp_uint64,
4611 kmp_uint64,
4612#if OMPT_SUPPORT
4613 void *,
4614#endif
4615 void *);
4616
4617// Execute part of the taskloop submitted as a task.
4618int __kmp_taskloop_task(int gtid, void *ptask) {
4619 __taskloop_params_t *p =
4620 (__taskloop_params_t *)((kmp_task_t *)ptask)->shareds;
4621 kmp_task_t *task = p->task;
4622 kmp_uint64 *lb = p->lb;
4623 kmp_uint64 *ub = p->ub;
4624 void *task_dup = p->task_dup;
4625 // p_task_dup_t ptask_dup = (p_task_dup_t)task_dup;
4626 kmp_int64 st = p->st;
4627 kmp_uint64 ub_glob = p->ub_glob;
4628 kmp_uint64 num_tasks = p->num_tasks;
4629 kmp_uint64 grainsize = p->grainsize;
4630 kmp_uint64 extras = p->extras;
4631 kmp_int64 last_chunk = p->last_chunk;
4632 kmp_uint64 tc = p->tc;
4633 kmp_uint64 num_t_min = p->num_t_min;
4634#if OMPT_SUPPORT
4635 void *codeptr_ra = p->codeptr_ra;
4636#endif
4637#if KMP_DEBUG
4638 kmp_taskdata_t *taskdata = KMP_TASK_TO_TASKDATA(task);
4639 KMP_DEBUG_ASSERT(task != NULL);
4640 KA_TRACE(20,
4641 ("__kmp_taskloop_task: T#%d, task %p: %lld tasks, grainsize"
4642 " %lld, extras %lld, last_chunk %lld, i=%lld,%lld(%d), dup %p\n",
4643 gtid, taskdata, num_tasks, grainsize, extras, last_chunk, *lb, *ub,
4644 st, task_dup));
4645#endif
4646 KMP_DEBUG_ASSERT(num_tasks * 2 + 1 > num_t_min);
4647 if (num_tasks > num_t_min)
4648 __kmp_taskloop_recur(NULL, gtid, task, lb, ub, st, ub_glob, num_tasks,
4649 grainsize, extras, last_chunk, tc, num_t_min,
4650#if OMPT_SUPPORT
4651 codeptr_ra,
4652#endif
4653 task_dup);
4654 else
4655 __kmp_taskloop_linear(NULL, gtid, task, lb, ub, st, ub_glob, num_tasks,
4656 grainsize, extras, last_chunk, tc,
4657#if OMPT_SUPPORT
4658 codeptr_ra,
4659#endif
4660 task_dup);
4661
4662 KA_TRACE(40, ("__kmp_taskloop_task(exit): T#%d\n", gtid));
4663 return 0;
4664}
4665
4666// Schedule part of the taskloop as a task,
4667// execute the rest of the taskloop.
4668//
4669// loc Source location information
4670// gtid Global thread ID
4671// task Pattern task, exposes the loop iteration range
4672// lb Pointer to loop lower bound in task structure
4673// ub Pointer to loop upper bound in task structure
4674// st Loop stride
4675// ub_glob Global upper bound (used for lastprivate check)
4676// num_tasks Number of tasks to execute
4677// grainsize Number of loop iterations per task
4678// extras Number of chunks with grainsize+1 iterations
4679// last_chunk Reduction of grainsize for last task
4680// tc Iterations count
4681// num_t_min Threshold to launch tasks recursively
4682// task_dup Tasks duplication routine
4683// codeptr_ra Return address for OMPT events
4684void __kmp_taskloop_recur(ident_t *loc, int gtid, kmp_task_t *task,
4685 kmp_uint64 *lb, kmp_uint64 *ub, kmp_int64 st,
4686 kmp_uint64 ub_glob, kmp_uint64 num_tasks,
4687 kmp_uint64 grainsize, kmp_uint64 extras,
4688 kmp_int64 last_chunk, kmp_uint64 tc,
4689 kmp_uint64 num_t_min,
4690#if OMPT_SUPPORT
4691 void *codeptr_ra,
4692#endif
4693 void *task_dup) {
4694 kmp_taskdata_t *taskdata = KMP_TASK_TO_TASKDATA(task);
4695 KMP_DEBUG_ASSERT(task != NULL);
4696 KMP_DEBUG_ASSERT(num_tasks > num_t_min);
4697 KA_TRACE(20,
4698 ("__kmp_taskloop_recur: T#%d, task %p: %lld tasks, grainsize"
4699 " %lld, extras %lld, last_chunk %lld, i=%lld,%lld(%d), dup %p\n",
4700 gtid, taskdata, num_tasks, grainsize, extras, last_chunk, *lb, *ub,
4701 st, task_dup));
4702 p_task_dup_t ptask_dup = (p_task_dup_t)task_dup;
4703 kmp_uint64 lower = *lb;
4704 kmp_info_t *thread = __kmp_threads[gtid];
4705 // kmp_taskdata_t *current_task = thread->th.th_current_task;
4706 kmp_task_t *next_task;
4707 size_t lower_offset =
4708 (char *)lb - (char *)task; // remember offset of lb in the task structure
4709 size_t upper_offset =
4710 (char *)ub - (char *)task; // remember offset of ub in the task structure
4711
4712 KMP_DEBUG_ASSERT(tc == num_tasks * grainsize +
4713 (last_chunk < 0 ? last_chunk : extras));
4714 KMP_DEBUG_ASSERT(num_tasks > extras);
4715 KMP_DEBUG_ASSERT(num_tasks > 0);
4716
4717 // split the loop in two halves
4718 kmp_uint64 lb1, ub0, tc0, tc1, ext0, ext1;
4719 kmp_int64 last_chunk0 = 0, last_chunk1 = 0;
4720 kmp_uint64 gr_size0 = grainsize;
4721 kmp_uint64 n_tsk0 = num_tasks >> 1; // num_tasks/2 to execute
4722 kmp_uint64 n_tsk1 = num_tasks - n_tsk0; // to schedule as a task
4723 if (last_chunk < 0) {
4724 ext0 = ext1 = 0;
4725 last_chunk1 = last_chunk;
4726 tc0 = grainsize * n_tsk0;
4727 tc1 = tc - tc0;
4728 } else if (n_tsk0 <= extras) {
4729 gr_size0++; // integrate extras into grainsize
4730 ext0 = 0; // no extra iters in 1st half
4731 ext1 = extras - n_tsk0; // remaining extras
4732 tc0 = gr_size0 * n_tsk0;
4733 tc1 = tc - tc0;
4734 } else { // n_tsk0 > extras
4735 ext1 = 0; // no extra iters in 2nd half
4736 ext0 = extras;
4737 tc1 = grainsize * n_tsk1;
4738 tc0 = tc - tc1;
4739 }
4740 ub0 = lower + st * (tc0 - 1);
4741 lb1 = ub0 + st;
4742
4743 // create pattern task for 2nd half of the loop
4744 next_task = __kmp_task_dup_alloc(thread, task); // duplicate the task
4745 // adjust lower bound (upper bound is not changed) for the 2nd half
4746 *(kmp_uint64 *)((char *)next_task + lower_offset) = lb1;
4747 if (ptask_dup != NULL) // construct firstprivates, etc.
4748 ptask_dup(next_task, task, 0);
4749 *ub = ub0; // adjust upper bound for the 1st half
4750
4751 // create auxiliary task for 2nd half of the loop
4752 // make sure new task has same parent task as the pattern task
4753 kmp_taskdata_t *current_task = thread->th.th_current_task;
4754 thread->th.th_current_task = taskdata->td_parent;
4755 kmp_task_t *new_task =
4756 __kmpc_omp_task_alloc(loc, gtid, 1, 3 * sizeof(void *),
4757 sizeof(__taskloop_params_t), &__kmp_taskloop_task);
4758 // restore current task
4759 thread->th.th_current_task = current_task;
4760 __taskloop_params_t *p = (__taskloop_params_t *)new_task->shareds;
4761 p->task = next_task;
4762 p->lb = (kmp_uint64 *)((char *)next_task + lower_offset);
4763 p->ub = (kmp_uint64 *)((char *)next_task + upper_offset);
4764 p->task_dup = task_dup;
4765 p->st = st;
4766 p->ub_glob = ub_glob;
4767 p->num_tasks = n_tsk1;
4768 p->grainsize = grainsize;
4769 p->extras = ext1;
4770 p->last_chunk = last_chunk1;
4771 p->tc = tc1;
4772 p->num_t_min = num_t_min;
4773#if OMPT_SUPPORT
4774 p->codeptr_ra = codeptr_ra;
4775#endif
4776
4777#if OMPT_SUPPORT
4778 // schedule new task with correct return address for OMPT events
4779 __kmp_omp_taskloop_task(NULL, gtid, new_task, codeptr_ra);
4780#else
4781 __kmp_omp_task(gtid, new_task, true); // schedule new task
4782#endif
4783
4784 // execute the 1st half of current subrange
4785 if (n_tsk0 > num_t_min)
4786 __kmp_taskloop_recur(loc, gtid, task, lb, ub, st, ub_glob, n_tsk0, gr_size0,
4787 ext0, last_chunk0, tc0, num_t_min,
4788#if OMPT_SUPPORT
4789 codeptr_ra,
4790#endif
4791 task_dup);
4792 else
4793 __kmp_taskloop_linear(loc, gtid, task, lb, ub, st, ub_glob, n_tsk0,
4794 gr_size0, ext0, last_chunk0, tc0,
4795#if OMPT_SUPPORT
4796 codeptr_ra,
4797#endif
4798 task_dup);
4799
4800 KA_TRACE(40, ("__kmp_taskloop_recur(exit): T#%d\n", gtid));
4801}
4802
4803static void __kmp_taskloop(ident_t *loc, int gtid, kmp_task_t *task, int if_val,
4804 kmp_uint64 *lb, kmp_uint64 *ub, kmp_int64 st,
4805 int nogroup, int sched, kmp_uint64 grainsize,
4806 int modifier, void *task_dup) {
4807 kmp_taskdata_t *taskdata = KMP_TASK_TO_TASKDATA(task);
4808 KMP_DEBUG_ASSERT(task != NULL);
4809 if (nogroup == 0) {
4810#if OMPT_SUPPORT && OMPT_OPTIONAL
4811 OMPT_STORE_RETURN_ADDRESS(gtid);
4812#endif
4813 __kmpc_taskgroup(loc, gtid);
4814 }
4815 // =========================================================================
4816 // calculate loop parameters
4817 kmp_taskloop_bounds_t task_bounds(task, lb, ub);
4818 kmp_uint64 tc;
4819 // compiler provides global bounds here
4820 kmp_uint64 lower = task_bounds.get_lb();
4821 kmp_uint64 upper = task_bounds.get_ub();
4822 kmp_uint64 ub_glob = upper; // global upper used to calc lastprivate flag
4823 kmp_uint64 num_tasks = 0, extras = 0;
4824 kmp_int64 last_chunk =
4825 0; // reduce grainsize of last task by last_chunk in strict mode
4826 kmp_uint64 num_tasks_min = __kmp_taskloop_min_tasks;
4827 kmp_info_t *thread = __kmp_threads[gtid];
4828 kmp_taskdata_t *current_task = thread->th.th_current_task;
4829
4830 KA_TRACE(20, ("__kmp_taskloop: T#%d, task %p, lb %lld, ub %lld, st %lld, "
4831 "grain %llu(%d, %d), dup %p\n",
4832 gtid, taskdata, lower, upper, st, grainsize, sched, modifier,
4833 task_dup));
4834
4835 // compute trip count
4836 if (st == 1) { // most common case
4837 tc = upper - lower + 1;
4838 } else if (st < 0) {
4839 tc = (lower - upper) / (-st) + 1;
4840 } else { // st > 0
4841 tc = (upper - lower) / st + 1;
4842 }
4843 if (tc == 0) {
4844 KA_TRACE(20, ("__kmp_taskloop(exit): T#%d zero-trip loop\n", gtid));
4845 // free the pattern task and exit
4846 __kmp_task_start(gtid, task, current_task);
4847 // do not execute anything for zero-trip loop
4848 __kmp_task_finish<false>(gtid, task, current_task);
4849 return;
4850 }
4851
4852#if OMPT_SUPPORT && OMPT_OPTIONAL
4853 ompt_team_info_t *team_info = __ompt_get_teaminfo(0, NULL);
4854 ompt_task_info_t *task_info = __ompt_get_task_info_object(0);
4855 if (ompt_enabled.ompt_callback_work) {
4856 ompt_callbacks.ompt_callback(ompt_callback_work)(
4857 ompt_work_taskloop, ompt_scope_begin, &(team_info->parallel_data),
4858 &(task_info->task_data), tc, OMPT_GET_RETURN_ADDRESS(0));
4859 }
4860#endif
4861
4862 if (num_tasks_min == 0)
4863 // TODO: can we choose better default heuristic?
4864 num_tasks_min =
4865 KMP_MIN(thread->th.th_team_nproc * 10, INITIAL_TASK_DEQUE_SIZE);
4866
4867 // compute num_tasks/grainsize based on the input provided
4868 switch (sched) {
4869 case 0: // no schedule clause specified, we can choose the default
4870 // let's try to schedule (team_size*10) tasks
4871 grainsize = thread->th.th_team_nproc * static_cast<kmp_uint64>(10);
4872 KMP_FALLTHROUGH();
4873 case 2: // num_tasks provided
4874 if (grainsize > tc) {
4875 num_tasks = tc; // too big num_tasks requested, adjust values
4876 grainsize = 1;
4877 extras = 0;
4878 } else {
4879 num_tasks = grainsize;
4880 grainsize = tc / num_tasks;
4881 extras = tc % num_tasks;
4882 }
4883 break;
4884 case 1: // grainsize provided
4885 if (grainsize > tc) {
4886 num_tasks = 1;
4887 grainsize = tc; // too big grainsize requested, adjust values
4888 extras = 0;
4889 } else {
4890 if (modifier) {
4891 num_tasks = (tc + grainsize - 1) / grainsize;
4892 last_chunk = tc - (num_tasks * grainsize);
4893 extras = 0;
4894 } else {
4895 num_tasks = tc / grainsize;
4896 // adjust grainsize for balanced distribution of iterations
4897 grainsize = tc / num_tasks;
4898 extras = tc % num_tasks;
4899 }
4900 }
4901 break;
4902 default:
4903 KMP_ASSERT2(0, "unknown scheduling of taskloop");
4904 }
4905
4906 KMP_DEBUG_ASSERT(tc == num_tasks * grainsize +
4907 (last_chunk < 0 ? last_chunk : extras));
4908 KMP_DEBUG_ASSERT(num_tasks > extras);
4909 KMP_DEBUG_ASSERT(num_tasks > 0);
4910 // =========================================================================
4911
4912 // check if clause value first
4913 // Also require GOMP_taskloop to reduce to linear (taskdata->td_flags.native)
4914 if (if_val == 0) { // if(0) specified, mark task as serial
4915 taskdata->td_flags.task_serial = 1;
4916 taskdata->td_flags.tiedness = TASK_TIED; // AC: serial task cannot be untied
4917 // always start serial tasks linearly
4918 __kmp_taskloop_linear(loc, gtid, task, lb, ub, st, ub_glob, num_tasks,
4919 grainsize, extras, last_chunk, tc,
4920#if OMPT_SUPPORT
4921 OMPT_GET_RETURN_ADDRESS(0),
4922#endif
4923 task_dup);
4924 // !taskdata->td_flags.native => currently force linear spawning of tasks
4925 // for GOMP_taskloop
4926 } else if (num_tasks > num_tasks_min && !taskdata->td_flags.native) {
4927 KA_TRACE(20, ("__kmp_taskloop: T#%d, go recursive: tc %llu, #tasks %llu"
4928 "(%lld), grain %llu, extras %llu, last_chunk %lld\n",
4929 gtid, tc, num_tasks, num_tasks_min, grainsize, extras,
4930 last_chunk));
4931 __kmp_taskloop_recur(loc, gtid, task, lb, ub, st, ub_glob, num_tasks,
4932 grainsize, extras, last_chunk, tc, num_tasks_min,
4933#if OMPT_SUPPORT
4934 OMPT_GET_RETURN_ADDRESS(0),
4935#endif
4936 task_dup);
4937 } else {
4938 KA_TRACE(20, ("__kmp_taskloop: T#%d, go linear: tc %llu, #tasks %llu"
4939 "(%lld), grain %llu, extras %llu, last_chunk %lld\n",
4940 gtid, tc, num_tasks, num_tasks_min, grainsize, extras,
4941 last_chunk));
4942 __kmp_taskloop_linear(loc, gtid, task, lb, ub, st, ub_glob, num_tasks,
4943 grainsize, extras, last_chunk, tc,
4944#if OMPT_SUPPORT
4945 OMPT_GET_RETURN_ADDRESS(0),
4946#endif
4947 task_dup);
4948 }
4949
4950#if OMPT_SUPPORT && OMPT_OPTIONAL
4951 if (ompt_enabled.ompt_callback_work) {
4952 ompt_callbacks.ompt_callback(ompt_callback_work)(
4953 ompt_work_taskloop, ompt_scope_end, &(team_info->parallel_data),
4954 &(task_info->task_data), tc, OMPT_GET_RETURN_ADDRESS(0));
4955 }
4956#endif
4957
4958 if (nogroup == 0) {
4959#if OMPT_SUPPORT && OMPT_OPTIONAL
4960 OMPT_STORE_RETURN_ADDRESS(gtid);
4961#endif
4962 __kmpc_end_taskgroup(loc, gtid);
4963 }
4964 KA_TRACE(20, ("__kmp_taskloop(exit): T#%d\n", gtid));
4965}
4966
4983void __kmpc_taskloop(ident_t *loc, int gtid, kmp_task_t *task, int if_val,
4984 kmp_uint64 *lb, kmp_uint64 *ub, kmp_int64 st, int nogroup,
4985 int sched, kmp_uint64 grainsize, void *task_dup) {
4986 __kmp_assert_valid_gtid(gtid);
4987 KA_TRACE(20, ("__kmpc_taskloop(enter): T#%d\n", gtid));
4988 __kmp_taskloop(loc, gtid, task, if_val, lb, ub, st, nogroup, sched, grainsize,
4989 0, task_dup);
4990 KA_TRACE(20, ("__kmpc_taskloop(exit): T#%d\n", gtid));
4991}
4992
5010void __kmpc_taskloop_5(ident_t *loc, int gtid, kmp_task_t *task, int if_val,
5011 kmp_uint64 *lb, kmp_uint64 *ub, kmp_int64 st,
5012 int nogroup, int sched, kmp_uint64 grainsize,
5013 int modifier, void *task_dup) {
5014 __kmp_assert_valid_gtid(gtid);
5015 KA_TRACE(20, ("__kmpc_taskloop_5(enter): T#%d\n", gtid));
5016 __kmp_taskloop(loc, gtid, task, if_val, lb, ub, st, nogroup, sched, grainsize,
5017 modifier, task_dup);
5018 KA_TRACE(20, ("__kmpc_taskloop_5(exit): T#%d\n", gtid));
5019}
5020
5030 if (gtid == KMP_GTID_DNE)
5031 return NULL;
5032
5033 kmp_info_t *thread = __kmp_thread_from_gtid(gtid);
5034 kmp_taskdata_t *taskdata = thread->th.th_current_task;
5035
5036 if (!taskdata)
5037 return NULL;
5038
5039 return &taskdata->td_target_data.async_handle;
5040}
5041
5050bool __kmpc_omp_has_task_team(kmp_int32 gtid) {
5051 if (gtid == KMP_GTID_DNE)
5052 return FALSE;
5053
5054 kmp_info_t *thread = __kmp_thread_from_gtid(gtid);
5055 kmp_taskdata_t *taskdata = thread->th.th_current_task;
5056
5057 if (!taskdata)
5058 return FALSE;
5059
5060 return taskdata->td_task_team != NULL;
5061}
struct kmp_taskred_data kmp_taskred_data_t
struct kmp_task_red_input kmp_task_red_input_t
struct kmp_taskred_flags kmp_taskred_flags_t
struct kmp_taskred_input kmp_taskred_input_t
#define KMP_COUNT_BLOCK(name)
Increments specified counter (name).
Definition: kmp_stats.h:911
void * __kmpc_task_reduction_get_th_data(int gtid, void *tskgrp, void *data)
void __kmpc_taskloop(ident_t *loc, int gtid, kmp_task_t *task, int if_val, kmp_uint64 *lb, kmp_uint64 *ub, kmp_int64 st, int nogroup, int sched, kmp_uint64 grainsize, void *task_dup)
void * __kmpc_task_reduction_modifier_init(ident_t *loc, int gtid, int is_ws, int num, void *data)
void * __kmpc_taskred_modifier_init(ident_t *loc, int gtid, int is_ws, int num, void *data)
bool __kmpc_omp_has_task_team(kmp_int32 gtid)
void __kmpc_proxy_task_completed_ooo(kmp_task_t *ptask)
void __kmpc_task_reduction_modifier_fini(ident_t *loc, int gtid, int is_ws)
kmp_int32 __kmpc_omp_reg_task_with_affinity(ident_t *loc_ref, kmp_int32 gtid, kmp_task_t *new_task, kmp_int32 naffins, kmp_task_affinity_info_t *affin_list)
void __kmpc_taskloop_5(ident_t *loc, int gtid, kmp_task_t *task, int if_val, kmp_uint64 *lb, kmp_uint64 *ub, kmp_int64 st, int nogroup, int sched, kmp_uint64 grainsize, int modifier, void *task_dup)
void * __kmpc_task_reduction_init(int gtid, int num, void *data)
void __kmpc_proxy_task_completed(kmp_int32 gtid, kmp_task_t *ptask)
void * __kmpc_taskred_init(int gtid, int num, void *data)
void ** __kmpc_omp_get_target_async_handle_ptr(kmp_int32 gtid)
Definition: kmp.h:217
kmp_taskred_flags_t flags
kmp_taskred_flags_t flags
kmp_taskred_flags_t flags