From 67ccd6b909d28ab84c77acecdfee927337489cc2 Mon Sep 17 00:00:00 2001 From: Alexander Momchilov Date: Tue, 8 Dec 2020 23:12:44 -0500 Subject: [PATCH] Unhardcode tick-to-ms conversion Division by 100000.0 worked because `sysconf(_SC_CLK_TCK)` happened to be 100. By unhardcoding: 1) It becomes more clear what this 100000.0 figure comes from. 2) It protects against bugs in the case `sysconf(_SC_CLK_TCK)` ever changes. --- darwin/DarwinProcess.c | 20 +++++++++----------- darwin/DarwinProcess.h | 2 +- darwin/DarwinProcessList.c | 10 +++++++++- darwin/Platform.c | 16 ++++++++++++++-- darwin/Platform.h | 2 ++ 5 files changed, 35 insertions(+), 15 deletions(-) diff --git a/darwin/DarwinProcess.c b/darwin/DarwinProcess.c index 94bb193e..15eff08c 100644 --- a/darwin/DarwinProcess.c +++ b/darwin/DarwinProcess.c @@ -292,23 +292,21 @@ void DarwinProcess_setFromKInfoProc(Process* proc, const struct kinfo_proc* ps, proc->updated = true; } -void DarwinProcess_setFromLibprocPidinfo(DarwinProcess* proc, DarwinProcessList* dpl) { +void DarwinProcess_setFromLibprocPidinfo(DarwinProcess* proc, DarwinProcessList* dpl, double time_interval) { struct proc_taskinfo pti; if (sizeof(pti) == proc_pidinfo(proc->super.pid, PROC_PIDTASKINFO, 0, &pti, sizeof(pti))) { - if (0 != proc->utime || 0 != proc->stime) { - uint64_t diff = (pti.pti_total_system - proc->stime) - + (pti.pti_total_user - proc->utime); + uint64_t total_existing_time = proc->stime + proc->utime; + uint64_t total_current_time = pti.pti_total_system + pti.pti_total_user; - proc->super.percent_cpu = (double)diff * (double)dpl->super.cpuCount * Platform_timebaseToNS - / ((double)dpl->global_diff * 100000.0); - -// fprintf(stderr, "%f %llu %llu %llu %llu %llu\n", proc->super.percent_cpu, -// proc->stime, proc->utime, pti.pti_total_system, pti.pti_total_user, dpl->global_diff); -// exit(7); + if (total_existing_time && 1e-6 < time_interval) { + uint64_t total_time_diff = total_current_time - total_existing_time; + proc->super.percent_cpu = ((double)total_time_diff / time_interval) * 100.0; + } else { + proc->super.percent_cpu = 0.0; } - proc->super.time = (pti.pti_total_system + pti.pti_total_user) / 10000000; + proc->super.time = total_current_time / 10000000; proc->super.nlwp = pti.pti_threadnum; proc->super.m_virt = pti.pti_virtual_size / ONE_K; proc->super.m_resident = pti.pti_resident_size / ONE_K; diff --git a/darwin/DarwinProcess.h b/darwin/DarwinProcess.h index 21da34af..f87dd182 100644 --- a/darwin/DarwinProcess.h +++ b/darwin/DarwinProcess.h @@ -34,7 +34,7 @@ bool Process_isThread(const Process* this); void DarwinProcess_setFromKInfoProc(Process* proc, const struct kinfo_proc* ps, bool exists); -void DarwinProcess_setFromLibprocPidinfo(DarwinProcess* proc, DarwinProcessList* dpl); +void DarwinProcess_setFromLibprocPidinfo(DarwinProcess* proc, DarwinProcessList* dpl, double time_interval); /* * Scan threads for process state information. diff --git a/darwin/DarwinProcessList.c b/darwin/DarwinProcessList.c index dec98270..e5ca5ad8 100644 --- a/darwin/DarwinProcessList.c +++ b/darwin/DarwinProcessList.c @@ -21,6 +21,7 @@ in the source distribution for its full text. #include "CRT.h" #include "DarwinProcess.h" +#include "Platform.h" #include "ProcessList.h" #include "zfs/openzfs_sysctl.h" #include "zfs/ZfsArcStats.h" @@ -158,6 +159,11 @@ void ProcessList_delete(ProcessList* this) { free(this); } +static double ticksToNanoseconds(const double ticks) { + const double nanos_per_sec = 1e9; + return ticks / (double) Platform_clockTicksPerSec * Platform_timebaseToNS * nanos_per_sec; +} + void ProcessList_goThroughEntries(ProcessList* super, bool pauseProcessUpdate) { DarwinProcessList* dpl = (DarwinProcessList*)super; bool preExisting = true; @@ -185,6 +191,8 @@ void ProcessList_goThroughEntries(ProcessList* super, bool pauseProcessUpdate) { } } + const double time_interval = ticksToNanoseconds(dpl->global_diff) / (double) dpl->super.cpuCount; + /* Clear the thread counts */ super->kernelThreads = 0; super->userlandThreads = 0; @@ -204,7 +212,7 @@ void ProcessList_goThroughEntries(ProcessList* super, bool pauseProcessUpdate) { proc = (DarwinProcess*)ProcessList_getProcess(super, ps[i].kp_proc.p_pid, &preExisting, DarwinProcess_new); DarwinProcess_setFromKInfoProc(&proc->super, &ps[i], preExisting); - DarwinProcess_setFromLibprocPidinfo(proc, dpl); + DarwinProcess_setFromLibprocPidinfo(proc, dpl, time_interval); // Disabled for High Sierra due to bug in macOS High Sierra bool isScanThreadSupported = ! ( CompareKernelVersion(17, 0, 0) >= 0 && CompareKernelVersion(17, 5, 0) < 0); diff --git a/darwin/Platform.c b/darwin/Platform.c index a0ea6721..a4ed4647 100644 --- a/darwin/Platform.c +++ b/darwin/Platform.c @@ -10,16 +10,18 @@ in the source distribution for its full text. #include "Platform.h" +#include #include #include - -#include +#include #include +#include #include #include #include "ClockMeter.h" #include "CPUMeter.h" +#include "CRT.h" #include "DarwinProcessList.h" #include "DateMeter.h" #include "DateTimeMeter.h" @@ -112,6 +114,8 @@ const MeterClass* const Platform_meterTypes[] = { double Platform_timebaseToNS = 1.0; +long Platform_clockTicksPerSec = -1; + void Platform_init(void) { // Check if we can determine the timebase used on this system. // If the API is unavailable assume we get our timebase in nanoseconds. @@ -122,6 +126,14 @@ void Platform_init(void) { #else Platform_timebaseToNS = 1.0; #endif + + // Determine the number of clock ticks per second + errno = 0; + Platform_clockTicksPerSec = sysconf(_SC_CLK_TCK); + + if (errno || Platform_clockTicksPerSec < 1) { + CRT_fatalError("Unable to retrieve clock tick rate"); + } } void Platform_done(void) { diff --git a/darwin/Platform.h b/darwin/Platform.h index 3e0369b8..623063b2 100644 --- a/darwin/Platform.h +++ b/darwin/Platform.h @@ -24,6 +24,8 @@ extern const ProcessField Platform_defaultFields[]; extern double Platform_timebaseToNS; +extern long Platform_clockTicksPerSec; + extern const SignalItem Platform_signals[]; extern const unsigned int Platform_numberOfSignals;