SystemInformation.cxx 144 KB
Newer Older
1 2 3
/*============================================================================
  KWSys - Kitware System Library
  Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
4

5 6
  Distributed under the OSI-approved BSD License (the "License");
  see accompanying file Copyright.txt for details.
7

8 9 10 11
  This software is distributed WITHOUT ANY WARRANTY; without even the
  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  See the License for more information.
============================================================================*/
12 13 14

#if defined(_WIN32)
# define NOMINMAX // use our min,max
15 16 17
# if !defined(_WIN32_WINNT) && !(defined(_MSC_VER) && _MSC_VER < 1300)
#  define _WIN32_WINNT 0x0501
# endif
Sebastien Barre's avatar
Sebastien Barre committed
18 19 20
# include <winsock.h> // WSADATA, include before sys/types.h
#endif

21 22 23 24
#if (defined(__GNUC__) || defined(__PGI)) && !defined(_GNU_SOURCE)
# define _GNU_SOURCE
#endif

25 26 27 28 29 30 31 32 33 34 35 36
// TODO:
// We need an alternative implementation for many functions in this file
// when USE_ASM_INSTRUCTIONS gets defined as 0.
//
// Consider using these on Win32/Win64 for some of them:
//
// IsProcessorFeaturePresent
// http://msdn.microsoft.com/en-us/library/ms724482(VS.85).aspx
//
// GetProcessMemoryInfo
// http://msdn.microsoft.com/en-us/library/ms683219(VS.85).aspx

37
#include "kwsysPrivate.h"
38 39 40
#include KWSYS_HEADER(stl/string)
#include KWSYS_HEADER(stl/vector)
#include KWSYS_HEADER(ios/iosfwd)
41 42 43
#include KWSYS_HEADER(SystemInformation.hxx)
#include KWSYS_HEADER(Process.h)
#include KWSYS_HEADER(ios/iostream)
44
#include KWSYS_HEADER(ios/sstream)
45
#include KWSYS_HEADER(ios/fstream)
46

47 48 49 50 51 52 53 54 55 56 57
// Work-around CMake dependency scanning limitation.  This must
// duplicate the above list of headers.
#if 0
# include "SystemInformation.hxx.in"
# include "Process.h.in"
# include "Configure.hxx.in"
# include "kwsys_stl.hxx.in"
# include "kwsys_stl_vector.in"
# include "kwsys_stl_iosfwd.in"
# include "kwsys_ios_sstream.h.in"
# include "kwsys_ios_iostream.h.in"
58
# include "kwsys_ios_fstream.h.in"
59 60
#endif

61
#if defined(_WIN32)
62
# include <windows.h>
63
# include <errno.h>
64 65 66
# if defined(KWSYS_SYS_HAS_PSAPI)
#  include <psapi.h>
# endif
67
# if !defined(siginfo_t)
68
typedef int siginfo_t;
69 70 71 72 73
# endif
#else
# include <sys/types.h>
# include <sys/time.h>
# include <sys/utsname.h> // int uname(struct utsname *buf);
74
# include <sys/resource.h> // getrlimit
75 76 77 78
# include <unistd.h>
# include <signal.h>
# include <fcntl.h>
# include <errno.h> // extern int errno;
79 80
#endif

81 82 83 84 85 86 87 88 89 90 91 92
#ifdef __FreeBSD__
# include <sys/sysctl.h>
# include <fenv.h>
# include <sys/socket.h>
# include <netdb.h>
# include <netinet/in.h>
# if defined(KWSYS_SYS_HAS_IFADDRS_H)
#  include <ifaddrs.h>
#  define KWSYS_SYSTEMINFORMATION_IMPLEMENT_FQDN
# endif
#endif

93 94 95 96 97
#if defined(__OpenBSD__) || defined(__NetBSD__)
# include <sys/param.h>
# include <sys/sysctl.h>
#endif

98 99 100 101
#if defined(KWSYS_SYS_HAS_MACHINE_CPU_H)
# include <machine/cpu.h>
#endif

102 103 104 105
#if defined(__DragonFly__)
# include <sys/sysctl.h>
#endif

106
#ifdef __APPLE__
107 108 109 110 111 112 113 114 115
# include <sys/sysctl.h>
# include <mach/vm_statistics.h>
# include <mach/host_info.h>
# include <mach/mach.h>
# include <mach/mach_types.h>
# include <fenv.h>
# include <sys/socket.h>
# include <netdb.h>
# include <netinet/in.h>
116 117 118 119
# if defined(KWSYS_SYS_HAS_IFADDRS_H)
#  include <ifaddrs.h>
#  define KWSYS_SYSTEMINFORMATION_IMPLEMENT_FQDN
# endif
120
# if __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__-0 >= 1050
121 122 123 124 125 126 127 128 129
#  if defined(KWSYS_SYSTEMINFORMATION_HAS_BACKTRACE)
#   include <execinfo.h>
#   if defined(KWSYS_SYSTEMINFORMATION_HAS_CPP_DEMANGLE)
#     include <cxxabi.h>
#   endif
#   if defined(KWSYS_SYSTEMINFORMATION_HAS_SYMBOL_LOOKUP)
#     include <dlfcn.h>
#   endif
#  endif
130
# endif
131 132
#endif

