SystemInformation.cxx 147 KB
Newer Older
1 2
/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
   file Copyright.txt or https://cmake.org/licensing#kwsys for details.  */
3
#if defined(_WIN32)
4 5 6 7 8
#define NOMINMAX // use our min,max
#if !defined(_WIN32_WINNT) && !(defined(_MSC_VER) && _MSC_VER < 1300)
#define _WIN32_WINNT 0x0501
#endif
#include <winsock.h> // WSADATA, include before sys/types.h
9 10
#endif

11
#if (defined(__GNUC__) || defined(__PGI)) && !defined(_GNU_SOURCE)
12
#define _GNU_SOURCE
13 14
#endif

15 16 17 18 19 20 21 22 23 24 25 26
// 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

27 28 29
#include "kwsysPrivate.h"
#include KWSYS_HEADER(SystemInformation.hxx)
#include KWSYS_HEADER(Process.h)
30

31 32 33
// Work-around CMake dependency scanning limitation.  This must
// duplicate the above list of headers.
#if 0
34 35
#include "Process.h.in"
#include "SystemInformation.hxx.in"
36 37
#endif

38 39 40
#include <algorithm>
#include <bitset>
#include <cassert>
41
#include <fstream>
42
#include <iostream>
43 44
#include <limits>
#include <set>
45
#include <sstream>
Brad King's avatar
Brad King committed
46 47
#include <string>
#include <vector>
48

49
#if defined(_WIN32)
50 51 52 53 54 55 56 57 58
#include <windows.h>
#if defined(_MSC_VER) && _MSC_VER >= 1800
#define KWSYS_WINDOWS_DEPRECATED_GetVersionEx
#endif
#include <errno.h>
#if defined(KWSYS_SYS_HAS_PSAPI)
#include <psapi.h>
#endif
#if !defined(siginfo_t)
59
typedef int siginfo_t;
60
#endif
61
#else
62 63 64 65 66 67 68 69 70
#include <sys/types.h>

#include <errno.h> // extern int errno;
#include <fcntl.h>
#include <signal.h>
#include <sys/resource.h> // getrlimit
#include <sys/time.h>
#include <sys/utsname.h> // int uname(struct utsname *buf);
#include <unistd.h>
71 72
#endif

73 74 75
#if defined(__CYGWIN__) && !defined(_WIN32)
#include <windows.h>
#undef _WIN32
76 77
#endif

78 79
#if defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__NetBSD__) ||    \
  defined(__DragonFly__)
80 81 82 83 84 85 86
#include <netdb.h>
#include <netinet/in.h>
#include <sys/param.h>
#include <sys/socket.h>
#include <sys/sysctl.h>
#if defined(KWSYS_SYS_HAS_IFADDRS_H)
#include <ifaddrs.h>
87
#include <net/if.h>
88 89
#define KWSYS_SYSTEMINFORMATION_IMPLEMENT_FQDN
#endif
90 91
#endif

92
#if defined(KWSYS_SYS_HAS_MACHINE_CPU_H)
93
#include <machine/cpu.h>
94 95
#endif

96
#ifdef __APPLE__
97 98 99 100 101 102 103 104 105 106 107
#include <fenv.h>
#include <mach/host_info.h>
#include <mach/mach.h>
#include <mach/mach_types.h>
#include <mach/vm_statistics.h>
#include <netdb.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/sysctl.h>
#if defined(KWSYS_SYS_HAS_IFADDRS_H)
#include <ifaddrs.h>
108
#include <net/if.h>
109 110 111 112 113
#define KWSYS_SYSTEMINFORMATION_IMPLEMENT_FQDN
#endif
#if !(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ - 0 >= 1050)
#undef KWSYS_SYSTEMINFORMATION_HAS_BACKTRACE
#endif
114 115
#endif

116 117 118 119 120 121 122
#if defined(__linux) || defined(__sun) || defined(_SCO_DS)
#include <fenv.h>
#include <netdb.h>
#include <netinet/in.h>
#include <sys/socket.h>
#if defined(KWSYS_SYS_HAS_IFADDRS_H)
#include <ifaddrs.h>
123
#include <net/if.h>
124 125 126 127 128
#if !defined(__LSB_VERSION__) /* LSB has no getifaddrs */
#define KWSYS_SYSTEMINFORMATION_IMPLEMENT_FQDN
#endif
#endif
#if defined(KWSYS_CXX_HAS_RLIMIT64)
129
typedef struct rlimit64 ResourceLimitType;
130 131
#define GetResourceLimit getrlimit64
#else
132
typedef struct rlimit ResourceLimitType;
133 134 135 136 137 138 139 140
#define GetResourceLimit getrlimit
#endif
#elif defined(__hpux)
#include <sys/param.h>
#include <sys/pstat.h>
#if defined(KWSYS_SYS_HAS_MPCTL_H)
#include <sys/mpctl.h>
#endif
141 142
#endif

143
#ifdef __HAIKU__
144
#include <OS.h>
145 146
#endif

147
#if defined(KWSYS_SYSTEMINFORMATION_HAS_BACKTRACE)
148 149 150 151 152 153 154
#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
155
#else
156 157
#undef KWSYS_SYSTEMINFORMATION_HAS_CPP_DEMANGLE
#undef KWSYS_SYSTEMINFORMATION_HAS_SYMBOL_LOOKUP
158 159
#endif

160
#include <ctype.h> // int isdigit(int c);
161 162
#include <memory.h>
#include <stdio.h>
163
#include <stdlib.h>
164 165
#include <string.h>

166
#if defined(KWSYS_USE_LONG_LONG)
167 168 169 170 171
#if defined(KWSYS_IOS_HAS_OSTREAM_LONG_LONG)
#define iostreamLongLong(x) (x)
#else
#define iostreamLongLong(x) ((long)(x))
#endif
172
#elif defined(KWSYS_USE___INT64)
173 174 175 176 177
#if defined(KWSYS_IOS_HAS_OSTREAM___INT64)
#define iostreamLongLong(x) (x)
#else
#define iostreamLongLong(x) ((long)(x))
#endif
178
#else
179
#error "No Long Long"
180 181 182
#endif

#if defined(KWSYS_CXX_HAS_ATOLL)
183 184 185 186 187 188
#define atoLongLong atoll
#else
#if defined(KWSYS_CXX_HAS__ATOI64)
#define atoLongLong _atoi64
#elif defined(KWSYS_CXX_HAS_ATOL)
#define atoLongLong atol
189
#else
190 191
#define atoLongLong atoi
#endif
192 193
#endif

194 195
#if defined(_MSC_VER) && (_MSC_VER >= 1300) && !defined(_WIN64) &&            \
  !defined(__clang__)
196 197 198 199 200
#define USE_ASM_INSTRUCTIONS 1
#else
#define USE_ASM_INSTRUCTIONS 0
#endif

201
#if defined(_MSC_VER) && (_MSC_VER >= 1400) && !defined(__clang__)
202 203 204 205 206 207
#include <intrin.h>
#define USE_CPUID_INTRINSICS 1
#else
#define USE_CPUID_INTRINSICS 0
#endif

208 209 210
#if USE_ASM_INSTRUCTIONS || USE_CPUID_INTRINSICS ||                           \
  defined(KWSYS_CXX_HAS_BORLAND_ASM_CPUID)
#define USE_CPUID 1
211
#else
212
#define USE_CPUID 0
213 214 215
#endif

#if USE_CPUID
216 217 218 219 220 221 222 223 224 225

#define CPUID_AWARE_COMPILER

/**
 * call CPUID instruction
 *
 * Will return false if the instruction failed.
 */
static bool call_cpuid(int select, int result[4])
{
226 227 228 229
#if USE_CPUID_INTRINSICS
  __cpuid(result, select);
  return true;
#else
230
  int tmp[4];
231
#if defined(_MSC_VER)
232 233 234 235 236
  // Use SEH to determine CPUID presence
  __try {
    _asm {
#ifdef CPUID_AWARE_COMPILER
      ; we must push/pop the registers <<CPUID>> writes to, as the
237
      ; optimiser does not know about <<CPUID>>, and so does not expect
238 239 240 241 242 243 244 245
      ; these registers to change.
      push eax
      push ebx
      push ecx
      push edx
#endif
      ; <<CPUID>>
      mov eax, select
246 247 248 249 250 251
#ifdef CPUID_AWARE_COMPILER
      cpuid
#else
      _asm _emit 0x0f
      _asm _emit 0xa2
#endif
252 253 254 255 256 257 258 259 260 261 262 263
      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
    }
264
  } __except (1) {
265
    return false;
266
  }
267

268
  memcpy(result, tmp, sizeof(tmp));
269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285
#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

286 287
  // The cpuid instruction succeeded.
  return true;
288
#endif
289 290 291
}
#endif

292 293 294
namespace KWSYS_NAMESPACE {
template <typename T>
T min(T a, T b)
295
{
296 297
  return a < b ? a : b;
}
298

299 300 301
extern "C" {
typedef void (*SigAction)(int, siginfo_t*, void*);
}
302

303
//  Define SystemInformationImplementation class
304
typedef void (*DELAY_FUNC)(unsigned int uiMS);
305

306 307
class SystemInformationImplementation
{
308
public:
309
  typedef SystemInformation::LongLong LongLong;
310 311
  SystemInformationImplementation();
  ~SystemInformationImplementation();
312

313 314
  const char* GetVendorString();
  const char* GetVendorID();
Brad King's avatar
Brad King committed
315 316 317 318 319
  std::string GetTypeID();
  std::string GetFamilyID();
  std::string GetModelID();
  std::string GetModelName();
  std::string GetSteppingCode();
320 321
  const char* GetExtendedProcessorName();
  const char* GetProcessorSerialNumber();
322
  int GetProcessorCacheSize();
323
  unsigned int GetLogicalProcessorsPerPhysical();
324 325 326 327
  float GetProcessorClockFrequency();
  int GetProcessorAPICID();
  int GetProcessorCacheXSize(long int);
  bool DoesCPUSupportFeature(long int);
328

329 330 331 332 333 334
  const char* GetOSName();
  const char* GetHostname();
  int GetFullyQualifiedDomainName(std::string& fqdn);
  const char* GetOSRelease();
  const char* GetOSVersion();
  const char* GetOSPlatform();
335 336 337 338 339 340 341 342 343

  bool Is64Bits();

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

  bool DoesCPUSupportCPUID();

  // Retrieve memory information in megabyte.
344 345 346
  size_t GetTotalVirtualMemory();
  size_t GetAvailableVirtualMemory();
  size_t GetTotalPhysicalMemory();
347 348
  size_t GetAvailablePhysicalMemory();

349
  LongLong GetProcessId();
350 351

  // Retrieve memory information in kib
352
  LongLong GetHostMemoryTotal();
353
  LongLong GetHostMemoryAvailable(const char* envVarName);
354 355
  LongLong GetHostMemoryUsed();

356 357
  LongLong GetProcMemoryAvailable(const char* hostLimitEnvVarName,
                                  const char* procLimitEnvVarName);
358
  LongLong GetProcMemoryUsed();
359

360 361
  double GetLoadAverage();

362
  // enable/disable stack trace signal handler.
363
  static void SetStackTraceOnError(int enable);
364

365
  // get current stack
366
  static std::string GetProgramStack(int firstFrame, int wholePath);
367

368 369 370 371
  /** Run the different checks */
  void RunCPUCheck();
  void RunOSCheck();
  void RunMemoryCheck();
372

373
public:
374
  typedef struct tagID
375
  {
376 377 378 379 380 381
    int Type;
    int Family;
    int Model;
    int Revision;
    int ExtendedFamily;
    int ExtendedModel;
Brad King's avatar
Brad King committed
382 383 384 385
    std::string ProcessorName;
    std::string Vendor;
    std::string SerialNumber;
    std::string ModelName;
386
  } ID;
387

388
  typedef struct tagCPUPowerManagement
389
  {
390 391 392
    bool HasVoltageID;
    bool HasFrequencyID;
    bool HasTempSenseDiode;
393
  } CPUPowerManagement;
394

395
  typedef struct tagCPUExtendedFeatures
396
  {
397 398 399 400 401
    bool Has3DNow;
    bool Has3DNowPlus;
    bool SupportsMP;
    bool HasMMXPlus;
    bool HasSSEMMX;
402
    unsigned int LogicalProcessorsPerPhysical;
403 404
    int APIC_ID;
    CPUPowerManagement PowerManagement;
405
  } CPUExtendedFeatures;
406 407

  typedef struct CPUtagFeatures
408
  {
409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426
    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;
427
  } CPUFeatures;
428 429

  enum Manufacturer
430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445
  {
    AMD,
    Intel,
    NSC,
    UMC,
    Cyrix,
    NexGen,
    IDT,
    Rise,
    Transmeta,
    Sun,
    IBM,
    Motorola,
    HP,
    UnknownManufacturer
  };
446

447
protected:
448
  // For windows
449 450 451 452 453 454 455 456 457 458 459 460
  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();
461

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

470
  void CPUCountWindows();    // For windows
471
  unsigned char GetAPICId(); // For windows
472
  bool IsSMTSupported();
473
  static LongLong GetCyclesDifference(DELAY_FUNC, unsigned int); // For windows
474

475
  // For Linux and Cygwin, /proc/cpuinfo formats are slightly different
476
  bool RetreiveInformationFromCpuInfoFile();
477 478
  std::string ExtractValueFromCpuInfoFile(std::string buffer, const char* word,
                                          size_t init = 0);
479

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

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

486
  void FindManufacturer(const std::string& family = "");
487 488 489

  // For Mac
  bool ParseSysCtl();
490
  int CallSwVers(const char* arg, std::string& ver);
Brad King's avatar
Brad King committed
491 492 493
  void TrimNewline(std::string&);
  std::string ExtractValueFromSysCtl(const char* word);
  std::string SysCtlBuffer;
494 495

  // For Solaris
496 497
  bool QuerySolarisMemory();
  bool QuerySolarisProcessor();
Brad King's avatar
Brad King committed
498 499
  std::string ParseValueFromKStat(const char* arguments);
  std::string RunProcess(std::vector<const char*> args);
500

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

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

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

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

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

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

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

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

Bill Hoffman's avatar
Bill Hoffman committed
533
  size_t CurrentPositionInFile;
534 535 536

  // Operating System information
  bool QueryOSInformation();
Brad King's avatar
Brad King committed
537 538 539 540 541
  std::string OSName;
  std::string Hostname;
  std::string OSRelease;
  std::string OSVersion;
  std::string OSPlatform;
542
  bool OSIs64Bit;
543
};
544

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

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

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

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

Brad King's avatar
Brad King committed
565
std::string SystemInformation::GetTypeID()
566 567 568
{
  return this->Implementation->GetTypeID();
}
569

Brad King's avatar
Brad King committed
570
std::string SystemInformation::GetFamilyID()
571 572 573
{
  return this->Implementation->GetFamilyID();
}
574

Brad King's avatar
Brad King committed
575
std::string SystemInformation::GetModelID()
576 577 578
{
  return this->Implementation->GetModelID();
}
579

Brad King's avatar
Brad King committed
580
std::string SystemInformation::GetModelName()
581 582 583 584
{
  return this->Implementation->GetModelName();
}

Brad King's avatar
Brad King committed
585
std::string SystemInformation::GetSteppingCode()
586 587 588
{
  return this->Implementation->GetSteppingCode();
}
589

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

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

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

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

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

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

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

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

Brad King's avatar
Brad King committed
630
std::string SystemInformation::GetCPUDescription()
631
{
632
  std::ostringstream oss;
633 634 635 636 637
  oss << this->GetNumberOfPhysicalCPU() << " core ";
  if (this->GetModelName().empty()) {
    oss << this->GetProcessorClockFrequency() << " MHz "
        << this->GetVendorString() << " " << this->GetExtendedProcessorName();
  } else {
638
    oss << this->GetModelName();
639
  }
640 641

  // remove extra spaces
642
  std::string tmp = oss.str();
643
  size_t pos;
644 645 646
  while ((pos = tmp.find("  ")) != std::string::npos) {
    tmp.replace(pos, 2, " ");
  }
647 648 649 650

  return tmp;
}

651
const char* SystemInformation::GetOSName()
652 653 654
{
  return this->Implementation->GetOSName();
}
655

656
const char* SystemInformation::GetHostname()
657 658 659
{
  return this->Implementation->GetHostname();
}
660

Brad King's avatar
Brad King committed
661
std::string SystemInformation::GetFullyQualifiedDomainName()
662
{
Brad King's avatar
Brad King committed
663
  std::string fqdn;
664
  this->Implementation->GetFullyQualifiedDomainName(fqdn);
665 666 667
  return fqdn;
}

668
const char* SystemInformation::GetOSRelease()
669 670 671
{
  return this->Implementation->GetOSRelease();
}
672

673
const char* SystemInformation::GetOSVersion()
674 675 676
{
  return this->Implementation->GetOSVersion();
}
677

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

683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709
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
}

