1 /* Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010
2 Free Software Foundation, Inc.
3 Contributed by Richard Henderson <rth@redhat.com>.
5 This file is part of the GNU OpenMP Library (libgomp).
7 Libgomp is free software; you can redistribute it and/or modify it
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)
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
14 FOR A PARTICULAR PURPOSE. See the GNU General Public License for
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.
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/>. */
26 /* This file defines the OpenMP internal control variables, and arranges
27 for them to be initialized from environment variables at startup. */
30 #include "libgomp_f.h"
33 #ifdef STRING_WITH_STRINGS
40 # ifdef HAVE_STRINGS_H
49 # define strtoull(ptr, eptr, base) strtoul (ptr, eptr, base)
52 struct gomp_task_icv gomp_global_icv
= {
54 .run_sched_var
= GFS_DYNAMIC
,
55 .run_sched_modifier
= 1,
60 unsigned short *gomp_cpu_affinity
;
61 size_t gomp_cpu_affinity_len
;
62 unsigned long gomp_max_active_levels_var
= INT_MAX
;
63 unsigned long gomp_thread_limit_var
= ULONG_MAX
;
64 unsigned long gomp_remaining_threads_count
;
65 #ifndef HAVE_SYNC_BUILTINS
66 gomp_mutex_t gomp_remaining_threads_lock
;
68 unsigned long gomp_available_cpus
= 1, gomp_managed_threads
= 1;
69 unsigned long long gomp_spin_count_var
, gomp_throttled_spin_count_var
;
71 /* Parse the OMP_SCHEDULE environment variable. */
79 env
= getenv ("OMP_SCHEDULE");
83 while (isspace ((unsigned char) *env
))
85 if (strncasecmp (env
, "static", 6) == 0)
87 gomp_global_icv
.run_sched_var
= GFS_STATIC
;
90 else if (strncasecmp (env
, "dynamic", 7) == 0)
92 gomp_global_icv
.run_sched_var
= GFS_DYNAMIC
;
95 else if (strncasecmp (env
, "guided", 6) == 0)
97 gomp_global_icv
.run_sched_var
= GFS_GUIDED
;
100 else if (strncasecmp (env
, "auto", 4) == 0)
102 gomp_global_icv
.run_sched_var
= GFS_AUTO
;
108 while (isspace ((unsigned char) *env
))
114 while (isspace ((unsigned char) *env
))
120 value
= strtoul (env
, &end
, 10);
124 while (isspace ((unsigned char) *end
))
129 if ((int)value
!= value
)
132 gomp_global_icv
.run_sched_modifier
= value
;
136 gomp_error ("Unknown value for environment variable OMP_SCHEDULE");
140 gomp_error ("Invalid value for chunk size in "
141 "environment variable OMP_SCHEDULE");
145 /* Parse an unsigned long environment variable. Return true if one was
146 present and it was successfully parsed. */
149 parse_unsigned_long (const char *name
, unsigned long *pvalue
, bool allow_zero
)
158 while (isspace ((unsigned char) *env
))
164 value
= strtoul (env
, &end
, 10);
165 if (errno
|| (long) value
<= 0 - allow_zero
)
168 while (isspace ((unsigned char) *end
))
177 gomp_error ("Invalid value for environment variable %s", name
);
181 /* Parse the OMP_STACKSIZE environment varible. Return true if one was
182 present and it was successfully parsed. */
185 parse_stacksize (const char *name
, unsigned long *pvalue
)
188 unsigned long value
, shift
= 10;
194 while (isspace ((unsigned char) *env
))
200 value
= strtoul (env
, &end
, 10);
204 while (isspace ((unsigned char) *end
))
208 switch (tolower ((unsigned char) *end
))
225 while (isspace ((unsigned char) *end
))
231 if (((value
<< shift
) >> shift
) != value
)
234 *pvalue
= value
<< shift
;
238 gomp_error ("Invalid value for environment variable %s", name
);
242 /* Parse the GOMP_SPINCOUNT environment varible. Return true if one was
243 present and it was successfully parsed. */
246 parse_spincount (const char *name
, unsigned long long *pvalue
)
249 unsigned long long value
, mult
= 1;
255 while (isspace ((unsigned char) *env
))
260 if (strncasecmp (env
, "infinite", 8) == 0
261 || strncasecmp (env
, "infinity", 8) == 0)
269 value
= strtoull (env
, &end
, 10);
273 while (isspace ((unsigned char) *end
))
277 switch (tolower ((unsigned char) *end
))
283 mult
= 1000LL * 1000LL;
286 mult
= 1000LL * 1000LL * 1000LL;
289 mult
= 1000LL * 1000LL * 1000LL * 1000LL;
296 while (isspace ((unsigned char) *end
))
302 if (value
> ~0ULL / mult
)
311 gomp_error ("Invalid value for environment variable %s", name
);
315 /* Parse a boolean value for environment variable NAME and store the
319 parse_boolean (const char *name
, bool *value
)
327 while (isspace ((unsigned char) *env
))
329 if (strncasecmp (env
, "true", 4) == 0)
334 else if (strncasecmp (env
, "false", 5) == 0)
341 while (isspace ((unsigned char) *env
))
344 gomp_error ("Invalid value for environment variable %s", name
);
347 /* Parse the OMP_WAIT_POLICY environment variable and store the
348 result in gomp_active_wait_policy. */
351 parse_wait_policy (void)
356 env
= getenv ("OMP_WAIT_POLICY");
360 while (isspace ((unsigned char) *env
))
362 if (strncasecmp (env
, "active", 6) == 0)
367 else if (strncasecmp (env
, "passive", 7) == 0)
374 while (isspace ((unsigned char) *env
))
378 gomp_error ("Invalid value for environment variable OMP_WAIT_POLICY");
382 /* Parse the GOMP_CPU_AFFINITY environment varible. Return true if one was
383 present and it was successfully parsed. */
386 parse_affinity (void)
389 unsigned long cpu_beg
, cpu_end
, cpu_stride
;
390 unsigned short *cpus
= NULL
;
391 size_t allocated
= 0, used
= 0, needed
;
393 env
= getenv ("GOMP_CPU_AFFINITY");
399 while (*env
== ' ' || *env
== '\t')
402 cpu_beg
= strtoul (env
, &end
, 0);
405 if (env
== end
|| cpu_beg
>= 65536)
411 cpu_end
= strtoul (++env
, &end
, 0);
412 if (env
== end
|| cpu_end
>= 65536 || cpu_end
< cpu_beg
)
418 cpu_stride
= strtoul (++env
, &end
, 0);
419 if (env
== end
|| cpu_stride
== 0 || cpu_stride
>= 65536)
426 needed
= (cpu_end
- cpu_beg
) / cpu_stride
+ 1;
427 if (used
+ needed
>= allocated
)
429 unsigned short *new_cpus
;
433 if (allocated
> needed
)
436 allocated
+= 2 * needed
;
437 new_cpus
= realloc (cpus
, allocated
* sizeof (unsigned short));
438 if (new_cpus
== NULL
)
441 gomp_error ("not enough memory to store GOMP_CPU_AFFINITY list");
450 cpus
[used
++] = cpu_beg
;
451 cpu_beg
+= cpu_stride
;
454 while (*env
== ' ' || *env
== '\t')
459 else if (*env
== '\0')
464 gomp_cpu_affinity
= cpus
;
465 gomp_cpu_affinity_len
= used
;
469 gomp_error ("Invalid value for enviroment variable GOMP_CPU_AFFINITY");
473 static void __attribute__((constructor
))
474 initialize_env (void)
476 unsigned long stacksize
;
479 /* Do a compile time check that mkomp_h.pl did good job. */
480 omp_check_defines ();
483 parse_boolean ("OMP_DYNAMIC", &gomp_global_icv
.dyn_var
);
484 parse_boolean ("OMP_NESTED", &gomp_global_icv
.nest_var
);
485 parse_unsigned_long ("OMP_MAX_ACTIVE_LEVELS", &gomp_max_active_levels_var
,
487 parse_unsigned_long ("OMP_THREAD_LIMIT", &gomp_thread_limit_var
, false);
488 if (gomp_thread_limit_var
!= ULONG_MAX
)
489 gomp_remaining_threads_count
= gomp_thread_limit_var
- 1;
490 #ifndef HAVE_SYNC_BUILTINS
491 gomp_mutex_init (&gomp_remaining_threads_lock
);
493 gomp_init_num_threads ();
494 gomp_available_cpus
= gomp_global_icv
.nthreads_var
;
495 if (!parse_unsigned_long ("OMP_NUM_THREADS", &gomp_global_icv
.nthreads_var
,
497 gomp_global_icv
.nthreads_var
= gomp_available_cpus
;
498 if (parse_affinity ())
499 gomp_init_affinity ();
500 wait_policy
= parse_wait_policy ();
501 if (!parse_spincount ("GOMP_SPINCOUNT", &gomp_spin_count_var
))
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. */
510 gomp_spin_count_var
= 30000000000LL;
511 else if (wait_policy
< 0)
512 gomp_spin_count_var
= 20000000LL;
514 /* gomp_throttled_spin_count_var is used when there are more libgomp
515 managed threads than available CPUs. Use very short spinning. */
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
;
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
);
527 if (parse_stacksize ("OMP_STACKSIZE", &stacksize
)
528 || parse_stacksize ("GOMP_STACKSIZE", &stacksize
))
532 err
= pthread_attr_setstacksize (&gomp_thread_attr
, stacksize
);
534 #ifdef PTHREAD_STACK_MIN
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));
542 gomp_error ("Stack size larger than system limit");
547 gomp_error ("Stack size change failed: %s", strerror (err
));
552 /* The public OpenMP API routines that access these variables. */
555 omp_set_num_threads (int n
)
557 struct gomp_task_icv
*icv
= gomp_icv (true);
558 icv
->nthreads_var
= (n
> 0 ? n
: 1);
562 omp_set_dynamic (int val
)
564 struct gomp_task_icv
*icv
= gomp_icv (true);
569 omp_get_dynamic (void)
571 struct gomp_task_icv
*icv
= gomp_icv (false);
576 omp_set_nested (int val
)
578 struct gomp_task_icv
*icv
= gomp_icv (true);
583 omp_get_nested (void)
585 struct gomp_task_icv
*icv
= gomp_icv (false);
586 return icv
->nest_var
;
590 omp_set_schedule (omp_sched_t kind
, int modifier
)
592 struct gomp_task_icv
*icv
= gomp_icv (true);
595 case omp_sched_static
:
598 icv
->run_sched_modifier
= modifier
;
600 case omp_sched_dynamic
:
601 case omp_sched_guided
:
604 icv
->run_sched_modifier
= modifier
;
611 icv
->run_sched_var
= kind
;
615 omp_get_schedule (omp_sched_t
*kind
, int *modifier
)
617 struct gomp_task_icv
*icv
= gomp_icv (false);
618 *kind
= icv
->run_sched_var
;
619 *modifier
= icv
->run_sched_modifier
;
623 omp_get_max_threads (void)
625 struct gomp_task_icv
*icv
= gomp_icv (false);
626 return icv
->nthreads_var
;
630 omp_get_thread_limit (void)
632 return gomp_thread_limit_var
> INT_MAX
? INT_MAX
: gomp_thread_limit_var
;
636 omp_set_max_active_levels (int max_levels
)
639 gomp_max_active_levels_var
= max_levels
;
643 omp_get_max_active_levels (void)
645 return gomp_max_active_levels_var
;
648 ialias (omp_set_dynamic
)
649 ialias (omp_set_nested
)
650 ialias (omp_set_num_threads
)
651 ialias (omp_get_dynamic
)
652 ialias (omp_get_nested
)
653 ialias (omp_set_schedule
)
654 ialias (omp_get_schedule
)
655 ialias (omp_get_max_threads
)
656 ialias (omp_get_thread_limit
)
657 ialias (omp_set_max_active_levels
)
658 ialias (omp_get_max_active_levels
)