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/perfetto_sql/intrinsics/table_functions/experimental_flat_slice.h"
17
18 #include <algorithm>
19 #include <cstdint>
20 #include <limits>
21 #include <utility>
22 #include <vector>
23
24 #include "src/trace_processor/containers/string_pool.h"
25 #include "src/trace_processor/db/table.h"
26 #include "src/trace_processor/storage/trace_storage.h"
27 #include "src/trace_processor/tables/slice_tables_py.h"
28 #include "test/gtest_and_gmock.h"
29
30 namespace perfetto::trace_processor {
31 namespace {
32
33 class TableInseter {
34 public:
Insert(int64_t ts,int64_t dur,uint32_t depth,TrackId track_id)35 void Insert(int64_t ts, int64_t dur, uint32_t depth, TrackId track_id) {
36 tables::SliceTable::Row row;
37 row.ts = ts;
38 row.dur = dur;
39 row.depth = depth;
40 row.track_id = track_id;
41 rows_.emplace_back(row);
42 }
43
Populate(tables::SliceTable & table)44 void Populate(tables::SliceTable& table) {
45 using R = tables::SliceTable::Row;
46 std::sort(rows_.begin(), rows_.end(),
47 [](const R& a, const R& b) { return a.ts < b.ts; });
48 for (const auto& row : rows_) {
49 table.Insert(row);
50 }
51 rows_.clear();
52 }
53
54 private:
55 std::vector<tables::SliceTable::Row> rows_;
56 };
57
58 class TableAsserter {
59 public:
TableAsserter(tables::ExperimentalFlatSliceTable::Iterator it)60 explicit TableAsserter(tables::ExperimentalFlatSliceTable::Iterator it)
61 : iterator_(std::move(it)) {}
62
NextSlice(int64_t ts,int64_t dur)63 void NextSlice(int64_t ts, int64_t dur) {
64 ASSERT_TRUE(HasMoreSlices());
65 ASSERT_EQ(iterator_.ts(), ts);
66 ASSERT_EQ(iterator_.dur(), dur);
67 ++iterator_;
68 }
69
HasMoreSlices()70 bool HasMoreSlices() { return bool(iterator_); }
71
72 private:
73 tables::ExperimentalFlatSliceTable::Iterator iterator_;
74 };
75
TEST(ExperimentalFlatSlice,Smoke)76 TEST(ExperimentalFlatSlice, Smoke) {
77 StringPool pool;
78 TableInseter inserter;
79 tables::SliceTable table(&pool);
80
81 // A simple stack on track 1.
82 inserter.Insert(100, 10, 0, TrackId{1});
83 inserter.Insert(104, 6, 1, TrackId{1});
84 inserter.Insert(107, 1, 2, TrackId{1});
85
86 // Back to back slices with a gap on track 2.
87 inserter.Insert(200, 10, 0, TrackId{2});
88 inserter.Insert(210, 10, 0, TrackId{2});
89 inserter.Insert(230, 10, 0, TrackId{2});
90
91 // Deep nesting on track 3.
92 inserter.Insert(300, 100, 0, TrackId{3});
93 inserter.Insert(301, 98, 1, TrackId{3});
94 inserter.Insert(302, 96, 2, TrackId{3});
95 inserter.Insert(303, 94, 3, TrackId{3});
96 inserter.Insert(304, 92, 4, TrackId{3});
97 inserter.Insert(305, 90, 5, TrackId{3});
98
99 // Populate the table.
100 inserter.Populate(table);
101
102 auto out = ExperimentalFlatSlice::ComputeFlatSliceTable(table, &pool, 0, 400);
103 Query q;
104 q.orders = {out->track_id().ascending(), out->ts().ascending()};
105 auto it = out->FilterToIterator(q);
106
107 TableAsserter asserter(std::move(it));
108
109 // Track 1's slices.
110 ASSERT_NO_FATAL_FAILURE(asserter.NextSlice(0, 100));
111 ASSERT_NO_FATAL_FAILURE(asserter.NextSlice(100, 4));
112 ASSERT_NO_FATAL_FAILURE(asserter.NextSlice(104, 3));
113 ASSERT_NO_FATAL_FAILURE(asserter.NextSlice(107, 1));
114 ASSERT_NO_FATAL_FAILURE(asserter.NextSlice(108, 2));
115 ASSERT_NO_FATAL_FAILURE(asserter.NextSlice(110, 0));
116 ASSERT_NO_FATAL_FAILURE(asserter.NextSlice(110, 290));
117
118 // Track 2's slices.
119 ASSERT_NO_FATAL_FAILURE(asserter.NextSlice(0, 200));
120 ASSERT_NO_FATAL_FAILURE(asserter.NextSlice(200, 10));
121 ASSERT_NO_FATAL_FAILURE(asserter.NextSlice(210, 0));
122 ASSERT_NO_FATAL_FAILURE(asserter.NextSlice(210, 10));
123 ASSERT_NO_FATAL_FAILURE(asserter.NextSlice(220, 10));
124 ASSERT_NO_FATAL_FAILURE(asserter.NextSlice(230, 10));
125 ASSERT_NO_FATAL_FAILURE(asserter.NextSlice(240, 160));
126
127 // Track 3's slices.
128 ASSERT_NO_FATAL_FAILURE(asserter.NextSlice(0, 300));
129 ASSERT_NO_FATAL_FAILURE(asserter.NextSlice(300, 1));
130 ASSERT_NO_FATAL_FAILURE(asserter.NextSlice(301, 1));
131 ASSERT_NO_FATAL_FAILURE(asserter.NextSlice(302, 1));
132 ASSERT_NO_FATAL_FAILURE(asserter.NextSlice(303, 1));
133 ASSERT_NO_FATAL_FAILURE(asserter.NextSlice(304, 1));
134 ASSERT_NO_FATAL_FAILURE(asserter.NextSlice(305, 90));
135 ASSERT_NO_FATAL_FAILURE(asserter.NextSlice(395, 1));
136 ASSERT_NO_FATAL_FAILURE(asserter.NextSlice(396, 1));
137 ASSERT_NO_FATAL_FAILURE(asserter.NextSlice(397, 1));
138 ASSERT_NO_FATAL_FAILURE(asserter.NextSlice(398, 1));
139 ASSERT_NO_FATAL_FAILURE(asserter.NextSlice(399, 1));
140 ASSERT_NO_FATAL_FAILURE(asserter.NextSlice(400, 0));
141
142 ASSERT_FALSE(asserter.HasMoreSlices());
143 }
144
TEST(ExperimentalFlatSlice,Bounds)145 TEST(ExperimentalFlatSlice, Bounds) {
146 StringPool pool;
147 TableInseter inserter;
148 tables::SliceTable table(&pool);
149
150 /// Our timebounds is between 200 and 300.
151 int64_t start = 200;
152 int64_t end = 300;
153
154 // Track 1 has all events inside bounds.
155 inserter.Insert(200, 10, 0, TrackId{1});
156 inserter.Insert(210, 10, 0, TrackId{1});
157 inserter.Insert(230, 10, 0, TrackId{1});
158
159 // Track 2 has a two stacks, first partially inside at start, second partially
160 // inside at end.
161 // First stack.
162 inserter.Insert(190, 20, 0, TrackId{2});
163 inserter.Insert(200, 9, 1, TrackId{2});
164 inserter.Insert(201, 1, 2, TrackId{2});
165
166 // Second stack.
167 inserter.Insert(290, 20, 0, TrackId{2});
168 inserter.Insert(299, 2, 1, TrackId{2});
169 inserter.Insert(300, 1, 2, TrackId{2});
170
171 // Track 3 has two stacks but *only* outside bounds.
172 inserter.Insert(190, 9, 0, TrackId{3});
173 inserter.Insert(195, 2, 1, TrackId{3});
174
175 inserter.Insert(300, 9, 0, TrackId{3});
176 inserter.Insert(301, 2, 1, TrackId{3});
177
178 // Track 4 has one stack which is partially inside at start.
179 inserter.Insert(190, 20, 0, TrackId{4});
180 inserter.Insert(201, 2, 1, TrackId{4});
181
182 // Populate the table.
183 inserter.Populate(table);
184
185 auto out =
186 ExperimentalFlatSlice::ComputeFlatSliceTable(table, &pool, start, end);
187 Query q;
188 q.orders = {out->track_id().ascending(), out->ts().ascending()};
189 auto it = out->FilterToIterator(q);
190
191 TableAsserter asserter(std::move(it));
192
193 // Track 1's slices.
194 ASSERT_NO_FATAL_FAILURE(asserter.NextSlice(200, 0));
195 ASSERT_NO_FATAL_FAILURE(asserter.NextSlice(200, 10));
196 ASSERT_NO_FATAL_FAILURE(asserter.NextSlice(210, 0));
197 ASSERT_NO_FATAL_FAILURE(asserter.NextSlice(210, 10));
198 ASSERT_NO_FATAL_FAILURE(asserter.NextSlice(220, 10));
199 ASSERT_NO_FATAL_FAILURE(asserter.NextSlice(230, 10));
200 ASSERT_NO_FATAL_FAILURE(asserter.NextSlice(240, 60));
201
202 // Track 2's slices.
203 ASSERT_NO_FATAL_FAILURE(asserter.NextSlice(200, 90));
204 ASSERT_NO_FATAL_FAILURE(asserter.NextSlice(290, 9));
205 ASSERT_NO_FATAL_FAILURE(asserter.NextSlice(299, 1));
206
207 ASSERT_FALSE(asserter.HasMoreSlices());
208 }
209
210 } // namespace
211 } // namespace perfetto::trace_processor
212