Browse Source

- implement omp simple locks and nested locks
- add test cases

Olivier Aumage 11 years ago
parent
commit
2c4892dcbe

+ 2 - 2
include/starpu_openmp.h

@@ -20,8 +20,8 @@
 #include <starpu_config.h>
 
 #if defined STARPU_OPENMP
-typedef void *starpu_omp_lock_t; /* TODO: select a proper type */
-typedef void *starpu_omp_nest_lock_t; /* TODO: select a proper type */
+typedef struct { void *internal; } starpu_omp_lock_t;
+typedef struct { void *internal; } starpu_omp_nest_lock_t;
 
 enum starpu_omp_sched_value
 {

+ 200 - 0
src/util/openmp_runtime_support.c

@@ -1957,6 +1957,206 @@ void starpu_omp_sections_combined(unsigned long long nb_sections, void (*section
 	}
 }
 
+static void _starpu_omp_lock_init(void **_internal)
+{
+	struct _starpu_omp_lock_internal * _lock;
+	_lock = malloc(sizeof(*_lock));
+	STARPU_ASSERT(_lock != NULL);
+	memset(_lock, 0, sizeof(*_lock));
+	_starpu_spin_init(&_lock->lock);
+	condition_init(&_lock->cond);
+	*_internal = _lock;
+}
+
+static void _starpu_omp_lock_destroy(void **_internal)
+{
+	struct _starpu_omp_lock_internal * const _lock = *_internal;
+	STARPU_ASSERT(_lock->state == 0);
+	condition_exit(&_lock->cond);
+	_starpu_spin_destroy(&_lock->lock);
+	memset(_lock, 0, sizeof(*_lock));
+	*_internal = NULL;
+}
+
+static void _starpu_omp_lock_set(void **_internal)
+{
+	struct _starpu_omp_lock_internal * const _lock = *_internal;
+	_starpu_spin_lock(&_lock->lock);
+	while (_lock->state != 0)
+	{
+		condition_wait(&_lock->cond, &_lock->lock);
+	}
+	_lock->state = 1;
+	_starpu_spin_unlock(&_lock->lock);
+}
+
+static void _starpu_omp_lock_unset(void **_internal)
+{
+	struct _starpu_omp_lock_internal * const _lock = *_internal;
+	_starpu_spin_lock(&_lock->lock);
+	STARPU_ASSERT(_lock->state == 1);
+	_lock->state = 0;
+	condition_broadcast(&_lock->cond);
+	_starpu_spin_unlock(&_lock->lock);
+}
+
+static int _starpu_omp_lock_test(void **_internal)
+{
+	struct _starpu_omp_lock_internal * const _lock = *_internal;
+	int ret = 0;
+	_starpu_spin_lock(&_lock->lock);
+	if (_lock->state == 0)
+	{
+		_lock->state = 1;
+		ret = 1;
+	}
+	_starpu_spin_unlock(&_lock->lock);
+	return ret;
+}
+
+static void _starpu_omp_nest_lock_init(void **_internal)
+{
+	struct _starpu_omp_nest_lock_internal * _nest_lock;
+	_nest_lock = malloc(sizeof(*_nest_lock));
+	STARPU_ASSERT(_nest_lock != NULL);
+	memset(_nest_lock, 0, sizeof(*_nest_lock));
+	_starpu_spin_init(&_nest_lock->lock);
+	condition_init(&_nest_lock->cond);
+	*_internal = _nest_lock;
+}
+
+static void _starpu_omp_nest_lock_destroy(void **_internal)
+{
+	struct _starpu_omp_nest_lock_internal * const _nest_lock = *_internal;
+	STARPU_ASSERT(_nest_lock->state == 0);
+	STARPU_ASSERT(_nest_lock->nesting == 0);
+	STARPU_ASSERT(_nest_lock->owner_task == NULL);
+	condition_exit(&_nest_lock->cond);
+	_starpu_spin_destroy(&_nest_lock->lock);
+	memset(_nest_lock, 0, sizeof(*_nest_lock));
+	*_internal = NULL;
+}
+
+static void _starpu_omp_nest_lock_set(void **_internal)
+{
+	struct _starpu_omp_nest_lock_internal * const _nest_lock = *_internal;
+	struct starpu_omp_task * const task = _starpu_omp_get_task();
+	_starpu_spin_lock(&_nest_lock->lock);
+	if (_nest_lock->owner_task == task)
+	{
+		STARPU_ASSERT(_nest_lock->state == 1);
+		STARPU_ASSERT(_nest_lock->nesting > 0);
+		_nest_lock->nesting++;
+	}
+	else
+	{
+		while (_nest_lock->state != 0)
+		{
+			condition_wait(&_nest_lock->cond, &_nest_lock->lock);
+		}
+		STARPU_ASSERT(_nest_lock->nesting == 0);
+		STARPU_ASSERT(_nest_lock->owner_task == NULL);
+		_nest_lock->state = 1;
+		_nest_lock->owner_task = task;
+		_nest_lock->nesting = 1;
+	}
+	_starpu_spin_unlock(&_nest_lock->lock);
+}
+
+static void _starpu_omp_nest_lock_unset(void **_internal)
+{
+	struct _starpu_omp_nest_lock_internal * const _nest_lock = *_internal;
+	struct starpu_omp_task * const task = _starpu_omp_get_task();
+	_starpu_spin_lock(&_nest_lock->lock);
+	STARPU_ASSERT(_nest_lock->owner_task == task);
+	STARPU_ASSERT(_nest_lock->state == 1);
+	STARPU_ASSERT(_nest_lock->nesting > 0);
+	_nest_lock->nesting--;
+	if (_nest_lock->nesting == 0)
+	{
+		_nest_lock->state = 0;
+		_nest_lock->owner_task = NULL;
+		condition_broadcast(&_nest_lock->cond);
+	}
+	_starpu_spin_unlock(&_nest_lock->lock);
+}
+
+static int _starpu_omp_nest_lock_test(void **_internal)
+{
+	struct _starpu_omp_nest_lock_internal * const _nest_lock = *_internal;
+	struct starpu_omp_task * const task = _starpu_omp_get_task();
+	int ret = 0;
+	_starpu_spin_lock(&_nest_lock->lock);
+	if (_nest_lock->state == 0)
+	{
+		STARPU_ASSERT(_nest_lock->nesting == 0);
+		STARPU_ASSERT(_nest_lock->owner_task == NULL);
+		_nest_lock->state = 1;
+		_nest_lock->owner_task = task;
+		_nest_lock->nesting = 1;
+		ret = 1;
+	}
+	else if (_nest_lock->owner_task == task)
+	{
+		STARPU_ASSERT(_nest_lock->state == 1);
+		STARPU_ASSERT(_nest_lock->nesting > 0);
+		_nest_lock->nesting++;
+		ret = 1;
+	}
+	_starpu_spin_unlock(&_nest_lock->lock);
+	return ret;
+}
+
+void starpu_omp_init_lock (starpu_omp_lock_t *lock)
+{
+	_starpu_omp_lock_init(&lock->internal);
+}
+
+void starpu_omp_destroy_lock (starpu_omp_lock_t *lock)
+{
+	_starpu_omp_lock_destroy(&lock->internal);
+}
+
+void starpu_omp_set_lock (starpu_omp_lock_t *lock)
+{
+	_starpu_omp_lock_set(&lock->internal);
+}
+
+void starpu_omp_unset_lock (starpu_omp_lock_t *lock)
+{
+	_starpu_omp_lock_unset(&lock->internal);
+}
+
+int starpu_omp_test_lock (starpu_omp_lock_t *lock)
+{
+	return _starpu_omp_lock_test(&lock->internal);
+}
+
+void starpu_omp_init_nest_lock (starpu_omp_nest_lock_t *nest_lock)
+{
+	_starpu_omp_nest_lock_init(&nest_lock->internal);
+}
+
+void starpu_omp_destroy_nest_lock (starpu_omp_nest_lock_t *nest_lock)
+{
+	_starpu_omp_nest_lock_destroy(&nest_lock->internal);
+}
+
+void starpu_omp_set_nest_lock (starpu_omp_nest_lock_t *nest_lock)
+{
+	_starpu_omp_nest_lock_set(&nest_lock->internal);
+}
+
+void starpu_omp_unset_nest_lock (starpu_omp_nest_lock_t *nest_lock)
+{
+	_starpu_omp_nest_lock_unset(&nest_lock->internal);
+}
+
+int starpu_omp_test_nest_lock (starpu_omp_nest_lock_t *nest_lock)
+{
+	return _starpu_omp_nest_lock_test(&nest_lock->internal);
+}
+
 /*
  * restore deprecated diagnostics (-Wdeprecated-declarations)
  */

+ 16 - 0
src/util/openmp_runtime_support.h

@@ -264,6 +264,22 @@ LIST_TYPE(starpu_omp_thread,
 	struct _starpu_worker *worker;
 )
 
+struct _starpu_omp_lock_internal
+{
+	struct _starpu_spinlock lock;
+	struct starpu_omp_condition cond;
+	unsigned state;
+};
+
+struct _starpu_omp_nest_lock_internal
+{
+	struct _starpu_spinlock lock;
+	struct starpu_omp_condition cond;
+	unsigned state;
+	struct starpu_omp_task *owner_task;
+	unsigned nesting;
+};
+
 struct starpu_omp_loop
 {
 	int id;

+ 0 - 61
src/util/openmp_runtime_support_omp_api.c

@@ -261,67 +261,6 @@ int starpu_omp_is_initial_device(void)
 	return device == _starpu_omp_global_state->initial_device;
 }
 
-
-void starpu_omp_init_lock (starpu_omp_lock_t *lock)
-{
-	(void) lock;
-	__not_implemented__;
-}
-
-void starpu_omp_destroy_lock (starpu_omp_lock_t *lock)
-{
-	(void) lock;
-	__not_implemented__;
-}
-
-void starpu_omp_set_lock (starpu_omp_lock_t *lock)
-{
-	(void) lock;
-	__not_implemented__;
-}
-
-void starpu_omp_unset_lock (starpu_omp_lock_t *lock)
-{
-	(void) lock;
-	__not_implemented__;
-}
-
-int starpu_omp_test_lock (starpu_omp_lock_t *lock)
-{
-	(void) lock;
-	__not_implemented__;
-}
-
-void starpu_omp_init_nest_lock (starpu_omp_nest_lock_t *lock)
-{
-	(void) lock;
-	__not_implemented__;
-}
-
-void starpu_omp_destroy_nest_lock (starpu_omp_nest_lock_t *lock)
-{
-	(void) lock;
-	__not_implemented__;
-}
-
-void starpu_omp_set_nest_lock (starpu_omp_nest_lock_t *lock)
-{
-	(void) lock;
-	__not_implemented__;
-}
-
-void starpu_omp_unset_nest_lock (starpu_omp_nest_lock_t *lock)
-{
-	(void) lock;
-	__not_implemented__;
-}
-
-int starpu_omp_test_nest_lock (starpu_omp_nest_lock_t *lock)
-{
-	(void) lock;
-	__not_implemented__;
-}
-
 double starpu_omp_get_wtime (void)
 {
 	return starpu_timing_now() - _starpu_omp_clock_ref;

+ 8 - 0
tests/Makefile.am

@@ -237,6 +237,8 @@ noinst_PROGRAMS =				\
 	openmp/parallel_critical_inline_01	\
 	openmp/parallel_critical_named_01	\
 	openmp/parallel_critical_named_inline_01\
+	openmp/parallel_simple_lock_01		\
+	openmp/parallel_nested_lock_01		\
 	openmp/parallel_for_01			\
 	openmp/parallel_for_02			\
 	openmp/parallel_for_ordered_01		\
@@ -507,6 +509,12 @@ openmp_parallel_critical_named_01_SOURCES = 	\
 openmp_parallel_critical_named_inline_01_SOURCES = 	\
 	openmp/parallel_critical_named_inline_01.c
 
+openmp_parallel_simple_lock_01_SOURCES = 	\
+	openmp/parallel_simple_lock_01.c
+
+openmp_parallel_nested_lock_01_SOURCES = 	\
+	openmp/parallel_nested_lock_01.c
+
 openmp_parallel_for_01_SOURCES = 	\
 	openmp/parallel_for_01.c
 

+ 117 - 0
tests/openmp/parallel_nested_lock_01.c

@@ -0,0 +1,117 @@
+/* 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();
+}
+
+starpu_omp_nest_lock_t omp_nest_lock;
+
+void locked_func_n2(void)
+{
+	const int worker_id = starpu_worker_get_id();
+	const pthread_t tid = pthread_self();
+	printf("[tid %p] task thread = %d -- locked function n2\n", (void *)tid, worker_id);
+}
+void locked_func_n1(void)
+{
+	const int worker_id = starpu_worker_get_id();
+	const pthread_t tid = pthread_self();
+	printf("[tid %p] task thread = %d -- locked function n1 -->\n", (void *)tid, worker_id);
+	starpu_omp_set_nest_lock(&omp_nest_lock);
+	locked_func_n2();
+	starpu_omp_unset_nest_lock(&omp_nest_lock);
+	printf("[tid %p] task thread = %d -- locked function n1 <--\n", (void *)tid, worker_id);
+}
+
+void master_g1(void *arg)
+{
+	starpu_omp_init_nest_lock(&omp_nest_lock);
+}
+
+void master_g2(void *arg)
+{
+	starpu_omp_destroy_nest_lock(&omp_nest_lock);
+}
+
+void parallel_region_f(void *buffers[], void *args)
+{
+	const int worker_id = starpu_worker_get_id();
+	const pthread_t tid = pthread_self();
+	(void) buffers;
+	(void) args;
+	printf("[tid %p] task thread = %d -- parallel -->\n", (void *)tid, worker_id);
+	starpu_omp_master(master_g1, NULL);
+	starpu_omp_barrier();
+
+	starpu_omp_set_nest_lock(&omp_nest_lock);
+	locked_func_n1();
+	starpu_omp_unset_nest_lock(&omp_nest_lock);
+
+	starpu_omp_set_nest_lock(&omp_nest_lock);
+	locked_func_n1();
+	starpu_omp_unset_nest_lock(&omp_nest_lock);
+
+	starpu_omp_set_nest_lock(&omp_nest_lock);
+	locked_func_n1();
+	starpu_omp_unset_nest_lock(&omp_nest_lock);
+
+	starpu_omp_set_nest_lock(&omp_nest_lock);
+	locked_func_n1();
+	starpu_omp_unset_nest_lock(&omp_nest_lock);
+
+	starpu_omp_barrier();
+	starpu_omp_master(master_g2, NULL);
+	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();
+	printf("<main>\n");
+	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);
+	printf("<main>\n");
+	starpu_omp_parallel_region(&attr);
+	printf("<main>\n");
+	return 0;
+}
+#endif

+ 107 - 0
tests/openmp/parallel_simple_lock_01.c

@@ -0,0 +1,107 @@
+/* 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();
+}
+
+starpu_omp_lock_t omp_lock;
+
+void locked_func(void)
+{
+	const int worker_id = starpu_worker_get_id();
+	const pthread_t tid = pthread_self();
+	printf("[tid %p] task thread = %d -- locked function\n", (void *)tid, worker_id);
+}
+
+void master_g1(void *arg)
+{
+	starpu_omp_init_lock(&omp_lock);
+}
+
+void master_g2(void *arg)
+{
+	starpu_omp_destroy_lock(&omp_lock);
+}
+
+void parallel_region_f(void *buffers[], void *args)
+{
+	const int worker_id = starpu_worker_get_id();
+	const pthread_t tid = pthread_self();
+	(void) buffers;
+	(void) args;
+	printf("[tid %p] task thread = %d -- parallel -->\n", (void *)tid, worker_id);
+	starpu_omp_master(master_g1, NULL);
+	starpu_omp_barrier();
+
+	starpu_omp_set_lock(&omp_lock);
+	locked_func();
+	starpu_omp_unset_lock(&omp_lock);
+
+	starpu_omp_set_lock(&omp_lock);
+	locked_func();
+	starpu_omp_unset_lock(&omp_lock);
+
+	starpu_omp_set_lock(&omp_lock);
+	locked_func();
+	starpu_omp_unset_lock(&omp_lock);
+
+	starpu_omp_set_lock(&omp_lock);
+	locked_func();
+	starpu_omp_unset_lock(&omp_lock);
+
+	starpu_omp_barrier();
+	starpu_omp_master(master_g2, NULL);
+	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();
+	printf("<main>\n");
+	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);
+	printf("<main>\n");
+	starpu_omp_parallel_region(&attr);
+	printf("<main>\n");
+	return 0;
+}
+#endif