blob: f6414cd47e3c989b4728948db27dc2e6409fcae4 [file] [log] [blame]
/*
* 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