Merge "CHANGELOG: TTID and TTFD in android_startup_metric" into main
diff --git a/Android.bp b/Android.bp
index b379ef7..14e7ab9 100644
--- a/Android.bp
+++ b/Android.bp
@@ -11871,6 +11871,7 @@
srcs: [
"src/trace_processor/containers/bit_vector_unittest.cc",
"src/trace_processor/containers/implicit_segment_forest_unittest.cc",
+ "src/trace_processor/containers/interval_tree_unittest.cc",
"src/trace_processor/containers/null_term_string_view_unittest.cc",
"src/trace_processor/containers/row_map_unittest.cc",
"src/trace_processor/containers/string_pool_unittest.cc",
@@ -12393,6 +12394,7 @@
"src/trace_processor/importers/proto/stack_profile_sequence_state.cc",
"src/trace_processor/importers/proto/track_event_module.cc",
"src/trace_processor/importers/proto/track_event_parser.cc",
+ "src/trace_processor/importers/proto/track_event_sequence_state.cc",
"src/trace_processor/importers/proto/track_event_tokenizer.cc",
"src/trace_processor/importers/proto/track_event_tracker.cc",
],
diff --git a/BUILD b/BUILD
index bf86ecc..3437d7c 100644
--- a/BUILD
+++ b/BUILD
@@ -1375,6 +1375,7 @@
":include_perfetto_public_protozero",
"src/trace_processor/containers/bit_vector.h",
"src/trace_processor/containers/implicit_segment_forest.h",
+ "src/trace_processor/containers/interval_tree.h",
"src/trace_processor/containers/null_term_string_view.h",
"src/trace_processor/containers/row_map.h",
"src/trace_processor/containers/row_map_algorithms.h",
@@ -1896,7 +1897,7 @@
"src/trace_processor/importers/proto/network_trace_module.h",
"src/trace_processor/importers/proto/packet_analyzer.cc",
"src/trace_processor/importers/proto/packet_analyzer.h",
- "src/trace_processor/importers/proto/packet_sequence_state.h",
+ "src/trace_processor/importers/proto/packet_sequence_state_builder.h",
"src/trace_processor/importers/proto/packet_sequence_state_generation.cc",
"src/trace_processor/importers/proto/perf_sample_tracker.cc",
"src/trace_processor/importers/proto/perf_sample_tracker.h",
@@ -1906,7 +1907,6 @@
"src/trace_processor/importers/proto/profile_packet_sequence_state.h",
"src/trace_processor/importers/proto/profile_packet_utils.cc",
"src/trace_processor/importers/proto/profile_packet_utils.h",
- "src/trace_processor/importers/proto/proto_incremental_state.h",
"src/trace_processor/importers/proto/proto_trace_parser_impl.cc",
"src/trace_processor/importers/proto/proto_trace_parser_impl.h",
"src/trace_processor/importers/proto/proto_trace_reader.cc",
@@ -1919,6 +1919,7 @@
"src/trace_processor/importers/proto/track_event_module.h",
"src/trace_processor/importers/proto/track_event_parser.cc",
"src/trace_processor/importers/proto/track_event_parser.h",
+ "src/trace_processor/importers/proto/track_event_sequence_state.cc",
"src/trace_processor/importers/proto/track_event_tokenizer.cc",
"src/trace_processor/importers/proto/track_event_tokenizer.h",
"src/trace_processor/importers/proto/track_event_tracker.cc",
@@ -1931,6 +1932,7 @@
name = "src_trace_processor_importers_proto_packet_sequence_state_generation_hdr",
srcs = [
"src/trace_processor/importers/proto/packet_sequence_state_generation.h",
+ "src/trace_processor/importers/proto/track_event_sequence_state.h",
],
)
diff --git a/include/perfetto/public/data_source.h b/include/perfetto/public/data_source.h
index 23fba92..83fb527 100644
--- a/include/perfetto/public/data_source.h
+++ b/include/perfetto/public/data_source.h
@@ -75,6 +75,10 @@
// How to behave when running out of shared memory buffer space.
enum PerfettoDsBufferExhaustedPolicy buffer_exhausted_policy;
+
+ // When true the data source is expected to ack the stop request through the
+ // NotifyDataSourceStopped() IPC.
+ bool will_notify_on_stop;
};
static inline struct PerfettoDsParams PerfettoDsParamsDefault(void) {
@@ -88,7 +92,8 @@
PERFETTO_NULL,
PERFETTO_NULL,
PERFETTO_NULL,
- PERFETTO_DS_BUFFER_EXHAUSTED_POLICY_DROP};
+ PERFETTO_DS_BUFFER_EXHAUSTED_POLICY_DROP,
+ true};
return ret;
}
@@ -112,6 +117,7 @@
PerfettoPbMsgInit(&desc.msg, &writer);
perfetto_protos_DataSourceDescriptor_set_cstr_name(&desc, data_source_name);
+ perfetto_protos_DataSourceDescriptor_set_will_notify_on_stop(&desc, params.will_notify_on_stop);
desc_size = PerfettoStreamWriterGetWrittenSize(&writer.writer);
desc_buf = malloc(desc_size);
diff --git a/src/trace_processor/containers/BUILD.gn b/src/trace_processor/containers/BUILD.gn
index c724df8..7974003 100644
--- a/src/trace_processor/containers/BUILD.gn
+++ b/src/trace_processor/containers/BUILD.gn
@@ -23,6 +23,7 @@
public = [
"bit_vector.h",
"implicit_segment_forest.h",
+ "interval_tree.h",
"null_term_string_view.h",
"row_map.h",
"row_map_algorithms.h",
@@ -46,6 +47,7 @@
sources = [
"bit_vector_unittest.cc",
"implicit_segment_forest_unittest.cc",
+ "interval_tree_unittest.cc",
"null_term_string_view_unittest.cc",
"row_map_unittest.cc",
"string_pool_unittest.cc",
diff --git a/src/trace_processor/containers/interval_tree.h b/src/trace_processor/containers/interval_tree.h
new file mode 100644
index 0000000..c083da0
--- /dev/null
+++ b/src/trace_processor/containers/interval_tree.h
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SRC_TRACE_PROCESSOR_CONTAINERS_INTERVAL_TREE_H_
+#define SRC_TRACE_PROCESSOR_CONTAINERS_INTERVAL_TREE_H_
+
+#include <cstdint>
+#include <limits>
+#include <memory>
+#include <vector>
+
+namespace perfetto::trace_processor {
+
+// An implementation of an interval tree data structure, designed to efficiently
+// perform overlap queries on a set of intervals. Used by `interval_intersect`,
+// where one set of intervals (generally the bigger one) has interval tree
+// created based on it, as another queries `FindOverlaps` function for each
+// interval.
+// As interval tree is build on sorted (by `start`) set of N intervals, the
+// complexity of creating a tree goes down from O(N*logN) to O(N) and the
+// created tree is optimally balanced. Each call to `FindOverlaps` is O(logN).
+class IntervalTree {
+ public:
+ struct Interval {
+ uint32_t start;
+ uint32_t end;
+ uint32_t id;
+ };
+
+ // Takes vector of sorted intervals.
+ explicit IntervalTree(std::vector<Interval>& sorted_intervals) {
+ tree_root_ = BuildFromSortedIntervals(
+ sorted_intervals, 0, static_cast<int32_t>(sorted_intervals.size() - 1));
+ }
+
+ // Modifies |overlaps| to contain ids of all intervals in the interval tree
+ // that overlap with |interval|.
+ void FindOverlaps(Interval interval, std::vector<uint32_t>& overlaps) const {
+ if (tree_root_) {
+ FindOverlaps(*tree_root_, interval, overlaps);
+ }
+ }
+
+ private:
+ struct Node {
+ Interval interval;
+ uint32_t max;
+ std::unique_ptr<Node> left;
+ std::unique_ptr<Node> right;
+
+ explicit Node(Interval i) : interval(i), max(i.end) {}
+ };
+
+ static std::unique_ptr<Node> Insert(std::unique_ptr<Node> root, Interval i) {
+ if (root == nullptr) {
+ return std::make_unique<Node>(i);
+ }
+
+ if (i.start < root->interval.start) {
+ root->left = Insert(std::move(root->left), i);
+ } else {
+ root->right = Insert(std::move(root->right), i);
+ }
+
+ if (root->max < i.end) {
+ root->max = i.end;
+ }
+
+ return root;
+ }
+
+ static std::unique_ptr<Node> BuildFromSortedIntervals(
+ const std::vector<Interval>& is,
+ int32_t start,
+ int32_t end) {
+ // |start == end| happens if there is one element so we need to check for
+ // |start > end| that happens in the next recursive call.
+ if (start > end) {
+ return nullptr;
+ }
+
+ int32_t mid = start + (end - start) / 2;
+ auto node = std::make_unique<Node>(is[static_cast<uint32_t>(mid)]);
+
+ node->left = BuildFromSortedIntervals(is, start, mid - 1);
+ node->right = BuildFromSortedIntervals(is, mid + 1, end);
+
+ uint32_t max_from_children = std::max(
+ node->left ? node->left->max : std::numeric_limits<uint32_t>::min(),
+ node->right ? node->right->max : std::numeric_limits<uint32_t>::min());
+
+ node->max = std::max(node->interval.end, max_from_children);
+
+ return node;
+ }
+
+ static void FindOverlaps(const Node& node,
+ const Interval& i,
+ std::vector<uint32_t>& overlaps) {
+ // Intervals overlap if one starts before the other ends and ends after it
+ // starts.
+ if (node.interval.start < i.end && node.interval.end > i.start) {
+ overlaps.push_back(node.interval.id);
+ }
+
+ // Try to find overlaps with left.
+ if (i.start <= node.interval.start && node.left) {
+ FindOverlaps(*node.left, i, overlaps);
+ }
+
+ // Try to find overlaps with right.
+ if (i.start < node.max && node.right) {
+ FindOverlaps(*node.right, i, overlaps);
+ }
+ }
+
+ std::unique_ptr<Node> tree_root_;
+};
+
+} // namespace perfetto::trace_processor
+
+#endif // SRC_TRACE_PROCESSOR_CONTAINERS_INTERVAL_TREE_H_
diff --git a/src/trace_processor/containers/interval_tree_unittest.cc b/src/trace_processor/containers/interval_tree_unittest.cc
new file mode 100644
index 0000000..61023d4
--- /dev/null
+++ b/src/trace_processor/containers/interval_tree_unittest.cc
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "src/trace_processor/containers/interval_tree.h"
+
+#include <cstddef>
+#include <cstdint>
+#include <numeric>
+#include <random>
+#include <tuple>
+#include <utility>
+#include <vector>
+
+#include "perfetto/base/compiler.h"
+#include "test/gtest_and_gmock.h"
+
+namespace perfetto::trace_processor {
+
+inline bool operator==(const IntervalTree::Interval& a,
+ const IntervalTree::Interval& b) {
+ return std::tie(a.start, a.end, a.id) == std::tie(b.start, b.end, b.id);
+}
+
+namespace {
+
+using Interval = IntervalTree::Interval;
+using testing::IsEmpty;
+using testing::UnorderedElementsAre;
+
+std::vector<Interval> CreateIntervals(
+ std::vector<std::pair<uint32_t, uint32_t>> periods) {
+ std::vector<Interval> res;
+ uint32_t id = 0;
+ for (auto period : periods) {
+ res.push_back({period.first, period.second, id++});
+ }
+ return res;
+}
+
+TEST(IntervalTree, Trivial) {
+ std::vector<Interval> interval({{10, 20, 5}});
+ IntervalTree tree(interval);
+ std::vector<uint32_t> overlaps;
+ tree.FindOverlaps({5, 30, 0}, overlaps);
+
+ ASSERT_THAT(overlaps, UnorderedElementsAre(5));
+}
+
+TEST(IntervalTree, Simple) {
+ auto intervals = CreateIntervals({{0, 10}, {5, 20}, {30, 40}});
+ IntervalTree tree(intervals);
+ std::vector<uint32_t> overlaps;
+ tree.FindOverlaps({4, 30, 0}, overlaps);
+
+ ASSERT_THAT(overlaps, UnorderedElementsAre(0, 1));
+}
+
+TEST(IntervalTree, SinglePointOverlap) {
+ auto intervals = CreateIntervals({{10, 20}});
+ IntervalTree tree(intervals);
+ std::vector<uint32_t> overlaps;
+
+ // Overlaps at the start point only
+ tree.FindOverlaps({10, 10, 0}, overlaps);
+ ASSERT_THAT(overlaps, IsEmpty());
+
+ overlaps.clear();
+
+ // Overlaps at the end point only
+ tree.FindOverlaps({20, 20, 0}, overlaps);
+ ASSERT_THAT(overlaps, IsEmpty());
+}
+
+TEST(IntervalTree, NoOverlaps) {
+ auto intervals = CreateIntervals({{10, 20}, {30, 40}});
+ IntervalTree tree(intervals);
+ std::vector<uint32_t> overlaps;
+
+ // Before all intervals
+ tree.FindOverlaps({5, 9, 0}, overlaps);
+ ASSERT_THAT(overlaps, IsEmpty());
+ overlaps.clear();
+
+ // Between intervals
+ tree.FindOverlaps({21, 29, 0}, overlaps);
+ ASSERT_THAT(overlaps, IsEmpty());
+ overlaps.clear();
+
+ // After all intervals
+ tree.FindOverlaps({41, 50, 0}, overlaps);
+ ASSERT_THAT(overlaps, IsEmpty());
+}
+
+TEST(IntervalTree, IdenticalIntervals) {
+ auto intervals = CreateIntervals({{10, 20}, {10, 20}});
+ IntervalTree tree(intervals);
+ std::vector<uint32_t> overlaps;
+ tree.FindOverlaps({10, 20, 0}, overlaps);
+ ASSERT_THAT(overlaps, UnorderedElementsAre(0, 1));
+}
+
+TEST(IntervalTree, MultipleOverlapsVariousPositions) {
+ auto intervals = CreateIntervals({{5, 15}, {10, 20}, {12, 22}, {25, 35}});
+ IntervalTree tree(intervals);
+
+ std::vector<uint32_t> overlaps;
+ /// Starts before, ends within
+ tree.FindOverlaps({9, 11, 0}, overlaps);
+ ASSERT_THAT(overlaps, UnorderedElementsAre(0, 1));
+
+ overlaps.clear();
+ // Starts within, ends within
+ tree.FindOverlaps({13, 21, 0}, overlaps);
+ ASSERT_THAT(overlaps, UnorderedElementsAre(1, 2));
+
+ overlaps.clear();
+ // Starts within, ends after
+ tree.FindOverlaps({18, 26, 0}, overlaps);
+ ASSERT_THAT(overlaps, UnorderedElementsAre(1, 2, 3));
+}
+
+TEST(IntervalTree, OverlappingEndpoints) {
+ auto intervals = CreateIntervals({{10, 20}, {20, 30}});
+ IntervalTree tree(intervals);
+ std::vector<uint32_t> overlaps;
+
+ tree.FindOverlaps({19, 21, 0}, overlaps);
+ ASSERT_THAT(overlaps, UnorderedElementsAre(0, 1));
+}
+
+TEST(IntervalTree, Stress) {
+ static constexpr size_t kCount = 9249;
+ std::minstd_rand0 rng(42);
+
+ std::vector<std::pair<uint32_t, uint32_t>> periods;
+ uint32_t prev_max = 0;
+ for (uint32_t i = 0; i < kCount; ++i) {
+ prev_max += static_cast<uint32_t>(rng()) % 100;
+ periods.push_back(
+ {prev_max, prev_max + (static_cast<uint32_t>(rng()) % 100)});
+ }
+ auto intervals = CreateIntervals(periods);
+ Interval query_i{periods.front().first, periods.back().first + 1, 5};
+ IntervalTree tree(intervals);
+ std::vector<uint32_t> overlaps;
+ tree.FindOverlaps(query_i, overlaps);
+
+ EXPECT_EQ(overlaps.size(), kCount);
+}
+
+} // namespace
+} // namespace perfetto::trace_processor
diff --git a/src/trace_processor/importers/proto/BUILD.gn b/src/trace_processor/importers/proto/BUILD.gn
index 18a617a..dde995c 100644
--- a/src/trace_processor/importers/proto/BUILD.gn
+++ b/src/trace_processor/importers/proto/BUILD.gn
@@ -40,7 +40,7 @@
"network_trace_module.h",
"packet_analyzer.cc",
"packet_analyzer.h",
- "packet_sequence_state.h",
+ "packet_sequence_state_builder.h",
"packet_sequence_state_generation.cc",
"perf_sample_tracker.cc",
"perf_sample_tracker.h",
@@ -50,7 +50,6 @@
"profile_packet_sequence_state.h",
"profile_packet_utils.cc",
"profile_packet_utils.h",
- "proto_incremental_state.h",
"proto_trace_parser_impl.cc",
"proto_trace_parser_impl.h",
"proto_trace_reader.cc",
@@ -63,6 +62,7 @@
"track_event_module.h",
"track_event_parser.cc",
"track_event_parser.h",
+ "track_event_sequence_state.cc",
"track_event_tokenizer.cc",
"track_event_tokenizer.h",
"track_event_tracker.cc",
@@ -70,7 +70,6 @@
]
public_deps = [ ":proto_importer_module" ]
deps = [
- ":packet_sequence_state_generation_hdr",
"../../../../gn:default_deps",
"../../../../include/perfetto/trace_processor:trace_processor",
"../../../../protos/perfetto/common:zero",
@@ -201,6 +200,7 @@
"proto_importer_module.cc",
"proto_importer_module.h",
]
+ public_deps = [ ":packet_sequence_state_generation_hdr" ]
deps = [
":packet_sequence_state_generation_hdr",
"../../../../gn:default_deps",
@@ -212,12 +212,16 @@
}
source_set("packet_sequence_state_generation_hdr") {
- sources = [ "packet_sequence_state_generation.h" ]
+ sources = [
+ "packet_sequence_state_generation.h",
+ "track_event_sequence_state.h",
+ ]
deps = [
"../../../../gn:default_deps",
"../../../../include/perfetto/ext/base",
"../../../../protos/perfetto/trace:non_minimal_zero",
"../../../../protos/perfetto/trace/track_event:zero",
+ "../../types:types",
"../../util:interned_message_view",
]
}
@@ -262,6 +266,7 @@
deps = [
":full",
":minimal",
+ ":packet_sequence_state_generation_hdr",
"../../../../gn:default_deps",
"../../../../gn:gtest_and_gmock",
"../../../../protos/perfetto/common:cpp",
diff --git a/src/trace_processor/importers/proto/frame_timeline_event_parser.h b/src/trace_processor/importers/proto/frame_timeline_event_parser.h
index 596f415..b1c1e12 100644
--- a/src/trace_processor/importers/proto/frame_timeline_event_parser.h
+++ b/src/trace_processor/importers/proto/frame_timeline_event_parser.h
@@ -20,7 +20,6 @@
#include "perfetto/protozero/field.h"
#include "src/trace_processor/importers/common/args_tracker.h"
#include "src/trace_processor/importers/common/async_track_set_tracker.h"
-#include "src/trace_processor/importers/proto/proto_incremental_state.h"
#include "src/trace_processor/storage/trace_storage.h"
#include "protos/perfetto/trace/android/frame_timeline_event.pbzero.h"
diff --git a/src/trace_processor/importers/proto/gpu_event_parser.h b/src/trace_processor/importers/proto/gpu_event_parser.h
index e2eaac8..6ca6527 100644
--- a/src/trace_processor/importers/proto/gpu_event_parser.h
+++ b/src/trace_processor/importers/proto/gpu_event_parser.h
@@ -25,7 +25,6 @@
#include "protos/perfetto/trace/android/gpu_mem_event.pbzero.h"
#include "protos/perfetto/trace/gpu/gpu_render_stage_event.pbzero.h"
#include "src/trace_processor/importers/common/args_tracker.h"
-#include "src/trace_processor/importers/proto/proto_incremental_state.h"
#include "src/trace_processor/importers/proto/vulkan_memory_tracker.h"
#include "src/trace_processor/storage/trace_storage.h"
diff --git a/src/trace_processor/importers/proto/graphics_frame_event_parser.h b/src/trace_processor/importers/proto/graphics_frame_event_parser.h
index 2d37612..146d126 100644
--- a/src/trace_processor/importers/proto/graphics_frame_event_parser.h
+++ b/src/trace_processor/importers/proto/graphics_frame_event_parser.h
@@ -23,7 +23,6 @@
#include "perfetto/ext/base/string_writer.h"
#include "perfetto/protozero/field.h"
#include "src/trace_processor/importers/common/args_tracker.h"
-#include "src/trace_processor/importers/proto/proto_incremental_state.h"
#include "src/trace_processor/importers/proto/vulkan_memory_tracker.h"
#include "src/trace_processor/storage/trace_storage.h"
diff --git a/src/trace_processor/importers/proto/packet_sequence_state.h b/src/trace_processor/importers/proto/packet_sequence_state.h
deleted file mode 100644
index b50af20..0000000
--- a/src/trace_processor/importers/proto/packet_sequence_state.h
+++ /dev/null
@@ -1,157 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_PACKET_SEQUENCE_STATE_H_
-#define SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_PACKET_SEQUENCE_STATE_H_
-
-#include <stdint.h>
-
-#include <memory>
-#include <type_traits>
-#include <vector>
-
-#include "perfetto/base/compiler.h"
-#include "src/trace_processor/importers/proto/packet_sequence_state_generation.h"
-#include "src/trace_processor/types/trace_processor_context.h"
-#include "src/trace_processor/util/interned_message_view.h"
-
-namespace perfetto {
-namespace trace_processor {
-
-class PacketSequenceState {
- public:
- explicit PacketSequenceState(TraceProcessorContext* context)
- : context_(context) {
- current_generation_.reset(new PacketSequenceStateGeneration(this));
- }
-
- int64_t IncrementAndGetTrackEventTimeNs(int64_t delta_ns) {
- PERFETTO_DCHECK(track_event_timestamps_valid());
- track_event_timestamp_ns_ += delta_ns;
- return track_event_timestamp_ns_;
- }
-
- int64_t IncrementAndGetTrackEventThreadTimeNs(int64_t delta_ns) {
- PERFETTO_DCHECK(track_event_timestamps_valid());
- track_event_thread_timestamp_ns_ += delta_ns;
- return track_event_thread_timestamp_ns_;
- }
-
- int64_t IncrementAndGetTrackEventThreadInstructionCount(int64_t delta) {
- PERFETTO_DCHECK(track_event_timestamps_valid());
- track_event_thread_instruction_count_ += delta;
- return track_event_thread_instruction_count_;
- }
-
- // Intern a message into the current generation.
- void InternMessage(uint32_t field_id, TraceBlobView message) {
- current_generation_->InternMessage(field_id, std::move(message));
- }
-
- // Set the trace packet defaults for the current generation. If the current
- // generation already has defaults set, starts a new generation without
- // invalidating other incremental state (such as interned data).
- void UpdateTracePacketDefaults(TraceBlobView defaults) {
- if (!current_generation_->GetTracePacketDefaultsView()) {
- current_generation_->SetTracePacketDefaults(std::move(defaults));
- return;
- }
-
- // The new defaults should only apply to subsequent messages on the
- // sequence. Add a new generation with the updated defaults but the
- // current generation's interned data state.
- current_generation_.reset(new PacketSequenceStateGeneration(
- this, current_generation_.get(), std::move(defaults)));
- }
-
- void SetThreadDescriptor(int32_t pid,
- int32_t tid,
- int64_t timestamp_ns,
- int64_t thread_timestamp_ns,
- int64_t thread_instruction_count) {
- track_event_timestamps_valid_ = true;
- pid_and_tid_valid_ = true;
- pid_ = pid;
- tid_ = tid;
- track_event_timestamp_ns_ = timestamp_ns;
- track_event_thread_timestamp_ns_ = thread_timestamp_ns;
- track_event_thread_instruction_count_ = thread_instruction_count;
- }
-
- void OnPacketLoss() {
- packet_loss_ = true;
- track_event_timestamps_valid_ = false;
- }
-
- // Starts a new generation with clean-slate incremental state and defaults.
- void OnIncrementalStateCleared() {
- packet_loss_ = false;
- current_generation_.reset(new PacketSequenceStateGeneration(this));
- }
-
- bool IsIncrementalStateValid() const { return !packet_loss_; }
-
- // Returns a ref-counted ptr to the current generation.
- RefPtr<PacketSequenceStateGeneration> current_generation() const {
- return current_generation_;
- }
-
- bool track_event_timestamps_valid() const {
- return track_event_timestamps_valid_;
- }
-
- bool pid_and_tid_valid() const { return pid_and_tid_valid_; }
-
- int32_t pid() const { return pid_; }
- int32_t tid() const { return tid_; }
-
- TraceProcessorContext* context() const { return context_; }
-
- private:
- TraceProcessorContext* context_;
-
- // If true, incremental state on the sequence is considered invalid until we
- // see the next packet with incremental_state_cleared. We assume that we
- // missed some packets at the beginning of the trace.
- bool packet_loss_ = true;
-
- // We can only consider TrackEvent delta timestamps to be correct after we
- // have observed a thread descriptor (since the last packet loss).
- bool track_event_timestamps_valid_ = false;
-
- // |pid_| and |tid_| are only valid after we parsed at least one
- // ThreadDescriptor packet on the sequence.
- bool pid_and_tid_valid_ = false;
-
- // Process/thread ID of the packet sequence set by a ThreadDescriptor
- // packet. Used as default values for TrackEvents that don't specify a
- // pid/tid override. Only valid after |pid_and_tid_valid_| is set to true.
- int32_t pid_ = 0;
- int32_t tid_ = 0;
-
- // Current wall/thread timestamps/counters used as reference for the next
- // TrackEvent delta timestamp.
- int64_t track_event_timestamp_ns_ = 0;
- int64_t track_event_thread_timestamp_ns_ = 0;
- int64_t track_event_thread_instruction_count_ = 0;
-
- RefPtr<PacketSequenceStateGeneration> current_generation_;
-};
-
-} // namespace trace_processor
-} // namespace perfetto
-
-#endif // SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_PACKET_SEQUENCE_STATE_H_
diff --git a/src/trace_processor/importers/proto/packet_sequence_state_builder.h b/src/trace_processor/importers/proto/packet_sequence_state_builder.h
new file mode 100644
index 0000000..599b03d
--- /dev/null
+++ b/src/trace_processor/importers/proto/packet_sequence_state_builder.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_PACKET_SEQUENCE_STATE_BUILDER_H_
+#define SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_PACKET_SEQUENCE_STATE_BUILDER_H_
+
+#include <cstdint>
+
+#include "perfetto/trace_processor/ref_counted.h"
+#include "src/trace_processor/importers/proto/packet_sequence_state_generation.h"
+#include "src/trace_processor/types/trace_processor_context.h"
+
+namespace perfetto {
+namespace trace_processor {
+
+// Helper class to generate a stream of PacketSequenceStateGeneration as we
+// receive packets for a sequence. This class deals with various events that
+// incrementally build up state that can be accessed by packet handling code
+// (tokenization nad parsing). An example of such state are interned messages or
+// trace packet defaults.
+class PacketSequenceStateBuilder {
+ public:
+ explicit PacketSequenceStateBuilder(TraceProcessorContext* context) {
+ generation_ = PacketSequenceStateGeneration::CreateFirst(context);
+ }
+
+ // Intern a message into the current generation.
+ void InternMessage(uint32_t field_id, TraceBlobView message) {
+ generation_->InternMessage(field_id, std::move(message));
+ }
+
+ // Set the trace packet defaults for the current generation. If the current
+ // generation already has defaults set, starts a new generation without
+ // invalidating other incremental state (such as interned data).
+ void UpdateTracePacketDefaults(TraceBlobView defaults) {
+ generation_ = generation_->OnNewTracePacketDefaults(std::move(defaults));
+ }
+
+ void OnPacketLoss() {
+ generation_ = generation_->OnPacketLoss();
+ packet_loss_ = true;
+ }
+
+ // Starts a new generation with clean-slate incremental state and defaults.
+ void OnIncrementalStateCleared() {
+ packet_loss_ = false;
+ generation_ = generation_->OnIncrementalStateCleared();
+ }
+
+ bool IsIncrementalStateValid() const { return !packet_loss_; }
+
+ // Returns a ref-counted ptr to the current generation.
+ RefPtr<PacketSequenceStateGeneration> current_generation() const {
+ return generation_;
+ }
+
+ private:
+ // If true, incremental state on the sequence is considered invalid until we
+ // see the next packet with incremental_state_cleared. We assume that we
+ // missed some packets at the beginning of the trace.
+ bool packet_loss_ = true;
+
+ RefPtr<PacketSequenceStateGeneration> generation_;
+};
+
+} // namespace trace_processor
+} // namespace perfetto
+
+#endif // SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_PACKET_SEQUENCE_STATE_BUILDER_H_
diff --git a/src/trace_processor/importers/proto/packet_sequence_state_generation.cc b/src/trace_processor/importers/proto/packet_sequence_state_generation.cc
index c520e92..711bb64 100644
--- a/src/trace_processor/importers/proto/packet_sequence_state_generation.cc
+++ b/src/trace_processor/importers/proto/packet_sequence_state_generation.cc
@@ -17,42 +17,89 @@
#include "src/trace_processor/importers/proto/packet_sequence_state_generation.h"
#include <cstddef>
-#include "src/trace_processor/importers/proto/packet_sequence_state.h"
+#include "src/trace_processor/importers/proto/track_event_sequence_state.h"
+#include "src/trace_processor/storage/stats.h"
#include "src/trace_processor/storage/trace_storage.h"
+#include "src/trace_processor/types/trace_processor_context.h"
-namespace perfetto {
-namespace trace_processor {
+namespace perfetto::trace_processor {
+
+PacketSequenceStateGeneration::CustomState::~CustomState() = default;
+
+// static
+RefPtr<PacketSequenceStateGeneration>
+PacketSequenceStateGeneration::CreateFirst(TraceProcessorContext* context) {
+ return RefPtr<PacketSequenceStateGeneration>(
+ new PacketSequenceStateGeneration(
+ context, TrackEventSequenceState::CreateFirst(), false));
+}
PacketSequenceStateGeneration::PacketSequenceStateGeneration(
- PacketSequenceState* state,
- PacketSequenceStateGeneration* prev_gen,
- TraceBlobView defaults)
- : state_(state),
- interned_data_(prev_gen->interned_data_),
- trace_packet_defaults_(InternedMessageView(std::move(defaults))),
- trackers_(prev_gen->trackers_) {
- for (auto& t : trackers_) {
- if (t.get() != nullptr) {
- t->set_generation(this);
+ TraceProcessorContext* context,
+ InternedFieldMap interned_data,
+ TrackEventSequenceState track_event_sequence_state,
+ CustomStateArray custom_state,
+ TraceBlobView trace_packet_defaults,
+ bool is_incremental_state_valid)
+ : context_(context),
+ interned_data_(std::move(interned_data)),
+ track_event_sequence_state_(std::move(track_event_sequence_state)),
+ custom_state_(std::move(custom_state)),
+ trace_packet_defaults_(std::move(trace_packet_defaults)),
+ is_incremental_state_valid_(is_incremental_state_valid) {
+ for (auto& s : custom_state_) {
+ if (s.get() != nullptr) {
+ s->set_generation(this);
}
}
}
-PacketSequenceStateGeneration::InternedDataTracker::~InternedDataTracker() =
- default;
-
-bool PacketSequenceStateGeneration::pid_and_tid_valid() const {
- return state_->pid_and_tid_valid();
-}
-int32_t PacketSequenceStateGeneration::pid() const {
- return state_->pid();
-}
-int32_t PacketSequenceStateGeneration::tid() const {
- return state_->tid();
+RefPtr<PacketSequenceStateGeneration>
+PacketSequenceStateGeneration::OnPacketLoss() {
+ // No need to increment the generation. If any future packet depends on
+ // previous messages to update the incremental state its packet (if the
+ // DataSource is behaving correctly) would have the
+ // SEQ_NEEDS_INCREMENTAL_STATE bit set and such a packet will be dropped by
+ // the ProtoTraceReader and never make it far enough to update any incremental
+ // state.
+ track_event_sequence_state_.OnPacketLoss();
+ is_incremental_state_valid_ = false;
+ return RefPtr<PacketSequenceStateGeneration>(this);
}
-TraceProcessorContext* PacketSequenceStateGeneration::GetContext() const {
- return state_->context();
+RefPtr<PacketSequenceStateGeneration>
+PacketSequenceStateGeneration::OnIncrementalStateCleared() {
+ return RefPtr<PacketSequenceStateGeneration>(
+ new PacketSequenceStateGeneration(
+ context_, track_event_sequence_state_.OnIncrementalStateCleared(),
+ true));
+}
+
+RefPtr<PacketSequenceStateGeneration>
+PacketSequenceStateGeneration::OnNewTracePacketDefaults(
+ TraceBlobView trace_packet_defaults) {
+ return RefPtr<PacketSequenceStateGeneration>(
+ new PacketSequenceStateGeneration(
+ context_, interned_data_,
+ track_event_sequence_state_.OnIncrementalStateCleared(),
+ custom_state_, std::move(trace_packet_defaults),
+ is_incremental_state_valid_));
+}
+
+InternedMessageView* PacketSequenceStateGeneration::GetInternedMessageView(
+ uint32_t field_id,
+ uint64_t iid) {
+ auto field_it = interned_data_.find(field_id);
+ if (field_it != interned_data_.end()) {
+ auto* message_map = &field_it->second;
+ auto it = message_map->find(iid);
+ if (it != message_map->end()) {
+ return &it->second;
+ }
+ }
+
+ context_->storage->IncrementStats(stats::interned_data_tokenizer_errors);
+ return nullptr;
}
void PacketSequenceStateGeneration::InternMessage(uint32_t field_id,
@@ -67,8 +114,7 @@
auto field = decoder.FindField(kIidFieldNumber);
if (PERFETTO_UNLIKELY(!field)) {
PERFETTO_DLOG("Interned message without interning_id");
- state_->context()->storage->IncrementStats(
- stats::interned_data_tokenizer_errors);
+ context_->storage->IncrementStats(stats::interned_data_tokenizer_errors);
return;
}
iid = field.as_uint64();
@@ -87,51 +133,4 @@
message_size) == 0));
}
-InternedMessageView* PacketSequenceStateGeneration::GetInternedMessageView(
- uint32_t field_id,
- uint64_t iid) {
- auto field_it = interned_data_.find(field_id);
- if (field_it != interned_data_.end()) {
- auto* message_map = &field_it->second;
- auto it = message_map->find(iid);
- if (it != message_map->end()) {
- return &it->second;
- }
- }
- state_->context()->storage->IncrementStats(
- stats::interned_data_tokenizer_errors);
- return nullptr;
-}
-
-int64_t PacketSequenceStateGeneration::IncrementAndGetTrackEventTimeNs(
- int64_t delta_ns) {
- return state_->IncrementAndGetTrackEventTimeNs(delta_ns);
-}
-int64_t PacketSequenceStateGeneration::IncrementAndGetTrackEventThreadTimeNs(
- int64_t delta_ns) {
- return state_->IncrementAndGetTrackEventThreadTimeNs(delta_ns);
-}
-int64_t
-PacketSequenceStateGeneration::IncrementAndGetTrackEventThreadInstructionCount(
- int64_t delta) {
- return state_->IncrementAndGetTrackEventThreadInstructionCount(delta);
-}
-bool PacketSequenceStateGeneration::track_event_timestamps_valid() const {
- return state_->track_event_timestamps_valid();
-}
-void PacketSequenceStateGeneration::SetThreadDescriptor(
- int32_t pid,
- int32_t tid,
- int64_t timestamp_ns,
- int64_t thread_timestamp_ns,
- int64_t thread_instruction_count) {
- state_->SetThreadDescriptor(pid, tid, timestamp_ns, thread_timestamp_ns,
- thread_instruction_count);
-}
-
-bool PacketSequenceStateGeneration::IsIncrementalStateValid() const {
- return state_->IsIncrementalStateValid();
-}
-
-} // namespace trace_processor
-} // namespace perfetto
+} // namespace perfetto::trace_processor
diff --git a/src/trace_processor/importers/proto/packet_sequence_state_generation.h b/src/trace_processor/importers/proto/packet_sequence_state_generation.h
index 6b60b59..82e2252 100644
--- a/src/trace_processor/importers/proto/packet_sequence_state_generation.h
+++ b/src/trace_processor/importers/proto/packet_sequence_state_generation.h
@@ -17,21 +17,16 @@
#ifndef SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_PACKET_SEQUENCE_STATE_GENERATION_H_
#define SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_PACKET_SEQUENCE_STATE_GENERATION_H_
-#include <array>
-#include <cstddef>
-#include <cstdint>
-#include <memory>
#include <optional>
-#include <tuple>
-#include <type_traits>
#include <unordered_map>
-#include "perfetto/public/compiler.h"
#include "perfetto/trace_processor/ref_counted.h"
#include "perfetto/trace_processor/trace_blob_view.h"
+#include "src/trace_processor/importers/proto/track_event_sequence_state.h"
#include "src/trace_processor/util/interned_message_view.h"
#include "protos/perfetto/trace/trace_packet_defaults.pbzero.h"
+#include "protos/perfetto/trace/track_event/thread_descriptor.pbzero.h"
#include "protos/perfetto/trace/track_event/track_event.pbzero.h"
namespace perfetto {
@@ -42,32 +37,36 @@
using InternedFieldMap =
std::unordered_map<uint32_t /*field_id*/, InternedMessageMap>;
-class PacketSequenceState;
class TraceProcessorContext;
class StackProfileSequenceState;
class ProfilePacketSequenceState;
class V8SequenceState;
-using InternedDataTrackers = std::tuple<StackProfileSequenceState,
- ProfilePacketSequenceState,
- V8SequenceState>;
+using CustomStateClasses = std::tuple<StackProfileSequenceState,
+ ProfilePacketSequenceState,
+ V8SequenceState>;
+// This is the public API exposed to packet tokenizers and parsers to access
+// state attached to a packet sequence. This state evolves as packets are
+// processed in sequence order. A packet that requires sequence state to be
+// properly parsed should snapshot this state by taking a copy of the RefPtr to
+// the currently active generation and passing it along with parsing specific
+// data to the sorting stage.
class PacketSequenceStateGeneration : public RefCounted {
public:
- // Base class to add custom sequence state. This state is keep per sequence
- // and per incremental state interval, that is, each time incremental state is
- // reset a new instance is created but not each time `TracePacketDefaults` are
- // updated. Note that this means that different
+ // Base class to attach custom state to the sequence state. This state is keep
+ // per sequence and per incremental state interval, that is, each time
+ // incremental state is reset a new instance is created but not each time
+ // `TracePacketDefaults` are updated. Note that this means that different
// `PacketSequenceStateGeneration` instances might point to the same
- // `InternedDataTracker` (because they only differ in their
- // `TracePacketDefaults`).
+ // `CustomState` (because they only differ in their `TracePacketDefaults`).
//
// ATTENTION: You should not create instances of these classes yourself but
- // use the `PacketSequenceStateGeneration::GetOrCreate<>' method instead.
- class InternedDataTracker : public RefCounted {
+ // use the `PacketSequenceStateGeneration::GetCustomState<>' method instead.
+ class CustomState : public RefCounted {
public:
- virtual ~InternedDataTracker();
+ virtual ~CustomState();
protected:
template <uint32_t FieldId, typename MessageType>
@@ -81,8 +80,8 @@
}
template <typename T>
- std::remove_cv_t<T>* GetOrCreate() {
- return generation_->GetOrCreate<T>();
+ std::remove_cv_t<T>* GetCustomState() {
+ return generation_->GetCustomState<T>();
}
bool pid_and_tid_valid() const { return generation_->pid_and_tid_valid(); }
@@ -103,32 +102,57 @@
// point to the latest one. We keep this member private to prevent misuse /
// confusion around this fact. Instead subclasses should access the public
// methods of this class to get any interned data.
+ // TODO(carlscab): Given that CustomState is ref counted this pointer might
+ // become invalid. CustomState should not be ref pointed and instead be
+ // owned by the `PacketSequenceStateGeneration` instance pointed at by
+ // `generation_`.
PacketSequenceStateGeneration* generation_ = nullptr;
};
- bool pid_and_tid_valid() const;
- int32_t pid() const;
- int32_t tid() const;
+ static RefPtr<PacketSequenceStateGeneration> CreateFirst(
+ TraceProcessorContext* context);
+
+ RefPtr<PacketSequenceStateGeneration> OnPacketLoss();
+
+ RefPtr<PacketSequenceStateGeneration> OnIncrementalStateCleared();
+
+ RefPtr<PacketSequenceStateGeneration> OnNewTracePacketDefaults(
+ TraceBlobView trace_packet_defaults);
+
+ bool pid_and_tid_valid() const {
+ return track_event_sequence_state_.pid_and_tid_valid();
+ }
+ int32_t pid() const { return track_event_sequence_state_.pid(); }
+ int32_t tid() const { return track_event_sequence_state_.tid(); }
// Returns |nullptr| if the message with the given |iid| was not found (also
// records a stat in this case).
template <uint32_t FieldId, typename MessageType>
- typename MessageType::Decoder* LookupInternedMessage(uint64_t iid);
+ typename MessageType::Decoder* LookupInternedMessage(uint64_t iid) {
+ auto* interned_message_view = GetInternedMessageView(FieldId, iid);
+ if (!interned_message_view)
+ return nullptr;
+
+ return interned_message_view->template GetOrCreateDecoder<MessageType>();
+ }
InternedMessageView* GetInternedMessageView(uint32_t field_id, uint64_t iid);
// Returns |nullptr| if no defaults were set.
InternedMessageView* GetTracePacketDefaultsView() {
- if (!trace_packet_defaults_)
+ if (!trace_packet_defaults_.has_value()) {
return nullptr;
- return &trace_packet_defaults_.value();
+ }
+
+ return &*trace_packet_defaults_;
}
// Returns |nullptr| if no defaults were set.
protos::pbzero::TracePacketDefaults::Decoder* GetTracePacketDefaults() {
- InternedMessageView* view = GetTracePacketDefaultsView();
- if (!view)
+ if (!trace_packet_defaults_.has_value()) {
return nullptr;
- return view->GetOrCreateDecoder<protos::pbzero::TracePacketDefaults>();
+ }
+ return trace_packet_defaults_
+ ->GetOrCreateDecoder<protos::pbzero::TracePacketDefaults>();
}
// Returns |nullptr| if no TrackEventDefaults were set.
@@ -148,30 +172,57 @@
return nullptr;
}
- // Extension point for custom sequence state. To add new per sequence state
- // just subclass ´PacketSequenceStateGeneration´ and get your sequence bound
- // instance by calling this method.
+ // Extension point for custom incremental state. Custom state classes need to
+ // inherit from `CustomState`.
+ //
+ // A common use case for this custom state is to store cache mappings between
+ // interning ids (iid) and TraceProcessor objects (e.g. table row). When we
+ // see an iid we need to access the InternedMessageView for that iid, and
+ // possibly do some computations, the result of all of this could then be
+ // cached so that next time we encounter the same iid we could reuse this
+ // cached value. This caching is only valid until incremental state is
+ // cleared, from then on subsequent iid values on the sequence will no longer
+ // refer to the same entities as the iid values before the clear. Custom state
+ // classes no not need to explicitly handle this: they are attached to an
+ // `IncrementalState` instance, and a new one is created when the state is
+ // cleared, so iid values after the clear will be processed by a new (empty)
+ // custom state instance.
template <typename T>
- std::remove_cv_t<T>* GetOrCreate();
+ std::remove_cv_t<T>* GetCustomState();
- // TODO(carlscab): All this should be tracked in a dedicated class
- // TrackEventSequenceState or something attached to the "incremental state".
- int64_t IncrementAndGetTrackEventTimeNs(int64_t delta_ns);
- int64_t IncrementAndGetTrackEventThreadTimeNs(int64_t delta_ns);
- int64_t IncrementAndGetTrackEventThreadInstructionCount(int64_t delta);
- bool track_event_timestamps_valid() const;
- void SetThreadDescriptor(int32_t pid,
- int32_t tid,
- int64_t timestamp_ns,
- int64_t thread_timestamp_ns,
- int64_t thread_instruction_count);
+ int64_t IncrementAndGetTrackEventTimeNs(int64_t delta_ns) {
+ return track_event_sequence_state_.IncrementAndGetTrackEventTimeNs(
+ delta_ns);
+ }
+
+ int64_t IncrementAndGetTrackEventThreadTimeNs(int64_t delta_ns) {
+ return track_event_sequence_state_.IncrementAndGetTrackEventThreadTimeNs(
+ delta_ns);
+ }
+
+ int64_t IncrementAndGetTrackEventThreadInstructionCount(int64_t delta) {
+ return track_event_sequence_state_
+ .IncrementAndGetTrackEventThreadInstructionCount(delta);
+ }
+
+ bool track_event_timestamps_valid() const {
+ return track_event_sequence_state_.timestamps_valid();
+ }
+
+ void SetThreadDescriptor(
+ const protos::pbzero::ThreadDescriptor::Decoder& descriptor) {
+ track_event_sequence_state_.SetThreadDescriptor(descriptor);
+ }
// TODO(carlscab): Nobody other than `ProtoTraceReader` should care about
// this. Remove.
- bool IsIncrementalStateValid() const;
+ bool IsIncrementalStateValid() const { return is_incremental_state_valid_; }
private:
- friend class PacketSequenceState;
+ friend class PacketSequenceStateBuilder;
+
+ using CustomStateArray =
+ std::array<RefPtr<CustomState>, std::tuple_size_v<CustomStateClasses>>;
// Helper to find the index in a tuple of a given type. Lookups are done
// ignoring cv qualifiers. If no index is found size of the tuple is returned.
@@ -195,56 +246,50 @@
}
}
- explicit PacketSequenceStateGeneration(PacketSequenceState* state)
- : state_(state) {}
+ PacketSequenceStateGeneration(TraceProcessorContext* context,
+ TrackEventSequenceState track_state,
+ bool is_incremental_state_valid)
+ : context_(context),
+ track_event_sequence_state_(std::move(track_state)),
+ is_incremental_state_valid_(is_incremental_state_valid) {}
- PacketSequenceStateGeneration(PacketSequenceState* state,
- PacketSequenceStateGeneration* prev_gen,
- TraceBlobView defaults);
+ PacketSequenceStateGeneration(
+ TraceProcessorContext* context,
+ InternedFieldMap interned_data,
+ TrackEventSequenceState track_event_sequence_state,
+ CustomStateArray custom_state,
+ TraceBlobView trace_packet_defaults,
+ bool is_incremental_state_valid);
- TraceProcessorContext* GetContext() const;
-
+ // Add an interned message to this incremental state view. This can only be
+ // called by `PacketSequenceStateBuilder' (which is a friend) as packet
+ // tokenizers and parsers should never deal directly with reading interned
+ // data out of trace packets.
void InternMessage(uint32_t field_id, TraceBlobView message);
- void SetTracePacketDefaults(TraceBlobView defaults) {
- // Defaults should only be set once per generation.
- PERFETTO_DCHECK(!trace_packet_defaults_);
- trace_packet_defaults_ = InternedMessageView(std::move(defaults));
- }
-
- // TODO(carlscab): This is dangerous given that PacketSequenceStateGeneration
- // is refcounted and PacketSequenceState is not.
- PacketSequenceState* state_;
+ TraceProcessorContext* const context_;
InternedFieldMap interned_data_;
+ TrackEventSequenceState track_event_sequence_state_;
+ CustomStateArray custom_state_;
std::optional<InternedMessageView> trace_packet_defaults_;
- std::array<RefPtr<InternedDataTracker>,
- std::tuple_size_v<InternedDataTrackers>>
- trackers_;
+ // TODO(carlscab): Should not be needed as clients of this class should not
+ // care about validity.
+ bool is_incremental_state_valid_ = true;
};
template <typename T>
-std::remove_cv_t<T>* PacketSequenceStateGeneration::GetOrCreate() {
- constexpr size_t index = FindUniqueType<InternedDataTrackers, T>();
- static_assert(index < std::tuple_size_v<InternedDataTrackers>, "Not found");
- auto& ptr = trackers_[index];
+std::remove_cv_t<T>* PacketSequenceStateGeneration::GetCustomState() {
+ constexpr size_t index = FindUniqueType<CustomStateClasses, T>();
+ static_assert(index < std::tuple_size_v<CustomStateClasses>, "Not found");
+ auto& ptr = custom_state_[index];
if (PERFETTO_UNLIKELY(ptr.get() == nullptr)) {
- ptr.reset(new T(GetContext()));
+ ptr.reset(new T(context_));
ptr->set_generation(this);
}
return static_cast<std::remove_cv_t<T>*>(ptr.get());
}
-template <uint32_t FieldId, typename MessageType>
-typename MessageType::Decoder*
-PacketSequenceStateGeneration::LookupInternedMessage(uint64_t iid) {
- auto* interned_message_view = GetInternedMessageView(FieldId, iid);
- if (!interned_message_view)
- return nullptr;
-
- return interned_message_view->template GetOrCreateDecoder<MessageType>();
-}
-
} // namespace trace_processor
} // namespace perfetto
diff --git a/src/trace_processor/importers/proto/profile_module.cc b/src/trace_processor/importers/proto/profile_module.cc
index 2bfb78a..55e3547 100644
--- a/src/trace_processor/importers/proto/profile_module.cc
+++ b/src/trace_processor/importers/proto/profile_module.cc
@@ -155,7 +155,7 @@
ProcessTracker* procs = context_->process_tracker.get();
TraceStorage* storage = context_->storage.get();
StackProfileSequenceState& stack_profile_sequence_state =
- *sequence_state->GetOrCreate<StackProfileSequenceState>();
+ *sequence_state->GetCustomState<StackProfileSequenceState>();
uint32_t pid = static_cast<uint32_t>(sequence_state->pid());
uint32_t tid = static_cast<uint32_t>(sequence_state->tid());
@@ -255,7 +255,7 @@
context_->process_tracker->GetOrCreateProcess(sample.pid());
StackProfileSequenceState& stack_profile_sequence_state =
- *sequence_state->GetOrCreate<StackProfileSequenceState>();
+ *sequence_state->GetCustomState<StackProfileSequenceState>();
uint64_t callstack_iid = sample.callstack_iid();
std::optional<CallsiteId> cs_id =
stack_profile_sequence_state.FindOrInsertCallstack(upid, callstack_iid);
@@ -306,7 +306,7 @@
PacketSequenceStateGeneration* sequence_state,
ConstBytes blob) {
ProfilePacketSequenceState& profile_packet_sequence_state =
- *sequence_state->GetOrCreate<ProfilePacketSequenceState>();
+ *sequence_state->GetCustomState<ProfilePacketSequenceState>();
protos::pbzero::ProfilePacket::Decoder packet(blob.data, blob.size);
profile_packet_sequence_state.SetProfilePacketIndex(packet.index());
diff --git a/src/trace_processor/importers/proto/profile_packet_sequence_state.cc b/src/trace_processor/importers/proto/profile_packet_sequence_state.cc
index b5cdb70..f0858e3 100644
--- a/src/trace_processor/importers/proto/profile_packet_sequence_state.cc
+++ b/src/trace_processor/importers/proto/profile_packet_sequence_state.cc
@@ -283,8 +283,8 @@
if (CallsiteId* id = callstacks_.Find(iid); id) {
return *id;
}
- return GetOrCreate<StackProfileSequenceState>()->FindOrInsertCallstack(upid,
- iid);
+ return GetCustomState<StackProfileSequenceState>()->FindOrInsertCallstack(
+ upid, iid);
}
} // namespace trace_processor
diff --git a/src/trace_processor/importers/proto/profile_packet_sequence_state.h b/src/trace_processor/importers/proto/profile_packet_sequence_state.h
index 3fb8dcd..7282657 100644
--- a/src/trace_processor/importers/proto/profile_packet_sequence_state.h
+++ b/src/trace_processor/importers/proto/profile_packet_sequence_state.h
@@ -34,7 +34,7 @@
// Keeps sequence specific state for profile packets.
class ProfilePacketSequenceState final
- : public PacketSequenceStateGeneration::InternedDataTracker {
+ : public PacketSequenceStateGeneration::CustomState {
public:
using SourceStringId = uint64_t;
diff --git a/src/trace_processor/importers/proto/profile_packet_sequence_state_unittest.cc b/src/trace_processor/importers/proto/profile_packet_sequence_state_unittest.cc
index c9cd6e3..ddaaa85 100644
--- a/src/trace_processor/importers/proto/profile_packet_sequence_state_unittest.cc
+++ b/src/trace_processor/importers/proto/profile_packet_sequence_state_unittest.cc
@@ -20,7 +20,7 @@
#include "src/trace_processor/importers/common/mapping_tracker.h"
#include "src/trace_processor/importers/common/stack_profile_tracker.h"
-#include "src/trace_processor/importers/proto/packet_sequence_state.h"
+#include "src/trace_processor/importers/proto/packet_sequence_state_generation.h"
#include "src/trace_processor/types/trace_processor_context.h"
#include "test/gtest_and_gmock.h"
@@ -61,7 +61,7 @@
context.storage.reset(new TraceStorage());
context.mapping_tracker.reset(new MappingTracker(&context));
context.stack_profile_tracker.reset(new StackProfileTracker(&context));
- packet_sequence_state.reset(new PacketSequenceState(&context));
+ sequence_state = PacketSequenceStateGeneration::CreateFirst(&context);
mapping_name = context.storage->InternString("[mapping]");
fully_qualified_mapping_name = context.storage->InternString("/[mapping]");
@@ -71,8 +71,7 @@
protected:
ProfilePacketSequenceState& profile_packet_sequence_state() {
- return *packet_sequence_state->current_generation()
- ->GetOrCreate<ProfilePacketSequenceState>();
+ return *sequence_state->GetCustomState<ProfilePacketSequenceState>();
}
void InsertMapping(const Packet& packet) {
profile_packet_sequence_state().AddString(packet.mapping_name_id,
@@ -117,7 +116,7 @@
StringId build;
StringId frame_name;
TraceProcessorContext context;
- std::unique_ptr<PacketSequenceState> packet_sequence_state;
+ RefPtr<PacketSequenceStateGeneration> sequence_state;
};
// Insert the same mapping from two different packets, with different strings
@@ -200,9 +199,9 @@
context.storage.reset(new TraceStorage());
context.mapping_tracker.reset(new MappingTracker(&context));
context.stack_profile_tracker.reset(new StackProfileTracker(&context));
- PacketSequenceState pss(&context);
+ auto state = PacketSequenceStateGeneration::CreateFirst(&context);
ProfilePacketSequenceState& ppss =
- *pss.current_generation()->GetOrCreate<ProfilePacketSequenceState>();
+ *state->GetCustomState<ProfilePacketSequenceState>();
constexpr auto kBuildId = 1u;
constexpr auto kMappingNameId1 = 2u;
@@ -235,9 +234,9 @@
context.mapping_tracker.reset(new MappingTracker(&context));
context.stack_profile_tracker.reset(new StackProfileTracker(&context));
- PacketSequenceState pss(&context);
+ auto state = PacketSequenceStateGeneration::CreateFirst(&context);
ProfilePacketSequenceState& ppss =
- *pss.current_generation()->GetOrCreate<ProfilePacketSequenceState>();
+ *state->GetCustomState<ProfilePacketSequenceState>();
uint32_t next_string_intern_id = 1;
diff --git a/src/trace_processor/importers/proto/proto_incremental_state.h b/src/trace_processor/importers/proto/proto_incremental_state.h
deleted file mode 100644
index aaac42f..0000000
--- a/src/trace_processor/importers/proto/proto_incremental_state.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_PROTO_INCREMENTAL_STATE_H_
-#define SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_PROTO_INCREMENTAL_STATE_H_
-
-#include <stdint.h>
-
-#include <map>
-
-#include "src/trace_processor/importers/proto/packet_sequence_state.h"
-
-namespace perfetto {
-namespace trace_processor {
-
-class TraceProcessorContext;
-
-// Stores per-packet-sequence incremental state during trace parsing, such as
-// reference timestamps for delta timestamp calculation and interned messages.
-class ProtoIncrementalState {
- public:
- ProtoIncrementalState(TraceProcessorContext* context) : context_(context) {}
-
- // Returns the PacketSequenceState for the packet sequence with the given id.
- // If this is a new sequence which we haven't tracked before, initializes and
- // inserts a new PacketSequenceState into the state map.
- PacketSequenceState* GetOrCreateStateForPacketSequence(uint32_t sequence_id) {
- auto& ptr = packet_sequence_states_[sequence_id];
- if (!ptr)
- ptr.reset(new PacketSequenceState(context_));
- return ptr.get();
- }
-
- private:
- // Stores unique_ptrs to ensure that pointers to a PacketSequenceState remain
- // valid even if the map rehashes.
- std::map<uint32_t, std::unique_ptr<PacketSequenceState>>
- packet_sequence_states_;
-
- TraceProcessorContext* context_;
-};
-
-} // namespace trace_processor
-} // namespace perfetto
-
-#endif // SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_PROTO_INCREMENTAL_STATE_H_
diff --git a/src/trace_processor/importers/proto/proto_trace_reader.cc b/src/trace_processor/importers/proto/proto_trace_reader.cc
index e139cbe..2e50f0c 100644
--- a/src/trace_processor/importers/proto/proto_trace_reader.cc
+++ b/src/trace_processor/importers/proto/proto_trace_reader.cc
@@ -34,8 +34,6 @@
#include "src/trace_processor/importers/common/track_tracker.h"
#include "src/trace_processor/importers/ftrace/ftrace_module.h"
#include "src/trace_processor/importers/proto/packet_analyzer.h"
-#include "src/trace_processor/importers/proto/packet_sequence_state.h"
-#include "src/trace_processor/importers/proto/proto_incremental_state.h"
#include "src/trace_processor/sorter/trace_sorter.h"
#include "src/trace_processor/storage/stats.h"
#include "src/trace_processor/storage/trace_storage.h"
diff --git a/src/trace_processor/importers/proto/proto_trace_reader.h b/src/trace_processor/importers/proto/proto_trace_reader.h
index 1243b97..a93ad98 100644
--- a/src/trace_processor/importers/proto/proto_trace_reader.h
+++ b/src/trace_processor/importers/proto/proto_trace_reader.h
@@ -19,11 +19,13 @@
#include <stdint.h>
-#include <memory>
+#include <tuple>
+#include <utility>
+#include "perfetto/ext/base/flat_hash_map.h"
#include "src/trace_processor/importers/common/chunked_trace_reader.h"
#include "src/trace_processor/importers/proto/multi_machine_trace_manager.h"
-#include "src/trace_processor/importers/proto/proto_incremental_state.h"
+#include "src/trace_processor/importers/proto/packet_sequence_state_builder.h"
#include "src/trace_processor/importers/proto/proto_trace_tokenizer.h"
#include "src/trace_processor/storage/trace_storage.h"
@@ -79,11 +81,15 @@
std::optional<StringId> GetBuiltinClockNameOrNull(int64_t clock_id);
- PacketSequenceState* GetIncrementalStateForPacketSequence(
+ PacketSequenceStateBuilder* GetIncrementalStateForPacketSequence(
uint32_t sequence_id) {
- if (!incremental_state)
- incremental_state.reset(new ProtoIncrementalState(context_));
- return incremental_state->GetOrCreateStateForPacketSequence(sequence_id);
+ auto* builder = packet_sequence_state_builders_.Find(sequence_id);
+ if (builder == nullptr) {
+ builder = packet_sequence_state_builders_
+ .Insert(sequence_id, PacketSequenceStateBuilder(context_))
+ .first;
+ }
+ return builder;
}
util::Status ParseExtensionDescriptor(ConstBytes descriptor);
@@ -95,9 +101,8 @@
// timestamp given is latest_timestamp_.
int64_t latest_timestamp_ = 0;
- // Stores incremental state and references to interned data, e.g. for track
- // event protos.
- std::unique_ptr<ProtoIncrementalState> incremental_state;
+ base::FlatHashMap<uint32_t, PacketSequenceStateBuilder>
+ packet_sequence_state_builders_;
StringId skipped_packet_key_id_;
StringId invalid_incremental_state_key_id_;
diff --git a/src/trace_processor/importers/proto/stack_profile_sequence_state.h b/src/trace_processor/importers/proto/stack_profile_sequence_state.h
index 518388d..e946e8d 100644
--- a/src/trace_processor/importers/proto/stack_profile_sequence_state.h
+++ b/src/trace_processor/importers/proto/stack_profile_sequence_state.h
@@ -23,7 +23,6 @@
#include "perfetto/ext/base/flat_hash_map.h"
#include "perfetto/ext/base/hash.h"
#include "perfetto/ext/base/string_view.h"
-#include "src/trace_processor/importers/common/mapping_tracker.h"
#include "src/trace_processor/importers/proto/packet_sequence_state_generation.h"
#include "src/trace_processor/storage/trace_storage.h"
#include "src/trace_processor/types/trace_processor_context.h"
@@ -35,7 +34,7 @@
class VirtualMemoryMapping;
class StackProfileSequenceState final
- : public PacketSequenceStateGeneration::InternedDataTracker {
+ : public PacketSequenceStateGeneration::CustomState {
public:
explicit StackProfileSequenceState(TraceProcessorContext* context);
diff --git a/src/trace_processor/importers/proto/track_event_parser.cc b/src/trace_processor/importers/proto/track_event_parser.cc
index 09ef474..b2b4e93 100644
--- a/src/trace_processor/importers/proto/track_event_parser.cc
+++ b/src/trace_processor/importers/proto/track_event_parser.cc
@@ -31,6 +31,7 @@
#include "src/trace_processor/importers/common/machine_tracker.h"
#include "src/trace_processor/importers/common/process_tracker.h"
#include "src/trace_processor/importers/common/track_tracker.h"
+#include "src/trace_processor/importers/common/virtual_memory_mapping.h"
#include "src/trace_processor/importers/json/json_utils.h"
#include "src/trace_processor/importers/proto/packet_analyzer.h"
#include "src/trace_processor/importers/proto/profile_packet_utils.h"
@@ -197,7 +198,7 @@
// Interned mapping_id loses it's meaning when the sequence ends. So we need
// to get an id from stack_profile_mapping table.
auto mapping = delegate.seq_state()
- ->GetOrCreate<StackProfileSequenceState>()
+ ->GetCustomState<StackProfileSequenceState>()
->FindOrInsertMapping(decoder->mapping_id());
if (!mapping) {
return std::nullopt;
diff --git a/src/trace_processor/importers/proto/track_event_sequence_state.cc b/src/trace_processor/importers/proto/track_event_sequence_state.cc
new file mode 100644
index 0000000..99bc93e
--- /dev/null
+++ b/src/trace_processor/importers/proto/track_event_sequence_state.cc
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "src/trace_processor/importers/proto/track_event_sequence_state.h"
+
+#include "protos/perfetto/trace/track_event/thread_descriptor.pbzero.h"
+
+namespace perfetto {
+namespace trace_processor {
+
+void TrackEventSequenceState::SetThreadDescriptor(
+ const protos::pbzero::ThreadDescriptor::Decoder& decoder) {
+ persistent_state_.pid_and_tid_valid = true;
+ persistent_state_.pid = decoder.pid();
+ persistent_state_.tid = decoder.tid();
+
+ timestamps_valid_ = true;
+ timestamp_ns_ = decoder.reference_timestamp_us() * 1000;
+ thread_timestamp_ns_ = decoder.reference_thread_time_us() * 1000;
+ thread_instruction_count_ = decoder.reference_thread_instruction_count();
+}
+
+} // namespace trace_processor
+} // namespace perfetto
diff --git a/src/trace_processor/importers/proto/track_event_sequence_state.h b/src/trace_processor/importers/proto/track_event_sequence_state.h
new file mode 100644
index 0000000..9291ef7
--- /dev/null
+++ b/src/trace_processor/importers/proto/track_event_sequence_state.h
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_TRACK_EVENT_SEQUENCE_STATE_H_
+#define SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_TRACK_EVENT_SEQUENCE_STATE_H_
+
+#include <utility>
+
+#include "protos/perfetto/trace/track_event/thread_descriptor.pbzero.h"
+
+namespace perfetto {
+namespace trace_processor {
+
+class TrackEventSequenceState {
+ public:
+ static TrackEventSequenceState CreateFirst() {
+ return TrackEventSequenceState(PersistentState());
+ }
+
+ TrackEventSequenceState OnIncrementalStateCleared() {
+ return TrackEventSequenceState(persistent_state_);
+ }
+
+ void OnPacketLoss() { timestamps_valid_ = false; }
+
+ bool pid_and_tid_valid() const { return persistent_state_.pid_and_tid_valid; }
+
+ int32_t pid() const { return persistent_state_.pid; }
+ int32_t tid() const { return persistent_state_.tid; }
+
+ bool timestamps_valid() const { return timestamps_valid_; }
+
+ int64_t IncrementAndGetTrackEventTimeNs(int64_t delta_ns) {
+ PERFETTO_DCHECK(timestamps_valid());
+ timestamp_ns_ += delta_ns;
+ return timestamp_ns_;
+ }
+
+ int64_t IncrementAndGetTrackEventThreadTimeNs(int64_t delta_ns) {
+ PERFETTO_DCHECK(timestamps_valid());
+ thread_timestamp_ns_ += delta_ns;
+ return thread_timestamp_ns_;
+ }
+
+ int64_t IncrementAndGetTrackEventThreadInstructionCount(int64_t delta) {
+ PERFETTO_DCHECK(timestamps_valid());
+ thread_instruction_count_ += delta;
+ return thread_instruction_count_;
+ }
+
+ void SetThreadDescriptor(const protos::pbzero::ThreadDescriptor::Decoder&);
+
+ private:
+ // State that is never cleared.
+ struct PersistentState {
+ // |pid_| and |tid_| are only valid after we parsed at least one
+ // ThreadDescriptor packet on the sequence.
+ bool pid_and_tid_valid = false;
+
+ // Process/thread ID of the packet sequence set by a ThreadDescriptor
+ // packet. Used as default values for TrackEvents that don't specify a
+ // pid/tid override. Only valid after |pid_and_tid_valid_| is set to true.
+ int32_t pid = 0;
+ int32_t tid = 0;
+ };
+
+ explicit TrackEventSequenceState(PersistentState persistent_state)
+ : persistent_state_(std::move(persistent_state)) {}
+
+ // We can only consider TrackEvent delta timestamps to be correct after we
+ // have observed a thread descriptor (since the last packet loss).
+ bool timestamps_valid_ = false;
+
+ // Current wall/thread timestamps/counters used as reference for the next
+ // TrackEvent delta timestamp.
+ int64_t timestamp_ns_ = 0;
+ int64_t thread_timestamp_ns_ = 0;
+ int64_t thread_instruction_count_ = 0;
+
+ PersistentState persistent_state_;
+};
+
+} // namespace trace_processor
+} // namespace perfetto
+
+#endif // SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_TRACK_EVENT_SEQUENCE_STATE_H_
diff --git a/src/trace_processor/importers/proto/track_event_tokenizer.cc b/src/trace_processor/importers/proto/track_event_tokenizer.cc
index d9ed336..c836052 100644
--- a/src/trace_processor/importers/proto/track_event_tokenizer.cc
+++ b/src/trace_processor/importers/proto/track_event_tokenizer.cc
@@ -212,10 +212,7 @@
const protos::pbzero::ThreadDescriptor::Decoder& thread) {
// TODO(eseckler): Remove support for legacy thread descriptor-based default
// tracks and delta timestamps.
- state.SetThreadDescriptor(thread.pid(), thread.tid(),
- thread.reference_timestamp_us() * 1000,
- thread.reference_thread_time_us() * 1000,
- thread.reference_thread_instruction_count());
+ state.SetThreadDescriptor(thread);
}
void TrackEventTokenizer::TokenizeTrackEventPacket(
diff --git a/src/trace_processor/importers/proto/v8_module.cc b/src/trace_processor/importers/proto/v8_module.cc
index 89360b6..88d8f53 100644
--- a/src/trace_processor/importers/proto/v8_module.cc
+++ b/src/trace_processor/importers/proto/v8_module.cc
@@ -142,7 +142,8 @@
void V8Module::ParseV8JsCode(protozero::ConstBytes bytes,
int64_t ts,
const TracePacketData& data) {
- V8SequenceState& state = *data.sequence_state->GetOrCreate<V8SequenceState>();
+ V8SequenceState& state =
+ *data.sequence_state->GetCustomState<V8SequenceState>();
V8JsCode::Decoder code(bytes);
@@ -169,7 +170,8 @@
void V8Module::ParseV8InternalCode(protozero::ConstBytes bytes,
int64_t ts,
const TracePacketData& data) {
- V8SequenceState& state = *data.sequence_state->GetOrCreate<V8SequenceState>();
+ V8SequenceState& state =
+ *data.sequence_state->GetCustomState<V8SequenceState>();
V8InternalCode::Decoder code(bytes);
@@ -190,7 +192,8 @@
void V8Module::ParseV8WasmCode(protozero::ConstBytes bytes,
int64_t ts,
const TracePacketData& data) {
- V8SequenceState& state = *data.sequence_state->GetOrCreate<V8SequenceState>();
+ V8SequenceState& state =
+ *data.sequence_state->GetCustomState<V8SequenceState>();
V8WasmCode::Decoder code(bytes);
@@ -217,7 +220,8 @@
void V8Module::ParseV8RegExpCode(protozero::ConstBytes bytes,
int64_t ts,
const TracePacketData& data) {
- V8SequenceState& state = *data.sequence_state->GetOrCreate<V8SequenceState>();
+ V8SequenceState& state =
+ *data.sequence_state->GetCustomState<V8SequenceState>();
V8RegExpCode::Decoder code(bytes);
@@ -238,7 +242,8 @@
void V8Module::ParseV8CodeMove(protozero::ConstBytes bytes,
int64_t,
const TracePacketData& data) {
- V8SequenceState& state = *data.sequence_state->GetOrCreate<V8SequenceState>();
+ V8SequenceState& state =
+ *data.sequence_state->GetCustomState<V8SequenceState>();
protos::pbzero::V8CodeMove::Decoder v8_code_move(bytes);
std::optional<IsolateId> isolate_id =
diff --git a/src/trace_processor/importers/proto/v8_sequence_state.h b/src/trace_processor/importers/proto/v8_sequence_state.h
index d2e008a..1b60ca0 100644
--- a/src/trace_processor/importers/proto/v8_sequence_state.h
+++ b/src/trace_processor/importers/proto/v8_sequence_state.h
@@ -24,7 +24,6 @@
#include "src/trace_processor/importers/proto/packet_sequence_state_generation.h"
#include "src/trace_processor/storage/trace_storage.h"
#include "src/trace_processor/tables/v8_tables_py.h"
-#include "src/trace_processor/types/destructible.h"
namespace perfetto {
namespace trace_processor {
@@ -34,7 +33,7 @@
// Helper class to deal with V8 related interned data.
class V8SequenceState final
- : public PacketSequenceStateGeneration::InternedDataTracker {
+ : public PacketSequenceStateGeneration::CustomState {
public:
explicit V8SequenceState(TraceProcessorContext* context);
diff --git a/src/trace_processor/importers/proto/vulkan_memory_tracker.h b/src/trace_processor/importers/proto/vulkan_memory_tracker.h
index 9d1afc5..dd44a89 100644
--- a/src/trace_processor/importers/proto/vulkan_memory_tracker.h
+++ b/src/trace_processor/importers/proto/vulkan_memory_tracker.h
@@ -17,19 +17,18 @@
#ifndef SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_VULKAN_MEMORY_TRACKER_H_
#define SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_VULKAN_MEMORY_TRACKER_H_
-#include "protos/perfetto/trace/profiling/profile_common.pbzero.h"
-#include "src/trace_processor/importers/proto/proto_incremental_state.h"
+#include "src/trace_processor/importers/proto/packet_sequence_state_generation.h"
#include "src/trace_processor/storage/trace_storage.h"
+#include "src/trace_processor/types/trace_processor_context.h"
#include "protos/perfetto/trace/gpu/vulkan_memory_event.pbzero.h"
+#include "protos/perfetto/trace/profiling/profile_common.pbzero.h"
namespace perfetto {
namespace trace_processor {
using protos::pbzero::VulkanMemoryEvent;
-class TraceProcessorContext;
-
class VulkanMemoryTracker {
public:
enum class DeviceCounterType {
diff --git a/src/trace_processor/sorter/BUILD.gn b/src/trace_processor/sorter/BUILD.gn
index 5d27204..8d4c9f9 100644
--- a/src/trace_processor/sorter/BUILD.gn
+++ b/src/trace_processor/sorter/BUILD.gn
@@ -50,9 +50,11 @@
"../../../gn:default_deps",
"../../../gn:gtest_and_gmock",
"../../../include/perfetto/trace_processor:storage",
+ "../../../include/perfetto/trace_processor:trace_processor",
"../../base",
"../importers/common:parser_types",
"../importers/proto:minimal",
+ "../importers/proto:packet_sequence_state_generation_hdr",
"../types",
]
}
diff --git a/src/trace_processor/sorter/trace_sorter.h b/src/trace_processor/sorter/trace_sorter.h
index dd38504..5ea0e0d 100644
--- a/src/trace_processor/sorter/trace_sorter.h
+++ b/src/trace_processor/sorter/trace_sorter.h
@@ -28,7 +28,6 @@
#include "perfetto/public/compiler.h"
#include "perfetto/trace_processor/basic_types.h"
#include "perfetto/trace_processor/trace_blob_view.h"
-#include "src/trace_processor/importers/common/parser_types.h"
#include "src/trace_processor/importers/common/trace_parser.h"
#include "src/trace_processor/importers/fuchsia/fuchsia_record.h"
#include "src/trace_processor/importers/systrace/systrace_line.h"
diff --git a/src/trace_processor/sorter/trace_sorter_unittest.cc b/src/trace_processor/sorter/trace_sorter_unittest.cc
index 3fc8f76..42421df 100644
--- a/src/trace_processor/sorter/trace_sorter_unittest.cc
+++ b/src/trace_processor/sorter/trace_sorter_unittest.cc
@@ -13,8 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-#include "perfetto/trace_processor/trace_blob_view.h"
-#include "src/trace_processor/importers/proto/proto_trace_parser_impl.h"
+#include "src/trace_processor/sorter/trace_sorter.h"
#include <map>
#include <random>
@@ -22,9 +21,10 @@
#include "perfetto/trace_processor/basic_types.h"
#include "perfetto/trace_processor/trace_blob.h"
+#include "perfetto/trace_processor/trace_blob_view.h"
#include "src/trace_processor/importers/common/parser_types.h"
-#include "src/trace_processor/importers/proto/packet_sequence_state.h"
-#include "src/trace_processor/sorter/trace_sorter.h"
+#include "src/trace_processor/importers/proto/packet_sequence_state_generation.h"
+#include "src/trace_processor/importers/proto/proto_trace_parser_impl.h"
#include "src/trace_processor/types/trace_processor_context.h"
#include "test/gtest_and_gmock.h"
@@ -105,26 +105,25 @@
};
TEST_F(TraceSorterTest, TestFtrace) {
- PacketSequenceState state(&context_);
+ auto state = PacketSequenceStateGeneration::CreateFirst(&context_);
TraceBlobView view = test_buffer_.slice_off(0, 1);
EXPECT_CALL(*parser_,
MOCK_ParseFtracePacket(0, 1000, view.data(), 1, kNullMachineId));
context_.sorter->PushFtraceEvent(0 /*cpu*/, 1000 /*timestamp*/,
- std::move(view), state.current_generation());
+ std::move(view), state);
context_.sorter->ExtractEventsForced();
}
TEST_F(TraceSorterTest, TestTracePacket) {
- PacketSequenceState state(&context_);
+ auto state = PacketSequenceStateGeneration::CreateFirst(&context_);
TraceBlobView view = test_buffer_.slice_off(0, 1);
EXPECT_CALL(*parser_, MOCK_ParseTracePacket(1000, view.data(), 1));
- context_.sorter->PushTracePacket(1000, state.current_generation(),
- std::move(view));
+ context_.sorter->PushTracePacket(1000, state, std::move(view));
context_.sorter->ExtractEventsForced();
}
TEST_F(TraceSorterTest, Ordering) {
- PacketSequenceState state(&context_);
+ auto state = PacketSequenceStateGeneration::CreateFirst(&context_);
TraceBlobView view_1 = test_buffer_.slice_off(0, 1);
TraceBlobView view_2 = test_buffer_.slice_off(0, 2);
TraceBlobView view_3 = test_buffer_.slice_off(0, 3);
@@ -140,22 +139,18 @@
kNullMachineId));
context_.sorter->PushFtraceEvent(2 /*cpu*/, 1200 /*timestamp*/,
- std::move(view_4),
- state.current_generation());
- context_.sorter->PushTracePacket(1001, state.current_generation(),
- std::move(view_2));
- context_.sorter->PushTracePacket(1100, state.current_generation(),
- std::move(view_3));
+ std::move(view_4), state);
+ context_.sorter->PushTracePacket(1001, state, std::move(view_2));
+ context_.sorter->PushTracePacket(1100, state, std::move(view_3));
context_.sorter->PushFtraceEvent(0 /*cpu*/, 1000 /*timestamp*/,
- std::move(view_1),
- state.current_generation());
+ std::move(view_1), state);
context_.sorter->ExtractEventsForced();
}
TEST_F(TraceSorterTest, IncrementalExtraction) {
CreateSorter(false);
- PacketSequenceState state(&context_);
+ auto state = PacketSequenceStateGeneration::CreateFirst(&context_);
TraceBlobView view_1 = test_buffer_.slice_off(0, 1);
TraceBlobView view_2 = test_buffer_.slice_off(0, 2);
@@ -166,10 +161,8 @@
// Flush at the start of packet sequence to match behavior of the
// service.
context_.sorter->NotifyFlushEvent();
- context_.sorter->PushTracePacket(1200, state.current_generation(),
- std::move(view_2));
- context_.sorter->PushTracePacket(1100, state.current_generation(),
- std::move(view_1));
+ context_.sorter->PushTracePacket(1200, state, std::move(view_2));
+ context_.sorter->PushTracePacket(1100, state, std::move(view_1));
// No data should be exttracted at this point because we haven't
// seen two flushes yet.
@@ -182,10 +175,8 @@
context_.sorter->NotifyFlushEvent();
context_.sorter->NotifyFlushEvent();
- context_.sorter->PushTracePacket(1400, state.current_generation(),
- std::move(view_4));
- context_.sorter->PushTracePacket(1300, state.current_generation(),
- std::move(view_3));
+ context_.sorter->PushTracePacket(1400, state, std::move(view_4));
+ context_.sorter->PushTracePacket(1300, state, std::move(view_3));
// This ReadBuffer call should finally extract until the first OnReadBuffer
// call.
@@ -197,8 +188,7 @@
context_.sorter->NotifyReadBufferEvent();
context_.sorter->NotifyFlushEvent();
- context_.sorter->PushTracePacket(1500, state.current_generation(),
- std::move(view_5));
+ context_.sorter->PushTracePacket(1500, state, std::move(view_5));
// Nothing should be extracted as we haven't seen the second flush.
context_.sorter->NotifyReadBufferEvent();
@@ -222,7 +212,7 @@
TEST_F(TraceSorterTest, OutOfOrder) {
CreateSorter(false);
- PacketSequenceState state(&context_);
+ auto state = PacketSequenceStateGeneration::CreateFirst(&context_);
TraceBlobView view_1 = test_buffer_.slice_off(0, 1);
TraceBlobView view_2 = test_buffer_.slice_off(0, 2);
@@ -231,10 +221,8 @@
context_.sorter->NotifyFlushEvent();
context_.sorter->NotifyFlushEvent();
- context_.sorter->PushTracePacket(1200, state.current_generation(),
- std::move(view_2));
- context_.sorter->PushTracePacket(1100, state.current_generation(),
- std::move(view_1));
+ context_.sorter->PushTracePacket(1200, state, std::move(view_2));
+ context_.sorter->PushTracePacket(1100, state, std::move(view_1));
context_.sorter->NotifyReadBufferEvent();
// Both of the packets should have been pushed through.
@@ -250,8 +238,7 @@
// Now, pass the third packet out of order.
context_.sorter->NotifyFlushEvent();
context_.sorter->NotifyFlushEvent();
- context_.sorter->PushTracePacket(1150, state.current_generation(),
- std::move(view_3));
+ context_.sorter->PushTracePacket(1150, state, std::move(view_3));
context_.sorter->NotifyReadBufferEvent();
// The third packet should still be pushed through.
@@ -268,8 +255,7 @@
// Push the fourth packet also out of order but after third.
context_.sorter->NotifyFlushEvent();
context_.sorter->NotifyFlushEvent();
- context_.sorter->PushTracePacket(1170, state.current_generation(),
- std::move(view_4));
+ context_.sorter->PushTracePacket(1170, state, std::move(view_4));
context_.sorter->NotifyReadBufferEvent();
// The fourt packet should still be pushed through.
@@ -286,7 +272,7 @@
// Tests that the output of the TraceSorter matches the timestamp order
// (% events happening at the same time on different CPUs).
TEST_F(TraceSorterTest, MultiQueueSorting) {
- PacketSequenceState state(&context_);
+ auto state = PacketSequenceStateGeneration::CreateFirst(&context_);
std::minstd_rand0 rnd_engine(0);
std::map<int64_t /*ts*/, std::vector<uint32_t /*cpu*/>> expectations;
@@ -320,8 +306,7 @@
for (uint8_t j = 0; j < num_cpus; j++) {
uint32_t cpu = static_cast<uint32_t>(rnd_engine() % 32);
expectations[ts].push_back(cpu);
- context_.sorter->PushFtraceEvent(cpu, ts, tbv.slice_off(i, 1),
- state.current_generation());
+ context_.sorter->PushFtraceEvent(cpu, ts, tbv.slice_off(i, 1), state);
}
}
@@ -331,7 +316,7 @@
// An generalized version of MultiQueueSorting with multiple machines.
TEST_F(TraceSorterTest, MultiMachineSorting) {
- PacketSequenceState state(&context_);
+ auto state = PacketSequenceStateGeneration::CreateFirst(&context_);
std::minstd_rand0 rnd_engine(0);
struct ExpectedMachineAndCpu {
@@ -426,9 +411,8 @@
for (uint8_t j = 0; j < num_cpus; j++) {
uint32_t cpu = static_cast<uint32_t>(rnd_engine() % 32);
expectations[ts].push_back(ExpectedMachineAndCpu{machine, cpu});
- context_.sorter->PushFtraceEvent(cpu, ts,
- tbv.slice_off(m * alloc_size + i, 1),
- state.current_generation(), machine);
+ context_.sorter->PushFtraceEvent(
+ cpu, ts, tbv.slice_off(m * alloc_size + i, 1), state, machine);
}
}
}
diff --git a/src/trace_processor/sorter/trace_token_buffer_unittest.cc b/src/trace_processor/sorter/trace_token_buffer_unittest.cc
index a8657d2..59f7e93 100644
--- a/src/trace_processor/sorter/trace_token_buffer_unittest.cc
+++ b/src/trace_processor/sorter/trace_token_buffer_unittest.cc
@@ -19,10 +19,11 @@
#include <optional>
#include "perfetto/base/compiler.h"
+#include "perfetto/trace_processor/ref_counted.h"
#include "perfetto/trace_processor/trace_blob.h"
#include "perfetto/trace_processor/trace_blob_view.h"
#include "src/trace_processor/importers/common/parser_types.h"
-#include "src/trace_processor/importers/proto/packet_sequence_state.h"
+#include "src/trace_processor/importers/proto/packet_sequence_state_generation.h"
#include "src/trace_processor/types/trace_processor_context.h"
#include "test/gtest_and_gmock.h"
@@ -34,17 +35,18 @@
protected:
TraceTokenBuffer store;
TraceProcessorContext context;
- PacketSequenceState state{&context};
+ RefPtr<PacketSequenceStateGeneration> state =
+ PacketSequenceStateGeneration::CreateFirst(&context);
};
TEST_F(TraceTokenBufferUnittest, TracePacketDataInOut) {
TraceBlobView tbv(TraceBlob::Allocate(1024));
- TracePacketData tpd{tbv.copy(), state.current_generation()};
+ TracePacketData tpd{tbv.copy(), state};
TraceTokenBuffer::Id id = store.Append(std::move(tpd));
TracePacketData extracted = store.Extract<TracePacketData>(id);
ASSERT_EQ(extracted.packet, tbv);
- ASSERT_EQ(extracted.sequence_state, state.current_generation());
+ ASSERT_EQ(extracted.sequence_state, state);
}
TEST_F(TraceTokenBufferUnittest, PacketAppendMultipleBlobs) {
@@ -53,14 +55,14 @@
TraceBlobView tbv_3(TraceBlob::Allocate(4096));
TraceTokenBuffer::Id id_1 =
- store.Append(TracePacketData{tbv_1.copy(), state.current_generation()});
+ store.Append(TracePacketData{tbv_1.copy(), state});
TraceTokenBuffer::Id id_2 =
- store.Append(TracePacketData{tbv_2.copy(), state.current_generation()});
+ store.Append(TracePacketData{tbv_2.copy(), state});
ASSERT_EQ(store.Extract<TracePacketData>(id_1).packet, tbv_1);
ASSERT_EQ(store.Extract<TracePacketData>(id_2).packet, tbv_2);
TraceTokenBuffer::Id id_3 =
- store.Append(TracePacketData{tbv_3.copy(), state.current_generation()});
+ store.Append(TracePacketData{tbv_3.copy(), state});
ASSERT_EQ(store.Extract<TracePacketData>(id_3).packet, tbv_3);
}
@@ -71,14 +73,14 @@
TraceBlobView tbv_3 = root.slice_off(1536, 512);
TraceTokenBuffer::Id id_1 =
- store.Append(TracePacketData{tbv_1.copy(), state.current_generation()});
+ store.Append(TracePacketData{tbv_1.copy(), state});
TraceTokenBuffer::Id id_2 =
- store.Append(TracePacketData{tbv_2.copy(), state.current_generation()});
+ store.Append(TracePacketData{tbv_2.copy(), state});
ASSERT_EQ(store.Extract<TracePacketData>(id_1).packet, tbv_1);
ASSERT_EQ(store.Extract<TracePacketData>(id_2).packet, tbv_2);
TraceTokenBuffer::Id id_3 =
- store.Append(TracePacketData{tbv_3.copy(), state.current_generation()});
+ store.Append(TracePacketData{tbv_3.copy(), state});
ASSERT_EQ(store.Extract<TracePacketData>(id_3).packet, tbv_3);
}
@@ -88,13 +90,11 @@
TraceBlobView tbv_2 = root.slice_off(1024, 512);
TraceTokenBuffer::Id id_1 =
- store.Append(TracePacketData{tbv_1.copy(), state.current_generation()});
+ store.Append(TracePacketData{tbv_1.copy(), state});
TraceTokenBuffer::Id id_2 =
- store.Append(TracePacketData{tbv_2.copy(), state.current_generation()});
- ASSERT_EQ(store.Extract<TracePacketData>(id_1).sequence_state,
- state.current_generation());
- ASSERT_EQ(store.Extract<TracePacketData>(id_2).sequence_state,
- state.current_generation());
+ store.Append(TracePacketData{tbv_2.copy(), state});
+ ASSERT_EQ(store.Extract<TracePacketData>(id_1).sequence_state, state);
+ ASSERT_EQ(store.Extract<TracePacketData>(id_2).sequence_state, state);
}
TEST_F(TraceTokenBufferUnittest, ManySequenceState) {
@@ -103,10 +103,9 @@
std::array<TraceTokenBuffer::Id, 1024> ids;
std::array<PacketSequenceStateGeneration*, 1024> refs;
for (uint32_t i = 0; i < 1024; ++i) {
- refs[i] = state.current_generation().get();
- ids[i] = store.Append(
- TracePacketData{root.slice_off(i, 1), state.current_generation()});
- state.OnIncrementalStateCleared();
+ refs[i] = state.get();
+ ids[i] = store.Append(TracePacketData{root.slice_off(i, 1), state});
+ state = state->OnNewTracePacketDefaults(TraceBlobView());
}
for (uint32_t i = 0; i < 1024; ++i) {
@@ -120,22 +119,22 @@
TraceBlobView slice_1 = tbv.slice_off(0, 1024ul);
TraceTokenBuffer::Id id_1 =
- store.Append(TracePacketData{slice_1.copy(), state.current_generation()});
+ store.Append(TracePacketData{slice_1.copy(), state});
TracePacketData out_1 = store.Extract<TracePacketData>(id_1);
ASSERT_EQ(out_1.packet, slice_1);
- ASSERT_EQ(out_1.sequence_state, state.current_generation());
+ ASSERT_EQ(out_1.sequence_state, state);
TraceBlobView slice_2 = tbv.slice_off(128ul * 1024, 1024ul);
TraceTokenBuffer::Id id_2 =
- store.Append(TracePacketData{slice_2.copy(), state.current_generation()});
+ store.Append(TracePacketData{slice_2.copy(), state});
TracePacketData out_2 = store.Extract<TracePacketData>(id_2);
ASSERT_EQ(out_2.packet, slice_2);
- ASSERT_EQ(out_2.sequence_state, state.current_generation());
+ ASSERT_EQ(out_2.sequence_state, state);
}
TEST_F(TraceTokenBufferUnittest, TrackEventDataInOut) {
TraceBlobView tbv(TraceBlob::Allocate(1234));
- TrackEventData ted(tbv.copy(), state.current_generation());
+ TrackEventData ted(tbv.copy(), state);
ted.thread_instruction_count = 123;
ted.extra_counter_values = {10, 2, 0, 0, 0, 0, 0, 0};
auto counter_array = ted.extra_counter_values;
@@ -143,8 +142,7 @@
TraceTokenBuffer::Id id = store.Append(std::move(ted));
TrackEventData extracted = store.Extract<TrackEventData>(id);
ASSERT_EQ(extracted.trace_packet_data.packet, tbv);
- ASSERT_EQ(extracted.trace_packet_data.sequence_state,
- state.current_generation());
+ ASSERT_EQ(extracted.trace_packet_data.sequence_state, state);
ASSERT_EQ(extracted.thread_instruction_count, 123);
ASSERT_EQ(extracted.thread_timestamp, std::nullopt);
ASSERT_DOUBLE_EQ(extracted.counter_value, 0.0);
diff --git a/src/trace_processor/util/BUILD.gn b/src/trace_processor/util/BUILD.gn
index 86ecf9c..5ca39a1 100644
--- a/src/trace_processor/util/BUILD.gn
+++ b/src/trace_processor/util/BUILD.gn
@@ -305,6 +305,7 @@
"../../protozero:testing_messages_zero",
"../importers/proto:gen_cc_track_event_descriptor",
"../importers/proto:minimal",
+ "../importers/proto:packet_sequence_state_generation_hdr",
"../storage",
"../types",
]
diff --git a/src/trace_processor/util/debug_annotation_parser_unittest.cc b/src/trace_processor/util/debug_annotation_parser_unittest.cc
index d9a4168..902e9da 100644
--- a/src/trace_processor/util/debug_annotation_parser_unittest.cc
+++ b/src/trace_processor/util/debug_annotation_parser_unittest.cc
@@ -18,6 +18,7 @@
#include "perfetto/ext/base/string_view.h"
#include "perfetto/protozero/scattered_heap_buffer.h"
+#include "perfetto/trace_processor/ref_counted.h"
#include "perfetto/trace_processor/trace_blob.h"
#include "perfetto/trace_processor/trace_blob_view.h"
#include "protos/perfetto/common/descriptor.pbzero.h"
@@ -27,7 +28,8 @@
#include "protos/perfetto/trace/track_event/debug_annotation.pbzero.h"
#include "protos/perfetto/trace/track_event/source_location.pbzero.h"
#include "src/protozero/test/example_proto/test_messages.pbzero.h"
-#include "src/trace_processor/importers/proto/packet_sequence_state.h"
+#include "src/trace_processor/importers/proto/packet_sequence_state_builder.h"
+#include "src/trace_processor/importers/proto/packet_sequence_state_generation.h"
#include "src/trace_processor/storage/trace_storage.h"
#include "src/trace_processor/test_messages.descriptor.h"
#include "src/trace_processor/types/trace_processor_context.h"
@@ -54,13 +56,13 @@
class DebugAnnotationParserTest : public ::testing::Test,
public ProtoToArgsParser::Delegate {
protected:
- DebugAnnotationParserTest() : sequence_state_(&context_) {
- context_.storage.reset(new TraceStorage());
- }
+ DebugAnnotationParserTest() { context_.storage.reset(new TraceStorage()); }
const std::vector<std::string>& args() const { return args_; }
- PacketSequenceState* mutable_seq_state() { return &sequence_state_; }
+ void InternMessage(uint32_t field_id, TraceBlobView message) {
+ state_builder_.InternMessage(field_id, std::move(message));
+ }
private:
using Key = ProtoToArgsParser::Key;
@@ -132,23 +134,19 @@
InternedMessageView* GetInternedMessageView(uint32_t field_id,
uint64_t iid) override {
- if (field_id !=
- protos::pbzero::InternedData::kDebugAnnotationStringValuesFieldNumber) {
- return nullptr;
- }
- return sequence_state_.current_generation()->GetInternedMessageView(
- field_id, iid);
+ return state_builder_.current_generation()->GetInternedMessageView(field_id,
+ iid);
}
PacketSequenceStateGeneration* seq_state() final {
- return sequence_state_.current_generation().get();
+ return state_builder_.current_generation().get();
}
std::vector<std::string> args_;
std::map<std::string, size_t> array_indices_;
TraceProcessorContext context_;
- PacketSequenceState sequence_state_;
+ PacketSequenceStateBuilder state_builder_{&context_};
};
// This test checks that in when an array is nested inside a dict which is
@@ -303,7 +301,7 @@
string->set_str("foo");
std::vector<uint8_t> data_serialized = string.SerializeAsArray();
- mutable_seq_state()->InternMessage(
+ InternMessage(
protos::pbzero::InternedData::kDebugAnnotationStringValuesFieldNumber,
TraceBlobView(
TraceBlob::CopyFrom(data_serialized.data(), data_serialized.size())));
diff --git a/src/trace_processor/util/interned_message_view.h b/src/trace_processor/util/interned_message_view.h
index f6a9a13..7ee28c3 100644
--- a/src/trace_processor/util/interned_message_view.h
+++ b/src/trace_processor/util/interned_message_view.h
@@ -103,7 +103,7 @@
return submessage_view;
}
- const TraceBlobView& message() { return message_; }
+ const TraceBlobView& message() const { return message_; }
private:
using SubMessageViewMap =
diff --git a/src/tracing/internal/tracing_muxer_impl.cc b/src/tracing/internal/tracing_muxer_impl.cc
index b9efcf5..8fd1d8a 100644
--- a/src/tracing/internal/tracing_muxer_impl.cc
+++ b/src/tracing/internal/tracing_muxer_impl.cc
@@ -1855,7 +1855,10 @@
rds.descriptor.set_no_flush(rds.no_flush);
}
rds.descriptor.set_will_notify_on_start(true);
- rds.descriptor.set_will_notify_on_stop(true);
+ if (!rds.descriptor.has_will_notify_on_stop()) {
+ rds.descriptor.set_will_notify_on_stop(true);
+ }
+
rds.descriptor.set_handles_incremental_state_clear(true);
rds.descriptor.set_id(rds.static_state->id);
if (is_registered) {
diff --git a/ui/release/channels.json b/ui/release/channels.json
index c80cab9..7e403f2 100644
--- a/ui/release/channels.json
+++ b/ui/release/channels.json
@@ -2,7 +2,7 @@
"channels": [
{
"name": "stable",
- "rev": "c7da51a07f6bee116c7e1c3b91fa7abfc2a084bb"
+ "rev": "444bb44f0712aeb12d6ab546035811d4541a8f93"
},
{
"name": "canary",
diff --git a/ui/src/common/actions.ts b/ui/src/common/actions.ts
index 92cad97..4cebecb 100644
--- a/ui/src/common/actions.ts
+++ b/ui/src/common/actions.ts
@@ -15,7 +15,7 @@
import {Draft} from 'immer';
import {assertExists, assertTrue} from '../base/logging';
-import {duration, time} from '../base/time';
+import {duration, Time, time} from '../base/time';
import {RecordConfig} from '../controller/record_config_types';
import {
GenericSliceDetailsTabConfig,
@@ -63,7 +63,6 @@
State,
Status,
ThreadTrackSortKey,
- TraceTime,
TrackSortKey,
UtidToTrackSortKey,
VisibleState,
@@ -474,10 +473,6 @@
state.permalink = {};
},
- setTraceTime(state: StateDraft, args: TraceTime): void {
- state.traceTime = args;
- },
-
updateStatus(state: StateDraft, args: Status): void {
if (statusTraceEvent) {
traceEventEnd(statusTraceEvent);
@@ -673,7 +668,7 @@
};
this.openFlamegraph(state, {
type: args.type,
- start: state.traceTime.start as time, // TODO(stevegolton): Avoid type assertion here.
+ start: Time.ZERO,
end: args.ts,
upids: [args.upid],
viewingOption: defaultViewingOption(args.type),
diff --git a/ui/src/common/empty_state.ts b/ui/src/common/empty_state.ts
index f866914..e3ed2b7 100644
--- a/ui/src/common/empty_state.ts
+++ b/ui/src/common/empty_state.ts
@@ -22,12 +22,7 @@
} from '../frontend/record_config';
import {SqlTables} from '../frontend/sql_table/well_known_tables';
-import {
- defaultTraceTime,
- NonSerializableState,
- State,
- STATE_VERSION,
-} from './state';
+import {NonSerializableState, State, STATE_VERSION} from './state';
const AUTOLOAD_STARTED_CONFIG_FLAG = featureFlags.register({
id: 'autoloadStartedConfig',
@@ -92,7 +87,6 @@
version: STATE_VERSION,
nextId: '-1',
newEngineMode: 'USE_HTTP_RPC_IF_AVAILABLE',
- traceTime: {...defaultTraceTime},
tracks: {},
utidToThreadSortKey: {},
aggregatePreferences: {},
@@ -112,7 +106,8 @@
frontendLocalState: {
visibleState: {
- ...defaultTraceTime,
+ start: Time.ZERO,
+ end: Time.ZERO,
lastUpdate: 0,
resolution: 0n,
},
diff --git a/ui/src/common/plugins.ts b/ui/src/common/plugins.ts
index 0f2b2b7..3a5899e 100644
--- a/ui/src/common/plugins.ts
+++ b/ui/src/common/plugins.ts
@@ -21,7 +21,6 @@
import {
Command,
DetailsPanel,
- EngineProxy,
MetricVisualisation,
Migrate,
Plugin,
@@ -36,7 +35,7 @@
GroupPredicate,
TrackRef,
} from '../public';
-import {Engine} from '../trace_processor/engine';
+import {EngineBase, Engine} from '../trace_processor/engine';
import {Actions} from './actions';
import {SCROLLING_TRACK_GROUP} from './state';
@@ -103,9 +102,12 @@
class PluginContextTraceImpl implements PluginContextTrace, Disposable {
private trash = new Trash();
private alive = true;
+ readonly engine: Engine;
- constructor(private ctx: PluginContext, readonly engine: EngineProxy) {
- this.trash.add(engine);
+ constructor(private ctx: PluginContext, engine: EngineBase) {
+ const engineProxy = engine.getProxy(ctx.pluginId);
+ this.trash.add(engineProxy);
+ this.engine = engineProxy;
}
registerCommand(cmd: Command): void {
@@ -380,7 +382,7 @@
export class PluginManager {
private registry: PluginRegistry;
private _plugins: Map<string, PluginDetails>;
- private engine?: Engine;
+ private engine?: EngineBase;
private flags = new Map<string, Flag>();
constructor(registry: PluginRegistry) {
@@ -466,7 +468,7 @@
// If a trace is already loaded when plugin is activated, make sure to
// call onTraceLoad().
if (this.engine) {
- await doPluginTraceLoad(pluginDetails, this.engine, id);
+ await doPluginTraceLoad(pluginDetails, this.engine);
}
this._plugins.set(id, pluginDetails);
@@ -528,7 +530,7 @@
}
async onTraceLoad(
- engine: Engine,
+ engine: EngineBase,
beforeEach?: (id: string) => void,
): Promise<void> {
this.engine = engine;
@@ -546,7 +548,7 @@
// time.
for (const {id, plugin} of pluginsShuffled) {
beforeEach?.(id);
- await doPluginTraceLoad(plugin, engine, id);
+ await doPluginTraceLoad(plugin, engine);
}
}
@@ -571,14 +573,11 @@
async function doPluginTraceLoad(
pluginDetails: PluginDetails,
- engine: Engine,
- pluginId: string,
+ engine: EngineBase,
): Promise<void> {
const {plugin, context} = pluginDetails;
- const engineProxy = engine.getProxy(pluginId);
-
- const traceCtx = new PluginContextTraceImpl(context, engineProxy);
+ const traceCtx = new PluginContextTraceImpl(context, engine);
pluginDetails.traceContext = traceCtx;
const startTime = performance.now();
diff --git a/ui/src/common/plugins_unittest.ts b/ui/src/common/plugins_unittest.ts
index 55fc82d..7efccda 100644
--- a/ui/src/common/plugins_unittest.ts
+++ b/ui/src/common/plugins_unittest.ts
@@ -14,12 +14,12 @@
import {globals} from '../frontend/globals';
import {Plugin} from '../public';
-import {Engine} from '../trace_processor/engine';
+import {EngineBase} from '../trace_processor/engine';
import {createEmptyState} from './empty_state';
import {PluginManager, PluginRegistry} from './plugins';
-class FakeEngine extends Engine {
+class FakeEngine extends EngineBase {
id: string = 'TestEngine';
rpcSendRequestBytes(_data: Uint8Array) {}
diff --git a/ui/src/common/queries.ts b/ui/src/common/queries.ts
index 857d8e9..a6c461b 100644
--- a/ui/src/common/queries.ts
+++ b/ui/src/common/queries.ts
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-import {EngineProxy} from '../trace_processor/engine';
+import {Engine} from '../trace_processor/engine';
import {Row} from '../trace_processor/query_result';
const MAX_DISPLAY_ROWS = 10000;
@@ -36,7 +36,7 @@
export async function runQuery(
sqlQuery: string,
- engine: EngineProxy,
+ engine: Engine,
params?: QueryRunParams,
): Promise<QueryResponse> {
const startMs = performance.now();
diff --git a/ui/src/common/schema.ts b/ui/src/common/schema.ts
index 75a4b2f..c3f33e4 100644
--- a/ui/src/common/schema.ts
+++ b/ui/src/common/schema.ts
@@ -12,10 +12,10 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-import {EngineProxy} from '../trace_processor/engine';
+import {Engine} from '../trace_processor/engine';
import {STR} from '../trace_processor/query_result';
-const CACHED_SCHEMAS = new WeakMap<EngineProxy, DatabaseSchema>();
+const CACHED_SCHEMAS = new WeakMap<Engine, DatabaseSchema>();
export class SchemaError extends Error {
constructor(message: string) {
@@ -40,7 +40,7 @@
}
async function getColumns(
- engine: EngineProxy,
+ engine: Engine,
table: string,
): Promise<ColumnInfo[]> {
const result = await engine.query(`PRAGMA table_info(${table});`);
@@ -83,7 +83,7 @@
// Deliberately not exported. Users should call getSchema below and
// participate in cacheing.
-async function createSchema(engine: EngineProxy): Promise<DatabaseSchema> {
+async function createSchema(engine: Engine): Promise<DatabaseSchema> {
const tables: TableInfo[] = [];
const result = await engine.query(`SELECT name from perfetto_tables;`);
const it = result.iter({
@@ -108,7 +108,7 @@
// The schemas are per-engine (i.e. they can't be statically determined
// at build time) since we might be in httpd mode and not-running
// against the version of trace_processor we build with.
-export async function getSchema(engine: EngineProxy): Promise<DatabaseSchema> {
+export async function getSchema(engine: Engine): Promise<DatabaseSchema> {
const schema = CACHED_SCHEMAS.get(engine);
if (schema === undefined) {
const newSchema = await createSchema(engine);
diff --git a/ui/src/common/state.ts b/ui/src/common/state.ts
index d0af73b..669f539 100644
--- a/ui/src/common/state.ts
+++ b/ui/src/common/state.ts
@@ -13,7 +13,7 @@
// limitations under the License.
import {BigintMath} from '../base/bigint_math';
-import {duration, Time, time} from '../base/time';
+import {duration, time} from '../base/time';
import {RecordConfig} from '../controller/record_config_types';
import {
Aggregation,
@@ -150,7 +150,8 @@
// 51. Changed structure of FlamegraphState.expandedCallsiteByViewingOption.
// 52. Update track group state - don't make the summary track the first track.
// 53. Remove android log state.
-export const STATE_VERSION = 53;
+// 54. Remove traceTime.
+export const STATE_VERSION = 54;
export const SCROLLING_TRACK_GROUP = 'ScrollingTracks';
@@ -315,11 +316,6 @@
isRecordingConfig?: boolean; // this permalink request is for a recording config only
}
-export interface TraceTime {
- start: time;
- end: time;
-}
-
export interface FrontendLocalState {
visibleState: VisibleState;
}
@@ -479,7 +475,6 @@
*/
newEngineMode: NewEngineMode;
engine?: EngineConfig;
- traceTime: TraceTime;
traceUuid?: string;
trackGroups: ObjectById<TrackGroupState>;
tracks: ObjectByKey<TrackState>;
@@ -558,11 +553,6 @@
plugins: {[key: string]: any};
}
-export const defaultTraceTime = {
- start: Time.ZERO,
- end: Time.fromSeconds(10),
-};
-
export declare type RecordMode =
| 'STOP_WHEN_FULL'
| 'RING_BUFFER'
@@ -645,11 +635,12 @@
}
export function getBuiltinChromeCategoryList(): string[] {
- // List of static Chrome categories, last updated at 2023-05-30 from HEAD of
+ // List of static Chrome categories, last updated at 2024-04-15 from HEAD of
// Chromium's //base/trace_event/builtin_categories.h.
return [
'accessibility',
'AccountFetcherService',
+ 'android.ui.jank',
'android_webview',
'android_webview.timeline',
'aogh',
@@ -686,6 +677,7 @@
'compositor',
'content',
'content_capture',
+ 'interactions',
'delegated_ink_trails',
'device',
'devtools',
@@ -713,6 +705,7 @@
'gpu.angle',
'gpu.angle.texture_metrics',
'gpu.capture',
+ 'graphics.pipeline',
'headless',
'history',
'hwoverlays',
@@ -720,6 +713,7 @@
'ime',
'IndexedDB',
'input',
+ 'input.scrolling',
'io',
'ipc',
'Java',
@@ -739,7 +733,9 @@
'mus',
'native',
'navigation',
+ 'navigation.debug',
'net',
+ 'network.scheduler',
'netlog',
'offline_pages',
'omnibox',
@@ -802,19 +798,19 @@
'webengine.fidl',
'weblayer',
'WebCore',
+ 'webnn',
'webrtc',
'webrtc_stats',
'xr',
'disabled-by-default-android_view_hierarchy',
'disabled-by-default-animation-worklet',
'disabled-by-default-audio',
- 'disabled-by-default-audio-worklet',
'disabled-by-default-audio.latency',
+ 'disabled-by-default-audio-worklet',
'disabled-by-default-base',
'disabled-by-default-blink.debug',
'disabled-by-default-blink.debug.display_lock',
'disabled-by-default-blink.debug.layout',
- 'disabled-by-default-blink.debug.layout.scrollbars',
'disabled-by-default-blink.debug.layout.trees',
'disabled-by-default-blink.feature_usage',
'disabled-by-default-blink.image_decoding',
@@ -842,6 +838,9 @@
'disabled-by-default-devtools.timeline.layers',
'disabled-by-default-devtools.timeline.picture',
'disabled-by-default-devtools.timeline.stack',
+ 'disabled-by-default-devtools.target-rundown',
+ 'disabled-by-default-devtools.v8-source-rundown',
+ 'disabled-by-default-devtools.v8-source-rundown-sources',
'disabled-by-default-file',
'disabled-by-default-fonts',
'disabled-by-default-gpu_cmd_queue',
@@ -849,6 +848,7 @@
'disabled-by-default-gpu.debug',
'disabled-by-default-gpu.decoder',
'disabled-by-default-gpu.device',
+ 'disabled-by-default-gpu.graphite.dawn',
'disabled-by-default-gpu.service',
'disabled-by-default-gpu.vulkan.vma',
'disabled-by-default-histogram_samples',
@@ -874,7 +874,9 @@
'disabled-by-default-skia.gpu',
'disabled-by-default-skia.gpu.cache',
'disabled-by-default-skia.shaders',
+ 'disabled-by-default-skottie',
'disabled-by-default-SyncFileSystem',
+ 'disabled-by-default-system_power',
'disabled-by-default-system_stats',
'disabled-by-default-thread_pool_diagnostics',
'disabled-by-default-toplevel.ipc',
@@ -893,6 +895,7 @@
'disabled-by-default-v8.wasm.detailed',
'disabled-by-default-v8.wasm.turbofan',
'disabled-by-default-video_and_image_capture',
+ 'disabled-by-default-display.framedisplayed',
'disabled-by-default-viz.gpu_composite_time',
'disabled-by-default-viz.debug.overlay_planes',
'disabled-by-default-viz.hit_testing_flow',
@@ -901,8 +904,10 @@
'disabled-by-default-viz.surface_id_flow',
'disabled-by-default-viz.surface_lifetime',
'disabled-by-default-viz.triangles',
+ 'disabled-by-default-viz.visual_debugger',
'disabled-by-default-webaudio.audionode',
'disabled-by-default-webgpu',
+ 'disabled-by-default-webnn',
'disabled-by-default-webrtc',
'disabled-by-default-worker.scheduler',
'disabled-by-default-xr.debug',
diff --git a/ui/src/common/track_helper.ts b/ui/src/common/track_helper.ts
index 84808df..396b955 100644
--- a/ui/src/common/track_helper.ts
+++ b/ui/src/common/track_helper.ts
@@ -19,16 +19,6 @@
import {raf} from '../core/raf_scheduler';
import {globals} from '../frontend/globals';
-export {EngineProxy} from '../trace_processor/engine';
-export {
- LONG,
- LONG_NULL,
- NUM,
- NUM_NULL,
- STR,
- STR_NULL,
-} from '../trace_processor/query_result';
-
type FetchTimeline<Data> = (
start: time,
end: time,
diff --git a/ui/src/controller/selection_controller.ts b/ui/src/controller/selection_controller.ts
index dc905ea..1b6dd0f 100644
--- a/ui/src/controller/selection_controller.ts
+++ b/ui/src/controller/selection_controller.ts
@@ -441,7 +441,7 @@
IFNULL(value, 0) as value
FROM counter WHERE ts < ${ts} and track_id = ${trackId}`);
const previousValue = previous.firstRow({value: NUM}).value;
- const endTs = rightTs !== -1n ? rightTs : globals.state.traceTime.end;
+ const endTs = rightTs !== -1n ? rightTs : globals.traceTime.end;
const delta = value - previousValue;
const duration = endTs - ts;
const trackKey = globals.trackManager.trackKeyByTrackId.get(trackId);
diff --git a/ui/src/controller/trace_controller.ts b/ui/src/controller/trace_controller.ts
index c1f0d6e..445bd4a 100644
--- a/ui/src/controller/trace_controller.ts
+++ b/ui/src/controller/trace_controller.ts
@@ -26,25 +26,26 @@
isMetatracingEnabled,
} from '../common/metatracing';
import {pluginManager} from '../common/plugins';
+import {EngineMode, PendingDeeplinkState, ProfileType} from '../common/state';
+import {featureFlags, Flag, PERF_SAMPLE_FLAG} from '../core/feature_flags';
import {
defaultTraceTime,
- EngineMode,
- PendingDeeplinkState,
- ProfileType,
-} from '../common/state';
-import {featureFlags, Flag, PERF_SAMPLE_FLAG} from '../core/feature_flags';
-import {globals, QuantizedLoad, ThreadDesc} from '../frontend/globals';
+ globals,
+ QuantizedLoad,
+ ThreadDesc,
+ TraceTime,
+} from '../frontend/globals';
import {
clearOverviewData,
publishHasFtrace,
publishMetricError,
publishOverviewData,
- publishRealtimeOffset,
publishThreads,
+ publishTraceDetails,
} from '../frontend/publish';
import {addQueryResultsTab} from '../frontend/query_result_tab';
import {Router} from '../frontend/router';
-import {Engine} from '../trace_processor/engine';
+import {Engine, EngineBase} from '../trace_processor/engine';
import {HttpRpcEngine} from '../trace_processor/http_rpc_engine';
import {
LONG,
@@ -224,7 +225,7 @@
// trace opened in the UI (for now only one trace is supported).
export class TraceController extends Controller<States> {
private readonly engineId: string;
- private engine?: Engine;
+ private engine?: EngineBase;
constructor(engineId: string) {
super('init');
@@ -450,13 +451,8 @@
// traceUuid will be '' if the trace is not cacheable (URL or RPC).
const traceUuid = await this.cacheCurrentTrace();
- const traceTime = await this.engine.getTraceTimeBounds();
- const start = traceTime.start;
- const end = traceTime.end;
- const traceTimeState = {
- start,
- end,
- };
+ const traceDetails = await getTraceTimeDetails(this.engine);
+ publishTraceDetails(traceDetails);
const shownJsonWarning =
window.localStorage.getItem(SHOWN_JSON_WARNING_KEY) !== null;
@@ -485,12 +481,11 @@
const actions: DeferredAction[] = [
Actions.setOmnibox(emptyOmniboxState),
Actions.setTraceUuid({traceUuid}),
- Actions.setTraceTime(traceTimeState),
];
const visibleTimeSpan = await computeVisibleTime(
- traceTime.start,
- traceTime.end,
+ traceDetails.start,
+ traceDetails.end,
isJsonTrace,
this.engine,
);
@@ -530,7 +525,9 @@
this.decideTabs();
await this.listThreads();
- await this.loadTimelineOverview(traceTime);
+ await this.loadTimelineOverview(
+ new TimeSpan(traceDetails.start, traceDetails.end),
+ );
{
// Check if we have any ftrace events at all
@@ -544,82 +541,12 @@
publishHasFtrace(res.numRows() > 0);
}
- {
- // Find the first REALTIME or REALTIME_COARSE clock snapshot.
- // Prioritize REALTIME over REALTIME_COARSE.
- const query = `select
- ts,
- clock_value as clockValue,
- clock_name as clockName
- from clock_snapshot
- where
- snapshot_id = 0 AND
- clock_name in ('REALTIME', 'REALTIME_COARSE')
- `;
- const result = await assertExists(this.engine).query(query);
- const it = result.iter({
- ts: LONG,
- clockValue: LONG,
- clockName: STR,
- });
-
- let snapshot = {
- clockName: '',
- ts: Time.ZERO,
- clockValue: Time.ZERO,
- };
-
- // Find the most suitable snapshot
- for (let row = 0; it.valid(); it.next(), row++) {
- if (it.clockName === 'REALTIME') {
- snapshot = {
- clockName: it.clockName,
- ts: Time.fromRaw(it.ts),
- clockValue: Time.fromRaw(it.clockValue),
- };
- break;
- } else if (it.clockName === 'REALTIME_COARSE') {
- if (snapshot.clockName !== 'REALTIME') {
- snapshot = {
- clockName: it.clockName,
- ts: Time.fromRaw(it.ts),
- clockValue: Time.fromRaw(it.clockValue),
- };
- }
- }
- }
-
- // The max() is so the query returns NULL if the tz info doesn't exist.
- const queryTz = `select max(int_value) as tzOffMin from metadata
- where name = 'timezone_off_mins'`;
- const resTz = await assertExists(this.engine).query(queryTz);
- const tzOffMin = resTz.firstRow({tzOffMin: NUM_NULL}).tzOffMin ?? 0;
-
- // This is the offset between the unix epoch and ts in the ts domain.
- // I.e. the value of ts at the time of the unix epoch - usually some large
- // negative value.
- const realtimeOffset = Time.sub(snapshot.ts, snapshot.clockValue);
-
- // Find the previous closest midnight from the trace start time.
- const utcOffset = Time.getLatestMidnight(
- globals.state.traceTime.start,
- realtimeOffset,
- );
-
- const traceTzOffset = Time.getLatestMidnight(
- globals.state.traceTime.start,
- Time.sub(realtimeOffset, Time.fromSeconds(tzOffMin * 60)),
- );
-
- publishRealtimeOffset(realtimeOffset, utcOffset, traceTzOffset);
- }
-
globals.dispatch(Actions.sortThreadTracks({}));
globals.dispatch(Actions.maybeExpandOnlyTrackGroup({}));
await this.selectFirstHeapProfile();
if (PERF_SAMPLE_FLAG.get()) {
- await this.selectPerfSample();
+ await this.selectPerfSample(traceDetails);
}
const pendingDeeplink = globals.state.pendingDeeplink;
@@ -663,7 +590,7 @@
return engineMode;
}
- private async selectPerfSample() {
+ private async selectPerfSample(traceTime: {start: time; end: time}) {
const query = `select upid
from perf_sample
join thread using (utid)
@@ -673,8 +600,8 @@
if (profile.numRows() !== 1) return;
const row = profile.firstRow({upid: NUM});
const upid = row.upid;
- const leftTs = globals.state.traceTime.start;
- const rightTs = globals.state.traceTime.end;
+ const leftTs = traceTime.start;
+ const rightTs = traceTime.end;
globals.dispatch(
Actions.selectPerfSamples({
id: 0,
@@ -766,7 +693,7 @@
private async listTracks() {
this.updateStatus('Loading tracks');
- const engine = assertExists<Engine>(this.engine);
+ const engine = assertExists(this.engine);
const actions = await decideTracks(engine);
globals.dispatchMultiple(actions);
}
@@ -918,7 +845,7 @@
}
async initialiseHelperViews() {
- const engine = assertExists<Engine>(this.engine);
+ const engine = assertExists(this.engine);
this.updateStatus('Creating annotation counter track table');
// Create the helper tables for all the annotations related data.
@@ -1217,3 +1144,77 @@
}
return HighPrecisionTimeSpan.fromTime(visibleStart, visibleEnd);
}
+
+async function getTraceTimeDetails(engine: EngineBase): Promise<TraceTime> {
+ const traceTime = await engine.getTraceTimeBounds();
+
+ // Find the first REALTIME or REALTIME_COARSE clock snapshot.
+ // Prioritize REALTIME over REALTIME_COARSE.
+ const query = `select
+ ts,
+ clock_value as clockValue,
+ clock_name as clockName
+ from clock_snapshot
+ where
+ snapshot_id = 0 AND
+ clock_name in ('REALTIME', 'REALTIME_COARSE')
+ `;
+ const result = await engine.query(query);
+ const it = result.iter({
+ ts: LONG,
+ clockValue: LONG,
+ clockName: STR,
+ });
+
+ let snapshot = {
+ clockName: '',
+ ts: Time.ZERO,
+ clockValue: Time.ZERO,
+ };
+
+ // Find the most suitable snapshot
+ for (let row = 0; it.valid(); it.next(), row++) {
+ if (it.clockName === 'REALTIME') {
+ snapshot = {
+ clockName: it.clockName,
+ ts: Time.fromRaw(it.ts),
+ clockValue: Time.fromRaw(it.clockValue),
+ };
+ break;
+ } else if (it.clockName === 'REALTIME_COARSE') {
+ if (snapshot.clockName !== 'REALTIME') {
+ snapshot = {
+ clockName: it.clockName,
+ ts: Time.fromRaw(it.ts),
+ clockValue: Time.fromRaw(it.clockValue),
+ };
+ }
+ }
+ }
+
+ // The max() is so the query returns NULL if the tz info doesn't exist.
+ const queryTz = `select max(int_value) as tzOffMin from metadata
+ where name = 'timezone_off_mins'`;
+ const resTz = await assertExists(engine).query(queryTz);
+ const tzOffMin = resTz.firstRow({tzOffMin: NUM_NULL}).tzOffMin ?? 0;
+
+ // This is the offset between the unix epoch and ts in the ts domain.
+ // I.e. the value of ts at the time of the unix epoch - usually some large
+ // negative value.
+ const realtimeOffset = Time.sub(snapshot.ts, snapshot.clockValue);
+
+ // Find the previous closest midnight from the trace start time.
+ const utcOffset = Time.getLatestMidnight(traceTime.start, realtimeOffset);
+
+ const traceTzOffset = Time.getLatestMidnight(
+ traceTime.start,
+ Time.sub(realtimeOffset, Time.fromSeconds(tzOffMin * 60)),
+ );
+
+ return {
+ ...traceTime,
+ realtimeOffset,
+ utcOffset,
+ traceTzOffset,
+ };
+}
diff --git a/ui/src/controller/track_decider.ts b/ui/src/controller/track_decider.ts
index f0c7ef4..e1b907c 100644
--- a/ui/src/controller/track_decider.ts
+++ b/ui/src/controller/track_decider.ts
@@ -27,7 +27,7 @@
import {PERF_SAMPLE_FLAG} from '../core/feature_flags';
import {PrimaryTrackSortKey} from '../public';
import {getTrackName} from '../public/utils';
-import {Engine, EngineProxy} from '../trace_processor/engine';
+import {Engine, EngineBase} from '../trace_processor/engine';
import {NUM, NUM_NULL, STR, STR_NULL} from '../trace_processor/query_result';
import {ASYNC_SLICE_TRACK_KIND} from '../core_plugins/async_slices';
import {
@@ -76,18 +76,20 @@
const CHROME_TRACK_GROUP = 'Chrome Global Tracks';
const MISC_GROUP = 'Misc Global Tracks';
-export async function decideTracks(engine: Engine): Promise<DeferredAction[]> {
+export async function decideTracks(
+ engine: EngineBase,
+): Promise<DeferredAction[]> {
return new TrackDecider(engine).decideTracks();
}
class TrackDecider {
- private engine: Engine;
+ private engine: EngineBase;
private upidToUuid = new Map<number, string>();
private utidToUuid = new Map<number, string>();
private tracksToAdd: AddTrackArgs[] = [];
private addTrackGroupActions: DeferredAction[] = [];
- constructor(engine: Engine) {
+ constructor(engine: EngineBase) {
this.engine = engine;
}
@@ -131,7 +133,7 @@
}
}
- async addCpuFreqTracks(engine: EngineProxy): Promise<void> {
+ async addCpuFreqTracks(engine: Engine): Promise<void> {
const cpus = await this.engine.getCpus();
for (const cpu of cpus) {
@@ -165,7 +167,7 @@
}
}
- async addGlobalAsyncTracks(engine: EngineProxy): Promise<void> {
+ async addGlobalAsyncTracks(engine: Engine): Promise<void> {
const rawGlobalAsyncTracks = await engine.query(`
with global_tracks_grouped as (
select distinct t.parent_id, t.name
@@ -226,7 +228,7 @@
}
}
- async addGpuFreqTracks(engine: EngineProxy): Promise<void> {
+ async addGpuFreqTracks(engine: Engine): Promise<void> {
const numGpus = await this.engine.getNumberOfGpus();
for (let gpu = 0; gpu < numGpus; gpu++) {
// Only add a gpu freq track if we have
@@ -248,7 +250,7 @@
}
}
- async addCpuFreqLimitCounterTracks(engine: EngineProxy): Promise<void> {
+ async addCpuFreqLimitCounterTracks(engine: Engine): Promise<void> {
const cpuFreqLimitCounterTracksSql = `
select name, id
from cpu_counter_track
@@ -259,7 +261,7 @@
this.addCpuCounterTracks(engine, cpuFreqLimitCounterTracksSql);
}
- async addCpuPerfCounterTracks(engine: EngineProxy): Promise<void> {
+ async addCpuPerfCounterTracks(engine: Engine): Promise<void> {
// Perf counter tracks are bound to CPUs, follow the scheduling and
// frequency track naming convention ("Cpu N ...").
// Note: we might not have a track for a given cpu if no data was seen from
@@ -274,7 +276,7 @@
this.addCpuCounterTracks(engine, addCpuPerfCounterTracksSql);
}
- async addCpuCounterTracks(engine: EngineProxy, sql: string): Promise<void> {
+ async addCpuCounterTracks(engine: Engine, sql: string): Promise<void> {
const result = await engine.query(sql);
const it = result.iter({
@@ -516,7 +518,7 @@
}
}
- async addAnnotationTracks(engine: EngineProxy): Promise<void> {
+ async addAnnotationTracks(engine: Engine): Promise<void> {
const sliceResult = await engine.query(`
select id, name, upid, group_name
from annotation_slice_track
@@ -607,7 +609,7 @@
}
}
- async addThreadStateTracks(engine: EngineProxy): Promise<void> {
+ async addThreadStateTracks(engine: Engine): Promise<void> {
const result = await engine.query(`
select
utid,
@@ -657,7 +659,7 @@
}
}
- async addThreadCpuSampleTracks(engine: EngineProxy): Promise<void> {
+ async addThreadCpuSampleTracks(engine: Engine): Promise<void> {
const result = await engine.query(`
with thread_cpu_sample as (
select distinct utid
@@ -695,7 +697,7 @@
}
}
- async addThreadCounterTracks(engine: EngineProxy): Promise<void> {
+ async addThreadCounterTracks(engine: Engine): Promise<void> {
const result = await engine.query(`
select
thread_counter_track.name as trackName,
@@ -745,7 +747,7 @@
}
}
- async addProcessAsyncSliceTracks(engine: EngineProxy): Promise<void> {
+ async addProcessAsyncSliceTracks(engine: Engine): Promise<void> {
const result = await engine.query(`
select
upid,
@@ -790,7 +792,7 @@
}
}
- async addUserAsyncSliceTracks(engine: EngineProxy): Promise<void> {
+ async addUserAsyncSliceTracks(engine: Engine): Promise<void> {
const result = await engine.query(`
with grouped_packages as materialized (
select
@@ -848,7 +850,7 @@
}
}
- async addActualFramesTracks(engine: EngineProxy): Promise<void> {
+ async addActualFramesTracks(engine: Engine): Promise<void> {
const result = await engine.query(`
select
upid,
@@ -891,7 +893,7 @@
}
}
- async addExpectedFramesTracks(engine: EngineProxy): Promise<void> {
+ async addExpectedFramesTracks(engine: Engine): Promise<void> {
const result = await engine.query(`
select
upid,
@@ -935,7 +937,7 @@
}
}
- async addThreadSliceTracks(engine: EngineProxy): Promise<void> {
+ async addThreadSliceTracks(engine: Engine): Promise<void> {
const result = await engine.query(`
select
thread_track.utid as utid,
@@ -990,7 +992,7 @@
}
}
- async addProcessCounterTracks(engine: EngineProxy): Promise<void> {
+ async addProcessCounterTracks(engine: Engine): Promise<void> {
const result = await engine.query(`
select
process_counter_track.id as trackId,
@@ -1034,7 +1036,7 @@
}
}
- async addProcessHeapProfileTracks(engine: EngineProxy): Promise<void> {
+ async addProcessHeapProfileTracks(engine: Engine): Promise<void> {
const result = await engine.query(`
select upid
from _process_available_info_summary
@@ -1052,7 +1054,7 @@
}
}
- async addProcessPerfSamplesTracks(engine: EngineProxy): Promise<void> {
+ async addProcessPerfSamplesTracks(engine: Engine): Promise<void> {
const result = await engine.query(`
select upid, pid
from _process_available_info_summary
@@ -1099,7 +1101,7 @@
this.upidToUuid.set(upid, uuid);
}
- async addKernelThreadGrouping(engine: EngineProxy): Promise<void> {
+ async addKernelThreadGrouping(engine: Engine): Promise<void> {
// Identify kernel threads if this is a linux system trace, and sufficient
// process information is available. Kernel threads are identified by being
// children of kthreadd (always pid 2).
@@ -1162,7 +1164,7 @@
}
}
- async addProcessTrackGroups(engine: EngineProxy): Promise<void> {
+ async addProcessTrackGroups(engine: Engine): Promise<void> {
// We want to create groups of tracks in a specific order.
// The tracks should be grouped:
// by upid
diff --git a/ui/src/core_plugins/android_log/logs_panel.ts b/ui/src/core_plugins/android_log/logs_panel.ts
index e326a38..ecb1a3b 100644
--- a/ui/src/core_plugins/android_log/logs_panel.ts
+++ b/ui/src/core_plugins/android_log/logs_panel.ts
@@ -21,7 +21,7 @@
import {globals} from '../../frontend/globals';
import {Timestamp} from '../../frontend/widgets/timestamp';
-import {EngineProxy, LONG, NUM, NUM_NULL, Store, STR} from '../../public';
+import {Engine, LONG, NUM, NUM_NULL, Store, STR} from '../../public';
import {Monitor} from '../../base/monitor';
import {AsyncLimiter} from '../../base/async_limiter';
import {escapeGlob, escapeQuery} from '../../trace_processor/query_utils';
@@ -43,7 +43,7 @@
export interface LogPanelAttrs {
filterStore: Store<LogFilteringCriteria>;
- engine: EngineProxy;
+ engine: Engine;
}
interface Pagination {
@@ -384,7 +384,7 @@
}
async function updateLogEntries(
- engine: EngineProxy,
+ engine: Engine,
span: Span<time, duration>,
pagination: Pagination,
): Promise<LogEntries> {
@@ -450,10 +450,7 @@
};
}
-async function updateLogView(
- engine: EngineProxy,
- filter: LogFilteringCriteria,
-) {
+async function updateLogView(engine: Engine, filter: LogFilteringCriteria) {
await engine.query('drop view if exists filtered_logs');
const globMatch = composeGlobMatch(filter.hideNonMatching, filter.textEntry);
diff --git a/ui/src/core_plugins/android_log/logs_track.ts b/ui/src/core_plugins/android_log/logs_track.ts
index 1c5b3c6..7027a65 100644
--- a/ui/src/core_plugins/android_log/logs_track.ts
+++ b/ui/src/core_plugins/android_log/logs_track.ts
@@ -14,11 +14,11 @@
import {Time, duration, time} from '../../base/time';
import {LIMIT, TrackData} from '../../common/track_data';
-import {LONG, NUM, TimelineFetcher} from '../../common/track_helper';
+import {TimelineFetcher} from '../../common/track_helper';
import {checkerboardExcept} from '../../frontend/checkerboard';
import {globals} from '../../frontend/globals';
import {PanelSize} from '../../frontend/panel';
-import {EngineProxy, Track} from '../../public';
+import {Engine, LONG, NUM, Track} from '../../public';
export interface Data extends TrackData {
// Total number of log events within [start, end], before any quantization.
@@ -52,7 +52,7 @@
export class AndroidLogTrack implements Track {
private fetcher = new TimelineFetcher<Data>(this.onBoundsChange.bind(this));
- constructor(private engine: EngineProxy) {}
+ constructor(private engine: Engine) {}
async onUpdate(): Promise<void> {
await this.fetcher.requestDataForCurrentTime();
diff --git a/ui/src/core_plugins/chrome_scroll_jank/index.ts b/ui/src/core_plugins/chrome_scroll_jank/index.ts
index 1feb5cc..4267f4c 100644
--- a/ui/src/core_plugins/chrome_scroll_jank/index.ts
+++ b/ui/src/core_plugins/chrome_scroll_jank/index.ts
@@ -25,7 +25,7 @@
PluginContextTrace,
PluginDescriptor,
} from '../../public';
-import {Engine, EngineProxy} from '../../trace_processor/engine';
+import {Engine} from '../../trace_processor/engine';
import {ChromeTasksScrollJankTrack} from './chrome_tasks_scroll_jank_track';
import {EventLatencySliceDetailsPanel} from './event_latency_details_panel';
@@ -329,7 +329,7 @@
}
}
-async function isChromeTrace(engine: EngineProxy) {
+async function isChromeTrace(engine: Engine) {
const queryResult = await engine.query(`
select utid, upid
from thread
diff --git a/ui/src/core_plugins/chrome_scroll_jank/scroll_delta_graph.ts b/ui/src/core_plugins/chrome_scroll_jank/scroll_delta_graph.ts
index d476019..a2f644b 100644
--- a/ui/src/core_plugins/chrome_scroll_jank/scroll_delta_graph.ts
+++ b/ui/src/core_plugins/chrome_scroll_jank/scroll_delta_graph.ts
@@ -15,7 +15,7 @@
import m from 'mithril';
import {duration, Time, time} from '../../base/time';
-import {EngineProxy} from '../../trace_processor/engine';
+import {Engine} from '../../trace_processor/engine';
import {LONG, NUM} from '../../trace_processor/query_result';
import {VegaView} from '../../widgets/vega_view';
@@ -45,7 +45,7 @@
}
export async function getUserScrollDeltas(
- engine: EngineProxy,
+ engine: Engine,
startTs: time,
dur: duration,
): Promise<ScrollDeltaDetails[]> {
@@ -82,7 +82,7 @@
}
export async function getAppliedScrollDeltas(
- engine: EngineProxy,
+ engine: Engine,
startTs: time,
dur: duration,
): Promise<ScrollDeltaDetails[]> {
@@ -123,7 +123,7 @@
}
export async function getJankIntervals(
- engine: EngineProxy,
+ engine: Engine,
startTs: time,
dur: duration,
): Promise<JankIntervalPlotDetails[]> {
diff --git a/ui/src/core_plugins/chrome_scroll_jank/scroll_jank_cause_link_utils.ts b/ui/src/core_plugins/chrome_scroll_jank/scroll_jank_cause_link_utils.ts
index 64e8784..80ee9e2 100644
--- a/ui/src/core_plugins/chrome_scroll_jank/scroll_jank_cause_link_utils.ts
+++ b/ui/src/core_plugins/chrome_scroll_jank/scroll_jank_cause_link_utils.ts
@@ -24,7 +24,7 @@
verticalScrollToTrack,
} from '../../frontend/scroll_helper';
import {SliceSqlId} from '../../frontend/sql_types';
-import {EngineProxy} from '../../trace_processor/engine';
+import {Engine} from '../../trace_processor/engine';
import {LONG, NUM, STR} from '../../trace_processor/query_result';
import {Anchor} from '../../widgets/anchor';
@@ -53,7 +53,7 @@
}
export async function getScrollJankCauseStage(
- engine: EngineProxy,
+ engine: Engine,
eventLatencyId: SliceSqlId,
): Promise<EventLatencyStage | undefined> {
const queryResult = await engine.query(`
@@ -95,7 +95,7 @@
}
export async function getEventLatencyCauseTracks(
- engine: EngineProxy,
+ engine: Engine,
scrollJankCauseStage: EventLatencyStage,
): Promise<EventLatencyCauseThreadTracks[]> {
const threadTracks: EventLatencyCauseThreadTracks[] = [];
@@ -130,7 +130,7 @@
}
async function getChromeCauseTracks(
- engine: EngineProxy,
+ engine: Engine,
eventLatencySliceId: number,
processName: CauseProcess,
threadName: CauseThread,
diff --git a/ui/src/core_plugins/chrome_scroll_jank/scroll_jank_slice.ts b/ui/src/core_plugins/chrome_scroll_jank/scroll_jank_slice.ts
index c05ac43..6dab538 100644
--- a/ui/src/core_plugins/chrome_scroll_jank/scroll_jank_slice.ts
+++ b/ui/src/core_plugins/chrome_scroll_jank/scroll_jank_slice.ts
@@ -24,7 +24,7 @@
constraintsToQuerySuffix,
SQLConstraints,
} from '../../frontend/sql_utils';
-import {EngineProxy} from '../../trace_processor/engine';
+import {Engine} from '../../trace_processor/engine';
import {LONG, NUM} from '../../trace_processor/query_result';
import {Anchor} from '../../widgets/anchor';
@@ -45,7 +45,7 @@
}
async function getSlicesFromTrack(
- engine: EngineProxy,
+ engine: Engine,
track: ScrollJankTrackSpec,
constraints: SQLConstraints,
): Promise<BasicSlice[]> {
@@ -75,7 +75,7 @@
export type ScrollJankSlice = BasicSlice;
export async function getScrollJankSlices(
- engine: EngineProxy,
+ engine: Engine,
id: number,
): Promise<ScrollJankSlice[]> {
const track = ScrollJankPluginState.getInstance().getTrack(
@@ -93,7 +93,7 @@
export type EventLatencySlice = BasicSlice;
export async function getEventLatencySlice(
- engine: EngineProxy,
+ engine: Engine,
id: number,
): Promise<EventLatencySlice | undefined> {
const track = ScrollJankPluginState.getInstance().getTrack(
@@ -112,7 +112,7 @@
}
export async function getEventLatencyDescendantSlice(
- engine: EngineProxy,
+ engine: Engine,
id: number,
descendant: string | undefined,
): Promise<EventLatencySlice | undefined> {
diff --git a/ui/src/core_plugins/chrome_scroll_jank/scroll_jank_v3_details_panel.ts b/ui/src/core_plugins/chrome_scroll_jank/scroll_jank_v3_details_panel.ts
index b117b08..646b7c6 100644
--- a/ui/src/core_plugins/chrome_scroll_jank/scroll_jank_v3_details_panel.ts
+++ b/ui/src/core_plugins/chrome_scroll_jank/scroll_jank_v3_details_panel.ts
@@ -24,7 +24,7 @@
import {sqlValueToString} from '../../frontend/sql_utils';
import {DurationWidget} from '../../frontend/widgets/duration';
import {Timestamp} from '../../frontend/widgets/timestamp';
-import {EngineProxy} from '../../trace_processor/engine';
+import {Engine} from '../../trace_processor/engine';
import {LONG, NUM, STR} from '../../trace_processor/query_result';
import {DetailsShell} from '../../widgets/details_shell';
import {GridLayout, GridLayoutColumn} from '../../widgets/grid_layout';
@@ -61,7 +61,7 @@
}
async function getSliceDetails(
- engine: EngineProxy,
+ engine: Engine,
id: number,
): Promise<SliceDetails | undefined> {
return getSlice(engine, asSliceSqlId(id));
diff --git a/ui/src/core_plugins/cpu_freq/index.ts b/ui/src/core_plugins/cpu_freq/index.ts
index b5fa5fa..07b9b1d 100644
--- a/ui/src/core_plugins/cpu_freq/index.ts
+++ b/ui/src/core_plugins/cpu_freq/index.ts
@@ -24,7 +24,7 @@
import {globals} from '../../frontend/globals';
import {PanelSize} from '../../frontend/panel';
import {
- EngineProxy,
+ Engine,
Plugin,
PluginContextTrace,
PluginDescriptor,
@@ -62,11 +62,11 @@
private hoveredIdle: number | undefined = undefined;
private fetcher = new TimelineFetcher<Data>(this.onBoundsChange.bind(this));
- private engine: EngineProxy;
+ private engine: Engine;
private config: Config;
private trackUuid = uuidv4Sql();
- constructor(config: Config, engine: EngineProxy) {
+ constructor(config: Config, engine: Engine) {
this.config = config;
this.engine = engine;
}
diff --git a/ui/src/core_plugins/cpu_profile/index.ts b/ui/src/core_plugins/cpu_profile/index.ts
index 4d3e87f..364225d 100644
--- a/ui/src/core_plugins/cpu_profile/index.ts
+++ b/ui/src/core_plugins/cpu_profile/index.ts
@@ -24,7 +24,7 @@
import {PanelSize} from '../../frontend/panel';
import {TimeScale} from '../../frontend/time_scale';
import {
- EngineProxy,
+ Engine,
Plugin,
PluginContextTrace,
PluginDescriptor,
@@ -54,10 +54,10 @@
private markerWidth = (this.getHeight() - MARGIN_TOP - BAR_HEIGHT) / 2;
private hoveredTs: time | undefined = undefined;
private fetcher = new TimelineFetcher<Data>(this.onBoundsChange.bind(this));
- private engine: EngineProxy;
+ private engine: Engine;
private utid: number;
- constructor(engine: EngineProxy, utid: number) {
+ constructor(engine: Engine, utid: number) {
this.engine = engine;
this.utid = utid;
}
diff --git a/ui/src/core_plugins/cpu_slices/index.ts b/ui/src/core_plugins/cpu_slices/index.ts
index 139bac5..1fc1e67 100644
--- a/ui/src/core_plugins/cpu_slices/index.ts
+++ b/ui/src/core_plugins/cpu_slices/index.ts
@@ -33,7 +33,7 @@
import {PanelSize} from '../../frontend/panel';
import {SliceDetailsPanel} from '../../frontend/slice_details_panel';
import {
- EngineProxy,
+ Engine,
Plugin,
PluginContextTrace,
PluginDescriptor,
@@ -67,12 +67,12 @@
private fetcher = new TimelineFetcher<Data>(this.onBoundsChange.bind(this));
private lastRowId = -1;
- private engine: EngineProxy;
+ private engine: Engine;
private cpu: number;
private trackKey: string;
private trackUuid = uuidv4Sql();
- constructor(engine: EngineProxy, trackKey: string, cpu: number) {
+ constructor(engine: Engine, trackKey: string, cpu: number) {
this.engine = engine;
this.trackKey = trackKey;
this.cpu = cpu;
@@ -490,7 +490,7 @@
});
}
- async guessCpuSizes(engine: EngineProxy): Promise<Map<number, string>> {
+ async guessCpuSizes(engine: Engine): Promise<Map<number, string>> {
const cpuToSize = new Map<number, string>();
await engine.query(`
INCLUDE PERFETTO MODULE cpu.size;
diff --git a/ui/src/core_plugins/debug/add_debug_track_menu.ts b/ui/src/core_plugins/debug/add_debug_track_menu.ts
index e03c9f2..a0c5b31 100644
--- a/ui/src/core_plugins/debug/add_debug_track_menu.ts
+++ b/ui/src/core_plugins/debug/add_debug_track_menu.ts
@@ -16,7 +16,7 @@
import {findRef} from '../../base/dom_utils';
import {raf} from '../../core/raf_scheduler';
-import {EngineProxy} from '../../trace_processor/engine';
+import {Engine} from '../../trace_processor/engine';
import {Form, FormLabel} from '../../widgets/form';
import {Select} from '../../widgets/select';
import {TextInput} from '../../widgets/text_input';
@@ -36,7 +36,7 @@
interface AddDebugTrackMenuAttrs {
dataSource: Required<SqlDataSource>;
- engine: EngineProxy;
+ engine: Engine;
}
const TRACK_NAME_FIELD_REF = 'TRACK_NAME_FIELD';
diff --git a/ui/src/core_plugins/debug/counter_track.ts b/ui/src/core_plugins/debug/counter_track.ts
index 5b37e3d..56274d3 100644
--- a/ui/src/core_plugins/debug/counter_track.ts
+++ b/ui/src/core_plugins/debug/counter_track.ts
@@ -16,7 +16,7 @@
import {BaseCounterTrack} from '../../frontend/base_counter_track';
import {TrackContext} from '../../public';
-import {EngineProxy} from '../../trace_processor/engine';
+import {Engine} from '../../trace_processor/engine';
import {CounterDebugTrackConfig} from '../../frontend/debug_tracks';
import {Disposable, DisposableCallback} from '../../base/disposable';
import {uuidv4Sql} from '../../base/uuid';
@@ -25,7 +25,7 @@
private config: CounterDebugTrackConfig;
private sqlTableName: string;
- constructor(engine: EngineProxy, ctx: TrackContext) {
+ constructor(engine: Engine, ctx: TrackContext) {
super({
engine,
trackKey: ctx.trackKey,
diff --git a/ui/src/core_plugins/debug/slice_track.ts b/ui/src/core_plugins/debug/slice_track.ts
index a53e4dc..49e5142 100644
--- a/ui/src/core_plugins/debug/slice_track.ts
+++ b/ui/src/core_plugins/debug/slice_track.ts
@@ -14,7 +14,7 @@
import {NamedSliceTrackTypes} from '../../frontend/named_slice_track';
import {TrackContext} from '../../public';
-import {EngineProxy} from '../../trace_processor/engine';
+import {Engine} from '../../trace_processor/engine';
import {
CustomSqlDetailsPanelConfig,
CustomSqlTableDefConfig,
@@ -40,7 +40,7 @@
private config: DebugTrackV2Config;
private sqlTableName: string;
- constructor(engine: EngineProxy, ctx: TrackContext) {
+ constructor(engine: Engine, ctx: TrackContext) {
super({
engine,
trackKey: ctx.trackKey,
diff --git a/ui/src/core_plugins/frames/actual_frames_track_v2.ts b/ui/src/core_plugins/frames/actual_frames_track_v2.ts
index 6ce0e3d..10b7d72 100644
--- a/ui/src/core_plugins/frames/actual_frames_track_v2.ts
+++ b/ui/src/core_plugins/frames/actual_frames_track_v2.ts
@@ -20,7 +20,7 @@
NamedSliceTrackTypes,
} from '../../frontend/named_slice_track';
import {SLICE_LAYOUT_FIT_CONTENT_DEFAULTS} from '../../frontend/slice_layout';
-import {EngineProxy, Slice, STR_NULL} from '../../public';
+import {Engine, Slice, STR_NULL} from '../../public';
// color named and defined based on Material Design color palettes
// 500 colors indicate a timeline slice is not a partial jank (not a jank or
@@ -54,7 +54,7 @@
export class ActualFramesTrack extends NamedSliceTrack<ActualFrameTrackTypes> {
constructor(
- engine: EngineProxy,
+ engine: Engine,
maxDepth: number,
trackKey: string,
private trackIds: number[],
diff --git a/ui/src/core_plugins/frames/expected_frames_track_v2.ts b/ui/src/core_plugins/frames/expected_frames_track_v2.ts
index ce602a1..e9cce12 100644
--- a/ui/src/core_plugins/frames/expected_frames_track_v2.ts
+++ b/ui/src/core_plugins/frames/expected_frames_track_v2.ts
@@ -16,13 +16,13 @@
import {makeColorScheme} from '../../core/colorizer';
import {NamedRow, NamedSliceTrack} from '../../frontend/named_slice_track';
import {SLICE_LAYOUT_FIT_CONTENT_DEFAULTS} from '../../frontend/slice_layout';
-import {EngineProxy, Slice} from '../../public';
+import {Engine, Slice} from '../../public';
const GREEN = makeColorScheme(new HSLColor('#4CAF50')); // Green 500
export class ExpectedFramesTrack extends NamedSliceTrack {
constructor(
- engine: EngineProxy,
+ engine: Engine,
maxDepth: number,
trackKey: string,
private trackIds: number[],
diff --git a/ui/src/core_plugins/ftrace/ftrace_explorer.ts b/ui/src/core_plugins/ftrace/ftrace_explorer.ts
index d8cad78..e034183 100644
--- a/ui/src/core_plugins/ftrace/ftrace_explorer.ts
+++ b/ui/src/core_plugins/ftrace/ftrace_explorer.ts
@@ -28,7 +28,7 @@
import {globals} from '../../frontend/globals';
import {Timestamp} from '../../frontend/widgets/timestamp';
import {FtraceFilter, FtraceStat} from './common';
-import {EngineProxy, LONG, NUM, Store, STR, STR_NULL} from '../../public';
+import {Engine, LONG, NUM, Store, STR, STR_NULL} from '../../public';
import {raf} from '../../core/raf_scheduler';
import {AsyncLimiter} from '../../base/async_limiter';
import {Monitor} from '../../base/monitor';
@@ -40,7 +40,7 @@
interface FtraceExplorerAttrs {
cache: FtraceExplorerCache;
filterStore: Store<FtraceFilter>;
- engine: EngineProxy;
+ engine: Engine;
}
interface FtraceEvent {
@@ -69,7 +69,7 @@
counters: FtraceStat[];
}
-async function getFtraceCounters(engine: EngineProxy): Promise<FtraceStat[]> {
+async function getFtraceCounters(engine: Engine): Promise<FtraceStat[]> {
// TODO(stevegolton): this is an extraordinarily slow query on large traces
// as it goes through every ftrace event which can be a lot on big traces.
// Consider if we can have some different UX which avoids needing these
@@ -264,7 +264,7 @@
}
async function lookupFtraceEvents(
- engine: EngineProxy,
+ engine: Engine,
offset: number,
count: number,
filter: FtraceFilter,
diff --git a/ui/src/core_plugins/ftrace/ftrace_track.ts b/ui/src/core_plugins/ftrace/ftrace_track.ts
index 6950eca..ed55cf6 100644
--- a/ui/src/core_plugins/ftrace/ftrace_track.ts
+++ b/ui/src/core_plugins/ftrace/ftrace_track.ts
@@ -20,7 +20,7 @@
import {globals} from '../../frontend/globals';
import {TrackData} from '../../common/track_data';
import {PanelSize} from '../../frontend/panel';
-import {EngineProxy, Track} from '../../public';
+import {Engine, Track} from '../../public';
import {LONG, STR} from '../../trace_processor/query_result';
import {FtraceFilter} from './common';
import {Store} from '../../public';
@@ -41,12 +41,12 @@
export class FtraceRawTrack implements Track {
private fetcher = new TimelineFetcher(this.onBoundsChange.bind(this));
- private engine: EngineProxy;
+ private engine: Engine;
private cpu: number;
private store: Store<FtraceFilter>;
private readonly monitor: Monitor;
- constructor(engine: EngineProxy, cpu: number, store: Store<FtraceFilter>) {
+ constructor(engine: Engine, cpu: number, store: Store<FtraceFilter>) {
this.engine = engine;
this.cpu = cpu;
this.store = store;
diff --git a/ui/src/core_plugins/ftrace/index.ts b/ui/src/core_plugins/ftrace/index.ts
index 3cc0616..9539c78 100644
--- a/ui/src/core_plugins/ftrace/index.ts
+++ b/ui/src/core_plugins/ftrace/index.ts
@@ -16,7 +16,7 @@
import {FtraceExplorer, FtraceExplorerCache} from './ftrace_explorer';
import {
- EngineProxy,
+ Engine,
Plugin,
PluginContextTrace,
PluginDescriptor,
@@ -108,7 +108,7 @@
this.trash.dispose();
}
- private async lookupCpuCores(engine: EngineProxy): Promise<number[]> {
+ private async lookupCpuCores(engine: Engine): Promise<number[]> {
const query = 'select distinct cpu from ftrace_event';
const result = await engine.query(query);
diff --git a/ui/src/core_plugins/perf_samples_profile/index.ts b/ui/src/core_plugins/perf_samples_profile/index.ts
index 752684a..319fb25 100644
--- a/ui/src/core_plugins/perf_samples_profile/index.ts
+++ b/ui/src/core_plugins/perf_samples_profile/index.ts
@@ -24,7 +24,7 @@
import {PanelSize} from '../../frontend/panel';
import {TimeScale} from '../../frontend/time_scale';
import {
- EngineProxy,
+ Engine,
Plugin,
PluginContextTrace,
PluginDescriptor,
@@ -50,9 +50,9 @@
private hoveredTs: time | undefined = undefined;
private fetcher = new TimelineFetcher(this.onBoundsChange.bind(this));
private upid: number;
- private engine: EngineProxy;
+ private engine: Engine;
- constructor(engine: EngineProxy, upid: number) {
+ constructor(engine: Engine, upid: number) {
this.upid = upid;
this.engine = engine;
}
diff --git a/ui/src/core_plugins/process_summary/process_scheduling_track.ts b/ui/src/core_plugins/process_summary/process_scheduling_track.ts
index 9725c29..28b536f 100644
--- a/ui/src/core_plugins/process_summary/process_scheduling_track.ts
+++ b/ui/src/core_plugins/process_summary/process_scheduling_track.ts
@@ -25,7 +25,7 @@
import {checkerboardExcept} from '../../frontend/checkerboard';
import {globals} from '../../frontend/globals';
import {PanelSize} from '../../frontend/panel';
-import {EngineProxy, Track} from '../../public';
+import {Engine, Track} from '../../public';
import {LONG, NUM, QueryResult} from '../../trace_processor/query_result';
import {uuidv4Sql} from '../../base/uuid';
@@ -57,11 +57,11 @@
private utidHoveredInThisTrack = -1;
private fetcher = new TimelineFetcher(this.onBoundsChange.bind(this));
private maxCpu = 0;
- private engine: EngineProxy;
+ private engine: Engine;
private trackUuid = uuidv4Sql();
private config: Config;
- constructor(engine: EngineProxy, config: Config) {
+ constructor(engine: Engine, config: Config) {
this.engine = engine;
this.config = config;
}
diff --git a/ui/src/core_plugins/process_summary/process_summary_track.ts b/ui/src/core_plugins/process_summary/process_summary_track.ts
index 7acf36b..5fa31de 100644
--- a/ui/src/core_plugins/process_summary/process_summary_track.ts
+++ b/ui/src/core_plugins/process_summary/process_summary_track.ts
@@ -19,11 +19,11 @@
import {duration, Time, time} from '../../base/time';
import {colorForTid} from '../../core/colorizer';
import {LIMIT, TrackData} from '../../common/track_data';
-import {EngineProxy, TimelineFetcher} from '../../common/track_helper';
+import {TimelineFetcher} from '../../common/track_helper';
import {checkerboardExcept} from '../../frontend/checkerboard';
import {globals} from '../../frontend/globals';
import {PanelSize} from '../../frontend/panel';
-import {Track} from '../../public';
+import {Engine, Track} from '../../public';
import {NUM} from '../../trace_processor/query_result';
export const PROCESS_SUMMARY_TRACK = 'ProcessSummaryTrack';
@@ -47,11 +47,11 @@
export class ProcessSummaryTrack implements Track {
private fetcher = new TimelineFetcher<Data>(this.onBoundsChange.bind(this));
- private engine: EngineProxy;
+ private engine: Engine;
private uuid = uuidv4();
private config: Config;
- constructor(engine: EngineProxy, config: Config) {
+ constructor(engine: Engine, config: Config) {
this.engine = engine;
this.config = config;
}
diff --git a/ui/src/core_plugins/sched/active_cpu_count.ts b/ui/src/core_plugins/sched/active_cpu_count.ts
index 721a884..2ab49bc 100644
--- a/ui/src/core_plugins/sched/active_cpu_count.ts
+++ b/ui/src/core_plugins/sched/active_cpu_count.ts
@@ -25,7 +25,7 @@
} from '../../frontend/base_counter_track';
import {CloseTrackButton} from '../../frontend/close_track_button';
import {globals} from '../../frontend/globals';
-import {EngineProxy, PrimaryTrackSortKey, TrackContext} from '../../public';
+import {Engine, PrimaryTrackSortKey, TrackContext} from '../../public';
export function addActiveCPUCountTrack(cpuType?: string) {
const cpuTypeName = cpuType === undefined ? '' : ` ${cpuType} `;
@@ -56,7 +56,7 @@
static readonly kind = 'dev.perfetto.Sched.ActiveCPUCount';
- constructor(ctx: TrackContext, engine: EngineProxy) {
+ constructor(ctx: TrackContext, engine: Engine) {
super({
engine,
trackKey: ctx.trackKey,
diff --git a/ui/src/core_plugins/screenshots/screenshot_panel.ts b/ui/src/core_plugins/screenshots/screenshot_panel.ts
index 066d14c..387ebf6 100644
--- a/ui/src/core_plugins/screenshots/screenshot_panel.ts
+++ b/ui/src/core_plugins/screenshots/screenshot_panel.ts
@@ -20,10 +20,10 @@
import {GenericSliceDetailsTabConfig} from '../../frontend/generic_slice_details_tab';
import {getSlice, SliceDetails} from '../../frontend/sql/slice';
import {asSliceSqlId} from '../../frontend/sql_types';
-import {EngineProxy} from '../../trace_processor/engine';
+import {Engine} from '../../trace_processor/engine';
async function getSliceDetails(
- engine: EngineProxy,
+ engine: Engine,
id: number,
): Promise<SliceDetails | undefined> {
return getSlice(engine, asSliceSqlId(id));
diff --git a/ui/src/frontend/app.ts b/ui/src/frontend/app.ts
index 92301b7..09b1036 100644
--- a/ui/src/frontend/app.ts
+++ b/ui/src/frontend/app.ts
@@ -32,7 +32,7 @@
} from '../core/timestamp_format';
import {raf} from '../core/raf_scheduler';
import {Command} from '../public';
-import {EngineProxy} from '../trace_processor/engine';
+import {Engine} from '../trace_processor/engine';
import {THREAD_STATE_TRACK_KIND} from '../core_plugins/thread_state';
import {HotkeyConfig, HotkeyContext} from '../widgets/hotkey_context';
import {HotkeyGlyphs} from '../widgets/hotkey_glyphs';
@@ -155,7 +155,7 @@
this.trash.add(new AggregationsTabs());
}
- private getEngine(): EngineProxy | undefined {
+ private getEngine(): Engine | undefined {
const engineId = globals.getCurrentEngine()?.id;
if (engineId === undefined) {
return undefined;
@@ -620,8 +620,8 @@
if (selection !== null && selection.kind === 'AREA') {
const area = globals.state.areas[selection.areaId];
const coversEntireTimeRange =
- globals.state.traceTime.start === area.start &&
- globals.state.traceTime.end === area.end;
+ globals.traceTime.start === area.start &&
+ globals.traceTime.end === area.end;
if (!coversEntireTimeRange) {
// If the current selection is an area which does not cover the
// entire time range, preserve the list of selected tracks and
@@ -636,7 +636,7 @@
// If the current selection is not an area, select all.
tracksToSelect = Object.keys(globals.state.tracks);
}
- const {start, end} = globals.state.traceTime;
+ const {start, end} = globals.traceTime;
globals.dispatch(
Actions.selectArea({
area: {
diff --git a/ui/src/frontend/base_counter_track.ts b/ui/src/frontend/base_counter_track.ts
index 990e6a3..9a37a6a 100644
--- a/ui/src/frontend/base_counter_track.ts
+++ b/ui/src/frontend/base_counter_track.ts
@@ -20,7 +20,7 @@
import {Time, time} from '../base/time';
import {drawTrackHoverTooltip} from '../common/canvas_utils';
import {raf} from '../core/raf_scheduler';
-import {EngineProxy, LONG, NUM, Track} from '../public';
+import {Engine, LONG, NUM, Track} from '../public';
import {Button} from '../widgets/button';
import {MenuItem, MenuDivider, PopupMenu2} from '../widgets/menu';
@@ -194,7 +194,7 @@
};
export abstract class BaseCounterTrack implements Track {
- protected engine: EngineProxy;
+ protected engine: Engine;
protected trackKey: string;
protected trackUuid = uuidv4Sql();
diff --git a/ui/src/frontend/base_slice_track.ts b/ui/src/frontend/base_slice_track.ts
index 7e013cc..720ace2 100644
--- a/ui/src/frontend/base_slice_track.ts
+++ b/ui/src/frontend/base_slice_track.ts
@@ -32,7 +32,7 @@
} from '../common/state';
import {featureFlags} from '../core/feature_flags';
import {raf} from '../core/raf_scheduler';
-import {EngineProxy, Slice, SliceRect, Track} from '../public';
+import {Engine, Slice, SliceRect, Track} from '../public';
import {LONG, NUM} from '../trace_processor/query_result';
import {checkerboardExcept} from './checkerboard';
@@ -175,7 +175,7 @@
> implements Track
{
protected sliceLayout: SliceLayout = {...DEFAULT_SLICE_LAYOUT};
- protected engine: EngineProxy;
+ protected engine: Engine;
protected trackKey: string;
protected trackUuid = uuidv4Sql();
diff --git a/ui/src/frontend/bottom_tab.ts b/ui/src/frontend/bottom_tab.ts
index d8ed117..9868a60 100644
--- a/ui/src/frontend/bottom_tab.ts
+++ b/ui/src/frontend/bottom_tab.ts
@@ -14,10 +14,10 @@
import m from 'mithril';
-import {EngineProxy} from '../trace_processor/engine';
+import {Engine} from '../trace_processor/engine';
export interface NewBottomTabArgs<Config> {
- engine: EngineProxy;
+ engine: Engine;
tag?: string;
uuid: string;
config: Config;
@@ -43,7 +43,7 @@
// Config for this details panel. Should be serializable.
protected readonly config: Config;
// Engine for running queries and fetching additional data.
- protected readonly engine: EngineProxy;
+ protected readonly engine: Engine;
// Optional tag, which is used to ensure that only one tab
// with the same tag can exist - adding a new tab with the same tag
// (e.g. 'current_selection') would close the previous one. This
diff --git a/ui/src/frontend/chrome_slice_details_tab.ts b/ui/src/frontend/chrome_slice_details_tab.ts
index 49196fa..91cf54f 100644
--- a/ui/src/frontend/chrome_slice_details_tab.ts
+++ b/ui/src/frontend/chrome_slice_details_tab.ts
@@ -19,7 +19,7 @@
import {exists} from '../base/utils';
import {runQuery} from '../common/queries';
import {raf} from '../core/raf_scheduler';
-import {EngineProxy} from '../trace_processor/engine';
+import {Engine} from '../trace_processor/engine';
import {LONG, LONG_NULL, NUM, STR_NULL} from '../trace_processor/query_result';
import {Button} from '../widgets/button';
import {DetailsShell} from '../widgets/details_shell';
@@ -167,7 +167,7 @@
return ITEMS.filter((item) => item.shouldDisplay(slice));
}
-function getEngine(): EngineProxy | undefined {
+function getEngine(): Engine | undefined {
const engineId = globals.getCurrentEngine()?.id;
if (engineId === undefined) {
return undefined;
@@ -177,7 +177,7 @@
}
async function getAnnotationSlice(
- engine: EngineProxy,
+ engine: Engine,
id: number,
): Promise<SliceDetails | undefined> {
const query = await engine.query(`
@@ -218,7 +218,7 @@
}
async function getSliceDetails(
- engine: EngineProxy,
+ engine: Engine,
id: number,
table: string,
): Promise<SliceDetails | undefined> {
@@ -300,7 +300,7 @@
return !exists(this.sliceDetails);
}
- private renderRhs(engine: EngineProxy, slice: SliceDetails): m.Children {
+ private renderRhs(engine: Engine, slice: SliceDetails): m.Children {
const precFlows = this.renderPrecedingFlows(slice);
const followingFlows = this.renderFollowingFlows(slice);
const args =
diff --git a/ui/src/frontend/debug_tracks.ts b/ui/src/frontend/debug_tracks.ts
index ed77bf0..7b3fe11 100644
--- a/ui/src/frontend/debug_tracks.ts
+++ b/ui/src/frontend/debug_tracks.ts
@@ -16,7 +16,7 @@
import {Actions, DeferredAction} from '../common/actions';
import {SCROLLING_TRACK_GROUP} from '../common/state';
import {globals} from './globals';
-import {EngineProxy, PrimaryTrackSortKey} from '../public';
+import {Engine, PrimaryTrackSortKey} from '../public';
import {DebugTrackV2Config} from '../core_plugins/debug/slice_track';
export const ARG_PREFIX = 'arg_';
@@ -55,7 +55,7 @@
// once or want to tweak the actions once produced. Otherwise, use
// addDebugSliceTrack().
export async function createDebugSliceTrackActions(
- _engine: EngineProxy,
+ _engine: Engine,
data: SqlDataSource,
trackName: string,
sliceColumns: SliceColumns,
@@ -90,7 +90,7 @@
}
export async function addPivotDebugSliceTracks(
- engine: EngineProxy,
+ engine: Engine,
data: SqlDataSource,
trackName: string,
sliceColumns: SliceColumns,
@@ -129,7 +129,7 @@
// Adds a debug track immediately. Use createDebugSliceTrackActions() if you
// want to create many tracks at once.
export async function addDebugSliceTrack(
- engine: EngineProxy,
+ engine: Engine,
data: SqlDataSource,
trackName: string,
sliceColumns: SliceColumns,
diff --git a/ui/src/frontend/globals.ts b/ui/src/frontend/globals.ts
index 50b2286..04cdc17 100644
--- a/ui/src/frontend/globals.ts
+++ b/ui/src/frontend/globals.ts
@@ -44,7 +44,7 @@
import {TrackManager} from '../common/track_cache';
import {setPerfHooks} from '../core/perf';
import {raf} from '../core/raf_scheduler';
-import {Engine} from '../trace_processor/engine';
+import {EngineBase} from '../trace_processor/engine';
import {HttpRpcState} from '../trace_processor/http_rpc_engine';
import {Analytics, initAnalytics} from './analytics';
@@ -221,6 +221,32 @@
pendingScrollId: number | undefined;
}
+export interface TraceTime {
+ readonly start: time;
+ readonly end: time;
+
+ // This is the ts value at the time of the Unix epoch.
+ // Normally some large negative value, because the unix epoch is normally in
+ // the past compared to ts=0.
+ readonly realtimeOffset: time;
+
+ // This is the timestamp that we should use for our offset when in UTC mode.
+ // Usually the most recent UTC midnight compared to the trace start time.
+ readonly utcOffset: time;
+
+ // Trace TZ is like UTC but keeps into account also the timezone_off_mins
+ // recorded into the trace, to show timestamps in the device local time.
+ readonly traceTzOffset: time;
+}
+
+export const defaultTraceTime: TraceTime = {
+ start: Time.ZERO,
+ end: Time.fromSeconds(10),
+ realtimeOffset: Time.ZERO,
+ utcOffset: Time.ZERO,
+ traceTzOffset: Time.ZERO,
+};
+
/**
* Global accessors for state/dispatch in the frontend.
*/
@@ -260,9 +286,6 @@
private _embeddedMode?: boolean = undefined;
private _hideSidebar?: boolean = undefined;
private _cmdManager = new CommandManager();
- private _realtimeOffset = Time.ZERO;
- private _utcOffset = Time.ZERO;
- private _traceTzOffset = Time.ZERO;
private _tabManager = new TabManager();
private _trackManager = new TrackManager(this._store);
private _selectionManager = new SelectionManager(this._store);
@@ -273,6 +296,8 @@
newVersionAvailable = false;
showPanningHint = false;
+ traceTime = defaultTraceTime;
+
// TODO(hjd): Remove once we no longer need to update UUID on redraw.
private _publishRedraw?: () => void = undefined;
@@ -290,7 +315,7 @@
count: new Uint8Array(0),
};
- engines = new Map<string, Engine>();
+ engines = new Map<string, EngineBase>();
initialize(dispatch: Dispatch, router: Router) {
this._dispatch = dispatch;
@@ -691,19 +716,19 @@
// Get a timescale that covers the entire trace
getTraceTimeScale(pxSpan: PxSpan): TimeScale {
- const {start, end} = this.state.traceTime;
+ const {start, end} = this.traceTime;
const traceTime = HighPrecisionTimeSpan.fromTime(start, end);
return TimeScale.fromHPTimeSpan(traceTime, pxSpan);
}
// Get the trace time bounds
stateTraceTime(): Span<HighPrecisionTime> {
- const {start, end} = this.state.traceTime;
+ const {start, end} = this.traceTime;
return HighPrecisionTimeSpan.fromTime(start, end);
}
stateTraceTimeTP(): Span<time, duration> {
- const {start, end} = this.state.traceTime;
+ const {start, end} = this.traceTime;
return new TimeSpan(start, end);
}
@@ -723,37 +748,6 @@
return assertExists(this._cmdManager);
}
- // This is the ts value at the time of the Unix epoch.
- // Normally some large negative value, because the unix epoch is normally in
- // the past compared to ts=0.
- get realtimeOffset(): time {
- return this._realtimeOffset;
- }
-
- set realtimeOffset(time: time) {
- this._realtimeOffset = time;
- }
-
- // This is the timestamp that we should use for our offset when in UTC mode.
- // Usually the most recent UTC midnight compared to the trace start time.
- get utcOffset(): time {
- return this._utcOffset;
- }
-
- set utcOffset(offset: time) {
- this._utcOffset = offset;
- }
-
- // Trace TZ is like UTC but keeps into account also the timezone_off_mins
- // recorded into the trace, to show timestamps in the device local time.
- get traceTzOffset(): time {
- return this._traceTzOffset;
- }
-
- set traceTzOffset(offset: time) {
- this._traceTzOffset = offset;
- }
-
get tabManager() {
return this._tabManager;
}
@@ -768,14 +762,14 @@
switch (fmt) {
case TimestampFormat.Timecode:
case TimestampFormat.Seconds:
- return this.state.traceTime.start;
+ return this.traceTime.start;
case TimestampFormat.Raw:
case TimestampFormat.RawLocale:
return Time.ZERO;
case TimestampFormat.UTC:
- return this.utcOffset;
+ return this.traceTime.utcOffset;
case TimestampFormat.TraceTz:
- return this.traceTzOffset;
+ return this.traceTime.traceTzOffset;
default:
const x: never = fmt;
throw new Error(`Unsupported format ${x}`);
diff --git a/ui/src/frontend/metrics_page.ts b/ui/src/frontend/metrics_page.ts
index 6b7ffce..124cb84 100644
--- a/ui/src/frontend/metrics_page.ts
+++ b/ui/src/frontend/metrics_page.ts
@@ -25,7 +25,7 @@
import {pluginManager, PluginManager} from '../common/plugins';
import {raf} from '../core/raf_scheduler';
import {MetricVisualisation} from '../public';
-import {EngineProxy} from '../trace_processor/engine';
+import {Engine} from '../trace_processor/engine';
import {STR} from '../trace_processor/query_result';
import {Select} from '../widgets/select';
import {Spinner} from '../widgets/spinner';
@@ -37,7 +37,7 @@
type Format = 'json' | 'prototext' | 'proto';
const FORMATS: Format[] = ['json', 'prototext', 'proto'];
-function getEngine(): EngineProxy | undefined {
+function getEngine(): Engine | undefined {
const engineId = globals.getCurrentEngine()?.id;
if (engineId === undefined) {
return undefined;
@@ -46,7 +46,7 @@
return engine;
}
-async function getMetrics(engine: EngineProxy): Promise<string[]> {
+async function getMetrics(engine: Engine): Promise<string[]> {
const metrics: string[] = [];
const metricsResult = await engine.query('select name from trace_metrics');
for (const it = metricsResult.iter({name: STR}); it.valid(); it.next()) {
@@ -56,7 +56,7 @@
}
async function getMetric(
- engine: EngineProxy,
+ engine: Engine,
metric: string,
format: Format,
): Promise<string> {
@@ -69,7 +69,7 @@
}
class MetricsController {
- engine: EngineProxy;
+ engine: Engine;
plugins: PluginManager;
private _metrics: string[];
private _selected?: string;
@@ -78,7 +78,7 @@
// eslint-disable-next-line @typescript-eslint/no-explicit-any
private _json: any;
- constructor(plugins: PluginManager, engine: EngineProxy) {
+ constructor(plugins: PluginManager, engine: Engine) {
this.plugins = plugins;
this.engine = engine;
this._metrics = [];
diff --git a/ui/src/frontend/publish.ts b/ui/src/frontend/publish.ts
index f8c36cb..bfb34ca 100644
--- a/ui/src/frontend/publish.ts
+++ b/ui/src/frontend/publish.ts
@@ -12,7 +12,6 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-import {time} from '../base/time';
import {Actions} from '../common/actions';
import {AggregateData} from '../common/aggregation_data';
import {ConversionJobStatusUpdate} from '../common/conversion_jobs';
@@ -32,6 +31,7 @@
SliceDetails,
ThreadDesc,
ThreadStateDetails,
+ TraceTime,
} from './globals';
import {findCurrentSelection} from './keyboard_event_handler';
@@ -96,14 +96,8 @@
globals.publishRedraw();
}
-export function publishRealtimeOffset(
- offset: time,
- utcOffset: time,
- traceTzOffset: time,
-) {
- globals.realtimeOffset = offset;
- globals.utcOffset = utcOffset;
- globals.traceTzOffset = traceTzOffset;
+export function publishTraceDetails(details: TraceTime): void {
+ globals.traceTime = details;
globals.publishRedraw();
}
diff --git a/ui/src/frontend/query_page.ts b/ui/src/frontend/query_page.ts
index 7afcbaf..80b8858 100644
--- a/ui/src/frontend/query_page.ts
+++ b/ui/src/frontend/query_page.ts
@@ -19,7 +19,7 @@
import {undoCommonChatAppReplacements} from '../base/string_utils';
import {QueryResponse, runQuery} from '../common/queries';
import {raf} from '../core/raf_scheduler';
-import {EngineProxy} from '../trace_processor/engine';
+import {Engine} from '../trace_processor/engine';
import {Callout} from '../widgets/callout';
import {Editor} from '../widgets/editor';
@@ -71,7 +71,7 @@
raf.scheduleDelayedFullRedraw();
}
-function getEngine(): EngineProxy | undefined {
+function getEngine(): Engine | undefined {
const engineId = globals.getCurrentEngine()?.id;
if (engineId === undefined) {
return undefined;
diff --git a/ui/src/frontend/query_result_tab.ts b/ui/src/frontend/query_result_tab.ts
index 7fe7b2d..e6feda3 100644
--- a/ui/src/frontend/query_result_tab.ts
+++ b/ui/src/frontend/query_result_tab.ts
@@ -32,7 +32,7 @@
import {globals} from './globals';
import {Actions} from '../common/actions';
import {BottomTabToTabAdapter} from '../public/utils';
-import {EngineProxy} from '../public';
+import {Engine} from '../public';
interface QueryResultTabConfig {
readonly query: string;
@@ -66,7 +66,7 @@
}
// TODO(stevegolton): Find a way to make this more elegant.
-function getEngine(): EngineProxy {
+function getEngine(): Engine {
const engConfig = globals.getCurrentEngine();
const engineId = assertExists(engConfig).id;
return assertExists(globals.engines.get(engineId)).getProxy('QueryResult');
diff --git a/ui/src/frontend/sidebar.ts b/ui/src/frontend/sidebar.ts
index be1d20e..1cedf6a 100644
--- a/ui/src/frontend/sidebar.ts
+++ b/ui/src/frontend/sidebar.ts
@@ -29,7 +29,7 @@
import {featureFlags} from '../core/feature_flags';
import {raf} from '../core/raf_scheduler';
import {SCM_REVISION, VERSION} from '../gen/perfetto_version';
-import {Engine} from '../trace_processor/engine';
+import {EngineBase} from '../trace_processor/engine';
import {showModal} from '../widgets/modal';
import {Animation} from './animation';
@@ -566,7 +566,7 @@
downloadUrl(fileName, url);
}
-function getCurrentEngine(): Engine | undefined {
+function getCurrentEngine(): EngineBase | undefined {
const engineId = globals.getCurrentEngine()?.id;
if (engineId === undefined) return undefined;
return globals.engines.get(engineId);
diff --git a/ui/src/frontend/simple_counter_track.ts b/ui/src/frontend/simple_counter_track.ts
index 361480b..5b21ded 100644
--- a/ui/src/frontend/simple_counter_track.ts
+++ b/ui/src/frontend/simple_counter_track.ts
@@ -13,7 +13,7 @@
// limitations under the License.
import m from 'mithril';
-import {EngineProxy, TrackContext} from '../public';
+import {Engine, TrackContext} from '../public';
import {BaseCounterTrack, CounterOptions} from './base_counter_track';
import {CounterColumns, SqlDataSource} from './debug_tracks';
import {Disposable, DisposableCallback} from '../base/disposable';
@@ -30,7 +30,7 @@
private sqlTableName: string;
constructor(
- engine: EngineProxy,
+ engine: Engine,
ctx: TrackContext,
config: SimpleCounterTrackConfig,
) {
diff --git a/ui/src/frontend/simple_slice_track.ts b/ui/src/frontend/simple_slice_track.ts
index f46812f..c292fe6 100644
--- a/ui/src/frontend/simple_slice_track.ts
+++ b/ui/src/frontend/simple_slice_track.ts
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-import {EngineProxy, TrackContext} from '../public';
+import {Engine, TrackContext} from '../public';
import {
CustomSqlDetailsPanelConfig,
CustomSqlTableDefConfig,
@@ -35,7 +35,7 @@
private sqlTableName: string;
constructor(
- engine: EngineProxy,
+ engine: Engine,
ctx: TrackContext,
config: SimpleSliceTrackConfig,
) {
diff --git a/ui/src/frontend/slice_args.ts b/ui/src/frontend/slice_args.ts
index 97b3b6f..ec9d609 100644
--- a/ui/src/frontend/slice_args.ts
+++ b/ui/src/frontend/slice_args.ts
@@ -22,7 +22,7 @@
import {Actions, AddTrackArgs} from '../common/actions';
import {InThreadTrackSortKey} from '../common/state';
import {ArgNode, convertArgsToTree, Key} from '../controller/args_parser';
-import {EngineProxy} from '../trace_processor/engine';
+import {Engine} from '../trace_processor/engine';
import {NUM} from '../trace_processor/query_result';
import {
VISUALISED_ARGS_SLICE_TRACK_URI,
@@ -39,7 +39,7 @@
import {assertExists} from '../base/logging';
// Renders slice arguments (key/value pairs) as a subtree.
-export function renderArguments(engine: EngineProxy, args: Arg[]): m.Children {
+export function renderArguments(engine: Engine, args: Arg[]): m.Children {
if (args.length > 0) {
const tree = convertArgsToTree(args);
return renderArgTreeNodes(engine, tree);
@@ -52,10 +52,7 @@
return exists(args) && args.length > 0;
}
-function renderArgTreeNodes(
- engine: EngineProxy,
- args: ArgNode<Arg>[],
-): m.Children {
+function renderArgTreeNodes(engine: Engine, args: ArgNode<Arg>[]): m.Children {
return args.map((arg) => {
const {key, value, children} = arg;
if (children && children.length === 1) {
@@ -80,11 +77,7 @@
});
}
-function renderArgKey(
- engine: EngineProxy,
- key: string,
- value?: Arg,
-): m.Children {
+function renderArgKey(engine: Engine, key: string, value?: Arg): m.Children {
if (value === undefined) {
return key;
} else {
@@ -125,7 +118,7 @@
}
}
-async function addVisualisedArg(engine: EngineProxy, argName: string) {
+async function addVisualisedArg(engine: Engine, argName: string) {
const escapedArgName = argName.replace(/[^a-zA-Z]/g, '_');
const tableName = `__arg_visualisation_helper_${escapedArgName}_slice`;
diff --git a/ui/src/frontend/sql/args.ts b/ui/src/frontend/sql/args.ts
index 2cf051c..f36f253 100644
--- a/ui/src/frontend/sql/args.ts
+++ b/ui/src/frontend/sql/args.ts
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-import {EngineProxy} from '../../trace_processor/engine';
+import {Engine} from '../../trace_processor/engine';
import {
LONG_NULL,
NUM,
@@ -42,7 +42,7 @@
}
export async function getArgs(
- engine: EngineProxy,
+ engine: Engine,
argSetId: ArgSetId,
): Promise<Arg[]> {
const query = await engine.query(`
diff --git a/ui/src/frontend/sql/details/details.ts b/ui/src/frontend/sql/details/details.ts
index 42b500d..d244747 100644
--- a/ui/src/frontend/sql/details/details.ts
+++ b/ui/src/frontend/sql/details/details.ts
@@ -18,7 +18,7 @@
import {Time} from '../../../base/time';
import {exists} from '../../../base/utils';
import {raf} from '../../../core/raf_scheduler';
-import {EngineProxy} from '../../../public';
+import {Engine} from '../../../public';
import {Row, SqlValue} from '../../../trace_processor/query_result';
import {Anchor} from '../../../widgets/anchor';
import {renderError} from '../../../widgets/error';
@@ -202,7 +202,7 @@
// Class responsible for fetching the data and rendering the data.
export class Details {
constructor(
- private engine: EngineProxy,
+ private engine: Engine,
private sqlTable: string,
private id: number,
schema: {[key: string]: ValueDesc},
@@ -278,14 +278,14 @@
// async `fetch` step for fetching data and sync `render` step for generating
// the vdom.
export type SqlIdRefRenderer = {
- fetch: (engine: EngineProxy, id: bigint) => Promise<{} | undefined>;
+ fetch: (engine: Engine, id: bigint) => Promise<{} | undefined>;
render: (data: {}) => RenderedValue;
};
// Type-safe helper to create a SqlIdRefRenderer, which ensures that the
// type returned from the fetch is the same type that renderer takes.
export function createSqlIdRefRenderer<Data extends {}>(
- fetch: (engine: EngineProxy, id: bigint) => Promise<Data>,
+ fetch: (engine: Engine, id: bigint) => Promise<Data>,
render: (data: Data) => RenderedValue,
): SqlIdRefRenderer {
return {fetch, render: render as (data: {}) => RenderedValue};
@@ -451,7 +451,7 @@
data?: Data;
constructor(
- private engine: EngineProxy,
+ private engine: Engine,
private sqlTable: string,
private id: number,
public sqlIdRefRenderers: {[table: string]: SqlIdRefRenderer},
@@ -652,7 +652,7 @@
// Generate the vdom for a given value using the fetched `data`.
function renderValue(
- engine: EngineProxy,
+ engine: Engine,
key: string,
value: ResolvedValue,
data: Data,
diff --git a/ui/src/frontend/sql/slice.ts b/ui/src/frontend/sql/slice.ts
index 050ec4e..bf35774 100644
--- a/ui/src/frontend/sql/slice.ts
+++ b/ui/src/frontend/sql/slice.ts
@@ -18,7 +18,7 @@
import {Icons} from '../../base/semantic_icons';
import {duration, Time, time} from '../../base/time';
import {exists} from '../../base/utils';
-import {EngineProxy} from '../../trace_processor/engine';
+import {Engine} from '../../trace_processor/engine';
import {
LONG,
LONG_NULL,
@@ -68,7 +68,7 @@
}
async function getUtidAndUpid(
- engine: EngineProxy,
+ engine: Engine,
sqlTrackId: number,
): Promise<{utid?: Utid; upid?: Upid}> {
const columnInfo = (
@@ -118,7 +118,7 @@
}
export async function getSliceFromConstraints(
- engine: EngineProxy,
+ engine: Engine,
constraints: SQLConstraints,
): Promise<SliceDetails[]> {
const query = await engine.query(`
@@ -186,7 +186,7 @@
}
export async function getSlice(
- engine: EngineProxy,
+ engine: Engine,
id: SliceSqlId,
): Promise<SliceDetails | undefined> {
const result = await getSliceFromConstraints(engine, {
@@ -272,7 +272,7 @@
// Get all descendants for a given slice in a tree form.
export async function getDescendantSliceTree(
- engine: EngineProxy,
+ engine: Engine,
id: SliceSqlId,
): Promise<SliceTreeNode | undefined> {
const slice = await getSlice(engine, id);
diff --git a/ui/src/frontend/sql/thread_state.ts b/ui/src/frontend/sql/thread_state.ts
index e47a5c1..7009a6f 100644
--- a/ui/src/frontend/sql/thread_state.ts
+++ b/ui/src/frontend/sql/thread_state.ts
@@ -15,7 +15,7 @@
import m from 'mithril';
import {duration, TimeSpan} from '../../base/time';
-import {EngineProxy} from '../../public';
+import {Engine} from '../../public';
import {
LONG,
NUM_NULL,
@@ -67,7 +67,7 @@
// Compute a breakdown of thread states for a given thread for a given time
// interval.
export async function breakDownIntervalByThreadState(
- engine: EngineProxy,
+ engine: Engine,
range: TimeSpan,
utid: Utid,
): Promise<BreakdownByThreadState> {
diff --git a/ui/src/frontend/sql_table/argument_selector.ts b/ui/src/frontend/sql_table/argument_selector.ts
index 29b4281..039cc0a 100644
--- a/ui/src/frontend/sql_table/argument_selector.ts
+++ b/ui/src/frontend/sql_table/argument_selector.ts
@@ -15,7 +15,7 @@
import m from 'mithril';
import {raf} from '../../core/raf_scheduler';
-import {EngineProxy} from '../../trace_processor/engine';
+import {Engine} from '../../trace_processor/engine';
import {STR} from '../../trace_processor/query_result';
import {FilterableSelect} from '../../widgets/select';
import {Spinner} from '../../widgets/spinner';
@@ -31,7 +31,7 @@
const MAX_ARGS_TO_DISPLAY = 15;
interface ArgumentSelectorAttrs {
- engine: EngineProxy;
+ engine: Engine;
argSetId: ArgSetIdColumn;
tableName: string;
constraints: SQLConstraints;
diff --git a/ui/src/frontend/sql_table/state.ts b/ui/src/frontend/sql_table/state.ts
index 96118f5..2093dad 100644
--- a/ui/src/frontend/sql_table/state.ts
+++ b/ui/src/frontend/sql_table/state.ts
@@ -17,7 +17,7 @@
import {isString} from '../../base/object_utils';
import {sqliteString} from '../../base/string_utils';
import {raf} from '../../core/raf_scheduler';
-import {EngineProxy} from '../../trace_processor/engine';
+import {Engine} from '../../trace_processor/engine';
import {NUM, Row} from '../../trace_processor/query_result';
import {
constraintsToQueryPrefix,
@@ -76,7 +76,7 @@
}
export class SqlTableState {
- private readonly engine_: EngineProxy;
+ private readonly engine_: Engine;
private readonly table_: SqlTableDescription;
private readonly additionalImports: string[];
@@ -95,7 +95,7 @@
private rowCount?: RowCount;
constructor(
- engine: EngineProxy,
+ engine: Engine,
table: SqlTableDescription,
filters?: Filter[],
imports?: string[],
diff --git a/ui/src/frontend/sql_table/state_unittest.ts b/ui/src/frontend/sql_table/state_unittest.ts
index 91d96a2..ebb20b5 100644
--- a/ui/src/frontend/sql_table/state_unittest.ts
+++ b/ui/src/frontend/sql_table/state_unittest.ts
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-import {Engine, EngineProxy} from '../../trace_processor/engine';
+import {EngineBase} from '../../trace_processor/engine';
import {Column} from './column';
import {SqlTableState} from './state';
@@ -44,14 +44,14 @@
],
};
-class FakeEngine extends Engine {
+class FakeEngine extends EngineBase {
id: string = 'TestEngine';
rpcSendRequestBytes(_data: Uint8Array) {}
}
test('sqlTableState: columnManupulation', () => {
- const engine = new EngineProxy(new FakeEngine(), 'test');
+ const engine = new FakeEngine();
const state = new SqlTableState(engine, table);
const idColumn = {
@@ -88,7 +88,7 @@
});
test('sqlTableState: sortedColumns', () => {
- const engine = new EngineProxy(new FakeEngine(), 'test');
+ const engine = new FakeEngine();
const state = new SqlTableState(engine, table);
// Verify that we have two columns: "id" and "name" and
@@ -139,7 +139,7 @@
}
test('sqlTableState: sqlStatement', () => {
- const engine = new EngineProxy(new FakeEngine(), 'test');
+ const engine = new FakeEngine();
const state = new SqlTableState(engine, table);
// Check the generated SQL statement.
diff --git a/ui/src/frontend/sql_table/tab.ts b/ui/src/frontend/sql_table/tab.ts
index 4267331..a91eee4 100644
--- a/ui/src/frontend/sql_table/tab.ts
+++ b/ui/src/frontend/sql_table/tab.ts
@@ -25,7 +25,7 @@
import {Filter, SqlTableState} from './state';
import {SqlTable} from './table';
import {SqlTableDescription, tableDisplayName} from './table_description';
-import {EngineProxy} from '../../public';
+import {Engine} from '../../public';
import {globals} from '../globals';
import {assertExists} from '../../base/logging';
import {uuidv4} from '../../base/uuid';
@@ -58,7 +58,7 @@
}
// TODO(stevegolton): Find a way to make this more elegant.
-function getEngine(): EngineProxy {
+function getEngine(): Engine {
const engConfig = globals.getCurrentEngine();
const engineId = assertExists(engConfig).id;
return assertExists(globals.engines.get(engineId)).getProxy('QueryResult');
diff --git a/ui/src/frontend/sql_table/table.ts b/ui/src/frontend/sql_table/table.ts
index d0db696..35e620f 100644
--- a/ui/src/frontend/sql_table/table.ts
+++ b/ui/src/frontend/sql_table/table.ts
@@ -16,7 +16,7 @@
import {isString} from '../../base/object_utils';
import {Icons} from '../../base/semantic_icons';
-import {EngineProxy} from '../../trace_processor/engine';
+import {Engine} from '../../trace_processor/engine';
import {Row} from '../../trace_processor/query_result';
import {Anchor} from '../../widgets/anchor';
import {BasicTable} from '../../widgets/basic_table';
@@ -37,7 +37,7 @@
export class SqlTable implements m.ClassComponent<SqlTableConfig> {
private readonly table: SqlTableDescription;
- private readonly engine: EngineProxy;
+ private readonly engine: Engine;
private state: SqlTableState;
diff --git a/ui/src/frontend/sql_utils.ts b/ui/src/frontend/sql_utils.ts
index 891a876..a78a88a 100644
--- a/ui/src/frontend/sql_utils.ts
+++ b/ui/src/frontend/sql_utils.ts
@@ -14,7 +14,7 @@
import {isString} from '../base/object_utils';
import {SortDirection} from '../common/state';
-import {EngineProxy} from '../trace_processor/engine';
+import {Engine} from '../trace_processor/engine';
import {ColumnType, NUM} from '../trace_processor/query_result';
export interface OrderClause {
@@ -111,7 +111,7 @@
}
export async function getTableRowCount(
- engine: EngineProxy,
+ engine: Engine,
tableName: string,
): Promise<number | undefined> {
const result = await engine.query(
diff --git a/ui/src/frontend/thread_and_process_info.ts b/ui/src/frontend/thread_and_process_info.ts
index b54cb45..2e70b29 100644
--- a/ui/src/frontend/thread_and_process_info.ts
+++ b/ui/src/frontend/thread_and_process_info.ts
@@ -17,7 +17,7 @@
import {copyToClipboard} from '../base/clipboard';
import {Icons} from '../base/semantic_icons';
import {exists} from '../base/utils';
-import {EngineProxy} from '../trace_processor/engine';
+import {Engine} from '../trace_processor/engine';
import {NUM, NUM_NULL, STR, STR_NULL} from '../trace_processor/query_result';
import {Anchor} from '../widgets/anchor';
import {MenuItem, PopupMenu2} from '../widgets/menu';
@@ -43,7 +43,7 @@
}
export async function getProcessInfo(
- engine: EngineProxy,
+ engine: Engine,
upid: Upid,
): Promise<ProcessInfo> {
const it = (
@@ -137,7 +137,7 @@
}
export async function getThreadInfo(
- engine: EngineProxy,
+ engine: Engine,
utid: Utid,
): Promise<ThreadInfo> {
const it = (
diff --git a/ui/src/frontend/thread_state.ts b/ui/src/frontend/thread_state.ts
index e912a7e..8a3d0ec 100644
--- a/ui/src/frontend/thread_state.ts
+++ b/ui/src/frontend/thread_state.ts
@@ -19,7 +19,7 @@
import {exists} from '../base/utils';
import {Actions} from '../common/actions';
import {translateState} from '../common/thread_state';
-import {EngineProxy} from '../trace_processor/engine';
+import {Engine} from '../trace_processor/engine';
import {LONG, NUM, NUM_NULL, STR_NULL} from '../trace_processor/query_result';
import {CPU_SLICE_TRACK_KIND} from '../core_plugins/cpu_slices';
import {THREAD_STATE_TRACK_KIND} from '../core_plugins/thread_state';
@@ -59,7 +59,7 @@
// Gets a list of thread state objects from Trace Processor with given
// constraints.
export async function getThreadStateFromConstraints(
- engine: EngineProxy,
+ engine: Engine,
constraints: SQLConstraints,
): Promise<ThreadState[]> {
const query = await engine.query(`
@@ -120,7 +120,7 @@
}
export async function getThreadState(
- engine: EngineProxy,
+ engine: Engine,
id: number,
): Promise<ThreadState | undefined> {
const result = await getThreadStateFromConstraints(engine, {
diff --git a/ui/src/frontend/time_axis_panel.ts b/ui/src/frontend/time_axis_panel.ts
index d20341f..af1f3df 100644
--- a/ui/src/frontend/time_axis_panel.ts
+++ b/ui/src/frontend/time_axis_panel.ts
@@ -57,16 +57,16 @@
break;
case TimestampFormat.UTC:
const offsetDate = Time.toDate(
- globals.utcOffset,
- globals.realtimeOffset,
+ globals.traceTime.utcOffset,
+ globals.traceTime.realtimeOffset,
);
const dateStr = toISODateOnly(offsetDate);
ctx.fillText(`UTC ${dateStr}`, 6, 10);
break;
case TimestampFormat.TraceTz:
const offsetTzDate = Time.toDate(
- globals.traceTzOffset,
- globals.realtimeOffset,
+ globals.traceTime.traceTzOffset,
+ globals.traceTime.realtimeOffset,
);
const dateTzStr = toISODateOnly(offsetTzDate);
ctx.fillText(dateTzStr, 6, 10);
diff --git a/ui/src/frontend/trace_info_page.ts b/ui/src/frontend/trace_info_page.ts
index 485146a..c8d7547 100644
--- a/ui/src/frontend/trace_info_page.ts
+++ b/ui/src/frontend/trace_info_page.ts
@@ -16,7 +16,7 @@
import {QueryResponse, runQuery} from '../common/queries';
import {raf} from '../core/raf_scheduler';
-import {EngineProxy} from '../trace_processor/engine';
+import {Engine} from '../trace_processor/engine';
import {globals} from './globals';
import {createPage} from './pages';
@@ -29,7 +29,7 @@
queryId: string;
}
-function getEngine(name: string): EngineProxy | undefined {
+function getEngine(name: string): Engine | undefined {
const currentEngine = globals.getCurrentEngine();
if (currentEngine === undefined) return undefined;
const engineId = currentEngine.id;
diff --git a/ui/src/frontend/track.ts b/ui/src/frontend/track.ts
index cd11ce3..c6462b0 100644
--- a/ui/src/frontend/track.ts
+++ b/ui/src/frontend/track.ts
@@ -12,9 +12,9 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-import {EngineProxy} from '../trace_processor/engine';
+import {Engine} from '../trace_processor/engine';
export interface NewTrackArgs {
trackKey: string;
- engine: EngineProxy;
+ engine: Engine;
}
diff --git a/ui/src/frontend/viewer_page.ts b/ui/src/frontend/viewer_page.ts
index b599dc7..b67f2e5 100644
--- a/ui/src/frontend/viewer_page.ts
+++ b/ui/src/frontend/viewer_page.ts
@@ -128,7 +128,7 @@
currentY: number,
editing: boolean,
) => {
- const traceTime = globals.state.traceTime;
+ const traceTime = globals.traceTime;
const {visibleTimeScale} = timeline;
this.keepCurrentSelection = true;
if (editing) {
diff --git a/ui/src/frontend/viz_page.ts b/ui/src/frontend/viz_page.ts
index dadb34a..6145763 100644
--- a/ui/src/frontend/viz_page.ts
+++ b/ui/src/frontend/viz_page.ts
@@ -15,14 +15,14 @@
import m from 'mithril';
import {raf} from '../core/raf_scheduler';
-import {EngineProxy} from '../trace_processor/engine';
+import {Engine} from '../trace_processor/engine';
import {Editor} from '../widgets/editor';
import {VegaView} from '../widgets/vega_view';
import {globals} from './globals';
import {createPage} from './pages';
-function getEngine(): EngineProxy | undefined {
+function getEngine(): Engine | undefined {
const engineId = globals.getCurrentEngine()?.id;
if (engineId === undefined) {
return undefined;
@@ -32,7 +32,7 @@
}
let SPEC = '';
-let ENGINE: EngineProxy | undefined = undefined;
+let ENGINE: Engine | undefined = undefined;
export const VizPage = createPage({
oncreate() {
diff --git a/ui/src/plugins/dev.perfetto.AndroidLongBatteryTracing/index.ts b/ui/src/plugins/dev.perfetto.AndroidLongBatteryTracing/index.ts
index 2a22aff..8f360b4 100644
--- a/ui/src/plugins/dev.perfetto.AndroidLongBatteryTracing/index.ts
+++ b/ui/src/plugins/dev.perfetto.AndroidLongBatteryTracing/index.ts
@@ -13,7 +13,7 @@
// limitations under the License.
import {Plugin, PluginContextTrace, PluginDescriptor} from '../../public';
-import {EngineProxy} from '../../trace_processor/engine';
+import {Engine} from '../../trace_processor/engine';
import {
SimpleSliceTrack,
SimpleSliceTrackConfig,
@@ -1694,7 +1694,7 @@
);
}
- async findFeatures(e: EngineProxy): Promise<Set<string>> {
+ async findFeatures(e: Engine): Promise<Set<string>> {
const features = new Set<string>();
const addFeatures = async (q: string) => {
diff --git a/ui/src/plugins/dev.perfetto.AndroidNetwork/index.ts b/ui/src/plugins/dev.perfetto.AndroidNetwork/index.ts
index 9cb8405..34fd087 100644
--- a/ui/src/plugins/dev.perfetto.AndroidNetwork/index.ts
+++ b/ui/src/plugins/dev.perfetto.AndroidNetwork/index.ts
@@ -14,14 +14,14 @@
import {Plugin, PluginContextTrace, PluginDescriptor} from '../../public';
import {addDebugSliceTrack} from '../../public';
-import {EngineProxy} from '../../trace_processor/engine';
+import {Engine} from '../../trace_processor/engine';
class AndroidNetwork implements Plugin {
// Adds a debug track using the provided query and given columns. The columns
// must be start with ts, dur, and a name column. The name column and all
// following columns are shown as arguments in slice details.
async addSimpleTrack(
- engine: EngineProxy,
+ engine: Engine,
trackName: string,
tableOrQuery: string,
columns: string[],
diff --git a/ui/src/plugins/dev.perfetto.AndroidPerf/index.ts b/ui/src/plugins/dev.perfetto.AndroidPerf/index.ts
index a53ff20..25f11f4 100644
--- a/ui/src/plugins/dev.perfetto.AndroidPerf/index.ts
+++ b/ui/src/plugins/dev.perfetto.AndroidPerf/index.ts
@@ -18,11 +18,11 @@
PluginContextTrace,
PluginDescriptor,
} from '../../public';
-import {EngineProxy} from '../../trace_processor/engine';
+import {Engine} from '../../trace_processor/engine';
class AndroidPerf implements Plugin {
async addAppProcessStartsDebugTrack(
- engine: EngineProxy,
+ engine: Engine,
reason: string,
sliceName: string,
): Promise<void> {
diff --git a/ui/src/public/index.ts b/ui/src/public/index.ts
index f3e4338..7fb2e44 100644
--- a/ui/src/public/index.ts
+++ b/ui/src/public/index.ts
@@ -20,10 +20,10 @@
import {ColorScheme} from '../core/colorizer';
import {LegacySelection} from '../common/state';
import {PanelSize} from '../frontend/panel';
-import {EngineProxy} from '../trace_processor/engine';
+import {Engine} from '../trace_processor/engine';
import {UntypedEventSet} from '../core/event_set';
-export {EngineProxy} from '../trace_processor/engine';
+export {Engine} from '../trace_processor/engine';
export {
LONG,
LONG_NULL,
@@ -344,7 +344,7 @@
// currently loaded trace. Passed to trace-relevant hooks on a plugin instead of
// PluginContext.
export interface PluginContextTrace extends PluginContext {
- readonly engine: EngineProxy;
+ readonly engine: Engine;
// Control over the main timeline.
timeline: {
diff --git a/ui/src/trace_processor/engine.ts b/ui/src/trace_processor/engine.ts
index b234c16..90901c5 100644
--- a/ui/src/trace_processor/engine.ts
+++ b/ui/src/trace_processor/engine.ts
@@ -13,7 +13,6 @@
// limitations under the License.
import {defer, Deferred} from '../base/deferred';
-import {Disposable} from '../base/disposable';
import {assertExists, assertTrue} from '../base/logging';
import {duration, Span, Time, time, TimeSpan} from '../base/time';
import {
@@ -42,6 +41,7 @@
} from './query_result';
import TPM = TraceProcessorRpc.TraceProcessorMethod;
+import {Disposable} from '../base/disposable';
export interface LoadingTracker {
beginLoading(): void;
@@ -66,6 +66,19 @@
ftraceDropUntilAllCpusValid: boolean;
}
+export interface Engine {
+ execute(sqlQuery: string, tag?: string): Promise<QueryResult> & QueryResult;
+ query(sqlQuery: string, tag?: string): Promise<QueryResult>;
+ getCpus(): Promise<number[]>;
+ getNumberOfGpus(): Promise<number>;
+ getTracingMetadataTimeBounds(): Promise<Span<time, duration>>;
+ computeMetric(
+ metrics: string[],
+ format: 'json' | 'prototext' | 'proto',
+ ): Promise<string | Uint8Array>;
+ readonly isAlive: boolean;
+}
+
// Abstract interface of a trace proccessor.
// This is the TypeScript equivalent of src/trace_processor/rpc.h.
// There are two concrete implementations:
@@ -77,7 +90,7 @@
// 1. Implement the abstract rpcSendRequestBytes() function, sending the
// proto-encoded TraceProcessorRpc requests to the TraceProcessor instance.
// 2. Call onRpcResponseBytes() when response data is received.
-export abstract class Engine {
+export abstract class EngineBase implements Engine {
abstract readonly id: string;
private _cpus?: number[];
private _numGpus?: number;
@@ -93,6 +106,7 @@
private pendingComputeMetrics = new Array<Deferred<string | Uint8Array>>();
private pendingReadMetatrace?: Deferred<DisableAndReadMetatraceResult>;
private _isMetatracingEnabled = false;
+ readonly isAlive = false;
constructor(tracker?: LoadingTracker) {
this.loadingTracker = tracker ? tracker : new NullLoadingTracker();
@@ -502,10 +516,9 @@
}
}
-// Lightweight wrapper over Engine exposing only `query` method and annotating
-// all queries going through it with a tag.
-export class EngineProxy implements Disposable {
- private engine: Engine;
+// Lightweight engine proxy which annotates all queries with a tag
+export class EngineProxy implements Engine, Disposable {
+ private engine: EngineBase;
private tag: string;
private _isAlive: boolean;
@@ -513,7 +526,7 @@
return this._isAlive;
}
- constructor(engine: Engine, tag: string) {
+ constructor(engine: EngineBase, tag: string) {
this.engine = engine;
this.tag = tag;
this._isAlive = true;
@@ -557,6 +570,10 @@
return this.engine.getNumberOfGpus();
}
+ async getTracingMetadataTimeBounds(): Promise<Span<time, bigint>> {
+ return this.engine.getTracingMetadataTimeBounds();
+ }
+
get engineId(): string {
return this.engine.id;
}
diff --git a/ui/src/trace_processor/http_rpc_engine.ts b/ui/src/trace_processor/http_rpc_engine.ts
index dfd9bc8..720e2b6 100644
--- a/ui/src/trace_processor/http_rpc_engine.ts
+++ b/ui/src/trace_processor/http_rpc_engine.ts
@@ -15,7 +15,7 @@
import {fetchWithTimeout} from '../base/http_utils';
import {assertExists} from '../base/logging';
import {StatusResult} from '../protos';
-import {Engine, LoadingTracker} from '../trace_processor/engine';
+import {EngineBase, LoadingTracker} from '../trace_processor/engine';
const RPC_CONNECT_TIMEOUT_MS = 2000;
@@ -25,7 +25,7 @@
failure?: string;
}
-export class HttpRpcEngine extends Engine {
+export class HttpRpcEngine extends EngineBase {
readonly id: string;
errorHandler: (err: string) => void = () => {};
private requestQueue = new Array<Uint8Array>();
diff --git a/ui/src/trace_processor/wasm_engine_proxy.ts b/ui/src/trace_processor/wasm_engine_proxy.ts
index 42740e2..163fac5 100644
--- a/ui/src/trace_processor/wasm_engine_proxy.ts
+++ b/ui/src/trace_processor/wasm_engine_proxy.ts
@@ -13,7 +13,7 @@
// limitations under the License.
import {assertExists, assertTrue} from '../base/logging';
-import {Engine, LoadingTracker} from '../trace_processor/engine';
+import {EngineBase, LoadingTracker} from '../trace_processor/engine';
let bundlePath: string;
let idleWasmWorker: Worker;
@@ -47,7 +47,7 @@
* This implementation of Engine uses a WASM backend hosted in a separate
* worker thread.
*/
-export class WasmEngineProxy extends Engine {
+export class WasmEngineProxy extends EngineBase {
readonly id: string;
private port: MessagePort;
diff --git a/ui/src/widgets/vega_view.ts b/ui/src/widgets/vega_view.ts
index 97d9826..39be606 100644
--- a/ui/src/widgets/vega_view.ts
+++ b/ui/src/widgets/vega_view.ts
@@ -20,7 +20,7 @@
import {getErrorMessage} from '../base/errors';
import {isString, shallowEquals} from '../base/object_utils';
import {SimpleResizeObserver} from '../base/resize_observer';
-import {EngineProxy} from '../trace_processor/engine';
+import {Engine} from '../trace_processor/engine';
import {QueryError} from '../trace_processor/query_result';
import {scheduleFullRedraw} from '../widgets/raf';
import {Spinner} from '../widgets/spinner';
@@ -45,7 +45,7 @@
interface VegaViewAttrs {
spec: string;
data: VegaViewData;
- engine?: EngineProxy;
+ engine?: Engine;
}
// VegaWrapper is in exactly one of these states:
@@ -62,10 +62,10 @@
}
class EngineLoader implements vega.Loader {
- private engine?: EngineProxy;
+ private engine?: Engine;
private loader: vega.Loader;
- constructor(engine: EngineProxy | undefined) {
+ constructor(engine: Engine | undefined) {
this.engine = engine;
this.loader = vega.loader();
}
@@ -125,7 +125,7 @@
private pending?: Promise<vega.View>;
private _status: Status;
private _error?: string;
- private _engine?: EngineProxy;
+ private _engine?: Engine;
constructor(dom: Element) {
this.dom = dom;
@@ -155,7 +155,7 @@
this.updateView();
}
- set engine(engine: EngineProxy | undefined) {
+ set engine(engine: Engine | undefined) {
this._engine = engine;
}