Explorar el Código

Kernel: Track performance events for context switches

Gunnar Beutner hace 4 años
padre
commit
8b2ace0326

+ 9 - 0
Kernel/PerformanceEventBuffer.cpp

@@ -107,6 +107,10 @@ KResult PerformanceEventBuffer::append_with_eip_and_ebp(ProcessID pid, ThreadID
         break;
     case PERF_EVENT_THREAD_EXIT:
         break;
+    case PERF_EVENT_CONTEXT_SWITCH:
+        event.data.context_switch.next_pid = arg1;
+        event.data.context_switch.next_tid = arg2;
+        break;
     default:
         return EINVAL;
     }
@@ -180,6 +184,11 @@ bool PerformanceEventBuffer::to_json_impl(Serializer& object) const
         case PERF_EVENT_THREAD_EXIT:
             event_object.add("type", "thread_exit");
             break;
+        case PERF_EVENT_CONTEXT_SWITCH:
+            event_object.add("type", "context_switch");
+            event_object.add("next_pid", static_cast<u64>(event.data.context_switch.next_pid));
+            event_object.add("next_tid", static_cast<u64>(event.data.context_switch.next_tid));
+            break;
         }
         event_object.add("pid", event.pid);
         event_object.add("tid", event.tid);

+ 6 - 0
Kernel/PerformanceEventBuffer.h

@@ -47,6 +47,11 @@ struct [[gnu::packed]] ThreadCreatePerformanceEvent {
     pid_t parent_tid;
 };
 
+struct [[gnu::packed]] ContextSwitchPerformanceEvent {
+    pid_t next_pid;
+    u32 next_tid;
+};
+
 struct [[gnu::packed]] PerformanceEvent {
     u8 type { 0 };
     u8 stack_size { 0 };
@@ -62,6 +67,7 @@ struct [[gnu::packed]] PerformanceEvent {
         ProcessCreatePerformanceEvent process_create;
         ProcessExecPerformanceEvent process_exec;
         ThreadCreatePerformanceEvent thread_create;
+        ContextSwitchPerformanceEvent context_switch;
     } data;
     static constexpr size_t max_stack_frame_count = 64;
     FlatPtr stack[max_stack_frame_count];

+ 7 - 0
Kernel/PerformanceManager.h

@@ -85,6 +85,13 @@ public:
         }
     }
 
+    inline static void add_context_switch_perf_event(Thread& current_thread, Thread& next_thread)
+    {
+        if (auto* event_buffer = current_thread.process().current_perf_events_buffer()) {
+            [[maybe_unused]] auto res = event_buffer->append(PERF_EVENT_CONTEXT_SWITCH, next_thread.pid().value(), next_thread.tid().value(), nullptr);
+        }
+    }
+
     inline static void timer_tick(RegisterState const& regs)
     {
         static Time last_wakeup;

+ 3 - 0
Kernel/Scheduler.cpp

@@ -10,6 +10,7 @@
 #include <AK/Time.h>
 #include <Kernel/Debug.h>
 #include <Kernel/Panic.h>
+#include <Kernel/PerformanceManager.h>
 #include <Kernel/Process.h>
 #include <Kernel/RTC.h>
 #include <Kernel/Scheduler.h>
@@ -365,6 +366,8 @@ bool Scheduler::context_switch(Thread* thread)
     }
     thread->set_state(Thread::Running);
 
+    PerformanceManager::add_context_switch_perf_event(*from_thread, *thread);
+
     proc.switch_context(from_thread, thread);
 
     // NOTE: from_thread at this point reflects the thread we were

+ 2 - 1
Kernel/UnixTypes.h

@@ -56,7 +56,8 @@ enum {
     PERF_EVENT_PROCESS_EXEC,
     PERF_EVENT_PROCESS_EXIT,
     PERF_EVENT_THREAD_CREATE,
-    PERF_EVENT_THREAD_EXIT
+    PERF_EVENT_THREAD_EXIT,
+    PERF_EVENT_CONTEXT_SWITCH,
 };
 
 #define WNOHANG 1

+ 2 - 1
Userland/Libraries/LibC/serenity.h

@@ -85,7 +85,8 @@ enum {
     PERF_EVENT_PROCESS_EXEC,
     PERF_EVENT_PROCESS_EXIT,
     PERF_EVENT_THREAD_CREATE,
-    PERF_EVENT_THREAD_EXIT
+    PERF_EVENT_THREAD_EXIT,
+    PERF_EVENT_CONTEXT_SWITCH,
 };
 
 int perf_event(int type, uintptr_t arg1, uintptr_t arg2);