Skip to content

Commit 2e58de2

Browse files
committed
Bring back conversion of process CPU time on macOS (#1638)
1 parent 7720dbd commit 2e58de2

File tree

6 files changed

+54
-2
lines changed

6 files changed

+54
-2
lines changed

configure.ac

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -413,6 +413,8 @@ return ptr != &ch; /* Should be 0 (exit success) */
413413
CFLAGS=$htop_save_CFLAGS
414414

415415
if test "$my_htop_platform" = darwin; then
416+
AC_CHECK_FUNCS([mach_timebase_info])
417+
416418
AC_CHECK_FUNCS([host_statistics64], [
417419
AC_CHECK_TYPES([struct vm_statistics64], [], [], [[#include <mach/vm_statistics.h>]])
418420
], [])

darwin/DarwinProcess.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -372,8 +372,8 @@ void DarwinProcess_setFromLibprocPidinfo(DarwinProcess* proc, DarwinProcessTable
372372
const DarwinMachine* dhost = (const DarwinMachine*) proc->super.super.host;
373373

374374
uint64_t total_existing_time_ns = proc->stime + proc->utime;
375-
uint64_t user_time_ns = pti.pti_total_user;
376-
uint64_t system_time_ns = pti.pti_total_system;
375+
uint64_t user_time_ns = Platform_machTicksToNanoseconds(pti.pti_total_user);
376+
uint64_t system_time_ns = Platform_machTicksToNanoseconds(pti.pti_total_system);
377377
uint64_t total_current_time_ns = user_time_ns + system_time_ns;
378378

379379
if (total_existing_time_ns < total_current_time_ns) {

darwin/Platform.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,11 +148,15 @@ const MeterClass* const Platform_meterTypes[] = {
148148
NULL
149149
};
150150

151+
static uint64_t Platform_nanosecondsPerMachTickNumer = 1;
152+
static uint64_t Platform_nanosecondsPerMachTickDenum = 1;
153+
151154
static double Platform_nanosecondsPerSchedulerTick = -1;
152155

153156
static mach_port_t iokit_port; // the mach port used to initiate communication with IOKit
154157

155158
bool Platform_init(void) {
159+
Platform_calculateNanosecondsPerMachTick(&Platform_nanosecondsPerMachTickNumer, &Platform_nanosecondsPerMachTickDenum);
156160

157161
// Determine the number of scheduler clock ticks per second
158162
errno = 0;
@@ -168,6 +172,12 @@ bool Platform_init(void) {
168172
return true;
169173
}
170174

175+
// Converts ticks in the Mach "timebase" to nanoseconds.
176+
// See `mach_timebase_info`, as used to define the `Platform_nanosecondsPerMachTick` constant.
177+
uint64_t Platform_machTicksToNanoseconds(uint64_t mach_ticks) {
178+
return (mach_ticks * Platform_nanosecondsPerMachTickNumer) / Platform_nanosecondsPerMachTickDenum;
179+
}
180+
171181
// Converts "scheduler ticks" to nanoseconds.
172182
// See `sysconf(_SC_CLK_TCK)`, as used to define the `Platform_nanosecondsPerSchedulerTick` constant.
173183
double Platform_schedulerTicksToNanoseconds(const double scheduler_ticks) {

darwin/Platform.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,10 @@ extern const MeterClass* const Platform_meterTypes[];
3838

3939
bool Platform_init(void);
4040

41+
// Converts ticks in the Mach "timebase" to nanoseconds.
42+
// See `mach_timebase_info`, as used to define the `Platform_nanosecondsPerMachTick*` constants.
43+
uint64_t Platform_machTicksToNanoseconds(uint64_t mach_ticks);
44+
4145
// Converts "scheduler ticks" to nanoseconds.
4246
// See `sysconf(_SC_CLK_TCK)`, as used to define the `Platform_nanosecondsPerSchedulerTick` constant.
4347
double Platform_schedulerTicksToNanoseconds(const double scheduler_ticks);

darwin/PlatformHelpers.c

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,3 +86,36 @@ bool Platform_isRunningTranslated(void) {
8686
}
8787
return ret;
8888
}
89+
90+
void Platform_calculateNanosecondsPerMachTick(uint64_t* numer, uint64_t* denom) {
91+
// Check if we can determine the timebase used on this system.
92+
// If the API is unavailable assume we get our timebase in nanoseconds.
93+
#ifdef HAVE_MACH_TIMEBASE_INFO
94+
mach_timebase_info_data_t info;
95+
96+
/* WORKAROUND for `mach_timebase_info` giving incorrect values on M1 under Rosetta 2.
97+
* rdar://FB9546856 https://openradar.appspot.com/radar?id=5055988478509056
98+
*
99+
* We don't know exactly what feature/attribute of the M1 chip causes this mistake under Rosetta 2.
100+
* Until we have more Apple ARM chips to compare against, the best we can do is special-case
101+
* the "Apple M1" chip specifically when running under Rosetta 2.
102+
*/
103+
104+
bool isRunningUnderRosetta2 = Platform_isRunningTranslated();
105+
106+
// Kernel version 20.0.0 is macOS 11.0 (Big Sur)
107+
bool isBuggedVersion = Platform_KernelVersionIsBetween((KernelVersion) {20, 0, 0}, (KernelVersion) {999, 999, 999});
108+
109+
if (isRunningUnderRosetta2 && isBuggedVersion) {
110+
// In this case `mach_timebase_info` provides the wrong value, so we hard-code the correct factor,
111+
// as determined from `mach_timebase_info` when the process running natively.
112+
info = (mach_timebase_info_data_t) { .numer = 125, .denom = 3 };
113+
} else {
114+
// No workarounds needed, use the OS-provided value.
115+
mach_timebase_info(&info);
116+
}
117+
118+
*numer = info.numer;
119+
*denom = info.denom;
120+
#endif
121+
}

darwin/PlatformHelpers.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ in the source distribution for its full text.
88
*/
99

1010
#include <stdbool.h>
11+
#include <stdint.h>
1112
#include <sys/types.h>
1213

1314

@@ -29,6 +30,8 @@ int Platform_CompareKernelVersion(KernelVersion v);
2930
// lowerBound <= currentVersion < upperBound
3031
bool Platform_KernelVersionIsBetween(KernelVersion lowerBound, KernelVersion upperBound);
3132

33+
void Platform_calculateNanosecondsPerMachTick(uint64_t* numer, uint64_t* denom);
34+
3235
void Platform_getCPUBrandString(char* cpuBrandString, size_t cpuBrandStringSize);
3336

3437
bool Platform_isRunningTranslated(void);

0 commit comments

Comments
 (0)