diff --git a/docs/report/1H-codesign-paper/figures/ipcq_alternatives_architecture_flow.png b/docs/report/1H-codesign-paper/figures/ipcq_alternatives_architecture_flow.png new file mode 100644 index 0000000..c71782b Binary files /dev/null and b/docs/report/1H-codesign-paper/figures/ipcq_alternatives_architecture_flow.png differ diff --git a/docs/report/1H-codesign-paper/figures/ipcq_alternatives_architecture_stacked.png b/docs/report/1H-codesign-paper/figures/ipcq_alternatives_architecture_stacked.png new file mode 100644 index 0000000..023130c Binary files /dev/null and b/docs/report/1H-codesign-paper/figures/ipcq_alternatives_architecture_stacked.png differ diff --git a/scripts/paper/paper_plot_ipcq_alternatives_comparison.py b/scripts/paper/paper_plot_ipcq_alternatives_comparison.py index 8676c8b..c1f633c 100644 --- a/scripts/paper/paper_plot_ipcq_alternatives_comparison.py +++ b/scripts/paper/paper_plot_ipcq_alternatives_comparison.py @@ -238,6 +238,267 @@ def _plot_architecture() -> Path: return out +# Module-level flow-diagram helpers and constants. +_FLOW_DATA = "#6699CC" # blue flit (data) +_FLOW_CTRL = "#ED7D65" # orange flit (control) +_FLOW_CRED = "#7BB661" # green (credit / ack) + + +def _flow_swim(ax, x, y, w, h, label, sub=None): + ax.add_patch(mpatches.FancyBboxPatch( + (x, y), w, h, + boxstyle="round,pad=0.02,rounding_size=0.08", + facecolor="white", edgecolor="#3a3a3a", linewidth=1.6)) + ax.text(x + w / 2, y + h / 2 + (0.20 if sub else 0), + label, ha="center", va="center", + fontsize=10.5, fontweight="bold", color="#111") + if sub: + ax.text(x + w / 2, y + h / 2 - 0.35, sub, + ha="center", va="center", + fontsize=8, color="#555", fontstyle="italic") + + +def _flow_flit(ax, x, y, color, letter="", size=0.32): + ax.add_patch(mpatches.FancyBboxPatch( + (x - size / 2, y - size / 2), size, size, + boxstyle="round,pad=0.01,rounding_size=0.04", + facecolor=color, edgecolor="#222", linewidth=0.8)) + if letter: + ax.text(x, y, letter, ha="center", va="center", + fontsize=8.5, fontweight="bold", color="white") + + +def _flow_wire(ax, x1, x2, y, color="#888"): + ax.plot([x1, x2], [y, y], color=color, lw=1.0, zorder=0) + + +def _flow_dot(ax, x, y, color): + ax.add_patch(mpatches.Circle((x, y), 0.13, + facecolor=color, edgecolor="#333", + linewidth=0.8, zorder=4)) + + +def _flow_label(ax, x, y, text, color="#222", fontsize=9): + ax.text(x, y, text, ha="center", va="center", + fontsize=fontsize, color=color, fontweight="bold") + + +def _flow_lead(ax, x_tail, y_tail, x_head, y_head, color="#777"): + ax.plot([x_tail, x_head], [y_tail, y_head], + color=color, lw=0.8, ls=":", zorder=2) + + +def _flow_setup(ax, kind): + ax.set_xlim(0, 20); ax.set_ylim(0, 10); ax.axis("off") + ax.add_patch(mpatches.FancyBboxPatch( + (0.15, 0.15), 19.7, 9.7, + boxstyle="round,pad=0.05,rounding_size=0.12", + facecolor="white", edgecolor=_COLOR[kind], + linewidth=2.2, zorder=0)) + ax.text(10, 0.65, _TITLE[kind], + ha="center", va="center", fontsize=11.5, + fontweight="bold", + color=("#1B5E20" if kind == "ipcq" else "white"), + bbox=dict( + facecolor=("#E8F5E9" if kind == "ipcq" else _COLOR[kind]), + edgecolor=("#2E7D32" if kind == "ipcq" else _COLOR[kind]), + boxstyle="round,pad=0.40", linewidth=1.5)) + + +def _draw_flow_case(ax, kind): + """Draw one Sender → NoC → Receiver flow panel for `kind`.""" + _flow_setup(ax, kind) + if kind == "doorbell": + _draw_case_doorbell(ax) + elif kind == "hmq": + _draw_case_hmq(ax) + elif kind == "rdma": + _draw_case_rdma(ax) + elif kind == "ipcq": + _draw_case_ipcq(ax) + + +def _draw_case_doorbell(ax): + _flow_swim(ax, 0.7, 4.4, 2.8, 2.0, "Sender\nkernel") + _flow_swim(ax, 7.4, 4.4, 3.0, 2.0, "NoC / UCIe", sub="2 DMA tx") + _flow_swim(ax, 14.4, 4.4, 3.0, 2.0, "Doorbell reg\n+ landing TCM") + _flow_swim(ax, 17.6, 6.7, 2.0, 1.7, "Receiver\n(poll)", sub="poll loop") + _flow_wire(ax, 3.5, 7.4, 5.7); _flow_wire(ax, 10.4, 14.4, 5.7) + for x in [4.0, 4.7, 5.4]: + _flow_flit(ax, x, 5.7, _FLOW_DATA, "D") + for x in [11.0, 11.7]: + _flow_flit(ax, x, 5.7, _FLOW_DATA, "D") + _flow_wire(ax, 3.5, 7.4, 5.1); _flow_wire(ax, 10.4, 14.4, 5.1) + _flow_flit(ax, 4.0, 5.1, _FLOW_CTRL, "F") + _flow_flit(ax, 4.7, 5.1, _FLOW_CTRL, "DB") + _flow_flit(ax, 11.0, 5.1, _FLOW_CTRL, "DB") + for y in (8.0, 7.5, 7.0): + ax.annotate("", xy=(15.5, y), xytext=(17.6, y), + arrowprops=dict(arrowstyle="->", color="#aa3a30", + lw=1.0, ls=":")) + _flow_dot(ax, 5.0, 3.5, "#c5a35a") + _flow_lead(ax, 5.0, 3.6, 5.0, 4.4) + _flow_label(ax, 5.0, 3.2, "fence + 2 DMA writes", color="#5a3e20") + _flow_dot(ax, 17.0, 8.8, "#7BB661") + _flow_lead(ax, 17.0, 8.7, 17.0, 8.0) + _flow_label(ax, 17.0, 9.1, "receiver polling loop", color="#2E7D32") + + +def _draw_case_hmq(ax): + _flow_swim(ax, 0.7, 4.4, 2.8, 2.0, "Sender CPU") + _flow_swim(ax, 4.6, 6.6, 2.8, 1.8, "HMQ engine", sub="descriptor") + _flow_swim(ax, 4.6, 3.6, 2.8, 1.8, "PE_DMA", sub="data path") + _flow_swim(ax, 9.6, 4.4, 3.0, 2.0, "NoC / UCIe", sub="2 paths") + _flow_swim(ax, 14.4, 6.6, 2.8, 1.8, "Peer HMQ") + _flow_swim(ax, 14.4, 3.6, 2.8, 1.8, "Recv TCM") + _flow_swim(ax, 17.6, 4.4, 2.0, 2.0, "Receiver\nCPU") + _flow_wire(ax, 3.5, 4.6, 7.5); _flow_wire(ax, 7.4, 9.6, 7.5) + _flow_wire(ax, 12.6, 14.4, 7.5); _flow_wire(ax, 17.2, 17.6, 5.4) + _flow_flit(ax, 4.0, 7.5, _FLOW_CTRL, "Hd") + _flow_flit(ax, 8.5, 7.5, _FLOW_CTRL, "Hd") + _flow_flit(ax, 13.5, 7.5, _FLOW_CTRL, "Hd") + _flow_wire(ax, 3.5, 4.6, 4.5); _flow_wire(ax, 7.4, 9.6, 4.5) + _flow_wire(ax, 12.6, 14.4, 4.5) + for x in [4.0, 8.0, 8.7, 13.5]: + _flow_flit(ax, x, 4.5, _FLOW_DATA, "D") + _flow_dot(ax, 11.1, 9.0, "#c5a35a") + _flow_lead(ax, 11.1, 8.9, 11.1, 7.6) + _flow_label(ax, 11.1, 9.25, "duplicated control + data paths", + color="#5a3e20") + + +def _draw_case_rdma(ax): + _flow_swim(ax, 0.7, 4.4, 2.8, 2.0, "Sender\nkernel") + _flow_swim(ax, 4.8, 4.4, 2.8, 2.0, "WQE +\nPE_DMA") + _flow_swim(ax, 8.5, 4.4, 3.0, 2.0, "NoC / UCIe") + _flow_swim(ax, 13.0, 4.4, 3.0, 2.0, "CQ + landing\nTCM", + sub="auto-CQE") + _flow_swim(ax, 17.0, 6.7, 2.5, 1.7, "Receiver\n(poll CQ)") + _flow_wire(ax, 3.5, 4.8, 5.7) + _flow_flit(ax, 4.0, 5.7, _FLOW_CTRL, "W") + _flow_wire(ax, 7.6, 8.5, 5.4); _flow_wire(ax, 11.5, 13.0, 5.4) + _flow_flit(ax, 8.1, 5.4, _FLOW_DATA, "D") + _flow_flit(ax, 9.2, 5.4, _FLOW_DATA, "D") + _flow_flit(ax, 9.9, 5.4, _FLOW_CTRL, "Q") + _flow_flit(ax, 11.0, 5.4, _FLOW_DATA, "D") + _flow_flit(ax, 12.0, 5.4, _FLOW_CTRL, "Q") + for y in (8.0, 7.5, 7.0): + ax.annotate("", xy=(14.5, y), xytext=(17.0, y), + arrowprops=dict(arrowstyle="->", color="#7c1b78", + lw=1.0, ls=":")) + _flow_dot(ax, 11.0, 3.5, "#c5a35a") + _flow_lead(ax, 11.0, 3.6, 11.0, 4.4) + _flow_label(ax, 11.0, 3.2, "CQE rides with DMA payload", + color="#5a3e20") + _flow_dot(ax, 18.0, 8.8, "#7BB661") + _flow_lead(ax, 18.0, 8.7, 18.0, 8.0) + _flow_label(ax, 18.0, 9.1, "CQ poll / IRQ", color="#2E7D32") + + +def _draw_case_ipcq(ax): + _flow_swim(ax, 0.7, 4.4, 2.8, 2.0, "Sender PE\n(tl.send)") + _flow_swim(ax, 4.5, 6.6, 3.0, 1.8, "PE_IPCQ", sub="ring push") + _flow_swim(ax, 4.5, 3.6, 3.0, 1.8, "PE_DMA", sub="data push") + _flow_swim(ax, 9.4, 4.4, 3.0, 2.0, "NoC / UCIe", sub="dir-addr") + _flow_swim(ax, 13.8, 6.6, 3.0, 1.8, "PE_IPCQ", + sub="tail++ , credit") + _flow_swim(ax, 13.8, 3.6, 3.0, 1.8, "PE_DMA", + sub="landing TCM") + _flow_swim(ax, 17.6, 4.4, 2.0, 2.0, "Receiver\nPE\n(tl.recv)") + _flow_wire(ax, 3.5, 4.5, 7.5); _flow_wire(ax, 7.5, 9.4, 7.5) + _flow_wire(ax, 12.4, 13.8, 7.5); _flow_wire(ax, 16.8, 17.6, 5.4) + _flow_flit(ax, 4.0, 7.5, _FLOW_CTRL, "M") + _flow_flit(ax, 8.4, 7.5, _FLOW_CTRL, "M") + _flow_flit(ax, 13.0, 7.5, _FLOW_CTRL, "M") + _flow_wire(ax, 3.5, 4.5, 4.5); _flow_wire(ax, 7.5, 9.4, 4.5) + _flow_wire(ax, 12.4, 13.8, 4.5) + _flow_flit(ax, 4.0, 4.5, _FLOW_DATA, "D") + _flow_flit(ax, 8.4, 4.5, _FLOW_DATA, "D") + _flow_flit(ax, 11.0, 4.5, _FLOW_DATA, "D") + _flow_flit(ax, 13.0, 4.5, _FLOW_DATA, "D") + ax.annotate("", xy=(4.5, 9.0), xytext=(16.8, 9.0), + arrowprops=dict(arrowstyle="->", color=_FLOW_CRED, + lw=1.6, ls=(0, (5, 3)))) + _flow_label(ax, 10.5, 9.35, "credit piggyback (no separate ACK)", + color=_FLOW_CRED) + _flow_dot(ax, 6.0, 2.6, "#c5a35a") + _flow_lead(ax, 6.0, 2.7, 6.0, 3.6) + _flow_label(ax, 6.0, 2.3, "one in-line ring push + one DMA", + color="#5a3e20") + + +def _flow_legend(fig, leg_y=0.02): + """Two-row legend so the long control-flit key doesn't overlap + the shorter data/credit entries.""" + row_top = [ + (_FLOW_DATA, "Data flit D = payload"), + (_FLOW_CRED, "Credit / piggyback return"), + ] + row_bottom = [ + (_FLOW_CTRL, "Control flit: W=WQE · Q=CQE · M=ring meta" + " · DB=doorbell · F=fence · Hd=HMQ desc"), + ] + + def _emit(items, y): + lx = 0.04 + for color, text in items: + fig.patches.append(mpatches.FancyBboxPatch( + (lx, y), 0.020, 0.022, + boxstyle="round,pad=0.005,rounding_size=0.005", + facecolor=color, edgecolor="#222", linewidth=0.6, + transform=fig.transFigure)) + fig.text(lx + 0.025, y + 0.011, text, + ha="left", va="center", fontsize=10, + fontweight="bold", color="#222") + lx += 0.32 + + _emit(row_top, y=leg_y + 0.030) + _emit(row_bottom, y=leg_y) + + +# ─── Diagram 1b : 4-case flow-style architecture (latency_model look) +def _plot_architecture_flow() -> Path: + """4 panels arranged 2×2 — each a horizontal Sender → NoC → Receiver + flow with small flit-style packets, dot-marker annotations and a + bottom name plate. Aesthetic mirrors latency_model.png.""" + fig, axes = plt.subplots(2, 2, figsize=(18.0, 11.5)) + _draw_flow_case(axes[0, 0], "doorbell") + _draw_flow_case(axes[0, 1], "hmq") + _draw_flow_case(axes[1, 0], "rdma") + _draw_flow_case(axes[1, 1], "ipcq") + fig.suptitle( + "Per-send architecture = $\\Sigma$ control overhead + " + "data-path DMA + receiver wake", + fontsize=14.5, fontweight="bold", y=0.995) + _flow_legend(fig, leg_y=0.015) + fig.tight_layout(rect=(0, 0.07, 1, 0.96)) + out = _OUT_DIR / "ipcq_alternatives_architecture_flow.png" + fig.savefig(out, dpi=150, bbox_inches="tight") + plt.close(fig) + return out + + +# ─── Diagram 1c : 4-case flow-style architecture — stacked 4×1 ────── +def _plot_architecture_stacked() -> Path: + """Same per-case flow content as the 2×2 figure, but stacked one + case per row (4 rows × 1 column). Wider panels give each case more + horizontal room.""" + fig, axes = plt.subplots(4, 1, figsize=(16.0, 19.0)) + for ax, kind in zip(axes, ["doorbell", "hmq", "rdma", "ipcq"]): + _draw_flow_case(ax, kind) + fig.suptitle( + "Per-send architecture = $\\Sigma$ control overhead + " + "data-path DMA + receiver wake", + fontsize=14.5, fontweight="bold", y=0.997) + _flow_legend(fig, leg_y=0.010) + fig.tight_layout(rect=(0, 0.05, 1, 0.97)) + out = _OUT_DIR / "ipcq_alternatives_architecture_stacked.png" + fig.savefig(out, dpi=150, bbox_inches="tight") + plt.close(fig) + return out + + + # ─── Diagram 2 : Per-send latency breakdown (vertical stacks) ─────── def _plot_latency() -> Path: # (label, short, illustrative cycles, fill) @@ -782,7 +1043,9 @@ def _plot_control_data_overlay() -> Path: def main() -> None: _OUT_DIR.mkdir(parents=True, exist_ok=True) - for plot in (_plot_architecture, _plot_latency, + for plot in (_plot_architecture, _plot_architecture_flow, + _plot_architecture_stacked, + _plot_latency, _plot_opcounts, _plot_sequence, _plot_decision_matrix, _plot_control_data_overlay): diff --git a/src/kernbench/benches/1H_milestone_output/IPCQ/ipcq_alternatives_architecture_flow.png b/src/kernbench/benches/1H_milestone_output/IPCQ/ipcq_alternatives_architecture_flow.png new file mode 100644 index 0000000..c71782b Binary files /dev/null and b/src/kernbench/benches/1H_milestone_output/IPCQ/ipcq_alternatives_architecture_flow.png differ diff --git a/src/kernbench/benches/1H_milestone_output/IPCQ/ipcq_alternatives_architecture_stacked.png b/src/kernbench/benches/1H_milestone_output/IPCQ/ipcq_alternatives_architecture_stacked.png new file mode 100644 index 0000000..023130c Binary files /dev/null and b/src/kernbench/benches/1H_milestone_output/IPCQ/ipcq_alternatives_architecture_stacked.png differ