env.c

Go to the documentation of this file.
00001 /* Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010
00002    Free Software Foundation, Inc.
00003    Contributed by Richard Henderson <rth@redhat.com>.
00004 
00005    This file is part of the GNU OpenMP Library (libgomp).
00006 
00007    Libgomp is free software; you can redistribute it and/or modify it
00008    under the terms of the GNU General Public License as published by
00009    the Free Software Foundation; either version 3, or (at your option)
00010    any later version.
00011 
00012    Libgomp is distributed in the hope that it will be useful, but WITHOUT ANY
00013    WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
00014    FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
00015    more details.
00016 
00017    Under Section 7 of GPL version 3, you are granted additional
00018    permissions described in the GCC Runtime Library Exception, version
00019    3.1, as published by the Free Software Foundation.
00020 
00021    You should have received a copy of the GNU General Public License and
00022    a copy of the GCC Runtime Library Exception along with this program;
00023    see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
00024    <http://www.gnu.org/licenses/>.  */
00025 
00026 /* This file defines the OpenMP internal control variables, and arranges
00027    for them to be initialized from environment variables at startup.  */
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 /* Parse the OMP_SCHEDULE environment variable.  */
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 /* Parse an unsigned long environment variable.  Return true if one was
00146    present and it was successfully parsed.  */
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 /* Parse the OMP_STACKSIZE environment varible.  Return true if one was
00182    present and it was successfully parsed.  */
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 /* Parse the GOMP_SPINCOUNT environment varible.  Return true if one was
00243    present and it was successfully parsed.  */
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 /* Parse a boolean value for environment variable NAME and store the
00316    result in VALUE.  */
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 /* Parse the OMP_WAIT_POLICY environment variable and store the
00348    result in gomp_active_wait_policy.  */
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 /* Parse the GOMP_CPU_AFFINITY environment varible.  Return true if one was
00383    present and it was successfully parsed.  */
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   /* Do a compile time check that mkomp_h.pl did good job.  */
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       /* Using a rough estimation of 100000 spins per msec,
00504      use 5 min blocking for OMP_WAIT_POLICY=active,
00505      3 msec blocking when OMP_WAIT_POLICY is not specificed
00506      and 0 when OMP_WAIT_POLICY=passive.
00507      Depending on the CPU speed, this can be e.g. 5 times longer
00508      or 5 times shorter.  */
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   /* gomp_throttled_spin_count_var is used when there are more libgomp
00515      managed threads than available CPUs.  Use very short spinning.  */
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   /* Not strictly environment related, but ordering constructors is tricky.  */
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 /* The public OpenMP API routines that access these variables.  */
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)

Generated on Fri Apr 5 05:38:09 2013 for Libgomp by  doxygen 1.4.7