From 8232f344936251056d59938980ce8d92062234ea Mon Sep 17 00:00:00 2001 From: Matheus Date: Wed, 2 Oct 2024 21:46:31 -0300 Subject: [PATCH] timekeeper: ticks_per_us (mhz) -> hz --- kernel-src/arch/x86-64/hpet.c | 8 +++--- kernel-src/arch/x86-64/kvmclock.c | 2 +- kernel-src/arch/x86-64/tsc.c | 14 +++++---- kernel-src/include/kernel/timekeeper.h | 2 +- kernel-src/sys/timekeeper.c | 39 ++++++++++++++------------ 5 files changed, 35 insertions(+), 30 deletions(-) diff --git a/kernel-src/arch/x86-64/hpet.c b/kernel-src/arch/x86-64/hpet.c index 2c7dde71..c7118251 100644 --- a/kernel-src/arch/x86-64/hpet.c +++ b/kernel-src/arch/x86-64/hpet.c @@ -89,7 +89,7 @@ static timekeeper_source_info_t *hpet_init(void) { struct acpi_hpet *table; MUTEX_ACQUIRE(&init_mutex, false); - if (timekeeper_source_info.ticks_per_us) { + if (timekeeper_source_info.hz) { // already initialized by someone else goto leave; } @@ -107,9 +107,9 @@ static timekeeper_source_info_t *hpet_init(void) { hpet_private.hpet = (void *)((uintptr_t)hpet_private.hpet + page_offset); uint64_t capabilities = read64(HPET_REG_CAPS); - timekeeper_source_info.ticks_per_us = 1000000000 / HPET_CAP_FSPERTICK(capabilities); - printf("hpet%lu: %lu ticks per us (%lu fs per tick)\n", table->number, timekeeper_source_info.ticks_per_us, HPET_CAP_FSPERTICK(capabilities)); - __assert(timekeeper_source_info.ticks_per_us); + timekeeper_source_info.hz = 1000000000000000lu / HPET_CAP_FSPERTICK(capabilities); + printf("hpet%lu: %lu ticks per us (%lu hz)\n", table->number, timekeeper_source_info.hz, HPET_CAP_FSPERTICK(capabilities)); + __assert(timekeeper_source_info.hz); write64(HPET_REG_CONFIG, 0); write64(HPET_REG_COUNTER, 0); diff --git a/kernel-src/arch/x86-64/kvmclock.c b/kernel-src/arch/x86-64/kvmclock.c index 56334846..7b7a70b5 100644 --- a/kernel-src/arch/x86-64/kvmclock.c +++ b/kernel-src/arch/x86-64/kvmclock.c @@ -47,7 +47,7 @@ static timekeeper_source_info_t *kvm_timer_init(void) { timekeeper_source_info_t *timekeeper_source_info = alloc(sizeof(timekeeper_source_info_t)); __assert(timekeeper_source_info); - timekeeper_source_info->ticks_per_us = 1000; // each tick in the kvm timer system_time field is 1 ns + timekeeper_source_info->hz = 1000000000; // each tick in the kvm timer system_time field is 1 ns void *virtual_address = alloc(sizeof(kvm_timer_info_t)); __assert(virtual_address); __assert(((uintptr_t)virtual_address % KVM_TIMER_SYSTEM_TIME_ALIGNMENT) == 0); diff --git a/kernel-src/arch/x86-64/tsc.c b/kernel-src/arch/x86-64/tsc.c index 116cd6f4..3477ef0b 100644 --- a/kernel-src/arch/x86-64/tsc.c +++ b/kernel-src/arch/x86-64/tsc.c @@ -21,7 +21,9 @@ static bool tsc_probe(void) { } static MUTEX_DEFINE(init_mutex); -static time_t ticks_per_us; +// keeping this here in a multisocket machine could possibly result in completely wrong +// tsc measurements for the other sokets. disable the tsc in these using the "notsc" commandline option. +static time_t hz; static timekeeper_source_info_t *tsc_init(void) { MUTEX_ACQUIRE(&init_mutex, false); @@ -32,7 +34,7 @@ static timekeeper_source_info_t *tsc_init(void) { timekeeper_source_info->private = current_cpu(); - if (ticks_per_us) + if (hz) goto leave; bool need_calibration = false; @@ -50,17 +52,17 @@ static timekeeper_source_info_t *tsc_init(void) { uint64_t core_denominator = cpuid_results.eax; uint64_t tsc_frequency = core_frequency * core_numerator / core_denominator; - ticks_per_us = tsc_frequency / 1000000; + hz = tsc_frequency; } calibrate: if (need_calibration) { - ticks_per_us = arch_hpet_calibrate_tsc(200) / 1000; - __assert(ticks_per_us); + hz = arch_hpet_calibrate_tsc(200) * 1000; + __assert(hz); } leave: - timekeeper_source_info->ticks_per_us = ticks_per_us; + timekeeper_source_info->hz = hz; MUTEX_RELEASE(&init_mutex); return timekeeper_source_info; } diff --git a/kernel-src/include/kernel/timekeeper.h b/kernel-src/include/kernel/timekeeper.h index 4e38d60e..3d4e09ae 100644 --- a/kernel-src/include/kernel/timekeeper.h +++ b/kernel-src/include/kernel/timekeeper.h @@ -7,7 +7,7 @@ #define TIMEKEEPER_SOURCE_FLAGS_EARLY 1 // can be used as an early timer typedef struct { - time_t ticks_per_us; + time_t hz; void *private; } timekeeper_source_info_t; diff --git a/kernel-src/sys/timekeeper.c b/kernel-src/sys/timekeeper.c index 98427c29..2f278747 100644 --- a/kernel-src/sys/timekeeper.c +++ b/kernel-src/sys/timekeeper.c @@ -17,17 +17,16 @@ timespec_t timekeeper_timefromboot(void) { time_t ticks = current_cpu()->timekeeper_source->ticks(current_cpu()->timekeeper_source_info); time_t base_ticks = current_cpu()->timekeeper_source_base_ticks; - time_t ticks_per_us = current_cpu()->timekeeper_source_info->ticks_per_us; + time_t hz = current_cpu()->timekeeper_source_info->hz; time_t tick_offset = current_cpu()->timekeeper_source_tick_offset; interrupt_loweripl(old_ipl); timespec_t ts; ticks = ticks - base_ticks + tick_offset; - time_t us_passed = ticks / ticks_per_us; - ts.s = us_passed / 1000000; - ts.ns = (us_passed * 1000) % 1000000000; + ts.s = ticks / hz; + ts.ns = (ticks % hz) / (hz / 1000000) * 1000; return ts; } @@ -46,8 +45,8 @@ static MUTEX_DEFINE(sync_mutex); static volatile bool sync_go_ahead; static volatile int cpus_waiting; static volatile int cpus_done; -static volatile time_t sync_ticks; -static volatile time_t sync_ticks_per_us; +static volatile time_t sync_sec; +static volatile time_t sync_usec; static void timekeeper_sync_isr(isr_t *, context_t *) { // taking interrupts here could possibly add an undetermined amount of latency, which is bad @@ -55,13 +54,15 @@ static void timekeeper_sync_isr(isr_t *, context_t *) { // try to get the tick code into the cache current_cpu()->timekeeper_source->ticks(current_cpu()->timekeeper_source_info); + time_t hz = current_cpu()->timekeeper_source_info->hz; + time_t mhz = hz / 1000000; __atomic_fetch_add(&cpus_waiting, 1, __ATOMIC_SEQ_CST); while (sync_go_ahead == false) asm(""); current_cpu()->timekeeper_source_base_ticks = current_cpu()->timekeeper_source->ticks(current_cpu()->timekeeper_source_info); - current_cpu()->timekeeper_source_tick_offset = sync_ticks / sync_ticks_per_us * current_cpu()->timekeeper_source_info->ticks_per_us; + current_cpu()->timekeeper_source_tick_offset = sync_sec * hz + sync_usec * mhz; __atomic_fetch_add(&cpus_done, 1, __ATOMIC_SEQ_CST); } @@ -88,13 +89,15 @@ void timekeeper_sync(void) { // try to get things into the cache timekeeper_source_t *timekeeper_source = current_cpu()->timekeeper_source; timekeeper_source_info_t *timekeeper_source_info = current_cpu()->timekeeper_source_info; - sync_ticks = timekeeper_source->ticks(timekeeper_source_info) - current_cpu()->timekeeper_source_base_ticks; - sync_ticks_per_us = timekeeper_source_info->ticks_per_us; + time_t hz = timekeeper_source_info->hz; + time_t mhz = hz / 1000000; while (cpus_waiting != arch_smp_cpusawake - 1) CPU_PAUSE(); // for real this time - sync_ticks = timekeeper_source->ticks(timekeeper_source_info) - current_cpu()->timekeeper_source_base_ticks; + time_t ticks = timekeeper_source->ticks(timekeeper_source_info) - current_cpu()->timekeeper_source_base_ticks; + sync_sec = ticks / hz; + sync_usec = (ticks % hz) / mhz; sync_go_ahead = true; while (cpus_done != arch_smp_cpusawake - 1) CPU_PAUSE(); @@ -103,7 +106,7 @@ void timekeeper_sync(void) { MUTEX_RELEASE(&sync_mutex); for (int i = 0; i < arch_smp_cpusawake; ++i) { - printf("cpu %d offset (us) @ %lu\n", smp_cpus[i]->id, smp_cpus[i]->timekeeper_source_tick_offset / smp_cpus[i]->timekeeper_source_info->ticks_per_us); + printf("cpu %d offset (ticks) @ %lu\n", smp_cpus[i]->id, smp_cpus[i]->timekeeper_source_tick_offset); } } @@ -154,10 +157,10 @@ void timekeeper_early_init(time_t us_offset) { // this tick offset is to account for any possible time before early_init. // for example, on SMP init the early init will have the time passed on the ap as an offset - current_cpu()->timekeeper_source_tick_offset = us_offset * early_source_info->ticks_per_us; + current_cpu()->timekeeper_source_tick_offset = us_offset * early_source_info->hz / 1000000; - printf("cpu%d: timekeeper: \"%s\" selected as early source. %lu ticks at early init (%lu ticks per us)\n", - current_cpu_id(), early_source->name, current_cpu()->timekeeper_source_base_ticks, early_source_info->ticks_per_us); + printf("cpu%d: timekeeper: \"%s\" selected as early source. %lu ticks at early init (%lu hz)\n", + current_cpu_id(), early_source->name, current_cpu()->timekeeper_source_base_ticks, early_source_info->hz); } // this will do a re-init per cpu @@ -190,11 +193,11 @@ void timekeeper_init(void) { // we will calculate how much time passed and have a tick offset time_t old_tick_offset = current_cpu()->timekeeper_source_tick_offset; time_t old_ticks = old_source->ticks(old_source_info); - time_t old_us = (old_ticks - old_base + old_tick_offset) / old_source_info->ticks_per_us; // XXX would a division with rounding be better for precision here? - current_cpu()->timekeeper_source_tick_offset = old_us * new_source_info->ticks_per_us; + time_t old_us = (old_ticks - old_base + old_tick_offset) / (old_source_info->hz / 1000000); // XXX would a division with rounding be better for precision here? + current_cpu()->timekeeper_source_tick_offset = old_us * (new_source_info->hz / 1000000); interrupt_loweripl(old_ipl); - printf("cpu%d: timekeeper: \"%s\" selected as main source. %lu ticks at init (%lu ticks per us)\n", - current_cpu_id(), new_source->name, current_cpu()->timekeeper_source_base_ticks, new_source_info->ticks_per_us); + printf("cpu%d: timekeeper: \"%s\" selected as main source. %lu ticks at init (%lu hz)\n", + current_cpu_id(), new_source->name, current_cpu()->timekeeper_source_base_ticks, new_source_info->hz); }