Guides
Trace a workload
Profile GPU timings and selected NVBit steps in your own Modal app; the package does not run CPU simulation.
# app.py
import modal
from cascade_profiler import Workload, register
app = modal.App("my-profiler")
runs = modal.Volume.from_name("my-profiler-runs", create_if_missing=True)
hf = modal.Volume.from_name("my-hf-cache", create_if_missing=True)
prof = register(app, runs, gpu="H100!", hf_cache=hf)
@app.local_entrypoint()
def main():
wl = Workload("facebook/opt-125m", ["Hello, my name is"], max_tokens=32, repeats=4)
run = prof.profile.remote(wl.to_dict(), trace_steps=[0, 5]) # GPU: baseline -> nsys -> NVBit on steps 0,5
print(run["run_name"], run["stage_wall_s"])
print(f"modal volume get my-profiler-runs {run['run_name']} ./{run['run_name']}")Optional S3 output: replace the registration above with:
prof = register(app, runs, gpu="H100!", hf_cache=hf,
s3={"endpoint": "https://s3.example.com", "bucket": "my-runs", "prefix": "profiles",
"region": "auto", "addressing_style": "path"},
secrets=[modal.Secret.from_name("my-s3-credentials")])Put AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY and optionally AWS_SESSION_TOKEN in that app-owned secret or the GPU runtime environment, never in destination options or files. The finished run uploads to s3://my-runs/profiles/<run_name>/, retaining the volume copy; run.json and traced/metadata.json record the destination and URI.
Run and download#
Use Python 3.12 locally: register() serializes Modal functions, so client and container Python minor versions must match.
pip install "cascade-profiler[modal] @ git+https://github.com/atoniolo76/cascade@profiler"
modal setup
modal run app.pyThe example prints the modal volume get command to download the run. The first invocation builds the GPU image; later runs reuse it.
The GPU function runs baseline (no profiler), nsys capture, then NVBit tracing of the selected steps. Outputs include corrected_timeline.json, trace_alignment.json and traced/traces/; traced-run timings are not used for reconciliation. S3 uploads happen at the end, with run.json last; keep_nsys_rep=True is rejected with S3 output to avoid exporting an unscrubbed environment capture.
See the OPT-125m sample analysis for measured costs, replay errors and limitations; its CPU simulation uses our own tooling, not the profiling package.
Legacy streaming into Cascade#
For the app's streaming trace layout, use accelsim_trace.py from validate-accelsim-modal (commit b348d7d), not the package example above. Pass the endpoint from Deploy the app: bucket cascade, path-style addressing.
modal run accelsim_trace.py --model facebook/opt-125m --list-layers
modal run accelsim_trace.py \
--model facebook/opt-125m \
--layers model.decoder.layers.10.self_attn \
--prompt "Hello, my name is" \
--max-tokens 4 \
--s3-endpoint https://<your-s3-endpoint> \
--s3-bucket cascade \
--s3-addressing-style pathChoose layer paths from --list-layers. --s3-prefix defaults to accelsim-traces and must match the app's CASCADE_S3_PREFIX; --s3-region defaults to auto. Use --run-name for an explicit identifier. --spinlock-handling defaults to mark_region; alternatives are fast_forward and none.
This legacy CLI checks bucket access before tracing, streams closed kernel files and deletes the local copies. It also uploads logs, spinlock data and metadata.json, including on failure, under s3://cascade/accelsim-traces/<run_name>/. The app post-processes this layout; see Traces. Package uploads instead retain the full profiling run layout.
Upload a legacy trace you already have#
scripts/upload_trace.py sends metadata.json last with status and a files list. Use --meta key=value for trace metadata, such as the GPU architecture (the app defaults to sm_90 for H100):
uv run python scripts/upload_trace.py ./my-run --run-name my-run \
--endpoint https://<your-s3-endpoint> --meta trace_gpu_arch=sm_80Add --status failed to mark the trace failed without processing it.