1 /*=========================================================================
4 Module: $RCSfile: SystemInformation.cxx,v $
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 =========================================================================*/
17 # include <winsock.h> // WSADATA, include before sys/types.h
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.
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"
45 # include <sys/utsname.h> // int uname(struct utsname *buf);
53 # include <sys/procfs.h>
54 # include <sys/types.h>
57 # include <ctype.h> // int isdigit(int c);
58 # include <errno.h> // extern int errno;
59 # include <sys/time.h>
61 # include <sys/param.h>
62 # include <sys/pstat.h>
72 namespace KWSYS_NAMESPACE
76 #if KWSYS_USE_LONG_LONG
77 typedef long long LongLong
;
78 #elif KWSYS_USE___INT64
79 typedef __int64 LongLong
;
81 # error "No Long Long"
84 // Define SystemInformationImplementation class
85 typedef void (*DELAY_FUNC
)(unsigned int uiMS
);
87 class SystemInformationImplementation
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();
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 */
131 void RunMemoryCheck();
133 #define VENDOR_STRING_LENGTH (12 + 1)
134 #define CHIPNAME_STRING_LENGTH (48 + 1)
135 #define SERIALNUMBER_STRING_LENGTH (29 + 1)
145 char ProcessorName
[CHIPNAME_STRING_LENGTH
];
146 char Vendor
[VENDOR_STRING_LENGTH
];
147 char SerialNumber
[SERIALNUMBER_STRING_LENGTH
];
150 typedef struct tagCPUPowerManagement
154 bool HasTempSenseDiode
;
155 } CPUPowerManagement
;
157 typedef struct tagCPUExtendedFeatures
164 bool SupportsHyperthreading
;
165 int LogicalProcessorsPerPhysical
;
167 CPUPowerManagement PowerManagement
;
168 } CPUExtendedFeatures
;
170 typedef struct CPUtagFeatures
189 CPUExtendedFeatures ExtendedFeatures
;
194 AMD
, Intel
, NSC
, UMC
, Cyrix
, NexGen
, IDT
, Rise
, Transmeta
, Sun
, UnknownManufacturer
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
;
216 unsigned int NumberOfLogicalCPU
;
217 unsigned int NumberOfPhysicalCPU
;
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();
237 kwsys_stl::string
ExtractValueFromSysCtl(const char* word
);
238 kwsys_stl::string SysCtlBuffer
;
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.
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
415 #define USE_ASM_INSTRUCTIONS 0
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
427 #define CPUID_INSTRUCTION _asm _emit 0x0f _asm _emit 0xa2
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
455 #define HT_NOT_CAPABLE 0
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
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;
495 this->OSRelease
= "";
496 this->OSVersion
= "";
497 this->OSPlatform
= "";
500 SystemInformationImplementation::~SystemInformationImplementation()
504 void SystemInformationImplementation::RunCPUCheck()
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();
534 #elif defined(__APPLE__)
536 #elif defined (__SVR4) && defined (__sun)
537 this->QuerySolarisInfo();
539 this->RetreiveInformationFromCpuInfoFile();
543 void SystemInformationImplementation::RunOSCheck()
545 this->QueryOSInformation();
548 void SystemInformationImplementation::RunMemoryCheck()
550 #if defined(__APPLE__)
552 #elif defined (__SVR4) && defined (__sun)
553 this->QuerySolarisInfo();
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
)
602 return "Intel Corporation";
604 return "Advanced Micro Devices";
606 return "National Semiconductor";
608 return "Cyrix Corp., VIA Inc.";
610 return "NexGen Inc., Advanced Micro Devices";
612 return "IDT\\Centaur, Via Inc.";
614 return "United Microelectronics Corp.";
620 return "Sun Microelectronics";
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
;
634 /** Return the family of the CPU present */
635 kwsys_stl::string
SystemInformationImplementation::GetFamilyID()
637 kwsys_ios::ostringstream str
;
638 str
<< this->ChipID
.Family
;
642 // Return the model of CPU present */
643 kwsys_stl::string
SystemInformationImplementation::GetModelID()
645 kwsys_ios::ostringstream str
;
646 str
<< this->ChipID
.Model
;
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
;
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
)
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
;
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;
783 void SystemInformationImplementation::Delay(unsigned int uiMS
)
786 LARGE_INTEGER Frequency
, StartCounter
, EndCounter
;
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
);
797 // Get the ending position of the counter.
798 QueryPerformanceCounter (&EndCounter
);
799 } while (EndCounter
.QuadPart
- StartCounter
.QuadPart
< x
);
804 bool SystemInformationImplementation::DoesCPUSupportCPUID()
806 #if USE_ASM_INSTRUCTIONS
807 // Use SEH to determine CPUID presence
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
.
823 #ifdef CPUID_AWARE_COMPILER
833 // Stop the class from trying to use CPUID again!
837 // The cpuid instruction succeeded.
840 // Assume no cpuid instruction.
845 bool SystemInformationImplementation::RetrieveCPUFeatures()
847 #if USE_ASM_INSTRUCTIONS
848 int localCPUFeatures
= 0;
849 int localCPUAdvanced
= 0;
852 // Use assembly to detect CPUID information...
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
.
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
870 mov localCPUFeatures
, edx
871 mov localCPUAdvanced
, ebx
873 #ifdef CPUID_AWARE_COMPILER
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.
906 // Perform: orps xmm0, xmm0
914 // SSE FP capable processor.
915 this->Features
.HasSSEFP
= true;
919 // bad instruction - processor or OS cannot handle SSE FP.
920 this->Features
.HasSSEFP
= false;
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);
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
965 bool SystemInformationImplementation::RetrieveCPUIdentity()
967 #if USE_ASM_INSTRUCTIONS
968 int localCPUVendor
[3];
969 int localCPUSignature
;
971 // Use assembly to detect CPUID information...
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
.
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
.
992 mov localCPUVendor
[0 * TYPE
int], ebx
993 mov localCPUVendor
[1 * TYPE
int], edx
994 mov localCPUVendor
[2 * TYPE
int], ecx
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
1002 mov localCPUSignature
, eax
1004 #ifdef CPUID_AWARE_COMPILER
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
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 ...
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
.
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.
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
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);
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 ...
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
.
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.
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
1136 // Save the L2 unified cache size (in KB) from ecx: bits 31..16.
1137 this->Features
.L2CacheSize
= ((L2Cache
[2] & 0xFFFF0000) >> 16);
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;
1150 // Return failure if we cannot detect either cache with this method.
1151 return ((this->Features
.L1CacheSize
== -1) && (this->Features
.L2CacheSize
== -1)) ? false : true;
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;
1165 // Use assembly to retrieve the L2 cache information ...
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
.
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.
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
1202 int bob
= ((TLBCacheData
[0] & 0x00FF0000) >> 16);
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.
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
)
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.
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
;
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;
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;
1347 this->Features
.L3CacheSize
= L3Unified
;
1355 bool SystemInformationImplementation::RetrieveCPUClockSpeed()
1358 // First of all we check to see if the RDTSC (0x0F, 0x31) instruction is supported.
1359 if (!this->Features
.HasTSC
)
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
);
1374 GetCyclesDifference (SystemInformationImplementation::DelayOverhead
,
1375 uiMSecPerRepetition
);
1378 // Calculate the MHz speed.
1379 i64Total
-= i64Overhead
;
1380 i64Total
/= uiRepetitions
;
1381 i64Total
/= uiMSecPerRepetition
;
1384 // Save the CPU speed.
1385 this->CPUSpeedInMHz
= (float) i64Total
;
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
);
1408 mov ebx
, CLASSICAL_CPU_FREQ_LOOP
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
;
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
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)
1497 #if USE_ASM_INSTRUCTIONS
1499 // Use assembly to detect CPUID information...
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
.
1512 ; eax
= 0x80000000 --> eax
: maximum supported extended level
1515 mov MaxCPUExtendedLevel
, eax
1517 #ifdef CPUID_AWARE_COMPILER
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
)
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
)
1554 // Check to see if what we are about to do is supported...
1555 if (!RetrieveCPUExtendedLevelSupport (0x80000001))
1559 #if USE_ASM_INSTRUCTIONS
1560 int localCPUExtendedFeatures
= 0;
1562 // Use assembly to detect CPUID information...
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
.
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
1582 mov localCPUExtendedFeatures
, edx
1584 #ifdef CPUID_AWARE_COMPILER
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
1620 bool SystemInformationImplementation::RetrieveProcessorSerialNumber()
1622 // Check to see if the processor supports the processor serial number.
1623 if (!this->Features
.HasSerial
)
1628 #if USE_ASM_INSTRUCTIONS
1629 int SerialNumber
[3];
1632 // Use assembly to detect CPUID information...
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
.
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
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
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));
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;
1698 #if USE_ASM_INSTRUCTIONS
1699 int localCPUPowerManagement
= 0;
1702 // Use assembly to detect CPUID information...
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
.
1715 ; eax
= 0x80000007 --> edx
: get processor power management
1718 mov localCPUPowerManagement
, edx
1720 #ifdef CPUID_AWARE_COMPILER
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);
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...
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
.
1768 ; eax
= 0x80000002 --> eax
, ebx
, ecx
, edx
: get processor name
string (part
1)
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
1777 ; eax
= 0x80000003 --> eax
, ebx
, ecx
, edx
: get processor name
string (part
2)
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
1786 ; eax
= 0x80000004 --> eax
, ebx
, ecx
, edx
: get processor name
string (part
3)
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
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.
1837 // Check to see if there is any white space at the start.
1838 if (ProcessorNameStartPos
== 0)
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
));
1852 bool SystemInformationImplementation::RetrieveClassicalCPUIdentity()
1854 // Start by decided which manufacturer we are using....
1855 switch (this->ChipManufacturer
)
1858 // Check the family / model / revision to determine the CPU ID.
1859 switch (this->ChipID
.Family
) {
1861 sprintf (this->ChipID
.ProcessorName
, "Newer i80386 family");
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;
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;
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;
1906 sprintf (this->ChipID
.ProcessorName
,"Intel Merced (IA-64)");
1909 // Check the extended family bits...
1910 switch (this->ChipID
.ExtendedFamily
)
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;
1922 sprintf (this->ChipID
.ProcessorName
,"Intel McKinley (IA-64)");
1925 sprintf (this->ChipID
.ProcessorName
,"Pentium");
1929 sprintf (this->ChipID
.ProcessorName
,"Unknown Intel family");
1935 // Check the family / model / revision to determine the CPU ID.
1936 switch (this->ChipID
.Family
)
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;
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;
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;
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)");
1979 default: sprintf (this->ChipID
.ProcessorName
,"Unknown K7 family"); return false;
1983 sprintf (this->ChipID
.ProcessorName
,"Unknown AMD family");
1989 switch (this->ChipID
.Family
)
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;
1999 sprintf (this->ChipID
.ProcessorName
,"Unknown Transmeta family");
2005 switch (this->ChipID
.Family
)
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;
2016 sprintf (this->ChipID
.ProcessorName
,"Unknown Rise family");
2022 switch (this->ChipID
.Family
)
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;
2033 sprintf (this->ChipID
.ProcessorName
,"Unknown UMC family");
2039 switch (this->ChipID
.Family
)
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;
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;
2058 sprintf (this->ChipID
.ProcessorName
,"Unknown IDT\\Centaur family");
2064 switch (this->ChipID
.Family
)
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;
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;
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;
2094 sprintf (this->ChipID
.ProcessorName
,"Unknown Cyrix family");
2100 switch (this->ChipID
.Family
)
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;
2110 sprintf (this->ChipID
.ProcessorName
,"Unknown NexGen family");
2116 sprintf (this->ChipID
.ProcessorName
,"Cx486SLC \\ DLC \\ Cx486S A-Step");
2119 sprintf (this->ChipID
.ProcessorName
,"Unknown family"); // We cannot identify the processor.
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
;
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" );
2154 kwsys_ios::cout
<< "Problem opening /proc/cpuinfo" << kwsys_ios::endl
;
2158 size_t fileSize
= 0;
2161 buffer
+= fgetc(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);
2176 // Find the largest physical id.
2178 kwsys_stl::string idc
=
2179 this->ExtractValueFromCpuInfoFile(buffer
,"physical id");
2180 while(this->CurrentPositionInFile
!= buffer
.npos
)
2182 int id
= atoi(idc
.c_str());
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);
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());
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()));
2221 this->ChipID
.Family
= atoi(this->ExtractValueFromCpuInfoFile(buffer
,"cpu family").c_str());
2224 strcpy(this->ChipID
.Vendor
,this->ExtractValueFromCpuInfoFile(buffer
,"vendor_id").c_str());
2225 this->FindManufacturer();
2228 this->ChipID
.Model
= atoi(this->ExtractValueFromCpuInfoFile(buffer
,"model").c_str());
2229 this->RetrieveClassicalCPUIdentity();
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());
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;
2254 GlobalMemoryStatus(&ms
);
2255 #define MEM_VAL(value) dw##value
2258 GlobalMemoryStatusEx(&ms
);
2259 #define MEM_VAL(value) ull##value
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;
2276 char buffer
[1024]; // for skipping unused lines
2281 // Find the Linux kernel version first
2282 struct utsname unameInfo
;
2283 int errorFlag
= uname(&unameInfo
);
2286 kwsys_ios::cout
<< "Problem calling uname(): " << strerror(errno
) << kwsys_ios::endl
;
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" );
2310 kwsys_ios::cout
<< "Problem opening /proc/meminfo" << kwsys_ios::endl
;
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...
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
2338 fgets(buffer
, sizeof(buffer
), fd
); // skip a line
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;
2350 // /proc/meminfo format for kernel older than 2.6.x
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;
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)
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;
2402 unsigned long SystemInformationImplementation::GetTotalVirtualMemory()
2404 return this->TotalVirtualMemory
;
2408 unsigned long SystemInformationImplementation::GetAvailableVirtualMemory()
2410 return this->AvailableVirtualMemory
;
2413 unsigned long SystemInformationImplementation::GetTotalPhysicalMemory()
2415 return this->TotalPhysicalMemory
;
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.
2436 push uiParameter
; push parameter param
2437 mov ebx
, DelayFunction
; store func in ebx
2441 mov esi
, eax
; esi
= eax
2442 mov edi
, edx
; edi
= edx
2444 call ebx
; call the delay functions
2450 mov edx2
, edx
; edx2
= edx
2451 mov eax2
, eax
; eax2
= eax
2453 mov edx1
, edi
; edx2
= edi
2454 mov eax1
, esi
; eax2
= esi
2462 return ((((__int64
) edx2
<< 32) + eax2
) - (((__int64
) edx1
<< 32) + eax1
));
2465 (void)DelayFunction
;
2471 /** Compute the delay overhead */
2472 void SystemInformationImplementation::DelayOverhead(unsigned int uiMS
)
2475 LARGE_INTEGER Frequency
, StartCounter
, EndCounter
;
2478 // Get the frequency of the high performance counter.
2479 if(!QueryPerformanceFrequency (&Frequency
))
2483 x
= Frequency
.QuadPart
/ 1000 * uiMS
;
2485 // Get the starting position of the counter.
2486 QueryPerformanceCounter (&StartCounter
);
2489 // Get the ending position of the counter.
2490 QueryPerformanceCounter (&EndCounter
);
2491 } while (EndCounter
.QuadPart
- StartCounter
.QuadPart
== x
);
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
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,
2521 VendorId
[3] = {0, 0, 0};
2522 __try
// Verify cpuid instruction is supported
2526 xor eax
, eax
// call cpuid with eax = 0
2527 cpuid
// Get vendor id string
2529 mov VendorId
+ 4, edx
2530 mov VendorId
+ 8, ecx
2532 mov eax
, 1 // call cpuid with eax = 1
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
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
2577 return (unsigned char) ((Regebx
& INITIAL_APIC_ID_BITS
) >> 24);
2580 /** Count the number of CPUs. Works only on windows. */
2581 int SystemInformationImplementation::CPUCount()
2584 unsigned char StatusFlag
= 0;
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
;
2604 # define DWORD_PTR DWORD
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.
2613 unsigned char PHY_ID_MASK
= 0xFF;
2614 //unsigned char PHY_ID_SHIFT = 0;
2616 while (i
< this->NumberOfLogicalCPU
)
2623 hCurrentProcessHandle
= GetCurrentProcess();
2624 GetProcessAffinityMask(hCurrentProcessHandle
, &dwProcessAffinity
,
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;
2637 while (dwAffinityMask
!= 0 && dwAffinityMask
<= dwProcessAffinity
)
2639 // Check if this CPU is available
2640 if (dwAffinityMask
& dwProcessAffinity
)
2642 if (SetProcessAffinityMask(hCurrentProcessHandle
,
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
;
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
;
2670 // Total physical processors in a Hyper-Threading enabled system.
2671 this->NumberOfPhysicalCPU
/= (this->NumberOfLogicalCPU
);
2672 StatusFlag
= HT_ENABLED
;
2676 StatusFlag
= HT_SUPPORTED_NOT_ENABLED
;
2683 // Processors do not have Hyper-Threading technology
2684 StatusFlag
= HT_NOT_CAPABLE
;
2685 this->NumberOfLogicalCPU
= 1;
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");
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;
2734 this->ChipID
.Family
= atoi(this->ExtractValueFromSysCtl("machdep.cpu.family:").c_str());
2737 strcpy(this->ChipID
.Vendor
,this->ExtractValueFromSysCtl("machdep.cpu.vendor:").c_str());
2738 this->FindManufacturer();
2741 this->ChipID
.Model
= atoi(this->ExtractValueFromSysCtl("machdep.cpu.model:").c_str());
2742 this->RetrieveClassicalCPUIdentity();
2745 this->Features
.L1CacheSize
= atoi(this->ExtractValueFromSysCtl("hw.l1icachesize:").c_str());
2746 this->Features
.L2CacheSize
= atoi(this->ExtractValueFromSysCtl("hw.l2cachesize:").c_str());
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);
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
);
2781 double timeout
= 255;
2783 while(kwsysProcess_WaitForData(gp
,&data
,&length
,&timeout
)) // wait for 1s
2785 for(int i
=0;i
<length
;i
++)
2790 kwsysProcess_WaitForExit(gp
, 0);
2793 switch(kwsysProcess_GetState(gp
))
2795 case kwsysProcess_State_Exited
:
2797 result
= kwsysProcess_GetExitValue(gp
);
2799 case kwsysProcess_State_Error
:
2801 kwsys_ios::cerr
<< "Error: Could not run " << args
[0] << ":\n";
2802 kwsys_ios::cerr
<< kwsysProcess_GetErrorString(gp
) << "\n";
2804 case kwsysProcess_State_Exception
:
2806 kwsys_ios::cerr
<< "Error: " << args
[0]
2807 << " terminated with an exception: "
2808 << kwsysProcess_GetExceptionString(gp
) << "\n";
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]
2820 kwsysProcess_Delete(gp
);
2823 kwsys_ios::cerr
<< "Error " << args
[0] << " returned :" << result
<< "\n";
2829 kwsys_stl::string
SystemInformationImplementation::ParseValueFromKStat(const char* arguments
)
2831 kwsys_stl::vector
<const char*> args
;
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
)
2852 b0
= command
.find('"',b1
+1);
2853 b1
= command
.find('"',b0
+1);
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());
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());
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')
2886 if(buffer
[i
] != '\n' && buffer
[i
] != '\r')
2888 kwsys_stl::string val
= value
;
2896 /** Querying for system information from Solaris */
2897 bool SystemInformationImplementation::QuerySolarisInfo()
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());
2911 this->ChipID
.Family
= 0;
2914 strcpy(this->ChipID
.Vendor
,"Sun");
2915 this->FindManufacturer();
2918 sprintf(this->ChipID
.ProcessorName
,"%s",this->ParseValueFromKStat("-s cpu_type").c_str());
2919 this->ChipID
.Model
= 0;
2922 this->Features
.L1CacheSize
= 0;
2923 this->Features
.L2CacheSize
= 0;
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;
2940 /** Query the operating system information */
2941 bool SystemInformationImplementation::QueryOSInformation()
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
))
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
2995 if (osvi
.wSuiteMask
& VER_SUITE_PERSONAL
)
2997 this->OSRelease
+= " Personal";
3001 this->OSRelease
+= " Professional";
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";
3025 this->OSRelease
+= " Server";
3029 sprintf (operatingSystem
, "%s (Build %ld)", osvi
.szCSDVersion
, osvi
.dwBuildNumber
& 0xFFFF);
3030 this->OSVersion
= operatingSystem
;
3033 #endif // VER_NT_WORKSTATION
3036 char szProductType
[80];
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
);
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";
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";
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
,
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
;
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
);
3108 // Windows 2000 and everything else.
3109 sprintf (operatingSystem
,"%s (Build %ld)", osvi
.szCSDVersion
, osvi
.dwBuildNumber
& 0xFFFF);
3110 this->OSVersion
= operatingSystem
;
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";
3144 case VER_PLATFORM_WIN32s
:
3145 this->OSRelease
= "Win32s";
3149 this->OSRelease
= "Unknown";
3154 WORD wVersionRequested
;
3157 wVersionRequested
= MAKEWORD(2,0);
3159 if ( WSAStartup( wVersionRequested
, &wsaData
) == 0 )
3161 gethostname(name
,sizeof(name
));
3164 this->Hostname
= name
;
3168 struct utsname unameInfo
;
3169 int errorFlag
= uname(&unameInfo
);
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
;
3184 /** Return true if the machine is 64 bits */
3185 bool SystemInformationImplementation::Is64Bits()
3187 return (sizeof(void*) == 8);
3190 } // namespace @KWSYS_NAMESPACE@