ohmu
·
2026-10-15
1#include "top.h"
2#include "common/debug.h"
3#include "common/mallocHelper.h"
4
5#include <errno.h>
6#include <string.h>
7
8#include <sys/types.h>
9#include <sys/resource.h>
10#include <sys/sysctl.h>
11#include <sys/user.h>
12
13const char* ffTopGetProcessSnapshot(FFlist* snapshots, [[maybe_unused]] FFTopTypes showTypes) {
14 int request[] = { CTL_KERN, KERN_PROC, KERN_PROC_PROC };
15 size_t length;
16
17 if (sysctl(request, ARRAY_SIZE(request), nullptr, &length, nullptr, 0) != 0) {
18 FF_DEBUG("sysctl({CTL_KERN, KERN_PROC, KERN_PROC_PROC}, nullptr) failed: %s", strerror(errno));
19 return "sysctl({CTL_KERN, KERN_PROC, KERN_PROC_PROC}) failed";
20 }
21
22 // The process table may change between the two sysctl calls; retry with a larger buffer.
23 length += length / 8 + sizeof(struct kinfo_proc);
24 FF_AUTO_FREE struct kinfo_proc* processes = malloc(length);
25 if (sysctl(request, ARRAY_SIZE(request), processes, &length, nullptr, 0) != 0) {
26 FF_DEBUG("sysctl({CTL_KERN, KERN_PROC, KERN_PROC_PROC}, processes) failed: %s", strerror(errno));
27 return "sysctl({CTL_KERN, KERN_PROC, KERN_PROC_PROC}) failed";
28 }
29 uint32_t count = (uint32_t) (length / sizeof(struct kinfo_proc));
30
31 const uint32_t pageSizeShift = instance.state.platform.sysinfo.pageSizeShift;
32
33 for (uint32_t i = 0; i < count; ++i) {
34 const struct kinfo_proc* proc = &processes[i];
35
36 if (proc->ki_flag & P_KPROC) {
37 continue;
38 }
39
40 uint32_t pid = (uint32_t) proc->ki_pid;
41
42 FFTopProcessSnapshot* item = FF_LIST_ADD(FFTopProcessSnapshot, *snapshots);
43
44 ffStrbufInitS(&item->name, proc->ki_comm);
45 item->pid = pid;
46
47 uint64_t userMs = (uint64_t) proc->ki_rusage.ru_utime.tv_sec * 1000 +
48 (uint64_t) proc->ki_rusage.ru_utime.tv_usec / 1000;
49 uint64_t sysMs = (uint64_t) proc->ki_rusage.ru_stime.tv_sec * 1000 +
50 (uint64_t) proc->ki_rusage.ru_stime.tv_usec / 1000;
51 item->cpuTime = userMs + sysMs;
52
53 item->memBytes = (uint64_t) proc->ki_rssize << pageSizeShift;
54
55 item->startTime = (uint64_t) proc->ki_start.tv_sec * 1000 +
56 (uint64_t) proc->ki_start.tv_usec / 1000;
57
58 item->bytesRead = (uint64_t) proc->ki_rusage.ru_inblock * DEV_BSIZE;
59 item->bytesWritten = (uint64_t) proc->ki_rusage.ru_oublock * DEV_BSIZE;
60 item->threads = (uint32_t) proc->ki_numthreads;
61 }
62
63 return NULL;
64}