Browse Source

- add begin/end API for taskgroups

Olivier Aumage 10 years ago
parent
commit
349ee9a0ab

+ 2 - 0
include/starpu_openmp.h

@@ -100,6 +100,8 @@ extern void starpu_omp_critical_inline_end(const char *name) __STARPU_OMP_NOTHRO
 extern void starpu_omp_task_region(const struct starpu_omp_task_region_attr *attr) __STARPU_OMP_NOTHROW;
 extern void starpu_omp_taskwait(void) __STARPU_OMP_NOTHROW;
 extern void starpu_omp_taskgroup(void (*f)(void *arg), void *arg) __STARPU_OMP_NOTHROW;
+extern void starpu_omp_taskgroup_begin(void) __STARPU_OMP_NOTHROW;
+extern void starpu_omp_taskgroup_end(void) __STARPU_OMP_NOTHROW;
 
 extern void starpu_omp_for(void (*f)(unsigned long long _first_i, unsigned long long _nb_i, void *arg), void *arg, unsigned long long nb_iterations, unsigned long long chunk, int schedule, int ordered, int nowait) __STARPU_OMP_NOTHROW;
 extern int starpu_omp_for_inline_first(unsigned long long nb_iterations, unsigned long long chunk, int schedule, int ordered, unsigned long long *_first_i, unsigned long long *_nb_i) __STARPU_OMP_NOTHROW;

+ 34 - 3
src/util/openmp_runtime_support.c

@@ -1634,9 +1634,8 @@ static void group__sleep_callback(void *_task)
 void starpu_omp_taskgroup(void (*f)(void *arg), void *arg)
 {
 	struct starpu_omp_task *task = STARPU_PTHREAD_GETSPECIFIC(omp_task_key);
-	struct starpu_omp_task_group *p_previous_task_group;
 	struct starpu_omp_task_group task_group;
-	p_previous_task_group = task->task_group;
+	task_group.p_previous_task_group = task->task_group;
 	task_group.descendent_task_count = 0;
 	task_group.leader_task = task;
 	task->task_group = &task_group;
@@ -1653,7 +1652,39 @@ void starpu_omp_taskgroup(void (*f)(void *arg), void *arg)
 	{
 		_starpu_spin_unlock(&task->lock);
 	}
-	task->task_group = p_previous_task_group;
+	task->task_group = task_group.p_previous_task_group;
+}
+
+void starpu_omp_taskgroup_begin(void)
+{
+	struct starpu_omp_task *task = STARPU_PTHREAD_GETSPECIFIC(omp_task_key);
+	struct starpu_omp_task_group *p_task_group = malloc(sizeof(*p_task_group));
+	if (p_task_group == NULL)
+		_STARPU_ERROR("memory allocation failed\n");
+	p_task_group->p_previous_task_group = task->task_group;
+	p_task_group->descendent_task_count = 0;
+	p_task_group->leader_task = task;
+	task->task_group = p_task_group;
+}
+
+void starpu_omp_taskgroup_end(void)
+{
+	struct starpu_omp_task *task = STARPU_PTHREAD_GETSPECIFIC(omp_task_key);
+	_starpu_spin_lock(&task->lock);
+	struct starpu_omp_task_group *p_task_group = task->task_group;
+	if (p_task_group->descendent_task_count > 0)
+	{
+		task->wait_on |= starpu_omp_task_wait_on_group;
+		_starpu_task_prepare_for_continuation_ext(0, group__sleep_callback, task);
+		starpu_omp_task_preempt();
+		STARPU_ASSERT(p_task_group->descendent_task_count == 0);
+	}
+	else
+	{
+		_starpu_spin_unlock(&task->lock);
+	}
+	task->task_group = p_task_group->p_previous_task_group;
+	free(p_task_group);
 }
 
 static inline void _starpu_omp_for_loop(struct starpu_omp_region *parallel_region, struct starpu_omp_task *task,

+ 1 - 0
src/util/openmp_runtime_support.h

@@ -150,6 +150,7 @@ struct starpu_omp_task_group
 {
 	int descendent_task_count;
 	struct starpu_omp_task *leader_task;
+	struct starpu_omp_task_group *p_previous_task_group;
 };
 
 struct starpu_omp_task_link

+ 4 - 0
tests/Makefile.am

@@ -251,6 +251,7 @@ noinst_PROGRAMS =				\
 	openmp/task_02				\
 	openmp/taskwait_01			\
 	openmp/taskgroup_01			\
+	openmp/taskgroup_02			\
 	overlap/overlap				\
 	overlap/gpu_concurrency			\
 	parallel_tasks/explicit_combined_worker	\
@@ -562,6 +563,9 @@ openmp_taskwait_01_SOURCES = 	\
 openmp_taskgroup_01_SOURCES = 	\
 	openmp/taskgroup_01.c
 
+openmp_taskgroup_02_SOURCES = 	\
+	openmp/taskgroup_02.c
+
 ###################
 # Block interface #
 ###################

+ 123 - 0
tests/openmp/taskgroup_02.c

@@ -0,0 +1,123 @@
+/* StarPU --- Runtime system for heterogeneous multicore architectures.
+ *
+ * Copyright (C) 2014  Inria
+ *
+ * StarPU is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or (at
+ * your option) any later version.
+ *
+ * StarPU is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * See the GNU Lesser General Public License in COPYING.LGPL for more details.
+ */
+
+#include <pthread.h>
+#include <starpu.h>
+#include "../helper.h"
+#include <stdio.h>
+
+#if !defined(STARPU_OPENMP)
+int main(int argc, char **argv)
+{
+	return STARPU_TEST_SKIPPED;
+}
+#else
+__attribute__((constructor))
+static void omp_constructor(void)
+{
+	int ret = starpu_omp_init();
+	STARPU_CHECK_RETURN_VALUE(ret, "starpu_omp_init");
+}
+
+__attribute__((destructor))
+static void omp_destructor(void)
+{
+	starpu_omp_shutdown();
+}
+
+void task_region_g(void *buffers[], void *args)
+{
+	(void) buffers;
+	int i = (int)(intptr_t) args;
+	int worker_id;
+	pthread_t tid;
+	tid = pthread_self();
+	worker_id = starpu_worker_get_id();
+	printf("[tid %p] task thread = %d: explicit task \"g[%d]\"\n", (void *)tid, worker_id, i);
+}
+
+void taskgroup_f(void *arg)
+{
+	struct starpu_omp_task_region_attr attr;
+	int *p_i = (int *)arg;
+	memset(&attr, 0, sizeof(attr));
+	attr.cl.cpu_funcs[0]  = task_region_g;
+	attr.cl.where         = STARPU_CPU;
+	attr.cl_arg_size      = sizeof(void *);
+	attr.cl_arg_free      = 0;
+	attr.if_clause        = 1;
+	attr.final_clause     = 0;
+	attr.untied_clause    = 1;
+	attr.mergeable_clause = 0;
+
+	attr.cl_arg = (void *)(intptr_t)(*p_i)++;
+	starpu_omp_task_region(&attr);
+
+	attr.cl_arg = (void *)(intptr_t)(*p_i)++;
+	starpu_omp_task_region(&attr);
+}
+
+void parallel_region_f(void *buffers[], void *args)
+{
+	(void) buffers;
+	(void) args;
+	int worker_id;
+	pthread_t tid;
+	struct starpu_omp_task_region_attr attr;
+	int i = 0;
+
+	tid = pthread_self();
+	worker_id = starpu_worker_get_id();
+	printf("[tid %p] task thread = %d: implicit task \"f\"\n", (void *)tid, worker_id);
+	
+	starpu_omp_taskgroup_begin();
+	taskgroup_f((void *)&i);
+	starpu_omp_taskgroup_end();
+	printf("[tid %p] task thread = %d: implicit task \"f\": taskgroup\n", (void *)tid, worker_id);
+
+	starpu_omp_taskgroup_begin();
+	taskgroup_f((void *)&i);
+	starpu_omp_taskgroup_end();
+	printf("[tid %p] task thread = %d: implicit task \"f\": taskgroup\n", (void *)tid, worker_id);
+
+	memset(&attr, 0, sizeof(attr));
+	attr.cl.cpu_funcs[0]  = task_region_g;
+	attr.cl.where         = STARPU_CPU;
+	attr.cl_arg_size      = sizeof(void *);
+	attr.cl_arg_free      = 0;
+	attr.if_clause        = 1;
+	attr.final_clause     = 0;
+	attr.untied_clause    = 1;
+	attr.mergeable_clause = 0;
+
+	attr.cl_arg = (void *)(intptr_t)i++;
+	starpu_omp_task_region(&attr);
+
+	attr.cl_arg = (void *)(intptr_t)i++;
+	starpu_omp_task_region(&attr);
+}
+
+int
+main (int argc, char *argv[]) {
+	struct starpu_omp_parallel_region_attr attr;
+	memset(&attr, 0, sizeof(attr));
+	attr.cl.cpu_funcs[0] = parallel_region_f;
+	attr.cl.where        = STARPU_CPU;
+	attr.if_clause       = 1;
+	starpu_omp_parallel_region(&attr);
+	return 0;
+}
+#endif