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