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