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