1 /* Copyright (C) 2015-2019 Free Software Foundation, Inc.
2 Contributed by Jakub Jelinek <jakub@redhat.com>.
4 This file is part of the GNU Offloading and Multi Processing Library
7 Libgomp is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3, or (at your option)
12 Libgomp is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14 FOR A PARTICULAR PURPOSE. See the GNU General Public License for
17 Under Section 7 of GPL version 3, you are granted additional
18 permissions described in the GCC Runtime Library Exception, version
19 3.1, as published by the Free Software Foundation.
21 You should have received a copy of the GNU General Public License and
22 a copy of the GCC Runtime Library Exception along with this program;
23 see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
24 <http://www.gnu.org/licenses/>. */
26 /* This file handles the taskloop construct. It is included twice, once
27 for the long and once for unsigned long long variant. */
29 /* Called when encountering an explicit task directive. If IF_CLAUSE is
30 false, then we must not delay in executing the task. If UNTIED is true,
31 then the task may be executed by any member of the team. */
34 GOMP_taskloop (void (*fn
) (void *), void *data
, void (*cpyfn
) (void *, void *),
35 long arg_size
, long arg_align
, unsigned flags
,
36 unsigned long num_tasks
, int priority
,
37 TYPE start
, TYPE end
, TYPE step
)
39 struct gomp_thread
*thr
= gomp_thread ();
40 struct gomp_team
*team
= thr
->ts
.team
;
42 #ifdef HAVE_BROKEN_POSIX_SEMAPHORES
43 /* If pthread_mutex_* is used for omp_*lock*, then each task must be
44 tied to one thread all the time. This means UNTIED tasks must be
45 tied and if CPYFN is non-NULL IF(0) must be forced, as CPYFN
46 might be running on different thread than FN. */
48 flags
&= ~GOMP_TASK_FLAG_IF
;
49 flags
&= ~GOMP_TASK_FLAG_UNTIED
;
52 /* If parallel or taskgroup has been cancelled, don't start new tasks. */
53 if (team
&& gomp_team_barrier_cancelled (&team
->barrier
))
70 UTYPE n
= (end
- start
+ s
) / step
;
73 if (flags
& GOMP_TASK_FLAG_UP
)
77 n
= (end
- start
+ step
- 1) / step
;
83 n
= (start
- end
- step
- 1) / -step
;
87 TYPE task_step
= step
;
88 unsigned long nfirst
= n
;
89 if (flags
& GOMP_TASK_FLAG_GRAINSIZE
)
91 unsigned long grainsize
= num_tasks
;
93 num_tasks
= n
/ grainsize
;
95 UTYPE ndiv
= n
/ grainsize
;
97 if (num_tasks
!= ndiv
)
103 task_step
= end
- start
;
105 else if (num_tasks
>= grainsize
111 UTYPE mul
= num_tasks
* grainsize
;
112 task_step
= (TYPE
) grainsize
* step
;
116 nfirst
= n
- mul
- 1;
121 UTYPE div
= n
/ num_tasks
;
122 UTYPE mod
= n
% num_tasks
;
123 task_step
= (TYPE
) div
* step
;
134 num_tasks
= team
? team
->nthreads
: 1;
139 UTYPE div
= n
/ num_tasks
;
140 UTYPE mod
= n
% num_tasks
;
141 task_step
= (TYPE
) div
* step
;
150 if (flags
& GOMP_TASK_FLAG_NOGROUP
)
152 if (__builtin_expect (gomp_cancel_var
, 0)
154 && thr
->task
->taskgroup
)
156 if (thr
->task
->taskgroup
->cancelled
)
158 if (thr
->task
->taskgroup
->workshare
159 && thr
->task
->taskgroup
->prev
160 && thr
->task
->taskgroup
->prev
->cancelled
)
166 ialias_call (GOMP_taskgroup_start
) ();
167 if (flags
& GOMP_TASK_FLAG_REDUCTION
)
169 struct gomp_data_head
{ TYPE t1
, t2
; uintptr_t *ptr
; };
170 uintptr_t *ptr
= ((struct gomp_data_head
*) data
)->ptr
;
171 ialias_call (GOMP_taskgroup_reduction_register
) (ptr
);
175 if (priority
> gomp_max_task_priority_var
)
176 priority
= gomp_max_task_priority_var
;
178 if ((flags
& GOMP_TASK_FLAG_IF
) == 0 || team
== NULL
179 || (thr
->task
&& thr
->task
->final_task
)
180 || team
->task_count
+ num_tasks
> 64 * team
->nthreads
)
183 if (__builtin_expect (cpyfn
!= NULL
, 0))
185 struct gomp_task task
[num_tasks
];
186 struct gomp_task
*parent
= thr
->task
;
187 arg_size
= (arg_size
+ arg_align
- 1) & ~(arg_align
- 1);
188 char buf
[num_tasks
* arg_size
+ arg_align
- 1];
189 char *arg
= (char *) (((uintptr_t) buf
+ arg_align
- 1)
190 & ~(uintptr_t) (arg_align
- 1));
191 char *orig_arg
= arg
;
192 for (i
= 0; i
< num_tasks
; i
++)
194 gomp_init_task (&task
[i
], parent
, gomp_icv (false));
195 task
[i
].priority
= priority
;
196 task
[i
].kind
= GOMP_TASK_UNDEFERRED
;
197 task
[i
].final_task
= (thr
->task
&& thr
->task
->final_task
)
198 || (flags
& GOMP_TASK_FLAG_FINAL
);
201 task
[i
].in_tied_task
= thr
->task
->in_tied_task
;
202 task
[i
].taskgroup
= thr
->task
->taskgroup
;
204 thr
->task
= &task
[i
];
209 for (i
= 0; i
< num_tasks
; i
++)
211 thr
->task
= &task
[i
];
212 ((TYPE
*)arg
)[0] = start
;
214 ((TYPE
*)arg
)[1] = start
;
219 if (!priority_queue_empty_p (&task
[i
].children_queue
,
222 gomp_mutex_lock (&team
->task_lock
);
223 gomp_clear_parent (&task
[i
].children_queue
);
224 gomp_mutex_unlock (&team
->task_lock
);
230 for (i
= 0; i
< num_tasks
; i
++)
232 struct gomp_task task
;
234 gomp_init_task (&task
, thr
->task
, gomp_icv (false));
235 task
.priority
= priority
;
236 task
.kind
= GOMP_TASK_UNDEFERRED
;
237 task
.final_task
= (thr
->task
&& thr
->task
->final_task
)
238 || (flags
& GOMP_TASK_FLAG_FINAL
);
241 task
.in_tied_task
= thr
->task
->in_tied_task
;
242 task
.taskgroup
= thr
->task
->taskgroup
;
245 ((TYPE
*)data
)[0] = start
;
247 ((TYPE
*)data
)[1] = start
;
251 if (!priority_queue_empty_p (&task
.children_queue
,
254 gomp_mutex_lock (&team
->task_lock
);
255 gomp_clear_parent (&task
.children_queue
);
256 gomp_mutex_unlock (&team
->task_lock
);
263 struct gomp_task
*tasks
[num_tasks
];
264 struct gomp_task
*parent
= thr
->task
;
265 struct gomp_taskgroup
*taskgroup
= parent
->taskgroup
;
270 for (i
= 0; i
< num_tasks
; i
++)
272 struct gomp_task
*task
273 = gomp_malloc (sizeof (*task
) + arg_size
+ arg_align
- 1);
275 arg
= (char *) (((uintptr_t) (task
+ 1) + arg_align
- 1)
276 & ~(uintptr_t) (arg_align
- 1));
277 gomp_init_task (task
, parent
, gomp_icv (false));
278 task
->priority
= priority
;
279 task
->kind
= GOMP_TASK_UNDEFERRED
;
280 task
->in_tied_task
= parent
->in_tied_task
;
281 task
->taskgroup
= taskgroup
;
286 task
->copy_ctors_done
= true;
289 memcpy (arg
, data
, arg_size
);
290 ((TYPE
*)arg
)[0] = start
;
292 ((TYPE
*)arg
)[1] = start
;
296 task
->kind
= GOMP_TASK_WAITING
;
299 task
->final_task
= (flags
& GOMP_TASK_FLAG_FINAL
) >> 1;
301 gomp_mutex_lock (&team
->task_lock
);
302 /* If parallel or taskgroup has been cancelled, don't start new
304 if (__builtin_expect (gomp_cancel_var
, 0)
307 if (gomp_team_barrier_cancelled (&team
->barrier
))
310 gomp_mutex_unlock (&team
->task_lock
);
311 for (i
= 0; i
< num_tasks
; i
++)
313 gomp_finish_task (tasks
[i
]);
316 if ((flags
& GOMP_TASK_FLAG_NOGROUP
) == 0)
317 ialias_call (GOMP_taskgroup_end
) ();
322 if (taskgroup
->cancelled
)
324 if (taskgroup
->workshare
326 && taskgroup
->prev
->cancelled
)
331 taskgroup
->num_children
+= num_tasks
;
332 for (i
= 0; i
< num_tasks
; i
++)
334 struct gomp_task
*task
= tasks
[i
];
335 priority_queue_insert (PQ_CHILDREN
, &parent
->children_queue
,
337 PRIORITY_INSERT_BEGIN
,
338 /*last_parent_depends_on=*/false,
339 task
->parent_depends_on
);
341 priority_queue_insert (PQ_TASKGROUP
, &taskgroup
->taskgroup_queue
,
342 task
, priority
, PRIORITY_INSERT_BEGIN
,
343 /*last_parent_depends_on=*/false,
344 task
->parent_depends_on
);
345 priority_queue_insert (PQ_TEAM
, &team
->task_queue
, task
, priority
,
347 /*last_parent_depends_on=*/false,
348 task
->parent_depends_on
);
350 ++team
->task_queued_count
;
352 gomp_team_barrier_set_task_pending (&team
->barrier
);
353 if (team
->task_running_count
+ !parent
->in_tied_task
356 do_wake
= team
->nthreads
- team
->task_running_count
357 - !parent
->in_tied_task
;
358 if ((unsigned long) do_wake
> num_tasks
)
363 gomp_mutex_unlock (&team
->task_lock
);
365 gomp_team_barrier_wake (&team
->barrier
, do_wake
);
367 if ((flags
& GOMP_TASK_FLAG_NOGROUP
) == 0)
368 ialias_call (GOMP_taskgroup_end
) ();