htop icon indicating copy to clipboard operation
htop copied to clipboard

GPU monitoring (percentage and time) in Darwin/macOS

Open Explorer09 opened this issue 10 months ago • 7 comments

This is a feature ticket, for people who are more familiar with Darwin/macOS to try and implement.

The Activity Monitor app in macOS has GPU Percentage and GPU Time columns for process monitoring. There is also a "GPU History" feature that shows the GPU usage as a graph.

This webpage (from a third party, not Apple) has brief descriptions and screenshots about the GPU monitoring in macOS: https://www.alphr.com/view-gpu-usage-mac/

It might be possible for such feature to be implemented in htop, too.

After #1288, we have GPU monitoring in Linux now. The GPU meter and columns shouldn't be limited to Linux.

Explorer09 avatar Jan 30 '25 16:01 Explorer09

@BenBE cc @Explorer09 It would be great to have that feature in htop. If it's ok for you, I'd like to start thinking about a possible implementation. I would start by separating two aspects of the problem.

  1. GPU model and its overall usage;
  2. GPU utilization by process.

I attach below a sample program that prints the overall GPU usage, which could be a first step to solve the first point, once properly adapted to the htop context. Unfortunately, as far as I know, there is no direct way to solve the second problem, as there is no API to trace this information. I would therefore start with the first point, adding a section (similar to the CPU or RAM usage section) that contains:

  • The model and version of the GPU;
  • The number of cores;
  • Their total GPU core utilization.
#include <stdio.h>
#include <IOKit/IOKitLib.h>
#include <CoreFoundation/CoreFoundation.h>

int main() {
    io_service_t service = IOServiceGetMatchingService(kIOMainPortDefault, IOServiceMatching("IOGPU"));

    if (!service) {
        printf("GPU not found\n");
        return 1;
    }

    CFMutableDictionaryRef properties = NULL;
    if (IORegistryEntryCreateCFProperties(service, &properties, kCFAllocatorDefault, kNilOptions) != KERN_SUCCESS) {
        fprintf(stderr, "Failed to get GPU properties\n");
        IOObjectRelease(service);
        return 1;
    }

    CFDictionaryRef perfStats = CFDictionaryGetValue(properties, CFSTR("PerformanceStatistics"));

    if (perfStats && CFGetTypeID(perfStats) == CFDictionaryGetTypeID()) {
        CFNumberRef rendererUtil, tilerUtil;
        
        rendererUtil = CFDictionaryGetValue(perfStats, CFSTR("Renderer Utilization %"));
        tilerUtil = CFDictionaryGetValue(perfStats, CFSTR("Tiler Utilization %"));

        int renderer, tiler;
        
        if (rendererUtil) CFNumberGetValue(rendererUtil, kCFNumberIntType, &renderer);
        if (tilerUtil) CFNumberGetValue(tilerUtil, kCFNumberIntType, &tiler);

        printf("Renderer Utilization: %d%%\n", renderer);
        printf("Tiler Utilization: %d%%\n", tiler);
    } else {
        printf("PerformanceStatistics not found\n");
    }

    CFRelease(properties);
    IOObjectRelease(service);
}

aestriplex avatar Feb 04 '25 14:02 aestriplex

I added a commit with a draft of the GPU usage meter for macOS. At this point I just replicated the linux/GPUMeter.c and linux/GPUMeter.h. It uses a static service variable that is allocated in the GPUMeter_init and deallocated in GPUMeter_done. If the GPU is not available (e.g. on the old intel Macs), it prints N/A instead of the percentage in the default style view. If you choose another style, it prints 0.0.

@BenBE Do you have any suggestion?

aestriplex avatar Feb 05 '25 14:02 aestriplex

@aestriplex Thank you for your effort.

  1. You can start a pull request so that htop contributors and I can comment on the code easily. GitHub allows reviewing code with comments by code line, but that requires you to start a PR first (you can mark the PR as a draft).

(By the way, you seem to be the first time contributing to htop. Hello and welcome.)

  1. My initial thoughts about your commit: First, I wish the GPUMeter.c and .h files be shared across platforms. Ideally we would move GPUMeter.c and .h from the linux/ sub-directory to the top source directory, and platform specific codes would be called from either <platform>/Platform.c or <platform>/<platform>Machine.c (or maybe <platform>/GPU.c). Do you think you can structure the code like that?

Explorer09 avatar Feb 05 '25 17:02 Explorer09

Unless the GPU stuff isn't too much code, putting things in <platform>/<Platform>Machine.c should be fine.

The BlankMeter should be the last in the list of meters.

IIRC there's a open PR re the time unit display in #1583, thus avoid to touch that code if possible.

When refactoring the GPU meter to the platform-independent code, split the refactoring and the new Darwin implementation to a separate commit.

BenBE avatar Feb 05 '25 18:02 BenBE

Thank you all for your comments, and sorry it took me a while to respond. @Explorer09 Thank you for the welcome message. Ok, I'll move GPUMeter.c and GPUMeter.h from the linux/ sub-directory to the top source directory. And yes, @BenBE I'll extract the logic I introduced into a function and I put it in darwin/DarwinMachine.c.

For what concerns the time unit display code that I moved, I'll bring it back in linux/GPUMeter.c.

@BenBE Ok, I'll split those changes in two separate commit. Once I have the two commits (hopefully tomorrow) I'll open the pull request.

aestriplex avatar Feb 06 '25 17:02 aestriplex

The humanTimeUnit() function is currently used only in the GPU meter, and it's too early to move the function to XUtils.c. Keep it in the GPUMeter.c, please. As for #1583, I can rebase it easily, so there's no need to worry about it right now.

Explorer09 avatar Feb 06 '25 17:02 Explorer09

I further investigated the point 2. made above, that is, the issue of GPU utilization by process. As I mentioned, Apple has not released any public API for this purpose. The question was whether a way could be found to get a good approximation of this value in some other way. After a bit of research and some testing, I came to the conclusion that no, there is no way that is reliable and stable (over time) to get this kind of metric. The best thing in my opinion is simply not to implement it. After all, more open systems offer more information, and this is nothing new (think of metrics regarding systems on Linux; you couldn't do anything similar with launchd on Mac). On the other hand, even tools such as nvtop simply make an estimate of the processes using the GPU and their relative consumption, but if you compare it with Activity Monitor (the only tool that officially supports this feature), the values are very approximate, not to say simply wrong. For my part, I think we could focus on other metrics that macOS makes available to us, some of which are already present in the libraries we are using. I will open an issue with a more detailed list tonight

aestriplex avatar Mar 05 '25 15:03 aestriplex