Coverage Report

Created: 2026-02-09 06:05

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