OSDN Git Service

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