1 /* Copyright (C) 2005, 2006, 2007, 2008, 2009 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 General Public License as published by
8 the Free Software Foundation; either version 3, or (at your option)
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 General Public License for
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.
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/>. */
25 /* This file defines the OpenMP internal control variables, and arranges
26 for them to be initialized from environment variables at startup. */
29 #include "libgomp_f.h"
32 #ifdef STRING_WITH_STRINGS
39 # ifdef HAVE_STRINGS_H
48 # define strtoull(ptr, eptr, base) strtoul (ptr, eptr, base)
51 struct gomp_task_icv gomp_global_icv
= {
53 .run_sched_var
= GFS_DYNAMIC
,
54 .run_sched_modifier
= 1,
59 unsigned short *gomp_cpu_affinity
;
60 size_t gomp_cpu_affinity_len
;
61 unsigned long gomp_max_active_levels_var
= INT_MAX
;
62 unsigned long gomp_thread_limit_var
= ULONG_MAX
;
63 unsigned long gomp_remaining_threads_count
;
64 #ifndef HAVE_SYNC_BUILTINS
65 gomp_mutex_t gomp_remaining_threads_lock
;
67 unsigned long gomp_available_cpus
= 1, gomp_managed_threads
= 1;
68 unsigned long long gomp_spin_count_var
, gomp_throttled_spin_count_var
;
70 /* Parse the OMP_SCHEDULE environment variable. */
78 env
= getenv ("OMP_SCHEDULE");
82 while (isspace ((unsigned char) *env
))
84 if (strncasecmp (env
, "static", 6) == 0)
86 gomp_global_icv
.run_sched_var
= GFS_STATIC
;
89 else if (strncasecmp (env
, "dynamic", 7) == 0)
91 gomp_global_icv
.run_sched_var
= GFS_DYNAMIC
;
94 else if (strncasecmp (env
, "guided", 6) == 0)
96 gomp_global_icv
.run_sched_var
= GFS_GUIDED
;
99 else if (strncasecmp (env
, "auto", 4) == 0)
101 gomp_global_icv
.run_sched_var
= GFS_AUTO
;
107 while (isspace ((unsigned char) *env
))
113 while (isspace ((unsigned char) *env
))
119 value
= strtoul (env
, &end
, 10);
123 while (isspace ((unsigned char) *end
))
128 if ((int)value
!= value
)
131 gomp_global_icv
.run_sched_modifier
= value
;
135 gomp_error ("Unknown value for environment variable OMP_SCHEDULE");
139 gomp_error ("Invalid value for chunk size in "
140 "environment variable OMP_SCHEDULE");
144 /* Parse an unsigned long environment variable. Return true if one was
145 present and it was successfully parsed. */
148 parse_unsigned_long (const char *name
, unsigned long *pvalue
)
157 while (isspace ((unsigned char) *env
))
163 value
= strtoul (env
, &end
, 10);
164 if (errno
|| (long) value
<= 0)
167 while (isspace ((unsigned char) *end
))
176 gomp_error ("Invalid value for environment variable %s", name
);
180 /* Parse the OMP_STACKSIZE environment varible. Return true if one was
181 present and it was successfully parsed. */
184 parse_stacksize (const char *name
, unsigned long *pvalue
)
187 unsigned long value
, shift
= 10;
193 while (isspace ((unsigned char) *env
))
199 value
= strtoul (env
, &end
, 10);
203 while (isspace ((unsigned char) *end
))
207 switch (tolower ((unsigned char) *end
))
224 while (isspace ((unsigned char) *end
))
230 if (((value
<< shift
) >> shift
) != value
)
233 *pvalue
= value
<< shift
;
237 gomp_error ("Invalid value for environment variable %s", name
);
241 /* Parse the GOMP_SPINCOUNT environment varible. Return true if one was
242 present and it was successfully parsed. */
245 parse_spincount (const char *name
, unsigned long long *pvalue
)
248 unsigned long long value
, mult
= 1;
254 while (isspace ((unsigned char) *env
))
259 if (strncasecmp (env
, "infinite", 8) == 0
260 || strncasecmp (env
, "infinity", 8) == 0)
268 value
= strtoull (env
, &end
, 10);
272 while (isspace ((unsigned char) *end
))
276 switch (tolower ((unsigned char) *end
))
282 mult
= 1000LL * 1000LL;
285 mult
= 1000LL * 1000LL * 1000LL;
288 mult
= 1000LL * 1000LL * 1000LL * 1000LL;
295 while (isspace ((unsigned char) *end
))
301 if (value
> ~0ULL / mult
)
310 gomp_error ("Invalid value for environment variable %s", name
);
314 /* Parse a boolean value for environment variable NAME and store the
318 parse_boolean (const char *name
, bool *value
)
326 while (isspace ((unsigned char) *env
))
328 if (strncasecmp (env
, "true", 4) == 0)
333 else if (strncasecmp (env
, "false", 5) == 0)
340 while (isspace ((unsigned char) *env
))
343 gomp_error ("Invalid value for environment variable %s", name
);
346 /* Parse the OMP_WAIT_POLICY environment variable and store the
347 result in gomp_active_wait_policy. */
350 parse_wait_policy (void)
355 env
= getenv ("OMP_WAIT_POLICY");
359 while (isspace ((unsigned char) *env
))
361 if (strncasecmp (env
, "active", 6) == 0)
366 else if (strncasecmp (env
, "passive", 7) == 0)
373 while (isspace ((unsigned char) *env
))
377 gomp_error ("Invalid value for environment variable OMP_WAIT_POLICY");
381 /* Parse the GOMP_CPU_AFFINITY environment varible. Return true if one was
382 present and it was successfully parsed. */
385 parse_affinity (void)
388 unsigned long cpu_beg
, cpu_end
, cpu_stride
;
389 unsigned short *cpus
= NULL
;
390 size_t allocated
= 0, used
= 0, needed
;
392 env
= getenv ("GOMP_CPU_AFFINITY");
398 while (*env
== ' ' || *env
== '\t')
401 cpu_beg
= strtoul (env
, &end
, 0);
404 if (env
== end
|| cpu_beg
>= 65536)
410 cpu_end
= strtoul (++env
, &end
, 0);
411 if (env
== end
|| cpu_end
>= 65536 || cpu_end
< cpu_beg
)
417 cpu_stride
= strtoul (++env
, &end
, 0);
418 if (env
== end
|| cpu_stride
== 0 || cpu_stride
>= 65536)
425 needed
= (cpu_end
- cpu_beg
) / cpu_stride
+ 1;
426 if (used
+ needed
>= allocated
)
428 unsigned short *new_cpus
;
432 if (allocated
> needed
)
435 allocated
+= 2 * needed
;
436 new_cpus
= realloc (cpus
, allocated
* sizeof (unsigned short));
437 if (new_cpus
== NULL
)
440 gomp_error ("not enough memory to store GOMP_CPU_AFFINITY list");
449 cpus
[used
++] = cpu_beg
;
450 cpu_beg
+= cpu_stride
;
453 while (*env
== ' ' || *env
== '\t')
458 else if (*env
== '\0')
463 gomp_cpu_affinity
= cpus
;
464 gomp_cpu_affinity_len
= used
;
468 gomp_error ("Invalid value for enviroment variable GOMP_CPU_AFFINITY");
472 static void __attribute__((constructor
))
473 initialize_env (void)
475 unsigned long stacksize
;
478 /* Do a compile time check that mkomp_h.pl did good job. */
479 omp_check_defines ();
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
)
487 gomp_remaining_threads_count
= gomp_thread_limit_var
- 1;
488 #ifndef HAVE_SYNC_BUILTINS
489 gomp_mutex_init (&gomp_remaining_threads_lock
);
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
;
495 if (parse_affinity ())
496 gomp_init_affinity ();
497 wait_policy
= parse_wait_policy ();
498 if (!parse_spincount ("GOMP_SPINCOUNT", &gomp_spin_count_var
))
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. */
507 gomp_spin_count_var
= 30000000000LL;
508 else if (wait_policy
< 0)
509 gomp_spin_count_var
= 20000000LL;
511 /* gomp_throttled_spin_count_var is used when there are more libgomp
512 managed threads than available CPUs. Use very short spinning. */
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
;
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
);
524 if (parse_stacksize ("OMP_STACKSIZE", &stacksize
)
525 || parse_stacksize ("GOMP_STACKSIZE", &stacksize
))
529 err
= pthread_attr_setstacksize (&gomp_thread_attr
, stacksize
);
531 #ifdef PTHREAD_STACK_MIN
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));
539 gomp_error ("Stack size larger than system limit");
544 gomp_error ("Stack size change failed: %s", strerror (err
));
549 /* The public OpenMP API routines that access these variables. */
552 omp_set_num_threads (int n
)
554 struct gomp_task_icv
*icv
= gomp_icv (true);
555 icv
->nthreads_var
= (n
> 0 ? n
: 1);
559 omp_set_dynamic (int val
)
561 struct gomp_task_icv
*icv
= gomp_icv (true);
566 omp_get_dynamic (void)
568 struct gomp_task_icv
*icv
= gomp_icv (false);
573 omp_set_nested (int val
)
575 struct gomp_task_icv
*icv
= gomp_icv (true);
580 omp_get_nested (void)
582 struct gomp_task_icv
*icv
= gomp_icv (false);
583 return icv
->nest_var
;
587 omp_set_schedule (omp_sched_t kind
, int modifier
)
589 struct gomp_task_icv
*icv
= gomp_icv (true);
592 case omp_sched_static
:
595 icv
->run_sched_modifier
= modifier
;
597 case omp_sched_dynamic
:
598 case omp_sched_guided
:
601 icv
->run_sched_modifier
= modifier
;
608 icv
->run_sched_var
= kind
;
612 omp_get_schedule (omp_sched_t
*kind
, int *modifier
)
614 struct gomp_task_icv
*icv
= gomp_icv (false);
615 *kind
= icv
->run_sched_var
;
616 *modifier
= icv
->run_sched_modifier
;
620 omp_get_max_threads (void)
622 struct gomp_task_icv
*icv
= gomp_icv (false);
623 return icv
->nthreads_var
;
627 omp_get_thread_limit (void)
629 return gomp_thread_limit_var
> INT_MAX
? INT_MAX
: gomp_thread_limit_var
;
633 omp_set_max_active_levels (int max_levels
)
636 gomp_max_active_levels_var
= max_levels
;
640 omp_get_max_active_levels (void)
642 return gomp_max_active_levels_var
;
645 ialias (omp_set_dynamic
)
646 ialias (omp_set_nested
)
647 ialias (omp_set_num_threads
)
648 ialias (omp_get_dynamic
)
649 ialias (omp_get_nested
)
650 ialias (omp_set_schedule
)
651 ialias (omp_get_schedule
)
652 ialias (omp_get_max_threads
)
653 ialias (omp_get_thread_limit
)
654 ialias (omp_set_max_active_levels
)
655 ialias (omp_get_max_active_levels
)