blob: ccad480495bb0bb848f1f4d889abcfa2ce24bf91 [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/experimental_flamegraph_generator.h"
#include "src/trace_processor/heap_profile_tracker.h"
#include "src/trace_processor/importers/proto/heap_graph_tracker.h"
#include "src/trace_processor/trace_processor_context.h"
namespace perfetto {
namespace trace_processor {
namespace {
ExperimentalFlamegraphGenerator::InputValues GetInputValues(
const std::vector<Constraint>& cs) {
using T = tables::ExperimentalFlamegraphNodesTable;
auto ts_fn = [](const Constraint& c) {
return c.col_idx == static_cast<uint32_t>(T::ColumnIndex::ts) &&
c.op == FilterOp::kEq;
};
auto upid_fn = [](const Constraint& c) {
return c.col_idx == static_cast<uint32_t>(T::ColumnIndex::upid) &&
c.op == FilterOp::kEq;
};
auto profile_type_fn = [](const Constraint& c) {
return c.col_idx == static_cast<uint32_t>(T::ColumnIndex::profile_type) &&
c.op == FilterOp::kEq;
};
auto ts_it = std::find_if(cs.begin(), cs.end(), ts_fn);
auto upid_it = std::find_if(cs.begin(), cs.end(), upid_fn);
auto profile_type_it = std::find_if(cs.begin(), cs.end(), profile_type_fn);
// We should always have valid iterators here because BestIndex should only
// allow the constraint set to be chosen when we have an equality constraint
// on both ts and upid.
PERFETTO_CHECK(ts_it != cs.end());
PERFETTO_CHECK(upid_it != cs.end());
PERFETTO_CHECK(profile_type_it != cs.end());
int64_t ts = ts_it->value.AsLong();
UniquePid upid = static_cast<UniquePid>(upid_it->value.AsLong());
std::string profile_type = profile_type_it->value.AsString();
return ExperimentalFlamegraphGenerator::InputValues{ts, upid, profile_type};
}
} // namespace
ExperimentalFlamegraphGenerator::ExperimentalFlamegraphGenerator(
TraceProcessorContext* context)
: context_(context) {}
ExperimentalFlamegraphGenerator::~ExperimentalFlamegraphGenerator() = default;
util::Status ExperimentalFlamegraphGenerator::ValidateConstraints(
const QueryConstraints& qc) {
using T = tables::ExperimentalFlamegraphNodesTable;
const auto& cs = qc.constraints();
auto ts_fn = [](const QueryConstraints::Constraint& c) {
return c.column == static_cast<int>(T::ColumnIndex::ts) &&
c.op == SQLITE_INDEX_CONSTRAINT_EQ;
};
bool has_ts_cs = std::find_if(cs.begin(), cs.end(), ts_fn) != cs.end();
auto upid_fn = [](const QueryConstraints::Constraint& c) {
return c.column == static_cast<int>(T::ColumnIndex::upid) &&
c.op == SQLITE_INDEX_CONSTRAINT_EQ;
};
bool has_upid_cs = std::find_if(cs.begin(), cs.end(), upid_fn) != cs.end();
auto profile_type_fn = [](const QueryConstraints::Constraint& c) {
return c.column == static_cast<int>(T::ColumnIndex::profile_type) &&
c.op == SQLITE_INDEX_CONSTRAINT_EQ;
};
bool has_profile_type_cs =
std::find_if(cs.begin(), cs.end(), profile_type_fn) != cs.end();
return has_ts_cs && has_upid_cs && has_profile_type_cs
? util::OkStatus()
: util::ErrStatus("Failed to find required constraints");
}
Table* ExperimentalFlamegraphGenerator::ComputeTable(
const std::vector<Constraint>& cs,
const std::vector<Order>&) {
// Get the input column values and compute the flamegraph using them.
auto values = GetInputValues(cs);
if (values.profile_type == "graph") {
auto* tracker = HeapGraphTracker::GetOrCreate(context_);
table_ = tracker->BuildFlamegraph(values.ts, values.upid);
}
if (values.profile_type == "native") {
table_ =
BuildNativeFlamegraph(context_->storage.get(), values.upid, values.ts);
}
return table_.get();
}
Table::Schema ExperimentalFlamegraphGenerator::CreateSchema() {
return tables::ExperimentalFlamegraphNodesTable::Schema();
}
std::string ExperimentalFlamegraphGenerator::TableName() {
return "experimental_flamegraph";
}
uint32_t ExperimentalFlamegraphGenerator::EstimateRowCount() {
// TODO(lalitm): return a better estimate here when possible.
return 1024;
}
} // namespace trace_processor
} // namespace perfetto