Przeglądaj źródła

- add support for omp sections (wait|nowait)
- add test case

Olivier Aumage 11 lat temu
rodzic
commit
580b168a39

+ 2 - 0
include/starpu_openmp.h

@@ -84,6 +84,8 @@ extern void starpu_omp_ordered_inline_begin(unsigned long long i) __STARPU_OMP_N
 extern void starpu_omp_ordered_inline_end(void) __STARPU_OMP_NOTHROW;
 extern void starpu_omp_ordered(void (*f)(unsigned long long _i, void *arg), void *arg, unsigned long long i) __STARPU_OMP_NOTHROW;
 
+extern void starpu_omp_sections(int nb_sections, void (**section_f)(void *arg), void **section_arg, int nowait) __STARPU_OMP_NOTHROW;
+
 extern void starpu_omp_set_num_threads(int threads) __STARPU_OMP_NOTHROW;
 extern int starpu_omp_get_num_threads() __STARPU_OMP_NOTHROW;
 extern int starpu_omp_get_thread_num() __STARPU_OMP_NOTHROW;

+ 79 - 0
src/util/openmp_runtime_support.c

@@ -1606,6 +1606,85 @@ void starpu_omp_ordered_inline_end(void)
 	_starpu_spin_unlock(&loop->ordered_lock);
 }
 
+static inline struct starpu_omp_sections *_starpu_omp_get_sections(struct starpu_omp_region *parallel_region, struct starpu_omp_task *task)
+{
+	struct starpu_omp_sections *sections;
+	sections = parallel_region->sections_list;
+	while (sections && sections->id != task->sections_id)
+	{
+		sections = sections->next_sections;
+	}
+	return sections;
+}
+
+static inline struct starpu_omp_sections *_starpu_omp_sections_begin(struct starpu_omp_region *parallel_region, struct starpu_omp_task *task)
+{
+	struct starpu_omp_sections *sections;
+	_starpu_spin_lock(&parallel_region->lock);
+	sections = _starpu_omp_get_sections(parallel_region, task);
+	if (!sections)
+	{
+		sections = malloc(sizeof(*sections));
+		if (sections == NULL)
+			_STARPU_ERROR("memory allocation failed\n");
+		sections->id = task->sections_id;
+		sections->next_section_num = 0;
+		sections->nb_completed_threads = 0;
+		sections->next_sections = parallel_region->sections_list;
+		parallel_region->sections_list = sections;
+	}
+	_starpu_spin_unlock(&parallel_region->lock);
+	return sections;
+}
+static inline void _starpu_omp_sections_end(struct starpu_omp_region *parallel_region, struct starpu_omp_task *task,
+		struct starpu_omp_sections *sections)
+{
+	_starpu_spin_lock(&parallel_region->lock);
+	sections->nb_completed_threads++;
+	if (sections->nb_completed_threads == parallel_region->nb_threads)
+	{
+		struct starpu_omp_sections **p_sections;
+		STARPU_ASSERT(sections->next_sections == NULL);
+		p_sections = &(parallel_region->sections_list);
+		while (*p_sections != sections)
+		{
+			p_sections = &((*p_sections)->next_sections);
+		}
+		*p_sections = NULL;
+		free(sections);
+	}
+	_starpu_spin_unlock(&parallel_region->lock);
+	task->sections_id++;
+}
+
+void starpu_omp_sections(int nb_sections, void (**section_f)(void *arg), void **section_arg, int nowait)
+{
+	struct starpu_omp_task *task = STARPU_PTHREAD_GETSPECIFIC(omp_task_key);
+	struct starpu_omp_region *parallel_region = task->owner_region;
+	struct starpu_omp_sections *sections = _starpu_omp_sections_begin(parallel_region, task);
+	for (;;)
+	{
+		void (*f)(void *arg) = NULL;
+		void *arg = NULL;
+		_starpu_spin_lock(&parallel_region->lock);
+		if (sections->next_section_num < nb_sections)
+		{
+			f = section_f[sections->next_section_num];
+			arg = section_arg[sections->next_section_num];
+			sections->next_section_num ++;
+		}
+		_starpu_spin_unlock(&parallel_region->lock);
+		if (f == NULL)
+			break;
+		f(arg);
+	}
+	_starpu_omp_sections_end(parallel_region, task, sections);
+	if (!nowait)
+	{
+		starpu_omp_barrier();
+	}
+}
+
 /*
  * restore deprecated diagnostics (-Wdeprecated-declarations)
  */

