SystemInformation.cxx 152 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
#  define NOMINMAX // use our min,max
5
6
7
#  if !defined(_WIN32_WINNT) && defined(_MSC_VER) && _MSC_VER >= 1800
#    define _WIN32_WINNT 0x0600 // vista
#  endif
8
9
10
11
#  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
12
13
#endif

14
#if (defined(__GNUC__) || defined(__PGI)) && !defined(_GNU_SOURCE)
15
#  define _GNU_SOURCE
16
17
#endif

18
19
20
21
22
23
24
25
26
27
28
29
// 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

30
31
32
#include "kwsysPrivate.h"
#include KWSYS_HEADER(SystemInformation.hxx)
#include KWSYS_HEADER(Process.h)
33

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

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

52
#if defined(_WIN32)
53
54
55
56
57
58
59
60
61
#  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)
62
typedef int siginfo_t;
63
#  endif
64
#else
65
66
#  include <sys/types.h>

67
68
#  include <cerrno> // extern int errno;
#  include <csignal>
69
70
71
72
73
#  include <fcntl.h>
#  include <sys/resource.h> // getrlimit
#  include <sys/time.h>
#  include <sys/utsname.h> // int uname(struct utsname *buf);
#  include <unistd.h>
74
75
#endif

76
#if defined(__CYGWIN__) && !defined(_WIN32)
77
78
#  include <windows.h>
#  undef _WIN32
79
80
#endif

81
82
#if defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__NetBSD__) ||    \
  defined(__DragonFly__)
83
84
85
86
87
88
89
90
91
92
#  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
93
94
#endif

95
#if defined(KWSYS_SYS_HAS_MACHINE_CPU_H)
96
#  include <machine/cpu.h>
97
98
#endif

99
#ifdef __APPLE__
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
#  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
116
117
#endif

118
119
#if defined(__linux) || defined(__sun) || defined(_SCO_DS) ||                 \
  defined(__GLIBC__) || defined(__GNU__)
120
121
122
123
124
125
126
#  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__)
127
/* LSB has no getifaddrs */
128
#    elif defined(__ANDROID_API__) && __ANDROID_API__ < 24
129
/* Android has no getifaddrs prior to API 24.  */
130
131
132
133
134
#    else
#      define KWSYS_SYSTEMINFORMATION_IMPLEMENT_FQDN
#    endif
#  endif
#  if defined(KWSYS_CXX_HAS_RLIMIT64)
135
using ResourceLimitType = struct rlimit64;
136
137
#    define GetResourceLimit getrlimit64
#  else
138
typedef struct rlimit ResourceLimitType;
139
140
#    define GetResourceLimit getrlimit
#  endif
141
#elif defined(__hpux)
142
143
144
145
146
#  include <sys/param.h>
#  include <sys/pstat.h>
#  if defined(KWSYS_SYS_HAS_MPCTL_H)
#    include <sys/mpctl.h>
#  endif
147
148
#endif

149
#ifdef __HAIKU__
150
#  include <OS.h>
151
152
#endif

153
#if defined(KWSYS_SYSTEMINFORMATION_HAS_BACKTRACE)
154
155
156
157
158
159
160
#  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
161
#else
162
163
#  undef KWSYS_SYSTEMINFORMATION_HAS_CPP_DEMANGLE
#  undef KWSYS_SYSTEMINFORMATION_HAS_SYMBOL_LOOKUP
164
165
#endif

166
167
168
169
#include <cctype> // int isdigit(int c);
#include <cstdio>
#include <cstdlib>
#include <cstring>
170
171
#include <memory.h>

172
173
#if defined(_MSC_VER) && (_MSC_VER >= 1300) && !defined(_WIN64) &&            \
  !defined(__clang__)
174
#  define USE_ASM_INSTRUCTIONS 1
175
#else
176
#  define USE_ASM_INSTRUCTIONS 0
177
178
#endif

179
180
#if defined(_MSC_VER) && (_MSC_VER >= 1400) && !defined(__clang__) &&         \
  !defined(_M_ARM64)
181
182
#  include <intrin.h>
#  define USE_CPUID_INTRINSICS 1
183
#else
184
#  define USE_CPUID_INTRINSICS 0
185
186
#endif

187
#if USE_ASM_INSTRUCTIONS || USE_CPUID_INTRINSICS
188
#  define USE_CPUID 1
189
#else
190
#  define USE_CPUID 0
191
192
193
#endif

#if USE_CPUID
194

195
#  define CPUID_AWARE_COMPILER
196
197
198
199
200
201
202
203

/**
 * call CPUID instruction
 *
 * Will return false if the instruction failed.
 */
