SystemInformation.cxx 148 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
#if defined(__CYGWIN__) && !defined(_WIN32)
74 75
#  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 87 88 89
#  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>
#    include <net/if.h>
#    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 108 109 110 111 112
#  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>
#    include <net/if.h>
#    define KWSYS_SYSTEMINFORMATION_IMPLEMENT_FQDN
#  endif
#  if !(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ - 0 >= 1050)
#    undef KWSYS_SYSTEMINFORMATION_HAS_BACKTRACE
#  endif
113 114
#endif

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

145
#ifdef __HAIKU__
146
#  include <OS.h>
147 148
#endif

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

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

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

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

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

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

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

#if USE_CPUID
218

219
#  define CPUID_AWARE_COMPILER
220 221 222 223 224 225 226 227

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

259
#      ifdef CPUID_AWARE_COMPILER
260 261 262 263
      pop edx
      pop ecx
      pop ebx
      pop eax
264
#      endif
265
    }
266
  } __except (1) {
267
    return false;
268
  }
269

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

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

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

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

305
//  Define SystemInformationImplementation class
306
typedef void (*DELAY_FUNC)(unsigned int uiMS);
307

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

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

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

  bool Is64Bits();

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

  bool DoesCPUSupportCPUID();

345
  // Retrieve memory information in MiB.
346 347 348
  size_t GetTotalVirtualMemory();
  size_t GetAvailableVirtualMemory();
  size_t GetTotalPhysicalMemory();
349 350
  size_t GetAvailablePhysicalMemory();

351
  LongLong GetProcessId();
352

353
  // Retrieve memory information in KiB.
354
  LongLong GetHostMemoryTotal();
355
  LongLong GetHostMemoryAvailable(const char* envVarName);
356 357
  LongLong GetHostMemoryUsed();

358 359
  LongLong GetProcMemoryAvailable(const char* hostLimitEnvVarName,
                                  const char* procLimitEnvVarName);
360
  LongLong GetProcMemoryUsed();
361

362 363
  double GetLoadAverage();

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

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

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

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

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

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

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

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

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

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

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

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

482
  bool QueryLinuxMemory();
483
  bool QueryCygwinMemory();
484

485 486
  static void Delay(unsigned int);
  static void DelayOverhead(unsigned int);
487

488
  void FindManufacturer(const std::string& family = "");
489 490 491

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

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

503
  // For Haiku OS
504 505
  bool QueryHaikuInfo();

506
  // For QNX
507 508 509
  bool QueryQNXMemory();
  bool QueryQNXProcessor();

510
  // For OpenBSD, FreeBSD, NetBSD, DragonFly
511 512 513
  bool QueryBSDMemory();
  bool QueryBSDProcessor();

514
  // For HP-UX
515
  bool QueryHPUXMemory();
516 517
  bool QueryHPUXProcessor();

518
  // For Microsoft Windows
519 520
  bool QueryWindowsMemory();

521
  // For AIX
522 523
  bool QueryAIXMemory();

524
  bool QueryProcessorBySysconf();
525 526
  bool QueryProcessor();

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

Bill Hoffman's avatar
Bill Hoffman committed
535
  size_t CurrentPositionInFile;
536 537 538

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  return tmp;
}

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

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

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

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

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

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

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 710 711
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
712
std::string SystemInformation::GetOSDescription()
713
{
714
  std::ostringstream oss;
715 716
  oss << this->GetOSName() << " " << this->GetOSRelease() << " "
      << this->GetOSVersion();
717 718 719 720

  return oss.str();
}

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

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

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

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

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

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

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

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

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

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

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

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

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

SystemInformation::LongLong SystemInformation::GetProcMemoryUsed()
{
  return this->Implementation->GetProcMemoryUsed();
804 805
}

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

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

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

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

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

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

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

// SystemInformationImplementation starts here

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

// Status Flag
851 852 853
#define HT_NOT_CAPABLE 0
#define HT_ENABLED 1
#define HT_DISABLED 2
854
#define HT_SUPPORTED_NOT_ENABLED 3
855
#define HT_CANNOT_DETECT 4
856 857

// EDX[28]  Bit 28 is set if HT is supported
858
#define HT_BIT 0x10000000
859 860

// EAX[11:8] Bit 8-11 contains family processor ID.
861 862
#define FAMILY_ID 0x0F00
#define PENTIUM4_ID 0x0F00
863
// EAX[23:20] Bit 20-23 contains extended family processor ID
864
#define EXT_FAMILY_ID 0x0F00000
865
// EBX[23:16] Bit 16-23 in ebx contains the number of logical
866
#define NUM_LOGICAL_BITS 0x00FF0000
867
// processors per physical processor when execute cpuid with
868
// eax set to 1
869
// EBX[31:24] Bits 24-31 (8 bits) return the 8-bit unique
870
#define INITIAL_APIC_ID_BITS 0xFF000000
871 872 873
// initial APIC ID for the processor this code is running on.
// Default value = 0xff if HT is not supported

874 875
// Hide implementation details in an anonymous namespace.
namespace {
876
// *****************************************************************************
877
#if defined(__linux) || defined(__APPLE__)
878
int LoadLines(FILE* file, std::vector<std::string>& lines)
879 880
{
  // Load each line in the given file into a the vector.
881 882 883 884 885
  int nRead = 0;
  const int bufSize = 1024;
  char buf[bufSize] = { '\0' };
  while (!feof(file) && !ferror(file)) {
    errno = 0;
886
    if (fgets(buf, bufSize, file) == KWSYS_NULLPTR) {
887
      if (ferror(file) && (errno == EINTR)) {
888
        clearerr(file);
889
      }
890 891 892 893 894 895 896 897
      continue;
    }
    char* pBuf = buf;
    while (*pBuf) {
      if (*pBuf == '\n')
        *pBuf = '\0';
      pBuf += 1;
    }
898 899
    lines.push_back(buf);
    ++nRead;
900 901
  }
  if (ferror(file)) {
902
    return 0;
903
  }
904 905 906
  return nRead;
}

907
#  if defined(__linux)
908
// *****************************************************************************
909
int LoadLines(const char* fileName, std::vector<std::string>& lines)
910
{
911 912
  FILE* file = fopen(fileName, "r");
  if (file == 0) {
913
    return 0;
914 915
  }
  int nRead = LoadLines(file, lines);
916
  fclose(file);
917 918
  return nRead;
}
919
#  endif
920 921

// ****************************************************************************
922
template <typename T>
Daniel Pfeifer's avatar
Daniel Pfeifer committed
923 924
int NameValue(std::vector<std::string> const& lines, std::string const& name,
              T& value)
925
{
926 927 928 929
  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) {
930
      continue;
931 932
    }
    std::istringstream is(lines[i].substr(at + name.size()));
933 934
    is >> value;
    return 0;
935
  }
936 937
  return -1;
}
938
#endif
939

940
#if defined(__linux)
941
// ****************************************************************************
942 943
template <typename T>
int GetFieldsFromFile(const char* fileName, const char** fieldNames, T* values)
944
{
Brad King's avatar
Brad King committed
945
  std::vector<std::string> fields;
946
  if (!LoadLines(fileName, fields)) {
947
    return -1;
948 949 950 951 952 953
  }
  int i = 0;
  while (fieldNames[i] != NULL) {
    int ierr = NameValue(fields, fieldNames[i], values[i]);
    if (ierr) {
      return -(i + 2);
954
    }
955 956
    i += 1;
  }
957 958 959 960
  return 0;
}

// ****************************************************************************
961 962 963 964 965 966 967
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) {
968
    return ierr;
969 970
  }
  value = values[0];
971 972
  return 0;
}
973
#endif
974 975

// ****************************************************************************
976
#if defined(__APPLE__)
977 978 979 980 981
template <typename T>
int GetFieldsFromCommand(const char* command, const char** fieldNames,
                         T* values)
{
  FILE* file = popen(command, "r");
982
  if (file == KWSYS_NULLPTR) {
983
    return -1;
984
  }
Brad King's avatar
Brad King committed
985
  std::vector<std::string> fields;
986
  int nl = LoadLines(file, fields);
987
  pclose(file);
988
  if (nl == 0) {
989
    return -1;
990 991
  }
  int i = 0;
992
  while (fieldNames[i] != KWSYS_NULLPTR) {
993 994 995
    int ierr = NameValue(fields, fieldNames[i], values[i]);
    if (ierr) {
      return -(i + 2);
996
    }
997 998
    i += 1;
  }
999 1000
  return 0;
}
1001
#endif
1002

1003
// ****************************************************************************
1004
#if !defined(_WIN32) && !defined(__MINGW32__) && !defined(__CYGWIN__)
1005 1006
void StacktraceSignalHandler(int sigNo, siginfo_t* sigInfo,
                             void* /*sigContext*/)
1007
{
1008
#  if defined(__linux) || defined(__APPLE__)
1009
  std::ostringstream oss;
1010 1011 1012 1013 1014
  oss << std::endl
      << "========================================================="
      << std::endl
      << "Process id " << getpid() << " ";
  switch (sigNo) {
1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026
    case SIGINT:
      oss << "Caught SIGINT";
      break;

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

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

1027
    case SIGFPE:
1028 1029
      oss << "Caught SIGFPE at "
          << (sigInfo->si_addr == KWSYS_NULLPTR ? "0x" : "")
1030 1031
          << sigInfo->si_addr << " ";
      switch (sigInfo->si_code) {
1032
#    if defined(FPE_INTDIV)
1033
        case FPE_INTDIV:
1034
          oss << "integer division by zero";
1035
          break;
1036
#    endif
1037

1038
#    if defined(FPE_INTOVF)
1039