From 7ae44db4b9a1b3b26f2d670135fc00324e24f348 Mon Sep 17 00:00:00 2001 From: KWSys Robot Date: Tue, 16 Oct 2012 17:12:23 -0400 Subject: [PATCH] KWSys 2012-10-16 (b7a97ac3) Extract upstream KWSys using the following shell commands. $ git archive --prefix=upstream-kwsys/ b7a97ac3 | tar x $ git shortlog --no-merges --abbrev=8 --format='%h %s' bab53989..b7a97ac3 Brad King (3): f9db7eab SystemInformation: Fix helper definition order a1e83e42 SystemInformation: Expose helper functions only where needed b7a97ac3 SystemInformation: Drop unused LoadLines on OS X Burlen Loring (1): 6072e63b SystemInformation: support for resource limits Sean McBride (2): a536d833 ProcessUNIX: Suppress warning about uninteresting return code 00852081 SystemInformation: Fix sloppy use of sysctlbyname() API Change-Id: Iae8af129a021435ef4e6daef255e312c99d7b773 --- CMakeLists.txt | 65 ++++- ProcessUNIX.c | 1 + SystemInformation.cxx | 581 ++++++++++++++++++++++++++++++-------- SystemInformation.hxx.in | 45 ++- kwsysPlatformTestsCXX.cxx | 66 +++++ testSystemInformation.cxx | 34 ++- 6 files changed, 658 insertions(+), 134 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 314ebd6df..777d76f4b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -509,19 +509,28 @@ ENDIF(KWSYS_USE_FundamentalType) IF(KWSYS_USE_IOStream) # Determine whether iostreams support long long. + SET(KWSYS_PLATFORM_CXX_TEST_DEFINES + -DKWSYS_IOS_USE_ANSI=${KWSYS_IOS_USE_ANSI} + -DKWSYS_IOS_HAVE_STD=${KWSYS_IOS_HAVE_STD}) IF(KWSYS_CXX_HAS_LONG_LONG) - SET(KWSYS_PLATFORM_CXX_TEST_DEFINES - -DKWSYS_IOS_USE_ANSI=${KWSYS_IOS_USE_ANSI} - -DKWSYS_IOS_HAVE_STD=${KWSYS_IOS_HAVE_STD}) KWSYS_PLATFORM_CXX_TEST(KWSYS_IOS_HAS_ISTREAM_LONG_LONG "Checking if istream supports long long" DIRECT) KWSYS_PLATFORM_CXX_TEST(KWSYS_IOS_HAS_OSTREAM_LONG_LONG "Checking if ostream supports long long" DIRECT) - SET(KWSYS_PLATFORM_CXX_TEST_DEFINES) ELSE() SET(KWSYS_IOS_HAS_ISTREAM_LONG_LONG 0) SET(KWSYS_IOS_HAS_OSTREAM_LONG_LONG 0) ENDIF() + IF(KWSYS_CXX_HAS___INT64) + KWSYS_PLATFORM_CXX_TEST(KWSYS_IOS_HAS_ISTREAM___INT64 + "Checking if istream supports __int64" DIRECT) + KWSYS_PLATFORM_CXX_TEST(KWSYS_IOS_HAS_OSTREAM___INT64 + "Checking if ostream supports __int64" DIRECT) + ELSE() + SET(KWSYS_IOS_HAS_ISTREAM___INT64 0) + SET(KWSYS_IOS_HAS_OSTREAM___INT64 0) + ENDIF() + SET(KWSYS_PLATFORM_CXX_TEST_DEFINES) ENDIF(KWSYS_USE_IOStream) IF(KWSYS_NAMESPACE MATCHES "^kwsys$") @@ -588,6 +597,54 @@ IF(KWSYS_USE_SystemInformation) ENDIF() ENDIF() ENDIF() + IF(KWSYS_LFS_AVAILABLE AND NOT KWSYS_LFS_DISABLE) + SET(KWSYS_PLATFORM_CXX_TEST_DEFINES -DKWSYS_HAS_LFS=1) + ENDIF() + KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_RLIMIT64 + "Checking whether CXX compiler has rlimit64" DIRECT) + SET(KWSYS_PLATFORM_CXX_TEST_DEFINES) + IF(KWSYS_CXX_HAS_RLIMIT64) + SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY + COMPILE_DEFINITIONS KWSYS_CXX_HAS_RLIMIT64=1) + ENDIF() + KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_ATOL + "Checking whether CXX compiler has atol" DIRECT) + IF(KWSYS_CXX_HAS_ATOL) + SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY + COMPILE_DEFINITIONS KWSYS_CXX_HAS_ATOL=1) + ENDIF() + KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_ATOLL + "Checking whether CXX compiler has atoll" DIRECT) + IF(KWSYS_CXX_HAS_ATOLL) + SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY + COMPILE_DEFINITIONS KWSYS_CXX_HAS_ATOLL=1) + ENDIF() + KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS__ATOI64 + "Checking whether CXX compiler has _atoi64" DIRECT) + IF(KWSYS_CXX_HAS__ATOI64) + SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY + COMPILE_DEFINITIONS KWSYS_CXX_HAS__ATOI64=1) + ENDIF() + IF(KWSYS_USE___INT64) + SET_PROPERTY(SOURCE SystemInformation.cxx testSystemInformation.cxx APPEND PROPERTY + COMPILE_DEFINITIONS KWSYS_USE___INT64=1) + ENDIF() + IF(KWSYS_USE_LONG_LONG) + SET_PROPERTY(SOURCE SystemInformation.cxx testSystemInformation.cxx APPEND PROPERTY + COMPILE_DEFINITIONS KWSYS_USE_LONG_LONG=1) + ENDIF() + IF(KWSYS_IOS_HAS_OSTREAM_LONG_LONG) + SET_PROPERTY(SOURCE SystemInformation.cxx testSystemInformation.cxx APPEND PROPERTY + COMPILE_DEFINITIONS KWSYS_IOS_HAS_OSTREAM_LONG_LONG=1) + ENDIF() + IF(KWSYS_IOS_HAS_OSTREAM___INT64) + SET_PROPERTY(SOURCE SystemInformation.cxx testSystemInformation.cxx APPEND PROPERTY + COMPILE_DEFINITIONS KWSYS_IOS_HAS_OSTREAM___INT64=1) + ENDIF() + IF(KWSYS_BUILD_SHARED) + SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY + COMPILE_DEFINITIONS KWSYS_BUILD_SHARED=1) + ENDIF() ENDIF() #----------------------------------------------------------------------------- diff --git a/ProcessUNIX.c b/ProcessUNIX.c index 9c66a4486..19922111a 100644 --- a/ProcessUNIX.c +++ b/ProcessUNIX.c @@ -2732,6 +2732,7 @@ static void kwsysProcessesSignalHandler(int signum kwsysProcess* cp = kwsysProcesses.Processes[i]; kwsysProcess_ssize_t status= read(cp->PipeReadEnds[KWSYSPE_PIPE_SIGNAL], &buf, 1); + (void)status; status=write(cp->SignalPipe, &buf, 1); (void)status; } diff --git a/SystemInformation.cxx b/SystemInformation.cxx index a9efe7b3e..cbd1bdc13 100644 --- a/SystemInformation.cxx +++ b/SystemInformation.cxx @@ -9,7 +9,9 @@ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the License for more information. ============================================================================*/ -#ifdef _WIN32 + +#if defined(_WIN32) +# define NOMINMAX // use our min,max # if !defined(_WIN32_WINNT) && !(defined(_MSC_VER) && _MSC_VER < 1300) # define _WIN32_WINNT 0x0501 # endif @@ -54,6 +56,7 @@ #if defined(_WIN32) # include +# include # if defined(KWSYS_SYS_HAS_PSAPI) # include # endif @@ -64,6 +67,7 @@ typedef int siginfo_t; # include # include # include // int uname(struct utsname *buf); +# include // getrlimit # include # include # include @@ -71,15 +75,15 @@ typedef int siginfo_t; #endif #ifdef __APPLE__ -#include -#include -#include -#include -#include -#include -#include -#include -#include +# include +# include +# include +# include +# include +# include +# include +# include +# include # if __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__-0 >= 1050 # include # define KWSYS_SYSTEMINFORMATION_HAVE_BACKTRACE @@ -95,6 +99,13 @@ typedef int siginfo_t; # include # define KWSYS_SYSTEMINFORMATION_HAVE_BACKTRACE # endif +# if defined(KWSYS_CXX_HAS_RLIMIT64) +typedef struct rlimit64 ResourceLimitType; +# define GetResourceLimit getrlimit64 +# else +typedef struct rlimit ResourceLimitType; +# define GetResourceLimit getrlimit +# endif #elif defined( __hpux ) # include # include @@ -105,7 +116,7 @@ typedef int siginfo_t; #endif #ifdef __HAIKU__ -#include +# include #endif #include @@ -114,8 +125,38 @@ typedef int siginfo_t; #include #include // int isdigit(int c); +#if defined(KWSYS_USE_LONG_LONG) +# if defined(KWSYS_IOS_HAS_OSTREAM_LONG_LONG) +# define iostreamLongLong(x) (x) +# else +# define iostreamLongLong(x) ((long)x) +# endif +#elif defined(KWSYS_USE___INT64) +# if defined(KWSYS_IOS_HAS_OSTREAM___INT64) +# define iostreamLongLong(x) (x) +# else +# define iostreamLongLong(x) ((long)x) +# endif +#else +# error "No Long Long" +#endif + +#if defined(KWSYS_CXX_HAS_ATOLL) +# define atoLongLong atoll +#else +# if defined(KWSYS_CXX_HAS__ATOI64) +# define atoLongLong _atoi64 +# elif defined(KWSYS_CXX_HAS_ATOL) +# define atoLongLong atol +# else +# define atoLongLong atoi +# endif +#endif + namespace KWSYS_NAMESPACE { +template +T min(T a, T b){ return aImplementation->GetFullyQualifiedDomainName(fqdn); - if (ierr) - { - fqdn="localhost"; - } + this->Implementation->GetFullyQualifiedDomainName(fqdn); return fqdn; } @@ -552,27 +595,54 @@ size_t SystemInformation::GetAvailablePhysicalMemory() return this->Implementation->GetAvailablePhysicalMemory(); } -kwsys_stl::string SystemInformation::GetMemoryDescription() +kwsys_stl::string SystemInformation::GetMemoryDescription( + const char *hostLimitEnvVarName, + const char *procLimitEnvVarName) { kwsys_stl::ostringstream oss; oss - << this->GetTotalPhysicalMemory() - << " MB physical " - << this->GetTotalVirtualMemory() - << " MB virtual"; - + << "Host Total: " + << iostreamLongLong(this->GetHostMemoryTotal()) + << " KiB, Host Available: " + << iostreamLongLong(this->GetHostMemoryAvailable(hostLimitEnvVarName)) + << " KiB, Process Available: " + << iostreamLongLong( + this->GetProcMemoryAvailable(hostLimitEnvVarName,procLimitEnvVarName)) + << " KiB"; return oss.str(); } -// Get total system RAM in units of KiB. -SystemInformation::LongLong SystemInformation::GetMemoryTotal() +// host memory info in units of KiB. +SystemInformation::LongLong SystemInformation::GetHostMemoryTotal() { - return this->Implementation->GetMemoryTotal(); + return this->Implementation->GetHostMemoryTotal(); } -SystemInformation::LongLong SystemInformation::GetMemoryUsed() +SystemInformation::LongLong +SystemInformation::GetHostMemoryAvailable(const char *hostLimitEnvVarName) { - return this->Implementation->GetMemoryUsed(); + return this->Implementation->GetHostMemoryAvailable(hostLimitEnvVarName); +} + +SystemInformation::LongLong SystemInformation::GetHostMemoryUsed() +{ + return this->Implementation->GetHostMemoryUsed(); +} + +// process memory info in units of KiB. +SystemInformation::LongLong +SystemInformation::GetProcMemoryAvailable( + const char *hostLimitEnvVarName, + const char *procLimitEnvVarName) +{ + return this->Implementation->GetProcMemoryAvailable( + hostLimitEnvVarName, + procLimitEnvVarName); +} + +SystemInformation::LongLong SystemInformation::GetProcMemoryUsed() +{ + return this->Implementation->GetProcMemoryUsed(); } SystemInformation::LongLong SystemInformation::GetProcessId() @@ -671,34 +741,56 @@ void SystemInformation::RunMemoryCheck() // initial APIC ID for the processor this code is running on. // Default value = 0xff if HT is not supported - -//***************************************************************************** +// Hide implementation details in an anonymous namespace. +namespace { +// ***************************************************************************** +#if defined(__linux) || defined(__APPLE__) int LoadLines( - const char *fileName, + FILE *file, kwsys_stl::vector &lines) { // Load each line in the given file into a the vector. int nRead=0; const int bufSize=1024; char buf[bufSize]={'\0'}; - kwsys_stl::ifstream file(fileName); - if (!file.is_open()) + while (!feof(file) && !ferror(file)) + { + errno=0; + if (fgets(buf,bufSize,file) == 0) + { + if (ferror(file) && (errno==EINTR)) + { + clearerr(file); + } + continue; + } + lines.push_back(buf); + ++nRead; + } + if (ferror(file)) { return 0; } - while(file.good()) - { - file.getline(buf,bufSize); - if (file.gcount()>1) - { - lines.push_back(buf); - ++nRead; - } - } - file.close(); return nRead; } +# if defined(__linux) +// ***************************************************************************** +int LoadLines( + const char *fileName, + kwsys_stl::vector &lines) +{ + FILE *file=fopen(fileName,"r"); + if (file==0) + { + return 0; + } + int nRead=LoadLines(file,lines); + fclose(file); + return nRead; +} +# endif + // **************************************************************************** template int NameValue( @@ -708,17 +800,44 @@ int NameValue( size_t nLines=lines.size(); for (size_t i=0; i> tok; - if (tok==name) + size_t at=lines[i].find(name); + if (at==kwsys_stl::string::npos) { - is >> value; - return 0; + continue; } + kwsys_stl::istringstream is(lines[i].substr(at+name.size())); + is >> value; + return 0; } return -1; } +#endif + +#if defined(__linux) +// **************************************************************************** +template +int GetFieldsFromFile( + const char *fileName, + const char **fieldNames, + T *values) +{ + kwsys_stl::vector fields; + if (!LoadLines(fileName,fields)) + { + return -1; + } + int i=0; + while (fieldNames[i]!=NULL) + { + int ierr=NameValue(fields,fieldNames[i],values[i]); + if (ierr) + { + return -(i+2); + } + i+=1; + } + return 0; +} // **************************************************************************** template @@ -727,202 +846,244 @@ int GetFieldFromFile( const char *fieldName, T &value) { - kwsys_stl::vector fields; - if (!LoadLines(fileName,fields)) + const char *fieldNames[2]={fieldName,NULL}; + T values[1]={T(0)}; + int ierr=GetFieldsFromFile(fileName,fieldNames,values); + if (ierr) + { + return ierr; + } + value=values[0]; + return 0; +} +#endif + +// **************************************************************************** +#if defined(__APPLE__) +template +int GetFieldsFromCommand( + const char *command, + const char **fieldNames, + T *values) +{ + FILE *file=popen(command,"r"); + if (file==0) { return -1; } - int ierr=NameValue(fields,fieldName,value); - if (ierr) + kwsys_stl::vector fields; + int nl=LoadLines(file,fields); + pclose(file); + if (nl==0) { - return -2; + return -1; + } + int i=0; + while (fieldNames[i]!=NULL) + { + int ierr=NameValue(fields,fieldNames[i],values[i]); + if (ierr) + { + return -(i+2); + } + i+=1; } return 0; } +#endif -//***************************************************************************** +// **************************************************************************** +#if !defined(_WIN32) && !defined(__MINGW32__) && !defined(__CYGWIN__) void StacktraceSignalHandler( int sigNo, siginfo_t *sigInfo, void * /*sigContext*/) { #if defined(__linux) || defined(__APPLE__) - kwsys_ios::cerr << "[" << getpid() << "] "; - + kwsys_ios::ostringstream oss; + oss + << "=========================================================" << kwsys_ios::endl + << "Process id " << getpid() << " "; switch (sigNo) { case SIGFPE: - kwsys_ios::cerr << "Caught SIGFPE "; + oss << "Caught SIGFPE "; switch (sigInfo->si_code) { # if defined(FPE_INTDIV) case FPE_INTDIV: - kwsys_ios::cerr << "integer division by zero"; + oss << "integer division by zero"; break; # endif # if defined(FPE_INTOVF) case FPE_INTOVF: - kwsys_ios::cerr << "integer overflow"; + oss << "integer overflow"; break; # endif case FPE_FLTDIV: - kwsys_ios::cerr << "floating point divide by zero"; + oss << "floating point divide by zero"; break; case FPE_FLTOVF: - kwsys_ios::cerr << "floating point overflow"; + oss << "floating point overflow"; break; case FPE_FLTUND: - kwsys_ios::cerr << "floating point underflow"; + oss << "floating point underflow"; break; case FPE_FLTRES: - kwsys_ios::cerr << "floating point inexact result"; + oss << "floating point inexact result"; break; case FPE_FLTINV: - kwsys_ios::cerr << "floating point invalid operation"; + oss << "floating point invalid operation"; break; #if defined(FPE_FLTSUB) case FPE_FLTSUB: - kwsys_ios::cerr << "floating point subscript out of range"; + oss << "floating point subscript out of range"; break; #endif default: - kwsys_ios::cerr << "code " << sigInfo->si_code; + oss << "code " << sigInfo->si_code; break; } break; case SIGSEGV: - kwsys_ios::cerr << "Caught SIGSEGV "; + oss << "Caught SIGSEGV "; switch (sigInfo->si_code) { case SEGV_MAPERR: - kwsys_ios::cerr << "address not mapped to object"; + oss << "address not mapped to object"; break; case SEGV_ACCERR: - kwsys_ios::cerr << "invalid permission for mapped object"; + oss << "invalid permission for mapped object"; break; default: - kwsys_ios::cerr << "code " << sigInfo->si_code; + oss << "code " << sigInfo->si_code; break; } break; case SIGINT: - kwsys_ios::cerr << "Caught SIGTERM"; + oss << "Caught SIGTERM"; break; case SIGTERM: - kwsys_ios::cerr << "Caught SIGTERM"; + oss << "Caught SIGTERM"; break; case SIGBUS: - kwsys_ios::cerr << "Caught SIGBUS type "; + oss << "Caught SIGBUS type "; switch (sigInfo->si_code) { case BUS_ADRALN: - kwsys_ios::cerr << "invalid address alignment"; + oss << "invalid address alignment"; break; # if defined(BUS_ADRERR) case BUS_ADRERR: - kwsys_ios::cerr << "non-exestent physical address"; + oss << "non-exestent physical address"; break; # endif # if defined(BUS_OBJERR) case BUS_OBJERR: - kwsys_ios::cerr << "object specific hardware error"; + oss << "object specific hardware error"; break; # endif default: - kwsys_ios::cerr << "code " << sigInfo->si_code; + oss << "code " << sigInfo->si_code; break; } break; case SIGILL: - kwsys_ios::cerr << "Caught SIGILL "; + oss << "Caught SIGILL "; switch (sigInfo->si_code) { case ILL_ILLOPC: - kwsys_ios::cerr << "illegal opcode"; + oss << "illegal opcode"; break; # if defined(ILL_ILLOPN) case ILL_ILLOPN: - kwsys_ios::cerr << "illegal operand"; + oss << "illegal operand"; break; # endif # if defined(ILL_ILLADR) case ILL_ILLADR: - kwsys_ios::cerr << "illegal addressing mode."; + oss << "illegal addressing mode."; break; # endif case ILL_ILLTRP: - kwsys_ios::cerr << "illegal trap"; + oss << "illegal trap"; case ILL_PRVOPC: - kwsys_ios::cerr << "privileged opcode"; + oss << "privileged opcode"; break; # if defined(ILL_PRVREG) case ILL_PRVREG: - kwsys_ios::cerr << "privileged register"; + oss << "privileged register"; break; # endif # if defined(ILL_COPROC) case ILL_COPROC: - kwsys_ios::cerr << "co-processor error"; + oss << "co-processor error"; break; # endif # if defined(ILL_BADSTK) case ILL_BADSTK: - kwsys_ios::cerr << "internal stack error"; + oss << "internal stack error"; break; # endif default: - kwsys_ios::cerr << "code " << sigInfo->si_code; + oss << "code " << sigInfo->si_code; break; } break; default: - kwsys_ios::cerr << "Caught " << sigNo << " code " << sigInfo->si_code; + oss << "Caught " << sigNo << " code " << sigInfo->si_code; break; } - kwsys_ios::cerr << kwsys_ios::endl; - + oss << kwsys_ios::endl; #if defined(KWSYS_SYSTEMINFORMATION_HAVE_BACKTRACE) - kwsys_ios::cerr << "Stack:" << kwsys_ios::endl; - void *stack[128]; - int n=backtrace(stack,128); - backtrace_symbols_fd(stack,n,2); + oss << "Program Stack:" << kwsys_ios::endl; + void *stackSymbols[128]; + int n=backtrace(stackSymbols,128); + char **stackText=backtrace_symbols(stackSymbols,n); + for (int i=0; iHostname.empty()) + { + this->Hostname="localhost"; +#if defined(_WIN32) + WORD wVersionRequested; + WSADATA wsaData; + char name[255]; + wVersionRequested = MAKEWORD(2,0); + if ( WSAStartup( wVersionRequested, &wsaData ) == 0 ) + { + gethostname(name,sizeof(name)); + WSACleanup( ); + } + this->Hostname = name; +#else + struct utsname unameInfo; + int errorFlag = uname(&unameInfo); + if(errorFlag == 0) + { + this->Hostname = unameInfo.nodename; + } +#endif + } return this->Hostname.c_str(); } @@ -1092,7 +1276,12 @@ int SystemInformationImplementation::GetFullyQualifiedDomainName( // we want the fully qualified domain name. Because there are // any number of interfaces on this system we look for the // first of these that contains the name returned by gethostname - // and is longer. failing that we return gethostname. + // and is longer. failing that we return gethostname and indicate + // with a failure code. Return of a failure code is not necessarilly + // an indication of an error. for instance gethostname may return + // the fully qualified domain name, or there may not be one if the + // system lives on a private network such as in the case of a cluster + // node. int ierr=0; char base[NI_MAXHOST]; @@ -1132,8 +1321,8 @@ int SystemInformationImplementation::GetFullyQualifiedDomainName( NI_NAMEREQD); if (ierr) { - // don't report the error now since we may succeed on another - // interface. If all attempts fail then retrun an error code. + // don't report the failure now since we may succeed on another + // interface. If all attempts fail then return the failure code. ierr=-3; continue; } @@ -1153,6 +1342,7 @@ int SystemInformationImplementation::GetFullyQualifiedDomainName( return ierr; #else /* TODO: Implement on more platforms. */ + fqdn=this->GetHostname(); return -1; #endif } @@ -2905,7 +3095,7 @@ int SystemInformationImplementation::RetreiveInformationFromCpuInfoFile() Get total system RAM in units of KiB. */ SystemInformation::LongLong -SystemInformationImplementation::GetMemoryTotal() +SystemInformationImplementation::GetHostMemoryTotal() { #if defined(_WIN32) # if defined(_MSC_VER) && _MSC_VER < 1300 @@ -2920,7 +3110,7 @@ SystemInformationImplementation::GetMemoryTotal() return statex.ullTotalPhys/1024; # endif #elif defined(__linux) - LongLong memTotal=0; + SystemInformation::LongLong memTotal=0; int ierr=GetFieldFromFile("/proc/meminfo","MemTotal:",memTotal); if (ierr) { @@ -2941,16 +3131,157 @@ SystemInformationImplementation::GetMemoryTotal() #endif } +/** +Get total system RAM in units of KiB. This may differ from the +host total if a host-wide resource limit is applied. +*/ +SystemInformation::LongLong +SystemInformationImplementation::GetHostMemoryAvailable(const char *hostLimitEnvVarName) +{ + SystemInformation::LongLong memTotal=this->GetHostMemoryTotal(); + + // the following mechanism is provided for systems that + // apply resource limits across groups of processes. + // this is of use on certain SMP systems (eg. SGI UV) + // where the host has a large amount of ram but a given user's + // access to it is severly restricted. The system will + // apply a limit across a set of processes. Units are in KiB. + if (hostLimitEnvVarName) + { + const char *hostLimitEnvVarValue=getenv(hostLimitEnvVarName); + if (hostLimitEnvVarValue) + { + SystemInformation::LongLong hostLimit=atoLongLong(hostLimitEnvVarValue); + if (hostLimit>0) + { + memTotal=min(hostLimit,memTotal); + } + } + } + + return memTotal; +} + +/** +Get total system RAM in units of KiB. This may differ from the +host total if a per-process resource limit is applied. +*/ +SystemInformation::LongLong +SystemInformationImplementation::GetProcMemoryAvailable( + const char *hostLimitEnvVarName, + const char *procLimitEnvVarName) +{ + SystemInformation::LongLong memAvail + = this->GetHostMemoryAvailable(hostLimitEnvVarName); + + // the following mechanism is provide for systems where rlimits + // are not employed. Units are in KiB. + if (procLimitEnvVarName) + { + const char *procLimitEnvVarValue=getenv(procLimitEnvVarName); + if (procLimitEnvVarValue) + { + SystemInformation::LongLong procLimit=atoLongLong(procLimitEnvVarValue); + if (procLimit>0) + { + memAvail=min(procLimit,memAvail); + } + } + } + +#if defined(__linux) + int ierr; + ResourceLimitType rlim; + ierr=GetResourceLimit(RLIMIT_DATA,&rlim); + if ((ierr==0) && (rlim.rlim_cur != RLIM_INFINITY)) + { + memAvail=min((SystemInformation::LongLong)rlim.rlim_cur/1024,memAvail); + } + + ierr=GetResourceLimit(RLIMIT_AS,&rlim); + if ((ierr==0) && (rlim.rlim_cur != RLIM_INFINITY)) + { + memAvail=min((SystemInformation::LongLong)rlim.rlim_cur/1024,memAvail); + } +#elif defined(__APPLE__) + struct rlimit rlim; + int ierr; + ierr=getrlimit(RLIMIT_DATA,&rlim); + if ((ierr==0) && (rlim.rlim_cur != RLIM_INFINITY)) + { + memAvail=min((SystemInformation::LongLong)rlim.rlim_cur/1024,memAvail); + } + + ierr=getrlimit(RLIMIT_RSS,&rlim); + if ((ierr==0) && (rlim.rlim_cur != RLIM_INFINITY)) + { + memAvail=min((SystemInformation::LongLong)rlim.rlim_cur/1024,memAvail); + } +#endif + + return memAvail; +} + +/** +Get RAM used by all processes in the host, in units of KiB. +*/ +SystemInformation::LongLong +SystemInformationImplementation::GetHostMemoryUsed() +{ +#if defined(_WIN32) +# if defined(_MSC_VER) && _MSC_VER < 1300 + MEMORYSTATUS stat; + stat.dwLength = sizeof(stat); + GlobalMemoryStatus(&stat); + return (stat.dwTotalPhys - stat.dwAvailPhys)/1024; +# else + MEMORYSTATUSEX statex; + statex.dwLength=sizeof(statex); + GlobalMemoryStatusEx(&statex); + return (statex.ullTotalPhys - statex.ullAvailPhys)/1024; +# endif +#elif defined(__linux) + const char *names[3]={"MemTotal:","MemFree:",NULL}; + SystemInformation::LongLong values[2]={SystemInformation::LongLong(0)}; + int ierr=GetFieldsFromFile("/proc/meminfo",names,values); + if (ierr) + { + return ierr; + } + SystemInformation::LongLong &memTotal=values[0]; + SystemInformation::LongLong &memFree=values[1]; + return memTotal - memFree; +#elif defined(__APPLE__) + SystemInformation::LongLong psz=getpagesize(); + if (psz<1) + { + return -1; + } + const char *names[4]={"Pages active:","Pages inactive:","Pages wired down:",NULL}; + SystemInformation::LongLong values[3]={SystemInformation::LongLong(0)}; + int ierr=GetFieldsFromCommand("vm_stat", names, values); + if (ierr) + { + return -1; + } + SystemInformation::LongLong &vmActive=values[0]; + SystemInformation::LongLong &vmInactive=values[1]; + SystemInformation::LongLong &vmWired=values[2]; + return ((vmActive+vmInactive+vmWired)*psz)/1024; +#else + return 0; +#endif +} + /** Get system RAM used by the process associated with the given process id in units of KiB. */ SystemInformation::LongLong -SystemInformationImplementation::GetMemoryUsed() +SystemInformationImplementation::GetProcMemoryUsed() { #if defined(_WIN32) && defined(KWSYS_SYS_HAS_PSAPI) long pid=GetCurrentProcessId(); - HANDLE hProc; hProc=OpenProcess( PROCESS_QUERY_INFORMATION|PROCESS_VM_READ, @@ -2960,7 +3291,6 @@ SystemInformationImplementation::GetMemoryUsed() { return -1; } - PROCESS_MEMORY_COUNTERS pmc; int ok=GetProcessMemoryInfo(hProc,&pmc,sizeof(pmc)); CloseHandle(hProc); @@ -2970,7 +3300,7 @@ SystemInformationImplementation::GetMemoryUsed() } return pmc.WorkingSetSize/1024; #elif defined(__linux) - LongLong memUsed=0; + SystemInformation::LongLong memUsed=0; int ierr=GetFieldFromFile("/proc/self/status","VmRSS:",memUsed); if (ierr) { @@ -2978,23 +3308,34 @@ SystemInformationImplementation::GetMemoryUsed() } return memUsed; #elif defined(__APPLE__) + SystemInformation::LongLong memUsed=0; pid_t pid=getpid(); kwsys_stl::ostringstream oss; oss << "ps -o rss= -p " << pid; - FILE *f=popen(oss.str().c_str(),"r"); - if (f==0) + FILE *file=popen(oss.str().c_str(),"r"); + if (file==0) { return -1; } oss.str(""); - char buf[256]={'\0'}; - while (fgets(buf, 256, f) != 0) + while (!feof(file) && !ferror(file)) { - oss << buf; + char buf[256]={'\0'}; + errno=0; + size_t nRead=fread(buf,1,256,file); + if (ferror(file) && (errno==EINTR)) + { + clearerr(file); + } + if (nRead) oss << buf; + } + int ierr=ferror(file); + pclose(file); + if (ierr) + { + return -2; } - pclose(f); kwsys_stl::istringstream iss(oss.str()); - LongLong memUsed=0; iss >> memUsed; return memUsed; #else @@ -3603,6 +3944,7 @@ bool SystemInformationImplementation::ParseSysCtl() if ( host_statistics(mach_host_self(), HOST_VM_INFO, (host_info_t) &vmstat, &count) == KERN_SUCCESS ) { + len = sizeof(value); err = sysctlbyname("hw.pagesize", &value, &len, NULL, 0); int64_t available_memory = vmstat.free_count * value; this->AvailablePhysicalMemory = static_cast< size_t >( available_memory / 1048576 ); @@ -3613,7 +3955,7 @@ bool SystemInformationImplementation::ParseSysCtl() int mib[2] = { CTL_VM, VM_SWAPUSAGE }; size_t miblen = sizeof(mib) / sizeof(mib[0]); struct xsw_usage swap; - len = sizeof(struct xsw_usage); + len = sizeof(swap); err = sysctl(mib, miblen, &swap, &len, NULL, 0); if (err == 0) { @@ -3628,6 +3970,7 @@ bool SystemInformationImplementation::ParseSysCtl() // CPU Info len = sizeof(this->NumberOfPhysicalCPU); sysctlbyname("hw.physicalcpu", &this->NumberOfPhysicalCPU, &len, NULL, 0); + len = sizeof(this->NumberOfLogicalCPU); sysctlbyname("hw.logicalcpu", &this->NumberOfLogicalCPU, &len, NULL, 0); this->Features.ExtendedFeatures.LogicalProcessorsPerPhysical = this->LogicalCPUPerPhysicalCPU(); @@ -3653,8 +3996,9 @@ bool SystemInformationImplementation::ParseSysCtl() if (machineBuf.find_first_of("Power") != kwsys_stl::string::npos) { this->ChipID.Vendor = "IBM"; - len = 4; + len = sizeof(this->ChipID.Family); err = sysctlbyname("hw.cputype", &this->ChipID.Family, &len, NULL, 0); + len = sizeof(this->ChipID.Model); err = sysctlbyname("hw.cpusubtype", &this->ChipID.Model, &len, NULL, 0); this->FindManufacturer(); } @@ -3679,8 +4023,8 @@ bool SystemInformationImplementation::ParseSysCtl() } // brand string - ::memset(retBuf, 0, 128); - len = 128; + ::memset(retBuf, 0, sizeof(retBuf)); + len = sizeof(retBuf); err = sysctlbyname("machdep.cpu.brand_string", retBuf, &len, NULL, 0); if (!err) { @@ -3692,6 +4036,7 @@ bool SystemInformationImplementation::ParseSysCtl() len = sizeof(value); err = sysctlbyname("hw.l1icachesize", &value, &len, NULL, 0); this->Features.L1CacheSize = static_cast< int >( value ); + len = sizeof(value); err = sysctlbyname("hw.l2cachesize", &value, &len, NULL, 0); this->Features.L2CacheSize = static_cast< int >( value ); diff --git a/SystemInformation.hxx.in b/SystemInformation.hxx.in index cb6c75903..8f4cb4e5a 100644 --- a/SystemInformation.hxx.in +++ b/SystemInformation.hxx.in @@ -24,7 +24,6 @@ namespace @KWSYS_NAMESPACE@ { - // forward declare the implementation class class SystemInformationImplementation; @@ -96,15 +95,44 @@ public: size_t GetTotalPhysicalMemory(); size_t GetAvailablePhysicalMemory(); - // returns an informative general description if the ram - // on this system - kwsys_stl::string GetMemoryDescription(); + // returns an informative general description if the installed and + // available ram on this system. See the GetHostMmeoryTotal, and + // Get{Host,Proc}MemoryAvailable methods for more information. + kwsys_stl::string GetMemoryDescription( + const char *hostLimitEnvVarName=NULL, + const char *procLimitEnvVarName=NULL); - // Retrieve physical memory information in kib - LongLong GetMemoryTotal(); - LongLong GetMemoryUsed(); + // Retrieve amount of physical memory installed on the system in KiB + // units. + LongLong GetHostMemoryTotal(); - // enable/disable stack trace signal handler. + // Get total system RAM in units of KiB available colectivley to all + // processes in a process group. An example of a process group + // are the processes comprising an mpi program which is running in + // parallel. The amount of memory reported may differ from the host + // total if a host wide resource limit is applied. Such reource limits + // are reported to us via an applicaiton specified environment variable. + LongLong GetHostMemoryAvailable(const char *hostLimitEnvVarName=NULL); + + // Get total system RAM in units of KiB available to this process. + // This may differ from the host available if a per-process resource + // limit is applied. per-process memory limits are applied on unix + // system via rlimit api. Resource limits that are not imposed via + // rlimit api may be reported to us via an application specified + // environment variable. + LongLong GetProcMemoryAvailable( + const char *hostLimitEnvVarName=NULL, + const char *procLimitEnvVarName=NULL); + + // Get the system RAM used by all processes on the host, in units of KiB. + LongLong GetHostMemoryUsed(); + + // Get system RAM used by this process id in units of KiB. + LongLong GetProcMemoryUsed(); + + // enable/disable stack trace signal handler. In order to + // produce an informative stack trace the application should + // be dynamically linked and compiled with debug symbols. static void SetStackTraceOnError(int enable); @@ -113,6 +141,7 @@ public: void RunOSCheck(); void RunMemoryCheck(); }; + } // namespace @KWSYS_NAMESPACE@ /* Undefine temporary macros. */ diff --git a/kwsysPlatformTestsCXX.cxx b/kwsysPlatformTestsCXX.cxx index 7b73d06df..ae5870342 100644 --- a/kwsysPlatformTestsCXX.cxx +++ b/kwsysPlatformTestsCXX.cxx @@ -358,6 +358,30 @@ int main() } #endif +#ifdef TEST_KWSYS_IOS_HAS_ISTREAM___INT64 +int test_istream(kwsys_ios::istream& is, __int64& x) +{ + return (is >> x)? 1:0; +} +int main() +{ + __int64 x = 0; + return test_istream(kwsys_ios::cin, x); +} +#endif + +#ifdef TEST_KWSYS_IOS_HAS_OSTREAM___INT64 +int test_ostream(kwsys_ios::ostream& os, __int64 x) +{ + return (os << x)? 1:0; +} +int main() +{ + __int64 x = 0; + return test_ostream(kwsys_ios::cout, x); +} +#endif + #ifdef TEST_KWSYS_CHAR_IS_SIGNED /* Return 0 for char signed and 1 for char unsigned. */ int main() @@ -428,6 +452,48 @@ int main() } #endif +#ifdef TEST_KWSYS_CXX_HAS_RLIMIT64 +# if defined(KWSYS_HAS_LFS) +# define _LARGEFILE_SOURCE +# define _LARGEFILE64_SOURCE +# define _LARGE_FILES +# define _FILE_OFFSET_BITS 64 +# endif +# include +int main() +{ + struct rlimit64 rlim; + return getrlimit64(0,&rlim); +} +#endif + +#ifdef TEST_KWSYS_CXX_HAS_ATOLL +#include +int main() +{ + const char *str="1024"; + return static_cast(atoll(str)); +} +#endif + +#ifdef TEST_KWSYS_CXX_HAS_ATOL +#include +int main() +{ + const char *str="1024"; + return static_cast(atol(str)); +} +#endif + +#ifdef TEST_KWSYS_CXX_HAS__ATOI64 +#include +int main() +{ + const char *str="1024"; + return static_cast(_atoi64(str)); +} +#endif + #ifdef TEST_KWSYS_CXX_TYPE_INFO /* Collect fundamental type information and save it to a CMake script. */ diff --git a/testSystemInformation.cxx b/testSystemInformation.cxx index b3afc9de9..41fcf384b 100644 --- a/testSystemInformation.cxx +++ b/testSystemInformation.cxx @@ -13,8 +13,6 @@ #include KWSYS_HEADER(SystemInformation.hxx) #include KWSYS_HEADER(ios/iostream) - - // Work-around CMake dependency scanning limitation. This must // duplicate the above list of headers. #if 0 @@ -22,12 +20,31 @@ # include "kwsys_ios_iostream.h.in" #endif -#define printMethod(inof, m) kwsys_ios::cout << #m << ": " \ +#if defined(KWSYS_USE_LONG_LONG) +# if defined(KWSYS_IOS_HAS_OSTREAM_LONG_LONG) +# define iostreamLongLong(x) (x) +# else +# define iostreamLongLong(x) ((long)x) +# endif +#elif defined(KWSYS_USE___INT64) +# if defined(KWSYS_IOS_HAS_OSTREAM___INT64) +# define iostreamLongLong(x) (x) +# else +# define iostreamLongLong(x) ((long)x) +# endif +#else +# error "No Long Long" +#endif + +#define printMethod(info, m) kwsys_ios::cout << #m << ": " \ << info.m() << "\n" -#define printMethod2(inof, m, unit) kwsys_ios::cout << #m << ": " \ +#define printMethod2(info, m, unit) kwsys_ios::cout << #m << ": " \ << info.m() << " " << unit << "\n" +#define printMethod3(info, m, unit) kwsys_ios::cout << #m << ": " \ +<< iostreamLongLong(info.m) << " " << unit << "\n" + int testSystemInformation(int, char*[]) { kwsys::SystemInformation info; @@ -35,7 +52,11 @@ int testSystemInformation(int, char*[]) info.RunOSCheck(); info.RunMemoryCheck(); printMethod(info, GetOSName); + printMethod(info, GetOSIsLinux); + printMethod(info, GetOSIsApple); + printMethod(info, GetOSIsWindows); printMethod(info, GetHostname); + printMethod(info, GetFullyQualifiedDomainName); printMethod(info, GetOSRelease); printMethod(info, GetOSVersion); printMethod(info, GetOSPlatform); @@ -58,6 +79,11 @@ int testSystemInformation(int, char*[]) printMethod2(info, GetAvailableVirtualMemory, "MB"); printMethod2(info, GetTotalPhysicalMemory, "MB"); printMethod2(info, GetAvailablePhysicalMemory, "MB"); + printMethod3(info, GetHostMemoryTotal(), "KiB"); + printMethod3(info, GetHostMemoryAvailable("KWSHL"), "KiB"); + printMethod3(info, GetProcMemoryAvailable("KWSHL","KWSPL"), "KiB"); + printMethod3(info, GetHostMemoryUsed(), "KiB"); + printMethod3(info, GetProcMemoryUsed(), "KiB"); //int GetProcessorCacheXSize(long int); // bool DoesCPUSupportFeature(long int);