static bool call_cpuid(int select, int result[4])
{
204
#  if USE_CPUID_INTRINSICS
205
206
  __cpuid(result, select);
  return true;
207
#  else
208
  int tmp[4];
209
#    if defined(_MSC_VER)
210
211
212
  // Use SEH to determine CPUID presence
  __try {
    _asm {
213
#      ifdef CPUID_AWARE_COMPILER
214
      ; we must push/pop the registers <<CPUID>> writes to, as the
215
      ; optimiser does not know about <<CPUID>>, and so does not expect
216
217
218
219
220
      ; these registers to change.
      push eax
      push ebx
      push ecx
      push edx
221
#      endif
222
223
      ; <<CPUID>>
      mov eax, select
224
#      ifdef CPUID_AWARE_COMPILER
225
      cpuid
226
#      else
227
228
      _asm _emit 0x0f
      _asm _emit 0xa2
229
#      endif
230
231
232
233
234
      mov tmp[0 * TYPE int], eax
      mov tmp[1 * TYPE int], ebx
      mov tmp[2 * TYPE int], ecx
      mov tmp[3 * TYPE int], edx

235
#      ifdef CPUID_AWARE_COMPILER
236
237
238
239
      pop edx
      pop ecx
      pop ebx
      pop eax
240
#      endif
241
    }
242
  } __except (1) {
243
    return false;
244
  }
245

246
  memcpy(result, tmp, sizeof(tmp));
247
#    endif
248

249
250
  // The cpuid instruction succeeded.
  return true;
251
#  endif
252
253
254
}
#endif

255
256
257
namespace KWSYS_NAMESPACE {
template <typename T>
T min(T a, T b)
258
{
259
260
  return a < b ? a : b;
}
261

262
extern "C" {
263
using SigAction = void (*)(int, siginfo_t*, void*);
264
}
265

266
//  Define SystemInformationImplementation class
267
using DELAY_FUNC = void (*)(unsigned int);
268

269
270
class SystemInformationImplementation
{
271
public:
272
  SystemInformationImplementation();
273
  ~SystemInformationImplementation() = default;
274

275
  const char* GetVendorString() const;
276
  const char* GetVendorID();
277
278
279
280
281
282
283
284
285
286
287
288
289
  std::string GetTypeID() const;
  std::string GetFamilyID() const;
  std::string GetModelID() const;
  std::string GetModelName() const;
  std::string GetSteppingCode() const;
  const char* GetExtendedProcessorName() const;
  const char* GetProcessorSerialNumber() const;
  int GetProcessorCacheSize() const;
  unsigned int GetLogicalProcessorsPerPhysical() const;
  float GetProcessorClockFrequency() const;
  int GetProcessorAPICID() const;
  int GetProcessorCacheXSize(long int) const;
  bool DoesCPUSupportFeature(long int) const;
290

291
292
293
294
295
296
  const char* GetOSName();
  const char* GetHostname();
  int GetFullyQualifiedDomainName(std::string& fqdn);
  const char* GetOSRelease();
  const char* GetOSVersion();
  const char* GetOSPlatform();
297

298
  bool Is64Bits() const;
299

300
301
  unsigned int GetNumberOfLogicalCPU() const; // per physical cpu
  unsigned int GetNumberOfPhysicalCPU() const;
302
303
304

  bool DoesCPUSupportCPUID();

305
  // Retrieve memory information in MiB.
306
307
308
309
  size_t GetTotalVirtualMemory() const;
  size_t GetAvailableVirtualMemory() const;
  size_t GetTotalPhysicalMemory() const;
  size_t GetAvailablePhysicalMemory() const;
310

311
  long long GetProcessId();
312

313
  // Retrieve memory information in KiB.
314
315
316
  long long GetHostMemoryTotal();
  long long GetHostMemoryAvailable(const char* hostLimitEnvVarName);
  long long GetHostMemoryUsed();
317

318
319
320
  long long GetProcMemoryAvailable(const char* hostLimitEnvVarName,
                                   const char* procLimitEnvVarName);
  long long GetProcMemoryUsed();
321

322
323
  double GetLoadAverage();

324
  // enable/disable stack trace signal handler.
325
  static void SetStackTraceOnError(int enable);
326

327
  // get current stack
328
  static std::string GetProgramStack(int firstFrame, int wholePath);
329

330
331
332
333
  /** Run the different checks */
  void RunCPUCheck();
  void RunOSCheck();
  void RunMemoryCheck();
334

335
public:
336
337
  using ID = struct tagID

338
  {
339

340
    int Type;
341

342
    int Family;
343

344
    int Model;
345

346
    int Revision;
347

348
    int ExtendedFamily;
349

350
    int ExtendedModel;
351

Brad King's avatar
Brad King committed
352
    std::string ProcessorName;
353

Brad King's avatar
Brad King committed
354
    std::string Vendor;
355

Brad King's avatar
Brad King committed
356
    std::string SerialNumber;
357

Brad King's avatar
Brad King committed
358
    std::string ModelName;
359
360
361
  };

