What the AMD device trace from profile returns for a hip or OpenMP-offload submission, which fields come back null, and what each refusal means.
Install
npx skillscat add spcl/hpcagent-bench/rocprof Install via the SkillsCat registry.
profile (POST /profile) on a hip submission, or with "tool":"rocprofv3" on an OpenMP-offloadc/cpp/fortran one, wraps rocprofv3 around the same measured child score times, built with
the same toolchain and flags. It records kernel dispatches, memory copies and the device's agent
report, and nothing else: no counters, no timeline. The trace covers the whole child process (setup,
warmup reps, measured reps), not only the timed calls. A profiler you run yourself measures a
different build on different inputs.
Asking
- Body: the
scorebody (same code fields) plus e.g."tool":"rocprofv3","reps":3,"min_percent":0.
Send"language"(hip, or the offload language): an unnamed language iscunless the judge
pins one. tooldefaults torocprofv3forhip;tool:"rocprof-compute"(device counters, below) andtool:"opt-report"(no run, compiler report) are also served.linuxperf,papi,nsys,ncuandnoneare a 400 namingrocprofv3; an unknown value is a 400
listing the valid tools. No 400 carries acause.threadsis ignored.- An OpenMP-offload submission is
c/cpp/fortran, nothip. On an offload armtool
defaults torocprofv3, which traces it built with the offload toolchain that grades it.rocprof-compute,linuxperf,papi,noneandtool:"opt-report"also serve it;nsysandncu
are 400s. On a non-offload armrocprofv3androcprof-computeonc/cpp/fortranare 400s. repsomitted is the judge's measured repeat count. Warmup reps are added, every rep is traced,
and the kill timeout grows with the total, so send a smallreps.min_percent(0-100, tool default 1; outside that range is a 400): kernels below it are dropped
and counted inkernels_omitted, ANDdevice_ns,device_ns_per_rep,device_pctandlaunch_countare summed over the kept kernels only.memory[]andlaunches[]are never pruned.
Send0for complete totals.residency: leave it out. Onhip,"host"is read asdeviceand"distributed"traces
host-resident pointers. An offload submission is traced the way it is graded: host pointers on
a host-pointer offload arm, device pointers on a device-resident (c-openmp-device) one. Any other value is a 400.counters:trueis refused withcounters_unsupported.
What comes back
build_ok:falseplusdetail(compiler tail): nothing was traced.kernels[], hottesttotal_nsfirst:name,instances,total_ns,mean_ns,min_ns,max_ns,time_pct.memory[]:operation,direction(h2d/d2h/d2d/h2h/memset/other),count,total_ns,mean_ns,total,unit.launches[], most-launched first: one row per distinct (name, grid, block, LDS, registers);launchescounts the dispatches that had it, and a dispatch with a zero grid or workgroup size is
skipped.blockisWorkgroup_Size_{X,Y,Z};gridisGrid_Size_{X,Y,Z}floor-divided by it,
so in BLOCKS (the trace counts work-items);blocksandthreads_per_blockare the products.warps_per_block= ceil(threads_per_block/Wave_Front_Size).registers_per_threadisVGPR_Count.shared_memoryisLDS_Block_Size(Group_Segment_Sizeon older rocprofiler-sdk),
rounded up to the allocation granule, so an upper bound;shared_memory_unitB.- Totals:
device_ns(sum of kepttotal_ns);device_ns_per_rep=device_ns/ (reps+warmup), both of which come back;device_pct= 100 xdevice_ns_per_rep/elapsed_ns, whereelapsed_nsis the FASTEST measured rep, so a mean over all traced reps is set against a best
case, and 0.0 whenelapsed_nsis 0;launch_count(sum of keptinstances);tool,trace,reports;occupancy_note(the geometry bounds occupancy; achieved occupancy belongs totool:"rocprof-compute");text(the same data rendered). ranges[]: your ROCTX ranges, below.ranges: []when the run pushed none.
Null means "not recorded", never 0:
total/unit: ALWAYS null on AMD. Copies come back counted and timed, never sized.min_ns/max_ns: null only under the legacyrocproffallback (toolnames it), which the
route takes only whenrocprofv3is absent. Under itmemory[]andlaunches[]come back as
EMPTY arrays, not rows of nulls.warps_per_block: null when the trace has no GPU agent row with a non-zeroWave_Front_Size. The
width is read, not assumed: NVIDIA's warp is 32, an AMD CDNA wavefront 64, RDNA 32.shared_memoryandshared_memory_unit: null when neither LDS column is present;registers_per_thread: null withoutVGPR_Count.- Of the agent report only
Agent_Type(to pick the GPU row) andWave_Front_Sizeare read: no
other column (Num_Xcc,Cu_Count,Simd_Count,Max_Waves_Per_Simd,Lds_Size_In_Kb,Product_Name) is in the payload.
Ranges: split one traced run
Evaluate the whole kernel first: kernels[], memory[] and device_pct answer most questions.
Add ranges only when those rows cannot say which stage of YOUR code a cost belongs to, e.g. two
stages dispatch the same kernel, or host work sits between launches.
- Only a
tool:"rocprofv3"profile build puts ROCTX on the include and link path (hip, andc/cpp/fortranon an OpenMP-offload arm).scoreandsubmitbuilds do not: a source that
still includes the header or calls ROCTX fails to build there. Remove every range beforescore. - C/C++:
#include <rocprofiler-sdk-roctx/roctx.h>, thenroctxRangePush("stage");before the
stage androctxRangePop();after it. A pop closes the latest push on that thread. - Fortran: no ROCTX module is on the include path, so this route has no ranges from Fortran.
ranges[], largesttotal_nsfirst, one row per range name:name,count(pushes),total_ns,mean_ns,min_ns,max_ns.min_percentdoes not prune them, and they are not indevice_nsordevice_pct.- What is recorded is HOST time from push to pop, not device time. A launch returns before the
kernel runs, so a range around a launch measures the launch. To see the stage, synchronize before
the pop (hipSynchronize(); an OpenMPtargetregion withoutnowaitalready waits). That
synchronize changes whatscorewould time, so it belongs to the profile build only. - The trace covers the whole child: a range inside your entry function is pushed once per warmup
and measured rep, socount= (reps+warmup) x pushes per call. Comparemean_ns. - Overhead: each push and pop is a host library call plus a trace record. Keep ranges out of inner
loops and around stages long enough to matter; kernel rows from a range build are still traced,
but take speedups fromscore.
Refusals: 503 with cause
Each one is "not measured", never "fast".
| cause | meaning | next |
|---|---|---|
counters_unsupported |
counters:true on a device submission |
drop counters; device counters are tool:"rocprof-compute" |
not_linux, rocprof_missing, rocminfo_missing |
judge host lacks Linux, a rocprofv3/rocprof on PATH, or rocminfo |
host fault, do not retry |
no_amd_gpu |
/dev/kfd absent, or rocminfo lists no gfx GPU agent |
host fault, do not retry |
kfd_permission_denied |
/dev/kfd not readable and writable; or no kernel report was written and the last 600 characters of profiler and program output (your own prints included) matched a device-access marker (/dev/kfd, permission denied, not permitted, HSA_STATUS_ERROR_OUT_OF_RESOURCES, rocr: unable to open), which wins over the exit code. AMD's gate is file access (render/video groups), not NVIDIA's CAP_SYS_ADMIN / ERR_NVGPUCTRPERM |
read the quoted output; host fault unless it names your allocation or your prints |
timed_out |
the rocminfo device probe did not answer in 30 s, or profiler and child ran past (reps + warmup + 2) x the per-rep kernel timeout and were killed; the message names which. One rep over the per-rep limit is a 500, not this |
retry once for the probe; else fewer reps, or find the hang |
rocprof_failed |
no marker matched; profiler exited non-zero with no kernel report after your program printed its result | read the quoted output |
rocprof_report_missing |
no marker matched; profiler exited 0 and wrote no kernel report | host fault (profiler build), do not retry |
kernel_share_missing |
the kernel report has no share column (tool renamed it) | not your code |
no_kernels |
the kernel report has zero rows: nothing was dispatched | your code ran on the host or the launch failed silently; check hipGetLastError() after it. Offload: no target region reached the device |
rocprof_unsupported |
raised only by the nsys path; the route answers a wrong tool with a 400 first |
-- |
A 500 whose error says traced run failed (exit N) is your program dying under the tracer, one rep
over the per-rep limit, or the memory cap; score the same code to see whether it also fails
without the tracer. Any other exception is a 500 profile failed for <kernel>: <reason>.
Device counters: tool:"rocprof-compute"
The trace says which kernel costs; rocprof-compute (formerly Omniperf) says what the device did
inside it: utilization, wavefront occupancy, launch geometry statistics, stalls, cache traffic.
- A separate run of the same build. It replays the whole program once per counter pass (13
passes on MI300A) with dispatches serialised, so no number is a time: its nanoseconds never go
next toelapsed_nsor a score. Trace first, then count the kernel the trace named. - Body: the
scorebody plus"tool":"rocprof-compute".repsdefaults to 1, because every
pass repeats every rep. Served forhipand, on an offload arm,c/cpp/fortran. kernels[], hottest first:name,count,total_ns,mean_ns,median_ns,time_pct, all
of the replayed run. Compare kernels bytime_pct, not by the durations.metrics[]:section,metric,value(the table's average),unit,min,max,peak,pct_of_peak, from five tables: System Speed-of-Light (utilizations, IPC, wavefront occupancy,
cache hit rates and bandwidths, each against its peak), Workgroup manager utilizations, Wavefront
launch stats, Wavefront runtime stats, and Busy and stall metrics. The tool'sN/Ais null, nevermetrics_missingnames a table the analysis did not write.
- The whole report is in your shared workspace at
report_dir:workload/(pmc_perf.csv,
one row of counters per dispatch, and the tool's log),analysis/tables/(every table as CSV,
about fifty) andanalysis/report.txt.report_fileslists what arrived;report_omittednames
each file left behind (over 16 MiB, past 64 MiB for the request, a symlink, a failed copy) and why. - Refusals, 503 with
cause:rocprof_compute_missing(norocprof-computeon the judge); the
trace's device gates (not_linux,rocprof_missing,rocminfo_missing,no_amd_gpu,kfd_permission_denied);rocprof_failed(no recording, non-zero exit, output quoted);rocprof_report_missing(a clean exit with no recording, or an analysis with no Top Kernels
table);no_kernels(the table is empty: nothing was dispatched);timed_out. A 500 whose error
saysrun failed under rocprof-compute (exit N)is your program dying in the counted run.
Other AMD tools you will read about
| tool | what it is | NVIDIA analogue |
|---|---|---|
rocprofv3 |
rocprofiler-sdk trace and counter CLI, the one behind this route | CUPTI, ncu's counters |
rocprof |
v1 CLI, deprecated; this route's fallback when rocprofv3 is absent |
-- |
rocprofv2 |
older CLI: different flags, different output | -- |
rocprof-sys (was Omnitrace) |
timeline and host sampling | nsys |
rocprof-compute (was Omniperf) |
per-kernel counters, roofline | ncu |
rocm-smi / amd-smi |
board state | nvidia-smi |
profile does not serve rocprof-sys and runs rocprof-compute as the tool above;
neither belongs inside a timed run.
Device counters are tool:"rocprof-compute" and nothing else. PAPI's rocm component is written against ROCProfiler V1; its
rocprofiler-sdk successor rocp_sdk is not among the components the image's PAPI 7.2.0 is built
with, and no route reads PAPI device components anyway -- plan the work without them. For counter
numbers met elsewhere: rocprofiler-sdk counter collection serialises dispatches,rocprofv3 fails a counter set that needs more than one pass and rocprof-compute replays the
program once per pass, so a counted run's wall clock is not a timing. Units differ by vendor:
ROCProfiler FETCH_SIZE / WRITE_SIZE are KB (NVIDIA: bytes), ROCm-SMI power uW (NVML: mW),
temperature millidegC (NVML: degC).
MI300A
- The judge's GPU agent is
gfx942, and the harness sizes the node as MI300A: Zen 4 cores and the
GPU in one package, host memory device-addressable. Anh2d/d2hrow is then a copy within one
memory, not a link transfer. - An OpenMP-offload build's map-clause data movement comes back as
d2drows
(MEMORY_COPY_DEVICE_TO_DEVICE), noth2d/d2h: measured on an explicit-memory arm, a matrix
multiply with three maps and two launches showed 11d2dcopies per trace. - Under
HSA_XNACK=1data moves by page migration, which the copy trace does not record: zero copy
rows beside unexplained kernel time can be migration. The harness setsHSA_XNACKonly on offload
arms (1unified memory,0explicit); ahiptrace runs under the judge's own value. - MI300X is the discrete part with several XCDs, where an
h2drow is a link transfer; nothing on
this page was measured on one.
The traced run inherits the judge's environment plus OMP_TOOL=disabled (the profiler's preloaded
library would otherwise start as an OpenMP tool); you cannot set it or read it back. Variables that
change what the trace shows: ROCR_VISIBLE_DEVICES and HIP_VISIBLE_DEVICES (filter and renumber
devices, the second on top of the first), HSA_XNACK (above), HSA_OVERRIDE_GFX_VERSION (the
runtime treats the part as another gfx target), and HSA_ENABLE_SDMA, which ROCm documents and the
harness never sets.