Skip to content

Add XAML profiler memory attribution - #11743

Open
Akanksha Patel (akanpatel2206) wants to merge 6 commits into
mainfrom
user/akanpatel/memorySnapshot
Open

Add XAML profiler memory attribution#11743
Akanksha Patel (akanpatel2206) wants to merge 6 commits into
mainfrom
user/akanpatel/memorySnapshot

Conversation

@akanpatel2206

Copy link
Copy Markdown
Contributor

Summary

  • add outstanding XAML allocator accounting and heap snapshots
  • trace DComp surface lifecycle, backing textures, visual associations, and process GPU memory
  • preserve the current public allocator behavior and the 10-field ElementEnteredTree payload

Validation

  • amd64chk Microsoft.UI.Xaml project build: 0 warnings, 0 errors
  • amd64fre Microsoft.UI.Xaml project build with local PGO disabled: 0 warnings, 0 errors
  • WinUI code review: no Critical, Important, or Minor findings

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

Copy link
Copy Markdown
Azure Pipelines:
There may be pipelines that require an authorized user to comment /azp run to run.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 DCompSurface and VisualContentRenderer to emit these events during surface creation/resize/release and primitive rendering.
  • Extends XcpAllocation with 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.

Comment thread dxaml/xcp/components/allocation/lib/XcpAllocation.cpp Outdated
Comment thread dxaml/xcp/plat/win/desktop/DCompSurface.cpp

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

  • OSMemoryResize updates g_outstandingAllocSize on successful HeapReAlloc, but it never increments g_outstandingAllocCount when pAddress == nullptr (realloc used as initial allocation, which the _Frees_ptr_opt_ contract allows). This will undercount outstanding allocations in XamlHeapSnapshot for 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>
@akanpatel2206
Akanksha Patel (akanpatel2206) marked this pull request as ready for review September 1, 2026 09:22
@azure-pipelines

Copy link
Copy Markdown
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>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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);
        }

Comment on lines 33 to +40
// 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();
@akanpatel2206

Copy link
Copy Markdown
Contributor Author

/azp

@azure-pipelines

Copy link
Copy Markdown
Supported commands
  • help:
    • Get descriptions, examples and documentation about supported commands
    • Example: help "command_name"
  • list:
    • List all pipelines for this repository using a comment.
    • Example: "list"
  • run:
    • Run all pipelines or specific pipelines for this repository using a comment. Use this command by itself to trigger all related pipelines, or specify specific pipelines to run.
    • Example: "run" or "run pipeline_name, pipeline_name, pipeline_name"
  • where:
    • Report back the Azure DevOps orgs that are related to this repository and org
    • Example: "where"

See additional documentation.

Comment on lines +377 to +378
g_outstandingAllocCount.fetch_sub(1, std::memory_order_relaxed);
g_outstandingAllocSize.fetch_sub(cSize, std::memory_order_relaxed);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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>
@akanpatel2206

Copy link
Copy Markdown
Contributor Author

/azp

@azure-pipelines

Copy link
Copy Markdown
Supported commands
  • help:
    • Get descriptions, examples and documentation about supported commands
    • Example: help "command_name"
  • list:
    • List all pipelines for this repository using a comment.
    • Example: "list"
  • run:
    • Run all pipelines or specific pipelines for this repository using a comment. Use this command by itself to trigger all related pipelines, or specify specific pipelines to run.
    • Example: "run" or "run pipeline_name, pipeline_name, pipeline_name"
  • where:
    • Report back the Azure DevOps orgs that are related to this repository and org
    • Example: "where"

See additional documentation.

@akanpatel2206

Copy link
Copy Markdown
Contributor Author

/azp run

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
1 pipeline(s) were filtered out due to trigger conditions.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

needs-triage Issue needs to be triaged by the area owners

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants