blob: b10d0cba00c68613ad500a500765b7dd2cec786d [file] [log] [blame]
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "src/trace_processor/containers/row_map.h"
namespace perfetto {
namespace trace_processor {
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);
return RowMap(start + selector_start, start + selector_end);
}
RowMap SelectRangeWithBv(uint32_t start,
uint32_t end,
const BitVector& selector) {
PERFETTO_DCHECK(start <= end);
PERFETTO_DCHECK(end - start == selector.size());
// If |start| == 0 and |end - start| == |selector.size()| (which is a
// precondition for this function), the BitVector we generate is going to be
// exactly |selector|.
//
// This is a fast path for the common situation where, post-filtering,
// 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)
return RowMap(selector.Copy());
BitVector bv(start, false);
bv.Resize(end, 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);
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;
}
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.GetNumBitsSet());
BitVector ret = bv.Copy();
for (auto it = ret.IterateSetBits(); it; it.Next()) {
auto set_idx = it.ordinal();
if (set_idx < selector_start || set_idx >= selector_end)
it.Clear();
}
return RowMap(std::move(ret));
}
RowMap SelectBvWithBv(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) {
std::vector<uint32_t> iv(selector.size());
for (uint32_t i = 0; i < selector.size(); ++i) {
// TODO(lalitm): this is pretty inefficient.
iv[i] = bv.IndexOfNthSet(selector[i]);
}
return RowMap(std::move(iv));
}
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());
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];
}
return RowMap(std::move(ret));
}
RowMap SelectIvWithBv(const std::vector<uint32_t>& iv,
const BitVector& selector) {
std::vector<uint32_t> copy = iv;
uint32_t idx = 0;
auto it = std::remove_if(
copy.begin(), copy.end(),
[&idx, &selector](uint32_t) { return !selector.IsSet(idx++); });
copy.erase(it, copy.end());
return RowMap(std::move(copy));
}
RowMap SelectIvWithIv(const std::vector<uint32_t>& iv,
const std::vector<uint32_t>& selector) {
std::vector<uint32_t> ret(selector.size());
for (uint32_t i = 0; i < selector.size(); ++i) {
PERFETTO_DCHECK(selector[i] < iv.size());
ret[i] = iv[selector[i]];
}
return RowMap(std::move(ret));
}
} // namespace
RowMap::RowMap() : RowMap(0, 0) {}
RowMap::RowMap(uint32_t start, uint32_t end)
: mode_(Mode::kRange), start_idx_(start), end_idx_(end) {}
RowMap::RowMap(BitVector bit_vector)
: mode_(Mode::kBitVector), bit_vector_(std::move(bit_vector)) {}
RowMap::RowMap(std::vector<uint32_t> vec)
: mode_(Mode::kIndexVector), index_vector_(std::move(vec)) {}
RowMap RowMap::Copy() const {
switch (mode_) {
case Mode::kRange:
return RowMap(start_idx_, end_idx_);
case Mode::kBitVector:
return RowMap(bit_vector_.Copy());
case Mode::kIndexVector:
return RowMap(index_vector_);
}
PERFETTO_FATAL("For GCC");
}
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_idx_, end_idx_, selector.start_idx_,
selector.end_idx_);
case Mode::kBitVector:
return SelectBvWithRange(bit_vector_, selector.start_idx_,
selector.end_idx_);
case Mode::kIndexVector:
return SelectIvWithRange(index_vector_, selector.start_idx_,
selector.end_idx_);
}
break;
case Mode::kBitVector:
switch (mode_) {
case Mode::kRange:
return SelectRangeWithBv(start_idx_, end_idx_, 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_idx_, end_idx_,
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");
}
} // namespace trace_processor
} // namespace perfetto