Merge "ui: Rename mouseenter -> onmouseenter in notes panel" into main
diff --git a/python/generators/trace_processor_table/serialize.py b/python/generators/trace_processor_table/serialize.py
index 2881ce0..2096f55 100644
--- a/python/generators/trace_processor_table/serialize.py
+++ b/python/generators/trace_processor_table/serialize.py
@@ -591,7 +591,7 @@
if (overlays()[i].row_map().IsIndexVector()) {{
overlay_layers[i].reset(new column::ArrangementOverlay(
overlays()[i].row_map().GetIfIndexVector(),
- Indices::State::kNonmonotonic));
+ column::DataLayerChain::Indices::State::kNonmonotonic));
}} else if (overlays()[i].row_map().IsBitVector()) {{
overlay_layers[i].reset(new column::SelectorOverlay(
overlays()[i].row_map().GetIfBitVector()));
diff --git a/src/trace_processor/db/column/arrangement_overlay.cc b/src/trace_processor/db/column/arrangement_overlay.cc
index b9e3000..4f4af85 100644
--- a/src/trace_processor/db/column/arrangement_overlay.cc
+++ b/src/trace_processor/db/column/arrangement_overlay.cc
@@ -71,8 +71,8 @@
op != FilterOp::kRegex) {
Range inner_res = inner_->OrderedIndexSearchValidated(
op, sql_val,
- Indices{arrangement_->data() + in.start, in.size(),
- arrangement_state_});
+ OrderedIndices{arrangement_->data() + in.start, in.size(),
+ arrangement_state_});
return RangeOrBitVector(
Range(inner_res.start + in.start, inner_res.end + in.start));
}
@@ -122,31 +122,22 @@
return RangeOrBitVector(std::move(builder).Build());
}
-RangeOrBitVector ArrangementOverlay::ChainImpl::IndexSearchValidated(
+void ArrangementOverlay::ChainImpl::IndexSearchValidated(
FilterOp op,
SqlValue sql_val,
- Indices indices) const {
+ Indices& indices) const {
PERFETTO_TP_TRACE(metatrace::Category::DB,
"ArrangementOverlay::ChainImpl::IndexSearch");
- std::vector<uint32_t> storage_iv(indices.size);
- // Should be SIMD optimized.
- for (uint32_t i = 0; i < indices.size; ++i) {
- storage_iv[i] = (*arrangement_)[indices.data[i]];
+ for (auto& i : indices.tokens) {
+ i.index = (*arrangement_)[i.index];
}
-
- // If both the arrangment passed indices are monotonic, we know that this
- // state was not lost.
- if (indices.state == Indices::State::kMonotonic) {
- return inner_->IndexSearchValidated(
- op, sql_val,
- Indices{storage_iv.data(), static_cast<uint32_t>(storage_iv.size()),
- arrangement_state_});
- }
- return inner_->IndexSearchValidated(
- op, sql_val,
- Indices{storage_iv.data(), static_cast<uint32_t>(storage_iv.size()),
- Indices::State::kNonmonotonic});
+ // If the indices state is monotonic, we can just pass the arrangement's
+ // state.
+ indices.state = indices.state == Indices::State::kMonotonic
+ ? arrangement_state_
+ : Indices::State::kNonmonotonic;
+ return inner_->IndexSearchValidated(op, sql_val, indices);
}
void ArrangementOverlay::ChainImpl::StableSort(SortToken* start,
diff --git a/src/trace_processor/db/column/arrangement_overlay.h b/src/trace_processor/db/column/arrangement_overlay.h
index bca884f..2bc61cb 100644
--- a/src/trace_processor/db/column/arrangement_overlay.h
+++ b/src/trace_processor/db/column/arrangement_overlay.h
@@ -35,7 +35,7 @@
class ArrangementOverlay final : public DataLayer {
public:
ArrangementOverlay(const std::vector<uint32_t>* arrangement,
- Indices::State arrangement_state);
+ DataLayerChain::Indices::State arrangement_state);
~ArrangementOverlay() override;
std::unique_ptr<DataLayerChain> MakeChain(
@@ -59,13 +59,11 @@
RangeOrBitVector SearchValidated(FilterOp, SqlValue, Range) const override;
- RangeOrBitVector IndexSearchValidated(FilterOp,
- SqlValue,
- Indices) const override;
+ void IndexSearchValidated(FilterOp, SqlValue, Indices&) const override;
Range OrderedIndexSearchValidated(FilterOp,
SqlValue,
- Indices) const override {
+ const OrderedIndices&) const override {
PERFETTO_FATAL(
"OrderedIndexSearch can't be called on ArrangementOverlay");
}
@@ -91,7 +89,7 @@
std::unique_ptr<DataLayerChain> inner_;
const std::vector<uint32_t>* arrangement_;
- const Indices::State arrangement_state_;
+ const DataLayerChain::Indices::State arrangement_state_;
};
} // namespace perfetto::trace_processor::column
diff --git a/src/trace_processor/db/column/arrangement_overlay_unittest.cc b/src/trace_processor/db/column/arrangement_overlay_unittest.cc
index 07f13c0..3a26f0c 100644
--- a/src/trace_processor/db/column/arrangement_overlay_unittest.cc
+++ b/src/trace_processor/db/column/arrangement_overlay_unittest.cc
@@ -18,6 +18,7 @@
#include <array>
#include <cstdint>
+#include <utility>
#include <vector>
#include "perfetto/trace_processor/basic_types.h"
@@ -35,6 +36,9 @@
using testing::ElementsAre;
using testing::IsEmpty;
+using Indices = DataLayerChain::Indices;
+using OrderedIndices = DataLayerChain::OrderedIndices;
+
TEST(ArrangementOverlay, SingleSearch) {
std::vector<uint32_t> arrangement{1, 1, 2, 2, 3, 3, 4, 4, 1, 1};
auto fake = FakeStorageChain::SearchSubset(5, std::vector<uint32_t>{1, 2});
@@ -97,13 +101,10 @@
ArrangementOverlay storage(&arrangement, Indices::State::kNonmonotonic);
auto chain = storage.MakeChain(std::move(fake));
- std::vector<uint32_t> table_idx{7u, 1u, 3u};
- RangeOrBitVector res = chain->IndexSearch(
- FilterOp::kGe, SqlValue::Long(0u),
- Indices{table_idx.data(), static_cast<uint32_t>(table_idx.size()),
- Indices::State::kNonmonotonic});
-
- ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(1u));
+ Indices indices = Indices::CreateWithIndexPayloadForTesting(
+ {7u, 1u, 3u}, Indices::State::kNonmonotonic);
+ chain->IndexSearch(FilterOp::kGe, SqlValue::Long(0u), indices);
+ ASSERT_THAT(utils::ExtractPayloadForTesting(indices), ElementsAre(1u));
}
TEST(ArrangementOverlay, OrderingSearch) {
@@ -116,7 +117,6 @@
RangeOrBitVector res =
chain->Search(FilterOp::kGe, SqlValue::Long(0u), Range(0, 5));
-
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(3, 4));
}
diff --git a/src/trace_processor/db/column/data_layer.cc b/src/trace_processor/db/column/data_layer.cc
index c8f8b68..634cbce 100644
--- a/src/trace_processor/db/column/data_layer.cc
+++ b/src/trace_processor/db/column/data_layer.cc
@@ -113,8 +113,9 @@
PERFETTO_FATAL("For GCC");
}
-ArrangementOverlay::ArrangementOverlay(const std::vector<uint32_t>* arrangement,
- Indices::State arrangement_state)
+ArrangementOverlay::ArrangementOverlay(
+ const std::vector<uint32_t>* arrangement,
+ DataLayerChain::Indices::State arrangement_state)
: DataLayer(Impl::kArrangement),
arrangement_(arrangement),
arrangement_state_(arrangement_state) {}
diff --git a/src/trace_processor/db/column/data_layer.h b/src/trace_processor/db/column/data_layer.h
index f43999c..c8d74a8 100644
--- a/src/trace_processor/db/column/data_layer.h
+++ b/src/trace_processor/db/column/data_layer.h
@@ -20,6 +20,8 @@
#include <cstdint>
#include <memory>
#include <string>
+#include <utility>
+#include <vector>
#include "perfetto/base/compiler.h"
#include "perfetto/base/logging.h"
@@ -107,6 +109,62 @@
};
using StorageProto = protos::pbzero::SerializedColumn_Storage;
+ // Index vector related data required to Filter using IndexSearch.
+ struct Indices {
+ enum class State {
+ // We can't guarantee that data is in monotonic order.
+ kNonmonotonic,
+ // Data is in monotonic order.
+ kMonotonic,
+ };
+ // Contains an index to an element in the chain and an opaque payload class
+ // which can be set to whatever the user of the chain requires.
+ struct Token {
+ // An index pointing to an element in this chain. Indicates the element
+ // at this index should be filtered.
+ uint32_t index;
+
+ // An opaque value which can be set to some value meaningful to the
+ // caller. While the exact meaning of |payload| should not be depended
+ // upon, implementations are free to make assumptions that |payload| will
+ // be strictly monotonic.
+ uint32_t payload;
+
+ struct PayloadComparator {
+ bool operator()(const Token& a, const Token& b) {
+ return a.payload < b.payload;
+ }
+ };
+ };
+ static Indices Create(const std::vector<uint32_t>& raw, State state) {
+ std::vector<Token> tokens;
+ tokens.reserve(tokens.size());
+ for (uint32_t r : raw) {
+ tokens.push_back(Token{r, r});
+ }
+ return Indices{std::move(tokens), state};
+ }
+ static Indices CreateWithIndexPayloadForTesting(
+ const std::vector<uint32_t>& raw,
+ State state) {
+ std::vector<Token> tokens;
+ tokens.reserve(tokens.size());
+ for (uint32_t i = 0; i < raw.size(); ++i) {
+ tokens.push_back(Token{raw[i], i});
+ }
+ return Indices{std::move(tokens), state};
+ }
+ std::vector<Token> tokens;
+ State state = State::kNonmonotonic;
+ };
+
+ // Index vector related data required to Filter using IndexSearch.
+ struct OrderedIndices {
+ const uint32_t* data = nullptr;
+ uint32_t size = 0;
+ Indices::State state = Indices::State::kNonmonotonic;
+ };
+
virtual ~DataLayerChain();
// Start of public API.
@@ -138,6 +196,7 @@
PERFETTO_ALWAYS_INLINE RangeOrBitVector Search(FilterOp op,
SqlValue value,
Range range) const {
+ PERFETTO_DCHECK(range.end <= size());
switch (ValidateSearchConstraints(op, value)) {
case SearchValidationResult::kAllData:
return RangeOrBitVector(range);
@@ -163,24 +222,27 @@
// Notes for implementors:
// * Implementations should ensure that, if they return a BitVector, it is
// precisely of size |indices_count|.
- PERFETTO_ALWAYS_INLINE RangeOrBitVector IndexSearch(FilterOp op,
- SqlValue value,
- Indices indices) const {
+ PERFETTO_ALWAYS_INLINE void IndexSearch(FilterOp op,
+ SqlValue value,
+ Indices& indices) const {
switch (ValidateSearchConstraints(op, value)) {
case SearchValidationResult::kAllData:
- return RangeOrBitVector(Range(0, indices.size));
+ return;
case SearchValidationResult::kNoData:
- return RangeOrBitVector(Range());
+ indices.tokens.clear();
+ return;
case SearchValidationResult::kOk:
- return IndexSearchValidated(op, value, indices);
+ IndexSearchValidated(op, value, indices);
+ return;
}
PERFETTO_FATAL("For GCC");
}
// Searches for elements which match |op| and |value| at the positions given
- // by indices data.
+ // by OrderedIndicesdata.
//
- // Returns a Range into Indices data of indices that pass the constraint.
+ // Returns a Range into OrderedIndicesdata of OrderedIndicesthat pass the
+ // constraint.
//
// Notes for callers:
// * Should not be called on:
@@ -190,9 +252,10 @@
// result.
// * Callers should note that the return value of this function corresponds
// to positions in |indices| *not* positions in the storage.
- PERFETTO_ALWAYS_INLINE Range OrderedIndexSearch(FilterOp op,
- SqlValue value,
- Indices indices) const {
+ PERFETTO_ALWAYS_INLINE Range
+ OrderedIndexSearch(FilterOp op,
+ SqlValue value,
+ const OrderedIndices& indices) const {
switch (ValidateSearchConstraints(op, value)) {
case SearchValidationResult::kAllData:
return {0, indices.size};
@@ -254,15 +317,13 @@
// Post-validated implementation of |IndexSearch|. See |IndexSearch|'s
// documentation.
- virtual RangeOrBitVector IndexSearchValidated(FilterOp,
- SqlValue,
- Indices) const = 0;
+ virtual void IndexSearchValidated(FilterOp, SqlValue, Indices&) const = 0;
// Post-validated implementation of |OrderedIndexSearch|. See
// |OrderedIndexSearch|'s documentation.
virtual Range OrderedIndexSearchValidated(FilterOp,
SqlValue,
- Indices) const = 0;
+ const OrderedIndices&) const = 0;
};
} // namespace perfetto::trace_processor::column
diff --git a/src/trace_processor/db/column/dense_null_overlay.cc b/src/trace_processor/db/column/dense_null_overlay.cc
index 970eb0f..e171ec0 100644
--- a/src/trace_processor/db/column/dense_null_overlay.cc
+++ b/src/trace_processor/db/column/dense_null_overlay.cc
@@ -21,6 +21,7 @@
#include <iterator>
#include <memory>
#include <utility>
+#include <vector>
#include "perfetto/base/logging.h"
#include "perfetto/trace_processor/basic_types.h"
@@ -135,84 +136,68 @@
return RangeOrBitVector(std::move(res));
}
-RangeOrBitVector DenseNullOverlay::ChainImpl::IndexSearchValidated(
- FilterOp op,
- SqlValue sql_val,
- Indices indices) const {
+void DenseNullOverlay::ChainImpl::IndexSearchValidated(FilterOp op,
+ SqlValue sql_val,
+ Indices& indices) const {
PERFETTO_TP_TRACE(metatrace::Category::DB,
"DenseNullOverlay::ChainImpl::IndexSearch");
if (op == FilterOp::kIsNull) {
+ // Partition the vector into all the null indices followed by all the
+ // non-null indices.
+ auto non_null_it = std::stable_partition(
+ indices.tokens.begin(), indices.tokens.end(),
+ [this](const Indices::Token& t) { return !non_null_->IsSet(t.index); });
+
+ // IndexSearch |inner_| with a vector containing a copy of the non-null
+ // indices.
+ Indices non_null{{non_null_it, indices.tokens.end()}, indices.state};
+ inner_->IndexSearch(op, sql_val, non_null);
+
+ // Replace all the original non-null positions with the result from calling
+ // IndexSearch.
+ auto new_non_null_it =
+ indices.tokens.erase(non_null_it, indices.tokens.end());
+ indices.tokens.insert(new_non_null_it, non_null.tokens.begin(),
+ non_null.tokens.end());
+
+ // Merge the two sorted index ranges together using the payload as the
+ // comparator. This is a required post-condition of IndexSearch.
+ std::inplace_merge(indices.tokens.begin(), new_non_null_it,
+ indices.tokens.end(),
+ Indices::Token::PayloadComparator());
+ return;
+ }
+
+ auto keep_only_non_null = [this, &indices]() {
+ indices.tokens.erase(
+ std::remove_if(indices.tokens.begin(), indices.tokens.end(),
+ [this](const Indices::Token& idx) {
+ return !non_null_->IsSet(idx.index);
+ }),
+ indices.tokens.end());
+ return;
+ };
+ if (op == FilterOp::kIsNotNull) {
switch (inner_->ValidateSearchConstraints(op, sql_val)) {
- case SearchValidationResult::kNoData: {
- BitVector::Builder null_indices(indices.size);
- for (const uint32_t* it = indices.data;
- it != indices.data + indices.size; it++) {
- null_indices.Append(!non_null_->IsSet(*it));
- }
- // There is no need to search in underlying storage. We should just
- // check if the index is set in |non_null_|.
- return RangeOrBitVector(std::move(null_indices).Build());
- }
+ case SearchValidationResult::kNoData:
+ indices.tokens.clear();
+ return;
case SearchValidationResult::kAllData:
- return RangeOrBitVector(Range(0, indices.size));
- case SearchValidationResult::kOk:
- break;
- }
- } else if (op == FilterOp::kIsNotNull) {
- switch (inner_->ValidateSearchConstraints(op, sql_val)) {
- case SearchValidationResult::kNoData: {
- BitVector::Builder non_null_indices(indices.size);
- for (const uint32_t* it = indices.data;
- it != indices.data + indices.size; it++) {
- non_null_indices.Append(non_null_->IsSet(*it));
- }
- // There is no need to search in underlying storage. We should just
- // check if the index is set in |non_null_|.
- return RangeOrBitVector(std::move(non_null_indices).Build());
- }
- case SearchValidationResult::kAllData:
- return RangeOrBitVector(Range(0, indices.size));
+ keep_only_non_null();
+ return;
case SearchValidationResult::kOk:
break;
}
}
-
- RangeOrBitVector inner_res =
- inner_->IndexSearchValidated(op, sql_val, indices);
- if (inner_res.IsRange()) {
- Range inner_range = std::move(inner_res).TakeIfRange();
- BitVector::Builder builder(indices.size, inner_range.start);
- for (uint32_t i = inner_range.start; i < inner_range.end; ++i) {
- builder.Append(non_null_->IsSet(indices.data[i]));
- }
- return RangeOrBitVector(std::move(builder).Build());
- }
-
- BitVector::Builder builder(indices.size);
- for (uint32_t i = 0; i < indices.size; ++i) {
- builder.Append(non_null_->IsSet(indices.data[i]));
- }
- BitVector non_null = std::move(builder).Build();
-
- BitVector res = std::move(inner_res).TakeIfBitVector();
-
- if (op == FilterOp::kIsNull) {
- BitVector null = std::move(non_null);
- null.Not();
- res.Or(null);
- } else {
- res.And(non_null);
- }
-
- PERFETTO_DCHECK(res.size() == indices.size);
- return RangeOrBitVector(std::move(res));
+ keep_only_non_null();
+ inner_->IndexSearchValidated(op, sql_val, indices);
}
Range DenseNullOverlay::ChainImpl::OrderedIndexSearchValidated(
FilterOp op,
SqlValue sql_val,
- Indices indices) const {
+ const OrderedIndices& indices) const {
// For NOT EQUAL the further analysis needs to be done by the caller.
PERFETTO_CHECK(op != FilterOp::kNe);
@@ -247,7 +232,8 @@
Range inner_range = inner_->OrderedIndexSearchValidated(
op, sql_val,
- Indices{first_non_null, non_null_size, Indices::State::kNonmonotonic});
+ OrderedIndices{first_non_null, non_null_size,
+ Indices::State::kNonmonotonic});
return {inner_range.start + non_null_offset,
inner_range.end + non_null_offset};
}
diff --git a/src/trace_processor/db/column/dense_null_overlay.h b/src/trace_processor/db/column/dense_null_overlay.h
index 0f881fb..b27beb5 100644
--- a/src/trace_processor/db/column/dense_null_overlay.h
+++ b/src/trace_processor/db/column/dense_null_overlay.h
@@ -54,13 +54,11 @@
RangeOrBitVector SearchValidated(FilterOp, SqlValue, Range) const override;
- RangeOrBitVector IndexSearchValidated(FilterOp,
- SqlValue,
- Indices) const override;
+ void IndexSearchValidated(FilterOp, SqlValue, Indices&) const override;
Range OrderedIndexSearchValidated(FilterOp,
SqlValue,
- Indices) const override;
+ const OrderedIndices&) const override;
void StableSort(SortToken* start,
SortToken* end,
diff --git a/src/trace_processor/db/column/dense_null_overlay_unittest.cc b/src/trace_processor/db/column/dense_null_overlay_unittest.cc
index 0cf6276..efda157 100644
--- a/src/trace_processor/db/column/dense_null_overlay_unittest.cc
+++ b/src/trace_processor/db/column/dense_null_overlay_unittest.cc
@@ -18,6 +18,7 @@
#include <cstdint>
#include <memory>
+#include <utility>
#include <vector>
#include "perfetto/trace_processor/basic_types.h"
@@ -35,6 +36,9 @@
using testing::ElementsAre;
using testing::IsEmpty;
+using Indices = DataLayerChain::Indices;
+using OrderedIndices = DataLayerChain::OrderedIndices;
+
TEST(DenseNullOverlay, NoFilteringSearch) {
std::vector<uint32_t> data{0, 1, 0, 1, 0};
auto numeric = std::make_unique<NumericStorage<uint32_t>>(
@@ -103,12 +107,10 @@
DenseNullOverlay storage(&bv);
auto chain = storage.MakeChain(numeric->MakeChain());
- std::vector<uint32_t> index({5, 2, 3, 4, 1});
- auto res = chain->IndexSearch(
- FilterOp::kGe, SqlValue::Long(0),
- Indices{index.data(), static_cast<uint32_t>(index.size()),
- Indices::State::kNonmonotonic});
- ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(0, 2, 3));
+ Indices indices = Indices::CreateWithIndexPayloadForTesting(
+ {5, 2, 3, 4, 1}, Indices::State::kNonmonotonic);
+ chain->IndexSearch(FilterOp::kGe, SqlValue::Long(0), indices);
+ ASSERT_THAT(utils::ExtractPayloadForTesting(indices), ElementsAre(0, 2, 3));
}
TEST(DenseNullOverlay, IsNullIndexSearch) {
@@ -118,12 +120,11 @@
DenseNullOverlay storage(&bv);
auto chain = storage.MakeChain(std::move(fake));
- std::vector<uint32_t> index({5, 2, 3, 4, 1});
- auto res = chain->IndexSearch(
- FilterOp::kIsNull, SqlValue(),
- Indices{index.data(), static_cast<uint32_t>(index.size()),
- Indices::State::kMonotonic});
- ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(0, 1, 2, 3));
+ Indices indices = Indices::CreateWithIndexPayloadForTesting(
+ {5, 2, 3, 4, 1}, Indices::State::kNonmonotonic);
+ chain->IndexSearch(FilterOp::kIsNull, SqlValue(), indices);
+ ASSERT_THAT(utils::ExtractPayloadForTesting(indices),
+ ElementsAre(0, 1, 2, 3));
}
TEST(DenseNullOverlay, OrderedIndexSearch) {
@@ -134,7 +135,7 @@
auto chain = storage.MakeChain(std::move(fake));
std::vector<uint32_t> indices_vec({0, 2, 4, 1, 3, 5});
- Indices indices{indices_vec.data(), 6, Indices::State::kNonmonotonic};
+ OrderedIndices indices{indices_vec.data(), 6, Indices::State::kNonmonotonic};
Range res = chain->OrderedIndexSearch(FilterOp::kIsNull, SqlValue(), indices);
ASSERT_EQ(res.start, 0u);
diff --git a/src/trace_processor/db/column/dummy_storage.cc b/src/trace_processor/db/column/dummy_storage.cc
index 54d7c61..27b464f 100644
--- a/src/trace_processor/db/column/dummy_storage.cc
+++ b/src/trace_processor/db/column/dummy_storage.cc
@@ -43,15 +43,16 @@
PERFETTO_FATAL("Shouldn't be called");
}
-RangeOrBitVector DummyStorage::ChainImpl::IndexSearchValidated(FilterOp,
- SqlValue,
- Indices) const {
+void DummyStorage::ChainImpl::IndexSearchValidated(FilterOp,
+ SqlValue,
+ Indices&) const {
PERFETTO_FATAL("Shouldn't be called");
}
-Range DummyStorage::ChainImpl::OrderedIndexSearchValidated(FilterOp,
- SqlValue,
- Indices) const {
+Range DummyStorage::ChainImpl::OrderedIndexSearchValidated(
+ FilterOp,
+ SqlValue,
+ const OrderedIndices&) const {
PERFETTO_FATAL("Shouldn't be called");
}
diff --git a/src/trace_processor/db/column/dummy_storage.h b/src/trace_processor/db/column/dummy_storage.h
index ced41a9..80674bb 100644
--- a/src/trace_processor/db/column/dummy_storage.h
+++ b/src/trace_processor/db/column/dummy_storage.h
@@ -43,13 +43,11 @@
RangeOrBitVector SearchValidated(FilterOp, SqlValue, Range) const override;
- RangeOrBitVector IndexSearchValidated(FilterOp,
- SqlValue,
- Indices) const override;
+ void IndexSearchValidated(FilterOp, SqlValue, Indices&) const override;
Range OrderedIndexSearchValidated(FilterOp,
SqlValue,
- Indices) const override;
+ const OrderedIndices&) const override;
void StableSort(SortToken* start,
SortToken* end,
diff --git a/src/trace_processor/db/column/fake_storage.cc b/src/trace_processor/db/column/fake_storage.cc
index 9fbc3ae..f587c77 100644
--- a/src/trace_processor/db/column/fake_storage.cc
+++ b/src/trace_processor/db/column/fake_storage.cc
@@ -82,32 +82,39 @@
PERFETTO_FATAL("For GCC");
}
-RangeOrBitVector FakeStorageChain::IndexSearchValidated(FilterOp,
- SqlValue,
- Indices indices) const {
+void FakeStorageChain::IndexSearchValidated(FilterOp,
+ SqlValue,
+ Indices& indices) const {
switch (strategy_) {
case kAll:
- return RangeOrBitVector(Range(0, indices.size));
+ return;
case kNone:
- return RangeOrBitVector(Range());
+ indices.tokens.clear();
+ return;
case kRange:
- case kBitVector: {
- BitVector::Builder builder(indices.size);
- for (const uint32_t* it = indices.data; it != indices.data + indices.size;
- ++it) {
- bool in_range = strategy_ == kRange && range_.Contains(*it);
- bool in_bv = strategy_ == kBitVector && bit_vector_.IsSet(*it);
- builder.Append(in_range || in_bv);
- }
- return RangeOrBitVector(std::move(builder).Build());
- }
+ indices.tokens.erase(
+ std::remove_if(indices.tokens.begin(), indices.tokens.end(),
+ [this](const Indices::Token& token) {
+ return !range_.Contains(token.index);
+ }),
+ indices.tokens.end());
+ return;
+ case kBitVector:
+ indices.tokens.erase(
+ std::remove_if(indices.tokens.begin(), indices.tokens.end(),
+ [this](const Indices::Token& token) {
+ return !bit_vector_.IsSet(token.index);
+ }),
+ indices.tokens.end());
+ return;
}
PERFETTO_FATAL("For GCC");
}
-Range FakeStorageChain::OrderedIndexSearchValidated(FilterOp,
- SqlValue,
- Indices indices) const {
+Range FakeStorageChain::OrderedIndexSearchValidated(
+ FilterOp,
+ SqlValue,
+ const OrderedIndices& indices) const {
if (strategy_ == kAll) {
return {0, indices.size};
}
diff --git a/src/trace_processor/db/column/fake_storage.h b/src/trace_processor/db/column/fake_storage.h
index aca6890..bc02300 100644
--- a/src/trace_processor/db/column/fake_storage.h
+++ b/src/trace_processor/db/column/fake_storage.h
@@ -82,11 +82,11 @@
RangeOrBitVector SearchValidated(FilterOp, SqlValue, Range) const override;
- RangeOrBitVector IndexSearchValidated(FilterOp,
- SqlValue,
- Indices) const override;
+ void IndexSearchValidated(FilterOp, SqlValue, Indices&) const override;
- Range OrderedIndexSearchValidated(FilterOp, SqlValue, Indices) const override;
+ Range OrderedIndexSearchValidated(FilterOp,
+ SqlValue,
+ const OrderedIndices&) const override;
void StableSort(SortToken* start,
SortToken* end,
diff --git a/src/trace_processor/db/column/id_storage.cc b/src/trace_processor/db/column/id_storage.cc
index df662af..e3f4d8a 100644
--- a/src/trace_processor/db/column/id_storage.cc
+++ b/src/trace_processor/db/column/id_storage.cc
@@ -21,7 +21,6 @@
#include <functional>
#include <iterator>
#include <limits>
-#include <memory>
#include <string>
#include <utility>
@@ -41,40 +40,13 @@
namespace {
template <typename Comparator>
-RangeOrBitVector IndexSearchWithComparator(uint32_t val,
- const uint32_t* indices,
- uint32_t indices_size,
- Comparator comparator) {
- // Slow path: we compare <64 elements and append to get us to a word
- // boundary.
- const uint32_t* ptr = indices;
- BitVector::Builder builder(indices_size);
- uint32_t front_elements = builder.BitsUntilWordBoundaryOrFull();
- for (uint32_t i = 0; i < front_elements; ++i) {
- builder.Append(comparator(ptr[i], val));
- }
- ptr += front_elements;
-
- // Fast path: we compare as many groups of 64 elements as we can.
- // This should be very easy for the compiler to auto-vectorize.
- uint32_t fast_path_elements = builder.BitsInCompleteWordsUntilFull();
- for (uint32_t i = 0; i < fast_path_elements; i += BitVector::kBitsInWord) {
- uint64_t word = 0;
- // This part should be optimised by SIMD and is expected to be fast.
- for (uint32_t k = 0; k < BitVector::kBitsInWord; ++k) {
- bool comp_result = comparator(ptr[i + k], val);
- word |= static_cast<uint64_t>(comp_result) << k;
- }
- builder.AppendWord(word);
- }
- ptr += fast_path_elements;
-
- // Slow path: we compare <64 elements and append to fill the Builder.
- uint32_t back_elements = builder.BitsUntilFull();
- for (uint32_t i = 0; i < back_elements; ++i) {
- builder.Append(comparator(ptr[i], val));
- }
- return RangeOrBitVector(std::move(builder).Build());
+void IndexSearchWithComparator(uint32_t val, DataLayerChain::Indices& indices) {
+ indices.tokens.erase(
+ std::remove_if(indices.tokens.begin(), indices.tokens.end(),
+ [val](const DataLayerChain::Indices::Token& idx) {
+ return !Comparator()(idx.index, val);
+ }),
+ indices.tokens.end());
}
} // namespace
@@ -226,14 +198,13 @@
return RangeOrBitVector(BinarySearchIntrinsic(op, val, search_range));
}
-RangeOrBitVector IdStorage::ChainImpl::IndexSearchValidated(
- FilterOp op,
- SqlValue sql_val,
- Indices indices) const {
+void IdStorage::ChainImpl::IndexSearchValidated(FilterOp op,
+ SqlValue sql_val,
+ Indices& indices) const {
PERFETTO_TP_TRACE(
metatrace::Category::DB, "IdStorage::ChainImpl::IndexSearch",
- [indices, op](metatrace::Record* r) {
- r->AddArg("Count", std::to_string(indices.size));
+ [&indices, op](metatrace::Record* r) {
+ r->AddArg("Count", std::to_string(indices.tokens.size()));
r->AddArg("Op", std::to_string(static_cast<uint32_t>(op)));
});
@@ -241,35 +212,30 @@
// requires special logic.
if (sql_val.type == SqlValue::kDouble) {
switch (utils::CompareIntColumnWithDouble(op, &sql_val)) {
+ case SearchValidationResult::kAllData:
+ return;
+ case SearchValidationResult::kNoData:
+ indices.tokens.clear();
+ return;
case SearchValidationResult::kOk:
break;
- case SearchValidationResult::kAllData:
- return RangeOrBitVector(Range(0, indices.size));
- case SearchValidationResult::kNoData:
- return RangeOrBitVector(Range());
}
}
auto val = static_cast<uint32_t>(sql_val.AsLong());
switch (op) {
case FilterOp::kEq:
- return IndexSearchWithComparator(val, indices.data, indices.size,
- std::equal_to<>());
+ return IndexSearchWithComparator<std::equal_to<>>(val, indices);
case FilterOp::kNe:
- return IndexSearchWithComparator(val, indices.data, indices.size,
- std::not_equal_to<>());
+ return IndexSearchWithComparator<std::not_equal_to<>>(val, indices);
case FilterOp::kLe:
- return IndexSearchWithComparator(val, indices.data, indices.size,
- std::less_equal<>());
+ return IndexSearchWithComparator<std::less_equal<>>(val, indices);
case FilterOp::kLt:
- return IndexSearchWithComparator(val, indices.data, indices.size,
- std::less<>());
+ return IndexSearchWithComparator<std::less<>>(val, indices);
case FilterOp::kGt:
- return IndexSearchWithComparator(val, indices.data, indices.size,
- std::greater<>());
+ return IndexSearchWithComparator<std::greater<>>(val, indices);
case FilterOp::kGe:
- return IndexSearchWithComparator(val, indices.data, indices.size,
- std::greater_equal<>());
+ return IndexSearchWithComparator<std::greater_equal<>>(val, indices);
case FilterOp::kIsNotNull:
case FilterOp::kIsNull:
case FilterOp::kGlob:
@@ -279,9 +245,10 @@
PERFETTO_FATAL("FilterOp not matched");
}
-Range IdStorage::ChainImpl::OrderedIndexSearchValidated(FilterOp op,
- SqlValue sql_val,
- Indices indices) const {
+Range IdStorage::ChainImpl::OrderedIndexSearchValidated(
+ FilterOp op,
+ SqlValue sql_val,
+ const OrderedIndices& indices) const {
PERFETTO_DCHECK(op != FilterOp::kNe);
PERFETTO_TP_TRACE(
@@ -305,10 +272,9 @@
}
auto val = static_cast<uint32_t>(sql_val.AsLong());
- // Indices are monotonic non contiguous values if OrderedIndexSearch was
- // called.
- // Look for the first and last index and find the result of looking for this
- // range in IdStorage.
+ // OrderedIndices are monotonic non contiguous values if OrderedIndexSearch
+ // was called. Look for the first and last index and find the result of
+ // looking for this range in IdStorage.
Range indices_range(indices.data[0], indices.data[indices.size - 1] + 1);
Range bin_search_ret = BinarySearchIntrinsic(op, val, indices_range);
diff --git a/src/trace_processor/db/column/id_storage.h b/src/trace_processor/db/column/id_storage.h
index e6e25ab..51b9f0d 100644
--- a/src/trace_processor/db/column/id_storage.h
+++ b/src/trace_processor/db/column/id_storage.h
@@ -53,13 +53,11 @@
RangeOrBitVector SearchValidated(FilterOp, SqlValue, Range) const override;
- RangeOrBitVector IndexSearchValidated(FilterOp,
- SqlValue,
- Indices) const override;
+ void IndexSearchValidated(FilterOp, SqlValue, Indices&) const override;
Range OrderedIndexSearchValidated(FilterOp,
SqlValue,
- Indices) const override;
+ const OrderedIndices&) const override;
void StableSort(SortToken* start,
SortToken* end,
diff --git a/src/trace_processor/db/column/id_storage_unittest.cc b/src/trace_processor/db/column/id_storage_unittest.cc
index 48ce18e..2d6fd44 100644
--- a/src/trace_processor/db/column/id_storage_unittest.cc
+++ b/src/trace_processor/db/column/id_storage_unittest.cc
@@ -42,6 +42,9 @@
using testing::ElementsAre;
using testing::IsEmpty;
+using Indices = DataLayerChain::Indices;
+using OrderedIndices = DataLayerChain::OrderedIndices;
+
TEST(IdStorage, InvalidSearchConstraints) {
IdStorage storage;
auto chain = storage.MakeChain();
@@ -214,32 +217,35 @@
IdStorage storage;
auto chain = storage.MakeChain();
SqlValue val = SqlValue::Long(5);
- std::vector<uint32_t> indices_vec{5, 4, 3, 9, 8, 7};
- Indices indices{indices_vec.data(), 6, Indices::State::kNonmonotonic};
- FilterOp op = FilterOp::kEq;
- auto res = chain->IndexSearch(op, val, indices);
- ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(0));
+ auto common_indices = Indices::CreateWithIndexPayloadForTesting(
+ {5, 4, 3, 9, 8, 7}, Indices::State::kNonmonotonic);
- op = FilterOp::kNe;
- res = chain->IndexSearch(op, val, indices);
- ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(1, 2, 3, 4, 5));
+ auto indices = common_indices;
+ chain->IndexSearch(FilterOp::kEq, val, indices);
+ ASSERT_THAT(utils::ExtractPayloadForTesting(indices), ElementsAre(0));
- op = FilterOp::kLe;
- res = chain->IndexSearch(op, val, indices);
- ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(0, 1, 2));
+ indices = common_indices;
+ chain->IndexSearch(FilterOp::kNe, val, indices);
+ ASSERT_THAT(utils::ExtractPayloadForTesting(indices),
+ ElementsAre(1, 2, 3, 4, 5));
- op = FilterOp::kLt;
- res = chain->IndexSearch(op, val, indices);
- ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(1, 2));
+ indices = common_indices;
+ chain->IndexSearch(FilterOp::kLe, val, indices);
+ ASSERT_THAT(utils::ExtractPayloadForTesting(indices), ElementsAre(0, 1, 2));
- op = FilterOp::kGe;
- res = chain->IndexSearch(op, val, indices);
- ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(0, 3, 4, 5));
+ indices = common_indices;
+ chain->IndexSearch(FilterOp::kLt, val, indices);
+ ASSERT_THAT(utils::ExtractPayloadForTesting(indices), ElementsAre(1, 2));
- op = FilterOp::kGt;
- res = chain->IndexSearch(op, val, indices);
- ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(3, 4, 5));
+ indices = common_indices;
+ chain->IndexSearch(FilterOp::kGe, val, indices);
+ ASSERT_THAT(utils::ExtractPayloadForTesting(indices),
+ ElementsAre(0, 3, 4, 5));
+
+ indices = common_indices;
+ chain->IndexSearch(FilterOp::kGt, val, indices);
+ ASSERT_THAT(utils::ExtractPayloadForTesting(indices), ElementsAre(3, 4, 5));
}
TEST(IdStorage, OrderedIndexSearch) {
@@ -247,7 +253,7 @@
auto chain = storage.MakeChain();
std::vector<uint32_t> indices_vec{0, 1, 2, 4, 4};
- Indices indices{indices_vec.data(), 5, Indices::State::kMonotonic};
+ OrderedIndices indices{indices_vec.data(), 5, Indices::State::kMonotonic};
Range range =
chain->OrderedIndexSearch(FilterOp::kEq, SqlValue::Long(2), indices);
@@ -274,17 +280,11 @@
TEST(IdStorage, IndexSearchEqTooBig) {
IdStorage storage;
auto chain = storage.MakeChain();
- std::vector<uint32_t> indices{1, 3, 5, 7, 9, 11, 2, 4};
- BitVector bv =
- chain
- ->IndexSearch(
- FilterOp::kEq, SqlValue::Long(20),
- Indices{indices.data(), static_cast<uint32_t>(indices.size()),
- Indices::State::kMonotonic})
- .TakeIfBitVector();
-
- ASSERT_EQ(bv.CountSetBits(), 0u);
+ auto indices = Indices::CreateWithIndexPayloadForTesting(
+ {1, 3, 5, 7, 9, 11, 2, 4}, Indices::State::kNonmonotonic);
+ chain->IndexSearch(FilterOp::kEq, SqlValue::Long(20), indices);
+ ASSERT_THAT(utils::ExtractPayloadForTesting(indices), IsEmpty());
}
TEST(IdStorage, SearchWithIdAsDoubleSimple) {
diff --git a/src/trace_processor/db/column/null_overlay.cc b/src/trace_processor/db/column/null_overlay.cc
index 8634eb6..fa1e679 100644
--- a/src/trace_processor/db/column/null_overlay.cc
+++ b/src/trace_processor/db/column/null_overlay.cc
@@ -162,76 +162,74 @@
return RangeOrBitVector(std::move(res));
}
-RangeOrBitVector NullOverlay::ChainImpl::IndexSearchValidated(
- FilterOp op,
- SqlValue sql_val,
- Indices indices) const {
+void NullOverlay::ChainImpl::IndexSearchValidated(FilterOp op,
+ SqlValue sql_val,
+ Indices& indices) const {
PERFETTO_TP_TRACE(metatrace::Category::DB,
"NullOverlay::ChainImpl::IndexSearch");
if (op == FilterOp::kIsNull) {
- switch (inner_->ValidateSearchConstraints(op, sql_val)) {
- case SearchValidationResult::kNoData: {
- BitVector::Builder null_indices(indices.size);
- for (const uint32_t* it = indices.data;
- it != indices.data + indices.size; it++) {
- null_indices.Append(!non_null_->IsSet(*it));
- }
- // There is no need to search in underlying storage. We should just
- // check if the index is set in |non_null_|.
- return RangeOrBitVector(std::move(null_indices).Build());
- }
- case SearchValidationResult::kAllData:
- return RangeOrBitVector(Range(0, indices.size));
- case SearchValidationResult::kOk:
- break;
+ // Partition the vector into all the null indices followed by all the
+ // non-null indices.
+ auto non_null_it = std::stable_partition(
+ indices.tokens.begin(), indices.tokens.end(),
+ [this](const Indices::Token& t) { return !non_null_->IsSet(t.index); });
+
+ // IndexSearch |inner_| with a vector containing a copy of the (translated)
+ // non-null indices.
+ Indices non_null{{non_null_it, indices.tokens.end()}, indices.state};
+ for (auto& token : non_null.tokens) {
+ token.index = non_null_->CountSetBits(token.index);
}
- } else if (op == FilterOp::kIsNotNull) {
+ inner_->IndexSearch(op, sql_val, non_null);
+
+ // Replace all the original non-null positions with the result from calling
+ // IndexSearch.
+ auto new_non_null_it =
+ indices.tokens.erase(non_null_it, indices.tokens.end());
+ indices.tokens.insert(new_non_null_it, non_null.tokens.begin(),
+ non_null.tokens.end());
+
+ // Merge the two sorted index ranges together using the payload as the
+ // comparator. This is a required post-condition of IndexSearch.
+ std::inplace_merge(indices.tokens.begin(), new_non_null_it,
+ indices.tokens.end(),
+ Indices::Token::PayloadComparator());
+ return;
+ }
+
+ auto keep_only_non_null = [this, &indices]() {
+ indices.tokens.erase(
+ std::remove_if(indices.tokens.begin(), indices.tokens.end(),
+ [this](const Indices::Token& idx) {
+ return !non_null_->IsSet(idx.index);
+ }),
+ indices.tokens.end());
+ return;
+ };
+ if (op == FilterOp::kIsNotNull) {
switch (inner_->ValidateSearchConstraints(op, sql_val)) {
- case SearchValidationResult::kNoData: {
- BitVector::Builder non_null_indices(indices.size);
- for (const uint32_t* it = indices.data;
- it != indices.data + indices.size; it++) {
- non_null_indices.Append(non_null_->IsSet(*it));
- }
- // There is no need to search in underlying storage. We should just
- // check if the index is set in |non_null_|.
- return RangeOrBitVector(std::move(non_null_indices).Build());
- }
+ case SearchValidationResult::kNoData:
+ indices.tokens.clear();
+ return;
case SearchValidationResult::kAllData:
- return RangeOrBitVector(Range(0, indices.size));
+ keep_only_non_null();
+ return;
case SearchValidationResult::kOk:
break;
}
}
-
- BitVector::Builder storage_non_null(indices.size);
- std::vector<uint32_t> storage_iv;
- storage_iv.reserve(indices.size);
- for (const uint32_t* it = indices.data; it != indices.data + indices.size;
- it++) {
- bool is_non_null = non_null_->IsSet(*it);
- if (is_non_null) {
- storage_iv.push_back(non_null_->CountSetBits(*it));
- }
- storage_non_null.Append(is_non_null);
+ keep_only_non_null();
+ for (auto& token : indices.tokens) {
+ token.index = non_null_->CountSetBits(token.index);
}
- RangeOrBitVector range_or_bv = inner_->IndexSearchValidated(
- op, sql_val,
- Indices{storage_iv.data(), static_cast<uint32_t>(storage_iv.size()),
- indices.state});
- BitVector res =
- ReconcileStorageResult(op, std::move(storage_non_null).Build(),
- std::move(range_or_bv), Range(0, indices.size));
-
- PERFETTO_DCHECK(res.size() == indices.size);
- return RangeOrBitVector(std::move(res));
+ inner_->IndexSearchValidated(op, sql_val, indices);
}
Range NullOverlay::ChainImpl::OrderedIndexSearchValidated(
FilterOp op,
SqlValue sql_val,
- Indices indices) const {
+ const OrderedIndices& indices) const {
// For NOT EQUAL the translation or results from EQUAL needs to be done by the
// caller.
PERFETTO_CHECK(op != FilterOp::kNe);
@@ -272,7 +270,8 @@
}
Range inner_range = inner_->OrderedIndexSearchValidated(
- op, sql_val, Indices{storage_iv.data(), non_null_size, indices.state});
+ op, sql_val,
+ OrderedIndices{storage_iv.data(), non_null_size, indices.state});
return {inner_range.start + non_null_offset,
inner_range.end + non_null_offset};
}
diff --git a/src/trace_processor/db/column/null_overlay.h b/src/trace_processor/db/column/null_overlay.h
index 99f6256..625959d 100644
--- a/src/trace_processor/db/column/null_overlay.h
+++ b/src/trace_processor/db/column/null_overlay.h
@@ -53,13 +53,11 @@
RangeOrBitVector SearchValidated(FilterOp, SqlValue, Range) const override;
- RangeOrBitVector IndexSearchValidated(FilterOp,
- SqlValue,
- Indices) const override;
+ void IndexSearchValidated(FilterOp, SqlValue, Indices&) const override;
Range OrderedIndexSearchValidated(FilterOp,
SqlValue,
- Indices) const override;
+ const OrderedIndices&) const override;
void StableSort(SortToken* start,
SortToken* end,
diff --git a/src/trace_processor/db/column/null_overlay_unittest.cc b/src/trace_processor/db/column/null_overlay_unittest.cc
index ceb6c9f..8f15746 100644
--- a/src/trace_processor/db/column/null_overlay_unittest.cc
+++ b/src/trace_processor/db/column/null_overlay_unittest.cc
@@ -18,6 +18,7 @@
#include <cstdint>
#include <memory>
+#include <utility>
#include <vector>
#include "perfetto/trace_processor/basic_types.h"
@@ -35,6 +36,9 @@
using testing::ElementsAre;
using testing::IsEmpty;
+using Indices = DataLayerChain::Indices;
+using OrderedIndices = DataLayerChain::OrderedIndices;
+
TEST(NullOverlay, SingleSearch) {
BitVector bv{0, 1, 0, 1, 1, 1};
auto fake = FakeStorageChain::SearchSubset(4, std::vector<uint32_t>{1, 2});
@@ -139,12 +143,10 @@
NullOverlay storage(&bv);
auto chain = storage.MakeChain(std::move(fake));
- std::vector<uint32_t> table_idx{1, 5, 2};
- auto res =
- chain->IndexSearch(FilterOp::kGt, SqlValue::Long(0),
- Indices{table_idx.data(), uint32_t(table_idx.size()),
- Indices::State::kNonmonotonic});
- ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(0, 1, 2));
+ Indices indices = Indices::CreateWithIndexPayloadForTesting(
+ {1, 5, 2}, Indices::State::kNonmonotonic);
+ chain->IndexSearch(FilterOp::kGt, SqlValue::Long(0), indices);
+ ASSERT_THAT(utils::ExtractPayloadForTesting(indices), ElementsAre(0, 1, 2));
}
TEST(NullOverlay, IndexSearchPartialElements) {
@@ -153,12 +155,10 @@
NullOverlay storage(&bv);
auto chain = storage.MakeChain(std::move(fake));
- std::vector<uint32_t> table_idx{1, 4, 2};
- auto res =
- chain->IndexSearch(FilterOp::kGt, SqlValue::Long(0),
- Indices{table_idx.data(), uint32_t(table_idx.size()),
- Indices::State::kNonmonotonic});
- ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(0, 2));
+ Indices indices = Indices::CreateWithIndexPayloadForTesting(
+ {1, 4, 2}, Indices::State::kNonmonotonic);
+ chain->IndexSearch(FilterOp::kGt, SqlValue::Long(0), indices);
+ ASSERT_THAT(utils::ExtractPayloadForTesting(indices), ElementsAre(0, 2));
}
TEST(NullOverlay, IndexSearchIsNullOpEmptyRes) {
@@ -167,12 +167,10 @@
NullOverlay storage(&bv);
auto chain = storage.MakeChain(std::move(fake));
- std::vector<uint32_t> table_idx{0, 3, 5, 4, 2};
- auto res =
- chain->IndexSearch(FilterOp::kIsNull, SqlValue(),
- Indices{table_idx.data(), uint32_t(table_idx.size()),
- Indices::State::kNonmonotonic});
- ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(0, 1, 3));
+ Indices indices = Indices::CreateWithIndexPayloadForTesting(
+ {0, 3, 5, 4, 2}, Indices::State::kNonmonotonic);
+ chain->IndexSearch(FilterOp::kIsNull, SqlValue(), indices);
+ ASSERT_THAT(utils::ExtractPayloadForTesting(indices), ElementsAre(0, 1, 3));
}
TEST(NullOverlay, IndexSearchIsNullOp) {
@@ -181,12 +179,11 @@
NullOverlay storage(&bv);
auto chain = storage.MakeChain(std::move(fake));
- std::vector<uint32_t> table_idx{0, 3, 2, 4, 5};
- auto res =
- chain->IndexSearch(FilterOp::kIsNull, SqlValue(),
- Indices{table_idx.data(), uint32_t(table_idx.size()),
- Indices::State::kNonmonotonic});
- ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(0, 1, 3, 4));
+ Indices indices = Indices::CreateWithIndexPayloadForTesting(
+ {0, 3, 2, 4, 5}, Indices::State::kNonmonotonic);
+ chain->IndexSearch(FilterOp::kIsNull, SqlValue(), indices);
+ ASSERT_THAT(utils::ExtractPayloadForTesting(indices),
+ ElementsAre(0, 1, 3, 4));
}
TEST(NullOverlay, IndexSearchIsNotNullOp) {
@@ -195,12 +192,10 @@
NullOverlay storage(&bv);
auto chain = storage.MakeChain(std::move(fake));
- std::vector<uint32_t> table_idx{0, 3, 4};
- auto res =
- chain->IndexSearch(FilterOp::kIsNotNull, SqlValue(),
- Indices{table_idx.data(), uint32_t(table_idx.size()),
- Indices::State::kNonmonotonic});
- ASSERT_THAT(utils::ToIndexVectorForTests(res), IsEmpty());
+ Indices indices = Indices::CreateWithIndexPayloadForTesting(
+ {0, 3, 4}, Indices::State::kNonmonotonic);
+ chain->IndexSearch(FilterOp::kIsNotNull, SqlValue(), indices);
+ ASSERT_THAT(utils::ExtractPayloadForTesting(indices), IsEmpty());
}
TEST(NullOverlay, OrderedIndexSearch) {
@@ -214,8 +209,8 @@
// Passing values on final data
// NULL, NULL, 0, 1, 1
std::vector<uint32_t> table_idx{0, 4, 5, 1, 3};
- Indices indices{table_idx.data(), uint32_t(table_idx.size()),
- Indices::State::kNonmonotonic};
+ OrderedIndices indices{table_idx.data(), uint32_t(table_idx.size()),
+ Indices::State::kNonmonotonic};
Range res = chain->OrderedIndexSearch(FilterOp::kIsNull, SqlValue(), indices);
ASSERT_EQ(res.start, 0u);
diff --git a/src/trace_processor/db/column/numeric_storage.cc b/src/trace_processor/db/column/numeric_storage.cc
index 2c16edd..46ab450 100644
--- a/src/trace_processor/db/column/numeric_storage.cc
+++ b/src/trace_processor/db/column/numeric_storage.cc
@@ -43,6 +43,9 @@
namespace perfetto::trace_processor::column {
namespace {
+using Indices = DataLayerChain::Indices;
+using OrderedIndices = DataLayerChain::OrderedIndices;
+
using NumericValue = std::variant<uint32_t, int32_t, int64_t, double>;
// Using the fact that binary operators in std are operators() of classes, we
@@ -135,7 +138,9 @@
}
template <typename T>
-uint32_t TypedLowerBoundExtrinsic(T val, const T* data, Indices indices) {
+uint32_t TypedLowerBoundExtrinsic(T val,
+ const T* data,
+ OrderedIndices indices) {
const auto* lower = std::lower_bound(
indices.data, indices.data + indices.size, val,
[data](uint32_t index, T value) { return data[index] < value; });
@@ -144,7 +149,7 @@
uint32_t LowerBoundExtrinsic(const void* vector_ptr,
NumericValue val,
- Indices indices) {
+ OrderedIndices indices) {
if (const auto* u32 = std::get_if<uint32_t>(&val)) {
const auto* start =
static_cast<const std::vector<uint32_t>*>(vector_ptr)->data();
@@ -170,7 +175,7 @@
uint32_t UpperBoundExtrinsic(const void* vector_ptr,
NumericValue val,
- Indices indices) {
+ OrderedIndices indices) {
return std::visit(
[vector_ptr, indices](auto val_data) {
using T = decltype(val_data);
@@ -458,49 +463,51 @@
return RangeOrBitVector(LinearSearchInternal(op, val, search_range));
}
-RangeOrBitVector NumericStorageBase::ChainImpl::IndexSearchValidated(
+void NumericStorageBase::ChainImpl::IndexSearchValidated(
FilterOp op,
SqlValue sql_val,
- Indices indices) const {
- PERFETTO_DCHECK(*std::max_element(indices.data, indices.data + indices.size) <
- size());
-
+ Indices& indices) const {
PERFETTO_TP_TRACE(
metatrace::Category::DB, "NumericStorage::ChainImpl::IndexSearch",
- [indices, op](metatrace::Record* r) {
- r->AddArg("Count", std::to_string(indices.size));
+ [&indices, op](metatrace::Record* r) {
+ r->AddArg("Count", std::to_string(indices.tokens.size()));
r->AddArg("Op", std::to_string(static_cast<uint32_t>(op)));
});
// Mismatched types - value is double and column is int.
if (sql_val.type == SqlValue::kDouble &&
storage_type_ != ColumnType::kDouble) {
- auto ret_opt =
- utils::CanReturnEarly(IntColumnWithDouble(op, &sql_val), indices.size);
- if (ret_opt) {
- return RangeOrBitVector(*ret_opt);
+ if (utils::CanReturnEarly(IntColumnWithDouble(op, &sql_val), indices)) {
+ return;
}
}
// Mismatched types - column is double and value is int.
if (sql_val.type != SqlValue::kDouble &&
storage_type_ == ColumnType::kDouble) {
- auto ret_opt =
- utils::CanReturnEarly(DoubleColumnWithInt(op, &sql_val), indices.size);
- if (ret_opt) {
- return RangeOrBitVector(*ret_opt);
+ if (utils::CanReturnEarly(DoubleColumnWithInt(op, &sql_val), indices)) {
+ return;
}
}
NumericValue val = GetNumericTypeVariant(storage_type_, sql_val);
- return RangeOrBitVector(
- IndexSearchInternal(op, val, indices.data, indices.size));
+ std::visit(
+ [this, &indices, op](auto val) {
+ using T = decltype(val);
+ auto* start = static_cast<const std::vector<T>*>(vector_ptr_)->data();
+ std::visit(
+ [start, &indices, val](auto comparator) {
+ utils::IndexSearchWithComparator(val, start, indices, comparator);
+ },
+ GetFilterOpVariant<T>(op));
+ },
+ val);
}
Range NumericStorageBase::ChainImpl::OrderedIndexSearchValidated(
FilterOp op,
SqlValue sql_val,
- Indices indices) const {
+ const OrderedIndices& indices) const {
PERFETTO_DCHECK(*std::max_element(indices.data, indices.data + indices.size) <
size());
@@ -604,27 +611,6 @@
return std::move(builder).Build();
}
-BitVector NumericStorageBase::ChainImpl::IndexSearchInternal(
- FilterOp op,
- NumericValue val,
- const uint32_t* indices,
- uint32_t indices_count) const {
- BitVector::Builder builder(indices_count);
- std::visit(
- [this, indices, op, &builder](auto val) {
- using T = decltype(val);
- auto* start = static_cast<const std::vector<T>*>(vector_ptr_)->data();
- std::visit(
- [start, indices, val, &builder](auto comparator) {
- utils::IndexSearchWithComparator(val, start, indices, comparator,
- builder);
- },
- GetFilterOpVariant<T>(op));
- },
- val);
- return std::move(builder).Build();
-}
-
Range NumericStorageBase::ChainImpl::BinarySearchIntrinsic(
FilterOp op,
NumericValue val,
diff --git a/src/trace_processor/db/column/numeric_storage.h b/src/trace_processor/db/column/numeric_storage.h
index 2dfafc6..f7cb51c 100644
--- a/src/trace_processor/db/column/numeric_storage.h
+++ b/src/trace_processor/db/column/numeric_storage.h
@@ -42,13 +42,11 @@
RangeOrBitVector SearchValidated(FilterOp, SqlValue, Range) const override;
- RangeOrBitVector IndexSearchValidated(FilterOp,
- SqlValue,
- Indices) const override;
+ void IndexSearchValidated(FilterOp, SqlValue, Indices&) const override;
Range OrderedIndexSearchValidated(FilterOp,
SqlValue,
- Indices) const override;
+ const OrderedIndices&) const override;
void Serialize(StorageProto*) const override;
@@ -63,11 +61,6 @@
BitVector LinearSearchInternal(FilterOp op, NumericValue val, Range) const;
- BitVector IndexSearchInternal(FilterOp op,
- NumericValue value,
- const uint32_t* indices,
- uint32_t indices_count) const;
-
Range BinarySearchIntrinsic(FilterOp op,
NumericValue val,
Range search_range) const;
diff --git a/src/trace_processor/db/column/numeric_storage_unittest.cc b/src/trace_processor/db/column/numeric_storage_unittest.cc
index 534338c..2b20306 100644
--- a/src/trace_processor/db/column/numeric_storage_unittest.cc
+++ b/src/trace_processor/db/column/numeric_storage_unittest.cc
@@ -42,6 +42,9 @@
using testing::ElementsAre;
using testing::IsEmpty;
+using Indices = DataLayerChain::Indices;
+using OrderedIndices = DataLayerChain::OrderedIndices;
+
TEST(NumericStorage, InvalidSearchConstraintsGeneralChecks) {
std::vector<uint32_t> data_vec(128);
std::iota(data_vec.begin(), data_vec.end(), 0);
@@ -244,27 +247,36 @@
auto chain = storage.MakeChain();
// -5, -3, -3, 3, 5, 0
- std::vector<uint32_t> indices_vec{0, 4, 4, 5, 1, 6};
- Indices indices{indices_vec.data(), 6, Indices::State::kMonotonic};
+ Indices common_indices = Indices::CreateWithIndexPayloadForTesting(
+ {0, 4, 4, 5, 1, 6}, Indices::State::kNonmonotonic);
SqlValue val = SqlValue::Long(3);
- auto res = chain->IndexSearch(FilterOp::kEq, val, indices);
- ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(3));
+ auto indices = common_indices;
+ chain->IndexSearch(FilterOp::kEq, val, indices);
+ ASSERT_THAT(utils::ExtractPayloadForTesting(indices), ElementsAre(3));
- res = chain->IndexSearch(FilterOp::kNe, val, indices);
- ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(0, 1, 2, 4, 5));
+ indices = common_indices;
+ chain->IndexSearch(FilterOp::kNe, val, indices);
+ ASSERT_THAT(utils::ExtractPayloadForTesting(indices),
+ ElementsAre(0, 1, 2, 4, 5));
- res = chain->IndexSearch(FilterOp::kLt, val, indices);
- ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(0, 1, 2, 5));
+ indices = common_indices;
+ chain->IndexSearch(FilterOp::kLt, val, indices);
+ ASSERT_THAT(utils::ExtractPayloadForTesting(indices),
+ ElementsAre(0, 1, 2, 5));
- res = chain->IndexSearch(FilterOp::kLe, val, indices);
- ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(0, 1, 2, 3, 5));
+ indices = common_indices;
+ chain->IndexSearch(FilterOp::kLe, val, indices);
+ ASSERT_THAT(utils::ExtractPayloadForTesting(indices),
+ ElementsAre(0, 1, 2, 3, 5));
- res = chain->IndexSearch(FilterOp::kGt, val, indices);
- ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(4));
+ indices = common_indices;
+ chain->IndexSearch(FilterOp::kGt, val, indices);
+ ASSERT_THAT(utils::ExtractPayloadForTesting(indices), ElementsAre(4));
- res = chain->IndexSearch(FilterOp::kGe, val, indices);
- ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(3, 4));
+ indices = common_indices;
+ chain->IndexSearch(FilterOp::kGe, val, indices);
+ ASSERT_THAT(utils::ExtractPayloadForTesting(indices), ElementsAre(3, 4));
}
TEST(NumericStorage, IndexSearchCompareWithNegative) {
@@ -273,27 +285,35 @@
auto chain = storage.MakeChain();
// -5, -3, -3, 3, 5, 0
- std::vector<uint32_t> indices_vec{0, 4, 4, 5, 1, 6};
- Indices indices{indices_vec.data(), 6, Indices::State::kMonotonic};
+ Indices common_indices = Indices::CreateWithIndexPayloadForTesting(
+ {0, 4, 4, 5, 1, 6}, Indices::State::kNonmonotonic);
SqlValue val = SqlValue::Long(-3);
- auto res = chain->IndexSearch(FilterOp::kEq, val, indices);
- ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(1, 2));
+ auto indices = common_indices;
+ chain->IndexSearch(FilterOp::kEq, val, indices);
+ ASSERT_THAT(utils::ExtractPayloadForTesting(indices), ElementsAre(1, 2));
- res = chain->IndexSearch(FilterOp::kNe, val, indices);
- ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(0, 3, 4, 5));
+ indices = common_indices;
+ chain->IndexSearch(FilterOp::kNe, val, indices);
+ ASSERT_THAT(utils::ExtractPayloadForTesting(indices),
+ ElementsAre(0, 3, 4, 5));
- res = chain->IndexSearch(FilterOp::kLt, val, indices);
- ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(0));
+ indices = common_indices;
+ chain->IndexSearch(FilterOp::kLt, val, indices);
+ ASSERT_THAT(utils::ExtractPayloadForTesting(indices), ElementsAre(0));
- res = chain->IndexSearch(FilterOp::kLe, val, indices);
- ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(0, 1, 2));
+ indices = common_indices;
+ chain->IndexSearch(FilterOp::kLe, val, indices);
+ ASSERT_THAT(utils::ExtractPayloadForTesting(indices), ElementsAre(0, 1, 2));
- res = chain->IndexSearch(FilterOp::kGt, val, indices);
- ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(3, 4, 5));
+ indices = common_indices;
+ chain->IndexSearch(FilterOp::kGt, val, indices);
+ ASSERT_THAT(utils::ExtractPayloadForTesting(indices), ElementsAre(3, 4, 5));
- res = chain->IndexSearch(FilterOp::kGe, val, indices);
- ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(1, 2, 3, 4, 5));
+ indices = common_indices;
+ chain->IndexSearch(FilterOp::kGe, val, indices);
+ ASSERT_THAT(utils::ExtractPayloadForTesting(indices),
+ ElementsAre(1, 2, 3, 4, 5));
}
TEST(NumericStorage, SearchFast) {
@@ -348,8 +368,8 @@
TEST(NumericStorage, OrderedIndexSearch) {
std::vector<uint32_t> data_vec{30, 40, 50, 60, 90, 80, 70, 0, 10, 20};
std::vector<uint32_t> sorted_order_vec{7, 8, 9, 0, 1, 2, 3, 6, 5, 4};
- Indices sorted_order{sorted_order_vec.data(), 10,
- Indices::State::kNonmonotonic};
+ OrderedIndices sorted_order{sorted_order_vec.data(), 10,
+ Indices::State::kNonmonotonic};
NumericStorage<uint32_t> storage(&data_vec, ColumnType::kUint32, false);
auto chain = storage.MakeChain();
@@ -417,27 +437,36 @@
auto chain = storage.MakeChain();
// -5, -3, -3, 3, 5, 0
- std::vector<uint32_t> indices_vec{0, 4, 4, 5, 1, 6};
- Indices indices{indices_vec.data(), 6, Indices::State::kMonotonic};
+ Indices common_indices = Indices::CreateWithIndexPayloadForTesting(
+ {0, 4, 4, 5, 1, 6}, Indices::State::kNonmonotonic);
SqlValue val = SqlValue::Double(3);
- auto res = chain->IndexSearch(FilterOp::kEq, val, indices);
- ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(3));
+ auto indices = common_indices;
+ chain->IndexSearch(FilterOp::kEq, val, indices);
+ ASSERT_THAT(utils::ExtractPayloadForTesting(indices), ElementsAre(3));
- res = chain->IndexSearch(FilterOp::kNe, val, indices);
- ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(0, 1, 2, 4, 5));
+ indices = common_indices;
+ chain->IndexSearch(FilterOp::kNe, val, indices);
+ ASSERT_THAT(utils::ExtractPayloadForTesting(indices),
+ ElementsAre(0, 1, 2, 4, 5));
- res = chain->IndexSearch(FilterOp::kLt, val, indices);
- ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(0, 1, 2, 5));
+ indices = common_indices;
+ chain->IndexSearch(FilterOp::kLt, val, indices);
+ ASSERT_THAT(utils::ExtractPayloadForTesting(indices),
+ ElementsAre(0, 1, 2, 5));
- res = chain->IndexSearch(FilterOp::kLe, val, indices);
- ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(0, 1, 2, 3, 5));
+ indices = common_indices;
+ chain->IndexSearch(FilterOp::kLe, val, indices);
+ ASSERT_THAT(utils::ExtractPayloadForTesting(indices),
+ ElementsAre(0, 1, 2, 3, 5));
- res = chain->IndexSearch(FilterOp::kGt, val, indices);
- ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(4));
+ indices = common_indices;
+ chain->IndexSearch(FilterOp::kGt, val, indices);
+ ASSERT_THAT(utils::ExtractPayloadForTesting(indices), ElementsAre(4));
- res = chain->IndexSearch(FilterOp::kGe, val, indices);
- ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(3, 4));
+ indices = common_indices;
+ chain->IndexSearch(FilterOp::kGe, val, indices);
+ ASSERT_THAT(utils::ExtractPayloadForTesting(indices), ElementsAre(3, 4));
}
TEST(NumericStorage, SearchInt32WithDouble) {
@@ -498,27 +527,36 @@
auto chain = storage.MakeChain();
// -5, -3, -3, 3, 5, 0
- std::vector<uint32_t> indices_vec{0, 4, 4, 5, 1, 6};
- Indices indices{indices_vec.data(), 6, Indices::State::kMonotonic};
+ Indices common_indices = Indices::CreateWithIndexPayloadForTesting(
+ {0, 4, 4, 5, 1, 6}, Indices::State::kNonmonotonic);
SqlValue val = SqlValue::Double(1.5);
- auto res = chain->IndexSearch(FilterOp::kEq, val, indices);
- ASSERT_THAT(utils::ToIndexVectorForTests(res), IsEmpty());
+ auto indices = common_indices;
+ chain->IndexSearch(FilterOp::kEq, val, indices);
+ ASSERT_THAT(utils::ExtractPayloadForTesting(indices), IsEmpty());
- res = chain->IndexSearch(FilterOp::kNe, val, indices);
- ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(0, 1, 2, 3, 4, 5));
+ indices = common_indices;
+ chain->IndexSearch(FilterOp::kNe, val, indices);
+ ASSERT_THAT(utils::ExtractPayloadForTesting(indices),
+ ElementsAre(0, 1, 2, 3, 4, 5));
- res = chain->IndexSearch(FilterOp::kLt, val, indices);
- ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(0, 1, 2, 5));
+ indices = common_indices;
+ chain->IndexSearch(FilterOp::kLt, val, indices);
+ ASSERT_THAT(utils::ExtractPayloadForTesting(indices),
+ ElementsAre(0, 1, 2, 5));
- res = chain->IndexSearch(FilterOp::kLe, val, indices);
- ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(0, 1, 2, 5));
+ indices = common_indices;
+ chain->IndexSearch(FilterOp::kLe, val, indices);
+ ASSERT_THAT(utils::ExtractPayloadForTesting(indices),
+ ElementsAre(0, 1, 2, 5));
- res = chain->IndexSearch(FilterOp::kGt, val, indices);
- ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(3, 4));
+ indices = common_indices;
+ chain->IndexSearch(FilterOp::kGt, val, indices);
+ ASSERT_THAT(utils::ExtractPayloadForTesting(indices), ElementsAre(3, 4));
- res = chain->IndexSearch(FilterOp::kGe, val, indices);
- ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(3, 4));
+ indices = common_indices;
+ chain->IndexSearch(FilterOp::kGe, val, indices);
+ ASSERT_THAT(utils::ExtractPayloadForTesting(indices), ElementsAre(3, 4));
}
TEST(NumericStorage, IndexSearchInt32WithNegDouble) {
@@ -527,27 +565,34 @@
auto chain = storage.MakeChain();
// -5, -3, -3, 3, 5, 0
- std::vector<uint32_t> indices_vec{0, 4, 4, 5, 1, 6};
- Indices indices{indices_vec.data(), 6, Indices::State::kMonotonic};
+ Indices common_indices = Indices::CreateWithIndexPayloadForTesting(
+ {0, 4, 4, 5, 1, 6}, Indices::State::kNonmonotonic);
SqlValue val = SqlValue::Double(-2.5);
- auto res = chain->IndexSearch(FilterOp::kEq, val, indices);
- ASSERT_THAT(utils::ToIndexVectorForTests(res), IsEmpty());
+ auto indices = common_indices;
+ chain->IndexSearch(FilterOp::kEq, val, indices);
+ ASSERT_THAT(utils::ExtractPayloadForTesting(indices), IsEmpty());
- res = chain->IndexSearch(FilterOp::kNe, val, indices);
- ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(0, 1, 2, 3, 4, 5));
+ indices = common_indices;
+ chain->IndexSearch(FilterOp::kNe, val, indices);
+ ASSERT_THAT(utils::ExtractPayloadForTesting(indices),
+ ElementsAre(0, 1, 2, 3, 4, 5));
- res = chain->IndexSearch(FilterOp::kLt, val, indices);
- ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(0, 1, 2));
+ indices = common_indices;
+ chain->IndexSearch(FilterOp::kLt, val, indices);
+ ASSERT_THAT(utils::ExtractPayloadForTesting(indices), ElementsAre(0, 1, 2));
- res = chain->IndexSearch(FilterOp::kLe, val, indices);
- ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(0, 1, 2));
+ indices = common_indices;
+ chain->IndexSearch(FilterOp::kLe, val, indices);
+ ASSERT_THAT(utils::ExtractPayloadForTesting(indices), ElementsAre(0, 1, 2));
- res = chain->IndexSearch(FilterOp::kGt, val, indices);
- ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(3, 4, 5));
+ indices = common_indices;
+ chain->IndexSearch(FilterOp::kGt, val, indices);
+ ASSERT_THAT(utils::ExtractPayloadForTesting(indices), ElementsAre(3, 4, 5));
- res = chain->IndexSearch(FilterOp::kGe, val, indices);
- ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(3, 4, 5));
+ indices = common_indices;
+ chain->IndexSearch(FilterOp::kGe, val, indices);
+ ASSERT_THAT(utils::ExtractPayloadForTesting(indices), ElementsAre(3, 4, 5));
}
TEST(NumericStorage, SearchUint32WithNegDouble) {
@@ -581,27 +626,36 @@
NumericStorage<uint32_t> storage(&data_vec, ColumnType::kInt32, false);
auto chain = storage.MakeChain();
- std::vector<uint32_t> indices_vec{0, 4, 4, 5, 1, 6};
- Indices indices{indices_vec.data(), 6, Indices::State::kMonotonic};
+ Indices common_indices = Indices::CreateWithIndexPayloadForTesting(
+ {0, 4, 4, 5, 1, 6}, Indices::State::kNonmonotonic);
SqlValue val = SqlValue::Double(-2.5);
- auto res = chain->IndexSearch(FilterOp::kEq, val, indices);
- ASSERT_THAT(utils::ToIndexVectorForTests(res), IsEmpty());
+ auto indices = common_indices;
+ chain->IndexSearch(FilterOp::kEq, val, indices);
+ ASSERT_THAT(utils::ExtractPayloadForTesting(indices), IsEmpty());
- res = chain->IndexSearch(FilterOp::kNe, val, indices);
- ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(0, 1, 2, 3, 4, 5));
+ indices = common_indices;
+ chain->IndexSearch(FilterOp::kNe, val, indices);
+ ASSERT_THAT(utils::ExtractPayloadForTesting(indices),
+ ElementsAre(0, 1, 2, 3, 4, 5));
- res = chain->IndexSearch(FilterOp::kLt, val, indices);
- ASSERT_THAT(utils::ToIndexVectorForTests(res), IsEmpty());
+ indices = common_indices;
+ chain->IndexSearch(FilterOp::kLt, val, indices);
+ ASSERT_THAT(utils::ExtractPayloadForTesting(indices), IsEmpty());
- res = chain->IndexSearch(FilterOp::kLe, val, indices);
- ASSERT_THAT(utils::ToIndexVectorForTests(res), IsEmpty());
+ indices = common_indices;
+ chain->IndexSearch(FilterOp::kLe, val, indices);
+ ASSERT_THAT(utils::ExtractPayloadForTesting(indices), IsEmpty());
- res = chain->IndexSearch(FilterOp::kGt, val, indices);
- ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(0, 1, 2, 3, 4, 5));
+ indices = common_indices;
+ chain->IndexSearch(FilterOp::kGt, val, indices);
+ ASSERT_THAT(utils::ExtractPayloadForTesting(indices),
+ ElementsAre(0, 1, 2, 3, 4, 5));
- res = chain->IndexSearch(FilterOp::kGe, val, indices);
- ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(0, 1, 2, 3, 4, 5));
+ indices = common_indices;
+ chain->IndexSearch(FilterOp::kGe, val, indices);
+ ASSERT_THAT(utils::ExtractPayloadForTesting(indices),
+ ElementsAre(0, 1, 2, 3, 4, 5));
}
TEST(NumericStorage, DoubleColumnWithIntThatCantBeRepresentedAsDouble) {
diff --git a/src/trace_processor/db/column/range_overlay.cc b/src/trace_processor/db/column/range_overlay.cc
index 338c989..84f19ce 100644
--- a/src/trace_processor/db/column/range_overlay.cc
+++ b/src/trace_processor/db/column/range_overlay.cc
@@ -108,34 +108,30 @@
return RangeOrBitVector(std::move(builder).Build());
}
-RangeOrBitVector RangeOverlay::ChainImpl::IndexSearchValidated(
- FilterOp op,
- SqlValue sql_val,
- Indices indices) const {
+void RangeOverlay::ChainImpl::IndexSearchValidated(FilterOp op,
+ SqlValue sql_val,
+ Indices& indices) const {
PERFETTO_TP_TRACE(metatrace::Category::DB, "RangeOverlay::IndexSearch");
-
- std::vector<uint32_t> storage_iv(indices.size);
- // Should be SIMD optimized.
- for (uint32_t i = 0; i < indices.size; ++i) {
- storage_iv[i] = indices.data[i] + range_->start;
+ for (auto& token : indices.tokens) {
+ token.index += range_->start;
}
- return inner_->IndexSearchValidated(
- op, sql_val, Indices{storage_iv.data(), indices.size, indices.state});
+ inner_->IndexSearchValidated(op, sql_val, indices);
}
Range RangeOverlay::ChainImpl::OrderedIndexSearchValidated(
FilterOp op,
SqlValue sql_val,
- Indices indices) const {
+ const OrderedIndices& indices) const {
PERFETTO_TP_TRACE(metatrace::Category::DB, "RangeOverlay::IndexSearch");
- std::vector<uint32_t> storage_iv(indices.size);
// Should be SIMD optimized.
+ std::vector<uint32_t> storage_iv(indices.size);
for (uint32_t i = 0; i < indices.size; ++i) {
storage_iv[i] = indices.data[i] + range_->start;
}
return inner_->OrderedIndexSearchValidated(
- op, sql_val, Indices{storage_iv.data(), indices.size, indices.state});
+ op, sql_val,
+ OrderedIndices{storage_iv.data(), indices.size, indices.state});
}
void RangeOverlay::ChainImpl::StableSort(SortToken* start,
diff --git a/src/trace_processor/db/column/range_overlay.h b/src/trace_processor/db/column/range_overlay.h
index 200d5d4..3adb319 100644
--- a/src/trace_processor/db/column/range_overlay.h
+++ b/src/trace_processor/db/column/range_overlay.h
@@ -50,13 +50,11 @@
RangeOrBitVector SearchValidated(FilterOp, SqlValue, Range) const override;
- RangeOrBitVector IndexSearchValidated(FilterOp p,
- SqlValue,
- Indices) const override;
+ void IndexSearchValidated(FilterOp p, SqlValue, Indices&) const override;
Range OrderedIndexSearchValidated(FilterOp,
SqlValue,
- Indices) const override;
+ const OrderedIndices&) const override;
void StableSort(SortToken* start,
SortToken* end,
diff --git a/src/trace_processor/db/column/range_overlay_unittest.cc b/src/trace_processor/db/column/range_overlay_unittest.cc
index 96c2f80..a965be3 100644
--- a/src/trace_processor/db/column/range_overlay_unittest.cc
+++ b/src/trace_processor/db/column/range_overlay_unittest.cc
@@ -35,6 +35,9 @@
using testing::IsEmpty;
using Range = Range;
+using Indices = DataLayerChain::Indices;
+using OrderedIndices = DataLayerChain::OrderedIndices;
+
TEST(RangeOverlay, SearchSingle) {
Range range(3, 8);
RangeOverlay storage(&range);
@@ -96,12 +99,10 @@
RangeOverlay storage(&range);
auto chain = storage.MakeChain(std::move(fake));
- std::vector<uint32_t> table_idx{1u, 0u, 3u};
- RangeOrBitVector res = chain->IndexSearch(
- FilterOp::kGe, SqlValue::Long(0u),
- Indices{table_idx.data(), static_cast<uint32_t>(table_idx.size()),
- Indices::State::kNonmonotonic});
- ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(1u));
+ Indices indices = Indices::CreateWithIndexPayloadForTesting(
+ {1u, 0u, 3u}, Indices::State::kNonmonotonic);
+ chain->IndexSearch(FilterOp::kGe, SqlValue::Long(0u), indices);
+ ASSERT_THAT(utils::ExtractPayloadForTesting(indices), ElementsAre(1u));
}
TEST(RangeOverlay, StableSort) {
diff --git a/src/trace_processor/db/column/selector_overlay.cc b/src/trace_processor/db/column/selector_overlay.cc
index 9ebbb71..999e4bb 100644
--- a/src/trace_processor/db/column/selector_overlay.cc
+++ b/src/trace_processor/db/column/selector_overlay.cc
@@ -56,8 +56,8 @@
PERFETTO_TP_TRACE(metatrace::Category::DB,
"SelectorOverlay::ChainImpl::Search");
- // Figure out the bounds of the indices in the underlying storage and search
- // it.
+ // Figure out the bounds of the OrderedIndices in the underlying storage and
+ // search it.
uint32_t start_idx = selector_->IndexOfNthSet(in.start);
uint32_t end_idx = selector_->IndexOfNthSet(in.end - 1) + 1;
@@ -83,35 +83,24 @@
return RangeOrBitVector(std::move(storage_bitvector));
}
-RangeOrBitVector SelectorOverlay::ChainImpl::IndexSearchValidated(
- FilterOp op,
- SqlValue sql_val,
- Indices indices) const {
- PERFETTO_DCHECK(
- indices.size == 0 ||
- *std::max_element(indices.data, indices.data + indices.size) <=
- selector_->size());
- // TODO(b/307482437): Use OrderedIndexSearch if arrangement orders storage.
-
+void SelectorOverlay::ChainImpl::IndexSearchValidated(FilterOp op,
+ SqlValue sql_val,
+ Indices& indices) const {
PERFETTO_TP_TRACE(metatrace::Category::DB,
"SelectorOverlay::ChainImpl::IndexSearch");
// To go from TableIndexVector to StorageIndexVector we need to find index in
// |selector_| by looking only into set bits.
- std::vector<uint32_t> storage_iv(indices.size);
- for (uint32_t i = 0; i < indices.size; ++i) {
- storage_iv[i] = selector_->IndexOfNthSet(indices.data[i]);
+ for (auto& token : indices.tokens) {
+ token.index = selector_->IndexOfNthSet(token.index);
}
- return inner_->IndexSearchValidated(
- op, sql_val,
- Indices{storage_iv.data(), static_cast<uint32_t>(storage_iv.size()),
- indices.state});
+ return inner_->IndexSearchValidated(op, sql_val, indices);
}
Range SelectorOverlay::ChainImpl::OrderedIndexSearchValidated(
FilterOp op,
SqlValue sql_val,
- Indices indices) const {
+ const OrderedIndices& indices) const {
// To go from TableIndexVector to StorageIndexVector we need to find index in
// |selector_| by looking only into set bits.
std::vector<uint32_t> inner_indices(indices.size);
@@ -120,8 +109,9 @@
}
return inner_->OrderedIndexSearchValidated(
op, sql_val,
- Indices{inner_indices.data(), static_cast<uint32_t>(inner_indices.size()),
- indices.state});
+ OrderedIndices{inner_indices.data(),
+ static_cast<uint32_t>(inner_indices.size()),
+ indices.state});
}
void SelectorOverlay::ChainImpl::StableSort(SortToken* start,
diff --git a/src/trace_processor/db/column/selector_overlay.h b/src/trace_processor/db/column/selector_overlay.h
index 04f178a..82e2fe3 100644
--- a/src/trace_processor/db/column/selector_overlay.h
+++ b/src/trace_processor/db/column/selector_overlay.h
@@ -54,13 +54,11 @@
RangeOrBitVector SearchValidated(FilterOp, SqlValue, Range) const override;
- RangeOrBitVector IndexSearchValidated(FilterOp p,
- SqlValue,
- Indices) const override;
+ void IndexSearchValidated(FilterOp p, SqlValue, Indices&) const override;
Range OrderedIndexSearchValidated(FilterOp,
SqlValue,
- Indices) const override;
+ const OrderedIndices&) const override;
void StableSort(SortToken* start,
SortToken* end,
diff --git a/src/trace_processor/db/column/selector_overlay_unittest.cc b/src/trace_processor/db/column/selector_overlay_unittest.cc
index 11d20f2..0abae4c 100644
--- a/src/trace_processor/db/column/selector_overlay_unittest.cc
+++ b/src/trace_processor/db/column/selector_overlay_unittest.cc
@@ -34,6 +34,9 @@
using testing::ElementsAre;
using testing::IsEmpty;
+using Indices = DataLayerChain::Indices;
+using OrderedIndices = DataLayerChain::OrderedIndices;
+
TEST(SelectorOverlay, SingleSearch) {
BitVector selector{0, 1, 1, 0, 0, 1, 1, 0};
auto fake = FakeStorageChain::SearchSubset(8, Range(2, 5));
@@ -94,12 +97,10 @@
SelectorOverlay storage(&selector);
auto chain = storage.MakeChain(std::move(fake));
- std::vector<uint32_t> table_idx{1u, 0u, 3u};
- RangeOrBitVector res = chain->IndexSearch(
- FilterOp::kGe, SqlValue::Long(0u),
- Indices{table_idx.data(), static_cast<uint32_t>(table_idx.size()),
- Indices::State::kNonmonotonic});
- ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(1u));
+ auto indices = Indices::CreateWithIndexPayloadForTesting(
+ {1u, 0u, 3u}, Indices::State::kNonmonotonic);
+ chain->IndexSearch(FilterOp::kGe, SqlValue::Long(0u), indices);
+ ASSERT_THAT(utils::ExtractPayloadForTesting(indices), ElementsAre(1u));
}
TEST(SelectorOverlay, OrderedIndexSearchTrivial) {
@@ -111,8 +112,8 @@
std::vector<uint32_t> table_idx{1u, 0u, 2u};
Range res = chain->OrderedIndexSearch(
FilterOp::kGe, SqlValue::Long(0u),
- Indices{table_idx.data(), static_cast<uint32_t>(table_idx.size()),
- Indices::State::kNonmonotonic});
+ OrderedIndices{table_idx.data(), static_cast<uint32_t>(table_idx.size()),
+ Indices::State::kNonmonotonic});
ASSERT_EQ(res.start, 0u);
ASSERT_EQ(res.end, 3u);
}
@@ -126,8 +127,8 @@
std::vector<uint32_t> table_idx{1u, 0u, 2u};
Range res = chain->OrderedIndexSearch(
FilterOp::kGe, SqlValue::Long(0u),
- Indices{table_idx.data(), static_cast<uint32_t>(table_idx.size()),
- Indices::State::kNonmonotonic});
+ OrderedIndices{table_idx.data(), static_cast<uint32_t>(table_idx.size()),
+ Indices::State::kNonmonotonic});
ASSERT_EQ(res.size(), 0u);
}
diff --git a/src/trace_processor/db/column/set_id_storage.cc b/src/trace_processor/db/column/set_id_storage.cc
index 780761c..23b63b8 100644
--- a/src/trace_processor/db/column/set_id_storage.cc
+++ b/src/trace_processor/db/column/set_id_storage.cc
@@ -194,76 +194,66 @@
return RangeOrBitVector(BinarySearchIntrinsic(op, val, search_range));
}
-RangeOrBitVector SetIdStorage::ChainImpl::IndexSearchValidated(
- FilterOp op,
- SqlValue sql_val,
- Indices indices) const {
+void SetIdStorage::ChainImpl::IndexSearchValidated(FilterOp op,
+ SqlValue sql_val,
+ Indices& indices) const {
PERFETTO_TP_TRACE(
metatrace::Category::DB, "SetIdStorage::ChainImpl::IndexSearch",
- [indices, op](metatrace::Record* r) {
- r->AddArg("Count", std::to_string(indices.size));
+ [&indices, op](metatrace::Record* r) {
+ r->AddArg("Count", std::to_string(indices.tokens.size()));
r->AddArg("Op", std::to_string(static_cast<uint32_t>(op)));
});
// It's a valid filter operation if |sql_val| is a double, although it
// requires special logic.
if (sql_val.type == SqlValue::kDouble) {
- switch (utils::CompareIntColumnWithDouble(op, &sql_val)) {
- case SearchValidationResult::kOk:
- break;
- case SearchValidationResult::kAllData:
- return RangeOrBitVector(Range(0, indices.size));
- case SearchValidationResult::kNoData:
- return RangeOrBitVector(Range());
+ if (utils::CanReturnEarly(utils::CompareIntColumnWithDouble(op, &sql_val),
+ indices)) {
+ return;
}
}
- auto val = static_cast<uint32_t>(sql_val.AsLong());
- BitVector::Builder builder(indices.size);
-
// TODO(mayzner): Instead of utils::IndexSearchWithComparator, use the
// property of SetId data - that for each index i, data[i] <= i.
+ auto val = static_cast<uint32_t>(sql_val.AsLong());
switch (op) {
case FilterOp::kEq:
- utils::IndexSearchWithComparator(val, values_->data(), indices.data,
- std::equal_to<>(), builder);
+ utils::IndexSearchWithComparator(val, values_->data(), indices,
+ std::equal_to<>());
break;
case FilterOp::kNe:
- utils::IndexSearchWithComparator(val, values_->data(), indices.data,
- std::not_equal_to<>(), builder);
+ utils::IndexSearchWithComparator(val, values_->data(), indices,
+ std::not_equal_to<>());
break;
case FilterOp::kLe:
- utils::IndexSearchWithComparator(val, values_->data(), indices.data,
- std::less_equal<>(), builder);
+ utils::IndexSearchWithComparator(val, values_->data(), indices,
+ std::less_equal<>());
break;
case FilterOp::kLt:
- utils::IndexSearchWithComparator(val, values_->data(), indices.data,
- std::less<>(), builder);
+ utils::IndexSearchWithComparator(val, values_->data(), indices,
+ std::less<>());
break;
case FilterOp::kGt:
- utils::IndexSearchWithComparator(val, values_->data(), indices.data,
- std::greater<>(), builder);
+ utils::IndexSearchWithComparator(val, values_->data(), indices,
+ std::greater<>());
break;
case FilterOp::kGe:
- utils::IndexSearchWithComparator(val, values_->data(), indices.data,
- std::greater_equal<>(), builder);
+ utils::IndexSearchWithComparator(val, values_->data(), indices,
+ std::greater_equal<>());
break;
case FilterOp::kIsNotNull:
- return RangeOrBitVector(Range(0, indices.size));
case FilterOp::kIsNull:
- return RangeOrBitVector(Range());
case FilterOp::kGlob:
case FilterOp::kRegex:
PERFETTO_FATAL("Illegal argument");
}
- return RangeOrBitVector(std::move(builder).Build());
}
Range SetIdStorage::ChainImpl::OrderedIndexSearchValidated(
FilterOp op,
SqlValue sql_val,
- Indices indices) const {
- // Indices are monotonic non-contiguous values.
+ const OrderedIndices& indices) const {
+ // OrderedIndices are monotonic non-contiguous values.
auto res = SearchValidated(
op, sql_val, Range(indices.data[0], indices.data[indices.size - 1] + 1));
PERFETTO_CHECK(res.IsRange());
diff --git a/src/trace_processor/db/column/set_id_storage.h b/src/trace_processor/db/column/set_id_storage.h
index 64f14a3..e5bdb76 100644
--- a/src/trace_processor/db/column/set_id_storage.h
+++ b/src/trace_processor/db/column/set_id_storage.h
@@ -52,13 +52,11 @@
RangeOrBitVector SearchValidated(FilterOp, SqlValue, Range) const override;
- RangeOrBitVector IndexSearchValidated(FilterOp,
- SqlValue,
- Indices) const override;
+ void IndexSearchValidated(FilterOp, SqlValue, Indices&) const override;
Range OrderedIndexSearchValidated(FilterOp,
SqlValue,
- Indices) const override;
+ const OrderedIndices&) const override;
void StableSort(SortToken* start,
SortToken* end,
diff --git a/src/trace_processor/db/column/set_id_storage_unittest.cc b/src/trace_processor/db/column/set_id_storage_unittest.cc
index 99371dc..7af21ac 100644
--- a/src/trace_processor/db/column/set_id_storage_unittest.cc
+++ b/src/trace_processor/db/column/set_id_storage_unittest.cc
@@ -44,6 +44,9 @@
using testing::ElementsAre;
using testing::IsEmpty;
+using Indices = DataLayerChain::Indices;
+using OrderedIndices = DataLayerChain::OrderedIndices;
+
TEST(SetIdStorage, SearchSingle) {
std::vector<uint32_t> storage_data{0, 0, 2, 2, 4, 4, 6, 6};
SetIdStorage storage(&storage_data);
@@ -176,32 +179,32 @@
auto chain = storage.MakeChain();
SqlValue val = SqlValue::Long(4);
// 6, 4, 2, 0
- std::vector<uint32_t> indices_vec{6, 4, 2, 0};
- Indices indices{indices_vec.data(), 4, Indices::State::kNonmonotonic};
+ auto common_indices = Indices::CreateWithIndexPayloadForTesting(
+ {6, 4, 2, 0}, Indices::State::kNonmonotonic);
- FilterOp op = FilterOp::kEq;
- auto res = chain->IndexSearch(op, val, indices);
- ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(1));
+ auto indices = common_indices;
+ chain->IndexSearch(FilterOp::kEq, val, indices);
+ ASSERT_THAT(utils::ExtractPayloadForTesting(indices), ElementsAre(1));
- op = FilterOp::kNe;
- res = chain->IndexSearch(op, val, indices);
- ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(0, 2, 3));
+ indices = common_indices;
+ chain->IndexSearch(FilterOp::kNe, val, indices);
+ ASSERT_THAT(utils::ExtractPayloadForTesting(indices), ElementsAre(0, 2, 3));
- op = FilterOp::kLe;
- res = chain->IndexSearch(op, val, indices);
- ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(1, 2, 3));
+ indices = common_indices;
+ chain->IndexSearch(FilterOp::kLe, val, indices);
+ ASSERT_THAT(utils::ExtractPayloadForTesting(indices), ElementsAre(1, 2, 3));
- op = FilterOp::kLt;
- res = chain->IndexSearch(op, val, indices);
- ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(2, 3));
+ indices = common_indices;
+ chain->IndexSearch(FilterOp::kLt, val, indices);
+ ASSERT_THAT(utils::ExtractPayloadForTesting(indices), ElementsAre(2, 3));
- op = FilterOp::kGe;
- res = chain->IndexSearch(op, val, indices);
- ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(0, 1));
+ indices = common_indices;
+ chain->IndexSearch(FilterOp::kGe, val, indices);
+ ASSERT_THAT(utils::ExtractPayloadForTesting(indices), ElementsAre(0, 1));
- op = FilterOp::kGt;
- res = chain->IndexSearch(op, val, indices);
- ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(0));
+ indices = common_indices;
+ chain->IndexSearch(FilterOp::kGt, val, indices);
+ ASSERT_THAT(utils::ExtractPayloadForTesting(indices), ElementsAre(0));
}
TEST(SetIdStorage, OrderedIndexSearchSimple) {
@@ -211,7 +214,7 @@
// 0, 2, 2, 4
std::vector<uint32_t> indices_vec{0, 3, 3, 5};
- Indices indices{indices_vec.data(), 4, Indices::State::kMonotonic};
+ OrderedIndices indices{indices_vec.data(), 4, Indices::State::kMonotonic};
Range range =
chain->OrderedIndexSearch(FilterOp::kEq, SqlValue::Long(2), indices);
@@ -284,13 +287,10 @@
auto chain = storage.MakeChain();
// {0, 3, 3, 6, 9, 9, 0, 3}
- std::vector<uint32_t> indices_vec{1, 3, 5, 7, 9, 11, 2, 4};
- Indices indices{indices_vec.data(), 8, Indices::State::kMonotonic};
-
- BitVector bv = chain->IndexSearch(FilterOp::kEq, SqlValue::Long(10), indices)
- .TakeIfBitVector();
-
- ASSERT_EQ(bv.CountSetBits(), 0u);
+ auto indices = Indices::CreateWithIndexPayloadForTesting(
+ {1, 3, 5, 7, 9, 11, 2, 4}, Indices::State::kNonmonotonic);
+ chain->IndexSearch(FilterOp::kEq, SqlValue::Long(10), indices);
+ ASSERT_THAT(utils::ExtractPayloadForTesting(indices), IsEmpty());
}
TEST(SetIdStorage, SearchWithIdAsSimpleDoubleIsInt) {
diff --git a/src/trace_processor/db/column/string_storage.cc b/src/trace_processor/db/column/string_storage.cc
index 05f5932..02c8696 100644
--- a/src/trace_processor/db/column/string_storage.cc
+++ b/src/trace_processor/db/column/string_storage.cc
@@ -76,20 +76,20 @@
};
struct NotEqual {
- bool operator()(StringPool::Id lhs, StringPool::Id rhs) {
+ bool operator()(StringPool::Id lhs, StringPool::Id rhs) const {
return lhs != StringPool::Id::Null() && lhs != rhs;
}
};
struct Glob {
- bool operator()(StringPool::Id lhs, util::GlobMatcher& matcher) const {
+ bool operator()(StringPool::Id lhs, const util::GlobMatcher& matcher) const {
return lhs != StringPool::Id::Null() && matcher.Matches(pool_->Get(lhs));
}
const StringPool* pool_;
};
struct GlobFullStringPool {
- GlobFullStringPool(StringPool* pool, util::GlobMatcher& matcher)
+ GlobFullStringPool(StringPool* pool, const util::GlobMatcher& matcher)
: pool_(pool), matches_(pool->MaxSmallStringId().raw_id()) {
PERFETTO_DCHECK(!pool->HasLargeString());
for (auto it = pool->CreateIterator(); it; ++it) {
@@ -97,7 +97,7 @@
matches_[id.raw_id()] = matcher.Matches(pool->Get(id));
}
}
- bool operator()(StringPool::Id lhs, StringPool::Id) {
+ bool operator()(StringPool::Id lhs, StringPool::Id) const {
return lhs != StringPool::Id::Null() && matches_[lhs.raw_id()];
}
StringPool* pool_;
@@ -105,7 +105,7 @@
};
struct Regex {
- bool operator()(StringPool::Id lhs, regex::Regex& pattern) const {
+ bool operator()(StringPool::Id lhs, const regex::Regex& pattern) const {
return lhs != StringPool::Id::Null() &&
pattern.Search(pool_->Get(lhs).c_str());
}
@@ -122,7 +122,7 @@
id != StringPool::Id::Null() && regex.Search(pool_->Get(id).c_str());
}
}
- bool operator()(StringPool::Id lhs, StringPool::Id) {
+ bool operator()(StringPool::Id lhs, StringPool::Id) const {
return matches_[lhs.raw_id()];
}
StringPool* pool_;
@@ -345,19 +345,71 @@
return RangeOrBitVector(LinearSearch(op, sql_val, search_range));
}
-RangeOrBitVector StringStorage::ChainImpl::IndexSearchValidated(
- FilterOp op,
- SqlValue sql_val,
- Indices indices) const {
- PERFETTO_DCHECK(indices.size <= size());
+void StringStorage::ChainImpl::IndexSearchValidated(FilterOp op,
+ SqlValue sql_val,
+ Indices& indices) const {
+ PERFETTO_DCHECK(indices.tokens.size() <= size());
PERFETTO_TP_TRACE(
metatrace::Category::DB, "StringStorage::ChainImpl::IndexSearch",
- [indices, op](metatrace::Record* r) {
- r->AddArg("Count", std::to_string(indices.size));
+ [&indices, op](metatrace::Record* r) {
+ r->AddArg("Count", std::to_string(indices.tokens.size()));
r->AddArg("Op", std::to_string(static_cast<uint32_t>(op)));
});
- return RangeOrBitVector(
- IndexSearchInternal(op, sql_val, indices.data, indices.size));
+
+ StringPool::Id val =
+ (op == FilterOp::kIsNull || op == FilterOp::kIsNotNull)
+ ? StringPool::Id::Null()
+ : string_pool_->InternString(base::StringView(sql_val.AsString()));
+ const StringPool::Id* start = data_->data();
+ switch (op) {
+ case FilterOp::kEq:
+ utils::IndexSearchWithComparator(val, start, indices, std::equal_to<>());
+ break;
+ case FilterOp::kNe:
+ utils::IndexSearchWithComparator(val, start, indices, NotEqual());
+ break;
+ case FilterOp::kLe:
+ utils::IndexSearchWithComparator(string_pool_->Get(val), start, indices,
+ LessEqual{string_pool_});
+ break;
+ case FilterOp::kLt:
+ utils::IndexSearchWithComparator(string_pool_->Get(val), start, indices,
+ Less{string_pool_});
+ break;
+ case FilterOp::kGt:
+ utils::IndexSearchWithComparator(string_pool_->Get(val), start, indices,
+ Greater{string_pool_});
+ break;
+ case FilterOp::kGe:
+ utils::IndexSearchWithComparator(string_pool_->Get(val), start, indices,
+ GreaterEqual{string_pool_});
+ break;
+ case FilterOp::kGlob: {
+ util::GlobMatcher matcher =
+ util::GlobMatcher::FromPattern(sql_val.AsString());
+ if (matcher.IsEquality()) {
+ utils::IndexSearchWithComparator(val, start, indices,
+ std::equal_to<>());
+ break;
+ }
+ utils::IndexSearchWithComparator(std::move(matcher), start, indices,
+ Glob{string_pool_});
+ break;
+ }
+ case FilterOp::kRegex: {
+ base::StatusOr<regex::Regex> regex =
+ regex::Regex::Create(sql_val.AsString());
+ utils::IndexSearchWithComparator(std::move(regex.value()), start, indices,
+ Regex{string_pool_});
+ break;
+ }
+ case FilterOp::kIsNull:
+ utils::IndexSearchWithComparator(val, start, indices, IsNull());
+ break;
+ case FilterOp::kIsNotNull:
+ utils::IndexSearchWithComparator(val, start, indices, IsNotNull());
+ break;
+ }
}
BitVector StringStorage::ChainImpl::LinearSearch(FilterOp op,
@@ -452,7 +504,7 @@
Range StringStorage::ChainImpl::OrderedIndexSearchValidated(
FilterOp op,
SqlValue sql_val,
- Indices indices) const {
+ const OrderedIndices& indices) const {
StringPool::Id val =
(op == FilterOp::kIsNull || op == FilterOp::kIsNotNull)
? StringPool::Id::Null()
@@ -509,75 +561,6 @@
PERFETTO_FATAL("For GCC");
}
-RangeOrBitVector StringStorage::ChainImpl::IndexSearchInternal(
- FilterOp op,
- SqlValue sql_val,
- const uint32_t* indices,
- uint32_t indices_size) const {
- StringPool::Id val =
- (op == FilterOp::kIsNull || op == FilterOp::kIsNotNull)
- ? StringPool::Id::Null()
- : string_pool_->InternString(base::StringView(sql_val.AsString()));
- const StringPool::Id* start = data_->data();
-
- BitVector::Builder builder(indices_size);
-
- switch (op) {
- case FilterOp::kEq:
- utils::IndexSearchWithComparator(val, start, indices, std::equal_to<>(),
- builder);
- break;
- case FilterOp::kNe:
- utils::IndexSearchWithComparator(val, start, indices, NotEqual(),
- builder);
- break;
- case FilterOp::kLe:
- utils::IndexSearchWithComparator(string_pool_->Get(val), start, indices,
- LessEqual{string_pool_}, builder);
- break;
- case FilterOp::kLt:
- utils::IndexSearchWithComparator(string_pool_->Get(val), start, indices,
- Less{string_pool_}, builder);
- break;
- case FilterOp::kGt:
- utils::IndexSearchWithComparator(string_pool_->Get(val), start, indices,
- Greater{string_pool_}, builder);
- break;
- case FilterOp::kGe:
- utils::IndexSearchWithComparator(string_pool_->Get(val), start, indices,
- GreaterEqual{string_pool_}, builder);
- break;
- case FilterOp::kGlob: {
- util::GlobMatcher matcher =
- util::GlobMatcher::FromPattern(sql_val.AsString());
- if (matcher.IsEquality()) {
- utils::IndexSearchWithComparator(val, start, indices, std::equal_to<>(),
- builder);
- break;
- }
- utils::IndexSearchWithComparator(std::move(matcher), start, indices,
- Glob{string_pool_}, builder);
- break;
- }
- case FilterOp::kRegex: {
- base::StatusOr<regex::Regex> regex =
- regex::Regex::Create(sql_val.AsString());
- utils::IndexSearchWithComparator(std::move(regex.value()), start, indices,
- Regex{string_pool_}, builder);
- break;
- }
- case FilterOp::kIsNull:
- utils::IndexSearchWithComparator(val, start, indices, IsNull(), builder);
- break;
- case FilterOp::kIsNotNull:
- utils::IndexSearchWithComparator(val, start, indices, IsNotNull(),
- builder);
- break;
- }
-
- return RangeOrBitVector(std::move(builder).Build());
-}
-
Range StringStorage::ChainImpl::BinarySearchIntrinsic(
FilterOp op,
SqlValue sql_val,
diff --git a/src/trace_processor/db/column/string_storage.h b/src/trace_processor/db/column/string_storage.h
index d61aef5..f037bd1 100644
--- a/src/trace_processor/db/column/string_storage.h
+++ b/src/trace_processor/db/column/string_storage.h
@@ -55,13 +55,11 @@
RangeOrBitVector SearchValidated(FilterOp, SqlValue, Range) const override;
- RangeOrBitVector IndexSearchValidated(FilterOp,
- SqlValue,
- Indices) const override;
+ void IndexSearchValidated(FilterOp, SqlValue, Indices&) const override;
Range OrderedIndexSearchValidated(FilterOp,
SqlValue,
- Indices) const override;
+ const OrderedIndices&) const override;
void StableSort(SortToken* start,
SortToken* end,
diff --git a/src/trace_processor/db/column/string_storage_unittest.cc b/src/trace_processor/db/column/string_storage_unittest.cc
index 303ab66..5312404 100644
--- a/src/trace_processor/db/column/string_storage_unittest.cc
+++ b/src/trace_processor/db/column/string_storage_unittest.cc
@@ -35,6 +35,9 @@
using testing::ElementsAre;
using testing::IsEmpty;
+using Indices = DataLayerChain::Indices;
+using OrderedIndices = DataLayerChain::OrderedIndices;
+
TEST(StringStorage, SearchOneElement) {
std::vector<std::string> strings{"cheese", "pasta", "pizza",
"pierogi", "onion", "fries"};
@@ -161,44 +164,48 @@
auto chain = storage.MakeChain();
SqlValue val = SqlValue::String("pierogi");
// "fries", "onion", "pierogi", NULL, "pizza", "pasta", "cheese"
- std::vector<uint32_t> indices_vec{6, 5, 4, 3, 2, 1, 0};
- Indices indices{indices_vec.data(), 7, Indices::State::kNonmonotonic};
+ Indices common_indices = Indices::CreateWithIndexPayloadForTesting(
+ {6, 5, 4, 3, 2, 1, 0}, Indices::State::kNonmonotonic);
- FilterOp op = FilterOp::kEq;
- auto res = chain->IndexSearch(op, val, indices);
- ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(2));
+ auto indices = common_indices;
+ chain->IndexSearch(FilterOp::kEq, val, indices);
+ ASSERT_THAT(utils::ExtractPayloadForTesting(indices), ElementsAre(2));
- op = FilterOp::kNe;
- res = chain->IndexSearch(op, val, indices);
- ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(0, 1, 4, 5, 6));
+ indices = common_indices;
+ chain->IndexSearch(FilterOp::kNe, val, indices);
+ ASSERT_THAT(utils::ExtractPayloadForTesting(indices),
+ ElementsAre(0, 1, 4, 5, 6));
- op = FilterOp::kLt;
- res = chain->IndexSearch(op, val, indices);
- ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(0, 1, 5, 6));
+ indices = common_indices;
+ chain->IndexSearch(FilterOp::kLt, val, indices);
+ ASSERT_THAT(utils::ExtractPayloadForTesting(indices),
+ ElementsAre(0, 1, 5, 6));
- op = FilterOp::kLe;
- res = chain->IndexSearch(op, val, indices);
- ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(0, 1, 2, 5, 6));
+ indices = common_indices;
+ chain->IndexSearch(FilterOp::kLe, val, indices);
+ ASSERT_THAT(utils::ExtractPayloadForTesting(indices),
+ ElementsAre(0, 1, 2, 5, 6));
- op = FilterOp::kGt;
- res = chain->IndexSearch(op, val, indices);
- ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(4));
+ indices = common_indices;
+ chain->IndexSearch(FilterOp::kGt, val, indices);
+ ASSERT_THAT(utils::ExtractPayloadForTesting(indices), ElementsAre(4));
- op = FilterOp::kGe;
- res = chain->IndexSearch(op, val, indices);
- ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(2, 4));
+ indices = common_indices;
+ chain->IndexSearch(FilterOp::kGe, val, indices);
+ ASSERT_THAT(utils::ExtractPayloadForTesting(indices), ElementsAre(2, 4));
- op = FilterOp::kIsNull;
- res = chain->IndexSearch(op, SqlValue(), indices);
- ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(3));
+ indices = common_indices;
+ chain->IndexSearch(FilterOp::kIsNull, SqlValue(), indices);
+ ASSERT_THAT(utils::ExtractPayloadForTesting(indices), ElementsAre(3));
- op = FilterOp::kIsNotNull;
- res = chain->IndexSearch(op, SqlValue(), indices);
- ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(0, 1, 2, 4, 5, 6));
+ indices = common_indices;
+ chain->IndexSearch(FilterOp::kIsNotNull, SqlValue(), indices);
+ ASSERT_THAT(utils::ExtractPayloadForTesting(indices),
+ ElementsAre(0, 1, 2, 4, 5, 6));
- op = FilterOp::kGlob;
- res = chain->IndexSearch(op, SqlValue::String("p*"), indices);
- ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(2, 4, 5));
+ indices = common_indices;
+ chain->IndexSearch(FilterOp::kGlob, SqlValue::String("p*"), indices);
+ ASSERT_THAT(utils::ExtractPayloadForTesting(indices), ElementsAre(2, 4, 5));
}
#if !PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
@@ -294,37 +301,36 @@
StringStorage storage(&pool, &ids, true);
auto chain = storage.MakeChain();
SqlValue val = SqlValue::String("cheese");
- // fries, eggplant, cheese, burger
- std::vector<uint32_t> indices_vec{5, 4, 2, 1};
- Indices indices{indices_vec.data(), 4, Indices::State::kNonmonotonic};
+ Indices common_indices = Indices::CreateWithIndexPayloadForTesting(
+ {5, 4, 2, 1}, Indices::State::kNonmonotonic);
- FilterOp op = FilterOp::kEq;
- auto res = chain->IndexSearch(op, val, indices);
- ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(2));
+ auto indices = common_indices;
+ chain->IndexSearch(FilterOp::kEq, val, indices);
+ ASSERT_THAT(utils::ExtractPayloadForTesting(indices), ElementsAre(2));
- op = FilterOp::kNe;
- res = chain->IndexSearch(op, val, indices);
- ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(0, 1, 3));
+ indices = common_indices;
+ chain->IndexSearch(FilterOp::kNe, val, indices);
+ ASSERT_THAT(utils::ExtractPayloadForTesting(indices), ElementsAre(0, 1, 3));
- op = FilterOp::kLt;
- res = chain->IndexSearch(op, val, indices);
- ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(3));
+ indices = common_indices;
+ chain->IndexSearch(FilterOp::kLt, val, indices);
+ ASSERT_THAT(utils::ExtractPayloadForTesting(indices), ElementsAre(3));
- op = FilterOp::kLe;
- res = chain->IndexSearch(op, val, indices);
- ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(2, 3));
+ indices = common_indices;
+ chain->IndexSearch(FilterOp::kLe, val, indices);
+ ASSERT_THAT(utils::ExtractPayloadForTesting(indices), ElementsAre(2, 3));
- op = FilterOp::kGt;
- res = chain->IndexSearch(op, val, indices);
- ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(0, 1));
+ indices = common_indices;
+ chain->IndexSearch(FilterOp::kGt, val, indices);
+ ASSERT_THAT(utils::ExtractPayloadForTesting(indices), ElementsAre(0, 1));
- op = FilterOp::kGe;
- res = chain->IndexSearch(op, val, indices);
- ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(0, 1, 2));
+ indices = common_indices;
+ chain->IndexSearch(FilterOp::kGe, val, indices);
+ ASSERT_THAT(utils::ExtractPayloadForTesting(indices), ElementsAre(0, 1, 2));
- op = FilterOp::kGlob;
- res = chain->IndexSearch(op, SqlValue::String("*e"), indices);
- ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(2));
+ indices = common_indices;
+ chain->IndexSearch(FilterOp::kGlob, SqlValue::String("*e"), indices);
+ ASSERT_THAT(utils::ExtractPayloadForTesting(indices), ElementsAre(2));
}
TEST(StringStorage, OrderedIndexSearch) {
@@ -340,7 +346,7 @@
SqlValue val = SqlValue::String("pierogi");
// cheese, fries, onion, pasta, pierogi, pizza
std::vector<uint32_t> indices_vec{0, 5, 4, 1, 3, 2};
- Indices indices{indices_vec.data(), 6, Indices::State::kNonmonotonic};
+ OrderedIndices indices{indices_vec.data(), 6, Indices::State::kNonmonotonic};
FilterOp op = FilterOp::kEq;
Range res = chain->OrderedIndexSearch(op, val, indices);
@@ -380,7 +386,7 @@
auto chain = storage.MakeChain();
std::vector<uint32_t> indices_vec{0, 2, 5, 7};
- Indices indices{indices_vec.data(), 4, Indices::State::kNonmonotonic};
+ OrderedIndices indices{indices_vec.data(), 4, Indices::State::kNonmonotonic};
auto res = chain->OrderedIndexSearch(FilterOp::kIsNull, SqlValue(), indices);
ASSERT_EQ(res.start, 0u);
ASSERT_EQ(res.end, 2u);
@@ -398,7 +404,7 @@
auto chain = storage.MakeChain();
std::vector<uint32_t> indices_vec{0, 2, 5, 7};
- Indices indices{indices_vec.data(), 4, Indices::State::kNonmonotonic};
+ OrderedIndices indices{indices_vec.data(), 4, Indices::State::kNonmonotonic};
auto res =
chain->OrderedIndexSearch(FilterOp::kIsNotNull, SqlValue(), indices);
ASSERT_EQ(res.start, 2u);
diff --git a/src/trace_processor/db/column/types.h b/src/trace_processor/db/column/types.h
index 803c6ce..b59084b 100644
--- a/src/trace_processor/db/column/types.h
+++ b/src/trace_processor/db/column/types.h
@@ -19,6 +19,7 @@
#include <cstdint>
#include <utility>
#include <variant>
+#include <vector>
#include "perfetto/base/logging.h"
#include "perfetto/trace_processor/basic_types.h"
@@ -113,21 +114,6 @@
kDummy,
};
-// Index vector related data required to Filter using IndexSearch.
-struct Indices {
- enum class State {
- // We can't guarantee that data is in monotonic order.
- kNonmonotonic,
- // Data is in monotonic order.
- // TODO(b/307482437): Use this to optimise filtering if storage is sorted.
- kMonotonic
- };
-
- const uint32_t* data = nullptr;
- uint32_t size = 0;
- State state = Indices::State::kNonmonotonic;
-};
-
} // namespace perfetto::trace_processor
#endif // SRC_TRACE_PROCESSOR_DB_COLUMN_TYPES_H_
diff --git a/src/trace_processor/db/column/utils.cc b/src/trace_processor/db/column/utils.cc
index efec000..e24f3bf 100644
--- a/src/trace_processor/db/column/utils.cc
+++ b/src/trace_processor/db/column/utils.cc
@@ -79,6 +79,16 @@
}
std::vector<uint32_t> ExtractPayloadForTesting(
+ const DataLayerChain::Indices& indices) {
+ std::vector<uint32_t> payload;
+ payload.reserve(indices.tokens.size());
+ for (const auto& token : indices.tokens) {
+ payload.push_back(token.payload);
+ }
+ return payload;
+}
+
+std::vector<uint32_t> ExtractPayloadForTesting(
std::vector<column::DataLayerChain::SortToken>& tokens) {
std::vector<uint32_t> payload;
payload.reserve(tokens.size());
@@ -113,4 +123,18 @@
PERFETTO_FATAL("For GCC");
}
+bool CanReturnEarly(SearchValidationResult res,
+ DataLayerChain::Indices& indices) {
+ switch (res) {
+ case SearchValidationResult::kOk:
+ return false;
+ case SearchValidationResult::kAllData:
+ return true;
+ case SearchValidationResult::kNoData:
+ indices.tokens.clear();
+ return true;
+ }
+ PERFETTO_FATAL("For GCC");
+}
+
} // namespace perfetto::trace_processor::column::utils
diff --git a/src/trace_processor/db/column/utils.h b/src/trace_processor/db/column/utils.h
index b1c71a3..14c6456 100644
--- a/src/trace_processor/db/column/utils.h
+++ b/src/trace_processor/db/column/utils.h
@@ -16,6 +16,7 @@
#ifndef SRC_TRACE_PROCESSOR_DB_COLUMN_UTILS_H_
#define SRC_TRACE_PROCESSOR_DB_COLUMN_UTILS_H_
+#include <algorithm>
#include <cstdint>
#include <functional>
#include <optional>
@@ -65,28 +66,14 @@
template <typename Comparator, typename ValType, typename DataType>
void IndexSearchWithComparator(ValType val,
const DataType* data_ptr,
- const uint32_t* indices,
- Comparator comparator,
- BitVector::Builder& builder) {
- // Fast path: we compare as many groups of 64 elements as we can.
- // This should be very easy for the compiler to auto-vectorize.
- const uint32_t* cur_idx = indices;
- uint32_t fast_path_elements = builder.BitsInCompleteWordsUntilFull();
- for (uint32_t i = 0; i < fast_path_elements; i += BitVector::kBitsInWord) {
- uint64_t word = 0;
- // This part should be optimised by SIMD and is expected to be fast.
- for (uint32_t k = 0; k < BitVector::kBitsInWord; ++k, ++cur_idx) {
- bool comp_result = comparator(*(data_ptr + *cur_idx), val);
- word |= static_cast<uint64_t>(comp_result) << k;
- }
- builder.AppendWord(word);
- }
-
- // Slow path: we compare <64 elements and append to fill the Builder.
- uint32_t back_elements = builder.BitsUntilFull();
- for (uint32_t i = 0; i < back_elements; ++i, ++cur_idx) {
- builder.Append(comparator(*(data_ptr + *cur_idx), val));
- }
+ DataLayerChain::Indices& indices,
+ Comparator comparator) {
+ auto it = std::remove_if(indices.tokens.begin(), indices.tokens.end(),
+ [&comparator, data_ptr,
+ &val](const DataLayerChain::Indices::Token& token) {
+ return !comparator(*(data_ptr + token.index), val);
+ });
+ indices.tokens.erase(it, indices.tokens.end());
}
template <typename T>
@@ -136,11 +123,18 @@
std::optional<Range> CanReturnEarly(SearchValidationResult,
uint32_t indices_size);
+// If the validation result doesn't require further search, will modify
+// |indices| to match and return true. Otherwise returns false.
+bool CanReturnEarly(SearchValidationResult res,
+ DataLayerChain::Indices& indices);
+
std::vector<uint32_t> ExtractPayloadForTesting(
std::vector<column::DataLayerChain::SortToken>&);
std::vector<uint32_t> ToIndexVectorForTests(RangeOrBitVector&);
+std::vector<uint32_t> ExtractPayloadForTesting(const DataLayerChain::Indices&);
+
} // namespace perfetto::trace_processor::column::utils
#endif // SRC_TRACE_PROCESSOR_DB_COLUMN_UTILS_H_
diff --git a/src/trace_processor/db/query_executor.cc b/src/trace_processor/db/query_executor.cc
index bd15245..0dd3aa9 100644
--- a/src/trace_processor/db/query_executor.cc
+++ b/src/trace_processor/db/query_executor.cc
@@ -19,6 +19,7 @@
#include <utility>
#include <vector>
+#include <sys/types.h>
#include "perfetto/base/logging.h"
#include "perfetto/trace_processor/basic_types.h"
#include "src/trace_processor/containers/bit_vector.h"
@@ -116,36 +117,17 @@
// Create outmost TableIndexVector.
std::vector<uint32_t> table_indices = std::move(*rm).TakeAsIndexVector();
- RangeOrBitVector matched = chain.IndexSearch(
- c.op, c.value,
- Indices{table_indices.data(), static_cast<uint32_t>(table_indices.size()),
- Indices::State::kMonotonic});
+ using Indices = column::DataLayerChain::Indices;
+ Indices indices = Indices::Create(table_indices, Indices::State::kMonotonic);
+ chain.IndexSearch(c.op, c.value, indices);
- if (matched.IsBitVector()) {
- BitVector res = std::move(matched).TakeIfBitVector();
- uint32_t i = 0;
- table_indices.erase(
- std::remove_if(table_indices.begin(), table_indices.end(),
- [&i, &res](uint32_t) { return !res.IsSet(i++); }),
- table_indices.end());
- *rm = RowMap(std::move(table_indices));
- return;
+ PERFETTO_DCHECK(indices.tokens.size() <= table_indices.size());
+ for (uint32_t i = 0; i < indices.tokens.size(); ++i) {
+ table_indices[i] = indices.tokens[i].payload;
}
-
- Range res = std::move(matched).TakeIfRange();
- if (res.size() == 0) {
- rm->Clear();
- return;
- }
- if (res.size() == table_indices.size()) {
- return;
- }
-
- PERFETTO_DCHECK(res.end <= table_indices.size());
- std::vector<uint32_t> res_as_iv(
- table_indices.begin() + static_cast<int>(res.start),
- table_indices.begin() + static_cast<int>(res.end));
- *rm = RowMap(std::move(res_as_iv));
+ table_indices.resize(indices.tokens.size());
+ PERFETTO_DCHECK(std::is_sorted(table_indices.begin(), table_indices.end()));
+ *rm = RowMap(std::move(table_indices));
}
RowMap QueryExecutor::FilterLegacy(const Table* table,
diff --git a/src/trace_processor/db/query_executor_unittest.cc b/src/trace_processor/db/query_executor_unittest.cc
index f0d8f03..161a106 100644
--- a/src/trace_processor/db/query_executor_unittest.cc
+++ b/src/trace_processor/db/query_executor_unittest.cc
@@ -52,6 +52,8 @@
using ArrangementOverlay = column::ArrangementOverlay;
using SelectorOverlay = column::SelectorOverlay;
+using Indices = column::DataLayerChain::Indices;
+
TEST(QueryExecutor, OnlyStorageRange) {
std::vector<int64_t> storage_data{1, 2, 3, 4, 5};
column::NumericStorage<int64_t> storage(&storage_data, ColumnType::kInt64,
diff --git a/src/trace_processor/db/table.cc b/src/trace_processor/db/table.cc
index 7bedbb7..641c745 100644
--- a/src/trace_processor/db/table.cc
+++ b/src/trace_processor/db/table.cc
@@ -157,7 +157,7 @@
if (table.overlays_[i].row_map().IsIndexVector()) {
overlay_layers[i].reset(new column::ArrangementOverlay(
table.overlays_[i].row_map().GetIfIndexVector(),
- Indices::State::kNonmonotonic));
+ column::DataLayerChain::Indices::State::kNonmonotonic));
} else if (table.overlays_[i].row_map().IsBitVector()) {
overlay_layers[i].reset(new column::SelectorOverlay(
table.overlays_[i].row_map().GetIfBitVector()));
diff --git a/src/trace_processor/util/glob.cc b/src/trace_processor/util/glob.cc
index f930683..3f44f36 100644
--- a/src/trace_processor/util/glob.cc
+++ b/src/trace_processor/util/glob.cc
@@ -78,7 +78,7 @@
trailing_star_ = !pattern.empty() && empty_segment;
}
-bool GlobMatcher::Matches(base::StringView in) {
+bool GlobMatcher::Matches(base::StringView in) const {
// If there are no segments, that means the pattern is either '' or '*'
// (or '**', '***' etc which is really the same as '*'). This means
// we are match if either a) there is a leading star (== trailing star) or
@@ -115,10 +115,10 @@
// sequentially with possibly some characters separating them. To handle
// this, we just need to iteratively find each segment, starting from the
// previous segment.
- Segment* segment_start = segments_.begin() + (leading_star_ ? 0 : 1);
- Segment* segment_end = segments_.end() - (trailing_star_ ? 0 : 1);
+ const Segment* segment_start = segments_.begin() + (leading_star_ ? 0 : 1);
+ const Segment* segment_end = segments_.end() - (trailing_star_ ? 0 : 1);
size_t find_idx = leading_star_ ? 0 : segments_.front().matched_chars;
- for (Segment* segment = segment_start; segment < segment_end; ++segment) {
+ for (const auto* segment = segment_start; segment < segment_end; ++segment) {
size_t pos = Find(in, *segment, find_idx);
if (pos == base::StringView::npos) {
return false;
@@ -131,7 +131,8 @@
return true;
}
-bool GlobMatcher::StartsWithSlow(base::StringView in, const Segment& segment) {
+bool GlobMatcher::StartsWithSlow(base::StringView in,
+ const Segment& segment) const {
base::StringView pattern = segment.pattern;
for (uint32_t i = 0, p = 0; p < pattern.size(); ++i, ++p) {
// We've run out of characters to consume in the input but still have more
diff --git a/src/trace_processor/util/glob.h b/src/trace_processor/util/glob.h
index b5bce6e..518cca8 100644
--- a/src/trace_processor/util/glob.h
+++ b/src/trace_processor/util/glob.h
@@ -80,7 +80,7 @@
// Checks the provided string against the pattern and returns whether it
// matches.
- bool Matches(base::StringView input);
+ bool Matches(base::StringView input) const;
// Returns whether the comparison should really be an equality comparison.
bool IsEquality() {
@@ -110,7 +110,7 @@
// Returns whether |input| starts with the pattern in |segment| following
// glob matching rules.
- bool StartsWith(base::StringView input, const Segment& segment) {
+ bool StartsWith(base::StringView input, const Segment& segment) const {
if (!contains_char_class_or_question_) {
return input.StartsWith(segment.pattern);
}
@@ -119,7 +119,7 @@
// Returns whether |input| ends with the pattern in |segment| following
// glob matching rules.
- bool EndsWith(base::StringView input, const Segment& segment) {
+ bool EndsWith(base::StringView input, const Segment& segment) const {
if (!contains_char_class_or_question_) {
return input.EndsWith(segment.pattern);
}
@@ -131,7 +131,9 @@
// Returns the index where |input| matches the pattern in |segment|
// following glob matching rules or base::StringView::npos, if no such index
// exists.
- size_t Find(base::StringView input, const Segment& segment, size_t start) {
+ size_t Find(base::StringView input,
+ const Segment& segment,
+ size_t start) const {
if (!contains_char_class_or_question_) {
return input.find(segment.pattern, start);
}
@@ -151,7 +153,7 @@
// Matches |in| against the given character class.
static bool MatchesCharacterClass(char input, base::StringView char_class);
- bool StartsWithSlow(base::StringView input, const Segment& segment);
+ bool StartsWithSlow(base::StringView input, const Segment& segment) const;
// IMPORTANT: this should *not* be modified after the constructor as we store
// pointers to the data inside here.