简体   繁体   中英

Programmatically get processor details from Mac OS X

My application running on Mac OS X that needs to retrieve details about the machine it is running on to report for system information. One of the items I need is details about the processor(s) installed in the computer.

My code currently works, but is far from an ideal solution, in fact I consider it a bad solution, but I have had no luck in finding a better one.

The information I report currently and after some formatting looks like:

Processor: Intel Core 2 Duo 2.1 GHz, Family 6 Model 23 Stepping 6

All of the info I get is through command-line utilities called from a popen(). The readable part of the processor description is taken from the "system_profiler" command output and the Family, Model, and Stepping values are taken from the "sysctl" command.

These command-line utilities must be getting there information from somewhere. I'm wondering if there is an programmatic interface available to get this same info?


Related:

Use sysctlbyname rather than sysctl , eg

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

You can get a list of the names that can be passed to systctlbyname by looking at the output of sysctl -a from the command line.

You need to look at the IOKit APIs. The IORegistryExplorer application (part of the standard devtools installation) will help you locate what you're looking for.

For instance, on my MacBook Pro, in IORegistryExplorer I select 'IODeviceTree' from the pull-down at the top-left of the window, and I can see two CPUs in the tree view below. Selecting either one gets me the following information:

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

'bus-frequency' and 'clock-frequency', and 'timebase-frequency' are all 32-bit integers wrapper in data objects, and must therefore be byte-swapped to interpret here (little-endian i386 machine words), and work out to the following values:

  • bus-frequency: 1064000000 Hz => 1.064 GHz
  • clock-frequency:2530000000 Hz => 2.53 GHz
  • timebase-frequency: 1000000000 HZ => 1.0 GHz

If you're reading these via IOKit however, you'll get back a CFDataRef, and can just copy the bytes into your own uint32_t like so:

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

Next, you can get processor info using the NXArchInfo() call obtained by including <mach-o/arch.h> . This will return a structure containing cpu type and subtype codes along with C-string names and descriptions. If that doesn't include a stepping ID, the only way I can think of to obtain that (off the top of my head) is via the CPUID instruction. Create a .s and .h file, and put in the following code:

.s file:

#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 file:

#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__ */

Please note that I'm not certain about the x86_64 bit above; in theory what I've typed there will ensure that the same code compiles for 64-bit, and will return a 64-bit value in that case. It will also save/restore the %rbx register, the 64-bit version of the %ebx register. Theoretically that will cover all bases.

sysctl(3) is probably a good place to start. You probably want the stuff defined by the CTL_HW selectors.

If you specifically want CPU information then use cpuid (in C __asm cpuid) instruction. It gives all possible information of a CPU including its family, model, company, number of cores etc. Primarily all APIs use this instruction to retrieve CPU information. You can get detailed information on CPUID on the web, including sample code and tutorials.

A variant of Paul R 's method

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

will directly show something like Intel(R) Core(TM)2 Duo CPU L9400 @ 1.86GHz .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM