Cross Runtime Benchmark Library — C# Edition¶
Biblioteca de Benchmarking de Alta Precisão para aplicações .NET
Solução profissional para medição de performance com rigor estatístico, isolamento metodológico e reprodutibilidade científica.
1. Visão Geral¶
A Cross Runtime Benchmark Library é uma solução completa para benchmarking de aplicações .NET, projetada para produzir resultados estatisticamente confiáveis e reproduzíveis.
Características Principais¶
| Característica | Descrição |
|---|---|
| Warmup Adaptativo | Detecção automática de estabilidade via CV% (Coeficiente de Variação) |
| Isolamento por Processo | Forking para eliminação de estado acumulado entre benchmarks |
| CPU Affinity | Pinning de threads em cores específicos para reduzir variação |
| Prevenção de DCE | Blackhole pattern para evitar Dead Code Elimination |
| Detecção de Outliers | Métodos IQR, MAD e Z-Score para filtragem estatística |
| Intervalos de Confiança | Cálculo de IC 95% via distribuição t-Student |
| Hardware Counters | Coleta de ciclos, instruções, cache misses (quando disponível) |
| Saída Padronizada | JSON compatível com Java para análise cross-platform |
Público-Alvo¶
- Equipes de engenharia de performance
- Desenvolvedores de bibliotecas críticas
- Pesquisadores em otimização de software
- Times de QA com foco em regressão de performance
2. Arquitetura¶

Componentes Principais¶
| Componente | Namespace | Responsabilidade |
|---|---|---|
BenchmarkRunner |
Core |
Orquestração do pipeline de execução |
ProcessBenchmarkRunner |
Core |
Execução com isolamento por processo |
WarmupManager |
Warmup |
Gerenciamento de aquecimento adaptativo |
StatisticalAnalysis |
Statistics |
Cálculos estatísticos descritivos |
AdvancedStatistics |
Statistics |
Testes de significância e comparação |
HardwareCountersCollector |
Metrics |
Coleta de contadores PMU |
JsonReporter |
Reporters |
Exportação em formato JSON |
Blackhole |
Utils |
Prevenção de Dead Code Elimination |
3. Fluxo de Execução¶

4. Instalação¶
NuGet¶
Package Reference¶
Build Local¶
git clone https://github.com/eduardocvalente/lib-cross-runtime-bench-csharp-ifg.git
cd lib-cross-runtime-bench-csharp/src/Cross.Runtime.Bench.Csharp
dotnet build -c Release
5. Exemplos de Uso¶
5.1 Benchmark Simples¶
using Cross.Runtime.Bench.Csharp;
using Cross.Runtime.Bench.Csharp.Models;
class Program
{
static void Main()
{
// Benchmark com configuração padrão
BenchmarkResult result = Benchmark.Run(() =>
{
// Código a ser medido
int sum = 0;
for (int i = 0; i < 1000; i++)
{
sum += i;
}
});
Console.WriteLine($"Mean: {result.MeanNs / 1_000_000.0:F3} ms (CV: {result.CvPercent:F2}%)");
}
}
5.2 Benchmark com Configuração Personalizada¶
using Cross.Runtime.Bench.Csharp;
using Cross.Runtime.Bench.Csharp.Config;
using Cross.Runtime.Bench.Csharp.Models;
class Program
{
static void Main()
{
// Configuração de alta precisão
var config = new BenchmarkConfig.Builder()
.WithWarmupIterations(200)
.WithMeasurementIterations(100)
.WithForks(5)
.WithOutlierFilter(OutlierFilter.MAD)
.WithAdaptiveWarmup(true)
.WithCvTargetPercent(3.0)
.WithCpuAffinity(true)
.WithCpuAffinityCores(2, 3)
.Build();
BenchmarkResult result = Benchmark.Run(() =>
{
PerformExpensiveOperation();
}, config);
// Exportar para JSON
result.ExportJson("benchmark_result.json");
}
}
5.3 Benchmark com Forking (Isolamento por Processo)¶
using Cross.Runtime.Bench.Csharp.Core;
using Cross.Runtime.Bench.Csharp.Config;
class Program
{
static void Main()
{
var config = new BenchmarkConfig.Builder()
.WithForks(5)
.WithEnableProcessIsolation(true)
.WithMeasurementIterations(50)
.Build();
var runner = new ProcessBenchmarkRunner(config, typeof(MyBenchmark));
BenchmarkResult result = runner.Run(() =>
{
// Cada fork executa em processo separado
// Estado JIT, heap, GC completamente isolados
});
}
}
5.4 Comparação de Algoritmos¶
using Cross.Runtime.Bench.Csharp;
using Cross.Runtime.Bench.Csharp.Statistics;
class Program
{
static void Main()
{
// Medir algoritmo A
var resultA = Benchmark.Run(() => AlgorithmA());
// Medir algoritmo B
var resultB = Benchmark.Run(() => AlgorithmB());
// Comparação estatística
double[] samplesA = resultA.AllMeasurements.Select(x => (double)x).ToArray();
double[] samplesB = resultB.AllMeasurements.Select(x => (double)x).ToArray();
var comparison = AdvancedStatistics.CompareBenchmarks(
samplesA, samplesB, "Algorithm A", "Algorithm B");
Console.WriteLine(comparison.Summary);
// Output: "Algorithm B is 15.3% faster (p < 0.001, Cohen's d = 1.2 [Large])"
}
}
5.5 Prevenção de DCE com Blackhole¶
using Cross.Runtime.Bench.Csharp.Utils;
class Program
{
static void Main()
{
var blackhole = new Blackhole();
Benchmark.Run(() =>
{
// Sem Blackhole: compilador pode eliminar código
int result = ExpensiveComputation();
// Com Blackhole: força execução do código
blackhole.Consume(result);
});
}
}
6. Configuração¶
6.1 Presets Disponíveis¶
| Preset | Warmup | Medição | Forks | Outliers | Uso |
|---|---|---|---|---|---|
DEFAULT |
100 iter | 50 iter | 3 | IQR | 90% dos casos |
FAST |
10 iter | 10 iter | 1 | None | Dev/debug rápido |
HIGH_PRECISION |
200 iter | 200 iter | 5 | MAD | Decisões críticas |
6.2 Parâmetros de Configuração¶
| Parâmetro | Tipo | Default | Descrição |
|---|---|---|---|
WarmupIterations |
int | 100 | Máximo de iterações de warmup |
MeasurementIterations |
int | 50 | Iterações de medição |
WarmupTimeSeconds |
double | 3.0 | Timeout de warmup |
Forks |
int | 3 | Número de processos isolados |
OutlierFilter |
enum | IQR | Método de filtragem (IQR/MAD/ZSCORE/NONE) |
AdaptiveWarmup |
bool | true | Warmup adaptativo via CV% |
CvTargetPercent |
double | 5.0 | CV% alvo para estabilidade |
CpuAffinity |
bool | true | Habilitar pinning de CPU |
CpuAffinityCores |
int[] | {0} | Cores para pinning |
ForceGc |
bool | true | Forçar GC antes de medir |
GcWaitTimeMs |
int | 100 | Pausa após GC |
CollectHardwareCounters |
bool | true | Coletar PMU counters |
ConfidenceLevel |
double | 0.95 | Nível de confiança para IC |
7. Técnicas de Isolamento¶
7.1 Warmup Adaptativo¶
Algoritmo:
1. Executar ação
2. A cada 5 iterações: calcular CV% das últimas N medições
3. Se CV% < target por 3 verificações consecutivas → parar
4. Senão: continuar até timeout ou max iterações
Por que é importante: - JIT/Tiered compilation ocorre nas primeiras execuções (10-100x mais lento) - Caches de CPU (L1/L2/L3) precisam ser aquecidos - Branch predictors precisam de histórico
7.2 Forking por Processo¶
Ver Fase 1 em
imagens/pipeline.pngpara o diagrama de isolamento por processo.
Benefícios: - Heap limpo (sem fragmentação acumulada) - JIT/Tiered cache fresco (sem perfis enviesados) - GC state resetado - Variação reduzida em 30-50%
7.3 CPU Affinity (Pinning)¶
// Windows: SetProcessAffinityMask via P/Invoke
// Linux: sched_setaffinity
CpuAffinityManager.SetCpuAffinity(new int[] { 2, 3 });
Benefícios: - Cache locality (L1/L2 permanecem quentes) - Menos context switches entre cores - Variação reduzida em 15-30%
7.4 Prevenção de DCE (Blackhole)¶
// Problema: compilador elimina código "morto"
int result = Compute(); // Pode ser eliminado!
// Solução: Blackhole
blackhole.Consume(result); // Força execução via volatile write
8. Métricas Coletadas¶
8.1 Timing¶
| Métrica | Unidade | Descrição |
|---|---|---|
MeanNs |
nanosegundos | Média aritmética |
MedianNs |
nanosegundos | Valor central (resistente a outliers) |
StdDevNs |
nanosegundos | Desvio padrão |
MinNs |
nanosegundos | Valor mínimo |
MaxNs |
nanosegundos | Valor máximo |
8.2 Memória¶
| Métrica | Unidade | Descrição |
|---|---|---|
HeapUsed |
bytes | Heap ocupado (GC.GetTotalMemory) |
HeapTotal |
bytes | Working set do processo |
Gen0Collections |
count | Coletas Gen 0 |
Gen1Collections |
count | Coletas Gen 1 |
Gen2Collections |
count | Coletas Gen 2 |
8.3 CPU¶
| Métrica | Unidade | Descrição |
|---|---|---|
UserTimeMs |
milissegundos | Tempo em user mode |
SystemTimeMs |
milissegundos | Tempo em kernel mode |
CpuPercent |
percentual | Utilização de CPU |
8.4 Hardware Counters (PMU)¶
| Métrica | Descrição |
|---|---|
Cycles |
Ciclos de CPU consumidos |
Instructions |
Instruções executadas |
IPC |
Instructions Per Cycle (eficiência) |
CPI |
Cycles Per Instruction (latência) |
CacheReferences |
Acessos ao cache |
CacheMisses |
Faltas de cache |
BranchInstructions |
Instruções de branch |
BranchMisses |
Branches mispredicted |
9. Análise Estatística¶
9.1 Estatísticas Descritivas¶
| Estatística | Fórmula | Interpretação |
|---|---|---|
| Mean (μ) | Σx / n | Centro da distribuição |
| Median | valor central | Resistente a outliers |
| StdDev (σ) | √(Σ(x-μ)²/(n-1)) | Dispersão |
| CV% | (σ/μ) × 100 | Confiabilidade relativa |
| IQR | Q3 - Q1 | Dispersão robusta |
9.2 Intervalo de Confiança 95%¶
IC = μ ± (t × SEM)
onde:
SEM = σ / √n (Erro Padrão da Média)
t = valor t-Student (depende de n-1 graus de liberdade)
9.3 Detecção de Outliers¶
| Método | Fórmula | Uso |
|---|---|---|
| IQR | Outlier se x < Q1-1.5×IQR ou x > Q3+1.5×IQR | Padrão, robusto |
| MAD | Outlier se |x - median| > 3 × MAD | Distribuições enviesadas |
| Z-Score | Outlier se |ModZ| > 3.5 | Distribuições normais |
9.4 Teste de Significância (Welch t-test)¶
var test = AdvancedStatistics.WelchTTestFull(sampleA, sampleB, 0.05);
// Interpretação:
// p < 0.05: Diferença significativa (95% confiança)
// p < 0.01: Diferença muito significativa (99% confiança)
// Cohen's d: Tamanho do efeito (0.2=small, 0.5=medium, 0.8=large)
10. Formato de Saída¶
10.1 JSON Schema¶
{
"export_date": "2026-02-17T12:34:56Z",
"benchmark_name": "sort_algorithm_benchmark",
"metrics": {
"timing": {
"mean_ns": 12345678.9,
"median_ns": 12200000,
"stddev_ns": 500000,
"min_ns": 11500000,
"max_ns": 13500000,
"sample_count": 50,
"cv_percent": 4.05
},
"throughput": {
"ops_per_second": 81.0
},
"memory": {
"heap_bytes": 33554432,
"total_bytes": 301989888
},
"cpu": {
"user_time_ms": 120.5,
"system_time_ms": 5.2,
"cpu_usage_percent": 12.34
},
"hardware_counters": {
"cycles": 2000000,
"instructions": 4000000,
"instructions_per_cycle": 2.0,
"is_available": true
}
},
"environment": {
"os": "Windows 11",
"runtime": ".NET 8.0.1",
"cpu_model": "Intel Core i7-9700K",
"processor_count": 8
}
}
10.2 Compatibilidade Cross-Platform¶
O schema JSON é 100% compatível com a implementação Java, permitindo: - Comparação de resultados entre runtimes - Análise unificada em ferramentas de BI - Integração com pipelines CI/CD multi-linguagem
11. Integração CI/CD¶
11.1 GitHub Actions¶
name: Performance Regression
on: [push, pull_request]
jobs:
benchmark:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: '8.0.x'
- name: Run Benchmarks
run: dotnet run --project src/MyBenchmark -c Release
- name: Check Regression
run: |
# Comparar com baseline
python scripts/check_regression.py \
--baseline baseline.json \
--current result.json \
--threshold 5
11.2 Armazenamento de Baselines¶
// Salvar baseline
result.ExportJson("baselines/v2.0.0_baseline.json");
// Comparar com baseline
var comparison = AdvancedStatistics.CompareBenchmarks(
baselineResults, currentResults);
if (comparison.StatisticalTest.IsSignificant &&
comparison.PercentChange > 5.0)
{
throw new RegressionDetectedException(comparison.Summary);
}
12. Referências¶
Literatura Acadêmica¶
- Georges, A., Buytaert, D., & Eeckhout, L. (2007). Statistically Rigorous Java Performance Evaluation. OOPSLA.
- Mytkowicz, T., et al. (2009). Producing Wrong Data Without Doing Anything Obviously Wrong!. ASPLOS.
- Kalibera, T., & Jones, R. (2013). Rigorous Benchmarking in Reasonable Time. ISMM.
Bibliotecas de Referência¶
- BenchmarkDotNet — .NET benchmarking
- JMH — Java Microbenchmark Harness
- Criterion.rs — Rust benchmarking
Recursos Adicionais¶
- imagens/architecture.png — Arquitetura em camadas
- imagens/pipeline.png — Pipeline de execução
- BENCHMARK_NOTES.md — Notas de implementação
- Examples/ — Exemplos de uso
Licença¶
MIT License — Copyright (c) 2026 Eduardo Costa Valente
Cross Runtime Benchmark Library — Medição de performance com rigor científico.