Sierra Toolkit Version of the Day
Platform.cpp
00001 
00010 #include <pwd.h>
00011 #include <unistd.h>
00012 
00013 #include <iostream>
00014 #include <ostream>
00015 #include <fstream>
00016 #include <sstream>
00017 #include <cstring>
00018 #include <cstdlib>
00019 #include <stdexcept>
00020 #include <iomanip>
00021 #include <algorithm>
00022 #include <locale>
00023 
00024 #include <stk_util/util/FeatureTest.hpp>
00025 #include <stk_util/diag/Env.hpp>
00026 #include <stk_util/diag/Platform.hpp>
00027 #include <stk_util/parallel/Exception.hpp>
00028 #include <stk_util/parallel/ExceptionReport.hpp>
00029 #include <stk_util/parallel/MPI.hpp>
00030 #ifdef STK_BUILT_IN_SIERRA
00031 #  include <stk_util/parallel/mpih.hpp>
00032 #endif
00033 #include <stk_util/environment/ProductRegistry.hpp>
00034 
00035 #include <stk_util/diag/Writer.hpp>
00036 #include <stk_util/diag/SlibDiagWriter.hpp>
00037 #include <stk_util/diag/Timer.hpp>
00038 #include <stk_util/diag/Trace.hpp>
00039 
00040 #include <fcntl.h>
00041 
00042 #if defined(__GNUC__)
00043 #include <fstream>
00044 #ifndef __APPLE__
00045 #include <malloc.h>
00046 #else
00047 #include <sys/malloc.h>
00048 #endif
00049 #include <cstdlib>
00050 #include <sys/time.h>
00051 #include <sys/resource.h>
00052 #if __GNUC__ == 3 || __GNUC__ == 4
00053 #include <cxxabi.h>
00054 #endif
00055 
00056 #elif defined(__PGI)
00057 #include <fstream>
00058 #include <malloc.h>
00059 #include <cstdlib>
00060 #include <sys/time.h>
00061 #include <sys/resource.h>
00062 
00063 #elif defined(__sun)
00064 #include <fstream>
00065 #include <procfs.h>
00066 #include <sys/resource.h>
00067 #include <sys/systeminfo.h>
00068 #include <sys/utsname.h>
00069 #include <sys/time.h>
00070 
00071 #elif defined(__SUNPRO_CC)
00072 #include <sys/resource.h>
00073 #include <sys/time.h>
00074 #include <sys/utsname.h>
00075 #include <netdb.h>
00076 #endif
00077 
00078 #if defined(__PUMAGON__)
00079 extern "C" {
00080 #include <util.h>
00081 #include <sys/param.h>
00082 }
00083 
00084 #elif defined(__sgi)
00085 #include <sys/time.h>
00086 #include <sys/resource.h>
00087 
00088 #elif defined(REDS)
00089 #include <sys/param.h>
00090 #include <sys/utsname.h>
00091 #include <sys/time.h>
00092 #include <sys/resource.h>
00093 #include <unistd.h>
00094 #include <catamount/catmalloc.h>
00095 extern void *__heap_start;    
00096 extern void *__heap_end;    
00097 
00098 #elif defined(__JVN)
00099 #include <sys/param.h>
00100 #include <sys/utsname.h>
00101 #include <sys/time.h>
00102 #include <sys/resource.h>
00103 #include <sys/wait.h>
00104 #include <unistd.h>
00105 
00106 #elif defined(__IBMC__) || defined(__IBMCPP__)
00107 #include <sys/utsname.h>
00108 #include <sys/time.h>
00109 #include <sys/resource.h>
00110 #include <netdb.h>
00111 
00112 #else
00113 #include <sys/utsname.h>
00114 #include <sys/time.h>
00115 #include <netdb.h>
00116 #endif
00117 
00118 #include <stk_util/util/MallocUsed.h>
00119 
00120 //
00121 //  NKC 2/21/08 Some of the calls in this file bomb out purify.  Uncomment the line below if trying
00122 //  to build a purify executable.
00123 //
00124 //#define PURIFY_BUILD
00125 
00126 #if defined(REDS)
00127 namespace {
00128   size_t get_redstorm_base_available_memory();
00129 }
00130 #endif
00131 
00132 namespace sierra {
00133 
00134 #ifdef SIERRA_USE_PLATFORM_DEMANGLER
00135 
00136 
00137 #if defined(__GNUC__)
00138 
00139 #if (__GNUC__ == 3)
00140 std::string
00141 demangle(
00142   const char *  symbol)
00143 {
00144 #ifdef PURIFY_BUILD
00145   return symbol;
00146 #else
00147   std::string   s;
00148   int   status;
00149 
00150   // GR: PathScale versions 4.x.x attempt to write the length of the demangled
00151   //     string to the third argument of __cxa_demangle even if a NULL value is
00152   //     provided. This seems to be a compiler bug. The following code change
00153   //     provides a work around to prevent a segfault.
00154   //char *demangled_symbol = abi::__cxa_demangle(symbol, 0, 0, &status);
00155   size_t len = 0;
00156   char *demangled_symbol = abi::__cxa_demangle(symbol, 0, &len, &status);
00157 
00158   if (demangled_symbol) {
00159     s = std::string(demangled_symbol);
00160     free(demangled_symbol);
00161   }
00162 
00163   if (status != 0)
00164     s = std::string(symbol);
00165 
00166   return s;
00167 #endif
00168 }
00169 
00170 #elif (__GNUC__ == 4)
00171 std::string
00172 demangle(
00173   const char *  symbol)
00174 {
00175 #ifdef PURIFY_BUILD
00176   return symbol;
00177 #else
00178   std::string   s;
00179 
00180   int   status;
00181 
00182   // GR: PathScale versions 4.x.x attempt to write the length of the demangled
00183   //     string to the third argument of __cxa_demangle even if a NULL value is
00184   //     provided. This seems to be a compiler bug. The following code change
00185   //     provides a work around to prevent a segfault.
00186   //char *demangled_symbol = __cxxabiv1::__cxa_demangle(symbol, 0, 0, &status);
00187   size_t len = 0;
00188   char *demangled_symbol = __cxxabiv1::__cxa_demangle(symbol, 0, &len, &status);
00189 
00190   if (demangled_symbol) {
00191     s = std::string(demangled_symbol);
00192     free(demangled_symbol);
00193   }
00194 
00195   if (status != 0)
00196     s = std::string(symbol);
00197 
00198   return s;
00199 #endif
00200 }
00201 #endif // (__GNUC__ == 3)
00202 
00203 #else
00204 std::string demangle(const char *symbol) {
00205   return symbol;
00206 }
00207 #endif // defined(__GNUC__)
00208 
00209 #else
00210 const char *demangle(const char *symbol) {
00211   return symbol;
00212 }
00213 #endif // SIERRA_USE_PLATFORM_DEMANGLER
00214 
00215 
00216 namespace Env {
00217 
00218 #if defined(REDS)
00219 // Manipulate standard output buffering
00220 void
00221 startup_preparallel_platform()
00222 {
00223   static char redstorm_cout_buf[32678];
00224   std::cout.rdbuf()->pubsetbuf(redstorm_cout_buf, sizeof(redstorm_cout_buf));
00225 
00226   static char redstorm_stdout_buf[32678];
00227   std::setvbuf(stdout, redstorm_stdout_buf, _IOFBF, sizeof(redstorm_stdout_buf));
00228 
00229   static char redstorm_cerr_buf[32678];
00230   std::cerr.rdbuf()->pubsetbuf(redstorm_cerr_buf, sizeof(redstorm_cerr_buf));
00231 
00232   static char redstorm_stderr_buf[32678];
00233   std::setvbuf(stderr, redstorm_stderr_buf, _IOFBF, sizeof(redstorm_stderr_buf));
00234   
00235   get_available_memory();
00236 }
00237 
00238 #elif defined(_AIX)
00239 // Cleanup AIX locale initialization problems
00240 void
00241 startup_preparallel_platform()
00242 {
00243   std::locale loc("POSIX");
00244 
00245   std::locale::global(loc); // std::locale::classic());
00246   std::cout.imbue(loc); // std::locale::classic());
00247   std::cin.imbue(loc); // std::locale::classic());
00248 
00249   std::ostringstream strout;
00250   strout << "Don't ask why the IBM locale works if I do this " << 10000000 << std::endl;
00251 }
00252 
00253 #else
00254 void
00255 startup_preparallel_platform()
00256 {}
00257 #endif
00258 
00259 
00260 double
00261 wall_now()
00262 {
00263   timeval tp;
00264   struct timezone tz;
00265   gettimeofday(&tp, &tz);
00266   return (tp.tv_sec + (((double)(tp.tv_usec))/1000000.0));
00267 }
00268 
00269 
00270 double
00271 cpu_now()
00272 {
00273 #if defined(REDS)
00274   struct rusage my_rusage;
00275 
00276   getrusage(RUSAGE_SELF, &my_rusage);
00277 
00278   return (double) (my_rusage.ru_utime.tv_sec)
00279     + ((double)(my_rusage.ru_utime.tv_usec))*1.0e-6;
00280 
00281 #elif ! defined(__PGI)
00282   struct rusage my_rusage;
00283 
00284   getrusage(RUSAGE_SELF, &my_rusage);
00285 
00286   return (double) (my_rusage.ru_utime.tv_sec + my_rusage.ru_stime.tv_sec)
00287     + ((double)(my_rusage.ru_utime.tv_usec + my_rusage.ru_stime.tv_usec))*1.0e-6;
00288 #else
00289   return 0;
00290 #endif
00291 }
00292 
00293 
00294 void
00295 get_heap_info(
00296   size_t &    heap_size,
00297   size_t &    largest_free)
00298 {
00299   heap_size = 0;
00300   largest_free = 0;
00301 
00302 #if defined(SIERRA_HEAP_INFO)
00303 
00304 # if defined(SIERRA_PTMALLOC3_ALLOCATOR) || defined(SIERRA_PTMALLOC2_ALLOCATOR)
00305   heap_size = malloc_used();
00306   
00307 # elif 0 // if defined(REDS) // Redstorm now links in gnu's malloc
00308   static size_t reds_fragments;
00309   static unsigned long reds_total_free;
00310   static unsigned long reds_heap_size;
00311   static unsigned long reds_largest_free;
00312 
00313   ::heap_info(&reds_fragments, &reds_total_free, &reds_largest_free, &reds_heap_size);
00314 
00315   heap_size = reds_heap_size;
00316   largest_free = reds_largest_free;
00317 
00318   slibout.m(Slib::LOG_MEMORY) <<"reds_fragments " << reds_fragments
00319             << ", reds_total_free " << reds_total_free
00320             << ", reds_largest_free " << reds_largest_free
00321             << ", reds_heap_size " << reds_heap_size << Diag::dendl;
00322 
00323 # elif ( defined(__linux__) || defined(REDS) ) && ! defined(__IBMCPP__)
00324   static struct mallinfo minfo;
00325   minfo = mallinfo();
00326   heap_size = (unsigned int) minfo.uordblks + (unsigned int) minfo.hblkhd;
00327   largest_free = (unsigned int) minfo.fordblks;
00328 
00329   slibout.m(Slib::LOG_MEMORY) << "size_t size " << sizeof(size_t)*8 << " bits"
00330                               << ", heap size " << heap_size
00331                               << ", arena " << (unsigned int) minfo.arena
00332             << ", ordblks " << minfo.ordblks
00333             << ", smblks " << minfo.smblks
00334             << ", hblks " << minfo.hblks
00335             << ", hblkhd " << (unsigned int) minfo.hblkhd
00336             << ", usmblks " << minfo.usmblks
00337             << ", fsmblks " << minfo.fsmblks
00338             << ", uordblks " << (unsigned int) minfo.uordblks
00339             << ", fordblks " << (unsigned int) minfo.fordblks
00340             << ", keepcost " << minfo.keepcost << Diag::dendl;
00341 
00342 
00343 # elif defined(__sun)
00344   pstatus_t proc_status;
00345 
00346   std::ifstream proc("/proc/self/status", std::ios_base::in|std::ios_base::binary);
00347   if (proc) {
00348     proc.read((char *)&proc_status, sizeof(proc_status));
00349     heap_size = proc_status.pr_brksize;
00350     slibout.m(Slib::LOG_MEMORY) <<"pr_brksize " << proc_status.pr_brksize
00351         << ", pr_stksize " << proc_status.pr_stksize << Diag::dendl;
00352   }
00353 # endif
00354 #endif // defined(SIERRA_HEAP_INFO)
00355 }
00356 
00357 
00358 size_t get_available_memory()
00359 {
00360 #if !defined(REDS)
00361   // The value returned for _SC_AVPHYS_PAGES is the amount of memory
00362   // the application can use without hindering any other process
00363   // (given that no other process increases its memory usage).
00364 #if !defined(__APPLE__) && !defined(__FreeBSD__)
00365   static size_t pagesize = getpagesize();
00366   size_t avail = sysconf(_SC_AVPHYS_PAGES);
00367   return avail * pagesize;
00368 #else
00369   // _SC_AVPHYS_PAGES does not exist on FreeBSD/Apple
00370   return 0;
00371 #endif
00372 #else
00373   // On redstorm, we get an estimate of the available memory at the
00374   // time that the application starts up and then we get the currently
00375   // available memory by subtracting the used memory from that initial
00376   // value. 
00377   static size_t initial_memory_size = 0;
00378   if (initial_memory_size == 0) {
00379     initial_memory_size = get_redstorm_base_available_memory();
00380   }
00381   return initial_memory_size - get_heap_usage();
00382 #endif
00383 }
00384 
00385 void
00386 get_memory_info(
00387   size_t &    memory_usage,
00388   size_t &    faults)
00389 {
00390   memory_usage = 0;
00391   faults = 0;
00392 
00393 #if defined(SIERRA_MEMORY_INFO)
00394 # if defined(REDS)
00395   memory_usage = (size_t) __heap_start + get_heap_usage();
00396 
00397 # elif defined(__linux__)
00398   std::ifstream proc("/proc/self/stat", std::ios_base::in|std::ios_base::binary);
00399   if (proc) {
00400 
00401     std::string s;
00402     int i;
00403     for (i = 0; i < 11; ++i)
00404       proc >> s;
00405 
00406     proc >> faults;
00407     ++i;
00408 
00409     for (; i < 22; ++i)
00410       proc >> s;
00411 
00412     proc >> memory_usage;
00413     ++i;
00414   }
00415 # elif defined(__sun)
00416   {
00417 
00418     psinfo_t proc_info;
00419 
00420     std::ifstream proc("/proc/self/psinfo", std::ios_base::in|std::ios_base::binary);
00421     if (proc) {
00422       proc.read((char *)&proc_info, sizeof(proc_info));
00423       memory_usage = proc_info.pr_size*1024;
00424     }
00425   }
00426 
00427   {
00428     prusage_t proc_usage;
00429 
00430     std::ifstream proc("/proc/self/usage", std::ios_base::in|std::ios_base::binary);
00431     if (proc) {
00432       proc.read((char *)&proc_usage, sizeof(proc_usage));
00433       faults = proc_usage.pr_majf;
00434     }
00435   }
00436 # endif
00437 #endif // defined(SIERRA_MEMORY_INFO)
00438 }
00439 
00440 
00441 double
00442 vm_now()
00443 {
00444   size_t  memory_usage;
00445   size_t  faults;
00446 
00447   get_memory_info(memory_usage, faults);
00448 
00449   return (double) memory_usage;
00450 }
00451 
00452 
00453 std::string
00454 hostname()
00455 {
00456   char buf[255];
00457   ::gethostname(buf, sizeof(buf));
00458   return std::string(buf);
00459 }
00460 
00461 
00462 std::string
00463 domainname()
00464 {
00465 #if defined(__PUMAGON__) || defined(REDS)
00466   return std::string(".sandia.gov");
00467 
00468 #elif defined(__sun)
00469   std::string domain(".");
00470   char buf[255];
00471 
00472   ::sysinfo(SI_SRPC_DOMAIN, buf, sizeof(buf));
00473   if (std::strlen(buf)) {
00474     domain += buf;
00475   }
00476   return domain;
00477 
00478 #else //#elif defined(__linux) || defined(__sgi) || defined(_AIX)
00479   std::string domain(".");
00480   char buf[255];
00481 
00482   ::getdomainname(buf, sizeof(buf));
00483   if (::strlen(buf)) {
00484     domain += buf;
00485   }
00486   return domain;
00487 
00488 #endif
00489 }
00490 
00491 
00492 std::string
00493 username()
00494 {
00495 #if defined(REDS) || defined(__CRAYXT_COMPUTE_LINUX_TARGET)
00496   if (get_param("username").empty())
00497     return "unknown";
00498   else
00499     return get_param("username");
00500 #else
00501   struct passwd *user_info = ::getpwuid(::geteuid());
00502 
00503   return (user_info ? user_info->pw_name : "unknown");
00504 #endif
00505 }
00506 
00507 
00508 std::string
00509 hardware()
00510 {
00511 #ifndef __sgi
00512   struct utsname  uts_name;
00513 
00514   uname(&uts_name);
00515 
00516   return uts_name.machine;
00517 #else
00518   std::string s;
00519   return s;
00520 #endif
00521 }
00522 
00523 
00524 std::string
00525 osname()
00526 {
00527 #ifndef __sgi
00528   struct utsname  uts_name;
00529 
00530   uname(&uts_name);
00531 
00532   return uts_name.sysname;
00533 #else
00534   std::string s;
00535   return s;
00536 #endif
00537 }
00538 
00539 
00540 std::string
00541 osversion()
00542 {
00543 #ifndef __sgi
00544   struct utsname  uts_name;
00545 
00546   uname(&uts_name);
00547 
00548   return uts_name.release;
00549 #else
00550   std::string s;
00551   return s;
00552 #endif
00553 }
00554 
00555 
00556 int
00557 pid()
00558 {
00559   return ::getpid();
00560 }
00561 
00562 
00563 int
00564 pgrp()
00565 {
00566 #if defined(__PUMAGON__) || defined(REDS)
00567   return 0;
00568 #else
00569   return ::getpgrp();
00570 #endif
00571 }
00572 
00573 
00574 bool
00575 path_access(
00576   const std::string & name,
00577   int     mode)
00578 
00579 {
00580   return !name.empty() && ::access(name.c_str(), mode) == 0;
00581 }
00582 
00583 
00584 bool
00585 path_exists(
00586   const std::string & name)
00587 {
00588   return path_access(name, F_OK);
00589 }
00590 
00591 
00592 bool
00593 path_read_access(
00594   const std::string & name)
00595 {
00596   return path_access(name, R_OK);
00597 }
00598 
00599 
00600 bool
00601 path_write_access(
00602   const std::string & name)
00603 {
00604   return path_access(name, W_OK);
00605 }
00606 
00607 
00608 namespace {
00609 
00610 struct flock *
00611 file_lock(
00612   short type,
00613   short whence)
00614 {
00615 //  /* %TRACE[SPEC]% */ Tracespec trace__("sierra::Fmwk::<unnamed>::file_lock( short type, short whence)"); /* %TRACE% */
00616   static struct flock ret;
00617   ret.l_type = type;
00618   ret.l_start = 0;
00619   ret.l_whence = whence;
00620   ret.l_len = 0;
00621   ret.l_pid = 0; //getpid();
00622   return &ret;
00623 }
00624 
00625 } // namespace <unnamed>
00626 
00627 bool
00628 write_lock(
00629   int   fd)
00630 {
00631   int i =::fcntl(fd, F_SETLK, file_lock(F_WRLCK, SEEK_SET));
00632 //   if (i == -1)
00633 //     fmwkout << "Write lock failed " << errno << dendl;
00634 
00635   return i != -1;
00636 }
00637 
00638 
00639 bool
00640 release_lock(
00641   int   fd)
00642 {
00643   int i =::fcntl(fd, F_SETLK, file_lock(F_UNLCK, SEEK_SET));
00644 //   if (i == -1)
00645 //     fmwkout << "Release lock failed " << errno << dendl;
00646 
00647   return i != -1;
00648 }
00649 
00650 
00651 bool
00652 read_lock(
00653   int   fd)
00654 {
00655   return ::fcntl(fd, F_SETLK, file_lock(F_RDLCK, SEEK_SET)) != -1;
00656 }
00657 
00658 
00659 bool
00660 append_lock(
00661   int   fd)
00662 {
00663   return ::fcntl(fd, F_SETLK, file_lock(F_WRLCK, SEEK_END)) != -1;
00664 }
00665 
00666 } // namespace Env
00667 } // namespace sierra
00668 
00669 #if defined(REDS) 
00670 
00671 #if defined(__GNUC__)
00672 namespace {
00673   size_t get_redstorm_base_available_memory()
00674   {
00675     return 0;
00676   }
00677 }
00678 #else
00679 // Written by Mike Davis
00680 #include <catamount/data.h>
00681 namespace {
00682 
00683   void stk_ptr (unsigned long *sp) {
00684     asm ("movq  %rsp, (%rdi)");
00685   }
00686   
00687   size_t get_redstorm_base_available_memory()
00688   {
00689     char *p1;
00690     size_t stack_top;
00691     size_t avail_mem;
00692     size_t heap_base;
00693     size_t stack_base;
00694     size_t stack_size;
00695     size_t unmapped_top = 4 * 1048576;
00696     size_t os_foot =    140 * 1048576;
00697     size_t avail_heap;
00698     
00703     stk_ptr (&stack_top);
00704 
00708     stack_top &= ~0x1fffff;
00709     stack_top +=  0x200000;
00710     
00716     avail_mem = stack_top + unmapped_top;
00717 
00721     avail_mem -= os_foot;
00722 
00727     avail_mem /= _my_pcb->upcb_vnm_degree;
00728 
00733     p1 = (char *) malloc (1);
00734     heap_base = (size_t) p1;
00735     free (p1);
00736 
00742     avail_heap = avail_mem - heap_base;
00743 
00748     stack_base = (size_t) _my_pcb;
00749     stack_base &= ~0x1fffff;
00750     stack_base +=  0x400000;
00751 
00757     stack_size = stack_top - stack_base;
00758     avail_heap -= unmapped_top;
00759     avail_heap -= stack_size;
00760 
00761     return avail_heap;
00762   }
00763 }
00764 #endif
00765 #endif
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines