| /* |
| * Copyright (C) 2019 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #include "src/trace_processor/tables/macros.h" |
| |
| #include "test/gtest_and_gmock.h" |
| |
| namespace perfetto { |
| namespace trace_processor { |
| namespace { |
| |
| // @param arg_set_id {@joinable args.arg_set_id} |
| #define PERFETTO_TP_TEST_EVENT_TABLE_DEF(NAME, PARENT, C) \ |
| NAME(TestEventTable, "event") \ |
| PARENT(PERFETTO_TP_ROOT_TABLE_PARENT_DEF, C) \ |
| C(int64_t, ts, Column::Flag::kSorted) \ |
| C(int64_t, arg_set_id) |
| PERFETTO_TP_TABLE(PERFETTO_TP_TEST_EVENT_TABLE_DEF); |
| |
| #define PERFETTO_TP_TEST_COUNTER_TABLE_DEF(NAME, PARENT, C) \ |
| NAME(TestCounterTable, "counter") \ |
| PARENT(PERFETTO_TP_TEST_EVENT_TABLE_DEF, C) \ |
| C(std::optional<double>, value) |
| PERFETTO_TP_TABLE(PERFETTO_TP_TEST_COUNTER_TABLE_DEF); |
| |
| #define PERFETTO_TP_TEST_SLICE_TABLE_DEF(NAME, PARENT, C) \ |
| NAME(TestSliceTable, "slice") \ |
| PARENT(PERFETTO_TP_TEST_EVENT_TABLE_DEF, C) \ |
| C(std::optional<int64_t>, dur) \ |
| C(int64_t, depth) |
| PERFETTO_TP_TABLE(PERFETTO_TP_TEST_SLICE_TABLE_DEF); |
| |
| #define PERFETTO_TP_TEST_CPU_SLICE_TABLE_DEF(NAME, PARENT, C) \ |
| NAME(TestCpuSliceTable, "cpu_slice") \ |
| PARENT(PERFETTO_TP_TEST_SLICE_TABLE_DEF, C) \ |
| C(int64_t, cpu) \ |
| C(int64_t, priority) \ |
| C(StringPool::Id, end_state) |
| PERFETTO_TP_TABLE(PERFETTO_TP_TEST_CPU_SLICE_TABLE_DEF); |
| |
| #define PERFETTO_TP_TEST_ARGS_TABLE_DEF(NAME, PARENT, C) \ |
| NAME(TestArgsTable, "args") \ |
| PARENT(PERFETTO_TP_ROOT_TABLE_PARENT_DEF, C) \ |
| C(uint32_t, arg_set_id, Column::Flag::kSetId | Column::Flag::kSorted) |
| PERFETTO_TP_TABLE(PERFETTO_TP_TEST_ARGS_TABLE_DEF); |
| |
| #define PERFETTO_TP_TEST_ARGS_CHILD_TABLE_DEF(NAME, PARENT, C) \ |
| NAME(TestArgsChildTable, "args_child") \ |
| PARENT(PERFETTO_TP_TEST_ARGS_TABLE_DEF, C) \ |
| C(uint32_t, child_col) |
| PERFETTO_TP_TABLE(PERFETTO_TP_TEST_ARGS_CHILD_TABLE_DEF); |
| |
| TestEventTable::~TestEventTable() = default; |
| TestCounterTable::~TestCounterTable() = default; |
| TestSliceTable::~TestSliceTable() = default; |
| TestCpuSliceTable::~TestCpuSliceTable() = default; |
| TestArgsTable::~TestArgsTable() = default; |
| TestArgsChildTable::~TestArgsChildTable() = default; |
| |
| class TableMacrosUnittest : public ::testing::Test { |
| protected: |
| StringPool pool_; |
| |
| TestEventTable event_{&pool_, nullptr}; |
| TestCounterTable counter_{&pool_, &event_}; |
| TestSliceTable slice_{&pool_, &event_}; |
| TestCpuSliceTable cpu_slice_{&pool_, &slice_}; |
| TestArgsTable args_{&pool_, nullptr}; |
| TestArgsChildTable args_child_{&pool_, &args_}; |
| }; |
| |
| TEST_F(TableMacrosUnittest, Name) { |
| ASSERT_STREQ(TestEventTable::Name(), "event"); |
| ASSERT_STREQ(TestSliceTable::Name(), "slice"); |
| ASSERT_STREQ(TestCpuSliceTable::Name(), "cpu_slice"); |
| } |
| |
| TEST_F(TableMacrosUnittest, InsertParent) { |
| auto id = event_.Insert(TestEventTable::Row(100, 0)).id; |
| ASSERT_EQ(id.value, 0u); |
| ASSERT_EQ(event_.type().GetString(0), "event"); |
| ASSERT_EQ(event_.ts()[0], 100); |
| ASSERT_EQ(event_.arg_set_id()[0], 0); |
| |
| id = slice_.Insert(TestSliceTable::Row(200, 123, 10, 0)).id; |
| ASSERT_EQ(id.value, 1u); |
| |
| ASSERT_EQ(event_.type().GetString(1), "slice"); |
| ASSERT_EQ(event_.ts()[1], 200); |
| ASSERT_EQ(event_.arg_set_id()[1], 123); |
| ASSERT_EQ(slice_.type().GetString(0), "slice"); |
| ASSERT_EQ(slice_.ts()[0], 200); |
| ASSERT_EQ(slice_.arg_set_id()[0], 123); |
| ASSERT_EQ(slice_.dur()[0], 10); |
| ASSERT_EQ(slice_.depth()[0], 0); |
| |
| id = slice_.Insert(TestSliceTable::Row(210, 456, std::nullopt, 0)).id; |
| ASSERT_EQ(id.value, 2u); |
| |
| ASSERT_EQ(event_.type().GetString(2), "slice"); |
| ASSERT_EQ(event_.ts()[2], 210); |
| ASSERT_EQ(event_.arg_set_id()[2], 456); |
| ASSERT_EQ(slice_.type().GetString(1), "slice"); |
| ASSERT_EQ(slice_.ts()[1], 210); |
| ASSERT_EQ(slice_.arg_set_id()[1], 456); |
| ASSERT_EQ(slice_.dur()[1], std::nullopt); |
| ASSERT_EQ(slice_.depth()[1], 0); |
| } |
| |
| TEST_F(TableMacrosUnittest, InsertChild) { |
| event_.Insert(TestEventTable::Row(100, 0)); |
| slice_.Insert(TestSliceTable::Row(200, 123, 10, 0)); |
| |
| auto reason = pool_.InternString("R"); |
| auto id = |
| cpu_slice_.Insert(TestCpuSliceTable::Row(205, 456, 5, 1, 4, 1024, reason)) |
| .id; |
| ASSERT_EQ(id.value, 2u); |
| ASSERT_EQ(event_.type().GetString(2), "cpu_slice"); |
| ASSERT_EQ(event_.ts()[2], 205); |
| ASSERT_EQ(event_.arg_set_id()[2], 456); |
| |
| ASSERT_EQ(slice_.type().GetString(1), "cpu_slice"); |
| ASSERT_EQ(slice_.ts()[1], 205); |
| ASSERT_EQ(slice_.arg_set_id()[1], 456); |
| ASSERT_EQ(slice_.dur()[1], 5); |
| ASSERT_EQ(slice_.depth()[1], 1); |
| |
| ASSERT_EQ(cpu_slice_.type().GetString(0), "cpu_slice"); |
| ASSERT_EQ(cpu_slice_.ts()[0], 205); |
| ASSERT_EQ(cpu_slice_.arg_set_id()[0], 456); |
| ASSERT_EQ(cpu_slice_.dur()[0], 5); |
| ASSERT_EQ(cpu_slice_.depth()[0], 1); |
| ASSERT_EQ(cpu_slice_.cpu()[0], 4); |
| ASSERT_EQ(cpu_slice_.priority()[0], 1024); |
| ASSERT_EQ(cpu_slice_.end_state()[0], reason); |
| ASSERT_EQ(cpu_slice_.end_state().GetString(0), "R"); |
| } |
| |
| TEST_F(TableMacrosUnittest, NullableLongComparision) { |
| slice_.Insert({}); |
| |
| TestSliceTable::Row row; |
| row.dur = 100; |
| slice_.Insert(row); |
| |
| row.dur = 101; |
| slice_.Insert(row); |
| |
| row.dur = 200; |
| slice_.Insert(row); |
| |
| slice_.Insert({}); |
| |
| Table out = slice_.Filter({slice_.dur().is_null()}); |
| const auto* dur = out.GetColumnByName("dur"); |
| ASSERT_EQ(out.row_count(), 2u); |
| ASSERT_EQ(dur->Get(0).type, SqlValue::kNull); |
| ASSERT_EQ(dur->Get(1).type, SqlValue::kNull); |
| |
| out = slice_.Filter({slice_.dur().is_not_null()}); |
| dur = out.GetColumnByName("dur"); |
| ASSERT_EQ(out.row_count(), 3u); |
| ASSERT_EQ(dur->Get(0).long_value, 100); |
| ASSERT_EQ(dur->Get(1).long_value, 101); |
| ASSERT_EQ(dur->Get(2).long_value, 200); |
| |
| out = slice_.Filter({slice_.dur().lt(101)}); |
| dur = out.GetColumnByName("dur"); |
| ASSERT_EQ(out.row_count(), 1u); |
| ASSERT_EQ(dur->Get(0).long_value, 100); |
| |
| out = slice_.Filter({slice_.dur().eq(101)}); |
| dur = out.GetColumnByName("dur"); |
| ASSERT_EQ(out.row_count(), 1u); |
| ASSERT_EQ(dur->Get(0).long_value, 101); |
| |
| out = slice_.Filter({slice_.dur().gt(101)}); |
| dur = out.GetColumnByName("dur"); |
| ASSERT_EQ(out.row_count(), 1u); |
| ASSERT_EQ(dur->Get(0).long_value, 200); |
| |
| out = slice_.Filter({slice_.dur().ne(100)}); |
| dur = out.GetColumnByName("dur"); |
| ASSERT_EQ(out.row_count(), 2u); |
| ASSERT_EQ(dur->Get(0).long_value, 101); |
| ASSERT_EQ(dur->Get(1).long_value, 200); |
| |
| out = slice_.Filter({slice_.dur().le(101)}); |
| dur = out.GetColumnByName("dur"); |
| ASSERT_EQ(out.row_count(), 2u); |
| ASSERT_EQ(dur->Get(0).long_value, 100); |
| ASSERT_EQ(dur->Get(1).long_value, 101); |
| |
| out = slice_.Filter({slice_.dur().ge(101)}); |
| dur = out.GetColumnByName("dur"); |
| ASSERT_EQ(out.row_count(), 2u); |
| ASSERT_EQ(dur->Get(0).long_value, 101); |
| ASSERT_EQ(dur->Get(1).long_value, 200); |
| } |
| |
| TEST_F(TableMacrosUnittest, NullableLongCompareWithDouble) { |
| slice_.Insert({}); |
| |
| TestSliceTable::Row row; |
| row.dur = 100; |
| slice_.Insert(row); |
| |
| row.dur = std::numeric_limits<int64_t>::max(); |
| slice_.Insert(row); |
| |
| row.dur = std::numeric_limits<int64_t>::min(); |
| slice_.Insert(row); |
| |
| Table out = slice_.Filter({slice_.dur().eq_value(SqlValue::Double(100.0))}); |
| const Column* dur = out.GetColumnByName("dur"); |
| ASSERT_EQ(out.row_count(), 1u); |
| ASSERT_EQ(dur->Get(0).long_value, 100); |
| |
| out = slice_.Filter({slice_.dur().le_value(SqlValue::Double(99.9999))}); |
| dur = out.GetColumnByName("dur"); |
| ASSERT_EQ(out.row_count(), 1u); |
| ASSERT_EQ(dur->Get(0).long_value, std::numeric_limits<int64_t>::min()); |
| |
| out = slice_.Filter({slice_.dur().ge_value(SqlValue::Double(99.9999))}); |
| dur = out.GetColumnByName("dur"); |
| ASSERT_EQ(out.row_count(), 2u); |
| ASSERT_EQ(dur->Get(0).long_value, 100); |
| ASSERT_EQ(dur->Get(1).long_value, std::numeric_limits<int64_t>::max()); |
| |
| out = slice_.Filter({slice_.dur().eq_value( |
| SqlValue::Double(std::numeric_limits<int64_t>::min()))}); |
| dur = out.GetColumnByName("dur"); |
| ASSERT_EQ(out.row_count(), 1u); |
| ASSERT_EQ(dur->Get(0).long_value, std::numeric_limits<int64_t>::min()); |
| } |
| |
| TEST_F(TableMacrosUnittest, NullableLongCompareWrongType) { |
| slice_.Insert({}); |
| |
| TestSliceTable::Row row; |
| row.dur = 100; |
| slice_.Insert(row); |
| |
| row.dur = 101; |
| slice_.Insert(row); |
| |
| row.dur = 200; |
| slice_.Insert(row); |
| |
| slice_.Insert({}); |
| |
| Table out = slice_.Filter({slice_.dur().ne_value(SqlValue())}); |
| ASSERT_EQ(out.row_count(), 0u); |
| |
| out = slice_.Filter({slice_.dur().eq_value(SqlValue::String("100"))}); |
| ASSERT_EQ(out.row_count(), 0u); |
| } |
| |
| TEST_F(TableMacrosUnittest, NullableDoubleComparision) { |
| counter_.Insert({}); |
| |
| TestCounterTable::Row row; |
| row.value = 100.0; |
| counter_.Insert(row); |
| |
| row.value = 101.0; |
| counter_.Insert(row); |
| |
| row.value = 200.0; |
| counter_.Insert(row); |
| |
| counter_.Insert({}); |
| |
| Table out = counter_.Filter({counter_.value().is_null()}); |
| const auto* value = out.GetColumnByName("value"); |
| ASSERT_EQ(out.row_count(), 2u); |
| ASSERT_EQ(value->Get(0).type, SqlValue::kNull); |
| ASSERT_EQ(value->Get(1).type, SqlValue::kNull); |
| |
| out = counter_.Filter({counter_.value().is_not_null()}); |
| value = out.GetColumnByName("value"); |
| ASSERT_EQ(out.row_count(), 3u); |
| ASSERT_DOUBLE_EQ(value->Get(0).double_value, 100); |
| ASSERT_DOUBLE_EQ(value->Get(1).double_value, 101); |
| ASSERT_DOUBLE_EQ(value->Get(2).double_value, 200); |
| |
| out = counter_.Filter({counter_.value().lt(101)}); |
| value = out.GetColumnByName("value"); |
| ASSERT_EQ(out.row_count(), 1u); |
| ASSERT_DOUBLE_EQ(value->Get(0).double_value, 100); |
| |
| out = counter_.Filter({counter_.value().eq(101)}); |
| value = out.GetColumnByName("value"); |
| ASSERT_EQ(out.row_count(), 1u); |
| ASSERT_DOUBLE_EQ(value->Get(0).double_value, 101); |
| |
| out = counter_.Filter({counter_.value().gt(101)}); |
| value = out.GetColumnByName("value"); |
| ASSERT_EQ(out.row_count(), 1u); |
| ASSERT_DOUBLE_EQ(value->Get(0).double_value, 200); |
| |
| out = counter_.Filter({counter_.value().ne(100)}); |
| value = out.GetColumnByName("value"); |
| ASSERT_EQ(out.row_count(), 2u); |
| ASSERT_DOUBLE_EQ(value->Get(0).double_value, 101); |
| ASSERT_DOUBLE_EQ(value->Get(1).double_value, 200); |
| |
| out = counter_.Filter({counter_.value().le(101)}); |
| value = out.GetColumnByName("value"); |
| ASSERT_EQ(out.row_count(), 2u); |
| ASSERT_DOUBLE_EQ(value->Get(0).double_value, 100); |
| ASSERT_DOUBLE_EQ(value->Get(1).double_value, 101); |
| |
| out = counter_.Filter({counter_.value().ge(101)}); |
| value = out.GetColumnByName("value"); |
| ASSERT_EQ(out.row_count(), 2u); |
| ASSERT_DOUBLE_EQ(value->Get(0).double_value, 101); |
| ASSERT_DOUBLE_EQ(value->Get(1).double_value, 200); |
| } |
| |
| TEST_F(TableMacrosUnittest, NullableDoubleCompareWithLong) { |
| counter_.Insert({}); |
| |
| TestCounterTable::Row row; |
| row.value = 100.0; |
| counter_.Insert(row); |
| |
| row.value = 99.9999; |
| counter_.Insert(row); |
| |
| row.value = static_cast<double>(std::numeric_limits<int64_t>::min()); |
| counter_.Insert(row); |
| |
| Table out = counter_.Filter({counter_.value().eq_value(SqlValue::Long(100))}); |
| const Column* value = out.GetColumnByName("value"); |
| ASSERT_EQ(out.row_count(), 1u); |
| ASSERT_DOUBLE_EQ(value->Get(0).double_value, 100.0); |
| |
| out = counter_.Filter({counter_.value().lt_value(SqlValue::Long(100))}); |
| value = out.GetColumnByName("value"); |
| ASSERT_EQ(out.row_count(), 2u); |
| ASSERT_DOUBLE_EQ(value->Get(0).double_value, 99.9999); |
| ASSERT_DOUBLE_EQ(value->Get(1).double_value, |
| std::numeric_limits<int64_t>::min()); |
| |
| out = counter_.Filter({counter_.value().eq_value( |
| SqlValue::Long(std::numeric_limits<int64_t>::min()))}); |
| value = out.GetColumnByName("value"); |
| ASSERT_EQ(out.row_count(), 1u); |
| ASSERT_DOUBLE_EQ(value->Get(0).double_value, |
| std::numeric_limits<int64_t>::min()); |
| } |
| |
| TEST_F(TableMacrosUnittest, StringComparision) { |
| cpu_slice_.Insert({}); |
| |
| TestCpuSliceTable::Row row; |
| row.end_state = pool_.InternString("R"); |
| cpu_slice_.Insert(row); |
| |
| row.end_state = pool_.InternString("D"); |
| cpu_slice_.Insert(row); |
| |
| cpu_slice_.Insert({}); |
| |
| Table out = cpu_slice_.Filter({cpu_slice_.end_state().is_null()}); |
| const auto* end_state = out.GetColumnByName("end_state"); |
| ASSERT_EQ(out.row_count(), 2u); |
| ASSERT_EQ(end_state->Get(0).type, SqlValue::kNull); |
| ASSERT_EQ(end_state->Get(1).type, SqlValue::kNull); |
| |
| out = cpu_slice_.Filter({cpu_slice_.end_state().is_not_null()}); |
| end_state = out.GetColumnByName("end_state"); |
| ASSERT_EQ(out.row_count(), 2u); |
| ASSERT_STREQ(end_state->Get(0).string_value, "R"); |
| ASSERT_STREQ(end_state->Get(1).string_value, "D"); |
| |
| out = cpu_slice_.Filter({cpu_slice_.end_state().lt("R")}); |
| end_state = out.GetColumnByName("end_state"); |
| ASSERT_EQ(out.row_count(), 1u); |
| ASSERT_STREQ(end_state->Get(0).string_value, "D"); |
| |
| out = cpu_slice_.Filter({cpu_slice_.end_state().eq("D")}); |
| end_state = out.GetColumnByName("end_state"); |
| ASSERT_EQ(out.row_count(), 1u); |
| ASSERT_STREQ(end_state->Get(0).string_value, "D"); |
| |
| out = cpu_slice_.Filter({cpu_slice_.end_state().gt("D")}); |
| end_state = out.GetColumnByName("end_state"); |
| ASSERT_EQ(out.row_count(), 1u); |
| ASSERT_STREQ(end_state->Get(0).string_value, "R"); |
| |
| out = cpu_slice_.Filter({cpu_slice_.end_state().ne("D")}); |
| end_state = out.GetColumnByName("end_state"); |
| ASSERT_EQ(out.row_count(), 1u); |
| ASSERT_STREQ(end_state->Get(0).string_value, "R"); |
| |
| out = cpu_slice_.Filter({cpu_slice_.end_state().le("R")}); |
| end_state = out.GetColumnByName("end_state"); |
| ASSERT_EQ(out.row_count(), 2u); |
| ASSERT_STREQ(end_state->Get(0).string_value, "R"); |
| ASSERT_STREQ(end_state->Get(1).string_value, "D"); |
| |
| out = cpu_slice_.Filter({cpu_slice_.end_state().ge("D")}); |
| end_state = out.GetColumnByName("end_state"); |
| ASSERT_EQ(out.row_count(), 2u); |
| ASSERT_STREQ(end_state->Get(0).string_value, "R"); |
| ASSERT_STREQ(end_state->Get(1).string_value, "D"); |
| } |
| |
| TEST_F(TableMacrosUnittest, FilterIdThenOther) { |
| TestCpuSliceTable::Row row; |
| row.cpu = 1; |
| row.end_state = pool_.InternString("D"); |
| |
| cpu_slice_.Insert(row); |
| cpu_slice_.Insert(row); |
| cpu_slice_.Insert(row); |
| |
| auto out = |
| cpu_slice_.Filter({cpu_slice_.id().eq(0), cpu_slice_.end_state().eq("D"), |
| cpu_slice_.cpu().eq(1)}); |
| const auto* end_state = out.GetColumnByName("end_state"); |
| const auto* cpu = out.GetColumnByName("cpu"); |
| |
| ASSERT_EQ(out.row_count(), 1u); |
| ASSERT_EQ(cpu->Get(0).long_value, 1u); |
| ASSERT_STREQ(end_state->Get(0).string_value, "D"); |
| } |
| |
| TEST_F(TableMacrosUnittest, Sort) { |
| ASSERT_TRUE(event_.ts().IsSorted()); |
| |
| event_.Insert(TestEventTable::Row(0 /* ts */, 100 /* arg_set_id */)); |
| event_.Insert(TestEventTable::Row(1 /* ts */, 1 /* arg_set_id */)); |
| event_.Insert(TestEventTable::Row(2 /* ts */, 3 /* arg_set_id */)); |
| |
| Table out = event_.Sort({event_.arg_set_id().ascending()}); |
| const auto* ts = out.GetColumnByName("ts"); |
| const auto* arg_set_id = out.GetColumnByName("arg_set_id"); |
| |
| ASSERT_FALSE(ts->IsSorted()); |
| ASSERT_TRUE(arg_set_id->IsSorted()); |
| |
| ASSERT_EQ(arg_set_id->Get(0).long_value, 1); |
| ASSERT_EQ(arg_set_id->Get(1).long_value, 3); |
| ASSERT_EQ(arg_set_id->Get(2).long_value, 100); |
| } |
| |
| TEST_F(TableMacrosUnittest, ChildDoesntInheritArgsSetFlag) { |
| ASSERT_FALSE(args_child_.arg_set_id().IsSetId()); |
| ASSERT_FALSE(TestArgsChildTable::ComputeStaticSchema() |
| .columns[args_child_.arg_set_id().index_in_table()] |
| .is_set_id); |
| } |
| |
| } // namespace |
| } // namespace trace_processor |
| } // namespace perfetto |