From 22fdfc4428457024878bdecc330b317f746f46e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Duval?= Date: Thu, 10 Sep 2020 22:24:43 +0200 Subject: [PATCH] kernel/cpu: add cpu_frequency() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit implement on x86 with APERFMPERF. Change-Id: Ia484854c76dee76c5447983de15800a25d791d39 Reviewed-on: https://review.haiku-os.org/c/haiku/+/3213 Reviewed-by: Jérôme Duval --- headers/private/kernel/arch/system_info.h | 2 ++ headers/private/kernel/cpu.h | 1 + .../kernel/arch/arm/arch_system_info.cpp | 9 ++++++ .../kernel/arch/arm64/arch_system_info.cpp | 8 +++++ .../kernel/arch/m68k/arch_system_info.cpp | 8 +++++ .../kernel/arch/ppc/arch_system_info.cpp | 8 +++++ .../kernel/arch/riscv64/arch_system_info.cpp | 7 ++++ .../kernel/arch/sparc/arch_system_info.cpp | 7 ++++ .../kernel/arch/x86/arch_system_info.cpp | 32 +++++++++++++++++++ src/system/kernel/cpu.cpp | 12 +++++++ 10 files changed, 94 insertions(+) diff --git a/headers/private/kernel/arch/system_info.h b/headers/private/kernel/arch/system_info.h index f765be64bd..d2eb6822c8 100644 --- a/headers/private/kernel/arch/system_info.h +++ b/headers/private/kernel/arch/system_info.h @@ -19,6 +19,8 @@ extern "C" { status_t arch_system_info_init(struct kernel_args *args); void arch_fill_topology_node(cpu_topology_node_info* node, int32 cpu); +status_t arch_get_frequency(uint64 *frequency, int32 cpu); + #ifdef __cplusplus } diff --git a/headers/private/kernel/cpu.h b/headers/private/kernel/cpu.h index 5c0f09c2fc..b8bf3df7d6 100644 --- a/headers/private/kernel/cpu.h +++ b/headers/private/kernel/cpu.h @@ -102,6 +102,7 @@ status_t cpu_init_percpu(struct kernel_args *ka, int curr_cpu); status_t cpu_init_post_vm(struct kernel_args *args); status_t cpu_init_post_modules(struct kernel_args *args); bigtime_t cpu_get_active_time(int32 cpu); +uint64 cpu_frequency(int32 cpu); cpu_ent *get_cpu_struct(void); extern inline cpu_ent *get_cpu_struct(void) { return &gCPU[smp_get_current_cpu()]; } diff --git a/src/system/kernel/arch/arm/arch_system_info.cpp b/src/system/kernel/arch/arm/arch_system_info.cpp index ae8784b405..1f8c1d3d2b 100644 --- a/src/system/kernel/arch/arm/arch_system_info.cpp +++ b/src/system/kernel/arch/arm/arch_system_info.cpp @@ -54,3 +54,12 @@ arch_system_info_init(struct kernel_args *args) { return B_OK; } + + +status_t +arch_get_frequency(uint64 *frequency, int32 cpu) +{ + *frequency = 0; + return B_OK; +} + diff --git a/src/system/kernel/arch/arm64/arch_system_info.cpp b/src/system/kernel/arch/arm64/arch_system_info.cpp index cc4b5031c1..4d76ae6800 100644 --- a/src/system/kernel/arch/arm64/arch_system_info.cpp +++ b/src/system/kernel/arch/arm64/arch_system_info.cpp @@ -27,3 +27,11 @@ arch_system_info_init(struct kernel_args *args) { return B_OK; } + + +status_t +arch_get_frequency(uint64 *frequency, int32 cpu) +{ + *frequency = 0; + return B_OK; +} diff --git a/src/system/kernel/arch/m68k/arch_system_info.cpp b/src/system/kernel/arch/m68k/arch_system_info.cpp index 003cc32807..3622f3a3ef 100644 --- a/src/system/kernel/arch/m68k/arch_system_info.cpp +++ b/src/system/kernel/arch/m68k/arch_system_info.cpp @@ -57,3 +57,11 @@ arch_system_info_init(struct kernel_args *args) return B_OK; } + + +status_t +arch_get_frequency(uint64 *frequency, int32 cpu) +{ + *frequency = sCPUClockFrequency; + return B_OK; +} diff --git a/src/system/kernel/arch/ppc/arch_system_info.cpp b/src/system/kernel/arch/ppc/arch_system_info.cpp index 21e5570aec..33fd183fcd 100644 --- a/src/system/kernel/arch/ppc/arch_system_info.cpp +++ b/src/system/kernel/arch/ppc/arch_system_info.cpp @@ -110,3 +110,11 @@ arch_system_info_init(struct kernel_args *args) return B_OK; } + + +status_t +arch_get_frequency(uint64 *frequency, int32 cpu) +{ + *frequency = sCPUClockFrequency; + return B_OK; +} diff --git a/src/system/kernel/arch/riscv64/arch_system_info.cpp b/src/system/kernel/arch/riscv64/arch_system_info.cpp index 97905d62e9..6fb0f54290 100644 --- a/src/system/kernel/arch/riscv64/arch_system_info.cpp +++ b/src/system/kernel/arch/riscv64/arch_system_info.cpp @@ -33,3 +33,10 @@ arch_system_info_init(struct kernel_args *args) return B_OK; } + +status_t +arch_get_frequency(uint64 *frequency, int32 cpu) +{ + *frequency = sCPUClockFrequency; + return B_OK; +} diff --git a/src/system/kernel/arch/sparc/arch_system_info.cpp b/src/system/kernel/arch/sparc/arch_system_info.cpp index 97905d62e9..6fb0f54290 100644 --- a/src/system/kernel/arch/sparc/arch_system_info.cpp +++ b/src/system/kernel/arch/sparc/arch_system_info.cpp @@ -33,3 +33,10 @@ arch_system_info_init(struct kernel_args *args) return B_OK; } + +status_t +arch_get_frequency(uint64 *frequency, int32 cpu) +{ + *frequency = sCPUClockFrequency; + return B_OK; +} diff --git a/src/system/kernel/arch/x86/arch_system_info.cpp b/src/system/kernel/arch/x86/arch_system_info.cpp index c208b54a82..a417449278 100644 --- a/src/system/kernel/arch/x86/arch_system_info.cpp +++ b/src/system/kernel/arch/x86/arch_system_info.cpp @@ -131,6 +131,38 @@ arch_fill_topology_node(cpu_topology_node_info* node, int32 cpu) } +static void +get_frequency_for(void *_frequency, int /*cpu*/) +{ + uint64 *frequency = (uint64*)_frequency; + uint64 mperf = x86_read_msr(IA32_MSR_MPERF); + uint64 aperf = x86_read_msr(IA32_MSR_APERF); + + for (int i = 0; i < 1000; i++) + arch_cpu_pause(); + + uint64 mperf2 = x86_read_msr(IA32_MSR_MPERF); + uint64 aperf2 = x86_read_msr(IA32_MSR_APERF); + + if (mperf2 == mperf) + *frequency = 0; + else + *frequency = (aperf2 - aperf) * sCPUClockSpeed / (mperf2 - mperf); +} + + +status_t +arch_get_frequency(uint64 *frequency, int32 cpu) +{ + if (x86_check_feature(IA32_FEATURE_APERFMPERF, FEATURE_6_ECX)) + call_single_cpu_sync(cpu, get_frequency_for, frequency); + else + *frequency = sCPUClockSpeed; + + return B_OK; +} + + // #pragma mark - diff --git a/src/system/kernel/cpu.cpp b/src/system/kernel/cpu.cpp index 519b05eb2a..b4cdad7f5e 100644 --- a/src/system/kernel/cpu.cpp +++ b/src/system/kernel/cpu.cpp @@ -12,6 +12,7 @@ #include #include +#include #include @@ -171,6 +172,17 @@ cpu_get_active_time(int32 cpu) } +uint64 +cpu_frequency(int32 cpu) +{ + if (cpu < 0 || cpu >= smp_get_num_cpus()) + return 0; + uint64 frequency = 0; + arch_get_frequency(&frequency, cpu); + return frequency; +} + + void clear_caches(void *address, size_t length, uint32 flags) {