mirror of
https://github.com/RGBCube/serenity
synced 2025-07-27 08:07:34 +00:00
Kernel+Profiler: Make profiling per-process and without core dumps
This patch merges the profiling functionality in the kernel with the performance events mechanism. A profiler sample is now just another perf event, rather than a dedicated thing. Since perf events were already per-process, this now makes profiling per-process as well. Processes with perf events would already write out a perfcore.PID file to the current directory on death, but since we may want to profile a process and then let it continue running, recorded perf events can now be accessed at any time via /proc/PID/perf_events. This patch also adds information about process memory regions to the perfcore JSON format. This removes the need to supply a core dump to the Profiler app for symbolication, and so the "profiler coredump" mechanism is removed entirely. There's still a hard limit of 4MB worth of perf events per process, so this is by no means a perfect final design, but it's a nice step forward for both simplicity and stability. Fixes #4848 Fixes #4849
This commit is contained in:
parent
f259d96871
commit
5dafb72370
20 changed files with 195 additions and 310 deletions
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
||||
* Copyright (c) 2018-2021, Andreas Kling <kling@serenityos.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
|
@ -29,8 +29,8 @@
|
|||
#include <AK/TemporaryChange.h>
|
||||
#include <Kernel/FileSystem/Custody.h>
|
||||
#include <Kernel/FileSystem/FileDescription.h>
|
||||
#include <Kernel/PerformanceEventBuffer.h>
|
||||
#include <Kernel/Process.h>
|
||||
#include <Kernel/Profiling.h>
|
||||
#include <Kernel/Random.h>
|
||||
#include <Kernel/Time/TimeManagement.h>
|
||||
#include <Kernel/VM/AllocationStrategy.h>
|
||||
|
@ -446,7 +446,6 @@ int Process::do_exec(NonnullRefPtr<FileDescription> main_program_description, Ve
|
|||
return -ENOENT;
|
||||
|
||||
// Disable profiling temporarily in case it's running on this process.
|
||||
bool was_profiling = is_profiling();
|
||||
TemporaryChange profiling_disabler(m_profiling, false);
|
||||
|
||||
// Mark this thread as the current thread that does exec
|
||||
|
@ -589,8 +588,9 @@ int Process::do_exec(NonnullRefPtr<FileDescription> main_program_description, Ve
|
|||
tss.cr3 = m_page_directory->cr3();
|
||||
tss.ss2 = m_pid.value();
|
||||
|
||||
if (was_profiling)
|
||||
Profiling::did_exec(path);
|
||||
// Throw away any recorded performance events in this process.
|
||||
if (m_perf_event_buffer)
|
||||
m_perf_event_buffer->clear();
|
||||
|
||||
{
|
||||
ScopedSpinLock lock(g_scheduler_lock);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
||||
* Copyright (c) 2018-2021, Andreas Kling <kling@serenityos.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
|
@ -31,9 +31,7 @@ namespace Kernel {
|
|||
|
||||
int Process::sys$perf_event(int type, FlatPtr arg1, FlatPtr arg2)
|
||||
{
|
||||
if (!m_perf_event_buffer)
|
||||
m_perf_event_buffer = make<PerformanceEventBuffer>();
|
||||
return m_perf_event_buffer->append(type, arg1, arg2);
|
||||
return ensure_perf_events().append(type, arg1, arg2);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
||||
* Copyright (c) 2018-2021, Andreas Kling <kling@serenityos.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
|
@ -25,8 +25,10 @@
|
|||
*/
|
||||
|
||||
#include <Kernel/CoreDump.h>
|
||||
#include <Kernel/FileSystem/FileDescription.h>
|
||||
#include <Kernel/FileSystem/VirtualFileSystem.h>
|
||||
#include <Kernel/PerformanceEventBuffer.h>
|
||||
#include <Kernel/Process.h>
|
||||
#include <Kernel/Profiling.h>
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
|
@ -41,7 +43,7 @@ int Process::sys$profiling_enable(pid_t pid)
|
|||
return -ESRCH;
|
||||
if (!is_superuser() && process->uid() != m_uid)
|
||||
return -EPERM;
|
||||
Profiling::start(*process);
|
||||
process->ensure_perf_events();
|
||||
process->set_profiling(true);
|
||||
return 0;
|
||||
}
|
||||
|
@ -54,20 +56,9 @@ int Process::sys$profiling_disable(pid_t pid)
|
|||
return -ESRCH;
|
||||
if (!is_superuser() && process->uid() != m_uid)
|
||||
return -EPERM;
|
||||
if (!process->is_profiling())
|
||||
return -EINVAL;
|
||||
process->set_profiling(false);
|
||||
Profiling::stop();
|
||||
|
||||
// We explicitly unlock here because we can't hold the lock when writing the coredump VFS
|
||||
lock.unlock();
|
||||
|
||||
if (auto coredump = CoreDump::create(*process, String::formatted("/tmp/profiler_coredumps/{}", pid))) {
|
||||
auto result = coredump->write();
|
||||
if (result.is_error())
|
||||
return result.error();
|
||||
} else {
|
||||
// FIXME: Return an error maybe?
|
||||
dbgln("Unable to create profiler coredump for PID {}", pid);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue