diff --git a/Userland/DevTools/Profiler/Profile.cpp b/Userland/DevTools/Profiler/Profile.cpp index 9d2df278b9..0d9dbc6b66 100644 --- a/Userland/DevTools/Profiler/Profile.cpp +++ b/Userland/DevTools/Profiler/Profile.cpp @@ -76,11 +76,15 @@ void Profile::rebuild_tree() HashTable live_allocations; - for_each_event_in_filter_range([&](auto& event) { - if (event.type == Event::Type::Malloc) - live_allocations.set(event.ptr); - else if (event.type == Event::Type::Free) - live_allocations.remove(event.ptr); + for_each_event_in_filter_range([&](Event const& event) { + event.data.visit( + [&](Event::MallocData const& data) { + live_allocations.set(data.ptr); + }, + [&](Event::FreeData const& data) { + live_allocations.remove(data.ptr); + }, + [&](auto&) {}); }); m_filtered_event_indices.clear(); @@ -99,10 +103,10 @@ void Profile::rebuild_tree() m_filtered_event_indices.append(event_index); - if (event.type == Event::Type::Malloc && !live_allocations.contains(event.ptr)) + if (auto* malloc_data = event.data.get_pointer(); malloc_data && !live_allocations.contains(malloc_data->ptr)) continue; - if (event.type == Event::Type::Free) + if (event.data.has()) continue; auto for_each_frame = [&](Callback callback) { @@ -245,43 +249,55 @@ Result, String> Profile::load_from_perfcore_file(const St auto type_string = perf_event.get("type").to_string(); if (type_string == "sample"sv) { - event.type = Event::Type::Sample; + event.data = Event::SampleData {}; } else if (type_string == "malloc"sv) { - event.type = Event::Type::Malloc; - event.ptr = perf_event.get("ptr").to_number(); - event.size = perf_event.get("size").to_number(); + event.data = Event::MallocData { + .ptr = perf_event.get("ptr"sv).to_number(), + .size = perf_event.get("size"sv).to_number(), + }; } else if (type_string == "free"sv) { - event.type = Event::Type::Free; - event.ptr = perf_event.get("ptr").to_number(); + event.data = Event::FreeData { + .ptr = perf_event.get("ptr"sv).to_number(), + }; } else if (type_string == "signpost"sv) { - event.type = Event::Type::Signpost; - auto string_id = perf_event.get("arg1").to_number(); - event.signpost_string = profile_strings.get(string_id).value_or(String::formatted("Signpost #{}", string_id)); - event.arg2 = perf_event.get("arg2").to_number(); + auto string_id = perf_event.get("arg1"sv).to_number(); + event.data = Event::SignpostData { + .string = profile_strings.get(string_id).value_or(String::formatted("Signpost #{}", string_id)), + .arg = perf_event.get("arg2"sv).to_number(), + }; } else if (type_string == "mmap"sv) { - event.type = Event::Type::Mmap; - event.ptr = perf_event.get("ptr").to_number(); - event.size = perf_event.get("size").to_number(); - event.name = perf_event.get("name").to_string(); + auto ptr = perf_event.get("ptr"sv).to_number(); + auto size = perf_event.get("size"sv).to_number(); + auto name = perf_event.get("name"sv).to_string(); + + event.data = Event::MmapData { + .ptr = ptr, + .size = size, + .name = name, + }; auto it = current_processes.find(event.pid); if (it != current_processes.end()) - it->value->library_metadata.handle_mmap(event.ptr, event.size, event.name); + it->value->library_metadata.handle_mmap(ptr, size, name); continue; } else if (type_string == "munmap"sv) { - event.type = Event::Type::Munmap; - event.ptr = perf_event.get("ptr").to_number(); - event.size = perf_event.get("size").to_number(); + event.data = Event::MunmapData { + .ptr = perf_event.get("ptr"sv).to_number(), + .size = perf_event.get("size"sv).to_number(), + }; continue; } else if (type_string == "process_create"sv) { - event.type = Event::Type::ProcessCreate; - event.parent_pid = perf_event.get("parent_pid").to_number(); - event.executable = perf_event.get("executable").to_string(); + auto parent_pid = perf_event.get("parent_pid"sv).to_number(); + auto executable = perf_event.get("executable"sv).to_string(); + event.data = Event::ProcessCreateData { + .parent_pid = parent_pid, + .executable = executable, + }; auto sampled_process = adopt_own(*new Process { .pid = event.pid, - .executable = event.executable, - .basename = LexicalPath::basename(event.executable), + .executable = executable, + .basename = LexicalPath::basename(executable), .start_valid = event.serial, .end_valid = {}, }); @@ -290,8 +306,10 @@ Result, String> Profile::load_from_perfcore_file(const St all_processes.append(move(sampled_process)); continue; } else if (type_string == "process_exec"sv) { - event.type = Event::Type::ProcessExec; - event.executable = perf_event.get("executable").to_string(); + auto executable = perf_event.get("executable"sv).to_string(); + event.data = Event::ProcessExecData { + .executable = executable, + }; auto old_process = current_processes.get(event.pid).value(); old_process->end_valid = event.serial; @@ -300,8 +318,8 @@ Result, String> Profile::load_from_perfcore_file(const St auto sampled_process = adopt_own(*new Process { .pid = event.pid, - .executable = event.executable, - .basename = LexicalPath::basename(event.executable), + .executable = executable, + .basename = LexicalPath::basename(executable), .start_valid = event.serial, .end_valid = {}, }); @@ -310,21 +328,21 @@ Result, String> Profile::load_from_perfcore_file(const St all_processes.append(move(sampled_process)); continue; } else if (type_string == "process_exit"sv) { - event.type = Event::Type::ProcessExit; auto old_process = current_processes.get(event.pid).value(); old_process->end_valid = event.serial; current_processes.remove(event.pid); continue; } else if (type_string == "thread_create"sv) { - event.type = Event::Type::ThreadCreate; - event.parent_tid = perf_event.get("parent_tid").to_i32(); + auto parent_tid = perf_event.get("parent_tid"sv).to_number(); + event.data = Event::ThreadCreateData { + .parent_tid = parent_tid, + }; auto it = current_processes.find(event.pid); if (it != current_processes.end()) it->value->handle_thread_create(event.tid, event.serial); continue; } else if (type_string == "thread_exit"sv) { - event.type = Event::Type::ThreadExit; auto it = current_processes.find(event.pid); if (it != current_processes.end()) it->value->handle_thread_exit(event.tid, event.serial); @@ -375,7 +393,9 @@ Result, String> Profile::load_from_perfcore_file(const St FlatPtr innermost_frame_address = event.frames.at(1).address; event.in_kernel = maybe_kernel_base.has_value() && innermost_frame_address >= maybe_kernel_base.value(); - if (event.type == Event::Type::Signpost) + dbgln("size: {}", sizeof(Event)); + + if (event.data.has()) signposts.append(move(event)); else events.append(move(event)); diff --git a/Userland/DevTools/Profiler/Profile.h b/Userland/DevTools/Profiler/Profile.h index 37ddabc345..d7f07204d5 100644 --- a/Userland/DevTools/Profiler/Profile.h +++ b/Userland/DevTools/Profiler/Profile.h @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -163,38 +164,57 @@ public: }; struct Event { - enum class Type { - Free, - Malloc, - Mmap, - Munmap, - ProcessCreate, - ProcessExec, - ProcessExit, - Sample, - Signpost, - ThreadCreate, - ThreadExit, - }; - Type type {}; - EventSerialNumber serial; u64 timestamp { 0 }; - FlatPtr ptr { 0 }; - size_t size { 0 }; - String name; - int parent_pid { 0 }; - int parent_tid { 0 }; - String executable; - int pid { 0 }; - int tid { 0 }; + EventSerialNumber serial; + pid_t pid { 0 }; + pid_t tid { 0 }; u32 lost_samples { 0 }; bool in_kernel { false }; - // FIXME: Put event type-specific arguments in a union to save memory. - String signpost_string; - FlatPtr arg2 {}; - Vector frames; + + struct SampleData { + }; + + struct MallocData { + FlatPtr ptr {}; + size_t size {}; + }; + + struct FreeData { + FlatPtr ptr {}; + }; + + struct SignpostData { + String string; + FlatPtr arg {}; + }; + + struct MmapData { + FlatPtr ptr {}; + size_t size {}; + String name; + }; + + struct MunmapData { + FlatPtr ptr {}; + size_t size {}; + }; + + struct ProcessCreateData { + pid_t parent_pid { 0 }; + String executable; + }; + + struct ProcessExecData { + String executable; + }; + + struct ThreadCreateData { + pid_t parent_tid {}; + }; + + Variant data { nullptr }; }; const Vector& events() const { return m_events; } diff --git a/Userland/DevTools/Profiler/TimelineTrack.cpp b/Userland/DevTools/Profiler/TimelineTrack.cpp index dcaef94c16..aa87042124 100644 --- a/Userland/DevTools/Profiler/TimelineTrack.cpp +++ b/Userland/DevTools/Profiler/TimelineTrack.cpp @@ -135,7 +135,8 @@ void TimelineTrack::mousemove_event(GUI::MouseEvent& event) constexpr int hoverable_padding = 2; Gfx::IntRect hoverable_rect { x - hoverable_padding, frame_thickness(), hoverable_padding * 2, height() - frame_thickness() * 2 }; if (hoverable_rect.contains_horizontally(event.x())) { - GUI::Application::the()->show_tooltip_immediately(String::formatted("{}, {}", signpost.signpost_string, signpost.arg2), this); + auto const& data = signpost.data.template get(); + GUI::Application::the()->show_tooltip_immediately(String::formatted("{}, {}", data.string, data.arg), this); hovering_a_signpost = true; return IterationDecision::Break; }