/* * Copyright (c) 2020, Andreas Kling * * SPDX-License-Identifier: BSD-2-Clause */ #pragma once #include #include namespace Kernel { class KBufferBuilder; struct RegisterState; struct [[gnu::packed]] MallocPerformanceEvent { size_t size; FlatPtr ptr; }; struct [[gnu::packed]] FreePerformanceEvent { size_t size; FlatPtr ptr; }; struct [[gnu::packed]] MmapPerformanceEvent { size_t size; FlatPtr ptr; char name[64]; }; struct [[gnu::packed]] MunmapPerformanceEvent { size_t size; FlatPtr ptr; }; struct [[gnu::packed]] ProcessCreatePerformanceEvent { pid_t parent_pid; char executable[64]; }; struct [[gnu::packed]] ProcessExecPerformanceEvent { char executable[64]; }; struct [[gnu::packed]] ThreadCreatePerformanceEvent { pid_t parent_tid; }; struct [[gnu::packed]] ContextSwitchPerformanceEvent { pid_t next_pid; u32 next_tid; }; struct [[gnu::packed]] KMallocPerformanceEvent { size_t size; FlatPtr ptr; }; struct [[gnu::packed]] KFreePerformanceEvent { size_t size; FlatPtr ptr; }; struct [[gnu::packed]] SignpostPerformanceEvent { FlatPtr arg1; 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 { u32 type { 0 }; u8 stack_size { 0 }; u32 pid { 0 }; u32 tid { 0 }; u64 timestamp; u32 lost_samples; union { MallocPerformanceEvent malloc; FreePerformanceEvent free; MmapPerformanceEvent mmap; MunmapPerformanceEvent munmap; ProcessCreatePerformanceEvent process_create; ProcessExecPerformanceEvent process_exec; ThreadCreatePerformanceEvent thread_create; ContextSwitchPerformanceEvent context_switch; KMallocPerformanceEvent kmalloc; KFreePerformanceEvent kfree; SignpostPerformanceEvent signpost; ReadPerformanceEvent read; } data; static constexpr size_t max_stack_frame_count = 64; FlatPtr stack[max_stack_frame_count]; }; enum class ProcessEventType { Create, Exec }; 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(), FlatPtr arg4 = 0, u64 arg5 = 0, ErrorOr const& 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, FlatPtr arg4 = 0, u64 arg5 = {}, ErrorOr const& arg6 = 0); ErrorOr append_with_ip_and_bp(ProcessID pid, ThreadID tid, RegisterState const& regs, int type, u32 lost_samples, FlatPtr arg1, FlatPtr arg2, StringView arg3, FlatPtr arg4 = 0, u64 arg5 = {}, ErrorOr const& arg6 = 0); void clear() { m_count = 0; } size_t capacity() const { return m_buffer->size() / sizeof(PerformanceEvent); } size_t count() const { return m_count; } PerformanceEvent const& at(size_t index) const { return const_cast(*this).at(index); } ErrorOr to_json(KBufferBuilder&) const; ErrorOr add_process(Process const&, ProcessEventType event_type); ErrorOr register_string(NonnullOwnPtr); private: explicit PerformanceEventBuffer(NonnullOwnPtr); template ErrorOr to_json_impl(Serializer&) const; PerformanceEvent& at(size_t index); size_t m_count { 0 }; NonnullOwnPtr m_buffer; HashMap, size_t> m_strings; }; extern bool g_profiling_all_threads; extern PerformanceEventBuffer* g_global_perf_events; extern u64 g_profiling_event_mask; }