ENH: fix for Vista
[cmake.git] / Source / kwsys / SystemInformation.cxx
blob65596ece07e12b2d35dc65eb782a29406da87656
1 /*=========================================================================
3 Program: BatchMake
4 Module: $RCSfile: SystemInformation.cxx,v $
5 Language: C++
6 Date: $Date: 2008-10-16 23:30:40 $
7 Version: $Revision: 1.23.2.1 $
8 Copyright (c) 2005 Insight Consortium. All rights reserved.
9 See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
12 This software is distributed WITHOUT ANY WARRANTY; without even
13 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
14 PURPOSE. See the above copyright notices for more information.
15 =========================================================================*/
16 #include "kwsysPrivate.h"
17 #include KWSYS_HEADER(FundamentalType.h)
18 #include KWSYS_HEADER(stl/string)
19 #include KWSYS_HEADER(stl/vector)
20 #include KWSYS_HEADER(ios/iosfwd)
21 #include KWSYS_HEADER(SystemInformation.hxx)
22 #include KWSYS_HEADER(Process.h)
23 #include KWSYS_HEADER(ios/iostream)
24 #include KWSYS_HEADER(ios/sstream)
25 // Work-around CMake dependency scanning limitation. This must
26 // duplicate the above list of headers.
27 #if 0
28 # include "FundamentalType.h.in"
29 # include "SystemInformation.hxx.in"
30 # include "Process.h.in"
31 # include "Configure.hxx.in"
32 # include "kwsys_stl.hxx.in"
33 # include "kwsys_stl_vector.in"
34 # include "kwsys_stl_iosfwd.in"
35 # include "kwsys_ios_sstream.h.in"
36 # include "kwsys_ios_iostream.h.in"
37 #endif
40 #ifndef WIN32
41 # include <sys/utsname.h> // int uname(struct utsname *buf);
42 #endif
44 #ifdef _WIN32
45 # include <windows.h>
46 #endif
48 #ifdef __linux
49 # include <sys/procfs.h>
50 # include <sys/types.h>
51 # include <unistd.h>
52 # include <fcntl.h>
53 # include <ctype.h> // int isdigit(int c);
54 # include <errno.h> // extern int errno;
55 # include <sys/time.h>
56 #elif __hpux
57 # include <sys/param.h>
58 # include <sys/pstat.h>
59 #endif
61 #include <memory.h>
62 #include <stdlib.h>
63 #include <stdio.h>
64 #include <string.h>
68 namespace KWSYS_NAMESPACE
71 // Create longlong
72 #if KWSYS_USE_LONG_LONG
73 typedef long long LongLong;
74 #elif KWSYS_USE___INT64
75 typedef __int64 LongLong;
76 #else
77 # error "No Long Long"
78 #endif
80 // Define SystemInformationImplementation class
81 typedef void (*DELAY_FUNC)(unsigned int uiMS);
83 class SystemInformationImplementation
86 public:
87 SystemInformationImplementation ();
88 ~SystemInformationImplementation ();
90 const char * GetVendorString();
91 const char * GetVendorID();
92 kwsys_stl::string GetTypeID();
93 kwsys_stl::string GetFamilyID();
94 kwsys_stl::string GetModelID();
95 kwsys_stl::string GetSteppingCode();
96 const char * GetExtendedProcessorName();
97 const char * GetProcessorSerialNumber();
98 int GetProcessorCacheSize();
99 int GetLogicalProcessorsPerPhysical();
100 float GetProcessorClockFrequency();
101 int GetProcessorAPICID();
102 int GetProcessorCacheXSize(long int);
103 bool DoesCPUSupportFeature(long int);
105 const char * GetOSName();
106 const char * GetHostname();
107 const char * GetOSRelease();
108 const char * GetOSVersion();
109 const char * GetOSPlatform();
111 bool Is64Bits();
113 unsigned int GetNumberOfLogicalCPU(); // per physical cpu
114 unsigned int GetNumberOfPhysicalCPU();
116 bool DoesCPUSupportCPUID();
118 // Retrieve memory information in megabyte.
119 unsigned long GetTotalVirtualMemory();
120 unsigned long GetAvailableVirtualMemory();
121 unsigned long GetTotalPhysicalMemory();
122 unsigned long GetAvailablePhysicalMemory();
124 /** Run the different checks */
125 void RunCPUCheck();
126 void RunOSCheck();
127 void RunMemoryCheck();
128 public:
129 #define VENDOR_STRING_LENGTH (12 + 1)
130 #define CHIPNAME_STRING_LENGTH (48 + 1)
131 #define SERIALNUMBER_STRING_LENGTH (29 + 1)
133 typedef struct tagID
135 int Type;
136 int Family;
137 int Model;
138 int Revision;
139 int ExtendedFamily;
140 int ExtendedModel;
141 char ProcessorName[CHIPNAME_STRING_LENGTH];
142 char Vendor[VENDOR_STRING_LENGTH];
143 char SerialNumber[SERIALNUMBER_STRING_LENGTH];
144 } ID;
146 typedef struct tagCPUPowerManagement
148 bool HasVoltageID;
149 bool HasFrequencyID;
150 bool HasTempSenseDiode;
151 } CPUPowerManagement;
153 typedef struct tagCPUExtendedFeatures
155 bool Has3DNow;
156 bool Has3DNowPlus;
157 bool SupportsMP;
158 bool HasMMXPlus;
159 bool HasSSEMMX;
160 bool SupportsHyperthreading;
161 int LogicalProcessorsPerPhysical;
162 int APIC_ID;
163 CPUPowerManagement PowerManagement;
164 } CPUExtendedFeatures;
166 typedef struct CPUtagFeatures
168 bool HasFPU;
169 bool HasTSC;
170 bool HasMMX;
171 bool HasSSE;
172 bool HasSSEFP;
173 bool HasSSE2;
174 bool HasIA64;
175 bool HasAPIC;
176 bool HasCMOV;
177 bool HasMTRR;
178 bool HasACPI;
179 bool HasSerial;
180 bool HasThermal;
181 int CPUSpeed;
182 int L1CacheSize;
183 int L2CacheSize;
184 int L3CacheSize;
185 CPUExtendedFeatures ExtendedFeatures;
186 } CPUFeatures;
188 enum Manufacturer
190 AMD, Intel, NSC, UMC, Cyrix, NexGen, IDT, Rise, Transmeta, Sun, UnknownManufacturer
192 protected:
194 // Functions.
195 bool RetrieveCPUFeatures();
196 bool RetrieveCPUIdentity();
197 bool RetrieveCPUCacheDetails();
198 bool RetrieveClassicalCPUCacheDetails();
199 bool RetrieveCPUClockSpeed();
200 bool RetrieveClassicalCPUClockSpeed();
201 bool RetrieveCPUExtendedLevelSupport(int);
202 bool RetrieveExtendedCPUFeatures();
203 bool RetrieveProcessorSerialNumber();
204 bool RetrieveCPUPowerManagement();
205 bool RetrieveClassicalCPUIdentity();
206 bool RetrieveExtendedCPUIdentity();
208 Manufacturer ChipManufacturer;
209 CPUFeatures Features;
210 ID ChipID;
211 float CPUSpeedInMHz;
212 unsigned int NumberOfLogicalCPU;
213 unsigned int NumberOfPhysicalCPU;
215 int CPUCount();
216 unsigned char LogicalCPUPerPhysicalCPU();
217 unsigned char GetAPICId();
218 unsigned int IsHyperThreadingSupported();
219 LongLong GetCyclesDifference(DELAY_FUNC, unsigned int);
221 // For Linux and Cygwin, /proc/cpuinfo formats are slightly different
222 int RetreiveInformationFromCpuInfoFile();
223 kwsys_stl::string ExtractValueFromCpuInfoFile(kwsys_stl::string buffer,
224 const char* word, size_t init=0);
226 static void Delay (unsigned int);
227 static void DelayOverhead (unsigned int);
229 void FindManufacturer();
231 // For Mac
232 bool ParseSysCtl();
233 kwsys_stl::string ExtractValueFromSysCtl(const char* word);
234 kwsys_stl::string SysCtlBuffer;
236 // For Solaris
237 bool QuerySolarisInfo();
238 kwsys_stl::string ParseValueFromKStat(const char* arguments);
239 kwsys_stl::string RunProcess(kwsys_stl::vector<const char*> args);
241 // Evaluate the memory information.
242 int QueryMemory();
243 unsigned long TotalVirtualMemory;
244 unsigned long AvailableVirtualMemory;
245 unsigned long TotalPhysicalMemory;
246 unsigned long AvailablePhysicalMemory;
248 size_t CurrentPositionInFile;
250 // Operating System information
251 bool QueryOSInformation();
252 kwsys_stl::string OSName;
253 kwsys_stl::string Hostname;
254 kwsys_stl::string OSRelease;
255 kwsys_stl::string OSVersion;
256 kwsys_stl::string OSPlatform;
263 SystemInformation::SystemInformation()
265 this->Implementation = new SystemInformationImplementation;
268 SystemInformation::~SystemInformation ()
270 delete this->Implementation;
273 const char * SystemInformation::GetVendorString()
275 return this->Implementation->GetVendorString();
277 const char * SystemInformation::GetVendorID()
279 return this->Implementation->GetVendorID();
281 kwsys_stl::string SystemInformation::GetTypeID()
283 return this->Implementation->GetTypeID();
285 kwsys_stl::string SystemInformation::GetFamilyID()
287 return this->Implementation->GetFamilyID();
289 kwsys_stl::string SystemInformation::GetModelID()
291 return this->Implementation->GetModelID();
293 kwsys_stl::string SystemInformation::GetSteppingCode()
295 return this->Implementation->GetSteppingCode();
297 const char * SystemInformation::GetExtendedProcessorName()
299 return this->Implementation->GetExtendedProcessorName();
301 const char * SystemInformation::GetProcessorSerialNumber()
303 return this->Implementation->GetProcessorSerialNumber();
305 int SystemInformation::GetProcessorCacheSize()
307 return this->Implementation->GetProcessorCacheSize();
309 int SystemInformation::GetLogicalProcessorsPerPhysical()
311 return this->Implementation->GetLogicalProcessorsPerPhysical();
313 float SystemInformation::GetProcessorClockFrequency()
315 return this->Implementation->GetProcessorClockFrequency();
317 int SystemInformation::GetProcessorAPICID()
319 return this->Implementation->GetProcessorAPICID();
321 int SystemInformation::GetProcessorCacheXSize(long int l)
323 return this->Implementation->GetProcessorCacheXSize(l);
325 bool SystemInformation::DoesCPUSupportFeature(long int i)
327 return this->Implementation->DoesCPUSupportFeature(i);
330 const char * SystemInformation::GetOSName()
332 return this->Implementation->GetOSName();
334 const char * SystemInformation::GetHostname()
336 return this->Implementation->GetHostname();
338 const char * SystemInformation::GetOSRelease()
340 return this->Implementation->GetOSRelease();
342 const char * SystemInformation::GetOSVersion()
344 return this->Implementation->GetOSVersion();
346 const char * SystemInformation::GetOSPlatform()
348 return this->Implementation->GetOSPlatform();
351 bool SystemInformation::Is64Bits()
353 return this->Implementation->Is64Bits();
356 unsigned int SystemInformation::GetNumberOfLogicalCPU() // per physical cpu
358 return this->Implementation->GetNumberOfLogicalCPU();
360 unsigned int SystemInformation::GetNumberOfPhysicalCPU()
362 return this->Implementation->GetNumberOfPhysicalCPU();
365 bool SystemInformation::DoesCPUSupportCPUID()
367 return this->Implementation->DoesCPUSupportCPUID();
370 // Retrieve memory information in megabyte.
371 unsigned long SystemInformation::GetTotalVirtualMemory()
373 return this->Implementation->GetTotalVirtualMemory();
375 unsigned long SystemInformation::GetAvailableVirtualMemory()
377 return this->Implementation->GetAvailableVirtualMemory();
379 unsigned long SystemInformation::GetTotalPhysicalMemory()
381 return this->Implementation->GetTotalPhysicalMemory();
384 unsigned long SystemInformation::GetAvailablePhysicalMemory()
386 return this->Implementation->GetAvailablePhysicalMemory();
389 /** Run the different checks */
390 void SystemInformation::RunCPUCheck()
392 this->Implementation->RunCPUCheck();
394 void SystemInformation::RunOSCheck()
396 this->Implementation->RunOSCheck();
398 void SystemInformation::RunMemoryCheck()
400 this->Implementation->RunMemoryCheck();
405 // --------------------------------------------------------------
406 // SystemInformationImplementation starts here
408 #if defined(_MSC_VER) && (_MSC_VER >= 1300) && !defined(_WIN64)
409 #define USE_ASM_INSTRUCTIONS 1
410 #else
411 #define USE_ASM_INSTRUCTIONS 0
412 #endif
414 #define STORE_TLBCACHE_INFO(x,y) x = (x < y) ? y : x
415 #define TLBCACHE_INFO_UNITS (15)
416 #define CLASSICAL_CPU_FREQ_LOOP 10000000
417 #define RDTSC_INSTRUCTION _asm _emit 0x0f _asm _emit 0x31
419 #define CPUID_AWARE_COMPILER
420 #ifdef CPUID_AWARE_COMPILER
421 #define CPUID_INSTRUCTION cpuid
422 #else
423 #define CPUID_INSTRUCTION _asm _emit 0x0f _asm _emit 0xa2
424 #endif
426 #define MMX_FEATURE 0x00000001
427 #define MMX_PLUS_FEATURE 0x00000002
428 #define SSE_FEATURE 0x00000004
429 #define SSE2_FEATURE 0x00000008
430 #define AMD_3DNOW_FEATURE 0x00000010
431 #define AMD_3DNOW_PLUS_FEATURE 0x00000020
432 #define IA64_FEATURE 0x00000040
433 #define MP_CAPABLE 0x00000080
434 #define HYPERTHREAD_FEATURE 0x00000100
435 #define SERIALNUMBER_FEATURE 0x00000200
436 #define APIC_FEATURE 0x00000400
437 #define SSE_FP_FEATURE 0x00000800
438 #define SSE_MMX_FEATURE 0x00001000
439 #define CMOV_FEATURE 0x00002000
440 #define MTRR_FEATURE 0x00004000
441 #define L1CACHE_FEATURE 0x00008000
442 #define L2CACHE_FEATURE 0x00010000
443 #define L3CACHE_FEATURE 0x00020000
444 #define ACPI_FEATURE 0x00040000
445 #define THERMALMONITOR_FEATURE 0x00080000
446 #define TEMPSENSEDIODE_FEATURE 0x00100000
447 #define FREQUENCYID_FEATURE 0x00200000
448 #define VOLTAGEID_FREQUENCY 0x00400000
450 // Status Flag
451 #define HT_NOT_CAPABLE 0
452 #define HT_ENABLED 1
453 #define HT_DISABLED 2
454 #define HT_SUPPORTED_NOT_ENABLED 3
455 #define HT_CANNOT_DETECT 4
457 // EDX[28] Bit 28 is set if HT is supported
458 #define HT_BIT 0x10000000
460 // EAX[11:8] Bit 8-11 contains family processor ID.
461 #define FAMILY_ID 0x0F00
462 #define PENTIUM4_ID 0x0F00
463 // EAX[23:20] Bit 20-23 contains extended family processor ID
464 #define EXT_FAMILY_ID 0x0F00000
465 // EBX[23:16] Bit 16-23 in ebx contains the number of logical
466 #define NUM_LOGICAL_BITS 0x00FF0000
467 // processors per physical processor when execute cpuid with
468 // eax set to 1
469 // EBX[31:24] Bits 24-31 (8 bits) return the 8-bit unique
470 #define INITIAL_APIC_ID_BITS 0xFF000000
471 // initial APIC ID for the processor this code is running on.
472 // Default value = 0xff if HT is not supported
476 SystemInformationImplementation::SystemInformationImplementation()
478 this->TotalVirtualMemory = 0;
479 this->AvailableVirtualMemory = 0;
480 this->TotalPhysicalMemory = 0;
481 this->AvailablePhysicalMemory = 0;
482 this->CurrentPositionInFile = 0;
483 this->ChipManufacturer = UnknownManufacturer;
484 memset(&this->Features, 0, sizeof(CPUFeatures));
485 memset(&this->ChipID, 0, sizeof(ID));
486 this->CPUSpeedInMHz = 0;
487 this->NumberOfLogicalCPU = 0;
488 this->NumberOfPhysicalCPU = 0;
489 this->OSName = "";
490 this->Hostname = "";
491 this->OSRelease = "";
492 this->OSVersion = "";
493 this->OSPlatform = "";
496 SystemInformationImplementation::~SystemInformationImplementation()
500 void SystemInformationImplementation::RunCPUCheck()
502 #ifdef WIN32
503 // Check to see if this processor supports CPUID.
504 if (DoesCPUSupportCPUID())
506 // Retrieve the CPU details.
507 RetrieveCPUIdentity();
508 RetrieveCPUFeatures();
509 if (!RetrieveCPUClockSpeed())
511 RetrieveClassicalCPUClockSpeed();
514 // Attempt to retrieve cache information.
515 if (!RetrieveCPUCacheDetails())
517 RetrieveClassicalCPUCacheDetails();
519 // Retrieve the extended CPU details.
520 if (!RetrieveExtendedCPUIdentity())
522 RetrieveClassicalCPUIdentity();
524 RetrieveExtendedCPUFeatures();
526 // Now attempt to retrieve the serial number (if possible).
527 RetrieveProcessorSerialNumber();
529 this->CPUCount();
530 #elif defined(__APPLE__)
531 this->ParseSysCtl();
532 #elif defined (__SVR4) && defined (__sun)
533 this->QuerySolarisInfo();
534 #else
535 this->RetreiveInformationFromCpuInfoFile();
536 #endif
539 void SystemInformationImplementation::RunOSCheck()
541 this->QueryOSInformation();
544 void SystemInformationImplementation::RunMemoryCheck()
546 #if defined(__APPLE__)
547 this->ParseSysCtl();
548 #elif defined (__SVR4) && defined (__sun)
549 this->QuerySolarisInfo();
550 #else
551 this->QueryMemory();
552 #endif
555 /** Get the vendor string */
556 const char * SystemInformationImplementation::GetVendorString()
558 return this->ChipID.Vendor;
561 /** Get the OS Name */
562 const char * SystemInformationImplementation::GetOSName()
564 return this->OSName.c_str();
567 /** Get the hostname */
568 const char* SystemInformationImplementation::GetHostname()
570 return this->Hostname.c_str();
573 /** Get the OS release */
574 const char* SystemInformationImplementation::GetOSRelease()
576 return this->OSRelease.c_str();
579 /** Get the OS version */
580 const char* SystemInformationImplementation::GetOSVersion()
582 return this->OSVersion.c_str();
585 /** Get the OS platform */
586 const char* SystemInformationImplementation::GetOSPlatform()
588 return this->OSPlatform.c_str();
591 /** Get the vendor ID */
592 const char * SystemInformationImplementation::GetVendorID()
594 // Return the vendor ID.
595 switch (this->ChipManufacturer)
597 case Intel:
598 return "Intel Corporation";
599 case AMD:
600 return "Advanced Micro Devices";
601 case NSC:
602 return "National Semiconductor";
603 case Cyrix:
604 return "Cyrix Corp., VIA Inc.";
605 case NexGen:
606 return "NexGen Inc., Advanced Micro Devices";
607 case IDT:
608 return "IDT\\Centaur, Via Inc.";
609 case UMC:
610 return "United Microelectronics Corp.";
611 case Rise:
612 return "Rise";
613 case Transmeta:
614 return "Transmeta";
615 case Sun:
616 return "Sun Microelectronics";
617 default:
618 return "Unknown Manufacturer";
622 /** Return the type ID of the CPU */
623 kwsys_stl::string SystemInformationImplementation::GetTypeID()
625 kwsys_ios::ostringstream str;
626 str << this->ChipID.Type;
627 return str.str();
630 /** Return the family of the CPU present */
631 kwsys_stl::string SystemInformationImplementation::GetFamilyID()
633 kwsys_ios::ostringstream str;
634 str << this->ChipID.Family;
635 return str.str();
638 // Return the model of CPU present */
639 kwsys_stl::string SystemInformationImplementation::GetModelID()
641 kwsys_ios::ostringstream str;
642 str << this->ChipID.Model;
643 return str.str();
646 /** Return the stepping code of the CPU present. */
647 kwsys_stl::string SystemInformationImplementation::GetSteppingCode()
649 kwsys_ios::ostringstream str;
650 str << this->ChipID.Revision;
651 return str.str();
654 /** Return the stepping code of the CPU present. */
655 const char * SystemInformationImplementation::GetExtendedProcessorName()
657 return this->ChipID.ProcessorName;
660 /** Return the serial number of the processor
661 * in hexadecimal: xxxx-xxxx-xxxx-xxxx-xxxx-xxxx. */
662 const char * SystemInformationImplementation::GetProcessorSerialNumber()
664 return this->ChipID.SerialNumber;
667 /** Return the logical processors per physical */
668 int SystemInformationImplementation::GetLogicalProcessorsPerPhysical()
670 return this->Features.ExtendedFeatures.LogicalProcessorsPerPhysical;
673 /** Return the processor clock frequency. */
674 float SystemInformationImplementation::GetProcessorClockFrequency()
676 return this->CPUSpeedInMHz;
679 /** Return the APIC ID. */
680 int SystemInformationImplementation::GetProcessorAPICID()
682 return this->Features.ExtendedFeatures.APIC_ID;
685 /** Return the L1 cache size. */
686 int SystemInformationImplementation::GetProcessorCacheSize()
688 return this->Features.L1CacheSize;
691 /** Return the chosen cache size. */
692 int SystemInformationImplementation::GetProcessorCacheXSize(long int dwCacheID)
694 switch (dwCacheID)
696 case L1CACHE_FEATURE:
697 return this->Features.L1CacheSize;
698 case L2CACHE_FEATURE:
699 return this->Features.L2CacheSize;
700 case L3CACHE_FEATURE:
701 return this->Features.L3CacheSize;
703 return -1;
706 bool SystemInformationImplementation::DoesCPUSupportFeature(long int dwFeature)
708 bool bHasFeature = false;
710 // Check for MMX instructions.
711 if (((dwFeature & MMX_FEATURE) != 0) && this->Features.HasMMX) bHasFeature = true;
713 // Check for MMX+ instructions.
714 if (((dwFeature & MMX_PLUS_FEATURE) != 0) && this->Features.ExtendedFeatures.HasMMXPlus) bHasFeature = true;
716 // Check for SSE FP instructions.
717 if (((dwFeature & SSE_FEATURE) != 0) && this->Features.HasSSE) bHasFeature = true;
719 // Check for SSE FP instructions.
720 if (((dwFeature & SSE_FP_FEATURE) != 0) && this->Features.HasSSEFP) bHasFeature = true;
722 // Check for SSE MMX instructions.
723 if (((dwFeature & SSE_MMX_FEATURE) != 0) && this->Features.ExtendedFeatures.HasSSEMMX) bHasFeature = true;
725 // Check for SSE2 instructions.
726 if (((dwFeature & SSE2_FEATURE) != 0) && this->Features.HasSSE2) bHasFeature = true;
728 // Check for 3DNow! instructions.
729 if (((dwFeature & AMD_3DNOW_FEATURE) != 0) && this->Features.ExtendedFeatures.Has3DNow) bHasFeature = true;
731 // Check for 3DNow+ instructions.
732 if (((dwFeature & AMD_3DNOW_PLUS_FEATURE) != 0) && this->Features.ExtendedFeatures.Has3DNowPlus) bHasFeature = true;
734 // Check for IA64 instructions.
735 if (((dwFeature & IA64_FEATURE) != 0) && this->Features.HasIA64) bHasFeature = true;
737 // Check for MP capable.
738 if (((dwFeature & MP_CAPABLE) != 0) && this->Features.ExtendedFeatures.SupportsMP) bHasFeature = true;
740 // Check for a serial number for the processor.
741 if (((dwFeature & SERIALNUMBER_FEATURE) != 0) && this->Features.HasSerial) bHasFeature = true;
743 // Check for a local APIC in the processor.
744 if (((dwFeature & APIC_FEATURE) != 0) && this->Features.HasAPIC) bHasFeature = true;
746 // Check for CMOV instructions.
747 if (((dwFeature & CMOV_FEATURE) != 0) && this->Features.HasCMOV) bHasFeature = true;
749 // Check for MTRR instructions.
750 if (((dwFeature & MTRR_FEATURE) != 0) && this->Features.HasMTRR) bHasFeature = true;
752 // Check for L1 cache size.
753 if (((dwFeature & L1CACHE_FEATURE) != 0) && (this->Features.L1CacheSize != -1)) bHasFeature = true;
755 // Check for L2 cache size.
756 if (((dwFeature & L2CACHE_FEATURE) != 0) && (this->Features.L2CacheSize != -1)) bHasFeature = true;
758 // Check for L3 cache size.
759 if (((dwFeature & L3CACHE_FEATURE) != 0) && (this->Features.L3CacheSize != -1)) bHasFeature = true;
761 // Check for ACPI capability.
762 if (((dwFeature & ACPI_FEATURE) != 0) && this->Features.HasACPI) bHasFeature = true;
764 // Check for thermal monitor support.
765 if (((dwFeature & THERMALMONITOR_FEATURE) != 0) && this->Features.HasThermal) bHasFeature = true;
767 // Check for temperature sensing diode support.
768 if (((dwFeature & TEMPSENSEDIODE_FEATURE) != 0) && this->Features.ExtendedFeatures.PowerManagement.HasTempSenseDiode) bHasFeature = true;
770 // Check for frequency ID support.
771 if (((dwFeature & FREQUENCYID_FEATURE) != 0) && this->Features.ExtendedFeatures.PowerManagement.HasFrequencyID) bHasFeature = true;
773 // Check for voltage ID support.
774 if (((dwFeature & VOLTAGEID_FREQUENCY) != 0) && this->Features.ExtendedFeatures.PowerManagement.HasVoltageID) bHasFeature = true;
776 return bHasFeature;
779 void SystemInformationImplementation::Delay(unsigned int uiMS)
781 #ifdef WIN32
782 LARGE_INTEGER Frequency, StartCounter, EndCounter;
783 __int64 x;
785 // Get the frequency of the high performance counter.
786 if (!QueryPerformanceFrequency (&Frequency)) return;
787 x = Frequency.QuadPart / 1000 * uiMS;
789 // Get the starting position of the counter.
790 QueryPerformanceCounter (&StartCounter);
792 do {
793 // Get the ending position of the counter.
794 QueryPerformanceCounter (&EndCounter);
795 } while (EndCounter.QuadPart - StartCounter.QuadPart < x);
796 #endif
797 (void)uiMS;
800 bool SystemInformationImplementation::DoesCPUSupportCPUID()
802 #if USE_ASM_INSTRUCTIONS
803 // Use SEH to determine CPUID presence
804 __try {
805 _asm {
806 #ifdef CPUID_AWARE_COMPILER
807 ; we must push/pop the registers <<CPUID>> writes to, as the
808 ; optimiser doesn't know about <<CPUID>>, and so doesn't expect
809 ; these registers to change.
810 push eax
811 push ebx
812 push ecx
813 push edx
814 #endif
815 ; <<CPUID>>
816 mov eax, 0
817 CPUID_INSTRUCTION
819 #ifdef CPUID_AWARE_COMPILER
820 pop edx
821 pop ecx
822 pop ebx
823 pop eax
824 #endif
827 __except(1)
829 // Stop the class from trying to use CPUID again!
830 return false;
833 // The cpuid instruction succeeded.
834 return true;
835 #else
836 // Assume no cpuid instruction.
837 return false;
838 #endif
841 bool SystemInformationImplementation::RetrieveCPUFeatures()
843 #if USE_ASM_INSTRUCTIONS
844 int localCPUFeatures = 0;
845 int localCPUAdvanced = 0;
848 // Use assembly to detect CPUID information...
849 __try {
850 _asm {
851 #ifdef CPUID_AWARE_COMPILER
852 ; we must push/pop the registers <<CPUID>> writes to, as the
853 ; optimiser doesn't know about <<CPUID>>, and so doesn't expect
854 ; these registers to change.
855 push eax
856 push ebx
857 push ecx
858 push edx
859 #endif
860 ; <<CPUID>>
861 ; 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
862 ; ebx: 31..24 - default APIC ID, 23..16 - logical processsor ID, 15..8 - CFLUSH chunk size , 7..0 - brand ID
863 ; edx: CPU feature flags
864 mov eax,1
865 CPUID_INSTRUCTION
866 mov localCPUFeatures, edx
867 mov localCPUAdvanced, ebx
869 #ifdef CPUID_AWARE_COMPILER
870 pop edx
871 pop ecx
872 pop ebx
873 pop eax
874 #endif
877 __except(1)
879 return false;
882 // Retrieve the features of CPU present.
883 this->Features.HasFPU = ((localCPUFeatures & 0x00000001) != 0); // FPU Present --> Bit 0
884 this->Features.HasTSC = ((localCPUFeatures & 0x00000010) != 0); // TSC Present --> Bit 4
885 this->Features.HasAPIC = ((localCPUFeatures & 0x00000200) != 0); // APIC Present --> Bit 9
886 this->Features.HasMTRR = ((localCPUFeatures & 0x00001000) != 0); // MTRR Present --> Bit 12
887 this->Features.HasCMOV = ((localCPUFeatures & 0x00008000) != 0); // CMOV Present --> Bit 15
888 this->Features.HasSerial = ((localCPUFeatures & 0x00040000) != 0); // Serial Present --> Bit 18
889 this->Features.HasACPI = ((localCPUFeatures & 0x00400000) != 0); // ACPI Capable --> Bit 22
890 this->Features.HasMMX = ((localCPUFeatures & 0x00800000) != 0); // MMX Present --> Bit 23
891 this->Features.HasSSE = ((localCPUFeatures & 0x02000000) != 0); // SSE Present --> Bit 25
892 this->Features.HasSSE2 = ((localCPUFeatures & 0x04000000) != 0); // SSE2 Present --> Bit 26
893 this->Features.HasThermal = ((localCPUFeatures & 0x20000000) != 0); // Thermal Monitor Present --> Bit 29
894 this->Features.HasIA64 = ((localCPUFeatures & 0x40000000) != 0); // IA64 Present --> Bit 30
896 // Retrieve extended SSE capabilities if SSE is available.
897 if (this->Features.HasSSE) {
899 // Attempt to __try some SSE FP instructions.
900 __try
902 // Perform: orps xmm0, xmm0
903 _asm
905 _emit 0x0f
906 _emit 0x56
907 _emit 0xc0
910 // SSE FP capable processor.
911 this->Features.HasSSEFP = true;
913 __except(1)
915 // bad instruction - processor or OS cannot handle SSE FP.
916 this->Features.HasSSEFP = false;
919 else
921 // Set the advanced SSE capabilities to not available.
922 this->Features.HasSSEFP = false;
925 // Retrieve Intel specific extended features.
926 if (this->ChipManufacturer == Intel)
928 this->Features.ExtendedFeatures.SupportsHyperthreading = ((localCPUFeatures & 0x10000000) != 0); // Intel specific: Hyperthreading --> Bit 28
929 this->Features.ExtendedFeatures.LogicalProcessorsPerPhysical = (this->Features.ExtendedFeatures.SupportsHyperthreading) ? ((localCPUAdvanced & 0x00FF0000) >> 16) : 1;
931 if ((this->Features.ExtendedFeatures.SupportsHyperthreading) && (this->Features.HasAPIC))
933 // Retrieve APIC information if there is one present.
934 this->Features.ExtendedFeatures.APIC_ID = ((localCPUAdvanced & 0xFF000000) >> 24);
937 #endif
938 return true;
942 /** Find the manufacturer given the vendor id */
943 void SystemInformationImplementation::FindManufacturer()
945 if (strcmp (this->ChipID.Vendor, "GenuineIntel") == 0) this->ChipManufacturer = Intel; // Intel Corp.
946 else if (strcmp (this->ChipID.Vendor, "UMC UMC UMC ") == 0) this->ChipManufacturer = UMC; // United Microelectronics Corp.
947 else if (strcmp (this->ChipID.Vendor, "AuthenticAMD") == 0) this->ChipManufacturer = AMD; // Advanced Micro Devices
948 else if (strcmp (this->ChipID.Vendor, "AMD ISBETTER") == 0) this->ChipManufacturer = AMD; // Advanced Micro Devices (1994)
949 else if (strcmp (this->ChipID.Vendor, "CyrixInstead") == 0) this->ChipManufacturer = Cyrix; // Cyrix Corp., VIA Inc.
950 else if (strcmp (this->ChipID.Vendor, "NexGenDriven") == 0) this->ChipManufacturer = NexGen; // NexGen Inc. (now AMD)
951 else if (strcmp (this->ChipID.Vendor, "CentaurHauls") == 0) this->ChipManufacturer = IDT; // IDT/Centaur (now VIA)
952 else if (strcmp (this->ChipID.Vendor, "RiseRiseRise") == 0) this->ChipManufacturer = Rise; // Rise
953 else if (strcmp (this->ChipID.Vendor, "GenuineTMx86") == 0) this->ChipManufacturer = Transmeta; // Transmeta
954 else if (strcmp (this->ChipID.Vendor, "TransmetaCPU") == 0) this->ChipManufacturer = Transmeta; // Transmeta
955 else if (strcmp (this->ChipID.Vendor, "Geode By NSC") == 0) this->ChipManufacturer = NSC; // National Semiconductor
956 else if (strcmp (this->ChipID.Vendor, "Sun") == 0) this->ChipManufacturer = Sun; // Sun Microelectronics
957 else this->ChipManufacturer = UnknownManufacturer; // Unknown manufacturer
960 /** */
961 bool SystemInformationImplementation::RetrieveCPUIdentity()
963 #if USE_ASM_INSTRUCTIONS
964 int localCPUVendor[3];
965 int localCPUSignature;
967 // Use assembly to detect CPUID information...
968 __try
970 _asm
972 #ifdef CPUID_AWARE_COMPILER
973 ; we must push/pop the registers <<CPUID>> writes to, as the
974 ; optimiser doesn't know about <<CPUID>>, and so doesn't expect
975 ; these registers to change.
976 push eax
977 push ebx
978 push ecx
979 push edx
980 #endif
981 ; <<CPUID>>
982 ; eax = 0 --> eax: maximum value of CPUID instruction.
983 ; ebx: part 1 of 3; CPU signature.
984 ; edx: part 2 of 3; CPU signature.
985 ; ecx: part 3 of 3; CPU signature.
986 mov eax, 0
987 CPUID_INSTRUCTION
988 mov localCPUVendor[0 * TYPE int], ebx
989 mov localCPUVendor[1 * TYPE int], edx
990 mov localCPUVendor[2 * TYPE int], ecx
992 ; <<CPUID>>
993 ; 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
994 ; ebx: 31..24 - default APIC ID, 23..16 - logical processsor ID, 15..8 - CFLUSH chunk size , 7..0 - brand ID
995 ; edx: CPU feature flags
996 mov eax,1
997 CPUID_INSTRUCTION
998 mov localCPUSignature, eax
1000 #ifdef CPUID_AWARE_COMPILER
1001 pop edx
1002 pop ecx
1003 pop ebx
1004 pop eax
1005 #endif
1008 __except(1)
1010 return false;
1013 // Process the returned information.
1014 memcpy (this->ChipID.Vendor, &(localCPUVendor[0]), sizeof (int));
1015 memcpy (&(this->ChipID.Vendor[4]), &(localCPUVendor[1]), sizeof (int));
1016 memcpy (&(this->ChipID.Vendor[8]), &(localCPUVendor[2]), sizeof (int));
1017 this->ChipID.Vendor[12] = '\0';
1019 this->FindManufacturer();
1021 // Retrieve the family of CPU present.
1022 this->ChipID.ExtendedFamily = ((localCPUSignature & 0x0FF00000) >> 20); // Bits 27..20 Used
1023 this->ChipID.ExtendedModel = ((localCPUSignature & 0x000F0000) >> 16); // Bits 19..16 Used
1024 this->ChipID.Type = ((localCPUSignature & 0x0000F000) >> 12); // Bits 15..12 Used
1025 this->ChipID.Family = ((localCPUSignature & 0x00000F00) >> 8); // Bits 11..8 Used
1026 this->ChipID.Model = ((localCPUSignature & 0x000000F0) >> 4); // Bits 7..4 Used
1027 this->ChipID.Revision = ((localCPUSignature & 0x0000000F) >> 0); // Bits 3..0 Used
1028 #endif
1030 return true;
1033 /** */
1034 bool SystemInformationImplementation::RetrieveCPUCacheDetails()
1036 #if USE_ASM_INSTRUCTIONS
1037 int L1Cache[4] = { 0, 0, 0, 0 };
1038 int L2Cache[4] = { 0, 0, 0, 0 };
1040 // Check to see if what we are about to do is supported...
1041 if (RetrieveCPUExtendedLevelSupport (0x80000005))
1043 // Use assembly to retrieve the L1 cache information ...
1044 __try
1046 _asm
1048 #ifdef CPUID_AWARE_COMPILER
1049 ; we must push/pop the registers <<CPUID>> writes to, as the
1050 ; optimiser doesn't know about <<CPUID>>, and so doesn't expect
1051 ; these registers to change.
1052 push eax
1053 push ebx
1054 push ecx
1055 push edx
1056 #endif
1057 ; <<CPUID>>
1058 ; eax = 0x80000005 --> eax: L1 cache information - Part 1 of 4.
1059 ; ebx: L1 cache information - Part 2 of 4.
1060 ; edx: L1 cache information - Part 3 of 4.
1061 ; ecx: L1 cache information - Part 4 of 4.
1062 mov eax, 0x80000005
1063 CPUID_INSTRUCTION
1064 mov L1Cache[0 * TYPE int], eax
1065 mov L1Cache[1 * TYPE int], ebx
1066 mov L1Cache[2 * TYPE int], ecx
1067 mov L1Cache[3 * TYPE int], edx
1069 #ifdef CPUID_AWARE_COMPILER
1070 pop edx
1071 pop ecx
1072 pop ebx
1073 pop eax
1074 #endif
1077 __except(1)
1079 return false;
1081 // Save the L1 data cache size (in KB) from ecx: bits 31..24 as well as data cache size from edx: bits 31..24.
1082 this->Features.L1CacheSize = ((L1Cache[2] & 0xFF000000) >> 24);
1083 this->Features.L1CacheSize += ((L1Cache[3] & 0xFF000000) >> 24);
1085 else
1087 // Store -1 to indicate the cache could not be queried.
1088 this->Features.L1CacheSize = -1;
1091 // Check to see if what we are about to do is supported...
1092 if (RetrieveCPUExtendedLevelSupport (0x80000006))
1094 // Use assembly to retrieve the L2 cache information ...
1095 __try
1097 _asm
1099 #ifdef CPUID_AWARE_COMPILER
1100 ; we must push/pop the registers <<CPUID>> writes to, as the
1101 ; optimiser doesn't know about <<CPUID>>, and so doesn't expect
1102 ; these registers to change.
1103 push eax
1104 push ebx
1105 push ecx
1106 push edx
1107 #endif
1108 ; <<CPUID>>
1109 ; eax = 0x80000006 --> eax: L2 cache information - Part 1 of 4.
1110 ; ebx: L2 cache information - Part 2 of 4.
1111 ; edx: L2 cache information - Part 3 of 4.
1112 ; ecx: L2 cache information - Part 4 of 4.
1113 mov eax, 0x80000006
1114 CPUID_INSTRUCTION
1115 mov L2Cache[0 * TYPE int], eax
1116 mov L2Cache[1 * TYPE int], ebx
1117 mov L2Cache[2 * TYPE int], ecx
1118 mov L2Cache[3 * TYPE int], edx
1120 #ifdef CPUID_AWARE_COMPILER
1121 pop edx
1122 pop ecx
1123 pop ebx
1124 pop eax
1125 #endif
1128 __except(1)
1130 return false;
1132 // Save the L2 unified cache size (in KB) from ecx: bits 31..16.
1133 this->Features.L2CacheSize = ((L2Cache[2] & 0xFFFF0000) >> 16);
1135 else
1137 // Store -1 to indicate the cache could not be queried.
1138 this->Features.L2CacheSize = -1;
1141 // Define L3 as being not present as we cannot test for it.
1142 this->Features.L3CacheSize = -1;
1144 #endif
1146 // Return failure if we cannot detect either cache with this method.
1147 return ((this->Features.L1CacheSize == -1) && (this->Features.L2CacheSize == -1)) ? false : true;
1150 /** */
1151 bool SystemInformationImplementation::RetrieveClassicalCPUCacheDetails()
1153 #if USE_ASM_INSTRUCTIONS
1154 int TLBCode = -1, TLBData = -1, L1Code = -1, L1Data = -1, L1Trace = -1, L2Unified = -1, L3Unified = -1;
1155 int TLBCacheData[4] = { 0, 0, 0, 0 };
1156 int TLBPassCounter = 0;
1157 int TLBCacheUnit = 0;
1160 do {
1161 // Use assembly to retrieve the L2 cache information ...
1162 __try {
1163 _asm {
1164 #ifdef CPUID_AWARE_COMPILER
1165 ; we must push/pop the registers <<CPUID>> writes to, as the
1166 ; optimiser doesn't know about <<CPUID>>, and so doesn't expect
1167 ; these registers to change.
1168 push eax
1169 push ebx
1170 push ecx
1171 push edx
1172 #endif
1173 ; <<CPUID>>
1174 ; eax = 2 --> eax: TLB and cache information - Part 1 of 4.
1175 ; ebx: TLB and cache information - Part 2 of 4.
1176 ; ecx: TLB and cache information - Part 3 of 4.
1177 ; edx: TLB and cache information - Part 4 of 4.
1178 mov eax, 2
1179 CPUID_INSTRUCTION
1180 mov TLBCacheData[0 * TYPE int], eax
1181 mov TLBCacheData[1 * TYPE int], ebx
1182 mov TLBCacheData[2 * TYPE int], ecx
1183 mov TLBCacheData[3 * TYPE int], edx
1185 #ifdef CPUID_AWARE_COMPILER
1186 pop edx
1187 pop ecx
1188 pop ebx
1189 pop eax
1190 #endif
1193 __except(1)
1195 return false;
1198 int bob = ((TLBCacheData[0] & 0x00FF0000) >> 16);
1199 (void)bob;
1200 // Process the returned TLB and cache information.
1201 for (int nCounter = 0; nCounter < TLBCACHE_INFO_UNITS; nCounter ++)
1203 // First of all - decide which unit we are dealing with.
1204 switch (nCounter)
1206 // eax: bits 8..15 : bits 16..23 : bits 24..31
1207 case 0: TLBCacheUnit = ((TLBCacheData[0] & 0x0000FF00) >> 8); break;
1208 case 1: TLBCacheUnit = ((TLBCacheData[0] & 0x00FF0000) >> 16); break;
1209 case 2: TLBCacheUnit = ((TLBCacheData[0] & 0xFF000000) >> 24); break;
1211 // ebx: bits 0..7 : bits 8..15 : bits 16..23 : bits 24..31
1212 case 3: TLBCacheUnit = ((TLBCacheData[1] & 0x000000FF) >> 0); break;
1213 case 4: TLBCacheUnit = ((TLBCacheData[1] & 0x0000FF00) >> 8); break;
1214 case 5: TLBCacheUnit = ((TLBCacheData[1] & 0x00FF0000) >> 16); break;
1215 case 6: TLBCacheUnit = ((TLBCacheData[1] & 0xFF000000) >> 24); break;
1217 // ecx: bits 0..7 : bits 8..15 : bits 16..23 : bits 24..31
1218 case 7: TLBCacheUnit = ((TLBCacheData[2] & 0x000000FF) >> 0); break;
1219 case 8: TLBCacheUnit = ((TLBCacheData[2] & 0x0000FF00) >> 8); break;
1220 case 9: TLBCacheUnit = ((TLBCacheData[2] & 0x00FF0000) >> 16); break;
1221 case 10: TLBCacheUnit = ((TLBCacheData[2] & 0xFF000000) >> 24); break;
1223 // edx: bits 0..7 : bits 8..15 : bits 16..23 : bits 24..31
1224 case 11: TLBCacheUnit = ((TLBCacheData[3] & 0x000000FF) >> 0); break;
1225 case 12: TLBCacheUnit = ((TLBCacheData[3] & 0x0000FF00) >> 8); break;
1226 case 13: TLBCacheUnit = ((TLBCacheData[3] & 0x00FF0000) >> 16); break;
1227 case 14: TLBCacheUnit = ((TLBCacheData[3] & 0xFF000000) >> 24); break;
1229 // Default case - an error has occured.
1230 default: return false;
1233 // Now process the resulting unit to see what it means....
1234 switch (TLBCacheUnit)
1236 case 0x00: break;
1237 case 0x01: STORE_TLBCACHE_INFO (TLBCode, 4); break;
1238 case 0x02: STORE_TLBCACHE_INFO (TLBCode, 4096); break;
1239 case 0x03: STORE_TLBCACHE_INFO (TLBData, 4); break;
1240 case 0x04: STORE_TLBCACHE_INFO (TLBData, 4096); break;
1241 case 0x06: STORE_TLBCACHE_INFO (L1Code, 8); break;
1242 case 0x08: STORE_TLBCACHE_INFO (L1Code, 16); break;
1243 case 0x0a: STORE_TLBCACHE_INFO (L1Data, 8); break;
1244 case 0x0c: STORE_TLBCACHE_INFO (L1Data, 16); break;
1245 case 0x10: STORE_TLBCACHE_INFO (L1Data, 16); break; // <-- FIXME: IA-64 Only
1246 case 0x15: STORE_TLBCACHE_INFO (L1Code, 16); break; // <-- FIXME: IA-64 Only
1247 case 0x1a: STORE_TLBCACHE_INFO (L2Unified, 96); break; // <-- FIXME: IA-64 Only
1248 case 0x22: STORE_TLBCACHE_INFO (L3Unified, 512); break;
1249 case 0x23: STORE_TLBCACHE_INFO (L3Unified, 1024); break;
1250 case 0x25: STORE_TLBCACHE_INFO (L3Unified, 2048); break;
1251 case 0x29: STORE_TLBCACHE_INFO (L3Unified, 4096); break;
1252 case 0x39: STORE_TLBCACHE_INFO (L2Unified, 128); break;
1253 case 0x3c: STORE_TLBCACHE_INFO (L2Unified, 256); break;
1254 case 0x40: STORE_TLBCACHE_INFO (L2Unified, 0); break; // <-- FIXME: No integrated L2 cache (P6 core) or L3 cache (P4 core).
1255 case 0x41: STORE_TLBCACHE_INFO (L2Unified, 128); break;
1256 case 0x42: STORE_TLBCACHE_INFO (L2Unified, 256); break;
1257 case 0x43: STORE_TLBCACHE_INFO (L2Unified, 512); break;
1258 case 0x44: STORE_TLBCACHE_INFO (L2Unified, 1024); break;
1259 case 0x45: STORE_TLBCACHE_INFO (L2Unified, 2048); break;
1260 case 0x50: STORE_TLBCACHE_INFO (TLBCode, 4096); break;
1261 case 0x51: STORE_TLBCACHE_INFO (TLBCode, 4096); break;
1262 case 0x52: STORE_TLBCACHE_INFO (TLBCode, 4096); break;
1263 case 0x5b: STORE_TLBCACHE_INFO (TLBData, 4096); break;
1264 case 0x5c: STORE_TLBCACHE_INFO (TLBData, 4096); break;
1265 case 0x5d: STORE_TLBCACHE_INFO (TLBData, 4096); break;
1266 case 0x66: STORE_TLBCACHE_INFO (L1Data, 8); break;
1267 case 0x67: STORE_TLBCACHE_INFO (L1Data, 16); break;
1268 case 0x68: STORE_TLBCACHE_INFO (L1Data, 32); break;
1269 case 0x70: STORE_TLBCACHE_INFO (L1Trace, 12); break;
1270 case 0x71: STORE_TLBCACHE_INFO (L1Trace, 16); break;
1271 case 0x72: STORE_TLBCACHE_INFO (L1Trace, 32); break;
1272 case 0x77: STORE_TLBCACHE_INFO (L1Code, 16); break; // <-- FIXME: IA-64 Only
1273 case 0x79: STORE_TLBCACHE_INFO (L2Unified, 128); break;
1274 case 0x7a: STORE_TLBCACHE_INFO (L2Unified, 256); break;
1275 case 0x7b: STORE_TLBCACHE_INFO (L2Unified, 512); break;
1276 case 0x7c: STORE_TLBCACHE_INFO (L2Unified, 1024); break;
1277 case 0x7e: STORE_TLBCACHE_INFO (L2Unified, 256); break;
1278 case 0x81: STORE_TLBCACHE_INFO (L2Unified, 128); break;
1279 case 0x82: STORE_TLBCACHE_INFO (L2Unified, 256); break;
1280 case 0x83: STORE_TLBCACHE_INFO (L2Unified, 512); break;
1281 case 0x84: STORE_TLBCACHE_INFO (L2Unified, 1024); break;
1282 case 0x85: STORE_TLBCACHE_INFO (L2Unified, 2048); break;
1283 case 0x88: STORE_TLBCACHE_INFO (L3Unified, 2048); break; // <-- FIXME: IA-64 Only
1284 case 0x89: STORE_TLBCACHE_INFO (L3Unified, 4096); break; // <-- FIXME: IA-64 Only
1285 case 0x8a: STORE_TLBCACHE_INFO (L3Unified, 8192); break; // <-- FIXME: IA-64 Only
1286 case 0x8d: STORE_TLBCACHE_INFO (L3Unified, 3096); break; // <-- FIXME: IA-64 Only
1287 case 0x90: STORE_TLBCACHE_INFO (TLBCode, 262144); break; // <-- FIXME: IA-64 Only
1288 case 0x96: STORE_TLBCACHE_INFO (TLBCode, 262144); break; // <-- FIXME: IA-64 Only
1289 case 0x9b: STORE_TLBCACHE_INFO (TLBCode, 262144); break; // <-- FIXME: IA-64 Only
1291 // Default case - an error has occured.
1292 default: return false;
1296 // Increment the TLB pass counter.
1297 TLBPassCounter ++;
1298 } while ((TLBCacheData[0] & 0x000000FF) > TLBPassCounter);
1300 // Ok - we now have the maximum TLB, L1, L2, and L3 sizes...
1301 if ((L1Code == -1) && (L1Data == -1) && (L1Trace == -1))
1303 this->Features.L1CacheSize = -1;
1305 else if ((L1Code == -1) && (L1Data == -1) && (L1Trace != -1))
1307 this->Features.L1CacheSize = L1Trace;
1309 else if ((L1Code != -1) && (L1Data == -1))
1311 this->Features.L1CacheSize = L1Code;
1313 else if ((L1Code == -1) && (L1Data != -1))
1315 this->Features.L1CacheSize = L1Data;
1317 else if ((L1Code != -1) && (L1Data != -1))
1319 this->Features.L1CacheSize = L1Code + L1Data;
1321 else
1323 this->Features.L1CacheSize = -1;
1326 // Ok - we now have the maximum TLB, L1, L2, and L3 sizes...
1327 if (L2Unified == -1)
1329 this->Features.L2CacheSize = -1;
1331 else
1333 this->Features.L2CacheSize = L2Unified;
1336 // Ok - we now have the maximum TLB, L1, L2, and L3 sizes...
1337 if (L3Unified == -1)
1339 this->Features.L3CacheSize = -1;
1341 else
1343 this->Features.L3CacheSize = L3Unified;
1346 #endif
1347 return true;
1350 /** */
1351 bool SystemInformationImplementation::RetrieveCPUClockSpeed()
1353 #if _WIN32
1354 // First of all we check to see if the RDTSC (0x0F, 0x31) instruction is supported.
1355 if (!this->Features.HasTSC)
1357 return false;
1360 unsigned int uiRepetitions = 1;
1361 unsigned int uiMSecPerRepetition = 50;
1362 __int64 i64Total = 0;
1363 __int64 i64Overhead = 0;
1365 for (unsigned int nCounter = 0; nCounter < uiRepetitions; nCounter ++)
1367 i64Total += GetCyclesDifference (SystemInformationImplementation::Delay,
1368 uiMSecPerRepetition);
1369 i64Overhead +=
1370 GetCyclesDifference (SystemInformationImplementation::DelayOverhead,
1371 uiMSecPerRepetition);
1374 // Calculate the MHz speed.
1375 i64Total -= i64Overhead;
1376 i64Total /= uiRepetitions;
1377 i64Total /= uiMSecPerRepetition;
1378 i64Total /= 1000;
1380 // Save the CPU speed.
1381 this->CPUSpeedInMHz = (float) i64Total;
1383 return true;
1384 #else
1385 return false;
1386 #endif
1389 /** */
1390 bool SystemInformationImplementation::RetrieveClassicalCPUClockSpeed()
1392 #if USE_ASM_INSTRUCTIONS
1393 LARGE_INTEGER liStart, liEnd, liCountsPerSecond;
1394 double dFrequency, dDifference;
1396 // Attempt to get a starting tick count.
1397 QueryPerformanceCounter (&liStart);
1399 __try
1401 _asm
1403 mov eax, 0x80000000
1404 mov ebx, CLASSICAL_CPU_FREQ_LOOP
1405 Timer_Loop:
1406 bsf ecx,eax
1407 dec ebx
1408 jnz Timer_Loop
1411 __except(1)
1413 return false;
1416 // Attempt to get a starting tick count.
1417 QueryPerformanceCounter (&liEnd);
1419 // Get the difference... NB: This is in seconds....
1420 QueryPerformanceFrequency (&liCountsPerSecond);
1421 dDifference = (((double) liEnd.QuadPart - (double) liStart.QuadPart) / (double) liCountsPerSecond.QuadPart);
1423 // Calculate the clock speed.
1424 if (this->ChipID.Family == 3)
1426 // 80386 processors.... Loop time is 115 cycles!
1427 dFrequency = (((CLASSICAL_CPU_FREQ_LOOP * 115) / dDifference) / 1048576);
1429 else if (this->ChipID.Family == 4)
1431 // 80486 processors.... Loop time is 47 cycles!
1432 dFrequency = (((CLASSICAL_CPU_FREQ_LOOP * 47) / dDifference) / 1048576);
1434 else if (this->ChipID.Family == 5)
1436 // Pentium processors.... Loop time is 43 cycles!
1437 dFrequency = (((CLASSICAL_CPU_FREQ_LOOP * 43) / dDifference) / 1048576);
1440 // Save the clock speed.
1441 this->Features.CPUSpeed = (int) dFrequency;
1442 #else
1443 return true;
1444 #endif
1447 /** */
1448 bool SystemInformationImplementation::RetrieveCPUExtendedLevelSupport(int CPULevelToCheck)
1450 int MaxCPUExtendedLevel = 0;
1452 // The extended CPUID is supported by various vendors starting with the following CPU models:
1454 // Manufacturer & Chip Name | Family Model Revision
1456 // AMD K6, K6-2 | 5 6 x
1457 // Cyrix GXm, Cyrix III "Joshua" | 5 4 x
1458 // IDT C6-2 | 5 8 x
1459 // VIA Cyrix III | 6 5 x
1460 // Transmeta Crusoe | 5 x x
1461 // Intel Pentium 4 | f x x
1464 // We check to see if a supported processor is present...
1465 if (this->ChipManufacturer == AMD)
1467 if (this->ChipID.Family < 5) return false;
1468 if ((this->ChipID.Family == 5) && (this->ChipID.Model < 6)) return false;
1470 else if (this->ChipManufacturer == Cyrix)
1472 if (this->ChipID.Family < 5) return false;
1473 if ((this->ChipID.Family == 5) && (this->ChipID.Model < 4)) return false;
1474 if ((this->ChipID.Family == 6) && (this->ChipID.Model < 5)) return false;
1476 else if (this->ChipManufacturer == IDT)
1478 if (this->ChipID.Family < 5) return false;
1479 if ((this->ChipID.Family == 5) && (this->ChipID.Model < 8)) return false;
1481 else if (this->ChipManufacturer == Transmeta)
1483 if (this->ChipID.Family < 5) return false;
1485 else if (this->ChipManufacturer == Intel)
1487 if (this->ChipID.Family < 0xf)
1489 return false;
1493 #if USE_ASM_INSTRUCTIONS
1495 // Use assembly to detect CPUID information...
1496 __try {
1497 _asm {
1498 #ifdef CPUID_AWARE_COMPILER
1499 ; we must push/pop the registers <<CPUID>> writes to, as the
1500 ; optimiser doesn't know about <<CPUID>>, and so doesn't expect
1501 ; these registers to change.
1502 push eax
1503 push ebx
1504 push ecx
1505 push edx
1506 #endif
1507 ; <<CPUID>>
1508 ; eax = 0x80000000 --> eax: maximum supported extended level
1509 mov eax,0x80000000
1510 CPUID_INSTRUCTION
1511 mov MaxCPUExtendedLevel, eax
1513 #ifdef CPUID_AWARE_COMPILER
1514 pop edx
1515 pop ecx
1516 pop ebx
1517 pop eax
1518 #endif
1521 __except(1)
1523 return false;
1525 #endif
1527 // Now we have to check the level wanted vs level returned...
1528 int nLevelWanted = (CPULevelToCheck & 0x7FFFFFFF);
1529 int nLevelReturn = (MaxCPUExtendedLevel & 0x7FFFFFFF);
1531 // Check to see if the level provided is supported...
1532 if (nLevelWanted > nLevelReturn)
1534 return false;
1537 return true;
1540 /** */
1541 bool SystemInformationImplementation::RetrieveExtendedCPUFeatures()
1544 // Check that we are not using an Intel processor as it does not support this.
1545 if (this->ChipManufacturer == Intel)
1547 return false;
1550 // Check to see if what we are about to do is supported...
1551 if (!RetrieveCPUExtendedLevelSupport (0x80000001))
1553 return false;
1555 #if USE_ASM_INSTRUCTIONS
1556 int localCPUExtendedFeatures = 0;
1558 // Use assembly to detect CPUID information...
1559 __try
1561 _asm
1563 #ifdef CPUID_AWARE_COMPILER
1564 ; we must push/pop the registers <<CPUID>> writes to, as the
1565 ; optimiser doesn't know about <<CPUID>>, and so doesn't expect
1566 ; these registers to change.
1567 push eax
1568 push ebx
1569 push ecx
1570 push edx
1571 #endif
1572 ; <<CPUID>>
1573 ; eax = 0x80000001 --> eax: CPU ID - bits 31..16 - unused, bits 15..12 - type, bits 11..8 - family, bits 7..4 - model, bits 3..0 - mask revision
1574 ; ebx: 31..24 - default APIC ID, 23..16 - logical processsor ID, 15..8 - CFLUSH chunk size , 7..0 - brand ID
1575 ; edx: CPU feature flags
1576 mov eax,0x80000001
1577 CPUID_INSTRUCTION
1578 mov localCPUExtendedFeatures, edx
1580 #ifdef CPUID_AWARE_COMPILER
1581 pop edx
1582 pop ecx
1583 pop ebx
1584 pop eax
1585 #endif
1588 __except(1)
1590 return false;
1593 // Retrieve the extended features of CPU present.
1594 this->Features.ExtendedFeatures.Has3DNow = ((localCPUExtendedFeatures & 0x80000000) != 0); // 3DNow Present --> Bit 31.
1595 this->Features.ExtendedFeatures.Has3DNowPlus = ((localCPUExtendedFeatures & 0x40000000) != 0); // 3DNow+ Present -- > Bit 30.
1596 this->Features.ExtendedFeatures.HasSSEMMX = ((localCPUExtendedFeatures & 0x00400000) != 0); // SSE MMX Present --> Bit 22.
1597 this->Features.ExtendedFeatures.SupportsMP = ((localCPUExtendedFeatures & 0x00080000) != 0); // MP Capable -- > Bit 19.
1599 // Retrieve AMD specific extended features.
1600 if (this->ChipManufacturer == AMD)
1602 this->Features.ExtendedFeatures.HasMMXPlus = ((localCPUExtendedFeatures & 0x00400000) != 0); // AMD specific: MMX-SSE --> Bit 22
1605 // Retrieve Cyrix specific extended features.
1606 if (this->ChipManufacturer == Cyrix)
1608 this->Features.ExtendedFeatures.HasMMXPlus = ((localCPUExtendedFeatures & 0x01000000) != 0); // Cyrix specific: Extended MMX --> Bit 24
1610 #endif
1612 return true;
1615 /** */
1616 bool SystemInformationImplementation::RetrieveProcessorSerialNumber()
1618 // Check to see if the processor supports the processor serial number.
1619 if (!this->Features.HasSerial)
1621 return false;
1624 #if USE_ASM_INSTRUCTIONS
1625 int SerialNumber[3];
1628 // Use assembly to detect CPUID information...
1629 __try {
1630 _asm {
1631 #ifdef CPUID_AWARE_COMPILER
1632 ; we must push/pop the registers <<CPUID>> writes to, as the
1633 ; optimiser doesn't know about <<CPUID>>, and so doesn't expect
1634 ; these registers to change.
1635 push eax
1636 push ebx
1637 push ecx
1638 push edx
1639 #endif
1640 ; <<CPUID>>
1641 ; eax = 3 --> ebx: top 32 bits are the processor signature bits --> NB: Transmeta only ?!?
1642 ; ecx: middle 32 bits are the processor signature bits
1643 ; edx: bottom 32 bits are the processor signature bits
1644 mov eax, 3
1645 CPUID_INSTRUCTION
1646 mov SerialNumber[0 * TYPE int], ebx
1647 mov SerialNumber[1 * TYPE int], ecx
1648 mov SerialNumber[2 * TYPE int], edx
1650 #ifdef CPUID_AWARE_COMPILER
1651 pop edx
1652 pop ecx
1653 pop ebx
1654 pop eax
1655 #endif
1658 __except(1)
1660 return false;
1663 // Process the returned information.
1664 sprintf (this->ChipID.SerialNumber, "%.2x%.2x-%.2x%.2x-%.2x%.2x-%.2x%.2x-%.2x%.2x-%.2x%.2x",
1665 ((SerialNumber[0] & 0xff000000) >> 24),
1666 ((SerialNumber[0] & 0x00ff0000) >> 16),
1667 ((SerialNumber[0] & 0x0000ff00) >> 8),
1668 ((SerialNumber[0] & 0x000000ff) >> 0),
1669 ((SerialNumber[1] & 0xff000000) >> 24),
1670 ((SerialNumber[1] & 0x00ff0000) >> 16),
1671 ((SerialNumber[1] & 0x0000ff00) >> 8),
1672 ((SerialNumber[1] & 0x000000ff) >> 0),
1673 ((SerialNumber[2] & 0xff000000) >> 24),
1674 ((SerialNumber[2] & 0x00ff0000) >> 16),
1675 ((SerialNumber[2] & 0x0000ff00) >> 8),
1676 ((SerialNumber[2] & 0x000000ff) >> 0));
1677 #endif
1679 return true;
1682 /** */
1683 bool SystemInformationImplementation::RetrieveCPUPowerManagement()
1685 // Check to see if what we are about to do is supported...
1686 if (!RetrieveCPUExtendedLevelSupport (0x80000007))
1688 this->Features.ExtendedFeatures.PowerManagement.HasFrequencyID = false;
1689 this->Features.ExtendedFeatures.PowerManagement.HasVoltageID = false;
1690 this->Features.ExtendedFeatures.PowerManagement.HasTempSenseDiode = false;
1691 return false;
1694 #if USE_ASM_INSTRUCTIONS
1695 int localCPUPowerManagement = 0;
1698 // Use assembly to detect CPUID information...
1699 __try {
1700 _asm {
1701 #ifdef CPUID_AWARE_COMPILER
1702 ; we must push/pop the registers <<CPUID>> writes to, as the
1703 ; optimiser doesn't know about <<CPUID>>, and so doesn't expect
1704 ; these registers to change.
1705 push eax
1706 push ebx
1707 push ecx
1708 push edx
1709 #endif
1710 ; <<CPUID>>
1711 ; eax = 0x80000007 --> edx: get processor power management
1712 mov eax,0x80000007
1713 CPUID_INSTRUCTION
1714 mov localCPUPowerManagement, edx
1716 #ifdef CPUID_AWARE_COMPILER
1717 pop edx
1718 pop ecx
1719 pop ebx
1720 pop eax
1721 #endif
1724 __except(1)
1726 return false;
1729 // Check for the power management capabilities of the CPU.
1730 this->Features.ExtendedFeatures.PowerManagement.HasTempSenseDiode = ((localCPUPowerManagement & 0x00000001) != 0);
1731 this->Features.ExtendedFeatures.PowerManagement.HasFrequencyID = ((localCPUPowerManagement & 0x00000002) != 0);
1732 this->Features.ExtendedFeatures.PowerManagement.HasVoltageID = ((localCPUPowerManagement & 0x00000004) != 0);
1734 #endif
1736 return true;
1739 /** */
1740 bool SystemInformationImplementation::RetrieveExtendedCPUIdentity()
1742 // Check to see if what we are about to do is supported...
1743 if (!RetrieveCPUExtendedLevelSupport(0x80000002)) return false;
1744 if (!RetrieveCPUExtendedLevelSupport(0x80000003)) return false;
1745 if (!RetrieveCPUExtendedLevelSupport(0x80000004)) return false;
1747 #if USE_ASM_INSTRUCTIONS
1748 int ProcessorNameStartPos = 0;
1749 int CPUExtendedIdentity[12];
1751 // Use assembly to detect CPUID information...
1752 __try {
1753 _asm {
1754 #ifdef CPUID_AWARE_COMPILER
1755 ; we must push/pop the registers <<CPUID>> writes to, as the
1756 ; optimiser doesn't know about <<CPUID>>, and so doesn't expect
1757 ; these registers to change.
1758 push eax
1759 push ebx
1760 push ecx
1761 push edx
1762 #endif
1763 ; <<CPUID>>
1764 ; eax = 0x80000002 --> eax, ebx, ecx, edx: get processor name string (part 1)
1765 mov eax,0x80000002
1766 CPUID_INSTRUCTION
1767 mov CPUExtendedIdentity[0 * TYPE int], eax
1768 mov CPUExtendedIdentity[1 * TYPE int], ebx
1769 mov CPUExtendedIdentity[2 * TYPE int], ecx
1770 mov CPUExtendedIdentity[3 * TYPE int], edx
1772 ; <<CPUID>>
1773 ; eax = 0x80000003 --> eax, ebx, ecx, edx: get processor name string (part 2)
1774 mov eax,0x80000003
1775 CPUID_INSTRUCTION
1776 mov CPUExtendedIdentity[4 * TYPE int], eax
1777 mov CPUExtendedIdentity[5 * TYPE int], ebx
1778 mov CPUExtendedIdentity[6 * TYPE int], ecx
1779 mov CPUExtendedIdentity[7 * TYPE int], edx
1781 ; <<CPUID>>
1782 ; eax = 0x80000004 --> eax, ebx, ecx, edx: get processor name string (part 3)
1783 mov eax,0x80000004
1784 CPUID_INSTRUCTION
1785 mov CPUExtendedIdentity[8 * TYPE int], eax
1786 mov CPUExtendedIdentity[9 * TYPE int], ebx
1787 mov CPUExtendedIdentity[10 * TYPE int], ecx
1788 mov CPUExtendedIdentity[11 * TYPE int], edx
1790 #ifdef CPUID_AWARE_COMPILER
1791 pop edx
1792 pop ecx
1793 pop ebx
1794 pop eax
1795 #endif
1798 __except(1)
1800 return false;
1803 // Process the returned information.
1804 memcpy (this->ChipID.ProcessorName, &(CPUExtendedIdentity[0]), sizeof (int));
1805 memcpy (&(this->ChipID.ProcessorName[4]), &(CPUExtendedIdentity[1]), sizeof (int));
1806 memcpy (&(this->ChipID.ProcessorName[8]), &(CPUExtendedIdentity[2]), sizeof (int));
1807 memcpy (&(this->ChipID.ProcessorName[12]), &(CPUExtendedIdentity[3]), sizeof (int));
1808 memcpy (&(this->ChipID.ProcessorName[16]), &(CPUExtendedIdentity[4]), sizeof (int));
1809 memcpy (&(this->ChipID.ProcessorName[20]), &(CPUExtendedIdentity[5]), sizeof (int));
1810 memcpy (&(this->ChipID.ProcessorName[24]), &(CPUExtendedIdentity[6]), sizeof (int));
1811 memcpy (&(this->ChipID.ProcessorName[28]), &(CPUExtendedIdentity[7]), sizeof (int));
1812 memcpy (&(this->ChipID.ProcessorName[32]), &(CPUExtendedIdentity[8]), sizeof (int));
1813 memcpy (&(this->ChipID.ProcessorName[36]), &(CPUExtendedIdentity[9]), sizeof (int));
1814 memcpy (&(this->ChipID.ProcessorName[40]), &(CPUExtendedIdentity[10]), sizeof (int));
1815 memcpy (&(this->ChipID.ProcessorName[44]), &(CPUExtendedIdentity[11]), sizeof (int));
1816 this->ChipID.ProcessorName[48] = '\0';
1818 // Because some manufacturers have leading white space - we have to post-process the name.
1819 if (this->ChipManufacturer == Intel)
1821 for (int nCounter = 0; nCounter < CHIPNAME_STRING_LENGTH; nCounter ++)
1823 // There will either be NULL (\0) or spaces ( ) as the leading characters.
1824 if ((this->ChipID.ProcessorName[nCounter] != '\0') && (this->ChipID.ProcessorName[nCounter] != ' '))
1826 // We have found the starting position of the name.
1827 ProcessorNameStartPos = nCounter;
1828 // Terminate the loop.
1829 break;
1833 // Check to see if there is any white space at the start.
1834 if (ProcessorNameStartPos == 0)
1836 return true;
1839 // Now move the name forward so that there is no white space.
1840 memmove(this->ChipID.ProcessorName, &(this->ChipID.ProcessorName[ProcessorNameStartPos]), (CHIPNAME_STRING_LENGTH - ProcessorNameStartPos));
1842 #endif
1844 return true;
1847 /** */
1848 bool SystemInformationImplementation::RetrieveClassicalCPUIdentity()
1850 // Start by decided which manufacturer we are using....
1851 switch (this->ChipManufacturer)
1853 case Intel:
1854 // Check the family / model / revision to determine the CPU ID.
1855 switch (this->ChipID.Family) {
1856 case 3:
1857 sprintf (this->ChipID.ProcessorName, "Newer i80386 family");
1858 break;
1859 case 4:
1860 switch (this->ChipID.Model) {
1861 case 0: sprintf (this->ChipID.ProcessorName,"i80486DX-25/33"); break;
1862 case 1: sprintf (this->ChipID.ProcessorName,"i80486DX-50"); break;
1863 case 2: sprintf (this->ChipID.ProcessorName,"i80486SX"); break;
1864 case 3: sprintf (this->ChipID.ProcessorName,"i80486DX2"); break;
1865 case 4: sprintf (this->ChipID.ProcessorName,"i80486SL"); break;
1866 case 5: sprintf (this->ChipID.ProcessorName,"i80486SX2"); break;
1867 case 7: sprintf (this->ChipID.ProcessorName,"i80486DX2 WriteBack"); break;
1868 case 8: sprintf (this->ChipID.ProcessorName,"i80486DX4"); break;
1869 case 9: sprintf (this->ChipID.ProcessorName,"i80486DX4 WriteBack"); break;
1870 default: sprintf (this->ChipID.ProcessorName,"Unknown 80486 family"); return false;
1872 break;
1873 case 5:
1874 switch (this->ChipID.Model)
1876 case 0: sprintf (this->ChipID.ProcessorName,"P5 A-Step"); break;
1877 case 1: sprintf (this->ChipID.ProcessorName,"P5"); break;
1878 case 2: sprintf (this->ChipID.ProcessorName,"P54C"); break;
1879 case 3: sprintf (this->ChipID.ProcessorName,"P24T OverDrive"); break;
1880 case 4: sprintf (this->ChipID.ProcessorName,"P55C"); break;
1881 case 7: sprintf (this->ChipID.ProcessorName,"P54C"); break;
1882 case 8: sprintf (this->ChipID.ProcessorName,"P55C (0.25micron)"); break;
1883 default: sprintf (this->ChipID.ProcessorName,"Unknown Pentium family"); return false;
1885 break;
1886 case 6:
1887 switch (this->ChipID.Model)
1889 case 0: sprintf (this->ChipID.ProcessorName,"P6 A-Step"); break;
1890 case 1: sprintf (this->ChipID.ProcessorName,"P6"); break;
1891 case 3: sprintf (this->ChipID.ProcessorName,"Pentium II (0.28 micron)"); break;
1892 case 5: sprintf (this->ChipID.ProcessorName,"Pentium II (0.25 micron)"); break;
1893 case 6: sprintf (this->ChipID.ProcessorName,"Pentium II With On-Die L2 Cache"); break;
1894 case 7: sprintf (this->ChipID.ProcessorName,"Pentium III (0.25 micron)"); break;
1895 case 8: sprintf (this->ChipID.ProcessorName,"Pentium III (0.18 micron) With 256 KB On-Die L2 Cache "); break;
1896 case 0xa: sprintf (this->ChipID.ProcessorName,"Pentium III (0.18 micron) With 1 Or 2 MB On-Die L2 Cache "); break;
1897 case 0xb: sprintf (this->ChipID.ProcessorName,"Pentium III (0.13 micron) With 256 Or 512 KB On-Die L2 Cache "); break;
1898 default: sprintf (this->ChipID.ProcessorName,"Unknown P6 family"); return false;
1900 break;
1901 case 7:
1902 sprintf (this->ChipID.ProcessorName,"Intel Merced (IA-64)");
1903 break;
1904 case 0xf:
1905 // Check the extended family bits...
1906 switch (this->ChipID.ExtendedFamily)
1908 case 0:
1909 switch (this->ChipID.Model)
1911 case 0: sprintf (this->ChipID.ProcessorName,"Pentium IV (0.18 micron)"); break;
1912 case 1: sprintf (this->ChipID.ProcessorName,"Pentium IV (0.18 micron)"); break;
1913 case 2: sprintf (this->ChipID.ProcessorName,"Pentium IV (0.13 micron)"); break;
1914 default: sprintf (this->ChipID.ProcessorName,"Unknown Pentium 4 family"); return false;
1916 break;
1917 case 1:
1918 sprintf (this->ChipID.ProcessorName,"Intel McKinley (IA-64)");
1919 break;
1920 default:
1921 sprintf (this->ChipID.ProcessorName,"Pentium");
1923 break;
1924 default:
1925 sprintf (this->ChipID.ProcessorName,"Unknown Intel family");
1926 return false;
1928 break;
1930 case AMD:
1931 // Check the family / model / revision to determine the CPU ID.
1932 switch (this->ChipID.Family)
1934 case 4:
1935 switch (this->ChipID.Model)
1937 case 3: sprintf (this->ChipID.ProcessorName,"80486DX2"); break;
1938 case 7: sprintf (this->ChipID.ProcessorName,"80486DX2 WriteBack"); break;
1939 case 8: sprintf (this->ChipID.ProcessorName,"80486DX4"); break;
1940 case 9: sprintf (this->ChipID.ProcessorName,"80486DX4 WriteBack"); break;
1941 case 0xe: sprintf (this->ChipID.ProcessorName,"5x86"); break;
1942 case 0xf: sprintf (this->ChipID.ProcessorName,"5x86WB"); break;
1943 default: sprintf (this->ChipID.ProcessorName,"Unknown 80486 family"); return false;
1945 break;
1946 case 5:
1947 switch (this->ChipID.Model)
1949 case 0: sprintf (this->ChipID.ProcessorName,"SSA5 (PR75, PR90, PR100)"); break;
1950 case 1: sprintf (this->ChipID.ProcessorName,"5k86 (PR120, PR133)"); break;
1951 case 2: sprintf (this->ChipID.ProcessorName,"5k86 (PR166)"); break;
1952 case 3: sprintf (this->ChipID.ProcessorName,"5k86 (PR200)"); break;
1953 case 6: sprintf (this->ChipID.ProcessorName,"K6 (0.30 micron)"); break;
1954 case 7: sprintf (this->ChipID.ProcessorName,"K6 (0.25 micron)"); break;
1955 case 8: sprintf (this->ChipID.ProcessorName,"K6-2"); break;
1956 case 9: sprintf (this->ChipID.ProcessorName,"K6-III"); break;
1957 case 0xd: sprintf (this->ChipID.ProcessorName,"K6-2+ or K6-III+ (0.18 micron)"); break;
1958 default: sprintf (this->ChipID.ProcessorName,"Unknown 80586 family"); return false;
1960 break;
1961 case 6:
1962 switch (this->ChipID.Model)
1964 case 1: sprintf (this->ChipID.ProcessorName,"Athlon- (0.25 micron)"); break;
1965 case 2: sprintf (this->ChipID.ProcessorName,"Athlon- (0.18 micron)"); break;
1966 case 3: sprintf (this->ChipID.ProcessorName,"Duron- (SF core)"); break;
1967 case 4: sprintf (this->ChipID.ProcessorName,"Athlon- (Thunderbird core)"); break;
1968 case 6: sprintf (this->ChipID.ProcessorName,"Athlon- (Palomino core)"); break;
1969 case 7: sprintf (this->ChipID.ProcessorName,"Duron- (Morgan core)"); break;
1970 case 8:
1971 if (this->Features.ExtendedFeatures.SupportsMP)
1972 sprintf (this->ChipID.ProcessorName,"Athlon - MP (Thoroughbred core)");
1973 else sprintf (this->ChipID.ProcessorName,"Athlon - XP (Thoroughbred core)");
1974 break;
1975 default: sprintf (this->ChipID.ProcessorName,"Unknown K7 family"); return false;
1977 break;
1978 default:
1979 sprintf (this->ChipID.ProcessorName,"Unknown AMD family");
1980 return false;
1982 break;
1984 case Transmeta:
1985 switch (this->ChipID.Family)
1987 case 5:
1988 switch (this->ChipID.Model)
1990 case 4: sprintf (this->ChipID.ProcessorName,"Crusoe TM3x00 and TM5x00"); break;
1991 default: sprintf (this->ChipID.ProcessorName,"Unknown Crusoe family"); return false;
1993 break;
1994 default:
1995 sprintf (this->ChipID.ProcessorName,"Unknown Transmeta family");
1996 return false;
1998 break;
2000 case Rise:
2001 switch (this->ChipID.Family)
2003 case 5:
2004 switch (this->ChipID.Model)
2006 case 0: sprintf (this->ChipID.ProcessorName,"mP6 (0.25 micron)"); break;
2007 case 2: sprintf (this->ChipID.ProcessorName,"mP6 (0.18 micron)"); break;
2008 default: sprintf (this->ChipID.ProcessorName,"Unknown Rise family"); return false;
2010 break;
2011 default:
2012 sprintf (this->ChipID.ProcessorName,"Unknown Rise family");
2013 return false;
2015 break;
2017 case UMC:
2018 switch (this->ChipID.Family)
2020 case 4:
2021 switch (this->ChipID.Model)
2023 case 1: sprintf (this->ChipID.ProcessorName,"U5D"); break;
2024 case 2: sprintf (this->ChipID.ProcessorName,"U5S"); break;
2025 default: sprintf (this->ChipID.ProcessorName,"Unknown UMC family"); return false;
2027 break;
2028 default:
2029 sprintf (this->ChipID.ProcessorName,"Unknown UMC family");
2030 return false;
2032 break;
2034 case IDT:
2035 switch (this->ChipID.Family)
2037 case 5:
2038 switch (this->ChipID.Model)
2040 case 4: sprintf (this->ChipID.ProcessorName,"C6"); break;
2041 case 8: sprintf (this->ChipID.ProcessorName,"C2"); break;
2042 case 9: sprintf (this->ChipID.ProcessorName,"C3"); break;
2043 default: sprintf (this->ChipID.ProcessorName,"Unknown IDT\\Centaur family"); return false;
2045 break;
2046 case 6:
2047 switch (this->ChipID.Model)
2049 case 6: sprintf (this->ChipID.ProcessorName,"VIA Cyrix III - Samuel"); break;
2050 default: sprintf (this->ChipID.ProcessorName,"Unknown IDT\\Centaur family"); return false;
2052 break;
2053 default:
2054 sprintf (this->ChipID.ProcessorName,"Unknown IDT\\Centaur family");
2055 return false;
2057 break;
2059 case Cyrix:
2060 switch (this->ChipID.Family)
2062 case 4:
2063 switch (this->ChipID.Model)
2065 case 4: sprintf (this->ChipID.ProcessorName,"MediaGX GX, GXm"); break;
2066 case 9: sprintf (this->ChipID.ProcessorName,"5x86"); break;
2067 default: sprintf (this->ChipID.ProcessorName,"Unknown Cx5x86 family"); return false;
2069 break;
2070 case 5:
2071 switch (this->ChipID.Model)
2073 case 2: sprintf (this->ChipID.ProcessorName,"Cx6x86"); break;
2074 case 4: sprintf (this->ChipID.ProcessorName,"MediaGX GXm"); break;
2075 default: sprintf (this->ChipID.ProcessorName,"Unknown Cx6x86 family"); return false;
2077 break;
2078 case 6:
2079 switch (this->ChipID.Model)
2081 case 0: sprintf (this->ChipID.ProcessorName,"6x86MX"); break;
2082 case 5: sprintf (this->ChipID.ProcessorName,"Cyrix M2 Core"); break;
2083 case 6: sprintf (this->ChipID.ProcessorName,"WinChip C5A Core"); break;
2084 case 7: sprintf (this->ChipID.ProcessorName,"WinChip C5B\\C5C Core"); break;
2085 case 8: sprintf (this->ChipID.ProcessorName,"WinChip C5C-T Core"); break;
2086 default: sprintf (this->ChipID.ProcessorName,"Unknown 6x86MX\\Cyrix III family"); return false;
2088 break;
2089 default:
2090 sprintf (this->ChipID.ProcessorName,"Unknown Cyrix family");
2091 return false;
2093 break;
2095 case NexGen:
2096 switch (this->ChipID.Family)
2098 case 5:
2099 switch (this->ChipID.Model)
2101 case 0: sprintf (this->ChipID.ProcessorName,"Nx586 or Nx586FPU"); break;
2102 default: sprintf (this->ChipID.ProcessorName,"Unknown NexGen family"); return false;
2104 break;
2105 default:
2106 sprintf (this->ChipID.ProcessorName,"Unknown NexGen family");
2107 return false;
2109 break;
2111 case NSC:
2112 sprintf (this->ChipID.ProcessorName,"Cx486SLC \\ DLC \\ Cx486S A-Step");
2113 break;
2114 default:
2115 sprintf (this->ChipID.ProcessorName,"Unknown family"); // We cannot identify the processor.
2116 return false;
2119 return true;
2122 /** Extract a value from the CPUInfo file */
2123 kwsys_stl::string SystemInformationImplementation::ExtractValueFromCpuInfoFile(kwsys_stl::string buffer,const char* word,size_t init)
2125 size_t pos = buffer.find(word,init);
2126 if(pos != buffer.npos)
2128 this->CurrentPositionInFile = pos;
2129 pos = buffer.find(":",pos);
2130 size_t pos2 = buffer.find("\n",pos);
2131 if(pos!=buffer.npos && pos2!=buffer.npos)
2133 return buffer.substr(pos+2,pos2-pos-2);
2136 this->CurrentPositionInFile = buffer.npos;
2137 return "";
2140 /** Query for the cpu status */
2141 int SystemInformationImplementation::RetreiveInformationFromCpuInfoFile()
2143 this->NumberOfLogicalCPU = 0;
2144 this->NumberOfPhysicalCPU = 0;
2145 kwsys_stl::string buffer;
2147 FILE *fd = fopen("/proc/cpuinfo", "r" );
2148 if ( !fd )
2150 kwsys_ios::cout << "Problem opening /proc/cpuinfo" << kwsys_stl::endl;
2151 return 0;
2154 size_t fileSize = 0;
2155 while(!feof(fd))
2157 buffer += fgetc(fd);
2158 fileSize++;
2160 fclose( fd );
2161 buffer.resize(fileSize-2);
2162 // Number of logical CPUs (combination of multiple processors, multi-core
2163 // and hyperthreading)
2164 size_t pos = buffer.find("processor\t");
2165 while(pos != buffer.npos)
2167 this->NumberOfLogicalCPU++;
2168 pos = buffer.find("processor\t",pos+1);
2171 #ifdef __linux
2172 // Find the largest physical id.
2173 int maxId = -1;
2174 kwsys_stl::string idc =
2175 this->ExtractValueFromCpuInfoFile(buffer,"physical id");
2176 while(this->CurrentPositionInFile != buffer.npos)
2178 int id = atoi(idc.c_str());
2179 if(id > maxId)
2181 maxId=id;
2183 idc = this->ExtractValueFromCpuInfoFile(buffer,"physical id",
2184 this->CurrentPositionInFile+1);
2186 // Physical ids returned by Linux don't distinguish cores.
2187 // We want to record the total number of cores in this->NumberOfPhysicalCPU
2188 // (checking only the first proc)
2189 kwsys_stl::string cores =
2190 this->ExtractValueFromCpuInfoFile(buffer,"cpu cores");
2191 int numberOfCoresPerCPU=atoi(cores.c_str());
2192 this->NumberOfPhysicalCPU=numberOfCoresPerCPU*(maxId+1);
2194 #else // __CYGWIN__
2195 // does not have "physical id" entries, neither "cpu cores"
2196 // this has to be fixed for hyper-threading.
2197 kwsys_stl::string cpucount =
2198 this->ExtractValueFromCpuInfoFile(buffer,"cpu count");
2199 this->NumberOfPhysicalCPU=
2200 this->NumberOfLogicalCPU = atoi(cpucount.c_str());
2201 #endif
2202 // gotta have one, and if this is 0 then we get a / by 0n
2203 // beter to have a bad answer than a crash
2204 if(this->NumberOfPhysicalCPU <= 0)
2206 this->NumberOfPhysicalCPU = 1;
2208 // LogicalProcessorsPerPhysical>1 => hyperthreading.
2209 this->Features.ExtendedFeatures.LogicalProcessorsPerPhysical=
2210 this->NumberOfLogicalCPU/this->NumberOfPhysicalCPU;
2212 // CPU speed (checking only the first proc
2213 kwsys_stl::string CPUSpeed = this->ExtractValueFromCpuInfoFile(buffer,"cpu MHz");
2214 this->CPUSpeedInMHz = static_cast<float>(atof(CPUSpeed.c_str()));
2216 // Chip family
2217 this->ChipID.Family = atoi(this->ExtractValueFromCpuInfoFile(buffer,"cpu family").c_str());
2219 // Chip Vendor
2220 strcpy(this->ChipID.Vendor,this->ExtractValueFromCpuInfoFile(buffer,"vendor_id").c_str());
2221 this->FindManufacturer();
2223 // Chip Model
2224 this->ChipID.Model = atoi(this->ExtractValueFromCpuInfoFile(buffer,"model").c_str());
2225 this->RetrieveClassicalCPUIdentity();
2227 // L1 Cache size
2228 kwsys_stl::string cacheSize = this->ExtractValueFromCpuInfoFile(buffer,"cache size");
2229 pos = cacheSize.find(" KB");
2230 if(pos!=cacheSize.npos)
2232 cacheSize = cacheSize.substr(0,pos);
2234 this->Features.L1CacheSize = atoi(cacheSize.c_str());
2235 return 1;
2238 /** Query for the memory status */
2239 int SystemInformationImplementation::QueryMemory()
2241 this->TotalVirtualMemory = 0;
2242 this->TotalPhysicalMemory = 0;
2243 this->AvailableVirtualMemory = 0;
2244 this->AvailablePhysicalMemory = 0;
2245 #ifdef __CYGWIN__
2246 return 0;
2247 #elif _WIN32
2248 #if _MSC_VER < 1300
2249 MEMORYSTATUS ms;
2250 GlobalMemoryStatus(&ms);
2251 #define MEM_VAL(value) dw##value
2252 #else
2253 MEMORYSTATUSEX ms;
2254 GlobalMemoryStatusEx(&ms);
2255 #define MEM_VAL(value) ull##value
2256 #endif
2257 unsigned long tv = ms.MEM_VAL(TotalVirtual);
2258 unsigned long tp = ms.MEM_VAL(TotalPhys);
2259 unsigned long av = ms.MEM_VAL(AvailVirtual);
2260 unsigned long ap = ms.MEM_VAL(AvailPhys);
2261 this->TotalVirtualMemory = tv>>10>>10;
2262 this->TotalPhysicalMemory = tp>>10>>10;
2263 this->AvailableVirtualMemory = av>>10>>10;
2264 this->AvailablePhysicalMemory = ap>>10>>10;
2265 return 1;
2266 #elif __linux
2267 unsigned long tv=0;
2268 unsigned long tp=0;
2269 unsigned long av=0;
2270 unsigned long ap=0;
2272 char buffer[1024]; // for skipping unused lines
2274 int linuxMajor = 0;
2275 int linuxMinor = 0;
2277 // Find the Linux kernel version first
2278 struct utsname unameInfo;
2279 int errorFlag = uname(&unameInfo);
2280 if( errorFlag!=0 )
2282 kwsys_ios::cout << "Problem calling uname(): " << strerror(errno) << kwsys_stl::endl;
2283 return 0;
2286 if( unameInfo.release!=0 && strlen(unameInfo.release)>=3 )
2288 // release looks like "2.6.3-15mdk-i686-up-4GB"
2289 char majorChar=unameInfo.release[0];
2290 char minorChar=unameInfo.release[2];
2292 if( isdigit(majorChar) )
2294 linuxMajor=majorChar-'0';
2297 if( isdigit(minorChar) )
2299 linuxMinor=minorChar-'0';
2303 FILE *fd = fopen("/proc/meminfo", "r" );
2304 if ( !fd )
2306 kwsys_ios::cout << "Problem opening /proc/meminfo" << kwsys_stl::endl;
2307 return 0;
2310 if( linuxMajor>=3 || ( (linuxMajor>=2) && (linuxMinor>=6) ) )
2312 // new /proc/meminfo format since kernel 2.6.x
2313 // Rigorously, this test should check from the developping version 2.5.x
2314 // that introduced the new format...
2316 long freeMem;
2317 long buffersMem;
2318 long cachedMem;
2320 fscanf(fd,"MemTotal:%ld kB\n", &this->TotalPhysicalMemory);
2321 fscanf(fd,"MemFree:%ld kB\n", &freeMem);
2322 fscanf(fd,"Buffers:%ld kB\n", &buffersMem);
2323 fscanf(fd,"Cached:%ld kB\n", &cachedMem);
2325 this->TotalPhysicalMemory /= 1024;
2326 this->AvailablePhysicalMemory = freeMem+cachedMem+buffersMem;
2327 this->AvailablePhysicalMemory /= 1024;
2329 // Skip SwapCached, Active, Inactive, HighTotal, HighFree, LowTotal
2330 // and LowFree.
2331 int i=0;
2332 while(i<7)
2334 fgets(buffer, sizeof(buffer), fd); // skip a line
2335 ++i;
2338 fscanf(fd,"SwapTotal:%ld kB\n", &this->TotalVirtualMemory);
2339 fscanf(fd,"SwapFree:%ld kB\n", &this->AvailableVirtualMemory);
2341 this->TotalVirtualMemory /= 1024;
2342 this->AvailableVirtualMemory /= 1024;
2344 else
2346 // /proc/meminfo format for kernel older than 2.6.x
2348 unsigned long temp;
2349 unsigned long cachedMem;
2350 unsigned long buffersMem;
2351 fgets(buffer, sizeof(buffer), fd); // Skip "total: used:..."
2353 fscanf(fd, "Mem: %lu %lu %lu %lu %lu %lu\n",
2354 &tp, &temp, &ap, &temp, &buffersMem, &cachedMem);
2355 fscanf(fd, "Swap: %lu %lu %lu\n", &tv, &temp, &av);
2357 this->TotalVirtualMemory = tv>>10>>10;
2358 this->TotalPhysicalMemory = tp>>10>>10;
2359 this->AvailableVirtualMemory = av>>10>>10;
2360 this->AvailablePhysicalMemory = (ap+buffersMem+cachedMem)>>10>>10;
2362 fclose( fd );
2363 return 1;
2364 #elif __hpux
2365 unsigned long tv=0;
2366 unsigned long tp=0;
2367 unsigned long av=0;
2368 unsigned long ap=0;
2369 struct pst_static pst;
2370 struct pst_dynamic pdy;
2372 unsigned long ps = 0;
2373 if (pstat_getstatic(&pst, sizeof(pst), (size_t) 1, 0) != -1)
2375 ps = pst.page_size;
2376 tp = pst.physical_memory *ps;
2377 tv = (pst.physical_memory + pst.pst_maxmem) * ps;
2378 if (pstat_getdynamic(&pdy, sizeof(pdy), (size_t) 1, 0) != -1)
2380 ap = tp - pdy.psd_rm * ps;
2381 av = tv - pdy.psd_vm;
2382 this->TotalVirtualMemory = tv>>10>>10;
2383 this->TotalPhysicalMemory = tp>>10>>10;
2384 this->AvailableVirtualMemory = av>>10>>10;
2385 this->AvailablePhysicalMemory = ap>>10>>10;
2386 return 1;
2389 return 0;
2390 #else
2391 return 0;
2392 #endif
2397 /** */
2398 unsigned long SystemInformationImplementation::GetTotalVirtualMemory()
2400 return this->TotalVirtualMemory;
2403 /** */
2404 unsigned long SystemInformationImplementation::GetAvailableVirtualMemory()
2406 return this->AvailableVirtualMemory;
2409 unsigned long SystemInformationImplementation::GetTotalPhysicalMemory()
2411 return this->TotalPhysicalMemory;
2414 /** */
2415 unsigned long SystemInformationImplementation::GetAvailablePhysicalMemory()
2417 return this->AvailablePhysicalMemory;
2420 /** Get Cycle differences */
2421 LongLong SystemInformationImplementation::GetCyclesDifference (DELAY_FUNC DelayFunction,
2422 unsigned int uiParameter)
2424 #if USE_ASM_INSTRUCTIONS
2426 unsigned int edx1, eax1;
2427 unsigned int edx2, eax2;
2429 // Calculate the frequency of the CPU instructions.
2430 __try {
2431 _asm {
2432 push uiParameter ; push parameter param
2433 mov ebx, DelayFunction ; store func in ebx
2435 RDTSC_INSTRUCTION
2437 mov esi, eax ; esi = eax
2438 mov edi, edx ; edi = edx
2440 call ebx ; call the delay functions
2442 RDTSC_INSTRUCTION
2444 pop ebx
2446 mov edx2, edx ; edx2 = edx
2447 mov eax2, eax ; eax2 = eax
2449 mov edx1, edi ; edx2 = edi
2450 mov eax1, esi ; eax2 = esi
2453 __except(1)
2455 return -1;
2458 return ((((__int64) edx2 << 32) + eax2) - (((__int64) edx1 << 32) + eax1));
2460 #else
2461 (void)DelayFunction;
2462 (void)uiParameter;
2463 return -1;
2464 #endif
2467 /** Compute the delay overhead */
2468 void SystemInformationImplementation::DelayOverhead(unsigned int uiMS)
2470 #if _WIN32
2471 LARGE_INTEGER Frequency, StartCounter, EndCounter;
2472 __int64 x;
2474 // Get the frequency of the high performance counter.
2475 if(!QueryPerformanceFrequency (&Frequency))
2477 return;
2479 x = Frequency.QuadPart / 1000 * uiMS;
2481 // Get the starting position of the counter.
2482 QueryPerformanceCounter (&StartCounter);
2484 do {
2485 // Get the ending position of the counter.
2486 QueryPerformanceCounter (&EndCounter);
2487 } while (EndCounter.QuadPart - StartCounter.QuadPart == x);
2488 #endif
2489 (void)uiMS;
2492 /** Return the number of logical CPU per physical CPUs Works only for windows */
2493 unsigned char SystemInformationImplementation::LogicalCPUPerPhysicalCPU(void)
2495 unsigned int Regebx = 0;
2496 #if USE_ASM_INSTRUCTIONS
2497 if (!this->IsHyperThreadingSupported())
2499 return (unsigned char) 1; // HT not supported
2501 __asm
2503 mov eax, 1
2504 cpuid
2505 mov Regebx, ebx
2507 #endif
2508 return (unsigned char) ((Regebx & NUM_LOGICAL_BITS) >> 16);
2511 /** Works only for windows */
2512 unsigned int SystemInformationImplementation::IsHyperThreadingSupported()
2514 #if USE_ASM_INSTRUCTIONS
2515 unsigned int Regedx = 0,
2516 Regeax = 0,
2517 VendorId[3] = {0, 0, 0};
2518 __try // Verify cpuid instruction is supported
2520 __asm
2522 xor eax, eax // call cpuid with eax = 0
2523 cpuid // Get vendor id string
2524 mov VendorId, ebx
2525 mov VendorId + 4, edx
2526 mov VendorId + 8, ecx
2528 mov eax, 1 // call cpuid with eax = 1
2529 cpuid
2530 mov Regeax, eax // eax contains family processor type
2531 mov Regedx, edx // edx has info about the availability of hyper-Threading
2534 __except (EXCEPTION_EXECUTE_HANDLER)
2536 return(0); // cpuid is unavailable
2539 if (((Regeax & FAMILY_ID) == PENTIUM4_ID) || (Regeax & EXT_FAMILY_ID))
2541 if (VendorId[0] == 'uneG')
2543 if (VendorId[1] == 'Ieni')
2545 if (VendorId[2] == 'letn')
2547 return(Regedx & HT_BIT); // Genuine Intel with hyper-Threading technology
2552 #endif
2554 return 0; // Not genuine Intel processor
2557 /** Return the APIC Id. Works only for windows. */
2558 unsigned char SystemInformationImplementation::GetAPICId()
2560 unsigned int Regebx = 0;
2561 #if USE_ASM_INSTRUCTIONS
2562 if (!this->IsHyperThreadingSupported())
2564 return (unsigned char) -1; // HT not supported
2565 } // Logical processor = 1
2566 __asm
2568 mov eax, 1
2569 cpuid
2570 mov Regebx, ebx
2572 #endif
2573 return (unsigned char) ((Regebx & INITIAL_APIC_ID_BITS) >> 24);
2576 /** Count the number of CPUs. Works only on windows. */
2577 int SystemInformationImplementation::CPUCount()
2579 #if _WIN32
2580 unsigned char StatusFlag = 0;
2581 SYSTEM_INFO info;
2583 this->NumberOfPhysicalCPU = 0;
2584 this->NumberOfLogicalCPU = 0;
2585 info.dwNumberOfProcessors = 0;
2586 GetSystemInfo (&info);
2588 // Number of physical processors in a non-Intel system
2589 // or in a 32-bit Intel system with Hyper-Threading technology disabled
2590 this->NumberOfPhysicalCPU = (unsigned char) info.dwNumberOfProcessors;
2592 if (this->IsHyperThreadingSupported())
2594 unsigned char HT_Enabled = 0;
2595 this->NumberOfLogicalCPU = this->LogicalCPUPerPhysicalCPU();
2596 if (this->NumberOfLogicalCPU >= 1) // >1 Doesn't mean HT is enabled in the BIOS
2598 HANDLE hCurrentProcessHandle;
2599 #ifndef _WIN64
2600 # define DWORD_PTR DWORD
2601 #endif
2602 DWORD_PTR dwProcessAffinity;
2603 DWORD_PTR dwSystemAffinity;
2604 DWORD dwAffinityMask;
2606 // Calculate the appropriate shifts and mask based on the
2607 // number of logical processors.
2608 unsigned int i = 1;
2609 unsigned char PHY_ID_MASK = 0xFF;
2610 //unsigned char PHY_ID_SHIFT = 0;
2612 while (i < this->NumberOfLogicalCPU)
2614 i *= 2;
2615 PHY_ID_MASK <<= 1;
2616 // PHY_ID_SHIFT++;
2619 hCurrentProcessHandle = GetCurrentProcess();
2620 GetProcessAffinityMask(hCurrentProcessHandle, &dwProcessAffinity,
2621 &dwSystemAffinity);
2623 // Check if available process affinity mask is equal to the
2624 // available system affinity mask
2625 if (dwProcessAffinity != dwSystemAffinity)
2627 StatusFlag = HT_CANNOT_DETECT;
2628 this->NumberOfPhysicalCPU = (unsigned char)-1;
2629 return StatusFlag;
2632 dwAffinityMask = 1;
2633 while (dwAffinityMask != 0 && dwAffinityMask <= dwProcessAffinity)
2635 // Check if this CPU is available
2636 if (dwAffinityMask & dwProcessAffinity)
2638 if (SetProcessAffinityMask(hCurrentProcessHandle,
2639 dwAffinityMask))
2641 unsigned char APIC_ID, LOG_ID;
2642 Sleep(0); // Give OS time to switch CPU
2644 APIC_ID = GetAPICId();
2645 LOG_ID = APIC_ID & ~PHY_ID_MASK;
2647 if (LOG_ID != 0)
2649 HT_Enabled = 1;
2653 dwAffinityMask = dwAffinityMask << 1;
2655 // Reset the processor affinity
2656 SetProcessAffinityMask(hCurrentProcessHandle, dwProcessAffinity);
2658 if (this->NumberOfLogicalCPU == 1) // Normal P4 : HT is disabled in hardware
2660 StatusFlag = HT_DISABLED;
2662 else
2664 if (HT_Enabled)
2666 // Total physical processors in a Hyper-Threading enabled system.
2667 this->NumberOfPhysicalCPU /= (this->NumberOfLogicalCPU);
2668 StatusFlag = HT_ENABLED;
2670 else
2672 StatusFlag = HT_SUPPORTED_NOT_ENABLED;
2677 else
2679 // Processors do not have Hyper-Threading technology
2680 StatusFlag = HT_NOT_CAPABLE;
2681 this->NumberOfLogicalCPU = 1;
2683 return StatusFlag;
2684 #else
2685 return 0;
2686 #endif
2689 /** Return the number of logical CPUs on the system */
2690 unsigned int SystemInformationImplementation::GetNumberOfLogicalCPU()
2692 return this->NumberOfLogicalCPU;
2695 /** Return the number of physical CPUs on the system */
2696 unsigned int SystemInformationImplementation::GetNumberOfPhysicalCPU()
2698 return this->NumberOfPhysicalCPU;
2701 /** For Mac we Parse the sysctl -a output */
2702 bool SystemInformationImplementation::ParseSysCtl()
2704 // Extract the arguments from the command line
2705 kwsys_stl::vector<const char*> args;
2706 args.push_back("sysctl");
2707 args.push_back("-a");
2708 args.push_back(0);
2710 this->SysCtlBuffer = this->RunProcess(args);
2712 // Parse values for Mac
2713 this->TotalPhysicalMemory = atoi(this->ExtractValueFromSysCtl("hw.memsize:").c_str())/(1024*1024);
2714 this->TotalVirtualMemory = 0;
2715 this->AvailablePhysicalMemory = 0;
2716 this->AvailableVirtualMemory = 0;
2718 this->NumberOfPhysicalCPU = atoi(this->ExtractValueFromSysCtl("hw.physicalcpu:").c_str());
2719 this->NumberOfLogicalCPU = atoi(this->ExtractValueFromSysCtl("hw.logicalcpu:").c_str());
2721 if(this->NumberOfPhysicalCPU!=0)
2723 this->NumberOfLogicalCPU /= this->NumberOfPhysicalCPU;
2726 this->CPUSpeedInMHz = atoi(this->ExtractValueFromSysCtl("hw.cpufrequency:").c_str());
2727 this->CPUSpeedInMHz /= 1000000;
2729 // Chip family
2730 this->ChipID.Family = atoi(this->ExtractValueFromSysCtl("machdep.cpu.family:").c_str());
2732 // Chip Vendor
2733 strcpy(this->ChipID.Vendor,this->ExtractValueFromSysCtl("machdep.cpu.vendor:").c_str());
2734 this->FindManufacturer();
2736 // Chip Model
2737 this->ChipID.Model = atoi(this->ExtractValueFromSysCtl("machdep.cpu.model:").c_str());
2738 this->RetrieveClassicalCPUIdentity();
2740 // Cache size
2741 this->Features.L1CacheSize = atoi(this->ExtractValueFromSysCtl("hw.l1icachesize:").c_str());
2742 this->Features.L2CacheSize = atoi(this->ExtractValueFromSysCtl("hw.l2cachesize:").c_str());
2744 return true;
2747 /** Extract a value from sysctl command */
2748 kwsys_stl::string SystemInformationImplementation::ExtractValueFromSysCtl(const char* word)
2750 size_t pos = this->SysCtlBuffer.find(word);
2751 if(pos != this->SysCtlBuffer.npos)
2753 pos = this->SysCtlBuffer.find(": ",pos);
2754 size_t pos2 = this->SysCtlBuffer.find("\n",pos);
2755 if(pos!=this->SysCtlBuffer.npos && pos2!=this->SysCtlBuffer.npos)
2757 return this->SysCtlBuffer.substr(pos+2,pos2-pos-2);
2760 return "";
2763 /** Run a given process */
2764 kwsys_stl::string SystemInformationImplementation::RunProcess(kwsys_stl::vector<const char*> args)
2766 kwsys_stl::string buffer = "";
2768 // Run the application
2769 kwsysProcess* gp = kwsysProcess_New();
2770 kwsysProcess_SetCommand(gp, &*args.begin());
2771 kwsysProcess_SetOption(gp,kwsysProcess_Option_HideWindow,1);
2773 kwsysProcess_Execute(gp);
2775 char* data = NULL;
2776 int length;
2777 double timeout = 255;
2779 while(kwsysProcess_WaitForData(gp,&data,&length,&timeout)) // wait for 1s
2781 for(int i=0;i<length;i++)
2783 buffer += data[i];
2786 kwsysProcess_WaitForExit(gp, 0);
2788 int result = 0;
2789 switch(kwsysProcess_GetState(gp))
2791 case kwsysProcess_State_Exited:
2793 result = kwsysProcess_GetExitValue(gp);
2794 } break;
2795 case kwsysProcess_State_Error:
2797 kwsys_ios::cerr << "Error: Could not run " << args[0] << ":\n";
2798 kwsys_ios::cerr << kwsysProcess_GetErrorString(gp) << "\n";
2799 } break;
2800 case kwsysProcess_State_Exception:
2802 kwsys_ios::cerr << "Error: " << args[0]
2803 << " terminated with an exception: "
2804 << kwsysProcess_GetExceptionString(gp) << "\n";
2805 } break;
2806 case kwsysProcess_State_Starting:
2807 case kwsysProcess_State_Executing:
2808 case kwsysProcess_State_Expired:
2809 case kwsysProcess_State_Killed:
2811 // Should not get here.
2812 kwsys_ios::cerr << "Unexpected ending state after running " << args[0]
2813 << kwsys_stl::endl;
2814 } break;
2816 kwsysProcess_Delete(gp);
2817 if(result)
2819 kwsys_ios::cerr << "Error " << args[0] << " returned :" << result << "\n";
2821 return buffer;
2825 kwsys_stl::string SystemInformationImplementation::ParseValueFromKStat(const char* arguments)
2827 kwsys_stl::vector<const char*> args;
2828 args.clear();
2829 args.push_back("kstat");
2830 args.push_back("-p");
2832 kwsys_stl::string command = arguments;
2833 size_t start = command.npos;
2834 size_t pos = command.find(' ',0);
2835 while(pos!=command.npos)
2837 bool inQuotes = false;
2838 // Check if we are between quotes
2839 size_t b0 = command.find('"',0);
2840 size_t b1 = command.find('"',b0+1);
2841 while(b0 != command.npos && b1 != command.npos && b1>b0)
2843 if(pos>b0 && pos<b1)
2845 inQuotes = true;
2846 break;
2848 b0 = command.find('"',b1+1);
2849 b1 = command.find('"',b0+1);
2852 if(!inQuotes)
2854 kwsys_stl::string arg = command.substr(start+1,pos-start-1);
2856 // Remove the quotes if any
2857 size_t quotes = arg.find('"');
2858 while(quotes != arg.npos)
2860 arg.erase(quotes,1);
2861 quotes = arg.find('"');
2863 args.push_back(arg.c_str());
2864 start = pos;
2866 pos = command.find(' ',pos+1);
2868 kwsys_stl::string lastArg = command.substr(start+1,command.size()-start-1);
2869 args.push_back(lastArg.c_str());
2871 args.push_back(0);
2873 kwsys_stl::string buffer = this->RunProcess(args);
2875 kwsys_stl::string value = "";
2876 for(size_t i=buffer.size()-1;i>0;i--)
2878 if(buffer[i] == ' ' || buffer[i] == '\t')
2880 break;
2882 if(buffer[i] != '\n' && buffer[i] != '\r')
2884 kwsys_stl::string val = value;
2885 value = buffer[i];
2886 value += val;
2889 return value;
2892 /** Querying for system information from Solaris */
2893 bool SystemInformationImplementation::QuerySolarisInfo()
2895 // Parse values
2896 this->NumberOfPhysicalCPU = atoi(this->ParseValueFromKStat("-n systethis->misc -s ncpus").c_str());
2897 this->NumberOfLogicalCPU = this->NumberOfPhysicalCPU;
2899 if(this->NumberOfPhysicalCPU!=0)
2901 this->NumberOfLogicalCPU /= this->NumberOfPhysicalCPU;
2904 this->CPUSpeedInMHz = atoi(this->ParseValueFromKStat("-s clock_MHz").c_str());
2906 // Chip family
2907 this->ChipID.Family = 0;
2909 // Chip Vendor
2910 strcpy(this->ChipID.Vendor,"Sun");
2911 this->FindManufacturer();
2913 // Chip Model
2914 sprintf(this->ChipID.ProcessorName,"%s",this->ParseValueFromKStat("-s cpu_type").c_str());
2915 this->ChipID.Model = 0;
2917 // Cache size
2918 this->Features.L1CacheSize = 0;
2919 this->Features.L2CacheSize = 0;
2921 char* tail;
2922 unsigned long totalMemory =
2923 strtoul(this->ParseValueFromKStat("-s physmem").c_str(),&tail,0);
2924 this->TotalPhysicalMemory = totalMemory/1024;
2925 this->TotalPhysicalMemory *= 8192;
2926 this->TotalPhysicalMemory /= 1024;
2928 // Undefined values (for now at least)
2929 this->TotalVirtualMemory = 0;
2930 this->AvailablePhysicalMemory = 0;
2931 this->AvailableVirtualMemory = 0;
2933 return true;
2936 /** Query the operating system information */
2937 bool SystemInformationImplementation::QueryOSInformation()
2939 #if _WIN32
2941 this->OSName = "Windows";
2943 OSVERSIONINFOEX osvi;
2944 BOOL bIsWindows64Bit;
2945 BOOL bOsVersionInfoEx;
2946 char operatingSystem[256];
2948 // Try calling GetVersionEx using the OSVERSIONINFOEX structure.
2949 ZeroMemory (&osvi, sizeof (OSVERSIONINFOEX));
2950 osvi.dwOSVersionInfoSize = sizeof (OSVERSIONINFOEX);
2951 bOsVersionInfoEx = GetVersionEx ((OSVERSIONINFO *) &osvi);
2952 if (!bOsVersionInfoEx)
2954 osvi.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
2955 if (!GetVersionEx ((OSVERSIONINFO *) &osvi))
2957 return false;
2961 switch (osvi.dwPlatformId)
2963 case VER_PLATFORM_WIN32_NT:
2964 // Test for the product.
2965 if (osvi.dwMajorVersion <= 4)
2967 this->OSRelease = "NT";
2969 if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0)
2971 this->OSRelease = "2000";
2973 if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1)
2975 this->OSRelease = "XP";
2977 #ifdef VER_NT_WORKSTATION
2978 // Test for product type.
2979 if (bOsVersionInfoEx)
2981 if (osvi.wProductType == VER_NT_WORKSTATION)
2983 if (osvi.dwMajorVersion == 6)
2985 this->OSRelease = "Vista";
2987 // VER_SUITE_PERSONAL may not be defined
2988 #ifdef VER_SUITE_PERSONAL
2989 else
2991 if (osvi.wSuiteMask & VER_SUITE_PERSONAL)
2993 this->OSRelease += " Personal";
2995 else
2997 this->OSRelease += " Professional";
3000 #endif
3002 else if (osvi.wProductType == VER_NT_SERVER)
3004 // Check for .NET Server instead of Windows XP.
3005 if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1)
3007 this->OSRelease = ".NET";
3010 // Continue with the type detection.
3011 if (osvi.wSuiteMask & VER_SUITE_DATACENTER)
3013 this->OSRelease += " DataCenter Server";
3015 else if (osvi.wSuiteMask & VER_SUITE_ENTERPRISE)
3017 this->OSRelease += " Advanced Server";
3019 else
3021 this->OSRelease += " Server";
3025 sprintf (operatingSystem, "%s (Build %ld)", osvi.szCSDVersion, osvi.dwBuildNumber & 0xFFFF);
3026 this->OSVersion = operatingSystem;
3028 else
3029 #endif // VER_NT_WORKSTATION
3031 HKEY hKey;
3032 char szProductType[80];
3033 DWORD dwBufLen;
3035 // Query the registry to retrieve information.
3036 RegOpenKeyEx (HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Control\\ProductOptions", 0, KEY_QUERY_VALUE, &hKey);
3037 RegQueryValueEx (hKey, "ProductType", NULL, NULL, (LPBYTE) szProductType, &dwBufLen);
3038 RegCloseKey (hKey);
3040 if (lstrcmpi ("WINNT", szProductType) == 0)
3042 this->OSRelease += " Professional";
3044 if (lstrcmpi ("LANMANNT", szProductType) == 0)
3046 // Decide between Windows 2000 Advanced Server and Windows .NET Enterprise Server.
3047 if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1)
3049 this->OSRelease += " Standard Server";
3051 else
3053 this->OSRelease += " Server";
3056 if (lstrcmpi ("SERVERNT", szProductType) == 0)
3058 // Decide between Windows 2000 Advanced Server and Windows .NET Enterprise Server.
3059 if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1)
3061 this->OSRelease += " Enterprise Server";
3063 else
3065 this->OSRelease += " Advanced Server";
3070 // Display version, service pack (if any), and build number.
3071 if (osvi.dwMajorVersion <= 4)
3073 // NB: NT 4.0 and earlier.
3074 sprintf (operatingSystem, "version %ld.%ld %s (Build %ld)",
3075 osvi.dwMajorVersion,
3076 osvi.dwMinorVersion,
3077 osvi.szCSDVersion,
3078 osvi.dwBuildNumber & 0xFFFF);
3079 this->OSVersion = operatingSystem;
3081 else if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1)
3083 // Windows XP and .NET server.
3084 typedef BOOL (CALLBACK* LPFNPROC) (HANDLE, BOOL *);
3085 HINSTANCE hKernelDLL;
3086 LPFNPROC DLLProc;
3088 // Load the Kernel32 DLL.
3089 hKernelDLL = LoadLibrary ("kernel32");
3090 if (hKernelDLL != NULL) {
3091 // Only XP and .NET Server support IsWOW64Process so... Load dynamically!
3092 DLLProc = (LPFNPROC) GetProcAddress (hKernelDLL, "IsWow64Process");
3094 // If the function address is valid, call the function.
3095 if (DLLProc != NULL) (DLLProc) (GetCurrentProcess (), &bIsWindows64Bit);
3096 else bIsWindows64Bit = false;
3098 // Free the DLL module.
3099 FreeLibrary (hKernelDLL);
3102 else
3104 // Windows 2000 and everything else.
3105 sprintf (operatingSystem,"%s (Build %ld)", osvi.szCSDVersion, osvi.dwBuildNumber & 0xFFFF);
3106 this->OSVersion = operatingSystem;
3108 break;
3110 case VER_PLATFORM_WIN32_WINDOWS:
3111 // Test for the product.
3112 if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 0)
3114 this->OSRelease = "95";
3115 if(osvi.szCSDVersion[1] == 'C')
3117 this->OSRelease += "OSR 2.5";
3119 else if(osvi.szCSDVersion[1] == 'B')
3121 this->OSRelease += "OSR 2";
3125 if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 10)
3127 this->OSRelease = "98";
3128 if (osvi.szCSDVersion[1] == 'A' )
3130 this->OSRelease += "SE";
3134 if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 90)
3136 this->OSRelease = "Me";
3138 break;
3140 case VER_PLATFORM_WIN32s:
3141 this->OSRelease = "Win32s";
3142 break;
3144 default:
3145 this->OSRelease = "Unknown";
3146 break;
3149 // Get the hostname
3150 WORD wVersionRequested;
3151 WSADATA wsaData;
3152 char name[255];
3153 wVersionRequested = MAKEWORD(2,0);
3155 if ( WSAStartup( wVersionRequested, &wsaData ) == 0 )
3157 gethostname(name,sizeof(name));
3158 WSACleanup( );
3160 this->Hostname = name;
3162 #else
3164 struct utsname unameInfo;
3165 int errorFlag = uname(&unameInfo);
3166 if(errorFlag == 0)
3168 this->OSName = unameInfo.sysname;
3169 this->Hostname = unameInfo.nodename;
3170 this->OSRelease = unameInfo.release;
3171 this->OSVersion = unameInfo.version;
3172 this->OSPlatform = unameInfo.machine;
3174 #endif
3176 return true;
3180 /** Return true if the machine is 64 bits */
3181 bool SystemInformationImplementation::Is64Bits()
3183 return (sizeof(void*) == 8);
3186 } // namespace @KWSYS_NAMESPACE@