xref: /aosp_15_r20/external/perfetto/src/trace_processor/sqlite/db_sqlite_table_unittest.cc (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
1 
2 /*
3  * Copyright (C) 2019 The Android Open Source Project
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 
18 #include "src/trace_processor/sqlite/db_sqlite_table.h"
19 
20 #include <sqlite3.h>
21 #include <array>
22 #include <cstdint>
23 
24 #include "perfetto/trace_processor/basic_types.h"
25 #include "src/trace_processor/db/table.h"
26 #include "test/gtest_and_gmock.h"
27 
28 namespace perfetto::trace_processor {
29 namespace {
30 
CreateSchema()31 Table::Schema CreateSchema() {
32   Table::Schema schema;
33   schema.columns.push_back({"id", SqlValue::Type::kLong, true /* is_id */,
34                             true /* is_sorted */, false /* is_hidden */,
35                             false /* is_set_id */});
36   schema.columns.push_back({"type", SqlValue::Type::kLong, false /* is_id */,
37                             false /* is_sorted */, false /* is_hidden */,
38                             false /* is_set_id */});
39   schema.columns.push_back({"test1", SqlValue::Type::kLong, false /* is_id */,
40                             true /* is_sorted */, false /* is_hidden */,
41                             false /* is_set_id */});
42   schema.columns.push_back({"test2", SqlValue::Type::kLong, false /* is_id */,
43                             false /* is_sorted */, false /* is_hidden */,
44                             false /* is_set_id */});
45   schema.columns.push_back({"test3", SqlValue::Type::kLong, false /* is_id */,
46                             false /* is_sorted */, false /* is_hidden */,
47                             false /* is_set_id */});
48   return schema;
49 }
50 
CreateConstraint(int col,uint8_t op)51 sqlite3_index_info::sqlite3_index_constraint CreateConstraint(int col,
52                                                               uint8_t op) {
53   return {col, op, true, 0};
54 }
55 
CreateUsage()56 sqlite3_index_info::sqlite3_index_constraint_usage CreateUsage() {
57   return {1, true};
58 }
59 
CreateCsIndexInfo(int cs_count,sqlite3_index_info::sqlite3_index_constraint * c,sqlite3_index_info::sqlite3_index_constraint_usage * u)60 sqlite3_index_info CreateCsIndexInfo(
61     int cs_count,
62     sqlite3_index_info::sqlite3_index_constraint* c,
63     sqlite3_index_info::sqlite3_index_constraint_usage* u) {
64   return {cs_count, c, 0, nullptr, u, 0, nullptr, false, 0, 0, 0, 0, 0};
65 }
66 
CreateObIndexInfo(int ob_count,sqlite3_index_info::sqlite3_index_orderby * o)67 sqlite3_index_info CreateObIndexInfo(
68     int ob_count,
69     sqlite3_index_info::sqlite3_index_orderby* o) {
70   return {0, nullptr, ob_count, o, nullptr, 0, nullptr, false, 0, 0, 0, 0, 0};
71 }
72 
TEST(DbSqliteModule,IdEqCheaperThanOtherEq)73 TEST(DbSqliteModule, IdEqCheaperThanOtherEq) {
74   auto schema = CreateSchema();
75   constexpr uint32_t kRowCount = 1234;
76 
77   auto c = CreateConstraint(0, SQLITE_INDEX_CONSTRAINT_EQ);
78   auto u = CreateUsage();
79   auto info = CreateCsIndexInfo(1, &c, &u);
80 
81   auto id_cost =
82       DbSqliteModule::EstimateCost(schema, kRowCount, &info, {0u}, {});
83 
84   c.iColumn = 1;
85   auto a_cost =
86       DbSqliteModule::EstimateCost(schema, kRowCount, &info, {0u}, {});
87 
88   ASSERT_LT(id_cost.cost, a_cost.cost);
89   ASSERT_LT(id_cost.rows, a_cost.rows);
90 }
91 
TEST(DbSqliteModule,IdEqCheaperThatOtherConstraint)92 TEST(DbSqliteModule, IdEqCheaperThatOtherConstraint) {
93   auto schema = CreateSchema();
94   constexpr uint32_t kRowCount = 1234;
95 
96   auto c = CreateConstraint(0, SQLITE_INDEX_CONSTRAINT_EQ);
97   auto u = CreateUsage();
98   auto info = CreateCsIndexInfo(1, &c, &u);
99 
100   auto id_cost =
101       DbSqliteModule::EstimateCost(schema, kRowCount, &info, {0u}, {});
102 
103   c.iColumn = 1;
104   c.op = SQLITE_INDEX_CONSTRAINT_LT;
105   auto a_cost =
106       DbSqliteModule::EstimateCost(schema, kRowCount, &info, {0u}, {});
107 
108   ASSERT_LT(id_cost.cost, a_cost.cost);
109   ASSERT_LT(id_cost.rows, a_cost.rows);
110 }
111 
TEST(DbSqliteModule,SingleEqCheaperThanMultipleConstraint)112 TEST(DbSqliteModule, SingleEqCheaperThanMultipleConstraint) {
113   auto schema = CreateSchema();
114   constexpr uint32_t kRowCount = 1234;
115 
116   auto c = CreateConstraint(1, SQLITE_INDEX_CONSTRAINT_EQ);
117   auto u = CreateUsage();
118   auto info = CreateCsIndexInfo(1, &c, &u);
119 
120   auto single_cost =
121       DbSqliteModule::EstimateCost(schema, kRowCount, &info, {0u}, {});
122 
123   std::array c2{CreateConstraint(1, SQLITE_INDEX_CONSTRAINT_EQ),
124                 CreateConstraint(2, SQLITE_INDEX_CONSTRAINT_EQ)};
125   std::array u2{CreateUsage(), CreateUsage()};
126   auto info2 = CreateCsIndexInfo(c2.size(), c2.data(), u2.data());
127 
128   auto multi_cost =
129       DbSqliteModule::EstimateCost(schema, kRowCount, &info2, {0u, 1u}, {});
130 
131   // The cost of the single filter should be cheaper (because of our special
132   // handling of single equality). But the number of rows should be greater.
133   ASSERT_LT(single_cost.cost, multi_cost.cost);
134   ASSERT_GT(single_cost.rows, multi_cost.rows);
135 }
136 
TEST(DbSqliteModule,MultiSortedEqCheaperThanMultiUnsortedEq)137 TEST(DbSqliteModule, MultiSortedEqCheaperThanMultiUnsortedEq) {
138   auto schema = CreateSchema();
139   constexpr uint32_t kRowCount = 1234;
140 
141   std::array c1{CreateConstraint(1, SQLITE_INDEX_CONSTRAINT_EQ),
142                 CreateConstraint(2, SQLITE_INDEX_CONSTRAINT_EQ)};
143   std::array u1{CreateUsage(), CreateUsage()};
144   auto info1 = CreateCsIndexInfo(c1.size(), c1.data(), u1.data());
145 
146   auto sorted_cost =
147       DbSqliteModule::EstimateCost(schema, kRowCount, &info1, {0u, 1u}, {});
148 
149   std::array c2{CreateConstraint(3, SQLITE_INDEX_CONSTRAINT_EQ),
150                 CreateConstraint(4, SQLITE_INDEX_CONSTRAINT_EQ)};
151   std::array u2{CreateUsage(), CreateUsage()};
152   auto info2 = CreateCsIndexInfo(c2.size(), c2.data(), u2.data());
153 
154   auto unsorted_cost =
155       DbSqliteModule::EstimateCost(schema, kRowCount, &info2, {0u, 1u}, {});
156 
157   // The number of rows should be the same but the cost of the sorted
158   // query should be less.
159   ASSERT_LT(sorted_cost.cost, unsorted_cost.cost);
160   ASSERT_EQ(sorted_cost.rows, unsorted_cost.rows);
161 }
162 
TEST(DbSqliteModule,EmptyTableCosting)163 TEST(DbSqliteModule, EmptyTableCosting) {
164   auto schema = CreateSchema();
165   constexpr uint32_t kRowCount = 0;
166 
167   std::array c1{CreateConstraint(0, SQLITE_INDEX_CONSTRAINT_EQ)};
168   std::array u1{CreateUsage()};
169   auto info1 = CreateCsIndexInfo(c1.size(), c1.data(), u1.data());
170 
171   auto id_cost =
172       DbSqliteModule::EstimateCost(schema, kRowCount, &info1, {0u}, {});
173 
174   std::array c2{CreateConstraint(0, SQLITE_INDEX_CONSTRAINT_EQ)};
175   std::array u2{CreateUsage()};
176   auto info2 = CreateCsIndexInfo(c2.size(), c2.data(), u2.data());
177 
178   auto a_cost =
179       DbSqliteModule::EstimateCost(schema, kRowCount, &info2, {0u}, {});
180 
181   ASSERT_DOUBLE_EQ(id_cost.cost, a_cost.cost);
182   ASSERT_EQ(id_cost.rows, a_cost.rows);
183 }
184 
TEST(DbSqliteModule,OrderByOnSortedCheaper)185 TEST(DbSqliteModule, OrderByOnSortedCheaper) {
186   auto schema = CreateSchema();
187   constexpr uint32_t kRowCount = 1234;
188 
189   sqlite3_index_info::sqlite3_index_orderby ob1{1u, false};
190   auto info1 = CreateObIndexInfo(1, &ob1);
191 
192   auto a_cost =
193       DbSqliteModule::EstimateCost(schema, kRowCount, &info1, {}, {0u});
194 
195   sqlite3_index_info::sqlite3_index_orderby ob2{2u, false};
196   auto info2 = CreateObIndexInfo(1, &ob2);
197 
198   // On an ordered column, the constraint for sorting would get pruned so
199   // we would end up with an empty constraint set.
200   auto sorted_cost =
201       DbSqliteModule::EstimateCost(schema, kRowCount, &info2, {}, {});
202 
203   ASSERT_LT(sorted_cost.cost, a_cost.cost);
204   ASSERT_EQ(sorted_cost.rows, a_cost.rows);
205 }
206 
207 }  // namespace
208 }  // namespace perfetto::trace_processor
209