Преглед на файлове

Kernel/Profiling: Add profiling to read syscall

Syscalls to read can now be profiled, allowing us to monitor
filesystem usage by different applications.
Jakub Berkop преди 3 години
родител
ревизия
4916c892b2
променени са 6 файла, в които са добавени 86 реда и са изтрити 9 реда
  1. 1 0
      Kernel/API/POSIX/serenity.h
  2. 20 5
      Kernel/PerformanceEventBuffer.cpp
  3. 13 4
      Kernel/PerformanceEventBuffer.h
  4. 34 0
      Kernel/PerformanceManager.h
  5. 2 0
      Kernel/Process.h
  6. 16 0
      Kernel/Syscalls/read.cpp

+ 1 - 0
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)

+ 20 - 5
Kernel/PerformanceEventBuffer.cpp

@@ -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;
 #if ARCH(I386)
@@ -32,7 +32,7 @@ NEVER_INLINE ErrorOr<void> 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<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,
-    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,
-    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())
         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.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<void> 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);

+ 13 - 4
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<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,
-        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,
-        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()
     {

+ 34 - 0
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<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)
     {
         static Time last_wakeup;

+ 2 - 0
Kernel/Process.h

@@ -556,6 +556,8 @@ private:
 
     ErrorOr<void> remap_range_as_stack(FlatPtr address, size_t size);
 
+    ErrorOr<FlatPtr> read_impl(int fd, Userspace<u8*> buffer, size_t size);
+
 public:
     NonnullRefPtr<ProcessProcFSTraits> procfs_traits() const { return *m_procfs_traits; }
     ErrorOr<void> procfs_get_fds_stats(KBufferBuilder& builder) const;

+ 16 - 0
Kernel/Syscalls/read.cpp

@@ -6,6 +6,7 @@
 
 #include <Kernel/Debug.h>
 #include <Kernel/FileSystem/OpenFileDescription.h>
+#include <Kernel/PerformanceManager.h>
 #include <Kernel/Process.h>
 
 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)
+{
+    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)
     TRY(require_promise(Pledge::stdio));
@@ -81,6 +96,7 @@ ErrorOr<FlatPtr> Process::sys$read(int fd, Userspace<u8*> 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));