  using CPUPowerManagement = struct tagCPUPowerManagement
362

363
  {
364

365
    bool HasVoltageID;
366

367
    bool HasFrequencyID;
368

369
    bool HasTempSenseDiode;
370
371
372
  };

  using CPUExtendedFeatures = struct tagCPUExtendedFeatures
373

374
  {
375

376
    bool Has3DNow;
377

378
    bool Has3DNowPlus;
379

380
    bool SupportsMP;
381

382
    bool HasMMXPlus;
383

384
    bool HasSSEMMX;
385

386
    unsigned int LogicalProcessorsPerPhysical;
387

388
    int APIC_ID;
389

390
    CPUPowerManagement PowerManagement;
391
392
393
  };

  using CPUFeatures = struct CPUtagFeatures
394

395
  {
396

397
    bool HasFPU;
398

399
    bool HasTSC;
400

401
    bool HasMMX;
402

403
    bool HasSSE;
404

405
    bool HasSSEFP;
406

407
    bool HasSSE2;
408

409
    bool HasIA64;
410

411
    bool HasAPIC;
412

413
    bool HasCMOV;
414

415
    bool HasMTRR;
416

417
    bool HasACPI;
418

419
    bool HasSerial;
420

421
    bool HasThermal;
422

423
    int CPUSpeed;
424

425
    int L1CacheSize;
426

427
    int L2CacheSize;
428

429
    int L3CacheSize;
430

431
    CPUExtendedFeatures ExtendedFeatures;
432
  };
433
434

  enum Manufacturer
435
436
437
438
439
440
441
442
443
444
445
446
447
448
  {
    AMD,
    Intel,
    NSC,
    UMC,
    Cyrix,
    NexGen,
    IDT,
    Rise,
    Transmeta,
    Sun,
    IBM,
    Motorola,
    HP,
449
    Hygon,
450
    Zhaoxin,
451
    Apple,
452
453
    UnknownManufacturer
  };
454

455
protected:
456
  // For windows
457
458
459
460
461
462
463
464
465
466
467
468
  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();
469

470
  // Processor information
471
472
473
474
475
476
  Manufacturer ChipManufacturer;
  CPUFeatures Features;
  ID ChipID;
  float CPUSpeedInMHz;
  unsigned int NumberOfLogicalCPU;
  unsigned int NumberOfPhysicalCPU;
477

478
  void CPUCountWindows();    // For windows
479
  unsigned char GetAPICId(); // For windows
480
  bool IsSMTSupported() const;
481
482
  static long long GetCyclesDifference(DELAY_FUNC,
                                       unsigned int); // For windows
483

484
  // For Linux and Cygwin, /proc/cpuinfo formats are slightly different
485
  bool RetreiveInformationFromCpuInfoFile();
486
487
  std::string ExtractValueFromCpuInfoFile(std::string buffer, const char* word,
                                          size_t init = 0);
488

489
  bool QueryLinuxMemory();
490
  bool QueryCygwinMemory();
491

492
493
  static void Delay(unsigned int);
  static void DelayOverhead(unsigned int);
494

495
  void FindManufacturer(const std::string& family = "");
496
497
498

  // For Mac
  bool ParseSysCtl();
499
  int CallSwVers(const char* arg, std::string& ver);
Brad King's avatar
Brad King committed
500
501
502
  void TrimNewline(std::string&);
  std::string ExtractValueFromSysCtl(const char* word);
  std::string SysCtlBuffer;
503
504

