blob: fb94a785fd7bee1aa6de36d1b27ce13b28784d62 [file]
/*
* Copyright (C) 2026 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.
*/
#ifndef SRC_TRACE_PROCESSOR_PLUGINS_FLAMEGRAPH_FLAMEGRAPH_H_
#define SRC_TRACE_PROCESSOR_PLUGINS_FLAMEGRAPH_FLAMEGRAPH_H_
#include <cstdint>
#include <optional>
#include <string>
#include <vector>
#include "perfetto/ext/base/regex.h"
#include "perfetto/ext/base/status_or.h"
#include "perfetto/ext/base/type_set.h"
#include "src/trace_processor/containers/string_pool.h"
#include "src/trace_processor/core/tree/tree.h"
#include "src/trace_processor/core/util/slab.h"
namespace perfetto::trace_processor::flamegraph {
inline bool IsNumericColumn(const core::Tree::Column& column) {
return column.type.Is<core::Int64>() || column.type.Is<core::Double>();
}
// Fully resolved inputs to the flamegraph algorithm. The SQL layer is
// responsible for resolving column names, validating column types, and
// compiling patterns before calling Build. Per-row matching remains part of
// the algorithm.
// Column pointers refer to the Tree passed to Build and only need to remain
// valid for that call.
struct Config {
explicit Config(StringPool& string_pool) : pool(string_pool) {}
static constexpr uint32_t kMaxShowStackFilters = 61;
// Structural orientations of the output. The named subsets below describe
// which views share a behaviour; membership tests use View::IsAnyOf.
struct TopDown {};
struct BottomUp {};
struct Pivot {};
struct FromFrame {};
using View = base::TypeSet<TopDown, BottomUp, Pivot, FromFrame>;
// Views anchored on frames matching |view_pattern|.
using PatternViews = base::TypeSet<Pivot, FromFrame>;
// Views which build the downward (descendant) half of the output.
using DownwardViews = base::TypeSet<TopDown, Pivot, FromFrame>;
// Views which build the upward (ancestor) half of the output.
using UpwardViews = base::TypeSet<BottomUp, Pivot>;
enum class Aggregate {
kSum,
kOneOrSummary,
kConcatWithComma,
};
struct AggregateColumn {
const core::Tree::Column* input;
Aggregate aggregate;
std::string output_name;
};
StringPool& pool;
// Structural orientation. Pivot builds both descendants and ancestors of
// rows matching |view_pattern|. From-frame builds only descendants of the
// matching rows. |view_pattern| is set exactly for those two views.
View view = View(TopDown{});
std::optional<base::Regex> view_pattern;
// Frame identity. Grouping columns, together with name, determine which
// frames can be merged. Regex filters match against all of these columns.
const core::Tree::Column* name = nullptr;
std::vector<const core::Tree::Column*> grouping_columns;
// Filtering, separated by operation before entering the algorithm.
std::vector<base::Regex> show_stack_filters;
std::vector<base::Regex> hide_stack_filters;
std::vector<base::Regex> hide_frame_filters;
// Numeric sample-weight columns. Each is SUM-aggregated into a
// self_<name>/cumulative_<name> output pair. At least one is required.
std::vector<const core::Tree::Column*> value_columns;
// Additional aggregates carried through structural folds. They do not
// contribute to flamegraph geometry.
std::vector<AggregateColumn> aggregate_columns;
// Returns true if any filters are configured, false otherwise.
bool HasFilters() const {
return !show_stack_filters.empty() || !hide_stack_filters.empty() ||
!hide_frame_filters.empty();
}
};
// Builds a merged structural flamegraph from a parent-before-child tree.
// Presentation layout is a separate operation: see ComputeLayout.
base::StatusOr<core::Tree> Build(const core::Tree&, const Config&);
// Presentation geometry for one built flamegraph, in render order:
// breadth-first, siblings packed left-to-right by decreasing cumulative
// value. A node's width is its cumulative value clamped to zero, so its end
// position is x_start plus that width.
struct Layout {
core::Slab<uint32_t> node; // output row -> tree row
core::Slab<uint32_t> parent_row; // output row -> parent output row
core::Slab<double> x_start;
};
// Computes presentation geometry for a tree returned by Build, positioning
// each node by |cumulative|, one of the tree's cumulative value columns.
// |depth| is the tree's depth column; its sign separates the downward and
// upward halves of the flamegraph, which are laid out as independent strips.
// Nodes with non-positive cumulative value take up no width but keep their
// position so that consumers of secondary value columns still see them.
Layout ComputeLayout(const core::Tree&,
const core::Tree::Column& cumulative,
const core::Tree::Column& depth);
} // namespace perfetto::trace_processor::flamegraph
#endif // SRC_TRACE_PROCESSOR_PLUGINS_FLAMEGRAPH_FLAMEGRAPH_H_