ENH: fix for VS6 and Cygwin
[cmake.git] / Source / kwsys / SystemInformation.cxx
blobdc69d32b675582e13589d2c094b4e6501c488eb5
1 /*=========================================================================
3 Program: BatchMake
4 Module: $RCSfile: SystemInformation.cxx,v $
5 Language: C++
6 Date: $Date: 2008-10-17 15:29:38 $
7 Version: $Revision: 1.23.2.2 $
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 #ifdef _WIN32
17 # include <winsock.h> // WSADATA, include before sys/types.h
18 #endif
20 #include "kwsysPrivate.h"
21 #include KWSYS_HEADER(FundamentalType.h)
22 #include KWSYS_HEADER(stl/string)
23 #include KWSYS_HEADER(stl/vector)
24 #include KWSYS_HEADER(ios/iosfwd)
25 #include KWSYS_HEADER(SystemInformation.hxx)
26 #include KWSYS_HEADER(Process.h)
27 #include KWSYS_HEADER(ios/iostream)
28 #include KWSYS_HEADER(ios/sstream)
29 // Work-around CMake dependency scanning limitation. This must
30 // duplicate the above list of headers.
31 #if 0
32 # include "FundamentalType.h.in"
33 # include "SystemInformation.hxx.in"
34 # include "Process.h.in"
35 # include "Configure.hxx.in"
36 # include "kwsys_stl.hxx.in"
37 # include "kwsys_stl_vector.in"
38 # include "kwsys_stl_iosfwd.in"
39 # include "kwsys_ios_sstream.h.in"
40 # include "kwsys_ios_iostream.h.in"
41 #endif
44 #ifndef WIN32
45 # include <sys/utsname.h> // int uname(struct utsname *buf);
46 #endif
48 #ifdef _WIN32
49 # include <windows.h>
50 #endif
52 #ifdef __linux
53 # include <sys/procfs.h>
54 # include <sys/types.h>
55 # include <unistd.h>
56 # include <fcntl.h>
57 # include <ctype.h> // int isdigit(int c);
58 # include <errno.h> // extern int errno;
59 # include <sys/time.h>
60 #elif __hpux
61 # include <sys/param.h>
62 # include <sys/pstat.h>
63 #endif
65 #include <memory.h>
66 #include <stdlib.h>
67 #include <stdio.h>
68 #include <string.h>
72 namespace KWSYS_NAMESPACE
75 // Create longlong
76 #if KWSYS_USE_LONG_LONG
77 typedef long long LongLong;
78 #elif KWSYS_USE___INT64
79 typedef __int64 LongLong;
80 #else
81 # error "No Long Long"
82 #endif
84 // Define SystemInformationImplementation class
85 typedef void (*DELAY_FUNC)(unsigned int uiMS);
87 class SystemInformationImplementation
90 public:
91 SystemInformationImplementation ();
92 ~SystemInformationImplementation ();
94 const char * GetVendorString();
95 const char * GetVendorID();
96 kwsys_stl::string GetTypeID();
97 kwsys_stl::string GetFamilyID();
98 kwsys_stl::string GetModelID();
99 kwsys_stl::string GetSteppingCode();
100 const char * GetExtendedProcessorName();
101 const char * GetProcessorSerialNumber();
102 int GetProcessorCacheSize();
103 int GetLogicalProcessorsPerPhysical();
104 float GetProcessorClockFrequency();
105 int GetProcessorAPICID();
106 int GetProcessorCacheXSize(long int);
107 bool DoesCPUSupportFeature(long int);
109 const char * GetOSName();
110 const char * GetHostname();
111 const char * GetOSRelease();
112 const char * GetOSVersion();
113 const char * GetOSPlatform();
115 bool Is64Bits();
117 unsigned int GetNumberOfLogicalCPU(); // per physical cpu
118 unsigned int GetNumberOfPhysicalCPU();
120 bool DoesCPUSupportCPUID();
122 // Retrieve memory information in megabyte.
123 unsigned long GetTotalVirtualMemory();
124 unsigned long GetAvailableVirtualMemory();
125 unsigned long GetTotalPhysicalMemory();
126 unsigned long GetAvailablePhysicalMemory();
128 /** Run the different checks */
129 void RunCPUCheck();
130 void RunOSCheck();
131 void RunMemoryCheck();
132 public:
133 #define VENDOR_STRING_LENGTH (12 + 1)
134 #define CHIPNAME_STRING_LENGTH (48 + 1)
135 #define SERIALNUMBER_STRING_LENGTH (29 + 1)
137 typedef struct tagID
139 int Type;
140 int Family;
141 int Model;
142 int Revision;
143 int ExtendedFamily;
144 int ExtendedModel;
145 char ProcessorName[CHIPNAME_STRING_LENGTH];
146 char Vendor[VENDOR_STRING_LENGTH];
147 char SerialNumber[SERIALNUMBER_STRING_LENGTH];
148 } ID;
150 typedef struct tagCPUPowerManagement
152 bool HasVoltageID;
153 bool HasFrequencyID;
154 bool HasTempSenseDiode;
155 } CPUPowerManagement;
157 typedef struct tagCPUExtendedFeatures
159 bool Has3DNow;
160 bool Has3DNowPlus;
161 bool SupportsMP;
162 bool HasMMXPlus;
163 bool HasSSEMMX;
164 bool SupportsHyperthreading;
165 int LogicalProcessorsPerPhysical;
166 int APIC_ID;
167 CPUPowerManagement PowerManagement;
168 } CPUExtendedFeatures;
170 typedef struct CPUtagFeatures
172 bool HasFPU;
173 bool HasTSC;
174 bool HasMMX;
175 bool HasSSE;
176 bool HasSSEFP;
177 bool HasSSE2;
178 bool HasIA64;
179 bool HasAPIC;
180 bool HasCMOV;
181 bool HasMTRR;
182 bool HasACPI;
183 bool HasSerial;
184 bool HasThermal;
185 int CPUSpeed;
186 int L1CacheSize;
187 int L2CacheSize;
188 int L3CacheSize;
189 CPUExtendedFeatures ExtendedFeatures;
190 } CPUFeatures;
192 enum Manufacturer
194 AMD, Intel, NSC, UMC, Cyrix, NexGen, IDT, Rise, Transmeta, Sun, UnknownManufacturer
196 protected:
198 // Functions.
199 bool RetrieveCPUFeatures();
200 bool RetrieveCPUIdentity();
201 bool RetrieveCPUCacheDetails();
202 bool RetrieveClassicalCPUCacheDetails();
203 bool RetrieveCPUClockSpeed();
204 bool RetrieveClassicalCPUClockSpeed();
205 bool RetrieveCPUExtendedLevelSupport(int);
206 bool RetrieveExtendedCPUFeatures();
207 bool RetrieveProcessorSerialNumber();
208 bool RetrieveCPUPowerManagement();
209 bool RetrieveClassicalCPUIdentity();
210 bool RetrieveExtendedCPUIdentity();
212 Manufacturer ChipManufacturer;
213 CPUFeatures Features;
214 ID ChipID;
215 float CPUSpeedInMHz;
216 unsigned int NumberOfLogicalCPU;
217 unsigned int NumberOfPhysicalCPU;
219 int CPUCount();
220 unsigned char LogicalCPUPerPhysicalCPU();
221 unsigned char GetAPICId();
222 unsigned int IsHyperThreadingSupported();
223 LongLong GetCyclesDifference(DELAY_FUNC, unsigned int);
225 // For Linux and Cygwin, /proc/cpuinfo formats are slightly different
226 int RetreiveInformationFromCpuInfoFile();
227 kwsys_stl::string ExtractValueFromCpuInfoFile(kwsys_stl::string buffer,
228 const char* word, size_t init=0);
230 static void Delay (unsigned int);
231 static void DelayOverhead (unsigned int);
233 void FindManufacturer();
235 // For Mac
236 bool ParseSysCtl();
237 kwsys_stl::string ExtractValueFromSysCtl(const char* word);
238 kwsys_stl::string SysCtlBuffer;
240 // For Solaris
241 bool QuerySolarisInfo();
242 kwsys_stl::string ParseValueFromKStat(const char* arguments);
243 kwsys_stl::string RunProcess(kwsys_stl::vector<const char*> args);
245 // Evaluate the memory information.
246 int QueryMemory();
247 unsigned long TotalVirtualMemory;
248 unsigned long AvailableVirtualMemory;
249 unsigned long TotalPhysicalMemory;
250 unsigned long AvailablePhysicalMemory;
252 size_t CurrentPositionInFile;
254 // Operating System information
255 bool QueryOSInformation();
256 kwsys_stl::string OSName;
257 kwsys_stl::string Hostname;
258 kwsys_stl::string OSRelease;
259 kwsys_stl::string OSVersion;
260 kwsys_stl::string OSPlatform;
267 SystemInformation::SystemInformation()
269 this->Implementation = new SystemInformationImplementation;
272 SystemInformation::~SystemInformation ()
274 delete this->Implementation;
277 const char * SystemInformation::GetVendorString()
279 return this->Implementation->GetVendorString();
281 const char * SystemInformation::GetVendorID()
283 return this->Implementation->GetVendorID();
285 kwsys_stl::string SystemInformation::GetTypeID()
287 return this->Implementation->GetTypeID();
289 kwsys_stl::string SystemInformation::GetFamilyID()
291 return this->Implementation->GetFamilyID();
293 kwsys_stl::string SystemInformation::GetModelID()
295 return this->Implementation->GetModelID();
297 kwsys_stl::string SystemInformation::GetSteppingCode()
299 return this->Implementation->GetSteppingCode();
301 const char * SystemInformation::GetExtendedProcessorName()
303 return this->Implementation->GetExtendedProcessorName();
305 const char * SystemInformation::GetProcessorSerialNumber()
307 return this->Implementation->GetProcessorSerialNumber();
309 int SystemInformation::GetProcessorCacheSize()
311 return this->Implementation->GetProcessorCacheSize();
313 int SystemInformation::GetLogicalProcessorsPerPhysical()
315 return this->Implementation->GetLogicalProcessorsPerPhysical();
317 float SystemInformation::GetProcessorClockFrequency()
319 return this->Implementation->GetProcessorClockFrequency();
321 int SystemInformation::GetProcessorAPICID()
323 return this->Implementation->GetProcessorAPICID();
325 int SystemInformation::GetProcessorCacheXSize(long int l)
327 return this->Implementation->GetProcessorCacheXSize(l);
329 bool SystemInformation::DoesCPUSupportFeature(long int i)
331 return this->Implementation->DoesCPUSupportFeature(i);
334 const char * SystemInformation::GetOSName()
336 return this->Implementation->GetOSName();
338 const char * SystemInformation::GetHostname()
340 return this->Implementation->GetHostname();
342 const char * SystemInformation::GetOSRelease()
344 return this->Implementation->GetOSRelease();
346 const char * SystemInformation::GetOSVersion()
348 return this->Implementation->GetOSVersion();
350 const char * SystemInformation::GetOSPlatform()
352 return this->Implementation->GetOSPlatform();
355 bool SystemInformation::Is64Bits()
357 return this->Implementation->Is64Bits();
360 unsigned int SystemInformation::GetNumberOfLogicalCPU() // per physical cpu
362 return this->Implementation->GetNumberOfLogicalCPU();
364 unsigned int SystemInformation::GetNumberOfPhysicalCPU()
366 return this->Implementation->GetNumberOfPhysicalCPU();
369 bool SystemInformation::DoesCPUSupportCPUID()
371 return this->Implementation->DoesCPUSupportCPUID();
374 // Retrieve memory information in megabyte.
375 unsigned long SystemInformation::GetTotalVirtualMemory()
377 return this->Implementation->GetTotalVirtualMemory();
379 unsigned long SystemInformation::GetAvailableVirtualMemory()
381 return this->Implementation->GetAvailableVirtualMemory();
383 unsigned long SystemInformation::GetTotalPhysicalMemory()
385 return this->Implementation->GetTotalPhysicalMemory();
388 unsigned long SystemInformation::GetAvailablePhysicalMemory()
390 return this->Implementation->GetAvailablePhysicalMemory();
393 /** Run the different checks */
394 void SystemInformation::RunCPUCheck()
396 this->Implementation->RunCPUCheck();
398 void SystemInformation::RunOSCheck()
400 this->Implementation->RunOSCheck();
402 void SystemInformation::RunMemoryCheck()
404 this->Implementation->RunMemoryCheck();
409 // --------------------------------------------------------------
410 // SystemInformationImplementation starts here
412 #if defined(_MSC_VER) && (_MSC_VER >= 1300) && !defined(_WIN64)
413 #define USE_ASM_INSTRUCTIONS 1
414 #else
415 #define USE_ASM_INSTRUCTIONS 0
416 #endif
418 #define STORE_TLBCACHE_INFO(x,y) x = (x < y) ? y : x
419 #define TLBCACHE_INFO_UNITS (15)
420 #define CLASSICAL_CPU_FREQ_LOOP 10000000
421 #define RDTSC_INSTRUCTION _asm _emit 0x0f _asm _emit 0x31
423 #define CPUID_AWARE_COMPILER
424 #ifdef CPUID_AWARE_COMPILER
425 #define CPUID_INSTRUCTION cpuid
426 #else
427 #define CPUID_INSTRUCTION _asm _emit 0x0f _asm _emit 0xa2
428 #endif
430 #define MMX_FEATURE 0x00000001
431 #define MMX_PLUS_FEATURE 0x00000002
432 #define SSE_FEATURE 0x00000004
433 #define SSE2_FEATURE 0x00000008
434 #define AMD_3DNOW_FEATURE 0x00000010
435 #define AMD_3DNOW_PLUS_FEATURE 0x00000020
436 #define IA64_FEATURE 0x00000040
437 #define MP_CAPABLE 0x00000080
438 #define HYPERTHREAD_FEATURE 0x00000100
439 #define SERIALNUMBER_FEATURE 0x00000200
440 #define APIC_FEATURE 0x00000400
441 #define SSE_FP_FEATURE 0x00000800
442 #define SSE_MMX_FEATURE 0x00001000
443 #define CMOV_FEATURE 0x00002000
444 #define MTRR_FEATURE 0x00004000
445 #define L1CACHE_FEATURE 0x00008000
446 #define L2CACHE_FEATURE 0x00010000
447 #define L3CACHE_FEATURE 0x00020000
448 #define ACPI_FEATURE 0x00040000
449 #define THERMALMONITOR_FEATURE 0x00080000
450 #define TEMPSENSEDIODE_FEATURE 0x00100000
451 #define FREQUENCYID_FEATURE 0x00200000
452 #define VOLTAGEID_FREQUENCY 0x00400000
454 // Status Flag
455 #define HT_NOT_CAPABLE 0
456 #define HT_ENABLED 1
457 #define HT_DISABLED 2
458 #define HT_SUPPORTED_NOT_ENABLED 3
459 #define HT_CANNOT_DETECT 4
461 // EDX[28] Bit 28 is set if HT is supported
462 #define HT_BIT 0x10000000
464 // EAX[11:8] Bit 8-11 contains family processor ID.
465 #define FAMILY_ID 0x0F00
466 #define PENTIUM4_ID 0x0F00
467 // EAX[23:20] Bit 20-23 contains extended family processor ID
468 #define EXT_FAMILY_ID 0x0F00000
469 // EBX[23:16] Bit 16-23 in ebx contains the number of logical
470 #define NUM_LOGICAL_BITS 0x00FF0000
471 // processors per physical processor when execute cpuid with
472 // eax set to 1
473 // EBX[31:24] Bits 24-31 (8 bits) return the 8-bit unique
474 #define INITIAL_APIC_ID_BITS 0xFF000000
475 // initial APIC ID for the processor this code is running on.
476 // Default value = 0xff if HT is not supported
480 SystemInformationImplementation::SystemInformationImplementation()
482 this->TotalVirtualMemory = 0;
483 this->AvailableVirtualMemory = 0;
484 this->TotalPhysicalMemory = 0;
485 this->AvailablePhysicalMemory = 0;
486 this->CurrentPositionInFile = 0;
487 this->ChipManufacturer = UnknownManufacturer;
488 memset(&this->Features, 0, sizeof(CPUFeatures));
489 memset(&this->ChipID, 0, sizeof(ID));
490 this->CPUSpeedInMHz = 0;
491 this->NumberOfLogicalCPU = 0;
492 this->NumberOfPhysicalCPU = 0;
493 this->OSName = "";
494 this->Hostname = "";
495 this->OSRelease = "";
496 this->OSVersion = "";
497 this->OSPlatform = "";
500 SystemInformationImplementation::~SystemInformationImplementation()
504 void SystemInformationImplementation::RunCPUCheck()
506 #ifdef WIN32
507 // Check to see if this processor supports CPUID.
508 if (DoesCPUSupportCPUID())
510 // Retrieve the CPU details.
511 RetrieveCPUIdentity();
512 RetrieveCPUFeatures();
513 if (!RetrieveCPUClockSpeed())
515 RetrieveClassicalCPUClockSpeed();
518 // Attempt to retrieve cache information.
519 if (!RetrieveCPUCacheDetails())
521 RetrieveClassicalCPUCacheDetails();
523 // Retrieve the extended CPU details.
524 if (!RetrieveExtendedCPUIdentity())
526 RetrieveClassicalCPUIdentity();
528 RetrieveExtendedCPUFeatures();
530 // Now attempt to retrieve the serial number (if possible).
531 RetrieveProcessorSerialNumber();
533 this->CPUCount();
534 #elif defined(__APPLE__)
535 this->ParseSysCtl();
536 #elif defined (__SVR4) && defined (__sun)
537 this->QuerySolarisInfo();
538 #else
539 this->RetreiveInformationFromCpuInfoFile();
540 #endif
543 void SystemInformationImplementation::RunOSCheck()
545 this->QueryOSInformation();
548 void SystemInformationImplementation::RunMemoryCheck()
550 #if defined(__APPLE__)
551 this->ParseSysCtl();
552 #elif defined (__SVR4) && defined (__sun)
553 this->QuerySolarisInfo();
554 #else
555 this->QueryMemory();
556 #endif
559 /** Get the vendor string */
560 const char * SystemInformationImplementation::GetVendorString()
562 return this->ChipID.Vendor;
565 /** Get the OS Name */
566 const char * SystemInformationImplementation::GetOSName()
568 return this->OSName.c_str();
571 /** Get the hostname */
572 const char* SystemInformationImplementation::GetHostname()
574 return this->Hostname.c_str();
577 /** Get the OS release */
578 const char* SystemInformationImplementation::GetOSRelease()
580 return this->OSRelease.c_str();
583 /** Get the OS version */
584 const char* SystemInformationImplementation::GetOSVersion()
586 return this->OSVersion.c_str();
589 /** Get the OS platform */
590 const char* SystemInformationImplementation::GetOSPlatform()
592 return this->OSPlatform.c_str();
595 /** Get the vendor ID */
596 const char * SystemInformationImplementation::GetVendorID()
598 // Return the vendor ID.
599 switch (this->ChipManufacturer)
601 case Intel:
602 return "Intel Corporation";
603 case AMD:
604 return "Advanced Micro Devices";
605 case NSC:
606 return "National Semiconductor";
607 case Cyrix:
608 return "Cyrix Corp., VIA Inc.";
609 case NexGen:
610 return "NexGen Inc., Advanced Micro Devices";
611 case IDT:
612 return "IDT\\Centaur, Via Inc.";
613 case UMC:
614 return "United Microelectronics Corp.";
615 case Rise:
616 return "Rise";
617 case Transmeta:
618 return "Transmeta";
619 case Sun:
620 return "Sun Microelectronics";
621 default:
622 return "Unknown Manufacturer";
626 /** Return the type ID of the CPU */
627 kwsys_stl::string SystemInformationImplementation::GetTypeID()
629 kwsys_ios::ostringstream str;
630 str << this->ChipID.Type;
631 return str.str();
634 /** Return the family of the CPU present */
635 kwsys_stl::string SystemInformationImplementation::GetFamilyID()
637 kwsys_ios::ostringstream str;
638 str << this->ChipID.Family;
639 return str.str();
642 // Return the model of CPU present */
643 kwsys_stl::string SystemInformationImplementation::GetModelID()
645 kwsys_ios::ostringstream str;
646 str << this->ChipID.Model;
647 return str.str();
650 /** Return the stepping code of the CPU present. */
651 kwsys_stl::string SystemInformationImplementation::GetSteppingCode()
653 kwsys_ios::ostringstream str;
654 str << this->ChipID.Revision;
655 return str.str();
658 /** Return the stepping code of the CPU present. */
659 const char * SystemInformationImplementation::GetExtendedProcessorName()
661 return this->ChipID.ProcessorName;
664 /** Return the serial number of the processor
665 * in hexadecimal: xxxx-xxxx-xxxx-xxxx-xxxx-xxxx. */
666 const char * SystemInformationImplementation::GetProcessorSerialNumber()
668 return this->ChipID.SerialNumber;
671 /** Return the logical processors per physical */
672 int SystemInformationImplementation::GetLogicalProcessorsPerPhysical()
674 return this->Features.ExtendedFeatures.LogicalProcessorsPerPhysical;
677 /** Return the processor clock frequency. */
678 float SystemInformationImplementation::GetProcessorClockFrequency()
680 return this->CPUSpeedInMHz;
683 /** Return the APIC ID. */
684 int SystemInformationImplementation::GetProcessorAPICID()
686 return this->Features.ExtendedFeatures.APIC_ID;
689 /** Return the L1 cache size. */
690 int SystemInformationImplementation::GetProcessorCacheSize()
692 return this->Features.L1CacheSize;
695 /** Return the chosen cache size. */
696 int SystemInformationImplementation::GetProcessorCacheXSize(long int dwCacheID)
698 switch (dwCacheID)
700 case L1CACHE_FEATURE:
701 return this->Features.L1CacheSize;
702 case L2CACHE_FEATURE:
703 return this->Features.L2CacheSize;
704 case L3CACHE_FEATURE:
705 return this->Features.L3CacheSize;
707 return -1;
710 bool SystemInformationImplementation::DoesCPUSupportFeature(long int dwFeature)
712 bool bHasFeature = false;
714 // Check for MMX instructions.
715 if (((dwFeature & MMX_FEATURE) != 0) && this->Features.HasMMX) bHasFeature = true;
717 // Check for MMX+ instructions.
718 if (((dwFeature & MMX_PLUS_FEATURE) != 0) && this->Features.ExtendedFeatures.HasMMXPlus) bHasFeature = true;
720 // Check for SSE FP instructions.
721 if (((dwFeature & SSE_FEATURE) != 0) && this->Features.HasSSE) bHasFeature = true;
723 // Check for SSE FP instructions.
724 if (((dwFeature & SSE_FP_FEATURE) != 0) && this->Features.HasSSEFP) bHasFeature = true;
726 // Check for SSE MMX instructions.
727 if (((dwFeature & SSE_MMX_FEATURE) != 0) && this->Features.ExtendedFeatures.HasSSEMMX) bHasFeature = true;
729 // Check for SSE2 instructions.
730 if (((dwFeature & SSE2_FEATURE) != 0) && this->Features.HasSSE2) bHasFeature = true;
732 // Check for 3DNow! instructions.
733 if (((dwFeature & AMD_3DNOW_FEATURE) != 0) && this->Features.ExtendedFeatures.Has3DNow) bHasFeature = true;
735 // Check for 3DNow+ instructions.
736 if (((dwFeature & AMD_3DNOW_PLUS_FEATURE) != 0) && this->Features.ExtendedFeatures.Has3DNowPlus) bHasFeature = true;
738 // Check for IA64 instructions.
739 if (((dwFeature & IA64_FEATURE) != 0) && this->Features.HasIA64) bHasFeature = true;
741 // Check for MP capable.
742 if (((dwFeature & MP_CAPABLE) != 0) && this->Features.ExtendedFeatures.SupportsMP) bHasFeature = true;
744 // Check for a serial number for the processor.
745 if (((dwFeature & SERIALNUMBER_FEATURE) != 0) && this->Features.HasSerial) bHasFeature = true;
747 // Check for a local APIC in the processor.
748 if (((dwFeature & APIC_FEATURE) != 0) && this->Features.HasAPIC) bHasFeature = true;
750 // Check for CMOV instructions.
751 if (((dwFeature & CMOV_FEATURE) != 0) && this->Features.HasCMOV) bHasFeature = true;
753 // Check for MTRR instructions.
754 if (((dwFeature & MTRR_FEATURE) != 0) && this->Features.HasMTRR) bHasFeature = true;
756 // Check for L1 cache size.
757 if (((dwFeature & L1CACHE_FEATURE) != 0) && (this->Features.L1CacheSize != -1)) bHasFeature = true;
759 // Check for L2 cache size.
760 if (((dwFeature & L2CACHE_FEATURE) != 0) && (this->Features.L2CacheSize != -1)) bHasFeature = true;
762 // Check for L3 cache size.
763 if (((dwFeature & L3CACHE_FEATURE) != 0) && (this->Features.L3CacheSize != -1)) bHasFeature = true;
765 // Check for ACPI capability.
766 if (((dwFeature & ACPI_FEATURE) != 0) && this->Features.HasACPI) bHasFeature = true;
768 // Check for thermal monitor support.
769 if (((dwFeature & THERMALMONITOR_FEATURE) != 0) && this->Features.HasThermal) bHasFeature = true;
771 // Check for temperature sensing diode support.
772 if (((dwFeature & TEMPSENSEDIODE_FEATURE) != 0) && this->Features.ExtendedFeatures.PowerManagement.HasTempSenseDiode) bHasFeature = true;
774 // Check for frequency ID support.
775 if (((dwFeature & FREQUENCYID_FEATURE) != 0) && this->Features.ExtendedFeatures.PowerManagement.HasFrequencyID) bHasFeature = true;
777 // Check for voltage ID support.
778 if (((dwFeature & VOLTAGEID_FREQUENCY) != 0) && this->Features.ExtendedFeatures.PowerManagement.HasVoltageID) bHasFeature = true;
780 return bHasFeature;
783 void SystemInformationImplementation::Delay(unsigned int uiMS)
785 #ifdef WIN32
786 LARGE_INTEGER Frequency, StartCounter, EndCounter;
787 __int64 x;
789 // Get the frequency of the high performance counter.
790 if (!QueryPerformanceFrequency (&Frequency)) return;
791 x = Frequency.QuadPart / 1000 * uiMS;
793 // Get the starting position of the counter.
794 QueryPerformanceCounter (&StartCounter);
796 do {
797 // Get the ending position of the counter.
798 QueryPerformanceCounter (&EndCounter);
799 } while (EndCounter.QuadPart - StartCounter.QuadPart < x);
800 #endif
801 (void)uiMS;
804 bool SystemInformationImplementation::DoesCPUSupportCPUID()
806 #if USE_ASM_INSTRUCTIONS
807 // Use SEH to determine CPUID presence
808 __try {
809 _asm {
810 #ifdef CPUID_AWARE_COMPILER
811 ; we must push/pop the registers <<CPUID>> writes to, as the
812 ; optimiser doesn't know about <<CPUID>>, and so doesn't expect
813 ; these registers to change.
814 push eax
815 push ebx
816 push ecx
817 push edx
818 #endif
819 ; <<CPUID>>
820 mov eax, 0
821 CPUID_INSTRUCTION
823 #ifdef CPUID_AWARE_COMPILER
824 pop edx
825 pop ecx
826 pop ebx
827 pop eax
828 #endif
831 __except(1)
833 // Stop the class from trying to use CPUID again!
834 return false;
837 // The cpuid instruction succeeded.
838 return true;
839 #else
840 // Assume no cpuid instruction.
841 return false;
842 #endif
845 bool SystemInformationImplementation::RetrieveCPUFeatures()
847 #if USE_ASM_INSTRUCTIONS
848 int localCPUFeatures = 0;
849 int localCPUAdvanced = 0;
852 // Use assembly to detect CPUID information...
853 __try {
854 _asm {
855 #ifdef CPUID_AWARE_COMPILER
856 ; we must push/pop the registers <<CPUID>> writes to, as the
857 ; optimiser doesn't know about <<CPUID>>, and so doesn't expect
858 ; these registers to change.
859 push eax
860 push ebx
861 push ecx
862 push edx
863 #endif
864 ; <<CPUID>>
865 ; 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
866 ; ebx: 31..24 - default APIC ID, 23..16 - logical processsor ID, 15..8 - CFLUSH chunk size , 7..0 - brand ID
867 ; edx: CPU feature flags
868 mov eax,1
869 CPUID_INSTRUCTION
870 mov localCPUFeatures, edx
871 mov localCPUAdvanced, ebx
873 #ifdef CPUID_AWARE_COMPILER
874 pop edx
875 pop ecx
876 pop ebx
877 pop eax
878 #endif
881 __except(1)
883 return false;
886 // Retrieve the features of CPU present.
887 this->Features.HasFPU = ((localCPUFeatures & 0x00000001) != 0); // FPU Present --> Bit 0
888 this->Features.HasTSC = ((localCPUFeatures & 0x00000010) != 0); // TSC Present --> Bit 4
889 this->Features.HasAPIC = ((localCPUFeatures & 0x00000200) != 0); // APIC Present --> Bit 9
890 this->Features.HasMTRR = ((localCPUFeatures & 0x00001000) != 0); // MTRR Present --> Bit 12
891 this->Features.HasCMOV = ((localCPUFeatures & 0x00008000) != 0); // CMOV Present --> Bit 15
892 this->Features.HasSerial = ((localCPUFeatures & 0x00040000) != 0); // Serial Present --> Bit 18
893 this->Features.HasACPI = ((localCPUFeatures & 0x00400000) != 0); // ACPI Capable --> Bit 22
894 this->Features.HasMMX = ((localCPUFeatures & 0x00800000) != 0); // MMX Present --> Bit 23
895 this->Features.HasSSE = ((localCPUFeatures & 0x02000000) != 0); // SSE Present --> Bit 25
896 this->Features.HasSSE2 = ((localCPUFeatures & 0x04000000) != 0); // SSE2 Present --> Bit 26
897 this->Features.HasThermal = ((localCPUFeatures & 0x20000000) != 0); // Thermal Monitor Present --> Bit 29
898 this->Features.HasIA64 = ((localCPUFeatures & 0x40000000) != 0); // IA64 Present --> Bit 30
900 // Retrieve extended SSE capabilities if SSE is available.
901 if (this->Features.HasSSE) {
903 // Attempt to __try some SSE FP instructions.
904 __try
906 // Perform: orps xmm0, xmm0
907 _asm
909 _emit 0x0f
910 _emit 0x56
911 _emit 0xc0
914 // SSE FP capable processor.
915 this->Features.HasSSEFP = true;
917 __except(1)
919 // bad instruction - processor or OS cannot handle SSE FP.
920 this->Features.HasSSEFP = false;
923 else
925 // Set the advanced SSE capabilities to not available.
926 this->Features.HasSSEFP = false;
929 // Retrieve Intel specific extended features.
930 if (this->ChipManufacturer == Intel)
932 this->Features.ExtendedFeatures.SupportsHyperthreading = ((localCPUFeatures & 0x10000000) != 0); // Intel specific: Hyperthreading --> Bit 28
933 this->Features.ExtendedFeatures.LogicalProcessorsPerPhysical = (this->Features.ExtendedFeatures.SupportsHyperthreading) ? ((localCPUAdvanced & 0x00FF0000) >> 16) : 1;
935 if ((this->Features.ExtendedFeatures.SupportsHyperthreading) && (this->Features.HasAPIC))
937 // Retrieve APIC information if there is one present.
938 this->Features.ExtendedFeatures.APIC_ID = ((localCPUAdvanced & 0xFF000000) >> 24);
941 #endif
942 return true;
946 /** Find the manufacturer given the vendor id */
947 void SystemInformationImplementation::FindManufacturer()
949 if (strcmp (this->ChipID.Vendor, "GenuineIntel") == 0) this->ChipManufacturer = Intel; // Intel Corp.
950 else if (strcmp (this->ChipID.Vendor, "UMC UMC UMC ") == 0) this->ChipManufacturer = UMC; // United Microelectronics Corp.
951 else if (strcmp (this->ChipID.Vendor, "AuthenticAMD") == 0) this->ChipManufacturer = AMD; // Advanced Micro Devices
952 else if (strcmp (this->ChipID.Vendor, "AMD ISBETTER") == 0) this->ChipManufacturer = AMD; // Advanced Micro Devices (1994)
953 else if (strcmp (this->ChipID.Vendor, "CyrixInstead") == 0) this->ChipManufacturer = Cyrix; // Cyrix Corp., VIA Inc.
954 else if (strcmp (this->ChipID.Vendor, "NexGenDriven") == 0) this->ChipManufacturer = NexGen; // NexGen Inc. (now AMD)
955 else if (strcmp (this->ChipID.Vendor, "CentaurHauls") == 0) this->ChipManufacturer = IDT; // IDT/Centaur (now VIA)
956 else if (strcmp (this->ChipID.Vendor, "RiseRiseRise") == 0) this->ChipManufacturer = Rise; // Rise
957 else if (strcmp (this->ChipID.Vendor, "GenuineTMx86") == 0) this->ChipManufacturer = Transmeta; // Transmeta
958 else if (strcmp (this->ChipID.Vendor, "TransmetaCPU") == 0) this->ChipManufacturer = Transmeta; // Transmeta
959 else if (strcmp (this->ChipID.Vendor, "Geode By NSC") == 0) this->ChipManufacturer = NSC; // National Semiconductor
960 else if (strcmp (this->ChipID.Vendor, "Sun") == 0) this->ChipManufacturer = Sun; // Sun Microelectronics
961 else this->ChipManufacturer = UnknownManufacturer; // Unknown manufacturer
964 /** */
965 bool SystemInformationImplementation::RetrieveCPUIdentity()
967 #if USE_ASM_INSTRUCTIONS
968 int localCPUVendor[3];
969 int localCPUSignature;
971 // Use assembly to detect CPUID information...
972 __try
974 _asm
976 #ifdef CPUID_AWARE_COMPILER
977 ; we must push/pop the registers <<CPUID>> writes to, as the
978 ; optimiser doesn't know about <<CPUID>>, and so doesn't expect
979 ; these registers to change.
980 push eax
981 push ebx
982 push ecx
983 push edx
984 #endif
985 ; <<CPUID>>
986 ; eax = 0 --> eax: maximum value of CPUID instruction.
987 ; ebx: part 1 of 3; CPU signature.
988 ; edx: part 2 of 3; CPU signature.
989 ; ecx: part 3 of 3; CPU signature.
990 mov eax, 0
991 CPUID_INSTRUCTION
992 mov localCPUVendor[0 * TYPE int], ebx
993 mov localCPUVendor[1 * TYPE int], edx
994 mov localCPUVendor[2 * TYPE int], ecx
996 ; <<CPUID>>
997 ; 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
998 ; ebx: 31..24 - default APIC ID, 23..16 - logical processsor ID, 15..8 - CFLUSH chunk size , 7..0 - brand ID
999 ; edx: CPU feature flags
1000 mov eax,1
1001 CPUID_INSTRUCTION
1002 mov localCPUSignature, eax
1004 #ifdef CPUID_AWARE_COMPILER
1005 pop edx
1006 pop ecx
1007 pop ebx
1008 pop eax
1009 #endif
1012 __except(1)
1014 return false;
1017 // Process the returned information.
1018 memcpy (this->ChipID.Vendor, &(localCPUVendor[0]), sizeof (int));
1019 memcpy (&(this->ChipID.Vendor[4]), &(localCPUVendor[1]), sizeof (int));
1020 memcpy (&(this->ChipID.Vendor[8]), &(localCPUVendor[2]), sizeof (int));
1021 this->ChipID.Vendor[12] = '\0';
1023 this->FindManufacturer();
1025 // Retrieve the family of CPU present.
1026 this->ChipID.ExtendedFamily = ((localCPUSignature & 0x0FF00000) >> 20); // Bits 27..20 Used
1027 this->ChipID.ExtendedModel = ((localCPUSignature & 0x000F0000) >> 16); // Bits 19..16 Used
1028 this->ChipID.Type = ((localCPUSignature & 0x0000F000) >> 12); // Bits 15..12 Used
1029 this->ChipID.Family = ((localCPUSignature & 0x00000F00) >> 8); // Bits 11..8 Used
1030 this->ChipID.Model = ((localCPUSignature & 0x000000F0) >> 4); // Bits 7..4 Used
1031 this->ChipID.Revision = ((localCPUSignature & 0x0000000F) >> 0); // Bits 3..0 Used
1032 #endif
1034 return true;
1037 /** */
1038 bool SystemInformationImplementation::RetrieveCPUCacheDetails()
1040 #if USE_ASM_INSTRUCTIONS
1041 int L1Cache[4] = { 0, 0, 0, 0 };
1042 int L2Cache[4] = { 0, 0, 0, 0 };
1044 // Check to see if what we are about to do is supported...
1045 if (RetrieveCPUExtendedLevelSupport (0x80000005))
1047 // Use assembly to retrieve the L1 cache information ...
1048 __try
1050 _asm
1052 #ifdef CPUID_AWARE_COMPILER
1053 ; we must push/pop the registers <<CPUID>> writes to, as the
1054 ; optimiser doesn't know about <<CPUID>>, and so doesn't expect
1055 ; these registers to change.
1056 push eax
1057 push ebx
1058 push ecx
1059 push edx
1060 #endif
1061 ; <<CPUID>>
1062 ; eax = 0x80000005 --> eax: L1 cache information - Part 1 of 4.
1063 ; ebx: L1 cache information - Part 2 of 4.
1064 ; edx: L1 cache information - Part 3 of 4.
1065 ; ecx: L1 cache information - Part 4 of 4.
1066 mov eax, 0x80000005
1067 CPUID_INSTRUCTION
1068 mov L1Cache[0 * TYPE int], eax
1069 mov L1Cache[1 * TYPE int], ebx
1070 mov L1Cache[2 * TYPE int], ecx
1071 mov L1Cache[3 * TYPE int], edx
1073 #ifdef CPUID_AWARE_COMPILER
1074 pop edx
1075 pop ecx
1076 pop ebx
1077 pop eax
1078 #endif
1081 __except(1)
1083 return false;
1085 // Save the L1 data cache size (in KB) from ecx: bits 31..24 as well as data cache size from edx: bits 31..24.
1086 this->Features.L1CacheSize = ((L1Cache[2] & 0xFF000000) >> 24);
1087 this->Features.L1CacheSize += ((L1Cache[3] & 0xFF000000) >> 24);
1089 else
1091 // Store -1 to indicate the cache could not be queried.
1092 this->Features.L1CacheSize = -1;
1095 // Check to see if what we are about to do is supported...
1096 if (RetrieveCPUExtendedLevelSupport (0x80000006))
1098 // Use assembly to retrieve the L2 cache information ...
1099 __try
1101 _asm
1103 #ifdef CPUID_AWARE_COMPILER
1104 ; we must push/pop the registers <<CPUID>> writes to, as the
1105 ; optimiser doesn't know about <<CPUID>>, and so doesn't expect
1106 ; these registers to change.
1107 push eax
1108 push ebx
1109 push ecx
1110 push edx
1111 #endif
1112 ; <<CPUID>>
1113 ; eax = 0x80000006 --> eax: L2 cache information - Part 1 of 4.
1114 ; ebx: L2 cache information - Part 2 of 4.
1115 ; edx: L2 cache information - Part 3 of 4.
1116 ; ecx: L2 cache information - Part 4 of 4.
1117 mov eax, 0x80000006
1118 CPUID_INSTRUCTION
1119 mov L2Cache[0 * TYPE int], eax
1120 mov L2Cache[1 * TYPE int], ebx
1121 mov L2Cache[2 * TYPE int], ecx
1122 mov L2Cache[3 * TYPE int], edx
1124 #ifdef CPUID_AWARE_COMPILER
1125 pop edx
1126 pop ecx
1127 pop ebx
1128 pop eax
1129 #endif
1132 __except(1)
1134 return false;
1136 // Save the L2 unified cache size (in KB) from ecx: bits 31..16.
1137 this->Features.L2CacheSize = ((L2Cache[2] & 0xFFFF0000) >> 16);
1139 else
1141 // Store -1 to indicate the cache could not be queried.
1142 this->Features.L2CacheSize = -1;
1145 // Define L3 as being not present as we cannot test for it.
1146 this->Features.L3CacheSize = -1;
1148 #endif
1150 // Return failure if we cannot detect either cache with this method.
1151 return ((this->Features.L1CacheSize == -1) && (this->Features.L2CacheSize == -1)) ? false : true;
1154 /** */
1155 bool SystemInformationImplementation::RetrieveClassicalCPUCacheDetails()
1157 #if USE_ASM_INSTRUCTIONS
1158 int TLBCode = -1, TLBData = -1, L1Code = -1, L1Data = -1, L1Trace = -1, L2Unified = -1, L3Unified = -1;
1159 int TLBCacheData[4] = { 0, 0, 0, 0 };
1160 int TLBPassCounter = 0;
1161 int TLBCacheUnit = 0;
1164 do {
1165 // Use assembly to retrieve the L2 cache information ...
1166 __try {
1167 _asm {
1168 #ifdef CPUID_AWARE_COMPILER
1169 ; we must push/pop the registers <<CPUID>> writes to, as the
1170 ; optimiser doesn't know about <<CPUID>>, and so doesn't expect
1171 ; these registers to change.
1172 push eax
1173 push ebx
1174 push ecx
1175 push edx
1176 #endif
1177 ; <<CPUID>>
1178 ; eax = 2 --> eax: TLB and cache information - Part 1 of 4.
1179 ; ebx: TLB and cache information - Part 2 of 4.
1180 ; ecx: TLB and cache information - Part 3 of 4.
1181 ; edx: TLB and cache information - Part 4 of 4.
1182 mov eax, 2
1183 CPUID_INSTRUCTION
1184 mov TLBCacheData[0 * TYPE int], eax
1185 mov TLBCacheData[1 * TYPE int], ebx
1186 mov TLBCacheData[2 * TYPE int], ecx
1187 mov TLBCacheData[3 * TYPE int], edx
1189 #ifdef CPUID_AWARE_COMPILER
1190 pop edx
1191 pop ecx
1192 pop ebx
1193 pop eax
1194 #endif
1197 __except(1)
1199 return false;
1202 int bob = ((TLBCacheData[0] & 0x00FF0000) >> 16);
1203 (void)bob;
1204 // Process the returned TLB and cache information.
1205 for (int nCounter = 0; nCounter < TLBCACHE_INFO_UNITS; nCounter ++)
1207 // First of all - decide which unit we are dealing with.
1208 switch (nCounter)
1210 // eax: bits 8..15 : bits 16..23 : bits 24..31
1211 case 0: TLBCacheUnit = ((TLBCacheData[0] & 0x0000FF00) >> 8); break;
1212 case 1: TLBCacheUnit = ((TLBCacheData[0] & 0x00FF0000) >> 16); break;
1213 case 2: TLBCacheUnit = ((TLBCacheData[0] & 0xFF000000) >> 24); break;
1215 // ebx: bits 0..7 : bits 8..15 : bits 16..23 : bits 24..31
1216 case 3: TLBCacheUnit = ((TLBCacheData[1] & 0x000000FF) >> 0); break;
1217 case 4: TLBCacheUnit = ((TLBCacheData[1] & 0x0000FF00) >> 8); break;
1218 case 5: TLBCacheUnit = ((TLBCacheData[1] & 0x00FF0000) >> 16); break;
1219 case 6: TLBCacheUnit = ((TLBCacheData[1] & 0xFF000000) >> 24); break;
1221 // ecx: bits 0..7 : bits 8..15 : bits 16..23 : bits 24..31
1222 case 7: TLBCacheUnit = ((TLBCacheData[2] & 0x000000FF) >> 0); break;
1223 case 8: TLBCacheUnit = ((TLBCacheData[2] & 0x0000FF00) >> 8); break;
1224 case 9: TLBCacheUnit = ((TLBCacheData[2] & 0x00FF0000) >> 16); break;
1225 case 10: TLBCacheUnit = ((TLBCacheData[2] & 0xFF000000) >> 24); break;
1227 // edx: bits 0..7 : bits 8..15 : bits 16..23 : bits 24..31
1228 case 11: TLBCacheUnit = ((TLBCacheData[3] & 0x000000FF) >> 0); break;
1229 case 12: TLBCacheUnit = ((TLBCacheData[3] & 0x0000FF00) >> 8); break;
1230 case 13: TLBCacheUnit = ((TLBCacheData[3] & 0x00FF0000) >> 16); break;
1231 case 14: TLBCacheUnit = ((TLBCacheData[3] & 0xFF000000) >> 24); break;
1233 // Default case - an error has occured.
1234 default: return false;
1237 // Now process the resulting unit to see what it means....
1238 switch (TLBCacheUnit)
1240 case 0x00: break;
1241 case 0x01: STORE_TLBCACHE_INFO (TLBCode, 4); break;
1242 case 0x02: STORE_TLBCACHE_INFO (TLBCode, 4096); break;
1243 case 0x03: STORE_TLBCACHE_INFO (TLBData, 4); break;
1244 case 0x04: STORE_TLBCACHE_INFO (TLBData, 4096); break;
1245 case 0x06: STORE_TLBCACHE_INFO (L1Code, 8); break;
1246 case 0x08: STORE_TLBCACHE_INFO (L1Code, 16); break;
1247 case 0x0a: STORE_TLBCACHE_INFO (L1Data, 8); break;
1248 case 0x0c: STORE_TLBCACHE_INFO (L1Data, 16); break;
1249 case 0x10: STORE_TLBCACHE_INFO (L1Data, 16); break; // <-- FIXME: IA-64 Only
1250 case 0x15: STORE_TLBCACHE_INFO (L1Code, 16); break; // <-- FIXME: IA-64 Only
1251 case 0x1a: STORE_TLBCACHE_INFO (L2Unified, 96); break; // <-- FIXME: IA-64 Only
1252 case 0x22: STORE_TLBCACHE_INFO (L3Unified, 512); break;
1253 case 0x23: STORE_TLBCACHE_INFO (L3Unified, 1024); break;
1254 case 0x25: STORE_TLBCACHE_INFO (L3Unified, 2048); break;
1255 case 0x29: STORE_TLBCACHE_INFO (L3Unified, 4096); break;
1256 case 0x39: STORE_TLBCACHE_INFO (L2Unified, 128); break;
1257 case 0x3c: STORE_TLBCACHE_INFO (L2Unified, 256); break;
1258 case 0x40: STORE_TLBCACHE_INFO (L2Unified, 0); break; // <-- FIXME: No integrated L2 cache (P6 core) or L3 cache (P4 core).
1259 case 0x41: STORE_TLBCACHE_INFO (L2Unified, 128); break;
1260 case 0x42: STORE_TLBCACHE_INFO (L2Unified, 256); break;
1261 case 0x43: STORE_TLBCACHE_INFO (L2Unified, 512); break;
1262 case 0x44: STORE_TLBCACHE_INFO (L2Unified, 1024); break;
1263 case 0x45: STORE_TLBCACHE_INFO (L2Unified, 2048); break;
1264 case 0x50: STORE_TLBCACHE_INFO (TLBCode, 4096); break;
1265 case 0x51: STORE_TLBCACHE_INFO (TLBCode, 4096); break;
1266 case 0x52: STORE_TLBCACHE_INFO (TLBCode, 4096); break;
1267 case 0x5b: STORE_TLBCACHE_INFO (TLBData, 4096); break;
1268 case 0x5c: STORE_TLBCACHE_INFO (TLBData, 4096); break;
1269 case 0x5d: STORE_TLBCACHE_INFO (TLBData, 4096); break;
1270 case 0x66: STORE_TLBCACHE_INFO (L1Data, 8); break;
1271 case 0x67: STORE_TLBCACHE_INFO (L1Data, 16); break;
1272 case 0x68: STORE_TLBCACHE_INFO (L1Data, 32); break;
1273 case 0x70: STORE_TLBCACHE_INFO (L1Trace, 12); break;
1274 case 0x71: STORE_TLBCACHE_INFO (L1Trace, 16); break;
1275 case 0x72: STORE_TLBCACHE_INFO (L1Trace, 32); break;
1276 case 0x77: STORE_TLBCACHE_INFO (L1Code, 16); break; // <-- FIXME: IA-64 Only
1277 case 0x79: STORE_TLBCACHE_INFO (L2Unified, 128); break;
1278 case 0x7a: STORE_TLBCACHE_INFO (L2Unified, 256); break;
1279 case 0x7b: STORE_TLBCACHE_INFO (L2Unified, 512); break;
1280 case 0x7c: STORE_TLBCACHE_INFO (L2Unified, 1024); break;
1281 case 0x7e: STORE_TLBCACHE_INFO (L2Unified, 256); break;
1282 case 0x81: STORE_TLBCACHE_INFO (L2Unified, 128); break;
1283 case 0x82: STORE_TLBCACHE_INFO (L2Unified, 256); break;
1284 case 0x83: STORE_TLBCACHE_INFO (L2Unified, 512); break;
1285 case 0x84: STORE_TLBCACHE_INFO (L2Unified, 1024); break;
1286 case 0x85: STORE_TLBCACHE_INFO (L2Unified, 2048); break;
1287 case 0x88: STORE_TLBCACHE_INFO (L3Unified, 2048); break; // <-- FIXME: IA-64 Only
1288 case 0x89: STORE_TLBCACHE_INFO (L3Unified, 4096); break; // <-- FIXME: IA-64 Only
1289 case 0x8a: STORE_TLBCACHE_INFO (L3Unified, 8192); break; // <-- FIXME: IA-64 Only
1290 case 0x8d: STORE_TLBCACHE_INFO (L3Unified, 3096); break; // <-- FIXME: IA-64 Only
1291 case 0x90: STORE_TLBCACHE_INFO (TLBCode, 262144); break; // <-- FIXME: IA-64 Only
1292 case 0x96: STORE_TLBCACHE_INFO (TLBCode, 262144); break; // <-- FIXME: IA-64 Only
1293 case 0x9b: STORE_TLBCACHE_INFO (TLBCode, 262144); break; // <-- FIXME: IA-64 Only
1295 // Default case - an error has occured.
1296 default: return false;
1300 // Increment the TLB pass counter.
1301 TLBPassCounter ++;
1302 } while ((TLBCacheData[0] & 0x000000FF) > TLBPassCounter);
1304 // Ok - we now have the maximum TLB, L1, L2, and L3 sizes...
1305 if ((L1Code == -1) && (L1Data == -1) && (L1Trace == -1))
1307 this->Features.L1CacheSize = -1;
1309 else if ((L1Code == -1) && (L1Data == -1) && (L1Trace != -1))
1311 this->Features.L1CacheSize = L1Trace;
1313 else if ((L1Code != -1) && (L1Data == -1))
1315 this->Features.L1CacheSize = L1Code;
1317 else if ((L1Code == -1) && (L1Data != -1))
1319 this->Features.L1CacheSize = L1Data;
1321 else if ((L1Code != -1) && (L1Data != -1))
1323 this->Features.L1CacheSize = L1Code + L1Data;
1325 else
1327 this->Features.L1CacheSize = -1;
1330 // Ok - we now have the maximum TLB, L1, L2, and L3 sizes...
1331 if (L2Unified == -1)
1333 this->Features.L2CacheSize = -1;
1335 else
1337 this->Features.L2CacheSize = L2Unified;
1340 // Ok - we now have the maximum TLB, L1, L2, and L3 sizes...
1341 if (L3Unified == -1)
1343 this->Features.L3CacheSize = -1;
1345 else
1347 this->Features.L3CacheSize = L3Unified;
1350 #endif
1351 return true;
1354 /** */
1355 bool SystemInformationImplementation::RetrieveCPUClockSpeed()
1357 #if _WIN32
1358 // First of all we check to see if the RDTSC (0x0F, 0x31) instruction is supported.
1359 if (!this->Features.HasTSC)
1361 return false;
1364 unsigned int uiRepetitions = 1;
1365 unsigned int uiMSecPerRepetition = 50;
1366 __int64 i64Total = 0;
1367 __int64 i64Overhead = 0;
1369 for (unsigned int nCounter = 0; nCounter < uiRepetitions; nCounter ++)
1371 i64Total += GetCyclesDifference (SystemInformationImplementation::Delay,
1372 uiMSecPerRepetition);
1373 i64Overhead +=
1374 GetCyclesDifference (SystemInformationImplementation::DelayOverhead,
1375 uiMSecPerRepetition);
1378 // Calculate the MHz speed.
1379 i64Total -= i64Overhead;
1380 i64Total /= uiRepetitions;
1381 i64Total /= uiMSecPerRepetition;
1382 i64Total /= 1000;
1384 // Save the CPU speed.
1385 this->CPUSpeedInMHz = (float) i64Total;
1387 return true;
1388 #else
1389 return false;
1390 #endif
1393 /** */
1394 bool SystemInformationImplementation::RetrieveClassicalCPUClockSpeed()
1396 #if USE_ASM_INSTRUCTIONS
1397 LARGE_INTEGER liStart, liEnd, liCountsPerSecond;
1398 double dFrequency, dDifference;
1400 // Attempt to get a starting tick count.
1401 QueryPerformanceCounter (&liStart);
1403 __try
1405 _asm
1407 mov eax, 0x80000000
1408 mov ebx, CLASSICAL_CPU_FREQ_LOOP
1409 Timer_Loop:
1410 bsf ecx,eax
1411 dec ebx
1412 jnz Timer_Loop
1415 __except(1)
1417 return false;
1420 // Attempt to get a starting tick count.
1421 QueryPerformanceCounter (&liEnd);
1423 // Get the difference... NB: This is in seconds....
1424 QueryPerformanceFrequency (&liCountsPerSecond);
1425 dDifference = (((double) liEnd.QuadPart - (double) liStart.QuadPart) / (double) liCountsPerSecond.QuadPart);
1427 // Calculate the clock speed.
1428 if (this->ChipID.Family == 3)
1430 // 80386 processors.... Loop time is 115 cycles!
1431 dFrequency = (((CLASSICAL_CPU_FREQ_LOOP * 115) / dDifference) / 1048576);
1433 else if (this->ChipID.Family == 4)
1435 // 80486 processors.... Loop time is 47 cycles!
1436 dFrequency = (((CLASSICAL_CPU_FREQ_LOOP * 47) / dDifference) / 1048576);
1438 else if (this->ChipID.Family == 5)
1440 // Pentium processors.... Loop time is 43 cycles!
1441 dFrequency = (((CLASSICAL_CPU_FREQ_LOOP * 43) / dDifference) / 1048576);
1444 // Save the clock speed.
1445 this->Features.CPUSpeed = (int) dFrequency;
1446 #else
1447 return true;
1448 #endif
1451 /** */
1452 bool SystemInformationImplementation::RetrieveCPUExtendedLevelSupport(int CPULevelToCheck)
1454 int MaxCPUExtendedLevel = 0;
1456 // The extended CPUID is supported by various vendors starting with the following CPU models:
1458 // Manufacturer & Chip Name | Family Model Revision
1460 // AMD K6, K6-2 | 5 6 x
1461 // Cyrix GXm, Cyrix III "Joshua" | 5 4 x
1462 // IDT C6-2 | 5 8 x
1463 // VIA Cyrix III | 6 5 x
1464 // Transmeta Crusoe | 5 x x
1465 // Intel Pentium 4 | f x x
1468 // We check to see if a supported processor is present...
1469 if (this->ChipManufacturer == AMD)
1471 if (this->ChipID.Family < 5) return false;
1472 if ((this->ChipID.Family == 5) && (this->ChipID.Model < 6)) return false;
1474 else if (this->ChipManufacturer == Cyrix)
1476 if (this->ChipID.Family < 5) return false;
1477 if ((this->ChipID.Family == 5) && (this->ChipID.Model < 4)) return false;
1478 if ((this->ChipID.Family == 6) && (this->ChipID.Model < 5)) return false;
1480 else if (this->ChipManufacturer == IDT)
1482 if (this->ChipID.Family < 5) return false;
1483 if ((this->ChipID.Family == 5) && (this->ChipID.Model < 8)) return false;
1485 else if (this->ChipManufacturer == Transmeta)
1487 if (this->ChipID.Family < 5) return false;
1489 else if (this->ChipManufacturer == Intel)
1491 if (this->ChipID.Family < 0xf)
1493 return false;
1497 #if USE_ASM_INSTRUCTIONS
1499 // Use assembly to detect CPUID information...
1500 __try {
1501 _asm {
1502 #ifdef CPUID_AWARE_COMPILER
1503 ; we must push/pop the registers <<CPUID>> writes to, as the
1504 ; optimiser doesn't know about <<CPUID>>, and so doesn't expect
1505 ; these registers to change.
1506 push eax
1507 push ebx
1508 push ecx
1509 push edx
1510 #endif
1511 ; <<CPUID>>
1512 ; eax = 0x80000000 --> eax: maximum supported extended level
1513 mov eax,0x80000000
1514 CPUID_INSTRUCTION
1515 mov MaxCPUExtendedLevel, eax
1517 #ifdef CPUID_AWARE_COMPILER
1518 pop edx
1519 pop ecx
1520 pop ebx
1521 pop eax
1522 #endif
1525 __except(1)
1527 return false;
1529 #endif
1531 // Now we have to check the level wanted vs level returned...
1532 int nLevelWanted = (CPULevelToCheck & 0x7FFFFFFF);
1533 int nLevelReturn = (MaxCPUExtendedLevel & 0x7FFFFFFF);
1535 // Check to see if the level provided is supported...
1536 if (nLevelWanted > nLevelReturn)
1538 return false;
1541 return true;
1544 /** */
1545 bool SystemInformationImplementation::RetrieveExtendedCPUFeatures()
1548 // Check that we are not using an Intel processor as it does not support this.
1549 if (this->ChipManufacturer == Intel)
1551 return false;
1554 // Check to see if what we are about to do is supported...
1555 if (!RetrieveCPUExtendedLevelSupport (0x80000001))
1557 return false;
1559 #if USE_ASM_INSTRUCTIONS
1560 int localCPUExtendedFeatures = 0;
1562 // Use assembly to detect CPUID information...
1563 __try
1565 _asm
1567 #ifdef CPUID_AWARE_COMPILER
1568 ; we must push/pop the registers <<CPUID>> writes to, as the
1569 ; optimiser doesn't know about <<CPUID>>, and so doesn't expect
1570 ; these registers to change.
1571 push eax
1572 push ebx
1573 push ecx
1574 push edx
1575 #endif
1576 ; <<CPUID>>
1577 ; 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
1578 ; ebx: 31..24 - default APIC ID, 23..16 - logical processsor ID, 15..8 - CFLUSH chunk size , 7..0 - brand ID
1579 ; edx: CPU feature flags
1580 mov eax,0x80000001
1581 CPUID_INSTRUCTION
1582 mov localCPUExtendedFeatures, edx
1584 #ifdef CPUID_AWARE_COMPILER
1585 pop edx
1586 pop ecx
1587 pop ebx
1588 pop eax
1589 #endif
1592 __except(1)
1594 return false;
1597 // Retrieve the extended features of CPU present.
1598 this->Features.ExtendedFeatures.Has3DNow = ((localCPUExtendedFeatures & 0x80000000) != 0); // 3DNow Present --> Bit 31.
1599 this->Features.ExtendedFeatures.Has3DNowPlus = ((localCPUExtendedFeatures & 0x40000000) != 0); // 3DNow+ Present -- > Bit 30.
1600 this->Features.ExtendedFeatures.HasSSEMMX = ((localCPUExtendedFeatures & 0x00400000) != 0); // SSE MMX Present --> Bit 22.
1601 this->Features.ExtendedFeatures.SupportsMP = ((localCPUExtendedFeatures & 0x00080000) != 0); // MP Capable -- > Bit 19.
1603 // Retrieve AMD specific extended features.
1604 if (this->ChipManufacturer == AMD)
1606 this->Features.ExtendedFeatures.HasMMXPlus = ((localCPUExtendedFeatures & 0x00400000) != 0); // AMD specific: MMX-SSE --> Bit 22
1609 // Retrieve Cyrix specific extended features.
1610 if (this->ChipManufacturer == Cyrix)
1612 this->Features.ExtendedFeatures.HasMMXPlus = ((localCPUExtendedFeatures & 0x01000000) != 0); // Cyrix specific: Extended MMX --> Bit 24
1614 #endif
1616 return true;
1619 /** */
1620 bool SystemInformationImplementation::RetrieveProcessorSerialNumber()
1622 // Check to see if the processor supports the processor serial number.
1623 if (!this->Features.HasSerial)
1625 return false;
1628 #if USE_ASM_INSTRUCTIONS
1629 int SerialNumber[3];
1632 // Use assembly to detect CPUID information...
1633 __try {
1634 _asm {
1635 #ifdef CPUID_AWARE_COMPILER
1636 ; we must push/pop the registers <<CPUID>> writes to, as the
1637 ; optimiser doesn't know about <<CPUID>>, and so doesn't expect
1638 ; these registers to change.
1639 push eax
1640 push ebx
1641 push ecx
1642 push edx
1643 #endif
1644 ; <<CPUID>>
1645 ; eax = 3 --> ebx: top 32 bits are the processor signature bits --> NB: Transmeta only ?!?
1646 ; ecx: middle 32 bits are the processor signature bits
1647 ; edx: bottom 32 bits are the processor signature bits
1648 mov eax, 3
1649 CPUID_INSTRUCTION
1650 mov SerialNumber[0 * TYPE int], ebx
1651 mov SerialNumber[1 * TYPE int], ecx
1652 mov SerialNumber[2 * TYPE int], edx
1654 #ifdef CPUID_AWARE_COMPILER
1655 pop edx
1656 pop ecx
1657 pop ebx
1658 pop eax
1659 #endif
1662 __except(1)
1664 return false;
1667 // Process the returned information.
1668 sprintf (this->ChipID.SerialNumber, "%.2x%.2x-%.2x%.2x-%.2x%.2x-%.2x%.2x-%.2x%.2x-%.2x%.2x",
1669 ((SerialNumber[0] & 0xff000000) >> 24),
1670 ((SerialNumber[0] & 0x00ff0000) >> 16),
1671 ((SerialNumber[0] & 0x0000ff00) >> 8),
1672 ((SerialNumber[0] & 0x000000ff) >> 0),
1673 ((SerialNumber[1] & 0xff000000) >> 24),
1674 ((SerialNumber[1] & 0x00ff0000) >> 16),
1675 ((SerialNumber[1] & 0x0000ff00) >> 8),
1676 ((SerialNumber[1] & 0x000000ff) >> 0),
1677 ((SerialNumber[2] & 0xff000000) >> 24),
1678 ((SerialNumber[2] & 0x00ff0000) >> 16),
1679 ((SerialNumber[2] & 0x0000ff00) >> 8),
1680 ((SerialNumber[2] & 0x000000ff) >> 0));
1681 #endif
1683 return true;
1686 /** */
1687 bool SystemInformationImplementation::RetrieveCPUPowerManagement()
1689 // Check to see if what we are about to do is supported...
1690 if (!RetrieveCPUExtendedLevelSupport (0x80000007))
1692 this->Features.ExtendedFeatures.PowerManagement.HasFrequencyID = false;
1693 this->Features.ExtendedFeatures.PowerManagement.HasVoltageID = false;
1694 this->Features.ExtendedFeatures.PowerManagement.HasTempSenseDiode = false;
1695 return false;
1698 #if USE_ASM_INSTRUCTIONS
1699 int localCPUPowerManagement = 0;
1702 // Use assembly to detect CPUID information...
1703 __try {
1704 _asm {
1705 #ifdef CPUID_AWARE_COMPILER
1706 ; we must push/pop the registers <<CPUID>> writes to, as the
1707 ; optimiser doesn't know about <<CPUID>>, and so doesn't expect
1708 ; these registers to change.
1709 push eax
1710 push ebx
1711 push ecx
1712 push edx
1713 #endif
1714 ; <<CPUID>>
1715 ; eax = 0x80000007 --> edx: get processor power management
1716 mov eax,0x80000007
1717 CPUID_INSTRUCTION
1718 mov localCPUPowerManagement, edx
1720 #ifdef CPUID_AWARE_COMPILER
1721 pop edx
1722 pop ecx
1723 pop ebx
1724 pop eax
1725 #endif
1728 __except(1)
1730 return false;
1733 // Check for the power management capabilities of the CPU.
1734 this->Features.ExtendedFeatures.PowerManagement.HasTempSenseDiode = ((localCPUPowerManagement & 0x00000001) != 0);
1735 this->Features.ExtendedFeatures.PowerManagement.HasFrequencyID = ((localCPUPowerManagement & 0x00000002) != 0);
1736 this->Features.ExtendedFeatures.PowerManagement.HasVoltageID = ((localCPUPowerManagement & 0x00000004) != 0);
1738 #endif
1740 return true;
1743 /** */
1744 bool SystemInformationImplementation::RetrieveExtendedCPUIdentity()
1746 // Check to see if what we are about to do is supported...
1747 if (!RetrieveCPUExtendedLevelSupport(0x80000002)) return false;
1748 if (!RetrieveCPUExtendedLevelSupport(0x80000003)) return false;
1749 if (!RetrieveCPUExtendedLevelSupport(0x80000004)) return false;
1751 #if USE_ASM_INSTRUCTIONS
1752 int ProcessorNameStartPos = 0;
1753 int CPUExtendedIdentity[12];
1755 // Use assembly to detect CPUID information...
1756 __try {
1757 _asm {
1758 #ifdef CPUID_AWARE_COMPILER
1759 ; we must push/pop the registers <<CPUID>> writes to, as the
1760 ; optimiser doesn't know about <<CPUID>>, and so doesn't expect
1761 ; these registers to change.
1762 push eax
1763 push ebx
1764 push ecx
1765 push edx
1766 #endif
1767 ; <<CPUID>>
1768 ; eax = 0x80000002 --> eax, ebx, ecx, edx: get processor name string (part 1)
1769 mov eax,0x80000002
1770 CPUID_INSTRUCTION
1771 mov CPUExtendedIdentity[0 * TYPE int], eax
1772 mov CPUExtendedIdentity[1 * TYPE int], ebx
1773 mov CPUExtendedIdentity[2 * TYPE int], ecx
1774 mov CPUExtendedIdentity[3 * TYPE int], edx
1776 ; <<CPUID>>
1777 ; eax = 0x80000003 --> eax, ebx, ecx, edx: get processor name string (part 2)
1778 mov eax,0x80000003
1779 CPUID_INSTRUCTION
1780 mov CPUExtendedIdentity[4 * TYPE int], eax
1781 mov CPUExtendedIdentity[5 * TYPE int], ebx
1782 mov CPUExtendedIdentity[6 * TYPE int], ecx
1783 mov CPUExtendedIdentity[7 * TYPE int], edx
1785 ; <<CPUID>>
1786 ; eax = 0x80000004 --> eax, ebx, ecx, edx: get processor name string (part 3)
1787 mov eax,0x80000004
1788 CPUID_INSTRUCTION
1789 mov CPUExtendedIdentity[8 * TYPE int], eax
1790 mov CPUExtendedIdentity[9 * TYPE int], ebx
1791 mov CPUExtendedIdentity[10 * TYPE int], ecx
1792 mov CPUExtendedIdentity[11 * TYPE int], edx
1794 #ifdef CPUID_AWARE_COMPILER
1795 pop edx
1796 pop ecx
1797 pop ebx
1798 pop eax
1799 #endif
1802 __except(1)
1804 return false;
1807 // Process the returned information.
1808 memcpy (this->ChipID.ProcessorName, &(CPUExtendedIdentity[0]), sizeof (int));
1809 memcpy (&(this->ChipID.ProcessorName[4]), &(CPUExtendedIdentity[1]), sizeof (int));
1810 memcpy (&(this->ChipID.ProcessorName[8]), &(CPUExtendedIdentity[2]), sizeof (int));
1811 memcpy (&(this->ChipID.ProcessorName[12]), &(CPUExtendedIdentity[3]), sizeof (int));
1812 memcpy (&(this->ChipID.ProcessorName[16]), &(CPUExtendedIdentity[4]), sizeof (int));
1813 memcpy (&(this->ChipID.ProcessorName[20]), &(CPUExtendedIdentity[5]), sizeof (int));
1814 memcpy (&(this->ChipID.ProcessorName[24]), &(CPUExtendedIdentity[6]), sizeof (int));
1815 memcpy (&(this->ChipID.ProcessorName[28]), &(CPUExtendedIdentity[7]), sizeof (int));
1816 memcpy (&(this->ChipID.ProcessorName[32]), &(CPUExtendedIdentity[8]), sizeof (int));
1817 memcpy (&(this->ChipID.ProcessorName[36]), &(CPUExtendedIdentity[9]), sizeof (int));
1818 memcpy (&(this->ChipID.ProcessorName[40]), &(CPUExtendedIdentity[10]), sizeof (int));
1819 memcpy (&(this->ChipID.ProcessorName[44]), &(CPUExtendedIdentity[11]), sizeof (int));
1820 this->ChipID.ProcessorName[48] = '\0';
1822 // Because some manufacturers have leading white space - we have to post-process the name.
1823 if (this->ChipManufacturer == Intel)
1825 for (int nCounter = 0; nCounter < CHIPNAME_STRING_LENGTH; nCounter ++)
1827 // There will either be NULL (\0) or spaces ( ) as the leading characters.
1828 if ((this->ChipID.ProcessorName[nCounter] != '\0') && (this->ChipID.ProcessorName[nCounter] != ' '))
1830 // We have found the starting position of the name.
1831 ProcessorNameStartPos = nCounter;
1832 // Terminate the loop.
1833 break;
1837 // Check to see if there is any white space at the start.
1838 if (ProcessorNameStartPos == 0)
1840 return true;
1843 // Now move the name forward so that there is no white space.
1844 memmove(this->ChipID.ProcessorName, &(this->ChipID.ProcessorName[ProcessorNameStartPos]), (CHIPNAME_STRING_LENGTH - ProcessorNameStartPos));
1846 #endif
1848 return true;
1851 /** */
1852 bool SystemInformationImplementation::RetrieveClassicalCPUIdentity()
1854 // Start by decided which manufacturer we are using....
1855 switch (this->ChipManufacturer)
1857 case Intel:
1858 // Check the family / model / revision to determine the CPU ID.
1859 switch (this->ChipID.Family) {
1860 case 3:
1861 sprintf (this->ChipID.ProcessorName, "Newer i80386 family");
1862 break;
1863 case 4:
1864 switch (this->ChipID.Model) {
1865 case 0: sprintf (this->ChipID.ProcessorName,"i80486DX-25/33"); break;
1866 case 1: sprintf (this->ChipID.ProcessorName,"i80486DX-50"); break;
1867 case 2: sprintf (this->ChipID.ProcessorName,"i80486SX"); break;
1868 case 3: sprintf (this->ChipID.ProcessorName,"i80486DX2"); break;
1869 case 4: sprintf (this->ChipID.ProcessorName,"i80486SL"); break;
1870 case 5: sprintf (this->ChipID.ProcessorName,"i80486SX2"); break;
1871 case 7: sprintf (this->ChipID.ProcessorName,"i80486DX2 WriteBack"); break;
1872 case 8: sprintf (this->ChipID.ProcessorName,"i80486DX4"); break;
1873 case 9: sprintf (this->ChipID.ProcessorName,"i80486DX4 WriteBack"); break;
1874 default: sprintf (this->ChipID.ProcessorName,"Unknown 80486 family"); return false;
1876 break;
1877 case 5:
1878 switch (this->ChipID.Model)
1880 case 0: sprintf (this->ChipID.ProcessorName,"P5 A-Step"); break;
1881 case 1: sprintf (this->ChipID.ProcessorName,"P5"); break;
1882 case 2: sprintf (this->ChipID.ProcessorName,"P54C"); break;
1883 case 3: sprintf (this->ChipID.ProcessorName,"P24T OverDrive"); break;
1884 case 4: sprintf (this->ChipID.ProcessorName,"P55C"); break;
1885 case 7: sprintf (this->ChipID.ProcessorName,"P54C"); break;
1886 case 8: sprintf (this->ChipID.ProcessorName,"P55C (0.25micron)"); break;
1887 default: sprintf (this->ChipID.ProcessorName,"Unknown Pentium family"); return false;
1889 break;
1890 case 6:
1891 switch (this->ChipID.Model)
1893 case 0: sprintf (this->ChipID.ProcessorName,"P6 A-Step"); break;
1894 case 1: sprintf (this->ChipID.ProcessorName,"P6"); break;
1895 case 3: sprintf (this->ChipID.ProcessorName,"Pentium II (0.28 micron)"); break;
1896 case 5: sprintf (this->ChipID.ProcessorName,"Pentium II (0.25 micron)"); break;
1897 case 6: sprintf (this->ChipID.ProcessorName,"Pentium II With On-Die L2 Cache"); break;
1898 case 7: sprintf (this->ChipID.ProcessorName,"Pentium III (0.25 micron)"); break;
1899 case 8: sprintf (this->ChipID.ProcessorName,"Pentium III (0.18 micron) With 256 KB On-Die L2 Cache "); break;
1900 case 0xa: sprintf (this->ChipID.ProcessorName,"Pentium III (0.18 micron) With 1 Or 2 MB On-Die L2 Cache "); break;
1901 case 0xb: sprintf (this->ChipID.ProcessorName,"Pentium III (0.13 micron) With 256 Or 512 KB On-Die L2 Cache "); break;
1902 default: sprintf (this->ChipID.ProcessorName,"Unknown P6 family"); return false;
1904 break;
1905 case 7:
1906 sprintf (this->ChipID.ProcessorName,"Intel Merced (IA-64)");
1907 break;
1908 case 0xf:
1909 // Check the extended family bits...
1910 switch (this->ChipID.ExtendedFamily)
1912 case 0:
1913 switch (this->ChipID.Model)
1915 case 0: sprintf (this->ChipID.ProcessorName,"Pentium IV (0.18 micron)"); break;
1916 case 1: sprintf (this->ChipID.ProcessorName,"Pentium IV (0.18 micron)"); break;
1917 case 2: sprintf (this->ChipID.ProcessorName,"Pentium IV (0.13 micron)"); break;
1918 default: sprintf (this->ChipID.ProcessorName,"Unknown Pentium 4 family"); return false;
1920 break;
1921 case 1:
1922 sprintf (this->ChipID.ProcessorName,"Intel McKinley (IA-64)");
1923 break;
1924 default:
1925 sprintf (this->ChipID.ProcessorName,"Pentium");
1927 break;
1928 default:
1929 sprintf (this->ChipID.ProcessorName,"Unknown Intel family");
1930 return false;
1932 break;
1934 case AMD:
1935 // Check the family / model / revision to determine the CPU ID.
1936 switch (this->ChipID.Family)
1938 case 4:
1939 switch (this->ChipID.Model)
1941 case 3: sprintf (this->ChipID.ProcessorName,"80486DX2"); break;
1942 case 7: sprintf (this->ChipID.ProcessorName,"80486DX2 WriteBack"); break;
1943 case 8: sprintf (this->ChipID.ProcessorName,"80486DX4"); break;
1944 case 9: sprintf (this->ChipID.ProcessorName,"80486DX4 WriteBack"); break;
1945 case 0xe: sprintf (this->ChipID.ProcessorName,"5x86"); break;
1946 case 0xf: sprintf (this->ChipID.ProcessorName,"5x86WB"); break;
1947 default: sprintf (this->ChipID.ProcessorName,"Unknown 80486 family"); return false;
1949 break;
1950 case 5:
1951 switch (this->ChipID.Model)
1953 case 0: sprintf (this->ChipID.ProcessorName,"SSA5 (PR75, PR90, PR100)"); break;
1954 case 1: sprintf (this->ChipID.ProcessorName,"5k86 (PR120, PR133)"); break;
1955 case 2: sprintf (this->ChipID.ProcessorName,"5k86 (PR166)"); break;
1956 case 3: sprintf (this->ChipID.ProcessorName,"5k86 (PR200)"); break;
1957 case 6: sprintf (this->ChipID.ProcessorName,"K6 (0.30 micron)"); break;
1958 case 7: sprintf (this->ChipID.ProcessorName,"K6 (0.25 micron)"); break;
1959 case 8: sprintf (this->ChipID.ProcessorName,"K6-2"); break;
1960 case 9: sprintf (this->ChipID.ProcessorName,"K6-III"); break;
1961 case 0xd: sprintf (this->ChipID.ProcessorName,"K6-2+ or K6-III+ (0.18 micron)"); break;
1962 default: sprintf (this->ChipID.ProcessorName,"Unknown 80586 family"); return false;
1964 break;
1965 case 6:
1966 switch (this->ChipID.Model)
1968 case 1: sprintf (this->ChipID.ProcessorName,"Athlon- (0.25 micron)"); break;
1969 case 2: sprintf (this->ChipID.ProcessorName,"Athlon- (0.18 micron)"); break;
1970 case 3: sprintf (this->ChipID.ProcessorName,"Duron- (SF core)"); break;
1971 case 4: sprintf (this->ChipID.ProcessorName,"Athlon- (Thunderbird core)"); break;
1972 case 6: sprintf (this->ChipID.ProcessorName,"Athlon- (Palomino core)"); break;
1973 case 7: sprintf (this->ChipID.ProcessorName,"Duron- (Morgan core)"); break;
1974 case 8:
1975 if (this->Features.ExtendedFeatures.SupportsMP)
1976 sprintf (this->ChipID.ProcessorName,"Athlon - MP (Thoroughbred core)");
1977 else sprintf (this->ChipID.ProcessorName,"Athlon - XP (Thoroughbred core)");
1978 break;
1979 default: sprintf (this->ChipID.ProcessorName,"Unknown K7 family"); return false;
1981 break;
1982 default:
1983 sprintf (this->ChipID.ProcessorName,"Unknown AMD family");
1984 return false;
1986 break;
1988 case Transmeta:
1989 switch (this->ChipID.Family)
1991 case 5:
1992 switch (this->ChipID.Model)
1994 case 4: sprintf (this->ChipID.ProcessorName,"Crusoe TM3x00 and TM5x00"); break;
1995 default: sprintf (this->ChipID.ProcessorName,"Unknown Crusoe family"); return false;
1997 break;
1998 default:
1999 sprintf (this->ChipID.ProcessorName,"Unknown Transmeta family");
2000 return false;
2002 break;
2004 case Rise:
2005 switch (this->ChipID.Family)
2007 case 5:
2008 switch (this->ChipID.Model)
2010 case 0: sprintf (this->ChipID.ProcessorName,"mP6 (0.25 micron)"); break;
2011 case 2: sprintf (this->ChipID.ProcessorName,"mP6 (0.18 micron)"); break;
2012 default: sprintf (this->ChipID.ProcessorName,"Unknown Rise family"); return false;
2014 break;
2015 default:
2016 sprintf (this->ChipID.ProcessorName,"Unknown Rise family");
2017 return false;
2019 break;
2021 case UMC:
2022 switch (this->ChipID.Family)
2024 case 4:
2025 switch (this->ChipID.Model)
2027 case 1: sprintf (this->ChipID.ProcessorName,"U5D"); break;
2028 case 2: sprintf (this->ChipID.ProcessorName,"U5S"); break;
2029 default: sprintf (this->ChipID.ProcessorName,"Unknown UMC family"); return false;
2031 break;
2032 default:
2033 sprintf (this->ChipID.ProcessorName,"Unknown UMC family");
2034 return false;
2036 break;
2038 case IDT:
2039 switch (this->ChipID.Family)
2041 case 5:
2042 switch (this->ChipID.Model)
2044 case 4: sprintf (this->ChipID.ProcessorName,"C6"); break;
2045 case 8: sprintf (this->ChipID.ProcessorName,"C2"); break;
2046 case 9: sprintf (this->ChipID.ProcessorName,"C3"); break;
2047 default: sprintf (this->ChipID.ProcessorName,"Unknown IDT\\Centaur family"); return false;
2049 break;
2050 case 6:
2051 switch (this->ChipID.Model)
2053 case 6: sprintf (this->ChipID.ProcessorName,"VIA Cyrix III - Samuel"); break;
2054 default: sprintf (this->ChipID.ProcessorName,"Unknown IDT\\Centaur family"); return false;
2056 break;
2057 default:
2058 sprintf (this->ChipID.ProcessorName,"Unknown IDT\\Centaur family");
2059 return false;
2061 break;
2063 case Cyrix:
2064 switch (this->ChipID.Family)
2066 case 4:
2067 switch (this->ChipID.Model)
2069 case 4: sprintf (this->ChipID.ProcessorName,"MediaGX GX, GXm"); break;
2070 case 9: sprintf (this->ChipID.ProcessorName,"5x86"); break;
2071 default: sprintf (this->ChipID.ProcessorName,"Unknown Cx5x86 family"); return false;
2073 break;
2074 case 5:
2075 switch (this->ChipID.Model)
2077 case 2: sprintf (this->ChipID.ProcessorName,"Cx6x86"); break;
2078 case 4: sprintf (this->ChipID.ProcessorName,"MediaGX GXm"); break;
2079 default: sprintf (this->ChipID.ProcessorName,"Unknown Cx6x86 family"); return false;
2081 break;
2082 case 6:
2083 switch (this->ChipID.Model)
2085 case 0: sprintf (this->ChipID.ProcessorName,"6x86MX"); break;
2086 case 5: sprintf (this->ChipID.ProcessorName,"Cyrix M2 Core"); break;
2087 case 6: sprintf (this->ChipID.ProcessorName,"WinChip C5A Core"); break;
2088 case 7: sprintf (this->ChipID.ProcessorName,"WinChip C5B\\C5C Core"); break;
2089 case 8: sprintf (this->ChipID.ProcessorName,"WinChip C5C-T Core"); break;
2090 default: sprintf (this->ChipID.ProcessorName,"Unknown 6x86MX\\Cyrix III family"); return false;
2092 break;
2093 default:
2094 sprintf (this->ChipID.ProcessorName,"Unknown Cyrix family");
2095 return false;
2097 break;
2099 case NexGen:
2100 switch (this->ChipID.Family)
2102 case 5:
2103 switch (this->ChipID.Model)
2105 case 0: sprintf (this->ChipID.ProcessorName,"Nx586 or Nx586FPU"); break;
2106 default: sprintf (this->ChipID.ProcessorName,"Unknown NexGen family"); return false;
2108 break;
2109 default:
2110 sprintf (this->ChipID.ProcessorName,"Unknown NexGen family");
2111 return false;
2113 break;
2115 case NSC:
2116 sprintf (this->ChipID.ProcessorName,"Cx486SLC \\ DLC \\ Cx486S A-Step");
2117 break;
2118 default:
2119 sprintf (this->ChipID.ProcessorName,"Unknown family"); // We cannot identify the processor.
2120 return false;
2123 return true;
2126 /** Extract a value from the CPUInfo file */
2127 kwsys_stl::string SystemInformationImplementation::ExtractValueFromCpuInfoFile(kwsys_stl::string buffer,const char* word,size_t init)
2129 size_t pos = buffer.find(word,init);
2130 if(pos != buffer.npos)
2132 this->CurrentPositionInFile = pos;
2133 pos = buffer.find(":",pos);
2134 size_t pos2 = buffer.find("\n",pos);
2135 if(pos!=buffer.npos && pos2!=buffer.npos)
2137 return buffer.substr(pos+2,pos2-pos-2);
2140 this->CurrentPositionInFile = buffer.npos;
2141 return "";
2144 /** Query for the cpu status */
2145 int SystemInformationImplementation::RetreiveInformationFromCpuInfoFile()
2147 this->NumberOfLogicalCPU = 0;
2148 this->NumberOfPhysicalCPU = 0;
2149 kwsys_stl::string buffer;
2151 FILE *fd = fopen("/proc/cpuinfo", "r" );
2152 if ( !fd )
2154 kwsys_ios::cout << "Problem opening /proc/cpuinfo" << kwsys_ios::endl;
2155 return 0;
2158 size_t fileSize = 0;
2159 while(!feof(fd))
2161 buffer += fgetc(fd);
2162 fileSize++;
2164 fclose( fd );
2165 buffer.resize(fileSize-2);
2166 // Number of logical CPUs (combination of multiple processors, multi-core
2167 // and hyperthreading)
2168 size_t pos = buffer.find("processor\t");
2169 while(pos != buffer.npos)
2171 this->NumberOfLogicalCPU++;
2172 pos = buffer.find("processor\t",pos+1);
2175 #ifdef __linux
2176 // Find the largest physical id.
2177 int maxId = -1;
2178 kwsys_stl::string idc =
2179 this->ExtractValueFromCpuInfoFile(buffer,"physical id");
2180 while(this->CurrentPositionInFile != buffer.npos)
2182 int id = atoi(idc.c_str());
2183 if(id > maxId)
2185 maxId=id;
2187 idc = this->ExtractValueFromCpuInfoFile(buffer,"physical id",
2188 this->CurrentPositionInFile+1);
2190 // Physical ids returned by Linux don't distinguish cores.
2191 // We want to record the total number of cores in this->NumberOfPhysicalCPU
2192 // (checking only the first proc)
2193 kwsys_stl::string cores =
2194 this->ExtractValueFromCpuInfoFile(buffer,"cpu cores");
2195 int numberOfCoresPerCPU=atoi(cores.c_str());
2196 this->NumberOfPhysicalCPU=numberOfCoresPerCPU*(maxId+1);
2198 #else // __CYGWIN__
2199 // does not have "physical id" entries, neither "cpu cores"
2200 // this has to be fixed for hyper-threading.
2201 kwsys_stl::string cpucount =
2202 this->ExtractValueFromCpuInfoFile(buffer,"cpu count");
2203 this->NumberOfPhysicalCPU=
2204 this->NumberOfLogicalCPU = atoi(cpucount.c_str());
2205 #endif
2206 // gotta have one, and if this is 0 then we get a / by 0n
2207 // beter to have a bad answer than a crash
2208 if(this->NumberOfPhysicalCPU <= 0)
2210 this->NumberOfPhysicalCPU = 1;
2212 // LogicalProcessorsPerPhysical>1 => hyperthreading.
2213 this->Features.ExtendedFeatures.LogicalProcessorsPerPhysical=
2214 this->NumberOfLogicalCPU/this->NumberOfPhysicalCPU;
2216 // CPU speed (checking only the first proc
2217 kwsys_stl::string CPUSpeed = this->ExtractValueFromCpuInfoFile(buffer,"cpu MHz");
2218 this->CPUSpeedInMHz = static_cast<float>(atof(CPUSpeed.c_str()));
2220 // Chip family
2221 this->ChipID.Family = atoi(this->ExtractValueFromCpuInfoFile(buffer,"cpu family").c_str());
2223 // Chip Vendor
2224 strcpy(this->ChipID.Vendor,this->ExtractValueFromCpuInfoFile(buffer,"vendor_id").c_str());
2225 this->FindManufacturer();
2227 // Chip Model
2228 this->ChipID.Model = atoi(this->ExtractValueFromCpuInfoFile(buffer,"model").c_str());
2229 this->RetrieveClassicalCPUIdentity();
2231 // L1 Cache size
2232 kwsys_stl::string cacheSize = this->ExtractValueFromCpuInfoFile(buffer,"cache size");
2233 pos = cacheSize.find(" KB");
2234 if(pos!=cacheSize.npos)
2236 cacheSize = cacheSize.substr(0,pos);
2238 this->Features.L1CacheSize = atoi(cacheSize.c_str());
2239 return 1;
2242 /** Query for the memory status */
2243 int SystemInformationImplementation::QueryMemory()
2245 this->TotalVirtualMemory = 0;
2246 this->TotalPhysicalMemory = 0;
2247 this->AvailableVirtualMemory = 0;
2248 this->AvailablePhysicalMemory = 0;
2249 #ifdef __CYGWIN__
2250 return 0;
2251 #elif _WIN32
2252 #if _MSC_VER < 1300
2253 MEMORYSTATUS ms;
2254 GlobalMemoryStatus(&ms);
2255 #define MEM_VAL(value) dw##value
2256 #else
2257 MEMORYSTATUSEX ms;
2258 GlobalMemoryStatusEx(&ms);
2259 #define MEM_VAL(value) ull##value
2260 #endif
2261 unsigned long tv = ms.MEM_VAL(TotalVirtual);
2262 unsigned long tp = ms.MEM_VAL(TotalPhys);
2263 unsigned long av = ms.MEM_VAL(AvailVirtual);
2264 unsigned long ap = ms.MEM_VAL(AvailPhys);
2265 this->TotalVirtualMemory = tv>>10>>10;
2266 this->TotalPhysicalMemory = tp>>10>>10;
2267 this->AvailableVirtualMemory = av>>10>>10;
2268 this->AvailablePhysicalMemory = ap>>10>>10;
2269 return 1;
2270 #elif __linux
2271 unsigned long tv=0;
2272 unsigned long tp=0;
2273 unsigned long av=0;
2274 unsigned long ap=0;
2276 char buffer[1024]; // for skipping unused lines
2278 int linuxMajor = 0;
2279 int linuxMinor = 0;
2281 // Find the Linux kernel version first
2282 struct utsname unameInfo;
2283 int errorFlag = uname(&unameInfo);
2284 if( errorFlag!=0 )
2286 kwsys_ios::cout << "Problem calling uname(): " << strerror(errno) << kwsys_ios::endl;
2287 return 0;
2290 if( unameInfo.release!=0 && strlen(unameInfo.release)>=3 )
2292 // release looks like "2.6.3-15mdk-i686-up-4GB"
2293 char majorChar=unameInfo.release[0];
2294 char minorChar=unameInfo.release[2];
2296 if( isdigit(majorChar) )
2298 linuxMajor=majorChar-'0';
2301 if( isdigit(minorChar) )
2303 linuxMinor=minorChar-'0';
2307 FILE *fd = fopen("/proc/meminfo", "r" );
2308 if ( !fd )
2310 kwsys_ios::cout << "Problem opening /proc/meminfo" << kwsys_ios::endl;
2311 return 0;
2314 if( linuxMajor>=3 || ( (linuxMajor>=2) && (linuxMinor>=6) ) )
2316 // new /proc/meminfo format since kernel 2.6.x
2317 // Rigorously, this test should check from the developping version 2.5.x
2318 // that introduced the new format...
2320 long freeMem;
2321 long buffersMem;
2322 long cachedMem;
2324 fscanf(fd,"MemTotal:%ld kB\n", &this->TotalPhysicalMemory);
2325 fscanf(fd,"MemFree:%ld kB\n", &freeMem);
2326 fscanf(fd,"Buffers:%ld kB\n", &buffersMem);
2327 fscanf(fd,"Cached:%ld kB\n", &cachedMem);
2329 this->TotalPhysicalMemory /= 1024;
2330 this->AvailablePhysicalMemory = freeMem+cachedMem+buffersMem;
2331 this->AvailablePhysicalMemory /= 1024;
2333 // Skip SwapCached, Active, Inactive, HighTotal, HighFree, LowTotal
2334 // and LowFree.
2335 int i=0;
2336 while(i<7)
2338 fgets(buffer, sizeof(buffer), fd); // skip a line
2339 ++i;
2342 fscanf(fd,"SwapTotal:%ld kB\n", &this->TotalVirtualMemory);
2343 fscanf(fd,"SwapFree:%ld kB\n", &this->AvailableVirtualMemory);
2345 this->TotalVirtualMemory /= 1024;
2346 this->AvailableVirtualMemory /= 1024;
2348 else
2350 // /proc/meminfo format for kernel older than 2.6.x
2352 unsigned long temp;
2353 unsigned long cachedMem;
2354 unsigned long buffersMem;
2355 fgets(buffer, sizeof(buffer), fd); // Skip "total: used:..."
2357 fscanf(fd, "Mem: %lu %lu %lu %lu %lu %lu\n",
2358 &tp, &temp, &ap, &temp, &buffersMem, &cachedMem);
2359 fscanf(fd, "Swap: %lu %lu %lu\n", &tv, &temp, &av);
2361 this->TotalVirtualMemory = tv>>10>>10;
2362 this->TotalPhysicalMemory = tp>>10>>10;
2363 this->AvailableVirtualMemory = av>>10>>10;
2364 this->AvailablePhysicalMemory = (ap+buffersMem+cachedMem)>>10>>10;
2366 fclose( fd );
2367 return 1;
2368 #elif __hpux
2369 unsigned long tv=0;
2370 unsigned long tp=0;
2371 unsigned long av=0;
2372 unsigned long ap=0;
2373 struct pst_static pst;
2374 struct pst_dynamic pdy;
2376 unsigned long ps = 0;
2377 if (pstat_getstatic(&pst, sizeof(pst), (size_t) 1, 0) != -1)
2379 ps = pst.page_size;
2380 tp = pst.physical_memory *ps;
2381 tv = (pst.physical_memory + pst.pst_maxmem) * ps;
2382 if (pstat_getdynamic(&pdy, sizeof(pdy), (size_t) 1, 0) != -1)
2384 ap = tp - pdy.psd_rm * ps;
2385 av = tv - pdy.psd_vm;
2386 this->TotalVirtualMemory = tv>>10>>10;
2387 this->TotalPhysicalMemory = tp>>10>>10;
2388 this->AvailableVirtualMemory = av>>10>>10;
2389 this->AvailablePhysicalMemory = ap>>10>>10;
2390 return 1;
2393 return 0;
2394 #else
2395 return 0;
2396 #endif
2401 /** */
2402 unsigned long SystemInformationImplementation::GetTotalVirtualMemory()
2404 return this->TotalVirtualMemory;
2407 /** */
2408 unsigned long SystemInformationImplementation::GetAvailableVirtualMemory()
2410 return this->AvailableVirtualMemory;
2413 unsigned long SystemInformationImplementation::GetTotalPhysicalMemory()
2415 return this->TotalPhysicalMemory;
2418 /** */
2419 unsigned long SystemInformationImplementation::GetAvailablePhysicalMemory()
2421 return this->AvailablePhysicalMemory;
2424 /** Get Cycle differences */
2425 LongLong SystemInformationImplementation::GetCyclesDifference (DELAY_FUNC DelayFunction,
2426 unsigned int uiParameter)
2428 #if USE_ASM_INSTRUCTIONS
2430 unsigned int edx1, eax1;
2431 unsigned int edx2, eax2;
2433 // Calculate the frequency of the CPU instructions.
2434 __try {
2435 _asm {
2436 push uiParameter ; push parameter param
2437 mov ebx, DelayFunction ; store func in ebx
2439 RDTSC_INSTRUCTION
2441 mov esi, eax ; esi = eax
2442 mov edi, edx ; edi = edx
2444 call ebx ; call the delay functions
2446 RDTSC_INSTRUCTION
2448 pop ebx
2450 mov edx2, edx ; edx2 = edx
2451 mov eax2, eax ; eax2 = eax
2453 mov edx1, edi ; edx2 = edi
2454 mov eax1, esi ; eax2 = esi
2457 __except(1)
2459 return -1;
2462 return ((((__int64) edx2 << 32) + eax2) - (((__int64) edx1 << 32) + eax1));
2464 #else
2465 (void)DelayFunction;
2466 (void)uiParameter;
2467 return -1;
2468 #endif
2471 /** Compute the delay overhead */
2472 void SystemInformationImplementation::DelayOverhead(unsigned int uiMS)
2474 #if _WIN32
2475 LARGE_INTEGER Frequency, StartCounter, EndCounter;
2476 __int64 x;
2478 // Get the frequency of the high performance counter.
2479 if(!QueryPerformanceFrequency (&Frequency))
2481 return;
2483 x = Frequency.QuadPart / 1000 * uiMS;
2485 // Get the starting position of the counter.
2486 QueryPerformanceCounter (&StartCounter);
2488 do {
2489 // Get the ending position of the counter.
2490 QueryPerformanceCounter (&EndCounter);
2491 } while (EndCounter.QuadPart - StartCounter.QuadPart == x);
2492 #endif
2493 (void)uiMS;
2496 /** Return the number of logical CPU per physical CPUs Works only for windows */
2497 unsigned char SystemInformationImplementation::LogicalCPUPerPhysicalCPU(void)
2499 unsigned int Regebx = 0;
2500 #if USE_ASM_INSTRUCTIONS
2501 if (!this->IsHyperThreadingSupported())
2503 return (unsigned char) 1; // HT not supported
2505 __asm
2507 mov eax, 1
2508 cpuid
2509 mov Regebx, ebx
2511 #endif
2512 return (unsigned char) ((Regebx & NUM_LOGICAL_BITS) >> 16);
2515 /** Works only for windows */
2516 unsigned int SystemInformationImplementation::IsHyperThreadingSupported()
2518 #if USE_ASM_INSTRUCTIONS
2519 unsigned int Regedx = 0,
2520 Regeax = 0,
2521 VendorId[3] = {0, 0, 0};
2522 __try // Verify cpuid instruction is supported
2524 __asm
2526 xor eax, eax // call cpuid with eax = 0
2527 cpuid // Get vendor id string
2528 mov VendorId, ebx
2529 mov VendorId + 4, edx
2530 mov VendorId + 8, ecx
2532 mov eax, 1 // call cpuid with eax = 1
2533 cpuid
2534 mov Regeax, eax // eax contains family processor type
2535 mov Regedx, edx // edx has info about the availability of hyper-Threading
2538 __except (EXCEPTION_EXECUTE_HANDLER)
2540 return(0); // cpuid is unavailable
2543 if (((Regeax & FAMILY_ID) == PENTIUM4_ID) || (Regeax & EXT_FAMILY_ID))
2545 if (VendorId[0] == 'uneG')
2547 if (VendorId[1] == 'Ieni')
2549 if (VendorId[2] == 'letn')
2551 return(Regedx & HT_BIT); // Genuine Intel with hyper-Threading technology
2556 #endif
2558 return 0; // Not genuine Intel processor
2561 /** Return the APIC Id. Works only for windows. */
2562 unsigned char SystemInformationImplementation::GetAPICId()
2564 unsigned int Regebx = 0;
2565 #if USE_ASM_INSTRUCTIONS
2566 if (!this->IsHyperThreadingSupported())
2568 return (unsigned char) -1; // HT not supported
2569 } // Logical processor = 1
2570 __asm
2572 mov eax, 1
2573 cpuid
2574 mov Regebx, ebx
2576 #endif
2577 return (unsigned char) ((Regebx & INITIAL_APIC_ID_BITS) >> 24);
2580 /** Count the number of CPUs. Works only on windows. */
2581 int SystemInformationImplementation::CPUCount()
2583 #if _WIN32
2584 unsigned char StatusFlag = 0;
2585 SYSTEM_INFO info;
2587 this->NumberOfPhysicalCPU = 0;
2588 this->NumberOfLogicalCPU = 0;
2589 info.dwNumberOfProcessors = 0;
2590 GetSystemInfo (&info);
2592 // Number of physical processors in a non-Intel system
2593 // or in a 32-bit Intel system with Hyper-Threading technology disabled
2594 this->NumberOfPhysicalCPU = (unsigned char) info.dwNumberOfProcessors;
2596 if (this->IsHyperThreadingSupported())
2598 unsigned char HT_Enabled = 0;
2599 this->NumberOfLogicalCPU = this->LogicalCPUPerPhysicalCPU();
2600 if (this->NumberOfLogicalCPU >= 1) // >1 Doesn't mean HT is enabled in the BIOS
2602 HANDLE hCurrentProcessHandle;
2603 #ifndef _WIN64
2604 # define DWORD_PTR DWORD
2605 #endif
2606 DWORD_PTR dwProcessAffinity;
2607 DWORD_PTR dwSystemAffinity;
2608 DWORD dwAffinityMask;
2610 // Calculate the appropriate shifts and mask based on the
2611 // number of logical processors.
2612 unsigned int i = 1;
2613 unsigned char PHY_ID_MASK = 0xFF;
2614 //unsigned char PHY_ID_SHIFT = 0;
2616 while (i < this->NumberOfLogicalCPU)
2618 i *= 2;
2619 PHY_ID_MASK <<= 1;
2620 // PHY_ID_SHIFT++;
2623 hCurrentProcessHandle = GetCurrentProcess();
2624 GetProcessAffinityMask(hCurrentProcessHandle, &dwProcessAffinity,
2625 &dwSystemAffinity);
2627 // Check if available process affinity mask is equal to the
2628 // available system affinity mask
2629 if (dwProcessAffinity != dwSystemAffinity)
2631 StatusFlag = HT_CANNOT_DETECT;
2632 this->NumberOfPhysicalCPU = (unsigned char)-1;
2633 return StatusFlag;
2636 dwAffinityMask = 1;
2637 while (dwAffinityMask != 0 && dwAffinityMask <= dwProcessAffinity)
2639 // Check if this CPU is available
2640 if (dwAffinityMask & dwProcessAffinity)
2642 if (SetProcessAffinityMask(hCurrentProcessHandle,
2643 dwAffinityMask))
2645 unsigned char APIC_ID, LOG_ID;
2646 Sleep(0); // Give OS time to switch CPU
2648 APIC_ID = GetAPICId();
2649 LOG_ID = APIC_ID & ~PHY_ID_MASK;
2651 if (LOG_ID != 0)
2653 HT_Enabled = 1;
2657 dwAffinityMask = dwAffinityMask << 1;
2659 // Reset the processor affinity
2660 SetProcessAffinityMask(hCurrentProcessHandle, dwProcessAffinity);
2662 if (this->NumberOfLogicalCPU == 1) // Normal P4 : HT is disabled in hardware
2664 StatusFlag = HT_DISABLED;
2666 else
2668 if (HT_Enabled)
2670 // Total physical processors in a Hyper-Threading enabled system.
2671 this->NumberOfPhysicalCPU /= (this->NumberOfLogicalCPU);
2672 StatusFlag = HT_ENABLED;
2674 else
2676 StatusFlag = HT_SUPPORTED_NOT_ENABLED;
2681 else
2683 // Processors do not have Hyper-Threading technology
2684 StatusFlag = HT_NOT_CAPABLE;
2685 this->NumberOfLogicalCPU = 1;
2687 return StatusFlag;
2688 #else
2689 return 0;
2690 #endif
2693 /** Return the number of logical CPUs on the system */
2694 unsigned int SystemInformationImplementation::GetNumberOfLogicalCPU()
2696 return this->NumberOfLogicalCPU;
2699 /** Return the number of physical CPUs on the system */
2700 unsigned int SystemInformationImplementation::GetNumberOfPhysicalCPU()
2702 return this->NumberOfPhysicalCPU;
2705 /** For Mac we Parse the sysctl -a output */
2706 bool SystemInformationImplementation::ParseSysCtl()
2708 // Extract the arguments from the command line
2709 kwsys_stl::vector<const char*> args;
2710 args.push_back("sysctl");
2711 args.push_back("-a");
2712 args.push_back(0);
2714 this->SysCtlBuffer = this->RunProcess(args);
2716 // Parse values for Mac
2717 this->TotalPhysicalMemory = atoi(this->ExtractValueFromSysCtl("hw.memsize:").c_str())/(1024*1024);
2718 this->TotalVirtualMemory = 0;
2719 this->AvailablePhysicalMemory = 0;
2720 this->AvailableVirtualMemory = 0;
2722 this->NumberOfPhysicalCPU = atoi(this->ExtractValueFromSysCtl("hw.physicalcpu:").c_str());
2723 this->NumberOfLogicalCPU = atoi(this->ExtractValueFromSysCtl("hw.logicalcpu:").c_str());
2725 if(this->NumberOfPhysicalCPU!=0)
2727 this->NumberOfLogicalCPU /= this->NumberOfPhysicalCPU;
2730 this->CPUSpeedInMHz = atoi(this->ExtractValueFromSysCtl("hw.cpufrequency:").c_str());
2731 this->CPUSpeedInMHz /= 1000000;
2733 // Chip family
2734 this->ChipID.Family = atoi(this->ExtractValueFromSysCtl("machdep.cpu.family:").c_str());
2736 // Chip Vendor
2737 strcpy(this->ChipID.Vendor,this->ExtractValueFromSysCtl("machdep.cpu.vendor:").c_str());
2738 this->FindManufacturer();
2740 // Chip Model
2741 this->ChipID.Model = atoi(this->ExtractValueFromSysCtl("machdep.cpu.model:").c_str());
2742 this->RetrieveClassicalCPUIdentity();
2744 // Cache size
2745 this->Features.L1CacheSize = atoi(this->ExtractValueFromSysCtl("hw.l1icachesize:").c_str());
2746 this->Features.L2CacheSize = atoi(this->ExtractValueFromSysCtl("hw.l2cachesize:").c_str());
2748 return true;
2751 /** Extract a value from sysctl command */
2752 kwsys_stl::string SystemInformationImplementation::ExtractValueFromSysCtl(const char* word)
2754 size_t pos = this->SysCtlBuffer.find(word);
2755 if(pos != this->SysCtlBuffer.npos)
2757 pos = this->SysCtlBuffer.find(": ",pos);
2758 size_t pos2 = this->SysCtlBuffer.find("\n",pos);
2759 if(pos!=this->SysCtlBuffer.npos && pos2!=this->SysCtlBuffer.npos)
2761 return this->SysCtlBuffer.substr(pos+2,pos2-pos-2);
2764 return "";
2767 /** Run a given process */
2768 kwsys_stl::string SystemInformationImplementation::RunProcess(kwsys_stl::vector<const char*> args)
2770 kwsys_stl::string buffer = "";
2772 // Run the application
2773 kwsysProcess* gp = kwsysProcess_New();
2774 kwsysProcess_SetCommand(gp, &*args.begin());
2775 kwsysProcess_SetOption(gp,kwsysProcess_Option_HideWindow,1);
2777 kwsysProcess_Execute(gp);
2779 char* data = NULL;
2780 int length;
2781 double timeout = 255;
2783 while(kwsysProcess_WaitForData(gp,&data,&length,&timeout)) // wait for 1s
2785 for(int i=0;i<length;i++)
2787 buffer += data[i];
2790 kwsysProcess_WaitForExit(gp, 0);
2792 int result = 0;
2793 switch(kwsysProcess_GetState(gp))
2795 case kwsysProcess_State_Exited:
2797 result = kwsysProcess_GetExitValue(gp);
2798 } break;
2799 case kwsysProcess_State_Error:
2801 kwsys_ios::cerr << "Error: Could not run " << args[0] << ":\n";
2802 kwsys_ios::cerr << kwsysProcess_GetErrorString(gp) << "\n";
2803 } break;
2804 case kwsysProcess_State_Exception:
2806 kwsys_ios::cerr << "Error: " << args[0]
2807 << " terminated with an exception: "
2808 << kwsysProcess_GetExceptionString(gp) << "\n";
2809 } break;
2810 case kwsysProcess_State_Starting:
2811 case kwsysProcess_State_Executing:
2812 case kwsysProcess_State_Expired:
2813 case kwsysProcess_State_Killed:
2815 // Should not get here.
2816 kwsys_ios::cerr << "Unexpected ending state after running " << args[0]
2817 << kwsys_ios::endl;
2818 } break;
2820 kwsysProcess_Delete(gp);
2821 if(result)
2823 kwsys_ios::cerr << "Error " << args[0] << " returned :" << result << "\n";
2825 return buffer;
2829 kwsys_stl::string SystemInformationImplementation::ParseValueFromKStat(const char* arguments)
2831 kwsys_stl::vector<const char*> args;
2832 args.clear();
2833 args.push_back("kstat");
2834 args.push_back("-p");
2836 kwsys_stl::string command = arguments;
2837 size_t start = command.npos;
2838 size_t pos = command.find(' ',0);
2839 while(pos!=command.npos)
2841 bool inQuotes = false;
2842 // Check if we are between quotes
2843 size_t b0 = command.find('"',0);
2844 size_t b1 = command.find('"',b0+1);
2845 while(b0 != command.npos && b1 != command.npos && b1>b0)
2847 if(pos>b0 && pos<b1)
2849 inQuotes = true;
2850 break;
2852 b0 = command.find('"',b1+1);
2853 b1 = command.find('"',b0+1);
2856 if(!inQuotes)
2858 kwsys_stl::string arg = command.substr(start+1,pos-start-1);
2860 // Remove the quotes if any
2861 size_t quotes = arg.find('"');
2862 while(quotes != arg.npos)
2864 arg.erase(quotes,1);
2865 quotes = arg.find('"');
2867 args.push_back(arg.c_str());
2868 start = pos;
2870 pos = command.find(' ',pos+1);
2872 kwsys_stl::string lastArg = command.substr(start+1,command.size()-start-1);
2873 args.push_back(lastArg.c_str());
2875 args.push_back(0);
2877 kwsys_stl::string buffer = this->RunProcess(args);
2879 kwsys_stl::string value = "";
2880 for(size_t i=buffer.size()-1;i>0;i--)
2882 if(buffer[i] == ' ' || buffer[i] == '\t')
2884 break;
2886 if(buffer[i] != '\n' && buffer[i] != '\r')
2888 kwsys_stl::string val = value;
2889 value = buffer[i];
2890 value += val;
2893 return value;
2896 /** Querying for system information from Solaris */
2897 bool SystemInformationImplementation::QuerySolarisInfo()
2899 // Parse values
2900 this->NumberOfPhysicalCPU = atoi(this->ParseValueFromKStat("-n systethis->misc -s ncpus").c_str());
2901 this->NumberOfLogicalCPU = this->NumberOfPhysicalCPU;
2903 if(this->NumberOfPhysicalCPU!=0)
2905 this->NumberOfLogicalCPU /= this->NumberOfPhysicalCPU;
2908 this->CPUSpeedInMHz = atoi(this->ParseValueFromKStat("-s clock_MHz").c_str());
2910 // Chip family
2911 this->ChipID.Family = 0;
2913 // Chip Vendor
2914 strcpy(this->ChipID.Vendor,"Sun");
2915 this->FindManufacturer();
2917 // Chip Model
2918 sprintf(this->ChipID.ProcessorName,"%s",this->ParseValueFromKStat("-s cpu_type").c_str());
2919 this->ChipID.Model = 0;
2921 // Cache size
2922 this->Features.L1CacheSize = 0;
2923 this->Features.L2CacheSize = 0;
2925 char* tail;
2926 unsigned long totalMemory =
2927 strtoul(this->ParseValueFromKStat("-s physmem").c_str(),&tail,0);
2928 this->TotalPhysicalMemory = totalMemory/1024;
2929 this->TotalPhysicalMemory *= 8192;
2930 this->TotalPhysicalMemory /= 1024;
2932 // Undefined values (for now at least)
2933 this->TotalVirtualMemory = 0;
2934 this->AvailablePhysicalMemory = 0;
2935 this->AvailableVirtualMemory = 0;
2937 return true;
2940 /** Query the operating system information */
2941 bool SystemInformationImplementation::QueryOSInformation()
2943 #if _WIN32
2945 this->OSName = "Windows";
2947 OSVERSIONINFOEX osvi;
2948 BOOL bIsWindows64Bit;
2949 BOOL bOsVersionInfoEx;
2950 char operatingSystem[256];
2952 // Try calling GetVersionEx using the OSVERSIONINFOEX structure.
2953 ZeroMemory (&osvi, sizeof (OSVERSIONINFOEX));
2954 osvi.dwOSVersionInfoSize = sizeof (OSVERSIONINFOEX);
2955 bOsVersionInfoEx = GetVersionEx ((OSVERSIONINFO *) &osvi);
2956 if (!bOsVersionInfoEx)
2958 osvi.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
2959 if (!GetVersionEx ((OSVERSIONINFO *) &osvi))
2961 return false;
2965 switch (osvi.dwPlatformId)
2967 case VER_PLATFORM_WIN32_NT:
2968 // Test for the product.
2969 if (osvi.dwMajorVersion <= 4)
2971 this->OSRelease = "NT";
2973 if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0)
2975 this->OSRelease = "2000";
2977 if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1)
2979 this->OSRelease = "XP";
2981 #ifdef VER_NT_WORKSTATION
2982 // Test for product type.
2983 if (bOsVersionInfoEx)
2985 if (osvi.wProductType == VER_NT_WORKSTATION)
2987 if (osvi.dwMajorVersion == 6)
2989 this->OSRelease = "Vista";
2991 // VER_SUITE_PERSONAL may not be defined
2992 #ifdef VER_SUITE_PERSONAL
2993 else
2995 if (osvi.wSuiteMask & VER_SUITE_PERSONAL)
2997 this->OSRelease += " Personal";
2999 else
3001 this->OSRelease += " Professional";
3004 #endif
3006 else if (osvi.wProductType == VER_NT_SERVER)
3008 // Check for .NET Server instead of Windows XP.
3009 if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1)
3011 this->OSRelease = ".NET";
3014 // Continue with the type detection.
3015 if (osvi.wSuiteMask & VER_SUITE_DATACENTER)
3017 this->OSRelease += " DataCenter Server";
3019 else if (osvi.wSuiteMask & VER_SUITE_ENTERPRISE)
3021 this->OSRelease += " Advanced Server";
3023 else
3025 this->OSRelease += " Server";
3029 sprintf (operatingSystem, "%s (Build %ld)", osvi.szCSDVersion, osvi.dwBuildNumber & 0xFFFF);
3030 this->OSVersion = operatingSystem;
3032 else
3033 #endif // VER_NT_WORKSTATION
3035 HKEY hKey;
3036 char szProductType[80];
3037 DWORD dwBufLen;
3039 // Query the registry to retrieve information.
3040 RegOpenKeyEx (HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Control\\ProductOptions", 0, KEY_QUERY_VALUE, &hKey);
3041 RegQueryValueEx (hKey, "ProductType", NULL, NULL, (LPBYTE) szProductType, &dwBufLen);
3042 RegCloseKey (hKey);
3044 if (lstrcmpi ("WINNT", szProductType) == 0)
3046 this->OSRelease += " Professional";
3048 if (lstrcmpi ("LANMANNT", szProductType) == 0)
3050 // Decide between Windows 2000 Advanced Server and Windows .NET Enterprise Server.
3051 if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1)
3053 this->OSRelease += " Standard Server";
3055 else
3057 this->OSRelease += " Server";
3060 if (lstrcmpi ("SERVERNT", szProductType) == 0)
3062 // Decide between Windows 2000 Advanced Server and Windows .NET Enterprise Server.
3063 if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1)
3065 this->OSRelease += " Enterprise Server";
3067 else
3069 this->OSRelease += " Advanced Server";
3074 // Display version, service pack (if any), and build number.
3075 if (osvi.dwMajorVersion <= 4)
3077 // NB: NT 4.0 and earlier.
3078 sprintf (operatingSystem, "version %ld.%ld %s (Build %ld)",
3079 osvi.dwMajorVersion,
3080 osvi.dwMinorVersion,
3081 osvi.szCSDVersion,
3082 osvi.dwBuildNumber & 0xFFFF);
3083 this->OSVersion = operatingSystem;
3085 else if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1)
3087 // Windows XP and .NET server.
3088 typedef BOOL (CALLBACK* LPFNPROC) (HANDLE, BOOL *);
3089 HINSTANCE hKernelDLL;
3090 LPFNPROC DLLProc;
3092 // Load the Kernel32 DLL.
3093 hKernelDLL = LoadLibrary ("kernel32");
3094 if (hKernelDLL != NULL) {
3095 // Only XP and .NET Server support IsWOW64Process so... Load dynamically!
3096 DLLProc = (LPFNPROC) GetProcAddress (hKernelDLL, "IsWow64Process");
3098 // If the function address is valid, call the function.
3099 if (DLLProc != NULL) (DLLProc) (GetCurrentProcess (), &bIsWindows64Bit);
3100 else bIsWindows64Bit = false;
3102 // Free the DLL module.
3103 FreeLibrary (hKernelDLL);
3106 else
3108 // Windows 2000 and everything else.
3109 sprintf (operatingSystem,"%s (Build %ld)", osvi.szCSDVersion, osvi.dwBuildNumber & 0xFFFF);
3110 this->OSVersion = operatingSystem;
3112 break;
3114 case VER_PLATFORM_WIN32_WINDOWS:
3115 // Test for the product.
3116 if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 0)
3118 this->OSRelease = "95";
3119 if(osvi.szCSDVersion[1] == 'C')
3121 this->OSRelease += "OSR 2.5";
3123 else if(osvi.szCSDVersion[1] == 'B')
3125 this->OSRelease += "OSR 2";
3129 if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 10)
3131 this->OSRelease = "98";
3132 if (osvi.szCSDVersion[1] == 'A' )
3134 this->OSRelease += "SE";
3138 if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 90)
3140 this->OSRelease = "Me";
3142 break;
3144 case VER_PLATFORM_WIN32s:
3145 this->OSRelease = "Win32s";
3146 break;
3148 default:
3149 this->OSRelease = "Unknown";
3150 break;
3153 // Get the hostname
3154 WORD wVersionRequested;
3155 WSADATA wsaData;
3156 char name[255];
3157 wVersionRequested = MAKEWORD(2,0);
3159 if ( WSAStartup( wVersionRequested, &wsaData ) == 0 )
3161 gethostname(name,sizeof(name));
3162 WSACleanup( );
3164 this->Hostname = name;
3166 #else
3168 struct utsname unameInfo;
3169 int errorFlag = uname(&unameInfo);
3170 if(errorFlag == 0)
3172 this->OSName = unameInfo.sysname;
3173 this->Hostname = unameInfo.nodename;
3174 this->OSRelease = unameInfo.release;
3175 this->OSVersion = unameInfo.version;
3176 this->OSPlatform = unameInfo.machine;
3178 #endif
3180 return true;
3184 /** Return true if the machine is 64 bits */
3185 bool SystemInformationImplementation::Is64Bits()
3187 return (sizeof(void*) == 8);
3190 } // namespace @KWSYS_NAMESPACE@