Brad King's avatar
Brad King committed
710
std::string SystemInformation::GetOSDescription()
711
{
712
  std::ostringstream oss;
713 714
  oss << this->GetOSName() << " " << this->GetOSRelease() << " "
      << this->GetOSVersion();
715 716 717 718

  return oss.str();
}

719 720 721 722 723 724 725 726 727
bool SystemInformation::Is64Bits()
{
  return this->Implementation->Is64Bits();
}

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

729 730 731 732 733 734 735 736 737 738 739
unsigned int SystemInformation::GetNumberOfPhysicalCPU()
{
  return this->Implementation->GetNumberOfPhysicalCPU();
}

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

// Retrieve memory information in megabyte.
740
size_t SystemInformation::GetTotalVirtualMemory()
741 742 743
{
  return this->Implementation->GetTotalVirtualMemory();
}
744

745
size_t SystemInformation::GetAvailableVirtualMemory()
746 747 748
{
  return this->Implementation->GetAvailableVirtualMemory();
}
749

750
size_t SystemInformation::GetTotalPhysicalMemory()
751 752 753 754
{
  return this->Implementation->GetTotalPhysicalMemory();
}

755
size_t SystemInformation::GetAvailablePhysicalMemory()
756 757 758 759
{
  return this->Implementation->GetAvailablePhysicalMemory();
}

Brad King's avatar
Brad King committed
760
std::string SystemInformation::GetMemoryDescription(
761
  const char* hostLimitEnvVarName, const char* procLimitEnvVarName)
762
{
763
  std::ostringstream oss;
764 765 766 767 768 769 770
  oss << "Host Total: " << iostreamLongLong(this->GetHostMemoryTotal())
      << " KiB, Host Available: "
      << iostreamLongLong(this->GetHostMemoryAvailable(hostLimitEnvVarName))
      << " KiB, Process Available: "
      << iostreamLongLong(this->GetProcMemoryAvailable(hostLimitEnvVarName,
                                                       procLimitEnvVarName))
      << " KiB";
771 772 773
  return oss.str();
}

774 775
// host memory info in units of KiB.
SystemInformation::LongLong SystemInformation::GetHostMemoryTotal()
776
{
777
  return this->Implementation->GetHostMemoryTotal();
778 779
}

780 781
SystemInformation::LongLong SystemInformation::GetHostMemoryAvailable(
  const char* hostLimitEnvVarName)
782
{
783 784 785 786 787 788 789 790 791
  return this->Implementation->GetHostMemoryAvailable(hostLimitEnvVarName);
}

SystemInformation::LongLong SystemInformation::GetHostMemoryUsed()
{
  return this->Implementation->GetHostMemoryUsed();
}

// process memory info in units of KiB.
792 793
SystemInformation::LongLong SystemInformation::GetProcMemoryAvailable(
  const char* hostLimitEnvVarName, const char* procLimitEnvVarName)
794
{
795 796
  return this->Implementation->GetProcMemoryAvailable(hostLimitEnvVarName,
                                                      procLimitEnvVarName);
797 798 799 800 801
}

SystemInformation::LongLong SystemInformation::GetProcMemoryUsed()
{
  return this->Implementation->GetProcMemoryUsed();
802 803
}

804 805 806 807 808
double SystemInformation::GetLoadAverage()
{
  return this->Implementation->GetLoadAverage();
}

809
SystemInformation::LongLong SystemInformation::GetProcessId()
810 811 812 813 814 815 816 817 818
{
  return this->Implementation->GetProcessId();
}

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

Brad King's avatar
Brad King committed
819
std::string SystemInformation::GetProgramStack(int firstFrame, int wholePath)
820
{
821 822
  return SystemInformationImplementation::GetProgramStack(firstFrame,
                                                          wholePath);
823 824
}

825 826 827
/** Run the different checks */
void SystemInformation::RunCPUCheck()
{
828
  this->Implementation->RunCPUCheck();
829
}
830

831 832
void SystemInformation::RunOSCheck()
{
833
  this->Implementation->RunOSCheck();
834
}
835

