Coverage Report

Created: 2026-09-14 06:43

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/CMake/Source/kwsys/SystemInformation.cxx
Line
Count
Source
1
/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
2
   file Copyright.txt or https://cmake.org/licensing#kwsys for details.  */
3
#if defined(_WIN32)
4
#  define NOMINMAX // use our min,max
5
#  if !defined(_WIN32_WINNT) && defined(_MSC_VER) && _MSC_VER >= 1800
6
#    define _WIN32_WINNT 0x0600 // vista
7
#  endif
8
#  if !defined(_WIN32_WINNT) && !(defined(_MSC_VER) && _MSC_VER < 1300)
9
#    define _WIN32_WINNT 0x0501
10
#  endif
11
#  include <winsock.h> // WSADATA, include before sys/types.h
12
#endif
13
14
#if (defined(__GNUC__) || defined(__PGI)) && !defined(_GNU_SOURCE)
15
#  define _GNU_SOURCE
16
#endif
17
18
// TODO:
19
// We need an alternative implementation for many functions in this file
20
// when USE_ASM_INSTRUCTIONS gets defined as 0.
21
//
22
// Consider using these on Win32/Win64 for some of them:
23
//
24
// IsProcessorFeaturePresent
25
// https://msdn.microsoft.com/en-us/library/ms724482(VS.85).aspx
26
//
27
// GetProcessMemoryInfo
28
// https://msdn.microsoft.com/en-us/library/ms683219(VS.85).aspx
29
30
#include "kwsysPrivate.h"
31
32
#include KWSYS_HEADER(String.h)
33
#include KWSYS_HEADER(SystemInformation.hxx)
34
#include KWSYS_HEADER(Process.h)
35
36
// Work-around CMake dependency scanning limitation.  This must
37
// duplicate the above list of headers.
38
#if 0
39
#  include "Process.h.in"
40
#  include "String.h.in"
41
#  include "SystemInformation.hxx.in"
42
#endif
43
44
#include <algorithm>
45
#include <bitset>
46
#include <cassert>
47
#include <fstream>
48
#include <iostream>
49
#include <limits>
50
#include <map>
51
#include <set>
52
53
#if !defined(_WIN32)
54
#  include <sys/resource.h>
55
#endif
56
#include <sstream>
57
#include <string>
58
#include <vector>
59
60
#if defined(_WIN32)
61
#  include <windows.h>
62
#  if defined(_MSC_VER) && _MSC_VER >= 1800
63
#    define KWSYS_WINDOWS_DEPRECATED_GetVersionEx
64
#  endif
65
#  include <errno.h>
66
#  if defined(KWSYS_SYS_HAS_PSAPI)
67
#    include <psapi.h>
68
#  endif
69
#  if !defined(siginfo_t)
70
using siginfo_t = int;
71
#  endif
72
#  include <powerbase.h>
73
#  include <winternl.h> // NTSTATUS
74
#else
75
#  include <cerrno> // extern int errno;
76
#  include <csignal>
77
78
#  include <fcntl.h>
79
#  include <unistd.h>
80
81
#  include <sys/resource.h> // getrlimit
82
#  include <sys/time.h>
83
#  include <sys/types.h>
84
#  include <sys/utsname.h> // int uname(struct utsname *buf);
85
#endif
86
87
#if defined(__CYGWIN__) && !defined(_WIN32)
88
#  include <windows.h>
89
#  undef _WIN32
90
#endif
91
92
#if defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__NetBSD__) ||    \
93
  defined(__DragonFly__)
94
#  include <netdb.h>
95
#  include <netinet/in.h>
96
97
#  include <sys/param.h>
98
#  include <sys/socket.h>
99
#  include <sys/sysctl.h>
100
#  if defined(KWSYS_SYS_HAS_IFADDRS_H)
101
#    include <ifaddrs.h>
102
#    include <net/if.h>
103
#    define KWSYS_SYSTEMINFORMATION_IMPLEMENT_FQDN
104
#  endif
105
#endif
106
107
#if defined(KWSYS_SYS_HAS_MACHINE_CPU_H)
108
#  include <machine/cpu.h>
109
#endif
110
111
#ifdef __APPLE__
112
#  include <mach/host_info.h>
113
#  include <mach/mach.h>
114
#  include <mach/mach_types.h>
115
#  include <mach/vm_statistics.h>
116
#  include <netdb.h>
117
#  include <netinet/in.h>
118
119
#  include <sys/socket.h>
120
#  include <sys/sysctl.h>
121
#  if defined(KWSYS_SYS_HAS_IFADDRS_H)
122
#    include <ifaddrs.h>
123
#    include <net/if.h>
124
#    define KWSYS_SYSTEMINFORMATION_IMPLEMENT_FQDN
125
#  endif
126
#  if !(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ - 0 >= 1050)
127
#    undef KWSYS_SYSTEMINFORMATION_HAS_BACKTRACE
128
#  endif
129
#endif
130
131
#if defined(__linux) || defined(__sun) || defined(_SCO_DS) ||                 \
132
  defined(__GLIBC__) || defined(__GNU__)
133
#  include <netdb.h>
134
#  include <netinet/in.h>
135
136
#  include <sys/socket.h>
137
#  if defined(KWSYS_SYS_HAS_IFADDRS_H)
138
#    include <ifaddrs.h>
139
#    include <net/if.h>
140
#    if defined(__LSB_VERSION__)
141
/* LSB has no getifaddrs */
142
#    elif defined(__ANDROID_API__) && __ANDROID_API__ < 24
143
/* Android has no getifaddrs prior to API 24.  */
144
#    else
145
#      define KWSYS_SYSTEMINFORMATION_IMPLEMENT_FQDN
146
#    endif
147
#  endif
148
#  if defined(KWSYS_CXX_HAS_RLIMIT64)
149
using ResourceLimitType = struct rlimit64;
150
0
#    define GetResourceLimit getrlimit64
151
#  else
152
using ResourceLimitType = struct rlimit;
153
#    define GetResourceLimit getrlimit
154
#  endif
155
#elif defined(__hpux)
156
#  include <sys/param.h>
157
#  include <sys/pstat.h>
158
#  if defined(KWSYS_SYS_HAS_MPCTL_H)
159
#    include <sys/mpctl.h>
160
#  endif
161
#endif
162
163
#ifdef __HAIKU__
164
#  include <OS.h>
165
#endif
166
167
#if defined(_WIN32) || defined(__CYGWIN__)
168
namespace {
169
unsigned __int64 fileTimeToUInt64(FILETIME const& ft)
170
{
171
  LARGE_INTEGER out;
172
  out.HighPart = ft.dwHighDateTime;
173
  out.LowPart = ft.dwLowDateTime;
174
  return out.QuadPart;
175
}
176
}
177
#endif
178
179
#if defined(KWSYS_SYSTEMINFORMATION_HAS_BACKTRACE)
180
#  include <execinfo.h>
181
#  if defined(KWSYS_SYSTEMINFORMATION_HAS_CPP_DEMANGLE)
182
#    include <cxxabi.h>
183
#  endif
184
#  if defined(KWSYS_SYSTEMINFORMATION_HAS_SYMBOL_LOOKUP)
185
#    include <dlfcn.h>
186
#  endif
187
#else
188
#  undef KWSYS_SYSTEMINFORMATION_HAS_CPP_DEMANGLE
189
#  undef KWSYS_SYSTEMINFORMATION_HAS_SYMBOL_LOOKUP
190
#endif
191
192
#include <cstdio>
193
#include <cstdlib>
194
#include <cstring>
195
196
#include <memory.h>
197
198
#if defined(_MSC_VER) && (_MSC_VER >= 1300) && !defined(_WIN64) &&            \
199
  !defined(__clang__)
200
#  define USE_ASM_INSTRUCTIONS 1
201
#else
202
#  define USE_ASM_INSTRUCTIONS 0
203
#endif
204
205
#if defined(_MSC_VER) && (_MSC_VER >= 1400) && !defined(__clang__) &&         \
206
  !defined(_M_ARM64)
207
#  include <intrin.h>
208
#  define USE_CPUID_INTRINSICS 1
209
#else
210
#  define USE_CPUID_INTRINSICS 0
211
#endif
212
213
#if USE_ASM_INSTRUCTIONS || USE_CPUID_INTRINSICS
214
#  define USE_CPUID 1
215
#else
216
#  define USE_CPUID 0
217
#endif
218
219
#if USE_CPUID
220
221
#  define CPUID_AWARE_COMPILER
222
223
/**
224
 * call CPUID instruction
225
 *
226
 * Will return false if the instruction failed.
227
 */
228
static bool call_cpuid(int select, int result[4])
229
{
230
#  if USE_CPUID_INTRINSICS
231
  __cpuid(result, select);
232
  return true;
233
#  else
234
  int tmp[4];
235
#    if defined(_MSC_VER)
236
  // Use SEH to determine CPUID presence
237
  __try {
238
    _asm {
239
#      ifdef CPUID_AWARE_COMPILER
240
      ; we must push/pop the registers <<CPUID>> writes to, as the
241
      ; optimiser does not know about <<CPUID>>, and so does not expect
242
      ; these registers to change.
243
      push eax
244
      push ebx
245
      push ecx
246
      push edx
247
#      endif
248
      ; <<CPUID>>
249
      mov eax, select
250
#      ifdef CPUID_AWARE_COMPILER
251
      cpuid
252
#      else
253
      _asm _emit 0x0f
254
      _asm _emit 0xa2
255
#      endif
256
      mov tmp[0 * TYPE int], eax
257
      mov tmp[1 * TYPE int], ebx
258
      mov tmp[2 * TYPE int], ecx
259
      mov tmp[3 * TYPE int], edx
260
261
#      ifdef CPUID_AWARE_COMPILER
262
      pop edx
263
      pop ecx
264
      pop ebx
265
      pop eax
266
#      endif
267
    }
268
  } __except (1) {
269
    return false;
270
  }
271
272
  memcpy(result, tmp, sizeof(tmp));
273
#    endif
274
275
  // The cpuid instruction succeeded.
276
  return true;
277
#  endif
278
}
279
#endif
280
281
// CPUID leaf 0x16 (processor frequency) reader, kept separate from USE_CPUID
282
// so GCC/Clang gain this query without the other MSVC-only CPUID routines.
283
#if defined(__x86_64__) || defined(__i386__) || defined(_M_X64) ||            \
284
  defined(_M_IX86)
