diff --git a/Kernel/API/POSIX/serenity.h b/Kernel/API/POSIX/serenity.h index eaa30095bc..1f9b46ad29 100644 --- a/Kernel/API/POSIX/serenity.h +++ b/Kernel/API/POSIX/serenity.h @@ -32,6 +32,7 @@ enum { PERF_EVENT_PAGE_FAULT = 8192, PERF_EVENT_SYSCALL = 16384, PERF_EVENT_SIGNPOST = 32768, + PERF_EVENT_READ = 65536, }; #define PERF_EVENT_MASK_ALL (~0ull) diff --git a/Kernel/PerformanceEventBuffer.cpp b/Kernel/PerformanceEventBuffer.cpp index 88e8fcceb9..2799ee2ae9 100644 --- a/Kernel/PerformanceEventBuffer.cpp +++ b/Kernel/PerformanceEventBuffer.cpp @@ -22,7 +22,7 @@ PerformanceEventBuffer::PerformanceEventBuffer(NonnullOwnPtr buffer) { } -NEVER_INLINE ErrorOr PerformanceEventBuffer::append(int type, FlatPtr arg1, FlatPtr arg2, StringView arg3, Thread* current_thread) +NEVER_INLINE ErrorOr PerformanceEventBuffer::append(int type, FlatPtr arg1, FlatPtr arg2, StringView arg3, Thread* current_thread, FlatPtr arg4, u64 arg5, ErrorOr arg6) { FlatPtr base_pointer; #if ARCH(I386) @@ -32,7 +32,7 @@ NEVER_INLINE ErrorOr PerformanceEventBuffer::append(int type, FlatPtr arg1 asm volatile("movq %%rbp, %%rax" : "=a"(base_pointer)); #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 raw_backtrace(FlatPtr bp, FlatPtr ip) @@ -73,13 +73,13 @@ static Vector raw_backtrace(Fl } ErrorOr 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 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 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 arg6) { if (count() >= capacity()) return ENOBUFS; @@ -165,6 +165,13 @@ ErrorOr PerformanceEventBuffer::append_with_ip_and_bp(ProcessID pid, Threa event.data.signpost.arg1 = arg1; event.data.signpost.arg2 = arg2; 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: return EINVAL; } @@ -278,6 +285,14 @@ ErrorOr PerformanceEventBuffer::to_json_impl(Serializer& object) const event_object.add("arg1"sv, event.data.signpost.arg1); event_object.add("arg2"sv, event.data.signpost.arg2); 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("tid", event.tid); diff --git a/Kernel/PerformanceEventBuffer.h b/Kernel/PerformanceEventBuffer.h index e07ca5ce1b..41d36a16cf 100644 --- a/Kernel/PerformanceEventBuffer.h +++ b/Kernel/PerformanceEventBuffer.h @@ -68,8 +68,16 @@ struct [[gnu::packed]] SignpostPerformanceEvent { 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 { - u16 type { 0 }; + u32 type { 0 }; u8 stack_size { 0 }; u32 pid { 0 }; u32 tid { 0 }; @@ -87,6 +95,7 @@ struct [[gnu::packed]] PerformanceEvent { KMallocPerformanceEvent kmalloc; KFreePerformanceEvent kfree; SignpostPerformanceEvent signpost; + ReadPerformanceEvent read; } data; static constexpr size_t max_stack_frame_count = 64; FlatPtr stack[max_stack_frame_count]; @@ -101,11 +110,11 @@ class PerformanceEventBuffer { public: static OwnPtr try_create_with_size(size_t buffer_size); - ErrorOr append(int type, FlatPtr arg1, FlatPtr arg2, StringView arg3, Thread* current_thread = Thread::current()); + ErrorOr append(int type, FlatPtr arg1, FlatPtr arg2, StringView arg3, Thread* current_thread = Thread::current(), FlatPtr arg4 = 0, u64 arg5 = 0, ErrorOr arg6 = 0); ErrorOr 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 arg6 = 0); ErrorOr 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 arg6 = 0); void clear() { diff --git a/Kernel/PerformanceManager.h b/Kernel/PerformanceManager.h index aba2e199b0..159a11e2f9 100644 --- a/Kernel/PerformanceManager.h +++ b/Kernel/PerformanceManager.h @@ -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 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(""); // 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) { static Time last_wakeup; diff --git a/Kernel/Process.h b/Kernel/Process.h index cd94e0426a..4e1c6f974f 100644 --- a/Kernel/Process.h +++ b/Kernel/Process.h @@ -556,6 +556,8 @@ private: ErrorOr remap_range_as_stack(FlatPtr address, size_t size); + ErrorOr read_impl(int fd, Userspace buffer, size_t size); + public: NonnullRefPtr procfs_traits() const { return *m_procfs_traits; } ErrorOr procfs_get_fds_stats(KBufferBuilder& builder) const; diff --git a/Kernel/Syscalls/read.cpp b/Kernel/Syscalls/read.cpp index 935daf1206..3e8e7e094f 100644 --- a/Kernel/Syscalls/read.cpp +++ b/Kernel/Syscalls/read.cpp @@ -6,6 +6,7 @@ #include #include +#include #include namespace Kernel { @@ -72,6 +73,20 @@ ErrorOr Process::sys$readv(int fd, Userspace iov, } ErrorOr Process::sys$read(int fd, Userspace 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 Process::read_impl(int fd, Userspace buffer, size_t size) { VERIFY_PROCESS_BIG_LOCK_ACQUIRED(this) TRY(require_promise(Pledge::stdio)); @@ -81,6 +96,7 @@ ErrorOr Process::sys$read(int fd, Userspace buffer, size_t size) return EINVAL; dbgln_if(IO_DEBUG, "sys$read({}, {}, {})", fd, buffer.ptr(), size); auto description = TRY(open_readable_file_description(fds(), fd)); + TRY(check_blocked_read(description)); auto user_buffer = TRY(UserOrKernelBuffer::for_user_buffer(buffer, size)); return TRY(description->read(user_buffer, size));