blob: 2507b927c3fbb74ed63fb070aac05c563324520e [file] [log] [blame]
/*
* Copyright (C) 2022 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/db/view.h"
#include "src/trace_processor/tables/macros.h"
#include "src/trace_processor/views/macros.h"
#include "test/gtest_and_gmock.h"
namespace perfetto {
namespace trace_processor {
namespace {
#define PERFETTO_TP_TEST_THREAD_TABLE_DEF(NAME, PARENT, C) \
NAME(TestThreadTable, "thread_table") \
PARENT(PERFETTO_TP_ROOT_TABLE_PARENT_DEF, C) \
C(StringPool::Id, name) \
C(uint32_t, tid)
PERFETTO_TP_TABLE(PERFETTO_TP_TEST_THREAD_TABLE_DEF);
#define PERFETTO_TP_TEST_TRACK_TABLE_DEF(NAME, PARENT, C) \
NAME(TestTrackTable, "track_table") \
PARENT(PERFETTO_TP_ROOT_TABLE_PARENT_DEF, C) \
C(StringPool::Id, name)
PERFETTO_TP_TABLE(PERFETTO_TP_TEST_TRACK_TABLE_DEF);
#define PERFETTO_TP_TEST_THREAD_TRACK_TABLE_DEF(NAME, PARENT, C) \
NAME(TestThreadTrackTable, "thread_track_table") \
PARENT(PERFETTO_TP_TEST_TRACK_TABLE_DEF, C) \
C(TestThreadTable::Id, utid)
PERFETTO_TP_TABLE(PERFETTO_TP_TEST_THREAD_TRACK_TABLE_DEF);
#define PERFETTO_TP_TEST_EVENT_TABLE_DEF(NAME, PARENT, C) \
NAME(TestEventTable, "event_table") \
PARENT(PERFETTO_TP_ROOT_TABLE_PARENT_DEF, C) \
C(int64_t, ts, Column::Flag::kSorted) \
C(TestTrackTable::Id, track_id)
PERFETTO_TP_TABLE(PERFETTO_TP_TEST_EVENT_TABLE_DEF);
#define PERFETTO_TP_TEST_SLICE_TABLE_DEF(NAME, PARENT, C) \
NAME(TestSliceTable, "slice_table") \
PARENT(PERFETTO_TP_TEST_EVENT_TABLE_DEF, C) \
C(StringPool::Id, name)
PERFETTO_TP_TABLE(PERFETTO_TP_TEST_SLICE_TABLE_DEF);
TestThreadTable::~TestThreadTable() = default;
TestTrackTable::~TestTrackTable() = default;
TestThreadTrackTable::~TestThreadTrackTable() = default;
TestEventTable::~TestEventTable() = default;
TestSliceTable::~TestSliceTable() = default;
template <typename ViewSubclass>
class AbstractViewTest : public ::testing::Test {
protected:
using ColIdx = typename ViewSubclass::ColumnIndex;
using QueryResult = typename ViewSubclass::QueryResult;
virtual ~AbstractViewTest() = default;
QueryResult Query(const std::vector<Constraint>& cs = {},
const std::vector<Order>& ob = {}) {
return Query(cs, ob, AllColsUsed(view()));
}
QueryResult QueryUsingCols(const std::vector<uint32_t>& cols_used) {
return Query({}, {}, cols_used);
}
QueryResult Query(const std::vector<Constraint>& cs,
const std::vector<Order>& ob,
const std::vector<uint32_t>& cols_used) {
return view().Query(cs, ob, IvToBv(view(), cols_used));
}
StringPool::Id Intern(const char* ptr) { return pool_.InternString(ptr); }
virtual ViewSubclass& view() = 0;
StringPool pool_;
private:
std::vector<uint32_t> AllColsUsed(const View& v) {
std::vector<uint32_t> used(v.GetColumnCount());
std::iota(used.begin(), used.end(), 0);
return used;
}
BitVector IvToBv(const View& v, const std::vector<uint32_t>& cols_used) {
BitVector bv(v.GetColumnCount());
for (uint32_t col : cols_used) {
bv.Set(col);
}
return bv;
}
};
#define PERFETTO_TP_EVENT_VIEW_DEF(NAME, FROM, JOIN, COL, _) \
NAME(TestEventView, "event_view") \
FROM(TestEventTable, event) \
JOIN(TestTrackTable, track, id, event, track_id, View::kIdAlwaysPresent) \
COL(id, event, id) \
COL(ts, event, ts) \
COL(track_id, event, track_id) \
COL(track_name, track, name)
PERFETTO_TP_DECLARE_VIEW(PERFETTO_TP_EVENT_VIEW_DEF);
PERFETTO_TP_DEFINE_VIEW(TestEventView);
class EventViewTest : public AbstractViewTest<TestEventView> {
protected:
EventViewTest() {
t1_id_ = track_.Insert({/* name */ Intern("foo")}).id;
t2_id_ = track_.Insert({/* name */ Intern("bar")}).id;
event_table_.Insert({/* ts */ 100, t1_id_});
event_table_.Insert({/* ts */ 101, t2_id_});
event_table_.Insert({/* ts */ 102, t1_id_});
}
virtual TestEventView& view() override { return event_view_; }
TestTrackTable::Id t1_id_;
TestTrackTable::Id t2_id_;
private:
TestEventTable event_table_{&pool_, nullptr};
TestTrackTable track_{&pool_, nullptr};
TestEventView event_view_{&event_table_, &track_};
};
TEST_F(EventViewTest, UnusedColumnsAreDummy) {
TestEventView::QueryResult result = QueryUsingCols({ColIdx::track_name});
ASSERT_TRUE(result.columns()[ColIdx::id].IsDummy());
ASSERT_TRUE(result.columns()[ColIdx::ts].IsDummy());
ASSERT_FALSE(result.columns()[ColIdx::track_name].IsDummy());
}
TEST_F(EventViewTest, Iterate) {
TestEventView::QueryResult result = Query();
auto it = result.IterateRows();
ASSERT_TRUE(it);
ASSERT_EQ(it.row_number().row_number(), 0u);
ASSERT_EQ(it.ts(), 100);
ASSERT_EQ(it.track_name(), Intern("foo"));
ASSERT_EQ(it.track_id(), t1_id_);
ASSERT_TRUE(++it);
ASSERT_EQ(it.row_number().row_number(), 1u);
ASSERT_EQ(it.ts(), 101);
ASSERT_EQ(it.track_name(), Intern("bar"));
ASSERT_EQ(it.track_id(), t2_id_);
ASSERT_TRUE(++it);
ASSERT_EQ(it.row_number().row_number(), 2u);
ASSERT_EQ(it.ts(), 102);
ASSERT_EQ(it.track_name(), Intern("foo"));
ASSERT_EQ(it.track_id(), t1_id_);
ASSERT_FALSE(++it);
}
TEST_F(EventViewTest, FilterEventEmpty) {
TestEventView::QueryResult result = Query({view().ts().eq(0)});
auto it = result.IterateRows();
ASSERT_FALSE(it);
}
TEST_F(EventViewTest, FilterEventNoUseTrack) {
TestEventView::QueryResult result =
Query({view().ts().eq(100)}, {}, {ColIdx::ts});
auto it = result.IterateRows();
ASSERT_TRUE(it);
ASSERT_EQ(it.ts(), 100);
ASSERT_FALSE(++it);
}
TEST_F(EventViewTest, FilterEventUseTrack) {
TestEventView::QueryResult result =
Query({view().ts().eq(100)}, {},
{ColIdx::ts, ColIdx::track_name, ColIdx::track_id});
auto it = result.IterateRows();
ASSERT_TRUE(it);
ASSERT_EQ(it.ts(), 100);
ASSERT_EQ(it.track_name(), Intern("foo"));
ASSERT_EQ(it.track_id(), t1_id_);
ASSERT_FALSE(++it);
}
TEST_F(EventViewTest, FilterTrackEmpty) {
TestEventView::QueryResult result = Query({view().track_id().eq(102398)});
auto it = result.IterateRows();
ASSERT_FALSE(it);
}
TEST_F(EventViewTest, FilterTrackNoUseEvent) {
TestEventView::QueryResult result =
Query({view().track_name().eq("foo")}, {},
{ColIdx::track_name, ColIdx::track_id});
auto it = result.IterateRows();
ASSERT_TRUE(it);
ASSERT_EQ(it.track_id(), t1_id_);
ASSERT_EQ(it.track_name(), Intern("foo"));
ASSERT_TRUE(++it);
ASSERT_EQ(it.track_id(), t1_id_);
ASSERT_EQ(it.track_name(), Intern("foo"));
ASSERT_FALSE(++it);
}
TEST_F(EventViewTest, FilterTrackUseEvent) {
TestEventView::QueryResult result =
Query({view().track_id().eq(t1_id_.value)}, {},
{ColIdx::ts, ColIdx::track_name, ColIdx::track_id});
auto it = result.IterateRows();
ASSERT_TRUE(it);
ASSERT_EQ(it.ts(), 100);
ASSERT_EQ(it.track_name(), Intern("foo"));
ASSERT_EQ(it.track_id(), t1_id_);
ASSERT_TRUE(++it);
ASSERT_EQ(it.ts(), 102);
ASSERT_EQ(it.track_name(), Intern("foo"));
ASSERT_EQ(it.track_id(), t1_id_);
ASSERT_FALSE(++it);
}
#define PERFETTO_TP_THREAD_EVENT_VIEW_DEF(NAME, FROM, JOIN, COL, _) \
NAME(TestThreadEventView, "thread_event_view") \
FROM(TestEventTable, event) \
JOIN(TestThreadTrackTable, track, id, event, track_id, View::kNoFlag) \
JOIN(TestThreadTable, thread, id, track, utid, View::kIdAlwaysPresent) \
COL(id, event, id) \
COL(ts, event, ts) \
COL(track_id, track, id) \
COL(track_name, track, name) \
COL(utid, track, utid) \
COL(thread_name, thread, name)
PERFETTO_TP_DECLARE_VIEW(PERFETTO_TP_THREAD_EVENT_VIEW_DEF);
PERFETTO_TP_DEFINE_VIEW(TestThreadEventView);
class ThreadEventViewTest : public AbstractViewTest<TestThreadEventView> {
protected:
ThreadEventViewTest() {
th1_id_ = thread_.Insert({Intern("th1"), 1}).id;
th2_id_ = thread_.Insert({Intern("th2"), 2}).id;
t1_id_ = track_.Insert({/* name */ Intern("t1")}).id;
t2_id_ = track_.Insert({/* name */ Intern("t2")}).id;
t3_id_ = thread_track_.Insert({/* name */ Intern("t3"), th2_id_}).id;
t4_id_ = thread_track_.Insert({/* name */ Intern("t4"), th1_id_}).id;
t5_id_ = thread_track_.Insert({/* name */ Intern("t5"), th2_id_}).id;
t6_id_ = track_.Insert({/* name */ Intern("t6")}).id;
event_table_.Insert({/* ts */ 100, t1_id_});
event_table_.Insert({/* ts */ 101, t2_id_});
event_table_.Insert({/* ts */ 102, t3_id_});
event_table_.Insert({/* ts */ 103, t5_id_});
event_table_.Insert({/* ts */ 104, t4_id_});
event_table_.Insert({/* ts */ 105, t5_id_});
event_table_.Insert({/* ts */ 106, t1_id_});
event_table_.Insert({/* ts */ 107, t4_id_});
}
virtual TestThreadEventView& view() override { return event_view_; }
TestThreadTable::Id th1_id_;
TestThreadTable::Id th2_id_;
TestTrackTable::Id t1_id_;
TestTrackTable::Id t2_id_;
TestTrackTable::Id t3_id_;
TestTrackTable::Id t4_id_;
TestTrackTable::Id t5_id_;
TestTrackTable::Id t6_id_;
private:
TestEventTable event_table_{&pool_, nullptr};
TestTrackTable track_{&pool_, nullptr};
TestThreadTrackTable thread_track_{&pool_, &track_};
TestThreadTable thread_{&pool_, nullptr};
TestThreadEventView event_view_{&event_table_, &thread_track_, &thread_};
};
TEST_F(ThreadEventViewTest, Iterate) {
auto result = Query();
auto it = result.IterateRows();
ASSERT_TRUE(it);
ASSERT_EQ(it.ts(), 102);
ASSERT_EQ(it.track_id(), t3_id_);
ASSERT_EQ(it.track_name(), Intern("t3"));
ASSERT_EQ(it.utid(), th2_id_);
ASSERT_EQ(it.thread_name(), Intern("th2"));
ASSERT_TRUE(++it);
ASSERT_EQ(it.ts(), 103);
ASSERT_EQ(it.track_name(), Intern("t5"));
ASSERT_EQ(it.track_id(), t5_id_);
ASSERT_EQ(it.utid(), th2_id_);
ASSERT_EQ(it.thread_name(), Intern("th2"));
ASSERT_TRUE(++it);
ASSERT_EQ(it.ts(), 104);
ASSERT_EQ(it.track_id(), t4_id_);
ASSERT_EQ(it.track_name(), Intern("t4"));
ASSERT_EQ(it.utid(), th1_id_);
ASSERT_EQ(it.thread_name(), Intern("th1"));
ASSERT_TRUE(++it);
ASSERT_EQ(it.ts(), 105);
ASSERT_EQ(it.track_id(), t5_id_);
ASSERT_EQ(it.track_name(), Intern("t5"));
ASSERT_EQ(it.utid(), th2_id_);
ASSERT_EQ(it.thread_name(), Intern("th2"));
ASSERT_TRUE(++it);
ASSERT_EQ(it.ts(), 107);
ASSERT_EQ(it.track_id(), t4_id_);
ASSERT_EQ(it.track_name(), Intern("t4"));
ASSERT_EQ(it.utid(), th1_id_);
ASSERT_EQ(it.thread_name(), Intern("th1"));
ASSERT_FALSE(++it);
}
TEST_F(ThreadEventViewTest, FilterEventUseTrackAndThread) {
auto result =
Query({view().ts().ge(105)}, {},
{ColIdx::ts, ColIdx::track_id, ColIdx::utid, ColIdx::thread_name});
auto it = result.IterateRows();
ASSERT_TRUE(it);
ASSERT_EQ(it.ts(), 105);
ASSERT_EQ(it.track_id(), t5_id_);
ASSERT_EQ(it.utid(), th2_id_);
ASSERT_EQ(it.thread_name(), Intern("th2"));
ASSERT_TRUE(++it);
ASSERT_EQ(it.ts(), 107);
ASSERT_EQ(it.track_id(), t4_id_);
ASSERT_EQ(it.utid(), th1_id_);
ASSERT_EQ(it.thread_name(), Intern("th1"));
ASSERT_FALSE(++it);
}
TEST_F(ThreadEventViewTest, FilterEventUseThreadNoUseTrack) {
auto result = Query({view().ts().ge(103), view().ts().le(105)}, {},
{ColIdx::ts, ColIdx::thread_name});
auto it = result.IterateRows();
ASSERT_TRUE(it);
ASSERT_EQ(it.ts(), 103);
ASSERT_EQ(it.thread_name(), Intern("th2"));
ASSERT_TRUE(++it);
ASSERT_EQ(it.ts(), 104);
ASSERT_EQ(it.thread_name(), Intern("th1"));
ASSERT_TRUE(++it);
ASSERT_EQ(it.ts(), 105);
ASSERT_EQ(it.thread_name(), Intern("th2"));
ASSERT_FALSE(++it);
}
TEST_F(ThreadEventViewTest, FilterTrackUseEventNoUseThread) {
auto result = Query({view().track_id().eq(t4_id_.value)}, {},
{ColIdx::ts, ColIdx::track_id});
auto it = result.IterateRows();
ASSERT_TRUE(it);
ASSERT_EQ(it.ts(), 104);
ASSERT_EQ(it.track_id(), t4_id_);
ASSERT_TRUE(++it);
ASSERT_EQ(it.ts(), 107);
ASSERT_EQ(it.track_id(), t4_id_);
ASSERT_FALSE(++it);
}
TEST_F(ThreadEventViewTest, FilterEventAndTrack) {
auto result = Query({view().ts().ge(103), view().track_name().eq("t5")}, {},
{ColIdx::ts, ColIdx::track_name});
auto it = result.IterateRows();
ASSERT_TRUE(it);
ASSERT_EQ(it.ts(), 103);
ASSERT_EQ(it.track_name(), Intern("t5"));
ASSERT_TRUE(++it);
ASSERT_EQ(it.ts(), 105);
ASSERT_EQ(it.track_name(), Intern("t5"));
ASSERT_FALSE(++it);
}
TEST_F(ThreadEventViewTest, FilterEventAndThread) {
auto result = Query({view().ts().ge(103), view().thread_name().eq("th1")}, {},
{ColIdx::ts, ColIdx::thread_name});
auto it = result.IterateRows();
ASSERT_TRUE(it);
ASSERT_EQ(it.ts(), 104);
ASSERT_EQ(it.thread_name(), Intern("th1"));
ASSERT_TRUE(++it);
ASSERT_EQ(it.ts(), 107);
ASSERT_EQ(it.thread_name(), Intern("th1"));
ASSERT_FALSE(++it);
}
#define PERFETTO_TP_THREAD_SLICE_VIEW_DEF(NAME, FROM, JOIN, COL, _) \
NAME(TestThreadSliceView, "thread_slice_view") \
COL(id, slice, id) \
COL(ts, slice, ts) \
COL(name, slice, name) \
COL(track_id, slice, track_id) \
COL(track_name, track, name) \
COL(utid, thread, id) \
COL(thread_name, thread, name) \
FROM(TestSliceTable, slice) \
JOIN(TestThreadTrackTable, track, id, slice, track_id, View::kNoFlag) \
JOIN(TestThreadTable, thread, id, track, utid, View::kIdAlwaysPresent)
PERFETTO_TP_DECLARE_VIEW(PERFETTO_TP_THREAD_SLICE_VIEW_DEF);
PERFETTO_TP_DEFINE_VIEW(TestThreadSliceView);
class ThreadSliceViewTest : public AbstractViewTest<TestThreadSliceView> {
protected:
ThreadSliceViewTest() {
th1_id_ = thread_.Insert({Intern("th1"), 1}).id;
th2_id_ = thread_.Insert({Intern("th2"), 2}).id;
t1_id_ = track_.Insert({/* name */ Intern("t1")}).id;
t2_id_ = track_.Insert({/* name */ Intern("t2")}).id;
t3_id_ = thread_track_.Insert({/* name */ Intern("t3"), th2_id_}).id;
t4_id_ = thread_track_.Insert({/* name */ Intern("t4"), th1_id_}).id;
t5_id_ = thread_track_.Insert({/* name */ Intern("t5"), th2_id_}).id;
t6_id_ = track_.Insert({/* name */ Intern("t6")}).id;
event_.Insert({/* ts */ 100, t1_id_});
event_.Insert({/* ts */ 101, t2_id_});
slice_table_.Insert({/* ts */ 102, t3_id_, Intern("ts102")});
slice_table_.Insert({/* ts */ 103, t5_id_, Intern("ts103")});
slice_table_.Insert({/* ts */ 104, t4_id_, Intern("ts104")});
event_.Insert({/* ts */ 105, t5_id_});
slice_table_.Insert({/* ts */ 106, t1_id_, Intern("ts106")});
slice_table_.Insert({/* ts */ 107, t4_id_, Intern("ts107")});
}
TestThreadSliceView& view() override { return slice_view_; }
TestThreadTable::Id th1_id_;
TestThreadTable::Id th2_id_;
TestTrackTable::Id t1_id_;
TestTrackTable::Id t2_id_;
TestTrackTable::Id t3_id_;
TestTrackTable::Id t4_id_;
TestTrackTable::Id t5_id_;
TestTrackTable::Id t6_id_;
private:
TestEventTable event_{&pool_, nullptr};
TestSliceTable slice_table_{&pool_, &event_};
TestTrackTable track_{&pool_, nullptr};
TestThreadTrackTable thread_track_{&pool_, &track_};
TestThreadTable thread_{&pool_, nullptr};
TestThreadSliceView slice_view_{&slice_table_, &thread_track_, &thread_};
};
TEST_F(ThreadSliceViewTest, Iterate) {
auto result = Query();
auto it = result.IterateRows();
ASSERT_TRUE(it);
ASSERT_EQ(it.ts(), 102);
ASSERT_EQ(it.track_id(), t3_id_);
ASSERT_EQ(it.track_name(), Intern("t3"));
ASSERT_EQ(it.utid(), th2_id_);
ASSERT_EQ(it.thread_name(), Intern("th2"));
ASSERT_TRUE(++it);
ASSERT_EQ(it.ts(), 103);
ASSERT_EQ(it.track_name(), Intern("t5"));
ASSERT_EQ(it.track_id(), t5_id_);
ASSERT_EQ(it.utid(), th2_id_);
ASSERT_EQ(it.thread_name(), Intern("th2"));
ASSERT_TRUE(++it);
ASSERT_EQ(it.ts(), 104);
ASSERT_EQ(it.track_id(), t4_id_);
ASSERT_EQ(it.track_name(), Intern("t4"));
ASSERT_EQ(it.utid(), th1_id_);
ASSERT_EQ(it.thread_name(), Intern("th1"));
ASSERT_TRUE(++it);
ASSERT_EQ(it.ts(), 107);
ASSERT_EQ(it.track_id(), t4_id_);
ASSERT_EQ(it.track_name(), Intern("t4"));
ASSERT_EQ(it.utid(), th1_id_);
ASSERT_EQ(it.thread_name(), Intern("th1"));
ASSERT_FALSE(++it);
}
TEST_F(ThreadSliceViewTest, FilterAll) {
auto result = Query({view().ts().le(106), view().track_id().le(t4_id_.value),
view().thread_name().eq("th2")},
{}, {ColIdx::ts, ColIdx::track_id, ColIdx::thread_name});
auto it = result.IterateRows();
ASSERT_TRUE(it);
ASSERT_EQ(it.ts(), 102);
ASSERT_EQ(it.track_id(), t3_id_);
ASSERT_EQ(it.thread_name(), Intern("th2"));
ASSERT_FALSE(++it);
}
TEST_F(ThreadSliceViewTest, FilterEventAndTrack) {
auto result = Query({view().ts().le(106), view().track_id().le(t4_id_.value)},
{}, {ColIdx::ts, ColIdx::track_id});
auto it = result.IterateRows();
ASSERT_TRUE(it);
ASSERT_EQ(it.ts(), 102);
ASSERT_EQ(it.track_id(), t3_id_);
ASSERT_TRUE(++it);
ASSERT_EQ(it.ts(), 104);
ASSERT_EQ(it.track_id(), t4_id_);
ASSERT_FALSE(++it);
}
TEST_F(ThreadSliceViewTest, Sort) {
auto result =
Query({}, {view().track_id().ascending(), view().ts().descending()},
{ColIdx::track_id, ColIdx::ts});
auto it = result.IterateRows();
ASSERT_TRUE(it);
ASSERT_EQ(it.ts(), 102);
ASSERT_EQ(it.track_id(), t3_id_);
ASSERT_TRUE(++it);
ASSERT_EQ(it.ts(), 107);
ASSERT_EQ(it.track_id(), t4_id_);
ASSERT_TRUE(++it);
ASSERT_EQ(it.ts(), 104);
ASSERT_EQ(it.track_id(), t4_id_);
ASSERT_TRUE(++it);
ASSERT_EQ(it.ts(), 103);
ASSERT_EQ(it.track_id(), t5_id_);
ASSERT_FALSE(++it);
}
TEST_F(ThreadSliceViewTest, FilterAndSort) {
auto result = Query({view().track_id().lt(t5_id_.value)},
{view().track_id().ascending(), view().ts().descending()},
{ColIdx::track_id, ColIdx::ts, ColIdx::thread_name});
auto it = result.IterateRows();
ASSERT_TRUE(it);
ASSERT_EQ(it.ts(), 102);
ASSERT_EQ(it.track_id(), t3_id_);
ASSERT_EQ(it.thread_name(), Intern("th2"));
ASSERT_TRUE(++it);
ASSERT_EQ(it.ts(), 107);
ASSERT_EQ(it.track_id(), t4_id_);
ASSERT_EQ(it.thread_name(), Intern("th1"));
ASSERT_TRUE(++it);
ASSERT_EQ(it.ts(), 104);
ASSERT_EQ(it.track_id(), t4_id_);
ASSERT_EQ(it.thread_name(), Intern("th1"));
ASSERT_FALSE(++it);
}
} // namespace
} // namespace trace_processor
} // namespace perfetto