Profile with Nsight Operator
Profile chosen Dynamo components on Kubernetes with Nsight Systems (nsys) through NVIDIA Nsight Operator
NVIDIA Nsight Operator adds Nsight Systems (nsys) to the pods you
select when they are created. It starts and stops capture windows on request, and each profiled pod uploads one report
per profiled process to S3 or to Nsight’s in-cluster storage. Its CLI and web UI are called Nsight Cloud.
Nsight’s Dynamo Quick Start Documentation covers installing and running the operator. This page adds only the parts that need Dynamo knowledge:
- which pod labels select each Dynamo component;
- a profile config with process patterns and
nsysarguments for each component; - the NVTX settings that add Dynamo’s own ranges to the reports;
- limitations when profiling Dynamo.
You can use the published Dynamo runtime images from NGC without a custom build, and the DynamoGraphDeployment (DGD) needs no new fields.
These instructions use Nsight Operator 26.3. If your cluster runs an older version, upgrade to 26.3 first.
Who Does What
Nsight’s multitenant quickstart defines three roles. To profile a Dynamo deployment, each role does the following:
Commands and reports take different paths:
By default, Nsight adds no privileged flag, capabilities, or host access to profiled pods, and nsys runs as the
container’s user. To keep it that way, do not turn on GPU metrics sampling (the nsys option --gpu-metrics-devices).
Nsight’s GPU metrics setup needs
extra privileges: it adds a collector DaemonSet whose pods run with privileged: true (or the SYS_ADMIN capability).
Tracing CUDA API calls and GPU kernels, as the worker configs below do, needs no extra privileges.
Try Nsight’s Dynamo Helper First
Nsight ships a Dynamo helper, nsight_operator_dynamo.py, with a
Dynamo quick start.
On a cluster where the operator already runs with auto-provisioning, its configure command (Option B) gives the
fastest first look. Adjust it as follows:
- Pass lowercase component types, such as
--components frontendor--components prefill decode. The helper compares them with the lowercasenvidia.com/dynamo-component-typelabel, so capitalized component names such asFrontendselect no pod. - Pass
--deployment-name <your DGD>. The helper selects every pod whose name contains that string, so pick a name that no other DGD’s name contains. - Set
--nsys-profile-args "-t cuda,nvtx,osrt --python-sampling=true". The helper’s default adds--pytorch=autograd-nvtx(see Limitations). - Leave out
--gpu-metrics. It installs Nsight’s GPU metrics collector: a DaemonSet whose pods run withprivileged: true, plus a profile config that runsnsys --gpu-metrics-devices=allin those pods.
For example, to profile the frontend and the aggregated workers of one DGD:
The helper then prints the next steps: deploy the DGD or recreate its pods, then start a capture, stop it, and list
the reports with nsight_operator.py.
Select Components
Select pods with the labels the Dynamo operator already sets on every pod. Always include
nvidia.com/dynamo-graph-deployment-name, so that other DGDs in the namespace are not matched.
Check the labels of your pods with:
Write a Profile Config
Apply one NsightOperatorProfileConfig for each DGD you profile, before you deploy that DGD; only pods created after
the config exists are profiled. This config follows Nsight’s
per-tenant storage example
and uses the field names of Nsight Operator 26.3. Replace my-dgd everywhere with your DGD name, my-namespace with
your namespace, and team-s3 with your storage config. Keep one rule for each component you want to record.
- OpenTelemetry. Both tool configs enable OpenTelemetry trace mirroring.
- Tags. Every rule uses the same literal tag, the DGD name, so one window profiles every selected component over the same period. A tag holds one profiling session at a time. For separate windows per component, give each rule its own tag.
- Names. Nsight looks up tool configs by name across the whole namespace, so give each profile config in a
namespace its own tool-config names. Do not name the config
dynamo-profile-config, which Nsight’s helper writes and deletes. - Patterns. They match Dynamo’s launch commands,
python -m dynamo.<module>andpython3 -m dynamo.<module>, so helper commands such aspython3 -c ...are not wrapped. - Fork tracing. The config leaves out
--trace-fork-before-exec=true, which Nsight’s template sets. The nsys documentation warns that it can make the application crash or deadlock.
Settings per Component
--cuda-graph-trace=nodeshows every kernel inside CUDA graphs and costs the most. For lower overhead, use--cuda-graph-trace=graph, which shows each graph launch as one item.- Set the NVTX variables in the component’s container
env, or in the DGD’sspec.envto set them on every component, before the pods start. - Keep each window at 300 seconds or less; Nsight Systems does not officially support longer runs.
Capture
Get nsight_operator.py from the
NGC resources of the
same release as the operator. It needs Python 3.12 or newer. Install its dependencies from the unpacked bundle:
Deploy the DGD after the profile config, wait until every selected pod is ready, and start your load. Then run:
--delay gives the load time to warm up. The coordinator starts and stops the window itself, so the CLI does not need
to stay connected. Download before session-end: without --session <UUID>, ls and download use the tag’s active
session. To download later, pass the session ID that session-begin printed. Reports appear after the delay, the
window, and the upload; a 30-second window on one GPU worker produced a report of about 100 MB. Each file name carries
the tag, the process, and the pod name. An otlp-converter entry in status or ls comes from Nsight’s OpenTelemetry
converter, not from a Dynamo pod. Open the reports with an Nsight Systems version at least as new as the nsys that the
operator injects.
autoconfigure copies the gateway’s storage key into ~/.nsight-cloud.conf on the machine that runs the CLI. To keep
the key off that machine:
- Set up the CLI with
configureinstead ofautoconfigure. - Download reports with your own storage credentials, as described in Configuring Storage Access for Downloads.
Profile One Replica of a Component
A rule selects every replica of a component: the injector decides when a pod is created, before the pod has its final
name, so a rule cannot pick one replica by name. To profile one replica, give each pod its own tag and start the window
on one pod’s tag. This uploads to the namespace’s in-cluster storage, which Nsight creates with auto-provisioning; it
was not tested with an S3 storage config such as team-s3, so leave out cloudStorageConfigRef on this rule. Change
the profile config above in two places:
Then run the commands in Capture with one pod’s name as the tag. Set T to that pod name instead of
my-dgd, and do not rerun the T=my-dgd line:
The window records only that pod, and its report goes to Nsight’s in-cluster storage. Other pods selected by the rule stay idle until you start a window on their own tags.
Profile One Pod with kubectl exec
To profile a single pod, you can also run nsys inside it with kubectl exec, without nsight_operator.py. The pod
must already be injected, which means a profile config selected it when the pod was created. The injected nsys is
at /mnt/nv/bin/nsight-systems/target-linux-x64/nsys on x86_64 nodes and
/mnt/nv/bin/nsight-systems/target-linux-sbsa-armv8/nsys on Arm nodes. Dynamo’s container is named main:
nsys stop waits until the report is written, which can take up to a minute for a GPU worker, and then prints its path
after Generated:, for example /tmp/tmpkro1yevt/<report>.nsys-rep. That file exists only inside the pod’s main
container: the operator does not upload it, nsight_operator.py ls and download do not list it, and it is lost if the
container restarts. Copy it out as soon as nsys stop returns:
Limitations
- Apply the profile config before the pods start. Only pods created after the config exists are profiled. After you change rules or arguments, recreate the pods.
- Use literal tags, or
${HOSTNAME}for one tag per pod. Other placeholders, such as{NVDT_POD_NAME}or${NVDT_POD_FULLNAME}, silently put the pod on thedefaulttag. - Leave out
--pytorch=autograd-nvtx. Nsight’s helper adds it by default. It can create a CUDA context on GPU 0 for every rank, which can shrink the KV cache. - Leave
DYN_NVTXunset on workers. On Dynamo 1.6.0,DYN_NVTX=1makespython -m dynamo.vllmfail at import undernsys, because some NVTX color names need matplotlib, which the runtime images do not ship. SGLang workers load the same module. - Keep profiled runs out of measured benchmarks. During a 30-second window with node-level CUDA graph tracing on one vLLM worker, end-to-end latency rose by about 18%; a frontend-only window changed it by less than 1%.
- Use one profiler per process. If your image already starts Dynamo under
nsys, use an image without that wrapper. - TensorRT-LLM on Blackwell GPUs:
-t cudacan use hardware CUDA trace. If a worker crashes in a device-to-device copy under tracing, use-t cuda-sw,nvtx,osrt. This was seen withnsysoutside Kubernetes. - If a pod is not profiled, follow Nsight’s
sidecar injection checks.
Setting
logOutput: /tmp/injector.logon a rule writes the process hook’s log inside the pod.