836 837
void SystemInformation::RunMemoryCheck()
{
838
  this->Implementation->RunMemoryCheck();
839 840 841 842 843
}

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

844 845 846 847
#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
848

849 850 851 852 853
#define MMX_FEATURE 0x00000001
#define MMX_PLUS_FEATURE 0x00000002
#define SSE_FEATURE 0x00000004
#define SSE2_FEATURE 0x00000008
#define AMD_3DNOW_FEATURE 0x00000010
854
#define AMD_3DNOW_PLUS_FEATURE 0x00000020
855 856 857 858 859 860 861 862 863 864 865 866 867
#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
#define SSE_MMX_FEATURE 0x00001000
#define CMOV_FEATURE 0x00002000
#define MTRR_FEATURE 0x00004000
#define L1CACHE_FEATURE 0x00008000
#define L2CACHE_FEATURE 0x00010000
#define L3CACHE_FEATURE 0x00020000
#define ACPI_FEATURE 0x00040000
868 869
#define THERMALMONITOR_FEATURE 0x00080000
#define TEMPSENSEDIODE_FEATURE 0x00100000
870 871
#define FREQUENCYID_FEATURE 0x00200000
#define VOLTAGEID_FREQUENCY 0x00400000
872 873

// Status Flag
874 875 876
#define HT_NOT_CAPABLE 0
#define HT_ENABLED 1
#define HT_DISABLED 2
877
#define HT_SUPPORTED_NOT_ENABLED 3
878
#define HT_CANNOT_DETECT 4
879 880

// EDX[28]  Bit 28 is set if HT is supported
881
#define HT_BIT 0x10000000
882 883

// EAX[11:8] Bit 8-11 contains family processor ID.
884 885
#define FAMILY_ID 0x0F00
#define PENTIUM4_ID 0x0F00
886
// EAX[23:20] Bit 20-23 contains extended family processor ID
887
#define EXT_FAMILY_ID 0x0F00000
888
// EBX[23:16] Bit 16-23 in ebx contains the number of logical
889
#define NUM_LOGICAL_BITS 0x00FF0000
890
// processors per physical processor when execute cpuid with
891
// eax set to 1
892
// EBX[31:24] Bits 24-31 (8 bits) return the 8-bit unique
893
#define INITIAL_APIC_ID_BITS 0xFF000000
894 895 896
// initial APIC ID for the processor this code is running on.
// Default value = 0xff if HT is not supported

