diff --git a/tinygrad/viz/js/index.js b/tinygrad/viz/js/index.js index df7f6f9fe2..05730691b9 100644 --- a/tinygrad/viz/js/index.js +++ b/tinygrad/viz/js/index.js @@ -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 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)])); diff --git a/tinygrad/viz/serve.py b/tinygrad/viz/serve.py index 7943a2f836..212426e738 100755 --- a/tinygrad/viz/serve.py +++ b/tinygrad/viz/serve.py @@ -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)):