소스 검색

- add partial support for OpenMP environment parsing

Olivier Aumage 11 년 전
부모
커밋
0e987f4f1d
2개의 변경된 파일873개의 추가작업 그리고 19개의 파일을 삭제
  1. 811 19
      src/util/openmp_runtime_support.c
  2. 62 0
      src/util/openmp_runtime_support.h

+ 811 - 19
src/util/openmp_runtime_support.c

@@ -16,10 +16,15 @@
 
 #include <starpu.h>
 #include <util/openmp_runtime_support.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <strings.h>
 
 #ifdef STARPU_OPENMP
 #define __not_implemented__ do { fprintf (stderr, "omp lib function %s not implemented\n", __func__); abort(); } while (0)
 
+#define _STARPU_INITIAL_PLACES_LIST_SIZE      4
+#define _STARPU_INITIAL_PLACE_ITEMS_LIST_SIZE 4
 static double _starpu_omp_clock_ref = 0.0; /* clock reference for starpu_omp_get_wtick */
 
 static struct starpu_omp_global_icvs _global_icvs;
@@ -33,7 +38,7 @@ static struct starpu_omp_initial_icv_values _initial_icv_values =
 	.bind_var = NULL,
 	.stacksize_var = 0,
 	.wait_policy_var = 0,
-	.max_active_levels_var = 0,
+	.max_active_levels_var = STARPU_OMP_MAX_ACTIVE_LEVELS,
 	.active_levels_var = 0,
 	.levels_var = 0,
 	.place_partition_var = 0,
@@ -44,43 +49,830 @@ static struct starpu_omp_initial_icv_values _initial_icv_values =
 struct starpu_omp_global_icvs *starpu_omp_global_icvs = NULL;
 struct starpu_omp_initial_icv_values *starpu_omp_initial_icv_values = NULL;
 
