Right way to call `host_processors`

Am I calling this right?

    host_priv_t hostPriv = 0;
    int err = host_get_host_priv_port(mach_host_self(), &hostPriv);
    err = host_processors(hostPriv, &processorList, &processorCount);

host_get_host_priv_port above returns 4 "(os/kern) invalid argument".

Tried with App Sandbox enabled and disabled.

Consider the small test project whose code is at the end [1]. If I run it normally it prints:

% ./Test748948
host_get_host_priv_port failed, kr: 4

But if I run it with privileges it prints:

% sudo ./Test748948
process count: 14

That seems pretty reasonable to me; you can’t get a processor control port from non-privileged code.

A sandboxed app is not able to escalate privileges, so it seems like your current path forward is blocked.

What’s you’re high-level goal here? Why do you intend to do with these processor control ports when you get them?

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

[1] My experience with Mach is that it’s run your tests with C before you start trying to get things to work with Swift. Also, it’s best to test with a simple command-line tool project rather than a full-blown app.


#include <stdio.h>
#include <stdlib.h>
#include <mach/mach.h>

int main(int argc, char **argv) {
    mach_port_t hostPrivPort = MACH_PORT_NULL;
    kern_return_t kr = host_get_host_priv_port(mach_host_self(), &hostPrivPort);
    if (kr != KERN_SUCCESS) {
        fprintf(stderr, "host_get_host_priv_port failed, kr: %d\n", (int) kr);
        exit(1);
    }
    processor_array_t processors = NULL;
    mach_msg_type_number_t processorCount = 0;
    kr = host_processors(hostPrivPort, &processors, &processorCount);
    if (kr != KERN_SUCCESS) {
        fprintf(stderr, "host_processors failed, kr: %d\n", (int) kr);
        exit(1);
    }
    fprintf(stderr, "process count: %d\n", (int) processorCount);
    return 0;
}

What’s you’re high-level goal here? Why do you intend to do with these processor control ports when you get them?

I want to get the CPU usage per processor / core, similar to Activity Monitor's "CPU Usage" window.

OK. I’ll need to escalate privileges then. See BSD Privilege Escalation on macOS.

IMPORTANT You mentioned the App Sandbox, and most folks only sandbox their apps if they plan to deploy via the Mac App Store. If that’s the case, see clause 2.4.5(v) of the App Review Guidelines.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

I see. Is there a path that doesn't involve privilege escalation? I am thinking of using task_threads + thread_info (with THREAD_BASIC_INFO to get cpu_usage) and somehow determine which processor/core the thread is currently assigned to (†) and then accumulate cpu usages per processor/core. This will only account for threads in the current app but for my purposes this would be enough.

(†) - pthread_cpu_number_np doesn't return sensible results for me.

Is there a path that doesn't involve privilege escalation?

I doubt it.

Honestly, you’re straying beyond what I’d consider to be supportable here. It sounds like you’re trying to replicate Activity Monitor’s CPU Usage window in a Mac App Store app, and that presents numerous challenges:

  • Mach APIs, while they are actually APIs, are very low level. My experience is that these APIs are tightly bound to the kernel and thus change behaviour as the kernel changes. For example, CPU usage is hard to quantify in a world of P and E cores, or indeed SMT. These APIs predate such things and thus you’re always looking at this through some level of compatibility goo.

  • Trying to exactly mirror Activity Monitor is not possible to do in a way that’ll be binary compatible in the long term. Activity Monitor is built in to the system, so it evolves as the system evolves to account for new hardware designs.

  • The approach you’ve proposed here is an example of the problem I described in Inferring High-Level Semantics from Low-Level Operations. I don’t support such things.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Right way to call `host_processors`
 
 
Q