Skip to content

perf: Improve Chart control rendering and data processing performance#388

Open
PaulAndersonS wants to merge 1 commit into
mainfrom
paulandersons/perf-chart-rendering-data-processing
Open

perf: Improve Chart control rendering and data processing performance#388
PaulAndersonS wants to merge 1 commit into
mainfrom
paulandersons/perf-chart-rendering-data-processing

Conversation

@PaulAndersonS
Copy link
Copy Markdown
Collaborator

@PaulAndersonS PaulAndersonS commented Jun 2, 2026

Summary

This PR delivers 10 performance improvements across the Chart control's hot paths, reducing GC pressure, memory allocations, and CPU usage during rendering and data processing.

Changes

Allocation Reduction

  1. Cache SideBySideSeriesPosition.Values.ToList() before loops — Avoids repeated list materialization per iteration in CartesianChartArea.cs
  2. Replace LINQ index generation with pre-allocated List<double> and for loops — Eliminates closure allocations and unnecessary enumerator overhead in CartesianSeries.cs
  3. Same LINQ→for-loop optimization in PolarSeries.cs — Consistent fix for the polar chart variant
  4. Remove unnecessary .ToList() from .Where() in UpdateSbsSeries — Iterates directly without intermediate list allocation
  5. Eliminate .Where().ToList() in ResetVisibleSeries — Inline filtering avoids allocation in StackingSeriesBase.cs
  6. Pre-allocate list with known capacity in ChartSeriesPartial.cs — Uses ICollection.Count to set initial capacity

String/StringBuilder Optimizations

  1. Use StringBuilder for label content assembly — Replaces repeated string concatenation in CategoryAxis.GetLabelContent
  2. Use string interpolation for tooltip text — Eliminates 5 temporary string allocations in BoxAndWhiskerSeries.cs

Algorithm Improvements

  1. Use HashSet for O(1) deduplication in GroupData — Replaces O(n) List.Contains() calls, reducing axis grouping from O(n²) to O(n) in CategoryAxis.cs
  2. Cache Math.Abs results in trackball hit detection — Avoids redundant computation per iteration in CartesianSeries.cs

Resource Management

  • Dispose PathF before reallocation in AreaSegment.cs to reduce GC pressure from orphaned graphics objects

Verification

  • Build passes with 0 errors across all target frameworks (net9.0, net10.0, iOS, Android, macCatalyst)

- Replace string concatenation in loop with StringBuilder (CategoryAxis.cs)
- Cache Dictionary.Values.ToList() before loop iteration (CartesianChartArea.cs)
- Replace LINQ .ToList() index generation with pre-allocated for loops (CartesianSeries.cs)
- Replace string concatenation in tooltip with string interpolation (BoxAndWhiskerSeries.cs)
- Remove unnecessary .ToList() allocation in side-by-side series filtering (CartesianSeries.cs)
- Replace List.Contains() with HashSet for O(1) lookups in GroupData (CategoryAxis.cs)
- Eliminate Distinct().ToList() by maintaining uniqueness via HashSet (CategoryAxis.cs)
- Dispose PathF before reallocation to reduce GC pressure (AreaSegment.cs)
- Pre-allocate list capacity using ICollection.Count for ItemsSource (ChartSeriesPartial.cs)
- Cache Math.Abs() results in trackball hit detection loop (CartesianSeries.cs)

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant