blob: 3ecb3179ec7e08c5ea432f6f8fa6951f65ee5a4b [file] [log] [blame]
/*
* Copyright (C) 2023 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/db/overlays/null_overlay.h"
#include "perfetto/ext/base/flat_hash_map.h"
#include "src/trace_processor/db/overlays/types.h"
namespace perfetto {
namespace trace_processor {
namespace overlays {
using Range = RowMap::Range;
StorageRange NullOverlay::MapToStorageRange(TableRange t_range) const {
uint32_t start = non_null_->CountSetBits(t_range.range.start);
uint32_t end = non_null_->CountSetBits(t_range.range.end);
return StorageRange({Range(start, end)});
}
TableBitVector NullOverlay::MapToTableBitVector(StorageBitVector s_bv,
OverlayOp op) const {
BitVector res = non_null_->Copy();
res.UpdateSetBits(s_bv.bv);
if (op != OverlayOp::kIsNull)
return {std::move(res)};
if (res.CountSetBits() == 0)
return {non_null_->Not()};
BitVector not_non_null = non_null_->Not();
res.Or(not_non_null);
return {std::move(res)};
}
BitVector NullOverlay::IsStorageLookupRequired(
OverlayOp op,
const TableIndexVector& t_iv) const {
PERFETTO_DCHECK(t_iv.indices.size() <= non_null_->size());
if (op != OverlayOp::kOther)
return BitVector(t_iv.size(), false);
BitVector in_storage(static_cast<uint32_t>(t_iv.indices.size()), false);
// For each index in TableIndexVector check whether this index is in storage.
for (uint32_t i = 0; i < t_iv.indices.size(); ++i) {
if (non_null_->IsSet(t_iv.indices[i]))
in_storage.Set(i);
}
return in_storage;
}
StorageIndexVector NullOverlay::MapToStorageIndexVector(
TableIndexVector t_iv_with_idx_in_storage) const {
PERFETTO_DCHECK(t_iv_with_idx_in_storage.indices.size() <=
non_null_->CountSetBits());
std::vector<uint32_t> storage_index_vector;
storage_index_vector.reserve(t_iv_with_idx_in_storage.indices.size());
for (auto t_idx : t_iv_with_idx_in_storage.indices) {
storage_index_vector.push_back(non_null_->CountSetBits(t_idx));
}
return StorageIndexVector({std::move(storage_index_vector)});
}
BitVector NullOverlay::IndexSearch(
OverlayOp op,
const TableIndexVector& t_iv_overlay_idx) const {
if (op == OverlayOp::kOther)
return BitVector(t_iv_overlay_idx.size(), false);
BitVector res(static_cast<uint32_t>(t_iv_overlay_idx.indices.size()), false);
if (op == OverlayOp::kIsNull) {
for (uint32_t i = 0; i < res.size(); ++i) {
if (!non_null_->IsSet(t_iv_overlay_idx.indices[i]))
res.Set(i);
}
return res;
}
PERFETTO_DCHECK(op == OverlayOp::kIsNotNull);
for (uint32_t i = 0; i < res.size(); ++i) {
if (non_null_->IsSet(t_iv_overlay_idx.indices[i]))
res.Set(i);
}
return res;
}
CostEstimatePerRow NullOverlay::EstimateCostPerRow(OverlayOp op) const {
// TODO(b/283763282): Replace with benchmarked data.
CostEstimatePerRow res;
// Two |BitVector::CountSetBits| calls.
res.to_storage_range = 100;
// Cost of |BitVector::UpdateSetBits|
res.to_table_bit_vector = 100;
if (op == OverlayOp::kOther) {
// Cost of |BitVector::IsSet| and |BitVector::Set|
res.is_storage_search_required = 10;
// Cost of iterating all set bits and looping the index vector divided by
// number of indices.
res.map_to_storage_index_vector = 100;
// Won't be called.
res.index_search = 0;
} else {
// Cost of creating trivial BitVector.
res.is_storage_search_required = 0;
// Won't be called
res.map_to_storage_index_vector = 0;
// Cost of calling |BitVector::IsSet|
res.index_search = 10;
}
return res;
}
} // namespace overlays
} // namespace trace_processor
} // namespace perfetto