• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "src/trace_processor/dynamic/descendant_generator.h"
18 
19 #include <memory>
20 #include <set>
21 
22 #include "src/trace_processor/types/trace_processor_context.h"
23 #include "src/trace_processor/util/status_macros.h"
24 
25 namespace perfetto {
26 namespace trace_processor {
27 namespace {
GetConstraintColumnIndex(TraceProcessorContext * context)28 uint32_t GetConstraintColumnIndex(TraceProcessorContext* context) {
29   return context->storage->slice_table().GetColumnCount();
30 }
31 
32 template <typename T>
ExtendTableWithStartId(const T & table,int64_t constraint_value)33 Table ExtendTableWithStartId(const T& table, int64_t constraint_value) {
34   // Add a new column that includes the constraint.
35   std::unique_ptr<NullableVector<int64_t>> child_ids(
36       new NullableVector<int64_t>());
37   for (uint32_t i = 0; i < table.row_count(); ++i)
38     child_ids->Append(constraint_value);
39   return table.ExtendWithColumn(
40       "start_id", std::move(child_ids),
41       TypedColumn<uint32_t>::default_flags() | TypedColumn<uint32_t>::kHidden);
42 }
43 
BuildDescendantsRowMap(const tables::SliceTable & slices,SliceId starting_id,RowMap & rowmap_return)44 base::Status BuildDescendantsRowMap(const tables::SliceTable& slices,
45                                     SliceId starting_id,
46                                     RowMap& rowmap_return) {
47   auto start_row = slices.id().IndexOf(starting_id);
48   // The query gave an invalid ID that doesn't exist in the slice table.
49   if (!start_row) {
50     return base::ErrStatus("no row with id %" PRIu32 "",
51                            static_cast<uint32_t>(starting_id.value));
52   }
53 
54   // All nested descendents must be on the same track, with a ts between
55   // |start_id.ts| and |start_id.ts| + |start_id.dur|, and who's depth is larger
56   // then |start_row|'s. So we just use Filter to select all relevant slices.
57   rowmap_return = slices.FilterToRowMap(
58       {slices.ts().ge(slices.ts()[*start_row]),
59        slices.ts().le(slices.ts()[*start_row] + slices.dur()[*start_row]),
60        slices.track_id().eq(slices.track_id()[*start_row].value),
61        slices.depth().gt(slices.depth()[*start_row])});
62   return base::OkStatus();
63 }
64 
BuildDescendantsTable(int64_t constraint_value,const tables::SliceTable & slices,SliceId starting_id,std::unique_ptr<Table> & table_return)65 base::Status BuildDescendantsTable(int64_t constraint_value,
66                                    const tables::SliceTable& slices,
67                                    SliceId starting_id,
68                                    std::unique_ptr<Table>& table_return) {
69   // Build up all the children row ids.
70   RowMap descendants;
71   RETURN_IF_ERROR(BuildDescendantsRowMap(slices, starting_id, descendants));
72 
73   table_return.reset(new Table(ExtendTableWithStartId(
74       slices.Apply(std::move(descendants)), constraint_value)));
75   return base::OkStatus();
76 }
77 }  // namespace
78 
DescendantGenerator(Descendant type,TraceProcessorContext * context)79 DescendantGenerator::DescendantGenerator(Descendant type,
80                                          TraceProcessorContext* context)
81     : type_(type), context_(context) {}
82 
ValidateConstraints(const QueryConstraints & qc)83 base::Status DescendantGenerator::ValidateConstraints(
84     const QueryConstraints& qc) {
85   const auto& cs = qc.constraints();
86 
87   int column = static_cast<int>(GetConstraintColumnIndex(context_));
88   auto id_fn = [column](const QueryConstraints::Constraint& c) {
89     return c.column == column && c.op == SQLITE_INDEX_CONSTRAINT_EQ;
90   };
91   bool has_id_cs = std::find_if(cs.begin(), cs.end(), id_fn) != cs.end();
92   return has_id_cs ? base::OkStatus()
93                    : base::ErrStatus("Failed to find required constraints");
94 }
95 
ComputeTable(const std::vector<Constraint> & cs,const std::vector<Order> &,const BitVector &,std::unique_ptr<Table> & table_return)96 base::Status DescendantGenerator::ComputeTable(
97     const std::vector<Constraint>& cs,
98     const std::vector<Order>&,
99     const BitVector&,
100     std::unique_ptr<Table>& table_return) {
101   const auto& slices = context_->storage->slice_table();
102 
103   uint32_t column = GetConstraintColumnIndex(context_);
104   auto constraint_it =
105       std::find_if(cs.begin(), cs.end(), [column](const Constraint& c) {
106         return c.col_idx == column && c.op == FilterOp::kEq;
107       });
108   PERFETTO_DCHECK(constraint_it != cs.end());
109   if (constraint_it == cs.end() ||
110       constraint_it->value.type != SqlValue::Type::kLong) {
111     return base::ErrStatus("invalid start_id");
112   }
113   auto start_id = constraint_it->value.AsLong();
114 
115   switch (type_) {
116     case Descendant::kSlice: {
117       RETURN_IF_ERROR(BuildDescendantsTable(
118           start_id, slices, SliceId(static_cast<uint32_t>(start_id)),
119           table_return));
120       return base::OkStatus();
121     }
122 
123     case Descendant::kSliceByStack: {
124       auto result = RowMap();
125       auto slice_ids = slices.FilterToRowMap({slices.stack_id().eq(start_id)});
126 
127       for (auto id_it = slice_ids.IterateRows(); id_it; id_it.Next()) {
128         auto slice_id = slices.id()[id_it.index()];
129 
130         auto descendants = GetDescendantSlices(slices, slice_id);
131         for (auto row_it = descendants->IterateRows(); row_it; row_it.Next()) {
132           result.Insert(row_it.index());
133         }
134       }
135 
136       table_return.reset(new Table(
137           ExtendTableWithStartId(slices.Apply(std::move(result)), start_id)));
138       return base::OkStatus();
139     }
140   }
141   return base::ErrStatus("unknown DescendantGenerator type");
142 }
143 
CreateSchema()144 Table::Schema DescendantGenerator::CreateSchema() {
145   auto schema = tables::SliceTable::Schema();
146   schema.columns.push_back(Table::Schema::Column{
147       "start_id", SqlValue::Type::kLong, /* is_id = */ false,
148       /* is_sorted = */ false, /* is_hidden = */ true});
149   return schema;
150 }
151 
TableName()152 std::string DescendantGenerator::TableName() {
153   switch (type_) {
154     case Descendant::kSlice:
155       return "descendant_slice";
156     case Descendant::kSliceByStack:
157       return "descendant_slice_by_stack";
158   }
159   return "descendant_unknown";
160 }
161 
EstimateRowCount()162 uint32_t DescendantGenerator::EstimateRowCount() {
163   return 1;
164 }
165 
166 // static
GetDescendantSlices(const tables::SliceTable & slices,SliceId slice_id)167 base::Optional<RowMap> DescendantGenerator::GetDescendantSlices(
168     const tables::SliceTable& slices,
169     SliceId slice_id) {
170   RowMap ret;
171   auto status = BuildDescendantsRowMap(slices, slice_id, ret);
172   if (!status.ok())
173     return base::nullopt;
174   return std::move(ret);  // -Wreturn-std-move-in-c++11
175 }
176 
177 }  // namespace trace_processor
178 }  // namespace perfetto
179