Skip to content

Commit

Permalink
Draft of darwin/GPUMeter (htop-dev#1597)
Browse files Browse the repository at this point in the history
  • Loading branch information
aestriplex committed Feb 5, 2025
1 parent ab455a2 commit 89ed546
Show file tree
Hide file tree
Showing 7 changed files with 183 additions and 44 deletions.
2 changes: 2 additions & 0 deletions Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -357,6 +357,7 @@ darwin_platform_headers = \
darwin/Platform.h \
darwin/PlatformHelpers.h \
darwin/ProcessField.h \
darwin/GPUMeter.h \
generic/fdstat_sysctl.h \
generic/gettime.h \
generic/hostname.h \
Expand All @@ -372,6 +373,7 @@ darwin_platform_sources = \
darwin/DarwinMachine.c \
darwin/DarwinProcess.c \
darwin/DarwinProcessTable.c \
darwin/GPUMeter.c \
generic/fdstat_sysctl.c \
generic/gettime.c \
generic/hostname.c \
Expand Down
45 changes: 45 additions & 0 deletions XUtils.c
Original file line number Diff line number Diff line change
Expand Up @@ -389,6 +389,51 @@ size_t countDigits(size_t n, size_t base) {
return res;
}

int humanTimeUnit(char* buffer, size_t size, unsigned long long int value) {

if (value < 1000)
return xSnprintf(buffer, size, "%3lluns", value);

if (value < 10000)
return xSnprintf(buffer, size, "%1llu.%1lluus", value / 1000, (value % 1000) / 100);

value /= 1000;

if (value < 1000)
return xSnprintf(buffer, size, "%3lluus", value);

if (value < 10000)
return xSnprintf(buffer, size, "%1llu.%1llums", value / 1000, (value % 1000) / 100);

value /= 1000;

if (value < 1000)
return xSnprintf(buffer, size, "%3llums", value);

if (value < 10000)
return xSnprintf(buffer, size, "%1llu.%1llus", value / 1000, (value % 1000) / 100);

value /= 1000;

if (value < 600)
return xSnprintf(buffer, size, "%3llus", value);

value /= 60;

if (value < 600)
return xSnprintf(buffer, size, "%3llum", value);

value /= 60;

if (value < 96)
return xSnprintf(buffer, size, "%3lluh", value);

value /= 24;

return xSnprintf(buffer, size, "%3llud", value);
}


#if !defined(HAVE_BUILTIN_CTZ)
// map a bit value mod 37 to its position
static const uint8_t mod37BitPosition[] = {
Expand Down
2 changes: 2 additions & 0 deletions XUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,8 @@ double sumPositiveValues(const double* array, size_t count);
appear often, hence it uses a O(log(n)) time algorithm. */
size_t countDigits(size_t n, size_t base);

int humanTimeUnit(char* buffer, size_t size, unsigned long long int value);

/* Returns the number of trailing zero bits */
#if defined(HAVE_BUILTIN_CTZ)
static inline unsigned int countTrailingZeros(unsigned int x) {
Expand Down
112 changes: 112 additions & 0 deletions darwin/GPUMeter.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
/*
htop - GPUMeter.c
(C) 2023 htop dev team
Released under the GNU GPLv2+, see the COPYING file
in the source distribution for its full text.
*/

#include "config.h" // IWYU pragma: keep

#include "darwin/GPUMeter.h"

#include "CRT.h"
#include "RichString.h"
#include "darwin/DarwinMachine.h"
#include "XUtils.h"

#include <IOKit/IOKitLib.h>
#include <CoreFoundation/CoreFoundation.h>


static size_t activeMeters;
static double totalUsage = 0;
static io_service_t service;

struct EngineData {
const char* key;
unsigned long long int timeDiff;
};

static const int GPUMeter_attributes[] = {
GPU_ENGINE_1,
};

bool GPUMeter_active(void) {
return activeMeters > 0;
}


static void GPUMeter_updateValues(Meter* this) {
char* buffer = this->txtBuffer;
size_t size = sizeof(this->txtBuffer);
CFMutableDictionaryRef properties = NULL;
CFDictionaryRef perfStats;
CFNumberRef deviceUtil;
int written, device = 0;

if (!service) {
/* GPU not found, early exit */
this->values[0] = device;
written = snprintf(buffer, size, "N/A");
METER_BUFFER_CHECK(buffer, size, written);
return;
}

if (IORegistryEntryCreateCFProperties(service, &properties, kCFAllocatorDefault, kNilOptions) != KERN_SUCCESS) {
return;
}

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

assert(perfStats && CFGetTypeID(perfStats) == CFDictionaryGetTypeID());

deviceUtil = CFDictionaryGetValue(perfStats, CFSTR("Device Utilization %"));
if (deviceUtil) CFNumberGetValue(deviceUtil, kCFNumberIntType, &device);

CFRelease(properties);

this->values[0] = (double) device;
totalUsage = (double) device;
written = snprintf(buffer, size, "%.1f", totalUsage);
METER_BUFFER_CHECK(buffer, size, written);
METER_BUFFER_APPEND_CHR(buffer, size, '%');
}

static void GPUMeter_display(const Object* cast ATTR_UNUSED, RichString* out) {
char buffer[50];
int written;

RichString_writeAscii(out, CRT_colors[METER_TEXT], ":");
written = xSnprintf(buffer, sizeof(buffer), "%4.1f", totalUsage);
RichString_appendnAscii(out, CRT_colors[METER_VALUE], buffer, written);
}

static void GPUMeter_init(Meter* this ATTR_UNUSED) {
service = IOServiceGetMatchingService(kIOMainPortDefault, IOServiceMatching("IOGPU"));
activeMeters++;
}

static void GPUMeter_done(Meter* this ATTR_UNUSED) {
IOObjectRelease(service);
assert(activeMeters > 0);
activeMeters--;
}

const MeterClass GPUMeter_class = {
.super = {
.extends = Class(Meter),
.delete = Meter_delete,
.display = GPUMeter_display,
},
.init = GPUMeter_init,
.done = GPUMeter_done,
.updateValues = GPUMeter_updateValues,
.defaultMode = BAR_METERMODE,
.supportedModes = METERMODE_DEFAULT_SUPPORTED,
.maxItems = 1,
.total = 100.0,
.attributes = GPUMeter_attributes,
.name = "GPU",
.uiName = "GPU usage",
.caption = "GPU"
};
19 changes: 19 additions & 0 deletions darwin/GPUMeter.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#ifndef HEADER_GPUMeter
#define HEADER_GPUMeter
/*
htop - GPUMeter.h
(C) 2023 htop dev team
Released under the GNU GPLv2+, see the COPYING file
in the source distribution for its full text.
*/

#include <stdbool.h>

#include "Meter.h"


extern const MeterClass GPUMeter_class;

bool GPUMeter_active(void);

#endif /* HEADER_GPUMeter */
2 changes: 2 additions & 0 deletions darwin/Platform.c
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ in the source distribution for its full text.
#include "UptimeMeter.h"
#include "darwin/DarwinMachine.h"
#include "darwin/PlatformHelpers.h"
#include "darwin/GPUMeter.h"
#include "generic/fdstat_sysctl.h"
#include "zfs/ZfsArcMeter.h"
#include "zfs/ZfsCompressedArcMeter.h"
Expand Down Expand Up @@ -145,6 +146,7 @@ const MeterClass* const Platform_meterTypes[] = {
&NetworkIOMeter_class,
&FileDescriptorMeter_class,
&BlankMeter_class,
&GPUMeter_class,
NULL
};

Expand Down
45 changes: 1 addition & 44 deletions linux/GPUMeter.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ in the source distribution for its full text.
#include "CRT.h"
#include "RichString.h"
#include "linux/LinuxMachine.h"
#include "XUtils.h"


static size_t activeMeters;
Expand All @@ -38,50 +39,6 @@ static const int GPUMeter_attributes[] = {
GPU_RESIDUE,
};

static int humanTimeUnit(char* buffer, size_t size, unsigned long long int value) {

if (value < 1000)
return xSnprintf(buffer, size, "%3lluns", value);

if (value < 10000)
return xSnprintf(buffer, size, "%1llu.%1lluus", value / 1000, (value % 1000) / 100);

value /= 1000;

if (value < 1000)
return xSnprintf(buffer, size, "%3lluus", value);

if (value < 10000)
return xSnprintf(buffer, size, "%1llu.%1llums", value / 1000, (value % 1000) / 100);

value /= 1000;

if (value < 1000)
return xSnprintf(buffer, size, "%3llums", value);

if (value < 10000)
return xSnprintf(buffer, size, "%1llu.%1llus", value / 1000, (value % 1000) / 100);

value /= 1000;

if (value < 600)
return xSnprintf(buffer, size, "%3llus", value);

value /= 60;

if (value < 600)
return xSnprintf(buffer, size, "%3llum", value);

value /= 60;

if (value < 96)
return xSnprintf(buffer, size, "%3lluh", value);

value /= 24;

return xSnprintf(buffer, size, "%3llud", value);
}

static void GPUMeter_updateValues(Meter* this) {
const Machine* host = this->host;
const LinuxMachine* lhost = (const LinuxMachine*) host;
Expand Down

0 comments on commit 89ed546

Please sign in to comment.