mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-22 23:50:19 +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) {
|
if (g_profiling_all_threads) {
|
||||||
VERIFY(g_global_perf_events);
|
VERIFY(g_global_perf_events);
|
||||||
// FIXME: We currently don't collect samples while idle.
|
perf_events = g_global_perf_events;
|
||||||
// That will be an interesting mode to add in the future. :^)
|
|
||||||
if (¤t_thread != Processor::current().idle_thread()) {
|
|
||||||
perf_events = g_global_perf_events;
|
|
||||||
}
|
|
||||||
} else if (current_thread.process().is_profiling()) {
|
} else if (current_thread.process().is_profiling()) {
|
||||||
VERIFY(current_thread.process().perf_events());
|
VERIFY(current_thread.process().perf_events());
|
||||||
perf_events = 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);
|
[[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 <AK/Time.h>
|
||||||
#include <Kernel/Debug.h>
|
#include <Kernel/Debug.h>
|
||||||
#include <Kernel/Panic.h>
|
#include <Kernel/Panic.h>
|
||||||
#include <Kernel/PerformanceManager.h>
|
|
||||||
#include <Kernel/Process.h>
|
#include <Kernel/Process.h>
|
||||||
#include <Kernel/RTC.h>
|
#include <Kernel/RTC.h>
|
||||||
#include <Kernel/Scheduler.h>
|
#include <Kernel/Scheduler.h>
|
||||||
|
@ -501,8 +500,6 @@ void Scheduler::timer_tick(const RegisterState& regs)
|
||||||
return; // TODO: This prevents scheduling on other CPUs!
|
return; // TODO: This prevents scheduling on other CPUs!
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
PerformanceManager::add_cpu_sample_event(*current_thread, regs);
|
|
||||||
|
|
||||||
if (current_thread->tick())
|
if (current_thread->tick())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#include <Kernel/FileSystem/VirtualFileSystem.h>
|
#include <Kernel/FileSystem/VirtualFileSystem.h>
|
||||||
#include <Kernel/PerformanceManager.h>
|
#include <Kernel/PerformanceManager.h>
|
||||||
#include <Kernel/Process.h>
|
#include <Kernel/Process.h>
|
||||||
|
#include <Kernel/Time/TimeManagement.h>
|
||||||
|
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
|
|
||||||
|
@ -34,6 +35,7 @@ KResultOr<int> Process::sys$profiling_enable(pid_t pid)
|
||||||
PerformanceManager::add_process_created_event(process);
|
PerformanceManager::add_process_created_event(process);
|
||||||
return IterationDecision::Continue;
|
return IterationDecision::Continue;
|
||||||
});
|
});
|
||||||
|
TimeManagement::the().enable_profile_timer();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,6 +50,7 @@ KResultOr<int> Process::sys$profiling_enable(pid_t pid)
|
||||||
if (!process->create_perf_events_buffer_if_needed())
|
if (!process->create_perf_events_buffer_if_needed())
|
||||||
return ENOMEM;
|
return ENOMEM;
|
||||||
process->set_profiling(true);
|
process->set_profiling(true);
|
||||||
|
TimeManagement::the().enable_profile_timer();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,6 +63,7 @@ KResultOr<int> Process::sys$profiling_disable(pid_t pid)
|
||||||
return EPERM;
|
return EPERM;
|
||||||
ScopedCritical critical;
|
ScopedCritical critical;
|
||||||
g_profiling_all_threads = false;
|
g_profiling_all_threads = false;
|
||||||
|
TimeManagement::the().disable_profile_timer();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,6 +75,7 @@ KResultOr<int> Process::sys$profiling_disable(pid_t pid)
|
||||||
return EPERM;
|
return EPERM;
|
||||||
if (!process->is_profiling())
|
if (!process->is_profiling())
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
|
TimeManagement::the().disable_profile_timer();
|
||||||
process->set_profiling(false);
|
process->set_profiling(false);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#include <Kernel/ACPI/Parser.h>
|
#include <Kernel/ACPI/Parser.h>
|
||||||
#include <Kernel/CommandLine.h>
|
#include <Kernel/CommandLine.h>
|
||||||
#include <Kernel/Interrupts/APIC.h>
|
#include <Kernel/Interrupts/APIC.h>
|
||||||
|
#include <Kernel/PerformanceManager.h>
|
||||||
#include <Kernel/Scheduler.h>
|
#include <Kernel/Scheduler.h>
|
||||||
#include <Kernel/Time/APICTimer.h>
|
#include <Kernel/Time/APICTimer.h>
|
||||||
#include <Kernel/Time/HPET.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
|
// We don't need an interrupt for time keeping purposes because we
|
||||||
// can query the timer.
|
// can query the timer.
|
||||||
m_time_keeper_timer = m_system_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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -379,4 +389,16 @@ void TimeManagement::system_timer_tick(const RegisterState& regs)
|
||||||
Scheduler::timer_tick(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 {
|
namespace Kernel {
|
||||||
|
|
||||||
#define OPTIMAL_TICKS_PER_SECOND_RATE 250
|
#define OPTIMAL_TICKS_PER_SECOND_RATE 250
|
||||||
|
#define OPTIMAL_PROFILE_TICKS_PER_SECOND_RATE 1000
|
||||||
|
|
||||||
class HardwareTimerBase;
|
class HardwareTimerBase;
|
||||||
|
|
||||||
|
@ -55,6 +56,9 @@ public:
|
||||||
|
|
||||||
static bool is_hpet_periodic_mode_allowed();
|
static bool is_hpet_periodic_mode_allowed();
|
||||||
|
|
||||||
|
void enable_profile_timer();
|
||||||
|
void disable_profile_timer();
|
||||||
|
|
||||||
u64 uptime_ms() const;
|
u64 uptime_ms() const;
|
||||||
static Time now();
|
static Time now();
|
||||||
|
|
||||||
|
@ -90,6 +94,9 @@ private:
|
||||||
|
|
||||||
RefPtr<HardwareTimerBase> m_system_timer;
|
RefPtr<HardwareTimerBase> m_system_timer;
|
||||||
RefPtr<HardwareTimerBase> m_time_keeper_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