mirror of
https://github.com/RGBCube/serenity
synced 2025-05-31 07:38:10 +00:00
Profiler: Implement "Top functions" feature like Instruments.app has
This view mode takes every stack frame and turns it into a root in the profile graph. This allows functions that are called from many places to bubble up to the top. It's a very handy way to discover heavy things in a profile that are otherwise obscured by having many callers.
This commit is contained in:
parent
46cc1f718e
commit
be4005cb9e
3 changed files with 83 additions and 19 deletions
|
@ -102,7 +102,8 @@ void Profile::rebuild_tree()
|
|||
live_allocations.remove(event.ptr);
|
||||
}
|
||||
|
||||
for (auto& event : m_events) {
|
||||
for (size_t event_index = 0; event_index < m_events.size(); ++event_index) {
|
||||
auto& event = m_events.at(event_index);
|
||||
if (has_timestamp_filter_range()) {
|
||||
auto timestamp = event.timestamp;
|
||||
if (timestamp < m_timestamp_filter_range_start || timestamp > m_timestamp_filter_range_end)
|
||||
|
@ -115,8 +116,6 @@ void Profile::rebuild_tree()
|
|||
if (event.type == "free")
|
||||
continue;
|
||||
|
||||
ProfileNode* node = nullptr;
|
||||
|
||||
auto for_each_frame = [&]<typename Callback>(Callback callback) {
|
||||
if (!m_inverted) {
|
||||
for (size_t i = 0; i < event.frames.size(); ++i) {
|
||||
|
@ -131,26 +130,62 @@ void Profile::rebuild_tree()
|
|||
}
|
||||
};
|
||||
|
||||
for_each_frame([&](const Frame& frame, bool is_innermost_frame) {
|
||||
auto& symbol = frame.symbol;
|
||||
auto& address = frame.address;
|
||||
auto& offset = frame.offset;
|
||||
if (!m_show_top_functions) {
|
||||
ProfileNode* node = nullptr;
|
||||
for_each_frame([&](const Frame& frame, bool is_innermost_frame) {
|
||||
auto& symbol = frame.symbol;
|
||||
auto& address = frame.address;
|
||||
auto& offset = frame.offset;
|
||||
|
||||
if (symbol.is_empty())
|
||||
return IterationDecision::Break;
|
||||
if (symbol.is_empty())
|
||||
return IterationDecision::Break;
|
||||
|
||||
if (!node)
|
||||
node = &find_or_create_root(symbol, address, offset, event.timestamp);
|
||||
else
|
||||
node = &node->find_or_create_child(symbol, address, offset, event.timestamp);
|
||||
if (!node)
|
||||
node = &find_or_create_root(symbol, address, offset, event.timestamp);
|
||||
else
|
||||
node = &node->find_or_create_child(symbol, address, offset, event.timestamp);
|
||||
|
||||
node->increment_event_count();
|
||||
if (is_innermost_frame) {
|
||||
node->add_event_address(address);
|
||||
node->increment_self_count();
|
||||
node->increment_event_count();
|
||||
if (is_innermost_frame) {
|
||||
node->add_event_address(address);
|
||||
node->increment_self_count();
|
||||
}
|
||||
return IterationDecision::Continue;
|
||||
});
|
||||
} else {
|
||||
for (size_t i = 0; i < event.frames.size(); ++i) {
|
||||
ProfileNode* node = nullptr;
|
||||
ProfileNode* root = nullptr;
|
||||
for (size_t j = i; j < event.frames.size(); ++j) {
|
||||
auto& frame = event.frames.at(j);
|
||||
auto& symbol = frame.symbol;
|
||||
auto& address = frame.address;
|
||||
auto& offset = frame.offset;
|
||||
if (symbol.is_empty())
|
||||
break;
|
||||
|
||||
if (!node) {
|
||||
node = &find_or_create_root(symbol, address, offset, event.timestamp);
|
||||
root = node;
|
||||
root->will_track_seen_events(m_events.size());
|
||||
} else {
|
||||
node = &node->find_or_create_child(symbol, address, offset, event.timestamp);
|
||||
}
|
||||
|
||||
if (!root->has_seen_event(event_index)) {
|
||||
root->did_see_event(event_index);
|
||||
root->increment_event_count();
|
||||
} else if (node != root) {
|
||||
node->increment_event_count();
|
||||
}
|
||||
|
||||
if (j == event.frames.size() - 1) {
|
||||
node->add_event_address(address);
|
||||
node->increment_self_count();
|
||||
}
|
||||
}
|
||||
}
|
||||
return IterationDecision::Continue;
|
||||
});
|
||||
}
|
||||
|
||||
++filtered_event_count;
|
||||
}
|
||||
|
@ -283,6 +318,14 @@ void Profile::set_inverted(bool inverted)
|
|||
rebuild_tree();
|
||||
}
|
||||
|
||||
void Profile::set_show_top_functions(bool show)
|
||||
{
|
||||
if (m_show_top_functions == show)
|
||||
return;
|
||||
m_show_top_functions = show;
|
||||
rebuild_tree();
|
||||
}
|
||||
|
||||
void Profile::set_show_percentages(bool show_percentages)
|
||||
{
|
||||
if (m_show_percentages == show_percentages)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue