blob: ce60d47c7af2aa1cda74f32847b976a3127699d7 [file] [log] [blame]
/*
* 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/dynamic/experimental_counter_dur_generator.h"
namespace perfetto {
namespace trace_processor {
ExperimentalCounterDurGenerator::ExperimentalCounterDurGenerator(
const tables::CounterTable& table)
: counter_table_(&table) {}
ExperimentalCounterDurGenerator::~ExperimentalCounterDurGenerator() = default;
Table::Schema ExperimentalCounterDurGenerator::CreateSchema() {
Table::Schema schema = tables::CounterTable::Schema();
schema.columns.emplace_back(
Table::Schema::Column{"dur", SqlValue::Type::kLong, false /* is_id */,
false /* is_sorted */, false /* is_hidden */});
schema.columns.emplace_back(
Table::Schema::Column{"delta", SqlValue::Type::kLong, false /* is_id */,
false /* is_sorted */, false /* is_hidden */});
return schema;
}
std::string ExperimentalCounterDurGenerator::TableName() {
return "experimental_counter_dur";
}
uint32_t ExperimentalCounterDurGenerator::EstimateRowCount() {
return counter_table_->row_count();
}
base::Status ExperimentalCounterDurGenerator::ValidateConstraints(
const QueryConstraints&) {
return base::OkStatus();
}
base::Status ExperimentalCounterDurGenerator::ComputeTable(
const std::vector<Constraint>&,
const std::vector<Order>&,
const BitVector&,
std::unique_ptr<Table>& table_return) {
if (!dur_column_) {
dur_column_.reset(
new NullableVector<int64_t>(ComputeDurColumn(*counter_table_)));
delta_column_.reset(
new NullableVector<double>(ComputeDeltaColumn(*counter_table_)));
}
Table t = counter_table_
->ExtendWithColumn("dur", std::move(dur_column_.get()),
TypedColumn<int64_t>::default_flags())
.ExtendWithColumn("delta", std::move(delta_column_.get()),
TypedColumn<int64_t>::default_flags());
table_return.reset(new Table(t.Copy()));
return base::OkStatus();
}
// static
NullableVector<int64_t> ExperimentalCounterDurGenerator::ComputeDurColumn(
const Table& table) {
// Keep track of the last seen row for each track id.
std::unordered_map<TrackId, uint32_t> last_row_for_track_id;
NullableVector<int64_t> dur;
const auto* ts_col =
TypedColumn<int64_t>::FromColumn(table.GetColumnByName("ts"));
const auto* track_id_col =
TypedColumn<tables::CounterTrackTable::Id>::FromColumn(
table.GetColumnByName("track_id"));
for (uint32_t i = 0; i < table.row_count(); ++i) {
// Check if we already have a previous row for the current track id.
TrackId track_id = (*track_id_col)[i];
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, i);
} 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.
uint32_t old_row = it->second;
it->second = i;
dur.Set(old_row, (*ts_col)[i] - (*ts_col)[old_row]);
}
// 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
NullableVector<double> ExperimentalCounterDurGenerator::ComputeDeltaColumn(
const Table& table) {
// Keep track of the last seen row for each track id.
std::unordered_map<TrackId, uint32_t> last_row_for_track_id;
NullableVector<double> delta;
const auto* value_col =
TypedColumn<double>::FromColumn(table.GetColumnByName("value"));
const auto* track_id_col =
TypedColumn<tables::CounterTrackTable::Id>::FromColumn(
table.GetColumnByName("track_id"));
for (uint32_t i = 0; i < table.row_count(); ++i) {
// Check if we already have a previous row for the current track id.
TrackId track_id = (*track_id_col)[i];
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, i);
} 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.
uint32_t old_row = it->second;
it->second = i;
delta.Set(old_row, (*value_col)[i] - (*value_col)[old_row]);
}
delta.Append(0);
}
return delta;
}
} // namespace trace_processor
} // namespace perfetto