OSDN Git Service

* gcc.dg/guality/inline-params.c: New testcase.
[pf3gnuchains/gcc-fork.git] / libgomp / env.c
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 "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
51 struct 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
59 unsigned short *gomp_cpu_affinity;
60 size_t gomp_cpu_affinity_len;
61 unsigned long gomp_max_active_levels_var = INT_MAX;
62 unsigned long gomp_thread_limit_var = ULONG_MAX;
63 unsigned long gomp_remaining_threads_count;
64 #ifndef HAVE_SYNC_BUILTINS
65 gomp_mutex_t gomp_remaining_threads_lock;
66 #endif
67 unsigned long gomp_available_cpus = 1, gomp_managed_threads = 1;
68 unsigned long long gomp_spin_count_var, gomp_throttled_spin_count_var;
69
70 /* Parse the OMP_SCHEDULE environment variable.  */
71
72 static void
73 parse_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 != 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
147 static bool
148 parse_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
183 static bool
184 parse_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
244 static bool
245 parse_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
317 static void
318 parse_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
349 static int
350 parse_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
384 static bool
385 parse_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
472 static void __attribute__((constructor))
473 initialize_env (void)
474 {
475   unsigned long stacksize;
476   int wait_policy;
477
478   /* Do a compile time check that mkomp_h.pl did good job.  */
479   omp_check_defines ();
480
481   parse_schedule ();
482   parse_boolean ("OMP_DYNAMIC", &gomp_global_icv.dyn_var);
483   parse_boolean ("OMP_NESTED", &gomp_global_icv.nest_var);
484   parse_unsigned_long ("OMP_MAX_ACTIVE_LEVELS", &gomp_max_active_levels_var);
485   parse_unsigned_long ("OMP_THREAD_LIMIT", &gomp_thread_limit_var);
486   if (gomp_thread_limit_var != ULONG_MAX)
487     gomp_remaining_threads_count = gomp_thread_limit_var - 1;
488 #ifndef HAVE_SYNC_BUILTINS
489   gomp_mutex_init (&gomp_remaining_threads_lock);
490 #endif
491   gomp_init_num_threads ();
492   gomp_available_cpus = gomp_global_icv.nthreads_var;
493   if (!parse_unsigned_long ("OMP_NUM_THREADS", &gomp_global_icv.nthreads_var))
494     gomp_global_icv.nthreads_var = gomp_available_cpus;
495   if (parse_affinity ())
496     gomp_init_affinity ();
497   wait_policy = parse_wait_policy ();
498   if (!parse_spincount ("GOMP_SPINCOUNT", &gomp_spin_count_var))
499     {
500       /* Using a rough estimation of 100000 spins per msec,
501          use 5 min blocking for OMP_WAIT_POLICY=active,
502          200 msec blocking when OMP_WAIT_POLICY is not specificed
503          and 0 when OMP_WAIT_POLICY=passive.
504          Depending on the CPU speed, this can be e.g. 5 times longer
505          or 5 times shorter.  */
506       if (wait_policy > 0)
507         gomp_spin_count_var = 30000000000LL;
508       else if (wait_policy < 0)
509         gomp_spin_count_var = 20000000LL;
510     }
511   /* gomp_throttled_spin_count_var is used when there are more libgomp
512      managed threads than available CPUs.  Use very short spinning.  */
513   if (wait_policy > 0)
514     gomp_throttled_spin_count_var = 1000LL;
515   else if (wait_policy < 0)
516     gomp_throttled_spin_count_var = 100LL;
517   if (gomp_throttled_spin_count_var > gomp_spin_count_var)
518     gomp_throttled_spin_count_var = gomp_spin_count_var;
519
520   /* Not strictly environment related, but ordering constructors is tricky.  */
521   pthread_attr_init (&gomp_thread_attr);
522   pthread_attr_setdetachstate (&gomp_thread_attr, PTHREAD_CREATE_DETACHED);
523
524   if (parse_stacksize ("OMP_STACKSIZE", &stacksize)
525       || parse_stacksize ("GOMP_STACKSIZE", &stacksize))
526     {
527       int err;
528
529       err = pthread_attr_setstacksize (&gomp_thread_attr, stacksize);
530
531 #ifdef PTHREAD_STACK_MIN
532       if (err == EINVAL)
533         {
534           if (stacksize < PTHREAD_STACK_MIN)
535             gomp_error ("Stack size less than minimum of %luk",
536                         PTHREAD_STACK_MIN / 1024ul
537                         + (PTHREAD_STACK_MIN % 1024 != 0));
538           else
539             gomp_error ("Stack size larger than system limit");
540         }
541       else
542 #endif
543       if (err != 0)
544         gomp_error ("Stack size change failed: %s", strerror (err));
545     }
546 }
547
548 \f
549 /* The public OpenMP API routines that access these variables.  */
550
551 void
552 omp_set_num_threads (int n)
553 {
554   struct gomp_task_icv *icv = gomp_icv (true);
555   icv->nthreads_var = (n > 0 ? n : 1);
556 }
557
558 void
559 omp_set_dynamic (int val)
560 {
561   struct gomp_task_icv *icv = gomp_icv (true);
562   icv->dyn_var = val;
563 }
564
565 int
566 omp_get_dynamic (void)
567 {
568   struct gomp_task_icv *icv = gomp_icv (false);
569   return icv->dyn_var;
570 }
571
572 void
573 omp_set_nested (int val)
574 {
575   struct gomp_task_icv *icv = gomp_icv (true);
576   icv->nest_var = val;
577 }
578
579 int
580 omp_get_nested (void)
581 {
582   struct gomp_task_icv *icv = gomp_icv (false);
583   return icv->nest_var;
584 }
585
586 void
587 omp_set_schedule (omp_sched_t kind, int modifier)
588 {
589   struct gomp_task_icv *icv = gomp_icv (true);
590   switch (kind)
591     {
592     case omp_sched_static:
593       if (modifier < 1)
594         modifier = 0;
595       icv->run_sched_modifier = modifier;
596       break;
597     case omp_sched_dynamic:
598     case omp_sched_guided:
599       if (modifier < 1)
600         modifier = 1;
601       icv->run_sched_modifier = modifier;
602       break;
603     case omp_sched_auto:
604       break;
605     default:
606       return;
607     }
608   icv->run_sched_var = kind;
609 }
610
611 void
612 omp_get_schedule (omp_sched_t *kind, int *modifier)
613 {
614   struct gomp_task_icv *icv = gomp_icv (false);
615   *kind = icv->run_sched_var;
616   *modifier = icv->run_sched_modifier;
617 }
618
619 int
620 omp_get_max_threads (void)
621 {
622   struct gomp_task_icv *icv = gomp_icv (false);
623   return icv->nthreads_var;
624 }
625
626 int
627 omp_get_thread_limit (void)
628 {
629   return gomp_thread_limit_var > INT_MAX ? INT_MAX : gomp_thread_limit_var;
630 }
631
632 void
633 omp_set_max_active_levels (int max_levels)
634 {
635   if (max_levels > 0)
636     gomp_max_active_levels_var = max_levels;
637 }
638
639 int
640 omp_get_max_active_levels (void)
641 {
642   return gomp_max_active_levels_var;
643 }
644
645 ialias (omp_set_dynamic)
646 ialias (omp_set_nested)
647 ialias (omp_set_num_threads)
648 ialias (omp_get_dynamic)
649 ialias (omp_get_nested)
650 ialias (omp_set_schedule)
651 ialias (omp_get_schedule)
652 ialias (omp_get_max_threads)
653 ialias (omp_get_thread_limit)
654 ialias (omp_set_max_active_levels)
655 ialias (omp_get_max_active_levels)