Add XAML profiler memory attribution - #11743
Add XAML profiler memory attribution#11743Akanksha Patel (akanpatel2206) wants to merge 6 commits into
Conversation
Track XAML heap usage, DComp surfaces, shared backing textures, and process GPU memory while preserving the current public allocator and ElementEnteredTree behavior. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 9fe96962-0ced-4203-bb8a-b14de89eba7c
|
Azure Pipelines: There may be pipelines that require an authorized user to comment /azp run to run. |
There was a problem hiding this comment.
Pull request overview
Adds XAML profiler tracing to attribute CPU heap usage and DComp/GPU surface usage to specific XAML surfaces/visuals, enabling heap and GPU memory snapshots alongside existing tree/visual tracing.
Changes:
- Introduces new XamlProfilerTracing events for XAML heap snapshots, DComp surface lifecycle/texture observations, visual→surface associations, and GPU memory snapshots.
- Adds instrumentation in
DCompSurfaceandVisualContentRendererto emit these events during surface creation/resize/release and primitive rendering. - Extends
XcpAllocationwith outstanding-allocation accounting and heap metadata used by the new heap snapshot event.
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| dxaml/xcp/plat/win/desktop/DCompSurface.h | Declares profiler-only helpers for surface memory/texture observation tracing. |
| dxaml/xcp/plat/win/desktop/DCompSurface.cpp | Emits DComp surface lifecycle/texture observations + heap/GPU snapshots when profiler is enabled. |
| dxaml/xcp/core/hw/VisualContentRenderer.cpp | Traces visual-to-surface associations for brush/mask roles when profiler is enabled. |
| dxaml/xcp/core/core/elements/uielement.cpp | Emits XAML heap snapshots alongside existing Enter/Leave profiler events. |
| dxaml/xcp/components/base/inc/XamlProfilerTracing.h | Defines new TraceLogging events for heap, DComp surface, visual surface, and GPU snapshots. |
| dxaml/xcp/components/allocation/lib/XcpAllocation.cpp | Adds outstanding allocation tracking and heap metadata accessors used by heap snapshot tracing. |
| dxaml/xcp/components/allocation/inc/XcpAllocation.h | Declares new allocation statistics/heap metadata APIs. |
Suppressed comments (1)
dxaml/xcp/plat/win/desktop/DCompSurface.cpp:1132
- Resize() traces a profiler "deallocation" (TraceProfilerMemoryChange(false)) before calling m_compositionSurfaceHelper.Resize(...). If Resize fails, the trace stream will contain an unmatched deallocation for a surface that is still alive (and the corresponding allocation trace is skipped).
ASSERT(m_compositionSurfaceHelper.HasSurface());
#ifdef XAMLPROFILER_ENABLED
TraceProfilerMemoryChange(false);
#endif
if (!IsVirtual())
{
UpdateMemoryFootprint(FALSE);
}
IFC(m_compositionSurfaceHelper.Resize(width, height));
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 7 out of 7 changed files in this pull request and generated no new comments.
Suppressed comments (1)
dxaml/xcp/components/allocation/lib/XcpAllocation.cpp:320
OSMemoryResizeupdatesg_outstandingAllocSizeon successfulHeapReAlloc, but it never incrementsg_outstandingAllocCountwhenpAddress == nullptr(realloc used as initial allocation, which the_Frees_ptr_opt_contract allows). This will undercount outstanding allocations inXamlHeapSnapshotfor any allocations that go through the realloc callback path (e.g. LineServices).
if (newAddress)
{
const size_t cNewSize = XcpAllocation::OSMemoryGetBlockSize(newAddress);
if (cNewSize >= cOldSize)
{
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
|
Azure Pipelines: There may be pipelines that require an authorized user to comment /azp run to run. |
Move the fallible resize ahead of memory accounting so failed resizes do not emit an unmatched deallocation. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 7 out of 7 changed files in this pull request and generated 1 comment.
Suppressed comments (3)
Previously missed (3) — in code that hasn't changed since the last review.
dxaml/xcp/core/hw/VisualContentRenderer.cpp:435
- The profiler VisualSurfaceChanged events are emitted before LinkVisual(). If LinkVisual fails (e.g., InsertVisualIntoCurrentContainer/Collection failure), the trace will record a visual/surface association that never actually became part of the composition tree, which can desync profiler state.
IFC_RETURN(LinkVisual(brush, nullptr, spVisual.Get()));
dxaml/xcp/plat/win/desktop/DCompSurface.cpp:1382
- TraceProfilerTextureObserved dereferences updateObject unconditionally. Even though current call sites likely pass a non-null COM pointer on success, a defensive null check would avoid a crash in profiler-enabled builds if a future caller passes nullptr or if a BeginDraw implementation ever returns S_OK with a null surface.
if (FAILED(updateObject->QueryInterface(IID_PPV_ARGS(&texture))))
dxaml/xcp/components/allocation/lib/XcpAllocation.cpp:365
- OSMemoryFree caches g_memoryTrackingEnabled into trackMemory, but then re-reads the global flag inside the block. Using the cached value keeps the function internally consistent (and avoids relying on a second non-atomic read).
if (g_memoryTrackingEnabled)
{
UpdateAllocatedMemory(-(INT64)cSize);
}
| // Test hooks to expose allocation statistics | ||
| size_t GetAllocationCount(); | ||
| size_t GetAllocationSize(); | ||
| size_t GetDeallocationCount(); | ||
| size_t GetOutstandingAllocationCount(); | ||
| size_t GetOutstandingAllocationSize(); | ||
| uint64_t GetHeapHandle(); | ||
| bool IsUsingPrivateHeap(); |
|
/azp |
Supported commands
See additional documentation. |
| g_outstandingAllocCount.fetch_sub(1, std::memory_order_relaxed); | ||
| g_outstandingAllocSize.fetch_sub(cSize, std::memory_order_relaxed); |
There was a problem hiding this comment.
The increment in RecordOutstandingAllocation and this decrement are both guarded on the size being non-zero, but OSMemoryResize can change that in between and never adjusts g_outstandingAllocCount. A block resized down to 0 then never gets decremented here, and one grown from 0 was never incremented so this fetch_sub wraps. UpdateAllocatedMemory already clamps for the same reason — we may have to do the same here.
| } | ||
|
|
||
| #ifdef XAMLPROFILER_ENABLED | ||
| TraceProfilerMemoryChange(true); |
There was a problem hiding this comment.
This is emitted after the failure exits above, but m_pCompositionSurface / m_pVirtualCompositionSurface can already be set by then — so if we return early there, ReleaseLegacyDCompResources still sees them non-null and emits the matching false on its own. The other InitializeSurface overload emits before its failure exits, which avoids this — same as what we corrected in Resize. May be we can move it up to match.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
/azp |
Supported commands
See additional documentation. |
|
/azp run |
|
Azure Pipelines: 1 pipeline(s) were filtered out due to trigger conditions. |
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Summary
ElementEnteredTreepayloadValidation
amd64chkMicrosoft.UI.Xaml project build: 0 warnings, 0 errorsamd64freMicrosoft.UI.Xaml project build with local PGO disabled: 0 warnings, 0 errors