Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions darwin/DarwinProcess.c
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ const ProcessFieldData Process_fields[LAST_PROCESSFIELD] = {
[PROC_EXE] = { .name = "EXE", .title = "EXE ", .description = "Basename of exe of the process from /proc/[pid]/exe", .flags = 0, },
[CWD] = { .name = "CWD", .title = "CWD ", .description = "The current working directory of the process", .flags = PROCESS_FLAG_CWD, },
[TRANSLATED] = { .name = "TRANSLATED", .title = "T ", .description = "Translation info (T translated, N native)", .flags = 0, },
[GPU_TIME] = { .name = "GPU_TIME", .title = "GPU TIME", .description = "Total GPU time", .flags = PROCESS_FLAG_GPU, .defaultSortDesc = true, },
[GPU_PERCENT] = { .name = "GPU_PERCENT", .title = " GPU% ", .description = "Percentage of the GPU time the process used in the last sampling", .flags = PROCESS_FLAG_GPU, .defaultSortDesc = true, },
};

Process* DarwinProcess_new(const Machine* host) {
Expand All @@ -77,14 +79,18 @@ void Process_delete(Object* cast) {

static void DarwinProcess_rowWriteField(const Row* super, RichString* str, ProcessField field) {
const DarwinProcess* dp = (const DarwinProcess*) super;
const Machine* host = (const Machine*) super->host;

bool coloring = host->settings->highlightMegabytes;
char buffer[256]; buffer[255] = '\0';
int attr = CRT_colors[DEFAULT_COLOR];
size_t n = sizeof(buffer) - 1;

switch (field) {
// add Platform-specific fields here
case TRANSLATED: xSnprintf(buffer, n, "%c ", dp->translated ? 'T' : 'N'); break;
case GPU_PERCENT: Row_printPercentage(dp->gpu_percent, buffer, n, 5, &attr); break;
case GPU_TIME: Row_printNanoseconds(str, dp->gpu_time, coloring); return;
default:
Process_writeField(&dp->super, str, field);
return;
Expand All @@ -101,6 +107,15 @@ static int DarwinProcess_compareByKey(const Process* v1, const Process* v2, Proc
// add Platform-specific fields here
case TRANSLATED:
return SPACESHIP_NUMBER(p1->translated, p2->translated);
case GPU_PERCENT: {
int r = compareRealNumbers(p1->gpu_percent, p2->gpu_percent);
if (r)
return r;

return SPACESHIP_NUMBER(p1->gpu_time, p2->gpu_time);
}
case GPU_TIME:
return SPACESHIP_NUMBER(p1->gpu_time, p2->gpu_time);
default:
return Process_compareByKey_Base(v1, v2, key);
}
Expand Down
8 changes: 8 additions & 0 deletions darwin/DarwinProcess.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ in the source distribution for its full text.


#define PROCESS_FLAG_TTY 0x00000100
#define PROCESS_FLAG_GPU 0x00000200

typedef struct DarwinProcess_ {
Process super;
Expand All @@ -22,6 +23,13 @@ typedef struct DarwinProcess_ {
uint64_t stime;
bool taskAccess;
bool translated;

/* Total GPU time used in nano seconds */
uint64_t gpu_time;
/* Total GPU time used in nano seconds in the last scan */
uint64_t gpu_time_last;
/* GPU utilization in percent */
float gpu_percent;
} DarwinProcess;

extern const ProcessClass DarwinProcess_class;
Expand Down
14 changes: 14 additions & 0 deletions darwin/DarwinProcessTable.c
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,8 @@ void ProcessTable_delete(Object* cast) {
void ProcessTable_goThroughEntries(ProcessTable* super) {
const Machine* host = super->super.host;
const DarwinMachine* dhost = (const DarwinMachine*) host;
const Settings* settings = host->settings;
const ScreenSettings* ss = settings->ss;
DarwinProcessTable* dpt = (DarwinProcessTable*) super;
bool preExisting = true;
struct kinfo_proc* ps;
Expand Down Expand Up @@ -122,12 +124,24 @@ void ProcessTable_goThroughEntries(ProcessTable* super) {
DarwinProcess_scanThreads(proc, dpt);
}

// Reset GPU time/percent
if (ss->flags & PROCESS_FLAG_GPU) {
proc->gpu_time_last = proc->gpu_time;
proc->gpu_time = 0;
proc->gpu_percent = 0.0F;
}

super->totalTasks += 1;

if (!preExisting) {
ProcessTable_add(super, &proc->super);
}
}

// Get GPU usage info for processes if requested
if (ss->flags & PROCESS_FLAG_GPU) {
Platform_setGPUProcesses(dpt);
}

free(ps);
}
83 changes: 83 additions & 0 deletions darwin/Platform.c
Original file line number Diff line number Diff line change
Expand Up @@ -798,3 +798,86 @@ static void Platform_getOSRelease(char* buffer, size_t bufferLen) {
const char* Platform_getRelease(void) {
return Generic_unameRelease(Platform_getOSRelease);
}

// GPU I/O registry dump: https://archive.org/download/ioreg-gpu/ioreg-gpu.log
void Platform_setGPUProcesses(DarwinProcessTable* dpt) {
const Machine* host = dpt->super.super.host;
const DarwinMachine* dhost = (const DarwinMachine*) host;

if (!dhost->GPUService)
return;

io_iterator_t iterator;
if (IORegistryEntryGetChildIterator(dhost->GPUService, kIOServicePlane, &iterator) != KERN_SUCCESS)
return;

io_registry_entry_t entry;
while ((entry = IOIteratorNext(iterator))) {
io_struct_inband_t buffer;
uint32_t size = sizeof(buffer);
if (IORegistryEntryGetProperty(entry, "IOUserClientCreator", buffer, &size) != KERN_SUCCESS)
goto cleanup;

int pid;
if (sscanf(buffer, "pid %d", &pid) != 1)
goto cleanup;
Comment on lines +816 to +823
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please provide some (short) inline documentation about what the contents of buffers are expected to be. Reference to corresponding documentation is fine; throw a copy to archive.org if possible in case the link breaks.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By the way, I don't like the assumption that pid_t always has the same width as int. It's better to sscanf into an int-type buffer then cast to pid_t when using.


uint64_t gpuTime = 0;
DarwinProcess* dp = (DarwinProcess*) ProcessTable_findProcess(&dpt->super, (pid_t) pid);
if (!dp)
goto cleanup;

if (IOObjectConformsTo(entry, "IOGPUDeviceUserClient")) {
CFArrayRef appUsage = IORegistryEntryCreateCFProperty(entry, CFSTR("AppUsage"), kCFAllocatorDefault, kNilOptions);
if (!appUsage)
goto cleanup;

assert(CFGetTypeID(appUsage) == CFArrayGetTypeID());

// Sum up the GPU time for all command queues for this client
size_t count = CFArrayGetCount(appUsage);
for (size_t i = 0; i < count; ++i) {
CFDictionaryRef appUsageEntry = CFArrayGetValueAtIndex(appUsage, i);
assert(CFGetTypeID(appUsageEntry) == CFDictionaryGetTypeID());

CFNumberRef accumulatedGPUTimeRef = CFDictionaryGetValue(appUsageEntry, CFSTR("accumulatedGPUTime"));
if (!accumulatedGPUTimeRef)
continue;

uint64_t accumulatedGPUTime = 0;
CFNumberGetValue(accumulatedGPUTimeRef, kCFNumberLongLongType, &accumulatedGPUTime);

gpuTime += accumulatedGPUTime;
Comment thread
BenBE marked this conversation as resolved.
}

CFRelease(appUsage);
} else if (IOObjectConformsTo(entry, "IOAccelSubmitter2")) {
CFNumberRef accumulatedGPUTimeRef = IORegistryEntryCreateCFProperty(entry, CFSTR("accumulatedGPUTime"), kCFAllocatorDefault, kNilOptions);
if (!accumulatedGPUTimeRef)
goto cleanup;

uint64_t accumulatedGPUTime = 0;
CFNumberGetValue(accumulatedGPUTimeRef, kCFNumberLongLongType, &accumulatedGPUTime);

gpuTime += accumulatedGPUTime;
Comment thread
BenBE marked this conversation as resolved.

CFRelease(accumulatedGPUTimeRef);
} else {
goto cleanup;
}

dp->gpu_time += gpuTime;

// Only calculate GPU percent if we have a previous sample, and the GPU time has increased
if (dp->gpu_time > dp->gpu_time_last && dp->gpu_time_last > 0) {
uint64_t gputimeDelta = saturatingSub(dp->gpu_time, dp->gpu_time_last);
uint64_t monotonicTimeDelta = host->monotonicMs - host->prevMonotonicMs;
dp->gpu_percent = 100.0F * gputimeDelta / (1000 * 1000) / monotonicTimeDelta;
}

cleanup:
IOObjectRelease(entry);
}

IOObjectRelease(iterator);
}
2 changes: 2 additions & 0 deletions darwin/Platform.h
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,8 @@ static inline void Platform_getHostname(char* buffer, size_t size) {

const char* Platform_getRelease(void);

void Platform_setGPUProcesses(DarwinProcessTable* dpt);

static inline const char* Platform_getFailedState(void) {
return NULL;
}
Expand Down
2 changes: 2 additions & 0 deletions darwin/ProcessField.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ in the source distribution for its full text.

#define PLATFORM_PROCESS_FIELDS \
TRANSLATED = 100, \
GPU_TIME = 101, \
GPU_PERCENT = 102, \
\
DUMMY_BUMP_FIELD = CWD, \
// End of list
Expand Down
2 changes: 1 addition & 1 deletion linux/LinuxProcess.c
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ const ProcessFieldData Process_fields[LAST_PROCESSFIELD] = {
#ifdef SCHEDULER_SUPPORT
[SCHEDULERPOLICY] = { .name = "SCHEDULERPOLICY", .title = "SCHED ", .description = "Current scheduling policy of the process", .flags = PROCESS_FLAG_SCHEDPOL, },
#endif
[GPU_TIME] = { .name = "GPU_TIME", .title = "GPU_TIME ", .description = "Total GPU time", .flags = PROCESS_FLAG_LINUX_GPU, .defaultSortDesc = true, },
[GPU_TIME] = { .name = "GPU_TIME", .title = "GPU TIME", .description = "Total GPU time", .flags = PROCESS_FLAG_LINUX_GPU, .defaultSortDesc = true, },
[GPU_PERCENT] = { .name = "GPU_PERCENT", .title = " GPU% ", .description = "Percentage of the GPU time the process used in the last sampling", .flags = PROCESS_FLAG_LINUX_GPU, .defaultSortDesc = true, },
};

Expand Down
Loading