Browse Source

- add support for single with copyprivate clause

Olivier Aumage 11 years ago
parent
commit
6ab9cdb01a

+ 3 - 0
include/starpu_openmp.h

@@ -88,6 +88,9 @@ extern int starpu_omp_master_inline(void) __STARPU_OMP_NOTHROW;
 
 extern void starpu_omp_single(void (*f)(void *arg), void *arg, int nowait) __STARPU_OMP_NOTHROW;
 extern int starpu_omp_single_inline(void) __STARPU_OMP_NOTHROW;
+extern void starpu_omp_single_copyprivate(void (*f)(void *arg, void *data, unsigned long long data_size), void *arg, void *data, unsigned long long data_size);
+extern void *starpu_omp_single_copyprivate_inline_begin(void *data);
+extern void starpu_omp_single_copyprivate_inline_end(void);
 
 extern void starpu_omp_critical(void (*f)(void *arg), void *arg, const char *name) __STARPU_OMP_NOTHROW;
 extern void starpu_omp_critical_inline_begin(const char *name) __STARPU_OMP_NOTHROW;

+ 54 - 0
src/util/openmp_runtime_support.c

@@ -1164,6 +1164,60 @@ int starpu_omp_single_inline(void)
 	return first;
 }
 
+void starpu_omp_single_copyprivate(void (*f)(void *arg, void *data, unsigned long long data_size), void *arg, void *data, unsigned long long data_size)
+{
+	struct starpu_omp_task *task = STARPU_PTHREAD_GETSPECIFIC(omp_task_key);
+	/* Assume singles are performed in by the implicit tasks of a region */
+	STARPU_ASSERT(task->is_implicit);
+	struct starpu_omp_region *region = task->owner_region;
+	int first = STARPU_BOOL_COMPARE_AND_SWAP(&region->single_id, task->single_id, task->single_id+1);
+	task->single_id++;
+	if (first)
+	{
+		region->copy_private_data = data;
+		f(arg, data, data_size);
+	} 
+	starpu_omp_barrier();
+	if (!first)
+	{
+		memcpy(data, region->copy_private_data, data_size);
+	} 
+	starpu_omp_barrier();
+}
+
+void *starpu_omp_single_copyprivate_inline_begin(void *data)
+{
+	struct starpu_omp_task *task = STARPU_PTHREAD_GETSPECIFIC(omp_task_key);
+	/* Assume singles are performed in by the implicit tasks of a region */
+	STARPU_ASSERT(task->is_implicit);
+	struct starpu_omp_region *region = task->owner_region;
+	int first = STARPU_BOOL_COMPARE_AND_SWAP(&region->single_id, task->single_id, task->single_id+1);
+	task->single_id++;
+	if (first)
+	{
+		task->single_first = 1;
+		region->copy_private_data = data;
+	} 
+	else
+	{
+		starpu_omp_barrier();
+	}
+	return first?NULL:region->copy_private_data;
+}
+
+void starpu_omp_single_copyprivate_inline_end(void)
+{
+	struct starpu_omp_task *task = STARPU_PTHREAD_GETSPECIFIC(omp_task_key);
+	/* Assume singles are performed in by the implicit tasks of a region */
+	STARPU_ASSERT(task->is_implicit);
+	if (task->single_first)
+	{
+		task->single_first = 0;
+		starpu_omp_barrier();
+	} 
+	starpu_omp_barrier();
+}
+
 static void critical__sleep_callback(void *_critical)
 {
 	struct starpu_omp_critical *critical = _critical;

+ 2 - 0
src/util/openmp_runtime_support.h

@@ -207,6 +207,7 @@ LIST_TYPE(starpu_omp_task,
 	int wait_on;
 	int barrier_count;
 	int single_id;
+	int single_first;
 	int loop_id;
 	unsigned long long ordered_first_i;
 	unsigned long long ordered_nb_i;
@@ -316,6 +317,7 @@ struct starpu_omp_region
 	int barrier_count;
 	int bound_explicit_task_count;
 	int single_id;
+	void *copy_private_data;
 	int level;
 	struct starpu_omp_loop *loop_list;
 	struct starpu_omp_sections *sections_list;

+ 8 - 0
tests/Makefile.am

@@ -233,6 +233,8 @@ noinst_PROGRAMS =				\
 	openmp/parallel_single_wait_01		\
 	openmp/parallel_single_nowait_01	\
 	openmp/parallel_single_inline_01	\
+	openmp/parallel_single_copyprivate_01	\
+	openmp/parallel_single_copyprivate_inline_01	\
 	openmp/parallel_critical_01		\
 	openmp/parallel_critical_inline_01	\
 	openmp/parallel_critical_named_01	\
@@ -497,6 +499,12 @@ openmp_parallel_single_nowait_01_SOURCES = 	\
 openmp_parallel_single_inline_01_SOURCES = 	\
 	openmp/parallel_single_inline_01.c
 
+openmp_parallel_single_copyprivate_01_SOURCES = 	\
+	openmp/parallel_single_copyprivate_01.c
+
+openmp_parallel_single_copyprivate_inline_01_SOURCES = 	\
+	openmp/parallel_single_copyprivate_inline_01.c
+
 openmp_parallel_critical_01_SOURCES = 	\
 	openmp/parallel_critical_01.c
 

+ 91 - 0
tests/openmp/parallel_single_copyprivate_01.c

@@ -0,0 +1,91 @@
+/* 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 single_g(void *arg, void *_data, unsigned long long data_size)
+{
+	(void) arg;
+	int *data = _data;
+	STARPU_ASSERT(data_size >= sizeof(*data));
+	int worker_id;
+	pthread_t tid;
+	tid = pthread_self();
+	worker_id = starpu_worker_get_id();
+	*data = worker_id;
+	printf("[tid %p] task thread = %d -- single\n", (void *)tid, worker_id);
+}
+
+void parallel_region_f(void *buffers[], void *args)
+{
+	(void) buffers;
+	(void) args;
+	int worker_id;
+	int single_worker_id;
+	pthread_t tid;
+	tid = pthread_self();
+	worker_id = starpu_worker_get_id();
+	printf("[tid %p] task thread = %d -- parallel -->\n", (void *)tid, worker_id);
+	starpu_omp_single_copyprivate(single_g, NULL, &single_worker_id, sizeof(single_worker_id));
+	printf("[tid %p] task thread = %d -- copyprivate: single_worker_id = %d\n", (void *)tid, worker_id, single_worker_id);
+	starpu_omp_single_copyprivate(single_g, NULL, &single_worker_id, sizeof(single_worker_id));
+	printf("[tid %p] task thread = %d -- copyprivate: single_worker_id = %d\n", (void *)tid, worker_id, single_worker_id);
+	starpu_omp_single_copyprivate(single_g, NULL, &single_worker_id, sizeof(single_worker_id));
+	printf("[tid %p] task thread = %d -- copyprivate: single_worker_id = %d\n", (void *)tid, worker_id, single_worker_id);
+	starpu_omp_single_copyprivate(single_g, NULL, &single_worker_id, sizeof(single_worker_id));
+	printf("[tid %p] task thread = %d -- copyprivate: single_worker_id = %d\n", (void *)tid, worker_id, single_worker_id);
+	printf("[tid %p] task thread = %d -- parallel <--\n", (void *)tid, worker_id);
+}
+
+int
+main (int argc, char *argv[]) {
+	struct starpu_omp_parallel_region_attr attr;
+	pthread_t tid;
+	tid = pthread_self();
+	memset(&attr, 0, sizeof(attr));
+	attr.cl.cpu_funcs[0] = parallel_region_f;
+	attr.cl.where        = STARPU_CPU;
+	attr.if_clause       = 1;
+	printf("<main>\n");
+	starpu_omp_parallel_region(&attr);
+	printf("<main>\n");
+	starpu_omp_parallel_region(&attr);
+	printf("<main>\n");
+	return 0;
+}
+#endif

+ 89 - 0
tests/openmp/parallel_single_copyprivate_inline_01.c

@@ -0,0 +1,89 @@
+/* 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 parallel_region_f(void *buffers[], void *args)
+{
+	(void) buffers;
+	(void) args;
+	int worker_id;
+	pthread_t tid;
+	tid = pthread_self();
+	worker_id = starpu_worker_get_id();
+	int single_worker_id;
+	int *single_data;
+	printf("[tid %p] task thread = %d -- parallel -->\n", (void *)tid, worker_id);
+	int i;
+
+	for (i=0; i<4; i++)
+	{
+		if ((single_data = starpu_omp_single_copyprivate_inline_begin(&single_worker_id)) == NULL)
+		{
+			printf("[tid %p] task thread = %d -- single\n", (void *)tid, worker_id);
+			single_worker_id = worker_id;
+			starpu_omp_single_copyprivate_inline_end();
+		}
+		else
+		{
+			memcpy(&single_worker_id, single_data, sizeof(single_worker_id));
+			starpu_omp_single_copyprivate_inline_end();
+		}
+		printf("[tid %p] task thread = %d -- single_worker_id = %d\n", (void *)tid, worker_id, single_worker_id);
+	}
+
+	printf("[tid %p] task thread = %d -- parallel <--\n", (void *)tid, worker_id);
+}
+
+int
+main (int argc, char *argv[]) {
+	struct starpu_omp_parallel_region_attr attr;
+	pthread_t tid;
+	tid = pthread_self();
+	memset(&attr, 0, sizeof(attr));
+	attr.cl.cpu_funcs[0] = parallel_region_f;
+	attr.cl.where        = STARPU_CPU;
+	attr.if_clause       = 1;
+	printf("<main>\n");
+	starpu_omp_parallel_region(&attr);
+	printf("<main>\n");
+	starpu_omp_parallel_region(&attr);
+	printf("<main>\n");
+	return 0;
+}
+#endif