Merge "tp: introduces SqliteEngine to broker all interactions with SQLite"
diff --git a/gn/BUILD.gn b/gn/BUILD.gn
index 192ede8..6edf379 100644
--- a/gn/BUILD.gn
+++ b/gn/BUILD.gn
@@ -275,7 +275,7 @@
"GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER",
]
cflags = []
- if (!is_clang || !is_win) {
+ if (!is_clang && !is_win) {
cflags += [ "-Wno-deprecated-declarations" ]
}
if (is_clang && is_win) {
diff --git a/gn/standalone/BUILD.gn b/gn/standalone/BUILD.gn
index d000f53..0af6551 100644
--- a/gn/standalone/BUILD.gn
+++ b/gn/standalone/BUILD.gn
@@ -100,6 +100,18 @@
# TODO(lalitm): remove this when we upgrade to a GCC version which is good
# enough to handle this.
cflags_cc += [ "-Wno-maybe-uninitialized" ]
+
+ # GCC's handling of detecting infinite recursion is flaky at best and
+ # causes some false positives.
+ # TODO(lalitm): remove this when we upgrade to a GCC version which is good
+ # enough to handle this.
+ cflags_cc += [ "-Wno-infinite-recursion" ]
+
+ # GCC's handling of detecting non null arguments is flaky at best and
+ # causes some false positives.
+ # TODO(lalitm): remove this when we upgrade to a GCC version which is good
+ # enough to handle this.
+ cflags_cc += [ "-Wno-nonnull" ]
}
}
diff --git a/gn/standalone/toolchain/win_find_msvc.py b/gn/standalone/toolchain/win_find_msvc.py
index 1628c07..6f7eb86 100644
--- a/gn/standalone/toolchain/win_find_msvc.py
+++ b/gn/standalone/toolchain/win_find_msvc.py
@@ -27,6 +27,7 @@
"""
import os
+import itertools
import subprocess
import sys
@@ -62,19 +63,19 @@
filt = lambda x: os.path.exists(os.path.join(x, 'ucrt', 'x64', 'ucrt.lib'))
out[1] = find_max_subdir(lib_base, filt)
- for year in ['2022', '2021', '2020', '2019']:
- for version in [
- 'BuildTools', 'Community', 'Professional', 'Enterprise', 'Preview'
- ]:
- msvc_base = ('C:\\Program Files (x86)\\Microsoft Visual Studio\\'
- f'{year}\\{version}\\VC\\Tools\\MSVC')
- if os.path.exists(msvc_base):
- filt = lambda x: os.path.exists(
- os.path.join(x, 'lib', 'x64', 'libcmt.lib'))
- max_msvc = find_max_subdir(msvc_base, filt)
- if max_msvc is not None:
- out[2] = os.path.join(msvc_base, max_msvc)
- break
+ for try_dir in itertools.product(
+ ['2022', '2021', '2020', '2019'],
+ ['BuildTools', 'Community', 'Professional', 'Enterprise', 'Preview'],
+ ['Program Files', 'Program Files (x86)']):
+ msvc_base = (f'C:\\{try_dir[2]}\\Microsoft Visual Studio\\'
+ f'{try_dir[0]}\\{try_dir[1]}\\VC\\Tools\\MSVC')
+ if os.path.exists(msvc_base):
+ filt = lambda x: os.path.exists(
+ os.path.join(x, 'lib', 'x64', 'libcmt.lib'))
+ max_msvc = find_max_subdir(msvc_base, filt)
+ if max_msvc is not None:
+ out[2] = os.path.join(msvc_base, max_msvc)
+ break
# Don't error in case of failure, GN scripts are supposed to deal with
# failures and allow the user to override the dirs.
diff --git a/protos/perfetto/metrics/webview/webview_jank_approximation.proto b/protos/perfetto/metrics/webview/webview_jank_approximation.proto
index 0d01a77..cdf7299 100644
--- a/protos/perfetto/metrics/webview/webview_jank_approximation.proto
+++ b/protos/perfetto/metrics/webview/webview_jank_approximation.proto
@@ -19,9 +19,9 @@
package perfetto.protos;
message WebViewJankApproximation {
- required int32 webview_janks = 1;
- required int32 webview_janks_without_startup = 2;
- required int32 webview_app_janks = 3;
- required int32 webview_total_janks = 4;
- required int32 total_janks = 5;
+ optional int32 webview_janks = 1;
+ optional int32 webview_janks_without_startup = 2;
+ optional int32 webview_app_janks = 3;
+ optional int32 webview_total_janks = 4;
+ optional int32 total_janks = 5;
}
diff --git a/src/trace_processor/containers/row_map.cc b/src/trace_processor/containers/row_map.cc
index b3d1d59..d00d487 100644
--- a/src/trace_processor/containers/row_map.cc
+++ b/src/trace_processor/containers/row_map.cc
@@ -15,6 +15,7 @@
*/
#include "src/trace_processor/containers/row_map.h"
+#include <unordered_set>
#include "src/trace_processor/containers/row_map_algorithms.h"
@@ -23,22 +24,19 @@
namespace {
-RowMap SelectRangeWithRange(uint32_t start,
- uint32_t end,
- uint32_t selector_start,
- uint32_t selector_end) {
- PERFETTO_DCHECK(start <= end);
- PERFETTO_DCHECK(selector_start <= selector_end);
- PERFETTO_DCHECK(selector_end <= end - start);
+using Range = RowMap::Range;
+using OutputIndex = RowMap::OutputIndex;
+using Variant = std::variant<Range, BitVector, std::vector<OutputIndex>>;
- return RowMap(start + selector_start, start + selector_end);
+RowMap Select(Range range, Range selector) {
+ PERFETTO_DCHECK(selector.start <= selector.end);
+ PERFETTO_DCHECK(selector.end <= range.size());
+
+ return RowMap(range.start + selector.start, range.start + selector.end);
}
-RowMap SelectRangeWithBv(uint32_t start,
- uint32_t end,
- const BitVector& selector) {
- PERFETTO_DCHECK(start <= end);
- PERFETTO_DCHECK(selector.size() <= end - start);
+RowMap Select(Range range, const BitVector& selector) {
+ PERFETTO_DCHECK(selector.size() <= range.size());
// If |start| == 0 and |selector.size()| <= |end - start| (which is a
// precondition for this function), the BitVector we generate is going to be
@@ -48,60 +46,52 @@
// SelectRows is called on all the table RowMaps with a BitVector. The self
// RowMap will always be a range so we expect this case to be hit at least
// once every filter operation.
- if (start == 0u)
+ if (range.start == 0u)
return RowMap(selector.Copy());
// We only need to resize to |start| + |selector.size()| as we know any rows
// not covered by |selector| are going to be removed below.
- BitVector bv(start, false);
- bv.Resize(start + selector.size(), true);
+ BitVector bv(range.start, false);
+ bv.Resize(range.start + selector.size(), true);
bv.UpdateSetBits(selector);
return RowMap(std::move(bv));
}
-RowMap SelectRangeWithIv(uint32_t start,
- uint32_t end,
- const std::vector<uint32_t>& selector) {
- PERFETTO_DCHECK(start <= end);
-
+RowMap Select(Range range, const std::vector<OutputIndex>& selector) {
std::vector<uint32_t> iv(selector.size());
for (uint32_t i = 0; i < selector.size(); ++i) {
- PERFETTO_DCHECK(selector[i] < end - start);
- iv[i] = selector[i] + start;
+ PERFETTO_DCHECK(selector[i] < range.size());
+ iv[i] = selector[i] + range.start;
}
return RowMap(std::move(iv));
}
-RowMap SelectBvWithRange(const BitVector& bv,
- uint32_t selector_start,
- uint32_t selector_end) {
- PERFETTO_DCHECK(selector_start <= selector_end);
- PERFETTO_DCHECK(selector_end <= bv.CountSetBits());
+RowMap Select(const BitVector& bv, Range selector) {
+ PERFETTO_DCHECK(selector.end <= bv.CountSetBits());
// If we're simply selecting every element in the bitvector, just
// return a copy of the BitVector without iterating.
BitVector ret = bv.Copy();
- if (selector_start == 0 && selector_end == bv.CountSetBits()) {
+ if (selector.start == 0 && selector.end == bv.CountSetBits()) {
return RowMap(std::move(ret));
}
for (auto it = ret.IterateSetBits(); it; it.Next()) {
auto set_idx = it.ordinal();
- if (set_idx < selector_start || set_idx >= selector_end)
+ if (set_idx < selector.start || set_idx >= selector.end)
it.Clear();
}
return RowMap(std::move(ret));
}
-RowMap SelectBvWithBv(const BitVector& bv, const BitVector& selector) {
+RowMap Select(const BitVector& bv, const BitVector& selector) {
BitVector ret = bv.Copy();
ret.UpdateSetBits(selector);
return RowMap(std::move(ret));
}
-RowMap SelectBvWithIv(const BitVector& bv,
- const std::vector<uint32_t>& selector) {
+RowMap Select(const BitVector& bv, const std::vector<uint32_t>& selector) {
// The value of this constant was found by considering the benchmarks
// |BM_SelectBvWithIvByConvertToIv| and |BM_SelectBvWithIvByIndexOfNthSet|.
//
@@ -130,21 +120,17 @@
row_map_algorithms::SelectBvWithIvByIndexOfNthSet(bv, selector));
}
-RowMap SelectIvWithRange(const std::vector<uint32_t>& iv,
- uint32_t selector_start,
- uint32_t selector_end) {
- PERFETTO_DCHECK(selector_start <= selector_end);
- PERFETTO_DCHECK(selector_end <= iv.size());
+RowMap Select(const std::vector<uint32_t>& iv, Range selector) {
+ PERFETTO_DCHECK(selector.end <= iv.size());
- std::vector<uint32_t> ret(selector_end - selector_start);
- for (uint32_t i = selector_start; i < selector_end; ++i) {
- ret[i - selector_start] = iv[i];
+ std::vector<uint32_t> ret(selector.size());
+ for (uint32_t i = selector.start; i < selector.end; ++i) {
+ ret[i - selector.start] = iv[i];
}
return RowMap(std::move(ret));
}
-RowMap SelectIvWithBv(const std::vector<uint32_t>& iv,
- const BitVector& selector) {
+RowMap Select(const std::vector<uint32_t>& iv, const BitVector& selector) {
PERFETTO_DCHECK(selector.size() <= iv.size());
std::vector<uint32_t> copy = iv;
@@ -158,83 +144,133 @@
return RowMap(std::move(copy));
}
-RowMap SelectIvWithIv(const std::vector<uint32_t>& iv,
- const std::vector<uint32_t>& selector) {
+RowMap Select(const std::vector<uint32_t>& iv,
+ const std::vector<uint32_t>& selector) {
return RowMap(row_map_algorithms::SelectIvWithIv(iv, selector));
}
+Variant IntersectInternal(BitVector& first, const BitVector& second) {
+ for (auto set_bit = first.IterateSetBits(); set_bit; set_bit.Next()) {
+ if (!second.IsSet(set_bit.index()))
+ set_bit.Clear();
+ }
+ return std::move(first);
+}
+
+Variant IntersectInternal(Range first, Range second) {
+ // If both RowMaps have ranges, we can just take the smallest intersection
+ // of them as the new RowMap.
+ // We have this as an explicit fast path as this is very common for
+ // constraints on id and sorted columns to satisfy this condition.
+ OutputIndex start = std::max(first.start, second.start);
+ OutputIndex end = std::max(start, std::min(first.end, second.end));
+ return Range{start, end};
+}
+
+Variant IntersectInternal(std::vector<OutputIndex>& first,
+ const std::vector<OutputIndex>& second) {
+ std::unordered_set<OutputIndex> lookup(second.begin(), second.end());
+ first.erase(std::remove_if(first.begin(), first.end(),
+ [lookup](OutputIndex ind) {
+ return lookup.find(ind) == lookup.end();
+ }),
+ first.end());
+ return std::move(first);
+}
+
+Variant IntersectInternal(Range range, const BitVector& bv) {
+ return bv.IntersectRange(range.start, range.end);
+}
+
+Variant IntersectInternal(BitVector& bv, Range range) {
+ return IntersectInternal(range, bv);
+}
+
+Variant IntersectInternal(const std::vector<OutputIndex>& index_vec,
+ const BitVector& bv) {
+ std::vector<OutputIndex> new_vec(index_vec.begin(), index_vec.end());
+ new_vec.erase(std::remove_if(new_vec.begin(), new_vec.end(),
+ [&bv](uint32_t i) { return !bv.IsSet(i); }),
+ new_vec.end());
+ return std::move(new_vec);
+}
+
+Variant IntersectInternal(const BitVector& bv,
+ const std::vector<OutputIndex>& index_vec) {
+ return IntersectInternal(index_vec, bv);
+}
+
+Variant IntersectInternal(Range range,
+ const std::vector<OutputIndex>& index_vec) {
+ std::vector<OutputIndex> new_vec(index_vec.begin(), index_vec.end());
+ new_vec.erase(std::remove_if(new_vec.begin(), new_vec.end(),
+ [range](uint32_t i) {
+ return i < range.start || i >= range.end;
+ }),
+ new_vec.end());
+ return std::move(new_vec);
+}
+
+Variant IntersectInternal(const std::vector<OutputIndex>& index_vec,
+ Range range) {
+ return IntersectInternal(range, index_vec);
+}
+
} // namespace
-RowMap::RowMap() : RowMap(0, 0) {}
+RowMap::RowMap() : RowMap(Range()) {}
RowMap::RowMap(uint32_t start, uint32_t end, OptimizeFor optimize_for)
- : mode_(Mode::kRange),
- start_index_(start),
- end_index_(end),
- optimize_for_(optimize_for) {}
+ : data_(Range{start, end}), optimize_for_(optimize_for) {}
-RowMap::RowMap(BitVector bit_vector)
- : mode_(Mode::kBitVector), bit_vector_(std::move(bit_vector)) {}
+RowMap::RowMap(Variant def) : data_(std::move(def)) {}
-RowMap::RowMap(std::vector<uint32_t> vec)
- : mode_(Mode::kIndexVector), index_vector_(std::move(vec)) {}
+RowMap::RowMap(Range r) : data_(r) {}
+
+// Creates a RowMap backed by a BitVector.
+RowMap::RowMap(BitVector bit_vector) : data_(std::move(bit_vector)) {}
+
+// Creates a RowMap backed by an std::vector<uint32_t>.
+RowMap::RowMap(IndexVector vec) : data_(vec) {}
RowMap RowMap::Copy() const {
- switch (mode_) {
- case Mode::kRange:
- return RowMap(start_index_, end_index_);
- case Mode::kBitVector:
- return RowMap(bit_vector_.Copy());
- case Mode::kIndexVector:
- return RowMap(index_vector_);
+ if (auto* range = std::get_if<Range>(&data_)) {
+ return RowMap(*range);
}
- PERFETTO_FATAL("For GCC");
+ if (auto* bv = std::get_if<BitVector>(&data_)) {
+ return RowMap(bv->Copy());
+ }
+ if (auto* vec = std::get_if<IndexVector>(&data_)) {
+ return RowMap(*vec);
+ }
+ NoVariantMatched();
}
RowMap RowMap::SelectRowsSlow(const RowMap& selector) const {
- // Pick the strategy based on the selector as there is more common code
- // between selectors of the same mode than between the RowMaps being
- // selected of the same mode.
- switch (selector.mode_) {
- case Mode::kRange:
- switch (mode_) {
- case Mode::kRange:
- return SelectRangeWithRange(start_index_, end_index_,
- selector.start_index_,
- selector.end_index_);
- case Mode::kBitVector:
- return SelectBvWithRange(bit_vector_, selector.start_index_,
- selector.end_index_);
- case Mode::kIndexVector:
- return SelectIvWithRange(index_vector_, selector.start_index_,
- selector.end_index_);
- }
- break;
- case Mode::kBitVector:
- switch (mode_) {
- case Mode::kRange:
- return SelectRangeWithBv(start_index_, end_index_,
- selector.bit_vector_);
- case Mode::kBitVector:
- return SelectBvWithBv(bit_vector_, selector.bit_vector_);
- case Mode::kIndexVector:
- return SelectIvWithBv(index_vector_, selector.bit_vector_);
- }
- break;
- case Mode::kIndexVector:
- switch (mode_) {
- case Mode::kRange:
- return SelectRangeWithIv(start_index_, end_index_,
- selector.index_vector_);
- case Mode::kBitVector:
- return SelectBvWithIv(bit_vector_, selector.index_vector_);
- case Mode::kIndexVector:
- return SelectIvWithIv(index_vector_, selector.index_vector_);
- }
- break;
- }
- PERFETTO_FATAL("For GCC");
+ return std::visit(
+ [](const auto& def, const auto& selector_def) {
+ return Select(def, selector_def);
+ },
+ data_, selector.data_);
}
+void RowMap::Intersect(const RowMap& second) {
+ data_ = std::visit(
+ [](auto& def, auto& selector_def) {
+ return IntersectInternal(def, selector_def);
+ },
+ data_, second.data_);
+}
+
+RowMap::Iterator::Iterator(const RowMap* rm) : rm_(rm) {
+ if (auto* range = std::get_if<Range>(&rm_->data_)) {
+ ordinal_ = range->start;
+ return;
+ }
+ if (auto* bv = std::get_if<BitVector>(&rm_->data_)) {
+ set_bits_it_.reset(new BitVector::SetBitsIterator(bv->IterateSetBits()));
+ return;
+ }
+}
} // namespace trace_processor
} // namespace perfetto
diff --git a/src/trace_processor/containers/row_map.h b/src/trace_processor/containers/row_map.h
index 8ab3915..283455c 100644
--- a/src/trace_processor/containers/row_map.h
+++ b/src/trace_processor/containers/row_map.h
@@ -21,6 +21,7 @@
#include <memory>
#include <optional>
+#include <variant>
#include <vector>
#include "perfetto/base/logging.h"
@@ -73,55 +74,24 @@
// more efficient than a BitVector; in this case, we will make a best effort
// switch to it but the cases where this happens is not precisely defined.
class RowMap {
- private:
- // We need to declare these iterator classes before RowMap::Iterator as it
- // depends on them. However, we don't want to make these public so keep them
- // under a special private section.
-
- // Iterator for ranged mode of RowMap.
- // This class should act as a drop-in replacement for
- // BitVector::SetBitsIterator.
- class RangeIterator {
- public:
- RangeIterator(const RowMap* rm) : rm_(rm), index_(rm->start_index_) {}
-
- void Next() { ++index_; }
-
- operator bool() const { return index_ < rm_->end_index_; }
-
- uint32_t index() const { return index_; }
-
- uint32_t ordinal() const { return index_ - rm_->start_index_; }
-
- private:
- const RowMap* rm_ = nullptr;
- uint32_t index_ = 0;
- };
-
- // Iterator for index vector mode of RowMap.
- // This class should act as a drop-in replacement for
- // BitVector::SetBitsIterator.
- class IndexVectorIterator {
- public:
- IndexVectorIterator(const RowMap* rm) : rm_(rm) {}
-
- void Next() { ++ordinal_; }
-
- operator bool() const { return ordinal_ < rm_->index_vector_.size(); }
-
- uint32_t index() const { return rm_->index_vector_[ordinal_]; }
-
- uint32_t ordinal() const { return ordinal_; }
-
- private:
- const RowMap* rm_ = nullptr;
- uint32_t ordinal_ = 0;
- };
-
public:
- // Input type.
using InputRow = uint32_t;
using OutputIndex = uint32_t;
+ using IndexVector = std::vector<OutputIndex>;
+
+ struct Range {
+ Range(OutputIndex start_index, OutputIndex end_index)
+ : start(start_index), end(end_index) {}
+ Range() : start(0), end(0) {}
+
+ OutputIndex start = 0; // This is an inclusive index.
+ OutputIndex end = 0; // This is an exclusive index.
+
+ uint32_t size() const {
+ PERFETTO_DCHECK(end >= start);
+ return end - start;
+ }
+ };
// Allows efficient iteration over the rows of a RowMap.
//
@@ -130,87 +100,72 @@
// of the RowMap on every method call.
class Iterator {
public:
- Iterator(const RowMap* rm) : rm_(rm) {
- switch (rm->mode_) {
- case Mode::kRange:
- range_it_.reset(new RangeIterator(rm));
- break;
- case Mode::kBitVector:
- set_bits_it_.reset(
- new BitVector::SetBitsIterator(rm->bit_vector_.IterateSetBits()));
- break;
- case Mode::kIndexVector:
- iv_it_.reset(new IndexVectorIterator(rm));
- break;
- }
- }
+ explicit Iterator(const RowMap* rm);
Iterator(Iterator&&) noexcept = default;
Iterator& operator=(Iterator&&) = default;
// Forwards the iterator to the next row of the RowMap.
void Next() {
- switch (rm_->mode_) {
- case Mode::kRange:
- range_it_->Next();
- break;
- case Mode::kBitVector:
- set_bits_it_->Next();
- break;
- case Mode::kIndexVector:
- iv_it_->Next();
- break;
+ if (std::get_if<Range>(&rm_->data_)) {
+ ++ordinal_;
+ } else if (std::get_if<BitVector>(&rm_->data_)) {
+ set_bits_it_->Next();
+ } else if (std::get_if<IndexVector>(&rm_->data_)) {
+ ++ordinal_;
}
}
// Returns if the iterator is still valid.
operator bool() const {
- switch (rm_->mode_) {
- case Mode::kRange:
- return *range_it_;
- case Mode::kBitVector:
- return *set_bits_it_;
- case Mode::kIndexVector:
- return *iv_it_;
+ if (auto* range = std::get_if<Range>(&rm_->data_)) {
+ return ordinal_ < range->end;
}
- PERFETTO_FATAL("For GCC");
+ if (std::get_if<BitVector>(&rm_->data_)) {
+ return bool(*set_bits_it_);
+ }
+ if (auto* vec = std::get_if<IndexVector>(&rm_->data_)) {
+ return ordinal_ < vec->size();
+ }
+ PERFETTO_FATAL("Didn't match any variant type.");
}
// Returns the index pointed to by this iterator.
OutputIndex index() const {
- switch (rm_->mode_) {
- case Mode::kRange:
- return range_it_->index();
- case Mode::kBitVector:
- return set_bits_it_->index();
- case Mode::kIndexVector:
- return iv_it_->index();
+ if (std::get_if<Range>(&rm_->data_)) {
+ return ordinal_;
}
- PERFETTO_FATAL("For GCC");
+ if (std::get_if<BitVector>(&rm_->data_)) {
+ return set_bits_it_->index();
+ }
+ if (auto* vec = std::get_if<IndexVector>(&rm_->data_)) {
+ return (*vec)[ordinal_];
+ }
+ PERFETTO_FATAL("Didn't match any variant type.");
}
// Returns the row of the index the iterator points to.
InputRow row() const {
- switch (rm_->mode_) {
- case Mode::kRange:
- return range_it_->ordinal();
- case Mode::kBitVector:
- return set_bits_it_->ordinal();
- case Mode::kIndexVector:
- return iv_it_->ordinal();
+ if (auto* range = std::get_if<Range>(&rm_->data_)) {
+ return ordinal_ - range->start;
}
- PERFETTO_FATAL("For GCC");
+ if (std::get_if<BitVector>(&rm_->data_)) {
+ return set_bits_it_->ordinal();
+ }
+ if (std::get_if<IndexVector>(&rm_->data_)) {
+ return ordinal_;
+ }
+ PERFETTO_FATAL("Didn't match any variant type.");
}
private:
Iterator(const Iterator&) = delete;
Iterator& operator=(const Iterator&) = delete;
- // Only one of the below will be non-null depending on the mode of the
- // RowMap.
- std::unique_ptr<RangeIterator> range_it_;
+ // Ordinal will not be used for BitVector based RowMap.
+ uint32_t ordinal_ = 0;
+ // Not nullptr for BitVector based RowMap.
std::unique_ptr<BitVector::SetBitsIterator> set_bits_it_;
- std::unique_ptr<IndexVectorIterator> iv_it_;
const RowMap* rm_ = nullptr;
};
@@ -228,15 +183,15 @@
// Creates a RowMap containing the range of indices between |start| and |end|
// i.e. all indices between |start| (inclusive) and |end| (exclusive).
- explicit RowMap(OutputIndex start,
- OutputIndex end,
- OptimizeFor optimize_for = OptimizeFor::kMemory);
+ RowMap(OutputIndex start,
+ OutputIndex end,
+ OptimizeFor optimize_for = OptimizeFor::kMemory);
// Creates a RowMap backed by a BitVector.
- explicit RowMap(BitVector bit_vector);
+ explicit RowMap(BitVector);
// Creates a RowMap backed by an std::vector<uint32_t>.
- explicit RowMap(std::vector<OutputIndex> vec);
+ explicit RowMap(IndexVector);
RowMap(const RowMap&) noexcept = delete;
RowMap& operator=(const RowMap&) = delete;
@@ -259,15 +214,16 @@
// Returns the size of the RowMap; that is the number of indices in the
// RowMap.
uint32_t size() const {
- switch (mode_) {
- case Mode::kRange:
- return end_index_ - start_index_;
- case Mode::kBitVector:
- return bit_vector_.CountSetBits();
- case Mode::kIndexVector:
- return static_cast<uint32_t>(index_vector_.size());
+ if (auto* range = std::get_if<Range>(&data_)) {
+ return range->size();
}
- PERFETTO_FATAL("For GCC");
+ if (auto* bv = std::get_if<BitVector>(&data_)) {
+ return bv->CountSetBits();
+ }
+ if (auto* vec = std::get_if<IndexVector>(&data_)) {
+ return static_cast<uint32_t>(vec->size());
+ }
+ NoVariantMatched();
}
// Returns whether this rowmap is empty.
@@ -275,57 +231,51 @@
// Returns the index at the given |row|.
OutputIndex Get(InputRow row) const {
- PERFETTO_DCHECK(row < size());
- switch (mode_) {
- case Mode::kRange:
- return GetRange(row);
- case Mode::kBitVector:
- return GetBitVector(row);
- case Mode::kIndexVector:
- return GetIndexVector(row);
+ if (auto* range = std::get_if<Range>(&data_)) {
+ return GetRange(*range, row);
}
- PERFETTO_FATAL("For GCC");
+ if (auto* bv = std::get_if<BitVector>(&data_)) {
+ return GetBitVector(*bv, row);
+ }
+ if (auto* vec = std::get_if<IndexVector>(&data_)) {
+ return GetIndexVector(*vec, row);
+ }
+ NoVariantMatched();
}
// Returns whether the RowMap contains the given index.
bool Contains(OutputIndex index) const {
- switch (mode_) {
- case Mode::kRange: {
- return index >= start_index_ && index < end_index_;
- }
- case Mode::kBitVector: {
- return index < bit_vector_.size() && bit_vector_.IsSet(index);
- }
- case Mode::kIndexVector: {
- auto it = std::find(index_vector_.begin(), index_vector_.end(), index);
- return it != index_vector_.end();
- }
+ if (auto* range = std::get_if<Range>(&data_)) {
+ return index >= range->start && index < range->end;
}
- PERFETTO_FATAL("For GCC");
+ if (auto* bv = std::get_if<BitVector>(&data_)) {
+ return index < bv->size() && bv->IsSet(index);
+ }
+ if (auto* vec = std::get_if<IndexVector>(&data_)) {
+ return std::find(vec->begin(), vec->end(), index) != vec->end();
+ }
+ NoVariantMatched();
}
// Returns the first row of the given |index| in the RowMap.
std::optional<InputRow> RowOf(OutputIndex index) const {
- switch (mode_) {
- case Mode::kRange: {
- if (index < start_index_ || index >= end_index_)
- return std::nullopt;
- return index - start_index_;
- }
- case Mode::kBitVector: {
- return index < bit_vector_.size() && bit_vector_.IsSet(index)
- ? std::make_optional(bit_vector_.CountSetBits(index))
- : std::nullopt;
- }
- case Mode::kIndexVector: {
- auto it = std::find(index_vector_.begin(), index_vector_.end(), index);
- return it != index_vector_.end()
- ? std::make_optional(static_cast<InputRow>(
- std::distance(index_vector_.begin(), it)))
- : std::nullopt;
- }
+ if (auto* range = std::get_if<Range>(&data_)) {
+ if (index < range->start || index >= range->end)
+ return std::nullopt;
+ return index - range->start;
}
- PERFETTO_FATAL("For GCC");
+ if (auto* bv = std::get_if<BitVector>(&data_)) {
+ return index < bv->size() && bv->IsSet(index)
+ ? std::make_optional(bv->CountSetBits(index))
+ : std::nullopt;
+ }
+ if (auto* vec = std::get_if<IndexVector>(&data_)) {
+ auto it = std::find(vec->begin(), vec->end(), index);
+ return it != vec->end() ? std::make_optional(static_cast<InputRow>(
+ std::distance(vec->begin(), it)))
+ : std::nullopt;
+ }
+ NoVariantMatched();
}
// Performs an ordered insert of the index into the current RowMap
@@ -343,34 +293,36 @@
// the RowMap is in range or BitVector mode but is a required condition for
// IndexVector mode.
void Insert(OutputIndex index) {
- switch (mode_) {
- case Mode::kRange:
- if (index == end_index_) {
- // Fast path: if we're just appending to the end of the range, we can
- // stay in range mode and just bump the end index.
- end_index_++;
- } else {
- // Slow path: the insert is somewhere else other than the end. This
- // means we need to switch to using a BitVector instead.
- bit_vector_.Resize(start_index_, false);
- bit_vector_.Resize(end_index_, true);
- *this = RowMap(std::move(bit_vector_));
-
- InsertIntoBitVector(index);
- }
- break;
- case Mode::kBitVector:
- InsertIntoBitVector(index);
- break;
- case Mode::kIndexVector: {
- PERFETTO_DCHECK(
- std::is_sorted(index_vector_.begin(), index_vector_.end()));
- auto it =
- std::upper_bound(index_vector_.begin(), index_vector_.end(), index);
- index_vector_.insert(it, index);
- break;
+ if (auto* range = std::get_if<Range>(&data_)) {
+ if (index == range->end) {
+ // Fast path: if we're just appending to the end
+ // of the range, we can stay in range mode and
+ // just bump the end index.
+ range->end++;
+ return;
}
+
+ // Slow path: the insert is somewhere else other
+ // than the end. This means we need to switch to
+ // using a BitVector instead.
+ BitVector bv;
+ bv.Resize(range->start, false);
+ bv.Resize(range->end, true);
+ InsertIntoBitVector(bv, index);
+ data_ = std::move(bv);
+ return;
}
+ if (auto* bv = std::get_if<BitVector>(&data_)) {
+ InsertIntoBitVector(*bv, index);
+ return;
+ }
+ if (auto* vec = std::get_if<IndexVector>(&data_)) {
+ PERFETTO_DCHECK(std::is_sorted(vec->begin(), vec->end()));
+ auto it = std::upper_bound(vec->begin(), vec->end(), index);
+ vec->insert(it, index);
+ return;
+ }
+ NoVariantMatched();
}
// Updates this RowMap by 'picking' the indices given by |picker|.
@@ -413,22 +365,7 @@
// if (start_index <= idx && idx < end_index)
// continue;
// Remove(idx)
- void Intersect(uint32_t start_index, uint32_t end_index) {
- if (mode_ == Mode::kRange) {
- // If both RowMaps have ranges, we can just take the smallest intersection
- // of them as the new RowMap.
- // We have this as an explicit fast path as this is very common for
- // constraints on id and sorted columns to satisfy this condition.
- start_index_ = std::max(start_index_, start_index);
- end_index_ = std::max(start_index_, std::min(end_index_, end_index));
- return;
- }
-
- // TODO(lalitm): improve efficiency of this if we end up needing it.
- Filter([start_index, end_index](OutputIndex index) {
- return index >= start_index && index < end_index;
- });
- }
+ void Intersect(const RowMap& second);
// Intersects this RowMap with |index|. If this RowMap contained |index|, then
// it will *only* contain |index|. Otherwise, it will be empty.
@@ -444,71 +381,82 @@
void Clear() { *this = RowMap(); }
template <typename Comparator = bool(uint32_t, uint32_t)>
- void StableSort(std::vector<uint32_t>* out, Comparator c) const {
- switch (mode_) {
- case Mode::kRange:
- std::stable_sort(out->begin(), out->end(),
- [this, c](uint32_t a, uint32_t b) {
- return c(GetRange(a), GetRange(b));
- });
- break;
- case Mode::kBitVector:
- std::stable_sort(out->begin(), out->end(),
- [this, c](uint32_t a, uint32_t b) {
- return c(GetBitVector(a), GetBitVector(b));
- });
- break;
- case Mode::kIndexVector:
- std::stable_sort(out->begin(), out->end(),
- [this, c](uint32_t a, uint32_t b) {
- return c(GetIndexVector(a), GetIndexVector(b));
- });
- break;
+ void StableSort(IndexVector* out, Comparator c) const {
+ if (auto* range = std::get_if<Range>(&data_)) {
+ std::stable_sort(out->begin(), out->end(),
+ [range, c](uint32_t a, uint32_t b) {
+ return c(GetRange(*range, a), GetRange(*range, b));
+ });
+ return;
}
+ if (auto* bv = std::get_if<BitVector>(&data_)) {
+ std::stable_sort(out->begin(), out->end(),
+ [&bv, c](uint32_t a, uint32_t b) {
+ return c(GetBitVector(*bv, a), GetBitVector(*bv, b));
+ });
+ return;
+ }
+ if (auto* vec = std::get_if<IndexVector>(&data_)) {
+ std::stable_sort(
+ out->begin(), out->end(), [vec, c](uint32_t a, uint32_t b) {
+ return c(GetIndexVector(*vec, a), GetIndexVector(*vec, b));
+ });
+ return;
+ }
+ NoVariantMatched();
}
// Filters the indices in |out| by keeping those which meet |p|.
template <typename Predicate = bool(OutputIndex)>
void Filter(Predicate p) {
- switch (mode_) {
- case Mode::kRange:
- FilterRange(p);
- break;
- case Mode::kBitVector: {
- for (auto it = bit_vector_.IterateSetBits(); it; it.Next()) {
- if (!p(it.index()))
- it.Clear();
- }
- break;
- }
- case Mode::kIndexVector: {
- auto ret = std::remove_if(index_vector_.begin(), index_vector_.end(),
- [p](uint32_t i) { return !p(i); });
- index_vector_.erase(ret, index_vector_.end());
- break;
- }
+ if (auto* range = std::get_if<Range>(&data_)) {
+ data_ = FilterRange(p, *range);
+ return;
}
+ if (auto* bv = std::get_if<BitVector>(&data_)) {
+ for (auto it = bv->IterateSetBits(); it; it.Next()) {
+ if (!p(it.index()))
+ it.Clear();
+ }
+ return;
+ }
+ if (auto* vec = std::get_if<IndexVector>(&data_)) {
+ auto ret = std::remove_if(vec->begin(), vec->end(),
+ [p](uint32_t i) { return !p(i); });
+ vec->erase(ret, vec->end());
+ return;
+ }
+ NoVariantMatched();
}
// Returns the iterator over the rows in this RowMap.
Iterator IterateRows() const { return Iterator(this); }
// Returns if the RowMap is internally represented using a range.
- bool IsRange() const { return mode_ == Mode::kRange; }
+ bool IsRange() const { return std::holds_alternative<Range>(data_); }
+
+ // Returns if the RowMap is internally represented using a BitVector.
+ bool IsBitVector() const { return std::holds_alternative<BitVector>(data_); }
+
+ // Returns if the RowMap is internally represented using an index vector.
+ bool IsIndexVector() const {
+ return std::holds_alternative<IndexVector>(data_);
+ }
private:
- enum class Mode {
- kRange,
- kBitVector,
- kIndexVector,
- };
+ using Variant = std::variant<Range, BitVector, IndexVector>;
+
+ explicit RowMap(Range);
+
+ explicit RowMap(Variant);
+
// TODO(lalitm): remove this when the coupling between RowMap and
// ColumnStorage Selector is broken (after filtering is moved out of here).
friend class ColumnStorageOverlay;
template <typename Predicate>
- void FilterRange(Predicate p) {
- uint32_t count = end_index_ - start_index_;
+ Variant FilterRange(Predicate p, Range r) {
+ uint32_t count = r.size();
// Optimization: if we are only going to scan a few indices, it's not
// worth the haslle of working with a BitVector.
@@ -517,7 +465,7 @@
// Optimization: weif the cost of a BitVector is more than the highest
// possible cost an index vector could have, use the index vector.
- uint32_t bit_vector_cost = BitVector::ApproxBytesCost(end_index_);
+ uint32_t bit_vector_cost = BitVector::ApproxBytesCost(r.end);
uint32_t index_vector_cost_ub = sizeof(uint32_t) * count;
// If either of the conditions hold which make it better to use an
@@ -527,7 +475,7 @@
optimize_for_ == OptimizeFor::kLookupSpeed) {
// Try and strike a good balance between not making the vector too
// big and good performance.
- std::vector<uint32_t> iv(std::min(kSmallRangeLimit, count));
+ IndexVector iv(std::min(kSmallRangeLimit, count));
uint32_t out_i = 0;
for (uint32_t i = 0; i < count; ++i) {
@@ -537,8 +485,8 @@
// We keep this branch free by always writing the index but only
// incrementing the out index if the return value is true.
- bool value = p(i + start_index_);
- iv[out_i] = i + start_index_;
+ bool value = p(i + r.start);
+ iv[out_i] = i + r.start;
out_i += value;
}
@@ -546,58 +494,44 @@
iv.resize(out_i);
iv.shrink_to_fit();
- *this = RowMap(std::move(iv));
- return;
+ return std::move(iv);
}
// Otherwise, create a bitvector which spans the full range using
// |p| as the filler for the bits between start and end.
- *this = RowMap(BitVector::Range(start_index_, end_index_, p));
+ return BitVector::Range(r.start, r.end, p);
}
- void InsertIntoBitVector(uint32_t row) {
- PERFETTO_DCHECK(mode_ == Mode::kBitVector);
-
- // If we're adding a row to precisely the end of the BitVector, just append
- // true instead of resizing and then setting.
- if (row == bit_vector_.size()) {
- bit_vector_.AppendTrue();
- return;
- }
-
- if (row > bit_vector_.size()) {
- bit_vector_.Resize(row + 1, false);
- }
- bit_vector_.Set(row);
+ PERFETTO_ALWAYS_INLINE static OutputIndex GetRange(Range r, InputRow row) {
+ return r.start + row;
}
-
- PERFETTO_ALWAYS_INLINE OutputIndex GetRange(InputRow row) const {
- PERFETTO_DCHECK(mode_ == Mode::kRange);
- return start_index_ + row;
+ PERFETTO_ALWAYS_INLINE static OutputIndex GetBitVector(const BitVector& bv,
+ uint32_t row) {
+ return bv.IndexOfNthSet(row);
}
- PERFETTO_ALWAYS_INLINE OutputIndex GetBitVector(uint32_t row) const {
- PERFETTO_DCHECK(mode_ == Mode::kBitVector);
- return bit_vector_.IndexOfNthSet(row);
- }
- PERFETTO_ALWAYS_INLINE OutputIndex GetIndexVector(uint32_t row) const {
- PERFETTO_DCHECK(mode_ == Mode::kIndexVector);
- return index_vector_[row];
+ PERFETTO_ALWAYS_INLINE static OutputIndex GetIndexVector(
+ const IndexVector& vec,
+ uint32_t row) {
+ return vec[row];
}
RowMap SelectRowsSlow(const RowMap& selector) const;
- Mode mode_ = Mode::kRange;
+ static void InsertIntoBitVector(BitVector& bv, OutputIndex row) {
+ if (row == bv.size()) {
+ bv.AppendTrue();
+ return;
+ }
+ if (row > bv.size())
+ bv.Resize(row + 1, false);
+ bv.Set(row);
+ }
- // Only valid when |mode_| == Mode::kRange.
- OutputIndex start_index_ = 0; // This is an inclusive index.
- OutputIndex end_index_ = 0; // This is an exclusive index.
+ PERFETTO_NORETURN void NoVariantMatched() const {
+ PERFETTO_FATAL("Didn't match any variant type.");
+ }
- // Only valid when |mode_| == Mode::kBitVector.
- BitVector bit_vector_;
-
- // Only valid when |mode_| == Mode::kIndexVector.
- std::vector<OutputIndex> index_vector_;
-
+ Variant data_;
OptimizeFor optimize_for_ = OptimizeFor::kMemory;
};
diff --git a/src/trace_processor/containers/row_map_unittest.cc b/src/trace_processor/containers/row_map_unittest.cc
index 6e1ca11..7f919bd 100644
--- a/src/trace_processor/containers/row_map_unittest.cc
+++ b/src/trace_processor/containers/row_map_unittest.cc
@@ -25,6 +25,191 @@
namespace trace_processor {
namespace {
+TEST(RowMapUnittest, SingleRow) {
+ RowMap rm(10, 20);
+ RowMap rm_row = rm.SingleRow(15u);
+ ASSERT_EQ(rm_row.size(), 1u);
+ ASSERT_TRUE(rm_row.Contains(15));
+ ASSERT_FALSE(rm_row.Contains(11));
+}
+
+TEST(RowMapUnittest, CopyRange) {
+ RowMap rm(10, 20);
+ RowMap rm_copy = rm.Copy();
+ ASSERT_EQ(rm_copy.size(), 10u);
+}
+
+TEST(RowMapUnittest, CopyBitVector) {
+ RowMap rm(BitVector{true, false, false, false, true, true});
+ RowMap rm_copy = rm.Copy();
+ ASSERT_EQ(rm_copy.size(), 3u);
+}
+
+TEST(RowMapUnittest, CopyIndexVector) {
+ RowMap rm(std::vector<uint32_t>{10, 17, 20, 21});
+ RowMap rm_copy = rm.Copy();
+ ASSERT_EQ(rm_copy.size(), 4u);
+}
+
+TEST(RowMapUnittest, GetFromRange) {
+ RowMap rm(10, 20);
+ ASSERT_EQ(rm.Get(5), 15u);
+}
+
+TEST(RowMapUnittest, GetFromBitVector) {
+ RowMap rm(BitVector{true, false, false, false, true, true});
+ ASSERT_EQ(rm.Get(1), 4u);
+}
+
+TEST(RowMapUnittest, GetFromIndexVector) {
+ RowMap rm(std::vector<uint32_t>{10, 17, 20, 21});
+ ASSERT_EQ(rm.Get(1), 17u);
+}
+
+TEST(RowMapUnittest, ContainsFromRange) {
+ RowMap rm(10, 20);
+ ASSERT_FALSE(rm.Contains(5));
+ ASSERT_TRUE(rm.Contains(15));
+}
+
+TEST(RowMapUnittest, ContainsFromBitVector) {
+ RowMap rm(BitVector{true, false, false, false, true, true});
+ ASSERT_FALSE(rm.Contains(3));
+ ASSERT_TRUE(rm.Contains(5));
+}
+
+TEST(RowMapUnittest, ContainsFromIndexVector) {
+ RowMap rm(std::vector<uint32_t>{10, 17, 20, 21});
+ ASSERT_FALSE(rm.Contains(5));
+ ASSERT_TRUE(rm.Contains(10));
+}
+
+TEST(RowMapUnittest, RowOfRange) {
+ RowMap rm(10, 20);
+ ASSERT_EQ(rm.RowOf(15).value(), 5u);
+ ASSERT_EQ(rm.RowOf(5), std::nullopt);
+}
+
+TEST(RowMapUnittest, RowOfBitVector) {
+ RowMap rm(BitVector{true, false, false, false, true, true});
+ ASSERT_EQ(rm.RowOf(4), 1u);
+ ASSERT_EQ(rm.RowOf(1), std::nullopt);
+}
+
+TEST(RowMapUnittest, RowOfIndexVector) {
+ RowMap rm(std::vector<uint32_t>{10, 17, 20, 21});
+ ASSERT_EQ(rm.RowOf(17), 1u);
+ ASSERT_EQ(rm.RowOf(5), std::nullopt);
+}
+
+TEST(RowMapUnittest, InsertIntoRangeAtTheEnd) {
+ RowMap rm(10, 20);
+ rm.Insert(21);
+ ASSERT_EQ(rm.size(), 11u);
+ ASSERT_TRUE(rm.Contains(21));
+}
+
+TEST(RowMapUnittest, InsertIntoRange) {
+ RowMap rm(10, 20);
+ rm.Insert(25);
+ ASSERT_EQ(rm.size(), 11u);
+ ASSERT_TRUE(rm.Contains(25));
+}
+
+TEST(RowMapUnittest, InsertIntoBitVector) {
+ RowMap rm(BitVector{true, false, false, false, true, true});
+ rm.Insert(25);
+ ASSERT_EQ(rm.size(), 4u);
+ ASSERT_TRUE(rm.Contains(25));
+}
+
+TEST(RowMapUnittest, InsertIntoIndexVector) {
+ RowMap rm(std::vector<uint32_t>{10, 17, 20, 21});
+ rm.Insert(25);
+ ASSERT_EQ(rm.size(), 5u);
+ ASSERT_TRUE(rm.Contains(25));
+}
+
+TEST(RowMapUnittest, SelectRowsFromRangeWithRange) {
+ RowMap rm(10, 20);
+
+ RowMap selector(4, 8);
+ RowMap selected = rm.SelectRows(selector);
+ ASSERT_EQ(selected.size(), 4u);
+ ASSERT_EQ(selected.Get(0), 14u);
+}
+
+TEST(RowMapUnittest, SelectRowsFromRangeWithBV) {
+ RowMap rm(10, 20);
+ // BitVector with values at 16, 18, 20 and so on.
+ RowMap selector(
+ BitVector::Range(4, 8, [](uint32_t x) { return x % 2 == 0; }));
+ RowMap selected = rm.SelectRows(selector);
+ ASSERT_EQ(selected.size(), 2u);
+ ASSERT_EQ(selected.Get(0), 14u);
+}
+
+TEST(RowMapUnittest, SelectRowsFromRangeWithIV) {
+ RowMap rm(10, 20);
+ RowMap selector(std::vector<uint32_t>{4, 6});
+ RowMap selected = rm.SelectRows(selector);
+ ASSERT_EQ(selected.size(), 2u);
+ ASSERT_EQ(selected.Get(0), 14u);
+}
+
+TEST(RowMapUnittest, SelectRowsFromBVWithRange) {
+ RowMap rm(BitVector::Range(10, 50, [](uint32_t x) { return x % 2 == 0; }));
+
+ RowMap selector(4, 8);
+ RowMap selected = rm.SelectRows(selector);
+ ASSERT_EQ(selected.size(), 4u);
+ ASSERT_EQ(selected.Get(0), 18u);
+}
+
+TEST(RowMapUnittest, SelectRowsFromBVWithBV) {
+ RowMap rm(BitVector::Range(10, 50, [](uint32_t x) { return x % 2 == 0; }));
+ // BitVector with values at 16, 18, 20 and so on.
+ RowMap selector(
+ BitVector::Range(4, 8, [](uint32_t x) { return x % 2 == 0; }));
+ RowMap selected = rm.SelectRows(selector);
+ ASSERT_EQ(selected.size(), 2u);
+ ASSERT_EQ(selected.Get(0), 18u);
+}
+
+TEST(RowMapUnittest, SelectRowsFromBVWithIV) {
+ RowMap rm(BitVector::Range(10, 50, [](uint32_t x) { return x % 2 == 0; }));
+ RowMap selector(std::vector<uint32_t>{4, 6});
+ RowMap selected = rm.SelectRows(selector);
+ ASSERT_EQ(selected.size(), 2u);
+ ASSERT_EQ(selected.Get(0), 18u);
+}
+
+TEST(RowMapUnittest, SelectRowsFromIVWithRange) {
+ RowMap rm(std::vector<uint32_t>{10, 12, 14, 16, 18, 20, 22, 24});
+
+ RowMap selector(4, 8);
+ RowMap selected = rm.SelectRows(selector);
+ ASSERT_EQ(selected.size(), 4u);
+ ASSERT_EQ(selected.Get(0), 18u);
+}
+
+TEST(RowMapUnittest, SelectRowsFromIVWithBV) {
+ RowMap rm(std::vector<uint32_t>{10, 12, 14, 16, 18, 20, 22, 24});
+ RowMap selector(
+ BitVector::Range(4, 8, [](uint32_t x) { return x % 2 == 0; }));
+ RowMap selected = rm.SelectRows(selector);
+ ASSERT_EQ(selected.size(), 2u);
+ ASSERT_EQ(selected.Get(0), 18u);
+}
+
+TEST(RowMapUnittest, SelectRowsFromIVWithIV) {
+ RowMap rm(std::vector<uint32_t>{10, 12, 14, 16, 18, 20, 22, 24});
+ RowMap selector(std::vector<uint32_t>{4, 6});
+ RowMap selected = rm.SelectRows(selector);
+ ASSERT_EQ(selected.size(), 2u);
+ ASSERT_EQ(selected.Get(0), 18u);
+}
+
TEST(RowMapUnittest, SmokeRange) {
RowMap rm(30, 47);
@@ -327,22 +512,86 @@
ASSERT_EQ(rm.size(), 0u);
}
-TEST(RowMapUnittest, IntersectManyRange) {
+TEST(RowMapUnittest, IntersectRangeWithRange) {
RowMap rm(3, 7);
- rm.Intersect(2, 4);
+ RowMap sec(2, 4);
+ rm.Intersect(sec);
ASSERT_EQ(rm.size(), 1u);
ASSERT_EQ(rm.Get(0u), 3u);
}
-TEST(RowMapUnittest, IntersectManyIv) {
- RowMap rm(std::vector<uint32_t>{3u, 2u, 0u, 1u, 1u, 3u});
- rm.Intersect(2, 4);
+TEST(RowMapUnittest, IntersectRangeWithBV) {
+ RowMap rm(2, 4);
+ RowMap sec(BitVector{true, false, true, true, false, true});
+ rm.Intersect(sec);
+
+ ASSERT_EQ(rm.size(), 2u);
+ ASSERT_EQ(rm.Get(0), 2u);
+}
+
+TEST(RowMapUnittest, IntersectRangeWithIV) {
+ RowMap rm(2, 10);
+ RowMap sec(std::vector<uint32_t>{0, 2, 5});
+ rm.Intersect(sec);
+
+ ASSERT_EQ(rm.size(), 2u);
+ ASSERT_EQ(rm.Get(0u), 2u);
+}
+
+TEST(RowMapUnittest, IntersectBVWithRange) {
+ RowMap rm(BitVector{true, false, true, true, false, true});
+ RowMap sec(2, 4);
+ rm.Intersect(sec);
+
+ ASSERT_EQ(rm.size(), 2u);
+ ASSERT_EQ(rm.Get(0), 2u);
+}
+
+TEST(RowMapUnittest, IntersectBVWithBV) {
+ RowMap rm(BitVector{true, false, true, true, false, true});
+ RowMap sec(BitVector{false, true, true, false, false, true, true});
+ rm.Intersect(sec);
+
+ ASSERT_EQ(rm.size(), 2u);
+ ASSERT_EQ(rm.Get(0), 2u);
+}
+
+TEST(RowMapUnittest, IntersectBVWithIV) {
+ RowMap rm(BitVector{true, false, true, true, false, true});
+ RowMap sec(std::vector<uint32_t>{0, 2, 5});
+ rm.Intersect(sec);
ASSERT_EQ(rm.size(), 3u);
- ASSERT_EQ(rm.Get(0u), 3u);
- ASSERT_EQ(rm.Get(1u), 2u);
- ASSERT_EQ(rm.Get(2u), 3u);
+ ASSERT_EQ(rm.Get(0), 0u);
+}
+
+TEST(RowMapUnittest, IntersectIVWithRange) {
+ RowMap rm(std::vector<uint32_t>{0, 2, 5});
+ RowMap sec(2, 10);
+ rm.Intersect(sec);
+
+ ASSERT_EQ(rm.size(), 2u);
+ ASSERT_EQ(rm.Get(0u), 2u);
+}
+
+TEST(RowMapUnittest, IntersectIVWithBV) {
+ RowMap rm(std::vector<uint32_t>{0, 2, 5});
+ RowMap sec(BitVector{true, false, true, true, false, true});
+ rm.Intersect(sec);
+
+ ASSERT_EQ(rm.size(), 3u);
+ ASSERT_EQ(rm.Get(0), 0u);
+}
+
+TEST(RowMapUnittest, IntersectIVWithIV) {
+ RowMap rm(std::vector<uint32_t>{0, 2, 5});
+ RowMap sec(std::vector<uint32_t>{1, 2, 6});
+
+ rm.Intersect(sec);
+
+ ASSERT_EQ(rm.size(), 1u);
+ ASSERT_EQ(rm.Get(0u), 2u);
}
} // namespace
diff --git a/src/trace_processor/db/column.h b/src/trace_processor/db/column.h
index 04425b9..a97d6e4 100644
--- a/src/trace_processor/db/column.h
+++ b/src/trace_processor/db/column.h
@@ -545,31 +545,31 @@
b, std::lower_bound(b, e, value, &compare::SqlValueComparator));
uint32_t end = std::distance(
b, std::upper_bound(b, e, value, &compare::SqlValueComparator));
- rm->Intersect(beg, end);
+ rm->Intersect({beg, end});
return true;
}
case FilterOp::kLe: {
uint32_t end = std::distance(
b, std::upper_bound(b, e, value, &compare::SqlValueComparator));
- rm->Intersect(0, end);
+ rm->Intersect({0, end});
return true;
}
case FilterOp::kLt: {
uint32_t end = std::distance(
b, std::lower_bound(b, e, value, &compare::SqlValueComparator));
- rm->Intersect(0, end);
+ rm->Intersect({0, end});
return true;
}
case FilterOp::kGe: {
uint32_t beg = std::distance(
b, std::lower_bound(b, e, value, &compare::SqlValueComparator));
- rm->Intersect(beg, overlay().size());
+ rm->Intersect({beg, overlay().size()});
return true;
}
case FilterOp::kGt: {
uint32_t beg = std::distance(
b, std::upper_bound(b, e, value, &compare::SqlValueComparator));
- rm->Intersect(beg, overlay().size());
+ rm->Intersect({beg, overlay().size()});
return true;
}
case FilterOp::kNe:
@@ -608,11 +608,13 @@
// Otherwise, find the end of the set and return the intersection for this.
for (uint32_t i = set_id + 1; i < ov.size(); ++i) {
if (st.Get(ov.Get(i)) != filter_set_id) {
- rm->Intersect(set_id, i);
+ RowMap r(set_id, i);
+ rm->Intersect(r);
return;
}
}
- rm->Intersect(set_id, ov.size());
+ RowMap r(set_id, ov.size());
+ rm->Intersect(r);
}
// Slow path filter method which will perform a full table scan.
diff --git a/src/trace_processor/db/column_storage_overlay.h b/src/trace_processor/db/column_storage_overlay.h
index 108dccd..997d4be 100644
--- a/src/trace_processor/db/column_storage_overlay.h
+++ b/src/trace_processor/db/column_storage_overlay.h
@@ -183,24 +183,12 @@
// meet |p|. However, if |this| is a BitVector, we end up needing expensive
// |IndexOfNthSet| calls (as we need to convert the row to an index before
// passing it to |p|).
- switch (row_map_.mode_) {
- case RowMap::Mode::kRange: {
- auto ip = [this, p](uint32_t row) { return p(row_map_.GetRange(row)); };
- out->Filter(ip);
- break;
- }
- case RowMap::Mode::kBitVector: {
- FilterIntoScanSelfBv(out, p);
- break;
- }
- case RowMap::Mode::kIndexVector: {
- auto ip = [this, p](uint32_t row) {
- return p(row_map_.GetIndexVector(row));
- };
- out->Filter(ip);
- break;
- }
+ if (row_map_.IsBitVector()) {
+ FilterIntoScanSelfBv(out, p);
+ return;
}
+ auto ip = [this, p](uint32_t row) { return p(row_map_.Get(row)); };
+ out->Filter(ip);
}
template <typename Comparator = bool(uint32_t, uint32_t)>
@@ -217,54 +205,57 @@
// Filters the current ColumnStorageOverlay into |out| by performing a full
// scan on |row_map.bit_vector_|. See |FilterInto| for a full breakdown of the
// semantics of this function.
- template <typename Predicate>
- void FilterIntoScanSelfBv(RowMap* out, Predicate p) const {
- auto it = row_map_.bit_vector_.IterateSetBits();
- switch (out->mode_) {
- case RowMap::Mode::kRange: {
- // TODO(lalitm): investigate whether we can reuse the data inside
- // out->bit_vector_ at some point.
- BitVector bv(out->end_index_, false);
- for (auto out_it = bv.IterateAllBits(); it; it.Next(), out_it.Next()) {
- uint32_t ordinal = it.ordinal();
- if (ordinal < out->start_index_)
- continue;
- if (ordinal >= out->end_index_)
- break;
- if (p(it.index())) {
- out_it.Set();
- }
+ template <typename Predicate>
+ struct FilterIntoScanSelfBvVisitor {
+ void operator()(RowMap::Range out_r) {
+ BitVector bv(out_r.end, false);
+ for (auto out_it = bv.IterateAllBits(); bv_iter;
+ bv_iter.Next(), out_it.Next()) {
+ uint32_t ordinal = bv_iter.ordinal();
+ if (ordinal < out_r.start)
+ continue;
+ if (ordinal >= out_r.end)
+ break;
+
+ if (p(bv_iter.index())) {
+ out_it.Set();
}
- *out = RowMap(std::move(bv));
- break;
}
- case RowMap::Mode::kBitVector: {
- auto out_it = out->bit_vector_.IterateAllBits();
- for (; out_it; it.Next(), out_it.Next()) {
- PERFETTO_DCHECK(it);
- if (out_it.IsSet() && !p(it.index()))
- out_it.Clear();
- }
- break;
- }
- case RowMap::Mode::kIndexVector: {
- PERFETTO_DCHECK(std::is_sorted(out->index_vector_.begin(),
- out->index_vector_.end()));
- auto fn = [&p, &it](uint32_t i) {
- while (it.ordinal() < i) {
- it.Next();
- PERFETTO_DCHECK(it);
- }
- PERFETTO_DCHECK(it.ordinal() == i);
- return !p(it.index());
- };
- auto iv_it = std::remove_if(out->index_vector_.begin(),
- out->index_vector_.end(), fn);
- out->index_vector_.erase(iv_it, out->index_vector_.end());
- break;
+ *out = RowMap(std::move(bv));
+ }
+ void operator()(const BitVector& out_bv) {
+ auto out_it = out_bv.IterateAllBits();
+ for (; out_it; bv_iter.Next(), out_it.Next()) {
+ PERFETTO_DCHECK(bv_iter);
+ if (out_it.IsSet() && !p(bv_iter.index()))
+ out_it.Clear();
}
}
+ void operator()(std::vector<OutputIndex>& out_vec) {
+ PERFETTO_DCHECK(std::is_sorted(out_vec.begin(), out_vec.end()));
+ auto fn = [this](uint32_t i) {
+ while (bv_iter.ordinal() < i) {
+ bv_iter.Next();
+ PERFETTO_DCHECK(bv_iter);
+ }
+ PERFETTO_DCHECK(bv_iter.ordinal() == i);
+ return !p(bv_iter.index());
+ };
+ auto iv_it = std::remove_if(out_vec.begin(), out_vec.end(), fn);
+ out_vec.erase(iv_it, out_vec.end());
+ }
+ RowMap* out;
+ Predicate p;
+ internal::SetBitsIterator bv_iter;
+ };
+
+ template <typename Predicate>
+ void FilterIntoScanSelfBv(RowMap* out, Predicate p) const {
+ const BitVector* bv = std::get_if<BitVector>(&row_map_.data_);
+ auto it = bv->IterateSetBits();
+ std::visit(FilterIntoScanSelfBvVisitor<Predicate>{out, p, std::move(it)},
+ out->data_);
}
RowMap row_map_;