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
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. */
32 #include "libgomp_f.h"
35 #ifdef STRING_WITH_STRINGS
42 # ifdef HAVE_STRINGS_H
51 # define strtoull(ptr, eptr, base) strtoul (ptr, eptr, base)
54 struct gomp_task_icv gomp_global_icv = {
56 .run_sched_var = GFS_DYNAMIC,
57 .run_sched_modifier = 1,
62 unsigned short *gomp_cpu_affinity;
63 size_t gomp_cpu_affinity_len;
64 unsigned long gomp_max_active_levels_var = INT_MAX;
65 unsigned long gomp_thread_limit_var = ULONG_MAX;
66 unsigned long gomp_remaining_threads_count;
67 #ifndef HAVE_SYNC_BUILTINS
68 gomp_mutex_t gomp_remaining_threads_lock;
70 unsigned long gomp_available_cpus = 1, gomp_managed_threads = 1;
71 unsigned long long gomp_spin_count_var, gomp_throttled_spin_count_var;
73 /* Parse the OMP_SCHEDULE environment variable. */
81 env = getenv ("OMP_SCHEDULE");
85 while (isspace ((unsigned char) *env))
87 if (strncasecmp (env, "static", 6) == 0)
89 gomp_global_icv.run_sched_var = GFS_STATIC;
92 else if (strncasecmp (env, "dynamic", 7) == 0)
94 gomp_global_icv.run_sched_var = GFS_DYNAMIC;
97 else if (strncasecmp (env, "guided", 6) == 0)
99 gomp_global_icv.run_sched_var = GFS_GUIDED;
102 else if (strncasecmp (env, "auto", 4) == 0)
104 gomp_global_icv.run_sched_var = GFS_AUTO;
110 while (isspace ((unsigned char) *env))
116 while (isspace ((unsigned char) *env))
122 value = strtoul (env, &end, 10);
126 while (isspace ((unsigned char) *end))
131 if ((int)value != value)
134 gomp_global_icv.run_sched_modifier = value;
138 gomp_error ("Unknown value for environment variable OMP_SCHEDULE");
142 gomp_error ("Invalid value for chunk size in "
143 "environment variable OMP_SCHEDULE");
147 /* Parse an unsigned long environment variable. Return true if one was
148 present and it was successfully parsed. */
151 parse_unsigned_long (const char *name, unsigned long *pvalue)
160 while (isspace ((unsigned char) *env))
166 value = strtoul (env, &end, 10);
167 if (errno || (long) value <= 0)
170 while (isspace ((unsigned char) *end))
179 gomp_error ("Invalid value for environment variable %s", name);
183 /* Parse the OMP_STACKSIZE environment varible. Return true if one was
184 present and it was successfully parsed. */
187 parse_stacksize (const char *name, unsigned long *pvalue)
190 unsigned long value, shift = 10;
196 while (isspace ((unsigned char) *env))
202 value = strtoul (env, &end, 10);
206 while (isspace ((unsigned char) *end))
210 switch (tolower (*end))
227 while (isspace ((unsigned char) *end))
233 if (((value << shift) >> shift) != value)
236 *pvalue = value << shift;
240 gomp_error ("Invalid value for environment variable %s", name);
244 /* Parse the GOMP_SPINCOUNT environment varible. Return true if one was
245 present and it was successfully parsed. */
248 parse_spincount (const char *name, unsigned long long *pvalue)
251 unsigned long long value, mult = 1;
257 while (isspace ((unsigned char) *env))
262 if (strncasecmp (env, "infinite", 8) == 0
263 || strncasecmp (env, "infinity", 8) == 0)
271 value = strtoull (env, &end, 10);
275 while (isspace ((unsigned char) *end))
279 switch (tolower (*end))
285 mult = 1000LL * 1000LL;
288 mult = 1000LL * 1000LL * 1000LL;
291 mult = 1000LL * 1000LL * 1000LL * 1000LL;
298 while (isspace ((unsigned char) *end))
304 if (value > ~0ULL / mult)
313 gomp_error ("Invalid value for environment variable %s", name);
317 /* Parse a boolean value for environment variable NAME and store the
321 parse_boolean (const char *name, bool *value)
329 while (isspace ((unsigned char) *env))
331 if (strncasecmp (env, "true", 4) == 0)
336 else if (strncasecmp (env, "false", 5) == 0)
343 while (isspace ((unsigned char) *env))
346 gomp_error ("Invalid value for environment variable %s", name);
349 /* Parse the OMP_WAIT_POLICY environment variable and store the
350 result in gomp_active_wait_policy. */
353 parse_wait_policy (void)
358 env = getenv ("OMP_WAIT_POLICY");
362 while (isspace ((unsigned char) *env))
364 if (strncasecmp (env, "active", 6) == 0)
369 else if (strncasecmp (env, "passive", 7) == 0)
376 while (isspace ((unsigned char) *env))
380 gomp_error ("Invalid value for environment variable OMP_WAIT_POLICY");
384 /* Parse the GOMP_CPU_AFFINITY environment varible. Return true if one was
385 present and it was successfully parsed. */
388 parse_affinity (void)
391 unsigned long cpu_beg, cpu_end, cpu_stride;
392 unsigned short *cpus = NULL;
393 size_t allocated = 0, used = 0, needed;
395 env = getenv ("GOMP_CPU_AFFINITY");
401 while (*env == ' ' || *env == '\t')
404 cpu_beg = strtoul (env, &end, 0);
407 if (env == end || cpu_beg >= 65536)
413 cpu_end = strtoul (++env, &end, 0);
414 if (env == end || cpu_end >= 65536 || cpu_end < cpu_beg)
420 cpu_stride = strtoul (++env, &end, 0);
421 if (env == end || cpu_stride == 0 || cpu_stride >= 65536)
428 needed = (cpu_end - cpu_beg) / cpu_stride + 1;
429 if (used + needed >= allocated)
431 unsigned short *new_cpus;
435 if (allocated > needed)
438 allocated += 2 * needed;
439 new_cpus = realloc (cpus, allocated * sizeof (unsigned short));
440 if (new_cpus == NULL)
443 gomp_error ("not enough memory to store GOMP_CPU_AFFINITY list");
452 cpus[used++] = cpu_beg;
453 cpu_beg += cpu_stride;
456 while (*env == ' ' || *env == '\t')
461 else if (*env == '\0')
466 gomp_cpu_affinity = cpus;
467 gomp_cpu_affinity_len = used;
471 gomp_error ("Invalid value for enviroment variable GOMP_CPU_AFFINITY");
475 static void __attribute__((constructor))
476 initialize_env (void)
478 unsigned long stacksize;
481 /* Do a compile time check that mkomp_h.pl did good job. */
482 omp_check_defines ();
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)
491 gomp_remaining_threads_count = gomp_thread_limit_var - 1;
492 #ifndef HAVE_SYNC_BUILTINS
493 gomp_mutex_init (&gomp_remaining_threads_lock);
496 gomp_init_num_threads ();
497 gomp_available_cpus = gomp_global_icv.nthreads_var;
498 if (!parse_unsigned_long ("OMP_NUM_THREADS", &gomp_global_icv.nthreads_var))
499 gomp_global_icv.nthreads_var = gomp_available_cpus;
500 if (parse_affinity ())
501 gomp_init_affinity ();
502 wait_policy = parse_wait_policy ();
503 if (!parse_spincount ("GOMP_SPINCOUNT", &gomp_spin_count_var))
505 /* Using a rough estimation of 100000 spins per msec,
506 use 5 min blocking for OMP_WAIT_POLICY=active,
507 200 msec blocking when OMP_WAIT_POLICY is not specificed
508 and 0 when OMP_WAIT_POLICY=passive.
509 Depending on the CPU speed, this can be e.g. 5 times longer
510 or 5 times shorter. */
512 gomp_spin_count_var = 30000000000LL;
513 else if (wait_policy < 0)
514 gomp_spin_count_var = 20000000LL;
516 /* gomp_throttled_spin_count_var is used when there are more libgomp
517 managed threads than available CPUs. Use very short spinning. */
519 gomp_throttled_spin_count_var = 1000LL;
520 else if (wait_policy < 0)
521 gomp_throttled_spin_count_var = 100LL;
522 if (gomp_throttled_spin_count_var > gomp_spin_count_var)
523 gomp_throttled_spin_count_var = gomp_spin_count_var;
525 /* Not strictly environment related, but ordering constructors is tricky. */
526 pthread_attr_init (&gomp_thread_attr);
527 pthread_attr_setdetachstate (&gomp_thread_attr, PTHREAD_CREATE_DETACHED);
529 if (parse_stacksize ("OMP_STACKSIZE", &stacksize)
530 || parse_stacksize ("GOMP_STACKSIZE", &stacksize))
534 err = pthread_attr_setstacksize (&gomp_thread_attr, stacksize);
536 #ifdef PTHREAD_STACK_MIN
539 if (stacksize < PTHREAD_STACK_MIN)
540 gomp_error ("Stack size less than minimum of %luk",
541 PTHREAD_STACK_MIN / 1024ul
542 + (PTHREAD_STACK_MIN % 1024 != 0));
544 gomp_error ("Stack size larger than system limit");
549 gomp_error ("Stack size change failed: %s", strerror (err));
554 /* The public OpenMP API routines that access these variables. */
557 omp_set_num_threads (int n)
559 struct gomp_task_icv *icv = gomp_icv (true);
560 icv->nthreads_var = (n > 0 ? n : 1);
564 omp_set_dynamic (int val)
566 struct gomp_task_icv *icv = gomp_icv (true);
571 omp_get_dynamic (void)
573 struct gomp_task_icv *icv = gomp_icv (false);
578 omp_set_nested (int val)
580 struct gomp_task_icv *icv = gomp_icv (true);
585 omp_get_nested (void)
587 struct gomp_task_icv *icv = gomp_icv (false);
588 return icv->nest_var;
592 omp_set_schedule (omp_sched_t kind, int modifier)
594 struct gomp_task_icv *icv = gomp_icv (true);
597 case omp_sched_static:
600 icv->run_sched_modifier = modifier;
602 case omp_sched_dynamic:
603 case omp_sched_guided:
606 icv->run_sched_modifier = modifier;
613 icv->run_sched_var = kind;
617 omp_get_schedule (omp_sched_t *kind, int *modifier)
619 struct gomp_task_icv *icv = gomp_icv (false);
620 *kind = icv->run_sched_var;
621 *modifier = icv->run_sched_modifier;
625 omp_get_max_threads (void)
627 struct gomp_task_icv *icv = gomp_icv (false);
628 return icv->nthreads_var;
632 omp_get_thread_limit (void)
634 return gomp_thread_limit_var > INT_MAX ? INT_MAX : gomp_thread_limit_var;
638 omp_set_max_active_levels (int max_levels)
641 gomp_max_active_levels_var = max_levels;
645 omp_get_max_active_levels (void)
647 return gomp_max_active_levels_var;
650 ialias (omp_set_dynamic)
651 ialias (omp_set_nested)
652 ialias (omp_set_num_threads)
653 ialias (omp_get_dynamic)
654 ialias (omp_get_nested)
655 ialias (omp_set_schedule)
656 ialias (omp_get_schedule)
657 ialias (omp_get_max_threads)
658 ialias (omp_get_thread_limit)
659 ialias (omp_set_max_active_levels)
660 ialias (omp_get_max_active_levels)