Sign in to follow this  

Figuring out system specs.

This topic is 3461 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

How does one figure out the system specs of the machine the game is running on? I mean memory, processor, gfx card... I'm sure there must be some pretty standard way of doing it, but google doesn't seem too willing to lend a hand on the matter. For my specific problem, it's for making a logging library, with no external dependencies, so no directx, opengl or any such libraries help me out, as I'm aiming for something lightweigh and portable. And working in C++. For now it's sufficient that it works on windows. Thanks in advance to anyone who can answer me! -- Ying

Share this post


Link to post
Share on other sites
I guess he meant programatically getting the system specs...
I don't know of a standard way in C++, I think you will have to dig through OS specific APIs to find what you need. Good luck

Share this post


Link to post
Share on other sites
You can forget about it being portable. Any approach would be platform specific.

For instance, in windows you can use GetSystemInfo() to get Number of, Brand, and Type of installed processors.

For this and more, take a look at Windows' System Information Functions.

Available video memory could be obtained through DirectX, e.g., IDirect3DDevice9::GetAvailableTextureMem(), or maybe there's a generic Win32 function for that as well.

Share this post


Link to post
Share on other sites
Didn't valve make something like this available as part of their Steamworks SDK or something? I'm pretty sure they've made the engine they use to perform their hardware surveys available in some way.

Share this post


Link to post
Share on other sites
Thanks everyone for your feedback!
I'll have a look at the windows specific functions Mike, and the link to the files of your SysID_rev22 lib is down Rick.

Thanks again everyone!

Share this post


Link to post
Share on other sites
You can use "dxdiag". If you go to start run, you'll now what I mean (if never used it before).

So what you can do, is have your application run that, and print it to a txt file. From there you can search for "CPU Speed:" and the grab the numbers after that etc.

Share this post


Link to post
Share on other sites
Quote:
Original post by dpadam450
You can use "dxdiag". If you go to start run, you'll now what I mean (if never used it before).

So what you can do, is have your application run that, and print it to a txt file. From there you can search for "CPU Speed:" and the grab the numbers after that etc.


Now THATS the info i was looking for! But exactly how do i extract the info in the dxdiag application to a txt file? And I've been playing arround with it and, at least in vista the thing is REALLY slow, takes several seconds of the specs to load, and another extra 3 seconds or so to print them using the "save info" button on the app. Not the best idea for a game log which might crash in milliseconds.

I'd appreciate more info on the matter! Thanks!

Share this post


Link to post
Share on other sites
I would think twice about the dxdiag approach (dxdiag /t specs.txt), TBH. It's slow (like you said) and requires a temporary file for something that should be able to be obtained programmatically, and it requires you to parse a text file, that might change format between revisions.

Share this post


Link to post
Share on other sites
Look up reading a text file in c++. <fstream> library is good

ifstream input; //input file stream
input.open("specs.txt");

string reading;
int speed;
input >> reading; //read a string from txt file
input >> speed; //read an integer from txt file

For the guys that suggested against it. You can do:

ifstream input; //input file stream
input.open("specs.txt");

if(!input)//meaning if you already ran dxdiag previously, dont run it again
{
run_dxdiag();
}

Share this post


Link to post
Share on other sites
It also doesnt matter if it changes format. Since its text, you can do something like I do:

string to_find;
input >> to_find;
while(to_find != "RAM")
{
input >> to_find;
}
//right here to_find = RAM so just read in an integer now
input >> speed;

while(to_find != "GraphicsVendor") //etc etc
{
}

Share this post


Link to post
Share on other sites
Keep forgetting things. You have to do cmd from start->run

dxdiag [/x outfile] [/t outfile]

In this command, /x sends the data to an XML file, /t sends the data to a text file, and outfile specifies the name and location of the file.


There is a way to use CreateProcess() windows function to invoke dxdiag which is more confusing at this point.

Share this post


Link to post
Share on other sites
...

@dpadam450:
That's the ugliest way of doing things I've ever seen. Might as well use the win32 API since your method is also non-portable. At least you don't have to write a parser that way. I'm sorry if I just ruined a joke at his expense.

Share this post


Link to post
Share on other sites
Critizisim and debate of all the methods is very interesting, but what other solutions have you guys got?
I'm not looking for anything extremely complex, but it's got some basic requirements and just generating the xml file with dxdiag takes bout half to a full second to generate a 150kb file, of which I only need the first 20 lines.

That is not a viable situation, as the log header can't make the system wait half a second for the file to be ready.

Any other alternatives or improvements to make it meet the requirements?

Share this post


Link to post
Share on other sites
From my code:

static const unsigned PROCESSOR_UNKNOWN = 0;
static const unsigned PROCESSOR_AMD = 1;
static const unsigned PROCESSOR_INTEL = 2;

//============================================================================
// Error handler
//============================================================================
static void ErrorBox(const std::string& strError)
{
MessageBoxA(NULL, strError.c_str(), "Error", MB_ICONERROR);
}

//============================================================================
// Read the CPU speed from the registry
//============================================================================
static DWORD ReadCPUSpeedFromRegistry(DWORD dwCPU)
{
HKEY hKey;
DWORD dwSpeed;

// Get the key name
char szKey[256];
_snprintf(szKey, sizeof(szKey),
"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\%d\\", dwCPU);

// Open the key
if(RegOpenKeyExA(HKEY_LOCAL_MACHINE,szKey, 0, KEY_QUERY_VALUE, &hKey) != ERROR_SUCCESS)
{
return 0;
}

// Read the value
DWORD dwLen = 4;
if(RegQueryValueExA(hKey, "~MHz", NULL, NULL, (LPBYTE)&dwSpeed, &dwLen) != ERROR_SUCCESS)
{
RegCloseKey(hKey);
return 0;
}

// Cleanup and return
RegCloseKey(hKey);
return dwSpeed;
}

//============================================================================
// Calculate and log the CPU speed and features
//============================================================================
static void LogCPU()
{
unsigned nHighestFeature;
unsigned nHighestFeatureEx;
int nBuff[4];
char szMan[13];
char szFeatures[256];
unsigned nProcessorType;

// Get CPU manufacturer and highest CPUID
__cpuid(nBuff, 0);
nHighestFeature = (unsigned)nBuff[0];
*(int*)&szMan[0] = nBuff[1];
*(int*)&szMan[4] = nBuff[3];
*(int*)&szMan[8] = nBuff[2];
szMan[12] = 0;
if(strcmp(szMan, "AuthenticAMD") == 0)
nProcessorType = PROCESSOR_AMD;
else if(strcmp(szMan, "GenuineIntel") == 0)
nProcessorType = PROCESSOR_INTEL;
else
nProcessorType = PROCESSOR_UNKNOWN;

// Get highest extended feature
__cpuid(nBuff, 0x80000000);
nHighestFeatureEx = (unsigned)nBuff[0];

// Get processor brand name
if(nHighestFeatureEx >= 0x80000004)
{
char szCPUName[49];
szCPUName[0] = 0;
__cpuid((int*)&szCPUName[0], 0x80000002);
__cpuid((int*)&szCPUName[16], 0x80000003);
__cpuid((int*)&szCPUName[32], 0x80000004);
szCPUName[48] = 0;
for(int i=(int)strlen(szCPUName)-1; i>=0; --i)
{
if(szCPUName[i] == ' ')
szCPUName[i] = '\0';
else
break;
}

ELog::Get().SystemFormat("PERF : CPU: %s (%s)\n", szCPUName, szMan);
}
else
ELog::Get().SystemFormat("PERF : CPU: %s\n", szMan);

// Get CPU features
szFeatures[0] = 0;
if(nHighestFeature >= 1)
{
__cpuid(nBuff, 1);
if(nBuff[3] & 1<<0)
strcat(szFeatures, "FPU ");
if(nBuff[3] & 1<<23)
strcat(szFeatures, "MMX ");
if(nBuff[3] & 1<<25)
strcat(szFeatures, "SSE ");
if(nBuff[3] & 1<<26)
strcat(szFeatures, "SSE2 ");
if(nBuff[2] & 1<<0)
strcat(szFeatures, "SSE3 ");

// Intel specific:
if(nProcessorType == PROCESSOR_INTEL)
{
if(nBuff[2] & 1<<9)
strcat(szFeatures, "SSSE3 ");
if(nBuff[2] & 1<<7)
strcat(szFeatures, "EST ");
}

if(nBuff[3] & 1<<28)
strcat(szFeatures, "HTT ");
}

// AMD specific:
if(nProcessorType == PROCESSOR_AMD)
{
// Get extended features
__cpuid(nBuff, 0x80000000);
if(nHighestFeatureEx >= 0x80000001)
{
__cpuid(nBuff, 0x80000001);
if(nBuff[3] & 1<<31)
strcat(szFeatures, "3DNow! ");
if(nBuff[3] & 1<<30)
strcat(szFeatures, "Ex3DNow! ");
if(nBuff[3] & 1<<22)
strcat(szFeatures, "MmxExt ");
}

// Get level 1 cache size
if(nHighestFeatureEx >= 0x80000005)
{
__cpuid(nBuff, 0x80000005);
ELog::Get().SystemFormat("PERF : L1 cache size: %dK\n", ((unsigned)nBuff[2])>>24);
}
}

// Get cache size
if(nHighestFeatureEx >= 0x80000006)
{
__cpuid(nBuff, 0x80000006);
ELog::Get().SystemFormat("PERF : L2 cache size: %dK\n", ((unsigned)nBuff[2])>>16);
}

// Log features
ELog::Get().SystemFormat("PERF : CPU Features: %s\n", szFeatures);

// Get misc system info
SYSTEM_INFO theInfo;
GetSystemInfo(&theInfo);

// Log number of CPUs and speeds
ELog::Get().SystemFormat("PERF : Number of CPUs: %d\n", theInfo.dwNumberOfProcessors);
for(DWORD i=0; i<theInfo.dwNumberOfProcessors; ++i)
{
DWORD dwCPUSpeed = ReadCPUSpeedFromRegistry(i);
ELog::Get().SystemFormat("PERF : * CPU %d speed: ~%dMHz\n", i, dwCPUSpeed);
}
}

//============================================================================
// Calculate and log the amount of RAM in the machine
//============================================================================
static void LogRAM()
{
// Get memory status
MEMORYSTATUS theStatus;
ZeroMemory(&theStatus,sizeof(theStatus));
theStatus.dwLength = sizeof(theStatus);
GlobalMemoryStatus(&theStatus);

// Log it
DWORD dwRAM = (DWORD)(theStatus.dwTotalPhys/(1024*1024));
if(theStatus.dwTotalPhys != dwRAM*1024*1024)
++dwRAM;
ELog::Get().SystemFormat("PERF : Available physical RAM: %dMB/%dMB\n",
theStatus.dwAvailPhys/(1024*1024), dwRAM);
}

