Ir para o conteúdo

Cross Runtime Benchmark Library — Java Edition

Version Java License

Biblioteca de Benchmarking de Alta Precisão para aplicações Java

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 Java, 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 C# 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

Arquitetura

Componentes Principais

Componente Pacote 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

Pipeline de Execução


4. Instalação

Maven

<dependency>
    <groupId>io.github.cross.runtime.bench</groupId>
    <artifactId>cross-runtime-bench-java</artifactId>
    <version>1.0.0</version>
</dependency>

Gradle

implementation 'io.github.cross.runtime.bench:cross-runtime-bench-java:1.0.0'

Build Local

git clone https://github.com/eduardocvalente/lib-cross-runtime-bench-java-ifg.git
cd lib-cross-runtime-bench-java
mvn clean install

5. Exemplos de Uso

5.1 Benchmark Simples

import crossruntimebench.Benchmark;
import crossruntimebench.models.BenchmarkResult;

public class SimpleBenchmark {
    public static void main(String[] args) {
        // 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;
            }
        });

        System.out.printf("Mean: %.3f ms (CV: %.2f%%)%n",
            result.getMeanNs() / 1_000_000.0,
            result.getCvPercent());
    }
}

5.2 Benchmark com Configuração Personalizada

import crossruntimebench.Benchmark;
import crossruntimebench.config.BenchmarkConfig;
import crossruntimebench.models.BenchmarkResult;

public class ConfiguredBenchmark {
    public static void main(String[] args) {
        // Configuração de alta precisão
        BenchmarkConfig config = new BenchmarkConfig.Builder()
            .withWarmupIterations(200)
            .withMeasurementIterations(100)
            .withForks(5)
            .withOutlierFilter(BenchmarkConfig.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)

import crossruntimebench.core.ProcessBenchmarkRunner;
import crossruntimebench.config.BenchmarkConfig;

public class IsolatedBenchmark {
    public static void main(String[] args) {
        BenchmarkConfig config = new BenchmarkConfig.Builder()
            .withForks(5)
            .withEnableProcessIsolation(true)
            .withMeasurementIterations(50)
            .build();

        ProcessBenchmarkRunner runner = new ProcessBenchmarkRunner(config, MyBenchmark.class);
        BenchmarkResult result = runner.run(() -> {
            // Cada fork executa em processo separado
            // Estado JIT, heap, GC completamente isolados
        });
    }
}

5.4 Comparação de Algoritmos

import crossruntimebench.Benchmark;
import crossruntimebench.statistics.AdvancedStatistics;
import crossruntimebench.statistics.BenchmarkComparisonResult;

public class AlgorithmComparison {
    public static void main(String[] args) {
        // Medir algoritmo A
        BenchmarkResult resultA = Benchmark.run(() -> algorithmA());

        // Medir algoritmo B
        BenchmarkResult resultB = Benchmark.run(() -> algorithmB());

        // Comparação estatística
        double[] samplesA = toDoubleArray(resultA.getAllMeasurements());
        double[] samplesB = toDoubleArray(resultB.getAllMeasurements());

        BenchmarkComparisonResult comparison = AdvancedStatistics.compareBenchmarks(
            samplesA, samplesB, "Algorithm A", "Algorithm B");

        System.out.println(comparison.getSummary());
        // Output: "Algorithm B is 15.3% faster (p < 0.001, Cohen's d = 1.2 [Large])"
    }
}

5.5 Prevenção de DCE com Blackhole

import crossruntimebench.utils.Blackhole;

public class BlackholeBenchmark {
    public static void main(String[] args) {
        Blackhole 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 boolean true Warmup adaptativo via CV%
cvTargetPercent double 5.0 CV% alvo para estabilidade
cpuAffinity boolean true Habilitar pinning de CPU
cpuAffinityCores int[] {0} Cores para pinning
forceGc boolean true Forçar GC antes de medir
gcWaitTimeMs int 100 Pausa após GC
collectHardwareCounters boolean 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 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.png para o diagrama de isolamento por processo.

Benefícios: - Heap limpo (sem fragmentação acumulada) - JIT cache fresco (sem perfis enviesados) - GC state resetado - Variação reduzida em 30-50%

7.3 CPU Affinity (Pinning)

// Windows: SetProcessAffinityMask via JNA
// Linux: taskset ou 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
heapTotal bytes Heap total alocado
nonHeapUsed bytes Metaspace + Code cache

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)

StatisticalTestResult 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": "OpenJDK 21.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 C#, 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 Java
        uses: actions/setup-java@v4
        with:
          java-version: '21'
          distribution: 'temurin'

      - name: Run Benchmarks
        run: mvn exec:java -Dexec.mainClass="MyBenchmark"

      - 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
BenchmarkComparisonResult comparison = AdvancedStatistics.compareBenchmarks(
    baselineResults, currentResults);

if (comparison.getStatisticalTest().isSignificant() && 
    comparison.getPercentChange() > 5.0) {
    throw new RegressionDetectedException(comparison.getSummary());
}

12. Referências

Literatura Acadêmica

  1. Georges, A., Buytaert, D., & Eeckhout, L. (2007). Statistically Rigorous Java Performance Evaluation. OOPSLA.
  2. Mytkowicz, T., et al. (2009). Producing Wrong Data Without Doing Anything Obviously Wrong!. ASPLOS.
  3. Kalibera, T., & Jones, R. (2013). Rigorous Benchmarking in Reasonable Time. ISMM.

Bibliotecas de Referência

Recursos Adicionais


Licença

MIT License — Copyright (c) 2026 Eduardo Costa Valente


Cross Runtime Benchmark Library — Medição de performance com rigor científico.