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