00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029 #include "libgomp.h"
00030 #include "libgomp_f.h"
00031 #include <ctype.h>
00032 #include <stdlib.h>
00033 #ifdef STRING_WITH_STRINGS
00034 # include <string.h>
00035 # include <strings.h>
00036 #else
00037 # ifdef HAVE_STRING_H
00038 # include <string.h>
00039 # else
00040 # ifdef HAVE_STRINGS_H
00041 # include <strings.h>
00042 # endif
00043 # endif
00044 #endif
00045 #include <limits.h>
00046 #include <errno.h>
00047
00048 #ifndef HAVE_STRTOULL
00049 # define strtoull(ptr, eptr, base) strtoul (ptr, eptr, base)
00050 #endif
00051
00052 struct gomp_task_icv gomp_global_icv = {
00053 .nthreads_var = 1,
00054 .run_sched_var = GFS_DYNAMIC,
00055 .run_sched_modifier = 1,
00056 .dyn_var = false,
00057 .nest_var = false
00058 };
00059
00060 unsigned short *gomp_cpu_affinity;
00061 size_t gomp_cpu_affinity_len;
00062 unsigned long gomp_max_active_levels_var = INT_MAX;
00063 unsigned long gomp_thread_limit_var = ULONG_MAX;
00064 unsigned long gomp_remaining_threads_count;
00065 #ifndef HAVE_SYNC_BUILTINS
00066 gomp_mutex_t gomp_remaining_threads_lock;
00067 #endif
00068 unsigned long gomp_available_cpus = 1, gomp_managed_threads = 1;
00069 unsigned long long gomp_spin_count_var, gomp_throttled_spin_count_var;
00070
00071
00072
00073 static void
00074 parse_schedule (void)
00075 {
00076 char *env, *end;
00077 unsigned long value;
00078
00079 env = getenv ("OMP_SCHEDULE");
00080 if (env == NULL)
00081 return;
00082
00083 while (isspace ((unsigned char) *env))
00084 ++env;
00085 if (strncasecmp (env, "static", 6) == 0)
00086 {
00087 gomp_global_icv.run_sched_var = GFS_STATIC;
00088 env += 6;
00089 }
00090 else if (strncasecmp (env, "dynamic", 7) == 0)
00091 {
00092 gomp_global_icv.run_sched_var = GFS_DYNAMIC;
00093 env += 7;
00094 }
00095 else if (strncasecmp (env, "guided", 6) == 0)
00096 {
00097 gomp_global_icv.run_sched_var = GFS_GUIDED;
00098 env += 6;
00099 }
00100 else if (strncasecmp (env, "auto", 4) == 0)
00101 {
00102 gomp_global_icv.run_sched_var = GFS_AUTO;
00103 env += 4;
00104 }
00105 else
00106 goto unknown;
00107
00108 while (isspace ((unsigned char) *env))
00109 ++env;
00110 if (*env == '\0')
00111 return;
00112 if (*env++ != ',')
00113 goto unknown;
00114 while (isspace ((unsigned char) *env))
00115 ++env;
00116 if (*env == '\0')
00117 goto invalid;
00118
00119 errno = 0;
00120 value = strtoul (env, &end, 10);
00121 if (errno)
00122 goto invalid;
00123
00124 while (isspace ((unsigned char) *end))
00125 ++end;
00126 if (*end != '\0')
00127 goto invalid;
00128
00129 if ((int)value != value)
00130 goto invalid;
00131
00132 gomp_global_icv.run_sched_modifier = value;
00133 return;
00134
00135 unknown:
00136 gomp_error ("Unknown value for environment variable OMP_SCHEDULE");
00137 return;
00138
00139 invalid:
00140 gomp_error ("Invalid value for chunk size in "
00141 "environment variable OMP_SCHEDULE");
00142 return;
00143 }
00144
00145
00146
00147
00148 static bool
00149 parse_unsigned_long (const char *name, unsigned long *pvalue, bool allow_zero)
00150 {
00151 char *env, *end;
00152 unsigned long value;
00153
00154 env = getenv (name);
00155 if (env == NULL)
00156 return false;
00157
00158 while (isspace ((unsigned char) *env))
00159 ++env;
00160 if (*env == '\0')
00161 goto invalid;
00162
00163 errno = 0;
00164 value = strtoul (env, &end, 10);
00165 if (errno || (long) value <= 0 - allow_zero)
00166 goto invalid;
00167
00168 while (isspace ((unsigned char) *end))
00169 ++end;
00170 if (*end != '\0')
00171 goto invalid;
00172
00173 *pvalue = value;
00174 return true;
00175
00176 invalid:
00177 gomp_error ("Invalid value for environment variable %s", name);
00178 return false;
00179 }
00180
00181
00182
00183
00184 static bool
00185 parse_stacksize (const char *name, unsigned long *pvalue)
00186 {
00187 char *env, *end;
00188 unsigned long value, shift = 10;
00189
00190 env = getenv (name);
00191 if (env == NULL)
00192 return false;
00193
00194 while (isspace ((unsigned char) *env))
00195 ++env;
00196 if (*env == '\0')
00197 goto invalid;
00198
00199 errno = 0;
00200 value = strtoul (env, &end, 10);
00201 if (errno)
00202 goto invalid;
00203
00204 while (isspace ((unsigned char) *end))
00205 ++end;
00206 if (*end != '\0')
00207 {
00208 switch (tolower ((unsigned char) *end))
00209 {
00210 case 'b':
00211 shift = 0;
00212 break;
00213 case 'k':
00214 break;
00215 case 'm':
00216 shift = 20;
00217 break;
00218 case 'g':
00219 shift = 30;
00220 break;
00221 default:
00222 goto invalid;
00223 }
00224 ++end;
00225 while (isspace ((unsigned char) *end))
00226 ++end;
00227 if (*end != '\0')
00228 goto invalid;
00229 }
00230
00231 if (((value << shift) >> shift) != value)
00232 goto invalid;
00233
00234 *pvalue = value << shift;
00235 return true;
00236
00237 invalid:
00238 gomp_error ("Invalid value for environment variable %s", name);
00239 return false;
00240 }
00241
00242
00243
00244
00245 static bool
00246 parse_spincount (const char *name, unsigned long long *pvalue)
00247 {
00248 char *env, *end;
00249 unsigned long long value, mult = 1;
00250
00251 env = getenv (name);
00252 if (env == NULL)
00253 return false;
00254
00255 while (isspace ((unsigned char) *env))
00256 ++env;
00257 if (*env == '\0')
00258 goto invalid;
00259
00260 if (strncasecmp (env, "infinite", 8) == 0
00261 || strncasecmp (env, "infinity", 8) == 0)
00262 {
00263 value = ~0ULL;
00264 end = env + 8;
00265 goto check_tail;
00266 }
00267
00268 errno = 0;
00269 value = strtoull (env, &end, 10);
00270 if (errno)
00271 goto invalid;
00272
00273 while (isspace ((unsigned char) *end))
00274 ++end;
00275 if (*end != '\0')
00276 {
00277 switch (tolower ((unsigned char) *end))
00278 {
00279 case 'k':
00280 mult = 1000LL;
00281 break;
00282 case 'm':
00283 mult = 1000LL * 1000LL;
00284 break;
00285 case 'g':
00286 mult = 1000LL * 1000LL * 1000LL;
00287 break;
00288 case 't':
00289 mult = 1000LL * 1000LL * 1000LL * 1000LL;
00290 break;
00291 default:
00292 goto invalid;
00293 }
00294 ++end;
00295 check_tail:
00296 while (isspace ((unsigned char) *end))
00297 ++end;
00298 if (*end != '\0')
00299 goto invalid;
00300 }
00301
00302 if (value > ~0ULL / mult)
00303 value = ~0ULL;
00304 else
00305 value *= mult;
00306
00307 *pvalue = value;
00308 return true;
00309
00310 invalid:
00311 gomp_error ("Invalid value for environment variable %s", name);
00312 return false;
00313 }
00314
00315
00316
00317
00318 static void
00319 parse_boolean (const char *name, bool *value)
00320 {
00321 const char *env;
00322
00323 env = getenv (name);
00324 if (env == NULL)
00325 return;
00326
00327 while (isspace ((unsigned char) *env))
00328 ++env;
00329 if (strncasecmp (env, "true", 4) == 0)
00330 {
00331 *value = true;
00332 env += 4;
00333 }
00334 else if (strncasecmp (env, "false", 5) == 0)
00335 {
00336 *value = false;
00337 env += 5;
00338 }
00339 else
00340 env = "X";
00341 while (isspace ((unsigned char) *env))
00342 ++env;
00343 if (*env != '\0')
00344 gomp_error ("Invalid value for environment variable %s", name);
00345 }
00346
00347
00348
00349
00350 static int
00351 parse_wait_policy (void)
00352 {
00353 const char *env;
00354 int ret = -1;
00355
00356 env = getenv ("OMP_WAIT_POLICY");
00357 if (env == NULL)
00358 return -1;
00359
00360 while (isspace ((unsigned char) *env))
00361 ++env;
00362 if (strncasecmp (env, "active", 6) == 0)
00363 {
00364 ret = 1;
00365 env += 6;
00366 }
00367 else if (strncasecmp (env, "passive", 7) == 0)
00368 {
00369 ret = 0;
00370 env += 7;
00371 }
00372 else
00373 env = "X";
00374 while (isspace ((unsigned char) *env))
00375 ++env;
00376 if (*env == '\0')
00377 return ret;
00378 gomp_error ("Invalid value for environment variable OMP_WAIT_POLICY");
00379 return -1;
00380 }
00381
00382
00383
00384
00385 static bool
00386 parse_affinity (void)
00387 {
00388 char *env, *end;
00389 unsigned long cpu_beg, cpu_end, cpu_stride;
00390 unsigned short *cpus = NULL;
00391 size_t allocated = 0, used = 0, needed;
00392
00393 env = getenv ("GOMP_CPU_AFFINITY");
00394 if (env == NULL)
00395 return false;
00396
00397 do
00398 {
00399 while (*env == ' ' || *env == '\t')
00400 env++;
00401
00402 cpu_beg = strtoul (env, &end, 0);
00403 cpu_end = cpu_beg;
00404 cpu_stride = 1;
00405 if (env == end || cpu_beg >= 65536)
00406 goto invalid;
00407
00408 env = end;
00409 if (*env == '-')
00410 {
00411 cpu_end = strtoul (++env, &end, 0);
00412 if (env == end || cpu_end >= 65536 || cpu_end < cpu_beg)
00413 goto invalid;
00414
00415 env = end;
00416 if (*env == ':')
00417 {
00418 cpu_stride = strtoul (++env, &end, 0);
00419 if (env == end || cpu_stride == 0 || cpu_stride >= 65536)
00420 goto invalid;
00421
00422 env = end;
00423 }
00424 }
00425
00426 needed = (cpu_end - cpu_beg) / cpu_stride + 1;
00427 if (used + needed >= allocated)
00428 {
00429 unsigned short *new_cpus;
00430
00431 if (allocated < 64)
00432 allocated = 64;
00433 if (allocated > needed)
00434 allocated <<= 1;
00435 else
00436 allocated += 2 * needed;
00437 new_cpus = realloc (cpus, allocated * sizeof (unsigned short));
00438 if (new_cpus == NULL)
00439 {
00440 free (cpus);
00441 gomp_error ("not enough memory to store GOMP_CPU_AFFINITY list");
00442 return false;
00443 }
00444
00445 cpus = new_cpus;
00446 }
00447
00448 while (needed--)
00449 {
00450 cpus[used++] = cpu_beg;
00451 cpu_beg += cpu_stride;
00452 }
00453
00454 while (*env == ' ' || *env == '\t')
00455 env++;
00456
00457 if (*env == ',')
00458 env++;
00459 else if (*env == '\0')
00460 break;
00461 }
00462 while (1);
00463
00464 gomp_cpu_affinity = cpus;
00465 gomp_cpu_affinity_len = used;
00466 return true;
00467
00468 invalid:
00469 gomp_error ("Invalid value for enviroment variable GOMP_CPU_AFFINITY");
00470 return false;
00471 }
00472
00473 static void __attribute__((constructor))
00474 initialize_env (void)
00475 {
00476 unsigned long stacksize;
00477 int wait_policy;
00478
00479
00480 omp_check_defines ();
00481
00482 parse_schedule ();
00483 parse_boolean ("OMP_DYNAMIC", &gomp_global_icv.dyn_var);
00484 parse_boolean ("OMP_NESTED", &gomp_global_icv.nest_var);
00485 parse_unsigned_long ("OMP_MAX_ACTIVE_LEVELS", &gomp_max_active_levels_var,
00486 true);
00487 parse_unsigned_long ("OMP_THREAD_LIMIT", &gomp_thread_limit_var, false);
00488 if (gomp_thread_limit_var != ULONG_MAX)
00489 gomp_remaining_threads_count = gomp_thread_limit_var - 1;
00490 #ifndef HAVE_SYNC_BUILTINS
00491 gomp_mutex_init (&gomp_remaining_threads_lock);
00492 #endif
00493 gomp_init_num_threads ();
00494 gomp_available_cpus = gomp_global_icv.nthreads_var;
00495 if (!parse_unsigned_long ("OMP_NUM_THREADS", &gomp_global_icv.nthreads_var,
00496 false))
00497 gomp_global_icv.nthreads_var = gomp_available_cpus;
00498 if (parse_affinity ())
00499 gomp_init_affinity ();
00500 wait_policy = parse_wait_policy ();
00501 if (!parse_spincount ("GOMP_SPINCOUNT", &gomp_spin_count_var))
00502 {
00503
00504
00505
00506
00507
00508
00509 if (wait_policy > 0)
00510 gomp_spin_count_var = 30000000000LL;
00511 else if (wait_policy < 0)
00512 gomp_spin_count_var = 300000LL;
00513 }
00514
00515
00516 if (wait_policy > 0)
00517 gomp_throttled_spin_count_var = 1000LL;
00518 else if (wait_policy < 0)
00519 gomp_throttled_spin_count_var = 100LL;
00520 if (gomp_throttled_spin_count_var > gomp_spin_count_var)
00521 gomp_throttled_spin_count_var = gomp_spin_count_var;
00522
00523
00524 pthread_attr_init (&gomp_thread_attr);
00525 pthread_attr_setdetachstate (&gomp_thread_attr, PTHREAD_CREATE_DETACHED);
00526
00527 if (parse_stacksize ("OMP_STACKSIZE", &stacksize)
00528 || parse_stacksize ("GOMP_STACKSIZE", &stacksize))
00529 {
00530 int err;
00531
00532 err = pthread_attr_setstacksize (&gomp_thread_attr, stacksize);
00533
00534 #ifdef PTHREAD_STACK_MIN
00535 if (err == EINVAL)
00536 {
00537 if (stacksize < PTHREAD_STACK_MIN)
00538 gomp_error ("Stack size less than minimum of %luk",
00539 PTHREAD_STACK_MIN / 1024ul
00540 + (PTHREAD_STACK_MIN % 1024 != 0));
00541 else
00542 gomp_error ("Stack size larger than system limit");
00543 }
00544 else
00545 #endif
00546 if (err != 0)
00547 gomp_error ("Stack size change failed: %s", strerror (err));
00548 }
00549 }
00550
00551
00552
00553
00554 void
00555 omp_set_num_threads (int n)
00556 {
00557 struct gomp_task_icv *icv = gomp_icv (true);
00558 icv->nthreads_var = (n > 0 ? n : 1);
00559 }
00560
00561 void
00562 omp_set_dynamic (int val)
00563 {
00564 struct gomp_task_icv *icv = gomp_icv (true);
00565 icv->dyn_var = val;
00566 }
00567
00568 int
00569 omp_get_dynamic (void)
00570 {
00571 struct gomp_task_icv *icv = gomp_icv (false);
00572 return icv->dyn_var;
00573 }
00574
00575 void
00576 omp_set_nested (int val)
00577 {
00578 struct gomp_task_icv *icv = gomp_icv (true);
00579 icv->nest_var = val;
00580 }
00581
00582 int
00583 omp_get_nested (void)
00584 {
00585 struct gomp_task_icv *icv = gomp_icv (false);
00586 return icv->nest_var;
00587 }
00588
00589 void
00590 omp_set_schedule (omp_sched_t kind, int modifier)
00591 {
00592 struct gomp_task_icv *icv = gomp_icv (true);
00593 switch (kind)
00594 {
00595 case omp_sched_static:
00596 if (modifier < 1)
00597 modifier = 0;
00598 icv->run_sched_modifier = modifier;
00599 break;
00600 case omp_sched_dynamic:
00601 case omp_sched_guided:
00602 if (modifier < 1)
00603 modifier = 1;
00604 icv->run_sched_modifier = modifier;
00605 break;
00606 case omp_sched_auto:
00607 break;
00608 default:
00609 return;
00610 }
00611 icv->run_sched_var = kind;
00612 }
00613
00614 void
00615 omp_get_schedule (omp_sched_t *kind, int *modifier)
00616 {
00617 struct gomp_task_icv *icv = gomp_icv (false);
00618 *kind = icv->run_sched_var;
00619 *modifier = icv->run_sched_modifier;
00620 }
00621
00622 int
00623 omp_get_max_threads (void)
00624 {
00625 struct gomp_task_icv *icv = gomp_icv (false);
00626 return icv->nthreads_var;
00627 }
00628
00629 int
00630 omp_get_thread_limit (void)
00631 {
00632 return gomp_thread_limit_var > INT_MAX ? INT_MAX : gomp_thread_limit_var;
00633 }
00634
00635 void
00636 omp_set_max_active_levels (int max_levels)
00637 {
00638 if (max_levels >= 0)
00639 gomp_max_active_levels_var = max_levels;
00640 }
00641
00642 int
00643 omp_get_max_active_levels (void)
00644 {
00645 return gomp_max_active_levels_var;
00646 }
00647
00648 ialias (omp_set_dynamic)
00649 ialias (omp_set_nested)
00650 ialias (omp_set_num_threads)
00651 ialias (omp_get_dynamic)
00652 ialias (omp_get_nested)
00653 ialias (omp_set_schedule)
00654 ialias (omp_get_schedule)
00655 ialias (omp_get_max_threads)
00656 ialias (omp_get_thread_limit)
00657 ialias (omp_set_max_active_levels)
00658 ialias (omp_get_max_active_levels)