/* * 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/descendant_slice_generator.h" #include #include #include "src/trace_processor/types/trace_processor_context.h" namespace perfetto { namespace trace_processor { DescendantSliceGenerator::DescendantSliceGenerator( TraceProcessorContext* context) : context_(context) {} DescendantSliceGenerator::~DescendantSliceGenerator() = default; util::Status DescendantSliceGenerator::ValidateConstraints( const QueryConstraints& qc) { const auto& cs = qc.constraints(); auto slice_id_fn = [this](const QueryConstraints::Constraint& c) { return c.column == static_cast( 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 DescendantSliceGenerator::ComputeTable( const std::vector& cs, const std::vector&) { const auto& slice = context_->storage->slice_table(); auto it = std::find_if(cs.begin(), cs.end(), [&slice](const Constraint& c) { return c.col_idx == slice.GetColumnCount() && c.op == FilterOp::kEq; }); PERFETTO_DCHECK(it != cs.end()); uint32_t start_id = static_cast(it->value.AsLong()); auto descendants = GetDescendantSlices(slice, SliceId(start_id)); if (!descendants) return nullptr; Table reduced_slice = slice.Apply(std::move(*descendants)); // For every row extend it to match the schema, and return it. std::unique_ptr> start_ids( new NullableVector()); for (size_t i = 0; i < reduced_slice.row_count(); ++i) { start_ids->Append(start_id); } return std::unique_ptr
( new Table(std::move(reduced_slice) .ExtendWithColumn("start_id", std::move(start_ids), TypedColumn::default_flags() | TypedColumn::kHidden))); } Table::Schema DescendantSliceGenerator::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 DescendantSliceGenerator::TableName() { return "descendant_slice"; } uint32_t DescendantSliceGenerator::EstimateRowCount() { return 1; } // static base::Optional DescendantSliceGenerator::GetDescendantSlices( const tables::SliceTable& slice, SliceId start_id) { auto start_row = slice.id().IndexOf(start_id); // The query gave an invalid ID that doesn't exist in the slice table. 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 base::nullopt; } // All nested descendents must be on the same track, with a ts between // |start_id.ts| and |start_id.ts| + |start_id.dur|, and who's depth is larger // then |start_row|'s. So we just use Filter to select all relevant slices. return slice.FilterToRowMap( {slice.ts().ge(slice.ts()[*start_row]), slice.ts().le(slice.ts()[*start_row] + slice.dur()[*start_row]), slice.track_id().eq(slice.track_id()[*start_row].value), slice.depth().gt(slice.depth()[*start_row])}); } } // namespace trace_processor } // namespace perfetto