Coverage Report

Created: 2026-03-12 06:35

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