---
title: "Benchmarking e Performance em Zig"
url: "https://ziglang.com.br/receitas/benchmarking-e-performance-em-zig/"
markdown_url: "https://ziglang.com.br/receitas/benchmarking-e-performance-em-zig.MD"
description: "Receita prática para benchmarking de código Zig. Medição de tempo, comparação de implementações, prevenção de otimização espúria e boas práticas de performance."
date: "2026-02-21"
author: "Zig Brasil"
---

# Benchmarking e Performance em Zig

Receita prática para benchmarking de código Zig. Medição de tempo, comparação de implementações, prevenção de otimização espúria e boas práticas de performance.


## Introdução

Medir performance é essencial para código de sistemas. Zig oferece ferramentas na biblioteca padrão para medição de tempo com alta resolução, e o sistema de testes pode ser usado para benchmarks simples. Para profiling avançado, Zig é compatível com ferramentas externas como perf e Valgrind.

Para testes em geral, veja [Testes Unitários Básicos](/receitas/zig-teste-unitario-basico/). Para otimização com SIMD, consulte o artigo [Zig vs Assembly](/artigos/zig-vs-assembly/).

## Pré-requisitos

- Zig instalado (versão 0.13+). Veja o [guia de instalação](/tutoriais/como-instalar-zig/)
- Conhecimento básico de Zig. Consulte a [introdução ao Zig](/tutoriais/introducao-ao-zig/)

## Medição de Tempo Básica

```zig
const std = @import("std");

pub fn main() !void {
    var timer = try std.time.Timer.start();

    // Código a ser medido
    var soma: u64 = 0;
    for (0..10_000_000) |i| {
        soma += i;
    }

    const elapsed = timer.read();

    std.debug.print("Resultado: {}\n", .{soma});
    std.debug.print("Tempo: {}ns ({d:.3}ms)\n", .{
        elapsed,
        @as(f64, @floatFromInt(elapsed)) / 1_000_000.0,
    });
}
```

## Benchmark com Múltiplas Iterações

```zig
const std = @import("std");

fn benchmark(comptime func: anytype, args: anytype, comptime iteracoes: usize) struct {
    media_ns: u64,
    min_ns: u64,
    max_ns: u64,
} {
    var min: u64 = std.math.maxInt(u64);
    var max: u64 = 0;
    var total: u64 = 0;

    for (0..iteracoes) |_| {
        var timer = std.time.Timer.start() catch unreachable;
        const resultado = @call(.never_inline, func, args);
        const elapsed = timer.read();
        std.mem.doNotOptimizeAway(&resultado);

        total += elapsed;
        if (elapsed < min) min = elapsed;
        if (elapsed > max) max = elapsed;
    }

    return .{
        .media_ns = total / iteracoes,
        .min_ns = min,
        .max_ns = max,
    };
}

fn somaIterativa(n: u64) u64 {
    var soma: u64 = 0;
    for (0..n) |i| {
        soma += i;
    }
    return soma;
}

fn somaFormula(n: u64) u64 {
    return n * (n - 1) / 2;
}

pub fn main() !void {
    const n: u64 = 1_000_000;
    const iter: usize = 100;

    const b1 = benchmark(somaIterativa, .{n}, iter);
    const b2 = benchmark(somaFormula, .{n}, iter);

    std.debug.print("Soma iterativa: média={}ns, min={}ns, max={}ns\n", .{
        b1.media_ns, b1.min_ns, b1.max_ns,
    });
    std.debug.print("Soma fórmula:   média={}ns, min={}ns, max={}ns\n", .{
        b2.media_ns, b2.min_ns, b2.max_ns,
    });
}
```

## Prevenir Otimização Espúria

O compilador pode eliminar código cujo resultado não é usado. Use `doNotOptimizeAway` para prevenir isso:

```zig
const std = @import("std");

fn benchmarkHash(dados: []const u8, iteracoes: usize) u64 {
    var timer = std.time.Timer.start() catch unreachable;

    for (0..iteracoes) |_| {
        const hash = std.hash.Wyhash.hash(0, dados);
        std.mem.doNotOptimizeAway(&hash); // Impede o compilador de eliminar
    }

    return timer.read();
}
```

