* utils.c (create_subprog_decl): If this is for the 'main' entry
[official-gcc.git] / libgomp / env.c
blob022fb1bb0ad9a19c68ec1c6fa9a8f4ced2c66297
1 /* Copyright (C) 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
2 Contributed by Richard Henderson <rth@redhat.com>.
4 This file is part of the GNU OpenMP Library (libgomp).
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.
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.
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. */
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. */
28 /* This file defines the OpenMP internal control variables, and arranges
29 for them to be initialized from environment variables at startup. */
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>
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
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;
70 /* Parse the OMP_SCHEDULE environment variable. */
72 static void
73 parse_schedule (void)
75 char *env, *end;
76 unsigned long value;
78 env = getenv ("OMP_SCHEDULE");
79 if (env == NULL)
80 return;
82 while (isspace ((unsigned char) *env))
83 ++env;
84 if (strncasecmp (env, "static", 6) == 0)
86 gomp_global_icv.run_sched_var = GFS_STATIC;
87 env += 6;
89 else if (strncasecmp (env, "dynamic", 7) == 0)
91 gomp_global_icv.run_sched_var = GFS_DYNAMIC;
92 env += 7;
94 else if (strncasecmp (env, "guided", 6) == 0)
96 gomp_global_icv.run_sched_var = GFS_GUIDED;
97 env += 6;
99 else if (strncasecmp (env, "auto", 4) == 0)
101 gomp_global_icv.run_sched_var = GFS_AUTO;
102 env += 4;
104 else
105 goto unknown;
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;
118 errno = 0;
119 value = strtoul (env, &end, 10);
120 if (errno)
121 goto invalid;
123 while (isspace ((unsigned char) *end))
124 ++end;
125 if (*end != '\0')
126 goto invalid;
128 if ((int)value != value)
129 goto invalid;
131 gomp_global_icv.run_sched_modifier = value;
132 return;
134 unknown:
135 gomp_error ("Unknown value for environment variable OMP_SCHEDULE");
136 return;
138 invalid:
139 gomp_error ("Invalid value for chunk size in "
140 "environment variable OMP_SCHEDULE");
141 return;
144 /* Parse an unsigned long environment variable. Return true if one was
145 present and it was successfully parsed. */
147 static bool
148 parse_unsigned_long (const char *name, unsigned long *pvalue)
150 char *env, *end;
151 unsigned long value;
153 env = getenv (name);
154 if (env == NULL)
155 return false;
157 while (isspace ((unsigned char) *env))
158 ++env;
159 if (*env == '\0')
160 goto invalid;
162 errno = 0;
163 value = strtoul (env, &end, 10);
164 if (errno || (long) value <= 0)
165 goto invalid;
167 while (isspace ((unsigned char) *end))
168 ++end;
169 if (*end != '\0')
170 goto invalid;
172 *pvalue = value;
173 return true;
175 invalid:
176 gomp_error ("Invalid value for environment variable %s", name);
177 return false;
180 /* Parse the OMP_STACKSIZE environment varible. Return true if one was
181 present and it was successfully parsed. */
183 static bool
184 parse_stacksize (const char *name, unsigned long *pvalue)
186 char *env, *end;
187 unsigned long value, shift = 10;
189 env = getenv (name);
190 if (env == NULL)
191 return false;
193 while (isspace ((unsigned char) *env))
194 ++env;
195 if (*env == '\0')
196 goto invalid;
198 errno = 0;
199 value = strtoul (env, &end, 10);
200 if (errno)
201 goto invalid;
203 while (isspace ((unsigned char) *end))
204 ++end;
205 if (*end != '\0')
207 switch (tolower (*end))
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;
223 ++end;
224 while (isspace ((unsigned char) *end))
225 ++end;
226 if (*end != '\0')
227 goto invalid;
230 if (((value << shift) >> shift) != value)
231 goto invalid;
233 *pvalue = value << shift;
234 return true;
236 invalid:
237 gomp_error ("Invalid value for environment variable %s", name);
238 return false;
241 /* Parse the GOMP_SPINCOUNT environment varible. Return true if one was
242 present and it was successfully parsed. */
244 static bool
245 parse_spincount (const char *name, unsigned long long *pvalue)
247 char *env, *end;
248 unsigned long long value, mult = 1;
250 env = getenv (name);
251 if (env == NULL)
252 return false;
254 while (isspace ((unsigned char) *env))
255 ++env;
256 if (*env == '\0')
257 goto invalid;
259 if (strncasecmp (env, "infinite", 8) == 0
260 || strncasecmp (env, "infinity", 8) == 0)
262 value = ~0ULL;
263 end = env + 8;
264 goto check_tail;
267 errno = 0;
268 value = strtoull (env, &end, 10);
269 if (errno)
270 goto invalid;
272 while (isspace ((unsigned char) *end))
273 ++end;
274 if (*end != '\0')
276 switch (tolower (*end))
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;
293 ++end;
294 check_tail:
295 while (isspace ((unsigned char) *end))
296 ++end;
297 if (*end != '\0')
298 goto invalid;
301 if (value > ~0ULL / mult)
302 value = ~0ULL;
303 else
304 value *= mult;
306 *pvalue = value;
307 return true;
309 invalid:
310 gomp_error ("Invalid value for environment variable %s", name);
311 return false;
314 /* Parse a boolean value for environment variable NAME and store the
315 result in VALUE. */
317 static void
318 parse_boolean (const char *name, bool *value)
320 const char *env;
322 env = getenv (name);
323 if (env == NULL)
324 return;
326 while (isspace ((unsigned char) *env))
327 ++env;
328 if (strncasecmp (env, "true", 4) == 0)
330 *value = true;
331 env += 4;
333 else if (strncasecmp (env, "false", 5) == 0)
335 *value = false;
336 env += 5;
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);
346 /* Parse the OMP_WAIT_POLICY environment variable and store the
347 result in gomp_active_wait_policy. */
349 static int
350 parse_wait_policy (void)
352 const char *env;
353 int ret = -1;
355 env = getenv ("OMP_WAIT_POLICY");
356 if (env == NULL)
357 return -1;
359 while (isspace ((unsigned char) *env))
360 ++env;
361 if (strncasecmp (env, "active", 6) == 0)
363 ret = 1;
364 env += 6;
366 else if (strncasecmp (env, "passive", 7) == 0)
368 ret = 0;
369 env += 7;
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;
381 /* Parse the GOMP_CPU_AFFINITY environment varible. Return true if one was
382 present and it was successfully parsed. */
384 static bool
385 parse_affinity (void)
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;
392 env = getenv ("GOMP_CPU_AFFINITY");
393 if (env == NULL)
394 return false;
398 while (*env == ' ' || *env == '\t')
399 env++;
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;
407 env = end;
408 if (*env == '-')
410 cpu_end = strtoul (++env, &end, 0);
411 if (env == end || cpu_end >= 65536 || cpu_end < cpu_beg)
412 goto invalid;
414 env = end;
415 if (*env == ':')
417 cpu_stride = strtoul (++env, &end, 0);
418 if (env == end || cpu_stride == 0 || cpu_stride >= 65536)
419 goto invalid;
421 env = end;
425 needed = (cpu_end - cpu_beg) / cpu_stride + 1;
426 if (used + needed >= allocated)
428 unsigned short *new_cpus;
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)
439 free (cpus);
440 gomp_error ("not enough memory to store GOMP_CPU_AFFINITY list");
441 return false;
444 cpus = new_cpus;
447 while (needed--)
449 cpus[used++] = cpu_beg;
450 cpu_beg += cpu_stride;
453 while (*env == ' ' || *env == '\t')
454 env++;
456 if (*env == ',')
457 env++;
458 else if (*env == '\0')
459 break;
461 while (1);
463 gomp_cpu_affinity = cpus;
464 gomp_cpu_affinity_len = used;
465 return true;
467 invalid:
468 gomp_error ("Invalid value for enviroment variable GOMP_CPU_AFFINITY");
469 return false;
472 static void __attribute__((constructor))
473 initialize_env (void)
475 unsigned long stacksize;
476 int wait_policy;
478 /* Do a compile time check that mkomp_h.pl did good job. */
479 omp_check_defines ();
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)
488 gomp_remaining_threads_count = gomp_thread_limit_var - 1;
489 #ifndef HAVE_SYNC_BUILTINS
490 gomp_mutex_init (&gomp_remaining_threads_lock);
491 #endif
493 gomp_init_num_threads ();
494 gomp_available_cpus = gomp_global_icv.nthreads_var;
495 if (!parse_unsigned_long ("OMP_NUM_THREADS", &gomp_global_icv.nthreads_var))
496 gomp_global_icv.nthreads_var = gomp_available_cpus;
497 if (parse_affinity ())
498 gomp_init_affinity ();
499 wait_policy = parse_wait_policy ();
500 if (!parse_spincount ("GOMP_SPINCOUNT", &gomp_spin_count_var))
502 /* Using a rough estimation of 100000 spins per msec,
503 use 5 min blocking for OMP_WAIT_POLICY=active,
504 200 msec blocking when OMP_WAIT_POLICY is not specificed
505 and 0 when OMP_WAIT_POLICY=passive.
506 Depending on the CPU speed, this can be e.g. 5 times longer
507 or 5 times shorter. */
508 if (wait_policy > 0)
509 gomp_spin_count_var = 30000000000LL;
510 else if (wait_policy < 0)
511 gomp_spin_count_var = 20000000LL;
513 /* gomp_throttled_spin_count_var is used when there are more libgomp
514 managed threads than available CPUs. Use very short spinning. */
515 if (wait_policy > 0)
516 gomp_throttled_spin_count_var = 1000LL;
517 else if (wait_policy < 0)
518 gomp_throttled_spin_count_var = 100LL;
519 if (gomp_throttled_spin_count_var > gomp_spin_count_var)
520 gomp_throttled_spin_count_var = gomp_spin_count_var;
522 /* Not strictly environment related, but ordering constructors is tricky. */
523 pthread_attr_init (&gomp_thread_attr);
524 pthread_attr_setdetachstate (&gomp_thread_attr, PTHREAD_CREATE_DETACHED);
526 if (parse_stacksize ("OMP_STACKSIZE", &stacksize)
527 || parse_stacksize ("GOMP_STACKSIZE", &stacksize))
529 int err;
531 err = pthread_attr_setstacksize (&gomp_thread_attr, stacksize);
533 #ifdef PTHREAD_STACK_MIN
534 if (err == EINVAL)
536 if (stacksize < PTHREAD_STACK_MIN)
537 gomp_error ("Stack size less than minimum of %luk",
538 PTHREAD_STACK_MIN / 1024ul
539 + (PTHREAD_STACK_MIN % 1024 != 0));
540 else
541 gomp_error ("Stack size larger than system limit");
543 else
544 #endif
545 if (err != 0)
546 gomp_error ("Stack size change failed: %s", strerror (err));
551 /* The public OpenMP API routines that access these variables. */
553 void
554 omp_set_num_threads (int n)
556 struct gomp_task_icv *icv = gomp_icv (true);
557 icv->nthreads_var = (n > 0 ? n : 1);
560 void
561 omp_set_dynamic (int val)
563 struct gomp_task_icv *icv = gomp_icv (true);
564 icv->dyn_var = val;
568 omp_get_dynamic (void)
570 struct gomp_task_icv *icv = gomp_icv (false);
571 return icv->dyn_var;
574 void
575 omp_set_nested (int val)
577 struct gomp_task_icv *icv = gomp_icv (true);
578 icv->nest_var = val;
582 omp_get_nested (void)
584 struct gomp_task_icv *icv = gomp_icv (false);
585 return icv->nest_var;
588 void
589 omp_set_schedule (omp_sched_t kind, int modifier)
591 struct gomp_task_icv *icv = gomp_icv (true);
592 switch (kind)
594 case omp_sched_static:
595 if (modifier < 1)
596 modifier = 0;
597 icv->run_sched_modifier = modifier;
598 break;
599 case omp_sched_dynamic:
600 case omp_sched_guided:
601 if (modifier < 1)
602 modifier = 1;
603 icv->run_sched_modifier = modifier;
604 break;
605 case omp_sched_auto:
606 break;
607 default:
608 return;
610 icv->run_sched_var = kind;
613 void
614 omp_get_schedule (omp_sched_t *kind, int *modifier)
616 struct gomp_task_icv *icv = gomp_icv (false);
617 *kind = icv->run_sched_var;
618 *modifier = icv->run_sched_modifier;
622 omp_get_max_threads (void)
624 struct gomp_task_icv *icv = gomp_icv (false);
625 return icv->nthreads_var;
629 omp_get_thread_limit (void)
631 return gomp_thread_limit_var > INT_MAX ? INT_MAX : gomp_thread_limit_var;
634 void
635 omp_set_max_active_levels (int max_levels)
637 if (max_levels > 0)
638 gomp_max_active_levels_var = max_levels;
642 omp_get_max_active_levels (void)
644 return gomp_max_active_levels_var;
647 ialias (omp_set_dynamic)
648 ialias (omp_set_nested)
649 ialias (omp_set_num_threads)
650 ialias (omp_get_dynamic)
651 ialias (omp_get_nested)
652 ialias (omp_set_schedule)
653 ialias (omp_get_schedule)
654 ialias (omp_get_max_threads)
655 ialias (omp_get_thread_limit)
656 ialias (omp_set_max_active_levels)
657 ialias (omp_get_max_active_levels)