summaryrefslogtreecommitdiff
path: root/DevTools/ProfileViewer/Profile.h
blob: 13c83beb4644254d67713b237613fe99184ba3a6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
#pragma once

#include <AK/JsonArray.h>
#include <AK/JsonObject.h>
#include <AK/JsonValue.h>
#include <AK/NonnullRefPtrVector.h>
#include <AK/OwnPtr.h>

class GModel;
class ProfileModel;

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));
    }

    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 sample_count() const { return m_sample_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 (int 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_sample_count() { ++m_sample_count; }

    void sort_children();

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_sample_count { 0 };
    u64 m_timestamp { 0 };
    Vector<NonnullRefPtr<ProfileNode>> m_children;
};

class Profile {
public:
    static OwnPtr<Profile> load_from_file(const StringView& path);
    ~Profile();

    GModel& model();

    const Vector<NonnullRefPtr<ProfileNode>>& roots() const { return m_roots; }

    template<typename Callback>
    void for_each_sample(Callback callback)
    {
        m_json.for_each([&](auto& value) {
            callback(value.as_object());
        });
    }

    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_first_timestamp; }

private:
    explicit Profile(const JsonArray&, Vector<NonnullRefPtr<ProfileNode>>&&, u64 first_timestamp, u64 last_timestamp);

    JsonArray m_json;
    RefPtr<ProfileModel> m_model;
    Vector<NonnullRefPtr<ProfileNode>> m_roots;
    u64 m_first_timestamp { 0 };
    u64 m_last_timestamp { 0 };
};