OSDN Git Service

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