]> git.ipfire.org Git - thirdparty/gcc.git/blame - libgomp/env.c
re PR debug/49496 (-fcompare-debug failure (length) with -O -ftree-vectorize)
[thirdparty/gcc.git] / libgomp / env.c
CommitLineData
80f046cc
JJ
1/* Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010
2 Free Software Foundation, Inc.
953ff289
DN
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
748086b7
JJ
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.
953ff289
DN
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
748086b7 14 FOR A PARTICULAR PURPOSE. See the GNU General Public License for
953ff289
DN
15 more details.
16
748086b7
JJ
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.
953ff289 20
748086b7
JJ
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/>. */
953ff289
DN
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"
89b3e3cd 31#include <ctype.h>
953ff289 32#include <stdlib.h>
a1b25e49
PG
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
d0d1b24d
RH
45#include <limits.h>
46#include <errno.h>
953ff289 47
976e44e3
JJ
48#ifndef HAVE_STRTOULL
49# define strtoull(ptr, eptr, base) strtoul (ptr, eptr, base)
50#endif
953ff289 51
a68ab351
JJ
52struct 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
a0884cf0
JJ
60unsigned short *gomp_cpu_affinity;
61size_t gomp_cpu_affinity_len;
a68ab351
JJ
62unsigned long gomp_max_active_levels_var = INT_MAX;
63unsigned long gomp_thread_limit_var = ULONG_MAX;
64unsigned long gomp_remaining_threads_count;
65#ifndef HAVE_SYNC_BUILTINS
66gomp_mutex_t gomp_remaining_threads_lock;
67#endif
68unsigned long gomp_available_cpus = 1, gomp_managed_threads = 1;
69unsigned long long gomp_spin_count_var, gomp_throttled_spin_count_var;
953ff289
DN
70
71/* Parse the OMP_SCHEDULE environment variable. */
72
73static void
74parse_schedule (void)
75{
76 char *env, *end;
6acf0b38 77 unsigned long value;
953ff289
DN
78
79 env = getenv ("OMP_SCHEDULE");
80 if (env == NULL)
81 return;
82
89b3e3cd
JJ
83 while (isspace ((unsigned char) *env))
84 ++env;
85 if (strncasecmp (env, "static", 6) == 0)
953ff289 86 {
a68ab351 87 gomp_global_icv.run_sched_var = GFS_STATIC;
953ff289
DN
88 env += 6;
89 }
89b3e3cd 90 else if (strncasecmp (env, "dynamic", 7) == 0)
953ff289 91 {
a68ab351 92 gomp_global_icv.run_sched_var = GFS_DYNAMIC;
953ff289
DN
93 env += 7;
94 }
89b3e3cd 95 else if (strncasecmp (env, "guided", 6) == 0)
953ff289 96 {
a68ab351 97 gomp_global_icv.run_sched_var = GFS_GUIDED;
953ff289
DN
98 env += 6;
99 }
a68ab351
JJ
100 else if (strncasecmp (env, "auto", 4) == 0)
101 {
102 gomp_global_icv.run_sched_var = GFS_AUTO;
103 env += 4;
104 }
953ff289
DN
105 else
106 goto unknown;
107
89b3e3cd
JJ
108 while (isspace ((unsigned char) *env))
109 ++env;
953ff289
DN
110 if (*env == '\0')
111 return;
89b3e3cd 112 if (*env++ != ',')
953ff289 113 goto unknown;
89b3e3cd
JJ
114 while (isspace ((unsigned char) *env))
115 ++env;
953ff289 116 if (*env == '\0')
953ff289
DN
117 goto invalid;
118
6acf0b38
UB
119 errno = 0;
120 value = strtoul (env, &end, 10);
121 if (errno)
122 goto invalid;
123
89b3e3cd
JJ
124 while (isspace ((unsigned char) *end))
125 ++end;
953ff289
DN
126 if (*end != '\0')
127 goto invalid;
6acf0b38 128
a68ab351
JJ
129 if ((int)value != value)
130 goto invalid;
131
132 gomp_global_icv.run_sched_modifier = value;
953ff289
DN
133 return;
134
135 unknown:
136 gomp_error ("Unknown value for environment variable OMP_SCHEDULE");
137 return;
138
139 invalid:
140 gomp_error ("Invalid value for chunk size in "
141 "environment variable OMP_SCHEDULE");
953ff289
DN
142 return;
143}
144
a68ab351 145/* Parse an unsigned long environment variable. Return true if one was
953ff289
DN
146 present and it was successfully parsed. */
147
148static bool
80f046cc 149parse_unsigned_long (const char *name, unsigned long *pvalue, bool allow_zero)
953ff289
DN
150{
151 char *env, *end;
d0d1b24d 152 unsigned long value;
953ff289 153
d0d1b24d 154 env = getenv (name);
953ff289
DN
155 if (env == NULL)
156 return false;
157
89b3e3cd
JJ
158 while (isspace ((unsigned char) *env))
159 ++env;
953ff289
DN
160 if (*env == '\0')
161 goto invalid;
162
6acf0b38 163 errno = 0;
d0d1b24d 164 value = strtoul (env, &end, 10);
80f046cc 165 if (errno || (long) value <= 0 - allow_zero)
6acf0b38
UB
166 goto invalid;
167
89b3e3cd
JJ
168 while (isspace ((unsigned char) *end))
169 ++end;
953ff289
DN
170 if (*end != '\0')
171 goto invalid;
d0d1b24d
RH
172
173 *pvalue = value;
953ff289
DN
174 return true;
175
176 invalid:
d0d1b24d 177 gomp_error ("Invalid value for environment variable %s", name);
953ff289
DN
178 return false;
179}
180
a68ab351
JJ
181/* Parse the OMP_STACKSIZE environment varible. Return true if one was
182 present and it was successfully parsed. */
183
184static bool
185parse_stacksize (const char *name, unsigned long *pvalue)
186{
187 char *env, *end;
188 unsigned long value, shift = 10;
189
190 env = getenv (name);
191 if (env == NULL)
192 return false;
193
194 while (isspace ((unsigned char) *env))
195 ++env;
196 if (*env == '\0')
197 goto invalid;
198
199 errno = 0;
200 value = strtoul (env, &end, 10);
201 if (errno)
202 goto invalid;
203
204 while (isspace ((unsigned char) *end))
205 ++end;
206 if (*end != '\0')
207 {
323ff903 208 switch (tolower ((unsigned char) *end))
a68ab351
JJ
209 {
210 case 'b':
211 shift = 0;
212 break;
213 case 'k':
214 break;
215 case 'm':
216 shift = 20;
217 break;
218 case 'g':
219 shift = 30;
220 break;
221 default:
222 goto invalid;
223 }
224 ++end;
225 while (isspace ((unsigned char) *end))
226 ++end;
227 if (*end != '\0')
228 goto invalid;
229 }
230
231 if (((value << shift) >> shift) != value)
232 goto invalid;
233
234 *pvalue = value << shift;
235 return true;
236
237 invalid:
238 gomp_error ("Invalid value for environment variable %s", name);
239 return false;
240}
241
242/* Parse the GOMP_SPINCOUNT environment varible. Return true if one was
243 present and it was successfully parsed. */
244
245static bool
246parse_spincount (const char *name, unsigned long long *pvalue)
247{
248 char *env, *end;
249 unsigned long long value, mult = 1;
250
251 env = getenv (name);
252 if (env == NULL)
253 return false;
254
255 while (isspace ((unsigned char) *env))
256 ++env;
257 if (*env == '\0')
258 goto invalid;
259
260 if (strncasecmp (env, "infinite", 8) == 0
261 || strncasecmp (env, "infinity", 8) == 0)
262 {
263 value = ~0ULL;
264 end = env + 8;
265 goto check_tail;
266 }
267
268 errno = 0;
269 value = strtoull (env, &end, 10);
270 if (errno)
271 goto invalid;
272
273 while (isspace ((unsigned char) *end))
274 ++end;
275 if (*end != '\0')
276 {
323ff903 277 switch (tolower ((unsigned char) *end))
a68ab351
JJ
278 {
279 case 'k':
280 mult = 1000LL;
281 break;
282 case 'm':
283 mult = 1000LL * 1000LL;
284 break;
285 case 'g':
286 mult = 1000LL * 1000LL * 1000LL;
287 break;
288 case 't':
289 mult = 1000LL * 1000LL * 1000LL * 1000LL;
290 break;
291 default:
292 goto invalid;
293 }
294 ++end;
295 check_tail:
296 while (isspace ((unsigned char) *end))
297 ++end;
298 if (*end != '\0')
299 goto invalid;
300 }
301
302 if (value > ~0ULL / mult)
303 value = ~0ULL;
304 else
305 value *= mult;
306
307 *pvalue = value;
308 return true;
309
310 invalid:
311 gomp_error ("Invalid value for environment variable %s", name);
312 return false;
313}
314
315/* Parse a boolean value for environment variable NAME and store the
953ff289
DN
316 result in VALUE. */
317
318static void
319parse_boolean (const char *name, bool *value)
320{
321 const char *env;
322
323 env = getenv (name);
324 if (env == NULL)
325 return;
326
89b3e3cd
JJ
327 while (isspace ((unsigned char) *env))
328 ++env;
329 if (strncasecmp (env, "true", 4) == 0)
330 {
331 *value = true;
332 env += 4;
333 }
334 else if (strncasecmp (env, "false", 5) == 0)
335 {
336 *value = false;
337 env += 5;
338 }
953ff289 339 else
89b3e3cd
JJ
340 env = "X";
341 while (isspace ((unsigned char) *env))
342 ++env;
343 if (*env != '\0')
d0d1b24d 344 gomp_error ("Invalid value for environment variable %s", name);
953ff289
DN
345}
346
a68ab351
JJ
347/* Parse the OMP_WAIT_POLICY environment variable and store the
348 result in gomp_active_wait_policy. */
349
350static int
351parse_wait_policy (void)
352{
353 const char *env;
354 int ret = -1;
355
356 env = getenv ("OMP_WAIT_POLICY");
357 if (env == NULL)
358 return -1;
359
360 while (isspace ((unsigned char) *env))
361 ++env;
362 if (strncasecmp (env, "active", 6) == 0)
363 {
364 ret = 1;
365 env += 6;
366 }
367 else if (strncasecmp (env, "passive", 7) == 0)
368 {
369 ret = 0;
370 env += 7;
371 }
372 else
373 env = "X";
374 while (isspace ((unsigned char) *env))
375 ++env;
376 if (*env == '\0')
377 return ret;
378 gomp_error ("Invalid value for environment variable OMP_WAIT_POLICY");
379 return -1;
380}
381
a0884cf0
JJ
382/* Parse the GOMP_CPU_AFFINITY environment varible. Return true if one was
383 present and it was successfully parsed. */
384
385static bool
386parse_affinity (void)
387{
388 char *env, *end;
389 unsigned long cpu_beg, cpu_end, cpu_stride;
390 unsigned short *cpus = NULL;
391 size_t allocated = 0, used = 0, needed;
392
393 env = getenv ("GOMP_CPU_AFFINITY");
394 if (env == NULL)
395 return false;
396
397 do
398 {
399 while (*env == ' ' || *env == '\t')
400 env++;
401
402 cpu_beg = strtoul (env, &end, 0);
403 cpu_end = cpu_beg;
404 cpu_stride = 1;
405 if (env == end || cpu_beg >= 65536)
406 goto invalid;
407
408 env = end;
409 if (*env == '-')
410 {
411 cpu_end = strtoul (++env, &end, 0);
412 if (env == end || cpu_end >= 65536 || cpu_end < cpu_beg)
413 goto invalid;
414
415 env = end;
416 if (*env == ':')
417 {
418 cpu_stride = strtoul (++env, &end, 0);
419 if (env == end || cpu_stride == 0 || cpu_stride >= 65536)
420 goto invalid;
421
422 env = end;
423 }
424 }
425
426 needed = (cpu_end - cpu_beg) / cpu_stride + 1;
427 if (used + needed >= allocated)
428 {
429 unsigned short *new_cpus;
430
431 if (allocated < 64)
432 allocated = 64;
433 if (allocated > needed)
434 allocated <<= 1;
435 else
436 allocated += 2 * needed;
437 new_cpus = realloc (cpus, allocated * sizeof (unsigned short));
438 if (new_cpus == NULL)
439 {
440 free (cpus);
441 gomp_error ("not enough memory to store GOMP_CPU_AFFINITY list");
442 return false;
443 }
444
445 cpus = new_cpus;
446 }
447
448 while (needed--)
449 {
450 cpus[used++] = cpu_beg;
451 cpu_beg += cpu_stride;
452 }
453
454 while (*env == ' ' || *env == '\t')
455 env++;
456
457 if (*env == ',')
458 env++;
459 else if (*env == '\0')
460 break;
461 }
462 while (1);
463
464 gomp_cpu_affinity = cpus;
465 gomp_cpu_affinity_len = used;
466 return true;
467
468 invalid:
469 gomp_error ("Invalid value for enviroment variable GOMP_CPU_AFFINITY");
470 return false;
471}
472
953ff289
DN
473static void __attribute__((constructor))
474initialize_env (void)
475{
d0d1b24d 476 unsigned long stacksize;
a68ab351 477 int wait_policy;
d0d1b24d 478
953ff289
DN
479 /* Do a compile time check that mkomp_h.pl did good job. */
480 omp_check_defines ();
481
482 parse_schedule ();
a68ab351
JJ
483 parse_boolean ("OMP_DYNAMIC", &gomp_global_icv.dyn_var);
484 parse_boolean ("OMP_NESTED", &gomp_global_icv.nest_var);
80f046cc
JJ
485 parse_unsigned_long ("OMP_MAX_ACTIVE_LEVELS", &gomp_max_active_levels_var,
486 true);
487 parse_unsigned_long ("OMP_THREAD_LIMIT", &gomp_thread_limit_var, false);
a68ab351 488 if (gomp_thread_limit_var != ULONG_MAX)
9c4e59e0 489 gomp_remaining_threads_count = gomp_thread_limit_var - 1;
a68ab351 490#ifndef HAVE_SYNC_BUILTINS
9c4e59e0 491 gomp_mutex_init (&gomp_remaining_threads_lock);
a68ab351 492#endif
a68ab351
JJ
493 gomp_init_num_threads ();
494 gomp_available_cpus = gomp_global_icv.nthreads_var;
80f046cc
JJ
495 if (!parse_unsigned_long ("OMP_NUM_THREADS", &gomp_global_icv.nthreads_var,
496 false))
a68ab351 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,
4c698cf8 505 3 msec blocking when OMP_WAIT_POLICY is not specificed
a68ab351
JJ
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)
4c698cf8 512 gomp_spin_count_var = 300000LL;
a68ab351
JJ
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{
80f046cc 638 if (max_levels >= 0)
a68ab351
JJ
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)