+ 10 - 0
src/util/openmp_runtime_support.h

@@ -225,6 +225,7 @@ LIST_TYPE(starpu_omp_task,
 	int barrier_count;
 	int single_id;
 	int loop_id;
+	int sections_id;
 	struct starpu_omp_data_environment_icvs data_env_icvs;
 	struct starpu_omp_implicit_task_icvs implicit_task_icvs;
 
@@ -286,6 +287,14 @@ struct starpu_omp_loop
 	unsigned long long ordered_iteration;
 };
 
+struct starpu_omp_sections
+{
+	int id;
+	int next_section_num;
+	int nb_completed_threads;
+	struct starpu_omp_sections *next_sections;
+};
+
 struct starpu_omp_region
 {
 	struct starpu_omp_region *parent_region;
@@ -304,6 +313,7 @@ struct starpu_omp_region
 	int single_id;
 	int level;
 	struct starpu_omp_loop *loop_list;
+	struct starpu_omp_sections *sections_list;
 	struct starpu_task *continuation_starpu_task;
 };
 

+ 4 - 0
tests/Makefile.am

@@ -239,6 +239,7 @@ noinst_PROGRAMS =				\
 	openmp/parallel_for_01			\
 	openmp/parallel_for_02			\
 	openmp/parallel_for_ordered_01		\
+	openmp/parallel_sections_01		\
 	openmp/task_01				\
 	openmp/taskwait_01			\
 	openmp/taskgroup_01			\
@@ -509,6 +510,9 @@ openmp_parallel_for_02_SOURCES = 	\
 openmp_parallel_for_ordered_01_SOURCES = 	\
 	openmp/parallel_for_ordered_01.c
 
+openmp_parallel_sections_01_SOURCES = 	\
+	openmp/parallel_sections_01.c
+
 openmp_task_01_SOURCES = 	\
 	openmp/task_01.c
 

+ 108 - 0
tests/openmp/parallel_sections_01.c

@@ -0,0 +1,108 @@
+/* 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 f(void *arg)
+{
+	int worker_id;
+	pthread_t tid;
+	tid = pthread_self();
+	worker_id = starpu_worker_get_id();
+	printf("[tid %p] task thread = %d, section [%s]\n", (void *)tid, worker_id, (const char *)arg);
+}
+
+void parallel_region_1_f(void *buffers[], void *args)
+{
+	(void) buffers;
+	(void) args;
+	void (*section_f[4])(void *);
+	void *section_args[4];
+	int worker_id;
+	pthread_t tid;
+	tid = pthread_self();
+	worker_id = starpu_worker_get_id();
+	printf("[tid %p] task thread = %d\n", (void *)tid, worker_id);
+
+	section_f[0] = f;
+	section_f[1] = f;
+	section_f[2] = f;
+	section_f[3] = f;
+
+	section_args[0] = (void *)"A";
+	section_args[1] = (void *)"B";
+	section_args[2] = (void *)"C";
+	section_args[3] = (void *)"D";
+
+	starpu_omp_sections(4, section_f, section_args, 0);
+
+	section_args[0] = (void *)"E";
+	section_args[1] = (void *)"F";
+	section_args[2] = (void *)"G";
+	section_args[3] = (void *)"H";
+
+	starpu_omp_sections(4, section_f, section_args, 0);
+
+	section_args[0] = (void *)"I";
+	section_args[1] = (void *)"J";
+	section_args[2] = (void *)"K";
+	section_args[3] = (void *)"L";
+
+	starpu_omp_sections(4, section_f, section_args, 0);
+
+	section_args[0] = (void *)"M";
+	section_args[1] = (void *)"N";
+	section_args[2] = (void *)"O";
+	section_args[3] = (void *)"P";
+
+	starpu_omp_sections(4, section_f, section_args, 0);
+}
+
+static struct starpu_codelet parallel_region_1_cl =
+{
+	.cpu_funcs    = { parallel_region_1_f, NULL },
+	.where        = STARPU_CPU,
+	.nbuffers     = 0
+};
+
+int
+main (int argc, char *argv[]) {
+	starpu_omp_parallel_region(&parallel_region_1_cl, NULL, NULL);
+	return 0;
+}
+#endif