SystemInformation.cxx 146 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
Sebastien Barre's avatar
Sebastien Barre committed
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
};
543

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

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

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

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

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

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

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

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

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

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

594
const char* SystemInformation::GetProcessorSerialNumber()
595 596 597
{
  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);
}

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

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

  return tmp;
}

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

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

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

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

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

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

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

  return oss.str();
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

848 849 850 851 852
#define MMX_FEATURE 0x00000001
#define MMX_PLUS_FEATURE 0x00000002
#define SSE_FEATURE 0x00000004
#define SSE2_FEATURE 0x00000008
#define AMD_3DNOW_FEATURE 0x00000010
853
#define AMD_3DNOW_PLUS_FEATURE 0x00000020
854 855 856 857 858 859 860 861 862 863 864 865 866
#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
867 868
#define THERMALMONITOR_FEATURE 0x00080000
#define TEMPSENSEDIODE_FEATURE 0x00100000
869 870
#define FREQUENCYID_FEATURE 0x00200000
#define VOLTAGEID_FREQUENCY 0x00400000
871 872

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

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

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

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

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

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

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

// ****************************************************************************
982 983 984 985 986 987 988
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) {
989
    return ierr;
990 991
  }
  value = values[0];
992 993
  return 0;
}
994
#endif
995 996

// ****************************************************************************
997
#if defined(__APPLE__)
998 999 1000 1001 1002 1003
template <typename T>
int GetFieldsFromCommand(const char* command, const char** fieldNames,
                         T* values)
{
  FILE* file = popen(command, "r");
  if (file == 0) {
1004
    return -1;
1005
  }
Brad King's avatar
Brad King committed
1006
  std::vector<std::string> fields;
1007
  int nl = LoadLines(file, fields);
1008
  pclose(file);
1009
  if (nl == 0) {
1010
    return -1;
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);
1017
    }
1018 1019
    i += 1;
  }
1020 1021
  return 0;
}
1022
#endif
1023

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

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

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

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

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

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

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

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

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

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

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

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

    case SIGSEGV: