Warp Eval
NVIDIAOfficialCreated by NVIDIA Corporation
- Skill
- Workflow
- Software development
- Apache-2.0
- Medium risk
- Has scripts
AutoGineer summary
Written by AutoGineer from the skill’s own files, not by the author
The warp-eval skill provides a structured, evidence-based methodology to determine if specific hot paths in an existing codebase are viable candidates for NVIDIA Warp. It emphasizes objective reporting over recommendations, requiring users to define clear performance metrics and semantic contracts before any prototyping occurs. The process includes static screening, rigorous baseline comparisons, and authorized benchmarking, ensuring that Warp is only considered after in-project alternatives have been exhausted. The skill enforces strict gates to abort evaluations that do not meet technical or policy requirements, ensuring that only credible candidates proceed to measurement.
What it does
- Screens code bottlenecks against specific technical gates to determine Warp suitability.
- Requires the establishment of a semantic contract and performance baseline before prototyping.
- Enforces a ladder of in-project optimizations to be exhausted before introducing Warp.
- Produces a standardized evaluation report containing measurements, evidence, and caveats.
- Ensures all performance claims are backed by synchronized, end-to-end measurements.
- Provides scripts for synchronized timing, memory profiling, and report validation.
When to use it
- When investigating performance bottlenecks involving irregular queries, simulations, or branch-heavy loops.
- When you need to objectively assess if Warp provides a measurable benefit over existing in-project baselines.
- When you require a reproducible, audit-ready report on potential GPU acceleration candidates.
- When you need to determine if a performance issue is material enough to warrant a new dependency.
Advantages
- Prevents premature optimization by requiring algorithmic improvements first.
- Provides a clear, objective framework to stop evaluations that are not technically viable.
- Ensures performance measurements include realistic overheads like JIT, transfers, and synchronization.
- Maintains production code integrity by working in isolated, independent patches.
- Standardizes the reporting of facts, hypotheses, and unknowns.
Usage examples
- “Evaluate if the particle simulation loop in my project is a good candidate for Warp.”
- The agent will identify the candidate seam, derive the contract, check initial gates, and provide a resource preview before asking for authorization to proceed with profiling.
- “I have a performance bottleneck in my geometry processing code; can you run a warp-eval?”
- The agent will initiate the screening process, request the target repository, and begin identifying candidate patterns to determine if a formal evaluation is warranted.
Install
Download the skill as a ZIP:
https://mp-staging.autogineer.com/agent-skills/nvidia/warp-eval/downloadUnzip it into the cross-client skills folder of your project:
mkdir -p .agents/skills && unzip warp-eval.zip -d .agents/skills
Documentation by NVIDIA Corporation
Warp evaluation
Purpose
Collect reproducible evidence about how a narrow seam in an existing codebase would behave in NVIDIA Warp. Report facts; the user decides.
Name Warp as the option under evaluation in the first line, state that no adoption recommendation will follow, and do not treat the triggering performance request as authorization to experiment.
Measured evaluations produce warp-evaluation-report/: the report, one
independently applicable diff per solution, the drivers, and raw results. Never
modify production code. Exits before measured work create no directory.
Hard rules
These override any local reasoning.
Default objectives are latency, throughput, and peak or retained memory. Count maintainability, ergonomics, packaging, extensibility, autodiff or new functionality only when the user names it; otherwise report them as constraints or costs, not benefits.
Correctness is a gate. If the incumbent is buggy or its contract unclear, abort that comparison until an independent oracle or clarified contract exists. Report the defect without prescribing a response.
Never predict savings from source shape or another workload. Materialized memory comes from profiler or allocator evidence, not source a compiler may fuse.
"It can be written in Warp" is a hypothesis, never a proven opportunity.
Gates are exact, never adjacent or analogous. Fire a gate only when every condition in its definition is established. Gate D requires a maintained implementation confirmed to execute with CUDA on an NVIDIA GPU; a fast native CPU library is a baseline, not Gate D.
Label every claim as observed fact, measurement, hypothesis or unknown.
Time the user-visible stage, not the kernel. Include Warp's cold import/init/JIT in the real process regime, transfers, launches, Python launch loops, structure build/refit, allocation, conversion, validation, compaction and synchronization. Report each cost and the end-to-end difference.
No measured work without explicit authorization. After stage 1, stop and ask before profiling, environment changes, prototyping, benchmarking or GPU use.
Authorized measured work includes Warp. If profiling exposes no gate, continue through the strongest in-project baseline, minimum Warp prototype and end-to-end comparison. If Warp is out of scope, stop before profiling.
Never infer environment intent. NVIDIA deployment and ownership of an optional compiled dependency are product decisions. Abort only on a stated constraint; otherwise ask once and stop (
AWAITING INTENT).Warp measurements are CUDA-only and synchronized. Resolve an explicit NVIDIA CUDA device; discard CPU resolution and dispatch-only timing.
Never recommend or rank adoption options. Report facts, measurements, hypotheses and unknowns per seam and regime.
Stop at the report. No rollout or production edits.
Requirements
Static screening requires the target repository and its stated product constraints. Measured work additionally requires explicit authorization, an NVIDIA CUDA GPU, target-project dependencies and a representative workload.
Limitations
Warp CPU kernels are serial and outside this skill's evaluation scope. "Run it on the CPU instead" is not a performance fallback.
Mesh and geometry queries compute in float32/int32 even behind a float64 public API. Absolute error grows with coordinate magnitude.
Warp does not follow semver. Feature releases can break APIs, only the newest feature line is maintained, deprecations run roughly four monthly releases.
latestdocs track development, not the shipped release. Pin to the target project's own Warp version; if it has none, use the current stable and say which.Kernel-only builtins are not resolvable from Python —
hasattr(wp, "mesh_query_point")isFalseon a release that has it. Probe the stub file or that version's docs before concluding a builtin is absent.enable_backward=False(kernel, module or global) removes adjoint codegen. If nothing differentiates through the seam, set it before measuring compile cost.
Output Format
| State | Reached when | Report directory |
|---|---|---|
ABORT | Any gate establishes that the evaluated seam cannot satisfy the stated scope | No if nothing was measured; otherwise preserve the evidence already collected |
AWAITING INTENT | The environment gates turn on a fact only the user has | No — one question, both branches concrete |
AWAITING AUTHORIZATION | A candidate pattern survives stage 1 | No — early findings plus scope/resource preview |
INCOMPLETE | Authorized work cannot obtain representative evidence required for the scoped evaluation | Yes — preserve collected evidence and name the one missing artifact |
| Report delivered | Authorized work produced measurements, or stopped after the report directory existed | Yes — facts per seam and regime, with missing evidence explicit |
Use this exact shape for an early exit:
ABORT — Gate <letter>: <cited fact>; <why the scoped Warp evaluation cannot proceed>.
Do not name a preferred alternative.
Reporting rules:
references/evidence-and-reporting.md.
A delivered directory follows the template's fixed order: schema and provenance,
authorization and evaluation state, stage census, one B<n> evidence section
per seam/regime, caveats, then environment/reproduction. solutions/,
benchmarks/ and results/ contain every linked artifact.
Examples
Gate exit: ABORT — Gate A: deployment.md requires one implementation with AMD, Apple and NVIDIA parity; a Warp-specific path cannot satisfy this scope.
Surviving candidate: Name the seam and pattern, label inferred facts as assumptions, state that no gate has fired, preview the profile/baseline/Warp prototype/benchmark scope and its cost, then ask the separate intent and authorization questions from references/authorization-checkpoint.md.
Inputs
Required: the target repository and a performance, memory or scale problem with a candidate seam. Optional: explicit deployment/packaging constraints, existing profiles or logs, representative datasets and acceptance criteria. Prompt constraints take precedence over repository policy/configuration, then existing logs. User corrections override inference. Never substitute an assumption for a stated fact or measurement.
Available scripts
| Script | Purpose | Arguments |
|---|---|---|
scripts/driver-template.py | Copy once per bottleneck; define workloads and variants | Edit placeholders, then run the copied driver |
scripts/measure.py | Import from drivers for synchronized timing, memory and isolated cases | Python API; do not execute directly |
scripts/validate_report_schema.py | Validate the delivered report and evidence links | <report-directory> |
Use run_script("scripts/validate_report_schema.py", args=["warp-evaluation-report"])
when supported; otherwise invoke the script with Python and the report directory.
Troubleshooting
No representative workload: mark the scope
INCOMPLETEand name the missing artifact; do not invent data or fire Gate F.Warp resolves to CPU or no CUDA device: discard the run and stop before correctness or timing claims.
Report validation fails: fix the report or referenced artifact; never waive the schema error.
Instructions
Every stage before the last can end the evaluation. Stop as soon as a gate fires; do not gather evidence that cannot change the scoped facts.
1. Read the code, derive the contract, check the gates
Identify a candidate and its metric with references/target-patterns.md.
Derive devices/residency, dtypes/shapes, sizes, frequency, process lifetime, gradients and packaging from the repository. Infer before asking.
State the inferred contract in one line and invite correction. Unknown hardware, counts, sizes and tolerances are assumptions, never measurements. Every inference remains open to correction and cannot satisfy a gate that requires a stated fact or measurement.
Check Gates A–E before profiling. Check Gate F now only if representative evidence already exists; otherwise carry it into stage 2. Every gate uses only the exact boundaries in references/rejection-gates.md.
| Gate | Fires when |
|---|---|
| A | Production is stated CPU-only or to need non-NVIDIA portability, with no acceptable optional CUDA path |
| B | Data must cross the host/device boundary per small or infrequent call and the boundary cannot be widened |
| C | The region is dense tensor algebra already mapped to a tuned framework or vendor library |
| D | A mature CUDA implementation already meets the contract, and no non-performance objective was requested |
| E | A stated policy blocks Warp's dependency, compilation, cache or fallback obligations |
| F | Representative evidence proves the region too small a share of its requested metric for any backend to move it |
Gate F can fire in stage 1 only from representative evidence that already exists — a supplied profile, structural bound, or arithmetic on figures the user quoted. If that evidence does not exist, Gate F remains open until stage 2 profiling; inferred values never fire it.
Gates A and E need a stated constraint. A CPU implementation, another accelerator, no Warp dependency, or a small dependency list proves nothing.
When A/E are unresolved and a pattern survives, ask whether an optional NVIDIA path is acceptable: named extra, soft import, existing fallback, default install unchanged. Every affirmative answer must say explicitly that Warp will be prototyped and benchmarked; conditions constrain only that Warp scope. A negative or undecided answer means
ABORT.Do not ask when another gate fired, the repository answers, or no pattern matched. No pattern means no profiling.
If a candidate survives, combine any intent question with the authorization checkpoint — early findings, exact scope, stages, resource cost — then stop. Stage 2 requires both settled intent and explicit authorization.
2. Profile the real application
Requires explicit authorization and a settled intent question.
Profile with the project's own profiler and representative entry points.
Measure synchronized end-to-end stage time and peak memory before choosing a backend. Report which entry points were profiled and which a gate screened.
Prioritize further measurement by observed cost, not source appearance.
Name each measurement by the public method and variant actually invoked. A fallback is an execution regime of that public seam, not a different operation, and a cheaper sibling method cannot screen out the named method.
Confirm the timed branch ran on the intended device. Unchanged cost and near-zero device allocation between host and device inputs exposes a host fallback.
Measure the stage's free-stage ceiling and stubbed floor through the public boundary. Do not subtract per-op timings.
If the measured ceiling proves the candidate cannot move its own metric,
ABORTthe affected scope under Gate F, preserve the evidence already collected, and stop. The existing authorization already covered this materiality check; do not ask for authorization again.If representative coverage is unavailable — no representative dataset, runnable entry point or production distribution — record the single missing artifact, mark the affected scope
INCOMPLETE, and stop. This is missing evidence, not Gate F and notABORT. An invented workload cannot prove materiality.
Protocol: references/benchmark-protocol.md.
3. Form falsifiable hypotheses
Record per candidate: source, bottleneck evidence, objective, narrow seam, mechanism Warp could change, strongest incumbent, risks, acceptance threshold, cheapest falsifying experiment. Screen against references/target-patterns.md; if none survives, write the report and stop.
4. Write the contract before the prototype
Define values, dtypes, shapes, devices, errors, mutation, ordering, ties, capacity/overflow, topology/degeneracy, tolerances, required gradients, streams, ownership, aliasing, invalidation, concurrency, capture, teardown and fallback.
Fix tolerances before seeing Warp output. Never weaken a contract after a mismatch.
ABORTbefore prototyping if the proposed seam cannot satisfy a required contract.Pre-register, before timing: workload provenance, the state variable and production range controlling cost, tuning knobs, incumbent run-to-run spread, and the oracle applied to every implementation.
Hazards and adversarial checks: references/semantic-contract.md.
5. Improve the baseline first
Algorithm before backend: (1) a better or output-sensitive algorithm; (2) chunking, tiling, sparse output, layout, rematerialization; (3) the incumbent framework's compiler and native primitives; (4) what the project already depends on — its own accelerator backend, a parallel idiom it ships but leaves off, or a capability an existing dependency exposes and nobody wired up; (5) only then narrow Warp.
Compare only in-scope options: the improved incumbent, capabilities reachable through current dependencies, and Warp. Do not add unrelated libraries.
Search declared dependencies for dormant backends, flags and bindings before calling a route absent.
Keep the improved incumbent as the oracle. A result against an untuned, incorrect or asymptotically inferior baseline does not establish a backend comparison.
Close every in-project route before prototyping Warp:
| State | What it takes to claim it |
|---|---|
| measured | timed through the same boundary as the baseline |
| absent | a cited declaration, symbol table or missing flag proves it is unavailable |
| waived | you asked the user and they chose to skip it; record their words |
A capability present but unbound is reachable, not absent. If exposing it costs no more than the planned Warp seam, measure it first. Ladder details: references/baselines.md. Waived routes do not block stage 6; every route not explicitly waived must be measured or evidenced absent before the Warp prototype begins.
6. Prototype the minimum unit
Work in a separate copy, production unchanged, integration seam off by default. Prototype only enough to test the hypothesis.
Select an explicit CUDA device for every Warp prototype and verify that Warp resolves it as CUDA before correctness or performance work. Never exercise or report Warp's CPU backend.
Size the unit by shared data and structure lifetime, not function boundaries: build/refit/query costs that amortize together are one unit.
Name variants before timing. Preserve each solution as an independent patch against the pinned baseline, and prove it applies cleanly and reproduces the measured result.
Surface unsupported cases and overflow before timing.
Run the adversarial contract checks, audit correctness at production scale, and deliberately break a branch to prove the tests fail. Any failed required check returns
ABORTfor the affected scope.Before treating a disappointing compute-bound or reuse-heavy result as representative, consider the stronger formulations in references/target-patterns.md. One naive kernel does not bound Warp's potential.
7. Benchmark the whole boundary
Copy scripts/driver-template.py once per bottleneck and measure through scripts/measure.py. Do not hand-roll timing or memory.
Warp launches are asynchronous. The measurement helper must synchronize the selected device immediately before starting and after enqueueing every timed region, before stopping its wall timer.
Include every rule-7 cost, the public call, the immediate downstream stage, realistic sizes, and cold/warm process regimes.
Transcribe every report cell from emitted JSON; absent records read
not measured.Report
null_test, and one-time costs both separately and amortized. Serialize GPU measurements under an exclusive device lock. Below 1.5× is no measured difference.ABORTfor a seam and regime whose predeclared end-to-end performance or memory requirement fails, after preserving the measurements.
Full protocol: references/benchmark-protocol.md.
8. Summarize the evidence
Per seam and execution regime, report semantic results, strongest-baseline measurements, workload provenance, time, memory, lifecycle, portability and ownership facts.
Use
pass,fail,not measured,not available,no representative data,unknownorn/aonly where a stated criterion makes that status objective. Missing evidence remains missing.Mark the report
completeonly when every evaluated seam and regime includes an end-to-end Warp measurement. Useaborted — <gate and scope>when a gate fired, orincomplete — <missing evidence and scope>when representative evidence was unavailable. Preserve everything collected. Never deliver an incumbent-only report as a completedwarp-eval.Give every stage worth ≥10 % of the measured total a census row with a status and a one-line reason, including the screened-out stages.
Check each gate against the metric that candidate's pattern exhausts, not the study's headline objective.
9. Hand back
Use assets/warp-evaluation-report-template.md unchanged in schema. Record authorization and scope.
One table per bottleneck: baseline, current-dependency solutions, then Warp; absolute time and peak memory, ratios, contract status, evidence gaps.
Include prose only where it explains the measurements or their bounds. Working artifacts belong in
results/.
uv run python scripts/validate_report_schema.py <report-directory>Run the validator once the first measurement establishes a census/table, and again before delivery. Fix every error.
Verify builds and imports from artifacts, not exit status. Ship the exact drivers run. Then stop.
Files
- ATTRIBUTION.mdAdded by AutoGineer897 B
- BENCHMARK.md4.3 KiB
- LICENSELicence file added by AutoGineer11.2 KiB
- SKILL.md19.2 KiB
- assets/warp-evaluation-report-template.md5.8 KiB
- config/skillspector-baseline.yaml475 B
- evals/evals.json22.3 KiB
- evals/files/gate-a-required-portability/deployment.md638 B
- evals/files/gate-a-required-portability/neighbors.pyScript872 B
- evals/files/gate-b-unwidenable-host-boundary/architecture.md794 B
- evals/files/gate-b-unwidenable-host-boundary/scoring.pyScript880 B
- evals/files/gate-c-dense-vendor-lowered/feature_stage.pyScript615 B
- evals/files/gate-d-cpu-incumbent-not-cuda/baseline.md472 B
- evals/files/gate-d-cpu-incumbent-not-cuda/operation_api.pyScript440 B
- evals/files/gate-d-mature-incumbent/baseline.md960 B
- evals/files/gate-d-mature-incumbent/contact_api.pyScript948 B
- evals/files/gate-e-runtime-obligations-forbidden/candidates.pyScript735 B
- evals/files/gate-e-runtime-obligations-forbidden/packaging-policy.md845 B
- evals/files/gate-f-immaterial-stage/profile.json603 B
- evals/files/gate-f-immaterial-stage/spatial_filter.pyScript646 B
- evals/files/pattern-fused-edge-intermediate/context.md742 B
- evals/files/pattern-fused-edge-intermediate/message_passing.pyScript521 B
- evals/files/pattern-sequential-recurrence/adaptive_filter.pyScript462 B
- evals/files/pattern-sequential-recurrence/context.md596 B
- evals/files/proceed-persistent-mesh-query/context.md767 B
- evals/files/proceed-persistent-mesh-query/queries.pyScript804 B
- references/authorization-checkpoint.md3.8 KiB
- references/baselines.md12.2 KiB
- references/benchmark-protocol.md16.3 KiB
- references/evidence-and-reporting.md7.2 KiB
- references/rejection-gates.md8.2 KiB
- references/semantic-contract.md13.3 KiB
- references/target-patterns.md16.3 KiB
- scripts/driver-template.pyScript3.4 KiB
- scripts/measure.pyScript20.8 KiB
- scripts/validate_report_schema.pyScript13.5 KiB
- skill-card.md4.4 KiB
- skill.oms.sig12.5 KiB
scripts/measure.py
#!/usr/bin/env python3
# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0
"""Measurement primitives implementing references/benchmark-protocol.md.
Import these from one driver script per bottleneck rather than hand-rolling
timing and memory code, so that two evaluations — or two agents — produce
comparable numbers. The protocol is the specification; this is its
implementation, and every default here encodes one of its rules:
time_it One discarded warm-up, then ONE timed run. Not a sampling
loop: more samples only sharpen a figure contaminated by a
machine you cannot quiet. Synchronizes before and after.
comparison Ratio plus protocol resolution. >=1.5x is directional; below
1.5x is no measured difference at this precision.
sig2 Two significant figures at most.
host_memory Reads /proc VmHWM, NOT resource.getrusage().ru_maxrss.
ru_maxrss is inherited across a process spawn: a 787 MB parent
yields a child reporting 787 MB before it allocates anything,
which silently defeats the protocol's "measure in fresh
processes" rule. VmHWM is per-process and correct after exec.
device_memory NVML per-process GPU memory — the device-side counterpart of
process RSS, and the only domain that sees every framework and
the CUDA context alike. A bare context is 445 MB that CuPy's
own pool counter reports as 0. Framework allocator counters
supplement it; they never replace it.
run_isolated Fresh process per case; peak counters are monotonic within a
process, so the second config measured in one process inherits
the first's high-water mark.
null_test Proves the harness runs the work. A harness that silently
fails to run reports a very fast time, which reads exactly
like an apparent speedup.
Timings are synchronized wall clock unless you call device_time.
Usage:
Import this module from one copied driver-template.py per bottleneck.
Arguments:
Each function documents its callable, device, case and environment inputs.
Output:
JSON-serializable measurement records; emit() writes JSON Lines.
Exit codes:
This is an import library and does not define a command-line exit code.
"""
from __future__ import annotations
import json
import os
import platform
import resource
import subprocess
import sys
import time
from importlib.metadata import PackageNotFoundError, version
from math import floor, isinf, log10
from pathlib import Path
__all__ = [
"comparison",
"device_baseline",
"device_memory",
"device_time",
"emit",
"env_fingerprint",
"host_memory",
"isolated_case",
"null_test",
"require_warp_cuda",
"run_isolated",
"sig2",
"time_it",
]
NOT_MEASURED = "not measured"
_BLOCKED_ENV_KEYS = frozenset({"PATH", "PYTHONHOME", "PYTHONPATH", "VIRTUAL_ENV"})
_BLOCKED_ENV_PREFIXES = ("DYLD_", "LD_")
# ------------------------------------------------------------------ reporting
def sig2(x: float | None) -> float | None:
"""Round to two significant figures. A single sample does not support
'1.87x'; it supports 'about 1.9x', often only 'about 2x'."""
if x is None or x == 0 or x != x or isinf(x):
return x
return round(x, -int(floor(log10(abs(x)))) + 1)
def comparison(baseline_s: float, candidate_s: float) -> dict:
"""Report a ratio at the protocol's measurement resolution."""
r = baseline_s / candidate_s if candidate_s else float("inf")
if r >= 1.5 or r <= 1 / 1.5:
resolution = "directional difference"
else:
resolution = "no measured difference at this precision"
return {
"ratio": sig2(r),
"comparison": resolution,
}
# ------------------------------------------------------------------------ env
# Distribution names differ from import names, and probing a version must never
# import the module: importing an uninitialized runtime makes it look live to _sync.
_DISTS = {"numpy": "numpy", "scipy": "scipy", "warp": "warp-lang", "cupy": "cupy-cuda12x", "torch": "torch"}
def _version(mod: str):
try:
return version(_DISTS.get(mod, mod))
except PackageNotFoundError:
return None
def _run(cmd: list[str]) -> str | None:
try:
out = subprocess.run(cmd, capture_output=True, text=True, timeout=15, check=False)
return out.stdout.strip() if out.returncode == 0 else None
except Exception:
return None
def env_fingerprint() -> dict:
"""Everything that decides whether two records are comparable. The thread
count is not optional: a CPU baseline measured below the deployment's thread
count has not been compared."""
gpu = driver = NOT_MEASURED
smi = _run(["nvidia-smi", "--query-gpu=name,driver_version", "--format=csv,noheader"])
if smi:
gpu, driver = (s.strip() for s in smi.splitlines()[0].split(","))
return {
"python": platform.python_version(),
"os": platform.platform(),
"cores": os.cpu_count(),
"threads": {
v: os.environ.get(v)
for v in ("OMP_NUM_THREADS", "OPENBLAS_NUM_THREADS", "MKL_NUM_THREADS", "NUMEXPR_NUM_THREADS")
},
"gpu": gpu,
"driver": driver,
"versions": {m: _version(m) for m in _DISTS},
"commit": _run(["git", "rev-parse", "HEAD"]),
}
# --------------------------------------------------------------------- timing
def require_warp_cuda(device="cuda:0"):
"""Resolve and return an explicitly selected CUDA device through Warp.
Warp's CPU backend is outside this evaluation's scope. Call this before
correctness work; ``time_it(..., warp_candidate=True)`` calls it
automatically before warm-up or timed execution.
"""
if device is None or str(device) == "cpu":
raise ValueError("Warp evaluation requires an explicit CUDA device, not CPU")
wp = sys.modules.get("warp")
if wp is None:
raise RuntimeError("import and initialize Warp before resolving its CUDA device")
try:
resolved = wp.get_device(device)
except Exception as exc:
raise RuntimeError(f"Warp could not resolve device={device!r}: {exc}") from exc
if not getattr(resolved, "is_cuda", False):
raise ValueError(f"Warp evaluation requires a CUDA device; resolved {resolved!s}")
return resolved
def _sync(device) -> None:
"""Synchronize `device` before and after a timed region.
Silently doing nothing here is how asynchronous dispatch time gets compared
against synchronized end-to-end time, so this raises rather than returns if
nothing could be synchronized.
"""
if device is None or str(device) == "cpu":
return
d = str(device)
# Syncing "whichever runtime is live" syncs its *current* device, which on a
# multi-GPU host need not be the one named. Resolve the index explicitly.
if d == "cuda":
idx = None
elif d.startswith("cuda:") and d[5:].isdigit():
idx = int(d[5:])
else:
raise ValueError(f"device={device!r} is not 'cpu', 'cuda', or 'cuda:<n>'")
errors = {}
for mod, fn in (
("cupy", lambda m: (m.cuda.Device(idx) if idx is not None else m.cuda.Device()).synchronize()),
("warp", lambda m: m.synchronize_device(d)),
("torch", lambda m: m.cuda.synchronize(idx)),
):
m = sys.modules.get(mod)
if m is None:
continue
try:
fn(m)
return
except Exception as exc: # imported but uninitialized, or no device
errors[mod] = f"{type(exc).__name__}: {exc}"
raise RuntimeError(
f"device={device!r} but no GPU runtime could be synchronized: {errors or 'none imported'}. "
"Initialize warp/cupy/torch first, or pass device=None for pure-CPU work."
)
def time_it(fn, *, device=None, warp_candidate: bool = False, warmup: int = 1, samples: int = 1) -> dict:
"""One discarded warm-up, then one timed run, synchronized both sides.
Warp candidates must set ``warp_candidate=True``. This rejects Warp's CPU
backend and records the resolved CUDA device and architecture.
`samples` defaults to 1 deliberately. Do not raise it to tighten a reported
figure — spend that budget on another size or regime instead. Raise it only
for a harness self-check (see null_test), and say so in the report.
Skipping the warm-up has moved a baseline by ~34%, enough to invert a
comparison, which is why it is not optional.
"""
warp_device = require_warp_cuda(device) if warp_candidate else None
if warp_device is not None:
device = str(warp_device)
for _ in range(warmup):
fn()
_sync(device)
times = []
for _ in range(samples):
_sync(device)
t0 = time.perf_counter()
fn()
_sync(device)
times.append(time.perf_counter() - t0)
record = {
"seconds": min(times),
"samples": samples,
"warmup_discarded": warmup,
"statistic": "synchronized_wall_clock",
"device": str(device) if device is not None else "cpu",
"warp_candidate": warp_candidate,
}
if warp_device is not None:
record["warp_device"] = {
"alias": str(warp_device),
"architecture": str(getattr(warp_device, "arch", NOT_MEASURED)),
}
return record
def device_time(fn, *, device="cuda:0", warmup: int = 1) -> dict:
"""Device-event time. Report beside time_it where wrapper or launch behavior
matters — never instead of it, since the evaluation covers the whole stage."""
cp = sys.modules.get("cupy")
if cp is None:
return {"seconds": None, "note": f"{NOT_MEASURED}: cupy not imported"}
for _ in range(warmup):
fn()
_sync(device)
start, end = cp.cuda.Event(), cp.cuda.Event()
start.record()
fn()
end.record()
end.synchronize()
return {
"seconds": cp.cuda.get_elapsed_time(start, end) / 1000.0,
"statistic": "cuda_event_device_time",
"device": str(device),
}
# --------------------------------------------------------------------- memory
def peak_host_mb() -> float:
"""Peak process RSS in MB, from /proc/self/status VmHWM on Linux.
NOT resource.getrusage().ru_maxrss: that is inherited across a subprocess
spawn, so a heavy parent censors every isolated measurement (measured: a
787 MB parent yields a child reporting 787 MB before allocating; the same
child's VmHWM correctly reads 24.1 MB, then 405.9 MB after a 400 MB array).
"""
if sys.platform.startswith("linux"):
try:
with open("/proc/self/status") as fh:
for line in fh:
if line.startswith("VmHWM:"):
return int(line.split()[1]) / 1024
except OSError:
pass
rss = resource.getrusage(resource.RUSAGE_SELF).ru_maxrss
return rss / 1024 if sys.platform.startswith("linux") else rss / (1024 * 1024)
_FLOOR_MB = peak_host_mb()
def host_memory() -> dict:
"""Host peak RSS — the domain that sees both sides of a comparison.
Take headline memory ratios from here. A per-language counter such as
tracemalloc cannot see a CUDA context at all and structurally understates a
candidate that reserves hundreds of MiB; it may supplement this, never
replace it.
"""
peak = peak_host_mb()
return {
"peak_mb": peak,
"floor_mb": _FLOOR_MB,
"workload_mb": peak - _FLOOR_MB,
"domain": "process RSS high-water (VmHWM)",
}
_NVML = {"handle": None, "ready": False, "error": None}
def _nvml(index: int = 0):
"""Lazily initialize NVML once. Returns the device handle, or None."""
if _NVML["ready"]:
return _NVML["handle"]
_NVML["ready"] = True
try:
import pynvml # noqa: PLC0415
except ImportError:
_NVML["error"] = "nvidia-ml-py not installed (pip install nvidia-ml-py)"
return None
try:
pynvml.nvmlInit()
_NVML["handle"] = pynvml.nvmlDeviceGetHandleByIndex(index)
except Exception as exc:
_NVML["error"] = f"{type(exc).__name__}: {exc}"
return _NVML["handle"]
def _nvml_process_mb(index: int = 0):
"""GPU memory this process holds, as the driver sees it. Framework-agnostic.
Returns None where per-process accounting is unavailable — inside MIG, in
some container configurations, and under restricted driver permissions —
rather than substituting a device-wide figure that includes other tenants.
"""
h = _nvml(index)
if h is None:
return None
import pynvml # noqa: PLC0415 # guaranteed importable: _nvml() returned a handle
try:
try:
procs = pynvml.nvmlDeviceGetComputeRunningProcesses_v3(h)
except AttributeError:
procs = pynvml.nvmlDeviceGetComputeRunningProcesses(h)
except Exception as exc:
_NVML["error"] = f"per-process accounting unavailable: {exc}"
return None
for p in procs:
if p.pid == os.getpid():
return (p.usedGpuMemory or 0) / 1e6
return 0.0
_DEVICE_BASELINE: dict = {}
def device_baseline(index: int = 0) -> dict:
"""Record device memory already resident — CUDA context, driver, library
handles — before the workload allocates.
That context is a floor the incumbent never pays, so without this a small
workload charges the candidate for it and can look worse at every small
size. Measured here: 445 MB for a bare CUDA context.
"""
global _DEVICE_BASELINE
_DEVICE_BASELINE = {"context_fixed_mb": _nvml_process_mb(index)}
return dict(_DEVICE_BASELINE)
def device_memory(index: int = 0, backend: str | None = None) -> dict:
"""Device memory for this process, from NVML — the domain that sees both sides.
NVML is framework-agnostic and is the device-side counterpart of process RSS:
it sees the CUDA context, every framework's allocations and any native
library's alike, through one code path. A framework's own allocator counter
cannot do this. Measured on an L40: a bare CUDA context is 445 MB of device
memory that CuPy's pool counter reports as 0.0 MB, and the same NVML call
tracked a 480 MB CuPy array and a 480 MB Warp array with no branch between
them. Take headline device-memory ratios from `process_mb`.
`backend` optionally attaches that framework's allocator detail — live versus
pool-reserved, which NVML cannot distinguish. It supplements the NVML figure
and never replaces it.
NVML has 1 MiB granularity, so a zero delta means "below snapshot
resolution", not "zero storage".
"""
proc_mb = _nvml_process_mb(index)
rec = {
"process_mb": proc_mb,
"context_fixed_mb": _DEVICE_BASELINE.get("context_fixed_mb"),
"workload_mb": (proc_mb - _DEVICE_BASELINE["context_fixed_mb"])
if proc_mb is not None and _DEVICE_BASELINE.get("context_fixed_mb") is not None
else None,
"domain": "NVML per-process GPU memory",
"granularity_mb": 1,
}
if proc_mb is None:
rec["note"] = f"{NOT_MEASURED}: {_NVML['error'] or 'NVML unavailable'}"
# Optional supplement: allocator detail NVML cannot provide.
if backend == "cupy" and "cupy" in sys.modules:
pool = sys.modules["cupy"].get_default_memory_pool()
rec["allocator"] = {
"backend": "cupy",
"live_mb": pool.used_bytes() / 1e6,
"reserved_mb": pool.total_bytes() / 1e6,
}
elif backend == "torch" and "torch" in sys.modules:
t = sys.modules["torch"]
rec["allocator"] = {
"backend": "torch",
"live_mb": t.cuda.memory_allocated() / 1e6,
"reserved_mb": t.cuda.memory_reserved() / 1e6,
}
elif backend:
rec["allocator"] = {"backend": backend, "note": f"{NOT_MEASURED}: no counter wired"}
return rec
# ------------------------------------------------------------------ null test
def null_test(make_fn, *, device=None, warp_candidate: bool = False, scale: int = 4, tol: float = 0.4) -> dict:
"""Prove the harness measures the work.
`make_fn(k)` returns a callable doing k times the base work. If scaling the
work does not scale the measurement, the harness is not running it — a
missing sync, a cached result, a kernel never launched, a test binary that
exits 0 without executing. All of those report a very fast time, which reads
exactly like an apparent speedup.
This is a harness self-check, not a reported figure, so it may take a few
samples without violating the one-timed-run rule.
"""
t1 = time_it(make_fn(1), device=device, warp_candidate=warp_candidate, samples=3)["seconds"]
tk = time_it(make_fn(scale), device=device, warp_candidate=warp_candidate, samples=3)["seconds"]
ratio = tk / t1 if t1 > 0 else float("inf")
return {
"scale": scale,
"observed_ratio": sig2(ratio),
"tolerance": tol,
"pass": abs(ratio - scale) / scale <= tol,
}
# -------------------------------------------------------- process isolation
def isolated_case() -> str | None:
"""Inside a run_isolated child, the case name; None in the parent."""
return os.environ.get("WARP_EVAL_CASE")
def _driver_path(script: str | None) -> Path:
"""Resolve a Python driver confined to the current workspace."""
candidate = Path(script or sys.argv[0])
if not candidate.is_absolute():
candidate = Path.cwd() / candidate
try:
resolved = candidate.resolve(strict=True)
except OSError as exc:
raise ValueError(f"measurement driver does not exist: {candidate}") from exc
workspace = Path.cwd().resolve()
if not resolved.is_relative_to(workspace):
raise ValueError(f"measurement driver must be inside {workspace}: {resolved}")
if resolved.suffix != ".py" or not resolved.is_file():
raise ValueError(f"measurement driver must be a Python file: {resolved}")
return resolved
def _extra_environment(extra_env: dict | None) -> dict[str, str]:
"""Validate case parameters without allowing runtime-loader overrides."""
safe: dict[str, str] = {}
for raw_key, raw_value in (extra_env or {}).items():
key = str(raw_key)
if not key or "=" in key or "\0" in key:
raise ValueError(f"invalid environment key: {key!r}")
if key in _BLOCKED_ENV_KEYS or key.startswith(_BLOCKED_ENV_PREFIXES):
raise ValueError(f"measurement environment may not override {key}")
value = str(raw_value)
if "\0" in value:
raise ValueError(f"environment value for {key} contains a null byte")
safe[key] = value
return safe
def run_isolated(case: str, *, script: str | None = None, extra_env: dict | None = None, timeout: int = 3600) -> dict:
"""Re-execute this script in a fresh process for `case` and return the JSON
record it printed. Required wherever allocators retain storage, and for any
peak-memory comparison: peak counters are monotonic within a process.
Driver shape:
if (case := measure.isolated_case()):
measure.emit(None, run_case(case)) # child: one JSON line
else:
for c in CASES: # parent: fresh process each
measure.emit(RESULTS, measure.run_isolated(c))
"""
if not isinstance(case, str) or not case or "\0" in case:
raise ValueError("case must be a non-empty string without null bytes")
driver = _driver_path(script)
proc = subprocess.run(
[sys.executable, str(driver)],
env={**os.environ, "WARP_EVAL_CASE": case, **_extra_environment(extra_env)},
capture_output=True,
text=True,
timeout=timeout,
check=False,
)
for raw_line in reversed(proc.stdout.splitlines()):
line = raw_line.strip()
if line.startswith("{"):
try:
return json.loads(line)
except json.JSONDecodeError:
continue
return {
"case": case,
"error": "no JSON record emitted",
"returncode": proc.returncode,
"stderr_tail": proc.stderr[-2000:],
}
# --------------------------------------------------------------------- output
def emit(path, record: dict) -> dict:
"""Append one record. Report tables are transcribed from this file; a cell
with no record here reads "not measured". Use run-unique filenames — a
second lock acquisition that re-runs a phase will otherwise silently
overwrite results the report already cites."""
record = {"env": env_fingerprint(), **record}
line = json.dumps(record, default=str)
if path is None:
print(line, flush=True)
else:
with open(path, "a") as fh:
fh.write(line + "\n")
return record
Requirements and compatibility
Works with: Claude Code, Claude apps, OpenAI Codex, GitHub Copilot, Cursor, Gemini CLI, Kiro, OpenCode, Goose, Amp, Roo Code, JetBrains Junie, Factory Droid, Devin (ex-Windsurf), Mistral Vibe, OpenHands, Letta
“Works with” means the tool reads the open Agent Skills format; a skill written for one tool may use features others lack.
Needs: Needs Python
The author says: Screening, static evaluation and reporting need no GPU. Measuring Warp requires an NVIDIA CUDA GPU, the target project's dependencies and a representative workload; without them, abort before profiling.
Security
What our scanner noticed· Medium risk
- Large base64-encoded blobs
- Scripts that your agent may run
This skill includes scripts that your agent may run. Read them before you use it.
A static scan is not a guarantee. Skills are third-party content: review a skill before you let an agent use it.
Attribution and licence
- Created by
- NVIDIA Corporation
- Publisher
- NVIDIA (Official)
- Source
- NVIDIA/skills · skills/warp-eval · commit fce3cca
- Licence
- Apache License 2.0 (redistribution allowed)
- LICENSE (added by AutoGineer from LICENSE-APACHE)
- ATTRIBUTION.md (written by AutoGineer)
- Synced
AutoGineer is not affiliated with or endorsed by NVIDIA Corporation or NVIDIA.
Download ZIP
The ZIP holds the skill’s files, its licence files and an ATTRIBUTION.md. Download warp-eval.zip