Skip to content

Perf: Eliminate per-frame List allocations in SunburstChart SeriesView.OnDraw#374

Merged
PaulAndersonS merged 5 commits into
mainfrom
paulandersons/supreme-fortnight
Jun 6, 2026
Merged

Perf: Eliminate per-frame List allocations in SunburstChart SeriesView.OnDraw#374
PaulAndersonS merged 5 commits into
mainfrom
paulandersons/supreme-fortnight

Conversation

@PaulAndersonS

Copy link
Copy Markdown
Collaborator

Root Cause of the Issue

The SeriesView.OnDraw method in the SunburstChart control allocates a new List<SunburstSegment> on every render frame via LINQ (.OrderBy().ToList() when selection is active, or .ToList() otherwise). Since OnDraw is called at 60+ fps during animations and interactions, this creates significant GC pressure and unnecessary allocations in a hot path.

Description of Change

  • Replaced LINQ-based list creation with zero-allocation indexed for loops that iterate the existing Segments collection directly.
  • When selection is active: Two passes are used — first drawing unselected segments, then selected segments on top — maintaining the same visual z-order without allocating a sorted copy.
  • When no selection: A single pass iterates segments directly without any intermediate collection.
  • Removed unused System.Linq using directive since LINQ is no longer used in this file.
  • Added 4 unit tests verifying the draw path works correctly with empty segments, segments without selection, and segments with mixed selection states.

Performance Impact

Metric Before After
Allocations per frame 1 List + internal array (OrderBy/ToList) 0
Algorithm O(n log n) sort per frame with selection O(n) two-pass iteration
GC pressure Continuous in render loop Eliminated

Issues Fixed

N/A — Proactive performance improvement identified via code analysis.

Screenshots

N/A — Internal rendering logic change with no visual difference.

…w.OnDraw

Replace OrderBy().ToList() / .ToList() allocations on every draw frame
with zero-allocation two-pass iteration using indexed for-loops.

Before: Every OnDraw call allocated a new List via LINQ (.ToList() or
OrderBy().ToList()), creating GC pressure on every render frame.

After: Iterate the existing Segments collection directly with for-loops.
When selection is active, use two passes (unselected first, selected on
top) to maintain the same visual z-order without any allocation.

Also removes the now-unused System.Linq import.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@PaulAndersonS PaulAndersonS added this to the v1.0.11 milestone May 26, 2026

@VimalaThirumalaikumar VimalaThirumalaikumar 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.

Source-level changes are fine.

Removed the AI suggested unit test cases, as they were only validating whether an exception was raised. Since the newly added test cases are not functional tests, they have been removed.

@SaiyathAliFathima SaiyathAliFathima left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Changes are fine.

@PaulAndersonS PaulAndersonS merged commit a0228a0 into main Jun 6, 2026
@PaulAndersonS

Copy link
Copy Markdown
Collaborator Author

#373

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants