diff options
author | Gunnar Beutner <gbeutner@serenityos.org> | 2021-05-13 22:15:13 +0200 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2021-05-14 00:35:57 +0200 |
commit | 8614d18956f90edb08c5057f8448493b4cd3315c (patch) | |
tree | 8d41f67f098f031355916163e736edf0618d4f75 /Kernel | |
parent | d6b3513aabbf1f34eb5232517cb612ca0b7cbc9d (diff) | |
download | serenity-8614d18956f90edb08c5057f8448493b4cd3315c.zip |
Kernel: Use a separate timer for profiling the system
This updates the profiling subsystem to use a separate timer to
trigger CPU sampling. This timer has a higher resolution (1000Hz)
and is independent from the scheduler. At a later time the
resolution could even be made configurable with an argument for
sys$profiling_enable() - but not today.
Diffstat (limited to 'Kernel')
-rw-r--r-- | Kernel/PerformanceManager.h | 17 | ||||
-rw-r--r-- | Kernel/Scheduler.cpp | 3 | ||||
-rw-r--r-- | Kernel/Syscalls/profiling.cpp | 5 | ||||
-rw-r--r-- | Kernel/Time/TimeManagement.cpp | 22 | ||||
-rw-r--r-- | Kernel/Time/TimeManagement.h | 7 |
5 files changed, 46 insertions, 8 deletions
diff --git a/Kernel/PerformanceManager.h b/Kernel/PerformanceManager.h index e6ac95b7a1..00a21785ec 100644 --- a/Kernel/PerformanceManager.h +++ b/Kernel/PerformanceManager.h @@ -58,11 +58,7 @@ public: if (g_profiling_all_threads) { VERIFY(g_global_perf_events); - // FIXME: We currently don't collect samples while idle. - // That will be an interesting mode to add in the future. :^) - if (¤t_thread != Processor::current().idle_thread()) { - perf_events = g_global_perf_events; - } + perf_events = g_global_perf_events; } else if (current_thread.process().is_profiling()) { VERIFY(current_thread.process().perf_events()); perf_events = current_thread.process().perf_events(); @@ -88,6 +84,17 @@ public: [[maybe_unused]] auto res = event_buffer->append(PERF_EVENT_MUNMAP, region.base().get(), region.size(), nullptr); } } + + inline static void timer_tick(RegisterState const& regs) + { + auto current_thread = Thread::current(); + // FIXME: We currently don't collect samples while idle. + // That will be an interesting mode to add in the future. :^) + if (!current_thread || current_thread == Processor::current().idle_thread()) + return; + + PerformanceManager::add_cpu_sample_event(*current_thread, regs); + } }; } diff --git a/Kernel/Scheduler.cpp b/Kernel/Scheduler.cpp index 457db25350..8417719bc3 100644 --- a/Kernel/Scheduler.cpp +++ b/Kernel/Scheduler.cpp @@ -10,7 +10,6 @@ #include <AK/Time.h> #include <Kernel/Debug.h> #include <Kernel/Panic.h> -#include <Kernel/PerformanceManager.h> #include <Kernel/Process.h> #include <Kernel/RTC.h> #include <Kernel/Scheduler.h> @@ -501,8 +500,6 @@ void Scheduler::timer_tick(const RegisterState& regs) return; // TODO: This prevents scheduling on other CPUs! #endif - PerformanceManager::add_cpu_sample_event(*current_thread, regs); - if (current_thread->tick()) return; diff --git a/Kernel/Syscalls/profiling.cpp b/Kernel/Syscalls/profiling.cpp index ba7685488c..806a040187 100644 --- a/Kernel/Syscalls/profiling.cpp +++ b/Kernel/Syscalls/profiling.cpp @@ -9,6 +9,7 @@ #include <Kernel/FileSystem/VirtualFileSystem.h> #include <Kernel/PerformanceManager.h> #include <Kernel/Process.h> +#include <Kernel/Time/TimeManagement.h> namespace Kernel { @@ -34,6 +35,7 @@ KResultOr<int> Process::sys$profiling_enable(pid_t pid) PerformanceManager::add_process_created_event(process); return IterationDecision::Continue; }); + TimeManagement::the().enable_profile_timer(); return 0; } @@ -48,6 +50,7 @@ KResultOr<int> Process::sys$profiling_enable(pid_t pid) if (!process->create_perf_events_buffer_if_needed()) return ENOMEM; process->set_profiling(true); + TimeManagement::the().enable_profile_timer(); return 0; } @@ -60,6 +63,7 @@ KResultOr<int> Process::sys$profiling_disable(pid_t pid) return EPERM; ScopedCritical critical; g_profiling_all_threads = false; + TimeManagement::the().disable_profile_timer(); return 0; } @@ -71,6 +75,7 @@ KResultOr<int> Process::sys$profiling_disable(pid_t pid) return EPERM; if (!process->is_profiling()) return EINVAL; + TimeManagement::the().disable_profile_timer(); process->set_profiling(false); return 0; } diff --git a/Kernel/Time/TimeManagement.cpp b/Kernel/Time/TimeManagement.cpp index 153b02bf21..106f836082 100644 --- a/Kernel/Time/TimeManagement.cpp +++ b/Kernel/Time/TimeManagement.cpp @@ -10,6 +10,7 @@ #include <Kernel/ACPI/Parser.h> #include <Kernel/CommandLine.h> #include <Kernel/Interrupts/APIC.h> +#include <Kernel/PerformanceManager.h> #include <Kernel/Scheduler.h> #include <Kernel/Time/APICTimer.h> #include <Kernel/Time/HPET.h> @@ -289,6 +290,15 @@ UNMAP_AFTER_INIT bool TimeManagement::probe_and_set_non_legacy_hardware_timers() // We don't need an interrupt for time keeping purposes because we // can query the timer. m_time_keeper_timer = m_system_timer; + + if (periodic_timers.size() > 1) + m_profile_timer = periodic_timers[1]; + else + m_profile_timer = non_periodic_timers[1]; + + m_profile_timer->set_callback(PerformanceManager::timer_tick); + m_profile_timer->try_to_set_frequency(m_profile_timer->calculate_nearest_possible_frequency(1)); + return true; } @@ -379,4 +389,16 @@ void TimeManagement::system_timer_tick(const RegisterState& regs) Scheduler::timer_tick(regs); } +void TimeManagement::enable_profile_timer() +{ + if (m_profile_enable_count.fetch_add(1) == 0) + m_profile_timer->try_to_set_frequency(m_profile_timer->calculate_nearest_possible_frequency(OPTIMAL_PROFILE_TICKS_PER_SECOND_RATE)); +} + +void TimeManagement::disable_profile_timer() +{ + if (m_profile_enable_count.fetch_sub(1) == 1) + m_profile_timer->try_to_set_frequency(m_profile_timer->calculate_nearest_possible_frequency(1)); +} + } diff --git a/Kernel/Time/TimeManagement.h b/Kernel/Time/TimeManagement.h index 0c48dd79c6..4c382d9577 100644 --- a/Kernel/Time/TimeManagement.h +++ b/Kernel/Time/TimeManagement.h @@ -16,6 +16,7 @@ namespace Kernel { #define OPTIMAL_TICKS_PER_SECOND_RATE 250 +#define OPTIMAL_PROFILE_TICKS_PER_SECOND_RATE 1000 class HardwareTimerBase; @@ -55,6 +56,9 @@ public: static bool is_hpet_periodic_mode_allowed(); + void enable_profile_timer(); + void disable_profile_timer(); + u64 uptime_ms() const; static Time now(); @@ -90,6 +94,9 @@ private: RefPtr<HardwareTimerBase> m_system_timer; RefPtr<HardwareTimerBase> m_time_keeper_timer; + + Atomic<u32> m_profile_enable_count { 0 }; + RefPtr<HardwareTimerBase> m_profile_timer; }; } |