Files
club-3090/docs/img/power-cap-4090-qwen36.py
noonghunna 20ca297378 docs: refresh 4090 cross-rig knee with @laurimyllari's richer 38-cap sweep
His earlier 15-cap sweep (260-400W, 16832066) is superseded by a
38-cap sweep at 10W resolution from 230-600W (16854218) — strictly
richer envelope. Two findings worth surfacing:

- Firmware boost-clock plateau at SM 2610 MHz: caps 400-600W produce
  identical 51.96 TPS at 393W actual draw. Auto-plateau detector in
  power-cap-sweep.sh caught both sub-plateaus cleanly (400-470W and
  480-600W).
- decode-concurrent N=4 plateau lower than decode-single (46 vs 52
  TPS) — on a 4090 + 27B Q3_K_XL the GPU is under-load at c=4 even
  at full TDP, so single-stream wins. Useful cross-rig signal.

HARDWARE.md table + chart caption updated; chart regenerated with
both load-mode curves overlaid + plateau zone shaded.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 19:54:49 +00:00

211 lines
7.7 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""Generate a tweet-ready chart from @laurimyllari's RTX 4090 power-cap sweep on llama.cpp.
Source data: https://github.com/noonghunna/club-3090/discussions/62#discussioncomment-16854218
Setup: 1× RTX 4090 air-cooled, llama.cpp default, Qwen3.6-27B-UD-Q3_K_XL GGUF, sweep on club-3090@aa99173.
Two load modes are overlaid:
- decode-single (10s × 2 timed streams per cap)
- decode-concurrent (concurrency=4, 4s/run × 3 runs × 2 batches per cap)
The two curves together show: (a) where the efficiency knee is (250-260W on either mode),
(b) the firmware boost-clock plateau locks at SM 2610 MHz / 393W draw from cap=400W onwards,
and (c) on this 27B model concurrency=4 sits below single-stream — i.e. the 4090 is in
under-load territory at c=4 on Q3_K_XL.
"""
import matplotlib.pyplot as plt
# decode-single: 38-cap sweep, 230-600W. Columns: cap, narr_tps, code_tps, actual_W, narr_tps_per_W
# Source: disc #62 16854218 (decode-single 14:42:23Z run)
decode_single = [
(230, 41.47, 41.47, 229.72, 0.181),
(240, 43.47, 43.77, 240.21, 0.181),
(250, 46.37, 46.36, 249.84, 0.186),
(260, 48.26, 48.16, 259.90, 0.186), # sweet spot (tied with 250W)
(270, 48.96, 48.96, 269.92, 0.181),
(280, 49.36, 49.36, 279.72, 0.176),
(290, 49.76, 49.86, 289.63, 0.172),
(300, 50.16, 50.16, 299.69, 0.167),
(310, 50.46, 50.56, 309.58, 0.163),
(320, 50.76, 50.76, 319.34, 0.159),
(330, 51.06, 51.06, 329.55, 0.155),
(340, 51.26, 51.26, 339.47, 0.151),
(350, 51.36, 51.36, 349.67, 0.147),
(360, 51.56, 51.56, 359.38, 0.143),
(370, 51.66, 51.66, 369.43, 0.140),
(380, 51.86, 51.86, 378.50, 0.137),
(390, 51.95, 51.96, 387.96, 0.134),
(400, 51.96, 51.96, 392.17, 0.132), # firmware plateau begins
(410, 51.96, 51.96, 391.69, 0.133),
(420, 51.96, 51.96, 392.14, 0.133),
(430, 51.96, 51.96, 392.13, 0.133),
(440, 51.95, 51.96, 393.26, 0.132),
(450, 51.96, 51.96, 393.25, 0.132),
(460, 51.86, 51.86, 393.58, 0.132),
(470, 51.96, 51.96, 393.19, 0.132),
(480, 51.85, 51.96, 394.23, 0.132),
(490, 51.86, 51.96, 394.13, 0.132),
(500, 51.86, 51.96, 393.15, 0.132),
(510, 51.86, 51.86, 394.03, 0.132),
(520, 51.86, 51.96, 393.96, 0.132),
(530, 51.85, 51.96, 394.25, 0.132),
(540, 51.86, 51.96, 394.76, 0.131),
(550, 51.86, 51.96, 394.88, 0.131),
(560, 51.86, 51.96, 394.58, 0.131),
(570, 51.85, 51.96, 394.33, 0.131),
(580, 51.86, 51.96, 394.32, 0.132),
(590, 51.86, 51.96, 394.52, 0.131),
(600, 51.85, 51.96, 394.87, 0.131),
]
# decode-concurrent N=4: 38-cap sweep, 230-600W.
# Source: disc #62 16854218 (decode-concurrent 14:58:09Z run, concurrency=4 auto-calibrated)
decode_concurrent = [
(230, 36.96, 36.46, 229.58, 0.161),
(240, 38.92, 38.69, 239.79, 0.162),
(250, 41.14, 40.66, 249.65, 0.165), # under-load knee (tied with 260W)
(260, 42.13, 42.35, 259.50, 0.162),
(270, 43.11, 43.34, 269.13, 0.160),
(280, 43.60, 43.61, 278.92, 0.156),
(290, 44.10, 43.85, 289.16, 0.153),
(300, 44.58, 44.35, 299.48, 0.149),
(310, 44.59, 44.83, 309.32, 0.144),
(320, 44.83, 45.08, 319.19, 0.140),
(330, 45.08, 45.07, 328.98, 0.137),
(340, 45.34, 45.33, 339.07, 0.134),
(350, 45.59, 45.58, 349.02, 0.131),
(360, 45.82, 45.57, 358.57, 0.128),
(370, 45.82, 45.81, 368.40, 0.124),
(380, 45.82, 46.06, 378.29, 0.121),
(390, 46.29, 46.07, 387.93, 0.119),
(400, 46.08, 46.06, 393.64, 0.117), # plateau begins
(410, 46.31, 46.06, 394.30, 0.117),
(420, 46.06, 46.07, 394.04, 0.117),
(430, 46.07, 46.07, 395.27, 0.117),
(440, 46.08, 46.07, 394.50, 0.117),
(450, 46.08, 46.07, 394.64, 0.117),
(460, 46.07, 46.04, 394.67, 0.117),
(470, 46.04, 46.08, 394.48, 0.117),
(480, 46.07, 46.08, 394.49, 0.117),
(490, 46.08, 46.07, 394.24, 0.117),
(500, 46.32, 46.07, 394.13, 0.118),
(510, 46.07, 46.08, 394.65, 0.117),
(520, 46.08, 46.07, 395.27, 0.117),
(530, 46.08, 46.06, 394.79, 0.117),
(540, 46.06, 46.07, 395.07, 0.117),
(550, 46.07, 46.07, 395.58, 0.116),
(560, 46.08, 46.07, 395.36, 0.117),
(570, 46.07, 46.07, 395.51, 0.116),
(580, 46.07, 46.07, 394.87, 0.117),
(590, 46.08, 46.07, 395.44, 0.117),
(600, 46.07, 46.06, 395.51, 0.116),
]
ds_caps = [d[0] for d in decode_single]
ds_narr = [d[1] for d in decode_single]
ds_eff = [d[4] for d in decode_single]
dc_caps = [d[0] for d in decode_concurrent]
dc_narr = [d[1] for d in decode_concurrent]
dc_eff = [d[4] for d in decode_concurrent]
plt.rcParams.update({
"font.family": "sans-serif",
"font.size": 12,
"axes.titlesize": 16,
"axes.titleweight": "bold",
"axes.labelsize": 13,
"figure.facecolor": "white",
"axes.facecolor": "white",
})
fig, ax1 = plt.subplots(figsize=(12, 6.5), dpi=150)
# Firmware boost-clock plateau shading (caps 400-600W)
ax1.axvspan(395, 605, color="#ffd6a5", alpha=0.35, zorder=0,
label="Firmware boost-clock plateau (SM 2610 MHz / 393W draw)")
# Left axis: TPS (both modes)
color_ds = "#1f77b4"
color_dc = "#2ca02c"
ax1.plot(ds_caps, ds_narr, "o-", color=color_ds, linewidth=2.2, markersize=5,
label="decode-single (narr TPS)", zorder=3)
ax1.plot(dc_caps, dc_narr, "s-", color=color_dc, linewidth=2.2, markersize=5,
label="decode-concurrent N=4 (narr TPS)", zorder=3)
ax1.set_xlabel("Power cap (W)", fontsize=13)
ax1.set_ylabel("Narrative wall TPS", fontsize=13)
ax1.set_xlim(225, 605)
ax1.set_ylim(35, 54)
ax1.grid(True, alpha=0.3, zorder=0)
ax1.tick_params(axis="both", labelsize=11)
# Right axis: TPS/W efficiency (both modes)
ax2 = ax1.twinx()
color_eff_ds = "#d62728"
color_eff_dc = "#9467bd"
ax2.plot(ds_caps, ds_eff, "^--", color=color_eff_ds, linewidth=1.5, markersize=4,
alpha=0.85, label="decode-single TPS/W", zorder=2)
ax2.plot(dc_caps, dc_eff, "v--", color=color_eff_dc, linewidth=1.5, markersize=4,
alpha=0.85, label="decode-concurrent TPS/W", zorder=2)
ax2.set_ylabel("Efficiency: TPS/W (narrative)", fontsize=13, color="#555")
ax2.tick_params(axis="y", labelcolor="#555", labelsize=11)
ax2.set_ylim(0.10, 0.20)
# Sweet spot annotation: 260W on decode-single
ax1.axvline(260, color="goldenrod", linestyle=":", alpha=0.5, linewidth=1.5)
ax1.annotate(
"★ 260W\n0.186 TPS/W\n(decode-single knee)\n42% below stock TDP",
xy=(260, 48.26),
xytext=(295, 50.5),
fontsize=10.5,
fontweight="bold",
bbox=dict(boxstyle="round,pad=0.4", facecolor="#fff3cd", edgecolor="goldenrod", linewidth=1.2),
arrowprops=dict(arrowstyle="->", color="goldenrod", lw=1.5),
zorder=4,
)
# Plateau annotation
ax1.annotate(
"Caps 400-600W functionally identical\n(SM 2610 MHz / 393W actual draw)",
xy=(500, 51.96),
xytext=(450, 47.5),
fontsize=9.5,
ha="center",
color="#a85a00",
fontstyle="italic",
arrowprops=dict(arrowstyle="->", color="#cc8800", lw=1),
)
# Title
ax1.set_title(
"RTX 4090 + Qwen3.6-27B + llama.cpp — power-cap efficiency curves",
pad=14,
)
# Subtitle
fig.text(
0.5, 0.92,
"1× 4090 air-cooled, llama.cpp default, Q3_K_XL GGUF, 38-cap sweep at 10W | data: @laurimyllari (club-3090 disc #62)",
ha="center", fontsize=10, color="#666",
style="italic",
)
# Combined legend
lines1, labels1 = ax1.get_legend_handles_labels()
lines2, labels2 = ax2.get_legend_handles_labels()
ax1.legend(lines1 + lines2, labels1 + labels2,
loc="lower right", fontsize=10, framealpha=0.95,
edgecolor="#ccc", ncol=1)
# Footer
fig.text(
0.99, 0.01,
"github.com/noonghunna/club-3090",
ha="right", fontsize=9, color="#888", style="italic",
)
plt.tight_layout(rect=(0, 0.02, 1, 0.92))
out = "docs/img/power-cap-4090-qwen36.png"
plt.savefig(out, dpi=150, bbox_inches="tight", facecolor="white")
print(f"Saved: {out}")