Skip to content

perf(Charts): 10 performance improvements in Chart control#400

Open
PaulAndersonS wants to merge 1 commit into
mainfrom
perf/chart-rendering-optimizations
Open

perf(Charts): 10 performance improvements in Chart control#400
PaulAndersonS wants to merge 1 commit into
mainfrom
perf/chart-rendering-optimizations

Conversation

@PaulAndersonS

Copy link
Copy Markdown
Collaborator

Summary

This PR consolidates 10 performance improvements to the Chart control, reducing allocations and eliminating hot-path inefficiencies.

Changes

# File Improvement Impact
1 CategoryAxis.cs Remove redundant Distinct().ToList() by ensuring uniqueness during insertion Eliminates LINQ allocation on every group data call
2 PolarAreaSegment.cs Replace multiple LINQ .Min()/.Max()/.Where() with single-pass loop Reduces 5 enumerations to 2 loops per segment
3 StackingAreaSegment.cs Replace LINQ .Where().Min() with single-pass loop Reduces 4 enumerations to 2 loops per segment
4 ChartTrackballBehavior.cs Use list swap for PreviousPointInfos Avoids Clear()+AddRange() copy on every pointer move
5 ChartTrackballBehavior.cs Reuse axis point info list with Clear() Avoids re-allocation per trackball generation
6 PolarSeries.cs Replace LINQ from..select..ToList() with for loop Eliminates delegate + iterator allocations
7 CartesianSeries.cs Replace .Where().ToList() with direct foreach Eliminates intermediate list allocation
8 CartesianChartArea.cs Pre-allocate List with known capacity Avoids internal array resizes in stacking loop
9 ChartAxis.cs Replace .Where() with direct loop + early return Avoids delegate allocation in GetCrossingAxis()
10 ChartUtils.cs Fast-path type checks in ConvertToDouble() + capacity in GetMidAngles() Avoids ToString() boxing for common types

Testing

  • All 2381 Chart unit tests pass ✅
  • Build succeeds with no new warnings ✅

1. CategoryAxis: Ensure uniqueness during insertion, eliminating redundant
   Distinct().ToList() allocation and extra enumeration.

2. PolarAreaSegment: Replace multiple LINQ .Min()/.Max()/.Where() calls with
   a single-pass loop for computing range bounds.

3. StackingAreaSegment: Replace LINQ .Where().Min() and separate .Min()/.Max()
   calls with single-pass loop for range computation.

4. ChartTrackballBehavior: Use list swap pattern for PreviousPointInfos to
   avoid Clear()+AddRange() copy on every pointer move.

5. ChartTrackballBehavior: Reuse _previousAxisPointInfos list with Clear()
   instead of re-allocating on each trackball generation.

6. PolarSeries: Replace LINQ 'from..select..ToList()' with pre-allocated
   List and simple for loop to avoid delegate and iterator allocations.

7. CartesianSeries: Replace .Where().ToList() with direct foreach loop in
   UpdateSbsSeries() to eliminate intermediate list allocation.

8. CartesianChartArea: Pre-allocate List<double> with known capacity in
   stacking calculation loop to avoid internal array resizes.

9. ChartAxis: Replace LINQ .Where() with direct foreach loop and early
   return in GetCrossingAxis() to avoid delegate allocation.

10. ChartUtils: Add fast-path type checks in ConvertToDouble() to avoid
    ToString() allocation for common numeric types (double, int, float,
    long, DateTime). Pre-allocate List capacity in GetMidAngles().

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
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.

1 participant