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