diff options
author | Andreas Kling <kling@serenityos.org> | 2021-05-22 21:22:23 +0200 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2021-05-22 22:23:52 +0200 |
commit | 8a5c78e93b6f51cf19c45a97fd52a56552d02feb (patch) | |
tree | 94fc904cfdc3defadb251ea053ddad810578aade /Userland/DevTools | |
parent | 65a341b82fc374b766e0eb205556baaca96fcc13 (diff) | |
download | serenity-8a5c78e93b6f51cf19c45a97fd52a56552d02feb.zip |
Profiler: Split the call tree into one subtree per process
This patch adds an additional level of hierarchy to the call tree:
Every process gets its own top-level node. :^)
Before this, selecting multiple processes would get quite confusing
as all the call stacks from different processes were combined together
into one big tree.
Diffstat (limited to 'Userland/DevTools')
-rw-r--r-- | Userland/DevTools/Profiler/DisassemblyModel.cpp | 8 | ||||
-rw-r--r-- | Userland/DevTools/Profiler/Process.h | 1 | ||||
-rw-r--r-- | Userland/DevTools/Profiler/Profile.cpp | 38 | ||||
-rw-r--r-- | Userland/DevTools/Profiler/Profile.h | 19 | ||||
-rw-r--r-- | Userland/DevTools/Profiler/ProfileModel.cpp | 10 |
5 files changed, 49 insertions, 27 deletions
diff --git a/Userland/DevTools/Profiler/DisassemblyModel.cpp b/Userland/DevTools/Profiler/DisassemblyModel.cpp index 9a6f6bfdeb..59e7818990 100644 --- a/Userland/DevTools/Profiler/DisassemblyModel.cpp +++ b/Userland/DevTools/Profiler/DisassemblyModel.cpp @@ -50,12 +50,8 @@ DisassemblyModel::DisassemblyModel(Profile& profile, ProfileNode& node) kernel_elf = make<ELF::Image>((const u8*)m_kernel_file->data(), m_kernel_file->size()); elf = kernel_elf.ptr(); } else { - auto process = node.process(profile, node.timestamp()); - if (!process) { - dbgln("no process for address {:p}", node.address()); - return; - } - auto library_data = process->library_metadata.library_containing(node.address()); + auto& process = node.process(); + auto library_data = process.library_metadata.library_containing(node.address()); if (!library_data) { dbgln("no library data for address {:p}", node.address()); return; diff --git a/Userland/DevTools/Profiler/Process.h b/Userland/DevTools/Profiler/Process.h index b928d7bc23..aec50c6142 100644 --- a/Userland/DevTools/Profiler/Process.h +++ b/Userland/DevTools/Profiler/Process.h @@ -54,6 +54,7 @@ struct Thread { struct Process { pid_t pid {}; String executable; + String basename; HashMap<int, Vector<Thread>> threads {}; LibraryMetadata library_metadata {}; u64 start_valid; diff --git a/Userland/DevTools/Profiler/Profile.cpp b/Userland/DevTools/Profiler/Profile.cpp index 59f1923954..ce89740bd4 100644 --- a/Userland/DevTools/Profiler/Profile.cpp +++ b/Userland/DevTools/Profiler/Profile.cpp @@ -61,13 +61,13 @@ void Profile::rebuild_tree() { Vector<NonnullRefPtr<ProfileNode>> roots; - auto find_or_create_root = [&roots](FlyString object_name, String symbol, u32 address, u32 offset, u64 timestamp, pid_t pid) -> ProfileNode& { + auto find_or_create_process_node = [this, &roots](pid_t pid, u64 timestamp) -> ProfileNode& { + auto& process = *find_process(pid, timestamp); for (auto root : roots) { - if (root->symbol() == symbol) { + if (&root->process() == &process) return root; - } } - auto new_root = ProfileNode::create(move(object_name), move(symbol), address, offset, timestamp, pid); + auto new_root = ProfileNode::create_process_node(process); roots.append(new_root); return new_root; }; @@ -119,6 +119,8 @@ void Profile::rebuild_tree() if (!m_show_top_functions) { ProfileNode* node = nullptr; + auto& process_node = find_or_create_process_node(event.pid, event.timestamp); + process_node.increment_event_count(); for_each_frame([&](const Frame& frame, bool is_innermost_frame) { auto& object_name = frame.object_name; auto& symbol = frame.symbol; @@ -130,9 +132,8 @@ void Profile::rebuild_tree() // FIXME: More cheating with intentional mixing of TID/PID here: if (!node) - node = &find_or_create_root(object_name, symbol, address, offset, event.timestamp, event.pid); - else - node = &node->find_or_create_child(object_name, symbol, address, offset, event.timestamp, event.pid); + node = &process_node; + node = &node->find_or_create_child(object_name, symbol, address, offset, event.timestamp, event.pid); node->increment_event_count(); if (is_innermost_frame) { @@ -142,6 +143,8 @@ void Profile::rebuild_tree() return IterationDecision::Continue; }); } else { + auto& process_node = find_or_create_process_node(event.pid, event.timestamp); + process_node.increment_event_count(); for (size_t i = 0; i < event.frames.size(); ++i) { ProfileNode* node = nullptr; ProfileNode* root = nullptr; @@ -156,7 +159,8 @@ void Profile::rebuild_tree() // FIXME: More PID/TID mixing cheats here: if (!node) { - node = &find_or_create_root(object_name, symbol, address, offset, event.timestamp, event.pid); + node = &find_or_create_process_node(event.pid, event.timestamp); + node = &node->find_or_create_child(object_name, symbol, address, offset, event.timestamp, event.pid); root = node; root->will_track_seen_events(m_events.size()); } else { @@ -248,6 +252,7 @@ Result<NonnullOwnPtr<Profile>, String> Profile::load_from_perfcore_file(const St auto sampled_process = adopt_own(*new Process { .pid = event.pid, .executable = event.executable, + .basename = LexicalPath(event.executable).basename(), .start_valid = event.timestamp, }); @@ -265,6 +270,7 @@ Result<NonnullOwnPtr<Profile>, String> Profile::load_from_perfcore_file(const St auto sampled_process = adopt_own(*new Process { .pid = event.pid, .executable = event.executable, + .basename = LexicalPath(event.executable).basename(), .start_valid = event.timestamp }); current_processes.set(sampled_process->pid, sampled_process); @@ -463,8 +469,15 @@ GUI::Model* Profile::disassembly_model() return m_disassembly_model; } -ProfileNode::ProfileNode(const String& object_name, String symbol, u32 address, u32 offset, u64 timestamp, pid_t pid) - : m_symbol(move(symbol)) +ProfileNode::ProfileNode(Process const& process) + : m_root(true) + , m_process(process) +{ +} + +ProfileNode::ProfileNode(Process const& process, const String& object_name, String symbol, u32 address, u32 offset, u64 timestamp, pid_t pid) + : m_process(process) + , m_symbol(move(symbol)) , m_pid(pid) , m_address(address) , m_offset(offset) @@ -479,9 +492,4 @@ ProfileNode::ProfileNode(const String& object_name, String symbol, u32 address, m_object_name = LexicalPath(object).basename(); } -const Process* ProfileNode::process(Profile& profile, u64 timestamp) const -{ - return profile.find_process(m_pid, timestamp); -} - } diff --git a/Userland/DevTools/Profiler/Profile.h b/Userland/DevTools/Profiler/Profile.h index eaccf27ac6..e25fe3ea29 100644 --- a/Userland/DevTools/Profiler/Profile.h +++ b/Userland/DevTools/Profiler/Profile.h @@ -28,9 +28,14 @@ namespace Profiler { class ProfileNode : public RefCounted<ProfileNode> { public: - static NonnullRefPtr<ProfileNode> create(FlyString object_name, String symbol, u32 address, u32 offset, u64 timestamp, pid_t pid) + static NonnullRefPtr<ProfileNode> create(Process const& process, FlyString object_name, String symbol, u32 address, u32 offset, u64 timestamp, pid_t pid) { - return adopt_ref(*new ProfileNode(move(object_name), move(symbol), address, offset, timestamp, pid)); + return adopt_ref(*new ProfileNode(process, move(object_name), move(symbol), address, offset, timestamp, pid)); + } + + static NonnullRefPtr<ProfileNode> create_process_node(Process const& process) + { + return adopt_ref(*new ProfileNode(process)); } // These functions are only relevant for root nodes @@ -71,7 +76,7 @@ public: return child; } } - auto new_child = ProfileNode::create(move(object_name), move(symbol), address, offset, timestamp, pid); + auto new_child = ProfileNode::create(m_process, move(object_name), move(symbol), address, offset, timestamp, pid); add_child(new_child); return new_child; }; @@ -96,11 +101,15 @@ public: pid_t pid() const { return m_pid; } - const Process* process(Profile&, u64 timestamp) const; + Process const& process() const { return m_process; } + bool is_root() const { return m_root; } private: - explicit ProfileNode(const String& object_name, String symbol, u32 address, u32 offset, u64 timestamp, pid_t); + explicit ProfileNode(Process const&); + explicit ProfileNode(Process const&, const String& object_name, String symbol, u32 address, u32 offset, u64 timestamp, pid_t); + bool m_root { false }; + Process const& m_process; ProfileNode* m_parent { nullptr }; FlyString m_object_name; String m_symbol; diff --git a/Userland/DevTools/Profiler/ProfileModel.cpp b/Userland/DevTools/Profiler/ProfileModel.cpp index f34f51722c..055106f98b 100644 --- a/Userland/DevTools/Profiler/ProfileModel.cpp +++ b/Userland/DevTools/Profiler/ProfileModel.cpp @@ -7,6 +7,7 @@ #include "ProfileModel.h" #include "Profile.h" #include <AK/StringBuilder.h> +#include <LibGUI/FileIconProvider.h> #include <ctype.h> #include <stdio.h> @@ -101,6 +102,9 @@ GUI::Variant ProfileModel::data(const GUI::ModelIndex& index, GUI::ModelRole rol } if (role == GUI::ModelRole::Icon) { if (index.column() == Column::StackFrame) { + if (node->is_root()) { + return GUI::FileIconProvider::icon_for_executable(node->process().executable); + } if (node->address() >= 0xc0000000) return m_kernel_frame_icon; return m_user_frame_icon; @@ -120,8 +124,12 @@ GUI::Variant ProfileModel::data(const GUI::ModelIndex& index, GUI::ModelRole rol } if (index.column() == Column::ObjectName) return node->object_name(); - if (index.column() == Column::StackFrame) + if (index.column() == Column::StackFrame) { + if (node->is_root()) { + return String::formatted("{} ({})", node->process().basename, node->process().pid); + } return node->symbol(); + } return {}; } return {}; |