diff options
author | Andreas Kling <kling@serenityos.org> | 2021-01-12 12:18:55 +0100 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2021-01-12 12:18:55 +0100 |
commit | 4055b0329117c1a280080bbd638eb48bafe29638 (patch) | |
tree | ee229fbeca2708ce66a3a8b377eee8974c0f5c5e /Userland/DevTools/Profiler/Profile.h | |
parent | 13d7c09125f8eec703d0a43a9a87fc8aa08f7319 (diff) | |
download | serenity-4055b0329117c1a280080bbd638eb48bafe29638.zip |
DevTools: Move to Userland/DevTools/
Diffstat (limited to 'Userland/DevTools/Profiler/Profile.h')
-rw-r--r-- | Userland/DevTools/Profiler/Profile.h | 234 |
1 files changed, 234 insertions, 0 deletions
diff --git a/Userland/DevTools/Profiler/Profile.h b/Userland/DevTools/Profiler/Profile.h new file mode 100644 index 0000000000..0acf3e917f --- /dev/null +++ b/Userland/DevTools/Profiler/Profile.h @@ -0,0 +1,234 @@ +/* + * Copyright (c) 2018-2021, Andreas Kling <kling@serenityos.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include <AK/Bitmap.h> +#include <AK/JsonArray.h> +#include <AK/JsonObject.h> +#include <AK/JsonValue.h> +#include <AK/MappedFile.h> +#include <AK/NonnullRefPtrVector.h> +#include <AK/OwnPtr.h> +#include <AK/Result.h> +#include <LibELF/Image.h> +#include <LibGUI/Forward.h> +#include <LibGUI/ModelIndex.h> + +class ProfileModel; +class DisassemblyModel; + +class ProfileNode : public RefCounted<ProfileNode> { +public: + static NonnullRefPtr<ProfileNode> create(const String& symbol, u32 address, u32 offset, u64 timestamp) + { + return adopt(*new ProfileNode(symbol, address, offset, timestamp)); + } + + // These functions are only relevant for root nodes + void will_track_seen_events(size_t profile_event_count) + { + if (m_seen_events.size() != profile_event_count) + m_seen_events = Bitmap::create(profile_event_count, false); + } + bool has_seen_event(size_t event_index) const { return m_seen_events.get(event_index); } + void did_see_event(size_t event_index) { m_seen_events.set(event_index, true); } + + const String& symbol() const { return m_symbol; } + u32 address() const { return m_address; } + u32 offset() const { return m_offset; } + u64 timestamp() const { return m_timestamp; } + + u32 event_count() const { return m_event_count; } + u32 self_count() const { return m_self_count; } + + int child_count() const { return m_children.size(); } + const Vector<NonnullRefPtr<ProfileNode>>& children() const { return m_children; } + + void add_child(ProfileNode& child) + { + if (child.m_parent == this) + return; + ASSERT(!child.m_parent); + child.m_parent = this; + m_children.append(child); + } + + ProfileNode& find_or_create_child(const String& symbol, u32 address, u32 offset, u64 timestamp) + { + for (size_t i = 0; i < m_children.size(); ++i) { + auto& child = m_children[i]; + if (child->symbol() == symbol) { + return child; + } + } + auto new_child = ProfileNode::create(symbol, address, offset, timestamp); + add_child(new_child); + return new_child; + }; + + ProfileNode* parent() { return m_parent; } + const ProfileNode* parent() const { return m_parent; } + + void increment_event_count() { ++m_event_count; } + void increment_self_count() { ++m_self_count; } + + void sort_children(); + + const HashMap<FlatPtr, size_t>& events_per_address() const { return m_events_per_address; } + void add_event_address(FlatPtr address) + { + auto it = m_events_per_address.find(address); + if (it == m_events_per_address.end()) + m_events_per_address.set(address, 1); + else + m_events_per_address.set(address, it->value + 1); + } + +private: + explicit ProfileNode(const String& symbol, u32 address, u32 offset, u64 timestamp) + : m_symbol(symbol) + , m_address(address) + , m_offset(offset) + , m_timestamp(timestamp) + { + } + + ProfileNode* m_parent { nullptr }; + String m_symbol; + u32 m_address { 0 }; + u32 m_offset { 0 }; + u32 m_event_count { 0 }; + u32 m_self_count { 0 }; + u64 m_timestamp { 0 }; + Vector<NonnullRefPtr<ProfileNode>> m_children; + HashMap<FlatPtr, size_t> m_events_per_address; + Bitmap m_seen_events; +}; + +class Profile { +public: + static Result<NonnullOwnPtr<Profile>, String> load_from_perfcore_file(const StringView& path); + ~Profile(); + + GUI::Model& model(); + GUI::Model* disassembly_model(); + + void set_disassembly_index(const GUI::ModelIndex&); + + const Vector<NonnullRefPtr<ProfileNode>>& roots() const { return m_roots; } + + struct Frame { + String symbol; + u32 address { 0 }; + u32 offset { 0 }; + }; + + struct Event { + u64 timestamp { 0 }; + String type; + FlatPtr ptr { 0 }; + size_t size { 0 }; + bool in_kernel { false }; + Vector<Frame> frames; + }; + + u32 filtered_event_count() const { return m_filtered_event_count; } + + const Vector<Event>& events() const { return m_events; } + + u64 length_in_ms() const { return m_last_timestamp - m_first_timestamp; } + u64 first_timestamp() const { return m_first_timestamp; } + u64 last_timestamp() const { return m_last_timestamp; } + u32 deepest_stack_depth() const { return m_deepest_stack_depth; } + + void set_timestamp_filter_range(u64 start, u64 end); + void clear_timestamp_filter_range(); + bool has_timestamp_filter_range() const { return m_has_timestamp_filter_range; } + + bool is_inverted() const { return m_inverted; } + void set_inverted(bool); + + void set_show_top_functions(bool); + + bool show_percentages() const { return m_show_percentages; } + void set_show_percentages(bool); + + const String& executable_path() const { return m_executable_path; } + + class LibraryMetadata { + public: + LibraryMetadata(JsonArray regions); + + String symbolicate(FlatPtr ptr, u32& offset) const; + + struct Library { + FlatPtr base; + size_t size; + String name; + NonnullRefPtr<MappedFile> file; + ELF::Image elf; + }; + + const Library* library_containing(FlatPtr) const; + + private: + mutable HashMap<String, OwnPtr<Library>> m_libraries; + JsonArray m_regions; + }; + + const LibraryMetadata& libraries() const { return *m_library_metadata; } + +private: + Profile(String executable_path, Vector<Event>, NonnullOwnPtr<LibraryMetadata>); + + void rebuild_tree(); + + String m_executable_path; + + RefPtr<ProfileModel> m_model; + RefPtr<DisassemblyModel> m_disassembly_model; + + GUI::ModelIndex m_disassembly_index; + + Vector<NonnullRefPtr<ProfileNode>> m_roots; + u32 m_filtered_event_count { 0 }; + u64 m_first_timestamp { 0 }; + u64 m_last_timestamp { 0 }; + + Vector<Event> m_events; + + NonnullOwnPtr<LibraryMetadata> m_library_metadata; + + bool m_has_timestamp_filter_range { false }; + u64 m_timestamp_filter_range_start { 0 }; + u64 m_timestamp_filter_range_end { 0 }; + + u32 m_deepest_stack_depth { 0 }; + bool m_inverted { false }; + bool m_show_top_functions { false }; + bool m_show_percentages { false }; +}; |