133
#ifdef __linux
134 135 136 137
# include <fenv.h>
# include <sys/socket.h>
# include <netdb.h>
# include <netinet/in.h>
138 139 140 141 142 143
# if defined(KWSYS_SYS_HAS_IFADDRS_H)
#  include <ifaddrs.h>
#  if !defined(__LSB_VERSION__) /* LSB has no getifaddrs */
#   define KWSYS_SYSTEMINFORMATION_IMPLEMENT_FQDN
#  endif
# endif
144
# if defined(KWSYS_SYSTEMINFORMATION_HAS_BACKTRACE)
145
#  include <execinfo.h>
146 147 148 149 150
#  if defined(KWSYS_SYSTEMINFORMATION_HAS_CPP_DEMANGLE)
#    include <cxxabi.h>
#  endif
#  if defined(KWSYS_SYSTEMINFORMATION_HAS_SYMBOL_LOOKUP)
#    include <dlfcn.h>
151
#  endif
152
# endif
153 154 155 156 157 158 159
# if defined(KWSYS_CXX_HAS_RLIMIT64)
typedef struct rlimit64 ResourceLimitType;
#  define GetResourceLimit getrlimit64
# else
typedef struct rlimit ResourceLimitType;
#  define GetResourceLimit getrlimit
# endif
160
#elif defined( __hpux )
161 162
# include <sys/param.h>
# include <sys/pstat.h>
163 164 165
# if defined(KWSYS_SYS_HAS_MPCTL_H)
#  include <sys/mpctl.h>
# endif
166 167
#endif

168
#ifdef __HAIKU__
169
# include <OS.h>
170 171
#endif

172 173 174 175
#include <memory.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
176
#include <ctype.h> // int isdigit(int c);
177

178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205
#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

206 207 208 209 210 211
#if defined(_MSC_VER) && (_MSC_VER >= 1300) && !defined(_WIN64)
#define USE_ASM_INSTRUCTIONS 1
#else
#define USE_ASM_INSTRUCTIONS 0
#endif

212 213 214 215 216 217 218
#if defined(_MSC_VER) && (_MSC_VER >= 1400)
#include <intrin.h>
#define USE_CPUID_INTRINSICS 1
#else
#define USE_CPUID_INTRINSICS 0
#endif

219
#if USE_ASM_INSTRUCTIONS || USE_CPUID_INTRINSICS || defined(KWSYS_CXX_HAS_BORLAND_ASM_CPUID)
220 221 222 223 224 225
# define USE_CPUID 1
#else
# define USE_CPUID 0
#endif

#if USE_CPUID
226 227 228 229 230 231 232 233 234 235

#define CPUID_AWARE_COMPILER

/**
 * call CPUID instruction
 *
 * Will return false if the instruction failed.
 */
static bool call_cpuid(int select, int result[4])
{
236 237 238 239
#if USE_CPUID_INTRINSICS
  __cpuid(result, select);
  return true;
#else
240
  int tmp[4];
241
#if defined(_MSC_VER)
242 243 244 245 246 247 248 249 250 251 252 253 254 255
  // Use SEH to determine CPUID presence
  __try {
    _asm {
#ifdef CPUID_AWARE_COMPILER
      ; we must push/pop the registers <<CPUID>> writes to, as the
      ; optimiser doesn't know about <<CPUID>>, and so doesn't expect
      ; these registers to change.
      push eax
      push ebx
      push ecx
      push edx
#endif
      ; <<CPUID>>
      mov eax, select
256 257 258 259 260 261
#ifdef CPUID_AWARE_COMPILER
      cpuid
#else
      _asm _emit 0x0f
      _asm _emit 0xa2
#endif
262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279
      mov tmp[0 * TYPE int], eax
      mov tmp[1 * TYPE int], ebx
      mov tmp[2 * TYPE int], ecx
      mov tmp[3 * TYPE int], edx

#ifdef CPUID_AWARE_COMPILER
      pop edx
      pop ecx
      pop ebx
      pop eax
#endif
      }
    }
  __except(1)
    {
    return false;
    }

280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297
    memcpy(result, tmp, sizeof(tmp));
#elif defined(KWSYS_CXX_HAS_BORLAND_ASM_CPUID)
  unsigned int a, b, c, d;
  __asm {
    mov EAX, select;
    cpuid
    mov a, EAX;
    mov b, EBX;
    mov c, ECX;
    mov d, EDX;
  }

  result[0] = a;
  result[1] = b;
  result[2] = c;
  result[3] = d;
#endif

298 299
  // The cpuid instruction succeeded.
  return true;
300
#endif
301 302 303 304
}
#endif


