【问题标题】:Programmatically get processor details from Mac OS X以编程方式从 Mac OS X 获取处理器详细信息
【发布时间】:2009-05-12 17:03:02
【问题描述】:

我的应用程序在 Mac OS X 上运行,它需要检索有关运行它的机器的详细信息以报告系统信息。我需要的其中一项是有关计算机中安装的处理器的详细信息。

我的代码目前可以运行,但远不是一个理想的解决方案,事实上我认为它是一个糟糕的解决方案,但我没有找到更好的解决方案。

我目前报告的信息以及经过一些格式化后的信息如下:

处理器:Intel Core 2 Duo 2.1 GHz,Family 6 Model 23 Stepping 6

我获得的所有信息都是通过从 popen() 调用的命令行实用程序。处理器描述的可读部分取自“system_profiler”命令输出,Family、Model 和 Stepping 值取自“sysctl”命令。

这些命令行实用程序必须从某个地方获取信息。 我想知道是否有可用的编程接口来获取相同的信息?


相关:

【问题讨论】:

  • 如果有人有答案,也应该将其添加到“相关”链接中......

标签: c++ macos hardware


【解决方案1】:

使用sysctlbyname 而不是sysctl,例如

#include <stdio.h>
#include <stdint.h>
#include <sys/types.h>
#include <sys/sysctl.h>

uint64_t get_cpu_freq(void)
{
    uint64_t freq = 0;
    size_t size = sizeof(freq);

    if (sysctlbyname("hw.cpufrequency", &freq, &size, NULL, 0) < 0)
    {
        perror("sysctl");
    }
    return freq;
}

您可以通过从命令行查看sysctl -a 的输出来获取可以传递给systctlbyname 的名称列表。

【讨论】:

    【解决方案2】:

    您需要查看 IOKit API。 IORegistryExplorer 应用程序(标准 devtools 安装的一部分)将帮助您找到所需内容。

    例如,在我的 MacBook Pro 上,在 IORegistryExplorer 中,我从窗口左上角的下拉菜单中选择“IODeviceTree”,我可以在下面的树视图中看到两个 CPU。选择其中任何一个都会得到以下信息:

    IORegistryExplorer screenshot http://blog.alanquatermain.net/images/IORegistryExplorer-CPUs.png

    'bus-frequency' 和 'clock-frequency' 和 'timebase-frequency' 都是数据对象中的 32 位整数包装器,因此必须在此处进行字节交换才能解释(小端 i386 机器字) ,并计算出以下值:

    • 总线频率:1064000000 Hz => 1.064 GHz
    • 时钟频率:2530000000 Hz => 2.53 GHz
    • 时基频率:1000000000 HZ => 1.0 GHz

    但是,如果您通过 IOKit 读取这些内容,您将返回一个 CFDataRef,并且可以像这样将字节复制到您自己的 uint32_t 中:

    uint32_t bus_frequency = 0;
    CFDataGetBytes( theData, (UInt8 *) &bus_frequency, sizeof(uint32_t) );
    

    接下来,您可以使用通过包含&lt;mach-o/arch.h&gt; 获得的NXArchInfo() 调用来获取处理器信息。这将返回一个包含 cpu 类型和子类型代码以及 C 字符串名称和描述的结构。如果这不包括步进 ID,那么我能想到的唯一方法(在我的脑海中)是通过 CPUID 指令。创建一个 .s 和 .h 文件,并输入以下代码:

    .s 文件:

    #ifdef __i386__ || __x86_64__
    
    .macro ENTRY
        .text
        .private_extern $0
        .align  4, 0x90
    $0:
    .endmacro
    
    // __private_extern__ unsigned long GetCPUSteppingID( void )
    ENTRY _GetCPUSteppingID
        push        %ebp                // store existing frame pointer
        mov         %esp,%ebp           // make a new frame pointer from stack pointer
    #if __x86_64__
        push        %rbx
    #endif
        push        %ebx                // we save %ebx because the cpuid instruction
                                        // will overwrite it, and it's expected
                                        // to be unchanged in the caller after
                                        // calling another function
        movl        $1,%eax             // fetch cpu info
        cpuid                           // stepping-id is in low 4 bits of %edx now
        and         $0x0000000f,%edx    // clear out everything we don't want
    #if __x86_64__
        mov         %edx,%rax           // %rax is 64-bit arch result register
    #else
        mov         %edx,%eax           // %eax is 32-bit arch result register
    #endif
        pop         %ebx                // restore saved value of %ebx
    #if __x86_64__
        pop         %rbx                // restore saved value of %rbx
    #endif
        leave                           // restores prior stack frame from %ebp
        ret                             // returns to caller
    
    #endif // __i386__ || __x86_64__
    

    .h 文件:

    #ifndef __GET_STEPPING_ID__
    #define __GET_STEPPING_ID__
    
    /* unsigned long is register-sized on both 32-bit and 64-bit OS X */
    __private_extern__ unsigned long GetSteppingID( void );
    
    #endif /* __GET_STEPPING_ID__ */
    

    请注意,我不确定上面的 x86_64 位;从理论上讲,我在那里输入的内容将确保相同的代码编译为 64 位,并且在这种情况下将返回一个 64 位的值。它还将保存/恢复 %rbx 寄存器,即 %ebx 寄存器的 64 位版本。 理论上将涵盖所有基础。

    【讨论】:

      【解决方案3】:

      sysctl(3) 可能是一个不错的起点。你可能想要CTL_HW 选择器定义的东西。

      【讨论】:

      • 我记得使用您提到的 CTL_HW 选择器查看 sysctl() 方法,但它似乎没有提供我现在得到的 Family、Model 和 Stepping 整数值,我认为它只提供了一个非常通用的 x86 类型的处理器描述。不过 sysctlbyname() 可能会有更好的运气。我不确定我是否曾经仔细观察过。我将调查并报告我的发现。谢谢!
      • 您可以使用 syscctlnametomib 提取可用于 sysctl 的系列、型号和步进的数字。它比 sysctlbyname 快大约 3 倍。
      【解决方案4】:

      Paul R 方法的变体

      #include <iostream>
      #include <stdio.h>
      #include <stdint.h>
      #include <sys/types.h>
      #include <sys/sysctl.h>
      
      void show_cpu_info(void)
      {
          char buffer[1024];
          size_t size=sizeof(buffer);
          if (sysctlbyname("machdep.cpu.brand_string", &buffer, &size, NULL, 0) < 0) {
              perror("sysctl");
          }
          std::cout << buffer << '\n';
      }
      

      会直接显示Intel(R) Core(TM)2 Duo CPU L9400 @ 1.86GHz之类的东西。

      【讨论】:

        【解决方案5】:

        如果您特别想要 CPU 信息,请使用 cpuid(在 C 中 __asm cpuid)指令。它提供了 CPU 的所有可能信息,包括其系列、型号、公司、内核数量等。主要所有 API 都使用此指令来检索 CPU 信息。您可以在网上获取有关 CPUID 的详细信息,包括示例代码和教程。

        【讨论】:

          猜你喜欢
          • 2018-12-29
          • 1970-01-01
          • 1970-01-01
          • 2016-09-06
          • 2014-10-15
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-03-27
          相关资源
          最近更新 更多