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