305 306
namespace KWSYS_NAMESPACE
{
307 308
template<typename T>
T min(T a, T b){ return a<b ? a : b; }
309

310 311
extern "C" { typedef void (*SigAction)(int,siginfo_t*,void*); }

312 313 314
//  Define SystemInformationImplementation class
typedef  void (*DELAY_FUNC)(unsigned int uiMS);

315 316
class SystemInformationImplementation
{
317
public:
318
  typedef SystemInformation::LongLong LongLong;
319 320 321 322 323 324 325 326
  SystemInformationImplementation ();
  ~SystemInformationImplementation ();

  const char * GetVendorString();
  const char * GetVendorID();
  kwsys_stl::string GetTypeID();
  kwsys_stl::string GetFamilyID();
  kwsys_stl::string GetModelID();
327
  kwsys_stl::string GetModelName();
328 329 330 331
  kwsys_stl::string GetSteppingCode();
  const char * GetExtendedProcessorName();
  const char * GetProcessorSerialNumber();
  int GetProcessorCacheSize();
332
  unsigned int GetLogicalProcessorsPerPhysical();
333 334 335 336
  float GetProcessorClockFrequency();
  int GetProcessorAPICID();
  int GetProcessorCacheXSize(long int);
  bool DoesCPUSupportFeature(long int);
337

338 339
  const char * GetOSName();
  const char * GetHostname();
340
  int GetFullyQualifiedDomainName(kwsys_stl::string &fqdn);
341 342 343 344 345 346 347 348 349 350 351 352
  const char * GetOSRelease();
  const char * GetOSVersion();
  const char * GetOSPlatform();

  bool Is64Bits();

  unsigned int GetNumberOfLogicalCPU(); // per physical cpu
  unsigned int GetNumberOfPhysicalCPU();

  bool DoesCPUSupportCPUID();

  // Retrieve memory information in megabyte.
353 354 355
  size_t GetTotalVirtualMemory();
  size_t GetAvailableVirtualMemory();
  size_t GetTotalPhysicalMemory();
356 357
  size_t GetAvailablePhysicalMemory();

358
  LongLong GetProcessId();
359 360

  // Retrieve memory information in kib
361 362 363 364 365 366 367 368
  LongLong GetHostMemoryTotal();
  LongLong GetHostMemoryAvailable(const char *envVarName);
  LongLong GetHostMemoryUsed();

  LongLong GetProcMemoryAvailable(
        const char *hostLimitEnvVarName,
        const char *procLimitEnvVarName);
  LongLong GetProcMemoryUsed();
369 370 371 372

  // enable/disable stack trace signal handler.
  static
  void SetStackTraceOnError(int enable);
373

374 375 376 377
  // get current stack
  static
  kwsys_stl::string GetProgramStack(int firstFrame, int wholePath);

378 379 380 381
  /** Run the different checks */
  void RunCPUCheck();
  void RunOSCheck();
  void RunMemoryCheck();
382

383
public:
384
  typedef struct tagID
385 386 387 388 389 390 391
    {
    int Type;
    int Family;
    int Model;
    int Revision;
    int ExtendedFamily;
    int ExtendedModel;
392 393 394
    kwsys_stl::string ProcessorName;
    kwsys_stl::string Vendor;
    kwsys_stl::string SerialNumber;
395
    kwsys_stl::string ModelName;
396 397
    } ID;

398
  typedef struct tagCPUPowerManagement
399 400 401 402 403 404
    {
    bool HasVoltageID;
    bool HasFrequencyID;
    bool HasTempSenseDiode;
    } CPUPowerManagement;

405
  typedef struct tagCPUExtendedFeatures
406 407 408 409 410 411 412
    {
    bool Has3DNow;
    bool Has3DNowPlus;
    bool SupportsMP;
    bool HasMMXPlus;
    bool HasSSEMMX;
    bool SupportsHyperthreading;
413
    unsigned int LogicalProcessorsPerPhysical;
414 415
    int APIC_ID;
    CPUPowerManagement PowerManagement;
416 417 418
    } CPUExtendedFeatures;

  typedef struct CPUtagFeatures
419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438
    {
    bool HasFPU;
    bool HasTSC;
    bool HasMMX;
    bool HasSSE;
    bool HasSSEFP;
    bool HasSSE2;
    bool HasIA64;
    bool HasAPIC;
    bool HasCMOV;
    bool HasMTRR;
    bool HasACPI;
    bool HasSerial;
    bool HasThermal;
    int CPUSpeed;
    int L1CacheSize;
    int L2CacheSize;
    int L3CacheSize;
    CPUExtendedFeatures ExtendedFeatures;
    } CPUFeatures;
439 440

