Performance Benchmarks
All benchmarks measured via bUnit + Stopwatch on .NET 9 (Apple M-series). JIT warmup pass runs before timing. These are server-side render times — the time from Render<T>() call to completed DOM, including SVG path calculation, layout engine, and Blazor diffing.
Methodology: Each benchmark renders the component once after a warmup pass that triggers JIT compilation. Times are wall-clock
Stopwatch.Elapsedaround the bUnitRender<T>()call. Run withdotnet test --filter "Category=Performance".
Charts
| Component | Data Size | Render Time | Target |
|---|---|---|---|
| LineChart | 100 points | 1 ms | < 20 ms |
| LineChart | 1,000 points | 5 ms | < 100 ms |
| LineChart | 10,000 points | 113 ms | < 500 ms |
| BarChart | 100 items | 7 ms | < 20 ms |
| PieChart | 20 slices | 1 ms | < 10 ms |
| SankeyChart | 50 nodes, 100 links | 5 ms | < 50 ms |
What’s measured
- SVG path computation (Catmull-Rom interpolation for smooth curves, arc calculations for pie)
- Layout engine (axis label sizing, tick generation, plot area calculation)
- Scale calculations (linear, logarithmic, time)
- Blazor render tree construction and diffing
What’s NOT measured
- Browser paint time (CSS, GPU compositing)
- Network latency (Blazor Server SignalR round-trip)
- Animation frame cost
- JS interop calls (pan/zoom, resize observer)
DataGrid
| Operation | Row Count | Time | Target |
|---|---|---|---|
| Initial render | 100 rows | 15 ms | < 50 ms |
| Initial render | 1,000 rows | < 1 ms | < 50 ms |
| Initial render | 10,000 rows | 1 ms | < 200 ms |
| Sort (click header) | 10,000 rows | 2 ms | < 50 ms |
| Filter (text search) | 10,000 rows | 3 ms | < 30 ms |
Note: The 100-row benchmark is slower than 1,000 and 10,000 because it includes first-render overhead (column collection, cascading parameter setup). Subsequent renders are faster due to cached state.
Virtual scrolling
When VirtualizeRows="true" is set, the DataGrid uses Blazor’s built-in Virtualize<T> component. Only visible rows (plus OverscanCount buffer rows) are rendered in the DOM. This means:
- 100,000 rows renders the same number of DOM elements as 50 rows
- Scroll performance is constant regardless of dataset size
- Memory usage grows linearly with data but DOM size stays fixed
Export performance
| Format | 10,000 rows × 6 columns | File Size |
|---|---|---|
| CSV | < 5 ms | ~400 KB |
| Excel (XLSX) | < 50 ms | ~200 KB |
Excel export uses a zero-dependency SpreadsheetML writer (raw ZIP + XML). No DocumentFormat.OpenXml required.
Comparison
| Metric | Arcadia | Syncfusion | Telerik |
|---|---|---|---|
| Chart bundle size | ~120 KB (DLL + CSS) | ~3 MB | ~1.5 MB |
| DataGrid bundle size | ~95 KB (DLL + CSS + JS) | ~800 KB | ~600 KB |
| JavaScript dependency | 0 KB (charts), 2.4 KB (grid resize) | Required | Required |
| Line chart 10K points | 113 ms | ~200 ms* | ~250 ms* |
| Grid 10K row sort | 2 ms | ~15 ms* | ~20 ms* |
*Competitor times are estimates from public benchmarks and may vary by version and hardware.
Running benchmarks locally
dotnet test tests/Arcadia.Tests.Unit/Arcadia.Tests.Unit.csproj \
--filter "Category=Performance" \
--logger "console;verbosity=detailed"
Benchmarks are excluded from CI by default (--filter "Category!=Performance") to avoid JIT variance on shared runners. Run locally for accurate results.
Hardware
These benchmarks were recorded on:
- Apple M-series (ARM64)
- .NET 9.0.115
- macOS 15.x
- bUnit 2.0.66
Your results will vary based on hardware and .NET version. The targets in the test assertions are set 3-5x higher than typical measured times to account for CI runner variance.