[ACCEPTED]-Programmatically get processor details from Mac OS X-hardware

Accepted answer
Score: 11

Use sysctlbyname rather than sysctl, e.g.

#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)
    return freq;

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

Score: 8

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

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

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

'bus-frequency' and 24 'clock-frequency', and 'timebase-frequency' are 23 all 32-bit integers wrapper in data objects, and 22 must therefore be byte-swapped to interpret 21 here (little-endian i386 machine words), and 20 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 19 reading these via IOKit however, you'll 18 get back a CFDataRef, and can just copy 17 the bytes into your own uint32_t like so:

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

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

.s file:

#ifdef __i386__ || __x86_64__

.macro ENTRY
    .private_extern $0
    .align  4, 0x90

// __private_extern__ unsigned long GetCPUSteppingID( void )
    push        %ebp                // store existing frame pointer
    mov         %esp,%ebp           // make a new frame pointer from stack pointer
#if __x86_64__
    push        %rbx
    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
    mov         %edx,%eax           // %eax is 32-bit arch result register
    pop         %ebx                // restore saved value of %ebx
#if __x86_64__
    pop         %rbx                // restore saved value of %rbx
    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 7 not certain about the x86_64 bit above; in 6 theory what I've typed there will ensure 5 that the same code compiles for 64-bit, and 4 will return a 64-bit value in that case. It 3 will also save/restore the %rbx register, the 2 64-bit version of the %ebx register. Theoretically that 1 will cover all bases.

Score: 5

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

Score: 2

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) {
    std::cout << buffer << '\n';

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

Score: 0

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

More Related questions