【问题标题】:How to determine the hardware (CPU and RAM) on a machine?如何确定机器上的硬件(CPU 和 RAM)?
【发布时间】:2010-10-25 10:42:35
【问题描述】:

我正在开发一个跨平台分析套件,并希望在每次运行的报告中添加有关机器 CPU(架构/时钟速度/内核)和 RAM(总数)的信息。目前我需要针对Windows和Unix,所以我需要从两个平台获取这些信息的方法,有什么线索吗?

编辑:感谢您的出色回答,现在我得到了 CPU 架构、CPU 内核数和总内存,但我仍然缺乏 CPU 的时钟速度,对此有什么想法吗?

【问题讨论】:

  • __cpuinfo 产生的字符串包括时钟速度
  • @bsruth 谢谢,现在我看到它确实在品牌字符串中

标签: c++ c memory hardware cpu


【解决方案1】:

这是在 Windows 机器上获取所需信息的一种方法。我从一个实际项目中复制并粘贴了它,并进行了一些小的修改,因此请随时清理它以使其更有意义。

        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;

有关详细信息,请参阅GetSystemInfoGlobalMemoryStatusEx__cpuid。虽然我没有包含,但是你也可以通过 GetSystemInfo 函数判断操作系统是 32 位还是 64 位。

【讨论】:

    【解决方案2】:

    在 Windows 上,您可以使用 GlobalMemoryStatusEx 来获取实际 RAM 的数量。

    处理器信息可通过GetSystemInfo获取。

    【讨论】:

      【解决方案3】:

      对于带有 GCC 的 Linux,您可以使用非常相似的解决方案,例如 windows。您需要包含&lt;cpuid.h&gt;,并且您需要根据this 修改__cpuid() 方法的输入。

      #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;
      

      【讨论】:

        【解决方案4】:

        在 Windows 上确定 CPU 时钟速度:

        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;
        }
        

        【讨论】:

          【解决方案5】:

          CPU 很简单。使用cpuid 指令。我将留下其他海报以找到一种便携式方法来确定系统有多少 RAM。 :-)

          对于特定于 Linux 的方法,您可以访问 /proc/meminfo(和 /proc/cpuinfo,如果您懒得解析 cpuid 响应)。

          【讨论】:

          • 并且大概如何在没有任何类型的 CPUID 指令的处理器上找到 CPU 信息? ;)(CPUID 甚至会告诉你处理器包有多少个内核吗?)
          • 阅读:intel.com/design/processor/applnots/241618.htm(简短回答:是)。如果 CPU 太旧而无法支持 cpuid,那么所有的赌注都将失败,但现代系统没有这个问题。
          • 我在想并不是所有的系统都基于 i386 架构处理器。 (尽管知道这可能不是 OP 感兴趣的情况)
          • Bleh,全世界都是 x86/x64! :-P(开个玩笑。)
          【解决方案6】:

          在 Linux 上,您可以解析 /proc/cpuinfo(包含每个处理器的信息块)和 /proc/meminfo(包含各种通用内存统计信息,包括 MemTotal)。

          【讨论】:

            【解决方案7】:

            我来晚了,但这是我的贡献。 我尝试采用更现代的 C++ 方法。

                #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://docs.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;
                }
            

            这是我自己的这个函数的结果: "Intel(R) Core(TM) i7-8700K CPU @ 3.70GHz"

            老实说,这样的事情还没有标准化真的很烦人......

            【讨论】:

            • 正在寻找方法来获取 MSInfo 中显示的 CPU 信息,但我找不到方法。我在 30 秒内完成了复制、粘贴和工作。这个功能很漂亮,谢谢!!
            【解决方案8】:

            在 Solaris 上:

            -为了记忆

             prtconf | grep Memory
            

            -对于 CPU

             psrinfo -v | grep MHz
            

            【讨论】:

              【解决方案9】:

              http://en.wikipedia.org/wiki/CPUID 可能对 CPUID 有帮助

              【讨论】:

                【解决方案10】:

                OP 想要一个可在 Windows 和 Linux 之间移植的 CPU 时钟速度计算例程。给你:

                #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));
                }
                

                显然这仅适用于 x86/x64,并且它依赖于 TSC 以与 CPU 相同的速度计数。如果你做了奇怪的超频事情,例如在我的身上,我超频了 FSB,但降低了倍频器以保持核心时钟符合规范,因此 TSC 将以 FSB 乘以最大倍频器计数,这太快了。

                为了获得最佳结果,在运行 GetClockSpeed() 之前,我建议您运行一个反 SpeedStep 循环,例如

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

                尼尔

                【讨论】:

                  【解决方案11】:

                  bsruth 在此页面上使用 __cpuid 循环不必要地通过不需要的扩展函数的最接受的答案。 如果您只需要知道处理器品牌字符串,则无需查询 0x80000000。

                  维基百科有一个很好的示例代码解释: 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);
                  }
                  

                  这是我想出的直接将其转换为 c++ 中的 std::string 的版本

                  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;
                  

                  此版本适用于 linux,但对于使用 __cpuid 的 windows 应该不难理解

                  【讨论】:

                    【解决方案12】:

                    我已经编写了一些使用 WMI 服务来获得最大时钟速度的代码,我知道它是 VB.net 但它显示了这个想法:

                    ''' <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 参考:http://msdn.microsoft.com/en-us/library/Aa394239

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

                    【讨论】:

                      【解决方案13】:

                      对于 Windows 和 Win32 C++ 项目:

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

                      上面的 URL 和包含的文章演示了在 Windows 上检索 CPU 信息的 3 种不同方法。源代码在文章的底部,写得很好,并且包含三个有用的类,您可以从您的 Win32 C++ 代码中调用它们。

                      【讨论】:

                        猜你喜欢
                        • 2016-01-17
                        • 1970-01-01
                        • 1970-01-01
                        • 2021-11-17
                        • 1970-01-01
                        • 1970-01-01
                        • 1970-01-01
                        • 1970-01-01
                        相关资源
                        最近更新 更多