+/* TODO: move to utils */
+static void remove_spaces(char *str)
+{
+	int i = 0;
+	int j = 0;
+
+	while (str[j] != '\0')
+	{
+		if (isspace(str[j]))
+		{
+			j++;
+			continue;
+		}
+		if (j > i)
+		{
+			str[i] = str[j];
+		}
+		i++;
+		j++;
+	}
+	if (j > i)
+	{
+		str[i] = str[j];
+	}
+}
+/* TODO: move to utils */
+static int strings_cmp(const char *strings[], const char *str)
+{
+	int mode = 0;
+	while (strings[mode])
+	{
+		if (strcasecmp(str, strings[mode]) == 0)
+			break;
+		mode++;
+	}
+	if (strings[mode] == NULL)
+		return -1;
+	return mode;
+}
+/* TODO: move to utils */
+static int stringsn_cmp(const char *strings[], const char *str, size_t n)
+{
+	int mode = 0;
+	while (strings[mode])
+	{
+		if (strncasecmp(str, strings[mode], n) == 0)
+			break;
+		mode++;
+	}
+	if (strings[mode] == NULL)
+		return -1;
+	return mode;
+}
+
+/* TODO: move to utils */
+static void read_boolean_var(const char *var, int *dest)
+{
+	const char *env = getenv(var);
+	if (env)
+	{
+		char *str = strdup(env);
+		if (str == NULL)
+			_STARPU_ERROR("memory allocation failed\n");
+		remove_spaces(str);
+		if (str[0] == '\0')
+		{
+			free(str);
+			return;
+		}
+		static const char *strings[] = { "false", "true", NULL };
+		int mode = strings_cmp(strings, str);
+		if (mode < 0)
+			_STARPU_ERROR("parse error in variable %s\n", var);
+		*dest = mode;
+		free(str);
+	}
+}
+
+/* TODO: move to utils */
 static void read_int_var(const char *var, int *dest)
 {
 	const char *env = getenv(var);
-	if (env) {
-		int v = (int)strtol(env, NULL, 16);
-		if (errno != 0) {
-			fprintf(stderr, "Warning: could not parse environment variable %s, strtol failed with error %s\n", var, strerror(errno));
-		} else {
-			*dest = v;
+	if (env)
+	{
+		char *str = strdup(env);
+		if (str == NULL)
+			_STARPU_ERROR("memory allocation failed\n");
+		remove_spaces(str);
+		if (str[0] == '\0')
+		{
+			free(str);
+			return;
+		}
+		int v = (int)strtol(str, NULL, 10);
+		if (errno != 0)
+			_STARPU_ERROR("could not parse environment variable %s, strtol failed with error %s\n", var, strerror(errno));
+		*dest = v;
+		free(str);
+	}
+}
+
+static void read_size_var(const char *var, int *dest)
+{
+	const char *env = getenv(var);
+	if (env)
+	{
+		char *str = strdup(env);
+		if (str == NULL)
+			_STARPU_ERROR("memory allocation failed\n");
+		remove_spaces(str);
+		if (str[0] == '\0')
+		{
+			free(str);
+			return;
+		}
+		char *endptr = NULL;
+		int mult = 1024;
+		int v = (int)strtol(str, &endptr, 10);
+		if (errno != 0)
+			_STARPU_ERROR("could not parse environment variable %s, strtol failed with error %s\n", var, strerror(errno));
+		if (*endptr != '\0')
+		{
+			switch (*endptr)
+			{
+				case 'b':
+				case 'B': mult = 1; break;
+				case 'k':
+				case 'K': mult = 1024; break;
+				case 'm':
+				case 'M': mult = 1024*1024; break;
+				case 'g':
+				case 'G': mult = 1024*1024*1024; break;
+			default:
+				_STARPU_ERROR("could not parse environment variable %s size suffix invalid\n", var);
+			}
+		}
+		*dest = v*mult;
+		free(str);
+	}
+}
+
+static void read_sched_var(const char *var, int *dest, int *dest_chunk)
+{
+	const char *env = getenv(var);
+	if (env)
+	{
+		char *str = strdup(env);
+		if (str == NULL)
+			_STARPU_ERROR("memory allocation failed\n");
+		remove_spaces(str);
+		if (str[0] == '\0')
+		{
+			free(str);
+			return;
+		}
+		static const char *strings[] = { "static", "dynamic", "guided", "auto", NULL };
+		int mode = strings_cmp(strings, str);
+		if (mode < 0)
+			_STARPU_ERROR("parse error in variable %s\n", var);
+		*dest = mode;
+		int offset = strlen(strings[mode]);
+		if (str[offset] == ',')
+		{
+			offset++;
+			int v = (int)strtol(str+offset, NULL, 10);
+			if (errno != 0)
+				_STARPU_ERROR("could not parse environment variable %s, strtol failed with error %s\n", var, strerror(errno));
+			*dest_chunk = v;
+		}
+		else
+		{
+			*dest_chunk = 1;
+		}
+		free(str);
+	}
+}
+
+static void read_wait_policy_var(const char *var, int *dest)
+{
+	const char *env = getenv(var);
+	if (env)
+	{
+		char *str = strdup(env);
+		if (str == NULL)
+			_STARPU_ERROR("memory allocation failed\n");
+		remove_spaces(str);
+		if (str[0] == '\0')
+		{
+			free(str);
+			return;
+		}
+		static const char *strings[] = { "passive", "active", NULL };
+		int mode = strings_cmp(strings, str);
+		if (mode < 0)
+			_STARPU_ERROR("parse error in variable %s\n", var);
+		*dest = mode;
+		free(str);
+	}
+}
+
+static void read_display_env_var(const char *var, int *dest)
+{
+	const char *env = getenv(var);
+	if (env)
+	{
+		char *str = strdup(env);
+		if (str == NULL)
+			_STARPU_ERROR("memory allocation failed\n");
+		remove_spaces(str);
+		if (str[0] == '\0')
+		{
+			free(str);
+			return;
 		}
+		static const char *strings[] = { "false", "true", "verbose", NULL };
+		int mode = strings_cmp(strings, str);
+		if (mode < 0)
+			_STARPU_ERROR("parse error in variable %s\n", var);
+		*dest = mode;
+		free(str);
 	}
 }
 
+static int convert_bind_mode(const char *str, size_t n)
+{
+	static const char *strings[] = { "false", "true", "master", "close", "spread", NULL };
+	int mode = stringsn_cmp(strings, str, n);
+	if (mode < 0)
+		_STARPU_ERROR("proc_bind list parse error\n");
+	return mode;
+}
+
+static void convert_bind_string(const char *_str, int *bind_list, const int max_levels)
+{
+	char *str = strdup(_str);
+	if (str == NULL)
+		_STARPU_ERROR("memory allocation failed\n");
+	remove_spaces(str);
+	if (str[0] == '\0')
+	{
+		free(str);
+		return;
+	}
+	enum { state_split, state_read };
+	int level = 0;
+	int i = 0;
+	int state = state_read;
+	while (1)
+	{
+		if (state == state_split)
+		{
+			if (str[i] == '\0')
+				break;
+			if (str[i] != ',')
+				_STARPU_ERROR("proc_bind list parse error\n");
+			i++;
+			state = state_read;
+		}
+		else if (state == state_read)
+		{
+			int n = 0;
+			while (isalpha(str[i+n]))
+				n++;
+			if (n == 0)
+				_STARPU_ERROR("proc_bind list parse error\n");
+			int mode = convert_bind_mode(str+i,n);
+			STARPU_ASSERT(mode >= starpu_omp_bind_false && mode <= starpu_omp_bind_spread);
+			bind_list[level] = mode;
+			level++;
+			if (level == max_levels)
+				break;
+			i += n;
+			state = state_split;
+		}
+		else
+			_STARPU_ERROR("invalid state in parsing proc_bind list\n");
+	}
+	free(str);
+}
+
+static void convert_num_threads_string(const char *_str, int *num_threads_list, const int max_levels)
+{
+	char *str = strdup(_str);
+	if (str == NULL)
+		_STARPU_ERROR("memory allocation failed\n");
+	remove_spaces(str);
+	if (str[0] == '\0')
+	{
+		free(str);
+		return;
+	}
+	enum { state_split, state_read };
+	int level = 0;
+	int i = 0;
+	int state = state_read;
+	while (1)
+	{
+		/* split a comma separated list of numerical items */
+		if (state == state_split)
+		{
+			if (str[i] == '\0')
+				break;
+			if (str[i] != ',')
+				_STARPU_ERROR("num_threads list parse error\n");
+			i++;
+			state = state_read;
+		}
+		/* read a numerical item */
+		else if (state == state_read)
+		{
+			char *endptr = NULL;
+			int num_threads = (int)strtol(str+i, &endptr, 10);
+			if (errno != 0)
+				_STARPU_ERROR("num_threads list parse error, strtol failed with error %s\n", strerror(errno));
+			if (num_threads < 1)
+				_STARPU_ERROR("num_threads list invalid value\n");
+			num_threads_list[level] = num_threads;
+			level++;
+			if (level == max_levels)
+				break;
+			i++;
+			state = state_split;
+		}
+		else
+			_STARPU_ERROR("invalid state in parsing num_threads list\n");
+	}
+	free(str);
+}
+
+static int convert_place_name(const char *str, size_t n)
+{
+	static const char *strings[] = { "threads", "cores", "sockets", NULL };
+	int mode = stringsn_cmp(strings, str, n);
+	if (mode < 0)
+		_STARPU_ERROR("place abstract name parse error\n");
+	return mode+1; /* 0 is for undefined abstract name */
+}
+
+/* Note: this function modifies the string str */
+static void read_a_place_name(char *str, struct starpu_omp_place *places)
+{
+	int i = 0;
+	/* detect exclusion of abstract name expressed as '!' prefix */
+	if (str[i] == '!')
+	{
+		places->abstract_excluded = 1;
+		i++;
+	}
+	else
+	{
+		places->abstract_excluded = 0;
+	}
+	/* detect length value for abstract name expressed as '(length)' suffix) */
+	char *begin_length_spec = strchr(str+i,'(');
+	if (begin_length_spec != NULL)
+	{
+		char *end_length_spec = strrchr(begin_length_spec+1, ')');
+		if (end_length_spec == NULL || end_length_spec <= begin_length_spec+1)
+			_STARPU_ERROR("parse error in places list\n");
+		*begin_length_spec = '\0';
+		*end_length_spec = '\0';
+		int v = (int)strtol(begin_length_spec+1, NULL, 10);
+		if (errno != 0)
+			_STARPU_ERROR("parse error in places list\n");
+		places->abstract_length = v;
+	}
+	else
+	{
+		places->abstract_length = 1;
+	}
+	/* convert abstract place name string to corresponding value */
+	{
+		int mode = convert_place_name(str+i, strlen(str+i));
+		STARPU_ASSERT(mode >= starpu_omp_place_threads && mode <= starpu_omp_place_sockets);
+		places->abstract_name = mode;
+		places->numeric_places = NULL;
+		places->nb_numeric_places = 0;
+	}
+}
+
+static void read_a_places_list(const char *str, struct starpu_omp_place *places)
+{
+	if (str[0] == '\0')
+	{
+		places->numeric_places = NULL;
+		places->nb_numeric_places = 0;
+		places->abstract_name = starpu_omp_place_undefined;
+		return;
+	}
+	enum { state_split,
+		state_read_brace_prefix,
+		state_read_opening_brace,
+		state_read_numeric_prefix,
+		state_read_numeric,
+		state_split_numeric,
+		state_read_closing_brace,
+		state_read_brace_suffix,
+	};
+	struct starpu_omp_numeric_place *places_list = NULL;
+	int places_list_size = 0;
+	int nb_places = 0;
+	int *included_items_list = NULL;
+	int included_items_list_size = 0;
+	int nb_included_items = 0;
+	int *excluded_items_list = NULL;
+	int excluded_items_list_size = 0;
+	int nb_excluded_items = 0;
+	int exclude_place_flag = 0;
+	int exclude_item_flag = 0;
+	int i = 0;
+	int state = state_read_brace_prefix;
+	while (1)
+	{
+		switch (state)
+		{
+			/* split a comma separated list of numerical places */
+			case state_split:
+				if (str[i] == '\0')
+				{
+					goto eol;
+				}
+				else if (str[i] != ',')
+					_STARPU_ERROR("parse error in places list\n");
+				i++;
+				state = state_read_brace_prefix;
+				break;
+			/* read optional exclude flag '!' for numerical place */
+			case state_read_brace_prefix:
+				exclude_place_flag = 0;
+				if (str[i] == '!')
+				{
+					exclude_place_flag = 1;
+					i++;
+				}
+				state = state_read_opening_brace;
+				break;
+			/* read place opening brace */
+			case state_read_opening_brace:
+				if (str[i] != '{')
+					_STARPU_ERROR("parse error in places list\n");
+				i++;
+				state = state_read_numeric_prefix;
+				break;
+			/* read optional exclude flag '!' for numerical item */
+			case state_read_numeric_prefix:
+				exclude_item_flag = 0;
+				if (str[i] == '!')
+				{
+					exclude_item_flag = 1;
+					i++;
+				}
+				state = state_read_numeric;
+				break;
+			/* read numerical item */
+			case state_read_numeric:
+				{
+					char *endptr = NULL;
+					int v = (int)strtol(str+i, &endptr, 10);
+					if (errno != 0)
+						_STARPU_ERROR("parse error in places list, strtol failed with error %s\n", strerror(errno));
+					if (exclude_item_flag)
+					{
+						if (excluded_items_list_size == 0)
+						{
+							excluded_items_list_size = _STARPU_INITIAL_PLACE_ITEMS_LIST_SIZE;
+							excluded_items_list = malloc(excluded_items_list_size * sizeof(int));
+							if (excluded_items_list == NULL)
+								_STARPU_ERROR("memory allocation failed");
+						}
+						else if (nb_excluded_items == excluded_items_list_size)
+						{
+							excluded_items_list_size *= 2;
+							excluded_items_list = realloc(excluded_items_list, excluded_items_list_size * sizeof(int));
+							if (excluded_items_list == NULL)
+								_STARPU_ERROR("memory allocation failed");
+						}
+						excluded_items_list[nb_excluded_items] = v;
+						nb_excluded_items++;
+					}
+					else
+					{
+						if (included_items_list_size == 0)
+						{
+							included_items_list_size = _STARPU_INITIAL_PLACE_ITEMS_LIST_SIZE;
+							included_items_list = malloc(included_items_list_size * sizeof(int));
+							if (included_items_list == NULL)
+								_STARPU_ERROR("memory allocation failed");
+						}
+						else if (nb_included_items == included_items_list_size)
+						{
+							included_items_list_size *= 2;
+							included_items_list = realloc(included_items_list, included_items_list_size * sizeof(int));
+							if (included_items_list == NULL)
+								_STARPU_ERROR("memory allocation failed");
+						}
+						included_items_list[nb_included_items] = v;
+						nb_included_items++;
+					}
+					exclude_item_flag = 0;
+					i = endptr - str;
+					state = state_split_numeric;
+				}
+				break;
+			/* read comma separated or colon separated numerical item list */
+			case state_split_numeric:
+				if (str[i] == ':')
+					/* length and stride colon separated arguments not supported for now */
+					_STARPU_ERROR("colon support unimplemented in numeric place list");
+				if (str[i] == ',')
+				{
+					i++;
+					state = state_read_numeric_prefix;
+				}
+				else
+				{
+					state = state_read_closing_brace;
+				}
+				break;
+			/* read end of numerical item list */
+			case state_read_closing_brace:
+				if (str[i] != '}')
+					_STARPU_ERROR("parse error in places list\n");
+				if (places_list_size == 0)
+				{
+					places_list_size = _STARPU_INITIAL_PLACES_LIST_SIZE;
+					places_list = malloc(places_list_size * sizeof(*places_list));
+					if (places_list == NULL)
+						_STARPU_ERROR("memory allocation failed");
+				}
+				else if (nb_places == places_list_size)
+				{
+					places_list_size *= 2;
+					places_list = realloc(places_list, places_list_size * sizeof(*places_list));
+					if (places_list == NULL)
+						_STARPU_ERROR("memory allocation failed");
+				}
+				places_list[nb_places].excluded_place = exclude_place_flag;
+				places_list[nb_places].included_numeric_items = included_items_list;
+				places_list[nb_places].nb_included_numeric_items = nb_included_items;
+				places_list[nb_places].excluded_numeric_items = excluded_items_list;
+				places_list[nb_places].nb_excluded_numeric_items = nb_excluded_items;
+				nb_places++;
+				exclude_place_flag = 0;
+				included_items_list = NULL;
+				included_items_list_size = 0;
+				nb_included_items = 0;
+				excluded_items_list = NULL;
+				excluded_items_list_size = 0;
+				nb_excluded_items = 0;
+				i++;
+				state = state_read_brace_suffix;
+				break;
+			/* read optional place colon separated suffix */
+			case state_read_brace_suffix:
+				if (str[i] == ':')
+					/* length and stride colon separated arguments not supported for now */
+					_STARPU_ERROR("colon support unimplemented in numeric place list");
+				state = state_split;
+				break;
+			default:
+				_STARPU_ERROR("invalid state in parsing places list\n");
+		}
+	}
+
+eol:
+	places->numeric_places = places_list;
+	places->nb_numeric_places = nb_places;
+	places->abstract_name = starpu_omp_place_numerical;
+}
+
+static void convert_places_string(const char *_str, struct starpu_omp_place *places)
+{
+	char *str = strdup(_str);
+	if (str == NULL)
+		_STARPU_ERROR("memory allocation failed\n");
+	remove_spaces(str);
+	if (str[0] != '\0')
+	{
+		/* check whether this is the start of an abstract name */
+		if (isalpha(str[0]) || (str[0] == '!' && isalpha(str[1])))
+		{
+			read_a_place_name(str, places);
+		}
+		/* else the string must contain a list of braces */
+		else
+		{
+			read_a_places_list(str, places);
+		}
+	}
+	free(str);
+}
+
 /*
  * Entry point to be called by the OpenMP runtime constructor
  */
 int starpu_omp_init(void)
 {
 	int ret;
-
-	read_int_var("OMP_DYNAMIC", &_initial_icv_values.dyn_var);
-	read_int_var("OMP_NESTED", &_initial_icv_values.nest_var);
-	/* TODO: OMP_NUM_THREADS */
-	read_int_var("OMP_SCHEDULE", &_initial_icv_values.run_sched_var);
-	/* TODO: OMP_PROC_BIND */
-	read_int_var("OMP_STACKSIZE", &_initial_icv_values.stacksize_var);
-	read_int_var("OMP_WAIT_POLICY", &_initial_icv_values.wait_policy_var);
+	int display_env = 0;
+	read_boolean_var("OMP_DYNAMIC", &_initial_icv_values.dyn_var);
+	read_boolean_var("OMP_NESTED", &_initial_icv_values.nest_var);
+	read_sched_var("OMP_SCHEDULE", &_initial_icv_values.run_sched_var, &_initial_icv_values.run_sched_chunk_var);
+	read_size_var("OMP_STACKSIZE", &_initial_icv_values.stacksize_var);
+	read_wait_policy_var("OMP_WAIT_POLICY", &_initial_icv_values.wait_policy_var);
 	read_int_var("OMP_THREAD_LIMIT", &_initial_icv_values.thread_limit_var);
 	read_int_var("OMP_MAX_ACTIVE_LEVELS", &_initial_icv_values.max_active_levels_var);
-	read_int_var("OMP_PLACES", &_initial_icv_values.place_partition_var);
-	read_int_var("OMP_CANCELLATION", &_initial_icv_values.cancel_var);
+	read_boolean_var("OMP_CANCELLATION", &_initial_icv_values.cancel_var);
 	read_int_var("OMP_DEFAULT_DEVICE", &_initial_icv_values.default_device_var);
 	starpu_omp_initial_icv_values = &_initial_icv_values;
+	read_display_env_var("OMP_DISPLAY_ENV", &display_env);
+
+	const int max_levels = _initial_icv_values.max_active_levels_var;
+
+	/* read OMP_PROC_BIND */
+	{
+		int *bind_list = malloc(max_levels * sizeof(*bind_list));
+		if (bind_list == NULL)
+			_STARPU_ERROR("memory allocation failed\n");
+		int level;
+		for (level = 0;level < max_levels;level++)
+		{
+			/* TODO: check what should be used as default value */
+			bind_list[level] = starpu_omp_bind_true;
+		}
+		const char *env = getenv("OMP_PROC_BIND");
+		if (env)
+		{
+			convert_bind_string(env, bind_list, max_levels);
+		}
+		_initial_icv_values.bind_var = bind_list;
+	}
+
+	/* read OMP_NUM_THREADS */
+	{
+		int *num_threads_list = malloc(max_levels * sizeof(*num_threads_list));
+		if (num_threads_list == NULL)
+			_STARPU_ERROR("memory allocation failed\n");
+		int level;
+		for (level = 0;level < max_levels;level++)
+		{
+			/* TODO: check what should be used as default value */
+			num_threads_list[level] = 0;
+		}
+		const char *env = getenv("OMP_NUM_THREADS");
+		if (env)
+		{
+			convert_num_threads_string(env, num_threads_list, max_levels);
+		}
+		_initial_icv_values.nthreads_var = num_threads_list;
+	}
+
+	/* read OMP_PLACES */
+	{
+		memset(&_initial_icv_values.places, 0, sizeof(_initial_icv_values.places));
+		_initial_icv_values.places.abstract_name = starpu_omp_place_undefined;
+		const char *env = getenv("OMP_PLACES");
+		if (env)
+		{
+			convert_places_string(env, &_initial_icv_values.places);
+		}
+	}
 
 	_global_icvs.cancel_var = starpu_omp_initial_icv_values->cancel_var;
 	starpu_omp_global_icvs = &_global_icvs;
 
+	if (display_env > 0)
+	{
+		printf("OPENMP DISPLAY ENVIRONMENT BEGIN\n");
+		printf("  _OPENMP='xxxxxx'\n");
+		printf("  [host] OMP_DYNAMIC='%s'\n", starpu_omp_initial_icv_values->dyn_var?"true":"false");
+		printf("  [host] OMP_NESTED='%s'\n", starpu_omp_initial_icv_values->nest_var?"true":"false");
+		printf("  [host] OMP_SCHEDULE='");
+		switch (starpu_omp_initial_icv_values->run_sched_var)
+		{
+			case starpu_omp_schedule_static:
+				printf("static, %d", starpu_omp_initial_icv_values->run_sched_chunk_var);
+				break;
+			case starpu_omp_schedule_dynamic:
+				printf("dynamic, %d", starpu_omp_initial_icv_values->run_sched_chunk_var);
+				break;
+			case starpu_omp_schedule_guided:
+				printf("guided, %d", starpu_omp_initial_icv_values->run_sched_chunk_var);
+				break;
+			case starpu_omp_schedule_auto:
+				printf("auto, %d", starpu_omp_initial_icv_values->run_sched_chunk_var);
+				break;
+			default:
+				printf("<unknown>");
+				break;
+		}
+		printf("'\n");
+				
+		printf("  [host] OMP_STACKSIZE='%d'\n", starpu_omp_initial_icv_values->stacksize_var);
+		printf("  [host] OMP_WAIT_POLICY='%s'\n", starpu_omp_initial_icv_values->wait_policy_var?"active":"passive");
+		printf("  [host] OMP_MAX_ACTIVE_LEVELS='%d'\n", starpu_omp_initial_icv_values->max_active_levels_var);
+		printf("  [host] OMP_CANCELLATION='%s'\n", starpu_omp_initial_icv_values->cancel_var?"true":"false");
+		printf("  [host] OMP_DEFAULT_DEVICE='%d'\n", starpu_omp_initial_icv_values->default_device_var);
+		printf("  [host] OMP_PROC_BIND='");
+		{
+			int level;
+			for (level = 0; level < starpu_omp_initial_icv_values->max_active_levels_var; level++)
+			{
+				if (level > 0)
+				{
+					printf(", ");
+				}
+				switch (starpu_omp_initial_icv_values->bind_var[level])
+				{
+					case starpu_omp_bind_false:
+						printf("false");
+						break;
+					case starpu_omp_bind_true:
+						printf("true");
+						break;
+					case starpu_omp_bind_master:
+						printf("master");
+						break;
+					case starpu_omp_bind_close:
+						printf("close");
+						break;
+					case starpu_omp_bind_spread:
+						printf("spread");
+						break;
+					default:
+						printf("<unknown>");
+						break;
+				}
+			}
+		}
+		printf("'\n");
+		printf("  [host] OMP_NUM_THREADS='");
+		{
+			int level;
+			for (level = 0; level < starpu_omp_initial_icv_values->max_active_levels_var; level++)
+			{
+				if (level > 0)
+				{
+					printf(", ");
+				}
+				printf("%d", starpu_omp_initial_icv_values->nthreads_var[level]);
+			}
+		}
+		printf("'\n");
+		printf("  [host] OMP_PLACES='");
+		{
+			struct starpu_omp_place *places = &starpu_omp_initial_icv_values->places;
+			if (places->nb_numeric_places > 0)
+			{
+				int p;
+				for (p = 0; p < places->nb_numeric_places; p++)
+				{
+					if (p > 0)
+					{
+						printf(",");
+					}
+					struct starpu_omp_numeric_place *np = &places->numeric_places[p];
+					if (np->excluded_place)
+					{
+						printf("!");
+					}
+					printf("{");
+					int i;
+					for (i = 0; i < np->nb_included_numeric_items; i++)
+					{
+						if (i > 0)
+						{
+							printf(",");
+						}
+						printf("%d", np->included_numeric_items[i]);
+					}
+					for (i = 0; i < np->nb_excluded_numeric_items; i++)
+					{
+						if (i > 0 || np->nb_included_numeric_items)
+						{
+							printf(",");
+						}
+						printf("!%d", np->excluded_numeric_items[i]);
+					}
+					printf("}");
+					/* TODO: print length/stride suffix */
+				}
+			}
+			else
+			{
+				if (places->abstract_excluded)
+				{
+					printf("!");
+				}
+				switch (places->abstract_name)
+				{
+					case starpu_omp_place_undefined:
+						printf("undefined");
+						break;
+					case starpu_omp_place_threads:
+						printf("threads");
+						break;
+					case starpu_omp_place_cores:
+						printf("cores");
+						break;
+					case starpu_omp_place_sockets:
+						printf("sockets");
+						break;
+					case starpu_omp_place_numerical:
+						printf("<numerical>");
+						break;
+					default:
+						printf("<unknown>");
+						break;
+				}
+				if (places->abstract_length)
+				{
+					printf("(%d)", places->abstract_length);
+				}
+			}
+		}
+		printf("'\n");
+
+		if (display_env > 1)
+		{
+			/* no vendor specific runtime variable */
+		}
+		printf("OPENMP DISPLAY ENVIRONMENT END\n");
+	}
+
 	ret = starpu_init(0);
 	if(ret < 0)
 		return ret;
@@ -94,6 +886,7 @@ int starpu_omp_init(void)
 void starpu_omp_shutdown(void)
 {
 	starpu_shutdown();
+	/* TODO: free ICV variables */
 }
 
 void starpu_omp_set_num_threads(int threads)
@@ -113,8 +906,7 @@ int starpu_omp_get_thread_num()
 	/* TODO: handle master thread case */
 	if (tid < 0)
 	{
-		fprintf(stderr, "starpu_omp_get_thread_num: no worker associated to this thread\n");
-		abort();
+		_STARPU_ERROR("starpu_omp_get_thread_num: no worker associated to this thread\n");
 	}
 	return tid;
 }

+ 62 - 0
src/util/openmp_runtime_support.h

@@ -21,6 +21,64 @@
 
 #ifdef STARPU_OPENMP
 
+/*
+ * Arbitrary limit on the number of nested parallel sections
+ */
+#define STARPU_OMP_MAX_ACTIVE_LEVELS 4
+
+/*
+ * Proc bind modes defined by the OpenMP spec
+ */
+enum starpu_omp_bind_mode
+{
+	starpu_omp_bind_false  = 0,
+	starpu_omp_bind_true   = 1,
+	starpu_omp_bind_master = 2,
+	starpu_omp_bind_close  = 3,
+	starpu_omp_bind_spread = 4
+};
+
+enum starpu_omp_schedule_mode
+{
+	starpu_omp_schedule_static  = 0,
+	starpu_omp_schedule_dynamic = 1,
+	starpu_omp_schedule_guided  = 2,
+	starpu_omp_schedule_auto    = 3
+};
+
+/*
+ * Possible abstract names for OpenMP places
+ */
+enum starpu_omp_place_name
+{
+	starpu_omp_place_undefined = 0,
+	starpu_omp_place_threads   = 1,
+	starpu_omp_place_cores     = 2,
+	starpu_omp_place_sockets   = 3,
+	starpu_omp_place_numerical = 4 /* place specified numerically */
+};
+
+struct starpu_omp_numeric_place
+{
+	int excluded_place;
+	int *included_numeric_items;
+	int nb_included_numeric_items;
+	int *excluded_numeric_items;
+	int nb_excluded_numeric_items;
+};
+
+/*
+ * OpenMP place for thread afinity, defined by the OpenMP spec
+ */
+struct starpu_omp_place
+{
+	int abstract_name;
+	int abstract_excluded;
+	int abstract_length;
+	struct starpu_omp_numeric_place *numeric_places;
+	int nb_numeric_places;
+};
+
 /* 
  * Internal Control Variables (ICVs) declared following
  * OpenMP 4.0.0 spec section 2.3.1
@@ -75,6 +133,7 @@ struct starpu_omp_initial_icv_values
 	int nest_var;
 	int *nthreads_var;
 	int run_sched_var;
+	int run_sched_chunk_var;
 	int def_sched_var;
 	int *bind_var;
 	int stacksize_var;
@@ -86,6 +145,9 @@ struct starpu_omp_initial_icv_values
 	int place_partition_var;
 	int cancel_var;
 	int default_device_var;
+
+	/* not a real ICV, but needed to store the contents of OMP_PLACES */
+	struct starpu_omp_place places;
 };
 
 extern struct starpu_omp_global_icvs *starpu_omp_global_icvs;