---
title: "WPF Chart Performance Benchmark: Rendering 1 Million Data Points"
published_at: "2025-10-29T12:33:10+00:00"
modified_at: "2026-06-24T13:34:24+00:00"
url: "https://www.syncfusion.com/blogs/post/wpf-chart-performance-benchmarking"
excerpt: "Discover how to benchmark WPF chart performance with 1 million data points using FastLineSeries and FastLineBitmapSeries. Learn techniques to optimize rendering speed, memory usage, and responsiveness in large-scale data visualization."
taxonomy_category:
  - "Chart"
  - "Chart of the week"
  - "Data Visualization"
  - "Performance"
  - "Performance Benchmarking"
  - "WPF"
taxonomy_post_tag:
  - "Chart"
  - "Data Visualization"
  - "performance"
  - "WPF Chart"
---

[Chart of the week](https://www.syncfusion.com/blogs/category/chart-of-the-week)
# WPF Chart Performance Benchmark: Rendering 1 Million Data Points

[Subash Sorimuthupattaraja](https://www.syncfusion.com/blogs/author/subash-sorimuthupattaraja)

![Optimizing WPF Chart performance A Benchmark with 1 Million Data Points](https://www.syncfusion.com/blogs/wp-content/uploads/2025/10/Optimizing-WPF-Chart-performance-A-Benchmark-with-1-Million-Data-Points-1.jpg)


**TL;DR:** Ever tried rendering 1 million data points in a WPF chart without crashing your app? This guide benchmarks two high-performance series types, FastLineSeries and FastLineBitmapSeries, to evaluate rendering speed, memory usage, and UI responsiveness. Learn how to choose the right charting strategy for scalable, real-time data visualization in WPF applications.

Welcome to the **Chart of the Week** blog series!

Handling large datasets in [WPF Charts](https://www.syncfusion.com/wpf-controls/charts)
 can be challenging. Slow rendering and laggy interactions can ruin the user experience. In this guide, we’ll benchmark WPF chart performance using two high-speed series types, `FastLineSeries` and `FastLineBitmapSeries`, by rendering 1 million data points. If you’re building dashboards, health trackers, or financial apps, this walkthrough will help you optimize chart responsiveness and memory usage.

![Benchmark performance in WPF Charts](https://www.syncfusion.com/blogs/wp-content/uploads/2025/10/img1.png)

Benchmark performance in WPF Charts

## Why chart performance matters

Modern applications often deal with massive datasets. For WPF desktop apps, efficient rendering and smooth interactions are critical. The [SfChart](https://help.syncfusion.com/wpf/charts/overview)
 is designed for high-performance charting, enabling the fast visualization of large datasets without compromising speed or responsiveness.

This benchmark demonstrates how specialized series types can deliver fast load times, responsive panning and zooming, and stable memory usage, even with millions of points.

**What you’ll learn:**

- **Build high-performance WPF Charts**: Configure charts to handle up to 1 million data points.
- **Choose the right series type**: Compare ** FastLineSeries** and ** FastLineBitmapSeries** for speed and responsiveness.
- **Implement a benchmarking workflow**: Measure load time, pan/scroll latency, zoom performance, and memory usage.
- **Scale confidently**: Ensure your charts remain smooth as data grows.

Simplify WPF Chart Development

Spend less time building data visualization features from scratch. Syncfusion WPF Charts includes ready-to-use support for multiple chart types, data binding, interactive tooltips, legends, zooming, selection, and responsive layouts.

[Start Building Today](https://www.syncfusion.com/wpf-controls/charts)

## Building the benchmarking app

### Step 1: Configure the WPF Chart

Begin by installing the [Syncfusion.SfChart.WPF](https://www.nuget.org/packages/Syncfusion.SfChart.WPF/)
 package via NuGet and referring to the official [documentation](https://help.syncfusion.com/wpf/charts/getting-started)
 to set up the chart control in your WPF application.

### Step 2: Define the Models

Next, create a `DataModel` class to represent individual data points, then define a `BenchmarkResult` class to store performance metrics such as:

- **InitialLoadMs**: Time to render after data binding.
- **PanScrollMs**: Time for panning or scrolling.
- **ZoomMs**: Time for zoom operations.
- **MemoryMB**: Memory consumed during rendering.
- **AvgUIFrameMs**: Average frame time for UI responsiveness.

Refer to the code example.

```
public class DataModel
{
    public double XValue { get; set; }
    public double YValue { get; set; }

    public DataModel(double x, double y)
    {
        XValue = x;
        YValue = y;
    }
}

public class BenchmarkResult
{
    public string SeriesType { get; set; } = "";
    public long   InitialLoadMs { get; set; }
    public long   PanScrollMs { get; set; }
    public long   ZoomMs { get; set; }
    public double MemoryMB { get; set; }
    public double AvgUIFrameMs { get; set; }
}
```

### Step 3: Set up the ViewModel

Create a **`BenchmarkViewModel`** class that implements `INotifyPropertyChanged` to enable real-time UI updates as data changes. Inside this class, generate a dataset consisting of 10 series, each containing 100,000 data points, using the `GenerateDataset()` method, resulting in a total of 1 million points.

Define two commands, `StartBenchmarkCommand`, which initiates the benchmarking process, and `ClearCommand`, which resets the chart and results. This structure promotes a clean separation of concerns, making the application easier to maintain, extend, and test.

Refer to the code example.

```
public class BenchmarkViewModel : INotifyPropertyChanged
{
    . . .

    public ICommand StartBenchmarkCommand { get; }
    public ICommand ClearCommand { get; }

    private readonly int seriesCount = 10;
    private readonly int pointsPerSeries = 100_000;
    private List<ObservableCollection<DataModel>> dataset = new();

    public BenchmarkViewModel()
    {
        StartBenchmarkCommand = new RelayCommand(async _ => await RunBenchmarkAsync(), _ => Chart != null);
        ClearCommand = new RelayCommand(_ => Clear());
        GenerateDataset();
    }

    private void GenerateDataset()
    {
        dataset.Clear();
        for (int s = 0; s < seriesCount; s++)
        {
            var col = new ObservableCollection<DataModel>();
            double y = rng.NextDouble() * 10.0; // common initial band

            for (int i = 0; i < pointsPerSeries; i++)
            {
                col.Add(new DataModel(i, y));
                if (randomNumber.NextDouble() > .5)
                {
                    y += randomNumber.NextDouble();
                }
                else
                {
                    y -= randomNumber.NextDouble();
                }
            }
            dataset.Add(col);
        }
    }
}
```

### Step 4: Select high-performance series types

When visualizing millions of data points, choosing the right series type is critical. **SfChart** provides specialized ** Fast Series** types optimized for speed:

- [FastLineSeries](https://help.syncfusion.com/cr/wpf/Syncfusion.UI.Xaml.Charts.FastLineSeries.html?tabs=tabid-1) : Renders data using polyline segments for smooth visualization of continuous trends across large datasets.
- [FastLineBitmapSeries](https://help.syncfusion.com/cr/wpf/Syncfusion.UI.Xaml.Charts.FastLineBitmapSeries.html?tabs=tabid-1) : Uses WritableBitmap for extreme performance, ideal for data-intensive scenarios where minor visual compromises are acceptable. This series type supports anti-aliasing. Enable **anti-aliasing** only when visual clarity is a priority, as it can slightly impact performance.

Refer to the code example.

```
public class BenchmarkViewModel : INotifyPropertyChanged
{
  . . .
private ChartSeriesCollection CreateSeries(bool isBitmap, bool antiAliasing)
{
    var list = new ChartSeriesCollection();
    for (int s = 0; s < seriesCount; s++)
    {
        if (isBitmap)
        {
            list.Add(new FastLineBitmapSeries
            {
                ItemsSource = dataset[s],
                XBindingPath = nameof(DataModel.XValue),
                YBindingPath = nameof(DataModel.YValue),
                EnableAntiAliasing = antiAliasing, 
                StrokeThickness = 1,
                Stroke = new SolidColorBrush(ColorFromIndex(s))
            });
        }
        else
        {
            list.Add(new FastLineSeries
            {
                ItemsSource = dataset[s],
                XBindingPath = nameof(DataModel.XValue),
                YBindingPath = nameof(DataModel.YValue),
                StrokeThickness = 1,
                Stroke = new SolidColorBrush(ColorFromIndex(s))
            });
        }
    }
    return list;
} 
 . . .
}
```

The benchmarking app uses these fast series types to demonstrate SfChart’s ability to efficiently handle large datasets, making it well-suited for performance-critical applications.

### Step 5: Execute benchmarking workflow

The `RunBenchmarkAsync` method coordinates the entire benchmarking process from start to finish. It performs a series of timed operations to evaluate performance under different conditions.

Specifically, it measures:

- Initial load time.
- Memory usage before and after rendering.
- Pan and zoom responsiveness.
- Average UI frame time

Refer to the code example.

```
public async Task RunBenchmarkAsync()
{
    if (Chart == null) return;

    Status = "Benchmark Started";
    CommandManager.InvalidateRequerySuggested();

    if (Chart.PrimaryAxis is ChartAxisBase2D x)
    {
        x.ZoomFactor = 1;
        x.ZoomPosition = 0;
    }

    // GC before measure for accurate memory tracking
    GC.Collect();
    GC.WaitForPendingFinalizers();
    GC.Collect();

    bool  isBitmap = SelectedSeriesType != "FastLineSeries";
    bool  enableAntiAliasing = isBitmap && EnableAA;

    ChartSeriesCollection seriesCollection = CreateSeries(isBitmap, enableAntiAliasing);

    long   memBefore     = GC.GetTotalMemory(true);
    Chart.Series.Clear();

    // Scenario 1: Measure load time
    var    stopWatch = Stopwatch.StartNew();

    Chart.Series = seriesCollection; 
    await WaitForChartRenderAsync(); 
    stopWatch.Stop();
    long   memAfter = GC.GetTotalMemory(true);
    long   exactLoadMs = stopWatch.ElapsedMilliseconds;

    double memMB = (memAfter - memBefore) / (1024.0 * 1024.0);

    await WaitForRenderAsync();
    await Task.Delay(DelayAfterLoadMs);

    // Scenario 2: Pan/Scroll
    frameTimes.Clear();
    int    panSteps = 30;
    stopWatch.Restart();
    for (int i = 0; i < panSteps; i++)
    {
        Chart.PrimaryAxis.ZoomFactor = 0.2;
        Chart.PrimaryAxis.ZoomPosition = i / (double)panSteps * (1.0 - Chart.PrimaryAxis.ZoomFactor);
        await WaitForChartRenderAsync();
    }
    stopWatch.Stop();
    long   panMs = stopWatch.ElapsedMilliseconds;

    // Scenario 3: Zoom cycles
    frameTimes.Clear();
    stopWatch.Restart();
    for (int i = 0; i < 5; i++)
    {
        await ZoomToAsync(0.1, i * 0.15);
        await ZoomToAsync(0.02, i * 0.15);
        await ZoomToAsync(1.0,  0.0);
    }
    stopWatch.Stop();
    long   zoomMs = stopWatch.ElapsedMilliseconds;

    double avgUiMs = frameTimes.Count > 0 ? frameTimes.Average() : 0;

    Status = "Benchmark Completed!";
}
```

### Step 6: Display benchmark results in the UI

To present benchmarking results effectively, the application displays key metrics such as LoadMetricsText, PanMetricsText, ZoomMetricsText, MemoryMetricsText, and UiRespMetricsText using TextBlock controls. These metrics are formatted via the FormatThreeCases helper method in the BenchmarkViewModel, offering a comparative view across:

- FastLineSeries.
- FastLineBitmapSeries.
- FastLineBitmapSeries with anti-aliasing enabled.

Additionally, the UI integrates [SfLineSparkline](https://help.syncfusion.com/wpf/sparkline/getting-started)
 controls to visualize historical performance trends for **load time** and ** UI responsiveness** over the last 10 benchmark runs, providing users with a quick and intuitive overview of performance consistency.

![Benchmark results in the UI using WPF Charts](https://www.syncfusion.com/blogs/wp-content/uploads/2025/10/img2.png)

Displaying benchmark results in the UI using WPF Charts

### Evaluate benchmark results

Once the benchmarking process is complete and the results are displayed in the UI, it’s important to interpret the metrics to understand how well the chart performs under load. Here’s a breakdown of what each value indicates:

- **Initial load**: ~57 ms for 1 million points.
- **Pan/scroll**: ~252 ms.
- **Zoom**: ~133 ms.
- **UI frame time**: ~4.47 ms/frame (well below 16.67 ms for 60 FPS).

Here’s a quick preview of the functional output of our benchmarking application:

![Benchmark performance results using Syncfusion WPF Charts](https://www.syncfusion.com/blogs/wp-content/uploads/2025/10/final-demo-1.gif)

Evaluating benchmark performance results using Syncfusion WPF Charts

### Performance best practices

This benchmark highlights how Syncfusion WPF Charts handle one million data points efficiently, showing the importance of using fast series types for responsive, high-performance applications.

- **Disable ListenPropertyChange** for large datasets unless real-time updates are needed.
- **Suspend and resume notifications** during batch updates using SuspendSeriesNotification() and ResumeSeriesNotification().
- **Use fast series types** for large datasets.
- **Profile performance** using tools like Visual Studio Diagnostics or dotTrace.
- **Monitor UI frame time** for smooth interactions.

For a deeper comparison of series types and optimization strategies, refer to this helpful Syncfusion on [KB article](https://support.syncfusion.com/kb/article/6191/comparison-of-line-series-fast-line-series-and-fast-line-bitmap-series-in-wpf-chart-sfchart)
.

## GitHub reference

You can find the full source code for this sample in our [GitHub](https://github.com/SyncfusionExamples/Visualizing-Big-Data--Benchmarking-WPF-Performance-Charts)
 demo.

## Conclusion

Thank you for taking the time to go through this blog. This benchmarking exercise demonstrates how Syncfusion [WPF Charts](https://www.syncfusion.com/wpf-controls/charts)
 efficiently handle large datasets, up to one million points, with optimized load times, smooth interactions, and minimal memory usage. `FastLineSeries` and `FastLineBitmapSeries` are key to achieving high performance in data-intensive applications. By applying these best practices, developers can build scalable, responsive WPF charts that deliver a superior user experience.

If you’re a Syncfusion user, you can download the setup from the [license and downloads](https://www.syncfusion.com/sales/teamlicense)
 page. Otherwise, you can download a free [30-day trial](https://www.syncfusion.com/downloads/)
.

You can also contact us through our [support forum](https://www.syncfusion.com/forums?_ga=2.160385213.108886952.1555906495-214292665.1551328372)
, [support portal](https://support.syncfusion.com/)
, or [feedback Portal](https://www.syncfusion.com/feedback/)
 for queries. We are always happy to assist you!

## Related Blogs



[Build a WPF Health Tracker Dashboard: Visualize Water Intake & Sleep Patterns with Interactive Charts](https://www.syncfusion.com/blogs/post/wpf-health-tracker-chart-phase-2)



[Build a WPF Health Tracker Dashboard: Visualize Calories and Steps with Interactive Charts](https://www.syncfusion.com/blogs/post/wpf-health-tracker-chart-calories-steps)



[Visualize Your Music: Real-Time WPF Charts that Sync with Sound](https://www.syncfusion.com/blogs/post/wpf-charts-audio-visualization)



[How to Build a Real-Time Cloud Monitoring Dashboard Using WPF Charts](https://www.syncfusion.com/blogs/post/real-time-cloud-monitoring-wpf-charts)
