//------------------------------------------------------------------------------
// CpuInfo.cpp
#include "CpuInfo.h"
#include <sstream>
using namespace std;
CpuInfo::CpuInfo(const bool fCpuSpeed/* = true*/)
{
m_strCpuSpeed = "0";
determineCpuInfo();
if (fCpuSpeed)
{
determineCpuSpeed();
}
}
CpuInfo::CpuInfo(const CpuInfo& source)
{
assign(source);
}
CpuInfo& CpuInfo::operator=(const CpuInfo& right)
{
if (this != &right)
{
assign(right);
}
return (*this);
}
CpuInfo::~CpuInfo()
{
// nothing to do yet
}
void CpuInfo::determineCpuInfo(void)
{
SYSTEM_INFO stCpuInfo;
GetSystemInfo(&stCpuInfo);
ostringstream os;
os << stCpuInfo.dwNumberOfProcessors << ends;
m_strNumProcessors = os.str();
determineCpuStats(stCpuInfo.wProcessorArchitecture);
}
// this is pretty straight forward. as long as it's a fairly-recent processor, we'll
// try to get the speed. first, though, we set the priority to high ... so that
// we'll get a greater chance of getting the correct speed.
// the current algorithm just goes until it gets two results in a row that match.
// a better approach may be to take two or three readings and average them.
void CpuInfo::determineCpuSpeed(void)
{
const int MAX_TRIES = 10;
DWORD dwSpeed = 0;
DWORD dwTestValue = UINT_MAX;
int nNumTimes = 0;
if ( ((m_cpuStats.getVendor() == CpuStats::VENDOR_INTEL) && (m_cpuStats.getFamily() > 4)) ||
((m_cpuStats.getVendor() == CpuStats::VENDOR_AMD) && (m_cpuStats.getFamily() > 5)) )
{
DWORD dwStartingPriority = GetPriorityClass(GetCurrentProcess());
SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS);
//--------------------------------------------------------
// Find the first two similarities up to ten times.
// This should be a maximum of five seconds.
//
while ((dwSpeed != dwTestValue) && (nNumTimes < MAX_TRIES))
{
dwTestValue = dwSpeed;
dwSpeed = calculateCpuSpeed();
nNumTimes++;
}
SetPriorityClass(GetCurrentProcess(), dwStartingPriority);
//--------------------------------------------------------
// If we've done ten queries and STILL don't have a
// valid reading, don't change anything so the speed will
// be Unknown. This if below should almost always evauluate
// to TRUE.
//
if (nNumTimes != MAX_TRIES)
{
ostringstream os;
os << dwSpeed << " MHz" << ends;
m_strCpuSpeed = os.str();
}
}
}
void CpuInfo::assign(const CpuInfo& source)
{
m_cpuStats = source.m_cpuStats;
m_strCpuSpeed = source.m_strCpuSpeed;
m_strNumProcessors = source.m_strNumProcessors;
}
void CpuInfo::determineCpuStats(WORD wProcessorArchitecture)
{
// make sure the cpu knows CPUID
if (!determineCpuId())
{
return;
}
m_cpuStats.setKnowsCpuId(true);
DWORD dwHighestCpuId = determineHighestCpuId();
switch (dwHighestCpuId)
{
case 2: // intel cpu's find cache information here
determineIntelCacheInfo();
// no break;
case 1: // x86 cpu's do processor identification here
determineCpuIdentification();
break;
case 0: // don't do anything funky; return
default:
return;
}
if (m_cpuStats.getVendor() == CpuStats::VENDOR_INTEL)
{
determineOldIntelName();
}
DWORD dwLargestExtendedFeature = determineLargestExtendedFeature();
switch (dwLargestExtendedFeature)
{
case AMD_L2CACHE_FEATURE:
determineAmdL2CacheInfo();
// no break;
case AMD_L1CACHE_FEATURE:
determineAmdL1CacheInfo();
// no break;
case NAMESTRING_FEATURE:
determineNameString();
// no break;
case AMD_EXTENDED_FEATURE:
determineExtendedFeature();
break;
case 0: // if they have no feature, do nothing
default:
break;
}
}
bool CpuInfo::determineCpuId(void)
{
int fKnowsCpuId = 0;
__asm
{
pushfd // save EFLAGS to stack.
pop eax // store EFLAGS in EAX.
mov edx, eax // save in EBX for testing later.
xor eax, 0200000h // switch bit 21.
push eax // copy "changed" value to stack.
popfd // save "changed" EAX to EFLAGS.
pushfd
pop eax
xor eax, edx // See if bit changeable.
jnz short has_cpuid // if so, mark
mov fKnowsCpuId, 0 // if not, put 0
jmp done
has_cpuid:
mov fKnowsCpuId, 1 // put 1
done:
}
return ((bool)fKnowsCpuId);
}
DWORD CpuInfo::determineHighestCpuId(void)
{
DWORD dwHighest = 0;
char szTemp[16] = {0};
__asm
{
mov eax, 0
CPUID
test eax,eax // 0 is highest function, then don't query more info
jz no_features
mov dwHighest, eax // highest supported instruction
mov DWORD PTR [szTemp+0],ebx // Stash the manufacturer string for later
mov DWORD PTR [szTemp+4],edx
mov DWORD PTR [szTemp+8],ecx
no_features:
}
if (dwHighest != 0)
{
string strVendorId = szTemp;
m_cpuStats.setVendorId(strVendorId);
}
return (dwHighest);
}
void CpuInfo::determineCpuIdentification(void)
{
DWORD dwSignature = 0;
DWORD dwFeatureEbx = 0;
DWORD dwFeatureEcx = 0 ;
DWORD dwFeatures = 0;
__asm
{
mov eax, 1
CPUID
mov [dwSignature], eax // store CPU signature
mov [dwFeatureEbx], ebx
mov [dwFeatureEcx], ecx
mov [dwFeatures], edx // features
}
m_cpuStats.setSignature(dwSignature);
m_cpuStats.setFeatureEbx(dwFeatureEbx);
m_cpuStats.setFeatureEcx(dwFeatureEcx);
m_cpuStats.setFeatures(dwFeatures);
}
DWORD CpuInfo::determineLargestExtendedFeature(void)
{
DWORD dwHighest = 0;
__asm
{
mov eax, 0x80000000
CPUID
mov dwHighest, eax
}
return (dwHighest);
}
void CpuInfo::determineExtendedFeature(void)
{
DWORD dwExtendedFeatures = 0;
__asm
{
mov eax, 0x80000001
CPUID
mov dwExtendedFeatures, edx
}
m_cpuStats.setExtendedFeatures(dwExtendedFeatures);
}
void CpuInfo::determineNameString(void)
{
char szName[64] = {0};
__asm
{
mov eax, 0x80000002
CPUID
mov DWORD PTR [szName+0],eax
mov DWORD PTR [szName+4],ebx
mov DWORD PTR [szName+8],ecx
mov DWORD PTR [szName+12],edx
mov eax, 0x80000003
CPUID
mov DWORD PTR [szName+16],eax
mov DWORD PTR [szName+20],ebx
mov DWORD PTR [szName+24],ecx
mov DWORD PTR [szName+28],edx
mov eax, 0x80000004
CPUID
mov DWORD PTR [szName+32],eax
mov DWORD PTR [szName+36],ebx
mov DWORD PTR [szName+40],ecx
mov DWORD PTR [szName+44],edx
}
m_cpuStats.setName(szName);
}
void CpuInfo::determineAmdL1CacheInfo(void)
{
DWORD dwEax = 0;
DWORD dwEbx = 0;
DWORD dwEcx = 0;
DWORD dwEdx = 0;
__asm
{
mov eax, 0x80000005
CPUID
mov dwEax, eax
mov dwEbx, ebx
mov dwEcx, ecx
mov dwEdx, edx
}
m_cpuStats.setCacheEax(dwEax);
m_cpuStats.setCacheEbx(dwEbx);
m_cpuStats.setCacheEcx(dwEcx);
m_cpuStats.setCacheEdx(dwEdx);
}
void CpuInfo::determineAmdL2CacheInfo(void)
{
DWORD dwEax = 0;
DWORD dwEbx = 0;
DWORD dwEcx = 0;
DWORD dwEdx = 0;
__asm
{
mov