//============================================================================
// Determine OS type
//============================================================================
static void LogOS()
{
char szOS[256];
OSVERSIONINFOEXA osInfo;
SYSTEM_INFO sysInfo;

// Get system info
ZeroMemory(&sysInfo, sizeof(sysInfo));
GetSystemInfo(&sysInfo);

// Get OS version
strcpy(szOS, "PERF : OS: ");
ZeroMemory(&osInfo, sizeof(osInfo));
osInfo.dwOSVersionInfoSize = sizeof(osInfo);
if(!GetVersionExA((OSVERSIONINFOA*)&osInfo))
{
ZeroMemory(&osInfo, sizeof(osInfo));
osInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
GetVersionExA((OSVERSIONINFOA*)&osInfo);
}

// Win 9x
if(osInfo.dwPlatformId == 1)
{
if((osInfo.dwMajorVersion == 4) && (osInfo.dwMinorVersion == 0))
strcat(szOS, "Windows 95 ");
else if((osInfo.dwMajorVersion == 4) && (osInfo.dwMinorVersion == 10))
strcat(szOS, "Windows 98 ");
else if((osInfo.dwMajorVersion == 4) && (osInfo.dwMinorVersion == 90))
strcat(szOS, "Windows ME ");
else
strcat(szOS, "Unknown Windows OS ");
}

// Win NT
else if(osInfo.dwPlatformId == 2)
{
if((osInfo.dwMajorVersion == 4) && (osInfo.dwMinorVersion == 0))
strcat(szOS, "Windows NT 4.0 ");
else if((osInfo.dwMajorVersion == 5) && (osInfo.dwMinorVersion == 0))
strcat(szOS, "Windows 2000 ");
else if((osInfo.dwMajorVersion == 5) && (osInfo.dwMinorVersion == 1))
strcat(szOS, "Windows XP ");
else if((osInfo.dwMajorVersion == 5) && (osInfo.dwMinorVersion == 2))
{
if(GetSystemMetrics(89)) // SM_SERVERR2 == 89
strcat(szOS, "Windows Server 2003 R2 ");
else if((osInfo.wProductType == VER_NT_WORKSTATION) &&
(sysInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64))
{
strcat(szOS, "Windows XP Professional x64 Edition ");
}
else
strcat(szOS, "Windows Server 2003 ");
}
else if((osInfo.dwMajorVersion == 6) && (osInfo.dwMinorVersion == 0))
strcat(szOS, "Windows Vista ");
else
strcat(szOS, "Unknown WinNT OS ");
}

// Unknown
else
strcat(szOS, "Unknown Operating System ");

strcat(szOS, osInfo.szCSDVersion);
strcat(szOS, "\n");

// Log
ELog::Get().SystemLog(szOS);
#if defined(BUILD_X64)
ELog::Get().SystemLog("PERF : Win64 version\n");
#elif defined(_WIN32)
ELog::Get().SystemLog("PERF : Win32 version\n");
#else
ELog::Get().SystemLog("PERF : Unknown version\n");
#endif
}

That logs the CPU speed and type, RAM and OS.

Share this post


Link to post
Share on other sites
Thanks everyone for your help!
I think Evil Steve's code will do the trick nicely, I've read it trough and it's what i was looking for.
Thanks Steve, and thanks again everyone!

Share this post


Link to post
Share on other sites
Yea evil steve has the way that I wish I knew, but I dont think many people know about his code there. I've never explicitely seen an example of how to do it which is why I use dxdiag, which isnt that bad if you only run it once.

As for people saying my code sucks well..your parsing a text file. What else do you want?? Yes, dxdiag is SLOW. Thats why you should only run it the first time a game is played. Then after that, save all the extracted info into a specs file. Then you can simply load from that text file without running dxdiag, and without parsing a bunch of crap.

Share this post


Link to post
Share on other sites
Quote:
if(nHighestFeatureEx >= 0x80000006)

I think this can backfire.. AMD and Intel have little qualms of breaking each others' CPUID subfunctions and/or lying about the maximum number. To be safe, you really have to wrap that call in an if(AMD) block; BTW, Intel reports cache information differently (and better).

Quote:
As for people saying my code sucks well..your parsing a text file. What else do you want?? Yes, dxdiag is SLOW. Thats why you should only run it the first time a game is played. Then after that, save all the extracted info into a specs file. Then you can simply load from that text file without running dxdiag, and without parsing a bunch of crap.

hehe.. what happens when people upgrade their hardware?

Share this post


Link to post
Share on other sites

This topic is 3461 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this