Profiling TorchNeuron (Part 1): System-level profiling on AWS Trainium.
Back to Articles Profiling TorchNeuron (Part 1): System-level profiling on AWS Trainium.
Enterprise Article Published October 21, 2026 Upvote - Josh Longenecker jlongen-aws Follow amazon Many ML practitioners have some intuition about how to make models run fast, but fewer know how to analyze why a model is slow.
In Part 1 of this series, you will learn how to systematically analyze inference performance and identify where the time is spent.This post starts from scratch and assumes no prior profiling experience.
The walkthrough uses AWS Trainium, a purpose-built AI chip for deep learning training and inference workloads, and TorchNeuron, its open source native PyTorch backend.TorchNeuron supports standard PyTorch workflows on Trainium, including eager execution, torch.
compile, and standard PyTorch APIs, with minimal code changes.Additionally, TorchNeuron integrates with Neuron Kernel Interface (NKI) to enable custom operators and performance optimization for Trainium hardware.By the end, you should know: How to configure torch.
profiler with the Neuron backend and capture a clean trace.How to read the keyaverages() table to identify which operations consume Neuron device time and compare their Self CPU time.
How to follow one operation through Neuron Explorer, from framework dispatch through runtime scheduling to hardware execution on a NeuronCore.How these signals change across three implementations of the same operation.
Neuron as a PyTorch Backend Before you profile a workload, it helps to understand how Neuron integrates with PyTorch.The Neuron backend uses PyTorch's PrivateUse1 extension point.This mechanism lets an accelerator integrate with the framework without adding a dedicated dispatch key such as cuda.
The torchneuronx package works with upstream PyTorch to register Neuron as a native backend for PyTorch code.For details about this extension mechanism, see Facilitating New Backend Integration by PrivateUse1.
Set Up the Profiler You use two objects to profile a Neuron workload: NeuronConfig controls which Neuron data streams and NeuronCores to capture and where to write the output.You pass it to torch.profiler.profile as experimentalconfig.
NeuronProfiler takes a NeuronConfig and provides an exporttrace callback.The callback writes the framework trace, trace.json, alongside the Neuron system traces.nc = NeuronConfig( modes=[ProfileMode.DEVICE, ProfileMode.
RUNTIME], profileoutputdir=OUTPUTDIR, captureenabledfornc='0', correlatedevicetime=True, ) exporter = NeuronProfiler(nc) The modes parameter selects the data streams to capture, such as device instructions and runtime traces.The captureenabledfornc parameter selects the NeuronCores to trace.
Setting correlatedevicetime=True propagates device time from the trace into the keyaverages() table, where you can compare CPU and Neuron device time.For the complete parameter reference and available ProfileMode values, see the NeuronConfig Profile Modes documentation.
Tooling: Neuron Explorer Neuron Explorer is a browser-based viewer for the system trace, device timeline, and per-engine breakdown.You can access it through an SSH tunnel or the Visual Studio Code extension.
In this post, you use Explorer to confirm what keyaverages() reports numerically and inspect what happens between dispatches.After profiling, the output directory contains the system trace and, when you capture device data, matched .neff and .ntff files.
The Neuron Executable File Format (NEFF) contains the compiled Neuron executable, while the matching NTFF contains its hardware instruction trace.The files share a numeric hash that identifies them as a pair.
To open the profile in Neuron Explorer, upload the complete output directory for a system or combined profile.For a device-only profile, upload the matching .neff and .ntff files individually.See Step 5: Upload your profile for the UI and command-line instructions.
Profile RMSNorm For this first analysis, you profile RMSNorm, a small operation with a clear sequence of arithmetic and reduction operations.
You profile three implementations of the same operation: Naive RMSNorm with individual PyTorch operations: multiply, mean, add, reciprocal square root, and multiply.torch.rmsnorm(), the PyTorch built-in lowered to a single fused Neuron kernel.Naive RMSNorm with torch.
compile, using the same operations as the first implementation.The scripts use the same inputs, profiler configuration, and schedule so the results are directly comparable.All scripts to reproduce this work are available in the torch-neuronx examples directory.
Profile 1: Naive PyTorch Operations Start by writing RMSNorm with individual PyTorch operations.Each line maps to one or more ATen operations and can create intermediate tensors.device = torch.device('neuron') x = torch.randn(4, 512, dtype=torch.bfloat16, device=device) weight = torch.
ones(512, dtype=torch.bfloat16, device=device) def rmsnormfn(t): xsq = t t # square meansq = xsq.mean(dim=-1, keepdim=True) # mean of squares rms = torch.
rsqrt(meansq + 1e-6) # 1 / sqrt(meansq + eps) return t rms weight # normalize + scale Call the profiler with two arguments required for the Neuron backend: Include ProfilerActivity.PrivateUse1 to collect activity from the Neuron device.
Pass NeuronConfig as experimentalconfig to enable the Neuron-specific Kineto features.The schedule uses wait=2, warmup=1, and active=1 across four prof.step() calls.This records one warm iteration without including initial setup overhead.Call torch.neuron.synchronize() inside the profiler loop.
Without this synchronization, the profiler can export before the device finishes and leave the Neuron time column empty.with torch.profiler.profile( activities=[ProfilerActivity.CPU, ProfilerActivity.PrivateUse1], experimentalconfig=nc, recordshapes=False, ontraceready=exporter.
exporttrace, schedule=torch.profiler.schedule(wait=2, warmup=1, active=1), ) as prof: for step in range(4): with torch.nograd(): = rmsnormfn(x) torch.neuron.synchronize() prof.step() After profiling finishes, inspect the keyaverages() table.
Sort by selfprivateuse1timetotal to place the operations with the highest device cost first.The table shown here is filtered to the RMSNorm operations that report Neuron device time.The full keyaverages() output also includes CPU-side events such as allocations and host-to-device transfers.
print(prof.keyaverages().table(sortby="selfprivateuse1timetotal", rowlimit=4)) The key averages table shows that three aten::mul calls account for the largest share of Neuron device time.
The table shows which ATen operations ran, how often they ran, and how much time they spent on the CPU and Neuron device.aten::mul has the highest total device time because the function performs three multiplications.Name # Calls Self CPU Self NEURON % NEURON aten::mul 3 60.9 μs 1,164.5 μs 49.
5% aten::add 1 26.6 μs 434.6 μs 18.5% aten::rsqrt 1 15.6 μs 415.0 μs 17.6% aten::mean 1 21.1 μs 340.8 μs 14.5% Self NEURON total: 2.355 ms Each row maps directly to the function.aten::mul runs for x x, x rms, and the final multiplication by weight.aten::mean reduces the last dimension.
aten::add adds the epsilon value and triggers a host-to-device copy because the scalar starts on the CPU.aten::rsqrt computes the reciprocal square root.Neuron Explorer follows an aten::mul operation from framework dispatch through runtime scheduling to execution on the Neuron hardware lanes.
Read the Trace in Explorer In Explorer, time flows from left to right and the event lifecycle flows from top to bottom.
Each ATen operation follows the same pattern: creation in the framework lane, scheduling in the runtime lane as nrtaexecuteschedule, and device execution in the hardware lane as ncexecrunning.The system trace view organizes events into lanes.
In the Default grouping mode, labels follow the pattern instance/PID/subsystem/identifier: Lane Label suffix What it shows Framework dispatch framework/TID: Operator dispatch events (PrivateUse1 runtime), grouped by thread ID.
Framework device framework/Stream: Device interaction events (PrivateUse1 driver), grouped by stream number.Neuron Runtime neuronrt/NC: Neuron Runtime API calls, grouped by logical NeuronCore.Neuron Hardware neuronhw/NC: Hardware execution events, grouped by physical NeuronCore.
In eager mode, each operation runs independently.Use the dependency chain viewer to follow aten::mul.Tensor from the framework layer through runtime scheduling to device execution.The dependency chain viewer highlights the lifecycle of one operation across the framework, runtime, and hardware lanes.
Profile 2: torch.rmsnorm Replace the individual operations with PyTorch's built-in rmsnorm function.Neuron lowers the operation to one fused kernel: def rmsnormfn(t): return torch.rmsnorm(t, [512], weight) The fused RMSNorm appears as one device operation in the key averages table.
Name # Calls Self CPU Self NEURON % NEURON aten::fusedrmsnorm 1 47.6 μs 403.3 μs 100% Self NEURON total: 403.3 μs The fused RMSNorm follows one framework-to-hardware path instead of dispatching each arithmetic operation separately.
Compare the Lowering Path In the naive implementation, each operation crosses the dispatch boundary independently and follows its own framework-to-runtime-to-hardware path.In the fused implementation, one Python call covers the complete computation.
The trace contains one dispatch and one hardware event, with no gaps between component operations.Profile 3: Naive PyTorch with torch.compile For the final example, compile the original naive RMSNorm function with torch.compile.With @torch.
compile(backend="neuron"), TorchDynamo captures the Python bytecode as an FX graph and AOTAutograd lowers it to ATen operations.The Neuron backend receives the complete graph instead of dispatching each operation separately.
It fuses the operations, optimizes memory access, and compiles the graph into a single NEFF artifact.The artifact runs as one hardware [email protected](backend='neuron', fullgraph=True) def naivecompiled(t): xsq = t t meansq = xsq.mean(dim=-1, keepdim=True) rms = torch.
rsqrt(meansq + 1e-6) return t rms weight The compiled function appears as one Torch-Compiled Region in the key averages table.Name # Calls Self CPU Self NEURON % NEURON Torch-Compiled Region: 0/0 1 98.4 μs 375.5 μs 100% Self NEURON total: 375.
5 μs The compiled graph follows one path through runtime scheduling and hardware execution.The table shows one device execution, as in Profile 2, but the code takes a different path.
Instead of calling a purpose-built fused operation, the compiler discovers the fusion from the original Python function.In this run, the Neuron time is comparable to torch.rmsnorm, at 375 μs compared with 403 μs.
Side-by-Side Summary Variant NEURON time Self CPU time Operator calls Naive ops 2,355 µs ~125 µs 6 torch.rmsnorm 403 µs ~48 µs 1 Naive + torch.compile 376 µs ~98 µs 1 Both torch.rmsnorm and torch.compile fuse RMSNorm into one kernel dispatch.
In these runs, either approach takes about one-sixth of the naive implementation's device time.Fusion removes the gaps between hardware executions and avoids materializing intermediate values such as xsq and meansq between separately dispatched operations.
Conclusion key_averages() shows which operations consume device time, while its full output also reveals CPU-side setup and transfers.Explorer provides the corresponding visual trace.
You can follow one operation from framework dispatch through runtime scheduling to hardware execution and see the gaps that fusion removes.You can use the same workflow on larger models: find a hotspot in the table, verify it in the trace, and then determine whether a fused operation or torch.
compile can reduce its cost.In Part 2, we will move into the device-level profile.You open the NEFF, inspect th
Related
相關文章
Profiling TorchNeuron (Part 1): System-level profiling on AWS Trainium.
Back to Articles Profiling TorchNeuron (Part 1): System-level profiling on AWS Trainium.
DeepSeek Harness不可錯過的12款神器!還有崔添翼推薦的
作者 | 江宇 編輯 | 漠影 一批民間開源插件正湧入DeepSeek Harness。10月21日報道,截至今日,DeepSeek Harness在全球開發者平臺GitHub上已經拿下超過25萬Stars。開源短短兩個多月,DeepSeek Harness已經吸引一批開發者為它打造插件,相關開源項目不斷湧現。
混合辦公催生新賽道:專業視訊終端為何被企業重新審視
企業會議室正在經歷一種看似反常的變化:協作工具越來越多,重要會議的組織成本卻未必隨之下降。遠端成員聽不清發言、共享材料看不清細節、會前反覆調試設備、不同平臺之間切換繁瑣,這些問題未必單獨出現在預算表上,卻常在跨區域會商、客戶溝通和項目評審中集中顯現。
Muse豆包遭集體“拉黑”,AI還能替我辦事嗎?
作者 | 李水青 編輯 | 心緣 近期,個人智能體(Agent)剛爆火就撞上“門禁”。 Meta在9月初用Muse打響個人Agent第一槍,而後OpenAI的Dots、阿里“千問Go”、字節“Spell”、騰訊LightVela等相繼跟進,個人Agent創企Instinct完成10億美元融資……賽道驟然升溫。
辦公Agent賽道迎新格局 WorkBuddy、百度搭子、千問辦公位居前三
具體來看,AI生活助手用戶規模增長至3.47億(同比增長55%),而AI辦公月活規模則達到1.42億(同比增長50.6%)。在典型辦公類Agent合計月活躍用戶規模排名中,騰訊WorkBuddy、百度百度搭子與阿里巴巴千問辦公分別以3235.
Mistral AI Releases Voxtral 3: Speech-to-Text, TTS and a Voice Agent SDK
Mistral AI just released Voxtral 3.Mistral Voxtral 3 is a speech model family paired with a voice agent SDK.It ships 3 transcription models, 1 text-to-speech model and an SDK built on LiveKit.