Skip to content

Commit 77b0e2d

Browse files
committed
Add payload relayout API and observatory graph relayout integration
1 parent d38fb2f commit 77b0e2d

3 files changed

Lines changed: 346 additions & 21 deletions

File tree

backends/qualcomm/debugger/observatory/observatory.py

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -417,6 +417,30 @@ def _generate_report_payload(
417417
dashboard_views[lens_name] = dashboard_view
418418

419419
graph_payload = graph_hub.build_payload()
420+
graph_assets = graph_payload["graph_assets"]
421+
graph_layers = graph_payload["graph_layers"]
422+
for graph_ref, asset in graph_assets.items():
423+
if not isinstance(asset, dict):
424+
continue
425+
base_payload = asset.get("base")
426+
if not isinstance(base_payload, dict):
427+
continue
428+
429+
extensions_payload = graph_layers.get(graph_ref, {})
430+
if not isinstance(extensions_payload, dict) or not extensions_payload:
431+
continue
432+
433+
try:
434+
asset["base"] = FXGraphExporter.relayout_payload_base(
435+
base_payload,
436+
extensions_payload=extensions_payload,
437+
)
438+
except Exception as exc:
439+
logging.warning(
440+
"[Observatory] FX relayout failed for graph_ref=%s: %s",
441+
graph_ref,
442+
exc,
443+
)
420444

421445
payload = {
422446
"resources": resources,
@@ -436,8 +460,8 @@ def _generate_report_payload(
436460
"start_data": session.start_data,
437461
"end_data": session.end_data,
438462
},
439-
"graph_assets": graph_payload["graph_assets"],
440-
"graph_layers": graph_payload["graph_layers"],
463+
"graph_assets": graph_assets,
464+
"graph_layers": graph_layers,
441465
}
442466

443467
Observatory._encode_html_blocks(serialized_records, dashboard_views)
Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
# Copyright (c) Qualcomm Innovation Center, Inc.
2+
# All rights reserved
3+
#
4+
# This source code is licensed under the BSD-style license found in the
5+
# LICENSE file in the root directory of this source tree.
6+
7+
from __future__ import annotations
8+
9+
from executorch.backends.qualcomm.debugger.observatory.interfaces import (
10+
AnalysisResult,
11+
Frontend,
12+
Lens,
13+
RecordAnalysis,
14+
RecordDigest,
15+
SessionResult,
16+
)
17+
from executorch.backends.qualcomm.debugger.observatory.observatory import Observatory
18+
from executorch.backends.qualcomm.utils.fx_viewer import (
19+
FXGraphExporter,
20+
GraphExtensionNodePayload,
21+
GraphExtensionPayload,
22+
)
23+
24+
25+
def _node_by_id(base_payload: dict, node_id: str) -> dict:
26+
for node in base_payload["nodes"]:
27+
if node.get("id") == node_id:
28+
return node
29+
raise KeyError(node_id)
30+
31+
32+
def test_relayout_payload_base_uses_extension_label_lines() -> None:
33+
base_payload = {
34+
"legend": [],
35+
"nodes": [
36+
{"id": "n0", "label": "a", "x": 0.0, "y": 0.0, "width": 100, "height": 36, "info": {}},
37+
{"id": "n1", "label": "b", "x": 0.0, "y": 0.0, "width": 100, "height": 36, "info": {}},
38+
],
39+
"edges": [{"v": "n0", "w": "n1", "points": []}],
40+
}
41+
ext_payload = {
42+
"acc/psnr": {
43+
"name": "PSNR",
44+
"legend": [],
45+
"nodes": {
46+
"n0": {"label_append": ["psnr=12.34567890123456789"]},
47+
},
48+
}
49+
}
50+
51+
relaid = FXGraphExporter.relayout_payload_base(base_payload, ext_payload)
52+
53+
assert _node_by_id(base_payload, "n0")["width"] == 100
54+
assert _node_by_id(base_payload, "n0")["height"] == 36
55+
assert base_payload["edges"][0]["points"] == []
56+
57+
n0 = _node_by_id(relaid, "n0")
58+
assert n0["width"] > 100
59+
assert n0["height"] > 36
60+
assert relaid["edges"][0]["points"]
61+
62+
63+
class _FakeGraphLens(Lens):
64+
@classmethod
65+
def get_name(cls) -> str:
66+
return "graph"
67+
68+
@staticmethod
69+
def get_frontend_spec() -> Frontend:
70+
return Frontend()
71+
72+
73+
class _FakeLayerLens(Lens):
74+
@classmethod
75+
def get_name(cls) -> str:
76+
return "fake_layer"
77+
78+
@staticmethod
79+
def analyze(records, config) -> AnalysisResult:
80+
result = AnalysisResult()
81+
for record in records:
82+
rec_analysis = RecordAnalysis()
83+
rec_analysis.add_graph_layer(
84+
"test",
85+
GraphExtensionPayload(
86+
id="test",
87+
name="Test Layer",
88+
legend=[],
89+
nodes={
90+
"n0": GraphExtensionNodePayload(
91+
label_append=["a long extension label for relayout"],
92+
)
93+
},
94+
),
95+
)
96+
result.per_record_data[record.name] = rec_analysis
97+
return result
98+
99+
@staticmethod
100+
def get_frontend_spec() -> Frontend:
101+
return Frontend()
102+
103+
104+
def test_observatory_relayout_applied_during_payload_assembly() -> None:
105+
records = [
106+
RecordDigest(
107+
name="r0",
108+
timestamp=0.0,
109+
data={
110+
"graph": {
111+
"graph_ref": "r0",
112+
"base": {
113+
"legend": [],
114+
"nodes": [
115+
{
116+
"id": "n0",
117+
"label": "a",
118+
"x": 0.0,
119+
"y": 0.0,
120+
"width": 100,
121+
"height": 36,
122+
"info": {},
123+
},
124+
{
125+
"id": "n1",
126+
"label": "b",
127+
"x": 0.0,
128+
"y": 0.0,
129+
"width": 100,
130+
"height": 36,
131+
"info": {},
132+
},
133+
],
134+
"edges": [{"v": "n0", "w": "n1", "points": []}],
135+
},
136+
"meta": {},
137+
}
138+
},
139+
)
140+
]
141+
142+
payload = Observatory._generate_report_payload(
143+
records=records,
144+
session=SessionResult(),
145+
config={},
146+
lens_registry=[_FakeGraphLens, _FakeLayerLens],
147+
)
148+
149+
base = payload["graph_assets"]["r0"]["base"]
150+
assert _node_by_id(base, "n0")["width"] > 100
151+
assert _node_by_id(base, "n0")["height"] > 36
152+
assert base["edges"][0]["points"]

0 commit comments

Comments
 (0)