Selaa lähdekoodia

ProfileViewer: Convert the JSON samples into a more efficient format

Only do the conversion from JSON once. This makes it much faster to do
time range filtering with the timeline widget. :^)
Andreas Kling 5 vuotta sitten
vanhempi
commit
063fef312e

+ 34 - 21
DevTools/ProfileViewer/Profile.cpp

@@ -11,14 +11,30 @@ Profile::Profile(const JsonArray& json)
     m_last_timestamp = m_json.at(m_json.size() - 1).as_object().get("timestamp").to_number<u64>();
 
     m_model = ProfileModel::create(*this);
-    rebuild_tree();
 
-    m_sample_data.ensure_capacity(m_json.size());
-    m_json.for_each([&](const JsonValue& sample) {
-        u64 timestamp = sample.as_object().get("timestamp").to_number<u64>() - m_first_timestamp;
-        bool in_kernel = sample.as_object().get("frames").as_array().at(1).as_object().get("address").to_number<u32>() < (8 * MB);
-        m_sample_data.append({ timestamp, in_kernel });
-    });
+    m_samples.ensure_capacity(m_json.size());
+    for (auto& sample_value : m_json.values()) {
+        auto& sample_object = sample_value.as_object();
+
+        Sample sample;
+        sample.timestamp = sample_object.get("timestamp").to_number<u64>();
+        sample.in_kernel = sample_object.get("frames").as_array().at(1).as_object().get("address").to_number<u32>() < (8 * MB);
+
+        auto frames_value = sample_object.get("frames");
+        auto& frames_array = frames_value.as_array();
+        for (int i = frames_array.size() - 1; i >= 0; --i) {
+            auto& frame_value = frames_array.at(i);
+            auto& frame_object = frame_value.as_object();
+            Frame frame;
+            frame.symbol = frame_object.get("symbol").as_string_or({});
+            frame.address = frame_object.get("address").as_u32();
+            frame.offset = frame_object.get("offset").as_u32();
+            sample.frames.append(move(frame));
+        };
+        m_samples.append(move(sample));
+    }
+
+    rebuild_tree();
 }
 
 Profile::~Profile()
@@ -46,35 +62,32 @@ void Profile::rebuild_tree()
         return new_root;
     };
 
-    m_json.for_each([&](const JsonValue& sample) {
+    for (auto& sample : m_samples) {
         if (has_timestamp_filter_range()) {
-            auto timestamp = sample.as_object().get("timestamp").to_number<u64>();
+            auto timestamp = sample.timestamp;
             if (timestamp < m_timestamp_filter_range_start || timestamp > m_timestamp_filter_range_end)
-                return;
+                continue;
         }
 
-        auto frames_value = sample.as_object().get("frames");
-        auto& frames = frames_value.as_array();
         ProfileNode* node = nullptr;
-        for (int i = frames.size() - 1; i >= 0; --i) {
-            auto& frame = frames.at(i);
+        for (int i = 0; i < sample.frames.size(); ++i) {
+            auto& frame = sample.frames.at(i);
 
-            auto symbol = frame.as_object().get("symbol").as_string_or({});
-            auto address = frame.as_object().get("address").as_u32();
-            auto offset = frame.as_object().get("offset").as_u32();
-            auto timestamp = frame.as_object().get("timestamp").to_number<u64>();
+            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, timestamp);
+                node = &find_or_create_root(symbol, address, offset, sample.timestamp);
             else
-                node = &node->find_or_create_child(symbol, address, offset, timestamp);
+                node = &node->find_or_create_child(symbol, address, offset, sample.timestamp);
 
             node->increment_sample_count();
         }
-    });
+    }
 
     for (auto& root : roots) {
         root.sort_children();

+ 9 - 10
DevTools/ProfileViewer/Profile.h

@@ -82,20 +82,19 @@ public:
 
     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());
-        });
-    }
+    struct Frame {
+        String symbol;
+        u32 address { 0 };
+        u32 offset { 0 };
+    };
 
-    struct SampleData {
+    struct Sample {
         u64 timestamp { 0 };
         bool in_kernel { false };
+        Vector<Frame> frames;
     };
 
-    const Vector<SampleData>& sample_data() const { return m_sample_data; }
+    const Vector<Sample>& samples() const { return m_samples; }
 
     u64 length_in_ms() const { return m_last_timestamp - m_first_timestamp; }
     u64 first_timestamp() const { return m_first_timestamp; }
@@ -116,7 +115,7 @@ private:
     u64 m_first_timestamp { 0 };
     u64 m_last_timestamp { 0 };
 
-    Vector<SampleData> m_sample_data;
+    Vector<Sample> m_samples;
 
     bool m_has_timestamp_filter_range { false };
     u64 m_timestamp_filter_range_start { 0 };

+ 2 - 2
DevTools/ProfileViewer/ProfileTimelineWidget.cpp

@@ -28,8 +28,8 @@ void ProfileTimelineWidget::paint_event(GPaintEvent& event)
 
     float column_width = (float)frame_inner_rect().width() / (float)m_profile.length_in_ms();
 
-    for (auto& sample : m_profile.sample_data()) {
-        u64 t = sample.timestamp;
+    for (auto& sample : m_profile.samples()) {
+        u64 t = sample.timestamp - m_profile.first_timestamp();
         int x = (int)((float)t * column_width);
         int cw = max(1, (int)column_width);