diff --git a/Kernel/PerformanceManager.h b/Kernel/PerformanceManager.h index e6ac95b7a1f..00a21785ec3 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 457db253504..8417719bc38 100644 --- a/Kernel/Scheduler.cpp +++ b/Kernel/Scheduler.cpp @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include @@ -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 ba7685488c8..806a040187d 100644 --- a/Kernel/Syscalls/profiling.cpp +++ b/Kernel/Syscalls/profiling.cpp @@ -9,6 +9,7 @@ #include #include #include +#include namespace Kernel { @@ -34,6 +35,7 @@ KResultOr 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 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 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 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 153b02bf214..106f836082e 100644 --- a/Kernel/Time/TimeManagement.cpp +++ b/Kernel/Time/TimeManagement.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -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 0c48dd79c6e..4c382d9577a 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 m_system_timer; RefPtr m_time_keeper_timer; + + Atomic m_profile_enable_count { 0 }; + RefPtr m_profile_timer; }; }