1 /*
2 * Copyright (C) 2020 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/prelude/table_functions/experimental_counter_dur.h"
18
19 #include "src/trace_processor/prelude/table_functions/tables_py.h"
20
21 namespace perfetto {
22 namespace trace_processor {
23 namespace tables {
24
25 ExperimentalCounterDurTable::~ExperimentalCounterDurTable() = default;
26
27 } // namespace tables
28
ExperimentalCounterDur(const tables::CounterTable & table)29 ExperimentalCounterDur::ExperimentalCounterDur(
30 const tables::CounterTable& table)
31 : counter_table_(&table) {}
32 ExperimentalCounterDur::~ExperimentalCounterDur() = default;
33
CreateSchema()34 Table::Schema ExperimentalCounterDur::CreateSchema() {
35 return tables::ExperimentalCounterDurTable::ComputeStaticSchema();
36 }
37
TableName()38 std::string ExperimentalCounterDur::TableName() {
39 return tables::ExperimentalCounterDurTable::Name();
40 }
41
EstimateRowCount()42 uint32_t ExperimentalCounterDur::EstimateRowCount() {
43 return counter_table_->row_count();
44 }
45
ValidateConstraints(const QueryConstraints &)46 base::Status ExperimentalCounterDur::ValidateConstraints(
47 const QueryConstraints&) {
48 return base::OkStatus();
49 }
50
ComputeTable(const std::vector<Constraint> &,const std::vector<Order> &,const BitVector &,std::unique_ptr<Table> & table_return)51 base::Status ExperimentalCounterDur::ComputeTable(
52 const std::vector<Constraint>&,
53 const std::vector<Order>&,
54 const BitVector&,
55 std::unique_ptr<Table>& table_return) {
56 if (!counter_dur_table_) {
57 counter_dur_table_ = tables::ExperimentalCounterDurTable::ExtendParent(
58 *counter_table_, ComputeDurColumn(*counter_table_),
59 ComputeDeltaColumn(*counter_table_));
60 }
61 table_return.reset(new Table(counter_dur_table_->Copy()));
62 return base::OkStatus();
63 }
64
65 // static
ComputeDurColumn(const CounterTable & table)66 ColumnStorage<int64_t> ExperimentalCounterDur::ComputeDurColumn(
67 const CounterTable& table) {
68 // Keep track of the last seen row for each track id.
69 std::unordered_map<TrackId, CounterTable::RowNumber> last_row_for_track_id;
70 ColumnStorage<int64_t> dur;
71
72 for (auto table_it = table.IterateRows(); table_it; ++table_it) {
73 // Check if we already have a previous row for the current track id.
74 TrackId track_id = table_it.track_id();
75 auto it = last_row_for_track_id.find(track_id);
76 if (it == last_row_for_track_id.end()) {
77 // This means we don't have any row - start tracking this row for the
78 // future.
79 last_row_for_track_id.emplace(track_id, table_it.row_number());
80 } else {
81 // This means we have an previous row for the current track id. Update
82 // the duration of the previous row to be up to the current ts.
83 CounterTable::RowNumber old_row = it->second;
84 it->second = table_it.row_number();
85 dur.Set(old_row.row_number(),
86 table_it.ts() - old_row.ToRowReference(table).ts());
87 }
88 // Append -1 to mark this event as not having been finished. On a later
89 // row, we may set this to have the correct value.
90 dur.Append(-1);
91 }
92 return dur;
93 }
94
95 // static
ComputeDeltaColumn(const CounterTable & table)96 ColumnStorage<double> ExperimentalCounterDur::ComputeDeltaColumn(
97 const CounterTable& table) {
98 // Keep track of the last seen row for each track id.
99 std::unordered_map<TrackId, CounterTable::RowNumber> last_row_for_track_id;
100 ColumnStorage<double> delta;
101
102 for (auto table_it = table.IterateRows(); table_it; ++table_it) {
103 // Check if we already have a previous row for the current track id.
104 TrackId track_id = table_it.track_id();
105 auto it = last_row_for_track_id.find(track_id);
106 if (it == last_row_for_track_id.end()) {
107 // This means we don't have any row - start tracking this row for the
108 // future.
109 last_row_for_track_id.emplace(track_id, table_it.row_number());
110 } else {
111 // This means we have an previous row for the current track id. Update
112 // the duration of the previous row to be up to the current ts.
113 CounterTable::RowNumber old_row = it->second;
114 it->second = table_it.row_number();
115 delta.Set(old_row.row_number(),
116 table_it.value() - old_row.ToRowReference(table).value());
117 }
118 delta.Append(0);
119 }
120 return delta;
121 }
122
123 } // namespace trace_processor
124 } // namespace perfetto
125