  enum Manufacturer
441
    {
442
    AMD, Intel, NSC, UMC, Cyrix, NexGen, IDT, Rise, Transmeta, Sun, IBM,
443
    Motorola, HP, UnknownManufacturer
444 445
    };

446
protected:
447 448 449 450 451 452 453 454 455 456 457 458 459
  // Functions.
  bool RetrieveCPUFeatures();
  bool RetrieveCPUIdentity();
  bool RetrieveCPUCacheDetails();
  bool RetrieveClassicalCPUCacheDetails();
  bool RetrieveCPUClockSpeed();
  bool RetrieveClassicalCPUClockSpeed();
  bool RetrieveCPUExtendedLevelSupport(int);
  bool RetrieveExtendedCPUFeatures();
  bool RetrieveProcessorSerialNumber();
  bool RetrieveCPUPowerManagement();
  bool RetrieveClassicalCPUIdentity();
  bool RetrieveExtendedCPUIdentity();
460

461 462 463 464 465 466 467 468 469 470
  Manufacturer  ChipManufacturer;
  CPUFeatures   Features;
  ID            ChipID;
  float         CPUSpeedInMHz;
  unsigned int  NumberOfLogicalCPU;
  unsigned int  NumberOfPhysicalCPU;

  int CPUCount();
  unsigned char LogicalCPUPerPhysicalCPU();
  unsigned char GetAPICId();
471
  bool IsHyperThreadingSupported();
472
  static LongLong GetCyclesDifference(DELAY_FUNC, unsigned int);
473

474
  // For Linux and Cygwin, /proc/cpuinfo formats are slightly different
475
  bool RetreiveInformationFromCpuInfoFile();
476
  kwsys_stl::string ExtractValueFromCpuInfoFile(kwsys_stl::string buffer,
Bill Hoffman's avatar
Bill Hoffman committed
477
                                          const char* word, size_t init=0);
478

479
  bool QueryLinuxMemory();
480
  bool QueryCygwinMemory();
481

482 483 484
  static void Delay (unsigned int);
  static void DelayOverhead (unsigned int);

485
  void FindManufacturer(const kwsys_stl::string &family = "");
486 487 488

  // For Mac
  bool ParseSysCtl();
489
  int CallSwVers(const char *arg, kwsys_stl::string &ver);
490
  void TrimNewline(kwsys_stl::string&);
491 492 493 494
  kwsys_stl::string ExtractValueFromSysCtl(const char* word);
  kwsys_stl::string SysCtlBuffer;

  // For Solaris
495 496
  bool QuerySolarisMemory();
  bool QuerySolarisProcessor();
497 498 499
  kwsys_stl::string ParseValueFromKStat(const char* arguments);
  kwsys_stl::string RunProcess(kwsys_stl::vector<const char*> args);

500 501 502
  //For Haiku OS
  bool QueryHaikuInfo();

503 504 505 506
  //For QNX
  bool QueryQNXMemory();
  bool QueryQNXProcessor();

507 508 509 510
  //For OpenBSD, FreeBSD, NetBSD, DragonFly
  bool QueryBSDMemory();
  bool QueryBSDProcessor();

511
  //For HP-UX
512
  bool QueryHPUXMemory();
513 514
  bool QueryHPUXProcessor();

515 516 517
  //For Microsoft Windows
  bool QueryWindowsMemory();

518 519 520
  //For AIX
  bool QueryAIXMemory();

521
  bool QueryProcessorBySysconf();
522 523
  bool QueryProcessor();

524
  // Evaluate the memory information.
525
  bool QueryMemoryBySysconf();
526
  bool QueryMemory();
527 528 529 530
  size_t TotalVirtualMemory;
  size_t AvailableVirtualMemory;
  size_t TotalPhysicalMemory;
  size_t AvailablePhysicalMemory;
531

Bill Hoffman's avatar
Bill Hoffman committed
532
  size_t CurrentPositionInFile;
533 534 535 536 537 538 539