  // For Solaris
505
506
  bool QuerySolarisMemory();
  bool QuerySolarisProcessor();
Brad King's avatar
Brad King committed
507
508
  std::string ParseValueFromKStat(const char* arguments);
  std::string RunProcess(std::vector<const char*> args);
509

510
  // For Haiku OS
511
512
  bool QueryHaikuInfo();

513
  // For QNX
514
515
516
  bool QueryQNXMemory();
  bool QueryQNXProcessor();

517
  // For OpenBSD, FreeBSD, NetBSD, DragonFly
518
519
520
  bool QueryBSDMemory();
  bool QueryBSDProcessor();

521
  // For HP-UX
522
  bool QueryHPUXMemory();
523
524
  bool QueryHPUXProcessor();

525
  // For Microsoft Windows
526
527
  bool QueryWindowsMemory();

528
  // For AIX
529
530
  bool QueryAIXMemory();

531
  bool QueryProcessorBySysconf();
532
533
  bool QueryProcessor();

534
  // Evaluate the memory information.
535
  bool QueryMemoryBySysconf();
536
  bool QueryMemory();
537
538
539
540
  size_t TotalVirtualMemory;
  size_t AvailableVirtualMemory;
  size_t TotalPhysicalMemory;
  size_t AvailablePhysicalMemory;
541

Bill Hoffman's avatar
Bill Hoffman committed
542
  size_t CurrentPositionInFile;
543
544
545

