Top: adds thread count detection

This commit is contained in:
李通洲
2026-08-31 20:27:22 +08:00
parent 6eef800ea2
commit 4ff931c06f
15 changed files with 113 additions and 33 deletions
+11 -2
View File
@@ -59,6 +59,12 @@ static int compareStartTimeResults(const FFTopProcessResult* a, const FFTopProce
if (a->startTime > b->startTime) return -1;
return (int) (a->pid - b->pid);
}
static int compareThreadsResults(const FFTopProcessResult* a, const FFTopProcessResult* b) {
if (a->threads < b->threads) return 1;
if (a->threads > b->threads) return -1;
return (int) (a->pid - b->pid);
}
// clang-format on
const char* ffDetectTopProcesses(FFTopOptions* options, FFlist* result) {
@@ -67,8 +73,8 @@ const char* ffDetectTopProcesses(FFTopOptions* options, FFlist* result) {
return nullptr;
}
// Memory usage is instantaneous; when neither CPU time nor disk IO counters
// are requested, a single snapshot suffices and no sampling wait is needed.
// Memory usage and thread count are instantaneous; when neither CPU time nor disk IO
// counters are requested, a single snapshot suffices and no sampling wait is needed.
const bool sampleOnce = (options->showTypes & (FF_TOP_TYPE_CPU | FF_TOP_TYPE_DISK)) == 0;
if (sampleOnce) {
@@ -92,6 +98,7 @@ const char* ffDetectTopProcesses(FFTopOptions* options, FFlist* result) {
item->bytesWritten = 0;
item->cpuPercent = 0;
item->startTime = snap->startTime;
item->threads = snap->threads;
ffStrbufInitMove(&item->name, &snap->name);
}
} else {
@@ -141,6 +148,7 @@ const char* ffDetectTopProcesses(FFTopOptions* options, FFlist* result) {
item->bytesWritten = (newItem->bytesWritten - oldItem->bytesWritten) * 1000u / (uint64_t) elapsed;
item->cpuPercent = (double) (newItem->cpuTime - oldItem->cpuTime) / elapsed * 100.0;
item->startTime = newItem->startTime;
item->threads = newItem->threads;
ffStrbufInitMove(&item->name, &oldItem->name);
}
@@ -154,6 +162,7 @@ const char* ffDetectTopProcesses(FFTopOptions* options, FFlist* result) {
: options->sort == FF_TOP_TYPE_DISK_READ ? (void*) compareDiskReadResults
: options->sort == FF_TOP_TYPE_MEMORY ? (void*) compareMemoryResults
: options->sort == FF_TOP_TYPE_START_TIME ? (void*) compareStartTimeResults
: options->sort == FF_TOP_TYPE_THREADS ? (void*) compareThreadsResults
: (void*) compareCpuResults;
ffListSort(result, sizeof(FFTopProcessResult), (void*) compare);
if (result->length > options->nProcesses) {
+2
View File
@@ -10,6 +10,7 @@ typedef struct FFTopProcessResult {
uint64_t bytesRead;
uint64_t bytesWritten;
uint64_t startTime;
uint32_t threads;
uint32_t pid;
} FFTopProcessResult;
@@ -20,6 +21,7 @@ typedef struct FFTopProcessSnapshot {
uint64_t bytesRead; // Physical storage read
uint64_t bytesWritten; // Physical storage written
uint64_t startTime; // Differs between platforms
uint32_t threads;
uint32_t pid;
} FFTopProcessSnapshot;
+8 -1
View File
@@ -5,7 +5,7 @@
#include <sys/sysctl.h>
#include <libproc.h>
const char* ffTopGetProcessSnapshot(FFlist* snapshots, FFTopTypes) {
const char* ffTopGetProcessSnapshot(FFlist* snapshots, FFTopTypes showTypes) {
int request[] = { CTL_KERN, KERN_PROC, KERN_PROC_ALL };
size_t length;
@@ -54,6 +54,13 @@ const char* ffTopGetProcessSnapshot(FFlist* snapshots, FFTopTypes) {
item->bytesRead = rusage.ri_diskio_bytesread;
item->bytesWritten = rusage.ri_diskio_byteswritten;
item->startTime = rusage.ri_proc_start_abstime;
item->threads = 0;
if (showTypes & FF_TOP_TYPE_THREADS) {
struct proc_taskinfo taskInfo;
if (proc_pidinfo(pid, PROC_PIDTASKINFO, 0, &taskInfo, sizeof(taskInfo)) == sizeof(taskInfo)) {
item->threads = (uint32_t) taskInfo.pti_threadnum;
}
}
}
return nullptr;
+2 -1
View File
@@ -6,7 +6,7 @@
#include <sys/sysctl.h>
#include <sys/user.h>
const char* ffTopGetProcessSnapshot(FFlist* snapshots, FFTopTypes) {
const char* ffTopGetProcessSnapshot(FFlist* snapshots, FFTopTypes showTypes) {
int request[] = { CTL_KERN, KERN_PROC, KERN_PROC_PROC };
size_t length;
@@ -51,6 +51,7 @@ const char* ffTopGetProcessSnapshot(FFlist* snapshots, FFTopTypes) {
item->bytesRead = (uint64_t) proc->ki_rusage.ru_inblock * DEV_BSIZE;
item->bytesWritten = (uint64_t) proc->ki_rusage.ru_oublock * DEV_BSIZE;
item->threads = (uint32_t) proc->ki_numthreads;
}
return NULL;
+2 -1
View File
@@ -6,7 +6,7 @@
#include <sys/sysctl.h>
#include <sys/user.h>
const char* ffTopGetProcessSnapshot(FFlist* snapshots, FFTopTypes) {
const char* ffTopGetProcessSnapshot(FFlist* snapshots, FFTopTypes showTypes) {
int request[] = { CTL_KERN, KERN_PROC, KERN_PROC_ALL };
size_t length;
@@ -52,6 +52,7 @@ const char* ffTopGetProcessSnapshot(FFlist* snapshots, FFTopTypes) {
item->bytesRead = (uint64_t) (proc->kp_ru.ru_inblock + proc->kp_lwp.kl_ru.ru_inblock) * DEV_BSIZE;
item->bytesWritten = (uint64_t) (proc->kp_ru.ru_oublock + proc->kp_lwp.kl_ru.ru_oublock) * DEV_BSIZE;
item->threads = (uint32_t) proc->kp_nthreads;
}
return nullptr;
+9 -2
View File
@@ -4,7 +4,7 @@
#include <string.h>
#include <ps.h>
const char* ffTopGetProcessSnapshot(FFlist* snapshots, FFTopTypes) {
const char* ffTopGetProcessSnapshot(FFlist* snapshots, FFTopTypes showTypes) {
struct ps_context* context = nullptr;
if (ps_context_create(getproc(), &context) != 0) {
return "ps_context_create(getproc()) failed";
@@ -24,7 +24,7 @@ const char* ffTopGetProcessSnapshot(FFlist* snapshots, FFTopTypes) {
// Flags that cannot be fetched for some process are simply left unset;
// each field must be checked before use.
if (proc_stat_list_set_flags(list, PSTAT_ARGS | PSTAT_STATE | PSTAT_TASK_BASIC) != 0) {
if (proc_stat_list_set_flags(list, PSTAT_ARGS | PSTAT_STATE | PSTAT_TASK_BASIC | ((showTypes & FF_TOP_TYPE_THREADS) ? PSTAT_NUM_THREADS : 0)) != 0) {
error = "proc_stat_list_set_flags() failed";
goto done;
}
@@ -60,6 +60,13 @@ const char* ffTopGetProcessSnapshot(FFlist* snapshots, FFTopTypes) {
item->cpuTime = 0;
item->memBytes = 0;
item->startTime = 0;
item->threads = 0;
if (showTypes & FF_TOP_TYPE_THREADS) {
if (proc_stat_has(stat, PSTAT_NUM_THREADS)) {
item->threads = (uint32_t) proc_stat_num_threads(stat);
}
}
if (proc_stat_has(stat, PSTAT_TASK_BASIC)) {
const task_basic_info_t info = proc_stat_task_basic_info(stat);
+2 -1
View File
@@ -3,7 +3,7 @@
#include <OS.h>
#include <string.h>
const char* ffTopGetProcessSnapshot(FFlist* snapshots, FFTopTypes) {
const char* ffTopGetProcessSnapshot(FFlist* snapshots, FFTopTypes showTypes) {
int32 cookie = 0;
team_info team;
while (get_next_team_info(&cookie, &team) == B_OK) {
@@ -41,6 +41,7 @@ const char* ffTopGetProcessSnapshot(FFlist* snapshots, FFTopTypes) {
// Storage io counters are not exposed by Haiku; leave them zeroed.
item->bytesRead = 0;
item->bytesWritten = 0;
item->threads = (uint32_t) team.thread_count;
}
return nullptr;
+8 -2
View File
@@ -24,8 +24,6 @@ static bool parseStat(const char* buffer, size_t length, FFTopProcessSnapshot* r
return false;
}
result->cpuTime = 0;
char* p;
for (uint32_t field = 3; field <= 22 /*start time*/; ++field) {
switch (field) {
@@ -43,6 +41,11 @@ static bool parseStat(const char* buffer, size_t length, FFTopProcessSnapshot* r
cursor = p;
break;
case 20: // number of threads
result->threads = (uint32_t) strtoul(cursor, &p, 10);
cursor = p;
break;
case 22: // start time
result->startTime = (uint64_t) strtoull(cursor, &p, 10);
cursor = p;
@@ -128,6 +131,9 @@ const char* ffTopGetProcessSnapshot(FFlist* snapshots, FFTopTypes showTypes) {
auto snapshot = FF_LIST_ADD(FFTopProcessSnapshot, *snapshots);
ffStrbufInit(&snapshot->name);
snapshot->threads = 0;
snapshot->cpuTime = 0;
snapshot->startTime = 0;
if (!parseStat(statBuffer, (size_t) statLength, snapshot)) {
ffStrbufDestroy(&snapshot->name);
+9 -1
View File
@@ -6,7 +6,7 @@
#include <sys/sysctl.h>
#include <errno.h>
const char* ffTopGetProcessSnapshot(FFlist* snapshots, FFTopTypes) {
const char* ffTopGetProcessSnapshot(FFlist* snapshots, FFTopTypes showTypes) {
int request[] = { CTL_KERN, KERN_PROC2, KERN_PROC_ALL, -1, sizeof(struct kinfo_proc2), INT_MAX };
size_t length;
@@ -50,6 +50,14 @@ const char* ffTopGetProcessSnapshot(FFlist* snapshots, FFTopTypes) {
item->bytesRead = (uint64_t) proc->p_uru_inblock * DEV_BSIZE;
item->bytesWritten = (uint64_t) proc->p_uru_oublock * DEV_BSIZE;
item->threads = 0;
if (showTypes & FF_TOP_TYPE_THREADS) {
int lwpRequest[] = { CTL_KERN, KERN_LWP, proc->p_pid, sizeof(struct kinfo_lwp), 0 };
size_t lwpLength = 0;
if (sysctl(lwpRequest, ARRAY_SIZE(lwpRequest), nullptr, &lwpLength, nullptr, 0) == 0) {
item->threads = (uint32_t) (lwpLength / sizeof(struct kinfo_lwp));
}
}
}
return NULL;
+18 -1
View File
@@ -5,7 +5,7 @@
#include <sys/sysctl.h>
#include <kvm.h>
const char* ffTopGetProcessSnapshot(FFlist* snapshots, FFTopTypes) {
const char* ffTopGetProcessSnapshot(FFlist* snapshots, FFTopTypes showTypes) {
kvm_t* kd = kvm_open(nullptr, nullptr, nullptr, KVM_NO_FILES, nullptr);
if (!kd) {
return "kvm_open() failed";
@@ -37,6 +37,23 @@ const char* ffTopGetProcessSnapshot(FFlist* snapshots, FFTopTypes) {
item->startTime = (uint64_t) proc->p_ustart_sec * 1000 + (uint64_t) proc->p_ustart_usec / 1000;
item->bytesRead = (uint64_t) proc->p_uru_inblock * DEV_BSIZE;
item->bytesWritten = (uint64_t) proc->p_uru_oublock * DEV_BSIZE;
item->threads = 0;
}
if (showTypes & FF_TOP_TYPE_THREADS) {
int threadCount = 0;
const struct kinfo_proc* threads = kvm_getprocs(kd,
KERN_PROC_ALL | KERN_PROC_SHOW_THREADS, 0, sizeof(struct kinfo_proc), &threadCount);
if (threads) {
for (uint32_t i = 0; i < snapshots->length; ++i) {
FFTopProcessSnapshot* item = FF_LIST_GET(FFTopProcessSnapshot, *snapshots, i);
for (int j = 0; j < threadCount; ++j) {
if (threads[j].p_pid == (pid_t) item->pid && threads[j].p_tid != -1) {
++item->threads;
}
}
}
}
}
kvm_close(kd);
+1
View File
@@ -60,6 +60,7 @@ const char* ffTopGetProcessSnapshot(FFlist* snapshots, FFTopTypes showTypes) {
item->bytesRead = 0;
item->bytesWritten = 0;
item->threads = (uint32_t) psinfo.pr_nlwp;
if (showTypes & FF_TOP_TYPE_DISK) {
prusage_t usage;
if (ffReadFileDataRelative(subfd, "usage", sizeof(usage), &usage) == (ssize_t) sizeof(usage)) {
+1
View File
@@ -38,6 +38,7 @@ const char* ffTopGetProcessSnapshot(FFlist* snapshots, FFTopTypes) {
item->memBytes = (uint64_t) info->VirtualMemoryCounters.WorkingSetSize;
item->bytesRead = (uint64_t) info->IoCounters.ReadTransferCount;
item->bytesWritten = (uint64_t) info->IoCounters.WriteTransferCount;
item->threads = info->NumberOfThreads;
ffStrbufInitNWS(&item->name, info->ImageName.Length / sizeof(wchar_t), info->ImageName.Buffer);
}
if (info->NextEntryOffset == 0) {