Skip to content

Commit

Permalink
Merge "ui: add support for contextual columns in QueryFlamegraph" int…
Browse files Browse the repository at this point in the history
…o main
  • Loading branch information
LalitMaganti authored and Gerrit Code Review committed Jul 22, 2024
2 parents 8f568a5 + fdfe6df commit 358e386
Show file tree
Hide file tree
Showing 2 changed files with 130 additions and 49 deletions.
96 changes: 64 additions & 32 deletions src/trace_processor/perfetto_sql/stdlib/viz/flamegraph.sql
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@
-- See the License for the specific language governing permissions and
-- limitations under the License.

include perfetto module graphs.scan;
INCLUDE PERFETTO MODULE graphs.scan;
INCLUDE PERFETTO MODULE metasql.column_list;

-- For each frame in |tab|, returns a row containing the result of running
-- all the filtering operations over that frame's name.
Expand All @@ -24,7 +25,8 @@ CREATE PERFETTO MACRO _viz_flamegraph_prepare_filter(
show_from_frame Expr,
hide_frame Expr,
pivot Expr,
impossible_stack_bits Expr
impossible_stack_bits Expr,
grouping _ColumnNameList
)
RETURNS TableOrSubquery
AS (
Expand All @@ -33,7 +35,8 @@ AS (
IIF($hide_stack, $impossible_stack_bits, $show_stack) AS stackBits,
$show_from_frame As showFromFrameBits,
$hide_frame = 0 AS showFrame,
$pivot AS isPivot
$pivot AS isPivot,
HASH(name, _metasql_unparenthesize_column_list!($grouping)) AS groupingHash
FROM $tab
ORDER BY id
);
Expand Down Expand Up @@ -168,12 +171,17 @@ AS (
ORDER BY id
);

CREATE PERFETTO MACRO _viz_flamegraph_s_prefix(col ColumnName)
RETURNS _SqlFragment AS s.$col;

-- Propogates the cumulative value of the pivot nodes to the roots
-- and computes the "fingerprint" of the path.
CREATE PERFETTO MACRO _viz_flamegraph_upwards_hash(
source TableOrSubquery,
filtered TableOrSubquery,
accumulated TableOrSubquery
accumulated TableOrSubquery,
grouping _ColumnNameList,
grouped _ColumnNameList
)
RETURNS TableOrSubquery
AS (
Expand All @@ -185,7 +193,7 @@ AS (
inits AS (
SELECT
f.id,
HASH(-1, s.name) AS hash,
HASH(-1, s.groupingHash) AS hash,
NULL AS parentHash,
-1 AS depth,
a.cumulativeValue
Expand All @@ -202,6 +210,8 @@ AS (
g.parentHash,
g.depth,
s.name,
_metasql_map_join_column_list!($grouping, _viz_flamegraph_s_prefix),
_metasql_map_join_column_list!($grouped, _viz_flamegraph_s_prefix),
f.value,
g.cumulativeValue
FROM _graph_scan!(
Expand All @@ -211,7 +221,7 @@ AS (
(
SELECT
t.id,
HASH(t.hash, x.name) AS hash,
HASH(t.hash, x.groupingHash) AS hash,
t.hash AS parentHash,
t.depth - 1 AS depth,
t.cumulativeValue
Expand All @@ -228,31 +238,36 @@ AS (
CREATE PERFETTO MACRO _viz_flamegraph_downwards_hash(
source TableOrSubquery,
filtered TableOrSubquery,
accumulated TableOrSubquery
accumulated TableOrSubquery,
grouping _ColumnNameList,
grouped _ColumnNameList
)
RETURNS TableOrSubquery
AS (
WITH edges AS (
SELECT parentId AS source_node_id, id AS dest_node_id
FROM $filtered
WHERE parentId IS NOT NULL
),
inits AS (
SELECT
f.id,
HASH(1, s.name) AS hash,
NULL AS parentHash,
1 AS depth
FROM $filtered f
JOIN $source s USING (id)
WHERE f.parentId IS NULL
)
WITH
edges AS (
SELECT parentId AS source_node_id, id AS dest_node_id
FROM $filtered
WHERE parentId IS NOT NULL
),
inits AS (
SELECT
f.id,
HASH(1, s.groupingHash) AS hash,
NULL AS parentHash,
1 AS depth
FROM $filtered f
JOIN $source s USING (id)
WHERE f.parentId IS NULL
)
SELECT
g.id,
g.hash,
g.parentHash,
g.depth,
s.name,
_metasql_map_join_column_list!($grouping, _viz_flamegraph_s_prefix),
_metasql_map_join_column_list!($grouped, _viz_flamegraph_s_prefix),
f.value,
a.cumulativeValue
FROM _graph_scan!(
Expand All @@ -262,7 +277,7 @@ AS (
(
SELECT
t.id,
HASH(t.hash, x.name) AS hash,
HASH(t.hash, x.groupingHash) AS hash,
t.hash AS parentHash,
t.depth + 1 AS depth
FROM $table t
Expand All @@ -275,10 +290,18 @@ AS (
ORDER BY hash
);

CREATE PERFETTO MACRO _viz_flamegraph_merge_grouped(
col ColumnName
)
RETURNS _SqlFragment
AS IIF(COUNT() = 1, $col, NULL) AS $col;

-- Converts a table of hashes and paretn hashes into ids and parent
-- ids, grouping all hashes together.
CREATE PERFETTO MACRO _viz_flamegraph_merge_hashes(
hashed TableOrSubquery
hashed TableOrSubquery,
grouping _ColumnNameList,
grouped _ColumnNameList
)
RETURNS TableOrSubquery
AS (
Expand All @@ -292,6 +315,11 @@ AS (
) AS parentId,
depth,
name,
-- The grouping columns should be passed through as-is because the
-- hash took them into account: we would not merged any nodes where
-- the grouping columns were different.
_metasql_unparenthesize_column_list!($grouping),
_metasql_map_join_column_list!($grouped, _viz_flamegraph_merge_grouped),
SUM(value) AS value,
SUM(cumulativeValue) AS cumulativeValue
FROM $hashed c
Expand Down Expand Up @@ -327,7 +355,9 @@ AS (
-- parents to their children.
CREATE PERFETTO MACRO _viz_flamegraph_global_layout(
merged TableOrSubquery,
layout TableOrSubquery
layout TableOrSubquery,
grouping _ColumnNameList,
grouped _ColumnNameList
)
RETURNS TableOrSubquery
AS (
Expand All @@ -343,12 +373,14 @@ AS (
WHERE h.parentId IS NULL
)
SELECT
h.id,
IFNULL(h.parentId, -1) AS parentId,
IIF(h.name = '', 'unknown', h.name) AS name,
h.value AS selfValue,
h.cumulativeValue,
h.depth,
s.id,
IFNULL(s.parentId, -1) AS parentId,
IIF(s.name = '', 'unknown', s.name) AS name,
_metasql_map_join_column_list!($grouping, _viz_flamegraph_s_prefix),
_metasql_map_join_column_list!($grouped, _viz_flamegraph_s_prefix),
s.value AS selfValue,
s.cumulativeValue,
s.depth,
g.xStart,
g.xEnd
FROM _graph_scan!(
Expand All @@ -364,6 +396,6 @@ AS (
JOIN $layout w USING (id)
)
) g
JOIN $merged h USING (id)
JOIN $merged s USING (id)
ORDER BY depth, xStart
);
83 changes: 66 additions & 17 deletions ui/src/core/query_flamegraph.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,15 @@ import {Monitor} from '../base/monitor';
import {featureFlags} from './feature_flags';
import {uuidv4Sql} from '../base/uuid';

interface QueryFlamegraphMetric {
export interface QueryFlamegraphColumn {
// The name of the column in SQL.
readonly name: string;

// The human readable name describing the contents of the column.
readonly displayName: string;
}

export interface QueryFlamegraphMetric {
// The human readable name of the metric: will be shown to the user to change
// between metrics.
readonly name: string;
Expand All @@ -43,8 +51,26 @@ interface QueryFlamegraphMetric {
readonly dependencySql?: string;

// A single SQL statement which returns the columns `id`, `parentId`, `name`
// and `selfValue`
// `selfValue`, all columns specified by `unaggregatableProperties` and
// `aggregatableProperties`.
readonly statement: string;

// Additional contextual columns containing data which should not be merged
// between sibling nodes, even if they have the same name.
//
// Examples include the mapping that a name comes from, the heap graph root
// type etc.
//
// Note: the name is always unaggregatable and should not be specified here.
readonly unaggregatableProperties?: ReadonlyArray<QueryFlamegraphColumn>;

// Additional contextual columns containing data which will be displayed to
// the user if there is no merging. If there is merging, currently the value
// will not be shown.
//
// TODO(lalitm): reconsider the decision to show nothing, instead maybe show
// the top 5 options etc.
readonly aggregatableProperties?: ReadonlyArray<QueryFlamegraphColumn>;
}

// Given a table and columns on those table (corresponding to metrics),
Expand Down Expand Up @@ -124,26 +150,25 @@ export class QueryFlamegraph implements m.ClassComponent<QueryFlamegraphAttrs> {
}

private async fetchData(attrs: QueryFlamegraphAttrs) {
const {statement, dependencySql} = assertExists(
const metric = assertExists(
attrs.metrics.find((metric) => metric.name === this.selectedMetricName),
);
const engine = attrs.engine;
const filters = this.filters;
this.queryLimiter.schedule(async () => {
this.data = await computeFlamegraphTree(
engine,
dependencySql,
statement,
filters,
);
this.data = await computeFlamegraphTree(engine, metric, filters);
});
}
}

async function computeFlamegraphTree(
engine: Engine,
dependencySql: string | undefined,
sql: string,
{
dependencySql,
statement,
unaggregatableProperties,
aggregatableProperties,
}: QueryFlamegraphMetric,
{showStack, hideStack, showFromFrame, hideFrame, pivot}: FlamegraphFilters,
) {
// Pivot also essentially acts as a "show stack" filter so treat it like one.
Expand Down Expand Up @@ -180,6 +205,12 @@ async function computeFlamegraphTree(

const pivotFilter = pivot === undefined ? '0' : `name like '%${pivot}%'`;

const unagg = unaggregatableProperties ?? [];
const agg = aggregatableProperties ?? [];

const groupingColumns = `(${(unagg.length === 0 ? ['groupingColumn'] : unagg).join()})`;
const groupedColumns = `(${(agg.length === 0 ? ['groupedColumn'] : agg).join()})`;

if (dependencySql !== undefined) {
await engine.query(dependencySql);
}
Expand All @@ -196,13 +227,23 @@ async function computeFlamegraphTree(
`
select *
from _viz_flamegraph_prepare_filter!(
(${sql}),
(
select
id,
parentId,
name,
value,
${(unagg.length === 0 ? ['0 as groupingColumn'] : unagg).join()},
${(agg.length === 0 ? ['0 as groupedColumn'] : agg).join()}
FROM (${statement})
),
(${showStackFilter}),
(${hideStackFilter}),
(${showFromFrameFilter}),
(${hideFrameFilter}),
(${pivotFilter}),
${1 << showStackAndPivot.length}
${1 << showStackAndPivot.length},
${groupingColumns}
)
`,
),
Expand Down Expand Up @@ -244,14 +285,18 @@ async function computeFlamegraphTree(
from _viz_flamegraph_downwards_hash!(
_flamegraph_source_${uuid},
_flamegraph_filtered_${uuid},
_flamegraph_accumulated_${uuid}
_flamegraph_accumulated_${uuid},
${groupingColumns},
${groupedColumns}
)
union all
select *
from _viz_flamegraph_upwards_hash!(
_flamegraph_source_${uuid},
_flamegraph_filtered_${uuid},
_flamegraph_accumulated_${uuid}
_flamegraph_accumulated_${uuid},
${groupingColumns},
${groupedColumns}
)
order by hash
`,
Expand All @@ -264,7 +309,9 @@ async function computeFlamegraphTree(
`
select *
from _viz_flamegraph_merge_hashes!(
_flamegraph_hash_${uuid}
_flamegraph_hash_${uuid},
${groupingColumns},
${groupedColumns}
)
`,
),
Expand All @@ -285,7 +332,9 @@ async function computeFlamegraphTree(
select *
from _viz_flamegraph_global_layout!(
_flamegraph_merged_${uuid},
_flamegraph_layout_${uuid}
_flamegraph_layout_${uuid},
${groupingColumns},
${groupedColumns}
)
`);
const it = res.iter({
Expand Down

0 comments on commit 358e386

Please sign in to comment.