Robert Gould
Robert Gould

Reputation: 69883

How to determine the hardware (CPU and RAM) on a machine?

I'm working on a cross platform profiling suite, and would like to add information about the machine's CPU (architecture/clock speed/cores) and RAM(total) to the report of each run. Currently I need to target Windows and Unix, so I need methods to obtain this information from both platforms, any clues?

Edit: Thanks for the great answers, Now I got CPU architecture, CPU number of cores and total Memory, but I'm still lacking a clockspeed for the CPU any ideas for that one?

Upvotes: 22

Views: 48742

Answers (13)

Benjamin Gillhofer
Benjamin Gillhofer

Reputation: 31

The most accepted answer by bsruth on this page using __cpuid loops unnecessarily through not needed extended functions. If all you need to know is the Processor Brand String then there is no need to query 0x80000000.

Wikipedia has a nice explanation with example code: https://en.wikipedia.org/wiki/CPUID#EAX=80000002h,80000003h,80000004h:_Processor_Brand_String

#include <cpuid.h>  // GCC-provided
#include <stdio.h>
#include <stdint.h>

int main(void) {
    uint32_t brand[12];

    if (!__get_cpuid_max(0x80000004, NULL)) {
        fprintf(stderr, "Feature not implemented.");
        return 2;
    }

    __get_cpuid(0x80000002, brand+0x0, brand+0x1, brand+0x2, brand+0x3);
    __get_cpuid(0x80000003, brand+0x4, brand+0x5, brand+0x6, brand+0x7);
    __get_cpuid(0x80000004, brand+0x8, brand+0x9, brand+0xa, brand+0xb);
    printf("Brand: %s\n", brand);
}

and here is the version i came up with to directly convert it to a std::string in c++

std::string CPUBrandString;
CPUBrandString.resize(49);
uint *CPUInfo = reinterpret_cast<uint*>(CPUBrandString.data());
for (uint i=0; i<3; i++)
    __cpuid(0x80000002+i, CPUInfo[i*4+0], CPUInfo[i*4+1], CPUInfo[i*4+2], CPUInfo[i*4+3]);
CPUBrandString.assign(CPUBrandString.data()); // correct null terminator
std::cout << CPUBrandString << std::endl;

this version is for linux, but it shouldn't be too hard to figure out for windows using __cpuid

Upvotes: 2

user8197171
user8197171

Reputation:

I'm very late but here is my contribution. I tried to have a more modern C++ approach.

    #include <intrin.h> // NOTE this header is MSVC specific!
    #include <string>
    #include <array>

    std::string GetCpuInfo()
    {
        // 4 is essentially hardcoded due to the __cpuid function requirements.
        // NOTE: Results are limited to whatever the sizeof(int) * 4 is...
        std::array<int, 4> integerBuffer = {};
        constexpr size_t sizeofIntegerBuffer = sizeof(int) * integerBuffer.size();

        std::array<char, 64> charBuffer = {};

        // The information you wanna query __cpuid for.
        // https://learn.microsoft.com/en-us/cpp/intrinsics/cpuid-cpuidex?view=vs-2019
        constexpr std::array<int, 3> functionIds = {
            // Manufacturer
            //  EX: "Intel(R) Core(TM"
            0x8000'0002,
            // Model
            //  EX: ") i7-8700K CPU @"
            0x8000'0003,
            // Clockspeed
            //  EX: " 3.70GHz"
            0x8000'0004
        };

        std::string cpu;

        for (int id : functionIds)
        {
            // Get the data for the current ID.
            __cpuid(integerBuffer.data(), id);
            
            // Copy the raw data from the integer buffer into the character buffer
            std::memcpy(charBuffer.data(), integerBuffer.data(), sizeofIntegerBuffer);

            // Copy that data into a std::string
            cpu += std::string(charBuffer.data());
        }

        return cpu;
    }

Here was the result of this function for myself: "Intel(R) Core(TM) i7-8700K CPU @ 3.70GHz"

Honestly it's really annoying something like this hasn't been standardized...

Upvotes: 12

Mate Zabo
Mate Zabo

Reputation: 1646

For Linux with GCC you can use a very similar solution like windows. You need to include the <cpuid.h> and you need to modify the input for the __cpuid() method based on this.

#include <cpuid.h>

char CPUBrandString[0x40];
unsigned int CPUInfo[4] = {0,0,0,0};

