blob: ff17f91d8537d0c3aba661fcb97a94fb61b701f5 [file] [log] [blame]
/*
* Copyright (C) 2020 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/dynamic/ancestor_slice_generator.h"
#include <memory>
#include <set>
#include "src/trace_processor/types/trace_processor_context.h"
namespace perfetto {
namespace trace_processor {
AncestorSliceGenerator::AncestorSliceGenerator(TraceProcessorContext* context)
: context_(context) {}
AncestorSliceGenerator::~AncestorSliceGenerator() = default;
util::Status AncestorSliceGenerator::ValidateConstraints(
const QueryConstraints& qc) {
const auto& cs = qc.constraints();
auto slice_id_fn = [this](const QueryConstraints::Constraint& c) {
return c.column == static_cast<int>(
context_->storage->slice_table().GetColumnCount()) &&
c.op == SQLITE_INDEX_CONSTRAINT_EQ;
};
bool has_slice_id_cs =
std::find_if(cs.begin(), cs.end(), slice_id_fn) != cs.end();
return has_slice_id_cs
? util::OkStatus()
: util::ErrStatus("Failed to find required constraints");
}
std::unique_ptr<Table> AncestorSliceGenerator::ComputeTable(
const std::vector<Constraint>& cs,
const std::vector<Order>&) {
using S = tables::SliceTable;
auto it = std::find_if(cs.begin(), cs.end(), [this](const Constraint& c) {
return c.col_idx == context_->storage->slice_table().GetColumnCount() &&
c.op == FilterOp::kEq;
});
PERFETTO_DCHECK(it != cs.end());
const auto& slice = context_->storage->slice_table();
uint32_t child_id = static_cast<uint32_t>(it->value.AsLong());
auto start_row = slice.id().IndexOf(S::Id(child_id));
if (!start_row) {
// TODO(lalitm): Ideally this should result in an error, or be filtered out
// during ValidateConstraints so we can just dereference |start_row|
// directly. However ValidateConstraints doesn't know the value we're
// filtering for so can't ensure it exists. For now we return a nullptr
// which will cause the query to surface an error with the message "SQL
// error: constraint failed".
return nullptr;
}
// Build up all the parents row ids, and a new column that includes the
// constraint.
std::vector<uint32_t> ids;
std::unique_ptr<NullableVector<uint32_t>> child_ids(
new NullableVector<uint32_t>());
auto maybe_parent_id = slice.parent_id()[*start_row];
while (maybe_parent_id) {
ids.push_back(maybe_parent_id.value().value);
child_ids->Append(child_id);
// Update the loop variable by looking up the next parent_id.
maybe_parent_id = slice.parent_id()[*slice.id().IndexOf(*maybe_parent_id)];
}
return std::unique_ptr<Table>(
new Table(slice.Apply(RowMap(std::move(ids)))
.ExtendWithColumn("start_id", std::move(child_ids),
TypedColumn<uint32_t>::default_flags() |
TypedColumn<uint32_t>::kHidden)));
}
Table::Schema AncestorSliceGenerator::CreateSchema() {
auto schema = tables::SliceTable::Schema();
schema.columns.push_back(Table::Schema::Column{
"start_id", SqlValue::Type::kLong, /* is_id = */ false,
/* is_sorted = */ false, /* is_hidden = */ true});
return schema;
}
std::string AncestorSliceGenerator::TableName() {
return "ancestor_slice";
}
uint32_t AncestorSliceGenerator::EstimateRowCount() {
return 1;
}
} // namespace trace_processor
} // namespace perfetto