## Benchmark em Testes

```zig
test "benchmark busca linear vs binária" {
    const dados = blk: {
        var arr: [10000]i32 = undefined;
        for (&arr, 0..) |*v, i| v.* = @intCast(i * 2);
        break :blk arr;
    };

    const alvo: i32 = 9998;

    // Busca linear
    {
        var timer = try std.time.Timer.start();
        for (0..1000) |_| {
            const resultado = std.mem.indexOf(i32, &dados, &.{alvo});
            std.mem.doNotOptimizeAway(&resultado);
        }
        const elapsed = timer.read();
        std.debug.print("\nBusca linear: {}ns/op\n", .{elapsed / 1000});
    }

    // Busca binária
    {
        var timer = try std.time.Timer.start();
        for (0..1000) |_| {
            const resultado = std.sort.binarySearch(i32, alvo, &dados, {}, struct {
                fn f(_: void, a: i32, b: i32) std.math.Order {
                    return std.math.order(a, b);
                }
            }.f);
            std.mem.doNotOptimizeAway(&resultado);
        }
        const elapsed = timer.read();
        std.debug.print("Busca binária: {}ns/op\n", .{elapsed / 1000});
    }
}
```

## Benchmark de Allocators

```zig
fn benchmarkAllocator(
    allocator: std.mem.Allocator,
    comptime nome: []const u8,
    iteracoes: usize,
) !void {
    var timer = try std.time.Timer.start();

    for (0..iteracoes) |_| {
        const buf = try allocator.alloc(u8, 1024);
        allocator.free(buf);
    }

    const elapsed = timer.read();
    std.debug.print("{s}: {}ns/op ({} operações)\n", .{
        nome,
        elapsed / iteracoes,
        iteracoes,
    });
}

pub fn main() !void {
    const iter = 100_000;

    // GPA
    {
        var gpa = std.heap.GeneralPurposeAllocator(.{}){};
        defer _ = gpa.deinit();
        try benchmarkAllocator(gpa.allocator(), "GPA", iter);
    }

    // Page allocator
    try benchmarkAllocator(std.heap.page_allocator, "Page", iter);

    // Arena
    {
        var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
        defer arena.deinit();
        try benchmarkAllocator(arena.allocator(), "Arena", iter);
    }
}
```

Veja [ArenaAllocator](/receitas/zig-arena-allocator/) e [GeneralPurposeAllocator](/receitas/zig-general-purpose-allocator/).

## Usando Ferramentas Externas

### perf (Linux)

```bash
# Compilar com símbolos de debug
zig build -Doptimize=ReleaseFast

# Profiling
perf stat ./zig-out/bin/meu-programa
perf record -g ./zig-out/bin/meu-programa
perf report
```

### Valgrind (Callgrind)

```bash
zig build -Doptimize=ReleaseFast

valgrind --tool=callgrind ./zig-out/bin/meu-programa
kcachegrind callgrind.out.*
```

### Hyperfine (benchmarks de CLI)

```bash
hyperfine './zig-out/bin/implementacao_a' './zig-out/bin/implementacao_b'
```

## Boas Práticas

1. **Compile com ReleaseFast para benchmarks**: `zig build -Doptimize=ReleaseFast`
2. **Faça warmup**: Ignore as primeiras iterações
3. **Use `doNotOptimizeAway`**: Previna eliminação de código pelo compilador
4. **Meça múltiplas vezes**: Use min/max/média para resultado confiável
5. **Isole o código medido**: Evite medir setup/teardown
6. **Compare com baseline**: Sempre compare com uma referência
7. **Use hardware consistente**: Desative turbo boost para resultados reproduzíveis

## Conclusão

Benchmarking em Zig é direto — use `std.time.Timer` para medições, `doNotOptimizeAway` para prevenir otimização espúria, e compile com `ReleaseFast` para resultados realistas. Para profiling mais detalhado, integre com ferramentas externas como perf e Valgrind.

Para mais sobre performance, veja o artigo [Zig vs Assembly](/artigos/zig-vs-assembly/) e [Quando Usar Zig](/artigos/quando-usar-zig/). Para testes, consulte [Testes Unitários](/receitas/zig-teste-unitario-basico/).
