From fb00d3ed25196cfe32cfd8a6f0d7608f634206de Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Fri, 18 Nov 2022 22:07:57 +0100 Subject: [PATCH] Kernel+lsirq: Track per-CPU IRQ handler call counts Each GenericInterruptHandler now tracks the number of calls that each CPU has serviced. This takes care of a FIXME in the /sys/kernel/interrupts generator. Also, the lsirq command line tool now displays per-CPU call counts. --- .../SysFS/Subsystems/Kernel/Interrupts.cpp | 8 +++++-- Kernel/Interrupts/GenericInterruptHandler.cpp | 7 +++++- Kernel/Interrupts/GenericInterruptHandler.h | 5 +++-- Userland/Utilities/lsirq.cpp | 22 +++++++++++++++---- 4 files changed, 33 insertions(+), 9 deletions(-) diff --git a/Kernel/FileSystem/SysFS/Subsystems/Kernel/Interrupts.cpp b/Kernel/FileSystem/SysFS/Subsystems/Kernel/Interrupts.cpp index 416ffc600b..984d3c730b 100644 --- a/Kernel/FileSystem/SysFS/Subsystems/Kernel/Interrupts.cpp +++ b/Kernel/FileSystem/SysFS/Subsystems/Kernel/Interrupts.cpp @@ -1,5 +1,6 @@ /* * Copyright (c) 2022, Liav A. + * Copyright (c) 2022, Andreas Kling * * SPDX-License-Identifier: BSD-2-Clause */ @@ -34,9 +35,12 @@ ErrorOr SysFSInterrupts::try_generate(KBufferBuilder& builder) TRY(obj.add("purpose"sv, handler.purpose())); TRY(obj.add("interrupt_line"sv, handler.interrupt_number())); TRY(obj.add("controller"sv, handler.controller())); - TRY(obj.add("cpu_handler"sv, 0)); // FIXME: Determine the responsible CPU for each interrupt handler. TRY(obj.add("device_sharing"sv, (unsigned)handler.sharing_devices_count())); - TRY(obj.add("call_count"sv, handler.call_count())); + auto per_cpu_call_counts = TRY(obj.add_array("per_cpu_call_counts"sv)); + for (auto call_count : handler.per_cpu_call_counts()) { + TRY(per_cpu_call_counts.add(call_count)); + } + TRY(per_cpu_call_counts.finish()); TRY(obj.finish()); return {}; })(); diff --git a/Kernel/Interrupts/GenericInterruptHandler.cpp b/Kernel/Interrupts/GenericInterruptHandler.cpp index 971cf57efd..9cc2e65535 100644 --- a/Kernel/Interrupts/GenericInterruptHandler.cpp +++ b/Kernel/Interrupts/GenericInterruptHandler.cpp @@ -67,9 +67,14 @@ void GenericInterruptHandler::change_interrupt_number(u8 number) register_generic_interrupt_handler(InterruptManagement::acquire_mapped_interrupt_number(interrupt_number()), *this); } +Span GenericInterruptHandler::per_cpu_call_counts() const +{ + return m_per_cpu_call_counts.span().slice(0, Processor::count()); +} + void GenericInterruptHandler::increment_call_count() { - ++m_call_count; + ++m_per_cpu_call_counts[Processor::current_id()]; } } diff --git a/Kernel/Interrupts/GenericInterruptHandler.h b/Kernel/Interrupts/GenericInterruptHandler.h index 8a193dd6b5..5d512c08a2 100644 --- a/Kernel/Interrupts/GenericInterruptHandler.h +++ b/Kernel/Interrupts/GenericInterruptHandler.h @@ -37,7 +37,7 @@ public: u8 interrupt_number() const { return m_interrupt_number; } - u32 call_count() const { return m_call_count; } + Span per_cpu_call_counts() const; virtual size_t sharing_devices_count() const = 0; virtual bool is_shared_handler() const = 0; @@ -57,7 +57,8 @@ protected: void disable_remap() { m_disable_remap = true; } private: - Atomic m_call_count { 0 }; + Array m_per_cpu_call_counts {}; + u8 m_interrupt_number { 0 }; bool m_disable_remap { false }; bool m_registered { false }; diff --git a/Userland/Utilities/lsirq.cpp b/Userland/Utilities/lsirq.cpp index ce7952a436..139e3909b1 100644 --- a/Userland/Utilities/lsirq.cpp +++ b/Userland/Utilities/lsirq.cpp @@ -1,5 +1,6 @@ /* * Copyright (c) 2020, Liav A. + * Copyright (c) 2022, Andreas Kling * * SPDX-License-Identifier: BSD-2-Clause */ @@ -20,17 +21,30 @@ ErrorOr serenity_main(Main::Arguments) TRY(Core::System::pledge("stdio")); - outln(" CPU0"); auto file_contents = proc_interrupts->read_all(); auto json = TRY(JsonValue::from_string(file_contents)); - json.as_array().for_each([](auto& value) { + + auto cpu_count = json.as_array().at(0).as_object().get("per_cpu_call_counts"sv).as_array().size(); + + out(" "sv); + for (size_t i = 0; i < cpu_count; ++i) { + out("{:>10}", String::formatted("CPU{}", i)); + } + outln(""); + + json.as_array().for_each([cpu_count](JsonValue const& value) { auto& handler = value.as_object(); auto purpose = handler.get("purpose"sv).to_string(); auto interrupt = handler.get("interrupt_line"sv).to_string(); auto controller = handler.get("controller"sv).to_string(); - auto call_count = handler.get("call_count"sv).to_string(); + auto call_counts = handler.get("per_cpu_call_counts"sv).as_array(); - outln("{:>4}: {:10} {:10} {:30}", interrupt, call_count, controller, purpose); + out("{:>4}: ", interrupt); + + for (size_t i = 0; i < cpu_count; ++i) + out("{:>10}", call_counts[i].to_string()); + + outln(" {:10} {:30}", controller, purpose); }); return 0;