gpu: tier selection — one setting, three values, and off means off - #90
Merged
Conversation
PERFAGENT_GPU_PC_SAMPLING becomes off | continuous | serialized (0 | 1 | 2
still accepted, since container specs already carry them), read by both
producers through one parser in shim/core/pctier.h and by the agent through
gpu/tier.go, and surfaced on cmd/gpu-cuda-profile as --gpu-pc-sampling.
TimelineConfig.SerializedSampling is replaced by TimelineConfig.PCSampling
rather than joined by it: two fields that can disagree about which tier is
running is how a profile ends up disclosing one thing and doing another.
The tiers cannot run together, and the reason is what is written down.
COLLECTION_MODE is a single per-CUcontext CUPTI attribute, so a process could
set different modes on different contexts - but which context a kernel lands
on is the application's choice, not the profiler's, so "both" would produce
one profile whose attribution quality varied along an axis the operator can
neither see nor control. Naming two tiers is therefore a startup error in all
three shapes it can take: one value naming both, the flag and the environment
naming different ones, and an unknown value in either. Every refusal falls
CLOSED to off and explains itself; none of them picks a tier. The value is
parsed rather than rejected as syntax on purpose - "both" has to be
expressible for the refusal to be reachable, and a parser that took the first
token of "continuous,serialized" would be the silent pick the rule forbids.
Because Tier A perturbs the workload it measures, "serialized" is refused
unless --gpu-pc-sampling-acknowledge-perturbation says so, and joinhealth
carries a standing warning for the whole run rather than once at startup - it
stands even on a Tier A snapshot in which nothing went wrong, which is exactly
the profile whose reader has no other way to learn the tier was on. The
warning names all three perturbations, because an operator told only about the
first will misread the other two: they will see gpu_serialized="true" on the
GPU samples, conclude the marked ones are the perturbed ones, and then trust
an off-CPU profile whose synchronization waits are inflated by this very
mechanism and carry no marking at all. The third is that Tier A is unavailable
where CUDA graphs are in use. A limitation an operator is told about is a
limitation; one they discover from a misleading profile is a defect.
Off means off, and it is asserted where a uprobe would assert it.
shim/stub/pc_tier_test.cc reads its own .note.stapsdt, patches the four
PC-sampling probe nops with int3 and counts the traps: with the tier off, and
with the stub's own PC knobs turned up, not one of them may fire, while the
launch and exec probes must - so an inert producer cannot make it pass. The
continuous and serialized passes fire those same sites, so the negative passes
are not vacuous. This needed the stub to honour the tier at all; it is now the
outer gate over the stub's own knobs, which no existing test sets.
One anomaly strengthened while in there: the "unknown" clause was guarded by
SamplingWindowsReceived > 0, which suppressed it in the worst available case -
Tier A selected, not one window received, every execution unknown. Unknown is
unreachable in the other two tiers, so the guard hid the case that most needed
raising; it now names which cause applies instead of disappearing.
Verified: make -C shim {,test,check-fpless,check-cubin-defer,nvidia}; go build
./... && go vet ./...; go test ./gpu/ ./gpuprobe/ ./internal/... -count=1; go
test ./gpu/ ./gpuprobe/ -race -count=4; golangci-lint 0 issues. The off-means-
off test was mutation-checked: removing the stub's tier gate makes it fail and
name the probe that fired. No CUpti_ path here has run - CapEff: 0, no GPU.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Task 11 of the GPU PC sampling plan.
PERFAGENT_GPU_PC_SAMPLING=off(default) |continuous|serialized, with0/1/2still accepted on both ends since container specs already carry them. One parser per side —gpu/tier.goandshim/core/pctier.h— with a test that reads the header from Go and pins that both accept the same six spellings. Surfaced as--gpu-pc-samplingoncmd/gpu-cuda-profile.One field, not two
TimelineConfig.SerializedSampling boolwas replaced byTimelineConfig.PCSampling PCSamplingTier, not joined by it: two fields that can disagree about which tier is running is how a profile discloses one thing and does another.The tier rides out on
Snapshot.PCSampling, because "Tier A asked for, no window arrived" and "Tier A never asked for" are different facts — and inferring them fromSamplingWindowsReceived == 0gets them backwards.Why exclusivity is process-wide, not just forbidden
COLLECTION_MODEis a single per-CUcontextCUPTI attribute. A process could set different modes on different contexts — but which context a kernel lands on is the application's choice, not the profiler's, so a "both" mode would produce a profile whose attribution quality varied along an axis the operator can neither see nor control. Worse than either tier alone.Refused in three shapes — one value naming both tiers, flag and environment naming different tiers, unknown value — each a startup error that falls closed to off and carries the
COLLECTION_MODEreason rather than the rule alone. "Both" is deliberately parseable so the refusal is reachable, and both orderings are tested, since a first-token parser answers differently for each.The acknowledgement gate and the standing warning
serializedrequires--gpu-pc-sampling-acknowledge-perturbation, and the refusal text itself names all three perturbations.joinhealththen prints a four-line standing warning on every render — including on a Tier A snapshot where nothing went wrong, which is exactly the profile whose reader has no other way to learn the tier was on. Counted separately from anomalies, withlen(lines)-1 == warnings + anomaliesasserted.All three perturbations, because an operator told only the first will misread the other two: GPU kernel durations inside a burst are inflated and marked
gpu_serialized="true"; CPU and off-CPU samples during a burst are distorted and carry no marking at all — serialization inflates precisely the sync wait off-CPU profiling exists to measure; and Tier A is unavailable where CUDA graphs are in use.Off means off, asserted at the probe site
shim/stub/pc_tier_test.ccpatches the four PC-sampling probe nops withint3— what a uprobe does — and counts traps. Tier off ⇒ zero fires with the stub's PC knobs turned up, while launch/exec probes must still fire so an inert producer cannot pass. Thecontinuousandserializedpasses fire those same sites, so the negatives are not vacuous. Mutation-checked: removing the stub's tier gate makes it fail and name the probe.This required the stub to honour the tier at all — it is now the outer gate over its own knobs, which no existing test sets.
Two defects found in already-merged code
The
"unknown"anomaly was guarded bySamplingWindowsReceived > 0, which suppressed it in the worst case: Tier A selected, not one window received, every execution unknown.unknownis unreachable in the other tiers, so the guard only hid the case that needed it most. It now names which cause applies rather than disappearing.anomalousSnapshot()carried the three serialization counters withPCSamplingoff — a combination that cannot occur — and would have quietly stopped exercising the warning a real Tier A run carries.Verification
make -C shim/test(incl. newpctier_testandpc_tier_test8/8) /check-fpless/check-cubin-defer/nvidia;go build/vet; the four-package test list;-race -count=4; golangci-lint 0 issues. No ABI, BPF or.ochurn; Tier A/B behaviour, cubin capture, theCubinViewguard and theMODULE_UNLOAD_STARTINGdrain untouched.Cannot verify (
CapEff: 0, no GPU — noCUpti_path here has run): the adapter's tier parse ordering relative toCONTEXT_CREATED,g_pc_tier_refusedon hardware, and that an explicit=offwins in a real injected process's environ.