mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 19:17:44 +00:00
Kernel/Profiling: Add profiling to read syscall
Syscalls to read can now be profiled, allowing us to monitor filesystem usage by different applications.
This commit is contained in:
parent
bd821982e0
commit
4916c892b2
6 changed files with 86 additions and 9 deletions
|
@ -32,6 +32,7 @@ enum {
|
||||||
PERF_EVENT_PAGE_FAULT = 8192,
|
PERF_EVENT_PAGE_FAULT = 8192,
|
||||||
PERF_EVENT_SYSCALL = 16384,
|
PERF_EVENT_SYSCALL = 16384,
|
||||||
PERF_EVENT_SIGNPOST = 32768,
|
PERF_EVENT_SIGNPOST = 32768,
|
||||||
|
PERF_EVENT_READ = 65536,
|
||||||
};
|
};
|
||||||
|
|
||||||
#define PERF_EVENT_MASK_ALL (~0ull)
|
#define PERF_EVENT_MASK_ALL (~0ull)
|
||||||
|
|
|
@ -22,7 +22,7 @@ PerformanceEventBuffer::PerformanceEventBuffer(NonnullOwnPtr<KBuffer> buffer)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
NEVER_INLINE ErrorOr<void> PerformanceEventBuffer::append(int type, FlatPtr arg1, FlatPtr arg2, StringView arg3, Thread* current_thread)
|
NEVER_INLINE ErrorOr<void> PerformanceEventBuffer::append(int type, FlatPtr arg1, FlatPtr arg2, StringView arg3, Thread* current_thread, FlatPtr arg4, u64 arg5, ErrorOr<FlatPtr> arg6)
|
||||||
{
|
{
|
||||||
FlatPtr base_pointer;
|
FlatPtr base_pointer;
|
||||||
#if ARCH(I386)
|
#if ARCH(I386)
|
||||||
|
@ -32,7 +32,7 @@ NEVER_INLINE ErrorOr<void> PerformanceEventBuffer::append(int type, FlatPtr arg1
|
||||||
asm volatile("movq %%rbp, %%rax"
|
asm volatile("movq %%rbp, %%rax"
|
||||||
: "=a"(base_pointer));
|
: "=a"(base_pointer));
|
||||||
#endif
|
#endif
|
||||||
return append_with_ip_and_bp(current_thread->pid(), current_thread->tid(), 0, base_pointer, type, 0, arg1, arg2, arg3);
|
return append_with_ip_and_bp(current_thread->pid(), current_thread->tid(), 0, base_pointer, type, 0, arg1, arg2, arg3, arg4, arg5, arg6);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Vector<FlatPtr, PerformanceEvent::max_stack_frame_count> raw_backtrace(FlatPtr bp, FlatPtr ip)
|
static Vector<FlatPtr, PerformanceEvent::max_stack_frame_count> raw_backtrace(FlatPtr bp, FlatPtr ip)
|
||||||
|
@ -73,13 +73,13 @@ static Vector<FlatPtr, PerformanceEvent::max_stack_frame_count> raw_backtrace(Fl
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorOr<void> PerformanceEventBuffer::append_with_ip_and_bp(ProcessID pid, ThreadID tid, const RegisterState& regs,
|
ErrorOr<void> PerformanceEventBuffer::append_with_ip_and_bp(ProcessID pid, ThreadID tid, const RegisterState& regs,
|
||||||
int type, u32 lost_samples, FlatPtr arg1, FlatPtr arg2, StringView arg3)
|
int type, u32 lost_samples, FlatPtr arg1, FlatPtr arg2, StringView arg3, FlatPtr arg4, u64 arg5, ErrorOr<FlatPtr> arg6)
|
||||||
{
|
{
|
||||||
return append_with_ip_and_bp(pid, tid, regs.ip(), regs.bp(), type, lost_samples, arg1, arg2, arg3);
|
return append_with_ip_and_bp(pid, tid, regs.ip(), regs.bp(), type, lost_samples, arg1, arg2, arg3, arg4, arg5, arg6);
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorOr<void> PerformanceEventBuffer::append_with_ip_and_bp(ProcessID pid, ThreadID tid,
|
ErrorOr<void> PerformanceEventBuffer::append_with_ip_and_bp(ProcessID pid, ThreadID tid,
|
||||||
FlatPtr ip, FlatPtr bp, int type, u32 lost_samples, FlatPtr arg1, FlatPtr arg2, StringView arg3)
|
FlatPtr ip, FlatPtr bp, int type, u32 lost_samples, FlatPtr arg1, FlatPtr arg2, StringView arg3, FlatPtr arg4, u64 arg5, ErrorOr<FlatPtr> arg6)
|
||||||
{
|
{
|
||||||
if (count() >= capacity())
|
if (count() >= capacity())
|
||||||
return ENOBUFS;
|
return ENOBUFS;
|
||||||
|
@ -165,6 +165,13 @@ ErrorOr<void> PerformanceEventBuffer::append_with_ip_and_bp(ProcessID pid, Threa
|
||||||
event.data.signpost.arg1 = arg1;
|
event.data.signpost.arg1 = arg1;
|
||||||
event.data.signpost.arg2 = arg2;
|
event.data.signpost.arg2 = arg2;
|
||||||
break;
|
break;
|
||||||
|
case PERF_EVENT_READ:
|
||||||
|
event.data.read.fd = arg1;
|
||||||
|
event.data.read.size = arg2;
|
||||||
|
event.data.read.filename_index = arg4;
|
||||||
|
event.data.read.start_timestamp = arg5;
|
||||||
|
event.data.read.success = !arg6.is_error();
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
|
@ -278,6 +285,14 @@ ErrorOr<void> PerformanceEventBuffer::to_json_impl(Serializer& object) const
|
||||||
event_object.add("arg1"sv, event.data.signpost.arg1);
|
event_object.add("arg1"sv, event.data.signpost.arg1);
|
||||||
event_object.add("arg2"sv, event.data.signpost.arg2);
|
event_object.add("arg2"sv, event.data.signpost.arg2);
|
||||||
break;
|
break;
|
||||||
|
case PERF_EVENT_READ:
|
||||||
|
event_object.add("type", "read");
|
||||||
|
event_object.add("fd", event.data.read.fd);
|
||||||
|
event_object.add("size"sv, event.data.read.size);
|
||||||
|
event_object.add("filename_index"sv, event.data.read.filename_index);
|
||||||
|
event_object.add("start_timestamp"sv, event.data.read.start_timestamp);
|
||||||
|
event_object.add("success"sv, event.data.read.success);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
event_object.add("pid", event.pid);
|
event_object.add("pid", event.pid);
|
||||||
event_object.add("tid", event.tid);
|
event_object.add("tid", event.tid);
|
||||||
|
|
|
@ -68,8 +68,16 @@ struct [[gnu::packed]] SignpostPerformanceEvent {
|
||||||
FlatPtr arg2;
|
FlatPtr arg2;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct [[gnu::packed]] ReadPerformanceEvent {
|
||||||
|
int fd;
|
||||||
|
size_t size;
|
||||||
|
size_t filename_index;
|
||||||
|
size_t start_timestamp;
|
||||||
|
bool success;
|
||||||
|
};
|
||||||
|
|
||||||
struct [[gnu::packed]] PerformanceEvent {
|
struct [[gnu::packed]] PerformanceEvent {
|
||||||
u16 type { 0 };
|
u32 type { 0 };
|
||||||
u8 stack_size { 0 };
|
u8 stack_size { 0 };
|
||||||
u32 pid { 0 };
|
u32 pid { 0 };
|
||||||
u32 tid { 0 };
|
u32 tid { 0 };
|
||||||
|
@ -87,6 +95,7 @@ struct [[gnu::packed]] PerformanceEvent {
|
||||||
KMallocPerformanceEvent kmalloc;
|
KMallocPerformanceEvent kmalloc;
|
||||||
KFreePerformanceEvent kfree;
|
KFreePerformanceEvent kfree;
|
||||||
SignpostPerformanceEvent signpost;
|
SignpostPerformanceEvent signpost;
|
||||||
|
ReadPerformanceEvent read;
|
||||||
} data;
|
} data;
|
||||||
static constexpr size_t max_stack_frame_count = 64;
|
static constexpr size_t max_stack_frame_count = 64;
|
||||||
FlatPtr stack[max_stack_frame_count];
|
FlatPtr stack[max_stack_frame_count];
|
||||||
|
@ -101,11 +110,11 @@ class PerformanceEventBuffer {
|
||||||
public:
|
public:
|
||||||
static OwnPtr<PerformanceEventBuffer> try_create_with_size(size_t buffer_size);
|
static OwnPtr<PerformanceEventBuffer> try_create_with_size(size_t buffer_size);
|
||||||
|
|
||||||
ErrorOr<void> append(int type, FlatPtr arg1, FlatPtr arg2, StringView arg3, Thread* current_thread = Thread::current());
|
ErrorOr<void> append(int type, FlatPtr arg1, FlatPtr arg2, StringView arg3, Thread* current_thread = Thread::current(), FlatPtr arg4 = 0, u64 arg5 = 0, ErrorOr<FlatPtr> arg6 = 0);
|
||||||
ErrorOr<void> append_with_ip_and_bp(ProcessID pid, ThreadID tid, FlatPtr eip, FlatPtr ebp,
|
ErrorOr<void> append_with_ip_and_bp(ProcessID pid, ThreadID tid, FlatPtr eip, FlatPtr ebp,
|
||||||
int type, u32 lost_samples, FlatPtr arg1, FlatPtr arg2, StringView arg3);
|
int type, u32 lost_samples, FlatPtr arg1, FlatPtr arg2, StringView arg3, FlatPtr arg4 = 0, u64 arg5 = {}, ErrorOr<FlatPtr> arg6 = 0);
|
||||||
ErrorOr<void> append_with_ip_and_bp(ProcessID pid, ThreadID tid, const RegisterState& regs,
|
ErrorOr<void> append_with_ip_and_bp(ProcessID pid, ThreadID tid, const RegisterState& regs,
|
||||||
int type, u32 lost_samples, FlatPtr arg1, FlatPtr arg2, StringView arg3);
|
int type, u32 lost_samples, FlatPtr arg1, FlatPtr arg2, StringView arg3, FlatPtr arg4 = 0, u64 arg5 = {}, ErrorOr<FlatPtr> arg6 = 0);
|
||||||
|
|
||||||
void clear()
|
void clear()
|
||||||
{
|
{
|
||||||
|
|
|
@ -127,6 +127,40 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline static void add_read_event(Thread& thread, int fd, size_t size, const OpenFileDescription& file_description, u64 start_timestamp, ErrorOr<FlatPtr> result)
|
||||||
|
{
|
||||||
|
if (thread.is_profiling_suppressed())
|
||||||
|
return;
|
||||||
|
|
||||||
|
auto* event_buffer = thread.process().current_perf_events_buffer();
|
||||||
|
if (event_buffer == nullptr)
|
||||||
|
return;
|
||||||
|
|
||||||
|
size_t filepath_string_index;
|
||||||
|
|
||||||
|
if (auto path = file_description.original_absolute_path(); !path.is_error()) {
|
||||||
|
auto registered_result = event_buffer->register_string(move(path.value()));
|
||||||
|
if (registered_result.is_error())
|
||||||
|
return;
|
||||||
|
filepath_string_index = registered_result.value();
|
||||||
|
} else if (auto pseudo_path = file_description.pseudo_path(); !pseudo_path.is_error()) {
|
||||||
|
auto registered_result = event_buffer->register_string(move(pseudo_path.value()));
|
||||||
|
if (registered_result.is_error())
|
||||||
|
return;
|
||||||
|
filepath_string_index = registered_result.value();
|
||||||
|
} else {
|
||||||
|
auto invalid_path_string = KString::try_create("<INVALID_FILE_PATH>"); // TODO: Performance, unecessary allocations.
|
||||||
|
if (invalid_path_string.is_error())
|
||||||
|
return;
|
||||||
|
auto registered_result = event_buffer->register_string(move(invalid_path_string.value()));
|
||||||
|
if (registered_result.is_error())
|
||||||
|
return;
|
||||||
|
filepath_string_index = registered_result.value();
|
||||||
|
}
|
||||||
|
|
||||||
|
[[maybe_unused]] auto rc = event_buffer->append(PERF_EVENT_READ, fd, size, 0, &thread, filepath_string_index, start_timestamp, result); // wrong arguments
|
||||||
|
}
|
||||||
|
|
||||||
inline static void timer_tick(RegisterState const& regs)
|
inline static void timer_tick(RegisterState const& regs)
|
||||||
{
|
{
|
||||||
static Time last_wakeup;
|
static Time last_wakeup;
|
||||||
|
|
|
@ -556,6 +556,8 @@ private:
|
||||||
|
|
||||||
ErrorOr<void> remap_range_as_stack(FlatPtr address, size_t size);
|
ErrorOr<void> remap_range_as_stack(FlatPtr address, size_t size);
|
||||||
|
|
||||||
|
ErrorOr<FlatPtr> read_impl(int fd, Userspace<u8*> buffer, size_t size);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
NonnullRefPtr<ProcessProcFSTraits> procfs_traits() const { return *m_procfs_traits; }
|
NonnullRefPtr<ProcessProcFSTraits> procfs_traits() const { return *m_procfs_traits; }
|
||||||
ErrorOr<void> procfs_get_fds_stats(KBufferBuilder& builder) const;
|
ErrorOr<void> procfs_get_fds_stats(KBufferBuilder& builder) const;
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
#include <Kernel/Debug.h>
|
#include <Kernel/Debug.h>
|
||||||
#include <Kernel/FileSystem/OpenFileDescription.h>
|
#include <Kernel/FileSystem/OpenFileDescription.h>
|
||||||
|
#include <Kernel/PerformanceManager.h>
|
||||||
#include <Kernel/Process.h>
|
#include <Kernel/Process.h>
|
||||||
|
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
|
@ -72,6 +73,20 @@ ErrorOr<FlatPtr> Process::sys$readv(int fd, Userspace<const struct iovec*> iov,
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorOr<FlatPtr> Process::sys$read(int fd, Userspace<u8*> buffer, size_t size)
|
ErrorOr<FlatPtr> Process::sys$read(int fd, Userspace<u8*> buffer, size_t size)
|
||||||
|
{
|
||||||
|
const auto start_timestamp = TimeManagement::the().uptime_ms();
|
||||||
|
const auto result = read_impl(fd, buffer, size);
|
||||||
|
|
||||||
|
if (Thread::current()->is_profiling_suppressed())
|
||||||
|
return result;
|
||||||
|
|
||||||
|
auto description = TRY(open_readable_file_description(fds(), fd));
|
||||||
|
PerformanceManager::add_read_event(*Thread::current(), fd, size, description, start_timestamp, result);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
ErrorOr<FlatPtr> Process::read_impl(int fd, Userspace<u8*> buffer, size_t size)
|
||||||
{
|
{
|
||||||
VERIFY_PROCESS_BIG_LOCK_ACQUIRED(this)
|
VERIFY_PROCESS_BIG_LOCK_ACQUIRED(this)
|
||||||
TRY(require_promise(Pledge::stdio));
|
TRY(require_promise(Pledge::stdio));
|
||||||
|
@ -81,6 +96,7 @@ ErrorOr<FlatPtr> Process::sys$read(int fd, Userspace<u8*> buffer, size_t size)
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
dbgln_if(IO_DEBUG, "sys$read({}, {}, {})", fd, buffer.ptr(), size);
|
dbgln_if(IO_DEBUG, "sys$read({}, {}, {})", fd, buffer.ptr(), size);
|
||||||
auto description = TRY(open_readable_file_description(fds(), fd));
|
auto description = TRY(open_readable_file_description(fds(), fd));
|
||||||
|
|
||||||
TRY(check_blocked_read(description));
|
TRY(check_blocked_read(description));
|
||||||
auto user_buffer = TRY(UserOrKernelBuffer::for_user_buffer(buffer, size));
|
auto user_buffer = TRY(UserOrKernelBuffer::for_user_buffer(buffer, size));
|
||||||
return TRY(description->read(user_buffer, size));
|
return TRY(description->read(user_buffer, size));
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue