Serenity Operating System
1/*
2 * Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
3 *
4 * SPDX-License-Identifier: BSD-2-Clause
5 */
6
7#pragma once
8
9#include <AK/Error.h>
10#include <Kernel/KBuffer.h>
11
12namespace Kernel {
13
14class KBufferBuilder;
15struct RegisterState;
16
17struct [[gnu::packed]] MallocPerformanceEvent {
18 size_t size;
19 FlatPtr ptr;
20};
21
22struct [[gnu::packed]] FreePerformanceEvent {
23 size_t size;
24 FlatPtr ptr;
25};
26
27struct [[gnu::packed]] MmapPerformanceEvent {
28 size_t size;
29 FlatPtr ptr;
30 char name[64];
31};
32
33struct [[gnu::packed]] MunmapPerformanceEvent {
34 size_t size;
35 FlatPtr ptr;
36};
37
38struct [[gnu::packed]] ProcessCreatePerformanceEvent {
39 pid_t parent_pid;
40 char executable[64];
41};
42
43struct [[gnu::packed]] ProcessExecPerformanceEvent {
44 char executable[64];
45};
46
47struct [[gnu::packed]] ThreadCreatePerformanceEvent {
48 pid_t parent_tid;
49};
50
51struct [[gnu::packed]] ContextSwitchPerformanceEvent {
52 pid_t next_pid;
53 u32 next_tid;
54};
55
56struct [[gnu::packed]] KMallocPerformanceEvent {
57 size_t size;
58 FlatPtr ptr;
59};
60
61struct [[gnu::packed]] KFreePerformanceEvent {
62 size_t size;
63 FlatPtr ptr;
64};
65
66struct [[gnu::packed]] SignpostPerformanceEvent {
67 FlatPtr arg1;
68 FlatPtr arg2;
69};
70
71struct [[gnu::packed]] ReadPerformanceEvent {
72 int fd;
73 size_t size;
74 size_t filename_index;
75 size_t start_timestamp;
76 bool success;
77};
78
79struct [[gnu::packed]] PerformanceEvent {
80 u32 type { 0 };
81 u8 stack_size { 0 };
82 u32 pid { 0 };
83 u32 tid { 0 };
84 u64 timestamp;
85 u32 lost_samples;
86 union {
87 MallocPerformanceEvent malloc;
88 FreePerformanceEvent free;
89 MmapPerformanceEvent mmap;
90 MunmapPerformanceEvent munmap;
91 ProcessCreatePerformanceEvent process_create;
92 ProcessExecPerformanceEvent process_exec;
93 ThreadCreatePerformanceEvent thread_create;
94 ContextSwitchPerformanceEvent context_switch;
95 KMallocPerformanceEvent kmalloc;
96 KFreePerformanceEvent kfree;
97 SignpostPerformanceEvent signpost;
98 ReadPerformanceEvent read;
99 } data;
100 static constexpr size_t max_stack_frame_count = 64;
101 FlatPtr stack[max_stack_frame_count];
102};
103
104enum class ProcessEventType {
105 Create,
106 Exec
107};
108
109class PerformanceEventBuffer {
110public:
111 static OwnPtr<PerformanceEventBuffer> try_create_with_size(size_t buffer_size);
112
113 ErrorOr<void> append(int type, FlatPtr arg1, FlatPtr arg2, StringView arg3, Thread* current_thread = Thread::current(), FlatPtr arg4 = 0, u64 arg5 = 0, ErrorOr<FlatPtr> const& arg6 = 0);
114 ErrorOr<void> append_with_ip_and_bp(ProcessID pid, ThreadID tid, FlatPtr eip, FlatPtr ebp,
115 int type, u32 lost_samples, FlatPtr arg1, FlatPtr arg2, StringView arg3, FlatPtr arg4 = 0, u64 arg5 = {}, ErrorOr<FlatPtr> const& arg6 = 0);
116 ErrorOr<void> append_with_ip_and_bp(ProcessID pid, ThreadID tid, RegisterState const& regs,
117 int type, u32 lost_samples, FlatPtr arg1, FlatPtr arg2, StringView arg3, FlatPtr arg4 = 0, u64 arg5 = {}, ErrorOr<FlatPtr> const& arg6 = 0);
118
119 void clear()
120 {
121 m_count = 0;
122 }
123
124 size_t capacity() const { return m_buffer->size() / sizeof(PerformanceEvent); }
125 size_t count() const { return m_count; }
126 PerformanceEvent const& at(size_t index) const
127 {
128 return const_cast<PerformanceEventBuffer&>(*this).at(index);
129 }
130
131 ErrorOr<void> to_json(KBufferBuilder&) const;
132
133 ErrorOr<void> add_process(Process const&, ProcessEventType event_type);
134
135 ErrorOr<FlatPtr> register_string(NonnullOwnPtr<KString>);
136
137private:
138 explicit PerformanceEventBuffer(NonnullOwnPtr<KBuffer>);
139
140 template<typename Serializer>
141 ErrorOr<void> to_json_impl(Serializer&) const;
142
143 PerformanceEvent& at(size_t index);
144
145 size_t m_count { 0 };
146 NonnullOwnPtr<KBuffer> m_buffer;
147
148 HashMap<NonnullOwnPtr<KString>, size_t> m_strings;
149};
150
151extern bool g_profiling_all_threads;
152extern PerformanceEventBuffer* g_global_perf_events;
153extern u64 g_profiling_event_mask;
154
155}