Coverage Report

Created: 2026-10-28 06:38

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