[ATT] Improved buffer management: per-agent shared trace buffers - #8272
[ATT] Improved buffer management: per-agent shared trace buffers#8272minseobshin11 wants to merge 4 commits into
Conversation
✅ All Policy Checks Passed
📖 Need help? See the Policy FAQ for details on every check and how to fix failures. |
|
🚫 Please fix the failed policies before requesting reviews. The following policy checks failed:
The |
6cf6b23 to
e63ffa3
Compare
e63ffa3 to
6b38dfe
Compare
There was a problem hiding this comment.
I think we shouldn't have two different code paths, one shared and one non-shared.
Ideally, there should be a single source of allocation. If that source cannot find an existing buffer satisfying the size requirements, then it can create a new shared one.
That way, we dont need to be checking if some pointer is shared.
| std::mutex& | ||
| get_mutex() | ||
| { | ||
| static auto* _mutex = new std::mutex{}; |
There was a problem hiding this comment.
why the static mutex pointer?
There was a problem hiding this comment.
was trying to use lazy allocation/construct on first use, but the codebase does have better convention of using static_object - modified.
There was a problem hiding this comment.
That is not what I meant - Is not affected by the global destructor in the same way.
There was a problem hiding this comment.
oh yea the previous approach did leak the new std::mutex and never destroyed it - I've changed it to static_object which gets destructed after finalize()
There was a problem hiding this comment.
its fine but unnecessary. The mutex does not need to be a pointer or a static_object , it can be just a regular object.
There was a problem hiding this comment.
keeping it static_object to outlive finalize() - regular namespace scoped mutex (Sychronized) can be destroyed before finalization and was failing attach-once-att
ApoKalipse-V
left a comment
There was a problem hiding this comment.
One more thing: We need a integration test that allocates hundreds of contexts (say with varying buffer size, target_cu, se_mask, simd_select, etc), runs each once and ensures it's all good. Note that not every target_cu is guaranteed to work, so the condition should be that "most" configs work for CUs in [0,1,2,3]
Allocating ~400 contexts of 1GB each would be impossible in the old implementation, so we can know for sure this works.
~400 contexts is not possible due to each context alloacating hsa queue, created a PR that addresses this issue. #8644 |
There was a problem hiding this comment.
Changes looks good, but we are missing two things:
(1) A lock to ensure no two contexts can use the same buffer at the same time. Right now, there is nothing preventing that except context management. We need stronger enforcement.
We have edge cases such as "disable dispatch thread trace while a kernel is running, then enable device thread trace".
(2) The CPU buffers also need to be reused. This can be a distinct PR (quick scan was merged only recently), but ideally reusing the same locking mechanism.
6fd101b to
00a0b6f
Compare
Co-authored-by: Cursor <cursoragent@cursor.com>
00a0b6f to
7178390
Compare
40458a3 to
90c1518
Compare
|
added a per-agent trace lease - the first active trace on an agent claims it and if a different context tries to trace the same agent, returns null. |



Motivation
Thread trace (ATT) allocated a separate GPU output buffer for every context on each agent (default 128 MB each), even though only one trace can be active per agent at a time. With multiple contexts on the same agent this wastes large amounts of device memory. This PR makes all contexts on an agent share a single output buffer sized to the largest requested
buffer_size, and adds a per-agent lease so that at most one context traces a given agent at a time — a second, concurrent request runs untraced rather than writing into the shared buffer.Technical Details
source/lib/rocprofiler-sdk/thread_trace/shared_trace_buffer.{hpp,cpp}.thread_trace::initialize()runs a pre-pass that registers every context's per-agentbuffer_sizebefore any buffer is built, so the shared buffer is sized to the max;finalize()frees the buffers once.TraceMemoryPool::Allocreturns the shared device buffer (one per ring slot viaoutput_buffer_index, so triple buffering keeps distinct slots);TraceMemoryPool::Freeskips shared buffers to avoid a double-free across the contexts that reuse them.source/lib/rocprofiler-sdk/thread_trace/shared_trace_lease.{hpp,cpp}enforcing the "one active trace per agent" invariant the shared buffer relies on: the first active trace on an agent atomically claims it (owner-keyed, re-entrant refcount) inget_control(), and a different context requesting a trace while the agent is held fails fast —get_control()returns null and that context runs untraced instead of concurrently writing the shared buffer. The lease is released when the agent's last in-flight trace ends (iterate_data/stop/ destructor).common::static_objectrather than plain namespace-scope globals: the state is freed byfinalize()(aregistration::finalize()atexithandler), and on the attach path a plain global's destructor can run beforefinalize()— a use-after-free.static_objectis destroyed bydestroy_static_objects()(sequenced afterfinalize()), so the state outlives teardown without leaking.JIRA ID
JIRA ID : AIPROFSDK-102
Test Plan
thread-trace-packet-test(including a newshared_buffer_reusecase covering cross-context reuse, distinct ring slots, and max sizing) andthread-trace-producer-consumer-test.ctest --repeat until-fail:10.Test Result
Unit tests pass reliably across repeated runs on MI300 (ROCm 7.2.3):
thread-trace-producer-consumer-test25/25 andthread-trace-packet-test10/10. Integration tests single/multi/agent/large-buffer/before-hsa-init and triple-buffer slow/multiple-cmds pass 10/10 repeats each. Thetriple-buffer-consistencyandtriple-buffer-hammertests can intermittently hit the pre-existing SQTT shutdown GPU hang tracked in AILIKFD-39; this was verified to reproduce ondevelopwithout this change (identicalreason :GPU Hang), so it is unrelated to the buffer-sharing rework and is not addressed here.Submission Checklist