Skip to content

Revert "darwin: process' running time should not depend on mach ticks" #1643

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
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
2 changes: 2 additions & 0 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -375,6 +375,8 @@ AC_CHECK_FUNCS([ \
])

if test "$my_htop_platform" = darwin; then
AC_CHECK_FUNCS([mach_timebase_info])

AC_CHECK_FUNCS([host_statistics64], [
AC_CHECK_TYPES([struct vm_statistics64], [], [], [[#include <mach/vm_statistics.h>]])
], [])
Expand Down
4 changes: 2 additions & 2 deletions darwin/DarwinProcess.c
Original file line number Diff line number Diff line change
Expand Up @@ -370,8 +370,8 @@ void DarwinProcess_setFromLibprocPidinfo(DarwinProcess* proc, DarwinProcessTable
const DarwinMachine* dhost = (const DarwinMachine*) proc->super.super.host;

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

if (total_existing_time_ns < total_current_time_ns) {
Expand Down
9 changes: 9 additions & 0 deletions darwin/Platform.c
Original file line number Diff line number Diff line change
Expand Up @@ -148,11 +148,14 @@ const MeterClass* const Platform_meterTypes[] = {
NULL
};

static double Platform_nanosecondsPerMachTick = 1.0;

static double Platform_nanosecondsPerSchedulerTick = -1;

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

bool Platform_init(void) {
Platform_nanosecondsPerMachTick = Platform_calculateNanosecondsPerMachTick();

// Determine the number of scheduler clock ticks per second
errno = 0;
Expand All @@ -168,6 +171,12 @@ bool Platform_init(void) {
return true;
}

// Converts ticks in the Mach "timebase" to nanoseconds.
// See `mach_timebase_info`, as used to define the `Platform_nanosecondsPerMachTick` constant.
uint64_t Platform_machTicksToNanoseconds(uint64_t mach_ticks) {
return (uint64_t) ((double) mach_ticks * Platform_nanosecondsPerMachTick);
}

// Converts "scheduler ticks" to nanoseconds.
// See `sysconf(_SC_CLK_TCK)`, as used to define the `Platform_nanosecondsPerSchedulerTick` constant.
double Platform_schedulerTicksToNanoseconds(const double scheduler_ticks) {
Expand Down
4 changes: 4 additions & 0 deletions darwin/Platform.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ extern const MeterClass* const Platform_meterTypes[];

bool Platform_init(void);

// Converts ticks in the Mach "timebase" to nanoseconds.
// See `mach_timebase_info`, as used to define the `Platform_nanosecondsPerMachTick` constant.
uint64_t Platform_machTicksToNanoseconds(uint64_t mach_ticks);

// Converts "scheduler ticks" to nanoseconds.
// See `sysconf(_SC_CLK_TCK)`, as used to define the `Platform_nanosecondsPerSchedulerTick` constant.
double Platform_schedulerTicksToNanoseconds(const double scheduler_ticks);
Expand Down
34 changes: 34 additions & 0 deletions darwin/PlatformHelpers.c
Original file line number Diff line number Diff line change
Expand Up @@ -86,3 +86,37 @@ bool Platform_isRunningTranslated(void) {
}
return ret;
}

double Platform_calculateNanosecondsPerMachTick(void) {
// Check if we can determine the timebase used on this system.
// If the API is unavailable assume we get our timebase in nanoseconds.
#ifndef HAVE_MACH_TIMEBASE_INFO
return 1.0;
#else
mach_timebase_info_data_t info;

/* WORKAROUND for `mach_timebase_info` giving incorrect values on M1 under Rosetta 2.
* rdar://FB9546856 https://openradar.appspot.com/radar?id=5055988478509056
*
* We don't know exactly what feature/attribute of the M1 chip causes this mistake under Rosetta 2.
* Until we have more Apple ARM chips to compare against, the best we can do is special-case
* the "Apple M1" chip specifically when running under Rosetta 2.
*/

bool isRunningUnderRosetta2 = Platform_isRunningTranslated();

// Kernel version 20.0.0 is macOS 11.0 (Big Sur)
bool isBuggedVersion = Platform_KernelVersionIsBetween((KernelVersion) {20, 0, 0}, (KernelVersion) {999, 999, 999});

if (isRunningUnderRosetta2 && isBuggedVersion) {
// In this case `mach_timebase_info` provides the wrong value, so we hard-code the correct factor,
// as determined from `mach_timebase_info` when the process running natively.
info = (mach_timebase_info_data_t) { .numer = 125, .denom = 3 };
} else {
// No workarounds needed, use the OS-provided value.
mach_timebase_info(&info);
}

return (double)info.numer / (double)info.denom;
#endif
}
4 changes: 4 additions & 0 deletions darwin/PlatformHelpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,12 @@ int Platform_CompareKernelVersion(KernelVersion v);
// lowerBound <= currentVersion < upperBound
bool Platform_KernelVersionIsBetween(KernelVersion lowerBound, KernelVersion upperBound);

double Platform_calculateNanosecondsPerMachTick(void);

void Platform_getCPUBrandString(char* cpuBrandString, size_t cpuBrandStringSize);

bool Platform_isRunningTranslated(void);

double Platform_calculateNanosecondsPerMachTick(void);

#endif
Loading