Skip to content

Commit 762ef22

Browse files
committed
[profiler-lib] Determine root node id dynamically instead of assuming it's matches the hard-coded constant
Signed-off-by: Karakatiza666 <bulakh.96@gmail.com>
1 parent e605013 commit 762ef22

6 files changed

Lines changed: 44 additions & 15 deletions

File tree

js-packages/profiler-layout/src/lib/components/MetricsView.svelte

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<script lang="ts" module>
2-
import { type NodeAttributes, TOP_NODE_ID } from 'profiler-lib'
2+
import type { NodeAttributes } from 'profiler-lib'
33
44
export type MetricsMode = 'overview' | 'node' | 'top-nodes'
55
@@ -10,9 +10,13 @@
1010
]
1111
1212
/** The toplevel node represents the whole circuit (the overview) rather than a single operator.
13-
* Reused wherever we need to distinguish overview data from a single node. */
14-
export function isOverviewAttributes(nodeAttributes: NodeAttributes): boolean {
15-
return nodeAttributes.nodeId === TOP_NODE_ID
13+
* `rootNodeId` is the loaded profile's actual toplevel id; while it is `undefined` (no profile
14+
* yet) nothing counts as the overview. */
15+
export function isOverviewAttributes(
16+
nodeAttributes: NodeAttributes,
17+
rootNodeId: string | undefined
18+
): boolean {
19+
return rootNodeId !== undefined && nodeAttributes.nodeId === rootNodeId
1620
}
1721
1822
/** The node id is what `search()` matches against, so it's the query that links back to the
@@ -31,6 +35,8 @@
3135
interface Props {
3236
mode: MetricsMode
3337
tooltipData: TooltipData | null
38+
/** The loaded profile's toplevel node id, used to recognise overview data. */
39+
rootNodeId: string | undefined
3440
/** When true, metrics flagged `advanced` in the profile metadata are included. */
3541
showAdvanced: boolean
3642
/** Lookup coordinator; the view registers an imperative handler so each Enter on the
@@ -41,13 +47,15 @@
4147
onSearchNode?: (query: string) => void
4248
}
4349
44-
const { mode, tooltipData, showAdvanced, lookup, onSearchNode }: Props = $props()
50+
const { mode, tooltipData, rootNodeId, showAdvanced, lookup, onSearchNode }: Props = $props()
4551
4652
const nodeAttributes = $derived(
4753
tooltipData && 'nodeAttributes' in tooltipData ? tooltipData.nodeAttributes : null
4854
)
4955
// Single-node data (a specific operator) as opposed to the whole-circuit overview.
50-
const isNodeView = $derived(nodeAttributes ? !isOverviewAttributes(nodeAttributes) : false)
56+
const isNodeView = $derived(
57+
nodeAttributes ? !isOverviewAttributes(nodeAttributes, rootNodeId) : false
58+
)
5159
const identityRows = $derived(
5260
nodeAttributes && isNodeView
5361
? idAttributes.flatMap((r) => {

js-packages/profiler-layout/src/lib/components/SupportBundleViewerLayout.svelte

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,8 @@
7373
}: Props = $props()
7474
7575
let profilerDiagram: ProfilerDiagram | undefined = $state()
76+
// The loaded profile's toplevel node id, so the analysis panel can recognise overview data.
77+
const diagramRootNodeId = $derived(profilerDiagram?.getProfile()?.rootNodeId)
7678
let tooltipData: TooltipData | null = $state(null)
7779
// Most recently inspected operator; the "Node" segment restores it via `setMetricsMode('node')`.
7880
let lastNodeData: NodeAttributes | null = $state(null)
@@ -258,6 +260,7 @@
258260
const analysisTabProps = $derived<AnalysisTabProps>({
259261
metricsMode,
260262
tooltipData,
263+
rootNodeId: diagramRootNodeId,
261264
showAdvancedMetrics,
262265
lookup,
263266
logText,

js-packages/profiler-layout/src/lib/components/tabs/MetricsTab.svelte

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@
99
export type AnalysisTabProps = {
1010
metricsMode: MetricsMode
1111
tooltipData: TooltipData | null
12+
/** Id of the loaded profile's toplevel node, so the Metrics view can tell the overview from a
13+
* single operator. `undefined` until a profile is loaded. */
14+
rootNodeId: string | undefined
1215
/** When true, metrics flagged `advanced` in the profile metadata are shown too. */
1316
showAdvancedMetrics: boolean
1417
lookup: LookupCoordinator
@@ -30,6 +33,7 @@
3033
let {
3134
metricsMode,
3235
tooltipData,
36+
rootNodeId,
3337
showAdvancedMetrics,
3438
lookup,
3539
onSearchNode
@@ -39,6 +43,7 @@
3943
<MetricsView
4044
mode={metricsMode}
4145
{tooltipData}
46+
{rootNodeId}
4247
showAdvanced={showAdvancedMetrics}
4348
{lookup}
4449
{onSearchNode}

js-packages/profiler-lib/src/index.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ export {
1919
CircuitProfile,
2020
PropertyValue,
2121
MissingValue,
22-
TOP_NODE_ID,
2322
type JsonProfiles
2423
} from './profile.js';
2524
export { type Dataflow, type SourcePositionRange } from './dataflow.js';

js-packages/profiler-lib/src/profile.test.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { describe, expect, it } from 'vitest'
22
import {
33
BooleanValue,
44
BytesValue,
5+
CircuitProfile,
56
CountValue,
67
MissingValue,
78
PercentValue,
@@ -10,6 +11,22 @@ import {
1011
TimeValue
1112
} from './profile.js'
1213

14+
describe('CircuitProfile.isTop', () => {
15+
it('recognises the toplevel node by the parsed root id', () => {
16+
const profile = new CircuitProfile(1, 'n')
17+
expect(profile.isTop('n')).toBe(true)
18+
expect(profile.isTop('n0')).toBe(false)
19+
expect(profile.isTop('42')).toBe(false)
20+
})
21+
22+
it('does not assume the root id is "n"', () => {
23+
// The format conventionally emits "n", but isTop must follow whatever the profile carries.
24+
const profile = new CircuitProfile(1, 'root-7')
25+
expect(profile.isTop('root-7')).toBe(true)
26+
expect(profile.isTop('n')).toBe(false)
27+
})
28+
})
29+
1330
describe('CountValue', () => {
1431
it('toString formats whole numbers with K/M/B suffixes', () => {
1532
expect(new CountValue(0).toString()).toBe('0')

js-packages/profiler-lib/src/profile.ts

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,6 @@ import { type MirNode, SourcePositionRanges, SourcePositionRange, Sources, type
66
type JsonMeasurement = Array<any>;
77
export type NodeId = string;
88

9-
/** Id of the toplevel profile graph node. Every profile graph is a single node containing the
10-
* whole circuit; its metrics are the circuit-wide overview rather than one operator's. The id is
11-
* fixed by the profile format. */
12-
export const TOP_NODE_ID: NodeId = "n";
13-
149
export type CircuitMetricCategory = string;
1510

1611
export interface ProfileMetricDescription {
@@ -1336,7 +1331,7 @@ export class CircuitProfile {
13361331
* Profile graphs are always a single node containing everything else inside.
13371332
* That node is pretty much ignored everywhere else in this code after parsing. */
13381333
isTop(node: NodeId): boolean {
1339-
return node === TOP_NODE_ID;
1334+
return node === this.rootNodeId;
13401335
}
13411336

13421337
addNode(n: JsonSimpleNodeWrapper | JsonClusterWrapper, parent: Option<NodeId>) {
@@ -1534,7 +1529,9 @@ export class CircuitProfile {
15341529
return Option.some(ranges[0]!);
15351530
}
15361531

1537-
constructor(readonly worker_count: number) { }
1532+
/** @param rootNodeId Id of the toplevel graph node, taken from the parsed profile rather than
1533+
* assumed, so {@link isTop} stays correct whatever id the format emits. */
1534+
constructor(readonly worker_count: number, readonly rootNodeId: NodeId) { }
15381535

15391536
// Scan the nodes and compute the range of each property
15401537
computePropertyRanges() {
@@ -1607,7 +1604,7 @@ export class CircuitProfile {
16071604
// Decode the graph structure and create the nodes.
16081605
// The graph itself is always a complex node.
16091606
let rootNodeId = json.graph.nodes.id;
1610-
let result = new CircuitProfile(worker_count);
1607+
let result = new CircuitProfile(worker_count, rootNodeId);
16111608
result.complexNodes.set(rootNodeId,
16121609
new ComplexNode(rootNodeId, json.graph.nodes.label, worker_count));
16131610
for (const nodeWrapper of json.graph.nodes.nodes) {

0 commit comments

Comments
 (0)