897 898
// Hide implementation details in an anonymous namespace.
namespace {
899
// *****************************************************************************
900
#if defined(__linux) || defined(__APPLE__)
901
int LoadLines(FILE* file, std::vector<std::string>& lines)
902 903
{
  // Load each line in the given file into a the vector.
904 905 906 907 908 909 910
  int nRead = 0;
  const int bufSize = 1024;
  char buf[bufSize] = { '\0' };
  while (!feof(file) && !ferror(file)) {
    errno = 0;
    if (fgets(buf, bufSize, file) == 0) {
      if (ferror(file) && (errno == EINTR)) {
911
        clearerr(file);
912
      }
913 914 915 916 917 918 919 920
      continue;
    }
    char* pBuf = buf;
    while (*pBuf) {
      if (*pBuf == '\n')
        *pBuf = '\0';
      pBuf += 1;
    }
921 922
    lines.push_back(buf);
    ++nRead;
923 924
  }
  if (ferror(file)) {
925
    return 0;
926
  }
927 928 929
  return nRead;
}

930
#if defined(__linux)
931
// *****************************************************************************
932
int LoadLines(const char* fileName, std::vector<std::string>& lines)
933
{
934 935
  FILE* file = fopen(fileName, "r");
  if (file == 0) {
936
    return 0;
937 938
  }
  int nRead = LoadLines(file, lines);
939
  fclose(file);
940 941
  return nRead;
}
942
#endif
943 944

// ****************************************************************************
945 946
template <typename T>
int NameValue(std::vector<std::string>& lines, std::string name, T& value)
947
{
948 949 950 951
  size_t nLines = lines.size();
  for (size_t i = 0; i < nLines; ++i) {
    size_t at = lines[i].find(name);
    if (at == std::string::npos) {
952
      continue;
953 954
    }
    std::istringstream is(lines[i].substr(at + name.size()));
955 956
    is >> value;
    return 0;
957
  }
958 959
  return -1;
}
960
#endif
961

962
#if defined(__linux)
963
// ****************************************************************************
964 965
template <typename T>
int GetFieldsFromFile(const char* fileName, const char** fieldNames, T* values)
966
{
Brad King's avatar
Brad King committed
967
  std::vector<std::string> fields;
968
  if (!LoadLines(fileName, fields)) {
969
    return -1;
970 971 972 973 974 975
  }
  int i = 0;
  while (fieldNames[i] != NULL) {
    int ierr = NameValue(fields, fieldNames[i], values[i]);
    if (ierr) {
      return -(i + 2);
976
    }
977 978
    i += 1;
  }
979 980 981 982
  return 0;
}

// ****************************************************************************
983 984 985 986 987 988 989
template <typename T>
int GetFieldFromFile(const char* fileName, const char* fieldName, T& value)
{
  const char* fieldNames[2] = { fieldName, NULL };
  T values[1] = { T(0) };
  int ierr = GetFieldsFromFile(fileName, fieldNames, values);
  if (ierr) {
990
    return ierr;
991 992
  }
  value = values[0];
993 994
  return 0;
}
995
#endif
996 997

// ****************************************************************************
998
#if defined(__APPLE__)
999 1000 1001 1002 1003 1004
template <typename T>
int GetFieldsFromCommand(const char* command, const char** fieldNames,
                         T* values)
{
  FILE* file = popen(command, "r");
  if (file == 0) {
1005
    return -1;
1006
  }
Brad King's avatar
Brad King committed
1007
  std::vector<std::string> fields;
1008
  int nl = LoadLines(file, fields);
1009
  pclose(file);
1010
  if (nl == 0) {
1011
    return -1;
1012 1013 1014 1015 1016 1017
  }
  int i = 0;
  while (fieldNames[i] != NULL) {
    int ierr = NameValue(fields, fieldNames[i], values[i]);
    if (ierr) {
      return -(i + 2);
1018
    }
1019 1020
    i += 1;
  }
1021 1022
  return 0;
}
1023
#endif
1024

1025
// ****************************************************************************
1026
#if !defined(_WIN32) && !defined(__MINGW32__) && !defined(__CYGWIN__)
1027 1028
void StacktraceSignalHandler(int sigNo, siginfo_t* sigInfo,
                             void* /*sigContext*/)
1029 1030
{
#if defined(__linux) || defined(__APPLE__)
1031
  std::ostringstream oss;
1032 1033 1034 1035 1036
  oss << std::endl
      << "========================================================="
      << std::endl
      << "Process id " << getpid() << " ";
  switch (sigNo) {
1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048
    case SIGINT:
      oss << "Caught SIGINT";
      break;

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

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

1049
    case SIGFPE:
1050 1051 1052 1053
      oss << "Caught SIGFPE at " << (sigInfo->si_addr == 0 ? "0x" : "")
          << sigInfo->si_addr << " ";
      switch (sigInfo->si_code) {
#if defined(FPE_INTDIV)
1054
        case FPE_INTDIV:
1055
          oss << "integer division by zero";
1056
          break;
1057
#endif
1058

1059
#if defined(FPE_INTOVF)
1060
        case FPE_INTOVF:
1061
          oss << "integer overflow";
1062
          break;
1063
#endif
1064 1065

        case FPE_FLTDIV:
1066
          oss << "floating point divide by zero";
1067 1068 1069
          break;

        case FPE_FLTOVF:
1070
          oss << "floating point overflow";
1071 1072 1073
          break;

        case FPE_FLTUND:
1074
          oss << "floating point underflow";
1075 1076 1077
          break;

        case FPE_FLTRES:
1078
          oss << "floating point inexact result";
1079 1080 1081
          break;

        case FPE_FLTINV:
1082
          oss << "floating point invalid operation";
1083 1084
          break;

1085
#if defined(FPE_FLTSUB)
1086
        case FPE_FLTSUB:
1087
          oss << "floating point subscript out of range";
1088
          break;
1089
#endif
1090 1091

        default:
1092
          oss << "code " << sigInfo->si_code;
1093
          break;
1094
      }
1095 1096 1097
      break;

    case SIGSEGV: