1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-26 07:27:45 +00:00

Kernel+Profiler: Improve profiling subsystem

This turns the perfcore format into more a log than it was before,
which lets us properly log process, thread and region
creation/destruction. This also makes it unnecessary to dump the
process' regions every time it is scheduled like we did before.

Incidentally this also fixes 'profile -c' because we previously ended
up incorrectly dumping the parent's region map into the profile data.

Log-based mmap support enables profiling shared libraries which
are loaded at runtime, e.g. via dlopen().

This enables profiling both the parent and child process for
programs which use execve(). Previously we'd discard the profiling
data for the old process.

The Profiler tool has been updated to not treat thread IDs as
process IDs anymore. This enables support for processes with more
than one thread. Also, there's a new widget to filter which
process should be displayed.
This commit is contained in:
Gunnar Beutner 2021-04-25 23:42:36 +02:00 committed by Andreas Kling
parent f57c57966b
commit eb798d5538
26 changed files with 658 additions and 292 deletions

View file

@ -628,9 +628,9 @@ KResult Process::do_exec(NonnullRefPtr<FileDescription> main_program_description
tss.cr3 = space().page_directory().cr3();
tss.ss2 = pid().value();
// Throw away any recorded performance events in this process.
if (m_perf_event_buffer)
m_perf_event_buffer->clear();
if (auto* event_buffer = current_perf_events_buffer()) {
event_buffer->add_process(*this, ProcessEventType::Exec);
}
{
ScopedSpinLock lock(g_scheduler_lock);

View file

@ -5,6 +5,7 @@
*/
#include <Kernel/KSyms.h>
#include <Kernel/PerformanceEventBuffer.h>
#include <Kernel/Process.h>
namespace Kernel {
@ -16,6 +17,11 @@ void Process::sys$exit(int status)
m_termination_status = status;
m_termination_signal = 0;
}
if (auto* event_buffer = current_perf_events_buffer()) {
[[maybe_unused]] auto rc = event_buffer->append(PERF_EVENT_THREAD_EXIT, Thread::current()->tid().value(), 0, nullptr);
}
die();
Thread::current()->die_if_needed();
VERIFY_NOT_REACHED();

View file

@ -7,6 +7,7 @@
#include <Kernel/Debug.h>
#include <Kernel/FileSystem/Custody.h>
#include <Kernel/FileSystem/FileDescription.h>
#include <Kernel/PerformanceEventBuffer.h>
#include <Kernel/Process.h>
#include <Kernel/VM/Region.h>
@ -84,6 +85,11 @@ KResultOr<pid_t> Process::sys$fork(RegisterState& regs)
g_processes->prepend(child);
}
if (g_profiling_all_threads) {
VERIFY(g_global_perf_events);
g_global_perf_events->add_process(*child, ProcessEventType::Create);
}
ScopedSpinLock lock(g_scheduler_lock);
child_first_thread->set_affinity(Thread::current()->affinity());
child_first_thread->set_state(Thread::State::Runnable);

View file

@ -246,6 +246,12 @@ KResultOr<FlatPtr> Process::sys$mmap(Userspace<const Syscall::SC_mmap_params*> u
if (!region)
return ENOMEM;
if (auto* event_buffer = current_perf_events_buffer()) {
[[maybe_unused]] auto res = event_buffer->append(PERF_EVENT_MMAP, region->vaddr().get(),
region->size(), name.is_null() ? region->name().characters() : name.characters());
}
region->set_mmap(true);
if (map_shared)
region->set_shared(true);
@ -430,6 +436,9 @@ KResultOr<int> Process::sys$set_mmap_name(Userspace<const Syscall::SC_set_mmap_n
return EINVAL;
if (!region->is_mmap())
return EPERM;
if (auto* event_buffer = current_perf_events_buffer()) {
[[maybe_unused]] auto res = event_buffer->append(PERF_EVENT_MMAP, region->vaddr().get(), region->size(), name.characters());
}
region->set_name(move(name));
return 0;
}
@ -453,8 +462,13 @@ KResultOr<int> Process::sys$munmap(Userspace<void*> addr, size_t size)
if (auto* whole_region = space().find_region_from_range(range_to_unmap)) {
if (!whole_region->is_mmap())
return EPERM;
auto base = whole_region->vaddr();
auto size = whole_region->size();
bool success = space().deallocate_region(*whole_region);
VERIFY(success);
if (auto* event_buffer = current_perf_events_buffer()) {
[[maybe_unused]] auto res = event_buffer->append(PERF_EVENT_MUNMAP, base.get(), size, nullptr);
}
return 0;
}
@ -479,6 +493,11 @@ KResultOr<int> Process::sys$munmap(Userspace<void*> addr, size_t size)
for (auto* new_region : new_regions) {
new_region->map(space().page_directory());
}
if (auto* event_buffer = current_perf_events_buffer()) {
[[maybe_unused]] auto res = event_buffer->append(PERF_EVENT_MUNMAP, range_to_unmap.base().get(), range_to_unmap.size(), nullptr);
}
return 0;
}
@ -521,6 +540,10 @@ KResultOr<int> Process::sys$munmap(Userspace<void*> addr, size_t size)
new_region->map(space().page_directory());
}
if (auto* event_buffer = current_perf_events_buffer()) {
[[maybe_unused]] auto res = event_buffer->append(PERF_EVENT_MUNMAP, range_to_unmap.base().get(), range_to_unmap.size(), nullptr);
}
return 0;
}

View file

@ -13,7 +13,7 @@ KResultOr<int> Process::sys$perf_event(int type, FlatPtr arg1, FlatPtr arg2)
{
if (!create_perf_events_buffer_if_needed())
return ENOMEM;
return perf_events()->append(type, arg1, arg2);
return perf_events()->append(type, arg1, arg2, nullptr);
}
}

View file

@ -12,8 +12,8 @@
namespace Kernel {
PerformanceEventBuffer* g_global_perf_events;
bool g_profiling_all_threads;
PerformanceEventBuffer* g_global_perf_events;
KResultOr<int> Process::sys$profiling_enable(pid_t pid)
{
@ -27,6 +27,11 @@ KResultOr<int> Process::sys$profiling_enable(pid_t pid)
g_global_perf_events->clear();
else
g_global_perf_events = PerformanceEventBuffer::try_create_with_size(32 * MiB).leak_ptr();
ScopedSpinLock lock(g_processes_lock);
Process::for_each([](auto& process) {
g_global_perf_events->add_process(process, ProcessEventType::Create);
return IterationDecision::Continue;
});
g_profiling_all_threads = true;
return 0;
}

View file

@ -8,6 +8,7 @@
#include <AK/String.h>
#include <AK/StringBuilder.h>
#include <AK/StringView.h>
#include <Kernel/PerformanceEventBuffer.h>
#include <Kernel/Process.h>
#include <Kernel/VM/MemoryManager.h>
#include <Kernel/VM/PageDirectory.h>
@ -69,6 +70,10 @@ KResultOr<int> Process::sys$create_thread(void* (*entry)(void*), Userspace<const
if (tsr_result.is_error())
return tsr_result.error();
if (m_perf_event_buffer) {
[[maybe_unused]] auto rc = m_perf_event_buffer->append(PERF_EVENT_THREAD_CREATE, thread->tid().value(), 0, nullptr);
}
ScopedSpinLock lock(g_scheduler_lock);
thread->set_priority(requested_thread_priority);
thread->set_state(Thread::State::Runnable);
@ -84,6 +89,10 @@ void Process::sys$exit_thread(Userspace<void*> exit_value)
this->sys$exit(0);
}
if (m_perf_event_buffer) {
[[maybe_unused]] auto rc = m_perf_event_buffer->append(PERF_EVENT_THREAD_EXIT, Thread::current()->tid().value(), 0, nullptr);
}
Thread::current()->exit(reinterpret_cast<void*>(exit_value.ptr()));
VERIFY_NOT_REACHED();
}