mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-12-04 05:20:30 +00:00
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.
This commit is contained in:
parent
d6b3513aab
commit
8614d18956
Notes:
sideshowbarker
2024-07-18 18:11:54 +09:00
Author: https://github.com/gunnarbeutner Commit: https://github.com/SerenityOS/serenity/commit/8614d18956f Pull-request: https://github.com/SerenityOS/serenity/pull/7090 Reviewed-by: https://github.com/awesomekling
5 changed files with 46 additions and 8 deletions
|
@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue