summaryrefslogtreecommitdiff
path: root/Userland/DevTools
diff options
context:
space:
mode:
authorAndreas Kling <kling@serenityos.org>2021-05-22 21:22:23 +0200
committerAndreas Kling <kling@serenityos.org>2021-05-22 22:23:52 +0200
commit8a5c78e93b6f51cf19c45a97fd52a56552d02feb (patch)
tree94fc904cfdc3defadb251ea053ddad810578aade /Userland/DevTools
parent65a341b82fc374b766e0eb205556baaca96fcc13 (diff)
downloadserenity-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.cpp8
-rw-r--r--Userland/DevTools/Profiler/Process.h1
-rw-r--r--Userland/DevTools/Profiler/Profile.cpp38
-rw-r--r--Userland/DevTools/Profiler/Profile.h19
-rw-r--r--Userland/DevTools/Profiler/ProfileModel.cpp10
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 {};