Merge "ui: Move aggregation tabs into details panel for area selections" into main
diff --git a/Android.bp b/Android.bp
index c81d04a..4541d4c 100644
--- a/Android.bp
+++ b/Android.bp
@@ -11100,12 +11100,10 @@
"src/trace_processor/importers/common/global_args_tracker.cc",
"src/trace_processor/importers/common/metadata_tracker.cc",
"src/trace_processor/importers/common/process_tracker.cc",
- "src/trace_processor/importers/common/sched_event_tracker.cc",
"src/trace_processor/importers/common/slice_tracker.cc",
"src/trace_processor/importers/common/slice_translation_table.cc",
"src/trace_processor/importers/common/stack_profile_tracker.cc",
"src/trace_processor/importers/common/system_info_tracker.cc",
- "src/trace_processor/importers/common/thread_state_tracker.cc",
"src/trace_processor/importers/common/trace_parser.cc",
"src/trace_processor/importers/common/track_tracker.cc",
],
@@ -11136,7 +11134,6 @@
"src/trace_processor/importers/common/process_tracker_unittest.cc",
"src/trace_processor/importers/common/slice_tracker_unittest.cc",
"src/trace_processor/importers/common/slice_translation_table_unittest.cc",
- "src/trace_processor/importers/common/thread_state_tracker_unittest.cc",
],
}
@@ -11165,13 +11162,14 @@
"src/trace_processor/importers/ftrace/drm_tracker.cc",
"src/trace_processor/importers/ftrace/ftrace_module_impl.cc",
"src/trace_processor/importers/ftrace/ftrace_parser.cc",
- "src/trace_processor/importers/ftrace/ftrace_sched_event_tracker.cc",
"src/trace_processor/importers/ftrace/ftrace_tokenizer.cc",
"src/trace_processor/importers/ftrace/gpu_work_period_tracker.cc",
"src/trace_processor/importers/ftrace/iostat_tracker.cc",
"src/trace_processor/importers/ftrace/mali_gpu_event_tracker.cc",
"src/trace_processor/importers/ftrace/pkvm_hyp_cpu_tracker.cc",
"src/trace_processor/importers/ftrace/rss_stat_tracker.cc",
+ "src/trace_processor/importers/ftrace/sched_event_tracker.cc",
+ "src/trace_processor/importers/ftrace/thread_state_tracker.cc",
"src/trace_processor/importers/ftrace/v4l2_tracker.cc",
"src/trace_processor/importers/ftrace/virtio_gpu_tracker.cc",
"src/trace_processor/importers/ftrace/virtio_video_tracker.cc",
@@ -11191,7 +11189,8 @@
name: "perfetto_src_trace_processor_importers_ftrace_unittests",
srcs: [
"src/trace_processor/importers/ftrace/binder_tracker_unittest.cc",
- "src/trace_processor/importers/ftrace/ftrace_sched_event_tracker_unittest.cc",
+ "src/trace_processor/importers/ftrace/sched_event_tracker_unittest.cc",
+ "src/trace_processor/importers/ftrace/thread_state_tracker_unittest.cc",
],
}
diff --git a/BUILD b/BUILD
index 071be0d..1e7c962 100644
--- a/BUILD
+++ b/BUILD
@@ -1471,9 +1471,6 @@
"src/trace_processor/importers/common/metadata_tracker.h",
"src/trace_processor/importers/common/process_tracker.cc",
"src/trace_processor/importers/common/process_tracker.h",
- "src/trace_processor/importers/common/sched_event_state.h",
- "src/trace_processor/importers/common/sched_event_tracker.cc",
- "src/trace_processor/importers/common/sched_event_tracker.h",
"src/trace_processor/importers/common/slice_tracker.cc",
"src/trace_processor/importers/common/slice_tracker.h",
"src/trace_processor/importers/common/slice_translation_table.cc",
@@ -1482,8 +1479,6 @@
"src/trace_processor/importers/common/stack_profile_tracker.h",
"src/trace_processor/importers/common/system_info_tracker.cc",
"src/trace_processor/importers/common/system_info_tracker.h",
- "src/trace_processor/importers/common/thread_state_tracker.cc",
- "src/trace_processor/importers/common/thread_state_tracker.h",
"src/trace_processor/importers/common/trace_parser.cc",
"src/trace_processor/importers/common/track_tracker.cc",
"src/trace_processor/importers/common/track_tracker.h",
@@ -1538,8 +1533,6 @@
"src/trace_processor/importers/ftrace/ftrace_module_impl.h",
"src/trace_processor/importers/ftrace/ftrace_parser.cc",
"src/trace_processor/importers/ftrace/ftrace_parser.h",
- "src/trace_processor/importers/ftrace/ftrace_sched_event_tracker.cc",
- "src/trace_processor/importers/ftrace/ftrace_sched_event_tracker.h",
"src/trace_processor/importers/ftrace/ftrace_tokenizer.cc",
"src/trace_processor/importers/ftrace/ftrace_tokenizer.h",
"src/trace_processor/importers/ftrace/gpu_work_period_tracker.cc",
@@ -1552,6 +1545,10 @@
"src/trace_processor/importers/ftrace/pkvm_hyp_cpu_tracker.h",
"src/trace_processor/importers/ftrace/rss_stat_tracker.cc",
"src/trace_processor/importers/ftrace/rss_stat_tracker.h",
+ "src/trace_processor/importers/ftrace/sched_event_tracker.cc",
+ "src/trace_processor/importers/ftrace/sched_event_tracker.h",
+ "src/trace_processor/importers/ftrace/thread_state_tracker.cc",
+ "src/trace_processor/importers/ftrace/thread_state_tracker.h",
"src/trace_processor/importers/ftrace/v4l2_tracker.cc",
"src/trace_processor/importers/ftrace/v4l2_tracker.h",
"src/trace_processor/importers/ftrace/virtio_gpu_tracker.cc",
diff --git a/src/trace_processor/importers/common/BUILD.gn b/src/trace_processor/importers/common/BUILD.gn
index 466876a..823edd8 100644
--- a/src/trace_processor/importers/common/BUILD.gn
+++ b/src/trace_processor/importers/common/BUILD.gn
@@ -40,9 +40,6 @@
"metadata_tracker.h",
"process_tracker.cc",
"process_tracker.h",
- "sched_event_state.h",
- "sched_event_tracker.cc",
- "sched_event_tracker.h",
"slice_tracker.cc",
"slice_tracker.h",
"slice_translation_table.cc",
@@ -51,8 +48,6 @@
"stack_profile_tracker.h",
"system_info_tracker.cc",
"system_info_tracker.h",
- "thread_state_tracker.cc",
- "thread_state_tracker.h",
"trace_parser.cc",
"track_tracker.cc",
"track_tracker.h",
@@ -110,7 +105,6 @@
"process_tracker_unittest.cc",
"slice_tracker_unittest.cc",
"slice_translation_table_unittest.cc",
- "thread_state_tracker_unittest.cc",
]
testonly = true
deps = [
diff --git a/src/trace_processor/importers/common/address_range.h b/src/trace_processor/importers/common/address_range.h
index 817ed9f..5d7f430 100644
--- a/src/trace_processor/importers/common/address_range.h
+++ b/src/trace_processor/importers/common/address_range.h
@@ -18,8 +18,10 @@
#define SRC_TRACE_PROCESSOR_IMPORTERS_COMMON_ADDRESS_RANGE_H_
#include <algorithm>
+
#include <cstdint>
#include <map>
+#include <set>
#include <tuple>
#include <utility>
@@ -33,6 +35,29 @@
// Note: This means that you can not have a range containing int64_max
class AddressRange {
public:
+ struct CompareByEnd {
+ // Allow heterogeneous lookups (https://abseil.io/tips/144)
+ using is_transparent = void;
+ // Keeps ranges sorted by end address
+ bool operator()(const AddressRange& lhs, const AddressRange& rhs) const {
+ return lhs.end() < rhs.end();
+ }
+
+ // Overload to implement PC lookup via upper_bound.
+ bool operator()(const AddressRange& lhs, uint64_t pc) const {
+ return lhs.end() < pc;
+ }
+
+ // Overload to implement PC lookup via upper_bound.
+ bool operator()(uint64_t pc, const AddressRange& rhs) const {
+ return pc < rhs.end();
+ }
+ };
+
+ static constexpr AddressRange FromStartAndSize(uint64_t start,
+ uint64_t size) {
+ return AddressRange(start, start + size);
+ }
constexpr AddressRange() : AddressRange(0, 0) {}
constexpr AddressRange(uint64_t start, uint64_t end)
@@ -62,7 +87,8 @@
// there exists a point such that Contains(point) would return true for both
// ranges.
constexpr bool Overlaps(const AddressRange& other) const {
- return start_ < other.end_ && other.start_ < end_;
+ return !empty() && !other.empty() && start_ < other.end_ &&
+ other.start_ < end_;
}
// Two ranges are the same is their respective limits are the same, that is A
@@ -91,49 +117,119 @@
uint64_t end_;
};
+// Contains unique collection of addresses. These addresses are kept as
+// sorted collection of non contiguous and non overlapping AddressRange
+// instances. As addresses are added or removed these AddressRange might be
+// merged or spliced as needed to keep the ranges non contiguous and non
+// overlapping.
+class AddressSet {
+ public:
+ // TODO(carlscab): Consider using base::FlatSet. As of now this class is used
+ // so little that it does not really matter.
+ using Impl = std::set<AddressRange, AddressRange::CompareByEnd>;
+
+ using value_type = typename Impl::value_type;
+ using const_iterator = typename Impl::const_iterator;
+ using size_type = typename Impl::size_type;
+
+ const_iterator begin() const { return ranges_.begin(); }
+ const_iterator end() const { return ranges_.end(); }
+
+ // Adds all the addresses in the given range to the set.
+ void Add(AddressRange range) {
+ if (range.empty()) {
+ return;
+ }
+ uint64_t start = range.start();
+ uint64_t end = range.end();
+ // Note lower_bound here as we might need to merge with the range just
+ // before.
+ auto it = ranges_.lower_bound(start);
+
+ PERFETTO_DCHECK(it == ranges_.end() || range.start() <= it->end());
+
+ while (it != ranges_.end() && range.end() >= it->start()) {
+ start = std::min(start, it->start());
+ end = std::max(end, it->end());
+ it = ranges_.erase(it);
+ }
+ ranges_.emplace_hint(it, AddressRange(start, end));
+ }
+
+ // Removes all the addresses in the given range from the set.
+ void Remove(AddressRange range) {
+ if (range.empty()) {
+ return;
+ }
+ auto it = ranges_.upper_bound(range.start());
+ PERFETTO_DCHECK(it == ranges_.end() || range.start() < it->end());
+
+ while (it != ranges_.end() && range.end() > it->start()) {
+ if (range.start() > it->start()) {
+ // range.start() is contained in *it. Split *it at range.start() into
+ // two ranges. Continue the loop at the second of them.
+ PERFETTO_DCHECK(it->Contains(range.start()));
+ auto old = *it;
+ it = ranges_.erase(it);
+ ranges_.emplace_hint(it, old.start(), range.start());
+ it = ranges_.emplace_hint(it, range.start(), old.end());
+ } else if (range.end() < it->end()) {
+ // range.end() is contained in *it. Split *it at range.end() into two
+ // ranges. The first of them needs to be deleted.
+ PERFETTO_DCHECK(it->Contains(range.end()));
+ auto old_end = it->end();
+ it = ranges_.erase(it);
+ ranges_.emplace_hint(it, range.end(), old_end);
+ } else {
+ // range fully contains *it, so it can be removed
+ PERFETTO_DCHECK(range.Contains(*it));
+ it = ranges_.erase(it);
+ }
+ }
+ }
+
+ bool operator==(const AddressSet& o) const { return ranges_ == o.ranges_; }
+ bool operator!=(const AddressSet& o) const { return ranges_ != o.ranges_; }
+
+ private:
+ // Invariants:
+ // * There are no overlapping ranges.
+ // * There are no empty ranges.
+ // * There are no two ranges a, b where a.end == b.start, that is there are
+ // no contiguous mappings.
+ // * Ranges are sorted by end
+ // Thus lookups are O(log N) and point lookups are trivial using upper_bound()
+ Impl ranges_;
+};
+
// Maps AddressRange instances to a given value. These AddressRange instances
// (basically the keys of the map) will never overlap, as insertions of
// overlapping ranges will always fail.
template <typename Value>
class AddressRangeMap {
public:
- struct CompareByEnd {
- // Allow heterogeneous lookups (https://abseil.io/tips/144)
- using is_transparent = void;
- // Keeps ranges sorted by end address
- bool operator()(const AddressRange& lhs, const AddressRange& rhs) const {
- return lhs.end() < rhs.end();
- }
-
- // Overload to implement PC lookup via upper_bound.
- bool operator()(const AddressRange& lhs, uint64_t pc) const {
- return lhs.end() < pc;
- }
-
- // Overload to implement PC lookup via upper_bound.
- bool operator()(uint64_t pc, const AddressRange& rhs) const {
- return pc < rhs.end();
- }
- };
-
- using Impl = std::map<AddressRange, Value, CompareByEnd>;
+ using Impl = std::map<AddressRange, Value, AddressRange::CompareByEnd>;
using value_type = typename Impl::value_type;
using iterator = typename Impl::iterator;
using const_iterator = typename Impl::const_iterator;
using size_type = typename Impl::size_type;
- // Fails if the new range overlaps with any existing one.
+ // Fails if the new range overlaps with any existing one or when inserting an
+ // empty range (as there is effectively no key to map from).
template <typename... Args>
- std::pair<iterator, bool> Emplace(AddressRange range, Args&&... args) {
+ bool Emplace(AddressRange range, Args&&... args) {
+ if (range.empty()) {
+ return false;
+ }
auto it = ranges_.upper_bound(range.start());
if (it != ranges_.end() && range.end() > it->first.start()) {
- return {it, false};
+ return false;
}
- return {ranges_.emplace_hint(
- it, std::piecewise_construct, std::forward_as_tuple(range),
- std::forward_as_tuple(std::forward<Args>(args)...)),
- true};
+ ranges_.emplace_hint(it, std::piecewise_construct,
+ std::forward_as_tuple(range),
+ std::forward_as_tuple(std::forward<Args>(args)...));
+ return true;
}
// Finds the map entry that fully contains the given `range` or `end()` if not
@@ -181,13 +277,15 @@
// Emplaces a new value into the map by first deleting all overlapping
// intervals. It takes an optional (set to nullptr to ignore) callback `cb`
// that will be called for each deleted map entry.
- // ATTENTION: `range` can not be empty. Supporting it would complicate things
- // too much for a not needed use case.
+ // Returns true on success, fails if the new range is empty (as there is
+ // effectively no key to map from).
template <typename Callback, typename... Args>
- void DeleteOverlapsAndEmplace(Callback cb,
+ bool DeleteOverlapsAndEmplace(Callback cb,
AddressRange range,
Args&&... args) {
- PERFETTO_CHECK(!range.empty());
+ if (range.empty()) {
+ return false;
+ }
auto it = ranges_.upper_bound(range.start());
PERFETTO_DCHECK(it == ranges_.end() || range.start() < it->first.end());
@@ -199,21 +297,38 @@
ranges_.emplace_hint(it, std::piecewise_construct,
std::forward_as_tuple(range),
std::forward_as_tuple(std::forward<Args>(args)...));
+ return true;
}
// Same as above but without a callback.
- template <typename Callback, typename... Args>
- void DeleteOverlapsAndEmplace(AddressRange range, Args&&... args) {
+ template <typename... Args>
+ bool DeleteOverlapsAndEmplace(AddressRange range, Args&&... args) {
struct NoOp {
void operator()(std::pair<const AddressRange, Value>&) {}
};
- DeleteOverlapsAndEmplace(NoOp(), range, std::forward<Args>(args)...);
+ return DeleteOverlapsAndEmplace(NoOp(), range, std::forward<Args>(args)...);
+ }
+
+ // Calls `cb` for each entry in the map that overlaps the given `range`. That
+ // is, there is a point so for which `AddressRange::Contains` returns true for
+ // both the entry and the given `range'
+ template <typename Callback>
+ void ForOverlaps(AddressRange range, Callback cb) {
+ if (range.empty()) {
+ return;
+ }
+ for (auto it = ranges_.upper_bound(range.start());
+ it != ranges_.end() && range.end() > it->first.start(); ++it) {
+ cb(*it);
+ }
}
private:
- // Invariant: There are no overlapping ranges.
- // Which makes lookups O(log N). Also, ranges are sorted by end which makes
- // point lookups trivial using upper_bound()
+ // Invariants:
+ // * There are no overlapping ranges.
+ // * There are no empty ranges.
+ // * Ranges are sorted by end
+ // Thus lookups are O(log N) and point lookups are trivial using upper_bound()
Impl ranges_;
};
diff --git a/src/trace_processor/importers/common/address_range_unittest.cc b/src/trace_processor/importers/common/address_range_unittest.cc
index 2ae43ff..35f67ae 100644
--- a/src/trace_processor/importers/common/address_range_unittest.cc
+++ b/src/trace_processor/importers/common/address_range_unittest.cc
@@ -38,6 +38,7 @@
namespace {
+using ::testing::_;
using ::testing::A;
using ::testing::AllOf;
using ::testing::ElementsAre;
@@ -49,6 +50,11 @@
using ::testing::Pointee;
using ::testing::SizeIs;
+MATCHER_P2(IteratorPointsTo, container, matcher, "") {
+ return ExplainMatchResult(Ne(container.end()), arg, result_listener) &&
+ ExplainMatchResult(matcher, *arg, result_listener);
+}
+
auto AppendRangesTo(std::vector<AddressRange>& ranges) {
return [&ranges](std::pair<const AddressRange, int>& e) {
ranges.push_back(e.first);
@@ -115,6 +121,18 @@
EXPECT_THAT(AddressRange(0, 10).IntersectWith(AddressRange()), IsEmpty());
}
+TEST(AddressRange, Overlap) {
+ EXPECT_FALSE(AddressRange(0, 10).Overlaps(AddressRange(5, 5)));
+ EXPECT_FALSE(AddressRange(5, 5).Overlaps(AddressRange(0, 10)));
+ EXPECT_FALSE(AddressRange(0, 10).Overlaps(AddressRange(10, 20)));
+ EXPECT_FALSE(AddressRange(10, 20).Overlaps(AddressRange(0, 10)));
+
+ EXPECT_TRUE(AddressRange(0, 10).Overlaps(AddressRange(9, 10)));
+ EXPECT_TRUE(AddressRange(10, 20).Overlaps(AddressRange(0, 11)));
+ EXPECT_TRUE(AddressRange(0, 10).Overlaps(AddressRange(5, 6)));
+ EXPECT_TRUE(AddressRange(0, 10).Overlaps(AddressRange(5, 20)));
+}
+
TEST(AddressRangeMap, Empty) {
AddressRangeMap<int> empty;
EXPECT_THAT(empty, IsEmpty());
@@ -122,25 +140,43 @@
TEST(AddressRangeMap, EmplaceFailsForOverlaps) {
AddressRangeMap<int> map;
- ASSERT_TRUE(map.Emplace(AddressRange(10, 20)).second);
+ ASSERT_TRUE(map.Emplace(AddressRange(10, 20), 42));
- EXPECT_FALSE(map.Emplace(AddressRange(10, 20)).second);
- EXPECT_FALSE(map.Emplace(AddressRange(11, 19)).second);
- EXPECT_FALSE(map.Emplace(AddressRange(0, 11)).second);
- EXPECT_FALSE(map.Emplace(AddressRange(19, 30)).second);
- EXPECT_THAT(map, SizeIs(1));
+ EXPECT_FALSE(map.Emplace(AddressRange(10, 20)));
+ EXPECT_FALSE(map.Emplace(AddressRange(11, 19)));
+ EXPECT_FALSE(map.Emplace(AddressRange(0, 11)));
+ EXPECT_FALSE(map.Emplace(AddressRange(19, 30)));
+ EXPECT_THAT(map, ElementsAre(Pair(AddressRange(10, 20), 42)));
}
TEST(AddressRangeMap, EmplaceSucceedsForNonOverlaps) {
AddressRangeMap<int> map;
- EXPECT_TRUE(map.Emplace(AddressRange(10, 20)).second);
- EXPECT_TRUE(map.Emplace(AddressRange(0, 10)).second);
- EXPECT_TRUE(map.Emplace(AddressRange(20, 30)).second);
+ EXPECT_TRUE(map.Emplace(AddressRange(10, 20)));
+ EXPECT_TRUE(map.Emplace(AddressRange(0, 10)));
+ EXPECT_TRUE(map.Emplace(AddressRange(20, 30)));
EXPECT_THAT(map, SizeIs(3));
}
+TEST(AddressRangeMap, EmplaceFailsForEmptyRange) {
+ AddressRangeMap<int> map;
+
+ EXPECT_FALSE(map.Emplace(AddressRange(0, 0)));
+ EXPECT_FALSE(map.Emplace(AddressRange(100, 100)));
+
+ EXPECT_THAT(map, IsEmpty());
+}
+
+TEST(AddressRangeMap, DeleteOverlapsAndEmplaceFailsForEmptyRange) {
+ AddressRangeMap<int> map;
+ EXPECT_TRUE(map.Emplace(AddressRange(0, 10), 42));
+ EXPECT_FALSE(map.Emplace(AddressRange(0, 0)));
+ EXPECT_FALSE(map.Emplace(AddressRange(100, 100)));
+
+ EXPECT_THAT(map, ElementsAre(Pair(AddressRange(0, 10), 42)));
+}
+
TEST(AddressRangeMap, FindAddress) {
AddressRangeMap<int> map;
map.Emplace(AddressRange(0, 10), 0);
@@ -174,30 +210,33 @@
TEST(AddressRangeMap, FindRangeThatContains) {
AddressRangeMap<int> map;
- const auto it_1 = map.Emplace(AddressRange(0, 10), 0).first;
- const auto it_2 = map.Emplace(AddressRange(10, 20), 1).first;
- const auto it_3 = map.Emplace(AddressRange(25, 30), 2).first;
- const auto end = map.end();
+ map.Emplace(AddressRange(0, 10), 0);
+ map.Emplace(AddressRange(10, 20), 1);
+ map.Emplace(AddressRange(25, 30), 2);
- EXPECT_THAT(map.FindRangeThatContains({0, 10}), Eq(it_1));
- EXPECT_THAT(map.FindRangeThatContains({0, 1}), Eq(it_1));
- EXPECT_THAT(map.FindRangeThatContains({3, 4}), Eq(it_1));
- EXPECT_THAT(map.FindRangeThatContains({9, 10}), Eq(it_1));
+ auto match_1 = IteratorPointsTo(map, Pair(AddressRange(0, 10), 0));
+ auto match_2 = IteratorPointsTo(map, Pair(AddressRange(10, 20), 1));
+ auto match_3 = IteratorPointsTo(map, Pair(AddressRange(25, 30), 2));
- EXPECT_THAT(map.FindRangeThatContains({10, 11}), Eq(it_2));
- EXPECT_THAT(map.FindRangeThatContains({11, 12}), Eq(it_2));
- EXPECT_THAT(map.FindRangeThatContains({19, 20}), Eq(it_2));
- EXPECT_THAT(map.FindRangeThatContains({10, 20}), Eq(it_2));
+ EXPECT_THAT(map.FindRangeThatContains({0, 10}), match_1);
+ EXPECT_THAT(map.FindRangeThatContains({0, 1}), match_1);
+ EXPECT_THAT(map.FindRangeThatContains({3, 4}), match_1);
+ EXPECT_THAT(map.FindRangeThatContains({9, 10}), match_1);
- EXPECT_THAT(map.FindRangeThatContains({25, 26}), Eq(it_3));
- EXPECT_THAT(map.FindRangeThatContains({26, 27}), Eq(it_3));
- EXPECT_THAT(map.FindRangeThatContains({29, 30}), Eq(it_3));
- EXPECT_THAT(map.FindRangeThatContains({25, 30}), Eq(it_3));
+ EXPECT_THAT(map.FindRangeThatContains({10, 11}), match_2);
+ EXPECT_THAT(map.FindRangeThatContains({11, 12}), match_2);
+ EXPECT_THAT(map.FindRangeThatContains({19, 20}), match_2);
+ EXPECT_THAT(map.FindRangeThatContains({10, 20}), match_2);
- EXPECT_THAT(map.FindRangeThatContains({9, 11}), Eq(end));
- EXPECT_THAT(map.FindRangeThatContains({20, 21}), Eq(end));
- EXPECT_THAT(map.FindRangeThatContains({24, 25}), Eq(end));
- EXPECT_THAT(map.FindRangeThatContains({14, 27}), Eq(end));
+ EXPECT_THAT(map.FindRangeThatContains({25, 26}), match_3);
+ EXPECT_THAT(map.FindRangeThatContains({26, 27}), match_3);
+ EXPECT_THAT(map.FindRangeThatContains({29, 30}), match_3);
+ EXPECT_THAT(map.FindRangeThatContains({25, 30}), match_3);
+
+ EXPECT_THAT(map.FindRangeThatContains({9, 11}), Eq(map.end()));
+ EXPECT_THAT(map.FindRangeThatContains({20, 21}), Eq(map.end()));
+ EXPECT_THAT(map.FindRangeThatContains({24, 25}), Eq(map.end()));
+ EXPECT_THAT(map.FindRangeThatContains({14, 27}), Eq(map.end()));
}
TEST(AddressRangeMap, DeleteOverlapsAndEmplace) {
@@ -285,6 +324,114 @@
EXPECT_THAT(map, ElementsAre(entry(5, 11, 5), entry(25, 30, 2)));
}
+TEST(AddressRangeMap, ForOverlapsEmptyRangeDoesNothing) {
+ AddressRangeMap<int> map;
+ map.Emplace(AddressRange(0, 10), 0);
+ map.Emplace(AddressRange(10, 20), 1);
+ map.Emplace(AddressRange(25, 30), 2);
+
+ MockFunction<void(AddressRangeMap<int>::value_type&)> cb;
+ EXPECT_CALL(cb, Call).Times(0);
+
+ map.ForOverlaps(AddressRange(5, 5), cb.AsStdFunction());
+}
+
+TEST(AddressRangeMap, ForOverlaps) {
+ AddressRangeMap<int> map;
+ map.Emplace(AddressRange(0, 10), 0);
+ map.Emplace(AddressRange(10, 20), 1);
+ map.Emplace(AddressRange(20, 30), 2);
+ map.Emplace(AddressRange(35, 40), 3);
+ map.Emplace(AddressRange(40, 50), 4);
+
+ MockFunction<void(AddressRangeMap<int>::value_type&)> cb;
+ EXPECT_CALL(cb, Call(Pair(AddressRange(10, 20), 1)));
+ EXPECT_CALL(cb, Call(Pair(AddressRange(20, 30), 2)));
+ EXPECT_CALL(cb, Call(Pair(AddressRange(35, 40), 3)));
+
+ map.ForOverlaps(AddressRange(15, 36), cb.AsStdFunction());
+}
+
+TEST(AddressSet, Empty) {
+ AddressSet empty;
+ EXPECT_THAT(empty, ElementsAre());
+}
+
+TEST(AddressSet, EmptyRangesAreNotAdded) {
+ AddressSet empty;
+
+ empty.Add({0, 0});
+ empty.Add({10, 10});
+
+ EXPECT_THAT(empty, ElementsAre());
+}
+
+TEST(AddressSet, NonOverlapingNonContiguousAreNotMerged) {
+ AddressSet set;
+ set.Add({0, 10});
+ set.Add({11, 20});
+
+ EXPECT_THAT(set, ElementsAre(AddressRange(0, 10), AddressRange(11, 20)));
+}
+
+TEST(AddressSet, ContiguousAreMerged) {
+ AddressSet set;
+ set.Add({0, 10});
+ set.Add({30, 40});
+ set.Add({10, 30});
+
+ EXPECT_THAT(set, ElementsAre(AddressRange(0, 40)));
+}
+
+TEST(AddressSet, OverlapsAreMerged) {
+ AddressSet set;
+ set.Add({0, 10});
+ set.Add({30, 40});
+ set.Add({5, 35});
+
+ EXPECT_THAT(set, ElementsAre(AddressRange(0, 40)));
+}
+
+TEST(AddressSet, SpliceRemove) {
+ AddressSet set;
+ set.Add({0, 10});
+ set.Remove({2, 5});
+
+ EXPECT_THAT(set, ElementsAre(AddressRange(0, 2), AddressRange(5, 10)));
+}
+
+TEST(AddressSet, PartialRemove) {
+ AddressSet set;
+ set.Add({0, 10});
+ set.Remove({0, 2});
+ set.Remove({8, 10});
+
+ EXPECT_THAT(set, ElementsAre(AddressRange(2, 8)));
+}
+
+TEST(AddressSet, MultipleRemove) {
+ AddressSet set;
+ set.Add({0, 10});
+ set.Add({12, 15});
+ set.Add({20, 30});
+ set.Remove({5, 25});
+
+ EXPECT_THAT(set, ElementsAre(AddressRange(0, 5), AddressRange(25, 30)));
+}
+
+TEST(AddressSet, RemoveEmptyRangeDoesNothing) {
+ AddressSet set;
+ set.Add({0, 10});
+ set.Add({20, 30});
+
+ set.Remove({0, 0});
+ set.Remove({2, 2});
+ set.Remove({10, 10});
+ set.Remove({11, 11});
+
+ EXPECT_THAT(set, ElementsAre(AddressRange(0, 10), AddressRange(20, 30)));
+}
+
} // namespace
} // namespace trace_processor
} // namespace perfetto
diff --git a/src/trace_processor/importers/common/sched_event_state.h b/src/trace_processor/importers/common/sched_event_state.h
deleted file mode 100644
index ef66fc2..0000000
--- a/src/trace_processor/importers/common/sched_event_state.h
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * 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_COMMON_SCHED_EVENT_STATE_H_
-#define SRC_TRACE_PROCESSOR_IMPORTERS_COMMON_SCHED_EVENT_STATE_H_
-
-#include "src/trace_processor/types/version_number.h"
-
-namespace perfetto {
-namespace trace_processor {
-
-// Responsible for keeping the state of pending sched events.
-class SchedEventState {
- public:
- // Information retained from the preceding sched_switch seen on a given cpu.
- struct PendingSchedInfo {
- // The pending scheduling slice that the next event will complete.
- uint32_t pending_slice_storage_idx = std::numeric_limits<uint32_t>::max();
-
- // pid/utid/prio corresponding to the last sched_switch seen on this cpu
- // (its "next_*" fields). There is some duplication with respect to the
- // slices storage, but we don't always have a slice when decoding events in
- // the compact format.
- uint32_t last_pid = std::numeric_limits<uint32_t>::max();
- UniqueTid last_utid = std::numeric_limits<UniqueTid>::max();
- int32_t last_prio = std::numeric_limits<int32_t>::max();
- };
-
- SchedEventState() {
- // Pre-allocate space for 128 CPUs, which should be enough for most hosts.
- // It's OK if this number is too small, the vector will be grown on-demand.
- pending_sched_per_cpu_.reserve(128);
- }
- SchedEventState(const SchedEventState&) = delete;
- ~SchedEventState() = default;
-
- // Get the sched info for the given CPU, resizing the vector if necessary.
- PendingSchedInfo* GetPendingSchedInfoForCpu(uint32_t cpu) {
- if (PERFETTO_UNLIKELY(cpu >= pending_sched_per_cpu_.size())) {
- pending_sched_per_cpu_.resize(cpu + 1);
- }
- return &pending_sched_per_cpu_[cpu];
- }
-
- private:
- // Information retained from the preceding sched_switch seen on a given cpu.
- std::vector<PendingSchedInfo> pending_sched_per_cpu_;
-};
-
-} // namespace trace_processor
-} // namespace perfetto
-
-#endif // SRC_TRACE_PROCESSOR_IMPORTERS_COMMON_SCHED_EVENT_STATE_H_
diff --git a/src/trace_processor/importers/common/sched_event_tracker.cc b/src/trace_processor/importers/common/sched_event_tracker.cc
deleted file mode 100644
index e541d58..0000000
--- a/src/trace_processor/importers/common/sched_event_tracker.cc
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * 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/common/sched_event_tracker.h"
-
-namespace perfetto {
-namespace trace_processor {
-
-SchedEventTracker::~SchedEventTracker() = default;
-
-} // namespace trace_processor
-} // namespace perfetto
diff --git a/src/trace_processor/importers/common/sched_event_tracker.h b/src/trace_processor/importers/common/sched_event_tracker.h
deleted file mode 100644
index 68a2926..0000000
--- a/src/trace_processor/importers/common/sched_event_tracker.h
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * 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_COMMON_SCHED_EVENT_TRACKER_H_
-#define SRC_TRACE_PROCESSOR_IMPORTERS_COMMON_SCHED_EVENT_TRACKER_H_
-
-#include "perfetto/ext/base/string_view.h"
-#include "perfetto/ext/base/utils.h"
-#include "src/trace_processor/importers/common/event_tracker.h"
-#include "src/trace_processor/importers/common/process_tracker.h"
-#include "src/trace_processor/importers/common/system_info_tracker.h"
-#include "src/trace_processor/importers/common/thread_state_tracker.h"
-#include "src/trace_processor/storage/trace_storage.h"
-#include "src/trace_processor/types/destructible.h"
-#include "src/trace_processor/types/task_state.h"
-#include "src/trace_processor/types/trace_processor_context.h"
-
-namespace perfetto {
-namespace trace_processor {
-
-// Tracks sched events and stores them into the storage as sched slices.
-class SchedEventTracker : public Destructible {
- public:
- PERFETTO_ALWAYS_INLINE
- SchedEventTracker(TraceProcessorContext* context) : context_(context) {}
- SchedEventTracker(const SchedEventTracker&) = delete;
- ~SchedEventTracker() override;
-
- PERFETTO_ALWAYS_INLINE
- uint32_t AddStartSlice(uint32_t cpu,
- int64_t ts,
- UniqueTid next_utid,
- int32_t next_prio) {
- // Open a new scheduling slice, corresponding to the task that was
- // just switched to. Set the duration to -1, to indicate that the event is
- // not finished. Duration will be updated later after event finish.
- auto* sched = context_->storage->mutable_sched_slice_table();
- auto row_and_id = sched->Insert(
- {ts, /* duration */ -1, cpu, next_utid, kNullStringId, next_prio});
- SchedId sched_id = row_and_id.id;
- return *sched->id().IndexOf(sched_id);
- }
-
- PERFETTO_ALWAYS_INLINE
- bool UpdateEventTrackerTimestamp(int64_t ts,
- const char* event_name,
- size_t stats) {
- // At this stage all events should be globally timestamp ordered.
- if (ts < context_->event_tracker->max_timestamp()) {
- PERFETTO_ELOG(
- "%s event out of order by %.4f ms, skipping", event_name,
- static_cast<double>(context_->event_tracker->max_timestamp() - ts) /
- 1e6);
- context_->storage->IncrementStats(stats);
- return false;
- }
- context_->event_tracker->UpdateMaxTimestamp(ts);
- return true;
- }
-
- PERFETTO_ALWAYS_INLINE
- void ClosePendingSlice(uint32_t pending_slice_idx,
- int64_t ts,
- StringId prev_state) {
- auto* slices = context_->storage->mutable_sched_slice_table();
-
- int64_t duration = ts - slices->ts()[pending_slice_idx];
- slices->mutable_dur()->Set(pending_slice_idx, duration);
-
- // We store the state as a uint16 as we only consider values up to 2048
- // when unpacking the information inside; this allows savings of 48 bits
- // per slice.
- slices->mutable_end_state()->Set(pending_slice_idx, prev_state);
- }
-
- PERFETTO_ALWAYS_INLINE
- StringId TaskStateToStringId(int64_t task_state_int) {
- using ftrace_utils::TaskState;
-
- std::optional<VersionNumber> kernel_version =
- SystemInfoTracker::GetOrCreate(context_)->GetKernelVersion();
- TaskState task_state = TaskState::FromRawPrevState(
- static_cast<uint16_t>(task_state_int), kernel_version);
- return task_state.is_valid()
- ? context_->storage->InternString(task_state.ToString().data())
- : kNullStringId;
- }
-
- private:
- TraceProcessorContext* const context_;
-};
-
-} // namespace trace_processor
-} // namespace perfetto
-
-#endif // SRC_TRACE_PROCESSOR_IMPORTERS_COMMON_SCHED_EVENT_TRACKER_H_
diff --git a/src/trace_processor/importers/ftrace/BUILD.gn b/src/trace_processor/importers/ftrace/BUILD.gn
index 3a533d1..c618978 100644
--- a/src/trace_processor/importers/ftrace/BUILD.gn
+++ b/src/trace_processor/importers/ftrace/BUILD.gn
@@ -37,8 +37,6 @@
"ftrace_module_impl.h",
"ftrace_parser.cc",
"ftrace_parser.h",
- "ftrace_sched_event_tracker.cc",
- "ftrace_sched_event_tracker.h",
"ftrace_tokenizer.cc",
"ftrace_tokenizer.h",
"gpu_work_period_tracker.cc",
@@ -51,6 +49,10 @@
"pkvm_hyp_cpu_tracker.h",
"rss_stat_tracker.cc",
"rss_stat_tracker.h",
+ "sched_event_tracker.cc",
+ "sched_event_tracker.h",
+ "thread_state_tracker.cc",
+ "thread_state_tracker.h",
"v4l2_tracker.cc",
"v4l2_tracker.h",
"virtio_gpu_tracker.cc",
@@ -97,7 +99,8 @@
testonly = true
sources = [
"binder_tracker_unittest.cc",
- "ftrace_sched_event_tracker_unittest.cc",
+ "sched_event_tracker_unittest.cc",
+ "thread_state_tracker_unittest.cc",
]
deps = [
"../../../../gn:default_deps",
diff --git a/src/trace_processor/importers/ftrace/ftrace_parser.cc b/src/trace_processor/importers/ftrace/ftrace_parser.cc
index 6948fc3..951c03d 100644
--- a/src/trace_processor/importers/ftrace/ftrace_parser.cc
+++ b/src/trace_processor/importers/ftrace/ftrace_parser.cc
@@ -26,9 +26,9 @@
#include "src/trace_processor/importers/common/metadata_tracker.h"
#include "src/trace_processor/importers/common/parser_types.h"
#include "src/trace_processor/importers/common/process_tracker.h"
-#include "src/trace_processor/importers/common/thread_state_tracker.h"
#include "src/trace_processor/importers/common/track_tracker.h"
#include "src/trace_processor/importers/ftrace/binder_tracker.h"
+#include "src/trace_processor/importers/ftrace/thread_state_tracker.h"
#include "src/trace_processor/importers/ftrace/v4l2_tracker.h"
#include "src/trace_processor/importers/ftrace/virtio_video_tracker.h"
#include "src/trace_processor/importers/i2c/i2c_tracker.h"
@@ -1120,11 +1120,10 @@
}
using protos::pbzero::FtraceEvent;
- FtraceSchedEventTracker* ftrace_sched_tracker =
- FtraceSchedEventTracker::GetOrCreate(context_);
- ftrace_sched_tracker->PushSchedSwitchCompact(
- cpu, ts, data.prev_state, static_cast<uint32_t>(data.next_pid),
- data.next_prio, data.next_comm);
+ SchedEventTracker* sched_tracker = SchedEventTracker::GetOrCreate(context_);
+ sched_tracker->PushSchedSwitchCompact(cpu, ts, data.prev_state,
+ static_cast<uint32_t>(data.next_pid),
+ data.next_prio, data.next_comm);
return util::OkStatus();
}
@@ -1139,9 +1138,8 @@
return util::OkStatus();
}
using protos::pbzero::FtraceEvent;
- FtraceSchedEventTracker* ftrace_sched_tracker =
- FtraceSchedEventTracker::GetOrCreate(context_);
- ftrace_sched_tracker->PushSchedWakingCompact(
+ SchedEventTracker* sched_tracker = SchedEventTracker::GetOrCreate(context_);
+ sched_tracker->PushSchedWakingCompact(
cpu, ts, static_cast<uint32_t>(data.pid), data.target_cpu, data.prio,
data.comm, data.common_flags);
return util::OkStatus();
@@ -1323,7 +1321,7 @@
protos::pbzero::SchedSwitchFtraceEvent::Decoder ss(blob.data, blob.size);
uint32_t prev_pid = static_cast<uint32_t>(ss.prev_pid());
uint32_t next_pid = static_cast<uint32_t>(ss.next_pid());
- FtraceSchedEventTracker::GetOrCreate(context_)->PushSchedSwitch(
+ SchedEventTracker::GetOrCreate(context_)->PushSchedSwitch(
cpu, timestamp, prev_pid, ss.prev_comm(), ss.prev_prio(), ss.prev_state(),
next_pid, ss.next_comm(), ss.next_prio());
}
diff --git a/src/trace_processor/importers/ftrace/ftrace_parser.h b/src/trace_processor/importers/ftrace/ftrace_parser.h
index b3764f1..f3234bd 100644
--- a/src/trace_processor/importers/ftrace/ftrace_parser.h
+++ b/src/trace_processor/importers/ftrace/ftrace_parser.h
@@ -26,12 +26,12 @@
#include "src/trace_processor/importers/common/trace_parser.h"
#include "src/trace_processor/importers/ftrace/drm_tracker.h"
#include "src/trace_processor/importers/ftrace/ftrace_descriptors.h"
-#include "src/trace_processor/importers/ftrace/ftrace_sched_event_tracker.h"
#include "src/trace_processor/importers/ftrace/gpu_work_period_tracker.h"
#include "src/trace_processor/importers/ftrace/iostat_tracker.h"
#include "src/trace_processor/importers/ftrace/mali_gpu_event_tracker.h"
#include "src/trace_processor/importers/ftrace/pkvm_hyp_cpu_tracker.h"
#include "src/trace_processor/importers/ftrace/rss_stat_tracker.h"
+#include "src/trace_processor/importers/ftrace/sched_event_tracker.h"
#include "src/trace_processor/importers/ftrace/virtio_gpu_tracker.h"
#include "src/trace_processor/types/trace_processor_context.h"
diff --git a/src/trace_processor/importers/ftrace/ftrace_sched_event_tracker.h b/src/trace_processor/importers/ftrace/ftrace_sched_event_tracker.h
deleted file mode 100644
index bc90532..0000000
--- a/src/trace_processor/importers/ftrace/ftrace_sched_event_tracker.h
+++ /dev/null
@@ -1,115 +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_FTRACE_FTRACE_SCHED_EVENT_TRACKER_H_
-#define SRC_TRACE_PROCESSOR_IMPORTERS_FTRACE_FTRACE_SCHED_EVENT_TRACKER_H_
-
-#include <array>
-#include <limits>
-
-#include "perfetto/ext/base/string_view.h"
-#include "perfetto/ext/base/utils.h"
-#include "src/trace_processor/importers/common/sched_event_tracker.h"
-#include "src/trace_processor/importers/common/sched_event_state.h"
-#include "src/trace_processor/storage/trace_storage.h"
-#include "src/trace_processor/types/destructible.h"
-#include "src/trace_processor/types/trace_processor_context.h"
-
-namespace perfetto {
-namespace trace_processor {
-
-class EventTracker;
-
-// Tracks sched events and stores them into the storage as sched slices.
-class FtraceSchedEventTracker : public Destructible {
- public:
- explicit FtraceSchedEventTracker(TraceProcessorContext*);
- ~FtraceSchedEventTracker() override;
-
- FtraceSchedEventTracker(
- const FtraceSchedEventTracker& ftrace_sched_event_tracker) = delete;
- FtraceSchedEventTracker& operator=(
- const FtraceSchedEventTracker& ftrace_sched_event_tracker) = delete;
-
- static FtraceSchedEventTracker* GetOrCreate(TraceProcessorContext* context) {
- if (!context->ftrace_sched_tracker) {
- context->ftrace_sched_tracker.reset(new FtraceSchedEventTracker(context));
- }
- return static_cast<FtraceSchedEventTracker*>(
- context->ftrace_sched_tracker.get());
- }
-
- // This method is called when a sched_switch event is seen in the trace.
- // Virtual for testing.
- virtual void PushSchedSwitch(uint32_t cpu,
- int64_t timestamp,
- uint32_t prev_pid,
- base::StringView prev_comm,
- int32_t prev_prio,
- int64_t prev_state,
- uint32_t next_pid,
- base::StringView next_comm,
- int32_t next_prio);
-
- void AddRawSchedSwitchEvent(uint32_t cpu,
- int64_t ts,
- UniqueTid prev_utid,
- uint32_t prev_pid,
- StringId prev_comm_id,
- int32_t prev_prio,
- int64_t prev_state,
- uint32_t next_pid,
- StringId next_comm_id,
- int32_t next_prio);
-
- // This method is called when parsing a sched_switch encoded in the compact
- // format.
- void PushSchedSwitchCompact(uint32_t cpu,
- int64_t ts,
- int64_t prev_state,
- uint32_t next_pid,
- int32_t next_prio,
- StringId next_comm_id);
-
- // This method is called when parsing a sched_waking encoded in the compact
- // format. Note that the default encoding is handled by
- // |EventTracker::PushInstant|.
- void PushSchedWakingCompact(uint32_t cpu,
- int64_t ts,
- uint32_t wakee_pid,
- uint16_t target_cpu,
- uint16_t prio,
- StringId comm_id,
- uint16_t common_flags);
-
- private:
- static constexpr uint8_t kSchedSwitchMaxFieldId = 7;
- std::array<StringId, kSchedSwitchMaxFieldId + 1> sched_switch_field_ids_;
- StringId sched_switch_id_;
-
- static constexpr uint8_t kSchedWakingMaxFieldId = 5;
- std::array<StringId, kSchedWakingMaxFieldId + 1> sched_waking_field_ids_;
- StringId sched_waking_id_;
-
- TraceProcessorContext* const context_;
-
- SchedEventState sched_event_state_;
-};
-
-} // namespace trace_processor
-} // namespace perfetto
-
-#endif // SRC_TRACE_PROCESSOR_IMPORTERS_FTRACE_FTRACE_SCHED_EVENT_TRACKER_H_
diff --git a/src/trace_processor/importers/ftrace/ftrace_sched_event_tracker.cc b/src/trace_processor/importers/ftrace/sched_event_tracker.cc
similarity index 67%
rename from src/trace_processor/importers/ftrace/ftrace_sched_event_tracker.cc
rename to src/trace_processor/importers/ftrace/sched_event_tracker.cc
index 36bf028..09459c4 100644
--- a/src/trace_processor/importers/ftrace/ftrace_sched_event_tracker.cc
+++ b/src/trace_processor/importers/ftrace/sched_event_tracker.cc
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#include "src/trace_processor/importers/ftrace/ftrace_sched_event_tracker.h"
+#include "src/trace_processor/importers/ftrace/sched_event_tracker.h"
#include <math.h>
@@ -22,11 +22,9 @@
#include "src/trace_processor/importers/common/args_tracker.h"
#include "src/trace_processor/importers/common/event_tracker.h"
#include "src/trace_processor/importers/common/process_tracker.h"
-#include "src/trace_processor/importers/common/sched_event_tracker.h"
-#include "src/trace_processor/importers/common/sched_event_state.h"
#include "src/trace_processor/importers/common/system_info_tracker.h"
-#include "src/trace_processor/importers/common/thread_state_tracker.h"
#include "src/trace_processor/importers/ftrace/ftrace_descriptors.h"
+#include "src/trace_processor/importers/ftrace/thread_state_tracker.h"
#include "src/trace_processor/storage/stats.h"
#include "src/trace_processor/types/task_state.h"
#include "src/trace_processor/types/trace_processor_context.h"
@@ -38,8 +36,9 @@
namespace perfetto {
namespace trace_processor {
-FtraceSchedEventTracker::FtraceSchedEventTracker(TraceProcessorContext* context)
- : context_(context) {
+SchedEventTracker::SchedEventTracker(TraceProcessorContext* context)
+ : waker_utid_id_(context->storage->InternString("waker_utid")),
+ context_(context) {
// pre-parse sched_switch
auto* switch_descriptor = GetMessageDescriptorForId(
protos::pbzero::FtraceEvent::kSchedSwitchFieldNumber);
@@ -61,11 +60,15 @@
context->storage->InternString(waking_descriptor->fields[i].name);
}
sched_waking_id_ = context->storage->InternString(waking_descriptor->name);
+
+ // Pre-allocate space for 128 CPUs, which should be enough for most hosts.
+ // It's OK if this number is too small, the vector will be grown on-demand.
+ pending_sched_per_cpu_.reserve(128);
}
-FtraceSchedEventTracker::~FtraceSchedEventTracker() = default;
+SchedEventTracker::~SchedEventTracker() = default;
-void FtraceSchedEventTracker::PushSchedSwitch(uint32_t cpu,
+void SchedEventTracker::PushSchedSwitch(uint32_t cpu,
int64_t ts,
uint32_t prev_pid,
base::StringView prev_comm,
@@ -74,10 +77,16 @@
uint32_t next_pid,
base::StringView next_comm,
int32_t next_prio) {
- if (!context_->sched_event_tracker->UpdateEventTrackerTimestamp(ts,
- "sched_switch",stats::sched_switch_out_of_order)) {
+ // At this stage all events should be globally timestamp ordered.
+ if (ts < context_->event_tracker->max_timestamp()) {
+ PERFETTO_ELOG(
+ "sched_switch event out of order by %.4f ms, skipping",
+ static_cast<double>(context_->event_tracker->max_timestamp() - ts) /
+ 1e6);
+ context_->storage->IncrementStats(stats::sched_switch_out_of_order);
return;
}
+ context_->event_tracker->UpdateMaxTimestamp(ts);
StringId next_comm_id = context_->storage->InternString(next_comm);
UniqueTid next_utid = context_->process_tracker->UpdateThreadName(
@@ -85,18 +94,16 @@
// First use this data to close the previous slice.
bool prev_pid_match_prev_next_pid = false;
- auto* pending_sched = sched_event_state_.GetPendingSchedInfoForCpu(cpu);
+ auto* pending_sched = PendingSchedByCPU(cpu);
uint32_t pending_slice_idx = pending_sched->pending_slice_storage_idx;
- StringId prev_state_string_id = context_->sched_event_tracker
- ->TaskStateToStringId(prev_state);
+ StringId prev_state_string_id = TaskStateToStringId(prev_state);
if (prev_state_string_id == kNullStringId) {
context_->storage->IncrementStats(stats::task_state_invalid);
}
if (pending_slice_idx < std::numeric_limits<uint32_t>::max()) {
prev_pid_match_prev_next_pid = prev_pid == pending_sched->last_pid;
if (PERFETTO_LIKELY(prev_pid_match_prev_next_pid)) {
- context_->sched_event_tracker->ClosePendingSlice(pending_slice_idx, ts,
- prev_state_string_id);
+ ClosePendingSlice(pending_slice_idx, ts, prev_state_string_id);
} else {
// If the pids are not consistent, make a note of this.
context_->storage->IncrementStats(stats::mismatched_sched_switch_tids);
@@ -110,11 +117,9 @@
UniqueTid prev_utid = context_->process_tracker->UpdateThreadName(
prev_pid, prev_comm_id, ThreadNamePriority::kFtrace);
- AddRawSchedSwitchEvent(cpu, ts, prev_utid, prev_pid, prev_comm_id, prev_prio,
- prev_state, next_pid, next_comm_id, next_prio);
-
- auto new_slice_idx = context_->sched_event_tracker
- ->AddStartSlice(cpu, ts, next_utid, next_prio);
+ auto new_slice_idx = AddRawEventAndStartSlice(
+ cpu, ts, prev_utid, prev_pid, prev_comm_id, prev_prio, prev_state,
+ next_utid, next_pid, next_comm_id, next_prio);
// Finally, update the info for the next sched switch on this CPU.
pending_sched->pending_slice_storage_idx = new_slice_idx;
@@ -127,21 +132,27 @@
ts, cpu, prev_utid, prev_state_string_id, next_utid);
}
-void FtraceSchedEventTracker::PushSchedSwitchCompact(uint32_t cpu,
- int64_t ts,
- int64_t prev_state,
- uint32_t next_pid,
- int32_t next_prio,
- StringId next_comm_id) {
- if (!context_->sched_event_tracker->UpdateEventTrackerTimestamp(ts,
- "sched_switch", stats::sched_switch_out_of_order)) {
+void SchedEventTracker::PushSchedSwitchCompact(uint32_t cpu,
+ int64_t ts,
+ int64_t prev_state,
+ uint32_t next_pid,
+ int32_t next_prio,
+ StringId next_comm_id) {
+ // At this stage all events should be globally timestamp ordered.
+ if (ts < context_->event_tracker->max_timestamp()) {
+ PERFETTO_ELOG(
+ "sched_switch event out of order by %.4f ms, skipping",
+ static_cast<double>(context_->event_tracker->max_timestamp() - ts) /
+ 1e6);
+ context_->storage->IncrementStats(stats::sched_switch_out_of_order);
return;
}
+ context_->event_tracker->UpdateMaxTimestamp(ts);
UniqueTid next_utid = context_->process_tracker->UpdateThreadName(
next_pid, next_comm_id, ThreadNamePriority::kFtrace);
- auto* pending_sched = sched_event_state_.GetPendingSchedInfoForCpu(cpu);
+ auto* pending_sched = PendingSchedByCPU(cpu);
// If we're processing the first compact event for this cpu, don't start a
// slice since we're missing the "prev_*" fields. The successive events will
@@ -161,14 +172,12 @@
// Close the pending slice if any (we won't have one when processing the first
// two compact events for a given cpu).
uint32_t pending_slice_idx = pending_sched->pending_slice_storage_idx;
- StringId prev_state_string_id = context_->sched_event_tracker
- ->TaskStateToStringId(prev_state);
+ StringId prev_state_string_id = TaskStateToStringId(prev_state);
if (prev_state_string_id == kNullStringId) {
context_->storage->IncrementStats(stats::task_state_invalid);
}
if (pending_slice_idx < std::numeric_limits<uint32_t>::max())
- context_->sched_event_tracker->ClosePendingSlice(pending_slice_idx, ts,
- prev_state_string_id);
+ ClosePendingSlice(pending_slice_idx, ts, prev_state_string_id);
// Use the previous event's values to infer this event's "prev_*" fields.
// There are edge cases, but this assumption should still produce sensible
@@ -183,10 +192,9 @@
context_->storage->thread_table().name()[prev_utid].value_or(
kNullStringId);
- AddRawSchedSwitchEvent(cpu, ts, prev_utid, prev_pid, prev_comm_id, prev_prio,
- prev_state, next_pid, next_comm_id, next_prio);
- auto new_slice_idx = context_->sched_event_tracker
- ->AddStartSlice(cpu, ts, next_utid, next_prio);
+ auto new_slice_idx = AddRawEventAndStartSlice(
+ cpu, ts, prev_utid, prev_pid, prev_comm_id, prev_prio, prev_state,
+ next_utid, next_pid, next_comm_id, next_prio);
// Finally, update the info for the next sched switch on this CPU.
pending_sched->pending_slice_storage_idx = new_slice_idx;
@@ -201,24 +209,30 @@
// Processes a sched_waking that was decoded from a compact representation,
// adding to the raw and instants tables.
-void FtraceSchedEventTracker::PushSchedWakingCompact(uint32_t cpu,
- int64_t ts,
- uint32_t wakee_pid,
- uint16_t target_cpu,
- uint16_t prio,
- StringId comm_id,
- uint16_t common_flags) {
- if (!context_->sched_event_tracker->UpdateEventTrackerTimestamp(ts,
- "sched_waking", stats::sched_waking_out_of_order)) {
+void SchedEventTracker::PushSchedWakingCompact(uint32_t cpu,
+ int64_t ts,
+ uint32_t wakee_pid,
+ uint16_t target_cpu,
+ uint16_t prio,
+ StringId comm_id,
+ uint16_t common_flags) {
+ // At this stage all events should be globally timestamp ordered.
+ if (ts < context_->event_tracker->max_timestamp()) {
+ PERFETTO_ELOG(
+ "sched_waking event out of order by %.4f ms, skipping",
+ static_cast<double>(context_->event_tracker->max_timestamp() - ts) /
+ 1e6);
+ context_->storage->IncrementStats(stats::sched_waking_out_of_order);
return;
}
+ context_->event_tracker->UpdateMaxTimestamp(ts);
// We infer the task that emitted the event (i.e. common_pid) from the
// scheduling slices. Drop the event if we haven't seen any sched_switch
// events for this cpu yet.
// Note that if sched_switch wasn't enabled, we will have to skip all
// compact waking events.
- auto* pending_sched = sched_event_state_.GetPendingSchedInfoForCpu(cpu);
+ auto* pending_sched = PendingSchedByCPU(cpu);
if (pending_sched->last_utid == std::numeric_limits<UniqueTid>::max()) {
context_->storage->IncrementStats(stats::compact_sched_waking_skipped);
return;
@@ -255,13 +269,14 @@
}
PERFETTO_ALWAYS_INLINE
-void FtraceSchedEventTracker::AddRawSchedSwitchEvent(uint32_t cpu,
+uint32_t SchedEventTracker::AddRawEventAndStartSlice(uint32_t cpu,
int64_t ts,
UniqueTid prev_utid,
uint32_t prev_pid,
StringId prev_comm_id,
int32_t prev_prio,
int64_t prev_state,
+ UniqueTid next_utid,
uint32_t next_pid,
StringId next_comm_id,
int32_t next_prio) {
@@ -290,6 +305,42 @@
add_raw_arg(SS::kNextPidFieldNumber, Variadic::Integer(next_pid));
add_raw_arg(SS::kNextPrioFieldNumber, Variadic::Integer(next_prio));
}
+
+ // Open a new scheduling slice, corresponding to the task that was
+ // just switched to. Set the duration to -1, to indicate that the event is not
+ // finished. Duration will be updated later after event finish.
+ auto* sched = context_->storage->mutable_sched_slice_table();
+ auto row_and_id = sched->Insert(
+ {ts, /* duration */ -1, cpu, next_utid, kNullStringId, next_prio});
+ SchedId sched_id = row_and_id.id;
+ return *sched->id().IndexOf(sched_id);
+}
+
+StringId SchedEventTracker::TaskStateToStringId(int64_t task_state_int) {
+ using ftrace_utils::TaskState;
+
+ std::optional<VersionNumber> kernel_version =
+ SystemInfoTracker::GetOrCreate(context_)->GetKernelVersion();
+ TaskState task_state = TaskState::FromRawPrevState(
+ static_cast<uint16_t>(task_state_int), kernel_version);
+ return task_state.is_valid()
+ ? context_->storage->InternString(task_state.ToString().data())
+ : kNullStringId;
+}
+
+PERFETTO_ALWAYS_INLINE
+void SchedEventTracker::ClosePendingSlice(uint32_t pending_slice_idx,
+ int64_t ts,
+ StringId prev_state) {
+ auto* slices = context_->storage->mutable_sched_slice_table();
+
+ int64_t duration = ts - slices->ts()[pending_slice_idx];
+ slices->mutable_dur()->Set(pending_slice_idx, duration);
+
+ // We store the state as a uint16 as we only consider values up to 2048
+ // when unpacking the information inside; this allows savings of 48 bits
+ // per slice.
+ slices->mutable_end_state()->Set(pending_slice_idx, prev_state);
}
} // namespace trace_processor
diff --git a/src/trace_processor/importers/ftrace/sched_event_tracker.h b/src/trace_processor/importers/ftrace/sched_event_tracker.h
new file mode 100644
index 0000000..745b7c3
--- /dev/null
+++ b/src/trace_processor/importers/ftrace/sched_event_tracker.h
@@ -0,0 +1,139 @@
+/*
+ * 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_FTRACE_SCHED_EVENT_TRACKER_H_
+#define SRC_TRACE_PROCESSOR_IMPORTERS_FTRACE_SCHED_EVENT_TRACKER_H_
+
+#include <array>
+#include <limits>
+
+#include "perfetto/ext/base/string_view.h"
+#include "perfetto/ext/base/utils.h"
+#include "src/trace_processor/storage/trace_storage.h"
+#include "src/trace_processor/types/destructible.h"
+#include "src/trace_processor/types/trace_processor_context.h"
+
+namespace perfetto {
+namespace trace_processor {
+
+class EventTracker;
+
+// Tracks sched events and stores them into the storage as sched slices.
+class SchedEventTracker : public Destructible {
+ public:
+ // Declared public for testing only.
+ explicit SchedEventTracker(TraceProcessorContext*);
+ SchedEventTracker(const SchedEventTracker&) = delete;
+ SchedEventTracker& operator=(const SchedEventTracker&) = delete;
+ ~SchedEventTracker() override;
+ static SchedEventTracker* GetOrCreate(TraceProcessorContext* context) {
+ if (!context->sched_tracker) {
+ context->sched_tracker.reset(new SchedEventTracker(context));
+ }
+ return static_cast<SchedEventTracker*>(context->sched_tracker.get());
+ }
+
+ // This method is called when a sched_switch event is seen in the trace.
+ // Virtual for testing.
+ virtual void PushSchedSwitch(uint32_t cpu,
+ int64_t timestamp,
+ uint32_t prev_pid,
+ base::StringView prev_comm,
+ int32_t prev_prio,
+ int64_t prev_state,
+ uint32_t next_pid,
+ base::StringView next_comm,
+ int32_t next_prio);
+
+ // This method is called when parsing a sched_switch encoded in the compact
+ // format.
+ void PushSchedSwitchCompact(uint32_t cpu,
+ int64_t ts,
+ int64_t prev_state,
+ uint32_t next_pid,
+ int32_t next_prio,
+ StringId next_comm_id);
+
+ // This method is called when parsing a sched_waking encoded in the compact
+ // format. Note that the default encoding is handled by
+ // |EventTracker::PushInstant|.
+ void PushSchedWakingCompact(uint32_t cpu,
+ int64_t ts,
+ uint32_t wakee_pid,
+ uint16_t target_cpu,
+ uint16_t prio,
+ StringId comm_id,
+ uint16_t common_flags);
+
+ private:
+ // Information retained from the preceding sched_switch seen on a given cpu.
+ struct PendingSchedInfo {
+ // The pending scheduling slice that the next event will complete.
+ uint32_t pending_slice_storage_idx = std::numeric_limits<uint32_t>::max();
+
+ // pid/utid/prio corresponding to the last sched_switch seen on this cpu
+ // (its "next_*" fields). There is some duplication with respect to the
+ // slices storage, but we don't always have a slice when decoding events in
+ // the compact format.
+ uint32_t last_pid = std::numeric_limits<uint32_t>::max();
+ UniqueTid last_utid = std::numeric_limits<UniqueTid>::max();
+ int32_t last_prio = std::numeric_limits<int32_t>::max();
+ };
+
+ uint32_t AddRawEventAndStartSlice(uint32_t cpu,
+ int64_t ts,
+ UniqueTid prev_utid,
+ uint32_t prev_pid,
+ StringId prev_comm_id,
+ int32_t prev_prio,
+ int64_t prev_state,
+ UniqueTid next_utid,
+ uint32_t next_pid,
+ StringId next_comm_id,
+ int32_t next_prio);
+
+ StringId TaskStateToStringId(int64_t task_state);
+
+ void ClosePendingSlice(uint32_t slice_idx, int64_t ts, StringId prev_state);
+
+ // Information retained from the preceding sched_switch seen on a given cpu.
+ std::vector<PendingSchedInfo> pending_sched_per_cpu_;
+
+ // Get the sched info for the given CPU, resizing the vector if necessary.
+ PendingSchedInfo* PendingSchedByCPU(uint32_t cpu) {
+ if (PERFETTO_UNLIKELY(cpu >= pending_sched_per_cpu_.size())) {
+ pending_sched_per_cpu_.resize(cpu + 1);
+ }
+ return &pending_sched_per_cpu_[cpu];
+ }
+
+ static constexpr uint8_t kSchedSwitchMaxFieldId = 7;
+ std::array<StringId, kSchedSwitchMaxFieldId + 1> sched_switch_field_ids_;
+ StringId sched_switch_id_;
+
+ static constexpr uint8_t kSchedWakingMaxFieldId = 5;
+ std::array<StringId, kSchedWakingMaxFieldId + 1> sched_waking_field_ids_;
+ StringId sched_waking_id_;
+
+ StringId waker_utid_id_;
+
+ TraceProcessorContext* const context_;
+};
+
+} // namespace trace_processor
+} // namespace perfetto
+
+#endif // SRC_TRACE_PROCESSOR_IMPORTERS_FTRACE_SCHED_EVENT_TRACKER_H_
diff --git a/src/trace_processor/importers/ftrace/ftrace_sched_event_tracker_unittest.cc b/src/trace_processor/importers/ftrace/sched_event_tracker_unittest.cc
similarity index 93%
rename from src/trace_processor/importers/ftrace/ftrace_sched_event_tracker_unittest.cc
rename to src/trace_processor/importers/ftrace/sched_event_tracker_unittest.cc
index a085078..5d275d6 100644
--- a/src/trace_processor/importers/ftrace/ftrace_sched_event_tracker_unittest.cc
+++ b/src/trace_processor/importers/ftrace/sched_event_tracker_unittest.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2023 The Android Open Source Project
+ * Copyright (C) 2020 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.
@@ -14,12 +14,11 @@
* limitations under the License.
*/
-#include "src/trace_processor/importers/ftrace/ftrace_sched_event_tracker.h"
+#include "src/trace_processor/importers/ftrace/sched_event_tracker.h"
#include "perfetto/base/logging.h"
#include "src/trace_processor/importers/common/args_tracker.h"
#include "src/trace_processor/importers/common/event_tracker.h"
-#include "src/trace_processor/importers/common/sched_event_tracker.h"
#include "src/trace_processor/importers/common/process_tracker.h"
#include "test/gtest_and_gmock.h"
@@ -40,13 +39,12 @@
context.args_tracker.reset(new ArgsTracker(&context));
context.event_tracker.reset(new EventTracker(&context));
context.process_tracker.reset(new ProcessTracker(&context));
- context.sched_event_tracker.reset(new SchedEventTracker(&context));
- sched_tracker = FtraceSchedEventTracker::GetOrCreate(&context);
+ sched_tracker = SchedEventTracker::GetOrCreate(&context);
}
protected:
TraceProcessorContext context;
- FtraceSchedEventTracker* sched_tracker;
+ SchedEventTracker* sched_tracker;
};
TEST_F(SchedEventTrackerTest, InsertSecondSched) {
diff --git a/src/trace_processor/importers/common/thread_state_tracker.cc b/src/trace_processor/importers/ftrace/thread_state_tracker.cc
similarity index 98%
rename from src/trace_processor/importers/common/thread_state_tracker.cc
rename to src/trace_processor/importers/ftrace/thread_state_tracker.cc
index a2daecd..7eda59e 100644
--- a/src/trace_processor/importers/common/thread_state_tracker.cc
+++ b/src/trace_processor/importers/ftrace/thread_state_tracker.cc
@@ -13,8 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
-#include "src/trace_processor/importers/common/thread_state_tracker.h"
+#include "src/trace_processor/importers/ftrace/thread_state_tracker.h"
#include <optional>
namespace perfetto {
diff --git a/src/trace_processor/importers/common/thread_state_tracker.h b/src/trace_processor/importers/ftrace/thread_state_tracker.h
similarity index 95%
rename from src/trace_processor/importers/common/thread_state_tracker.h
rename to src/trace_processor/importers/ftrace/thread_state_tracker.h
index 2b7206b..839ad31 100644
--- a/src/trace_processor/importers/common/thread_state_tracker.h
+++ b/src/trace_processor/importers/ftrace/thread_state_tracker.h
@@ -13,9 +13,8 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
-#ifndef SRC_TRACE_PROCESSOR_IMPORTERS_COMMON_THREAD_STATE_TRACKER_H_
-#define SRC_TRACE_PROCESSOR_IMPORTERS_COMMON_THREAD_STATE_TRACKER_H_
+#ifndef SRC_TRACE_PROCESSOR_IMPORTERS_FTRACE_THREAD_STATE_TRACKER_H_
+#define SRC_TRACE_PROCESSOR_IMPORTERS_FTRACE_THREAD_STATE_TRACKER_H_
#include "src/trace_processor/storage/trace_storage.h"
#include "src/trace_processor/types/destructible.h"
@@ -105,4 +104,4 @@
} // namespace trace_processor
} // namespace perfetto
-#endif // SRC_TRACE_PROCESSOR_IMPORTERS_COMMON_THREAD_STATE_TRACKER_H_
+#endif // SRC_TRACE_PROCESSOR_IMPORTERS_FTRACE_THREAD_STATE_TRACKER_H_
diff --git a/src/trace_processor/importers/common/thread_state_tracker_unittest.cc b/src/trace_processor/importers/ftrace/thread_state_tracker_unittest.cc
similarity index 98%
rename from src/trace_processor/importers/common/thread_state_tracker_unittest.cc
rename to src/trace_processor/importers/ftrace/thread_state_tracker_unittest.cc
index ea6794a..1b0e1a3 100644
--- a/src/trace_processor/importers/common/thread_state_tracker_unittest.cc
+++ b/src/trace_processor/importers/ftrace/thread_state_tracker_unittest.cc
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#include "src/trace_processor/importers/common/thread_state_tracker.h"
+#include "src/trace_processor/importers/ftrace/thread_state_tracker.h"
#include <algorithm>
diff --git a/src/trace_processor/importers/fuchsia/fuchsia_parser_unittest.cc b/src/trace_processor/importers/fuchsia/fuchsia_parser_unittest.cc
index 9f90bed..d644742 100644
--- a/src/trace_processor/importers/fuchsia/fuchsia_parser_unittest.cc
+++ b/src/trace_processor/importers/fuchsia/fuchsia_parser_unittest.cc
@@ -31,7 +31,7 @@
#include "src/trace_processor/importers/common/slice_tracker.h"
#include "src/trace_processor/importers/common/stack_profile_tracker.h"
#include "src/trace_processor/importers/common/track_tracker.h"
-#include "src/trace_processor/importers/ftrace/ftrace_sched_event_tracker.h"
+#include "src/trace_processor/importers/ftrace/sched_event_tracker.h"
#include "src/trace_processor/importers/proto/additional_modules.h"
#include "src/trace_processor/importers/proto/default_modules.h"
#include "src/trace_processor/importers/proto/proto_trace_parser.h"
@@ -91,10 +91,10 @@
using ::testing::Return;
using ::testing::ReturnRef;
using ::testing::UnorderedElementsAreArray;
-class MockSchedEventTracker : public FtraceSchedEventTracker {
+class MockSchedEventTracker : public SchedEventTracker {
public:
explicit MockSchedEventTracker(TraceProcessorContext* context)
- : FtraceSchedEventTracker(context) {}
+ : SchedEventTracker(context) {}
MOCK_METHOD(void,
PushSchedSwitch,
@@ -244,7 +244,7 @@
event_ = new MockEventTracker(&context_);
context_.event_tracker.reset(event_);
sched_ = new MockSchedEventTracker(&context_);
- context_.ftrace_sched_tracker.reset(sched_);
+ context_.sched_tracker.reset(sched_);
process_ = new NiceMock<MockProcessTracker>(&context_);
context_.process_tracker.reset(process_);
slice_ = new NiceMock<MockSliceTracker>(&context_);
diff --git a/src/trace_processor/importers/proto/proto_trace_parser_unittest.cc b/src/trace_processor/importers/proto/proto_trace_parser_unittest.cc
index 11a45f5..148bf60 100644
--- a/src/trace_processor/importers/proto/proto_trace_parser_unittest.cc
+++ b/src/trace_processor/importers/proto/proto_trace_parser_unittest.cc
@@ -30,7 +30,7 @@
#include "src/trace_processor/importers/common/slice_tracker.h"
#include "src/trace_processor/importers/common/stack_profile_tracker.h"
#include "src/trace_processor/importers/common/track_tracker.h"
-#include "src/trace_processor/importers/ftrace/ftrace_sched_event_tracker.h"
+#include "src/trace_processor/importers/ftrace/sched_event_tracker.h"
#include "src/trace_processor/importers/proto/additional_modules.h"
#include "src/trace_processor/importers/proto/default_modules.h"
#include "src/trace_processor/importers/proto/proto_trace_parser.h"
@@ -106,10 +106,10 @@
}
} // namespace
-class MockSchedEventTracker : public FtraceSchedEventTracker {
+class MockSchedEventTracker : public SchedEventTracker {
public:
explicit MockSchedEventTracker(TraceProcessorContext* context)
- : FtraceSchedEventTracker(context) {}
+ : SchedEventTracker(context) {}
MOCK_METHOD(void,
PushSchedSwitch,
@@ -260,7 +260,7 @@
event_ = new MockEventTracker(&context_);
context_.event_tracker.reset(event_);
sched_ = new MockSchedEventTracker(&context_);
- context_.ftrace_sched_tracker.reset(sched_);
+ context_.sched_tracker.reset(sched_);
process_ = new NiceMock<MockProcessTracker>(&context_);
context_.process_tracker.reset(process_);
slice_ = new NiceMock<MockSliceTracker>(&context_);
diff --git a/src/trace_processor/importers/systrace/systrace_line_parser.cc b/src/trace_processor/importers/systrace/systrace_line_parser.cc
index 7bfb844..ccf711e 100644
--- a/src/trace_processor/importers/systrace/systrace_line_parser.cc
+++ b/src/trace_processor/importers/systrace/systrace_line_parser.cc
@@ -23,10 +23,10 @@
#include "src/trace_processor/importers/common/event_tracker.h"
#include "src/trace_processor/importers/common/process_tracker.h"
#include "src/trace_processor/importers/common/slice_tracker.h"
-#include "src/trace_processor/importers/common/thread_state_tracker.h"
#include "src/trace_processor/importers/common/track_tracker.h"
#include "src/trace_processor/importers/ftrace/binder_tracker.h"
-#include "src/trace_processor/importers/ftrace/ftrace_sched_event_tracker.h"
+#include "src/trace_processor/importers/ftrace/sched_event_tracker.h"
+#include "src/trace_processor/importers/ftrace/thread_state_tracker.h"
#include "src/trace_processor/importers/systrace/systrace_parser.h"
#include "src/trace_processor/types/task_state.h"
@@ -107,7 +107,7 @@
return util::Status("Could not parse sched_switch");
}
- FtraceSchedEventTracker::GetOrCreate(context_)->PushSchedSwitch(
+ SchedEventTracker::GetOrCreate(context_)->PushSchedSwitch(
line.cpu, line.ts, prev_pid.value(), prev_comm, prev_prio.value(),
prev_state, next_pid.value(), next_comm, next_prio.value());
} else if (line.event_name == "tracing_mark_write" ||
diff --git a/src/trace_processor/perfetto_sql/engine/BUILD.gn b/src/trace_processor/perfetto_sql/engine/BUILD.gn
index 122d576..6a3baf1 100644
--- a/src/trace_processor/perfetto_sql/engine/BUILD.gn
+++ b/src/trace_processor/perfetto_sql/engine/BUILD.gn
@@ -35,7 +35,10 @@
"../..:metatrace",
"../../../../gn:default_deps",
"../../../../gn:sqlite",
+ "../../../../include/perfetto/trace_processor:basic_types",
+ "../../../../protos/perfetto/trace_processor:zero",
"../../../base",
+ "../../containers",
"../../db",
"../../perfetto_sql/intrinsics/functions:interface",
"../../perfetto_sql/intrinsics/table_functions:interface",
diff --git a/src/trace_processor/perfetto_sql/engine/perfetto_sql_engine.cc b/src/trace_processor/perfetto_sql/engine/perfetto_sql_engine.cc
index e29933b..86d96bc 100644
--- a/src/trace_processor/perfetto_sql/engine/perfetto_sql_engine.cc
+++ b/src/trace_processor/perfetto_sql/engine/perfetto_sql_engine.cc
@@ -16,12 +16,16 @@
#include "src/trace_processor/perfetto_sql/engine/perfetto_sql_engine.h"
+#include <algorithm>
+#include <array>
#include <cctype>
#include <cstddef>
#include <cstdint>
+#include <cstring>
#include <memory>
#include <optional>
#include <string>
+#include <string_view>
#include <utility>
#include <variant>
#include <vector>
@@ -31,6 +35,7 @@
#include "perfetto/ext/base/status_or.h"
#include "perfetto/ext/base/string_utils.h"
#include "perfetto/ext/base/string_view.h"
+#include "src/trace_processor/containers/string_pool.h"
#include "src/trace_processor/db/runtime_table.h"
#include "src/trace_processor/db/table.h"
#include "src/trace_processor/perfetto_sql/engine/created_function.h"
@@ -40,13 +45,18 @@
#include "src/trace_processor/perfetto_sql/engine/runtime_table_function.h"
#include "src/trace_processor/perfetto_sql/intrinsics/table_functions/static_table_function.h"
#include "src/trace_processor/sqlite/db_sqlite_table.h"
+#include "src/trace_processor/sqlite/query_cache.h"
#include "src/trace_processor/sqlite/scoped_db.h"
#include "src/trace_processor/sqlite/sql_source.h"
#include "src/trace_processor/sqlite/sqlite_engine.h"
#include "src/trace_processor/sqlite/sqlite_table.h"
#include "src/trace_processor/tp_metatrace.h"
+#include "src/trace_processor/util/sql_argument.h"
+#include "src/trace_processor/util/sql_modules.h"
#include "src/trace_processor/util/status_macros.h"
+#include "protos/perfetto/trace_processor/metatrace_categories.pbzero.h"
+
// Implementation details
// ----------------------
//
@@ -140,18 +150,18 @@
});
bool IsTokenAllowedInMacro(const std::string& view) {
- for (const char* allowed_token : kTokensAllowedInMacro) {
- if (base::ToLower(view) == base::ToLower(allowed_token)) {
- return true;
- }
- }
- return false;
+ std::string lower = base::ToLower(view);
+ return std::any_of(kTokensAllowedInMacro.begin(), kTokensAllowedInMacro.end(),
+ [&lower](const std::string& allowed_token) {
+ return lower == base::ToLower(allowed_token);
+ });
}
std::string GetTokenNamesAllowedInMacro() {
std::vector<std::string> result;
+ result.reserve(kTokensAllowedInMacro.size());
for (const char* token : kTokensAllowedInMacro) {
- result.push_back(token);
+ result.emplace_back(token);
}
return base::Join(result, ", ");
}
@@ -177,7 +187,7 @@
auto context = std::make_unique<DbSqliteTable::Context>(
query_cache_.get(),
[this](const std::string& name) {
- auto table = runtime_tables_.Find(name);
+ auto* table = runtime_tables_.Find(name);
PERFETTO_CHECK(table);
return table->get();
},
@@ -270,10 +280,9 @@
std::optional<SqlSource> source;
if (auto* cf = std::get_if<PerfettoSqlParser::CreateFunction>(
&parser.statement())) {
- auto source_or = ExecuteCreateFunction(*cf, parser);
- RETURN_IF_ERROR(
- AddTracebackIfNeeded(source_or.status(), parser.statement_sql()));
- source = std::move(source_or.value());
+ RETURN_IF_ERROR(AddTracebackIfNeeded(ExecuteCreateFunction(*cf),
+ parser.statement_sql()));
+ source = RewriteToDummySql(parser.statement_sql());
} else if (auto* cst = std::get_if<PerfettoSqlParser::CreateTable>(
&parser.statement())) {
RETURN_IF_ERROR(AddTracebackIfNeeded(ExecuteCreateTable(*cst),
@@ -368,7 +377,7 @@
base::Status PerfettoSqlEngine::RegisterRuntimeFunction(
bool replace,
const FunctionPrototype& prototype,
- std::string return_type_str,
+ const std::string& return_type_str,
SqlSource sql) {
// Parse the return type into a enum format.
auto opt_return_type =
@@ -403,8 +412,8 @@
std::move(created_fn_ctx)));
runtime_function_count_++;
}
- return CreatedFunction::Prepare(ctx, std::move(prototype),
- std::move(*opt_return_type), std::move(sql));
+ return CreatedFunction::Prepare(ctx, prototype, *opt_return_type,
+ std::move(sql));
}
base::Status PerfettoSqlEngine::ExecuteCreateTable(
@@ -468,6 +477,13 @@
}
ASSIGN_OR_RETURN(auto table, std::move(builder).Build(rows));
+ // TODO(lalitm): unfortunately, in the (very unlikely) event that there is a
+ // sqlite3_interrupt call between the DROP and CREATE, we can end up with the
+ // non-atomic query execution. Fixing this is extremely difficult as it
+ // involves telling SQLite that we want the drop/create to be atomic.
+ //
+ // We would need to do with the transaction API but given we have no usage of
+ // this until now, investigating that needs some proper work.
if (runtime_tables_.Find(create_table.name)) {
if (!create_table.replace) {
return base::ErrStatus("CREATE PERFETTO TABLE: table '%s' already exists",
@@ -483,9 +499,15 @@
runtime_tables_.Insert(create_table.name, std::move(table));
base::StackString<1024> create("CREATE VIRTUAL TABLE %s USING runtime_table",
create_table.name.c_str());
- return Execute(
- SqlSource::FromTraceProcessorImplementation(create.ToStdString()))
- .status();
+ auto status =
+ Execute(SqlSource::FromTraceProcessorImplementation(create.ToStdString()))
+ .status();
+ if (!status.ok()) {
+ // If the registration of the table with SQLite failed, erase the state
+ // we hold.
+ PERFETTO_CHECK(runtime_tables_.Erase(create_table.name));
+ }
+ return status;
}
base::Status PerfettoSqlEngine::ExecuteCreateView(
@@ -520,8 +542,8 @@
base::Status PerfettoSqlEngine::EnableSqlFunctionMemoization(
const std::string& name) {
constexpr size_t kSupportedArgCount = 1;
- CreatedFunction::Context* ctx = static_cast<CreatedFunction::Context*>(
- sqlite_engine()->GetFunctionContext(name.c_str(), kSupportedArgCount));
+ auto* ctx = static_cast<CreatedFunction::Context*>(
+ sqlite_engine()->GetFunctionContext(name, kSupportedArgCount));
if (!ctx) {
return base::ErrStatus(
"EXPERIMENTAL_MEMOIZE: Function %s(INT) does not exist", name.c_str());
@@ -544,7 +566,7 @@
}
std::string module_name = sql_modules::GetModuleName(key);
- auto module = FindModule(module_name);
+ auto* module = FindModule(module_name);
if (!module) {
return base::ErrStatus("INCLUDE: Unknown module name provided - %s",
key.c_str());
@@ -600,25 +622,26 @@
return base::OkStatus();
}
-base::StatusOr<SqlSource> PerfettoSqlEngine::ExecuteCreateFunction(
- const PerfettoSqlParser::CreateFunction& cf,
- const PerfettoSqlParser& parser) {
+base::Status PerfettoSqlEngine::ExecuteCreateFunction(
+ const PerfettoSqlParser::CreateFunction& cf) {
if (!cf.is_table) {
- RETURN_IF_ERROR(
- RegisterRuntimeFunction(cf.replace, cf.prototype, cf.returns, cf.sql));
- return RewriteToDummySql(parser.statement_sql());
+ return RegisterRuntimeFunction(cf.replace, cf.prototype, cf.returns,
+ cf.sql);
}
- RuntimeTableFunction::State state{cf.sql, cf.prototype, {}, std::nullopt};
+ std::unique_ptr<RuntimeTableFunction::State> state(
+ new RuntimeTableFunction::State{cf.sql, cf.prototype, {}, std::nullopt});
// Parse the return type into a enum format.
- base::Status status =
- sql_argument::ParseArgumentDefinitions(cf.returns, state.return_values);
- if (!status.ok()) {
- return base::ErrStatus(
- "CREATE PERFETTO FUNCTION[prototype=%s, return=%s]: unknown return "
- "type specified",
- state.prototype.ToString().c_str(), cf.returns.c_str());
+ {
+ base::Status status = sql_argument::ParseArgumentDefinitions(
+ cf.returns, state->return_values);
+ if (!status.ok()) {
+ return base::ErrStatus(
+ "CREATE PERFETTO FUNCTION[prototype=%s, return=%s]: unknown return "
+ "type specified",
+ state->prototype.ToString().c_str(), cf.returns.c_str());
+ }
}
// Verify that the provided SQL prepares to a statement correctly.
@@ -638,7 +661,7 @@
return base::ErrStatus(
"%s: \"Nameless\" SQL parameters cannot be used in the SQL "
"statements of view functions.",
- state.prototype.function_name.c_str());
+ state->prototype.function_name.c_str());
}
if (!base::StringView(name).StartsWith("$")) {
@@ -646,71 +669,81 @@
"%s: invalid parameter name %s used in the SQL definition of "
"the view function: all parameters must be prefixed with '$' not "
"':' or '@'.",
- state.prototype.function_name.c_str(), name);
+ state->prototype.function_name.c_str(), name);
}
- auto it = std::find_if(state.prototype.arguments.begin(),
- state.prototype.arguments.end(),
+ auto it = std::find_if(state->prototype.arguments.begin(),
+ state->prototype.arguments.end(),
[name](const sql_argument::ArgumentDefinition& arg) {
return arg.dollar_name() == name;
});
- if (it == state.prototype.arguments.end()) {
+ if (it == state->prototype.arguments.end()) {
return base::ErrStatus(
"%s: parameter %s does not appear in the list of arguments in the "
"prototype of the view function.",
- state.prototype.function_name.c_str(), name);
+ state->prototype.function_name.c_str(), name);
}
}
// Verify that the prepared statement column count matches the return
// count.
- uint32_t col_count =
+ auto col_count =
static_cast<uint32_t>(sqlite3_column_count(stmt.sqlite_stmt()));
- if (col_count != state.return_values.size()) {
+ if (col_count != state->return_values.size()) {
return base::ErrStatus(
"%s: number of return values %u does not match SQL statement column "
"count %zu.",
- state.prototype.function_name.c_str(), col_count,
- state.return_values.size());
+ state->prototype.function_name.c_str(), col_count,
+ state->return_values.size());
}
// Verify that the return names matches the prepared statment column names.
for (uint32_t i = 0; i < col_count; ++i) {
const char* name =
sqlite3_column_name(stmt.sqlite_stmt(), static_cast<int>(i));
- if (name != state.return_values[i].name()) {
+ if (name != state->return_values[i].name()) {
return base::ErrStatus(
"%s: column %s at index %u does not match return value name %s.",
- state.prototype.function_name.c_str(), name, i,
- state.return_values[i].name().c_str());
+ state->prototype.function_name.c_str(), name, i,
+ state->return_values[i].name().c_str());
}
}
- state.reusable_stmt = std::move(stmt);
+ state->reusable_stmt = std::move(stmt);
- std::string fn_name = state.prototype.function_name;
- std::string lower_name = base::ToLower(state.prototype.function_name);
+ // TODO(lalitm): this suffers the same non-atomic DROP/CREATE problem as
+ // CREATE PERFETTO TABLE implementation above: see the comment there for
+ // more info on this.
+ std::string fn_name = state->prototype.function_name;
+ std::string lower_name = base::ToLower(state->prototype.function_name);
if (runtime_table_fn_states_.Find(lower_name)) {
if (!cf.replace) {
return base::ErrStatus("Table function named %s already exists",
- state.prototype.function_name.c_str());
+ state->prototype.function_name.c_str());
}
// This will cause |OnTableFunctionDestroyed| below to be executed.
base::StackString<1024> drop("DROP TABLE %s",
- state.prototype.function_name.c_str());
+ state->prototype.function_name.c_str());
auto res = Execute(
SqlSource::FromTraceProcessorImplementation(drop.ToStdString()));
RETURN_IF_ERROR(res.status());
}
- auto it_and_inserted = runtime_table_fn_states_.Insert(
- lower_name,
- std::make_unique<RuntimeTableFunction::State>(std::move(state)));
+ auto it_and_inserted =
+ runtime_table_fn_states_.Insert(lower_name, std::move(state));
PERFETTO_CHECK(it_and_inserted.second);
base::StackString<1024> create(
"CREATE VIRTUAL TABLE %s USING runtime_table_function", fn_name.c_str());
- return cf.sql.RewriteAllIgnoreExisting(
- SqlSource::FromTraceProcessorImplementation(create.ToStdString()));
+ auto status = Execute(cf.sql.RewriteAllIgnoreExisting(
+ SqlSource::FromTraceProcessorImplementation(
+ create.ToStdString())))
+ .status();
+ if (!status.ok()) {
+ // If the registration of the table with SQLite failed, erase the state
+ // we hold.
+ PERFETTO_CHECK(runtime_table_fn_states_.Erase(lower_name));
+ }
+ return status;
}
base::Status PerfettoSqlEngine::ExecuteCreateMacro(
@@ -736,6 +769,7 @@
}
std::vector<std::string> args;
+ args.reserve(create_macro.args.size());
for (const auto& arg : create_macro.args) {
args.push_back(arg.first.sql());
}
@@ -745,7 +779,7 @@
std::move(args),
create_macro.sql,
};
- if (auto it = macros_.Find(create_macro.name.sql()); it) {
+ if (auto* it = macros_.Find(create_macro.name.sql()); it) {
if (!create_macro.replace) {
// TODO(lalitm): add a link to create macro documentation.
return base::ErrStatus("%sMacro already exists",
@@ -762,7 +796,7 @@
RuntimeTableFunction::State* PerfettoSqlEngine::GetRuntimeTableFunctionState(
const std::string& name) const {
- auto it = runtime_table_fn_states_.Find(base::ToLower(name));
+ auto* it = runtime_table_fn_states_.Find(base::ToLower(name));
PERFETTO_CHECK(it);
return it->get();
}
@@ -775,8 +809,8 @@
base::StatusOr<std::vector<std::string>>
PerfettoSqlEngine::GetColumnNamesFromSelectStatement(
const SqliteEngine::PreparedStatement& stmt,
- const char* tag) const {
- uint32_t columns =
+ const char* tag) {
+ auto columns =
static_cast<uint32_t>(sqlite3_column_count(stmt.sqlite_stmt()));
std::vector<std::string> column_names;
for (uint32_t i = 0; i < columns; ++i) {
@@ -804,7 +838,7 @@
base::Status PerfettoSqlEngine::ValidateColumnNames(
const std::vector<std::string>& column_names,
const std::vector<sql_argument::ArgumentDefinition>& schema,
- const char* tag) const {
+ const char* tag) {
// If the user has not provided a schema, we have nothing to validate.
if (schema.empty()) {
return base::OkStatus();
@@ -860,13 +894,13 @@
const RuntimeTable* PerfettoSqlEngine::GetRuntimeTableOrNull(
std::string_view name) const {
- auto table_ptr = runtime_tables_.Find(name.data());
+ auto* table_ptr = runtime_tables_.Find(name.data());
return table_ptr ? table_ptr->get() : nullptr;
}
const Table* PerfettoSqlEngine::GetStaticTableOrNull(
std::string_view name) const {
- auto table_ptr = static_tables_.Find(name.data());
+ auto* table_ptr = static_tables_.Find(name.data());
return table_ptr ? *table_ptr : nullptr;
}
diff --git a/src/trace_processor/perfetto_sql/engine/perfetto_sql_engine.h b/src/trace_processor/perfetto_sql/engine/perfetto_sql_engine.h
index 60772ec..69e6b58 100644
--- a/src/trace_processor/perfetto_sql/engine/perfetto_sql_engine.h
+++ b/src/trace_processor/perfetto_sql/engine/perfetto_sql_engine.h
@@ -19,24 +19,30 @@
#include <cstdint>
#include <memory>
-#include <optional>
#include <string>
+#include <string_view>
+#include <utility>
+#include <vector>
#include "perfetto/base/logging.h"
#include "perfetto/base/status.h"
#include "perfetto/ext/base/flat_hash_map.h"
#include "perfetto/ext/base/status_or.h"
+#include "perfetto/trace_processor/basic_types.h"
+#include "src/trace_processor/containers/string_pool.h"
#include "src/trace_processor/db/runtime_table.h"
#include "src/trace_processor/db/table.h"
+#include "src/trace_processor/perfetto_sql/engine/function_util.h"
#include "src/trace_processor/perfetto_sql/engine/perfetto_sql_parser.h"
#include "src/trace_processor/perfetto_sql/engine/perfetto_sql_preprocessor.h"
#include "src/trace_processor/perfetto_sql/engine/runtime_table_function.h"
#include "src/trace_processor/perfetto_sql/intrinsics/functions/sql_function.h"
#include "src/trace_processor/perfetto_sql/intrinsics/table_functions/static_table_function.h"
-#include "src/trace_processor/sqlite/scoped_db.h"
+#include "src/trace_processor/sqlite/query_cache.h"
#include "src/trace_processor/sqlite/sql_source.h"
#include "src/trace_processor/sqlite/sqlite_engine.h"
#include "src/trace_processor/sqlite/sqlite_utils.h"
+#include "src/trace_processor/util/sql_argument.h"
#include "src/trace_processor/util/sql_modules.h"
namespace perfetto::trace_processor {
@@ -111,7 +117,7 @@
// of |return_type| and is implemented by executing the SQL statement |sql|.
base::Status RegisterRuntimeFunction(bool replace,
const FunctionPrototype& prototype,
- std::string return_type,
+ const std::string& return_type,
SqlSource sql);
// Enables memoization for the given SQL function.
@@ -176,9 +182,7 @@
const Table* GetStaticTableOrNull(std::string_view) const;
private:
- base::StatusOr<SqlSource> ExecuteCreateFunction(
- const PerfettoSqlParser::CreateFunction&,
- const PerfettoSqlParser& parser);
+ base::Status ExecuteCreateFunction(const PerfettoSqlParser::CreateFunction&);
base::Status ExecuteInclude(const PerfettoSqlParser::Include&,
const PerfettoSqlParser& parser);
@@ -200,16 +204,16 @@
// Get the column names from a statement.
// |operator_name| is used in the error message if the statement is invalid.
- base::StatusOr<std::vector<std::string>> GetColumnNamesFromSelectStatement(
- const SqliteEngine::PreparedStatement& stmt,
- const char* tag) const;
+ static base::StatusOr<std::vector<std::string>>
+ GetColumnNamesFromSelectStatement(const SqliteEngine::PreparedStatement& stmt,
+ const char* tag);
// Validates that the column names in |column_names| match the |schema|.
// |operator_name| is used in the error message if the statement is invalid.
- base::Status ValidateColumnNames(
+ static base::Status ValidateColumnNames(
const std::vector<std::string>& column_names,
const std::vector<sql_argument::ArgumentDefinition>& schema,
- const char* operator_name) const;
+ const char* operator_name);
// Given a module and a key, include the correct file(s) from the module.
// The key can contain a wildcard to include all files in the module with the
@@ -255,7 +259,7 @@
template <typename Function>
void WrapSqlFunction(sqlite3_context* ctx, int argc, sqlite3_value** argv) {
using Context = typename Function::Context;
- Context* ud = static_cast<Context*>(sqlite3_user_data(ctx));
+ auto* ud = static_cast<Context*>(sqlite3_user_data(ctx));
ScopedCleanup<Function> scoped_cleanup{ud};
SqlValue value{};
@@ -314,14 +318,14 @@
base::Status PerfettoSqlEngine::RegisterStaticFunction(
const char* name,
int argc,
- std::unique_ptr<typename Function::Context> user_data,
+ std::unique_ptr<typename Function::Context> ctx,
bool deterministic) {
// Metric proto builder functions can be reregistered: don't double count when
// this happens.
if (!engine_->GetFunctionContext(name, argc)) {
static_function_count_++;
}
- return RegisterFunctionWithSqlite<Function>(name, argc, std::move(user_data),
+ return RegisterFunctionWithSqlite<Function>(name, argc, std::move(ctx),
deterministic);
}
@@ -329,14 +333,14 @@
base::Status PerfettoSqlEngine::RegisterFunctionWithSqlite(
const char* name,
int argc,
- std::unique_ptr<typename Function::Context> user_data,
+ std::unique_ptr<typename Function::Context> ctx,
bool deterministic) {
auto ctx_destructor = [](void* ptr) {
delete static_cast<typename Function::Context*>(ptr);
};
return engine_->RegisterFunction(
name, argc, perfetto_sql_internal::WrapSqlFunction<Function>,
- user_data.release(), ctx_destructor, deterministic);
+ ctx.release(), ctx_destructor, deterministic);
}
} // namespace perfetto::trace_processor
diff --git a/src/trace_processor/sqlite/sqlite_engine.cc b/src/trace_processor/sqlite/sqlite_engine.cc
index 25cc651..9c5da35 100644
--- a/src/trace_processor/sqlite/sqlite_engine.cc
+++ b/src/trace_processor/sqlite/sqlite_engine.cc
@@ -139,14 +139,14 @@
}
}
- // Reset the database itself.
- db_.reset();
-
- // SQLite is not guaranteed to pick saved tables back up when destroyed as
- // from it's perspective, it has called xDisconnect. Make sure to do that
- // ourselves.
+ // SQLite will not pick saved tables back up when destroyed as, from it's
+ // perspective, it has called xDisconnect. Make sure to do that ourselves.
saved_tables_.Clear();
+ // Reset the database itself. We need to do this after clearing the saved
+ // tables as the saved tables could hold onto prepared statements.
+ db_.reset();
+
// The above operations should have cleared all the tables.
if (PERFETTO_UNLIKELY(sqlite_tables_.size() != 0)) {
std::vector<std::string> tables;
diff --git a/src/trace_processor/trace_processor_context.cc b/src/trace_processor/trace_processor_context.cc
index 908fdea..c7cea38 100644
--- a/src/trace_processor/trace_processor_context.cc
+++ b/src/trace_processor/trace_processor_context.cc
@@ -29,7 +29,6 @@
#include "src/trace_processor/importers/common/global_args_tracker.h"
#include "src/trace_processor/importers/common/metadata_tracker.h"
#include "src/trace_processor/importers/common/process_tracker.h"
-#include "src/trace_processor/importers/common/sched_event_tracker.h"
#include "src/trace_processor/importers/common/slice_tracker.h"
#include "src/trace_processor/importers/common/slice_translation_table.h"
#include "src/trace_processor/importers/common/stack_profile_tracker.h"
diff --git a/src/trace_processor/trace_processor_storage_impl.cc b/src/trace_processor/trace_processor_storage_impl.cc
index 1f06a0f..05b88c0 100644
--- a/src/trace_processor/trace_processor_storage_impl.cc
+++ b/src/trace_processor/trace_processor_storage_impl.cc
@@ -28,7 +28,6 @@
#include "src/trace_processor/importers/common/flow_tracker.h"
#include "src/trace_processor/importers/common/metadata_tracker.h"
#include "src/trace_processor/importers/common/process_tracker.h"
-#include "src/trace_processor/importers/common/sched_event_tracker.h"
#include "src/trace_processor/importers/common/slice_tracker.h"
#include "src/trace_processor/importers/common/slice_translation_table.h"
#include "src/trace_processor/importers/common/stack_profile_tracker.h"
@@ -60,7 +59,6 @@
new SliceTranslationTable(context_.storage.get()));
context_.flow_tracker.reset(new FlowTracker(&context_));
context_.event_tracker.reset(new EventTracker(&context_));
- context_.sched_event_tracker.reset(new SchedEventTracker(&context_));
context_.process_tracker.reset(new ProcessTracker(&context_));
context_.clock_tracker.reset(new ClockTracker(&context_));
context_.clock_converter.reset(new ClockConverter(&context_));
diff --git a/src/trace_processor/types/trace_processor_context.h b/src/trace_processor/types/trace_processor_context.h
index 3b3336c..ad4e148 100644
--- a/src/trace_processor/types/trace_processor_context.h
+++ b/src/trace_processor/types/trace_processor_context.h
@@ -60,7 +60,6 @@
class ProtoImporterModule;
class TrackEventModule;
class ProcessTracker;
-class SchedEventTracker;
class SliceTracker;
class SliceTranslationTable;
class FlowTracker;
@@ -99,7 +98,6 @@
std::unique_ptr<FlowTracker> flow_tracker;
std::unique_ptr<ProcessTracker> process_tracker;
std::unique_ptr<EventTracker> event_tracker;
- std::unique_ptr<SchedEventTracker> sched_event_tracker;
std::unique_ptr<ClockTracker> clock_tracker;
std::unique_ptr<ClockConverter> clock_converter;
std::unique_ptr<PerfSampleTracker> perf_sample_tracker;
@@ -114,6 +112,7 @@
std::unique_ptr<Destructible> android_probes_tracker; // AndroidProbesTracker
std::unique_ptr<Destructible> binder_tracker; // BinderTracker
std::unique_ptr<Destructible> heap_graph_tracker; // HeapGraphTracker
+ std::unique_ptr<Destructible> sched_tracker; // SchedEventTracker
std::unique_ptr<Destructible> syscall_tracker; // SyscallTracker
std::unique_ptr<Destructible> system_info_tracker; // SystemInfoTracker
std::unique_ptr<Destructible> v4l2_tracker; // V4l2Tracker
@@ -126,8 +125,6 @@
std::unique_ptr<Destructible>
shell_transitions_tracker; // ShellTransitionsTracker
std::unique_ptr<Destructible> v8_tracker; // V8Tracker
- std::unique_ptr<Destructible>
- ftrace_sched_tracker; // FtraceSchedEventTracker
// These fields are trace readers which will be called by |forwarding_parser|
// once the format of the trace is discovered. They are placed here as they
diff --git a/ui/src/controller/pivot_table_controller.ts b/ui/src/controller/pivot_table_controller.ts
index 230a151..864c402 100644
--- a/ui/src/controller/pivot_table_controller.ts
+++ b/ui/src/controller/pivot_table_controller.ts
@@ -15,7 +15,6 @@
*/
import {Actions} from '../common/actions';
-import {DEFAULT_CHANNEL, getCurrentChannel} from '../common/channels';
import {
AreaSelection,
PivotTableQuery,
@@ -39,8 +38,7 @@
id: 'pivotTable',
name: 'Pivot tables V2',
description: 'Second version of pivot table',
- // Enabled in canary and autopush by default.
- defaultValue: getCurrentChannel() !== DEFAULT_CHANNEL,
+ defaultValue: true,
});
function expectNumber(value: ColumnType): number {