  // Operating System information
  bool QueryOSInformation();
Brad King's avatar
Brad King committed
546
547
548
549
550
  std::string OSName;
  std::string Hostname;
  std::string OSRelease;
  std::string OSVersion;
  std::string OSPlatform;
551
  bool OSIs64Bit;
552
};
553

554
SystemInformation::SystemInformation()
555
556
557
558
{
  this->Implementation = new SystemInformationImplementation;
}

559
SystemInformation::~SystemInformation()
560
561
562
563
{
  delete this->Implementation;
}

564
const char* SystemInformation::GetVendorString()
565
566
567
{
  return this->Implementation->GetVendorString();
}
568

569
const char* SystemInformation::GetVendorID()
570
571
572
{
  return this->Implementation->GetVendorID();
}
573

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

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

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

Brad King's avatar
Brad King committed
589
std::string SystemInformation::GetModelName()
590
591
592
593
{
  return this->Implementation->GetModelName();
}

Brad King's avatar
Brad King committed
594
std::string SystemInformation::GetSteppingCode()
595
596
597
{
  return this->Implementation->GetSteppingCode();
}
598

599
const char* SystemInformation::GetExtendedProcessorName()
600
601
602
{
  return this->Implementation->GetExtendedProcessorName();
}
603

604
const char* SystemInformation::GetProcessorSerialNumber()
605
606
607
{
  return this->Implementation->GetProcessorSerialNumber();
}
608

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

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

619
620
621
622
float SystemInformation::GetProcessorClockFrequency()
{
  return this->Implementation->GetProcessorClockFrequency();
}
623

624
625
626
627
int SystemInformation::GetProcessorAPICID()
{
  return this->Implementation->GetProcessorAPICID();
}
628

629
630
631
632
int SystemInformation::GetProcessorCacheXSize(long int l)
{
  return this->Implementation->GetProcessorCacheXSize(l);
}
633

634
635
636
637
638
bool SystemInformation::DoesCPUSupportFeature(long int i)
{
  return this->Implementation->DoesCPUSupportFeature(i);
}

Brad King's avatar
Brad King committed
639
std::string SystemInformation::GetCPUDescription()
640
{
641
  std::ostringstream oss;
642
643
644
645
646
  oss << this->GetNumberOfPhysicalCPU() << " core ";
  if (this->GetModelName().empty()) {
    oss << this->GetProcessorClockFrequency() << " MHz "
        << this->GetVendorString() << " " << this->GetExtendedProcessorName();
  } else {
647
    oss << this->GetModelName();
648
  }
649
650

  // remove extra spaces
651
  std::string tmp = oss.str();
652
  size_t pos;
653
654
655
  while ((pos = tmp.find("  ")) != std::string::npos) {
    tmp.replace(pos, 2, " ");
  }
656
657
658
659

  return tmp;
}

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

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

Brad King's avatar
Brad King committed
670
std::string SystemInformation::GetFullyQualifiedDomainName()
671
{
Brad King's avatar
Brad King committed
672
  std::string fqdn;
673
  this->Implementation->GetFullyQualifiedDomainName(fqdn);
674
675
676
  return fqdn;
}

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

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

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

692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
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
719
std::string SystemInformation::GetOSDescription()
720
{
721
  std::ostringstream oss;
722
723
  oss << this->GetOSName() << " " << this->GetOSRelease() << " "
      << this->GetOSVersion();
724
725
726
727

  return oss.str();
}

728
729
730
731
732
733
734
735
736
bool SystemInformation::Is64Bits()
{
  return this->Implementation->Is64Bits();
}

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

738
739
740
741
742
743
744
745
746
747
unsigned int SystemInformation::GetNumberOfPhysicalCPU()
{
  return this->Implementation->GetNumberOfPhysicalCPU();
}

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

748
// Retrieve memory information in MiB.
749
size_t SystemInformation::GetTotalVirtualMemory()
750
751
752
{
  return this->Implementation->GetTotalVirtualMemory();
}
753

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

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

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

Brad King's avatar
Brad King committed
769
std::string SystemInformation::GetMemoryDescription(
770
  const char* hostLimitEnvVarName, const char* procLimitEnvVarName)
771
{
772
  std::ostringstream oss;
773
  oss << "Host Total: " << this->GetHostMemoryTotal()
774
      << " KiB, Host Available: "
775
      << this->GetHostMemoryAvailable(hostLimitEnvVarName)
776
      << " KiB, Process Available: "
777
      << this->GetProcMemoryAvailable(hostLimitEnvVarName, procLimitEnvVarName)
778
      << " KiB";
779
780
781
  return oss.str();
}

782
// host memory info in units of KiB.
783
long long SystemInformation::GetHostMemoryTotal()
784
{
785
  return this->Implementation->GetHostMemoryTotal();
786
787
}

788
long long SystemInformation::GetHostMemoryAvailable(
789
  const char* hostLimitEnvVarName)
790
{
791
792
793
  return this->Implementation->GetHostMemoryAvailable(hostLimitEnvVarName);
}

794
long long SystemInformation::GetHostMemoryUsed()
795
796
797
798
799
{
  return this->Implementation->GetHostMemoryUsed();
}

// process memory info in units of KiB.
800
long long SystemInformation::GetProcMemoryAvailable(
801
  const char* hostLimitEnvVarName, const char* procLimitEnvVarName)
802
{
803
804
  return this->Implementation->GetProcMemoryAvailable(hostLimitEnvVarName,
                                                      procLimitEnvVarName);
805
806
}

807
long long SystemInformation::GetProcMemoryUsed()
808
809
{
  return this->Implementation->GetProcMemoryUsed();
810
811
}

812
813
814
815
816
double SystemInformation::GetLoadAverage()
{
  return this->Implementation->GetLoadAverage();
}

817
long long SystemInformation::GetProcessId()
818
819
820
821
822
823
824
825
826
{
  return this->Implementation->GetProcessId();
}

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

Brad King's avatar
Brad King committed
827
std::string SystemInformation::GetProgramStack(int firstFrame, int wholePath)
828
{
829
830
  return SystemInformationImplementation::GetProgramStack(firstFrame,
                                                          wholePath);
831
832
}

833
834
835
/** Run the different checks */
void SystemInformation::RunCPUCheck()
{
836
  this->Implementation->RunCPUCheck();
837
}
838

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

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

// SystemInformationImplementation starts here

Sean McBride's avatar
Sean McBride committed
851
852
853
854
855
856
857
858
859
860
#if USE_CPUID
#  define STORE_TLBCACHE_INFO(x, y) x = (x < (y)) ? (y) : x
#  define TLBCACHE_INFO_UNITS (15)
#endif

#if USE_ASM_INSTRUCTIONS
#  define CLASSICAL_CPU_FREQ_LOOP 10000000
#  define RDTSC_INSTRUCTION _asm _emit 0x0f _asm _emit 0x31
#endif

861
#define INITIAL_APIC_ID_BITS 0xFF000000
862
863
864
// initial APIC ID for the processor this code is running on.
// Default value = 0xff if HT is not supported

865
866
// Hide implementation details in an anonymous namespace.
namespace {
867
// *****************************************************************************
868
#if defined(__linux) || defined(__APPLE__) || defined(__CYGWIN__)
869
int LoadLines(FILE* file, std::vector<std::string>& lines)
870
871
{
  // Load each line in the given file into a the vector.
872
873
874
875
876
  int nRead = 0;
  const int bufSize = 1024;
  char buf[bufSize] = { '\0' };
  while (!feof(file) && !ferror(file)) {
    errno = 0;
877
    if (fgets(buf, bufSize, file) == nullptr) {
878
      if (ferror(file) && (errno == EINTR)) {
879
        clearerr(file);
880
      }
881
882
883
884
885
886
887
888
      continue;
    }
    char* pBuf = buf;
    while (*pBuf) {
      if (*pBuf == '\n')
        *pBuf = '\0';
      pBuf += 1;
    }
889
    lines.emplace_back(buf);
890
    ++nRead;
891
892
  }
  if (ferror(file)) {
893
    return 0;
894
  }
895
896
897
  return nRead;
}

898
#  if defined(__linux) || defined(__CYGWIN__)
899
// *****************************************************************************
900
int LoadLines(const char* fileName, std::vector<std::string>& lines)
901
{
902
  FILE* file = fopen(fileName, "r");
Hans Johnson's avatar