• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/db/column.h"
18 
19 #include "src/trace_processor/db/compare.h"
20 #include "src/trace_processor/db/table.h"
21 #include "src/trace_processor/util/glob.h"
22 
23 namespace perfetto {
24 namespace trace_processor {
25 
Column(const Column & column,Table * table,uint32_t col_idx,uint32_t overlay_idx,const char * name)26 Column::Column(const Column& column,
27                Table* table,
28                uint32_t col_idx,
29                uint32_t overlay_idx,
30                const char* name)
31     : Column(name ? name : column.name_,
32              column.type_,
33              column.flags_ & ~kNoCrossTableInheritFlags,
34              table,
35              col_idx,
36              overlay_idx,
37              column.storage_) {}
38 
Column(const char * name,ColumnType type,uint32_t flags,Table * table,uint32_t index_in_table,uint32_t overlay_index,ColumnStorageBase * st)39 Column::Column(const char* name,
40                ColumnType type,
41                uint32_t flags,
42                Table* table,
43                uint32_t index_in_table,
44                uint32_t overlay_index,
45                ColumnStorageBase* st)
46     : type_(type),
47       storage_(st),
48       name_(name),
49       flags_(flags),
50       table_(table),
51       index_in_table_(index_in_table),
52       overlay_index_(overlay_index),
53       string_pool_(table->string_pool_) {
54   // Check that the dense-ness of the column and the nullable vector match.
55   if (IsNullable() && !IsDummy()) {
56     bool is_storage_dense;
57     switch (type_) {
58       case ColumnType::kInt32:
59         is_storage_dense = storage<std::optional<int32_t>>().IsDense();
60         break;
61       case ColumnType::kUint32:
62         is_storage_dense = storage<std::optional<uint32_t>>().IsDense();
63         break;
64       case ColumnType::kInt64:
65         is_storage_dense = storage<std::optional<int64_t>>().IsDense();
66         break;
67       case ColumnType::kDouble:
68         is_storage_dense = storage<std::optional<double>>().IsDense();
69         break;
70       case ColumnType::kString:
71         PERFETTO_FATAL("String column should not be nullable");
72       case ColumnType::kId:
73         PERFETTO_FATAL("Id column should not be nullable");
74       case ColumnType::kDummy:
75         PERFETTO_FATAL("Dummy column excluded above");
76     }
77     PERFETTO_DCHECK(is_storage_dense == IsDense());
78   }
79   PERFETTO_DCHECK(IsFlagsAndTypeValid(flags_, type_));
80 }
81 
DummyColumn(const char * name,Table * table,uint32_t col_idx_in_table)82 Column Column::DummyColumn(const char* name,
83                            Table* table,
84                            uint32_t col_idx_in_table) {
85   return Column(name, ColumnType::kDummy, Flag::kNoFlag, table,
86                 col_idx_in_table, std::numeric_limits<uint32_t>::max(),
87                 nullptr);
88 }
89 
IdColumn(Table * table,uint32_t col_idx,uint32_t overlay_idx)90 Column Column::IdColumn(Table* table, uint32_t col_idx, uint32_t overlay_idx) {
91   return Column("id", ColumnType::kId, kIdFlags, table, col_idx, overlay_idx,
92                 nullptr);
93 }
94 
StableSort(bool desc,std::vector<uint32_t> * idx) const95 void Column::StableSort(bool desc, std::vector<uint32_t>* idx) const {
96   if (desc) {
97     StableSort<true /* desc */>(idx);
98   } else {
99     StableSort<false /* desc */>(idx);
100   }
101 }
102 
FilterIntoSlow(FilterOp op,SqlValue value,RowMap * rm) const103 void Column::FilterIntoSlow(FilterOp op, SqlValue value, RowMap* rm) const {
104   switch (type_) {
105     case ColumnType::kInt32: {
106       if (IsNullable()) {
107         FilterIntoNumericSlow<int32_t, true /* is_nullable */>(op, value, rm);
108       } else {
109         FilterIntoNumericSlow<int32_t, false /* is_nullable */>(op, value, rm);
110       }
111       break;
112     }
113     case ColumnType::kUint32: {
114       if (IsNullable()) {
115         FilterIntoNumericSlow<uint32_t, true /* is_nullable */>(op, value, rm);
116       } else {
117         FilterIntoNumericSlow<uint32_t, false /* is_nullable */>(op, value, rm);
118       }
119       break;
120     }
121     case ColumnType::kInt64: {
122       if (IsNullable()) {
123         FilterIntoNumericSlow<int64_t, true /* is_nullable */>(op, value, rm);
124       } else {
125         FilterIntoNumericSlow<int64_t, false /* is_nullable */>(op, value, rm);
126       }
127       break;
128     }
129     case ColumnType::kDouble: {
130       if (IsNullable()) {
131         FilterIntoNumericSlow<double, true /* is_nullable */>(op, value, rm);
132       } else {
133         FilterIntoNumericSlow<double, false /* is_nullable */>(op, value, rm);
134       }
135       break;
136     }
137     case ColumnType::kString: {
138       FilterIntoStringSlow(op, value, rm);
139       break;
140     }
141     case ColumnType::kId: {
142       FilterIntoIdSlow(op, value, rm);
143       break;
144     }
145     case ColumnType::kDummy:
146       PERFETTO_FATAL("FilterIntoSlow not allowed on dummy column");
147   }
148 }
149 
150 template <typename T, bool is_nullable>
FilterIntoNumericSlow(FilterOp op,SqlValue value,RowMap * rm) const151 void Column::FilterIntoNumericSlow(FilterOp op,
152                                    SqlValue value,
153                                    RowMap* rm) const {
154   PERFETTO_DCHECK(IsNullable() == is_nullable);
155   PERFETTO_DCHECK(type_ == ColumnTypeHelper<T>::ToColumnType());
156   PERFETTO_DCHECK(std::is_arithmetic<T>::value);
157 
158   if (op == FilterOp::kIsNull) {
159     PERFETTO_DCHECK(value.is_null());
160     if (is_nullable) {
161       overlay().FilterInto(rm, [this](uint32_t row) {
162         return !storage<std::optional<T>>().Get(row).has_value();
163       });
164     } else {
165       rm->Clear();
166     }
167     return;
168   } else if (op == FilterOp::kIsNotNull) {
169     PERFETTO_DCHECK(value.is_null());
170     if (is_nullable) {
171       overlay().FilterInto(rm, [this](uint32_t row) {
172         return storage<std::optional<T>>().Get(row).has_value();
173       });
174     }
175     return;
176   }
177 
178   if (value.type == SqlValue::Type::kDouble) {
179     double double_value = value.double_value;
180     if (std::is_same<T, double>::value) {
181       auto fn = [double_value](T v) {
182         // We static cast here as this code will be compiled even when T ==
183         // int64_t as we don't have if constexpr in C++11. In reality the cast
184         // is a noop but we cannot statically verify that for the compiler.
185         return compare::Numeric(static_cast<double>(v), double_value);
186       };
187       FilterIntoNumericWithComparatorSlow<T, is_nullable>(op, rm, fn);
188     } else {
189       auto fn = [double_value](T v) {
190         // We static cast here as this code will be compiled even when T ==
191         // double as we don't have if constexpr in C++11. In reality the cast is
192         // a noop but we cannot statically verify that for the compiler.
193         return compare::LongToDouble(static_cast<int64_t>(v), double_value);
194       };
195       FilterIntoNumericWithComparatorSlow<T, is_nullable>(op, rm, fn);
196     }
197   } else if (value.type == SqlValue::Type::kLong) {
198     int64_t long_value = value.long_value;
199     if (std::is_same<T, double>::value) {
200       auto fn = [long_value](T v) {
201         // We negate the return value as the long is always the first parameter
202         // for this function even though the LHS of the comparator should
203         // actually be |v|. This saves us having a duplicate implementation of
204         // the comparision function.
205         return -compare::LongToDouble(long_value, static_cast<double>(v));
206       };
207       FilterIntoNumericWithComparatorSlow<T, is_nullable>(op, rm, fn);
208     } else {
209       auto fn = [long_value](T v) {
210         // We static cast here as this code will be compiled even when T ==
211         // double as we don't have if constexpr in C++11. In reality the cast is
212         // a noop but we cannot statically verify that for the compiler.
213         return compare::Numeric(static_cast<int64_t>(v), long_value);
214       };
215       FilterIntoNumericWithComparatorSlow<T, is_nullable>(op, rm, fn);
216     }
217   } else {
218     rm->Clear();
219   }
220 }
221 
222 template <typename T, bool is_nullable, typename Comparator>
FilterIntoNumericWithComparatorSlow(FilterOp op,RowMap * rm,Comparator cmp) const223 void Column::FilterIntoNumericWithComparatorSlow(FilterOp op,
224                                                  RowMap* rm,
225                                                  Comparator cmp) const {
226   switch (op) {
227     case FilterOp::kLt:
228       overlay().FilterInto(rm, [this, &cmp](uint32_t idx) {
229         if (is_nullable) {
230           auto opt_value = storage<std::optional<T>>().Get(idx);
231           return opt_value && cmp(*opt_value) < 0;
232         }
233         return cmp(storage<T>().Get(idx)) < 0;
234       });
235       break;
236     case FilterOp::kEq:
237       overlay().FilterInto(rm, [this, &cmp](uint32_t idx) {
238         if (is_nullable) {
239           auto opt_value = storage<std::optional<T>>().Get(idx);
240           return opt_value && cmp(*opt_value) == 0;
241         }
242         return cmp(storage<T>().Get(idx)) == 0;
243       });
244       break;
245     case FilterOp::kGt:
246       overlay().FilterInto(rm, [this, &cmp](uint32_t idx) {
247         if (is_nullable) {
248           auto opt_value = storage<std::optional<T>>().Get(idx);
249           return opt_value && cmp(*opt_value) > 0;
250         }
251         return cmp(storage<T>().Get(idx)) > 0;
252       });
253       break;
254     case FilterOp::kNe:
255       overlay().FilterInto(rm, [this, &cmp](uint32_t idx) {
256         if (is_nullable) {
257           auto opt_value = storage<std::optional<T>>().Get(idx);
258           return opt_value && cmp(*opt_value) != 0;
259         }
260         return cmp(storage<T>().Get(idx)) != 0;
261       });
262       break;
263     case FilterOp::kLe:
264       overlay().FilterInto(rm, [this, &cmp](uint32_t idx) {
265         if (is_nullable) {
266           auto opt_value = storage<std::optional<T>>().Get(idx);
267           return opt_value && cmp(*opt_value) <= 0;
268         }
269         return cmp(storage<T>().Get(idx)) <= 0;
270       });
271       break;
272     case FilterOp::kGe:
273       overlay().FilterInto(rm, [this, &cmp](uint32_t idx) {
274         if (is_nullable) {
275           auto opt_value = storage<std::optional<T>>().Get(idx);
276           return opt_value && cmp(*opt_value) >= 0;
277         }
278         return cmp(storage<T>().Get(idx)) >= 0;
279       });
280       break;
281     case FilterOp::kGlob:
282       rm->Clear();
283       break;
284     case FilterOp::kIsNull:
285     case FilterOp::kIsNotNull:
286       PERFETTO_FATAL("Should be handled above");
287   }
288 }
289 
FilterIntoStringSlow(FilterOp op,SqlValue value,RowMap * rm) const290 void Column::FilterIntoStringSlow(FilterOp op,
291                                   SqlValue value,
292                                   RowMap* rm) const {
293   PERFETTO_DCHECK(type_ == ColumnType::kString);
294 
295   if (op == FilterOp::kIsNull) {
296     PERFETTO_DCHECK(value.is_null());
297     overlay().FilterInto(rm, [this](uint32_t row) {
298       return GetStringPoolStringAtIdx(row).data() == nullptr;
299     });
300     return;
301   } else if (op == FilterOp::kIsNotNull) {
302     PERFETTO_DCHECK(value.is_null());
303     overlay().FilterInto(rm, [this](uint32_t row) {
304       return GetStringPoolStringAtIdx(row).data() != nullptr;
305     });
306     return;
307   }
308 
309   if (value.type != SqlValue::Type::kString) {
310     rm->Clear();
311     return;
312   }
313 
314   NullTermStringView str_value = value.string_value;
315   PERFETTO_DCHECK(str_value.data() != nullptr);
316 
317   switch (op) {
318     case FilterOp::kLt:
319       overlay().FilterInto(rm, [this, str_value](uint32_t idx) {
320         auto v = GetStringPoolStringAtIdx(idx);
321         return v.data() != nullptr && compare::String(v, str_value) < 0;
322       });
323       break;
324     case FilterOp::kEq:
325       overlay().FilterInto(rm, [this, str_value](uint32_t idx) {
326         auto v = GetStringPoolStringAtIdx(idx);
327         return v.data() != nullptr && compare::String(v, str_value) == 0;
328       });
329       break;
330     case FilterOp::kGt:
331       overlay().FilterInto(rm, [this, str_value](uint32_t idx) {
332         auto v = GetStringPoolStringAtIdx(idx);
333         return v.data() != nullptr && compare::String(v, str_value) > 0;
334       });
335       break;
336     case FilterOp::kNe:
337       overlay().FilterInto(rm, [this, str_value](uint32_t idx) {
338         auto v = GetStringPoolStringAtIdx(idx);
339         return v.data() != nullptr && compare::String(v, str_value) != 0;
340       });
341       break;
342     case FilterOp::kLe:
343       overlay().FilterInto(rm, [this, str_value](uint32_t idx) {
344         auto v = GetStringPoolStringAtIdx(idx);
345         return v.data() != nullptr && compare::String(v, str_value) <= 0;
346       });
347       break;
348     case FilterOp::kGe:
349       overlay().FilterInto(rm, [this, str_value](uint32_t idx) {
350         auto v = GetStringPoolStringAtIdx(idx);
351         return v.data() != nullptr && compare::String(v, str_value) >= 0;
352       });
353       break;
354     case FilterOp::kGlob: {
355       util::GlobMatcher matcher = util::GlobMatcher::FromPattern(str_value);
356       overlay().FilterInto(rm, [this, &matcher](uint32_t idx) {
357         auto v = GetStringPoolStringAtIdx(idx);
358         return v.data() != nullptr && matcher.Matches(v);
359       });
360       break;
361     }
362     case FilterOp::kIsNull:
363     case FilterOp::kIsNotNull:
364       PERFETTO_FATAL("Should be handled above");
365   }
366 }
367 
FilterIntoIdSlow(FilterOp op,SqlValue value,RowMap * rm) const368 void Column::FilterIntoIdSlow(FilterOp op, SqlValue value, RowMap* rm) const {
369   PERFETTO_DCHECK(type_ == ColumnType::kId);
370 
371   if (op == FilterOp::kIsNull) {
372     PERFETTO_DCHECK(value.is_null());
373     rm->Clear();
374     return;
375   } else if (op == FilterOp::kIsNotNull) {
376     PERFETTO_DCHECK(value.is_null());
377     return;
378   }
379 
380   if (value.type != SqlValue::Type::kLong) {
381     rm->Clear();
382     return;
383   }
384 
385   uint32_t id_value = static_cast<uint32_t>(value.long_value);
386   switch (op) {
387     case FilterOp::kLt:
388       overlay().FilterInto(rm, [id_value](uint32_t idx) {
389         return compare::Numeric(idx, id_value) < 0;
390       });
391       break;
392     case FilterOp::kEq:
393       overlay().FilterInto(rm, [id_value](uint32_t idx) {
394         return compare::Numeric(idx, id_value) == 0;
395       });
396       break;
397     case FilterOp::kGt:
398       overlay().FilterInto(rm, [id_value](uint32_t idx) {
399         return compare::Numeric(idx, id_value) > 0;
400       });
401       break;
402     case FilterOp::kNe:
403       overlay().FilterInto(rm, [id_value](uint32_t idx) {
404         return compare::Numeric(idx, id_value) != 0;
405       });
406       break;
407     case FilterOp::kLe:
408       overlay().FilterInto(rm, [id_value](uint32_t idx) {
409         return compare::Numeric(idx, id_value) <= 0;
410       });
411       break;
412     case FilterOp::kGe:
413       overlay().FilterInto(rm, [id_value](uint32_t idx) {
414         return compare::Numeric(idx, id_value) >= 0;
415       });
416       break;
417     case FilterOp::kGlob:
418       rm->Clear();
419       break;
420     case FilterOp::kIsNull:
421     case FilterOp::kIsNotNull:
422       PERFETTO_FATAL("Should be handled above");
423   }
424 }
425 
426 template <bool desc>
StableSort(std::vector<uint32_t> * out) const427 void Column::StableSort(std::vector<uint32_t>* out) const {
428   switch (type_) {
429     case ColumnType::kInt32: {
430       if (IsNullable()) {
431         StableSortNumeric<desc, int32_t, true /* is_nullable */>(out);
432       } else {
433         StableSortNumeric<desc, int32_t, false /* is_nullable */>(out);
434       }
435       break;
436     }
437     case ColumnType::kUint32: {
438       if (IsNullable()) {
439         StableSortNumeric<desc, uint32_t, true /* is_nullable */>(out);
440       } else {
441         StableSortNumeric<desc, uint32_t, false /* is_nullable */>(out);
442       }
443       break;
444     }
445     case ColumnType::kInt64: {
446       if (IsNullable()) {
447         StableSortNumeric<desc, int64_t, true /* is_nullable */>(out);
448       } else {
449         StableSortNumeric<desc, int64_t, false /* is_nullable */>(out);
450       }
451       break;
452     }
453     case ColumnType::kDouble: {
454       if (IsNullable()) {
455         StableSortNumeric<desc, double, true /* is_nullable */>(out);
456       } else {
457         StableSortNumeric<desc, double, false /* is_nullable */>(out);
458       }
459       break;
460     }
461     case ColumnType::kString: {
462       overlay().StableSort(out, [this](uint32_t a_idx, uint32_t b_idx) {
463         auto a_str = GetStringPoolStringAtIdx(a_idx);
464         auto b_str = GetStringPoolStringAtIdx(b_idx);
465 
466         int res = compare::NullableString(a_str, b_str);
467         return desc ? res > 0 : res < 0;
468       });
469       break;
470     }
471     case ColumnType::kId:
472       overlay().StableSort(out, [](uint32_t a_idx, uint32_t b_idx) {
473         int res = compare::Numeric(a_idx, b_idx);
474         return desc ? res > 0 : res < 0;
475       });
476       break;
477     case ColumnType::kDummy:
478       PERFETTO_FATAL("StableSort not allowed on dummy column");
479   }
480 }
481 
482 template <bool desc, typename T, bool is_nullable>
StableSortNumeric(std::vector<uint32_t> * out) const483 void Column::StableSortNumeric(std::vector<uint32_t>* out) const {
484   PERFETTO_DCHECK(IsNullable() == is_nullable);
485   PERFETTO_DCHECK(ColumnTypeHelper<T>::ToColumnType() == type_);
486 
487   overlay().StableSort(out, [this](uint32_t a_idx, uint32_t b_idx) {
488     if (is_nullable) {
489       auto a_val = storage<std::optional<T>>().Get(a_idx);
490       auto b_val = storage<std::optional<T>>().Get(b_idx);
491 
492       int res = compare::NullableNumeric(a_val, b_val);
493       return desc ? res > 0 : res < 0;
494     }
495     auto a_val = storage<T>().Get(a_idx);
496     auto b_val = storage<T>().Get(b_idx);
497 
498     int res = compare::Numeric(a_val, b_val);
499     return desc ? res > 0 : res < 0;
500   });
501 }
502 
overlay() const503 const ColumnStorageOverlay& Column::overlay() const {
504   PERFETTO_DCHECK(type_ != ColumnType::kDummy);
505   return table_->overlays_[overlay_index()];
506 }
507 
508 }  // namespace trace_processor
509 }  // namespace perfetto
510