viz: ui cleanups from the sqtt real time branch (#15195)

* label location for packets

* work

* OTHER_* packets always get filtered out

* less
This commit is contained in:
qazal
2026-03-09 22:33:53 +02:00
committed by GitHub
parent a615ed8ebe
commit 02ceeab3a7
2 changed files with 16 additions and 20 deletions

View File

@@ -268,7 +268,7 @@ function setFocus(key) {
const html = d3.select(".info").html("");
if (eventType === EventTypes.EXEC) {
const [n, _, ...rest] = e.arg.tooltipText.split("\n");
html.append(() => tabulate([["Name", colored(e.label)], ["Duration", formatTime(e.width)], ["Start Time", formatTime(e.x)]]));
html.append(() => tabulate([["Name", colored(e.arg.label)], ["Duration", formatTime(e.width)], ["Start Time", formatTime(e.x)]]));
let group = html.append("div").classed("args", true);
for (const r of rest) group.append("p").text(r);
group = html.append("div").classed("args", true);
@@ -323,10 +323,10 @@ function setFocus(key) {
const EventTypes = { EXEC:0, BUF:1 };
async function renderProfiler(path, unit, opts) {
async function renderProfiler(path, opts) {
displaySelection("#profiler");
// support non realtime x axis units
formatTime = unit === "realtime" ? formatMicroseconds : formatCycles;
formatTime = opts.unit === "ms" ? formatMicroseconds : formatCycles;
if (data?.path !== path) { data = {tracks:new Map(), axes:{}, path, first:null, pcToShape:new Map()}; focusedDevice = null; focusedShape = null; }
setFocus(focusedShape);
// layout once!
@@ -378,16 +378,12 @@ async function renderProfiler(path, unit, opts) {
for (let j=0; j<eventsLen; j++) {
const e = {name:strings[u32()], ref:optional(u32()), key:optional(u32()), st:u32(), dur:f32(), info:strings[u32()] || null};
// find a free level to put the event
let depth = 0;
if (opts.levelKey != null) { depth = opts.levelKey(e); levels[depth] = 0; }
else {
depth = levels.findIndex(levelEt => e.st >= levelEt);
const et = e.st+Math.trunc(e.dur);
if (depth === -1) {
depth = levels.length;
levels.push(et);
} else levels[depth] = et;
}
let depth = levels.findIndex(levelEt => e.st >= levelEt);
const et = e.st+Math.trunc(e.dur);
if (depth === -1) {
depth = levels.length;
levels.push(et);
} else levels[depth] = et;
if (depth === 0 || opts.colorByName) colorKey = e.name.split(" ")[0];
if (!colorMap.has(colorKey)) {
const color = typeof colors === "function" ? colors(colorKey)
@@ -597,7 +593,7 @@ async function renderProfiler(path, unit, opts) {
const labelX = x+ctx.lineWidth+2;
if (labelX <= lastLabelEnd) continue;
const label = formatTime(tick, et-st <= 1e3 ? true : false);
const label = formatTime(tick, et-st <= 1e3);
ctx.textBaseline = "top";
ctx.fillText(label, labelX, tickSize);
lastLabelEnd = labelX + ctx.measureText(label).width + 4;
@@ -880,7 +876,7 @@ async function main() {
if (url.pathname+url.search !== ckey) e.close();
else if (e.readyState === EventSource.OPEN) activeSrc = e;
}
if (ctx.name === "Profiler") return renderProfiler("/get_profile", "realtime", { width:"132px" });
if (ctx.name === "Profiler") return renderProfiler("/get_profile", {unit:"ms", width:"132px"});
if (workerUrl == null) await initWorker();
if (ckey in cache) {
ret = cache[ckey];
@@ -898,8 +894,8 @@ async function main() {
}
// timeline with cycles on the x axis
if (ret instanceof ArrayBuffer) {
opts = {heightScale:0.5, hideLabels:true, levelKey:step.name.includes("PKTS") ? (e) => parseInt(e.name.split(" ")[1].split(":")[1]) : null, colorByName:ckey.includes("pkts")};
return renderProfiler(ckey, "clk", opts);
const pkts = step.name.includes("PKTS");
return renderProfiler(ckey, {unit:"clk", heightScale:0.5, hideLabels:true, colorByName:pkts});
}
metadata.replaceChildren(...((ret.metadata ?? []).map((m) => {
return tabulate(m.map((e) => [e.label.trim(), typeof e.value === "string" ? e.value : formatUnit(e.value)]));

View File

@@ -340,17 +340,17 @@ def sqtt_timeline(data:bytes, lib:bytes, target:str) -> list[ProfileEvent]:
ret:list[ProfileEvent] = []
rows:dict[str, None] = {}
trace:dict[str, set[int]] = {}
def add(name:str, p:PacketType, idx=0, width=1, op_name=None, wave=None, info:InstructionInfo|None=None) -> None:
def add(name:str, p:PacketType, width=1, op_name=None, wave=None, info:InstructionInfo|None=None) -> None:
if hasattr(p, "wave"): wave = p.wave
rows.setdefault(r:=(f"WAVE:{wave}" if wave is not None else f"{p.__class__.__name__}:0 {name}"))
key = TracingKey(f"{op_name if op_name is not None else name} OP:{idx}", ret=f"PC:{info.pc}" if info is not None else None)
key = TracingKey(f"{op_name if op_name is not None else name}", ret=f"PC:{info.pc}" if info is not None else None)
ret.append(ProfileRangeEvent(r, key, Decimal(p._time), Decimal(p._time+width)))
for p, info in map_insts(data, lib, target):
if len(ret) > getenv("MAX_SQTT_PKTS", 50_000): break
if isinstance(p, (INST, INST_RDNA4)):
op_name = p.op.name if isinstance(p.op, (InstOp, InstOpRDNA4)) else f"0x{p.op:02x}"
name, width = (op_name, 10 if "BARRIER" in op_name else 1)
add(name, p, width=width, idx=int("OTHER" in name), info=info)
add(name, p, width=width, info=info)
if isinstance(p, (VALUINST, IMMEDIATE)): add(p.__class__.__name__, p, info=info)
if isinstance(p, IMMEDIATE_MASK): add("IMMEDIATE", p, wave=unwrap(info).wave, info=info)
if isinstance(p, (VMEMEXEC, ALUEXEC)):