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/dynamic/experimental_counter_dur_generator.h"
18 
19 namespace perfetto {
20 namespace trace_processor {
21 
ExperimentalCounterDurGenerator(const tables::CounterTable & table)22 ExperimentalCounterDurGenerator::ExperimentalCounterDurGenerator(
23     const tables::CounterTable& table)
24     : counter_table_(&table) {}
25 ExperimentalCounterDurGenerator::~ExperimentalCounterDurGenerator() = default;
26 
CreateSchema()27 Table::Schema ExperimentalCounterDurGenerator::CreateSchema() {
28   Table::Schema schema = tables::CounterTable::Schema();
29   schema.columns.emplace_back(
30       Table::Schema::Column{"dur", SqlValue::Type::kLong, false /* is_id */,
31                             false /* is_sorted */, false /* is_hidden */});
32   return schema;
33 }
34 
TableName()35 std::string ExperimentalCounterDurGenerator::TableName() {
36   return "experimental_counter_dur";
37 }
38 
EstimateRowCount()39 uint32_t ExperimentalCounterDurGenerator::EstimateRowCount() {
40   return counter_table_->row_count();
41 }
42 
ValidateConstraints(const QueryConstraints &)43 util::Status ExperimentalCounterDurGenerator::ValidateConstraints(
44     const QueryConstraints&) {
45   return util::OkStatus();
46 }
47 
ComputeTable(const std::vector<Constraint> &,const std::vector<Order> &)48 std::unique_ptr<Table> ExperimentalCounterDurGenerator::ComputeTable(
49     const std::vector<Constraint>&,
50     const std::vector<Order>&) {
51   if (!dur_column_) {
52     dur_column_.reset(
53         new NullableVector<int64_t>(ComputeDurColumn(*counter_table_)));
54   }
55   return std::unique_ptr<Table>(new Table(counter_table_->ExtendWithColumn(
56       "dur", dur_column_.get(), TypedColumn<int64_t>::default_flags())));
57 }
58 
59 // static
ComputeDurColumn(const Table & table)60 NullableVector<int64_t> ExperimentalCounterDurGenerator::ComputeDurColumn(
61     const Table& table) {
62   // Keep track of the last seen row for each track id.
63   std::unordered_map<TrackId, uint32_t> last_row_for_track_id;
64   NullableVector<int64_t> dur;
65 
66   const auto* ts_col =
67       TypedColumn<int64_t>::FromColumn(table.GetColumnByName("ts"));
68   const auto* track_id_col =
69       TypedColumn<tables::CounterTrackTable::Id>::FromColumn(
70           table.GetColumnByName("track_id"));
71 
72   for (uint32_t i = 0; i < table.row_count(); ++i) {
73     // Check if we already have a previous row for the current track id.
74     TrackId track_id = (*track_id_col)[i];
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, i);
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       uint32_t old_row = it->second;
84       it->second = i;
85       dur.Set(old_row, (*ts_col)[i] - (*ts_col)[old_row]);
86     }
87     // Append -1 to mark this event as not having been finished. On a later
88     // row, we may set this to have the correct value.
89     dur.Append(-1);
90   }
91   return dur;
92 }
93 
94 }  // namespace trace_processor
95 }  // namespace perfetto
96