• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2024 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/range_overlay.h"
18 
19 #include <cstdint>
20 #include <memory>
21 #include <optional>
22 #include <utility>
23 #include <vector>
24 
25 #include "perfetto/base/logging.h"
26 #include "perfetto/trace_processor/basic_types.h"
27 #include "src/trace_processor/containers/bit_vector.h"
28 #include "src/trace_processor/db/column/data_layer.h"
29 #include "src/trace_processor/db/column/types.h"
30 #include "src/trace_processor/tp_metatrace.h"
31 
32 #include "protos/perfetto/trace_processor/metatrace_categories.pbzero.h"
33 
34 namespace perfetto::trace_processor::column {
35 
36 using Range = Range;
37 
ChainImpl(std::unique_ptr<DataLayerChain> inner,const Range * range)38 RangeOverlay::ChainImpl::ChainImpl(std::unique_ptr<DataLayerChain> inner,
39                                    const Range* range)
40     : inner_(std::move(inner)), range_(range) {
41   PERFETTO_CHECK(range->end <= inner_->size());
42 }
43 
SingleSearch(FilterOp op,SqlValue sql_val,uint32_t i) const44 SingleSearchResult RangeOverlay::ChainImpl::SingleSearch(FilterOp op,
45                                                          SqlValue sql_val,
46                                                          uint32_t i) const {
47   PERFETTO_DCHECK(i < range_->size());
48   return inner_->SingleSearch(op, sql_val, i + range_->start);
49 }
50 
ValidateSearchConstraints(FilterOp op,SqlValue sql_val) const51 SearchValidationResult RangeOverlay::ChainImpl::ValidateSearchConstraints(
52     FilterOp op,
53     SqlValue sql_val) const {
54   return inner_->ValidateSearchConstraints(op, sql_val);
55 }
56 
SearchValidated(FilterOp op,SqlValue sql_val,Range search_range) const57 RangeOrBitVector RangeOverlay::ChainImpl::SearchValidated(
58     FilterOp op,
59     SqlValue sql_val,
60     Range search_range) const {
61   PERFETTO_DCHECK(search_range.size() <= range_->size());
62   PERFETTO_TP_TRACE(metatrace::Category::DB, "RangeOverlay::Search");
63 
64   Range inner_search_range(search_range.start + range_->start,
65                            search_range.end + range_->start);
66   auto inner_res = inner_->SearchValidated(op, sql_val, inner_search_range);
67   if (inner_res.IsRange()) {
68     Range inner_res_range = std::move(inner_res).TakeIfRange();
69     if (inner_res_range.empty()) {
70       return RangeOrBitVector(Range());
71     }
72     return RangeOrBitVector(Range(inner_res_range.start - range_->start,
73                                   inner_res_range.end - range_->start));
74   }
75 
76   BitVector inner_res_bv = std::move(inner_res).TakeIfBitVector();
77   if (range_->start == 0 && inner_res_bv.size() == range_->end) {
78     return RangeOrBitVector{std::move(inner_res_bv)};
79   }
80 
81   PERFETTO_DCHECK(inner_res_bv.size() == inner_search_range.end);
82   PERFETTO_DCHECK(inner_res_bv.CountSetBits(inner_search_range.start) == 0);
83 
84   BitVector::Builder builder(search_range.end, search_range.start);
85   uint32_t cur_val = search_range.start;
86   uint32_t front_elements = builder.BitsUntilWordBoundaryOrFull();
87   for (uint32_t i = 0; i < front_elements; ++i, ++cur_val) {
88     builder.Append(inner_res_bv.IsSet(cur_val + range_->start));
89   }
90 
91   // Fast path: we compare as many groups of 64 elements as we can.
92   // This should be very easy for the compiler to auto-vectorize.
93   uint32_t fast_path_elements = builder.BitsInCompleteWordsUntilFull();
94   for (uint32_t i = 0; i < fast_path_elements; i += BitVector::kBitsInWord) {
95     uint64_t word = 0;
96     // This part should be optimised by SIMD and is expected to be fast.
97     for (uint32_t k = 0; k < BitVector::kBitsInWord; ++k, ++cur_val) {
98       bool comp_result = inner_res_bv.IsSet(cur_val + range_->start);
99       word |= static_cast<uint64_t>(comp_result) << k;
100     }
101     builder.AppendWord(word);
102   }
103 
104   // Slow path: we compare <64 elements and append to fill the Builder.
105   uint32_t back_elements = builder.BitsUntilFull();
106   for (uint32_t i = 0; i < back_elements; ++i, ++cur_val) {
107     builder.Append(inner_res_bv.IsSet(cur_val + range_->start));
108   }
109   return RangeOrBitVector(std::move(builder).Build());
110 }
111 
IndexSearchValidated(FilterOp op,SqlValue sql_val,Indices & indices) const112 void RangeOverlay::ChainImpl::IndexSearchValidated(FilterOp op,
113                                                    SqlValue sql_val,
114                                                    Indices& indices) const {
115   PERFETTO_TP_TRACE(metatrace::Category::DB, "RangeOverlay::IndexSearch");
116   for (auto& token : indices.tokens) {
117     token.index += range_->start;
118   }
119   inner_->IndexSearchValidated(op, sql_val, indices);
120 }
121 
StableSort(SortToken * start,SortToken * end,SortDirection direction) const122 void RangeOverlay::ChainImpl::StableSort(SortToken* start,
123                                          SortToken* end,
124                                          SortDirection direction) const {
125   for (SortToken* it = start; it != end; ++it) {
126     it->index += range_->start;
127   }
128   inner_->StableSort(start, end, direction);
129 }
130 
Distinct(Indices & indices) const131 void RangeOverlay::ChainImpl::Distinct(Indices& indices) const {
132   PERFETTO_TP_TRACE(metatrace::Category::DB, "RangeOverlay::Distinct");
133   for (auto& token : indices.tokens) {
134     token.index += range_->start;
135   }
136   inner_->Distinct(indices);
137 }
138 
MaxElement(Indices & indices) const139 std::optional<Token> RangeOverlay::ChainImpl::MaxElement(
140     Indices& indices) const {
141   PERFETTO_TP_TRACE(metatrace::Category::DB, "RangeOverlay::MaxElement");
142   for (auto& token : indices.tokens) {
143     token.index += range_->start;
144   }
145   return inner_->MaxElement(indices);
146 }
147 
Get_AvoidUsingBecauseSlow(uint32_t index) const148 SqlValue RangeOverlay::ChainImpl::Get_AvoidUsingBecauseSlow(
149     uint32_t index) const {
150   return inner_->Get_AvoidUsingBecauseSlow(index + range_->start);
151 }
152 
MinElement(Indices & indices) const153 std::optional<Token> RangeOverlay::ChainImpl::MinElement(
154     Indices& indices) const {
155   PERFETTO_TP_TRACE(metatrace::Category::DB, "RangeOverlay::MinElement");
156   for (auto& token : indices.tokens) {
157     token.index += range_->start;
158   }
159   return inner_->MinElement(indices);
160 }
161 
Serialize(StorageProto *) const162 void RangeOverlay::ChainImpl::Serialize(StorageProto*) const {
163   PERFETTO_FATAL("Not implemented");
164 }
165 
166 }  // namespace perfetto::trace_processor::column
167