1 /*
2 * Copyright (C) 2019 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
17 #include "src/trace_processor/tables/macros.h"
18
19 #include "test/gtest_and_gmock.h"
20
21 namespace perfetto {
22 namespace trace_processor {
23 namespace {
24
25 // @param arg_set_id {@joinable args.arg_set_id}
26 #define PERFETTO_TP_TEST_EVENT_TABLE_DEF(NAME, PARENT, C) \
27 NAME(TestEventTable, "event") \
28 PARENT(PERFETTO_TP_ROOT_TABLE_PARENT_DEF, C) \
29 C(int64_t, ts, Column::Flag::kSorted) \
30 C(int64_t, arg_set_id)
31 PERFETTO_TP_TABLE(PERFETTO_TP_TEST_EVENT_TABLE_DEF);
32
33 #define PERFETTO_TP_TEST_COUNTER_TABLE_DEF(NAME, PARENT, C) \
34 NAME(TestCounterTable, "counter") \
35 PARENT(PERFETTO_TP_TEST_EVENT_TABLE_DEF, C) \
36 C(base::Optional<double>, value)
37 PERFETTO_TP_TABLE(PERFETTO_TP_TEST_COUNTER_TABLE_DEF);
38
39 #define PERFETTO_TP_TEST_SLICE_TABLE_DEF(NAME, PARENT, C) \
40 NAME(TestSliceTable, "slice") \
41 PARENT(PERFETTO_TP_TEST_EVENT_TABLE_DEF, C) \
42 C(base::Optional<int64_t>, dur) \
43 C(int64_t, depth)
44 PERFETTO_TP_TABLE(PERFETTO_TP_TEST_SLICE_TABLE_DEF);
45
46 #define PERFETTO_TP_TEST_CPU_SLICE_TABLE_DEF(NAME, PARENT, C) \
47 NAME(TestCpuSliceTable, "cpu_slice") \
48 PARENT(PERFETTO_TP_TEST_SLICE_TABLE_DEF, C) \
49 C(int64_t, cpu) \
50 C(int64_t, priority) \
51 C(StringPool::Id, end_state)
52 PERFETTO_TP_TABLE(PERFETTO_TP_TEST_CPU_SLICE_TABLE_DEF);
53
54 TestEventTable::~TestEventTable() = default;
55 TestCounterTable::~TestCounterTable() = default;
56 TestSliceTable::~TestSliceTable() = default;
57 TestCpuSliceTable::~TestCpuSliceTable() = default;
58
59 class TableMacrosUnittest : public ::testing::Test {
60 protected:
61 StringPool pool_;
62
63 TestEventTable event_{&pool_, nullptr};
64 TestCounterTable counter_{&pool_, &event_};
65 TestSliceTable slice_{&pool_, &event_};
66 TestCpuSliceTable cpu_slice_{&pool_, &slice_};
67 };
68
TEST_F(TableMacrosUnittest,Name)69 TEST_F(TableMacrosUnittest, Name) {
70 ASSERT_STREQ(event_.table_name(), "event");
71 ASSERT_STREQ(slice_.table_name(), "slice");
72 ASSERT_STREQ(cpu_slice_.table_name(), "cpu_slice");
73 }
74
TEST_F(TableMacrosUnittest,InsertParent)75 TEST_F(TableMacrosUnittest, InsertParent) {
76 auto id = event_.Insert(TestEventTable::Row(100, 0)).id;
77 ASSERT_EQ(id.value, 0u);
78 ASSERT_EQ(event_.type().GetString(0), "event");
79 ASSERT_EQ(event_.ts()[0], 100);
80 ASSERT_EQ(event_.arg_set_id()[0], 0);
81
82 id = slice_.Insert(TestSliceTable::Row(200, 123, 10, 0)).id;
83 ASSERT_EQ(id.value, 1u);
84
85 ASSERT_EQ(event_.type().GetString(1), "slice");
86 ASSERT_EQ(event_.ts()[1], 200);
87 ASSERT_EQ(event_.arg_set_id()[1], 123);
88 ASSERT_EQ(slice_.type().GetString(0), "slice");
89 ASSERT_EQ(slice_.ts()[0], 200);
90 ASSERT_EQ(slice_.arg_set_id()[0], 123);
91 ASSERT_EQ(slice_.dur()[0], 10);
92 ASSERT_EQ(slice_.depth()[0], 0);
93
94 id = slice_.Insert(TestSliceTable::Row(210, 456, base::nullopt, 0)).id;
95 ASSERT_EQ(id.value, 2u);
96
97 ASSERT_EQ(event_.type().GetString(2), "slice");
98 ASSERT_EQ(event_.ts()[2], 210);
99 ASSERT_EQ(event_.arg_set_id()[2], 456);
100 ASSERT_EQ(slice_.type().GetString(1), "slice");
101 ASSERT_EQ(slice_.ts()[1], 210);
102 ASSERT_EQ(slice_.arg_set_id()[1], 456);
103 ASSERT_EQ(slice_.dur()[1], base::nullopt);
104 ASSERT_EQ(slice_.depth()[1], 0);
105 }
106
TEST_F(TableMacrosUnittest,InsertChild)107 TEST_F(TableMacrosUnittest, InsertChild) {
108 event_.Insert(TestEventTable::Row(100, 0));
109 slice_.Insert(TestSliceTable::Row(200, 123, 10, 0));
110
111 auto reason = pool_.InternString("R");
112 auto id =
113 cpu_slice_.Insert(TestCpuSliceTable::Row(205, 456, 5, 1, 4, 1024, reason))
114 .id;
115 ASSERT_EQ(id.value, 2u);
116 ASSERT_EQ(event_.type().GetString(2), "cpu_slice");
117 ASSERT_EQ(event_.ts()[2], 205);
118 ASSERT_EQ(event_.arg_set_id()[2], 456);
119
120 ASSERT_EQ(slice_.type().GetString(1), "cpu_slice");
121 ASSERT_EQ(slice_.ts()[1], 205);
122 ASSERT_EQ(slice_.arg_set_id()[1], 456);
123 ASSERT_EQ(slice_.dur()[1], 5);
124 ASSERT_EQ(slice_.depth()[1], 1);
125
126 ASSERT_EQ(cpu_slice_.type().GetString(0), "cpu_slice");
127 ASSERT_EQ(cpu_slice_.ts()[0], 205);
128 ASSERT_EQ(cpu_slice_.arg_set_id()[0], 456);
129 ASSERT_EQ(cpu_slice_.dur()[0], 5);
130 ASSERT_EQ(cpu_slice_.depth()[0], 1);
131 ASSERT_EQ(cpu_slice_.cpu()[0], 4);
132 ASSERT_EQ(cpu_slice_.priority()[0], 1024);
133 ASSERT_EQ(cpu_slice_.end_state()[0], reason);
134 ASSERT_EQ(cpu_slice_.end_state().GetString(0), "R");
135 }
136
TEST_F(TableMacrosUnittest,NullableLongComparision)137 TEST_F(TableMacrosUnittest, NullableLongComparision) {
138 slice_.Insert({});
139
140 TestSliceTable::Row row;
141 row.dur = 100;
142 slice_.Insert(row);
143
144 row.dur = 101;
145 slice_.Insert(row);
146
147 row.dur = 200;
148 slice_.Insert(row);
149
150 slice_.Insert({});
151
152 Table out = slice_.Filter({slice_.dur().is_null()});
153 const auto* dur = out.GetColumnByName("dur");
154 ASSERT_EQ(out.row_count(), 2u);
155 ASSERT_EQ(dur->Get(0).type, SqlValue::kNull);
156 ASSERT_EQ(dur->Get(1).type, SqlValue::kNull);
157
158 out = slice_.Filter({slice_.dur().is_not_null()});
159 dur = out.GetColumnByName("dur");
160 ASSERT_EQ(out.row_count(), 3u);
161 ASSERT_EQ(dur->Get(0).long_value, 100);
162 ASSERT_EQ(dur->Get(1).long_value, 101);
163 ASSERT_EQ(dur->Get(2).long_value, 200);
164
165 out = slice_.Filter({slice_.dur().lt(101)});
166 dur = out.GetColumnByName("dur");
167 ASSERT_EQ(out.row_count(), 1u);
168 ASSERT_EQ(dur->Get(0).long_value, 100);
169
170 out = slice_.Filter({slice_.dur().eq(101)});
171 dur = out.GetColumnByName("dur");
172 ASSERT_EQ(out.row_count(), 1u);
173 ASSERT_EQ(dur->Get(0).long_value, 101);
174
175 out = slice_.Filter({slice_.dur().gt(101)});
176 dur = out.GetColumnByName("dur");
177 ASSERT_EQ(out.row_count(), 1u);
178 ASSERT_EQ(dur->Get(0).long_value, 200);
179
180 out = slice_.Filter({slice_.dur().ne(100)});
181 dur = out.GetColumnByName("dur");
182 ASSERT_EQ(out.row_count(), 2u);
183 ASSERT_EQ(dur->Get(0).long_value, 101);
184 ASSERT_EQ(dur->Get(1).long_value, 200);
185
186 out = slice_.Filter({slice_.dur().le(101)});
187 dur = out.GetColumnByName("dur");
188 ASSERT_EQ(out.row_count(), 2u);
189 ASSERT_EQ(dur->Get(0).long_value, 100);
190 ASSERT_EQ(dur->Get(1).long_value, 101);
191
192 out = slice_.Filter({slice_.dur().ge(101)});
193 dur = out.GetColumnByName("dur");
194 ASSERT_EQ(out.row_count(), 2u);
195 ASSERT_EQ(dur->Get(0).long_value, 101);
196 ASSERT_EQ(dur->Get(1).long_value, 200);
197 }
198
TEST_F(TableMacrosUnittest,NullableLongCompareWithDouble)199 TEST_F(TableMacrosUnittest, NullableLongCompareWithDouble) {
200 slice_.Insert({});
201
202 TestSliceTable::Row row;
203 row.dur = 100;
204 slice_.Insert(row);
205
206 row.dur = std::numeric_limits<int64_t>::max();
207 slice_.Insert(row);
208
209 row.dur = std::numeric_limits<int64_t>::min();
210 slice_.Insert(row);
211
212 Table out = slice_.Filter({slice_.dur().eq_value(SqlValue::Double(100.0))});
213 const Column* dur = out.GetColumnByName("dur");
214 ASSERT_EQ(out.row_count(), 1u);
215 ASSERT_EQ(dur->Get(0).long_value, 100);
216
217 out = slice_.Filter({slice_.dur().le_value(SqlValue::Double(99.9999))});
218 dur = out.GetColumnByName("dur");
219 ASSERT_EQ(out.row_count(), 1u);
220 ASSERT_EQ(dur->Get(0).long_value, std::numeric_limits<int64_t>::min());
221
222 out = slice_.Filter({slice_.dur().ge_value(SqlValue::Double(99.9999))});
223 dur = out.GetColumnByName("dur");
224 ASSERT_EQ(out.row_count(), 2u);
225 ASSERT_EQ(dur->Get(0).long_value, 100);
226 ASSERT_EQ(dur->Get(1).long_value, std::numeric_limits<int64_t>::max());
227
228 out = slice_.Filter({slice_.dur().eq_value(
229 SqlValue::Double(std::numeric_limits<int64_t>::min()))});
230 dur = out.GetColumnByName("dur");
231 ASSERT_EQ(out.row_count(), 1u);
232 ASSERT_EQ(dur->Get(0).long_value, std::numeric_limits<int64_t>::min());
233 }
234
TEST_F(TableMacrosUnittest,NullableLongCompareWrongType)235 TEST_F(TableMacrosUnittest, NullableLongCompareWrongType) {
236 slice_.Insert({});
237
238 TestSliceTable::Row row;
239 row.dur = 100;
240 slice_.Insert(row);
241
242 row.dur = 101;
243 slice_.Insert(row);
244
245 row.dur = 200;
246 slice_.Insert(row);
247
248 slice_.Insert({});
249
250 Table out = slice_.Filter({slice_.dur().ne_value(SqlValue())});
251 ASSERT_EQ(out.row_count(), 0u);
252
253 out = slice_.Filter({slice_.dur().eq_value(SqlValue::String("100"))});
254 ASSERT_EQ(out.row_count(), 0u);
255 }
256
TEST_F(TableMacrosUnittest,NullableDoubleComparision)257 TEST_F(TableMacrosUnittest, NullableDoubleComparision) {
258 counter_.Insert({});
259
260 TestCounterTable::Row row;
261 row.value = 100.0;
262 counter_.Insert(row);
263
264 row.value = 101.0;
265 counter_.Insert(row);
266
267 row.value = 200.0;
268 counter_.Insert(row);
269
270 counter_.Insert({});
271
272 Table out = counter_.Filter({counter_.value().is_null()});
273 const auto* value = out.GetColumnByName("value");
274 ASSERT_EQ(out.row_count(), 2u);
275 ASSERT_EQ(value->Get(0).type, SqlValue::kNull);
276 ASSERT_EQ(value->Get(1).type, SqlValue::kNull);
277
278 out = counter_.Filter({counter_.value().is_not_null()});
279 value = out.GetColumnByName("value");
280 ASSERT_EQ(out.row_count(), 3u);
281 ASSERT_DOUBLE_EQ(value->Get(0).double_value, 100);
282 ASSERT_DOUBLE_EQ(value->Get(1).double_value, 101);
283 ASSERT_DOUBLE_EQ(value->Get(2).double_value, 200);
284
285 out = counter_.Filter({counter_.value().lt(101)});
286 value = out.GetColumnByName("value");
287 ASSERT_EQ(out.row_count(), 1u);
288 ASSERT_DOUBLE_EQ(value->Get(0).double_value, 100);
289
290 out = counter_.Filter({counter_.value().eq(101)});
291 value = out.GetColumnByName("value");
292 ASSERT_EQ(out.row_count(), 1u);
293 ASSERT_DOUBLE_EQ(value->Get(0).double_value, 101);
294
295 out = counter_.Filter({counter_.value().gt(101)});
296 value = out.GetColumnByName("value");
297 ASSERT_EQ(out.row_count(), 1u);
298 ASSERT_DOUBLE_EQ(value->Get(0).double_value, 200);
299
300 out = counter_.Filter({counter_.value().ne(100)});
301 value = out.GetColumnByName("value");
302 ASSERT_EQ(out.row_count(), 2u);
303 ASSERT_DOUBLE_EQ(value->Get(0).double_value, 101);
304 ASSERT_DOUBLE_EQ(value->Get(1).double_value, 200);
305
306 out = counter_.Filter({counter_.value().le(101)});
307 value = out.GetColumnByName("value");
308 ASSERT_EQ(out.row_count(), 2u);
309 ASSERT_DOUBLE_EQ(value->Get(0).double_value, 100);
310 ASSERT_DOUBLE_EQ(value->Get(1).double_value, 101);
311
312 out = counter_.Filter({counter_.value().ge(101)});
313 value = out.GetColumnByName("value");
314 ASSERT_EQ(out.row_count(), 2u);
315 ASSERT_DOUBLE_EQ(value->Get(0).double_value, 101);
316 ASSERT_DOUBLE_EQ(value->Get(1).double_value, 200);
317 }
318
TEST_F(TableMacrosUnittest,NullableDoubleCompareWithLong)319 TEST_F(TableMacrosUnittest, NullableDoubleCompareWithLong) {
320 counter_.Insert({});
321
322 TestCounterTable::Row row;
323 row.value = 100.0;
324 counter_.Insert(row);
325
326 row.value = 99.9999;
327 counter_.Insert(row);
328
329 row.value = static_cast<double>(std::numeric_limits<int64_t>::min());
330 counter_.Insert(row);
331
332 Table out = counter_.Filter({counter_.value().eq_value(SqlValue::Long(100))});
333 const Column* value = out.GetColumnByName("value");
334 ASSERT_EQ(out.row_count(), 1u);
335 ASSERT_DOUBLE_EQ(value->Get(0).double_value, 100.0);
336
337 out = counter_.Filter({counter_.value().lt_value(SqlValue::Long(100))});
338 value = out.GetColumnByName("value");
339 ASSERT_EQ(out.row_count(), 2u);
340 ASSERT_DOUBLE_EQ(value->Get(0).double_value, 99.9999);
341 ASSERT_DOUBLE_EQ(value->Get(1).double_value,
342 std::numeric_limits<int64_t>::min());
343
344 out = counter_.Filter({counter_.value().eq_value(
345 SqlValue::Long(std::numeric_limits<int64_t>::min()))});
346 value = out.GetColumnByName("value");
347 ASSERT_EQ(out.row_count(), 1u);
348 ASSERT_DOUBLE_EQ(value->Get(0).double_value,
349 std::numeric_limits<int64_t>::min());
350 }
351
TEST_F(TableMacrosUnittest,StringComparision)352 TEST_F(TableMacrosUnittest, StringComparision) {
353 cpu_slice_.Insert({});
354
355 TestCpuSliceTable::Row row;
356 row.end_state = pool_.InternString("R");
357 cpu_slice_.Insert(row);
358
359 row.end_state = pool_.InternString("D");
360 cpu_slice_.Insert(row);
361
362 cpu_slice_.Insert({});
363
364 Table out = cpu_slice_.Filter({cpu_slice_.end_state().is_null()});
365 const auto* end_state = out.GetColumnByName("end_state");
366 ASSERT_EQ(out.row_count(), 2u);
367 ASSERT_EQ(end_state->Get(0).type, SqlValue::kNull);
368 ASSERT_EQ(end_state->Get(1).type, SqlValue::kNull);
369
370 out = cpu_slice_.Filter({cpu_slice_.end_state().is_not_null()});
371 end_state = out.GetColumnByName("end_state");
372 ASSERT_EQ(out.row_count(), 2u);
373 ASSERT_STREQ(end_state->Get(0).string_value, "R");
374 ASSERT_STREQ(end_state->Get(1).string_value, "D");
375
376 out = cpu_slice_.Filter({cpu_slice_.end_state().lt("R")});
377 end_state = out.GetColumnByName("end_state");
378 ASSERT_EQ(out.row_count(), 1u);
379 ASSERT_STREQ(end_state->Get(0).string_value, "D");
380
381 out = cpu_slice_.Filter({cpu_slice_.end_state().eq("D")});
382 end_state = out.GetColumnByName("end_state");
383 ASSERT_EQ(out.row_count(), 1u);
384 ASSERT_STREQ(end_state->Get(0).string_value, "D");
385
386 out = cpu_slice_.Filter({cpu_slice_.end_state().gt("D")});
387 end_state = out.GetColumnByName("end_state");
388 ASSERT_EQ(out.row_count(), 1u);
389 ASSERT_STREQ(end_state->Get(0).string_value, "R");
390
391 out = cpu_slice_.Filter({cpu_slice_.end_state().ne("D")});
392 end_state = out.GetColumnByName("end_state");
393 ASSERT_EQ(out.row_count(), 1u);
394 ASSERT_STREQ(end_state->Get(0).string_value, "R");
395
396 out = cpu_slice_.Filter({cpu_slice_.end_state().le("R")});
397 end_state = out.GetColumnByName("end_state");
398 ASSERT_EQ(out.row_count(), 2u);
399 ASSERT_STREQ(end_state->Get(0).string_value, "R");
400 ASSERT_STREQ(end_state->Get(1).string_value, "D");
401
402 out = cpu_slice_.Filter({cpu_slice_.end_state().ge("D")});
403 end_state = out.GetColumnByName("end_state");
404 ASSERT_EQ(out.row_count(), 2u);
405 ASSERT_STREQ(end_state->Get(0).string_value, "R");
406 ASSERT_STREQ(end_state->Get(1).string_value, "D");
407 }
408
TEST_F(TableMacrosUnittest,FilterIdThenOther)409 TEST_F(TableMacrosUnittest, FilterIdThenOther) {
410 TestCpuSliceTable::Row row;
411 row.cpu = 1;
412 row.end_state = pool_.InternString("D");
413
414 cpu_slice_.Insert(row);
415 cpu_slice_.Insert(row);
416 cpu_slice_.Insert(row);
417
418 auto out =
419 cpu_slice_.Filter({cpu_slice_.id().eq(0), cpu_slice_.end_state().eq("D"),
420 cpu_slice_.cpu().eq(1)});
421 const auto* end_state = out.GetColumnByName("end_state");
422 const auto* cpu = out.GetColumnByName("cpu");
423
424 ASSERT_EQ(out.row_count(), 1u);
425 ASSERT_EQ(cpu->Get(0).long_value, 1u);
426 ASSERT_STREQ(end_state->Get(0).string_value, "D");
427 }
428
TEST_F(TableMacrosUnittest,Sort)429 TEST_F(TableMacrosUnittest, Sort) {
430 ASSERT_TRUE(event_.ts().IsSorted());
431
432 event_.Insert(TestEventTable::Row(0 /* ts */, 100 /* arg_set_id */));
433 event_.Insert(TestEventTable::Row(1 /* ts */, 1 /* arg_set_id */));
434 event_.Insert(TestEventTable::Row(2 /* ts */, 3 /* arg_set_id */));
435
436 Table out = event_.Sort({event_.arg_set_id().ascending()});
437 const auto* ts = out.GetColumnByName("ts");
438 const auto* arg_set_id = out.GetColumnByName("arg_set_id");
439
440 ASSERT_FALSE(ts->IsSorted());
441 ASSERT_TRUE(arg_set_id->IsSorted());
442
443 ASSERT_EQ(arg_set_id->Get(0).long_value, 1);
444 ASSERT_EQ(arg_set_id->Get(1).long_value, 3);
445 ASSERT_EQ(arg_set_id->Get(2).long_value, 100);
446 }
447
448 } // namespace
449 } // namespace trace_processor
450 } // namespace perfetto
451