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