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