Serenity Operating System
1/*
2 * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice, this
9 * list of conditions and the following disclaimer.
10 *
11 * 2. Redistributions in binary form must reproduce the above copyright notice,
12 * this list of conditions and the following disclaimer in the documentation
13 * and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
22 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
23 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27#pragma once
28
29#include <AK/JsonArray.h>
30#include <AK/JsonObject.h>
31#include <AK/JsonValue.h>
32#include <AK/NonnullRefPtrVector.h>
33#include <AK/OwnPtr.h>
34#include <LibGUI/Forward.h>
35
36class ProfileModel;
37
38class ProfileNode : public RefCounted<ProfileNode> {
39public:
40 static NonnullRefPtr<ProfileNode> create(const String& symbol, u32 address, u32 offset, u64 timestamp)
41 {
42 return adopt(*new ProfileNode(symbol, address, offset, timestamp));
43 }
44
45 const String& symbol() const { return m_symbol; }
46 u32 address() const { return m_address; }
47 u32 offset() const { return m_offset; }
48 u64 timestamp() const { return m_timestamp; }
49
50 u32 event_count() const { return m_event_count; }
51 u32 self_count() const { return m_self_count; }
52
53 int child_count() const { return m_children.size(); }
54 const Vector<NonnullRefPtr<ProfileNode>>& children() const { return m_children; }
55
56 void add_child(ProfileNode& child)
57 {
58 if (child.m_parent == this)
59 return;
60 ASSERT(!child.m_parent);
61 child.m_parent = this;
62 m_children.append(child);
63 }
64
65 ProfileNode& find_or_create_child(const String& symbol, u32 address, u32 offset, u64 timestamp)
66 {
67 for (size_t i = 0; i < m_children.size(); ++i) {
68 auto& child = m_children[i];
69 if (child->symbol() == symbol) {
70 return child;
71 }
72 }
73 auto new_child = ProfileNode::create(symbol, address, offset, timestamp);
74 add_child(new_child);
75 return new_child;
76 };
77
78 ProfileNode* parent() { return m_parent; }
79 const ProfileNode* parent() const { return m_parent; }
80
81 void increment_event_count() { ++m_event_count; }
82 void increment_self_count() { ++m_self_count; }
83
84 void sort_children();
85
86private:
87 explicit ProfileNode(const String& symbol, u32 address, u32 offset, u64 timestamp)
88 : m_symbol(symbol)
89 , m_address(address)
90 , m_offset(offset)
91 , m_timestamp(timestamp)
92 {
93 }
94
95 ProfileNode* m_parent { nullptr };
96 String m_symbol;
97 u32 m_address { 0 };
98 u32 m_offset { 0 };
99 u32 m_event_count { 0 };
100 u32 m_self_count { 0 };
101 u64 m_timestamp { 0 };
102 Vector<NonnullRefPtr<ProfileNode>> m_children;
103};
104
105class Profile {
106public:
107 static OwnPtr<Profile> load_from_perfcore_file(const StringView& path);
108 ~Profile();
109
110 GUI::Model& model();
111
112 const Vector<NonnullRefPtr<ProfileNode>>& roots() const { return m_roots; }
113
114 struct Frame {
115 String symbol;
116 u32 address { 0 };
117 u32 offset { 0 };
118 };
119
120 struct Event {
121 u64 timestamp { 0 };
122 String type;
123 FlatPtr ptr { 0 };
124 size_t size { 0 };
125 bool in_kernel { false };
126 Vector<Frame> frames;
127 };
128
129 u32 filtered_event_count() const { return m_filtered_event_count; }
130
131 const Vector<Event>& events() const { return m_events; }
132
133 u64 length_in_ms() const { return m_last_timestamp - m_first_timestamp; }
134 u64 first_timestamp() const { return m_first_timestamp; }
135 u64 last_timestamp() const { return m_last_timestamp; }
136 u32 deepest_stack_depth() const { return m_deepest_stack_depth; }
137
138 void set_timestamp_filter_range(u64 start, u64 end);
139 void clear_timestamp_filter_range();
140 bool has_timestamp_filter_range() const { return m_has_timestamp_filter_range; }
141
142 bool is_inverted() const { return m_inverted; }
143 void set_inverted(bool);
144
145 bool show_percentages() const { return m_show_percentages; }
146 void set_show_percentages(bool);
147
148private:
149 explicit Profile(Vector<Event>);
150
151 void rebuild_tree();
152
153 RefPtr<ProfileModel> m_model;
154 Vector<NonnullRefPtr<ProfileNode>> m_roots;
155 u32 m_filtered_event_count { 0 };
156 u64 m_first_timestamp { 0 };
157 u64 m_last_timestamp { 0 };
158
159 Vector<Event> m_events;
160
161 bool m_has_timestamp_filter_range { false };
162 u64 m_timestamp_filter_range_start { 0 };
163 u64 m_timestamp_filter_range_end { 0 };
164
165 u32 m_deepest_stack_depth { 0 };
166 bool m_inverted { false };
167 bool m_show_percentages { false };
168};