Executable programs and extensions

Verifying a 3090 unlock: boot logs, GEMM and llama-bench

Without recording the same conditions, you cannot separate the unlock's share.

Comparing before and after starts with fixing conditions: record the kernel, driver, VBIOS, power limit and context length1, measure matrix throughput2 with a torch GEMM and prefill3 and decode4 with llama-bench. Check the logs after a cold boot, and roll back by removing the kernel command-line option if it fails.

Requirements and key details
  • Record the kernel, driver, VBIOS and power limit for the comparison to hold.
  • GEMM isolates matrix compute; llama-bench reports prefill and decode separately.
  • Check the cold-boot logs, and roll back by removing the command-line option if it fails.

Record the baseline first

Before measuring, record the kernel version, NVIDIA driver, VBIOS, power limit and current clocks. uname -r, nvidia-smi and nvidia-smi -q show them. The same card gives different results under a different driver or power setting.

Keep the power limit fixed for the whole experiment. The 3090 defaults to 350 W, and lowering it to 300 or 280 W slows decode slightly. Changing power between runs mixes the compute effect with the power effect.

Baseline recording commands
uname -r
nvidia-smi --query-gpu=name,driver_version,vbios_version,power.limit,clocks.max.sm,memory.total --format=csv
nvidia-smi -q | grep -A2 "GPU Power Limit"
Keep the output verbatim. If the driver or VBIOS changes, treat the next comparison as a separate experiment.
A graphics card with magnified callouts of its fan, power connector and PCIe contacts
Verification starts with the card's connection, power and slot.

Measure matrix compute with GEMM

The published comparison used a dense 8192³ GEMM with FP325 accumulation and five-sample medians. Measuring FP166, BF167 and TF32 under the same setup isolates the unlock's effect on matrix compute. Discard warm-up runs and use the median.

In PyTorch8, TF32 is used only when torch.backends.cuda.matmul.allow_tf32 is enabled, and BF16 requires torch.bfloat16 inputs. Write the script yourself, following the conditions in the repository issue.

GEMM measurement example (verify the conditions yourself)
import torch, time, statistics
assert torch.cuda.is_available()
torch.backends.cuda.matmul.allow_tf32 = True
n = 8192
for dtype in (torch.float16, torch.bfloat16):
    a = torch.randn(n, n, device='cuda', dtype=dtype)
    b = torch.randn(n, n, device='cuda', dtype=dtype)
    for _ in range(3): a @ b
    torch.cuda.synchronize()
    times = []
    for _ in range(5):
        start = time.perf_counter(); a @ b; torch.cuda.synchronize()
        times.append(time.perf_counter() - start)
    med = statistics.median(times)
    print(dtype, round(2 * n**3 / med / 1e12, 2), 'TFLOPS')
This example covers FP16 and BF16 only; measure TF32 with its own settings and dtype. Compare the ratio before and after, not the absolute number.

Measure prefill and decode with llama-bench

llama-bench reports prefill and decode separately for the same model. Fix context and repetitions with something like -p 4096 -n 128 -r 5, and keep the model, quantization9 and power limit identical before and after. Use a GGUF10 already on the card.

Many of llama.cpp's quantized kernels do not use BF16 matrix products. A large GEMM difference can therefore leave llama-bench decode unchanged. You need to explain that gap to interpret the results.

Prefill and decode measurement example
llama-bench -m /path/to/model.gguf -p 4096 -n 128 -r 5
Keep the model path and options identical in both runs, and record the standard deviation as well.

Check logs after a cold boot

The unlock applies after a full power-off and restart. After boot, check the module log with journalctl -k -b | grep gpu_unlock and the driver binding with lspci -nnk -s <PCI address>, and confirm the card appears normally in nvidia-smi.

Stop the experiment if you see Xid errors or a driver reset. A card already used by a driver in the same power cycle is refused, so power off before retrying.

Post-boot checks
journalctl -k -b | grep gpu_unlock
lspci -nnk -s 0000:21:00.0
nvidia-smi
Replace the PCI address with the one from `lspci -D`; it differs from the GPU index.
A case with an RTX 3090 beside a check mark, and an open notebook with flow diagrams on the desk
Recording conditions in a note lets the next comparison use the same baseline.

Rollback and failure recovery

If something goes wrong, remove the gpu_unlock.targets= entry from the kernel command line and reboot. Uninstalling the packages also removes the module and initramfs configuration. If the display stays blank, delete the option temporarily in the bootloader edit screen and boot.

If the log says firmware never stopped, DMA buffers remain until the next power-off. Power off before retrying, and test on a spare card when possible.

Record sheet

Fill in these fields for both runs to make the comparison reproducible. If a value differs, explain it first; if it cannot be explained, do not count it as the unlock's effect.

Before-and-after record fields
FieldExample
Kernel, driver, VBIOS7.2.8-1, 615.71.09, 94.02.42.00.9b
Power limit350W
BF16 GEMM87.50 → 157.41 TFLOPS
llama-bench prefillRecord with conditions
llama-bench decode68.9 tok/s (3090, 350W)
Two graphics cards side by side, one short with a single fan and one long with two fans
Measure before and after at the same model and power to isolate the unlock's share.

Terminology notes

  1. Context window — The token span of input and generated content a model can handle in one request. The supported limit and memory use depend on the model and runtime settings.

    Back to the text
  2. Throughput — The amount of work processed or generated over time. Comparisons need the unit, such as tokens per second or requests per second.

    Back to the text
  3. Prefill — The stage where an LLM reads the input prompt and computes representations for its tokens. Longer prompts contain more tokens to process.

    Back to the text
  4. Token decoding — The stage that generates successive output tokens using the input and the response produced so far.

    Back to the text
  5. FP32 — A 32-bit floating-point format. It uses more memory per value than BF16 and can represent values more precisely.

    Back to the text
  6. FP16 — A 16-bit floating-point format. It uses the same bit width as BF16 but allocates bits differently between exponent and significand.

    Back to the text
  7. BF16 — A 16-bit floating-point format for model values. Its exponent has the same width as FP32, giving it a similarly wide value range.

    Back to the text
  8. PyTorch — A software framework for building and running AI models. Check the compatible PyTorch version and hardware support along with the model.

    Back to the text
  9. Quantization — A way to represent model weights or values with fewer bits, reducing storage and memory use. The coarser representation can also affect accuracy.

    Back to the text
  10. GGUF — A file format for model data, widely used by llama.cpp-based tools.

    Back to the text

Frequently asked questions

What should you check first in this article?
Comparing before and after starts with fixing conditions: record the kernel, driver, VBIOS, power limit and context length, measure matrix throughput with a torch GEMM and prefill and decode with llama-bench. Check the logs after a cold boot, and roll back by removing the kernel command-line option if it fails.