1 /*
2 * Copyright (C) 2021 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 #include "src/trace_processor/prelude/table_functions/experimental_flat_slice.h"
17
18 #include "test/gtest_and_gmock.h"
19
20 namespace perfetto {
21 namespace trace_processor {
22 namespace {
23
24 class TableInseter {
25 public:
Insert(int64_t ts,int64_t dur,uint32_t depth,TrackId track_id)26 void Insert(int64_t ts, int64_t dur, uint32_t depth, TrackId track_id) {
27 tables::SliceTable::Row row;
28 row.ts = ts;
29 row.dur = dur;
30 row.depth = depth;
31 row.track_id = track_id;
32 rows_.emplace_back(std::move(row));
33 }
34
Populate(tables::SliceTable & table)35 void Populate(tables::SliceTable& table) {
36 using R = tables::SliceTable::Row;
37 std::sort(rows_.begin(), rows_.end(),
38 [](const R& a, const R& b) { return a.ts < b.ts; });
39 for (const auto& row : rows_) {
40 table.Insert(row);
41 }
42 rows_.clear();
43 }
44
45 private:
46 std::vector<tables::SliceTable::Row> rows_;
47 };
48
49 class TableAsserter {
50 public:
TableAsserter(Table table)51 TableAsserter(Table table) : table_(std::move(table)) {}
52
NextSlice(int64_t ts,int64_t dur)53 void NextSlice(int64_t ts, int64_t dur) {
54 ++idx_;
55 ASSERT_LT(idx_, table_.row_count());
56 ASSERT_EQ(table_.GetTypedColumnByName<int64_t>("ts")[idx_], ts)
57 << "where idx_ = " << idx_;
58 ASSERT_EQ(table_.GetTypedColumnByName<int64_t>("dur")[idx_], dur)
59 << "where idx_ = " << idx_;
60 }
61
HasMoreSlices()62 bool HasMoreSlices() { return idx_ + 1 < table_.row_count(); }
63
64 private:
65 Table table_;
66 uint32_t idx_ = std::numeric_limits<uint32_t>::max();
67 };
68
TEST(ExperimentalFlatSlice,Smoke)69 TEST(ExperimentalFlatSlice, Smoke) {
70 StringPool pool;
71 TableInseter inserter;
72 tables::SliceTable table(&pool);
73
74 // A simple stack on track 1.
75 inserter.Insert(100, 10, 0, TrackId{1});
76 inserter.Insert(104, 6, 1, TrackId{1});
77 inserter.Insert(107, 1, 2, TrackId{1});
78
79 // Back to back slices with a gap on track 2.
80 inserter.Insert(200, 10, 0, TrackId{2});
81 inserter.Insert(210, 10, 0, TrackId{2});
82 inserter.Insert(230, 10, 0, TrackId{2});
83
84 // Deep nesting on track 3.
85 inserter.Insert(300, 100, 0, TrackId{3});
86 inserter.Insert(301, 98, 1, TrackId{3});
87 inserter.Insert(302, 96, 2, TrackId{3});
88 inserter.Insert(303, 94, 3, TrackId{3});
89 inserter.Insert(304, 92, 4, TrackId{3});
90 inserter.Insert(305, 90, 5, TrackId{3});
91
92 // Populate the table.
93 inserter.Populate(table);
94
95 auto out = ExperimentalFlatSlice::ComputeFlatSliceTable(table, &pool, 0, 400);
96 auto sorted = out->Sort({out->track_id().ascending(), out->ts().ascending()});
97
98 TableAsserter asserter(std::move(sorted));
99
100 // Track 1's slices.
101 ASSERT_NO_FATAL_FAILURE(asserter.NextSlice(0, 100));
102 ASSERT_NO_FATAL_FAILURE(asserter.NextSlice(100, 4));
103 ASSERT_NO_FATAL_FAILURE(asserter.NextSlice(104, 3));
104 ASSERT_NO_FATAL_FAILURE(asserter.NextSlice(107, 1));
105 ASSERT_NO_FATAL_FAILURE(asserter.NextSlice(108, 2));
106 ASSERT_NO_FATAL_FAILURE(asserter.NextSlice(110, 0));
107 ASSERT_NO_FATAL_FAILURE(asserter.NextSlice(110, 290));
108
109 // Track 2's slices.
110 ASSERT_NO_FATAL_FAILURE(asserter.NextSlice(0, 200));
111 ASSERT_NO_FATAL_FAILURE(asserter.NextSlice(200, 10));
112 ASSERT_NO_FATAL_FAILURE(asserter.NextSlice(210, 0));
113 ASSERT_NO_FATAL_FAILURE(asserter.NextSlice(210, 10));
114 ASSERT_NO_FATAL_FAILURE(asserter.NextSlice(220, 10));
115 ASSERT_NO_FATAL_FAILURE(asserter.NextSlice(230, 10));
116 ASSERT_NO_FATAL_FAILURE(asserter.NextSlice(240, 160));
117
118 // Track 3's slices.
119 ASSERT_NO_FATAL_FAILURE(asserter.NextSlice(0, 300));
120 ASSERT_NO_FATAL_FAILURE(asserter.NextSlice(300, 1));
121 ASSERT_NO_FATAL_FAILURE(asserter.NextSlice(301, 1));
122 ASSERT_NO_FATAL_FAILURE(asserter.NextSlice(302, 1));
123 ASSERT_NO_FATAL_FAILURE(asserter.NextSlice(303, 1));
124 ASSERT_NO_FATAL_FAILURE(asserter.NextSlice(304, 1));
125 ASSERT_NO_FATAL_FAILURE(asserter.NextSlice(305, 90));
126 ASSERT_NO_FATAL_FAILURE(asserter.NextSlice(395, 1));
127 ASSERT_NO_FATAL_FAILURE(asserter.NextSlice(396, 1));
128 ASSERT_NO_FATAL_FAILURE(asserter.NextSlice(397, 1));
129 ASSERT_NO_FATAL_FAILURE(asserter.NextSlice(398, 1));
130 ASSERT_NO_FATAL_FAILURE(asserter.NextSlice(399, 1));
131 ASSERT_NO_FATAL_FAILURE(asserter.NextSlice(400, 0));
132
133 ASSERT_FALSE(asserter.HasMoreSlices());
134 }
135
TEST(ExperimentalFlatSlice,Bounds)136 TEST(ExperimentalFlatSlice, Bounds) {
137 StringPool pool;
138 TableInseter inserter;
139 tables::SliceTable table(&pool);
140
141 /// Our timebounds is between 200 and 300.
142 int64_t start = 200;
143 int64_t end = 300;
144
145 // Track 1 has all events inside bounds.
146 inserter.Insert(200, 10, 0, TrackId{1});
147 inserter.Insert(210, 10, 0, TrackId{1});
148 inserter.Insert(230, 10, 0, TrackId{1});
149
150 // Track 2 has a two stacks, first partially inside at start, second partially
151 // inside at end.
152 // First stack.
153 inserter.Insert(190, 20, 0, TrackId{2});
154 inserter.Insert(200, 9, 1, TrackId{2});
155 inserter.Insert(201, 1, 2, TrackId{2});
156
157 // Second stack.
158 inserter.Insert(290, 20, 0, TrackId{2});
159 inserter.Insert(299, 2, 1, TrackId{2});
160 inserter.Insert(300, 1, 2, TrackId{2});
161
162 // Track 3 has two stacks but *only* outside bounds.
163 inserter.Insert(190, 9, 0, TrackId{3});
164 inserter.Insert(195, 2, 1, TrackId{3});
165
166 inserter.Insert(300, 9, 0, TrackId{3});
167 inserter.Insert(301, 2, 1, TrackId{3});
168
169 // Track 4 has one stack which is partially inside at start.
170 inserter.Insert(190, 20, 0, TrackId{4});
171 inserter.Insert(201, 2, 1, TrackId{4});
172
173 // Populate the table.
174 inserter.Populate(table);
175
176 auto out =
177 ExperimentalFlatSlice::ComputeFlatSliceTable(table, &pool, start, end);
178 auto sorted = out->Sort({out->track_id().ascending(), out->ts().ascending()});
179
180 TableAsserter asserter(std::move(sorted));
181
182 // Track 1's slices.
183 ASSERT_NO_FATAL_FAILURE(asserter.NextSlice(200, 0));
184 ASSERT_NO_FATAL_FAILURE(asserter.NextSlice(200, 10));
185 ASSERT_NO_FATAL_FAILURE(asserter.NextSlice(210, 0));
186 ASSERT_NO_FATAL_FAILURE(asserter.NextSlice(210, 10));
187 ASSERT_NO_FATAL_FAILURE(asserter.NextSlice(220, 10));
188 ASSERT_NO_FATAL_FAILURE(asserter.NextSlice(230, 10));
189 ASSERT_NO_FATAL_FAILURE(asserter.NextSlice(240, 60));
190
191 // Track 2's slices.
192 ASSERT_NO_FATAL_FAILURE(asserter.NextSlice(200, 90));
193 ASSERT_NO_FATAL_FAILURE(asserter.NextSlice(290, 9));
194 ASSERT_NO_FATAL_FAILURE(asserter.NextSlice(299, 1));
195
196 ASSERT_FALSE(asserter.HasMoreSlices());
197 }
198
199 } // namespace
200 } // namespace trace_processor
201 } // namespace perfetto
202