  // Operating System information
  bool QueryOSInformation();
  kwsys_stl::string OSName;
  kwsys_stl::string Hostname;
  kwsys_stl::string OSRelease;
  kwsys_stl::string OSVersion;
540
  kwsys_stl::string OSPlatform;
541
};
542

543

544
SystemInformation::SystemInformation()
545 546 547 548
{
  this->Implementation = new SystemInformationImplementation;
}

549
SystemInformation::~SystemInformation()
550 551 552 553 554 555 556 557
{
  delete this->Implementation;
}

const char * SystemInformation::GetVendorString()
{
  return this->Implementation->GetVendorString();
}
558

559 560 561 562
const char * SystemInformation::GetVendorID()
{
  return this->Implementation->GetVendorID();
}
563

564 565 566 567
kwsys_stl::string SystemInformation::GetTypeID()
{
  return this->Implementation->GetTypeID();
}
568

569 570 571 572
kwsys_stl::string SystemInformation::GetFamilyID()
{
  return this->Implementation->GetFamilyID();
}
573

574 575 576 577
kwsys_stl::string SystemInformation::GetModelID()
{
  return this->Implementation->GetModelID();
}
578

579 580 581 582 583
kwsys_stl::string SystemInformation::GetModelName()
{
  return this->Implementation->GetModelName();
}

584 585 586 587
kwsys_stl::string SystemInformation::GetSteppingCode()
{
  return this->Implementation->GetSteppingCode();
}
588

589 590 591 592
const char * SystemInformation::GetExtendedProcessorName()
{
  return this->Implementation->GetExtendedProcessorName();
}
593

594 595 596 597
const char * SystemInformation::GetProcessorSerialNumber()
{
  return this->Implementation->GetProcessorSerialNumber();
}
598

599 600 601 602
int SystemInformation::GetProcessorCacheSize()
{
  return this->Implementation->GetProcessorCacheSize();
}
603

604
unsigned int SystemInformation::GetLogicalProcessorsPerPhysical()
605 606 607
{
  return this->Implementation->GetLogicalProcessorsPerPhysical();
}
608

609 610 611 612
float SystemInformation::GetProcessorClockFrequency()
{
  return this->Implementation->GetProcessorClockFrequency();
}
613

614 615 616 617
int SystemInformation::GetProcessorAPICID()
{
  return this->Implementation->GetProcessorAPICID();
}
618

619 620 621 622
int SystemInformation::GetProcessorCacheXSize(long int l)
{
  return this->Implementation->GetProcessorCacheXSize(l);
}
623

624 625 626 627 628
bool SystemInformation::DoesCPUSupportFeature(long int i)
{
  return this->Implementation->DoesCPUSupportFeature(i);
}

629 630
kwsys_stl::string SystemInformation::GetCPUDescription()
{
631
  kwsys_ios::ostringstream oss;
632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659
  oss
    << this->GetNumberOfPhysicalCPU()
    << " core ";
  if (this->GetModelName().empty())
    {
    oss
      << this->GetProcessorClockFrequency()
      << " MHz "
      << this->GetVendorString()
      << " "
      << this->GetExtendedProcessorName();
    }
  else
    {
    oss << this->GetModelName();
    }

  // remove extra spaces
  kwsys_stl::string tmp=oss.str();
  size_t pos;
  while( (pos=tmp.find("  "))!=kwsys_stl::string::npos)
    {
    tmp.replace(pos,2," ");
    }

  return tmp;
}

660 661 662 663
const char * SystemInformation::GetOSName()
{
  return this->Implementation->GetOSName();
}
664

665 666 667 668
const char * SystemInformation::GetHostname()
{
  return this->Implementation->GetHostname();
}
669

670 671 672
kwsys_stl::string SystemInformation::GetFullyQualifiedDomainName()
{
  kwsys_stl::string fqdn;
673
  this->Implementation->GetFullyQualifiedDomainName(fqdn);
674 675 676
  return fqdn;
}

677 678 679 680
const char * SystemInformation::GetOSRelease()
{
  return this->Implementation->GetOSRelease();
}
681

682 683 684 685
const char * SystemInformation::GetOSVersion()
{
  return this->Implementation->GetOSVersion();
}
686

687 688 689 690 691
const char * SystemInformation::GetOSPlatform()
{
  return this->Implementation->GetOSPlatform();
}

692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720
int SystemInformation::GetOSIsWindows()
{
#if defined(_WIN32)
  return 1;
#else
  return 0;
#endif
}

int SystemInformation::GetOSIsLinux()
{
#if defined(__linux)
  return 1;
#else
  return 0;
#endif
}

int SystemInformation::GetOSIsApple()
{
#if defined(__APPLE__)
  return 1;
#else
  return 0;
#endif
}

kwsys_stl::string SystemInformation::GetOSDescription()
{
721
  kwsys_ios::ostringstream oss;
722 723 724 725 726 727 728 729 730 731
  oss
    << this->GetOSName()
    << " "
    << this->GetOSRelease()
    << " "
    << this->GetOSVersion();

  return oss.str();
}

732 733 734 735 736 737 738 739 740
bool SystemInformation::Is64Bits()
{
  return this->Implementation->Is64Bits();
}

unsigned int SystemInformation::GetNumberOfLogicalCPU() // per physical cpu
{
  return this->Implementation->GetNumberOfLogicalCPU();
}
741

742 743 744 745 746 747 748 749 750 751 752
unsigned int SystemInformation::GetNumberOfPhysicalCPU()
{
  return this->Implementation->GetNumberOfPhysicalCPU();
}

bool SystemInformation::DoesCPUSupportCPUID()
{
  return this->Implementation->DoesCPUSupportCPUID();
}

// Retrieve memory information in megabyte.
753
size_t SystemInformation::GetTotalVirtualMemory()
754 755 756
{
  return this->Implementation->GetTotalVirtualMemory();
}
757

758
size_t SystemInformation::GetAvailableVirtualMemory()
759 760 761
{
  return this->Implementation->GetAvailableVirtualMemory();
}
762

763
size_t SystemInformation::GetTotalPhysicalMemory()
764 765 766 767
{
  return this->Implementation->GetTotalPhysicalMemory();
}

768
size_t SystemInformation::GetAvailablePhysicalMemory()
769 770 771 772
{
  return this->Implementation->GetAvailablePhysicalMemory();
}

773 774 775
kwsys_stl::string SystemInformation::GetMemoryDescription(
      const char *hostLimitEnvVarName,
      const char *procLimitEnvVarName)
776
{
777
  kwsys_ios::ostringstream oss;
778
  oss
779 780 781 782 783 784 785 786
    << "Host Total: "
    << iostreamLongLong(this->GetHostMemoryTotal())
    << " KiB, Host Available: "
    << iostreamLongLong(this->GetHostMemoryAvailable(hostLimitEnvVarName))
    << " KiB, Process Available: "
    << iostreamLongLong(
         this->GetProcMemoryAvailable(hostLimitEnvVarName,procLimitEnvVarName))
    << " KiB";
787 788 789
  return oss.str();
}

790 791
// host memory info in units of KiB.
SystemInformation::LongLong SystemInformation::GetHostMemoryTotal()
792
{
793
  return this->Implementation->GetHostMemoryTotal();
794 795
}

796 797
SystemInformation::LongLong
SystemInformation::GetHostMemoryAvailable(const char *hostLimitEnvVarName)
798
{
799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820
  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();
821 822
}

823
SystemInformation::LongLong SystemInformation::GetProcessId()
824 825 826 827 828 829 830 831 832
{
  return this->Implementation->GetProcessId();
}

void SystemInformation::SetStackTraceOnError(int enable)
{
  SystemInformationImplementation::SetStackTraceOnError(enable);
}

833 834 835 836 837
kwsys_stl::string SystemInformation::GetProgramStack(int firstFrame, int wholePath)
{
  return SystemInformationImplementation::GetProgramStack(firstFrame, wholePath);
}

838 839 840
/** Run the different checks */
void SystemInformation::RunCPUCheck()
{
841
  this->Implementation->RunCPUCheck();
842
}
843

844 845
void SystemInformation::RunOSCheck()
{
846
  this->Implementation->RunOSCheck();
847
}
848

849 850
void SystemInformation::RunMemoryCheck()
{
851
  this->Implementation->RunMemoryCheck();
852 853 854 855 856 857 858 859 860 861 862
}


// --------------------------------------------------------------
// SystemInformationImplementation starts here

#define STORE_TLBCACHE_INFO(x,y)  x = (x < y) ? y : x
#define TLBCACHE_INFO_UNITS      (15)
#define CLASSICAL_CPU_FREQ_LOOP    10000000
#define RDTSC_INSTRUCTION      _asm _emit 0x0f _asm _emit 0x31

863 864 865 866
#define MMX_FEATURE            0x00000001
#define MMX_PLUS_FEATURE       0x00000002
#define SSE_FEATURE            0x00000004
#define SSE2_FEATURE           0x00000008
867
#define AMD_3DNOW_FEATURE      0x00000010
868 869 870 871 872 873 874
#define AMD_3DNOW_PLUS_FEATURE 0x00000020
#define IA64_FEATURE           0x00000040
#define MP_CAPABLE             0x00000080
#define HYPERTHREAD_FEATURE    0x00000100
#define SERIALNUMBER_FEATURE   0x00000200
#define APIC_FEATURE           0x00000400
#define SSE_FP_FEATURE         0x00000800
875
#define SSE_MMX_FEATURE        0x00001000
876 877
#define CMOV_FEATURE           0x00002000
#define MTRR_FEATURE           0x00004000
878 879 880
#define L1CACHE_FEATURE        0x00008000
#define L2CACHE_FEATURE        0x00010000
#define L3CACHE_FEATURE        0x00020000
881 882 883 884 885
#define ACPI_FEATURE           0x00040000
#define THERMALMONITOR_FEATURE 0x00080000
#define TEMPSENSEDIODE_FEATURE 0x00100000
#define FREQUENCYID_FEATURE    0x00200000
#define VOLTAGEID_FREQUENCY    0x00400000
886 887 888 889 890 891 892 893 894

// Status Flag
#define HT_NOT_CAPABLE           0
#define HT_ENABLED               1
#define HT_DISABLED              2
#define HT_SUPPORTED_NOT_ENABLED 3
#define HT_CANNOT_DETECT         4

// EDX[28]  Bit 28 is set if HT is supported
895
#define HT_BIT             0x10000000
896 897 898

// EAX[11:8] Bit 8-11 contains family processor ID.
#define FAMILY_ID          0x0F00
899
#define PENTIUM4_ID        0x0F00
900
// EAX[23:20] Bit 20-23 contains extended family processor ID
901
#define EXT_FAMILY_ID      0x0F00000
902
// EBX[23:16] Bit 16-23 in ebx contains the number of logical
903 904
#define NUM_LOGICAL_BITS   0x00FF0000
// processors per physical processor when execute cpuid with
905
// eax set to 1
906 907
// EBX[31:24] Bits 24-31 (8 bits) return the 8-bit unique
#define INITIAL_APIC_ID_BITS  0xFF000000
908 909 910
// initial APIC ID for the processor this code is running on.
// Default value = 0xff if HT is not supported

911 912
// Hide implementation details in an anonymous namespace.
namespace {
913
// *****************************************************************************
914
#if defined(__linux) || defined(__APPLE__)
915
int LoadLines(
916
      FILE *file,
917 918 919 920 921 922
      kwsys_stl::vector<kwsys_stl::string> &lines)
{
  // Load each line in the given file into a the vector.
  int nRead=0;
  const int bufSize=1024;
  char buf[bufSize]={'\0'};
923 924 925 926 927 928 929 930 931 932 933
  while (!feof(file) && !ferror(file))
    {
    errno=0;
    if (fgets(buf,bufSize,file) == 0)
      {
      if (ferror(file) && (errno==EINTR))
        {
        clearerr(file);
        }
      continue;
      }
934 935 936 937 938 939
    char *pBuf=buf;
    while(*pBuf)
      {
      if (*pBuf=='\n') *pBuf='\0';
      pBuf+=1;
      }
940 941 942 943
    lines.push_back(buf);
    ++nRead;
    }
  if (ferror(file))
944 945 946
    {
    return 0;
    }
947 948 949
  return nRead;
}

950
# if defined(__linux)
951 952 953 954 955 956 957
// *****************************************************************************
int LoadLines(
      const char *fileName,
      kwsys_stl::vector<kwsys_stl::string> &lines)
{
  FILE *file=fopen(fileName,"r");
  if (file==0)
958
    {
959
    return 0;
960
    }
961 962
  int nRead=LoadLines(file,lines);
  fclose(file);
963 964
  return nRead;
}
965
# endif
966 967 968 969 970 971 972 973 974 975

// ****************************************************************************
template<typename T>
int NameValue(
      kwsys_stl::vector<kwsys_stl::string> &lines,
      kwsys_stl::string name, T &value)
{
  size_t nLines=lines.size();
  for (size_t i=0; i<nLines; ++i)
    {
976 977
    size_t at=lines[i].find(name);
    if (at==kwsys_stl::string::npos)
978
      {
979
      continue;
980
      }
981
    kwsys_ios::istringstream is(lines[i].substr(at+name.size()));
982 983
    is >> value;
    return 0;
984 985 986
    }
  return -1;
}
987
#endif
988

989
#if defined(__linux)
990 991 992 993 994 995
// ****************************************************************************
template<typename T>
int GetFieldsFromFile(
      const char *fileName,
      const char **fieldNames,
      T *values)
996 997 998 999 1000 1001
{
  kwsys_stl::vector<kwsys_stl::string> fields;
  if (!LoadLines(fileName,fields))
    {
    return -1;
    }
1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016
  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<typename T>
1017 1018
int GetFieldFromFile(
      const char *fileName,
1019 1020 1021
      const char *fieldName,
      T &value)
{
1022
  const char *fieldNames[2]={fieldName,NULL};
1023
  T values[1]={T(0)};
1024
  int ierr=GetFieldsFromFile(fileName,fieldNames,values);
1025 1026
  if (ierr)
    {
1027 1028 1029 1030 1031
    return ierr;
    }
  value=values[0];
  return 0;
}
1032
#endif
1033 1034

// ****************************************************************************
1035
#if defined(__APPLE__)
1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062
template<typename T>
int GetFieldsFromCommand(
      const char *command,
      const char **fieldNames,
      T *values)
{
  FILE *file=popen(command,"r");
  if (file==0)
    {
    return -1;
    }
  kwsys_stl::vector<kwsys_stl::string> fields;
  int nl=LoadLines(file,fields);
  pclose(file);
  if (nl==0)
    {
    return -1;
    }
  int i=0;
  while (fieldNames[i]!=NULL)
    {
    int ierr=NameValue(fields,fieldNames[i],values[i]);
    if (ierr)
      {
      return -(i+2);
      }
    i+=1;
1063 1064 1065
    }
  return 0;
}
1066
#endif
1067

1068
// ****************************************************************************
1069
#if !defined(_WIN32) && !defined(__MINGW32__) && !defined(__CYGWIN__)
1070 1071 1072 1073 1074 1075
void StacktraceSignalHandler(
      int sigNo,
      siginfo_t *sigInfo,
      void * /*sigContext*/)
{
#if defined(__linux) || defined(__APPLE__)
1076 1077
  kwsys_ios::ostringstream oss;
  oss
1078
     << kwsys_ios::endl
1079 1080
     << "=========================================================" << kwsys_ios::endl
     << "Process id " << getpid() << " ";
1081 1082
  switch (sigNo)
    {
1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094
    case SIGINT:
      oss << "Caught SIGINT";
      break;

    case SIGTERM:
      oss << "Caught SIGTERM";
      break;

    case SIGABRT:
      oss << "Caught SIGABRT";
      break;

1095
    case SIGFPE:
1096 1097 1098 1099 1100
      oss
        << "Caught SIGFPE at "
        << (sigInfo->si_addr==0?"0x":"")
        << sigInfo->si_addr
        <<  " ";
1101 1102
      switch (sigInfo->si_code)
        {
1103
# if defined(FPE_INTDIV)
1104
        case FPE_INTDIV:
1105
          oss << "integer division by zero";
1106
          break;
1107
# endif
1108

1109
# if defined(FPE_INTOVF)
1110
        case FPE_INTOVF:
1111
          oss << "integer overflow";
1112
          break;
1113
# endif
1114 1115

        case FPE_FLTDIV:
1116
          oss << "floating point divide by zero";
1117 1118 1119
          break;

        case FPE_FLTOVF:
1120
          oss << "floating point overflow";
1121 1122 1123
          break;

        case FPE_FLTUND:
1124
          oss << "floating point underflow";
1125 1126 1127
          break;

        case FPE_FLTRES:
1128
          oss << "floating point inexact result";
1129 1130 1131
          break;

        case FPE_FLTINV:
1132
          oss << "floating point invalid operation";
1133 1134
          break;

1135
#if defined(FPE_FLTSUB)
1136
        case FPE_FLTSUB:
1137
          oss << "floating point subscript out of range";
1138
          break;
1139
#endif
1140 1141

        default:
1142
          oss << "code " << sigInfo->si_code;
1143 1144 1145 1146 1147
          break;
        }
      break;

    case SIGSEGV:
1148 1149 1150 1151 1152
      oss
        << "Caught SIGSEGV at "
        << (sigInfo->si_addr==0?"0x":"")
        << sigInfo->si_addr
        <<  " ";
1153 1154 1155
      switch (sigInfo->si_code)
        {
        case SEGV_MAPERR:
1156
          oss << "address not mapped to object";
1157 1158 1159
          break;

        case SEGV_ACCERR:
1160
          oss << "invalid permission for mapped object";
1161 1162 1163
          break;

        default:
1164
          oss << "code " << sigInfo->si_code;
1165 1166 1167 1168 1169
          break;
        }
      break;

    case SIGBUS:
1170 1171 1172 1173 1174
      oss
        << "Caught SIGBUS at "
        << (sigInfo->si_addr==0?"0x":"")
        << sigInfo->si_addr
        <<  " ";
1175 1176 1177
      switch (sigInfo->si_code)
        {
        case BUS_ADRALN:
1178
          oss << "invalid address alignment";
1179 1180
          break;

1181
# if defined(BUS_ADRERR)
1182
        case BUS_ADRERR:
1183
          oss << "nonexistent physical address";
1184
          break;
1185
# endif
1186

1187
# if defined(BUS_OBJERR)
1188
        case BUS_OBJERR:
1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201
          oss << "object-specific hardware error";
          break;
# endif

# if defined(BUS_MCEERR_AR)
        case BUS_MCEERR_AR:
          oss << "Hardware memory error consumed on a machine check; action required.";
          break;
# endif

# if defined(BUS_MCEERR_AO)
        case BUS_MCEERR_AO:
          oss << "Hardware memory error detected in process but not consumed; action optional.";
1202
          break;
1203
# endif
1204 1205

        default:
1206
          oss << "code " << sigInfo->si_code;
1207 1208 1209 1210 1211
          break;
        }
      break;

    case SIGILL:
1212 1213 1214 1215 1216
      oss
        << "Caught SIGILL at "
        << (sigInfo->si_addr==0?"0x":"")
        << sigInfo->si_addr
        <<  " ";
1217 1218 1219
      switch (sigInfo->si_code)
        {
        case ILL_ILLOPC:
1220
          oss << "illegal opcode";
1221 1222
          break;

1223
# if defined(ILL_ILLOPN)
1224
        case ILL_ILLOPN:
1225
          oss << "illegal operand";
1226
          break;
1227
# endif
1228

1229
# if defined(ILL_ILLADR)
1230
        case ILL_ILLADR:
1231
          oss << "illegal addressing mode.";
1232
          break;
1233
# endif
1234 1235

        case ILL_ILLTRP:
1236
          oss << "illegal trap";
1237 1238

        case ILL_PRVOPC:
1239
          oss << "privileged opcode";
1240 1241
          break;

1242
# if defined(ILL_PRVREG)
1243
        case ILL_PRVREG:
1244
          oss << "privileged register";
1245
          break;
1246
# endif
1247

1248
# if defined(ILL_COPROC)
1249
        case ILL_COPROC:
1250
          oss << "co-processor error";
1251
          break;
1252
# endif
1253

1254
# if defined(ILL_BADSTK)
1255
        case ILL_BADSTK:
1256
          oss << "internal stack error";
1257
          break;
1258
# endif
1259 1260

        default:
1261
          oss << "code " << sigInfo->si_code;
1262 1263 1264 1265 1266
          break;
        }
      break;

    default:
1267
      oss << "Caught " << sigNo << " code " << sigInfo->si_code;
1268 1269
      break;
    }
1270
  oss
1271 1272 1273 1274
    << kwsys_ios::endl
    << "Program Stack:" << kwsys_ios::endl
    << SystemInformationImplementation::GetProgramStack(2,0)
    << "=========================================================" << kwsys_ios::endl;
1275
  kwsys_ios::cerr << oss.str() << kwsys_ios::endl;
1276 1277 1278 1279

  // restore the previously registered handlers
  // and abort
  SystemInformationImplementation::SetStackTraceOnError(0);
1280 1281 1282 1283 1284 1285 1286
  abort();
#else
  // avoid warning C4100
  (void)sigNo;
  (void)sigInfo;
#endif
}
1287
#endif
1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342