Hi!

While the standard talks about list form of nthreads-var everywhere, given
that omp_set_num_threads only affects the first element of the list,
only the first element is also used everywhere but during parallel creation
of new implicit tasks, I think this patch is equivalent to it.

Regtested on x86_64-linux, committed to gomp-3_1-branch.

2011-03-07  Jakub Jelinek  <ja...@redhat.com>

        * libgomp.h (gomp_nthreads_var_list, gomp_nthreads_var_list_len): New
        externs.
        * env.c (gomp_nthreads_var_list, gomp_nthreads_var_list_len): New
        variables.
        (parse_unsigned_long_list): New function.
        (initialize_env): Use it for OMP_NUM_THREADS.
        * team.c (gomp_team_start): Override new task's nthreads_var icv
        if list form OMP_NUM_THREADS has been used and it has value for
        the new nesting level.

--- libgomp/libgomp.h.jj        2011-02-24 14:11:10.000000000 +0100
+++ libgomp/libgomp.h   2011-03-07 15:57:44.000000000 +0100
@@ -226,6 +226,7 @@ extern gomp_mutex_t gomp_remaining_threa
 extern unsigned long gomp_max_active_levels_var;
 extern unsigned long long gomp_spin_count_var, gomp_throttled_spin_count_var;
 extern unsigned long gomp_available_cpus, gomp_managed_threads;
+extern unsigned long *gomp_nthreads_var_list, gomp_nthreads_var_list_len;
 
 enum gomp_task_kind
 {
--- libgomp/env.c.jj    2011-02-24 14:11:10.000000000 +0100
+++ libgomp/env.c       2011-03-07 16:14:03.000000000 +0100
@@ -67,6 +67,7 @@ gomp_mutex_t gomp_remaining_threads_lock
 #endif
 unsigned long gomp_available_cpus = 1, gomp_managed_threads = 1;
 unsigned long long gomp_spin_count_var, gomp_throttled_spin_count_var;
+unsigned long *gomp_nthreads_var_list, gomp_nthreads_var_list_len;
 
 /* Parse the OMP_SCHEDULE environment variable.  */
 
@@ -178,6 +179,95 @@ parse_unsigned_long (const char *name, u
   return false;
 }
 
+/* Parse an unsigned long list environment variable.  Return true if one was
+   present and it was successfully parsed.  */
+
+static bool
+parse_unsigned_long_list (const char *name, unsigned long *p1stvalue,
+                         unsigned long **pvalues,
+                         unsigned long *pnvalues)
+{
+  char *env, *end;
+  unsigned long value, *values = NULL;
+
+  env = getenv (name);
+  if (env == NULL)
+    return false;
+
+  while (isspace ((unsigned char) *env))
+    ++env;
+  if (*env == '\0')
+    goto invalid;
+
+  errno = 0;
+  value = strtoul (env, &end, 10);
+  if (errno || (long) value <= 0)
+    goto invalid;
+
+  while (isspace ((unsigned char) *end))
+    ++end;
+  if (*end != '\0')
+    {
+      if (*end == ',')
+       {
+         unsigned long nvalues = 0, nalloced = 0;
+
+         do
+           {
+             env = end + 1;
+             if (nvalues == nalloced)
+               {
+                 unsigned long *n;
+                 nalloced = nalloced ? nalloced * 2 : 16;
+                 n = realloc (values, nalloced * sizeof (unsigned long));
+                 if (n == NULL)
+                   {
+                     free (values);
+                     gomp_error ("Out of memory while trying to parse"
+                                 " environment variable %s", name);
+                     return false;
+                   }
+                 values = n;
+                 if (nvalues == 0)
+                   values[nvalues++] = value;
+               }
+
+             while (isspace ((unsigned char) *env))
+               ++env;
+             if (*env == '\0')
+               goto invalid;
+
+             errno = 0;
+             value = strtoul (env, &end, 10);
+             if (errno || (long) value <= 0)
+               goto invalid;
+
+             values[nvalues++] = value;
+             while (isspace ((unsigned char) *end))
+               ++end;
+             if (*end == '\0')
+               break;
+             if (*end != ',')
+               goto invalid;
+           }
+         while (1);
+         *p1stvalue = values[0];
+         *pvalues = values;
+         *pnvalues = nvalues;
+         return true;
+       }
+      goto invalid;
+    }
+
+  *p1stvalue = value;
+  return true;
+
+ invalid:
+  free (values);
+  gomp_error ("Invalid value for environment variable %s", name);
+  return false;
+}
+
 /* Parse the OMP_STACKSIZE environment varible.  Return true if one was
    present and it was successfully parsed.  */
 
@@ -492,8 +582,10 @@ initialize_env (void)
 #endif
   gomp_init_num_threads ();
   gomp_available_cpus = gomp_global_icv.nthreads_var;
-  if (!parse_unsigned_long ("OMP_NUM_THREADS", &gomp_global_icv.nthreads_var,
-                           false))
+  if (!parse_unsigned_long_list ("OMP_NUM_THREADS",
+                                &gomp_global_icv.nthreads_var,
+                                &gomp_nthreads_var_list,
+                                &gomp_nthreads_var_list_len))
     gomp_global_icv.nthreads_var = gomp_available_cpus;
   if (parse_affinity ())
     gomp_init_affinity ();
--- libgomp/team.c.jj   2011-02-24 14:11:10.000000000 +0100
+++ libgomp/team.c      2011-03-07 16:13:23.000000000 +0100
@@ -260,6 +260,7 @@ gomp_team_start (void (*fn) (void *), vo
   struct gomp_thread_pool *pool;
   unsigned i, n, old_threads_used = 0;
   pthread_attr_t thread_attr, *attr;
+  unsigned long nthreads_var;
 
   thr = gomp_thread ();
   nested = thr->ts.team != NULL;
@@ -289,7 +290,12 @@ gomp_team_start (void (*fn) (void *), vo
 #endif
   thr->ts.static_trip = 0;
   thr->task = &team->implicit_task[0];
+  nthreads_var = icv->nthreads_var;
+  if (__builtin_expect (gomp_nthreads_var_list != NULL, 0)
+      && thr->ts.level < gomp_nthreads_var_list_len)
+    nthreads_var = gomp_nthreads_var_list[thr->ts.level];
   gomp_init_task (thr->task, task, icv);
+  team->implicit_task[0].icv.nthreads_var = nthreads_var;
 
   if (nthreads == 1)
     return;
@@ -342,6 +348,7 @@ gomp_team_start (void (*fn) (void *), vo
          nthr->ts.static_trip = 0;
          nthr->task = &team->implicit_task[i];
          gomp_init_task (nthr->task, task, icv);
+         team->implicit_task[i].icv.nthreads_var = nthreads_var;
          nthr->fn = fn;
          nthr->data = data;
          team->ordered_release[i] = &nthr->release;
@@ -413,6 +420,7 @@ gomp_team_start (void (*fn) (void *), vo
       start_data->ts.static_trip = 0;
       start_data->task = &team->implicit_task[i];
       gomp_init_task (start_data->task, task, icv);
+      team->implicit_task[i].icv.nthreads_var = nthreads_var;
       start_data->thread_pool = pool;
       start_data->nested = nested;
 

        Jakub

Reply via email to