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