285
#  define KWSYS_CPUID_FREQ 1
286
#else
287
#  define KWSYS_CPUID_FREQ 0
288
#endif
289
290
#if KWSYS_CPUID_FREQ
291
#  if defined(_MSC_VER)
292
#    include <intrin.h>
293
#  else
294
#    include <cpuid.h>
295
#  endif
296
namespace {
297
// Base clock in MHz from CPUID leaf 0x16; 0 if the leaf is unsupported.
298
float kwsysCpuidBaseFrequencyMHz()
299
0
{
300
0
  unsigned int eax = 0;
301
#  if defined(_MSC_VER)
302
  int regs[4] = { 0, 0, 0, 0 };
303
  __cpuid(regs, 0);
304
  if (static_cast<unsigned int>(regs[0]) < 0x16u) {
305
    return 0.0f;
306
  }
307
  __cpuidex(regs, 0x16, 0);
308
  eax = static_cast<unsigned int>(regs[0]);
309
#  else
310
  // __get_cpuid_count() is missing from older <cpuid.h> (GCC < 7, the Apple
311
  // Clang in the macOS 10.10/10.11 SDK), so gate on the max leaf ourselves and
312
  // read via the long-standing __cpuid_count() macro.
313
0
  if (static_cast<unsigned int>(__get_cpuid_max(0, nullptr)) < 0x16u) {
314
0
    return 0.0f;
315
0
  }
316
0
  unsigned int ebx = 0;
317
0
  unsigned int ecx = 0;
318
0
  unsigned int edx = 0;
319
0
  __cpuid_count(0x16u, 0u, eax, ebx, ecx, edx);
320
0
#  endif
321
0
  return static_cast<float>(eax & 0xffffu); // EAX[15:0] = base MHz
322
0
}
323
}
324
#endif
325
326
namespace KWSYS_NAMESPACE {
327
// Linux cpufreq sysfs resolution, at namespace scope so the test suite can
328
// drive it with an injected sysfs tree.
329
namespace SystemInformationDetail {
330
// First base-10 unsigned integer in a file; false if missing or non-numeric.
331
static bool ReadFileUInt(std::string const& path, unsigned long long& value)
332
0
{
333
0
  FILE* f = fopen(path.c_str(), "r");
334
0
  if (!f) {
335
0
    return false;
336
0
  }
337
0
  char buf[64];
338
0
  size_t n = fread(buf, 1, sizeof(buf) - 1, f);
339
0
  fclose(f);
340
0
  buf[n] = '\0';
341
0
  char* end = nullptr;
342
0
  unsigned long long const v = strtoull(buf, &end, 10);
343
0
  if (end == buf) {
344
0
    return false;
345
0
  }
346
0
  value = v;
347
0
  return true;
348
0
}
349
350
// Lowest online CPU; 0 (cpu0) when the online file is absent.
351
static int RepresentativeCpu(std::string const& cpuRoot)
352
0
{
353
0
  unsigned long long v = 0;
354
0
  if (ReadFileUInt(cpuRoot + "/online", v)) {
355
0
    return static_cast<int>(v);
356
0
  }
357
0
  return 0;
358
0
}
359
360
// Base/nominal frequency in MHz from cpufreq, or 0 if unavailable.
361
float LinuxBaseFrequencyMHz(std::string const& cpuRoot)
362
0
{
363
0
  std::string const cpu =
364
0
    cpuRoot + "/cpu" + std::to_string(RepresentativeCpu(cpuRoot));
365
0
  unsigned long long value = 0;
366
  // Intel P-state base frequency (kHz).
367
0
  if (ReadFileUInt(cpu + "/cpufreq/base_frequency", value) && value > 0) {
368
0
    return static_cast<float>(value) / 1000.0f;
369
0
  }
370
  // AMD CPPC nominal frequency (MHz).
371
0
  if (ReadFileUInt(cpu + "/acpi_cppc/nominal_freq", value) && value > 0) {
372
0
    return static_cast<float>(value);
373
0
  }
374
0
  return 0.0f;
375
0
}
376
377
// Maximum frequency in MHz from cpufreq, or 0 if unavailable.  Used as a
378
// fallback where no base frequency exists.
379
float LinuxMaxFrequencyMHz(std::string const& cpuRoot)
380
0
{
381
0
  std::string const cpu =
382
0
    cpuRoot + "/cpu" + std::to_string(RepresentativeCpu(cpuRoot));
383
0
  unsigned long long value = 0;
384
0
  if (ReadFileUInt(cpu + "/cpufreq/cpuinfo_max_freq", value) && value > 0) {
385
0
    return static_cast<float>(value) / 1000.0f;
386
0
  }
387
0
  return 0.0f;
388
0
}
389
}
390
391
template <typename T>
392
T min(T a, T b)
393
0
{
394
0
  return a < b ? a : b;
395
0
}
396
397
extern "C" {
398
using SigAction = void (*)(int, siginfo_t*, void*);
399
}
400
401
//  Define SystemInformationImplementation class
402
using DELAY_FUNC = void (*)(unsigned int);
403
404
class SystemInformationImplementation
405
{
406
public:
407
  SystemInformationImplementation();
408
0
  ~SystemInformationImplementation() = default;
409
410
  char const* GetVendorString() const;
411
  char const* GetVendorID();
412
  std::string GetTypeID() const;
413
  std::string GetFamilyID() const;
414
  std::string GetModelID() const;
415
  std::string GetModelName() const;
416
  std::string GetSteppingCode() const;
417
  char const* GetExtendedProcessorName() const;
418
  char const* GetProcessorSerialNumber() const;
419
  int GetProcessorCacheSize() const;
420
  unsigned int GetLogicalProcessorsPerPhysical() const;
421
  float GetProcessorClockFrequency() const;
422
  int GetProcessorAPICID() const;
423
  int GetProcessorCacheXSize(long int) const;
424
  bool DoesCPUSupportFeature(long int) const;
425
426
  char const* GetOSName();
427
  char const* GetHostname();
428
  int GetFullyQualifiedDomainName(std::string& fqdn);
429
  char const* GetOSRelease();
430
  char const* GetOSVersion();
431
  char const* GetOSPlatform();
432
433
  bool Is64Bits() const;
434
435
  unsigned int GetNumberOfLogicalCPU() const; // per physical cpu
436
  unsigned int GetNumberOfPhysicalCPU() const;
437
438
  bool DoesCPUSupportCPUID();
439
440
  // Retrieve memory information in MiB.
441
  size_t GetTotalVirtualMemory() const;
442
  size_t GetAvailableVirtualMemory() const;
443
  size_t GetTotalPhysicalMemory() const;
444
  size_t GetAvailablePhysicalMemory() const;
445
446
  long long GetProcessId();
447
448
  // Retrieve memory information in KiB.
449
  long long GetHostMemoryTotal();
450
  long long GetHostMemoryAvailable(char const* hostLimitEnvVarName);
451
  long long GetHostMemoryUsed();
452
453
  long long GetProcMemoryAvailable(char const* hostLimitEnvVarName,
454
                                   char const* procLimitEnvVarName);
455
  long long GetProcMemoryUsed();
456
457
  double GetLoadAverage();
458
459
  // enable/disable stack trace signal handler.
460
  static void SetStackTraceOnError(int enable);
461
462
  // get current stack
463
  static std::string GetProgramStack(int firstFrame, int wholePath);
464
465
  /** Run the different checks */
466
  void RunCPUCheck();
467
  void RunOSCheck();
468
  void RunMemoryCheck();
469
470
public:
471
  struct ID
472
  {
473
    int Type;
474
    int Family;
475
    int Model;
476
    int Revision;
477
    int ExtendedFamily;
478
    int ExtendedModel;
479
    std::string ProcessorName;
480
    std::string Vendor;
481
    std::string SerialNumber;
482
    std::string ModelName;
483
  };
484
485
  struct CPUPowerManagement
486
  {
487
    bool HasVoltageID;
488
    bool HasFrequencyID;
489
    bool HasTempSenseDiode;
490
  };
491
492
  struct CPUExtendedFeatures
493
  {
494
    bool Has3DNow;
495
    bool Has3DNowPlus;
496
    bool SupportsMP;
497
    bool HasMMXPlus;
498
    bool HasSSEMMX;
499
    unsigned int LogicalProcessorsPerPhysical;
500
    int APIC_ID;
501
    CPUPowerManagement PowerManagement;
502
  };
503
504
  struct CPUFeatures
505
  {
506
    bool HasFPU;
507
    bool HasTSC;
508
    bool HasMMX;
509
    bool HasSSE;
510
    bool HasSSEFP;
511
    bool HasSSE2;
512
    bool HasIA64;
513
    bool HasAPIC;
514
    bool HasCMOV;
515
    bool HasMTRR;
516
    bool HasACPI;
517
    bool HasSerial;
518
    bool HasThermal;
519
    int CPUSpeed;
520
    int L1CacheSize;
521
    int L2CacheSize;
522
    int L3CacheSize;
523
    CPUExtendedFeatures ExtendedFeatures;
524
  };
525
526
  enum Manufacturer
527
  {
528
    AMD,
529
    Intel,
530
    NSC,
531
    UMC,
532
    Cyrix,
533
    NexGen,
534
    IDT,
535
    Rise,
536
    Transmeta,
537
    Sun,
538
    IBM,
539
    Motorola,
540
    HP,
541
    Hygon,
542
    Zhaoxin,
543
    Apple,
544
    UnknownManufacturer
545
  };
546
547
protected:
548
  // For windows
549
  bool RetrieveCPUFeatures();
550
  bool RetrieveCPUIdentity();
551
  bool RetrieveCPUCacheDetails();
552
  bool RetrieveClassicalCPUCacheDetails();
553
  bool RetrieveCPUClockSpeed();
554
  bool RetrieveClassicalCPUClockSpeed();
555
  bool RetrieveCPUExtendedLevelSupport(int);
556
  bool RetrieveExtendedCPUFeatures();
557
  bool RetrieveProcessorSerialNumber();
558
  bool RetrieveCPUPowerManagement();
559
  bool RetrieveClassicalCPUIdentity();
560
  bool RetrieveExtendedCPUIdentity();
561
562
  // Processor information
563
  Manufacturer ChipManufacturer;
564
  CPUFeatures Features;
565
  ID ChipID;
566
  float CPUSpeedInMHz;
567
  unsigned int NumberOfLogicalCPU;
568
  unsigned int NumberOfPhysicalCPU;
569
570
  void CPUCountWindows();    // For windows
571
  unsigned char GetAPICId(); // For windows
572
  bool IsSMTSupported() const;
573
  static long long GetCyclesDifference(DELAY_FUNC,
574
                                       unsigned int); // For windows
575
576
  // For Linux and Cygwin, /proc/cpuinfo formats are slightly different
577
  bool RetrieveInformationFromCpuInfoFile();
578
  std::string ExtractValueFromCpuInfoFile(std::string buffer, char const* word,
579
                                          size_t init = 0);
580
581
  bool QueryLinuxMemory();
582
  bool QueryCygwinMemory();
583
584
  static void Delay(unsigned int);
585
  static void DelayOverhead(unsigned int);
586
587
  void FindManufacturer(std::string const& family = "");
588
589
  // For Mac
590
  bool ParseSysCtl();
591
  int CallSwVers(char const* arg, std::string& ver);
592
  void TrimNewline(std::string&);
593
  std::string ExtractValueFromSysCtl(char const* word);
594
  std::string SysCtlBuffer;
595
596
  // For Solaris
597
  bool QuerySolarisMemory();
598
  bool QuerySolarisProcessor();
599
  std::string ParseValueFromKStat(char const* arguments);
600
  std::string RunProcess(std::vector<char const*> args);
601
602
  // For Haiku OS
603
  bool QueryHaikuInfo();
604
605
  // For QNX
606
  bool QueryQNXMemory();
607
  bool QueryQNXProcessor();
608
609
  // For OpenBSD, FreeBSD, NetBSD, DragonFly
610
  bool QueryBSDMemory();
611
  bool QueryBSDProcessor();
612
613
  // For HP-UX
614
  bool QueryHPUXMemory();
615
  bool QueryHPUXProcessor();
616
617
  // For Microsoft Windows
618
  bool QueryWindowsMemory();
619
620
  // For AIX
621
  bool QueryAIXMemory();
622
623
  bool QueryProcessorBySysconf();
624
  bool QueryProcessor();
625
626
  // Evaluate the memory information.
627
  bool QueryMemoryBySysconf();
628
  bool QueryMemory();
629
  size_t TotalVirtualMemory;
630
  size_t AvailableVirtualMemory;
631
  size_t TotalPhysicalMemory;
632
  size_t AvailablePhysicalMemory;
633
634
  size_t CurrentPositionInFile;
635
636
  // Operating System information
637
  bool QueryOSInformation();
638
  std::string OSName;
639
  std::string Hostname;
640
  std::string OSRelease;
641
  std::string OSVersion;
642
  std::string OSPlatform;
643
  bool OSIs64Bit;
644
};
645
646
SystemInformation::SystemInformation()
647
0
{
648
0
  this->Implementation = new SystemInformationImplementation;
649
0
}
650
651
SystemInformation::~SystemInformation()
652
0
{
653
0
  delete this->Implementation;
654
0
}
655
656
char const* SystemInformation::GetVendorString()
657
0
{
658
0
  return this->Implementation->GetVendorString();
659
0
}
660
661
char const* SystemInformation::GetVendorID()
662
0
{
663
0
  return this->Implementation->GetVendorID();
664
0
}
665
666
std::string SystemInformation::GetTypeID()
667
0
{
668
0
  return this->Implementation->GetTypeID();
669
0
}
670
671
std::string SystemInformation::GetFamilyID()
672
0
{
673
0
  return this->Implementation->GetFamilyID();
674
0
}
675
676
std::string SystemInformation::GetModelID()
677
0
{
678
0
  return this->Implementation->GetModelID();
679
0
}
680
681
std::string SystemInformation::GetModelName()
682
0
{
683
0
  return this->Implementation->GetModelName();
684
0
}
685
686
std::string SystemInformation::GetSteppingCode()
687
0
{
688
0
  return this->Implementation->GetSteppingCode();
689
0
}
690
691
char const* SystemInformation::GetExtendedProcessorName()
692
0
{
693
0
  return this->Implementation->GetExtendedProcessorName();
694
0
}
695
696
char const* SystemInformation::GetProcessorSerialNumber()
697
0
{
698
0
  return this->Implementation->GetProcessorSerialNumber();
699
0
}
700
701
int SystemInformation::GetProcessorCacheSize()
702
0
{
703
0
  return this->Implementation->GetProcessorCacheSize();
704
0
}
705
706
unsigned int SystemInformation::GetLogicalProcessorsPerPhysical()
707
0
{
708
0
  return this->Implementation->GetLogicalProcessorsPerPhysical();
709
0
}
710
711
float SystemInformation::GetProcessorClockFrequency()
712
0
{
713
0
  return this->Implementation->GetProcessorClockFrequency();
714
0
}
715
716
int SystemInformation::GetProcessorAPICID()
717
0
{
718
0
  return this->Implementation->GetProcessorAPICID();
719
0
}
720
721
int SystemInformation::GetProcessorCacheXSize(long int l)
722
0
{
723
0
  return this->Implementation->GetProcessorCacheXSize(l);
724
0
}
725
726
bool SystemInformation::DoesCPUSupportFeature(long int i)
727
0
{
728
0
  return this->Implementation->DoesCPUSupportFeature(i);
729
0
}
730
731
std::string SystemInformation::GetCPUDescription()
732
0
{
733
0
  std::ostringstream oss;
734
0
  oss << this->GetNumberOfPhysicalCPU() << " core ";
735
0
  if (this->GetModelName().empty()) {
736
0
    oss << this->GetProcessorClockFrequency() << " MHz "
737
0
        << this->GetVendorString() << ' ' << this->GetExtendedProcessorName();
738
0
  } else {
739
0
    oss << this->GetModelName();
740
0
  }
741
742
  // remove extra spaces
743
0
  std::string tmp = oss.str();
744
0
  size_t pos;
745
0
  while ((pos = tmp.find("  ")) != std::string::npos) {
746
0
    tmp.replace(pos, 2, " ");
747
0
  }
748
749
0
  return tmp;
750
0
}
751
752
char const* SystemInformation::GetOSName()
753
0
{
754
0
  return this->Implementation->GetOSName();
755
0
}
756
757
char const* SystemInformation::GetHostname()
758
0
{
759
0
  return this->Implementation->GetHostname();
760
0
}
761
762
std::string SystemInformation::GetFullyQualifiedDomainName()
763
0
{
764
0
  std::string fqdn;
765
0
  this->Implementation->GetFullyQualifiedDomainName(fqdn);
766
0
  return fqdn;
767
0
}
768
769
char const* SystemInformation::GetOSRelease()
770
0
{
771
0
  return this->Implementation->GetOSRelease();
772
0
}
773
774
char const* SystemInformation::GetOSVersion()
775
0
{
776
0
  return this->Implementation->GetOSVersion();
777
0
}
778
779
char const* SystemInformation::GetOSPlatform()
780
0
{
781
0
  return this->Implementation->GetOSPlatform();
782
0
}
783
784
int SystemInformation::GetOSIsWindows()
785
0
{
786
#if defined(_WIN32)
787
  return 1;
788
#else
789
0
  return 0;
790
0
#endif
791
0
}
792
793
int SystemInformation::GetOSIsLinux()
794
0
{
795
0
#if defined(__linux)
796
0
  return 1;
797
#else
798
  return 0;
799
#endif
800
0
}
801
802
int SystemInformation::GetOSIsApple()
803
0
{
804
#if defined(__APPLE__)
805
  return 1;
806
#else
807
0
  return 0;
808
0
#endif
809
0
}
810
811
std::string SystemInformation::GetOSDescription()
812
0
{
813
0
  std::ostringstream oss;
814
0
  oss << this->GetOSName() << ' ' << this->GetOSRelease() << ' '
815
0
      << this->GetOSVersion();
816
817
0
  return oss.str();
818
0
}
819
820
bool SystemInformation::Is64Bits()
821
0
{
822
0
  return this->Implementation->Is64Bits();
823
0
}
824
825
unsigned int SystemInformation::GetNumberOfLogicalCPU() // per physical cpu
826
0
{
827
0
  return this->Implementation->GetNumberOfLogicalCPU();
828
0
}
829
830
unsigned int SystemInformation::GetNumberOfPhysicalCPU()
831
0
{
832
0
  return this->Implementation->GetNumberOfPhysicalCPU();
833
0
}
834
835
bool SystemInformation::DoesCPUSupportCPUID()
836
0
{
837
0
  return this->Implementation->DoesCPUSupportCPUID();
838
0
}
839
840
// Retrieve memory information in MiB.
841
size_t SystemInformation::GetTotalVirtualMemory()
842
0
{
843
0
  return this->Implementation->GetTotalVirtualMemory();
844
0
}
845
846
size_t SystemInformation::GetAvailableVirtualMemory()
847
0
{
848
0
  return this->Implementation->GetAvailableVirtualMemory();
849
0
}
850
851
size_t SystemInformation::GetTotalPhysicalMemory()
852
0
{
853
0
  return this->Implementation->GetTotalPhysicalMemory();
854
0
}
855
856
size_t SystemInformation::GetAvailablePhysicalMemory()
857
0
{
858
0
  return this->Implementation->GetAvailablePhysicalMemory();
859
0
}
860
861
std::string SystemInformation::GetMemoryDescription(
862
  char const* hostLimitEnvVarName, char const* procLimitEnvVarName)
863
0
{
864
0
  std::ostringstream oss;
865
0
  oss << "Host Total: " << this->GetHostMemoryTotal()
866
0
      << " KiB, Host Available: "
867
0
      << this->GetHostMemoryAvailable(hostLimitEnvVarName)
868
0
      << " KiB, Process Available: "
869
0
      << this->GetProcMemoryAvailable(hostLimitEnvVarName, procLimitEnvVarName)
870
0
      << " KiB";
871
0
  return oss.str();
872
0
}
873
874
// host memory info in units of KiB.
875
long long SystemInformation::GetHostMemoryTotal()
876
0
{
877
0
  return this->Implementation->GetHostMemoryTotal();
878
0
}
879
880
long long SystemInformation::GetHostMemoryAvailable(
881
  char const* hostLimitEnvVarName)
882
0
{
883
0
  return this->Implementation->GetHostMemoryAvailable(hostLimitEnvVarName);
884
0
}
885
886
long long SystemInformation::GetHostMemoryUsed()
887
0
{
888
0
  return this->Implementation->GetHostMemoryUsed();
889
0
}
890
891
// process memory info in units of KiB.
892
long long SystemInformation::GetProcMemoryAvailable(
893
  char const* hostLimitEnvVarName, char const* procLimitEnvVarName)
894
0
{
895
0
  return this->Implementation->GetProcMemoryAvailable(hostLimitEnvVarName,
896
0
                                                      procLimitEnvVarName);
897
0
}
898
899
long long SystemInformation::GetProcMemoryUsed()
900
0
{
901
0
  return this->Implementation->GetProcMemoryUsed();
902
0
}
903
904
double SystemInformation::GetLoadAverage()
905
0
{
906
0
  return this->Implementation->GetLoadAverage();
907
0
}
908
909
long long SystemInformation::GetProcessId()
910
0
{
911
0
  return this->Implementation->GetProcessId();
912
0
}
913
914
bool SystemInformation::GetProcessResourceUsage(
915
  SystemInformation::ProcessResourceUsage& usage, void* processHandle)
916
0
{
917
#if defined(_WIN32)
918
#  if defined(KWSYS_SYS_HAS_PSAPI)
919
  HANDLE hProc = static_cast<HANDLE>(processHandle);
920
  if (!hProc) {
921
    return false;
922
  }
923
924
  FILETIME creationTime;
925
  FILETIME exitTime;
926
  FILETIME kernelTime;
927
  FILETIME userTime;
928
  if (!GetProcessTimes(hProc, &creationTime, &exitTime, &kernelTime,
929
                       &userTime)) {
930
    return false;
931
  }
932
933
  PROCESS_MEMORY_COUNTERS pmc;
934
  if (!GetProcessMemoryInfo(hProc, &pmc, sizeof(pmc))) {
935
    return false;
936
  }
937
938
  usage = SystemInformation::ProcessResourceUsage{};
939
  usage.ru_maxrss =
940
    static_cast<decltype(usage.ru_maxrss)>(pmc.PeakWorkingSetSize / 1024);
941
942
  unsigned __int64 const user100ns = fileTimeToUInt64(userTime);
943
  unsigned __int64 const kernel100ns = fileTimeToUInt64(kernelTime);
944
  unsigned __int64 const userUSec = user100ns / 10ULL;
945
  unsigned __int64 const kernelUSec = kernel100ns / 10ULL;
946
947
  usage.ru_utime.tv_sec = static_cast<long>(userUSec / 1000000ULL);
948
  usage.ru_utime.tv_usec = static_cast<long>(userUSec % 1000000ULL);
949
  usage.ru_stime.tv_sec = static_cast<long>(kernelUSec / 1000000ULL);
950
  usage.ru_stime.tv_usec = static_cast<long>(kernelUSec % 1000000ULL);
951
  return true;
952
#  else // !defined(KWSYS_SYS_HAS_PSAPI)
953
  static_cast<void>(usage);
954
  static_cast<void>(processHandle);
955
  return false;
956
#  endif
957
#else // !defined(_WIN32)
958
0
  static_cast<void>(processHandle);
959
0
  struct rusage rusage;
960
0
  if (getrusage(RUSAGE_CHILDREN, &rusage) != 0) {
961
0
    return false;
962
0
  }
963
0
  usage = SystemInformation::ProcessResourceUsage{};
964
0
  usage.ru_maxrss = rusage.ru_maxrss;
965
#  if defined(__APPLE__)
966
  // Apple platforms report bytes.  Convert to KiB.
967
  usage.ru_maxrss /= 1024;
968
#  elif defined(__sun)
969
  // Solaris platforms report pages.  Convert to KiB.
970
  usage.ru_maxrss *= getpagesize() / 1024;
971
#  endif
972
0
  usage.ru_utime.tv_sec = rusage.ru_utime.tv_sec;
973
0
  usage.ru_utime.tv_usec = rusage.ru_utime.tv_usec;
974
0
  usage.ru_stime.tv_sec = rusage.ru_stime.tv_sec;
975
0
  usage.ru_stime.tv_usec = rusage.ru_stime.tv_usec;
976
0
  return true;
977
0
#endif
978
0
}
979
980
void SystemInformation::SetStackTraceOnError(int enable)
981
0
{
982
0
  SystemInformationImplementation::SetStackTraceOnError(enable);
983
0
}
984
985
std::string SystemInformation::GetProgramStack(int firstFrame, int wholePath)
986
0
{
987
0
  return SystemInformationImplementation::GetProgramStack(firstFrame,
988
0
                                                          wholePath);
989
0
}
990
991
/** Run the different checks */
992
void SystemInformation::RunCPUCheck()
993
0
{
994
0
  this->Implementation->RunCPUCheck();
995
0
}
996
997
void SystemInformation::RunOSCheck()
998
0
{
999
0
  this->Implementation->RunOSCheck();
1000
0
}
1001
1002
void SystemInformation::RunMemoryCheck()
1003
0
{
1004
0
  this->Implementation->RunMemoryCheck();
1005
0
}
1006
1007
// SystemInformationImplementation starts here
1008
1009
#if USE_CPUID
1010
#  define STORE_TLBCACHE_INFO(x, y) x = (x < (y)) ? (y) : x
1011
#  define TLBCACHE_INFO_UNITS (15)
1012
#endif
1013
1014
#if USE_ASM_INSTRUCTIONS
1015
#  define CLASSICAL_CPU_FREQ_LOOP 10000000
1016
#  define RDTSC_INSTRUCTION _asm _emit 0x0f _asm _emit 0x31
1017
#endif
1018
1019
0
#define INITIAL_APIC_ID_BITS 0xFF000000
1020
// initial APIC ID for the processor this code is running on.
1021
// Default value = 0xff if HT is not supported
1022
1023
// Hide implementation details in an anonymous namespace.
1024
namespace {
1025
// *****************************************************************************
1026
#if defined(__linux) || defined(__APPLE__) || defined(__CYGWIN__)
1027
int LoadLines(FILE* file, std::vector<std::string>& lines)
1028
0
{
1029
  // Load each line in the given file into a the vector.
1030
0
  int nRead = 0;
1031
0
  int const bufSize = 1024;
1032
0
  char buf[bufSize] = { '\0' };
1033
0
  while (!feof(file) && !ferror(file)) {
1034
0
    errno = 0;
1035
0
    if (!fgets(buf, bufSize, file)) {
1036
0
      if (ferror(file) && (errno == EINTR)) {
1037
0
        clearerr(file);
1038
0
      }
1039
0
      continue;
1040
0
    }
1041
0
    char* pBuf = buf;
1042
0
    while (*pBuf) {
1043
0
      if (*pBuf == '\n')
1044
0
        *pBuf = '\0';
1045
0
      pBuf += 1;
1046
0
    }
1047
0
    lines.emplace_back(buf);
1048
0
    ++nRead;
1049
0
  }
1050
0
  if (ferror(file)) {
1051
0
    return 0;
1052
0
  }
1053
0
  return nRead;
1054
0
}
1055
1056
#  if defined(__linux) || defined(__CYGWIN__)
1057
// *****************************************************************************
1058
int LoadLines(char const* fileName, std::vector<std::string>& lines)
1059
0
{
1060
0
  FILE* file = fopen(fileName, "r");
1061
0
  if (!file) {
1062
0
    return 0;
1063
0
  }
1064
0
  int nRead = LoadLines(file, lines);
1065
0
  fclose(file);
1066
0
  return nRead;
1067
0
}
1068
#  endif
1069
1070
// ****************************************************************************
1071
template <typename T>
1072
int NameValue(std::vector<std::string> const& lines, std::string const& name,
1073
              T& value)
1074
0
{
1075
0
  size_t nLines = lines.size();
1076
0
  for (size_t i = 0; i < nLines; ++i) {
1077
0
    size_t at = lines[i].find(name);
1078
0
    if (at == std::string::npos) {
1079
0
      continue;
1080
0
    }
1081
0
    std::istringstream is(lines[i].substr(at + name.size()));
1082
0
    is >> value;
1083
0
    return 0;
1084
0
  }
1085
0
  return -1;
1086
0
}
1087
#endif
1088
1089
#if defined(__linux) || defined(__CYGWIN__)
1090
// ****************************************************************************
1091
template <typename T>
1092
int GetFieldsFromFile(char const* fileName, char const** fieldNames, T* values)
1093
0
{
1094
0
  std::vector<std::string> fields;
1095
0
  if (!LoadLines(fileName, fields)) {
1096
0
    return -1;
1097
0
  }
1098
0
  int i = 0;
1099
0
  while (fieldNames[i]) {
1100
0
    int ierr = NameValue(fields, fieldNames[i], values[i]);
1101
0
    if (ierr) {
1102
0
      return -(i + 2);
1103
0
    }
1104
0
    i += 1;
1105
0
  }
1106
0
  return 0;
1107
0
}
1108
1109
// ****************************************************************************
1110
template <typename T>
1111
int GetFieldFromFile(char const* fileName, char const* fieldName, T& value)
1112
0
{
1113
0
  char const* fieldNames[2] = { fieldName, nullptr };
1114
0
  T values[1] = { T(0) };
1115
0
  int ierr = GetFieldsFromFile(fileName, fieldNames, values);
1116
0
  if (ierr) {
1117
0
    return ierr;
1118
0
  }
1119
0
  value = values[0];
1120
0
  return 0;
1121
0
}
1122
#endif
1123
1124
// ****************************************************************************
1125
#if defined(__APPLE__)
1126
template <typename T>
1127
int GetFieldsFromCommand(char const* command, char const** fieldNames,
1128
                         T* values)
1129
{
1130
  FILE* file = popen(command, "r");
1131
  if (!file) {
1132
    return -1;
1133
  }
1134
  std::vector<std::string> fields;
1135
  int nl = LoadLines(file, fields);
1136
  pclose(file);
1137
  if (nl == 0) {
1138
    return -1;
1139
  }
1140
  int i = 0;
1141
  while (fieldNames[i]) {
1142
    int ierr = NameValue(fields, fieldNames[i], values[i]);
1143
    if (ierr) {
1144
      return -(i + 2);
1145
    }
1146
    i += 1;
1147
  }
1148
  return 0;
1149
}
1150
#endif
1151
1152
// ****************************************************************************
1153
#if !defined(_WIN32) && !defined(__MINGW32__) && !defined(__CYGWIN__)
1154
void StacktraceSignalHandler(int sigNo, siginfo_t* sigInfo,
1155
                             void* /*sigContext*/)
1156
0
{
1157
0
#  if defined(__linux) || defined(__APPLE__)
1158
0
  std::ostringstream oss;
1159
0
  oss << std::endl
1160
0
      << "========================================================="
1161
0
      << std::endl
1162
0
      << "Process id " << getpid() << ' ';
1163
0
  switch (sigNo) {
1164
0
    case SIGINT:
1165
0
      oss << "Caught SIGINT";
1166
0
      break;
1167
1168
0
    case SIGTERM:
1169
0
      oss << "Caught SIGTERM";
1170
0
      break;
1171
1172
0
    case SIGABRT:
1173
0
      oss << "Caught SIGABRT";
1174
0
      break;
1175
1176
0
    case SIGFPE:
1177
0
      oss << "Caught SIGFPE at " << (sigInfo->si_addr ? "" : "0x")
1178
0
          << sigInfo->si_addr << ' ';
1179
0
      switch (sigInfo->si_code) {
1180
0
#    if defined(FPE_INTDIV)
1181
0
        case FPE_INTDIV:
1182
0
          oss << "integer division by zero";
1183
0
          break;
1184
0
#    endif
1185
1186
0
#    if defined(FPE_INTOVF)
1187
0
        case FPE_INTOVF:
1188
0
          oss << "integer overflow";
1189
0
          break;
1190
0
#    endif
1191
1192
0
        case FPE_FLTDIV:
1193
0
          oss << "floating point divide by zero";
1194
0
          break;
1195
1196
0
        case FPE_FLTOVF:
1197
0
          oss << "floating point overflow";
1198
0
          break;
1199
1200
0
        case FPE_FLTUND:
1201
0
          oss << "floating point underflow";
1202
0
          break;
1203
1204
0
        case FPE_FLTRES:
1205
0
          oss << "floating point inexact result";
1206
0
          break;
1207
1208
0
        case FPE_FLTINV:
1209
0
          oss << "floating point invalid operation";
1210
0
          break;
1211
1212
0
#    if defined(FPE_FLTSUB)
1213
0
        case FPE_FLTSUB:
1214
0
          oss << "floating point subscript out of range";
1215
0
          break;
1216
0
#    endif
1217
1218
0
        default:
1219
0
          oss << "code " << sigInfo->si_code;
1220
0
          break;
1221
0
      }
1222
0
      break;
1223
1224
0
    case SIGSEGV:
1225
0
      oss << "Caught SIGSEGV at " << (sigInfo->si_addr ? "" : "0x")
1226
0
          << sigInfo->si_addr << ' ';
1227
0
      switch (sigInfo->si_code) {
1228
0
        case SEGV_MAPERR:
1229
0
          oss << "address not mapped to object";
1230
0
          break;
1231
1232
0
        case SEGV_ACCERR:
1233
0
          oss << "invalid permission for mapped object";
1234
0
          break;
1235
1236
0
        default:
1237
0
          oss << "code " << sigInfo->si_code;
1238
0
          break;
1239
0
      }
1240
0
      break;
1241
1242
0
    case SIGBUS:
1243
0
      oss << "Caught SIGBUS at " << (sigInfo->si_addr ? "" : "0x")
1244
0
          << sigInfo->si_addr << ' ';
1245
0
      switch (sigInfo->si_code) {
1246
0
        case BUS_ADRALN:
1247
0
          oss << "invalid address alignment";
1248
0
          break;
1249
1250
0
#    if defined(BUS_ADRERR)
1251
0
        case BUS_ADRERR:
1252
0
          oss << "nonexistent physical address";
1253
0
          break;
1254
0
#    endif
1255
1256
0
#    if defined(BUS_OBJERR)
1257
0
        case BUS_OBJERR:
1258
0
          oss << "object-specific hardware error";
1259
0
          break;
1260
0
#    endif
1261
1262
0
#    if defined(BUS_MCEERR_AR)
1263
0
        case BUS_MCEERR_AR:
1264
0
          oss << "Hardware memory error consumed on a machine check; action "
1265
0
                 "required.";
1266
0
          break;
1267
0
#    endif
1268
1269
0
#    if defined(BUS_MCEERR_AO)
1270
0
        case BUS_MCEERR_AO:
1271
0
          oss << "Hardware memory error detected in process but not consumed; "
1272
0
                 "action optional.";
1273
0
          break;
1274
0
#    endif
1275
1276
0
        default:
1277
0
          oss << "code " << sigInfo->si_code;
1278
0
          break;
1279
0
      }
1280
0
      break;
1281
1282
0
    case SIGILL:
1283
0
      oss << "Caught SIGILL at " << (sigInfo->si_addr ? "" : "0x")
1284
0
          << sigInfo->si_addr << ' ';
1285
0
      switch (sigInfo->si_code) {
1286
0
        case ILL_ILLOPC:
1287
0
          oss << "illegal opcode";
1288
0
          break;
1289
1290
0
#    if defined(ILL_ILLOPN)
1291
0
        case ILL_ILLOPN:
1292
0
          oss << "illegal operand";
1293
0
          break;
1294
0
#    endif
1295
1296
0
#    if defined(ILL_ILLADR)
1297
0
        case ILL_ILLADR:
1298
0
          oss << "illegal addressing mode.";
1299
0
          break;
1300
0
#    endif
1301
1302
0
        case ILL_ILLTRP:
1303
0
          oss << "illegal trap";
1304
0
          break;
1305
1306
0
        case ILL_PRVOPC:
1307
0
          oss << "privileged opcode";
1308
0
          break;
1309
1310
0
#    if defined(ILL_PRVREG)
1311
0
        case ILL_PRVREG:
1312
0
          oss << "privileged register";
1313
0
          break;
1314
0
#    endif
1315
1316
0
#    if defined(ILL_COPROC)
1317
0
        case ILL_COPROC:
1318
0
          oss << "co-processor error";
1319
0
          break;
1320
0
#    endif
1321
1322
0
#    if defined(ILL_BADSTK)
1323
0
        case ILL_BADSTK:
1324
0
          oss << "internal stack error";
1325
0
          break;
1326
0
#    endif
1327
1328
0
        default:
1329
0
          oss << "code " << sigInfo->si_code;
1330
0
          break;
1331
0
      }
1332
0
      break;
1333
1334
0
    default:
1335
0
      oss << "Caught " << sigNo << " code " << sigInfo->si_code;
1336
0
      break;
1337
0
  }
1338
0
  oss << std::endl
1339
0
      << "Program Stack:" << std::endl
1340
0
      << SystemInformationImplementation::GetProgramStack(2, 0)
1341
0
      << "========================================================="
1342
0
      << std::endl;
1343
0
  std::cerr << oss.str() << std::endl;
1344
1345
  // restore the previously registered handlers
1346
  // and abort
1347
0
  SystemInformationImplementation::SetStackTraceOnError(0);
1348
0
  abort();
1349
#  else
1350
  // avoid warning C4100
1351
  (void)sigNo;
1352
  (void)sigInfo;
1353
#  endif
1354
0
}
1355
#endif
1356
1357
#if defined(KWSYS_SYSTEMINFORMATION_HAS_BACKTRACE)
1358
0
#  define safes(_arg) ((_arg) ? (_arg) : "???")
1359
1360
// Description:
1361
// A container for symbol properties. Each instance
1362
// must be Initialized.
1363
class SymbolProperties
1364
{
1365
public:
1366
  SymbolProperties();
1367
1368
  // Description:
1369
  // The SymbolProperties instance must be initialized by
1370
  // passing a stack address.
1371
  void Initialize(void* address);
1372
1373
  // Description:
1374
  // Get the symbol's stack address.
1375
0
  void* GetAddress() const { return this->Address; }
1376
1377
  // Description:
1378
  // If not set paths will be removed. eg, from a binary
1379
  // or source file.
1380
0
  void SetReportPath(int rp) { this->ReportPath = rp; }
1381
1382
  // Description:
1383
  // Set/Get the name of the binary file that the symbol
1384
  // is found in.
1385
0
  void SetBinary(char const* binary) { this->Binary = safes(binary); }
1386
1387
  std::string GetBinary() const;
1388
1389
  // Description:
1390
  // Set the name of the function that the symbol is found in.
1391
  // If c++ demangling is supported it will be demangled.
1392
  void SetFunction(char const* function)
1393
0
  {
1394
0
    this->Function = this->Demangle(function);
1395
0
  }
1396
1397
0
  std::string GetFunction() const { return this->Function; }
1398
1399
  // Description:
1400
  // Set/Get the name of the source file where the symbol
1401
  // is defined.
1402
  void SetSourceFile(char const* sourcefile)
1403
0
  {
1404
0
    this->SourceFile = safes(sourcefile);
1405
0
  }
1406
1407
  std::string GetSourceFile() const
1408
0
  {
1409
0
    return this->GetFileName(this->SourceFile);
1410
0
  }
1411
1412
  // Description:
1413
  // Set/Get the line number where the symbol is defined
1414
0
  void SetLineNumber(long linenumber) { this->LineNumber = linenumber; }
1415
0
  long GetLineNumber() const { return this->LineNumber; }
1416
1417
  // Description:
1418
  // Set the address where the binary image is mapped
1419
  // into memory.
1420
  void SetBinaryBaseAddress(void* address)
1421
0
  {
1422
0
    this->BinaryBaseAddress = address;
1423
0
  }
1424
1425
private:
1426
  size_t GetRealAddress() const
1427
0
  {
1428
0
    return static_cast<size_t>(static_cast<char*>(this->Address) -
1429
0
                               static_cast<char*>(this->BinaryBaseAddress));
1430
0
  }
1431
1432
  std::string GetFileName(std::string const& path) const;
1433
  std::string Demangle(char const* symbol) const;
1434
1435
private:
1436
  std::string Binary;
1437
  void* BinaryBaseAddress;
1438
  void* Address;
1439
  std::string SourceFile;
1440
  std::string Function;
1441
  long LineNumber;
1442
  int ReportPath;
1443
};
1444
1445
std::ostream& operator<<(std::ostream& os, SymbolProperties const& sp)
1446
0
{
1447
0
#  if defined(KWSYS_SYSTEMINFORMATION_HAS_SYMBOL_LOOKUP)
1448
0
  os << std::hex << sp.GetAddress() << " : " << sp.GetFunction() << " [("
1449
0
     << sp.GetBinary() << ") " << sp.GetSourceFile() << ':' << std::dec
1450
0
     << sp.GetLineNumber() << ']';
1451
#  elif defined(KWSYS_SYSTEMINFORMATION_HAS_BACKTRACE)
1452
  void* addr = sp.GetAddress();
1453
  char** syminfo = backtrace_symbols(&addr, 1);
1454
  os << safes(syminfo[0]);
1455
  free(syminfo);
1456
#  else
1457
  (void)os;
1458
  (void)sp;
1459
#  endif
1460
0
  return os;
1461
0
}
1462
1463
SymbolProperties::SymbolProperties()
1464
0
{
1465
  // not using an initializer list
1466
  // to avoid some PGI compiler warnings
1467
0
  this->SetBinary("???");
1468
0
  this->SetBinaryBaseAddress(nullptr);
1469
0
  this->Address = nullptr;
1470
0
  this->SetSourceFile("???");
1471
0
  this->SetFunction("???");
1472
0
  this->SetLineNumber(-1);
1473
0
  this->SetReportPath(0);
1474
  // avoid PGI compiler warnings
1475
0
  this->GetRealAddress();
1476
0
  this->GetFunction();
1477
0
  this->GetSourceFile();
1478
0
  this->GetLineNumber();
1479
0
}
1480
1481
std::string SymbolProperties::GetFileName(std::string const& path) const
1482
0
{
1483
0
  std::string file(path);
1484
0
  if (!this->ReportPath) {
1485
0
    size_t at = file.rfind('/');
1486
0
    if (at != std::string::npos) {
1487
0
      file.erase(0, at + 1);
1488
0
    }
1489
0
  }
1490
0
  return file;
1491
0
}
1492
1493
std::string SymbolProperties::GetBinary() const
1494
0
{
1495
// only linux has proc fs
1496
0
#  if defined(__linux__)
1497
0
  if (this->Binary == "/proc/self/exe") {
1498
0
    std::string binary;
1499
0
    char buf[1024] = { '\0' };
1500
0
    ssize_t ll = 0;
1501
0
    if ((ll = readlink("/proc/self/exe", buf, 1024)) > 0 && ll < 1024) {
1502
0
      buf[ll] = '\0';
1503
0
      binary = buf;
1504
0
    } else {
1505
0
      binary = "/proc/self/exe";
1506
0
    }
1507
0
    return this->GetFileName(binary);
1508
0
  }
1509
0
#  endif
1510
0
  return this->GetFileName(this->Binary);
1511
0
}
1512
1513
std::string SymbolProperties::Demangle(char const* symbol) const
1514
0
{
1515
0
  std::string result = safes(symbol);
1516
0
#  if defined(KWSYS_SYSTEMINFORMATION_HAS_CPP_DEMANGLE)
1517
0
  int status = 0;
1518
0
  char* demangledSymbol =
1519
0
    abi::__cxa_demangle(symbol, nullptr, nullptr, &status);
1520
0
  if (!status) {
1521
0
    result = demangledSymbol;
1522
0
  }
1523
0
  free(demangledSymbol);
1524
#  else
1525
  (void)symbol;
1526
#  endif
1527
0
  return result;
1528
0
}
1529
1530
void SymbolProperties::Initialize(void* address)
1531
0
{
1532
0
  this->Address = address;
1533
0
#  if defined(KWSYS_SYSTEMINFORMATION_HAS_SYMBOL_LOOKUP)
1534
  // first fallback option can demangle c++ functions
1535
0
  Dl_info info;
1536
0
  int ierr = dladdr(this->Address, &info);
1537
0
  if (ierr && info.dli_sname && info.dli_saddr) {
1538
0
    this->SetBinary(info.dli_fname);
1539
0
    this->SetFunction(info.dli_sname);
1540
0
  }
1541
#  else
1542
// second fallback use builtin backtrace_symbols
1543
// to decode the backtrace.
1544
#  endif
1545
0
}
1546
#endif // don't define this class if we're not using it
1547
1548
#if defined(_WIN32) || defined(__CYGWIN__)
1549
#  define KWSYS_SYSTEMINFORMATION_USE_GetSystemTimes
1550
#endif
1551
#if defined(_MSC_VER) && _MSC_VER < 1310
1552
#  undef KWSYS_SYSTEMINFORMATION_USE_GetSystemTimes
1553
#endif
1554
#if defined(KWSYS_SYSTEMINFORMATION_USE_GetSystemTimes)
1555
double calculateCPULoad(unsigned __int64 idleTicks,
1556
                        unsigned __int64 totalTicks)
1557
{
1558
  static double previousLoad = -0.0;
1559
  static unsigned __int64 previousIdleTicks = 0;
1560
  static unsigned __int64 previousTotalTicks = 0;
1561
1562
  unsigned __int64 const idleTicksSinceLastTime =
1563
    idleTicks - previousIdleTicks;
1564
  unsigned __int64 const totalTicksSinceLastTime =
1565
    totalTicks - previousTotalTicks;
1566
1567
  double load;
1568
  if (previousTotalTicks == 0 || totalTicksSinceLastTime == 0) {
1569
    // No new information.  Use previous result.
1570
    load = previousLoad;
1571
  } else {
1572
    // Calculate load since last time.
1573
    load = 1.0 - double(idleTicksSinceLastTime) / totalTicksSinceLastTime;
1574
1575
    // Smooth if possible.
1576
    if (previousLoad > 0) {
1577
      load = 0.25 * load + 0.75 * previousLoad;
1578
    }
1579
  }
1580
1581
  previousLoad = load;
1582
  previousIdleTicks = idleTicks;
1583
  previousTotalTicks = totalTicks;
1584
1585
  return load;
1586
}
1587
1588
#endif
1589
1590
} // anonymous namespace
1591
1592
SystemInformationImplementation::SystemInformationImplementation()
1593
0
{
1594
0
  this->TotalVirtualMemory = 0;
1595
0
  this->AvailableVirtualMemory = 0;
1596
0
  this->TotalPhysicalMemory = 0;
1597
0
  this->AvailablePhysicalMemory = 0;
1598
0
  this->CurrentPositionInFile = 0;
1599
0
  this->ChipManufacturer = UnknownManufacturer;
1600
0
  memset(&this->Features, 0, sizeof(CPUFeatures));
1601
0
  this->ChipID.Type = 0;
1602
0
  this->ChipID.Family = 0;
1603
0
  this->ChipID.Model = 0;
1604
0
  this->ChipID.Revision = 0;
1605
0
  this->ChipID.ExtendedFamily = 0;
1606
0
  this->ChipID.ExtendedModel = 0;
1607
0
  this->CPUSpeedInMHz = 0;
1608
0
  this->NumberOfLogicalCPU = 0;
1609
0
  this->NumberOfPhysicalCPU = 0;
1610
0
  this->OSName = "";
1611
0
  this->Hostname = "";
1612
0
  this->OSRelease = "";
1613
0
  this->OSVersion = "";
1614
0
  this->OSPlatform = "";
1615
0
  this->OSIs64Bit = (sizeof(void*) == 8);
1616
0
}
1617
1618
void SystemInformationImplementation::RunCPUCheck()
1619
0
{
1620
#ifdef _WIN32
1621
  // Check to see if this processor supports CPUID.
1622
  bool supportsCPUID = DoesCPUSupportCPUID();
1623
1624
  if (supportsCPUID) {
1625
    // Retrieve the CPU details.
1626
    RetrieveCPUIdentity();
1627
    this->FindManufacturer();
1628
    RetrieveCPUFeatures();
1629
  }
1630
1631
  // These two may be called without support for the CPUID instruction.
1632
  // (But if the instruction is there, they should be called *after*
1633
  // the above call to RetrieveCPUIdentity... that's why the two if
1634
  // blocks exist with the same "if (supportsCPUID)" logic...
1635
  //
1636
  if (!RetrieveCPUClockSpeed()) {
1637
    RetrieveClassicalCPUClockSpeed();
1638
  }
1639
1640
  if (supportsCPUID) {
1641
    // Retrieve cache information.
1642
    if (!RetrieveCPUCacheDetails()) {
1643
      RetrieveClassicalCPUCacheDetails();
1644
    }
1645
1646
    // Retrieve the extended CPU details.
1647
    if (!RetrieveExtendedCPUIdentity()) {
1648
      RetrieveClassicalCPUIdentity();
1649
    }
1650
1651
    RetrieveExtendedCPUFeatures();
1652
    RetrieveCPUPowerManagement();
1653
1654
    // Now attempt to retrieve the serial number (if possible).
1655
    RetrieveProcessorSerialNumber();
1656
  }
1657
1658
  this->CPUCountWindows();
1659
1660
#elif defined(__APPLE__)
1661
  this->ParseSysCtl();
1662
#elif defined(__SVR4) && defined(__sun)
1663
  this->QuerySolarisProcessor();
1664
#elif defined(__HAIKU__)
1665
  this->QueryHaikuInfo();
1666
#elif defined(__QNX__)
1667
  this->QueryQNXProcessor();
1668
#elif defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__NetBSD__) ||  \
1669
  defined(__DragonFly__)
1670
  this->QueryBSDProcessor();
1671
#elif defined(__hpux)
1672
  this->QueryHPUXProcessor();
1673
#elif defined(__linux) || defined(__CYGWIN__)
1674
  this->RetrieveInformationFromCpuInfoFile();
1675
#else
1676
  this->QueryProcessor();
1677
#endif
1678
0
}
1679
1680
void SystemInformationImplementation::RunOSCheck()
1681
0
{
1682
0
  this->QueryOSInformation();
1683
0
}
1684
1685
void SystemInformationImplementation::RunMemoryCheck()
1686
0
{
1687
#if defined(__APPLE__)
1688
  this->ParseSysCtl();
1689
#elif defined(__SVR4) && defined(__sun)
1690
  this->QuerySolarisMemory();
1691
#elif defined(__HAIKU__)
1692
  this->QueryHaikuInfo();
1693
#elif defined(__QNX__)
1694
  this->QueryQNXMemory();
1695
#elif defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__NetBSD__) ||  \
1696
  defined(__DragonFly__)
1697
  this->QueryBSDMemory();
1698
#elif defined(__CYGWIN__)
1699
  this->QueryCygwinMemory();
1700
#elif defined(_WIN32)
1701
  this->QueryWindowsMemory();
1702
#elif defined(__hpux)
1703
  this->QueryHPUXMemory();
1704
#elif defined(__linux)
1705
  this->QueryLinuxMemory();
1706
#elif defined(_AIX)
1707
  this->QueryAIXMemory();
1708
#else
1709
  this->QueryMemory();
1710
#endif
1711
0
}
1712
1713
/** Get the vendor string */
1714
char const* SystemInformationImplementation::GetVendorString() const
1715
0
{
1716
0
  return this->ChipID.Vendor.c_str();
1717
0
}
1718
1719
/** Get the OS Name */
1720
char const* SystemInformationImplementation::GetOSName()
1721
0
{
1722
0
  return this->OSName.c_str();
1723
0
}
1724
1725
/** Get the hostname */
1726
char const* SystemInformationImplementation::GetHostname()
1727
0
{
1728
0
  if (this->Hostname.empty()) {
1729
0
    this->Hostname = "localhost";
1730
#if defined(_WIN32)
1731
    WORD wVersionRequested;
1732
    WSADATA wsaData;
1733
    char name[255];
1734
    wVersionRequested = MAKEWORD(2, 0);
1735
    if (WSAStartup(wVersionRequested, &wsaData) == 0) {
1736
      gethostname(name, sizeof(name));
1737
      WSACleanup();
1738
    }
1739
    this->Hostname = name;
1740
#else
1741
0
    struct utsname unameInfo;
1742
0
    int errorFlag = uname(&unameInfo);
1743
0
    if (errorFlag == 0) {
1744
0
      this->Hostname = unameInfo.nodename;
1745
0
    }
1746
0
#endif
1747
0
  }
1748
0
  return this->Hostname.c_str();
1749
0
}
1750
1751
/** Get the FQDN */
1752
int SystemInformationImplementation::GetFullyQualifiedDomainName(
1753
  std::string& fqdn)
1754
0
{
1755
  // in the event of absolute failure return localhost.
1756
0
  fqdn = "localhost";
1757
1758
#if defined(_WIN32)
1759
  int ierr;
1760
  // TODO - a more robust implementation for windows, see comments
1761
  // in unix implementation.
1762
  WSADATA wsaData;
1763
  WORD ver = MAKEWORD(2, 0);
1764
  ierr = WSAStartup(ver, &wsaData);
1765
  if (ierr) {
1766
    return -1;
1767
  }
1768
1769
  char base[256] = { '\0' };
1770
  ierr = gethostname(base, 256);
1771
  if (ierr) {
1772
    WSACleanup();
1773
    return -2;
1774
  }
1775
  fqdn = base;
1776
1777
  HOSTENT* hent = gethostbyname(base);
1778
  if (hent) {
1779
    fqdn = hent->h_name;
1780
  }
1781
1782
  WSACleanup();
1783
  return 0;
1784
1785
#elif defined(KWSYS_SYSTEMINFORMATION_IMPLEMENT_FQDN)
1786
  // gethostname typical returns an alias for loopback interface
1787
  // we want the fully qualified domain name. Because there are
1788
  // any number of interfaces on this system we look for the
1789
  // first of these that contains the name returned by gethostname
1790
  // and is longer. failing that we return gethostname and indicate
1791
  // with a failure code. Return of a failure code is not necessarily
1792
  // an indication of an error. for instance gethostname may return
1793
  // the fully qualified domain name, or there may not be one if the
1794
  // system lives on a private network such as in the case of a cluster
1795
  // node.
1796
1797
0
  int ierr = 0;
1798
0
  char base[NI_MAXHOST];
1799
0
  ierr = gethostname(base, NI_MAXHOST);
1800
0
  if (ierr) {
1801
0
    return -1;
1802
0
  }
1803
0
  size_t baseSize = strlen(base);
1804
0
  fqdn = base;
1805
1806
0
  struct ifaddrs* ifas;
1807
0
  struct ifaddrs* ifa;
1808
0
  ierr = getifaddrs(&ifas);
1809
0
  if (ierr) {
1810
0
    return -2;
1811
0
  }
1812
1813
0
  for (ifa = ifas; ifa; ifa = ifa->ifa_next) {
1814
0
    int fam = ifa->ifa_addr ? ifa->ifa_addr->sa_family : -1;
1815
    // Skip Loopback interfaces
1816
0
    if (((fam == AF_INET) || (fam == AF_INET6)) &&
1817
0
        !(ifa->ifa_flags & IFF_LOOPBACK)) {
1818
0
      char host[NI_MAXHOST] = { '\0' };
1819
1820
0
      size_t const addrlen = (fam == AF_INET ? sizeof(struct sockaddr_in)
1821
0
                                             : sizeof(struct sockaddr_in6));
1822
1823
0
      ierr = getnameinfo(ifa->ifa_addr, static_cast<socklen_t>(addrlen), host,
1824
0
                         NI_MAXHOST, nullptr, 0, NI_NAMEREQD);
1825
0
      if (ierr) {
1826
        // don't report the failure now since we may succeed on another
1827
        // interface. If all attempts fail then return the failure code.
1828
0
        ierr = -3;
1829
0
        continue;
1830
0
      }
1831
1832
0
      std::string candidate = host;
1833
0
      if ((candidate.find(base) != std::string::npos) &&
1834
0
          baseSize < candidate.size()) {
1835
        // success, stop now.
1836
0
        ierr = 0;
1837
0
        fqdn = candidate;
1838
0
        break;
1839
0
      }
1840
0
    }
1841
0
  }
1842
0
  freeifaddrs(ifas);
1843
1844
0
  return ierr;
1845
#else
1846
  /* TODO: Implement on more platforms.  */
1847
  fqdn = this->GetHostname();
1848
  return -1;
1849
#endif
1850
0
}
1851
1852
/** Get the OS release */
1853
char const* SystemInformationImplementation::GetOSRelease()
1854
0
{
1855
0
  return this->OSRelease.c_str();
1856
0
}
1857
1858
/** Get the OS version */
1859
char const* SystemInformationImplementation::GetOSVersion()
1860
0
{
1861
0
  return this->OSVersion.c_str();
1862
0
}
1863
1864
/** Get the OS platform */
1865
char const* SystemInformationImplementation::GetOSPlatform()
1866
0
{
1867
0
  return this->OSPlatform.c_str();
1868
0
}
1869
1870
/** Get the vendor ID */
1871
char const* SystemInformationImplementation::GetVendorID()
1872
0
{
1873
  // Return the vendor ID.
1874
0
  switch (this->ChipManufacturer) {
1875
0
    case Intel:
1876
0
      return "Intel Corporation";
1877
0
    case AMD:
1878
0
      return "Advanced Micro Devices";
1879
0
    case NSC:
1880
0
      return "National Semiconductor";
1881
0
    case Cyrix:
1882
0
      return "Cyrix Corp., VIA Inc.";
1883
0
    case NexGen:
1884
0
      return "NexGen Inc., Advanced Micro Devices";
1885
0
    case IDT:
1886
0
      return "IDT\\Centaur, Via Inc., Shanghai Zhaoxin Semiconductor Co., "
1887
0
             "Ltd.";
1888
0
    case UMC:
1889
0
      return "United Microelectronics Corp.";
1890
0
    case Rise:
1891
0
      return "Rise";
1892
0
    case Transmeta:
1893
0
      return "Transmeta";
1894
0
    case Sun:
1895
0
      return "Sun Microelectronics";
1896
0
    case IBM:
1897
0
      return "IBM";
1898
0
    case Motorola:
1899
0
      return "Motorola";
1900
0
    case HP:
1901
0
      return "Hewlett-Packard";
1902
0
    case Hygon:
1903
0
      return "Chengdu Haiguang IC Design Co., Ltd.";
1904
0
    case Zhaoxin:
1905
0
      return "Shanghai Zhaoxin Semiconductor Co., Ltd.";
1906
0
    case Apple:
1907
0
      return "Apple";
1908
0
    case UnknownManufacturer:
1909
0
    default:
1910
0
      return "Unknown Manufacturer";
1911
0
  }
1912
0
}
1913
1914
/** Return the type ID of the CPU */
1915
std::string SystemInformationImplementation::GetTypeID() const
1916
0
{
1917
0
  std::ostringstream str;
1918
0
  str << this->ChipID.Type;
1919
0
  return str.str();
1920
0
}
1921
1922
/** Return the family of the CPU present */
1923
std::string SystemInformationImplementation::GetFamilyID() const
1924
0
{
1925
0
  std::ostringstream str;
1926
0
  str << this->ChipID.Family;
1927
0
  return str.str();
1928
0
}
1929
1930
// Return the model of CPU present */
1931
std::string SystemInformationImplementation::GetModelID() const
1932
0
{
1933
0
  std::ostringstream str;
1934
0
  str << this->ChipID.Model;
1935
0
  return str.str();
1936
0
}
1937
1938
// Return the model name of CPU present */
1939
std::string SystemInformationImplementation::GetModelName() const
1940
0
{
1941
0
  return this->ChipID.ModelName;
1942
0
}
1943
1944
/** Return the stepping code of the CPU present. */
1945
std::string SystemInformationImplementation::GetSteppingCode() const
1946
0
{
1947
0
  std::ostringstream str;
1948
0
  str << this->ChipID.Revision;
1949
0
  return str.str();
1950
0
}
1951
1952
/** Return the stepping code of the CPU present. */
1953
char const* SystemInformationImplementation::GetExtendedProcessorName() const
1954
0
{
1955
0
  return this->ChipID.ProcessorName.c_str();
1956
0
}
1957
1958
/** Return the serial number of the processor
1959
 *  in hexadecimal: xxxx-xxxx-xxxx-xxxx-xxxx-xxxx. */
1960
char const* SystemInformationImplementation::GetProcessorSerialNumber() const
1961
0
{
1962
0
  return this->ChipID.SerialNumber.c_str();
1963
0
}
1964
1965
/** Return the logical processors per physical */
1966
unsigned int SystemInformationImplementation::GetLogicalProcessorsPerPhysical()
1967
  const
1968
0
{
1969
0
  return this->Features.ExtendedFeatures.LogicalProcessorsPerPhysical;
1970
0
}
1971
1972
/** Return the processor clock frequency. */
1973
float SystemInformationImplementation::GetProcessorClockFrequency() const
1974
0
{
1975
0
  return this->CPUSpeedInMHz;
1976
0
}
1977
1978
/**  Return the APIC ID. */
1979
int SystemInformationImplementation::GetProcessorAPICID() const
1980
0
{
1981
0
  return this->Features.ExtendedFeatures.APIC_ID;
1982
0
}
1983
1984
/** Return the L1 cache size. */
1985
int SystemInformationImplementation::GetProcessorCacheSize() const
1986
0
{
1987
0
  return this->Features.L1CacheSize;
1988
0
}
1989
1990
/** Return the chosen cache size. */
1991
int SystemInformationImplementation::GetProcessorCacheXSize(
1992
  long int dwCacheID) const
1993
0
{
1994
0
  switch (dwCacheID) {
1995
0
    case SystemInformation::CPU_FEATURE_L1CACHE:
1996
0
      return this->Features.L1CacheSize;
1997
0
    case SystemInformation::CPU_FEATURE_L2CACHE:
1998
0
      return this->Features.L2CacheSize;
1999
0
    case SystemInformation::CPU_FEATURE_L3CACHE:
2000
0
      return this->Features.L3CacheSize;
2001
0
    default:
2002
0
      break;
2003
0
  }
2004
0
  return -1;
2005
0
}
2006
2007
bool SystemInformationImplementation::DoesCPUSupportFeature(
2008
  long int dwFeature) const
2009
0
{
2010
0
  bool bHasFeature = false;
2011
2012
  // Check for MMX instructions.
2013
0
  if (((dwFeature & SystemInformation::CPU_FEATURE_MMX) != 0) &&
2014
0
      this->Features.HasMMX)
2015
0
    bHasFeature = true;
2016
2017
  // Check for MMX+ instructions.
2018
0
  if (((dwFeature & SystemInformation::CPU_FEATURE_MMX_PLUS) != 0) &&
2019
0
      this->Features.ExtendedFeatures.HasMMXPlus)
2020
0
    bHasFeature = true;
2021
2022
  // Check for SSE FP instructions.
2023
0
  if (((dwFeature & SystemInformation::CPU_FEATURE_SSE) != 0) &&
2024
0
      this->Features.HasSSE)
2025
0
    bHasFeature = true;
2026
2027
  // Check for SSE FP instructions.
2028
0
  if (((dwFeature & SystemInformation::CPU_FEATURE_SSE_FP) != 0) &&
2029
0
      this->Features.HasSSEFP)
2030
0
    bHasFeature = true;
2031
2032
  // Check for SSE MMX instructions.
2033
0
  if (((dwFeature & SystemInformation::CPU_FEATURE_SSE_MMX) != 0) &&
2034
0
      this->Features.ExtendedFeatures.HasSSEMMX)
2035
0
    bHasFeature = true;
2036
2037
  // Check for SSE2 instructions.
2038
0
  if (((dwFeature & SystemInformation::CPU_FEATURE_SSE2) != 0) &&
2039
0
      this->Features.HasSSE2)
2040
0
    bHasFeature = true;
2041
2042
  // Check for 3DNow! instructions.
2043
0
  if (((dwFeature & SystemInformation::CPU_FEATURE_AMD_3DNOW) != 0) &&
2044
0
      this->Features.ExtendedFeatures.Has3DNow)
2045
0
    bHasFeature = true;
2046
2047
  // Check for 3DNow+ instructions.
2048
0
  if (((dwFeature & SystemInformation::CPU_FEATURE_AMD_3DNOW_PLUS) != 0) &&
2049
0
      this->Features.ExtendedFeatures.Has3DNowPlus)
2050
0
    bHasFeature = true;
2051
2052
  // Check for IA64 instructions.
2053
0
  if (((dwFeature & SystemInformation::CPU_FEATURE_IA64) != 0) &&
2054
0
      this->Features.HasIA64)
2055
0
    bHasFeature = true;
2056
2057
  // Check for MP capable.
2058
0
  if (((dwFeature & SystemInformation::CPU_FEATURE_MP_CAPABLE) != 0) &&
2059
0
      this->Features.ExtendedFeatures.SupportsMP)
2060
0
    bHasFeature = true;
2061
2062
  // Check for a serial number for the processor.
2063
0
  if (((dwFeature & SystemInformation::CPU_FEATURE_SERIALNUMBER) != 0) &&
2064
0
      this->Features.HasSerial)
2065
0
    bHasFeature = true;
2066
2067
  // Check for a local APIC in the processor.
2068
0
  if (((dwFeature & SystemInformation::CPU_FEATURE_APIC) != 0) &&
2069
0
      this->Features.HasAPIC)
2070
0
    bHasFeature = true;
2071
2072
  // Check for CMOV instructions.
2073
0
  if (((dwFeature & SystemInformation::CPU_FEATURE_CMOV) != 0) &&
2074
0
      this->Features.HasCMOV)
2075
0
    bHasFeature = true;
2076
2077
  // Check for MTRR instructions.
2078
0
  if (((dwFeature & SystemInformation::CPU_FEATURE_MTRR) != 0) &&
2079
0
      this->Features.HasMTRR)
2080
0
    bHasFeature = true;
2081
2082
  // Check for L1 cache size.
2083
0
  if (((dwFeature & SystemInformation::CPU_FEATURE_L1CACHE) != 0) &&
2084
0
      (this->Features.L1CacheSize != -1))
2085
0
    bHasFeature = true;
2086
2087
  // Check for L2 cache size.
2088
0
  if (((dwFeature & SystemInformation::CPU_FEATURE_L2CACHE) != 0) &&
2089
0
      (this->Features.L2CacheSize != -1))
2090
0
    bHasFeature = true;
2091
2092
  // Check for L3 cache size.
2093
0
  if (((dwFeature & SystemInformation::CPU_FEATURE_L3CACHE) != 0) &&
2094
0
      (this->Features.L3CacheSize != -1))
2095
0
    bHasFeature = true;
2096
2097
  // Check for ACPI capability.
2098
0
  if (((dwFeature & SystemInformation::CPU_FEATURE_ACPI) != 0) &&
2099
0
      this->Features.HasACPI)
2100
0
    bHasFeature = true;
2101
2102
  // Check for thermal monitor support.
2103
0
  if (((dwFeature & SystemInformation::CPU_FEATURE_THERMALMONITOR) != 0) &&
2104
0
      this->Features.HasThermal)
2105
0
    bHasFeature = true;
2106
2107
  // Check for temperature sensing diode support.
2108
0
  if (((dwFeature & SystemInformation::CPU_FEATURE_TEMPSENSEDIODE) != 0) &&
2109
0
      this->Features.ExtendedFeatures.PowerManagement.HasTempSenseDiode)
2110
0
    bHasFeature = true;
2111
2112
  // Check for frequency ID support.
2113
0
  if (((dwFeature & SystemInformation::CPU_FEATURE_FREQUENCYID) != 0) &&
2114
0
      this->Features.ExtendedFeatures.PowerManagement.HasFrequencyID)
2115
0
    bHasFeature = true;
2116
2117
  // Check for voltage ID support.
2118
0
  if (((dwFeature & SystemInformation::CPU_FEATURE_VOLTAGEID_FREQUENCY) !=
2119
0
       0) &&
2120
0
      this->Features.ExtendedFeatures.PowerManagement.HasVoltageID)
2121
0
    bHasFeature = true;
2122
2123
  // Check for FPU support.
2124
0
  if (((dwFeature & SystemInformation::CPU_FEATURE_FPU) != 0) &&
2125
0
      this->Features.HasFPU)
2126
0
    bHasFeature = true;
2127
2128
0
  return bHasFeature;
2129
0
}
2130
2131
void SystemInformationImplementation::Delay(unsigned int uiMS)
2132
0
{
2133
#ifdef _WIN32
2134
  LARGE_INTEGER Frequency, StartCounter, EndCounter;
2135
  __int64 x;
2136
2137
  // Get the frequency of the high performance counter.
2138
  if (!QueryPerformanceFrequency(&Frequency))
2139
    return;
2140
  x = Frequency.QuadPart / 1000 * uiMS;
2141
2142
  // Get the starting position of the counter.
2143
  QueryPerformanceCounter(&StartCounter);
2144
2145
  do {
2146
    // Get the ending position of the counter.
2147
    QueryPerformanceCounter(&EndCounter);
2148
  } while (EndCounter.QuadPart - StartCounter.QuadPart < x);
2149
#endif
2150
0
  (void)uiMS;
2151
0
}
2152
2153
bool SystemInformationImplementation::DoesCPUSupportCPUID()
2154
0
{
2155
#if USE_CPUID
2156
  int dummy[4] = { 0, 0, 0, 0 };
2157
2158
#  if USE_ASM_INSTRUCTIONS
2159
  return call_cpuid(0, dummy);
2160
#  else
2161
  call_cpuid(0, dummy);
2162
  return dummy[0] || dummy[1] || dummy[2] || dummy[3];
2163
#  endif
2164
#else
2165
  // Assume no cpuid instruction.
2166
0
  return false;
2167
0
#endif
2168
0
}
2169
2170
bool SystemInformationImplementation::RetrieveCPUFeatures()
2171
0
{
2172
#if USE_CPUID
2173
  int cpuinfo[4] = { 0, 0, 0, 0 };
2174
2175
  if (!call_cpuid(1, cpuinfo)) {
2176
    return false;
2177
  }
2178
2179
  // Retrieve the features of CPU present.
2180
  this->Features.HasFPU =
2181
    ((cpuinfo[3] & 0x00000001) != 0); // FPU Present --> Bit 0
2182
  this->Features.HasTSC =
2183
    ((cpuinfo[3] & 0x00000010) != 0); // TSC Present --> Bit 4
2184
  this->Features.HasAPIC =
2185
    ((cpuinfo[3] & 0x00000200) != 0); // APIC Present --> Bit 9
2186
  this->Features.HasMTRR =
2187
    ((cpuinfo[3] & 0x00001000) != 0); // MTRR Present --> Bit 12
2188
  this->Features.HasCMOV =
2189
    ((cpuinfo[3] & 0x00008000) != 0); // CMOV Present --> Bit 15
2190
  this->Features.HasSerial =
2191
    ((cpuinfo[3] & 0x00040000) != 0); // Serial Present --> Bit 18
2192
  this->Features.HasACPI =
2193
    ((cpuinfo[3] & 0x00400000) != 0); // ACPI Capable --> Bit 22
2194
  this->Features.HasMMX =
2195
    ((cpuinfo[3] & 0x00800000) != 0); // MMX Present --> Bit 23
2196
  this->Features.HasSSE =
2197
    ((cpuinfo[3] & 0x02000000) != 0); // SSE Present --> Bit 25
2198
  this->Features.HasSSE2 =
2199
    ((cpuinfo[3] & 0x04000000) != 0); // SSE2 Present --> Bit 26
2200
  this->Features.HasThermal =
2201
    ((cpuinfo[3] & 0x20000000) != 0); // Thermal Monitor Present --> Bit 29
2202
  this->Features.HasIA64 =
2203
    ((cpuinfo[3] & 0x40000000) != 0); // IA64 Present --> Bit 30
2204
2205
#  if USE_ASM_INSTRUCTIONS
2206
  // Retrieve extended SSE capabilities if SSE is available.
2207
  if (this->Features.HasSSE) {
2208
2209
    // Attempt to __try some SSE FP instructions.
2210
    __try {
2211
      // Perform: orps xmm0, xmm0
2212
      _asm
2213
      {
2214
        _emit 0x0f
2215
        _emit 0x56
2216
        _emit 0xc0
2217
      }
2218
2219
      // SSE FP capable processor.
2220
      this->Features.HasSSEFP = true;
2221
    } __except (1) {
2222
      // bad instruction - processor or OS cannot handle SSE FP.
2223
      this->Features.HasSSEFP = false;
2224
    }
2225
  } else {
2226
    // Set the advanced SSE capabilities to not available.
2227
    this->Features.HasSSEFP = false;
2228
  }
2229
#  else
2230
  this->Features.HasSSEFP = false;
2231
#  endif
2232
2233
  // Retrieve Intel specific extended features.
2234
  if (this->ChipManufacturer == Intel) {
2235
    bool SupportsSMT =
2236
      ((cpuinfo[3] & 0x10000000) != 0); // Intel specific: SMT --> Bit 28
2237
2238
    if ((SupportsSMT) && (this->Features.HasAPIC)) {
2239
      // Retrieve APIC information if there is one present.
2240
      this->Features.ExtendedFeatures.APIC_ID =
2241
        ((cpuinfo[1] & 0xFF000000) >> 24);
2242
    }
2243
  }
2244
2245
  return true;
2246
2247
#else
2248
0
  return false;
2249
0
#endif
2250
0
}
2251
2252
/** Find the manufacturer given the vendor id */
2253
void SystemInformationImplementation::FindManufacturer(
2254
  std::string const& family)
2255
0
{
2256
0
  if (this->ChipID.Vendor == "GenuineIntel")
2257
0
    this->ChipManufacturer = Intel; // Intel Corp.
2258
0
  else if (this->ChipID.Vendor == "UMC UMC UMC ")
2259
0
    this->ChipManufacturer = UMC; // United Microelectronics Corp.
2260
0
  else if (this->ChipID.Vendor == "AuthenticAMD")
2261
0
    this->ChipManufacturer = AMD; // Advanced Micro Devices
2262
0
  else if (this->ChipID.Vendor == "AMD ISBETTER")
2263
0
    this->ChipManufacturer = AMD; // Advanced Micro Devices (1994)
2264
0
  else if (this->ChipID.Vendor == "HygonGenuine")
2265
0
    this->ChipManufacturer = Hygon; // Chengdu Haiguang IC Design Co., Ltd.
2266
0
  else if (this->ChipID.Vendor == "CyrixInstead")
2267
0
    this->ChipManufacturer = Cyrix; // Cyrix Corp., VIA Inc.
2268
0
  else if (this->ChipID.Vendor == "NexGenDriven")
2269
0
    this->ChipManufacturer = NexGen; // NexGen Inc. (now AMD)
2270
0
  else if (this->ChipID.Vendor == "CentaurHauls")
2271
0
    this->ChipManufacturer = IDT; // original IDT/Centaur/VIA (now Zhaoxin)
2272
0
  else if (this->ChipID.Vendor == "  Shanghai  ")
2273
0
    this->ChipManufacturer =
2274
0
      Zhaoxin; // Shanghai Zhaoxin Semiconductor Co., Ltd.
2275
0
  else if (this->ChipID.Vendor == "RiseRiseRise")
2276
0
    this->ChipManufacturer = Rise; // Rise
2277
0
  else if (this->ChipID.Vendor == "GenuineTMx86")
2278
0
    this->ChipManufacturer = Transmeta; // Transmeta
2279
0
  else if (this->ChipID.Vendor == "TransmetaCPU")
2280
0
    this->ChipManufacturer = Transmeta; // Transmeta
2281
0
  else if (this->ChipID.Vendor == "Geode By NSC")
2282
0
    this->ChipManufacturer = NSC; // National Semiconductor
2283
0
  else if (this->ChipID.Vendor == "Sun")
2284
0
    this->ChipManufacturer = Sun; // Sun Microelectronics
2285
0
  else if (this->ChipID.Vendor == "IBM")
2286
0
    this->ChipManufacturer = IBM; // IBM Microelectronics
2287
0
  else if (this->ChipID.Vendor == "Hewlett-Packard")
2288
0
    this->ChipManufacturer = HP; // Hewlett-Packard
2289
0
  else if (this->ChipID.Vendor == "Motorola")
2290
0
    this->ChipManufacturer = Motorola; // Motorola Microelectronics
2291
0
  else if (family.compare(0, 7, "PA-RISC") == 0)
2292
0
    this->ChipManufacturer = HP; // Hewlett-Packard
2293
0
  else if (this->ChipID.Vendor == "Apple")
2294
0
    this->ChipManufacturer = Apple; // Apple
2295
0
  else
2296
0
    this->ChipManufacturer = UnknownManufacturer; // Unknown manufacturer
2297
0
}
2298
2299
/** */
2300
bool SystemInformationImplementation::RetrieveCPUIdentity()
2301
0
{
2302
#if USE_CPUID
2303
  int localCPUVendor[4];
2304
  int localCPUSignature[4];
2305
2306
  if (!call_cpuid(0, localCPUVendor)) {
2307
    return false;
2308
  }
2309
  if (!call_cpuid(1, localCPUSignature)) {
2310
    return false;
2311
  }
2312
2313
  // Process the returned information.
2314
  //    ; eax = 0 --> eax: maximum value of CPUID instruction.
2315
  //    ;        ebx: part 1 of 3; CPU signature.
2316
  //    ;        edx: part 2 of 3; CPU signature.
2317
  //    ;        ecx: part 3 of 3; CPU signature.
2318
  char vbuf[13];
2319
  memcpy(&(vbuf[0]), &(localCPUVendor[1]), sizeof(int));
2320
  memcpy(&(vbuf[4]), &(localCPUVendor[3]), sizeof(int));
2321
  memcpy(&(vbuf[8]), &(localCPUVendor[2]), sizeof(int));
2322
  vbuf[12] = '\0';
2323
  this->ChipID.Vendor = vbuf;
2324
2325
  // Retrieve the family of CPU present.
2326
  //    ; eax = 1 --> eax: CPU ID - bits 31..16 - unused, bits 15..12 - type,
2327
  //    bits 11..8 - family, bits 7..4 - model, bits 3..0 - mask revision
2328
  //    ;        ebx: 31..24 - default APIC ID, 23..16 - logical processor ID,
2329
  //    15..8 - CFLUSH chunk size , 7..0 - brand ID
2330
  //    ;        edx: CPU feature flags
2331
  this->ChipID.ExtendedFamily =
2332
    ((localCPUSignature[0] & 0x0FF00000) >> 20); // Bits 27..20 Used
2333
  this->ChipID.ExtendedModel =
2334
    ((localCPUSignature[0] & 0x000F0000) >> 16); // Bits 19..16 Used
2335
  this->ChipID.Type =
2336
    ((localCPUSignature[0] & 0x0000F000) >> 12); // Bits 15..12 Used
2337
  this->ChipID.Family =
2338
    ((localCPUSignature[0] & 0x00000F00) >> 8); // Bits 11..8 Used
2339
  this->ChipID.Model =
2340
    ((localCPUSignature[0] & 0x000000F0) >> 4); // Bits 7..4 Used
2341
  this->ChipID.Revision =
2342
    ((localCPUSignature[0] & 0x0000000F) >> 0); // Bits 3..0 Used
2343
2344
  return true;
2345
2346
#else
2347
0
  return false;
2348
0
#endif
2349
0
}
2350
2351
/** */
2352
bool SystemInformationImplementation::RetrieveCPUCacheDetails()
2353
0
{
2354
#if USE_CPUID
2355
  int L1Cache[4] = { 0, 0, 0, 0 };
2356
  int L2Cache[4] = { 0, 0, 0, 0 };
2357
2358
  // Check to see if what we are about to do is supported...
2359
  if (RetrieveCPUExtendedLevelSupport(0x80000005)) {
2360
    if (!call_cpuid(0x80000005, L1Cache)) {
2361
      return false;
2362
    }
2363
    // Save the L1 data cache size (in KB) from ecx: bits 31..24 as well as
2364
    // data cache size from edx: bits 31..24.
2365
    this->Features.L1CacheSize = ((L1Cache[2] & 0xFF000000) >> 24);
2366
    this->Features.L1CacheSize += ((L1Cache[3] & 0xFF000000) >> 24);
2367
  } else {
2368
    // Store -1 to indicate the cache could not be queried.
2369
    this->Features.L1CacheSize = -1;
2370
  }
2371
2372
  // Check to see if what we are about to do is supported...
2373
  if (RetrieveCPUExtendedLevelSupport(0x80000006)) {
2374
    if (!call_cpuid(0x80000006, L2Cache)) {
2375
      return false;
2376
    }
2377
    // Save the L2 unified cache size (in KB) from ecx: bits 31..16.
2378
    this->Features.L2CacheSize = ((L2Cache[2] & 0xFFFF0000) >> 16);
2379
  } else {
2380
    // Store -1 to indicate the cache could not be queried.
2381
    this->Features.L2CacheSize = -1;
2382
  }
2383
2384
  // Define L3 as being not present as we cannot test for it.
2385
  this->Features.L3CacheSize = -1;
2386
2387
#endif
2388
2389
  // Return failure if we cannot detect either cache with this method.
2390
0
  return ((this->Features.L1CacheSize == -1) &&
2391
0
          (this->Features.L2CacheSize == -1))
2392
0
    ? false
2393
0
    : true;
2394
0
}
2395
2396
/** */
2397
bool SystemInformationImplementation::RetrieveClassicalCPUCacheDetails()
2398
0
{
2399
#if USE_CPUID
2400
  int TLBCode = -1, TLBData = -1, L1Code = -1, L1Data = -1, L1Trace = -1,
2401
      L2Unified = -1, L3Unified = -1;
2402
  int TLBCacheData[4] = { 0, 0, 0, 0 };
2403
  int TLBPassCounter = 0;
2404
  int TLBCacheUnit = 0;
2405
2406
  do {
2407
    if (!call_cpuid(2, TLBCacheData)) {
2408
      return false;
2409
    }
2410
2411
    int bob = ((TLBCacheData[0] & 0x00FF0000) >> 16);
2412
    (void)bob;
2413
    // Process the returned TLB and cache information.
2414
    for (int nCounter = 0; nCounter < TLBCACHE_INFO_UNITS; nCounter++) {
2415
      // First of all - decide which unit we are dealing with.
2416
      switch (nCounter) {
2417
        // eax: bits 8..15 : bits 16..23 : bits 24..31
2418
        case 0:
2419
          TLBCacheUnit = ((TLBCacheData[0] & 0x0000FF00) >> 8);
2420
          break;
2421
        case 1:
2422
          TLBCacheUnit = ((TLBCacheData[0] & 0x00FF0000) >> 16);
2423
          break;
2424
        case 2:
2425
          TLBCacheUnit = ((TLBCacheData[0] & 0xFF000000) >> 24);
2426
          break;
2427
2428
        // ebx: bits 0..7 : bits 8..15 : bits 16..23 : bits 24..31
2429
        case 3:
2430
          TLBCacheUnit = ((TLBCacheData[1] & 0x000000FF) >> 0);
2431
          break;
2432
        case 4:
2433
          TLBCacheUnit = ((TLBCacheData[1] & 0x0000FF00) >> 8);
2434
          break;
2435
        case 5:
2436
          TLBCacheUnit = ((TLBCacheData[1] & 0x00FF0000) >> 16);
2437
          break;
2438
        case 6:
2439
          TLBCacheUnit = ((TLBCacheData[1] & 0xFF000000) >> 24);
2440
          break;
2441
2442
        // ecx: bits 0..7 : bits 8..15 : bits 16..23 : bits 24..31
2443
        case 7:
2444
          TLBCacheUnit = ((TLBCacheData[2] & 0x000000FF) >> 0);
2445
          break;
2446
        case 8:
2447
          TLBCacheUnit = ((TLBCacheData[2] & 0x0000FF00) >> 8);
2448
          break;
2449
        case 9:
2450
          TLBCacheUnit = ((TLBCacheData[2] & 0x00FF0000) >> 16);
2451
          break;
2452
        case 10:
2453
          TLBCacheUnit = ((TLBCacheData[2] & 0xFF000000) >> 24);
2454
          break;
2455
2456
        // edx: bits 0..7 : bits 8..15 : bits 16..23 : bits 24..31
2457
        case 11:
2458
          TLBCacheUnit = ((TLBCacheData[3] & 0x000000FF) >> 0);
2459
          break;
2460
        case 12:
2461
          TLBCacheUnit = ((TLBCacheData[3] & 0x0000FF00) >> 8);
2462
          break;
2463
        case 13:
2464
          TLBCacheUnit = ((TLBCacheData[3] & 0x00FF0000) >> 16);
2465
          break;
2466
        case 14:
2467
          TLBCacheUnit = ((TLBCacheData[3] & 0xFF000000) >> 24);
2468
          break;
2469
2470
        // Default case - an error has occurred.
2471
        default:
2472
          return false;
2473
      }
2474
2475
      // Now process the resulting unit to see what it means....
2476
      switch (TLBCacheUnit) {
2477
        case 0x00:
2478
          break;
2479
        case 0x01:
2480
          STORE_TLBCACHE_INFO(TLBCode, 4);
2481
          break;
2482
        case 0x02:
2483
          STORE_TLBCACHE_INFO(TLBCode, 4096);
2484
          break;
2485
        case 0x03:
2486
          STORE_TLBCACHE_INFO(TLBData, 4);
2487
          break;
2488
        case 0x04:
2489
          STORE_TLBCACHE_INFO(TLBData, 4096);
2490
          break;
2491
        case 0x06:
2492
          STORE_TLBCACHE_INFO(L1Code, 8);
2493
          break;
2494
        case 0x08:
2495
          STORE_TLBCACHE_INFO(L1Code, 16);
2496
          break;
2497
        case 0x0a:
2498
          STORE_TLBCACHE_INFO(L1Data, 8);
2499
          break;
2500
        case 0x0c:
2501
          STORE_TLBCACHE_INFO(L1Data, 16);
2502
          break;
2503
        case 0x10:
2504
          STORE_TLBCACHE_INFO(L1Data, 16);
2505
          break; // <-- FIXME: IA-64 Only
2506
        case 0x15:
2507
          STORE_TLBCACHE_INFO(L1Code, 16);
2508
          break; // <-- FIXME: IA-64 Only
2509
        case 0x1a:
2510
          STORE_TLBCACHE_INFO(L2Unified, 96);
2511
          break; // <-- FIXME: IA-64 Only
2512
        case 0x22:
2513
          STORE_TLBCACHE_INFO(L3Unified, 512);
2514
          break;
2515
        case 0x23:
2516
          STORE_TLBCACHE_INFO(L3Unified, 1024);
2517
          break;
2518
        case 0x25:
2519
          STORE_TLBCACHE_INFO(L3Unified, 2048);
2520
          break;
2521
        case 0x29:
2522
          STORE_TLBCACHE_INFO(L3Unified, 4096);
2523
          break;
2524
        case 0x39:
2525
          STORE_TLBCACHE_INFO(L2Unified, 128);
2526
          break;
2527
        case 0x3c:
2528
          STORE_TLBCACHE_INFO(L2Unified, 256);
2529
          break;
2530
        case 0x40:
2531
          STORE_TLBCACHE_INFO(L2Unified, 0);
2532
          break; // <-- FIXME: No integrated L2 cache (P6 core) or L3 cache (P4
2533
                 // core).
2534
        case 0x41:
2535
          STORE_TLBCACHE_INFO(L2Unified, 128);
2536
          break;
2537
        case 0x42:
2538
          STORE_TLBCACHE_INFO(L2Unified, 256);
2539
          break;
2540
        case 0x43:
2541
          STORE_TLBCACHE_INFO(L2Unified, 512);
2542
          break;
2543
        case 0x44:
2544
          STORE_TLBCACHE_INFO(L2Unified, 1024);
2545
          break;
2546
        case 0x45:
2547
          STORE_TLBCACHE_INFO(L2Unified, 2048);
2548
          break;
2549
        case 0x50:
2550
          STORE_TLBCACHE_INFO(TLBCode, 4096);
2551
          break;
2552
        case 0x51:
2553
          STORE_TLBCACHE_INFO(TLBCode, 4096);
2554
          break;
2555
        case 0x52:
2556
          STORE_TLBCACHE_INFO(TLBCode, 4096);
2557
          break;
2558
        case 0x5b:
2559
          STORE_TLBCACHE_INFO(TLBData, 4096);
2560
          break;
2561
        case 0x5c:
2562
          STORE_TLBCACHE_INFO(TLBData, 4096);
2563
          break;
2564
        case 0x5d:
2565
          STORE_TLBCACHE_INFO(TLBData, 4096);
2566
          break;
2567
        case 0x66:
2568
          STORE_TLBCACHE_INFO(L1Data, 8);
2569
          break;
2570
        case 0x67:
2571
          STORE_TLBCACHE_INFO(L1Data, 16);
2572
          break;
2573
        case 0x68:
2574
          STORE_TLBCACHE_INFO(L1Data, 32);
2575
          break;
2576
        case 0x70:
2577
          STORE_TLBCACHE_INFO(L1Trace, 12);
2578
          break;
2579
        case 0x71:
2580
          STORE_TLBCACHE_INFO(L1Trace, 16);
2581
          break;
2582
        case 0x72:
2583
          STORE_TLBCACHE_INFO(L1Trace, 32);
2584
          break;
2585
        case 0x77:
2586
          STORE_TLBCACHE_INFO(L1Code, 16);
2587
          break; // <-- FIXME: IA-64 Only
2588
        case 0x79:
2589
          STORE_TLBCACHE_INFO(L2Unified, 128);
2590
          break;
2591
        case 0x7a:
2592
          STORE_TLBCACHE_INFO(L2Unified, 256);
2593
          break;
2594
        case 0x7b:
2595
          STORE_TLBCACHE_INFO(L2Unified, 512);
2596
          break;
2597
        case 0x7c:
2598
          STORE_TLBCACHE_INFO(L2Unified, 1024);
2599
          break;
2600
        case 0x7e:
2601
          STORE_TLBCACHE_INFO(L2Unified, 256);
2602
          break;
2603
        case 0x81:
2604
          STORE_TLBCACHE_INFO(L2Unified, 128);
2605
          break;
2606
        case 0x82:
2607
          STORE_TLBCACHE_INFO(L2Unified, 256);
2608
          break;
2609
        case 0x83:
2610
          STORE_TLBCACHE_INFO(L2Unified, 512);
2611
          break;
2612
        case 0x84:
2613
          STORE_TLBCACHE_INFO(L2Unified, 1024);
2614
          break;
2615
        case 0x85:
2616
          STORE_TLBCACHE_INFO(L2Unified, 2048);
2617
          break;
2618
        case 0x88:
2619
          STORE_TLBCACHE_INFO(L3Unified, 2048);
2620
          break; // <-- FIXME: IA-64 Only
2621
        case 0x89:
2622
          STORE_TLBCACHE_INFO(L3Unified, 4096);
2623
          break; // <-- FIXME: IA-64 Only
2624
        case 0x8a:
2625
          STORE_TLBCACHE_INFO(L3Unified, 8192);
2626
          break; // <-- FIXME: IA-64 Only
2627
        case 0x8d:
2628
          STORE_TLBCACHE_INFO(L3Unified, 3096);
2629
          break; // <-- FIXME: IA-64 Only
2630
        case 0x90:
2631
          STORE_TLBCACHE_INFO(TLBCode, 262144);
2632
          break; // <-- FIXME: IA-64 Only
2633
        case 0x96:
2634
          STORE_TLBCACHE_INFO(TLBCode, 262144);
2635
          break; // <-- FIXME: IA-64 Only
2636
        case 0x9b:
2637
          STORE_TLBCACHE_INFO(TLBCode, 262144);
2638
          break; // <-- FIXME: IA-64 Only
2639
2640
        // Default case - an error has occurred.
2641
        default:
2642
          return false;
2643
      }
2644
    }
2645
2646
    // Increment the TLB pass counter.
2647
    TLBPassCounter++;
2648
  } while ((TLBCacheData[0] & 0x000000FF) > TLBPassCounter);
2649
2650
  // Ok - we now have the maximum TLB, L1, L2, and L3 sizes...
2651
  if ((L1Code == -1) && (L1Data == -1) && (L1Trace == -1)) {
2652
    this->Features.L1CacheSize = -1;
2653
  } else if ((L1Code == -1) && (L1Data == -1) && (L1Trace != -1)) {
2654
    this->Features.L1CacheSize = L1Trace;
2655
  } else if ((L1Code != -1) && (L1Data == -1)) {
2656
    this->Features.L1CacheSize = L1Code;
2657
  } else if ((L1Code == -1) && (L1Data != -1)) {
2658
    this->Features.L1CacheSize = L1Data;
2659
  } else if ((L1Code != -1) && (L1Data != -1)) {
2660
    this->Features.L1CacheSize = L1Code + L1Data;
2661
  } else {
2662
    this->Features.L1CacheSize = -1;
2663
  }
2664
2665
  // Ok - we now have the maximum TLB, L1, L2, and L3 sizes...
2666
  if (L2Unified == -1) {
2667
    this->Features.L2CacheSize = -1;
2668
  } else {
2669
    this->Features.L2CacheSize = L2Unified;
2670
  }
2671
2672
  // Ok - we now have the maximum TLB, L1, L2, and L3 sizes...
2673
  if (L3Unified == -1) {
2674
    this->Features.L3CacheSize = -1;
2675
  } else {
2676
    this->Features.L3CacheSize = L3Unified;
2677
  }
2678
2679
  return true;
2680
2681
#else
2682
0
  return false;
2683
0
#endif
2684
0
}
2685
2686
#if defined(_WIN32)
2687
typedef struct _PROCESSOR_POWER_INFORMATION
2688
{
2689
  ULONG Number;
2690
  ULONG MaxMhz;
2691
  ULONG CurrentMhz;
2692
  ULONG MhzLimit;
2693
  ULONG MaxIdleState;
2694
  ULONG CurrentIdleState;
2695
} PROCESSOR_POWER_INFORMATION, *PPROCESSOR_POWER_INFORMATION;
2696
2697
#  ifndef ALL_PROCESSOR_GROUPS
2698
#    define ALL_PROCESSOR_GROUPS 0xffff
2699
#  endif
2700
2701
#  ifndef STATUS_BUFFER_TOO_SMALL
2702
#    define STATUS_BUFFER_TOO_SMALL ((NTSTATUS)0xC0000023L)
2703
#  endif
2704
#endif
2705
2706
/** */
2707
bool SystemInformationImplementation::RetrieveCPUClockSpeed()
2708
0
{
2709
0
  bool retrieved = false;
2710
2711
#if defined(_WIN32)
2712
#  if KWSYS_CPUID_FREQ
2713
  // Prefer CPUID leaf 0x16 base frequency; fall back to the OS max clock.
2714
  {
2715
    float const baseMHz = kwsysCpuidBaseFrequencyMHz();
2716
    if (baseMHz > 0.0f) {
2717
      this->CPUSpeedInMHz = baseMHz;
2718
      return true;
2719
    }
2720
  }
2721
#  endif
2722
  // CallNtPowerInformation writes one record per logical processor; a
2723
  // fixed 64-entry buffer overflows across multiple processor groups.
2724
  using GetMaximumProcessorCountType = DWORD(WINAPI*)(WORD);
2725
  static GetMaximumProcessorCountType pGetMaximumProcessorCount =
2726
    reinterpret_cast<GetMaximumProcessorCountType>((void*)GetProcAddress(
2727
      GetModuleHandleW(L"kernel32"), "GetMaximumProcessorCount"));
2728
2729
  // GetMaximumProcessorCount() needs Windows 7+; older systems cap at 64.
2730
  DWORD processorCount = 64;
2731
  if (pGetMaximumProcessorCount) {
2732
    DWORD const maxProcessorCount =
2733
      pGetMaximumProcessorCount(ALL_PROCESSOR_GROUPS);
2734
    if (maxProcessorCount > 0) {
2735
      processorCount = maxProcessorCount;
2736
    }
2737
  }
2738
2739
  std::vector<PROCESSOR_POWER_INFORMATION> powerInfo(processorCount);
2740
  NTSTATUS status = STATUS_BUFFER_TOO_SMALL;
2741
  // Grow and retry if the estimate was too small (e.g. CPU hot-add).
2742
  for (int attempt = 0; attempt < 4 && status == STATUS_BUFFER_TOO_SMALL;
2743
       ++attempt) {
2744
    status = CallNtPowerInformation(
2745
      ProcessorInformation, nullptr, 0, powerInfo.data(),
2746
      static_cast<ULONG>(sizeof(PROCESSOR_POWER_INFORMATION) *
2747
                         powerInfo.size()));
2748
    if (status == STATUS_BUFFER_TOO_SMALL) {
2749
      powerInfo.resize(powerInfo.size() * 2);
2750
    }
2751
  }
2752
2753
  if (status == 0 && !powerInfo.empty()) {
2754
    this->CPUSpeedInMHz = (float)powerInfo[0].MaxMhz;
2755
    retrieved = true;
2756
  }
2757
2758
  if (!retrieved) {
2759
    unsigned int uiRepetitions = 1;
2760
    unsigned int uiMSecPerRepetition = 50;
2761
    __int64 i64Total = 0;
2762
    __int64 i64Overhead = 0;
2763
2764
    // Check if the TSC implementation works at all
2765
    if (this->Features.HasTSC &&
2766
        GetCyclesDifference(SystemInformationImplementation::Delay,
2767
                            uiMSecPerRepetition) > 0) {
2768
      for (unsigned int nCounter = 0; nCounter < uiRepetitions; nCounter++) {
2769
        i64Total += GetCyclesDifference(SystemInformationImplementation::Delay,
2770
                                        uiMSecPerRepetition);
2771
        i64Overhead += GetCyclesDifference(
2772
          SystemInformationImplementation::DelayOverhead, uiMSecPerRepetition);
2773
      }
2774
2775
      // Calculate the MHz speed.
2776
      i64Total -= i64Overhead;
2777
      i64Total /= uiRepetitions;
2778
      i64Total /= uiMSecPerRepetition;
2779
      i64Total /= 1000;
2780
2781
      // Save the CPU speed.
2782
      this->CPUSpeedInMHz = (float)i64Total;
2783
      retrieved = true;
2784
    }
2785
  }
2786
2787
  // If RDTSC is not supported, we fallback to trying to read this value
2788
  // from the registry:
2789
  if (!retrieved) {
2790
    HKEY hKey = nullptr;
2791
    LONG err =
2792
      RegOpenKeyExW(HKEY_LOCAL_MACHINE,
2793
                    L"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0", 0,
2794
                    KEY_READ, &hKey);
2795
2796
    if (ERROR_SUCCESS == err) {
2797
      DWORD dwType = 0;
2798
      DWORD data = 0;
2799
      DWORD dwSize = sizeof(DWORD);
2800
2801
      err =
2802
        RegQueryValueExW(hKey, L"~MHz", 0, &dwType, (LPBYTE)&data, &dwSize);
2803
2804
      if (ERROR_SUCCESS == err) {
2805
        this->CPUSpeedInMHz = (float)data;
2806
        retrieved = true;
2807
      }
2808
2809
      RegCloseKey(hKey);
2810
      hKey = nullptr;
2811
    }
2812
  }
2813
#endif
2814
2815
0
  return retrieved;
2816
0
}
2817
2818
/** */
2819
bool SystemInformationImplementation::RetrieveClassicalCPUClockSpeed()
2820
0
{
2821
#if USE_ASM_INSTRUCTIONS
2822
  LARGE_INTEGER liStart, liEnd, liCountsPerSecond;
2823
  double dFrequency, dDifference;
2824
2825
  // Attempt to get a starting tick count.
2826
  QueryPerformanceCounter(&liStart);
2827
2828
  __try {
2829
    _asm {
2830
      mov eax, 0x80000000
2831
      mov ebx, CLASSICAL_CPU_FREQ_LOOP
2832
      Timer_Loop:
2833
      bsf ecx,eax
2834
      dec ebx
2835
      jnz Timer_Loop
2836
    }
2837
  } __except (1) {
2838
    return false;
2839
  }
2840
2841
  // Attempt to get a starting tick count.
2842
  QueryPerformanceCounter(&liEnd);
2843
2844
  // Get the difference...  NB: This is in seconds....
2845
  QueryPerformanceFrequency(&liCountsPerSecond);
2846
  dDifference = (((double)liEnd.QuadPart - (double)liStart.QuadPart) /
2847
                 (double)liCountsPerSecond.QuadPart);
2848
2849
  // Calculate the clock speed.
2850
  if (this->ChipID.Family == 3) {
2851
    // 80386 processors....  Loop time is 115 cycles!
2852
    dFrequency = (((CLASSICAL_CPU_FREQ_LOOP * 115) / dDifference) / 1000000);
2853
  } else if (this->ChipID.Family == 4) {
2854
    // 80486 processors....  Loop time is 47 cycles!
2855
    dFrequency = (((CLASSICAL_CPU_FREQ_LOOP * 47) / dDifference) / 1000000);
2856
  } else if (this->ChipID.Family == 5) {
2857
    // Pentium processors....  Loop time is 43 cycles!
2858
    dFrequency = (((CLASSICAL_CPU_FREQ_LOOP * 43) / dDifference) / 1000000);
2859
  }
2860
2861
  // Save the clock speed.
2862
  this->Features.CPUSpeed = (int)dFrequency;
2863
2864
  return true;
2865
2866
#else
2867
0
  return false;
2868
0
#endif
2869
0
}
2870
2871
/** */
2872
bool SystemInformationImplementation::RetrieveCPUExtendedLevelSupport(
2873
  int CPULevelToCheck)
2874
0
{
2875
0
  int cpuinfo[4] = { 0, 0, 0, 0 };
2876
2877
  // The extended CPUID is supported by various vendors starting with the
2878
  // following CPU models:
2879
  //
2880
  //    Manufacturer & Chip Name      |    Family     Model    Revision
2881
  //
2882
  //    AMD K6, K6-2                  |       5       6      x
2883
  //    Cyrix GXm, Cyrix III "Joshua" |       5       4      x
2884
  //    IDT C6-2                      |       5       8      x
2885
  //    VIA Cyrix III                 |       6       5      x
2886
  //    Transmeta Crusoe              |       5       x      x
2887
  //    Intel Pentium 4               |       f       x      x
2888
  //
2889
2890
  // We check to see if a supported processor is present...
2891
0
  if (this->ChipManufacturer == AMD) {
2892
0
    if (this->ChipID.Family < 5)
2893
0
      return false;
2894
0
    if ((this->ChipID.Family == 5) && (this->ChipID.Model < 6))
2895
0
      return false;
2896
0
  } else if (this->ChipManufacturer == Cyrix) {
2897
0
    if (this->ChipID.Family < 5)
2898
0
      return false;
2899
0
    if ((this->ChipID.Family == 5) && (this->ChipID.Model < 4))
2900
0
      return false;
2901
0
    if ((this->ChipID.Family == 6) && (this->ChipID.Model < 5))
2902
0
      return false;
2903
0
  } else if (this->ChipManufacturer == IDT) {
2904
0
    if (this->ChipID.Family < 5)
2905
0
      return false;
2906
0
    if ((this->ChipID.Family == 5) && (this->ChipID.Model < 8))
2907
0
      return false;
2908
0
  } else if (this->ChipManufacturer == Transmeta) {
2909
0
    if (this->ChipID.Family < 5)
2910
0
      return false;
2911
0
  } else if (this->ChipManufacturer == Intel) {
2912
0
    if (this->ChipID.Family < 0xf) {
2913
0
      return false;
2914
0
    }
2915
0
  }
2916
2917
#if USE_CPUID
2918
  if (!call_cpuid(0x80000000, cpuinfo)) {
2919
    return false;
2920
  }
2921
#endif
2922
2923
  // Now we have to check the level wanted vs level returned...
2924
0
  int nLevelWanted = (CPULevelToCheck & 0x7FFFFFFF);
2925
0
  int nLevelReturn = (cpuinfo[0] & 0x7FFFFFFF);
2926
2927
  // Check to see if the level provided is supported...
2928
0
  if (nLevelWanted > nLevelReturn) {
2929
0
    return false;
2930
0
  }
2931
2932
0
  return true;
2933
0
}
2934
2935
/** */
2936
bool SystemInformationImplementation::RetrieveExtendedCPUFeatures()
2937
0
{
2938
2939
  // Check that we are not using an Intel processor as it does not support
2940
  // this.
2941
0
  if (this->ChipManufacturer == Intel) {
2942
0
    return false;
2943
0
  }
2944
2945
  // Check to see if what we are about to do is supported...
2946
0
  if (!RetrieveCPUExtendedLevelSupport(static_cast<int>(0x80000001))) {
2947
0
    return false;
2948
0
  }
2949
2950
#if USE_CPUID
2951
  int localCPUExtendedFeatures[4] = { 0, 0, 0, 0 };
2952
2953
  if (!call_cpuid(0x80000001, localCPUExtendedFeatures)) {
2954
    return false;
2955
  }
2956
2957
  // Retrieve the extended features of CPU present.
2958
  this->Features.ExtendedFeatures.Has3DNow =
2959
    ((localCPUExtendedFeatures[3] & 0x80000000) !=
2960
     0); // 3DNow Present --> Bit 31.
2961
  this->Features.ExtendedFeatures.Has3DNowPlus =
2962
    ((localCPUExtendedFeatures[3] & 0x40000000) !=
2963
     0); // 3DNow+ Present -- > Bit 30.
2964
  this->Features.ExtendedFeatures.HasSSEMMX =
2965
    ((localCPUExtendedFeatures[3] & 0x00400000) !=
2966
     0); // SSE MMX Present --> Bit 22.
2967
  this->Features.ExtendedFeatures.SupportsMP =
2968
    ((localCPUExtendedFeatures[3] & 0x00080000) !=
2969
     0); // MP Capable -- > Bit 19.
2970
2971
  // Retrieve AMD specific extended features.
2972
  if (this->ChipManufacturer == AMD || this->ChipManufacturer == Hygon) {
2973
    this->Features.ExtendedFeatures.HasMMXPlus =
2974
      ((localCPUExtendedFeatures[3] & 0x00400000) !=
2975
       0); // AMD specific: MMX-SSE --> Bit 22
2976
  }
2977
2978
  // Retrieve Cyrix specific extended features.
2979
  if (this->ChipManufacturer == Cyrix) {
2980
    this->Features.ExtendedFeatures.HasMMXPlus =
2981
      ((localCPUExtendedFeatures[3] & 0x01000000) !=
2982
       0); // Cyrix specific: Extended MMX --> Bit 24
2983
  }
2984
2985
  return true;
2986
2987
#else
2988
0
  return false;
2989
0
#endif
2990
0
}
2991
2992
/** */
2993
bool SystemInformationImplementation::RetrieveProcessorSerialNumber()
2994
0
{
2995
  // Check to see if the processor supports the processor serial number.
2996
0
  if (!this->Features.HasSerial) {
2997
0
    return false;
2998
0
  }
2999
3000
#if USE_CPUID
3001
  int SerialNumber[4];
3002
3003
  if (!call_cpuid(3, SerialNumber)) {
3004
    return false;
3005
  }
3006
3007
  // Process the returned information.
3008
  //    ; eax = 3 --> ebx: top 32 bits are the processor signature bits --> NB:
3009
  //    Transmeta only ?!?
3010
  //    ;        ecx: middle 32 bits are the processor signature bits
3011
  //    ;        edx: bottom 32 bits are the processor signature bits
3012
  char sn[128];
3013
  snprintf(sn, sizeof(sn),
3014
           "%.2x%.2x-%.2x%.2x-%.2x%.2x-%.2x%.2x-%.2x%.2x-%.2x%.2x",
3015
           ((SerialNumber[1] & 0xff000000) >> 24),
3016
           ((SerialNumber[1] & 0x00ff0000) >> 16),
3017
           ((SerialNumber[1] & 0x0000ff00) >> 8),
3018
           ((SerialNumber[1] & 0x000000ff) >> 0),
3019
           ((SerialNumber[2] & 0xff000000) >> 24),
3020
           ((SerialNumber[2] & 0x00ff0000) >> 16),
3021
           ((SerialNumber[2] & 0x0000ff00) >> 8),
3022
           ((SerialNumber[2] & 0x000000ff) >> 0),
3023
           ((SerialNumber[3] & 0xff000000) >> 24),
3024
           ((SerialNumber[3] & 0x00ff0000) >> 16),
3025
           ((SerialNumber[3] & 0x0000ff00) >> 8),
3026
           ((SerialNumber[3] & 0x000000ff) >> 0));
3027
  this->ChipID.SerialNumber = sn;
3028
  return true;
3029
3030
#else
3031
0
  return false;
3032
0
#endif
3033
0
}
3034
3035
/** */
3036
bool SystemInformationImplementation::RetrieveCPUPowerManagement()
3037
0
{
3038
  // Check to see if what we are about to do is supported...
3039
0
  if (!RetrieveCPUExtendedLevelSupport(static_cast<int>(0x80000007))) {
3040
0
    this->Features.ExtendedFeatures.PowerManagement.HasFrequencyID = false;
3041
0
    this->Features.ExtendedFeatures.PowerManagement.HasVoltageID = false;
3042
0
    this->Features.ExtendedFeatures.PowerManagement.HasTempSenseDiode = false;
3043
0
    return false;
3044
0
  }
3045
3046
#if USE_CPUID
3047
  int localCPUPowerManagement[4] = { 0, 0, 0, 0 };
3048
3049
  if (!call_cpuid(0x80000007, localCPUPowerManagement)) {
3050
    return false;
3051
  }
3052
3053
  // Check for the power management capabilities of the CPU.
3054
  this->Features.ExtendedFeatures.PowerManagement.HasTempSenseDiode =
3055
    ((localCPUPowerManagement[3] & 0x00000001) != 0);
3056
  this->Features.ExtendedFeatures.PowerManagement.HasFrequencyID =
3057
    ((localCPUPowerManagement[3] & 0x00000002) != 0);
3058
  this->Features.ExtendedFeatures.PowerManagement.HasVoltageID =
3059
    ((localCPUPowerManagement[3] & 0x00000004) != 0);
3060
3061
  return true;
3062
3063
#else
3064
0
  return false;
3065
0
#endif
3066
0
}
3067
3068
#if USE_CPUID
3069
// Used only in USE_CPUID implementation below.
3070
static void SystemInformationTrimSpace(std::string& s)
3071
{
3072
  // Because some manufacturers have leading and/or trailing white space,
3073
  // we have to post-process the name.
3074
  auto const not_space = [](char c) { return c != ' '; };
3075
  s.erase(s.begin(), std::find_if(s.begin(), s.end(), not_space));
3076
  s.erase(std::find_if(s.rbegin(), s.rend(), not_space).base(), s.end());
3077
}
3078
#endif
3079
3080
/** */
3081
bool SystemInformationImplementation::RetrieveExtendedCPUIdentity()
3082
0
{
3083
  // Check to see if what we are about to do is supported...
3084
0
  if (!RetrieveCPUExtendedLevelSupport(static_cast<int>(0x80000002)))
3085
0
    return false;
3086
0
  if (!RetrieveCPUExtendedLevelSupport(static_cast<int>(0x80000003)))
3087
0
    return false;
3088
0
  if (!RetrieveCPUExtendedLevelSupport(static_cast<int>(0x80000004)))
3089
0
    return false;
3090
3091
#if USE_CPUID
3092
  int CPUExtendedIdentity[12];
3093
3094
  if (!call_cpuid(0x80000002, CPUExtendedIdentity)) {
3095
    return false;
3096
  }
3097
  if (!call_cpuid(0x80000003, CPUExtendedIdentity + 4)) {
3098
    return false;
3099
  }
3100
  if (!call_cpuid(0x80000004, CPUExtendedIdentity + 8)) {
3101
    return false;
3102
  }
3103
3104
  // Process the returned information.
3105
  char nbuf[49];
3106
  memcpy(&(nbuf[0]), &(CPUExtendedIdentity[0]), sizeof(int));
3107
  memcpy(&(nbuf[4]), &(CPUExtendedIdentity[1]), sizeof(int));
3108
  memcpy(&(nbuf[8]), &(CPUExtendedIdentity[2]), sizeof(int));
3109
  memcpy(&(nbuf[12]), &(CPUExtendedIdentity[3]), sizeof(int));
3110
  memcpy(&(nbuf[16]), &(CPUExtendedIdentity[4]), sizeof(int));
3111
  memcpy(&(nbuf[20]), &(CPUExtendedIdentity[5]), sizeof(int));
3112
  memcpy(&(nbuf[24]), &(CPUExtendedIdentity[6]), sizeof(int));
3113
  memcpy(&(nbuf[28]), &(CPUExtendedIdentity[7]), sizeof(int));
3114
  memcpy(&(nbuf[32]), &(CPUExtendedIdentity[8]), sizeof(int));
3115
  memcpy(&(nbuf[36]), &(CPUExtendedIdentity[9]), sizeof(int));
3116
  memcpy(&(nbuf[40]), &(CPUExtendedIdentity[10]), sizeof(int));
3117
  memcpy(&(nbuf[44]), &(CPUExtendedIdentity[11]), sizeof(int));
3118
  nbuf[48] = '\0';
3119
  this->ChipID.ProcessorName = nbuf;
3120
  this->ChipID.ModelName = nbuf;
3121
3122
  // Because some manufacturers have leading and/or trailing white space,
3123
  // we have to post-process the names.
3124
  SystemInformationTrimSpace(this->ChipID.ProcessorName);
3125
  SystemInformationTrimSpace(this->ChipID.ModelName);
3126
  return true;
3127
#else
3128
0
  return false;
3129
0
#endif
3130
0
}
3131
3132
/** */
3133
bool SystemInformationImplementation::RetrieveClassicalCPUIdentity()
3134
0
{
3135
  // Start by decided which manufacturer we are using....
3136
0
  switch (this->ChipManufacturer) {
3137
0
    case Intel:
3138
      // Check the family / model / revision to determine the CPU ID.
3139
0
      switch (this->ChipID.Family) {
3140
0
        case 3:
3141
0
          this->ChipID.ProcessorName = "Newer i80386 family";
3142
0
          break;
3143
0
        case 4:
3144
0
          switch (this->ChipID.Model) {
3145
0
            case 0:
3146
0
              this->ChipID.ProcessorName = "i80486DX-25/33";
3147
0
              break;
3148
0
            case 1:
3149
0
              this->ChipID.ProcessorName = "i80486DX-50";
3150
0
              break;
3151
0
            case 2:
3152
0
              this->ChipID.ProcessorName = "i80486SX";
3153
0
              break;
3154
0
            case 3:
3155
0
              this->ChipID.ProcessorName = "i80486DX2";
3156
0
              break;
3157
0
            case 4:
3158
0
              this->ChipID.ProcessorName = "i80486SL";
3159
0
              break;
3160
0
            case 5:
3161
0
              this->ChipID.ProcessorName = "i80486SX2";
3162
0
              break;
3163
0
            case 7:
3164
0
              this->ChipID.ProcessorName = "i80486DX2 WriteBack";
3165
0
              break;
3166
0
            case 8:
3167
0
              this->ChipID.ProcessorName = "i80486DX4";
3168
0
              break;
3169
0
            case 9:
3170
0
              this->ChipID.ProcessorName = "i80486DX4 WriteBack";
3171
0
              break;
3172
0
            default:
3173
0
              this->ChipID.ProcessorName = "Unknown 80486 family";
3174
0
              return false;
3175
0
          }
3176
0
          break;
3177
0
        case 5:
3178
0
          switch (this->ChipID.Model) {
3179
0
            case 0:
3180
0
              this->ChipID.ProcessorName = "P5 A-Step";
3181
0
              break;
3182
0
            case 1:
3183
0
              this->ChipID.ProcessorName = "P5";
3184
0
              break;
3185
0
            case 2:
3186
0
              this->ChipID.ProcessorName = "P54C";
3187
0
              break;
3188
0
            case 3:
3189
0
              this->ChipID.ProcessorName = "P24T OverDrive";
3190
0
              break;
3191
0
            case 4:
3192
0
              this->ChipID.ProcessorName = "P55C";
3193
0
              break;
3194
0
            case 7:
3195
0
              this->ChipID.ProcessorName = "P54C";
3196
0
              break;
3197
0
            case 8:
3198
0
              this->ChipID.ProcessorName = "P55C (0.25micron)";
3199
0
              break;
3200
0
            default:
3201
0
              this->ChipID.ProcessorName = "Unknown Pentium family";
3202
0
              return false;
3203
0
          }
3204
0
          break;
3205
0
        case 6:
3206
0
          switch (this->ChipID.Model) {
3207
0
            case 0:
3208
0
              this->ChipID.ProcessorName = "P6 A-Step";
3209
0
              break;
3210
0
            case 1:
3211
0
              this->ChipID.ProcessorName = "P6";
3212
0
              break;
3213
0
            case 3:
3214
0
              this->ChipID.ProcessorName = "Pentium II (0.28 micron)";
3215
0
              break;
3216
0
            case 5:
3217
0
              this->ChipID.ProcessorName = "Pentium II (0.25 micron)";
3218
0
              break;
3219
0
            case 6:
3220
0
              this->ChipID.ProcessorName = "Pentium II With On-Die L2 Cache";
3221
0
              break;
3222
0
            case 7:
3223
0
              this->ChipID.ProcessorName = "Pentium III (0.25 micron)";
3224
0
              break;
3225
0
            case 8:
3226
0
              this->ChipID.ProcessorName =
3227
0
                "Pentium III (0.18 micron) With 256 KB On-Die L2 Cache ";
3228
0
              break;
3229
0
            case 0xa:
3230
0
              this->ChipID.ProcessorName =
3231
0
                "Pentium III (0.18 micron) With 1 Or 2 MB On-Die L2 Cache ";
3232
0
              break;
3233
0
            case 0xb:
3234
0
              this->ChipID.ProcessorName = "Pentium III (0.13 micron) With "
3235
0
                                           "256 Or 512 KB On-Die L2 Cache ";
3236
0
              break;
3237
0
            case 23:
3238
0
              this->ChipID.ProcessorName =
3239
0
                "Intel(R) Core(TM)2 Duo CPU     T9500  @ 2.60GHz";
3240
0
              break;
3241
0
            default:
3242
0
              this->ChipID.ProcessorName = "Unknown P6 family";
3243
0
              return false;
3244
0
          }
3245
0
          break;
3246
0
        case 7:
3247
0
          this->ChipID.ProcessorName = "Intel Merced (IA-64)";
3248
0
          break;
3249
0
        case 0xf:
3250
          // Check the extended family bits...
3251
0
          switch (this->ChipID.ExtendedFamily) {
3252
0
            case 0:
3253
0
              switch (this->ChipID.Model) {
3254
0
                case 0:
3255
0
                  this->ChipID.ProcessorName = "Pentium IV (0.18 micron)";
3256
0
                  break;
3257
0
                case 1:
3258
0
                  this->ChipID.ProcessorName = "Pentium IV (0.18 micron)";
3259
0
                  break;
3260
0
                case 2:
3261
0
                  this->ChipID.ProcessorName = "Pentium IV (0.13 micron)";
3262
0
                  break;
3263
0
                default:
3264
0
                  this->ChipID.ProcessorName = "Unknown Pentium 4 family";
3265
0
                  return false;
3266
0
              }
3267
0
              break;
3268
0
            case 1:
3269
0
              this->ChipID.ProcessorName = "Intel McKinley (IA-64)";
3270
0
              break;
3271
0
            default:
3272
0
              this->ChipID.ProcessorName = "Pentium";
3273
0
          }
3274
0
          break;
3275
0
        default:
3276
0
          this->ChipID.ProcessorName = "Unknown Intel family";
3277
0
          return false;
3278
0
      }
3279
0
      break;
3280
3281
0
    case AMD:
3282
      // Check the family / model / revision to determine the CPU ID.
3283
0
      switch (this->ChipID.Family) {
3284
0
        case 4:
3285
0
          switch (this->ChipID.Model) {
3286
0
            case 3:
3287
0
              this->ChipID.ProcessorName = "80486DX2";
3288
0
              break;
3289
0
            case 7:
3290
0
              this->ChipID.ProcessorName = "80486DX2 WriteBack";
3291
0
              break;
3292
0
            case 8:
3293
0
              this->ChipID.ProcessorName = "80486DX4";
3294
0
              break;
3295
0
            case 9:
3296
0
              this->ChipID.ProcessorName = "80486DX4 WriteBack";
3297
0
              break;
3298
0
            case 0xe:
3299
0
              this->ChipID.ProcessorName = "5x86";
3300
0
              break;
3301
0
            case 0xf:
3302
0
              this->ChipID.ProcessorName = "5x86WB";
3303
0
              break;
3304
0
            default:
3305
0
              this->ChipID.ProcessorName = "Unknown 80486 family";
3306
0
              return false;
3307
0
          }
3308
0
          break;
3309
0
        case 5:
3310
0
          switch (this->ChipID.Model) {
3311
0
            case 0:
3312
0
              this->ChipID.ProcessorName = "SSA5 (PR75, PR90 =  PR100)";
3313
0
              break;
3314
0
            case 1:
3315
0
              this->ChipID.ProcessorName = "5k86 (PR120 =  PR133)";
3316
0
              break;
3317
0
            case 2:
3318
0
              this->ChipID.ProcessorName = "5k86 (PR166)";
3319
0
              break;
3320
0
            case 3:
3321
0
              this->ChipID.ProcessorName = "5k86 (PR200)";
3322
0
              break;
3323
0
            case 6:
3324
0
              this->ChipID.ProcessorName = "K6 (0.30 micron)";
3325
0
              break;
3326
0
            case 7:
3327
0
              this->ChipID.ProcessorName = "K6 (0.25 micron)";
3328
0
              break;
3329
0
            case 8:
3330
0
              this->ChipID.ProcessorName = "K6-2";
3331
0
              break;
3332
0
            case 9:
3333
0
              this->ChipID.ProcessorName = "K6-III";
3334
0
              break;
3335
0
            case 0xd:
3336
0
              this->ChipID.ProcessorName = "K6-2+ or K6-III+ (0.18 micron)";
3337
0
              break;
3338
0
            default:
3339
0
              this->ChipID.ProcessorName = "Unknown 80586 family";
3340
0
              return false;
3341
0
          }
3342
0
          break;
3343
0
        case 6:
3344
0
          switch (this->ChipID.Model) {
3345
0
            case 1:
3346
0
              this->ChipID.ProcessorName = "Athlon- (0.25 micron)";
3347
0
              break;
3348
0
            case 2:
3349
0
              this->ChipID.ProcessorName = "Athlon- (0.18 micron)";
3350
0
              break;
3351
0
            case 3:
3352
0
              this->ChipID.ProcessorName = "Duron- (SF core)";
3353
0
              break;
3354
0
            case 4:
3355
0
              this->ChipID.ProcessorName = "Athlon- (Thunderbird core)";
3356
0
              break;
3357
0
            case 6:
3358
0
              this->ChipID.ProcessorName = "Athlon- (Palomino core)";
3359
0
              break;
3360
0
            case 7:
3361
0
              this->ChipID.ProcessorName = "Duron- (Morgan core)";
3362
0
              break;
3363
0
            case 8:
3364
0
              if (this->Features.ExtendedFeatures.SupportsMP)
3365
0
                this->ChipID.ProcessorName = "Athlon - MP (Thoroughbred core)";
3366
0
              else
3367
0
                this->ChipID.ProcessorName = "Athlon - XP (Thoroughbred core)";
3368
0
              break;
3369
0
            default:
3370
0
              this->ChipID.ProcessorName = "Unknown K7 family";
3371
0
              return false;
3372
0
          }
3373
0
          break;
3374
0
        default:
3375
0
          this->ChipID.ProcessorName = "Unknown AMD family";
3376
0
          return false;
3377
0
      }
3378
0
      break;
3379
3380
0
    case Hygon:
3381
0
      this->ChipID.ProcessorName = "Unknown Hygon family";
3382
0
      return false;
3383
3384
0
    case Transmeta:
3385
0
      switch (this->ChipID.Family) {
3386
0
        case 5:
3387
0
          switch (this->ChipID.Model) {
3388
0
            case 4:
3389
0
              this->ChipID.ProcessorName = "Crusoe TM3x00 and TM5x00";
3390
0
              break;
3391
0
            default:
3392
0
              this->ChipID.ProcessorName = "Unknown Crusoe family";
3393
0
              return false;
3394
0
          }
3395
0
          break;
3396
0
        default:
3397
0
          this->ChipID.ProcessorName = "Unknown Transmeta family";
3398
0
          return false;
3399
0
      }
3400
0
      break;
3401
3402
0
    case Rise:
3403
0
      switch (this->ChipID.Family) {
3404
0
        case 5:
3405
0
          switch (this->ChipID.Model) {
3406
0
            case 0:
3407
0
              this->ChipID.ProcessorName = "mP6 (0.25 micron)";
3408
0
              break;
3409
0
            case 2:
3410
0
              this->ChipID.ProcessorName = "mP6 (0.18 micron)";
3411
0
              break;
3412
0
            default:
3413
0
              this->ChipID.ProcessorName = "Unknown Rise family";
3414
0
              return false;
3415
0
          }
3416
0
          break;
3417
0
        default:
3418
0
          this->ChipID.ProcessorName = "Unknown Rise family";
3419
0
          return false;
3420
0
      }
3421
0
      break;
3422
3423
0
    case UMC:
3424
0
      switch (this->ChipID.Family) {
3425
0
        case 4:
3426
0
          switch (this->ChipID.Model) {
3427
0
            case 1:
3428
0
              this->ChipID.ProcessorName = "U5D";
3429
0
              break;
3430
0
            case 2:
3431
0
              this->ChipID.ProcessorName = "U5S";
3432
0
              break;
3433
0
            default:
3434
0
              this->ChipID.ProcessorName = "Unknown UMC family";
3435
0
              return false;
3436
0
          }
3437
0
          break;
3438
0
        default:
3439
0
          this->ChipID.ProcessorName = "Unknown UMC family";
3440
0
          return false;
3441
0
      }
3442
0
      break;
3443
3444
0
    case IDT:
3445
0
      switch (this->ChipID.Family) {
3446
0
        case 5:
3447
0
          switch (this->ChipID.Model) {
3448
0
            case 4:
3449
0
              this->ChipID.ProcessorName = "C6";
3450
0
              break;
3451
0
            case 8:
3452
0
              this->ChipID.ProcessorName = "C2";
3453
0
              break;
3454
0
            case 9:
3455
0
              this->ChipID.ProcessorName = "C3";
3456
0
              break;
3457
0
            default:
3458
0
              this->ChipID.ProcessorName =
3459
0
                "Unknown IDT\\Centaur\\VIA\\Zhaoxin family";
3460
0
              return false;
3461
0
          }
3462
0
          break;
3463
0
        case 6:
3464
0
          switch (this->ChipID.Model) {
3465
0
            case 6:
3466
0
              this->ChipID.ProcessorName = "VIA Cyrix III - Samuel";
3467
0
              break;
3468
0
            case 0xf:
3469
0
              this->ChipID.ProcessorName = "Zhaoxin zxc";
3470
0
              break;
3471
0
            default:
3472
0
              this->ChipID.ProcessorName =
3473
0
                "Unknown IDT\\Centaur\\VIA\\Zhaoxin family";
3474
0
              return false;
3475
0
          }
3476
0
          break;
3477
0
        case 7:
3478
0
          switch (this->ChipID.Model) {
3479
0
            case 0x1b:
3480
0
              this->ChipID.ProcessorName = "Zhaoxin kx5000";
3481
0
              break;
3482
0
            case 0x3b:
3483
0
              this->ChipID.ProcessorName = "Zhaoxin kx6000";
3484
0
              break;
3485
0
            case 0x5b:
3486
0
              this->ChipID.ProcessorName = "Zhaoxin kh40000";
3487
0
              break;
3488
0
            default:
3489
0
              this->ChipID.ProcessorName =
3490
0
                "Unknown IDT\\Centaur\\VIA\\Zhaoxin family";
3491
0
              return false;
3492
0
          }
3493
0
          break;
3494
0
        default:
3495
0
          this->ChipID.ProcessorName =
3496
0
            "Unknown IDT\\Centaur\\VIA\\Zhaoxin family";
3497
0
          return false;
3498
0
      }
3499
0
      break;
3500
3501
0
    case Zhaoxin:
3502
0
      switch (this->ChipID.Family) {
3503
0
        case 6:
3504
0
          switch (this->ChipID.Model) {
3505
0
            case 0x19:
3506
0
              this->ChipID.ProcessorName = "Zhaoxin zxc";
3507
0
              break;
3508
0
            default:
3509
0
              this->ChipID.ProcessorName = "Unknown Zhaoxin family";
3510
0
              return false;
3511
0
          }
3512
0
          break;
3513
0
        case 7:
3514
0
          switch (this->ChipID.Model) {
3515
0
            case 0x1b:
3516
0
              this->ChipID.ProcessorName = "Zhaoxin kx5000";
3517
0
              break;
3518
0
            case 0x3b:
3519
0
              this->ChipID.ProcessorName = "Zhaoxin kx6000";
3520
0
              break;
3521
0
            case 0x5b:
3522
0
              this->ChipID.ProcessorName = "Zhaoxin kh40000";
3523
0
              break;
3524
0
            default:
3525
0
              this->ChipID.ProcessorName = "Unknown Zhaoxin family";
3526
0
              return false;
3527
0
          }
3528
0
          break;
3529
0
        default:
3530
0
          this->ChipID.ProcessorName = "Unknown Zhaoxin family";
3531
0
          return false;
3532
0
      }
3533
0
      break;
3534
3535
0
    case Cyrix:
3536
0
      switch (this->ChipID.Family) {
3537
0
        case 4:
3538
0
          switch (this->ChipID.Model) {
3539
0
            case 4:
3540
0
              this->ChipID.ProcessorName = "MediaGX GX =  GXm";
3541
0
              break;
3542
0
            case 9:
3543
0
              this->ChipID.ProcessorName = "5x86";
3544
0
              break;
3545
0
            default:
3546
0
              this->ChipID.ProcessorName = "Unknown Cx5x86 family";
3547
0
              return false;
3548
0
          }
3549
0
          break;
3550
0
        case 5:
3551
0
          switch (this->ChipID.Model) {
3552
0
            case 2:
3553
0
              this->ChipID.ProcessorName = "Cx6x86";
3554
0
              break;
3555
0
            case 4:
3556
0
              this->ChipID.ProcessorName = "MediaGX GXm";
3557
0
              break;
3558
0
            default:
3559
0
              this->ChipID.ProcessorName = "Unknown Cx6x86 family";
3560
0
              return false;
3561
0
          }
3562
0
          break;
3563
0
        case 6:
3564
0
          switch (this->ChipID.Model) {
3565
0
            case 0:
3566
0
              this->ChipID.ProcessorName = "6x86MX";
3567
0
              break;
3568
0
            case 5:
3569
0
              this->ChipID.ProcessorName = "Cyrix M2 Core";
3570
0
              break;
3571
0
            case 6:
3572
0
              this->ChipID.ProcessorName = "WinChip C5A Core";
3573
0
              break;
3574
0
            case 7:
3575
0
              this->ChipID.ProcessorName = "WinChip C5B\\C5C Core";
3576
0
              break;
3577
0
            case 8:
3578
0
              this->ChipID.ProcessorName = "WinChip C5C-T Core";
3579
0
              break;
3580
0
            default:
3581
0
              this->ChipID.ProcessorName = "Unknown 6x86MX\\Cyrix III family";
3582
0
              return false;
3583
0
          }
3584
0
          break;
3585
0
        default:
3586
0
          this->ChipID.ProcessorName = "Unknown Cyrix family";
3587
0
          return false;
3588
0
      }
3589
0
      break;
3590
3591
0
    case NexGen:
3592
0
      switch (this->ChipID.Family) {
3593
0
        case 5:
3594
0
          switch (this->ChipID.Model) {
3595
0
            case 0:
3596
0
              this->ChipID.ProcessorName = "Nx586 or Nx586FPU";
3597
0
              break;
3598
0
            default:
3599
0
              this->ChipID.ProcessorName = "Unknown NexGen family";
3600
0
              return false;
3601
0
          }
3602
0
          break;
3603
0
        default:
3604
0
          this->ChipID.ProcessorName = "Unknown NexGen family";
3605
0
          return false;
3606
0
      }
3607
0
      break;
3608
3609
0
    case NSC:
3610
0
      this->ChipID.ProcessorName = "Cx486SLC \\ DLC \\ Cx486S A-Step";
3611
0
      break;
3612
3613
0
    case Sun:
3614
0
    case IBM:
3615
0
    case Motorola:
3616
0
    case HP:
3617
0
    case UnknownManufacturer:
3618
0
    default:
3619
0
      this->ChipID.ProcessorName =
3620
0
        "Unknown family"; // We cannot identify the processor.
3621
0
      return false;
3622
0
  }
3623
3624
0
  return true;
3625
0
}
3626
3627
/** Extract a value from the CPUInfo file */
3628
std::string SystemInformationImplementation::ExtractValueFromCpuInfoFile(
3629
  std::string buffer, char const* word, size_t init)
3630
0
{
3631
0
  size_t pos = buffer.find(word, init);
3632
0
  if (pos != std::string::npos) {
3633
0
    this->CurrentPositionInFile = pos;
3634
0
    pos = buffer.find(':', pos);
3635
0
    size_t pos2 = buffer.find('\n', pos);
3636
0
    if (pos != std::string::npos && pos2 != std::string::npos) {
3637
      // It may happen that the beginning matches, but this is still not the
3638
      // requested key.
3639
      // An example is looking for "cpu" when "cpu family" comes first. So we
3640
      // check that
3641
      // we have only spaces from here to pos, otherwise we search again.
3642
0
      for (size_t i = this->CurrentPositionInFile + strlen(word); i < pos;
3643
0
           ++i) {
3644
0
        if (buffer[i] != ' ' && buffer[i] != '\t') {
3645
0
          return this->ExtractValueFromCpuInfoFile(buffer, word, pos2);
3646
0
        }
3647
0
      }
3648
0
      buffer.erase(0, pos + 2);
3649
0
      buffer.resize(pos2 - pos - 2);
3650
0
      return buffer;
3651
0
    }
3652
0
  }
3653
0
  this->CurrentPositionInFile = std::string::npos;
3654
0
  return "";
3655
0
}
3656
3657
/** Query for the cpu status */
3658
bool SystemInformationImplementation::RetrieveInformationFromCpuInfoFile()
3659
0
{
3660
0
  this->NumberOfLogicalCPU = 0;
3661
0
  this->NumberOfPhysicalCPU = 0;
3662
0
  std::string buffer;
3663
3664
0
  FILE* fd = fopen("/proc/cpuinfo", "r");
3665
0
  if (!fd) {
3666
0
    std::cerr << "Problem opening /proc/cpuinfo\n";
3667
0
    return false;
3668
0
  }
3669
3670
0
  size_t fileSize = 0;
3671
0
  int fc;
3672
0
  while ((fc = fgetc(fd)) != EOF) {
3673
0
    buffer += static_cast<char>(fc);
3674
0
    fileSize++;
3675
0
  }
3676
0
  fclose(fd);
3677
0
  if (fileSize < 2) {
3678
0
    std::cerr << "No data in /proc/cpuinfo\n";
3679
0
    return false;
3680
0
  }
3681
0
  buffer.resize(fileSize - 2);
3682
  // Number of logical CPUs (combination of multiple processors, multi-core
3683
  // and SMT)
3684
0
  char const* processor_string =
3685
#ifdef __s390x__
3686
    "cpu number";
3687
#else
3688
0
    "processor\t";
3689
0
#endif
3690
0
  size_t pos = buffer.find(processor_string);
3691
0
  while (pos != std::string::npos) {
3692
0
    this->NumberOfLogicalCPU++;
3693
0
    pos = buffer.find(processor_string, pos + 1);
3694
0
  }
3695
3696
0
#if defined(__linux) || defined(__CYGWIN__)
3697
  // Count sockets.
3698
0
  std::set<int> PhysicalIDs;
3699
0
  std::string idc = this->ExtractValueFromCpuInfoFile(buffer, "physical id");
3700
0
  while (this->CurrentPositionInFile != std::string::npos) {
3701
0
    int id = atoi(idc.c_str());
3702
0
    PhysicalIDs.insert(id);
3703
0
    idc = this->ExtractValueFromCpuInfoFile(buffer, "physical id",
3704
0
                                            this->CurrentPositionInFile + 1);
3705
0
  }
3706
0
  uint64_t NumberOfSockets = PhysicalIDs.size();
3707
  // Physical ids returned by Linux don't distinguish cores.
3708
  // We want to record the total number of cores in this->NumberOfPhysicalCPU
3709
  // (checking only the first proc)
3710
0
  std::string Cores = this->ExtractValueFromCpuInfoFile(buffer, "cpu cores");
3711
0
  if (Cores.empty()) {
3712
    // Linux Sparc is different
3713
0
    Cores = this->ExtractValueFromCpuInfoFile(buffer, "ncpus probed");
3714
0
  }
3715
0
  auto NumberOfCoresPerSocket = (unsigned int)atoi(Cores.c_str());
3716
  // If either one is 0, will be assigned with NumberOfLogicalCPU or 1 below.
3717
0
  if (NumberOfSockets > 0 && NumberOfCoresPerSocket > 0) {
3718
0
    this->NumberOfPhysicalCPU =
3719
0
      NumberOfCoresPerSocket * (unsigned int)NumberOfSockets;
3720
0
  }
3721
3722
#else
3723
  // For systems which do not have "physical id" entries, neither "cpu cores"
3724
  // this has to be fixed for hyper-threading.
3725
  std::string cpucount =
3726
    this->ExtractValueFromCpuInfoFile(buffer, "cpu count");
3727
  this->NumberOfPhysicalCPU = this->NumberOfLogicalCPU =
3728
    atoi(cpucount.c_str());
3729
#endif
3730
  // gotta have one, and if this is 0 then we get a / by 0n
3731
  // better to have a bad answer than a crash
3732
0
  if (this->NumberOfPhysicalCPU == 0 && this->NumberOfLogicalCPU == 0) {
3733
0
    this->NumberOfPhysicalCPU = this->NumberOfLogicalCPU = 1;
3734
0
  } else if (this->NumberOfPhysicalCPU == 0) {
3735
0
    this->NumberOfPhysicalCPU = this->NumberOfLogicalCPU;
3736
0
  } else if (this->NumberOfLogicalCPU == 0) {
3737
0
    this->NumberOfLogicalCPU = this->NumberOfPhysicalCPU;
3738
0
  }
3739
  // LogicalProcessorsPerPhysical>1 => SMT.
3740
0
  this->Features.ExtendedFeatures.LogicalProcessorsPerPhysical =
3741
0
    this->NumberOfLogicalCPU / this->NumberOfPhysicalCPU;
3742
3743
  // Prefer a stable base frequency over the fluctuating "cpu MHz" current.
3744
0
  char const* const cpuRoot = "/sys/devices/system/cpu";
3745
0
  float baseMHz = SystemInformationDetail::LinuxBaseFrequencyMHz(cpuRoot);
3746
0
#if KWSYS_CPUID_FREQ
3747
0
  if (baseMHz == 0.0f) {
3748
0
    baseMHz = kwsysCpuidBaseFrequencyMHz();
3749
0
  }
3750
0
#endif
3751
0
  if (baseMHz == 0.0f) {
3752
0
    baseMHz = SystemInformationDetail::LinuxMaxFrequencyMHz(cpuRoot);
3753
0
  }
3754
0
  if (baseMHz > 0.0f) {
3755
0
    this->CPUSpeedInMHz = baseMHz;
3756
0
  } else {
3757
    // Last resort: current frequency, so we do not regress to no value.
3758
0
    std::string CPUSpeed =
3759
0
      this->ExtractValueFromCpuInfoFile(buffer, "cpu MHz");
3760
0
    if (!CPUSpeed.empty()) {
3761
0
      this->CPUSpeedInMHz = static_cast<float>(atof(CPUSpeed.c_str()));
3762
0
    }
3763
0
#ifdef __linux
3764
0
    else {
3765
      // Linux Sparc: CPU speed is in Hz and encoded in hexadecimal
3766
0
      CPUSpeed = this->ExtractValueFromCpuInfoFile(buffer, "Cpu0ClkTck");
3767
0
      if (!CPUSpeed.empty()) {
3768
0
        this->CPUSpeedInMHz =
3769
0
          static_cast<float>(strtoull(CPUSpeed.c_str(), nullptr, 16)) /
3770
0
          1000000.0f;
3771
0
      } else {
3772
        // if the kernel is build as Sparc32 it's in decimal, note the
3773
        // different case
3774
0
        CPUSpeed = this->ExtractValueFromCpuInfoFile(buffer, "CPU0ClkTck");
3775
0
        this->CPUSpeedInMHz =
3776
0
          static_cast<float>(strtoull(CPUSpeed.c_str(), nullptr, 10)) /
3777
0
          1000000.0f;
3778
0
      }
3779
0
    }
3780
0
#endif
3781
0
  }
3782
3783
  // Chip family
3784
0
  std::string familyStr =
3785
0
    this->ExtractValueFromCpuInfoFile(buffer, "cpu family");
3786
0
  if (familyStr.empty()) {
3787
0
    familyStr = this->ExtractValueFromCpuInfoFile(buffer, "CPU architecture");
3788
0
  }
3789
0
  this->ChipID.Family = atoi(familyStr.c_str());
3790
3791
  // Chip Vendor
3792
0
  this->ChipID.Vendor = this->ExtractValueFromCpuInfoFile(buffer, "vendor_id");
3793
0
  this->FindManufacturer(familyStr);
3794
3795
  // second try for setting family
3796
0
  if (this->ChipID.Family == 0 && this->ChipManufacturer == HP) {
3797
0
    if (familyStr == "PA-RISC 1.1a")
3798
0
      this->ChipID.Family = 0x11a;
3799
0
    else if (familyStr == "PA-RISC 2.0")
3800
0
      this->ChipID.Family = 0x200;
3801
    // If you really get CMake to work on a machine not belonging to
3802
    // any of those families I owe you a dinner if you get it to
3803
    // contribute nightly builds regularly.
3804
0
  }
3805
3806
  // Chip Model
3807
0
  this->ChipID.Model =
3808
0
    atoi(this->ExtractValueFromCpuInfoFile(buffer, "model").c_str());
3809
0
  if (!this->RetrieveClassicalCPUIdentity()) {
3810
    // Some platforms (e.g. PA-RISC) tell us their CPU name here.
3811
    // Note: x86 does not.
3812
0
    std::string cpuname = this->ExtractValueFromCpuInfoFile(buffer, "cpu");
3813
0
    if (!cpuname.empty()) {
3814
0
      this->ChipID.ProcessorName = cpuname;
3815
0
    }
3816
0
  }
3817
3818
  // Chip revision
3819
0
  std::string cpurev = this->ExtractValueFromCpuInfoFile(buffer, "stepping");
3820
0
  if (cpurev.empty()) {
3821
0
    cpurev = this->ExtractValueFromCpuInfoFile(buffer, "CPU revision");
3822
0
  }
3823
0
  this->ChipID.Revision = atoi(cpurev.c_str());
3824
3825
  // Chip Model Name
3826
0
  this->ChipID.ModelName =
3827
0
    this->ExtractValueFromCpuInfoFile(buffer, "model name");
3828
3829
  // L1 Cache size
3830
  // Different architectures may show different names for the caches.
3831
  // Sum up everything we find.
3832
0
  std::vector<char const*> cachename;
3833
0
  cachename.clear();
3834
3835
0
  cachename.push_back("cache size"); // e.g. x86
3836
0
  cachename.push_back("I-cache");    // e.g. PA-RISC
3837
0
  cachename.push_back("D-cache");    // e.g. PA-RISC
3838
3839
0
  this->Features.L1CacheSize = 0;
3840
0
  for (auto& index : cachename) {
3841
0
    std::string cacheSize = this->ExtractValueFromCpuInfoFile(buffer, index);
3842
0
    if (!cacheSize.empty()) {
3843
0
      pos = cacheSize.find(" KB");
3844
0
      if (pos != std::string::npos) {
3845
0
        cacheSize.resize(pos);
3846
0
      }
3847
0
      this->Features.L1CacheSize += atoi(cacheSize.c_str());
3848
0
    }
3849
0
  }
3850
3851
  // processor feature flags (probably x86 specific)
3852
0
  std::string cpuflags = this->ExtractValueFromCpuInfoFile(buffer, "flags");
3853
0
  if (!cpurev.empty()) {
3854
    // now we can match every flags as space + flag + space
3855
0
    cpuflags = ' ' + cpuflags + ' ';
3856
0
    if ((cpuflags.find(" fpu ") != std::string::npos)) {
3857
0
      this->Features.HasFPU = true;
3858
0
    }
3859
0
    if ((cpuflags.find(" tsc ") != std::string::npos)) {
3860
0
      this->Features.HasTSC = true;
3861
0
    }
3862
0
    if ((cpuflags.find(" mmx ") != std::string::npos)) {
3863
0
      this->Features.HasMMX = true;
3864
0
    }
3865
0
    if ((cpuflags.find(" sse ") != std::string::npos)) {
3866
0
      this->Features.HasSSE = true;
3867
0
    }
3868
0
    if ((cpuflags.find(" sse2 ") != std::string::npos)) {
3869
0
      this->Features.HasSSE2 = true;
3870
0
    }
3871
0
    if ((cpuflags.find(" apic ") != std::string::npos)) {
3872
0
      this->Features.HasAPIC = true;
3873
0
    }
3874
0
    if ((cpuflags.find(" cmov ") != std::string::npos)) {
3875
0
      this->Features.HasCMOV = true;
3876
0
    }
3877
0
    if ((cpuflags.find(" mtrr ") != std::string::npos)) {
3878
0
      this->Features.HasMTRR = true;
3879
0
    }
3880
0
    if ((cpuflags.find(" acpi ") != std::string::npos)) {
3881
0
      this->Features.HasACPI = true;
3882
0
    }
3883
0
    if ((cpuflags.find(" 3dnow ") != std::string::npos)) {
3884
0
      this->Features.ExtendedFeatures.Has3DNow = true;
3885
0
    }
3886
0
  }
3887
3888
0
  return true;
3889
0
}
3890
3891
bool SystemInformationImplementation::QueryProcessorBySysconf()
3892
0
{
3893
#if defined(_SC_NPROC_ONLN) && !defined(_SC_NPROCESSORS_ONLN)
3894
// IRIX names this slightly different
3895
#  define _SC_NPROCESSORS_ONLN _SC_NPROC_ONLN
3896
#endif
3897
3898
0
#ifdef _SC_NPROCESSORS_ONLN
3899
0
  long c = sysconf(_SC_NPROCESSORS_ONLN);
3900
0
  if (c <= 0) {
3901
0
    return false;
3902
0
  }
3903
3904
0
  this->NumberOfPhysicalCPU = static_cast<unsigned int>(c);
3905
0
  this->NumberOfLogicalCPU = this->NumberOfPhysicalCPU;
3906
3907
0
  return true;
3908
#else
3909
  return false;
3910
#endif
3911
0
}
3912
3913
bool SystemInformationImplementation::QueryProcessor()
3914
0
{
3915
0
  return this->QueryProcessorBySysconf();
3916
0
}
3917
3918
/**
3919
Get total system RAM in units of KiB.
3920
*/
3921
long long SystemInformationImplementation::GetHostMemoryTotal()
3922
0
{
3923
#if defined(_WIN32)
3924
#  if defined(_MSC_VER) && _MSC_VER < 1300
3925
  MEMORYSTATUS stat;
3926
  stat.dwLength = sizeof(stat);
3927
  GlobalMemoryStatus(&stat);
3928
  return stat.dwTotalPhys / 1024;
3929
#  else
3930
  MEMORYSTATUSEX statex;
3931
  statex.dwLength = sizeof(statex);
3932
  GlobalMemoryStatusEx(&statex);
3933
  return statex.ullTotalPhys / 1024;
3934
#  endif
3935
#elif defined(__linux) || defined(__CYGWIN__)
3936
  long long memTotal = 0;
3937
0
  int ierr = GetFieldFromFile("/proc/meminfo", "MemTotal:", memTotal);
3938
0
  if (ierr) {
3939
0
    return -1;
3940
0
  }
3941
0
  return memTotal;
3942
#elif defined(__APPLE__)
3943
  uint64_t mem;
3944
  size_t len = sizeof(mem);
3945
  int ierr = sysctlbyname("hw.memsize", &mem, &len, nullptr, 0);
3946
  if (ierr) {
3947
    return -1;
3948
  }
3949
  return mem / 1024;
3950
#else
3951
  return 0;
3952
#endif
3953
0
}
3954
3955
/**
3956
Get total system RAM in units of KiB. This may differ from the
3957
host total if a host-wide resource limit is applied.
3958
*/
3959
long long SystemInformationImplementation::GetHostMemoryAvailable(
3960
  char const* hostLimitEnvVarName)
3961
0
{
3962
0
  long long memTotal = this->GetHostMemoryTotal();
3963
3964
  // the following mechanism is provided for systems that
3965
  // apply resource limits across groups of processes.
3966
  // this is of use on certain SMP systems (eg. SGI UV)
3967
  // where the host has a large amount of ram but a given user's
3968
  // access to it is severely restricted. The system will
3969
  // apply a limit across a set of processes. Units are in KiB.
3970
0
  if (hostLimitEnvVarName) {
3971
0
    char const* hostLimitEnvVarValue = getenv(hostLimitEnvVarName);
3972
0
    if (hostLimitEnvVarValue) {
3973
0
      long long hostLimit = std::atoll(hostLimitEnvVarValue);
3974
0
      if (hostLimit > 0) {
3975
0
        memTotal = min(hostLimit, memTotal);
3976
0
      }
3977
0
    }
3978
0
  }
3979
3980
0
  return memTotal;
3981
0
}
3982
3983
/**
3984
Get total system RAM in units of KiB. This may differ from the
3985
host total if a per-process resource limit is applied.
3986
*/
3987
long long SystemInformationImplementation::GetProcMemoryAvailable(
3988
  char const* hostLimitEnvVarName, char const* procLimitEnvVarName)
3989
0
{
3990
0
  long long memAvail = this->GetHostMemoryAvailable(hostLimitEnvVarName);
3991
3992
  // the following mechanism is provide for systems where rlimits
3993
  // are not employed. Units are in KiB.
3994
0
  if (procLimitEnvVarName) {
3995
0
    char const* procLimitEnvVarValue = getenv(procLimitEnvVarName);
3996
0
    if (procLimitEnvVarValue) {
3997
0
      long long procLimit = std::atoll(procLimitEnvVarValue);
3998
0
      if (procLimit > 0) {
3999
0
        memAvail = min(procLimit, memAvail);
4000
0
      }
4001
0
    }
4002
0
  }
4003
4004
0
#if defined(__linux)
4005
0
  int ierr;
4006
0
  ResourceLimitType rlim;
4007
0
  ierr = GetResourceLimit(RLIMIT_DATA, &rlim);
4008
0
  if ((ierr == 0) && (rlim.rlim_cur != RLIM_INFINITY)) {
4009
0
    memAvail = min(static_cast<long long>(rlim.rlim_cur) / 1024, memAvail);
4010
0
  }
4011
4012
0
  ierr = GetResourceLimit(RLIMIT_AS, &rlim);
4013
0
  if ((ierr == 0) && (rlim.rlim_cur != RLIM_INFINITY)) {
4014
0
    memAvail = min(static_cast<long long>(rlim.rlim_cur) / 1024, memAvail);
4015
0
  }
4016
#elif defined(__APPLE__)
4017
  struct rlimit rlim;
4018
  int ierr;
4019
  ierr = getrlimit(RLIMIT_DATA, &rlim);
4020
  if ((ierr == 0) && (rlim.rlim_cur != RLIM_INFINITY)) {
4021
    memAvail = min(static_cast<long long>(rlim.rlim_cur) / 1024, memAvail);
4022
  }
4023
4024
  ierr = getrlimit(RLIMIT_RSS, &rlim);
4025
  if ((ierr == 0) && (rlim.rlim_cur != RLIM_INFINITY)) {
4026
    memAvail = min(static_cast<long long>(rlim.rlim_cur) / 1024, memAvail);
4027
  }
4028
#endif
4029
4030
0
  return memAvail;
4031
0
}
4032
4033
/**
4034
Get RAM used by all processes in the host, in units of KiB.
4035
*/
4036
long long SystemInformationImplementation::GetHostMemoryUsed()
4037
0
{
4038
#if defined(_WIN32)
4039
#  if defined(_MSC_VER) && _MSC_VER < 1300
4040
  MEMORYSTATUS stat;
4041
  stat.dwLength = sizeof(stat);
4042
  GlobalMemoryStatus(&stat);
4043
  return (stat.dwTotalPhys - stat.dwAvailPhys) / 1024;
4044
#  else
4045
  MEMORYSTATUSEX statex;
4046
  statex.dwLength = sizeof(statex);
4047
  GlobalMemoryStatusEx(&statex);
4048
  return (statex.ullTotalPhys - statex.ullAvailPhys) / 1024;
4049
#  endif
4050
#elif defined(__CYGWIN__)
4051
  char const* names[3] = { "MemTotal:", "MemFree:", nullptr };
4052
  long long values[2] = { 0 };
4053
  int ierr = GetFieldsFromFile("/proc/meminfo", names, values);
4054
  if (ierr) {
4055
    return ierr;
4056
  }
4057
  long long& memTotal = values[0];
4058
  long long& memFree = values[1];
4059
  return memTotal - memFree;
4060
#elif defined(__linux)
4061
  // First try to use MemAvailable, but it only works on newer kernels
4062
0
  char const* names2[3] = { "MemTotal:", "MemAvailable:", nullptr };
4063
0
  long long values2[2] = { 0 };
4064
0
  int ierr = GetFieldsFromFile("/proc/meminfo", names2, values2);
4065
0
  if (ierr) {
4066
0
    char const* names4[5] = { "MemTotal:", "MemFree:", "Buffers:", "Cached:",
4067
0
                              nullptr };
4068
0
    long long values4[4] = { 0 };
4069
0
    ierr = GetFieldsFromFile("/proc/meminfo", names4, values4);
4070
0
    if (ierr) {
4071
0
      return ierr;
4072
0
    }
4073
0
    long long& memTotal = values4[0];
4074
0
    long long& memFree = values4[1];
4075
0
    long long& memBuffers = values4[2];
4076
0
    long long& memCached = values4[3];
4077
0
    return memTotal - memFree - memBuffers - memCached;
4078
0
  }
4079
0
  long long& memTotal = values2[0];
4080
0
  long long& memAvail = values2[1];
4081
0
  return memTotal - memAvail;
4082
#elif defined(__APPLE__)
4083
  long long psz = getpagesize();
4084
  if (psz < 1) {
4085
    return -1;
4086
  }
4087
  char const* names[3] = { "Pages wired down:", "Pages active:", nullptr };
4088
  long long values[2] = { 0 };
4089
  int ierr = GetFieldsFromCommand("vm_stat", names, values);
4090
  if (ierr) {
4091
    return -1;
4092
  }
4093
  long long& vmWired = values[0];
4094
  long long& vmActive = values[1];
4095
  return ((vmActive + vmWired) * psz) / 1024;
4096
#else
4097
  return 0;
4098
#endif
4099
0
}
4100
4101
/**
4102
Get system RAM used by the process associated with the given
4103
process id in units of KiB.
4104
*/
4105
long long SystemInformationImplementation::GetProcMemoryUsed()
4106
0
{
4107
#if defined(_WIN32) && defined(KWSYS_SYS_HAS_PSAPI)
4108
  long pid = GetCurrentProcessId();
4109
  HANDLE hProc;
4110
  hProc = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, false, pid);
4111
  if (hProc == 0) {
4112
    return -1;
4113
  }
4114
  PROCESS_MEMORY_COUNTERS pmc;
4115
  int ok = GetProcessMemoryInfo(hProc, &pmc, sizeof(pmc));
4116
  CloseHandle(hProc);
4117
  if (!ok) {
4118
    return -2;
4119
  }
4120
  return pmc.WorkingSetSize / 1024;
4121
#elif defined(__linux) || defined(__CYGWIN__)
4122
  long long memUsed = 0;
4123
0
  int ierr = GetFieldFromFile("/proc/self/status", "VmRSS:", memUsed);
4124
0
  if (ierr) {
4125
0
    return -1;
4126
0
  }
4127
0
  return memUsed;
4128
#elif defined(__APPLE__)
4129
  long long memUsed = 0;
4130
  pid_t pid = getpid();
4131
  std::ostringstream oss;
4132
  oss << "ps -o rss= -p " << pid;
4133
  FILE* file = popen(oss.str().c_str(), "r");
4134
  if (!file) {
4135
    return -1;
4136
  }
4137
  oss.str("");
4138
  while (!feof(file) && !ferror(file)) {
4139
    char buf[256] = { '\0' };
4140
    errno = 0;
4141
    size_t nRead = fread(buf, 1, 256, file);
4142
    if (ferror(file) && (errno == EINTR)) {
4143
      clearerr(file);
4144
    }
4145
    if (nRead)
4146
      oss << buf;
4147
  }
4148
  int ierr = ferror(file);
4149
  pclose(file);
4150
  if (ierr) {
4151
    return -2;
4152
  }
4153
  std::istringstream iss(oss.str());
4154
  iss >> memUsed;
4155
  return memUsed;
4156
#else
4157
  return 0;
4158
#endif
4159
0
}
4160
4161
double SystemInformationImplementation::GetLoadAverage()
4162
0
{
4163
0
#if defined(KWSYS_CXX_HAS_GETLOADAVG)
4164
0
  double loadavg[3] = { 0.0, 0.0, 0.0 };
4165
0
  if (getloadavg(loadavg, 3) > 0) {
4166
0
    return loadavg[0];
4167
0
  }
4168
0
  return -0.0;
4169
#elif defined(KWSYS_SYSTEMINFORMATION_USE_GetSystemTimes)
4170
  // Old windows.h headers do not provide GetSystemTimes.
4171
  using GetSystemTimesType = BOOL(WINAPI*)(LPFILETIME, LPFILETIME, LPFILETIME);
4172
  static GetSystemTimesType pGetSystemTimes =
4173
    (GetSystemTimesType)(void*)GetProcAddress(GetModuleHandleW(L"kernel32"),
4174
                                              "GetSystemTimes");
4175
  FILETIME idleTime, kernelTime, userTime;
4176
  if (pGetSystemTimes && pGetSystemTimes(&idleTime, &kernelTime, &userTime)) {
4177
    unsigned __int64 const idleTicks = fileTimeToUInt64(idleTime);
4178
    unsigned __int64 const totalTicks =
4179
      fileTimeToUInt64(kernelTime) + fileTimeToUInt64(userTime);
4180
    return calculateCPULoad(idleTicks, totalTicks) * GetNumberOfPhysicalCPU();
4181
  }
4182
  return -0.0;
4183
#else
4184
  // Not implemented on this platform.
4185
  return -0.0;
4186
#endif
4187
0
}
4188
4189
/**
4190
Get the process id of the running process.
4191
*/
4192
long long SystemInformationImplementation::GetProcessId()
4193
0
{
4194
#if defined(_WIN32)
4195
  return GetCurrentProcessId();
4196
#elif defined(__linux) || defined(__APPLE__) || defined(__OpenBSD__) ||       \
4197
  defined(__FreeBSD__) || defined(__NetBSD__) || defined(__DragonFly__) ||    \
4198
  defined(__CYGWIN__)
4199
  return getpid();
4200
#else
4201
  return -1;
4202
#endif
4203
0
}
4204
4205
/**
4206
 * Used in GetProgramStack(...) below
4207
 */
4208
#if defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0600 && defined(_MSC_VER) &&   \
4209
  _MSC_VER >= 1800
4210
#  define KWSYS_SYSTEMINFORMATION_HAS_DBGHELP
4211
#  define TRACE_MAX_STACK_FRAMES 1024
4212
#  define TRACE_MAX_FUNCTION_NAME_LENGTH 1024
4213
#  pragma warning(push)
4214
#  pragma warning(disable : 4091) /* 'typedef ': ignored on left of '' */
4215
#  include "dbghelp.h"
4216
#  pragma warning(pop)
4217
#endif
4218
4219
/**
4220
return current program stack in a string
4221
demangle cxx symbols if possible.
4222
*/
4223
std::string SystemInformationImplementation::GetProgramStack(int firstFrame,
4224
                                                             int wholePath)
4225
0
{
4226
0
  std::ostringstream oss;
4227
0
  std::string programStack;
4228
4229
#ifdef KWSYS_SYSTEMINFORMATION_HAS_DBGHELP
4230
  (void)wholePath;
4231
4232
  void* stack[TRACE_MAX_STACK_FRAMES];
4233
  HANDLE process = GetCurrentProcess();
4234
  // SymSetOptions affects the process-global symbol handler options, so
4235
  // save the caller's options and restore them before returning.
4236
  DWORD options = SymGetOptions();
4237
  SymSetOptions(options | SYMOPT_UNDNAME | SYMOPT_DEFERRED_LOADS |
4238
                SYMOPT_LOAD_LINES);
4239
  SymInitialize(process, nullptr, TRUE);
4240
  WORD numberOfFrames =
4241
    CaptureStackBackTrace(firstFrame, TRACE_MAX_STACK_FRAMES, stack, nullptr);
4242
  SYMBOL_INFO* symbol = static_cast<SYMBOL_INFO*>(
4243
    calloc(1,
4244
           sizeof(SYMBOL_INFO) +
4245
             (TRACE_MAX_FUNCTION_NAME_LENGTH - 1) * sizeof(TCHAR)));
4246
  symbol->MaxNameLen = TRACE_MAX_FUNCTION_NAME_LENGTH;
4247
  symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
4248
  DWORD displacement;
4249
  IMAGEHLP_LINE64 line;
4250
  line.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
4251
  for (int i = 0; i < numberOfFrames; i++) {
4252
    DWORD64 address = reinterpret_cast<DWORD64>(stack[i]);
4253
    DWORD64 symDisplacement = 0;
4254
    bool haveName =
4255
      SymFromAddr(process, address, &symDisplacement, symbol) != FALSE;
4256
    // When a module has no matching PDB, dbghelp falls back to its export
4257
    // table and reports the nearest preceding export, which is generally not
4258
    // the (non-exported) function the address really belongs to. Names are
4259
    // only exact when real debug info was loaded for the module, so ask the
4260
    // module how its symbols were obtained rather than trusting the name.
4261
    // Inexact names are still printed, but marked and always accompanied by
4262
    // the module-relative address so they cannot be mistaken for the truth.
4263
    bool exactName = haveName;
4264
    if (exactName) {
4265
      IMAGEHLP_MODULE64 moduleInfo;
4266
      memset(&moduleInfo, 0, sizeof(moduleInfo));
4267
      moduleInfo.SizeOfStruct = sizeof(moduleInfo);
4268
      if (!SymGetModuleInfo64(process, address, &moduleInfo) ||
4269
          moduleInfo.SymType == SymNone || moduleInfo.SymType == SymExport ||
4270
          moduleInfo.SymType == SymDeferred) {
4271
        exactName = false;
4272
      }
4273
    }
4274
    if (exactName &&
4275
        SymGetLineFromAddr64(process, address, &displacement, &line)) {
4276
      oss << " at " << symbol->Name << " in " << line.FileName << " line "
4277
          << line.LineNumber << std::endl;
4278
    } else if (exactName) {
4279
      oss << " at " << symbol->Name << "+0x" << std::hex << symDisplacement
4280
          << std::dec << std::endl;
4281
    } else {
4282
      // Report the module containing the address together with the offset
4283
      // into that module, which is what a disassembler needs, plus the
4284
      // nearest export as an approximate location hint when one is known.
4285
      wchar_t modulePath[MAX_PATH];
4286
      DWORD64 moduleBase = SymGetModuleBase64(process, address);
4287
      if (moduleBase &&
4288
          GetModuleFileNameW(reinterpret_cast<HMODULE>(moduleBase), modulePath,
4289
                             MAX_PATH) > 0) {
4290
        oss << " at " << modulePath << "+0x" << std::hex
4291
            << (address - moduleBase) << std::dec;
4292
      } else {
4293
        oss << " at 0x" << std::hex << address << std::dec;
4294
      }
4295
      if (haveName) {
4296
        oss << " (near " << symbol->Name << "+0x" << std::hex
4297
            << symDisplacement << std::dec << ")";
4298
      }
4299
      oss << std::endl;
4300
    }
4301
  }
4302
  free(symbol);
4303
  SymSetOptions(options);
4304
  SymCleanup(process);
4305
4306
#else
4307
0
  programStack += ""
4308
#  if !defined(KWSYS_SYSTEMINFORMATION_HAS_BACKTRACE)
4309
                  "WARNING: The stack could not be examined "
4310
                  "because backtrace is not supported.\n"
4311
#  elif !defined(KWSYS_SYSTEMINFORMATION_HAS_DEBUG_BUILD)
4312
                  "WARNING: The stack trace will not use advanced "
4313
0
                  "capabilities because this is a release build.\n"
4314
#  else
4315
#    if !defined(KWSYS_SYSTEMINFORMATION_HAS_SYMBOL_LOOKUP)
4316
                  "WARNING: Function names will not be demangled "
4317
                  "because dladdr is not available.\n"
4318
#    endif
4319
#    if !defined(KWSYS_SYSTEMINFORMATION_HAS_CPP_DEMANGLE)
4320
                  "WARNING: Function names will not be demangled "
4321
                  "because cxxabi is not available.\n"
4322
#    endif
4323
#  endif
4324
0
    ;
4325
4326
0
#  if defined(KWSYS_SYSTEMINFORMATION_HAS_BACKTRACE)
4327
0
  void* stackSymbols[256];
4328
0
  int nFrames = backtrace(stackSymbols, 256);
4329
0
  for (int i = firstFrame; i < nFrames; ++i) {
4330
0
    SymbolProperties symProps;
4331
0
    symProps.SetReportPath(wholePath);
4332
0
    symProps.Initialize(stackSymbols[i]);
4333
0
    oss << symProps << std::endl;
4334
0
  }
4335
#  else
4336
  (void)firstFrame;
4337
  (void)wholePath;
4338
#  endif
4339
0
#endif
4340
4341
0
  programStack += oss.str();
4342
4343
0
  return programStack;
4344
0
}
4345
4346
/**
4347
when set print stack trace in response to common signals.
4348
*/
4349
void SystemInformationImplementation::SetStackTraceOnError(int enable)
4350
0
{
4351
0
#if !defined(_WIN32) && !defined(__MINGW32__) && !defined(__CYGWIN__)
4352
0
  static int saOrigValid = 0;
4353
0
  static struct sigaction saABRTOrig;
4354
0
  static struct sigaction saSEGVOrig;
4355
0
  static struct sigaction saTERMOrig;
4356
0
  static struct sigaction saINTOrig;
4357
0
  static struct sigaction saILLOrig;
4358
0
  static struct sigaction saBUSOrig;
4359
0
  static struct sigaction saFPEOrig;
4360
4361
0
  if (enable && !saOrigValid) {
4362
    // save the current actions
4363
0
    sigaction(SIGABRT, nullptr, &saABRTOrig);
4364
0
    sigaction(SIGSEGV, nullptr, &saSEGVOrig);
4365
0
    sigaction(SIGTERM, nullptr, &saTERMOrig);
4366
0
    sigaction(SIGINT, nullptr, &saINTOrig);
4367
0
    sigaction(SIGILL, nullptr, &saILLOrig);
4368
0
    sigaction(SIGBUS, nullptr, &saBUSOrig);
4369
0
    sigaction(SIGFPE, nullptr, &saFPEOrig);
4370
4371
    // enable read, disable write
4372
0
    saOrigValid = 1;
4373
4374
    // install ours
4375
0
    struct sigaction sa;
4376
0
    sa.sa_sigaction = static_cast<SigAction>(StacktraceSignalHandler);
4377
0
    sa.sa_flags = SA_SIGINFO | SA_RESETHAND;
4378
0
#  ifdef SA_RESTART
4379
0
    sa.sa_flags |= SA_RESTART;
4380
0
#  endif
4381
0
    sigemptyset(&sa.sa_mask);
4382
4383
0
    sigaction(SIGABRT, &sa, nullptr);
4384
0
    sigaction(SIGSEGV, &sa, nullptr);
4385
0
    sigaction(SIGTERM, &sa, nullptr);
4386
0
    sigaction(SIGINT, &sa, nullptr);
4387
0
    sigaction(SIGILL, &sa, nullptr);
4388
0
    sigaction(SIGBUS, &sa, nullptr);
4389
0
    sigaction(SIGFPE, &sa, nullptr);
4390
0
  } else if (!enable && saOrigValid) {
4391
    // restore previous actions
4392
0
    sigaction(SIGABRT, &saABRTOrig, nullptr);
4393
0
    sigaction(SIGSEGV, &saSEGVOrig, nullptr);
4394
0
    sigaction(SIGTERM, &saTERMOrig, nullptr);
4395
0
    sigaction(SIGINT, &saINTOrig, nullptr);
4396
0
    sigaction(SIGILL, &saILLOrig, nullptr);
4397
0
    sigaction(SIGBUS, &saBUSOrig, nullptr);
4398
0
    sigaction(SIGFPE, &saFPEOrig, nullptr);
4399
4400
    // enable write, disable read
4401
0
    saOrigValid = 0;
4402
0
  }
4403
#else
4404
  // avoid warning C4100
4405
  (void)enable;
4406
#endif
4407
0
}
4408
4409
bool SystemInformationImplementation::QueryWindowsMemory()
4410
0
{
4411
#if defined(_WIN32)
4412
#  if defined(_MSC_VER) && _MSC_VER < 1300
4413
  MEMORYSTATUS ms;
4414
  unsigned long tv, tp, av, ap;
4415
  ms.dwLength = sizeof(ms);
4416
  GlobalMemoryStatus(&ms);
4417
#    define MEM_VAL(value) dw##value
4418
#  else
4419
  MEMORYSTATUSEX ms;
4420
  DWORDLONG tv, tp, av, ap;
4421
  ms.dwLength = sizeof(ms);
4422
  if (0 == GlobalMemoryStatusEx(&ms)) {
4423
    return 0;
4424
  }
4425
#    define MEM_VAL(value) ull##value
4426
#  endif
4427
  tv = ms.MEM_VAL(TotalPageFile);
4428
  tp = ms.MEM_VAL(TotalPhys);
4429
  av = ms.MEM_VAL(AvailPageFile);
4430
  ap = ms.MEM_VAL(AvailPhys);
4431
  this->TotalVirtualMemory = tv >> 10 >> 10;
4432
  this->TotalPhysicalMemory = tp >> 10 >> 10;
4433
  this->AvailableVirtualMemory = av >> 10 >> 10;
4434
  this->AvailablePhysicalMemory = ap >> 10 >> 10;
4435
4436
  // The virtual WinAPI memory contains both physical memory and page file.
4437
  this->TotalVirtualMemory -= this->TotalPhysicalMemory;
4438
  this->AvailableVirtualMemory -= this->AvailablePhysicalMemory;
4439
  return true;
4440
#else
4441
0
  return false;
4442
0
#endif
4443
0
}
4444
4445
bool SystemInformationImplementation::QueryLinuxMemory()
4446
0
{
4447
0
#if defined(__linux)
4448
0
  unsigned long tv = 0;
4449
0
  unsigned long tp = 0;
4450
0
  unsigned long av = 0;
4451
0
  unsigned long ap = 0;
4452
4453
0
  char buffer[1024]; // for reading lines
4454
4455
0
  int linuxMajor = 0;
4456
0
  int linuxMinor = 0;
4457
4458
  // Find the Linux kernel version first
4459
0
  struct utsname unameInfo;
4460
0
  int errorFlag = uname(&unameInfo);
4461
0
  if (errorFlag != 0) {
4462
0
    std::cerr << "Problem calling uname(): " << strerror(errno) << "\n";
4463
0
    return false;
4464
0
  }
4465
4466
0
  if (strlen(unameInfo.release) >= 3) {
4467
    // release looks like "2.6.3-15mdk-i686-up-4GB"
4468
0
    char majorChar = unameInfo.release[0];
4469
0
    char minorChar = unameInfo.release[2];
4470
4471
0
    if (kwsysString_isdigit(majorChar)) {
4472
0
      linuxMajor = majorChar - '0';
4473
0
    }
4474
4475
0
    if (kwsysString_isdigit(minorChar)) {
4476
0
      linuxMinor = minorChar - '0';
4477
0
    }
4478
0
  }
4479
4480
0
  FILE* fd = fopen("/proc/meminfo", "r");
4481
0
  if (!fd) {
4482
0
    std::cerr << "Problem opening /proc/meminfo\n";
4483
0
    return false;
4484
0
  }
4485
4486
0
  if (linuxMajor >= 3 || ((linuxMajor >= 2) && (linuxMinor >= 6))) {
4487
    // new /proc/meminfo format since kernel 2.6.x
4488
    // Rigorously, this test should check from the developing version 2.5.x
4489
    // that introduced the new format...
4490
4491
0
    enum
4492
0
    {
4493
0
      mMemTotal,
4494
0
      mMemFree,
4495
0
      mBuffers,
4496
0
      mCached,
4497
0
      mSwapTotal,
4498
0
      mSwapFree
4499
0
    };
4500
0
    char const* format[6] = { "MemTotal:%lu kB",  "MemFree:%lu kB",
4501
0
                              "Buffers:%lu kB",   "Cached:%lu kB",
4502
0
                              "SwapTotal:%lu kB", "SwapFree:%lu kB" };
4503
0
    bool have[6] = { false, false, false, false, false, false };
4504
0
    unsigned long value[6];
4505
0
    int count = 0;
4506
0
    while (fgets(buffer, static_cast<int>(sizeof(buffer)), fd)) {
4507
0
      for (int i = 0; i < 6; ++i) {
4508
0
        if (!have[i] && sscanf(buffer, format[i], &value[i]) == 1) {
4509
0
          have[i] = true;
4510
0
          ++count;
4511
0
        }
4512
0
      }
4513
0
    }
4514
0
    if (count == 6) {
4515
0
      this->TotalPhysicalMemory = value[mMemTotal] / 1024;
4516
0
      this->AvailablePhysicalMemory =
4517
0
        (value[mMemFree] + value[mBuffers] + value[mCached]) / 1024;
4518
0
      this->TotalVirtualMemory = value[mSwapTotal] / 1024;
4519
0
      this->AvailableVirtualMemory = value[mSwapFree] / 1024;
4520
0
    } else {
4521
0
      std::cerr << "Problem parsing /proc/meminfo\n";
4522
0
      fclose(fd);
4523
0
      return false;
4524
0
    }
4525
0
  } else {
4526
    // /proc/meminfo format for kernel older than 2.6.x
4527
4528
0
    unsigned long temp;
4529
0
    unsigned long cachedMem;
4530
0
    unsigned long buffersMem;
4531
    // Skip "total: used:..."
4532
0
    char* r = fgets(buffer, static_cast<int>(sizeof(buffer)), fd);
4533
0
    int status = 0;
4534
0
    if (r == buffer) {
4535
0
      status += fscanf(fd, "Mem: %lu %lu %lu %lu %lu %lu\n", &tp, &temp, &ap,
4536
0
                       &temp, &buffersMem, &cachedMem);
4537
0
    }
4538
0
    if (status == 6) {
4539
0
      status += fscanf(fd, "Swap: %lu %lu %lu\n", &tv, &temp, &av);
4540
0
    }
4541
0
    if (status == 9) {
4542
0
      this->TotalVirtualMemory = tv >> 10 >> 10;
4543
0
      this->TotalPhysicalMemory = tp >> 10 >> 10;
4544
0
      this->AvailableVirtualMemory = av >> 10 >> 10;
4545
0
      this->AvailablePhysicalMemory =
4546
0
        (ap + buffersMem + cachedMem) >> 10 >> 10;
4547
0
    } else {
4548
0
      std::cerr << "Problem parsing /proc/meminfo\n";
4549
0
      fclose(fd);
4550
0
      return false;
4551
0
    }
4552
0
  }
4553
0
  fclose(fd);
4554
4555
0
  return true;
4556
#else
4557
  return false;
4558
#endif
4559
0
}
4560
4561
bool SystemInformationImplementation::QueryCygwinMemory()
4562
0
{
4563
#ifdef __CYGWIN__
4564
  // _SC_PAGE_SIZE does return the mmap() granularity on Cygwin,
4565
  // see https://sourceware.org/legacy-ml/cygwin/2006-06/msg00350.html
4566
  // Therefore just use 4096 as the page size of Windows.
4567
  long m = sysconf(_SC_PHYS_PAGES);
4568
  if (m < 0) {
4569
    return false;
4570
  }
4571
  this->TotalPhysicalMemory = m >> 8;
4572
  return true;
4573
#else
4574
0
  return false;
4575
0
#endif
4576
0
}
4577
4578
bool SystemInformationImplementation::QueryAIXMemory()
4579
0
{
4580
#if defined(_AIX) && defined(_SC_AIX_REALMEM)
4581
  long c = sysconf(_SC_AIX_REALMEM);
4582
  if (c <= 0) {
4583
    return false;
4584
  }
4585
4586
  this->TotalPhysicalMemory = c / 1024;
4587
4588
  return true;
4589
#else
4590
0
  return false;
4591
0
#endif
4592
0
}
4593
4594
bool SystemInformationImplementation::QueryMemoryBySysconf()
4595
0
{
4596
0
#if defined(_SC_PHYS_PAGES) && defined(_SC_PAGESIZE)
4597
  // Assume the mmap() granularity as returned by _SC_PAGESIZE is also
4598
  // the system page size. The only known system where this isn't true
4599
  // is Cygwin.
4600
0
  long p = sysconf(_SC_PHYS_PAGES);
4601
0
  long m = sysconf(_SC_PAGESIZE);
4602
4603
0
  if (p < 0 || m < 0) {
4604
0
    return false;
4605
0
  }
4606
4607
  // assume pagesize is a power of 2 and smaller 1 MiB
4608
0
  size_t pagediv = (1024 * 1024 / m);
4609
4610
0
  this->TotalPhysicalMemory = p;
4611
0
  this->TotalPhysicalMemory /= pagediv;
4612
4613
0
#  if defined(_SC_AVPHYS_PAGES)
4614
0
  p = sysconf(_SC_AVPHYS_PAGES);
4615
0
  if (p < 0) {
4616
0
    return false;
4617
0
  }
4618
4619
0
  this->AvailablePhysicalMemory = p;
4620
0
  this->AvailablePhysicalMemory /= pagediv;
4621
0
#  endif
4622
4623
0
  return true;
4624
#else
4625
  return false;
4626
#endif
4627
0
}
4628
4629
/** Query for the memory status */
4630
bool SystemInformationImplementation::QueryMemory()
4631
0
{
4632
0
  return this->QueryMemoryBySysconf();
4633
0
}
4634
4635
/** */
4636
size_t SystemInformationImplementation::GetTotalVirtualMemory() const
4637
0
{
4638
0
  return this->TotalVirtualMemory;
4639
0
}
4640
4641
/** */
4642
size_t SystemInformationImplementation::GetAvailableVirtualMemory() const
4643
0
{
4644
0
  return this->AvailableVirtualMemory;
4645
0
}
4646
4647
size_t SystemInformationImplementation::GetTotalPhysicalMemory() const
4648
0
{
4649
0
  return this->TotalPhysicalMemory;
4650
0
}
4651
4652
/** */
4653
size_t SystemInformationImplementation::GetAvailablePhysicalMemory() const
4654
0
{
4655
0
  return this->AvailablePhysicalMemory;
4656
0
}
4657
4658
/** Get Cycle differences */
4659
long long SystemInformationImplementation::GetCyclesDifference(
4660
  DELAY_FUNC DelayFunction, unsigned int uiParameter)
4661
0
{
4662
#if defined(_MSC_VER) && (_MSC_VER >= 1400)
4663
  unsigned __int64 stamp1, stamp2;
4664
4665
#  ifdef _M_ARM64
4666
  stamp1 = _ReadStatusReg(ARM64_PMCCNTR_EL0);
4667
  DelayFunction(uiParameter);
4668
  stamp2 = _ReadStatusReg(ARM64_PMCCNTR_EL0);
4669
#  else
4670
  stamp1 = __rdtsc();
4671
  DelayFunction(uiParameter);
4672
  stamp2 = __rdtsc();
4673
#  endif
4674
4675
  return stamp2 - stamp1;
4676
#elif USE_ASM_INSTRUCTIONS
4677
4678
  unsigned int edx1, eax1;
4679
  unsigned int edx2, eax2;
4680
4681
  // Calculate the frequency of the CPU instructions.
4682
  __try {
4683
    _asm {
4684
      push uiParameter ; push parameter param
4685
      mov ebx, DelayFunction ; store func in ebx
4686
4687
      RDTSC_INSTRUCTION
4688
4689
      mov esi, eax ; esi = eax
4690
      mov edi, edx ; edi = edx
4691
4692
      call ebx ; call the delay functions
4693
4694
      RDTSC_INSTRUCTION
4695
4696
      pop ebx
4697
4698
      mov edx2, edx      ; edx2 = edx
4699
      mov eax2, eax      ; eax2 = eax
4700
4701
      mov edx1, edi      ; edx2 = edi
4702
      mov eax1, esi      ; eax2 = esi
4703
    }
4704
  } __except (1) {
4705
    return -1;
4706
  }
4707
4708
  return ((((__int64)edx2 << 32) + eax2) - (((__int64)edx1 << 32) + eax1));
4709
4710
#else
4711
0
  (void)DelayFunction;
4712
0
  (void)uiParameter;
4713
0
  return -1;
4714
0
#endif
4715
0
}
4716
4717
/** Compute the delay overhead */
4718
void SystemInformationImplementation::DelayOverhead(unsigned int uiMS)
4719
0
{
4720
#if defined(_WIN32)
4721
  LARGE_INTEGER Frequency, StartCounter, EndCounter;
4722
  __int64 x;
4723
4724
  // Get the frequency of the high performance counter.
4725
  if (!QueryPerformanceFrequency(&Frequency)) {
4726
    return;
4727
  }
4728
  x = Frequency.QuadPart / 1000 * uiMS;
4729
4730
  // Get the starting position of the counter.
4731
  QueryPerformanceCounter(&StartCounter);
4732
4733
  do {
4734
    // Get the ending position of the counter.
4735
    QueryPerformanceCounter(&EndCounter);
4736
  } while (EndCounter.QuadPart - StartCounter.QuadPart == x);
4737
#endif
4738
0
  (void)uiMS;
4739
0
}
4740
4741
/** Works only for windows */
4742
bool SystemInformationImplementation::IsSMTSupported() const
4743
0
{
4744
0
  return this->Features.ExtendedFeatures.LogicalProcessorsPerPhysical > 1;
4745
0
}
4746
4747
/** Return the APIC Id. Works only for windows. */
4748
unsigned char SystemInformationImplementation::GetAPICId()
4749
0
{
4750
0
  int Regs[4] = { 0, 0, 0, 0 };
4751
4752
#if USE_CPUID
4753
  if (!this->IsSMTSupported()) {
4754
    return static_cast<unsigned char>(-1); // HT not supported
4755
  } // Logical processor = 1
4756
  call_cpuid(1, Regs);
4757
#endif
4758
4759
0
  return static_cast<unsigned char>((Regs[1] & INITIAL_APIC_ID_BITS) >> 24);
4760
0
}
4761
4762
/** Count the number of CPUs. Works only on windows. */
4763
void SystemInformationImplementation::CPUCountWindows()
4764
0
{
4765
#if defined(_WIN32)
4766
  this->NumberOfPhysicalCPU = 0;
4767
  this->NumberOfLogicalCPU = 0;
4768
4769
  using GetLogicalProcessorInformationType =
4770
    BOOL(WINAPI*)(PSYSTEM_LOGICAL_PROCESSOR_INFORMATION, PDWORD);
4771
  static GetLogicalProcessorInformationType pGetLogicalProcessorInformation =
4772
    reinterpret_cast<GetLogicalProcessorInformationType>((void*)GetProcAddress(
4773
      GetModuleHandleW(L"kernel32"), "GetLogicalProcessorInformation"));
4774
4775
  if (!pGetLogicalProcessorInformation) {
4776
    // Fallback to approximate implementation on ancient Windows versions.
4777
    SYSTEM_INFO info;
4778
    ZeroMemory(&info, sizeof(info));
4779
    GetSystemInfo(&info);
4780
    this->NumberOfPhysicalCPU =
4781
      static_cast<unsigned int>(info.dwNumberOfProcessors);
4782
    this->NumberOfLogicalCPU = this->NumberOfPhysicalCPU;
4783
    return;
4784
  }
4785
4786
  std::vector<SYSTEM_LOGICAL_PROCESSOR_INFORMATION> ProcInfo;
4787
  {
4788
    DWORD Length = 0;
4789
    DWORD rc = pGetLogicalProcessorInformation(nullptr, &Length);
4790
    assert(FALSE == rc);
4791
    (void)rc; // Silence unused variable warning
4792
    assert(GetLastError() == ERROR_INSUFFICIENT_BUFFER);
4793
    ProcInfo.resize(Length / sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION));
4794
    rc = pGetLogicalProcessorInformation(&ProcInfo[0], &Length);
4795
    assert(rc != FALSE);
4796
    (void)rc; // Silence unused variable warning
4797
  }
4798
4799
  for (SYSTEM_LOGICAL_PROCESSOR_INFORMATION const& PInfo : ProcInfo) {
4800
    if (PInfo.Relationship != RelationProcessorCore) {
4801
      continue;
4802
    }
4803
4804
    std::bitset<std::numeric_limits<ULONG_PTR>::digits> ProcMask(
4805
      (unsigned long long)PInfo.ProcessorMask);
4806
    unsigned int count = (unsigned int)ProcMask.count();
4807
    if (count == 0) { // I think this should never happen, but just to be safe.
4808
      continue;
4809
    }
4810
    this->NumberOfPhysicalCPU++;
4811
    this->NumberOfLogicalCPU += (unsigned int)count;
4812
    this->Features.ExtendedFeatures.LogicalProcessorsPerPhysical = count;
4813
  }
4814
  this->NumberOfPhysicalCPU = std::max(1u, this->NumberOfPhysicalCPU);
4815
  this->NumberOfLogicalCPU = std::max(1u, this->NumberOfLogicalCPU);
4816
#else
4817
0
#endif
4818
0
}
4819
4820
/** Return the number of logical CPUs on the system */
4821
unsigned int SystemInformationImplementation::GetNumberOfLogicalCPU() const
4822
0
{
4823
0
  return this->NumberOfLogicalCPU;
4824
0
}
4825
4826
/** Return the number of physical CPUs on the system */
4827
unsigned int SystemInformationImplementation::GetNumberOfPhysicalCPU() const
4828
0
{
4829
0
  return this->NumberOfPhysicalCPU;
4830
0
}
4831
4832
#if defined(__APPLE__)
4833
static int kw_sysctlbyname_int32(char const* name, int32_t* value)
4834
{
4835
  size_t len = sizeof(int32_t);
4836
  int err = sysctlbyname(name, value, &len, nullptr, 0);
4837
  if (err == 0) {
4838
    assert(len == sizeof(int32_t));
4839
  }
4840
  return err;
4841
}
4842
4843
static int kw_sysctlbyname_int64(char const* name, int64_t* value)
4844
{
4845
  size_t len = sizeof(int64_t);
4846
  int err = sysctlbyname(name, value, &len, nullptr, 0);
4847
  if (err == 0) {
4848
    assert(len == sizeof(int64_t));
4849
  }
4850
  return err;
4851
}
4852
#endif
4853
4854
/** For Apple use sysctlbyname calls to find system info */
4855
bool SystemInformationImplementation::ParseSysCtl()
4856
0
{
4857
#if defined(__APPLE__)
4858
  char tempBuff[128];
4859
  int32_t tempInt32 = 0;
4860
  int64_t tempInt64 = 0;
4861
  int err = 0;
4862
  size_t len;
4863
4864
  this->TotalPhysicalMemory = 0;
4865
  err = kw_sysctlbyname_int64("hw.memsize", &tempInt64);
4866
  if (err == 0) {
4867
    this->TotalPhysicalMemory = static_cast<size_t>(tempInt64 / 1024 / 1024);
4868
  }
4869
4870
  this->AvailablePhysicalMemory = 0;
4871
  vm_statistics_data_t vmstat;
4872
  mach_msg_type_number_t count = HOST_VM_INFO_COUNT;
4873
  if (host_statistics(mach_host_self(), HOST_VM_INFO,
4874
                      reinterpret_cast<host_info_t>(&vmstat),
4875
                      &count) == KERN_SUCCESS) {
4876
    err = kw_sysctlbyname_int64("hw.pagesize", &tempInt64);
4877
    if (err == 0) {
4878
      int64_t available_memory =
4879
        (vmstat.free_count + vmstat.inactive_count) * tempInt64;
4880
      this->AvailablePhysicalMemory =
4881
        static_cast<size_t>(available_memory / 1024 / 1024);
4882
    }
4883
  }
4884
4885
  // Virtual memory.
4886
  this->AvailableVirtualMemory = 0;
4887
  this->TotalVirtualMemory = 0;
4888
#  ifdef VM_SWAPUSAGE
4889
  int mib[2] = { CTL_VM, VM_SWAPUSAGE };
4890
  unsigned int miblen =
4891
    static_cast<unsigned int>(sizeof(mib) / sizeof(mib[0]));
4892
  struct xsw_usage swap;
4893
  len = sizeof(swap);
4894
  err = sysctl(mib, miblen, &swap, &len, nullptr, 0);
4895
  if (err == 0) {
4896
    this->AvailableVirtualMemory =
4897
      static_cast<size_t>(swap.xsu_avail / 1024 / 1024);
4898
    this->TotalVirtualMemory =
4899
      static_cast<size_t>(swap.xsu_total / 1024 / 1024);
4900
  }
4901
#  endif
4902
4903
  // CPU Info
4904
  this->NumberOfPhysicalCPU = 1;
4905
  err = kw_sysctlbyname_int32("hw.physicalcpu", &tempInt32);
4906
  if (err == 0) {
4907
    this->NumberOfPhysicalCPU = tempInt32;
4908
  }
4909
4910
  this->NumberOfLogicalCPU = 1;
4911
  err = kw_sysctlbyname_int32("hw.logicalcpu", &tempInt32);
4912
  if (err == 0) {
4913
    this->NumberOfLogicalCPU = tempInt32;
4914
  }
4915
4916
  this->Features.ExtendedFeatures.LogicalProcessorsPerPhysical = 1;
4917
  err = kw_sysctlbyname_int32("machdep.cpu.cores_per_package", &tempInt32);
4918
  if (err == 0) {
4919
    this->Features.ExtendedFeatures.LogicalProcessorsPerPhysical = tempInt32;
4920
  }
4921
4922
  this->CPUSpeedInMHz = 0;
4923
  err = kw_sysctlbyname_int64("hw.cpufrequency", &tempInt64);
4924
  if (err == 0) {
4925
    this->CPUSpeedInMHz = static_cast<float>(tempInt64) / 1000000.0f;
4926
  }
4927
4928
  // Chip family
4929
  // Seems only the Intel chips will have this name so if this fails it is
4930
  // a PowerPC or ARM, or something unknown
4931
  this->ChipID.Vendor = "";
4932
  this->ChipID.Family = 0;
4933
  this->ChipID.Model = 0;
4934
  this->ChipID.Revision = 0;
4935
  err = kw_sysctlbyname_int32("machdep.cpu.family", &tempInt32);
4936
  if (err != 0) // Go back to names we know but are less descriptive
4937
  {
4938
    ::memset(tempBuff, 0, sizeof(tempBuff));
4939
    len = sizeof(tempBuff) - 1; // leave a byte for null termination
4940
    err = sysctlbyname("hw.machine", &tempBuff, &len, nullptr, 0);
4941
    if (err == 0) {
4942
      std::string machineBuf(tempBuff);
4943
      if (machineBuf.find("Power") != std::string::npos) {
4944
        this->ChipID.Vendor = "IBM";
4945
4946
        err = kw_sysctlbyname_int32("hw.cputype", &tempInt32);
4947
        if (err == 0) {
4948
          this->ChipID.Family = tempInt32;
4949
        }
4950
4951
        err = kw_sysctlbyname_int32("hw.cpusubtype", &tempInt32);
4952
        if (err == 0) {
4953
          this->ChipID.Model = tempInt32;
4954
        }
4955
4956
        this->FindManufacturer();
4957
      } else if (machineBuf.find("arm64") != std::string::npos) {
4958
        this->ChipID.Vendor = "Apple";
4959
4960
        this->FindManufacturer();
4961
4962
        err = kw_sysctlbyname_int32("hw.optional.floatingpoint", &tempInt32);
4963
        if (err == 0) {
4964
          this->Features.HasFPU = static_cast<bool>(tempInt32);
4965
        }
4966
      }
4967
    }
4968
  } else {
4969
    // Should be an Intel Chip.
4970
    err = kw_sysctlbyname_int32("machdep.cpu.family", &tempInt32);
4971
    if (err == 0) {
4972
      this->ChipID.Family = tempInt32;
4973
    }
4974
4975
    // Chip Vendor
4976
    ::memset(tempBuff, 0, sizeof(tempBuff));
4977
    len = sizeof(tempBuff) - 1; // leave a byte for null termination
4978
    err = sysctlbyname("machdep.cpu.vendor", tempBuff, &len, nullptr, 0);
4979
    if (err == 0) {
4980
      this->ChipID.Vendor = tempBuff;
4981
    }
4982
    this->FindManufacturer();
4983
4984
    // Chip Model
4985
    err = kw_sysctlbyname_int32("machdep.cpu.model", &tempInt32);
4986
    if (err == 0) {
4987
      this->ChipID.Model = tempInt32;
4988
    }
4989
4990
    // Chip Stepping
4991
    err = kw_sysctlbyname_int32("machdep.cpu.stepping", &tempInt32);
4992
    if (err == 0) {
4993
      this->ChipID.Revision = tempInt32;
4994
    }
4995
4996
    // feature string
4997
    char* buf = nullptr;
4998
    size_t allocSize = 128;
4999
5000
    err = 0;
5001
    len = 0;
5002
5003
    // sysctlbyname() will return with err==0 && len==0 if the buffer is too
5004
    // small
5005
    while (err == 0 && len == 0) {
5006
      delete[] buf;
5007
      allocSize *= 2;
5008
      buf = new char[allocSize];
5009
      if (!buf) {
5010
        break;
5011
      }
5012
      buf[0] = ' ';
5013
      len = allocSize - 2; // keep space for leading and trailing space
5014
      err = sysctlbyname("machdep.cpu.features", buf + 1, &len, nullptr, 0);
5015
    }
5016
    if (err == 0 && buf && len) {
5017
      // now we can match every flags as space + flag + space
5018
      buf[len + 1] = ' ';
5019
      std::string cpuflags(buf, len + 2);
5020
5021
      if (cpuflags.find(" FPU ") != std::string::npos) {
5022
        this->Features.HasFPU = true;
5023
      }
5024
      if (cpuflags.find(" TSC ") != std::string::npos) {
5025
        this->Features.HasTSC = true;
5026
      }
5027
      if (cpuflags.find(" MMX ") != std::string::npos) {
5028
        this->Features.HasMMX = true;
5029
      }
5030
      if (cpuflags.find(" SSE ") != std::string::npos) {
5031
        this->Features.HasSSE = true;
5032
      }
5033
      if (cpuflags.find(" SSE2 ") != std::string::npos) {
5034
        this->Features.HasSSE2 = true;
5035
      }
5036
      if (cpuflags.find(" APIC ") != std::string::npos) {
5037
        this->Features.HasAPIC = true;
5038
      }
5039
      if (cpuflags.find(" CMOV ") != std::string::npos) {
5040
        this->Features.HasCMOV = true;
5041
      }
5042
      if (cpuflags.find(" MTRR ") != std::string::npos) {
5043
        this->Features.HasMTRR = true;
5044
      }
5045
      if (cpuflags.find(" ACPI ") != std::string::npos) {
5046
        this->Features.HasACPI = true;
5047
      }
5048
    }
5049
    delete[] buf;
5050
  }
5051
5052
  // brand string
5053
  this->ChipID.ProcessorName = "";
5054
  this->ChipID.ModelName = "";
5055
  ::memset(tempBuff, 0, sizeof(tempBuff));
5056
  len = sizeof(tempBuff) - 1; // leave a byte for null termination
5057
  err = sysctlbyname("machdep.cpu.brand_string", tempBuff, &len, nullptr, 0);
5058
  if (err == 0) {
5059
    this->ChipID.ProcessorName = tempBuff;
5060
    this->ChipID.ModelName = tempBuff;
5061
  }
5062
5063
  // L1 Cache size
5064
  this->Features.L1CacheSize = 0;
5065
  err = kw_sysctlbyname_int64("hw.l1icachesize", &tempInt64);
5066
  if (err == 0) {
5067
    this->Features.L1CacheSize = static_cast<int>(tempInt64);
5068
  }
5069
5070
  // L2 Cache size
5071
  this->Features.L2CacheSize = 0;
5072
  err = kw_sysctlbyname_int64("hw.l2cachesize", &tempInt64);
5073
  if (err == 0) {
5074
    this->Features.L2CacheSize = static_cast<int>(tempInt64);
5075
  }
5076
5077
  return true;
5078
#else
5079
0
  return false;
5080
0
#endif
5081
0
}
5082
5083
/** Extract a value from sysctl command */
5084
std::string SystemInformationImplementation::ExtractValueFromSysCtl(
5085
  char const* word)
5086
0
{
5087
0
  size_t pos = this->SysCtlBuffer.find(word);
5088
0
  if (pos != std::string::npos) {
5089
0
    pos = this->SysCtlBuffer.find(": ", pos);
5090
0
    size_t pos2 = this->SysCtlBuffer.find('\n', pos);
5091
0
    if (pos != std::string::npos && pos2 != std::string::npos) {
5092
0
      return this->SysCtlBuffer.substr(pos + 2, pos2 - pos - 2);
5093
0
    }
5094
0
  }
5095
0
  return "";
5096
0
}
5097
5098
/** Run a given process */
5099
std::string SystemInformationImplementation::RunProcess(
5100
  std::vector<char const*> args)
5101
0
{
5102
0
  std::string out;
5103
5104
  // Run the application
5105
0
  kwsysProcess* gp = kwsysProcess_New();
5106
0
  kwsysProcess_SetCommand(gp, args.data());
5107
0
  kwsysProcess_SetOption(gp, kwsysProcess_Option_HideWindow, 1);
5108
5109
0
  kwsysProcess_Execute(gp);
5110
5111
0
  char* data = nullptr;
5112
0
  int length;
5113
0
  double timeout = 255;
5114
0
  int pipe; // pipe id as returned by kwsysProcess_WaitForData()
5115
5116
0
  while ((static_cast<void>(
5117
0
            pipe = kwsysProcess_WaitForData(gp, &data, &length, &timeout)),
5118
0
          (pipe == kwsysProcess_Pipe_STDOUT ||
5119
0
           pipe == kwsysProcess_Pipe_STDERR))) // wait for 1s
5120
0
  {
5121
    // Keep stdout, ignore stderr.
5122
0
    if (pipe == kwsysProcess_Pipe_STDOUT) {
5123
0
      out.append(data, length);
5124
0
    }
5125
0
  }
5126
0
  kwsysProcess_WaitForExit(gp, nullptr);
5127
5128
0
  int result = 0;
5129
0
  switch (kwsysProcess_GetState(gp)) {
5130
0
    case kwsysProcess_State_Exited: {
5131
0
      result = kwsysProcess_GetExitValue(gp);
5132
0
    } break;
5133
0
    case kwsysProcess_State_Error: {
5134
0
      std::cerr << "Error: Could not run " << args[0] << ":\n";
5135
0
      std::cerr << kwsysProcess_GetErrorString(gp) << "\n";
5136
0
    } break;
5137
0
    case kwsysProcess_State_Exception: {
5138
0
      std::cerr << "Error: " << args[0] << " terminated with an exception: "
5139
0
                << kwsysProcess_GetExceptionString(gp) << "\n";
5140
0
    } break;
5141
0
    case kwsysProcess_State_Starting:
5142
0
    case kwsysProcess_State_Executing:
5143
0
    case kwsysProcess_State_Expired:
5144
0
    case kwsysProcess_State_Killed: {
5145
      // Should not get here.
5146
0
      std::cerr << "Unexpected ending state after running " << args[0]
5147
0
                << std::endl;
5148
0
    } break;
5149
0
    default:
5150
0
      break;
5151
0
  }
5152
0
  kwsysProcess_Delete(gp);
5153
0
  if (result) {
5154
0
    std::cerr << "Error " << args[0] << " returned :" << result << "\n";
5155
0
  }
5156
0
  return out;
5157
0
}
5158
5159
std::string SystemInformationImplementation::ParseValueFromKStat(
5160
  char const* arguments)
5161
0
{
5162
0
  std::vector<std::string> args_string;
5163
0
  std::string command = arguments;
5164
0
  size_t start = std::string::npos;
5165
0
  size_t pos = command.find(' ', 0);
5166
0
  while (pos != std::string::npos) {
5167
0
    bool inQuotes = false;
5168
    // Check if we are between quotes
5169
0
    size_t b0 = command.find('"', 0);
5170
0
    size_t b1 = command.find('"', b0 + 1);
5171
0
    while (b0 != std::string::npos && b1 != std::string::npos && b1 > b0) {
5172
0
      if (pos > b0 && pos < b1) {
5173
0
        inQuotes = true;
5174
0
        break;
5175
0
      }
5176
0
      b0 = command.find('"', b1 + 1);
5177
0
      b1 = command.find('"', b0 + 1);
5178
0
    }
5179
5180
0
    if (!inQuotes) {
5181
0
      args_string.push_back(command.substr(start + 1, pos - start - 1));
5182
0
      std::string& arg = args_string.back();
5183
5184
      // Remove the quotes if any
5185
0
      arg.erase(std::remove(arg.begin(), arg.end(), '"'), arg.end());
5186
0
      start = pos;
5187
0
    }
5188
0
    pos = command.find(' ', pos + 1);
5189
0
  }
5190
0
  command.erase(0, start + 1);
5191
0
  args_string.push_back(command);
5192
5193
0
  std::vector<char const*> args;
5194
0
  args.reserve(3 + args_string.size());
5195
0
  args.push_back("kstat");
5196
0
  args.push_back("-p");
5197
0
  for (auto const& i : args_string) {
5198
0
    args.push_back(i.c_str());
5199
0
  }
5200
0
  args.push_back(nullptr);
5201
5202
0
  std::string buffer = this->RunProcess(args);
5203
5204
0
  std::string value;
5205
0
  for (size_t i = buffer.size() - 1; i > 0; i--) {
5206
0
    if (buffer[i] == ' ' || buffer[i] == '\t') {
5207
0
      break;
5208
0
    }
5209
0
    if (buffer[i] != '\n' && buffer[i] != '\r') {
5210
0
      value.insert(0u, 1, buffer[i]);
5211
0
    }
5212
0
  }
5213
0
  return value;
5214
0
}
5215
5216
/** Querying for system information from Solaris */
5217
bool SystemInformationImplementation::QuerySolarisMemory()
5218
0
{
5219
#if defined(__SVR4) && defined(__sun)
5220
// Solaris allows querying this value by sysconf, but if this is
5221
// a 32 bit process on a 64 bit host the returned memory will be
5222
// limited to 4GiB. So if this is a 32 bit process or if the sysconf
5223
// method fails use the kstat interface.
5224
#  if SIZEOF_VOID_P == 8
5225
  if (this->QueryMemoryBySysconf()) {
5226
    return true;
5227
  }
5228
#  endif
5229
5230
  char* tail;
5231
  unsigned long totalMemory =
5232
    strtoul(this->ParseValueFromKStat("-s physmem").c_str(), &tail, 0);
5233
  this->TotalPhysicalMemory = totalMemory / 128;
5234
5235
  return true;
5236
#else
5237
0
  return false;
5238
0
#endif
5239
0
}
5240
5241
bool SystemInformationImplementation::QuerySolarisProcessor()
5242
0
{
5243
0
  if (!this->QueryProcessorBySysconf()) {
5244
0
    return false;
5245
0
  }
5246
5247
  // Parse values
5248
0
  this->CPUSpeedInMHz = static_cast<float>(
5249
0
    atoi(this->ParseValueFromKStat("-s clock_MHz").c_str()));
5250
5251
  // Chip family
5252
0
  this->ChipID.Family = 0;
5253
5254
  // Chip Model
5255
0
  this->ChipID.ProcessorName = this->ParseValueFromKStat("-s cpu_type");
5256
0
  this->ChipID.Model = 0;
5257
5258
  // Chip Vendor
5259
0
  if (this->ChipID.ProcessorName != "i386") {
5260
0
    this->ChipID.Vendor = "Sun";
5261
0
    this->FindManufacturer();
5262
0
  }
5263
5264
0
  return true;
5265
0
}
5266
5267
/** Querying for system information from Haiku OS */
5268
bool SystemInformationImplementation::QueryHaikuInfo()
5269
0
{
5270
#if defined(__HAIKU__)
5271
5272
  // CPU count
5273
  system_info info;
5274
  get_system_info(&info);
5275
  this->NumberOfPhysicalCPU = info.cpu_count;
5276
5277
  // CPU speed
5278
  uint32 topologyNodeCount = 0;
5279
  cpu_topology_node_info* topology = 0;
5280
  get_cpu_topology_info(0, &topologyNodeCount);
5281
  if (topologyNodeCount != 0)
5282
    topology = new cpu_topology_node_info[topologyNodeCount];
5283
  get_cpu_topology_info(topology, &topologyNodeCount);
5284
5285
  for (uint32 i = 0; i < topologyNodeCount; i++) {
5286
    if (topology[i].type == B_TOPOLOGY_CORE) {
5287
      this->CPUSpeedInMHz =
5288
        topology[i].data.core.default_frequency / 1000000.0f;
5289
      break;
5290
    }
5291
  }
5292
5293
  delete[] topology;
5294
5295
  // Physical Memory
5296
  this->TotalPhysicalMemory = (info.max_pages * B_PAGE_SIZE) / (1024 * 1024);
5297
  this->AvailablePhysicalMemory = this->TotalPhysicalMemory -
5298
    ((info.used_pages * B_PAGE_SIZE) / (1024 * 1024));
5299
5300
  // NOTE: get_system_info_etc is currently a private call so just set to 0
5301
  // until it becomes public
5302
  this->TotalVirtualMemory = 0;
5303
  this->AvailableVirtualMemory = 0;
5304
5305
  // Retrieve cpuid_info union for cpu 0
5306
  cpuid_info cpu_info;
5307
  get_cpuid(&cpu_info, 0, 0);
5308
5309
  // Chip Vendor
5310
  // Use a temporary buffer so that we can add NULL termination to the string
5311
  char vbuf[13];
5312
  strncpy(vbuf, cpu_info.eax_0.vendor_id, 12);
5313
  vbuf[12] = '\0';
5314
  this->ChipID.Vendor = vbuf;
5315
5316
  this->FindManufacturer();
5317
5318
  // Retrieve cpuid_info union for cpu 0 this time using a register value of 1
5319
  get_cpuid(&cpu_info, 1, 0);
5320
5321
  this->NumberOfLogicalCPU = cpu_info.eax_1.logical_cpus;
5322
5323
  // Chip type
5324
  this->ChipID.Type = cpu_info.eax_1.type;
5325
5326
  // Chip family
5327
  this->ChipID.Family = cpu_info.eax_1.family;
5328
5329
  // Chip Model
5330
  this->ChipID.Model = cpu_info.eax_1.model;
5331
5332
  // Chip Revision
5333
  this->ChipID.Revision = cpu_info.eax_1.stepping;
5334
5335
  // Chip Extended Family
5336
  this->ChipID.ExtendedFamily = cpu_info.eax_1.extended_family;
5337
5338
  // Chip Extended Model
5339
  this->ChipID.ExtendedModel = cpu_info.eax_1.extended_model;
5340
5341
  // Get ChipID.ProcessorName from other information already gathered
5342
  this->RetrieveClassicalCPUIdentity();
5343
5344
  // Cache size
5345
  this->Features.L1CacheSize = 0;
5346
  this->Features.L2CacheSize = 0;
5347
5348
  return true;
5349
5350
#else
5351
0
  return false;
5352
0
#endif
5353
0
}
5354
5355
bool SystemInformationImplementation::QueryQNXMemory()
5356
0
{
5357
#if defined(__QNX__)
5358
  std::string buffer;
5359
  std::vector<char const*> args;
5360
  args.clear();
5361
5362
  args.push_back("showmem");
5363
  args.push_back("-S");
5364
  args.push_back(0);
5365
  buffer = this->RunProcess(args);
5366
  args.clear();
5367
5368
  size_t pos = buffer.find("System RAM:");
5369
  if (pos == std::string::npos)
5370
    return false;
5371
  pos = buffer.find(':', pos);
5372
  size_t pos2 = buffer.find("M (", pos);
5373
  if (pos2 == std::string::npos)
5374
    return false;
5375
5376
  pos++;
5377
  while (buffer[pos] == ' ')
5378
    pos++;
5379
5380
  buffer.erase(0, pos);
5381
  buffer.resize(pos2);
5382
  this->TotalPhysicalMemory = atoi(buffer.c_str());
5383
  return true;
5384
#endif
5385
0
  return false;
5386
0
}
5387
5388
bool SystemInformationImplementation::QueryBSDMemory()
5389
0
{
5390
#if defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__NetBSD__) ||    \
5391
  defined(__DragonFly__)
5392
  int ctrl[2] = { CTL_HW, HW_PHYSMEM };
5393
#  if defined(HW_PHYSMEM64)
5394
  int64_t k;
5395
  ctrl[1] = HW_PHYSMEM64;
5396
#  else
5397
  int k;
5398
#  endif
5399
  size_t sz = sizeof(k);
5400
5401
  if (sysctl(ctrl, 2, &k, &sz, nullptr, 0) != 0) {
5402
    return false;
5403
  }
5404
5405
  this->TotalPhysicalMemory = k >> 10 >> 10;
5406
5407
  return true;
5408
#else
5409
0
  return false;
5410
0
#endif
5411
0
}
5412
5413
bool SystemInformationImplementation::QueryQNXProcessor()
5414
0
{
5415
#if defined(__QNX__)
5416
  // the output on my QNX 6.4.1 looks like this:
5417
  // Processor1: 686 Pentium II Stepping 3 2175MHz FPU
5418
  std::string buffer;
5419
  std::vector<char const*> args;
5420
  args.clear();
5421
5422
  args.push_back("pidin");
5423
  args.push_back("info");
5424
  args.push_back(0);
5425
  buffer = this->RunProcess(args);
5426
  args.clear();
5427
5428
  size_t pos = buffer.find("Processor1:");
5429
  if (pos == std::string::npos)
5430
    return false;
5431
5432
  size_t pos2 = buffer.find("MHz", pos);
5433
  if (pos2 == std::string::npos)
5434
    return false;
5435
5436
  size_t pos3 = pos2;
5437
  while (buffer[pos3] != ' ')
5438
    --pos3;
5439
5440
  this->CPUSpeedInMHz = atoi(buffer.substr(pos3 + 1, pos2 - pos3 - 1).c_str());
5441
5442
  pos2 = buffer.find(" Stepping", pos);
5443
  if (pos2 != std::string::npos) {
5444
    pos2 = buffer.find(' ', pos2 + 1);
5445
    if (pos2 != std::string::npos && pos2 < pos3) {
5446
      this->ChipID.Revision =
5447
        atoi(buffer.substr(pos2 + 1, pos3 - pos2).c_str());
5448
    }
5449
  }
5450
5451
  this->NumberOfPhysicalCPU = 0;
5452
  do {
5453
    pos = buffer.find("\nProcessor", pos + 1);
5454
    ++this->NumberOfPhysicalCPU;
5455
  } while (pos != std::string::npos);
5456
  this->NumberOfLogicalCPU = 1;
5457
5458
  return true;
5459
#else
5460
0
  return false;
5461
0
#endif
5462
0
}
5463
5464
bool SystemInformationImplementation::QueryBSDProcessor()
5465
0
{
5466
#if defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__NetBSD__) ||    \
5467
  defined(__DragonFly__)
5468
  int k;
5469
  size_t sz = sizeof(k);
5470
#  ifdef HW_NCPUONLINE
5471
  int ctrl[2] = { CTL_HW, HW_NCPUONLINE };
5472
#  else
5473
  int ctrl[2] = { CTL_HW, HW_NCPU };
5474
#  endif
5475
5476
  if (sysctl(ctrl, 2, &k, &sz, nullptr, 0) != 0) {
5477
    return false;
5478
  }
5479
5480
  this->NumberOfPhysicalCPU = k;
5481
  this->NumberOfLogicalCPU = this->NumberOfPhysicalCPU;
5482
5483
#  if defined(HW_CPUSPEED)
5484
  ctrl[1] = HW_CPUSPEED;
5485
5486
  if (sysctl(ctrl, 2, &k, &sz, nullptr, 0) != 0) {
5487
    return false;
5488
  }
5489
5490
  this->CPUSpeedInMHz = (float)k;
5491
#  endif
5492
5493
#  if defined(CPU_SSE)
5494
  ctrl[0] = CTL_MACHDEP;
5495
  ctrl[1] = CPU_SSE;
5496
5497
  if (sysctl(ctrl, 2, &k, &sz, nullptr, 0) != 0) {
5498
    return false;
5499
  }
5500
5501
  this->Features.HasSSE = (k > 0);
5502
#  endif
5503
5504
#  if defined(CPU_SSE2)
5505
  ctrl[0] = CTL_MACHDEP;
5506
  ctrl[1] = CPU_SSE2;
5507
5508
  if (sysctl(ctrl, 2, &k, &sz, nullptr, 0) != 0) {
5509
    return false;
5510
  }
5511
5512
  this->Features.HasSSE2 = (k > 0);
5513
#  endif
5514
5515
#  if defined(CPU_CPUVENDOR)
5516
  ctrl[0] = CTL_MACHDEP;
5517
  ctrl[1] = CPU_CPUVENDOR;
5518
  char vbuf[25];
5519
  ::memset(vbuf, 0, sizeof(vbuf));
5520
  sz = sizeof(vbuf) - 1;
5521
  if (sysctl(ctrl, 2, vbuf, &sz, nullptr, 0) != 0) {
5522
    return false;
5523
  }
5524
5525
  this->ChipID.Vendor = vbuf;
5526
  this->FindManufacturer();
5527
#  endif
5528
5529
  return true;
5530
#else
5531
0
  return false;
5532
0
#endif
5533
0
}
5534
5535
bool SystemInformationImplementation::QueryHPUXMemory()
5536
0
{
5537
#if defined(__hpux)
5538
  unsigned long tv = 0;
5539
  unsigned long tp = 0;
5540
  unsigned long av = 0;
5541
  unsigned long ap = 0;
5542
  struct pst_static pst;
5543
  struct pst_dynamic pdy;
5544
5545
  unsigned long ps = 0;
5546
  if (pstat_getstatic(&pst, sizeof(pst), (size_t)1, 0) == -1) {
5547
    return false;
5548
  }
5549
5550
  ps = pst.page_size;
5551
  tp = pst.physical_memory * ps;
5552
  tv = (pst.physical_memory + pst.pst_maxmem) * ps;
5553
  if (pstat_getdynamic(&pdy, sizeof(pdy), (size_t)1, 0) == -1) {
5554
    return false;
5555
  }
5556
5557
  ap = tp - pdy.psd_rm * ps;
5558
  av = tv - pdy.psd_vm;
5559
  this->TotalVirtualMemory = tv >> 10 >> 10;
5560
  this->TotalPhysicalMemory = tp >> 10 >> 10;
5561
  this->AvailableVirtualMemory = av >> 10 >> 10;
5562
  this->AvailablePhysicalMemory = ap >> 10 >> 10;
5563
  return true;
5564
#else
5565
0
  return false;
5566
0
#endif
5567
0
}
5568
5569
bool SystemInformationImplementation::QueryHPUXProcessor()
5570
0
{
5571
#if defined(__hpux)
5572
#  if defined(KWSYS_SYS_HAS_MPCTL_H)
5573
  int c = mpctl(MPC_GETNUMSPUS_SYS, 0, 0);
5574
  if (c <= 0) {
5575
    return false;
5576
  }
5577
5578
  this->NumberOfPhysicalCPU = c;
5579
  this->NumberOfLogicalCPU = this->NumberOfPhysicalCPU;
5580
5581
  long t = sysconf(_SC_CPU_VERSION);
5582
5583
  if (t == -1) {
5584
    return false;
5585
  }
5586
5587
  switch (t) {
5588
    case CPU_PA_RISC1_0:
5589
      this->ChipID.Vendor = "Hewlett-Packard";
5590
      this->ChipID.Family = 0x100;
5591
      break;
5592
    case CPU_PA_RISC1_1:
5593
      this->ChipID.Vendor = "Hewlett-Packard";
5594
      this->ChipID.Family = 0x110;
5595
      break;
5596
    case CPU_PA_RISC2_0:
5597
      this->ChipID.Vendor = "Hewlett-Packard";
5598
      this->ChipID.Family = 0x200;
5599
      break;
5600
#    if defined(CPU_HP_INTEL_EM_1_0) || defined(CPU_IA64_ARCHREV_0)
5601
#      ifdef CPU_HP_INTEL_EM_1_0
5602
    case CPU_HP_INTEL_EM_1_0:
5603
#      endif
5604
#      ifdef CPU_IA64_ARCHREV_0
5605
    case CPU_IA64_ARCHREV_0:
5606
#      endif
5607
      this->ChipID.Vendor = "GenuineIntel";
5608
      this->Features.HasIA64 = true;
5609
      break;
5610
#    endif
5611
    default:
5612
      return false;
5613
  }
5614
5615
  this->FindManufacturer();
5616
5617
  return true;
5618
#  else
5619
  return false;
5620
#  endif
5621
#else
5622
0
  return false;
5623
0
#endif
5624
0
}
5625
5626
/** Query the operating system information */
5627
bool SystemInformationImplementation::QueryOSInformation()
5628
0
{
5629
#if defined(_WIN32)
5630
5631
  this->OSName = "Windows";
5632
5633
  OSVERSIONINFOEXW osvi = {};
5634
  osvi.dwOSVersionInfoSize = sizeof(osvi);
5635
#  ifdef KWSYS_WINDOWS_DEPRECATED_GetVersionEx
5636
#    pragma warning(push)
5637
#    ifdef __INTEL_COMPILER
5638
#      pragma warning(disable : 1478)
5639
#    elif defined __clang__
5640
#      pragma clang diagnostic push
5641
#      pragma clang diagnostic ignored "-Wdeprecated-declarations"
5642
#    else
5643
#      pragma warning(disable : 4996)
5644
#    endif
5645
#  endif
5646
  if (!GetVersionExW((OSVERSIONINFOW*)&osvi)) {
5647
    return false;
5648
  }
5649
#  ifdef KWSYS_WINDOWS_DEPRECATED_GetVersionEx
5650
#    ifdef __clang__
5651
#      pragma clang diagnostic pop
5652
#    else
5653
#      pragma warning(pop)
5654
#    endif
5655
#  endif
5656
5657
  // Produce the release like it is displayed in `cmd`
5658
  this->OSRelease = std::to_string(osvi.dwMajorVersion) + '.' +
5659
    std::to_string(osvi.dwMinorVersion) + '.' +
5660
    std::to_string(osvi.dwBuildNumber & 0xFFFF);
5661
5662
  struct VersionNames
5663
  {
5664
    char const* workstation;
5665
    char const* server;
5666
  };
5667
5668
  std::map<std::pair<DWORD, DWORD>, VersionNames> const products = {
5669
    // clang-format off
5670
    { { 10,  0 }, { "10",    "2016"    } },
5671
    { {  6,  3 }, { "8.1",   "2012 R2" } },
5672
    { {  6,  2 }, { "8",     "2012"    } },
5673
    { {  6,  1 }, { "7",     "2008 R2" } },
5674
    { {  6,  0 }, { "Vista", "2008"    } },
5675
    { {  5,  2 }, { "XP",    "2003"    } },
5676
    { {  5,  1 }, { "XP",    ".NET"    } },
5677
    { {  5,  0 }, { "2000",  "2000"    } },
5678
    { {  4, 90 }, { "Me",    ""        } },
5679
    { {  4, 10 }, { "98",    ""        } },
5680
    { {  4,  0 }, { "95",    "NT 4.0"  } },
5681
    { {  3, 51 }, {   "",    "NT 3.51" } },
5682
    { {  3, 10 }, { "3.1",   ""        } },
5683
    { {  3,  0 }, { "3.0",   ""        } },
5684
    { {  2,  0 }, { "2.0",   ""        } },
5685
    // clang-format on
5686
  };
5687
5688
  this->OSVersion = "Windows ";
5689
  if (osvi.wProductType == VER_NT_SERVER) {
5690
    this->OSVersion += "Server ";
5691
  }
5692
5693
  auto const it = products.find({ osvi.dwMajorVersion, osvi.dwMinorVersion });
5694
  if (it != products.end()) {
5695
    bool const useServer =
5696
      (osvi.dwPlatformId == VER_PLATFORM_WIN32_NT &&
5697
       (osvi.dwMajorVersion <= 4 || osvi.wProductType != VER_NT_WORKSTATION));
5698
    this->OSVersion += useServer ? it->second.server : it->second.workstation;
5699
  } else {
5700
    this->OSVersion += "Unknown Version";
5701
  }
5702
5703
  if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 2) {
5704
    // special case for Windows XP x64
5705
    if (osvi.wProductType == VER_NT_WORKSTATION) {
5706
      this->OSVersion += " x64";
5707
    }
5708
5709
    // special case for Windows Server 2003 R2
5710
    else if (GetSystemMetrics(SM_SERVERR2) != 0) {
5711
      this->OSVersion += " R2";
5712
    }
5713
  }
5714
5715
  // special case for Windows 98 SE
5716
  else if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 10) {
5717
    if (osvi.szCSDVersion[1] == 'A') {
5718
      this->OSVersion += " SE";
5719
    }
5720
  }
5721
5722
  // special case for Windows 95 OSR 2
5723
  else if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 0) {
5724
    if (osvi.szCSDVersion[1] == 'C') {
5725
      this->OSVersion += " OSR 2.5";
5726
    } else if (osvi.szCSDVersion[1] == 'B') {
5727
      this->OSVersion += " OSR 2";
5728
    }
5729
  }
5730
5731
  if (osvi.wSuiteMask & VER_SUITE_DATACENTER) {
5732
    this->OSVersion += " DataCenter";
5733
  } else if (osvi.wSuiteMask & VER_SUITE_ENTERPRISE) {
5734
    this->OSVersion += " Enterprise";
5735
  }
5736
5737
  // append service pack (if any)
5738
  if (osvi.szCSDVersion[0] != 0 && osvi.szCSDVersion[0] != ' ') {
5739
    char buffer[256];
5740
    snprintf(buffer, sizeof(buffer), " %ls", osvi.szCSDVersion);
5741
    this->OSVersion += buffer;
5742
  }
5743
5744
  // Get the hostname
5745
  WORD wVersionRequested;
5746
  WSADATA wsaData;
5747
  char name[255];
5748
  wVersionRequested = MAKEWORD(2, 0);
5749
5750
  if (WSAStartup(wVersionRequested, &wsaData) == 0) {
5751
    gethostname(name, sizeof(name));
5752
    WSACleanup();
5753
  }
5754
  this->Hostname = name;
5755
5756
  char const* arch = getenv("PROCESSOR_ARCHITECTURE");
5757
  char const* wow64 = getenv("PROCESSOR_ARCHITEW6432");
5758
  if (arch) {
5759
    this->OSPlatform = arch;
5760
  }
5761
5762
  if (wow64) {
5763
    // the PROCESSOR_ARCHITEW6432 is only defined when running 32bit programs
5764
    // on 64bit OS
5765
    this->OSIs64Bit = true;
5766
  } else if (arch) {
5767
    // all values other than x86 map to 64bit architectures
5768
    this->OSIs64Bit = (strncmp(arch, "x86", 3) != 0);
5769
  }
5770
5771
#else
5772
5773
0
  struct utsname unameInfo;
5774
0
  int errorFlag = uname(&unameInfo);
5775
0
  if (errorFlag == 0) {
5776
0
    this->OSName = unameInfo.sysname;
5777
0
    this->Hostname = unameInfo.nodename;
5778
0
    this->OSRelease = unameInfo.release;
5779
0
    this->OSVersion = unameInfo.version;
5780
0
    this->OSPlatform = unameInfo.machine;
5781
5782
    // This is still insufficient to capture 64bit architecture such
5783
    // powerpc and possible mips and sparc
5784
0
    if (this->OSPlatform.find_first_of("64") != std::string::npos) {
5785
0
      this->OSIs64Bit = true;
5786
0
    }
5787
0
  }
5788
5789
#  ifdef __APPLE__
5790
  this->OSName = "Unknown Apple OS";
5791
  this->OSRelease = "Unknown product version";
5792
  this->OSVersion = "Unknown build version";
5793
5794
  this->CallSwVers("-productName", this->OSName);
5795
  this->CallSwVers("-productVersion", this->OSRelease);
5796
  this->CallSwVers("-buildVersion", this->OSVersion);
5797
#  endif
5798
5799
0
#endif
5800
5801
0
  return true;
5802
0
}
5803
5804
int SystemInformationImplementation::CallSwVers(char const* arg,
5805
                                                std::string& ver)
5806
0
{
5807
#ifdef __APPLE__
5808
  std::vector<char const*> args;
5809
  args.push_back("sw_vers");
5810
  args.push_back(arg);
5811
  args.push_back(nullptr);
5812
  ver = this->RunProcess(args);
5813
  this->TrimNewline(ver);
5814
#else
5815
  // avoid C4100
5816
0
  (void)arg;
5817
0
  (void)ver;
5818
0
#endif
5819
0
  return 0;
5820
0
}
5821
5822
void SystemInformationImplementation::TrimNewline(std::string& output)
5823
0
{
5824
  // remove \r
5825
0
  std::string::size_type pos = 0;
5826
0
  while ((pos = output.find('\r', pos)) != std::string::npos) {
5827
0
    output.erase(pos);
5828
0
  }
5829
5830
  // remove \n
5831
0
  pos = 0;
5832
0
  while ((pos = output.find('\n', pos)) != std::string::npos) {
5833
0
    output.erase(pos);
5834
0
  }
5835
0
}
5836
5837
/** Return true if the machine is 64 bits */
5838
bool SystemInformationImplementation::Is64Bits() const
5839
0
{
5840
0
  return this->OSIs64Bit;
5841
0
}
5842
}