diff options
author | Andreas Kling <kling@serenityos.org> | 2021-08-14 00:41:38 +0200 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2021-08-14 01:28:26 +0200 |
commit | 8f590cbeb8adfc6eda25fc34c2d0cfeb7333f81d (patch) | |
tree | 3f6934aaf50df6cd683c4066e06b0fd42cba378c | |
parent | 9a334ebb3a01ba03ae52a290955e1036c336aaac (diff) | |
download | serenity-8f590cbeb8adfc6eda25fc34c2d0cfeb7333f81d.zip |
Profiler: Add a "Signposts" tab next to the "Samples" tab
This tab provides a filtered listing of all the signpost events in the
currently selected time range.
-rw-r--r-- | Userland/DevTools/Profiler/CMakeLists.txt | 1 | ||||
-rw-r--r-- | Userland/DevTools/Profiler/Profile.cpp | 16 | ||||
-rw-r--r-- | Userland/DevTools/Profiler/Profile.h | 5 | ||||
-rw-r--r-- | Userland/DevTools/Profiler/SignpostsModel.cpp | 95 | ||||
-rw-r--r-- | Userland/DevTools/Profiler/SignpostsModel.h | 47 | ||||
-rw-r--r-- | Userland/DevTools/Profiler/main.cpp | 15 |
6 files changed, 178 insertions, 1 deletions
diff --git a/Userland/DevTools/Profiler/CMakeLists.txt b/Userland/DevTools/Profiler/CMakeLists.txt index f08eebaa15..427a8340cb 100644 --- a/Userland/DevTools/Profiler/CMakeLists.txt +++ b/Userland/DevTools/Profiler/CMakeLists.txt @@ -12,6 +12,7 @@ set(SOURCES Profile.cpp ProfileModel.cpp SamplesModel.cpp + SignpostsModel.cpp TimelineContainer.cpp TimelineHeader.cpp TimelineTrack.cpp diff --git a/Userland/DevTools/Profiler/Profile.cpp b/Userland/DevTools/Profiler/Profile.cpp index 104af281ca..432bcf17ba 100644 --- a/Userland/DevTools/Profiler/Profile.cpp +++ b/Userland/DevTools/Profiler/Profile.cpp @@ -45,6 +45,7 @@ Profile::Profile(Vector<Process> processes, Vector<Event> events) m_model = ProfileModel::create(*this); m_samples_model = SamplesModel::create(*this); + m_signposts_model = SignpostsModel::create(*this); rebuild_tree(); } @@ -59,6 +60,11 @@ GUI::Model& Profile::samples_model() return *m_samples_model; } +GUI::Model& Profile::signposts_model() +{ + return *m_signposts_model; +} + void Profile::rebuild_tree() { Vector<NonnullRefPtr<ProfileNode>> roots; @@ -92,6 +98,7 @@ void Profile::rebuild_tree() }); m_filtered_event_indices.clear(); + m_filtered_signpost_indices.clear(); for (size_t event_index = 0; event_index < m_events.size(); ++event_index) { auto& event = m_events.at(event_index); @@ -105,8 +112,10 @@ void Profile::rebuild_tree() if (!process_filter_contains(event.pid, event.serial)) continue; - if (event.data.has<Event::SignpostData>()) + if (event.data.has<Event::SignpostData>()) { + m_filtered_signpost_indices.append(event_index); continue; + } m_filtered_event_indices.append(event_index); @@ -435,6 +444,7 @@ void Profile::set_timestamp_filter_range(u64 start, u64 end) rebuild_tree(); m_samples_model->invalidate(); + m_signposts_model->invalidate(); } void Profile::clear_timestamp_filter_range() @@ -444,6 +454,7 @@ void Profile::clear_timestamp_filter_range() m_has_timestamp_filter_range = false; rebuild_tree(); m_samples_model->invalidate(); + m_signposts_model->invalidate(); } void Profile::add_process_filter(pid_t pid, EventSerialNumber start_valid, EventSerialNumber end_valid) @@ -457,6 +468,7 @@ void Profile::add_process_filter(pid_t pid, EventSerialNumber start_valid, Event if (m_disassembly_model) m_disassembly_model->invalidate(); m_samples_model->invalidate(); + m_signposts_model->invalidate(); } void Profile::remove_process_filter(pid_t pid, EventSerialNumber start_valid, EventSerialNumber end_valid) @@ -472,6 +484,7 @@ void Profile::remove_process_filter(pid_t pid, EventSerialNumber start_valid, Ev if (m_disassembly_model) m_disassembly_model->invalidate(); m_samples_model->invalidate(); + m_signposts_model->invalidate(); } void Profile::clear_process_filter() @@ -483,6 +496,7 @@ void Profile::clear_process_filter() if (m_disassembly_model) m_disassembly_model->invalidate(); m_samples_model->invalidate(); + m_signposts_model->invalidate(); } bool Profile::process_filter_contains(pid_t pid, EventSerialNumber serial) diff --git a/Userland/DevTools/Profiler/Profile.h b/Userland/DevTools/Profiler/Profile.h index f665513797..4bd65b4f5c 100644 --- a/Userland/DevTools/Profiler/Profile.h +++ b/Userland/DevTools/Profiler/Profile.h @@ -11,6 +11,7 @@ #include "Profile.h" #include "ProfileModel.h" #include "SamplesModel.h" +#include "SignpostsModel.h" #include <AK/Bitmap.h> #include <AK/FlyString.h> #include <AK/JsonArray.h> @@ -142,6 +143,7 @@ public: GUI::Model& model(); GUI::Model& samples_model(); + GUI::Model& signposts_model(); GUI::Model* disassembly_model(); const Process* find_process(pid_t pid, EventSerialNumber serial) const @@ -219,6 +221,7 @@ public: Vector<Event> const& events() const { return m_events; } const Vector<size_t>& filtered_event_indices() const { return m_filtered_event_indices; } + const Vector<size_t>& filtered_signpost_indices() const { return m_filtered_signpost_indices; } u64 length_in_ms() const { return m_last_timestamp - m_first_timestamp; } u64 first_timestamp() const { return m_first_timestamp; } @@ -274,6 +277,7 @@ private: RefPtr<ProfileModel> m_model; RefPtr<SamplesModel> m_samples_model; + RefPtr<SignpostsModel> m_signposts_model; RefPtr<DisassemblyModel> m_disassembly_model; GUI::ModelIndex m_disassembly_index; @@ -286,6 +290,7 @@ private: Vector<Process> m_processes; Vector<Event> m_events; Vector<size_t> m_signpost_indices; + Vector<size_t> m_filtered_signpost_indices; bool m_has_timestamp_filter_range { false }; u64 m_timestamp_filter_range_start { 0 }; diff --git a/Userland/DevTools/Profiler/SignpostsModel.cpp b/Userland/DevTools/Profiler/SignpostsModel.cpp new file mode 100644 index 0000000000..e652cf4fce --- /dev/null +++ b/Userland/DevTools/Profiler/SignpostsModel.cpp @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2021, Andreas Kling <kling@serenityos.org> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include "SignpostsModel.h" +#include "Profile.h" +#include <AK/StringBuilder.h> + +namespace Profiler { + +SignpostsModel::SignpostsModel(Profile& profile) + : m_profile(profile) +{ +} + +SignpostsModel::~SignpostsModel() +{ +} + +int SignpostsModel::row_count(const GUI::ModelIndex&) const +{ + return m_profile.filtered_signpost_indices().size(); +} + +int SignpostsModel::column_count(const GUI::ModelIndex&) const +{ + return Column::__Count; +} + +String SignpostsModel::column_name(int column) const +{ + switch (column) { + case Column::SignpostIndex: + return "#"; + case Column::Timestamp: + return "Timestamp"; + case Column::ProcessID: + return "PID"; + case Column::ThreadID: + return "TID"; + case Column::ExecutableName: + return "Executable"; + case Column::SignpostString: + return "String"; + case Column::SignpostArgument: + return "Argument"; + default: + VERIFY_NOT_REACHED(); + } +} + +GUI::Variant SignpostsModel::data(const GUI::ModelIndex& index, GUI::ModelRole role) const +{ + u32 event_index = m_profile.filtered_signpost_indices()[index.row()]; + auto& event = m_profile.events().at(event_index); + + if (role == GUI::ModelRole::Custom) { + return event_index; + } + + if (role == GUI::ModelRole::Display) { + if (index.column() == Column::SignpostIndex) + return event_index; + + if (index.column() == Column::ProcessID) + return event.pid; + + if (index.column() == Column::ThreadID) + return event.tid; + + if (index.column() == Column::ExecutableName) { + if (auto* process = m_profile.find_process(event.pid, event.serial)) + return process->executable; + return ""; + } + + if (index.column() == Column::Timestamp) { + return (u32)event.timestamp; + } + + if (index.column() == Column::SignpostString) { + return event.data.get<Profile::Event::SignpostData>().string; + } + + if (index.column() == Column::SignpostArgument) { + return event.data.get<Profile::Event::SignpostData>().arg; + } + return {}; + } + return {}; +} + +} diff --git a/Userland/DevTools/Profiler/SignpostsModel.h b/Userland/DevTools/Profiler/SignpostsModel.h new file mode 100644 index 0000000000..5162c30694 --- /dev/null +++ b/Userland/DevTools/Profiler/SignpostsModel.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2021, Andreas Kling <kling@serenityos.org> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include <LibGUI/Model.h> + +namespace Profiler { + +class Profile; + +class SignpostsModel final : public GUI::Model { +public: + static NonnullRefPtr<SignpostsModel> create(Profile& profile) + { + return adopt_ref(*new SignpostsModel(profile)); + } + + enum Column { + SignpostIndex, + Timestamp, + ProcessID, + ThreadID, + ExecutableName, + SignpostString, + SignpostArgument, + __Count + }; + + virtual ~SignpostsModel() override; + + virtual int row_count(const GUI::ModelIndex& = GUI::ModelIndex()) const override; + virtual int column_count(const GUI::ModelIndex& = GUI::ModelIndex()) const override; + virtual String column_name(int) const override; + virtual GUI::Variant data(const GUI::ModelIndex&, GUI::ModelRole) const override; + virtual bool is_column_sortable(int) const override { return false; } + +private: + explicit SignpostsModel(Profile&); + + Profile& m_profile; +}; + +} diff --git a/Userland/DevTools/Profiler/main.cpp b/Userland/DevTools/Profiler/main.cpp index 77a9383bed..e3de2f2bcc 100644 --- a/Userland/DevTools/Profiler/main.cpp +++ b/Userland/DevTools/Profiler/main.cpp @@ -176,6 +176,21 @@ int main(int argc, char** argv) individual_sample_view.set_model(move(model)); }; + auto& signposts_tab = tab_widget.add_tab<GUI::Widget>("Signposts"); + signposts_tab.set_layout<GUI::VerticalBoxLayout>(); + signposts_tab.layout()->set_margins({ 4, 4, 4, 4 }); + + auto& signposts_splitter = signposts_tab.add<GUI::HorizontalSplitter>(); + auto& signposts_table_view = signposts_splitter.add<GUI::TableView>(); + signposts_table_view.set_model(profile->signposts_model()); + + auto& individual_signpost_view = signposts_splitter.add<GUI::TableView>(); + signposts_table_view.on_selection_change = [&] { + const auto& index = signposts_table_view.selection().first(); + auto model = IndividualSampleModel::create(*profile, index.data(GUI::ModelRole::Custom).to_integer<size_t>()); + individual_signpost_view.set_model(move(model)); + }; + const u64 start_of_trace = profile->first_timestamp(); const u64 end_of_trace = start_of_trace + profile->length_in_ms(); const auto clamp_timestamp = [start_of_trace, end_of_trace](u64 timestamp) -> u64 { |