]> git.ipfire.org Git - thirdparty/gcc.git/blame - libgomp/env.c
re PR testsuite/39696 (gcc.dg/tree-ssa/ssa-ccp-25.c scan-tree-dump doesn't work on...
[thirdparty/gcc.git] / libgomp / env.c
CommitLineData
a68ab351 1/* Copyright (C) 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
953ff289
DN
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
a68ab351 16 You should have received a copy of the GNU Lesser General Public License
953ff289
DN
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"
89b3e3cd 33#include <ctype.h>
953ff289 34#include <stdlib.h>
a1b25e49
PG
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
d0d1b24d
RH
47#include <limits.h>
48#include <errno.h>
953ff289 49
976e44e3
JJ
50#ifndef HAVE_STRTOULL
51# define strtoull(ptr, eptr, base) strtoul (ptr, eptr, base)
52#endif
953ff289 53
a68ab351
JJ
54struct 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
a0884cf0
JJ
62unsigned short *gomp_cpu_affinity;
63size_t gomp_cpu_affinity_len;
a68ab351
JJ
64unsigned long gomp_max_active_levels_var = INT_MAX;
65unsigned long gomp_thread_limit_var = ULONG_MAX;
66unsigned long gomp_remaining_threads_count;
67#ifndef HAVE_SYNC_BUILTINS
68gomp_mutex_t gomp_remaining_threads_lock;
69#endif
70unsigned long gomp_available_cpus = 1, gomp_managed_threads = 1;
71unsigned long long gomp_spin_count_var, gomp_throttled_spin_count_var;
953ff289
DN
72
73/* Parse the OMP_SCHEDULE environment variable. */
74
75static void
76parse_schedule (void)
77{
78 char *env, *end;
6acf0b38 79 unsigned long value;
953ff289
DN
80
81 env = getenv ("OMP_SCHEDULE");
82 if (env == NULL)
83 return;
84
89b3e3cd
JJ
85 while (isspace ((unsigned char) *env))
86 ++env;
87 if (strncasecmp (env, "static", 6) == 0)
953ff289 88 {
a68ab351 89 gomp_global_icv.run_sched_var = GFS_STATIC;
953ff289
DN
90 env += 6;
91 }
89b3e3cd 92 else if (strncasecmp (env, "dynamic", 7) == 0)
953ff289 93 {
a68ab351 94 gomp_global_icv.run_sched_var = GFS_DYNAMIC;
953ff289
DN
95 env += 7;
96 }
89b3e3cd 97 else if (strncasecmp (env, "guided", 6) == 0)
953ff289 98 {
a68ab351 99 gomp_global_icv.run_sched_var = GFS_GUIDED;
953ff289
DN
100 env += 6;
101 }
a68ab351
JJ
102 else if (strncasecmp (env, "auto", 4) == 0)
103 {
104 gomp_global_icv.run_sched_var = GFS_AUTO;
105 env += 4;
106 }
953ff289
DN
107 else
108 goto unknown;
109
89b3e3cd
JJ
110 while (isspace ((unsigned char) *env))
111 ++env;
953ff289
DN
112 if (*env == '\0')
113 return;
89b3e3cd 114 if (*env++ != ',')
953ff289 115 goto unknown;
89b3e3cd
JJ
116 while (isspace ((unsigned char) *env))
117 ++env;
953ff289 118 if (*env == '\0')
953ff289
DN
119 goto invalid;
120
6acf0b38
UB
121 errno = 0;
122 value = strtoul (env, &end, 10);
123 if (errno)
124 goto invalid;
125
89b3e3cd
JJ
126 while (isspace ((unsigned char) *end))
127 ++end;
953ff289
DN
128 if (*end != '\0')
129 goto invalid;
6acf0b38 130
a68ab351
JJ
131 if ((int)value != value)
132 goto invalid;
133
134 gomp_global_icv.run_sched_modifier = value;
953ff289
DN
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");
953ff289
DN
144 return;
145}
146
a68ab351 147/* Parse an unsigned long environment variable. Return true if one was
953ff289
DN
148 present and it was successfully parsed. */
149
150static bool
d0d1b24d 151parse_unsigned_long (const char *name, unsigned long *pvalue)
953ff289
DN
152{
153 char *env, *end;
d0d1b24d 154 unsigned long value;
953ff289 155
d0d1b24d 156 env = getenv (name);
953ff289
DN
157 if (env == NULL)
158 return false;
159
89b3e3cd
JJ
160 while (isspace ((unsigned char) *env))
161 ++env;
953ff289
DN
162 if (*env == '\0')
163 goto invalid;
164
6acf0b38 165 errno = 0;
d0d1b24d 166 value = strtoul (env, &end, 10);
6acf0b38
UB
167 if (errno || (long) value <= 0)
168 goto invalid;
169
89b3e3cd
JJ
170 while (isspace ((unsigned char) *end))
171 ++end;
953ff289
DN
172 if (*end != '\0')
173 goto invalid;
d0d1b24d
RH
174
175 *pvalue = value;
953ff289
DN
176 return true;
177
178 invalid:
d0d1b24d 179 gomp_error ("Invalid value for environment variable %s", name);
953ff289
DN
180 return false;
181}
182
a68ab351
JJ
183/* Parse the OMP_STACKSIZE environment varible. Return true if one was
184 present and it was successfully parsed. */
185
186static bool
187parse_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 {
323ff903 210 switch (tolower ((unsigned char) *end))
a68ab351
JJ
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
247static bool
248parse_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 {
323ff903 279 switch (tolower ((unsigned char) *end))
a68ab351
JJ
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
953ff289
DN
318 result in VALUE. */
319
320static void
321parse_boolean (const char *name, bool *value)
322{
323 const char *env;
324
325 env = getenv (name);
326 if (env == NULL)
327 return;
328
89b3e3cd
JJ
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 }
953ff289 341 else
89b3e3cd
JJ
342 env = "X";
343 while (isspace ((unsigned char) *env))
344 ++env;
345 if (*env != '\0')
d0d1b24d 346 gomp_error ("Invalid value for environment variable %s", name);
953ff289
DN
347}
348
a68ab351
JJ
349/* Parse the OMP_WAIT_POLICY environment variable and store the
350 result in gomp_active_wait_policy. */
351
352static int
353parse_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
a0884cf0
JJ
384/* Parse the GOMP_CPU_AFFINITY environment varible. Return true if one was
385 present and it was successfully parsed. */
386
387static bool
388parse_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
953ff289
DN
475static void __attribute__((constructor))
476initialize_env (void)
477{
d0d1b24d 478 unsigned long stacksize;
a68ab351 479 int wait_policy;
d0d1b24d 480
953ff289
DN
481 /* Do a compile time check that mkomp_h.pl did good job. */
482 omp_check_defines ();
483
484 parse_schedule ();
a68ab351
JJ
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)
9c4e59e0 490 gomp_remaining_threads_count = gomp_thread_limit_var - 1;
a68ab351 491#ifndef HAVE_SYNC_BUILTINS
9c4e59e0 492 gomp_mutex_init (&gomp_remaining_threads_lock);
a68ab351 493#endif
a68ab351
JJ
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;
a0884cf0
JJ
498 if (parse_affinity ())
499 gomp_init_affinity ();
a68ab351
JJ
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;
d0d1b24d
RH
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
a68ab351
JJ
527 if (parse_stacksize ("OMP_STACKSIZE", &stacksize)
528 || parse_stacksize ("GOMP_STACKSIZE", &stacksize))
d0d1b24d 529 {
c3b11a40
RH
530 int err;
531
c3b11a40
RH
532 err = pthread_attr_setstacksize (&gomp_thread_attr, stacksize);
533
534#ifdef PTHREAD_STACK_MIN
535 if (err == EINVAL)
d0d1b24d 536 {
c3b11a40
RH
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
d0d1b24d 542 gomp_error ("Stack size larger than system limit");
d0d1b24d 543 }
c3b11a40
RH
544 else
545#endif
546 if (err != 0)
547 gomp_error ("Stack size change failed: %s", strerror (err));
d0d1b24d 548 }
953ff289
DN
549}
550
551\f
552/* The public OpenMP API routines that access these variables. */
553
554void
555omp_set_num_threads (int n)
556{
a68ab351
JJ
557 struct gomp_task_icv *icv = gomp_icv (true);
558 icv->nthreads_var = (n > 0 ? n : 1);
953ff289
DN
559}
560
561void
562omp_set_dynamic (int val)
563{
a68ab351
JJ
564 struct gomp_task_icv *icv = gomp_icv (true);
565 icv->dyn_var = val;
953ff289
DN
566}
567
568int
569omp_get_dynamic (void)
570{
a68ab351
JJ
571 struct gomp_task_icv *icv = gomp_icv (false);
572 return icv->dyn_var;
953ff289
DN
573}
574
575void
576omp_set_nested (int val)
577{
a68ab351
JJ
578 struct gomp_task_icv *icv = gomp_icv (true);
579 icv->nest_var = val;
953ff289
DN
580}
581
582int
583omp_get_nested (void)
584{
a68ab351
JJ
585 struct gomp_task_icv *icv = gomp_icv (false);
586 return icv->nest_var;
587}
588
589void
590omp_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
614void
615omp_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
622int
623omp_get_max_threads (void)
624{
625 struct gomp_task_icv *icv = gomp_icv (false);
626 return icv->nthreads_var;
627}
628
629int
630omp_get_thread_limit (void)
631{
632 return gomp_thread_limit_var > INT_MAX ? INT_MAX : gomp_thread_limit_var;
633}
634
635void
636omp_set_max_active_levels (int max_levels)
637{
638 if (max_levels > 0)
639 gomp_max_active_levels_var = max_levels;
640}
641
642int
643omp_get_max_active_levels (void)
644{
645 return gomp_max_active_levels_var;
953ff289
DN
646}
647
648ialias (omp_set_dynamic)
649ialias (omp_set_nested)
650ialias (omp_set_num_threads)
651ialias (omp_get_dynamic)
652ialias (omp_get_nested)
a68ab351
JJ
653ialias (omp_set_schedule)
654ialias (omp_get_schedule)
655ialias (omp_get_max_threads)
656ialias (omp_get_thread_limit)
657ialias (omp_set_max_active_levels)
658ialias (omp_get_max_active_levels)