| /* |
| * 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/prelude/table_functions/experimental_counter_dur.h" |
| |
| #include "src/trace_processor/tables/counter_tables.h" |
| |
| namespace perfetto { |
| namespace trace_processor { |
| namespace tables { |
| |
| #define PERFETTO_TP_COUNTER_DUR_TABLE_DEF(NAME, PARENT, C) \ |
| NAME(ExperimentalCounterDurTable, "experimental_counter_dur") \ |
| PARENT(PERFETTO_TP_COUNTER_TABLE_DEF, C) \ |
| C(int64_t, dur) \ |
| C(double, delta) |
| |
| PERFETTO_TP_TABLE(PERFETTO_TP_COUNTER_DUR_TABLE_DEF); |
| |
| ExperimentalCounterDurTable::~ExperimentalCounterDurTable() = default; |
| |
| } // namespace tables |
| |
| ExperimentalCounterDur::ExperimentalCounterDur( |
| const tables::CounterTable& table) |
| : counter_table_(&table) {} |
| ExperimentalCounterDur::~ExperimentalCounterDur() = default; |
| |
| Table::Schema ExperimentalCounterDur::CreateSchema() { |
| return tables::ExperimentalCounterDurTable::ComputeStaticSchema(); |
| } |
| |
| std::string ExperimentalCounterDur::TableName() { |
| return tables::ExperimentalCounterDurTable::Name(); |
| } |
| |
| uint32_t ExperimentalCounterDur::EstimateRowCount() { |
| return counter_table_->row_count(); |
| } |
| |
| base::Status ExperimentalCounterDur::ValidateConstraints( |
| const QueryConstraints&) { |
| return base::OkStatus(); |
| } |
| |
| base::Status ExperimentalCounterDur::ComputeTable( |
| const std::vector<Constraint>&, |
| const std::vector<Order>&, |
| const BitVector&, |
| std::unique_ptr<Table>& table_return) { |
| if (!counter_dur_table_) { |
| counter_dur_table_ = tables::ExperimentalCounterDurTable::ExtendParent( |
| *counter_table_, ComputeDurColumn(*counter_table_), |
| ComputeDeltaColumn(*counter_table_)); |
| } |
| table_return.reset(new Table(counter_dur_table_->Copy())); |
| return base::OkStatus(); |
| } |
| |
| // static |
| ColumnStorage<int64_t> ExperimentalCounterDur::ComputeDurColumn( |
| const CounterTable& table) { |
| // Keep track of the last seen row for each track id. |
| std::unordered_map<TrackId, CounterTable::RowNumber> last_row_for_track_id; |
| ColumnStorage<int64_t> dur; |
| |
| for (auto table_it = table.IterateRows(); table_it; ++table_it) { |
| // Check if we already have a previous row for the current track id. |
| TrackId track_id = table_it.track_id(); |
| auto it = last_row_for_track_id.find(track_id); |
| if (it == last_row_for_track_id.end()) { |
| // This means we don't have any row - start tracking this row for the |
| // future. |
| last_row_for_track_id.emplace(track_id, table_it.row_number()); |
| } else { |
| // This means we have an previous row for the current track id. Update |
| // the duration of the previous row to be up to the current ts. |
| CounterTable::RowNumber old_row = it->second; |
| it->second = table_it.row_number(); |
| dur.Set(old_row.row_number(), |
| table_it.ts() - old_row.ToRowReference(table).ts()); |
| } |
| // Append -1 to mark this event as not having been finished. On a later |
| // row, we may set this to have the correct value. |
| dur.Append(-1); |
| } |
| return dur; |
| } |
| |
| // static |
| ColumnStorage<double> ExperimentalCounterDur::ComputeDeltaColumn( |
| const CounterTable& table) { |
| // Keep track of the last seen row for each track id. |
| std::unordered_map<TrackId, CounterTable::RowNumber> last_row_for_track_id; |
| ColumnStorage<double> delta; |
| |
| for (auto table_it = table.IterateRows(); table_it; ++table_it) { |
| // Check if we already have a previous row for the current track id. |
| TrackId track_id = table_it.track_id(); |
| auto it = last_row_for_track_id.find(track_id); |
| if (it == last_row_for_track_id.end()) { |
| // This means we don't have any row - start tracking this row for the |
| // future. |
| last_row_for_track_id.emplace(track_id, table_it.row_number()); |
| } else { |
| // This means we have an previous row for the current track id. Update |
| // the duration of the previous row to be up to the current ts. |
| CounterTable::RowNumber old_row = it->second; |
| it->second = table_it.row_number(); |
| delta.Set(old_row.row_number(), |
| table_it.value() - old_row.ToRowReference(table).value()); |
| } |
| delta.Append(0); |
| } |
| return delta; |
| } |
| |
| } // namespace trace_processor |
| } // namespace perfetto |