]> git.ipfire.org Git - thirdparty/gcc.git/blame - libgomp/env.c
New file.
[thirdparty/gcc.git] / libgomp / env.c
CommitLineData
fb79f500 1/* Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011
80f046cc 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 110 if (*env == '\0')
fb79f500
JJ
111 {
112 gomp_global_icv.run_sched_modifier
113 = gomp_global_icv.run_sched_var != GFS_STATIC;
114 return;
115 }
89b3e3cd 116 if (*env++ != ',')
953ff289 117 goto unknown;
89b3e3cd
JJ
118 while (isspace ((unsigned char) *env))
119 ++env;
953ff289 120 if (*env == '\0')
953ff289
DN
121 goto invalid;
122
6acf0b38
UB
123 errno = 0;
124 value = strtoul (env, &end, 10);
125 if (errno)
126 goto invalid;
127
89b3e3cd
JJ
128 while (isspace ((unsigned char) *end))
129 ++end;
953ff289
DN
130 if (*end != '\0')
131 goto invalid;
6acf0b38 132
a68ab351
JJ
133 if ((int)value != value)
134 goto invalid;
135
fb79f500
JJ
136 if (value == 0 && gomp_global_icv.run_sched_var != GFS_STATIC)
137 value = 1;
a68ab351 138 gomp_global_icv.run_sched_modifier = value;
953ff289
DN
139 return;
140
141 unknown:
142 gomp_error ("Unknown value for environment variable OMP_SCHEDULE");
143 return;
144
145 invalid:
146 gomp_error ("Invalid value for chunk size in "
147 "environment variable OMP_SCHEDULE");
953ff289
DN
148 return;
149}
150
a68ab351 151/* Parse an unsigned long environment variable. Return true if one was
953ff289
DN
152 present and it was successfully parsed. */
153
154static bool
80f046cc 155parse_unsigned_long (const char *name, unsigned long *pvalue, bool allow_zero)
953ff289
DN
156{
157 char *env, *end;
d0d1b24d 158 unsigned long value;
953ff289 159
d0d1b24d 160 env = getenv (name);
953ff289
DN
161 if (env == NULL)
162 return false;
163
89b3e3cd
JJ
164 while (isspace ((unsigned char) *env))
165 ++env;
953ff289
DN
166 if (*env == '\0')
167 goto invalid;
168
6acf0b38 169 errno = 0;
d0d1b24d 170 value = strtoul (env, &end, 10);
80f046cc 171 if (errno || (long) value <= 0 - allow_zero)
6acf0b38
UB
172 goto invalid;
173
89b3e3cd
JJ
174 while (isspace ((unsigned char) *end))
175 ++end;
953ff289
DN
176 if (*end != '\0')
177 goto invalid;
d0d1b24d
RH
178
179 *pvalue = value;
953ff289
DN
180 return true;
181
182 invalid:
d0d1b24d 183 gomp_error ("Invalid value for environment variable %s", name);
953ff289
DN
184 return false;
185}
186
a68ab351
JJ
187/* Parse the OMP_STACKSIZE environment varible. Return true if one was
188 present and it was successfully parsed. */
189
190static bool
191parse_stacksize (const char *name, unsigned long *pvalue)
192{
193 char *env, *end;
194 unsigned long value, shift = 10;
195
196 env = getenv (name);
197 if (env == NULL)
198 return false;
199
200 while (isspace ((unsigned char) *env))
201 ++env;
202 if (*env == '\0')
203 goto invalid;
204
205 errno = 0;
206 value = strtoul (env, &end, 10);
207 if (errno)
208 goto invalid;
209
210 while (isspace ((unsigned char) *end))
211 ++end;
212 if (*end != '\0')
213 {
323ff903 214 switch (tolower ((unsigned char) *end))
a68ab351
JJ
215 {
216 case 'b':
217 shift = 0;
218 break;
219 case 'k':
220 break;
221 case 'm':
222 shift = 20;
223 break;
224 case 'g':
225 shift = 30;
226 break;
227 default:
228 goto invalid;
229 }
230 ++end;
231 while (isspace ((unsigned char) *end))
232 ++end;
233 if (*end != '\0')
234 goto invalid;
235 }
236
237 if (((value << shift) >> shift) != value)
238 goto invalid;
239
240 *pvalue = value << shift;
241 return true;
242
243 invalid:
244 gomp_error ("Invalid value for environment variable %s", name);
245 return false;
246}
247
248/* Parse the GOMP_SPINCOUNT environment varible. Return true if one was
249 present and it was successfully parsed. */
250
251static bool
252parse_spincount (const char *name, unsigned long long *pvalue)
253{
254 char *env, *end;
255 unsigned long long value, mult = 1;
256
257 env = getenv (name);
258 if (env == NULL)
259 return false;
260
261 while (isspace ((unsigned char) *env))
262 ++env;
263 if (*env == '\0')
264 goto invalid;
265
266 if (strncasecmp (env, "infinite", 8) == 0
267 || strncasecmp (env, "infinity", 8) == 0)
268 {
269 value = ~0ULL;
270 end = env + 8;
271 goto check_tail;
272 }
273
274 errno = 0;
275 value = strtoull (env, &end, 10);
276 if (errno)
277 goto invalid;
278
279 while (isspace ((unsigned char) *end))
280 ++end;
281 if (*end != '\0')
282 {
323ff903 283 switch (tolower ((unsigned char) *end))
a68ab351
JJ
284 {
285 case 'k':
286 mult = 1000LL;
287 break;
288 case 'm':
289 mult = 1000LL * 1000LL;
290 break;
291 case 'g':
292 mult = 1000LL * 1000LL * 1000LL;
293 break;
294 case 't':
295 mult = 1000LL * 1000LL * 1000LL * 1000LL;
296 break;
297 default:
298 goto invalid;
299 }
300 ++end;
301 check_tail:
302 while (isspace ((unsigned char) *end))
303 ++end;
304 if (*end != '\0')
305 goto invalid;
306 }
307
308 if (value > ~0ULL / mult)
309 value = ~0ULL;
310 else
311 value *= mult;
312
313 *pvalue = value;
314 return true;
315
316 invalid:
317 gomp_error ("Invalid value for environment variable %s", name);
318 return false;
319}
320
321/* Parse a boolean value for environment variable NAME and store the
953ff289
DN
322 result in VALUE. */
323
324static void
325parse_boolean (const char *name, bool *value)
326{
327 const char *env;
328
329 env = getenv (name);
330 if (env == NULL)
331 return;
332
89b3e3cd
JJ
333 while (isspace ((unsigned char) *env))
334 ++env;
335 if (strncasecmp (env, "true", 4) == 0)
336 {
337 *value = true;
338 env += 4;
339 }
340 else if (strncasecmp (env, "false", 5) == 0)
341 {
342 *value = false;
343 env += 5;
344 }
953ff289 345 else
89b3e3cd
JJ
346 env = "X";
347 while (isspace ((unsigned char) *env))
348 ++env;
349 if (*env != '\0')
d0d1b24d 350 gomp_error ("Invalid value for environment variable %s", name);
953ff289
DN
351}
352
a68ab351
JJ
353/* Parse the OMP_WAIT_POLICY environment variable and store the
354 result in gomp_active_wait_policy. */
355
356static int
357parse_wait_policy (void)
358{
359 const char *env;
360 int ret = -1;
361
362 env = getenv ("OMP_WAIT_POLICY");
363 if (env == NULL)
364 return -1;
365
366 while (isspace ((unsigned char) *env))
367 ++env;
368 if (strncasecmp (env, "active", 6) == 0)
369 {
370 ret = 1;
371 env += 6;
372 }
373 else if (strncasecmp (env, "passive", 7) == 0)
374 {
375 ret = 0;
376 env += 7;
377 }
378 else
379 env = "X";
380 while (isspace ((unsigned char) *env))
381 ++env;
382 if (*env == '\0')
383 return ret;
384 gomp_error ("Invalid value for environment variable OMP_WAIT_POLICY");
385 return -1;
386}
387
a0884cf0
JJ
388/* Parse the GOMP_CPU_AFFINITY environment varible. Return true if one was
389 present and it was successfully parsed. */
390
391static bool
392parse_affinity (void)
393{
394 char *env, *end;
395 unsigned long cpu_beg, cpu_end, cpu_stride;
396 unsigned short *cpus = NULL;
397 size_t allocated = 0, used = 0, needed;
398
399 env = getenv ("GOMP_CPU_AFFINITY");
400 if (env == NULL)
401 return false;
402
403 do
404 {
405 while (*env == ' ' || *env == '\t')
406 env++;
407
408 cpu_beg = strtoul (env, &end, 0);
409 cpu_end = cpu_beg;
410 cpu_stride = 1;
411 if (env == end || cpu_beg >= 65536)
412 goto invalid;
413
414 env = end;
415 if (*env == '-')
416 {
417 cpu_end = strtoul (++env, &end, 0);
418 if (env == end || cpu_end >= 65536 || cpu_end < cpu_beg)
419 goto invalid;
420
421 env = end;
422 if (*env == ':')
423 {
424 cpu_stride = strtoul (++env, &end, 0);
425 if (env == end || cpu_stride == 0 || cpu_stride >= 65536)
426 goto invalid;
427
428 env = end;
429 }
430 }
431
432 needed = (cpu_end - cpu_beg) / cpu_stride + 1;
433 if (used + needed >= allocated)
434 {
435 unsigned short *new_cpus;
436
437 if (allocated < 64)
438 allocated = 64;
439 if (allocated > needed)
440 allocated <<= 1;
441 else
442 allocated += 2 * needed;
443 new_cpus = realloc (cpus, allocated * sizeof (unsigned short));
444 if (new_cpus == NULL)
445 {
446 free (cpus);
447 gomp_error ("not enough memory to store GOMP_CPU_AFFINITY list");
448 return false;
449 }
450
451 cpus = new_cpus;
452 }
453
454 while (needed--)
455 {
456 cpus[used++] = cpu_beg;
457 cpu_beg += cpu_stride;
458 }
459
460 while (*env == ' ' || *env == '\t')
461 env++;
462
463 if (*env == ',')
464 env++;
465 else if (*env == '\0')
466 break;
467 }
468 while (1);
469
470 gomp_cpu_affinity = cpus;
471 gomp_cpu_affinity_len = used;
472 return true;
473
474 invalid:
475 gomp_error ("Invalid value for enviroment variable GOMP_CPU_AFFINITY");
476 return false;
477}
478
953ff289
DN
479static void __attribute__((constructor))
480initialize_env (void)
481{
d0d1b24d 482 unsigned long stacksize;
a68ab351 483 int wait_policy;
d0d1b24d 484
953ff289
DN
485 /* Do a compile time check that mkomp_h.pl did good job. */
486 omp_check_defines ();
487
488 parse_schedule ();
a68ab351
JJ
489 parse_boolean ("OMP_DYNAMIC", &gomp_global_icv.dyn_var);
490 parse_boolean ("OMP_NESTED", &gomp_global_icv.nest_var);
80f046cc
JJ
491 parse_unsigned_long ("OMP_MAX_ACTIVE_LEVELS", &gomp_max_active_levels_var,
492 true);
493 parse_unsigned_long ("OMP_THREAD_LIMIT", &gomp_thread_limit_var, false);
a68ab351 494 if (gomp_thread_limit_var != ULONG_MAX)
9c4e59e0 495 gomp_remaining_threads_count = gomp_thread_limit_var - 1;
a68ab351 496#ifndef HAVE_SYNC_BUILTINS
9c4e59e0 497 gomp_mutex_init (&gomp_remaining_threads_lock);
a68ab351 498#endif
a68ab351
JJ
499 gomp_init_num_threads ();
500 gomp_available_cpus = gomp_global_icv.nthreads_var;
80f046cc
JJ
501 if (!parse_unsigned_long ("OMP_NUM_THREADS", &gomp_global_icv.nthreads_var,
502 false))
a68ab351 503 gomp_global_icv.nthreads_var = gomp_available_cpus;
a0884cf0
JJ
504 if (parse_affinity ())
505 gomp_init_affinity ();
a68ab351
JJ
506 wait_policy = parse_wait_policy ();
507 if (!parse_spincount ("GOMP_SPINCOUNT", &gomp_spin_count_var))
508 {
509 /* Using a rough estimation of 100000 spins per msec,
510 use 5 min blocking for OMP_WAIT_POLICY=active,
4c698cf8 511 3 msec blocking when OMP_WAIT_POLICY is not specificed
a68ab351
JJ
512 and 0 when OMP_WAIT_POLICY=passive.
513 Depending on the CPU speed, this can be e.g. 5 times longer
514 or 5 times shorter. */
515 if (wait_policy > 0)
516 gomp_spin_count_var = 30000000000LL;
517 else if (wait_policy < 0)
4c698cf8 518 gomp_spin_count_var = 300000LL;
a68ab351
JJ
519 }
520 /* gomp_throttled_spin_count_var is used when there are more libgomp
521 managed threads than available CPUs. Use very short spinning. */
522 if (wait_policy > 0)
523 gomp_throttled_spin_count_var = 1000LL;
524 else if (wait_policy < 0)
525 gomp_throttled_spin_count_var = 100LL;
526 if (gomp_throttled_spin_count_var > gomp_spin_count_var)
527 gomp_throttled_spin_count_var = gomp_spin_count_var;
d0d1b24d
RH
528
529 /* Not strictly environment related, but ordering constructors is tricky. */
530 pthread_attr_init (&gomp_thread_attr);
531 pthread_attr_setdetachstate (&gomp_thread_attr, PTHREAD_CREATE_DETACHED);
532
a68ab351
JJ
533 if (parse_stacksize ("OMP_STACKSIZE", &stacksize)
534 || parse_stacksize ("GOMP_STACKSIZE", &stacksize))
d0d1b24d 535 {
c3b11a40
RH
536 int err;
537
c3b11a40
RH
538 err = pthread_attr_setstacksize (&gomp_thread_attr, stacksize);
539
540#ifdef PTHREAD_STACK_MIN
541 if (err == EINVAL)
d0d1b24d 542 {
c3b11a40
RH
543 if (stacksize < PTHREAD_STACK_MIN)
544 gomp_error ("Stack size less than minimum of %luk",
545 PTHREAD_STACK_MIN / 1024ul
546 + (PTHREAD_STACK_MIN % 1024 != 0));
547 else
d0d1b24d 548 gomp_error ("Stack size larger than system limit");
d0d1b24d 549 }
c3b11a40
RH
550 else
551#endif
552 if (err != 0)
553 gomp_error ("Stack size change failed: %s", strerror (err));
d0d1b24d 554 }
953ff289
DN
555}
556
557\f
558/* The public OpenMP API routines that access these variables. */
559
560void
561omp_set_num_threads (int n)
562{
a68ab351
JJ
563 struct gomp_task_icv *icv = gomp_icv (true);
564 icv->nthreads_var = (n > 0 ? n : 1);
953ff289
DN
565}
566
567void
568omp_set_dynamic (int val)
569{
a68ab351
JJ
570 struct gomp_task_icv *icv = gomp_icv (true);
571 icv->dyn_var = val;
953ff289
DN
572}
573
574int
575omp_get_dynamic (void)
576{
a68ab351
JJ
577 struct gomp_task_icv *icv = gomp_icv (false);
578 return icv->dyn_var;
953ff289
DN
579}
580
581void
582omp_set_nested (int val)
583{
a68ab351
JJ
584 struct gomp_task_icv *icv = gomp_icv (true);
585 icv->nest_var = val;
953ff289
DN
586}
587
588int
589omp_get_nested (void)
590{
a68ab351
JJ
591 struct gomp_task_icv *icv = gomp_icv (false);
592 return icv->nest_var;
593}
594
595void
596omp_set_schedule (omp_sched_t kind, int modifier)
597{
598 struct gomp_task_icv *icv = gomp_icv (true);
599 switch (kind)
600 {
601 case omp_sched_static:
602 if (modifier < 1)
603 modifier = 0;
604 icv->run_sched_modifier = modifier;
605 break;
606 case omp_sched_dynamic:
607 case omp_sched_guided:
608 if (modifier < 1)
609 modifier = 1;
610 icv->run_sched_modifier = modifier;
611 break;
612 case omp_sched_auto:
613 break;
614 default:
615 return;
616 }
617 icv->run_sched_var = kind;
618}
619
620void
621omp_get_schedule (omp_sched_t *kind, int *modifier)
622{
623 struct gomp_task_icv *icv = gomp_icv (false);
624 *kind = icv->run_sched_var;
625 *modifier = icv->run_sched_modifier;
626}
627
628int
629omp_get_max_threads (void)
630{
631 struct gomp_task_icv *icv = gomp_icv (false);
632 return icv->nthreads_var;
633}
634
635int
636omp_get_thread_limit (void)
637{
638 return gomp_thread_limit_var > INT_MAX ? INT_MAX : gomp_thread_limit_var;
639}
640
641void
642omp_set_max_active_levels (int max_levels)
643{
80f046cc 644 if (max_levels >= 0)
a68ab351
JJ
645 gomp_max_active_levels_var = max_levels;
646}
647
648int
649omp_get_max_active_levels (void)
650{
651 return gomp_max_active_levels_var;
953ff289
DN
652}
653
654ialias (omp_set_dynamic)
655ialias (omp_set_nested)
656ialias (omp_set_num_threads)
657ialias (omp_get_dynamic)
658ialias (omp_get_nested)
a68ab351
JJ
659ialias (omp_set_schedule)
660ialias (omp_get_schedule)
661ialias (omp_get_max_threads)
662ialias (omp_get_thread_limit)
663ialias (omp_set_max_active_levels)
664ialias (omp_get_max_active_levels)