__cpuid(0x80000000, CPUInfo[0], CPUInfo[1], CPUInfo[2], CPUInfo[3]);
unsigned int nExIds = CPUInfo[0];

memset(CPUBrandString, 0, sizeof(CPUBrandString));

for (unsigned int i = 0x80000000; i <= nExIds; ++i)
{
    __cpuid(i, CPUInfo[0], CPUInfo[1], CPUInfo[2], CPUInfo[3]);

    if (i == 0x80000002)
        memcpy(CPUBrandString, CPUInfo, sizeof(CPUInfo));
    else if (i == 0x80000003)
        memcpy(CPUBrandString + 16, CPUInfo, sizeof(CPUInfo));
    else if (i == 0x80000004)
        memcpy(CPUBrandString + 32, CPUInfo, sizeof(CPUInfo));
}

cout << "CPU Type: " << CPUBrandString << endl;

Upvotes: 10

Cosmic OM...
Cosmic OM...

Reputation: 291

For Windows and Win32 C++ Projects:

http://www.codeguru.com/cpp/w-p/system/hardwareinformation/article.php/c9087/Three-Ways-to-Retrieve-Processor-Information.htm

The above URL and contained article demonstrates 3 different ways to retrieve CPU info on Windows. The source code is at the bottom of the article, is well written, and has three useful classes that you can call from your Win32 C++ code.

Upvotes: 0

Niall Douglas
Niall Douglas

Reputation: 9762

The OP wants a CPU clock speed calculating routine portable between Windows and Linux. Here you go:

#ifdef WIN32
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
typedef unsigned __int64 usCount;
static usCount GetUsCount()
{
    static LARGE_INTEGER ticksPerSec;
    static double scalefactor;
    LARGE_INTEGER val;
    if(!scalefactor)
    {
        if(QueryPerformanceFrequency(&ticksPerSec))
            scalefactor=ticksPerSec.QuadPart/1000000000000.0;
        else
            scalefactor=1;
    }
    if(!QueryPerformanceCounter(&val))
        return (usCount) GetTickCount() * 1000000000;
    return (usCount) (val.QuadPart/scalefactor);
}
#else
#include <sys/time.h>
#include <time.h>
#include <sched.h>
typedef unsigned long long usCount;
static usCount GetUsCount()
{
#ifdef CLOCK_MONOTONIC
    struct timespec ts;
    clock_gettime(CLOCK_MONOTONIC, &ts);
    return ((usCount) ts.tv_sec*1000000000000LL)+ts.tv_nsec*1000LL;
#else
    struct timeval tv;
    gettimeofday(&tv, 0);
    return ((usCount) tv.tv_sec*1000000000000LL)+tv.tv_usec*1000000LL;
#endif
}
#endif
static usCount usCountOverhead, CPUClockSpeed;
#ifdef __GNUC__
#include "x86intrin.h"
#define __rdtsc() __builtin_ia32_rdtsc()
#endif
static usCount GetClockSpeed()
{
  int n;
  usCount start, end, start_tsc, end_tsc;
  if(!usCountOverhead)
  {
    usCount foo=0;
    start=GetUsCount();
    for(n=0; n<1000000; n++)
    {
      foo+=GetUsCount();
    }
    end=GetUsCount();
    usCountOverhead=(end-start)/n;
  }
  start=GetUsCount();
  start_tsc=__rdtsc();
  for(n=0; n<1000; n++)
#ifdef WIN32
    Sleep(0);
#else
    sched_yield();
#endif
  end_tsc=__rdtsc();
  end=GetUsCount();
  return (usCount)((1000000000000.0*(end_tsc-start_tsc))/(end-start-usCountOverhead));
}

Obviously this only works on x86/x64, and it relies on TSC counting at the same speed as the CPU. If you've done weird overclocking things e.g. on mine I overclock the FSB but downrate the multiplier to keep the core clock at spec, so TSC will count at FSB times the maximum multiplier which is too fast.

To get the best results, before running GetClockSpeed() I'd suggest you run an anti-SpeedStep loop e.g.

usCount start;
start=GetUsCount();
while(GetUsCount()-start<3000000000000ULL);
CPUClockSpeed=GetClockSpeed();

Niall

Upvotes: 1

VikingProgrammer
VikingProgrammer

Reputation: 555

I've written some code which uses the WMI service to get the Max Clock Speed, I know it's VB.net but it shows the idea:

''' <summary>
''' Use WMI to get the Clock Speed in Hz
''' </summary>
Public Function GetMaxClockSpeedInHz() As Double
    Dim manObj = New ManagementObject("Win32_Processor.DeviceID='CPU0'")
    manObj.Get()
    GetMaxClockSpeedInHz = Convert.ToInt32(manObj.Properties("MaxClockSpeed").Value)
End Function

Win32_OperatingSystem reference : http://msdn.microsoft.com/en-us/library/Aa394239

WMI Reference : http://msdn.microsoft.com/en-us/library/aa394572(v=VS.85).aspx

Upvotes: 0

Sweeney
Sweeney

Reputation: 672

http://en.wikipedia.org/wiki/CPUID Might help for the CPUID

Upvotes: 1

Robert Gould
Robert Gould

Reputation: 69883

On Windows to determine CPU clock speed:

double CPUSpeed()
{
    wchar_t Buffer[_MAX_PATH];
    DWORD BufSize = _MAX_PATH;
    DWORD dwMHz = _MAX_PATH;
    HKEY hKey;

    // open the key where the proc speed is hidden:
    long lError = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
                                L"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0",
                                0,
                                KEY_READ,
                                &hKey);
    if(lError != ERROR_SUCCESS)
    {// if the key is not found, tell the user why:
        FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
                        NULL,
                        lError,
                        0,
                        Buffer,
                        _MAX_PATH,
                        0);
        wprintf(Buffer);
        return 0;
    }

    // query the key:
    RegQueryValueEx(hKey, L"~MHz", NULL, NULL, (LPBYTE) &dwMHz, &BufSize);
    return (double)dwMHz;
}

Upvotes: 7

bsruth
bsruth

Reputation: 5502

Here is one method for getting the information you want on a Windows machine. I copied and pasted it from an actual project with some minor modifications, so feel free to clean it up to make more sense.

        int CPUInfo[4] = {-1};
        unsigned   nExIds, i =  0;
        char CPUBrandString[0x40];
        // Get the information associated with each extended ID.
        __cpuid(CPUInfo, 0x80000000);
        nExIds = CPUInfo[0];
        for (i=0x80000000; i<=nExIds; ++i)
        {
            __cpuid(CPUInfo, i);
            // Interpret CPU brand string
            if  (i == 0x80000002)
                memcpy(CPUBrandString, CPUInfo, sizeof(CPUInfo));
            else if  (i == 0x80000003)
                memcpy(CPUBrandString + 16, CPUInfo, sizeof(CPUInfo));
            else if  (i == 0x80000004)
                memcpy(CPUBrandString + 32, CPUInfo, sizeof(CPUInfo));
        }
        //string includes manufacturer, model and clockspeed
        cout << "CPU Type: " << CPUBrandString << endl;


        SYSTEM_INFO sysInfo;
        GetSystemInfo(&sysInfo);
        cout << "Number of Cores: " << sysInfo.dwNumberOfProcessors << endl;

        MEMORYSTATUSEX statex;
        statex.dwLength = sizeof (statex);
        GlobalMemoryStatusEx(&statex);
        cout << "Total System Memory: " << (statex.ullTotalPhys/1024)/1024 << "MB" << endl;

For more information, see GetSystemInfo, GlobalMemoryStatusEx and __cpuid. Although I didn't include it, you can also determine if the OS is 32 or 64 bit via the GetSystemInfo function.

Upvotes: 14

Robert Gould
Robert Gould

Reputation: 69883

On Solaris:

-For memory

 prtconf | grep Memory

-For CPU

 psrinfo -v | grep MHz

Upvotes: 1

i_am_jorf
i_am_jorf

Reputation: 54620

On Windows you can use GlobalMemoryStatusEx to get the amount of actual RAM.

Processor information can be obtained via GetSystemInfo.

Upvotes: 10

araqnid
araqnid

Reputation: 133712

On Linux you can parse /proc/cpuinfo (contains a block of info on each processor) and /proc/meminfo (contains a variety of general memory statistics, including MemTotal).

Upvotes: 5

C. K. Young
C. K. Young

Reputation: 223143

The CPU is easy. Use the cpuid instruction. I'll leave other posters to find a portable way to determine how much RAM a system has. :-)

For Linux-specific methods, you can access /proc/meminfo (and /proc/cpuinfo, if you can't be bothered to parse cpuid responses).

Upvotes: 6

Related Questions