Skip to main content

Performance Benchmarks

The Toggly .NET SDK is designed for high performance with minimal overhead. All benchmarks were run using BenchmarkDotNet on .NET 9.0.

Feature Flag Evaluation Performance​

Simple Flag Evaluation​

The primary metric for most use cases - evaluating a simple feature flag with no targeting rules:

MetricValue
Mean Time~360 nanoseconds (0.36 µs)
Memory Allocated1.55 KB
GC Collections (Gen0)0.19 per evaluation

This means you can perform over 2.7 million feature flag evaluations per second on a single core (more than 2.7 million per second).

Evaluation with Many Flags​

Performance remains consistent even with large numbers of flags in cache:

Flag CountMean TimeMemory Allocated
100 flags366 ns1.55 KB
500 flags356 ns1.55 KB
1,000 flags363 ns1.55 KB

The SDK uses efficient dictionary lookups, so cache size has minimal impact on evaluation performance.

Non-Existent Flags​

Evaluating flags that don't exist is even faster:

MetricValue
Mean Time~163 nanoseconds (0.16 µs)
Memory Allocated304 bytes

Targeting Rules Performance​

Percentage Rollout​

Evaluating flags with percentage-based rollouts:

MetricValue
Mean Time~785 nanoseconds (0.79 µs)
Memory Allocated2.88 KB
Overhead vs Simple~2.2x

User Targeting​

Evaluating flags with user-based targeting rules:

MetricValue
Mean Time~1,660 nanoseconds (1.66 µs)
Memory Allocated3.16 KB
Overhead vs Simple~4.6x

Complex Targeting​

Evaluating flags with multiple targeting rules:

MetricValue
Mean Time~1,540 nanoseconds (1.54 µs)
Memory Allocated4.34 KB

Memory Allocation​

Per-Evaluation Memory​

Each feature flag evaluation allocates minimal memory:

ScenarioMemory Allocated
Simple evaluation1.55 KB
With usage stats1.55 KB
With context1.58 KB
Percentage rollout2.88 KB
User targeting3.16 KB

Bulk Evaluations​

Memory scales linearly with the number of evaluations:

EvaluationsTotal MemoryPer Evaluation
10 flags2.97 KB~297 bytes
50 flags14.84 KB~297 bytes
100 flags29.69 KB~297 bytes

Usage Statistics Overhead​

The SDK tracks usage statistics with minimal overhead:

OperationMean TimeMemory Allocated
Record check~59 ns32 bytes
Record usage~82 ns56 bytes
Full evaluation with stats~360 ns1.55 KB

Usage statistics tracking adds less than 0.1 microseconds of overhead per evaluation.

Initialization Performance​

Service Collection Setup​

Time to configure the dependency injection container:

MetricValue
Mean Time~139 microseconds (0.14 ms)

Provider Initialization​

Time to initialize the feature provider and load flags from snapshot:

MetricValue
Mean Time~202 milliseconds
Memory Allocated374 KB
info

This initialization happens once at application startup. Flags are loaded from a snapshot provider (e.g., distributed cache, database) to ensure fast startup times.

Initial Flag Load​

Time to load flags from snapshot provider:

MetricValue
Mean Time~31 nanoseconds
Memory Allocated208 bytes

This demonstrates the efficiency of snapshot-based loading.

Parallel Evaluation​

The SDK handles concurrent evaluations efficiently:

EvaluationsSequentialParallelOverhead
1 flag167 ns202 ns+21%
5 flags828 ns880 ns+6%
10 flags1,599 ns1,722 ns+8%
50 flags8,571 ns8,957 ns+5%

Parallel evaluation has minimal overhead, making it safe to evaluate flags concurrently.

Performance Summary​

Key Metrics​

  • Simple evaluation: ~360 ns (0.36 µs)
  • Memory per evaluation: ~1.55 KB
  • Throughput: More than 2.7 million evaluations/second per core
  • Targeting overhead: 2-5x for complex rules
  • Usage stats overhead: Less than 0.1 µs

Comparison to Alternatives​

The Toggly .NET SDK adds minimal overhead compared to alternatives:

  • Simple evaluation is comparable to a dictionary lookup
  • Memory allocation is optimized with object pooling where applicable
  • No blocking I/O during evaluation (flags are cached in memory)
  • Thread-safe concurrent evaluations with minimal contention

Best Practices for Performance​

1. Use Snapshot Providers​

Snapshot providers (Redis, SQL Server, etc.) enable fast startup by loading flags from a persistent cache rather than fetching from the API:

services.AddTogglyWeb(options => {
options.AppKey = "your-app-key";
options.Environment = "production";
});

// Add snapshot provider for fast startup
services.AddSingleton<IFeatureSnapshotProvider>(
new DistributedCacheFeatureSnapshotProvider(cache));

2. Cache Feature Definitions​

Feature definitions are automatically cached in memory and refreshed periodically. No additional caching is needed.

3. Evaluate Flags Efficiently​

// Good: Evaluate once and reuse
var isEnabled = await _featureManager.IsEnabledAsync("my-feature");
if (isEnabled) {
// Use feature
}

// Avoid: Multiple evaluations in the same request
if (await _featureManager.IsEnabledAsync("my-feature")) { }
if (await _featureManager.IsEnabledAsync("my-feature")) { } // Don't do this

4. Use IFeatureManagerSnapshot​

IFeatureManagerSnapshot ensures consistent flag values throughout a request:

// Recommended for web applications
public class MyController : Controller
{
private readonly IFeatureManagerSnapshot _featureManager;

public MyController(IFeatureManagerSnapshot featureManager)
{
_featureManager = featureManager;
}
}

Benchmark Environment​

All benchmarks were run on:

  • Platform: macOS (Apple M4 Max)
  • .NET Version: 9.0.0
  • Runtime: Arm64 RyuJIT AdvSIMD
  • Tool: BenchmarkDotNet v0.13.12

Results may vary slightly on different hardware and .NET versions, but the relative performance characteristics remain consistent.

Source Code​

The complete benchmark source code is available in the Toggly.FeatureManagement repository:

📦 Benchmark Source Code

You can run the benchmarks yourself to verify these results or test on your own hardware.

Next Steps​