source: trunk/sys/libgomp/env.c @ 202

Last change on this file since 202 was 1, checked in by alain, 8 years ago

First import

File size: 14.4 KB
Line 
1/* Copyright (C) 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
2   Contributed by Richard Henderson <rth@redhat.com>.
3
4   This file is part of the GNU OpenMP Library (libgomp).
5
6   Libgomp is free software; you can redistribute it and/or modify it
7   under the terms of the GNU General Public License as published by
8   the Free Software Foundation; either version 3, or (at your option)
9   any later version.
10
11   Libgomp is distributed in the hope that it will be useful, but WITHOUT ANY
12   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13   FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
14   more details.
15
16   Under Section 7 of GPL version 3, you are granted additional
17   permissions described in the GCC Runtime Library Exception, version
18   3.1, as published by the Free Software Foundation.
19
20   You should have received a copy of the GNU General Public License and
21   a copy of the GCC Runtime Library Exception along with this program;
22   see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
23   <http://www.gnu.org/licenses/>.  */
24
25/* This file defines the OpenMP internal control variables, and arranges
26   for them to be initialized from environment variables at startup.  */
27
28#include <gomp/libgomp.h>
29//#include "libgomp_f.h"
30#include <ctype.h>
31#include <stdlib.h>
32#ifdef STRING_WITH_STRINGS
33# include <string.h>
34# include <strings.h>
35#else
36# ifdef HAVE_STRING_H
37#  include <string.h>
38# else
39#  ifdef HAVE_STRINGS_H
40#   include <strings.h>
41#  endif
42# endif
43#endif
44#include <limits.h>
45#include <errno.h>
46
47#ifndef HAVE_STRTOULL
48# define strtoull(ptr, eptr, base) strtoul (ptr, eptr, base)
49#endif
50
51struct gomp_task_icv gomp_global_icv = {
52  .nthreads_var = 1,
53  .run_sched_var = GFS_DYNAMIC,
54  .run_sched_modifier = 1,
55  .dyn_var = false,
56  .nest_var = false
57};
58
59unsigned short *gomp_cpu_affinity;
60size_t gomp_cpu_affinity_len;
61unsigned long gomp_max_active_levels_var = INT_MAX;
62unsigned long gomp_thread_limit_var = ULONG_MAX;
63unsigned long gomp_remaining_threads_count;
64#ifndef HAVE_SYNC_BUILTINS
65gomp_mutex_t gomp_remaining_threads_lock;
66#endif
67unsigned long gomp_available_cpus = 1, gomp_managed_threads = 1;
68unsigned long long gomp_spin_count_var, gomp_throttled_spin_count_var;
69
70/* Parse the OMP_SCHEDULE environment variable.  */
71
72static void
73parse_schedule (void)
74{
75  char *env, *end;
76  unsigned long value;
77
78  env = getenv ("OMP_SCHEDULE");
79  if (env == NULL)
80    return;
81
82  while (isspace ((unsigned char) *env))
83    ++env;
84  if (strncasecmp (env, "static", 6) == 0)
85    {
86      gomp_global_icv.run_sched_var = GFS_STATIC;
87      env += 6;
88    }
89  else if (strncasecmp (env, "dynamic", 7) == 0)
90    {
91      gomp_global_icv.run_sched_var = GFS_DYNAMIC;
92      env += 7;
93    }
94  else if (strncasecmp (env, "guided", 6) == 0)
95    {
96      gomp_global_icv.run_sched_var = GFS_GUIDED;
97      env += 6;
98    }
99  else if (strncasecmp (env, "auto", 4) == 0)
100    {
101      gomp_global_icv.run_sched_var = GFS_AUTO;
102      env += 4;
103    }
104  else
105    goto unknown;
106
107  while (isspace ((unsigned char) *env))
108    ++env;
109  if (*env == '\0')
110    return;
111  if (*env++ != ',')
112    goto unknown;
113  while (isspace ((unsigned char) *env))
114    ++env;
115  if (*env == '\0')
116    goto invalid;
117
118  errno = 0;
119  value = strtoul (env, &end, 10);
120  if (errno)
121    goto invalid;
122
123  while (isspace ((unsigned char) *end))
124    ++end;
125  if (*end != '\0')
126    goto invalid;
127
128  if ((int)value != (int)value)
129    goto invalid;
130
131  gomp_global_icv.run_sched_modifier = value;
132  return;
133
134 unknown:
135  gomp_error ("Unknown value for environment variable OMP_SCHEDULE");
136  return;
137
138 invalid:
139  gomp_error ("Invalid value for chunk size in "
140              "environment variable OMP_SCHEDULE");
141  return;
142}
143
144/* Parse an unsigned long environment variable.  Return true if one was
145   present and it was successfully parsed.  */
146
147static bool
148parse_unsigned_long (const char *name, unsigned long *pvalue)
149{
150  char *env, *end;
151  unsigned long value;
152
153  env = getenv (name);
154  if (env == NULL)
155    return false;
156
157  while (isspace ((unsigned char) *env))
158    ++env;
159  if (*env == '\0')
160    goto invalid;
161
162  errno = 0;
163  value = strtoul (env, &end, 10);
164  if (errno || (long) value <= 0)
165    goto invalid;
166
167  while (isspace ((unsigned char) *end))
168    ++end;
169  if (*end != '\0')
170    goto invalid;
171
172  *pvalue = value;
173  return true;
174
175 invalid:
176  gomp_error ("Invalid value for environment variable %s", name);
177  return false;
178}
179
180/* Parse the OMP_STACKSIZE environment varible.  Return true if one was
181   present and it was successfully parsed.  */
182
183static bool
184parse_stacksize (const char *name, unsigned long *pvalue)
185{
186  char *env, *end;
187  unsigned long value, shift = 10;
188
189  env = getenv (name);
190  if (env == NULL)
191    return false;
192
193  while (isspace ((unsigned char) *env))
194    ++env;
195  if (*env == '\0')
196    goto invalid;
197
198  errno = 0;
199  value = strtoul (env, &end, 10);
200  if (errno)
201    goto invalid;
202
203  while (isspace ((unsigned char) *end))
204    ++end;
205  if (*end != '\0')
206    {
207      switch (tolower ((unsigned char) *end))
208        {
209        case 'b':
210          shift = 0;
211          break;
212        case 'k':
213          break;
214        case 'm':
215          shift = 20;
216          break;
217        case 'g':
218          shift = 30;
219          break;
220        default:
221          goto invalid;
222        }
223      ++end;
224      while (isspace ((unsigned char) *end))
225        ++end;
226      if (*end != '\0')
227        goto invalid;
228    }
229
230  if (((value << shift) >> shift) != value)
231    goto invalid;
232
233  *pvalue = value << shift;
234  return true;
235
236 invalid:
237  gomp_error ("Invalid value for environment variable %s", name);
238  return false;
239}
240
241/* Parse the GOMP_SPINCOUNT environment varible.  Return true if one was
242   present and it was successfully parsed.  */
243
244static bool
245parse_spincount (const char *name, unsigned long long *pvalue)
246{
247  char *env, *end;
248  unsigned long long value, mult = 1;
249
250  env = getenv (name);
251  if (env == NULL)
252    return false;
253
254  while (isspace ((unsigned char) *env))
255    ++env;
256  if (*env == '\0')
257    goto invalid;
258
259  if (strncasecmp (env, "infinite", 8) == 0
260      || strncasecmp (env, "infinity", 8) == 0)
261    {
262      value = ~0ULL;
263      end = env + 8;
264      goto check_tail;
265    }
266
267  errno = 0;
268  value = strtoull (env, &end, 10);
269  if (errno)
270    goto invalid;
271
272  while (isspace ((unsigned char) *end))
273    ++end;
274  if (*end != '\0')
275    {
276      switch (tolower ((unsigned char) *end))
277        {
278        case 'k':
279          mult = 1000LL;
280          break;
281        case 'm':
282          mult = 1000LL * 1000LL;
283          break;
284        case 'g':
285          mult = 1000LL * 1000LL * 1000LL;
286          break;
287        case 't':
288          mult = 1000LL * 1000LL * 1000LL * 1000LL;
289          break;
290        default:
291          goto invalid;
292        }
293      ++end;
294     check_tail:
295      while (isspace ((unsigned char) *end))
296        ++end;
297      if (*end != '\0')
298        goto invalid;
299    }
300
301  if (value > ~0ULL / mult)
302    value = ~0ULL;
303  else
304    value *= mult;
305
306  *pvalue = value;
307  return true;
308
309 invalid:
310  gomp_error ("Invalid value for environment variable %s", name);
311  return false;
312}
313
314/* Parse a boolean value for environment variable NAME and store the
315   result in VALUE.  */
316
317static void
318parse_boolean (const char *name, bool *value)
319{
320  const char *env;
321
322  env = getenv (name);
323  if (env == NULL)
324    return;
325
326  while (isspace ((unsigned char) *env))
327    ++env;
328  if (strncasecmp (env, "true", 4) == 0)
329    {
330      *value = true;
331      env += 4;
332    }
333  else if (strncasecmp (env, "false", 5) == 0)
334    {
335      *value = false;
336      env += 5;
337    }
338  else
339    env = "X";
340  while (isspace ((unsigned char) *env))
341    ++env;
342  if (*env != '\0')
343    gomp_error ("Invalid value for environment variable %s", name);
344}
345
346/* Parse the OMP_WAIT_POLICY environment variable and store the
347   result in gomp_active_wait_policy.  */
348
349static int
350parse_wait_policy (void)
351{
352  const char *env;
353  int ret = -1;
354
355  env = getenv ("OMP_WAIT_POLICY");
356  if (env == NULL)
357    return -1;
358
359  while (isspace ((unsigned char) *env))
360    ++env;
361  if (strncasecmp (env, "active", 6) == 0)
362    {
363      ret = 1;
364      env += 6;
365    }
366  else if (strncasecmp (env, "passive", 7) == 0)
367    {
368      ret = 0;
369      env += 7;
370    }
371  else
372    env = "X";
373  while (isspace ((unsigned char) *env))
374    ++env;
375  if (*env == '\0')
376    return ret;
377  gomp_error ("Invalid value for environment variable OMP_WAIT_POLICY");
378  return -1;
379}
380
381/* Parse the GOMP_CPU_AFFINITY environment varible.  Return true if one was
382   present and it was successfully parsed.  */
383
384static bool
385parse_affinity (void)
386{
387  char *env, *end;
388  unsigned long cpu_beg, cpu_end, cpu_stride;
389  unsigned short *cpus = NULL;
390  size_t allocated = 0, used = 0, needed;
391
392  env = getenv ("GOMP_CPU_AFFINITY");
393  if (env == NULL)
394    return false;
395
396  do
397    {
398      while (*env == ' ' || *env == '\t')
399        env++;
400
401      cpu_beg = strtoul (env, &end, 0);
402      cpu_end = cpu_beg;
403      cpu_stride = 1;
404      if (env == end || cpu_beg >= 65536)
405        goto invalid;
406
407      env = end;
408      if (*env == '-')
409        {
410          cpu_end = strtoul (++env, &end, 0);
411          if (env == end || cpu_end >= 65536 || cpu_end < cpu_beg)
412            goto invalid;
413
414          env = end;
415          if (*env == ':')
416            {
417              cpu_stride = strtoul (++env, &end, 0);
418              if (env == end || cpu_stride == 0 || cpu_stride >= 65536)
419                goto invalid;
420
421              env = end;
422            }
423        }
424
425      needed = (cpu_end - cpu_beg) / cpu_stride + 1;
426      if (used + needed >= allocated)
427        {
428          unsigned short *new_cpus;
429
430          if (allocated < 64)
431            allocated = 64;
432          if (allocated > needed)
433            allocated <<= 1;
434          else
435            allocated += 2 * needed;
436          new_cpus = realloc (cpus, allocated * sizeof (unsigned short));
437          if (new_cpus == NULL)
438            {
439              free (cpus);
440              gomp_error ("not enough memory to store GOMP_CPU_AFFINITY list");
441              return false;
442            }
443
444          cpus = new_cpus;
445        }
446
447      while (needed--)
448        {
449          cpus[used++] = cpu_beg;
450          cpu_beg += cpu_stride;
451        }
452
453      while (*env == ' ' || *env == '\t')
454        env++;
455
456      if (*env == ',')
457        env++;
458      else if (*env == '\0')
459        break;
460    }
461  while (1);
462
463  gomp_cpu_affinity = cpus;
464  gomp_cpu_affinity_len = used;
465  return true;
466
467 invalid:
468  gomp_error ("Invalid value for enviroment variable GOMP_CPU_AFFINITY");
469  return false;
470}
471
472void initialize_env (void)
473{
474  unsigned long stacksize;
475  int wait_policy;
476
477  /* Do a compile time check that mkomp_h.pl did good job.  */
478  //omp_check_defines();
479
480  parse_schedule ();
481  parse_boolean ("OMP_DYNAMIC", (bool*)&gomp_global_icv.dyn_var);
482  parse_boolean ("OMP_NESTED", (bool*)&gomp_global_icv.nest_var);
483  parse_unsigned_long ("OMP_MAX_ACTIVE_LEVELS", &gomp_max_active_levels_var);
484  parse_unsigned_long ("OMP_THREAD_LIMIT", &gomp_thread_limit_var);
485  if (gomp_thread_limit_var != ULONG_MAX)
486    gomp_remaining_threads_count = gomp_thread_limit_var - 1;
487#ifndef HAVE_SYNC_BUILTINS
488  gomp_mutex_init (&gomp_remaining_threads_lock);
489#endif
490  gomp_init_num_threads ();
491  gomp_available_cpus = gomp_global_icv.nthreads_var;
492  if (!parse_unsigned_long ("OMP_NUM_THREADS", &gomp_global_icv.nthreads_var))
493    gomp_global_icv.nthreads_var = gomp_available_cpus;
494  if (parse_affinity ())
495    gomp_init_affinity ();
496  wait_policy = parse_wait_policy ();
497  if (!parse_spincount ("GOMP_SPINCOUNT", &gomp_spin_count_var))
498    {
499      /* Using a rough estimation of 100000 spins per msec,
500         use 5 min blocking for OMP_WAIT_POLICY=active,
501         200 msec blocking when OMP_WAIT_POLICY is not specificed
502         and 0 when OMP_WAIT_POLICY=passive.
503         Depending on the CPU speed, this can be e.g. 5 times longer
504         or 5 times shorter.  */
505      if (wait_policy > 0)
506        gomp_spin_count_var = 30000000000LL;
507      else if (wait_policy < 0)
508        gomp_spin_count_var = 20000000LL;
509    }
510  /* gomp_throttled_spin_count_var is used when there are more libgomp
511     managed threads than available CPUs.  Use very short spinning.  */
512  if (wait_policy > 0)
513    gomp_throttled_spin_count_var = 1000LL;
514  else if (wait_policy < 0)
515    gomp_throttled_spin_count_var = 100LL;
516  if (gomp_throttled_spin_count_var > gomp_spin_count_var)
517    gomp_throttled_spin_count_var = gomp_spin_count_var;
518
519  /* Not strictly environment related, but ordering constructors is tricky.  */
520  pthread_attr_init (&gomp_thread_attr);
521  pthread_attr_setdetachstate (&gomp_thread_attr, PTHREAD_CREATE_DETACHED);
522
523  if (parse_stacksize ("OMP_STACKSIZE", &stacksize)
524      || parse_stacksize ("GOMP_STACKSIZE", &stacksize))
525    {
526      int err;
527
528      err = pthread_attr_setstacksize (&gomp_thread_attr, stacksize);
529
530#ifdef PTHREAD_STACK_MIN
531      if (err == EINVAL)
532        {
533          if (stacksize < PTHREAD_STACK_MIN)
534            gomp_error ("Stack size less than minimum of %luk",
535                        PTHREAD_STACK_MIN / 1024ul
536                        + (PTHREAD_STACK_MIN % 1024 != 0));
537          else
538            gomp_error ("Stack size larger than system limit");
539        }
540      else
541#endif
542      if (err != 0)
543        gomp_error ("Stack size change failed: %s", strerror (err));
544    }
545}
546
547
548/* The public OpenMP API routines that access these variables.  */
549
550void
551omp_set_num_threads (int n)
552{
553  struct gomp_task_icv *icv = gomp_icv (true);
554  icv->nthreads_var = (n > 0 ? n : 1);
555}
556
557void
558omp_set_dynamic (int val)
559{
560  struct gomp_task_icv *icv = gomp_icv (true);
561  icv->dyn_var = val;
562}
563
564int
565omp_get_dynamic (void)
566{
567  struct gomp_task_icv *icv = gomp_icv (false);
568  return icv->dyn_var;
569}
570
571void
572omp_set_nested (int val)
573{
574  struct gomp_task_icv *icv = gomp_icv (true);
575  icv->nest_var = val;
576}
577
578int
579omp_get_nested (void)
580{
581  struct gomp_task_icv *icv = gomp_icv (false);
582  return icv->nest_var;
583}
584
585void
586omp_set_schedule (omp_sched_t kind, int modifier)
587{
588  struct gomp_task_icv *icv = gomp_icv (true);
589  switch (kind)
590    {
591    case omp_sched_static:
592      if (modifier < 1)
593        modifier = 0;
594      icv->run_sched_modifier = modifier;
595      break;
596    case omp_sched_dynamic:
597    case omp_sched_guided:
598      if (modifier < 1)
599        modifier = 1;
600      icv->run_sched_modifier = modifier;
601      break;
602    case omp_sched_auto:
603      break;
604    default:
605      return;
606    }
607  icv->run_sched_var = kind;
608}
609
610void
611omp_get_schedule (omp_sched_t *kind, int *modifier)
612{
613  struct gomp_task_icv *icv = gomp_icv (false);
614  *kind = icv->run_sched_var;
615  *modifier = icv->run_sched_modifier;
616}
617
618int
619omp_get_max_threads (void)
620{
621  struct gomp_task_icv *icv = gomp_icv (false);
622  return icv->nthreads_var;
623}
624
625int
626omp_get_thread_limit (void)
627{
628  return gomp_thread_limit_var > INT_MAX ? INT_MAX : gomp_thread_limit_var;
629}
630
631void
632omp_set_max_active_levels (int max_levels)
633{
634  if (max_levels > 0)
635    gomp_max_active_levels_var = max_levels;
636}
637
638int
639omp_get_max_active_levels (void)
640{
641  return gomp_max_active_levels_var;
642}
643
644ialias (omp_set_dynamic)
645ialias (omp_set_nested)
646ialias (omp_set_num_threads)
647ialias (omp_get_dynamic)
648ialias (omp_get_nested)
649ialias (omp_set_schedule)
650ialias (omp_get_schedule)
651ialias (omp_get_max_threads)
652ialias (omp_get_thread_limit)
653ialias (omp_set_max_active_levels)
654ialias (omp_get_max_active_levels)
Note: See TracBrowser for help on using the repository browser.