---
title: "Ferramentas de Profiling para Zig: perf, Tracy e Valgrind"
url: "https://ziglang.com.br/tutoriais/zig-profiling-tools/"
markdown_url: "https://ziglang.com.br/tutoriais/zig-profiling-tools.MD"
description: "Domine profiling de codigo Zig com perf, Tracy, Valgrind e flame graphs. Identifique hotspots, cache misses e gargalos de performance. Tutorial completo."
date: "2026-02-21"
author: ""
---

# Ferramentas de Profiling para Zig: perf, Tracy e Valgrind

Domine profiling de codigo Zig com perf, Tracy, Valgrind e flame graphs. Identifique hotspots, cache misses e gargalos de performance. Tutorial completo.


Otimizacao sem profiling e adivinhacao. Profiling mostra exatamente onde seu programa gasta tempo, quanta memoria usa e onde estao os gargalos. Neste artigo, exploramos as principais ferramentas de profiling para codigo Zig.

> Continuacao do artigo sobre [SIMD e vetorizacao em Zig](/tutoriais/zig-performance/artigo-3-simd-vetorizacao/).

## A Regra de Ouro: Meça Antes de Otimizar

Donald Knuth disse: "Otimizacao prematura e a raiz de todo mal." A versao moderna dessa frase e:

1. **Faca funcionar** — codigo correto primeiro
2. **Meça** — profile para encontrar o gargalo real
3. **Otimize o hotspot** — foque nos 20% que causam 80% do tempo
4. **Meça de novo** — confirme que a otimizacao funcionou

## Linux perf

`perf` e a ferramenta de profiling mais poderosa no Linux. Ela usa hardware performance counters da CPU para medir com precisao e baixo overhead.

### Compilando para Profiling

```bash
# Compilar com simbolos de debug + otimizacoes
zig build -Doptimize=ReleaseSafe

# ReleaseSafe mantem simbolos de debug e bounds checking
# mas aplica otimizacoes do compilador
```

### Profiling Basico com perf

```bash
# Gravar perfil de execucao
perf record -g ./zig-out/bin/minha-app

# Visualizar resultados
perf report

# Estatisticas rapidas (sem gravacao)
perf stat ./zig-out/bin/minha-app
```

Saida tipica do `perf stat`:

```
Performance counter stats for './zig-out/bin/minha-app':

          1,234.56 msec task-clock
                42      context-switches
                 3      cpu-migrations
            12,345      page-faults
     4,567,890,123      cycles
     8,901,234,567      instructions       #    1.95  insn per cycle
     1,234,567,890      branches
        12,345,678      branch-misses      #    1.00% of all branches
       345,678,901      L1-dcache-loads
        23,456,789      L1-dcache-load-misses  #    6.79% of all L1-dcache
```

### Analisando Cache Misses

```bash
# Medir cache misses especificamente
perf stat -e L1-dcache-loads,L1-dcache-load-misses,LLC-loads,LLC-load-misses \
    ./zig-out/bin/minha-app

# Encontrar funcoes com mais cache misses
perf record -e cache-misses -g ./zig-out/bin/minha-app
perf report --sort=dso,symbol
```

### Flame Graphs

Flame graphs mostram visualmente onde seu programa gasta tempo:

```bash
# Gravar dados
perf record -F 99 -g ./zig-out/bin/minha-app

# Gerar flame graph (requer FlameGraph tools)
perf script | stackcollapse-perf.pl | flamegraph.pl > flamegraph.svg

# Abrir no navegador
xdg-open flamegraph.svg
```

## Tracy Profiler

[Tracy](https://github.com/wolfpld/tracy) e um profiler em tempo real, ideal para games e aplicacoes interativas. O Zig tem integracao nativa via `std.debug.Trace`.

### Integrando Tracy no Codigo Zig

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

pub fn main() void {
    // Zona de profiling com nome
    {
        const zone = tracy.trace(@src());
        defer zone.end();

        // Codigo a ser medido
        processarDados();
    }

    // Zona com cor customizada
    {
        const zone = tracy.trace(@src());
        defer zone.end();
        zone.setColor(0xFF0000); // Vermelho
        zone.setName("Renderizar Frame");

        renderizar();
    }
}

fn processarDados() void {
    const zone = tracy.trace(@src());
    defer zone.end();

    // Marcar alocacoes de memoria
    const allocator = tracy.tracyAllocator(std.heap.page_allocator);
    const dados = allocator.alloc(u8, 1024) catch return;
    defer allocator.free(dados);

    // ... processar ...
}

fn renderizar() void {
    const zone = tracy.trace(@src());
    defer zone.end();

    // Plotar valor no timeline do Tracy
    tracy.plot("FPS", 60.0);
    tracy.plot("Memoria MB", 128.5);
}
```

### Configurando Tracy no build.zig

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

pub fn build(b: *std.Build) void {
    const target = b.standardTargetOptions(.{});
    const optimize = b.standardOptimizeOption(.{});

    // Flag para habilitar/desabilitar Tracy
    const enable_tracy = b.option(bool, "tracy", "Habilitar Tracy profiler") orelse false;

    const exe = b.addExecutable(.{
        .name = "minha-app",
        .root_source_file = b.path("src/main.zig"),
        .target = target,
        .optimize = optimize,
    });

    if (enable_tracy) {
        const tracy_dep = b.dependency("tracy", .{
            .target = target,
            .optimize = optimize,
        });
        exe.root_module.addImport("tracy", tracy_dep.module("tracy"));
        exe.linkLibC();
    }

    b.installArtifact(exe);
}
```

## Valgrind

Valgrind e essencial para encontrar problemas de memoria e analisar comportamento de cache.

### Callgrind: Profiling de CPU

```bash
# Executar com Callgrind
valgrind --tool=callgrind ./zig-out/bin/minha-app

# Visualizar com KCachegrind
kcachegrind callgrind.out.*
```

### Cachegrind: Analise de Cache

```bash
# Simular comportamento de cache
valgrind --tool=cachegrind ./zig-out/bin/minha-app

# Saida mostra misses por funcao:
# ==1234== D   refs:      12,345,678
# ==1234== D1  misses:       234,567  (1.90%)
# ==1234== LLd misses:        12,345  (0.10%)

# Anotar codigo fonte com contagens de cache
cg_annotate cachegrind.out.* src/main.zig
```

### Massif: Profiling de Memoria

```bash
# Rastrear uso de memoria ao longo do tempo
valgrind --tool=massif ./zig-out/bin/minha-app

# Visualizar
ms_print massif.out.*
```

## Instrumentacao Manual em Zig

### Timer Embutido para Profiling Leve

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

/// Profiler leve embutido no codigo
const Profiler = struct {
    const MAX_ZONAS = 64;

    const Zona = struct {
        nome: []const u8,
        total_ns: u64 = 0,
        chamadas: u64 = 0,
        min_ns: u64 = std.math.maxInt(u64),
        max_ns: u64 = 0,
    };

    zonas: [MAX_ZONAS]Zona = undefined,
    num_zonas: usize = 0,

    pub fn registrarZona(self: *Profiler, nome: []const u8) usize {
        const id = self.num_zonas;
        self.zonas[id] = .{ .nome = nome };
        self.num_zonas += 1;
        return id;
    }

    pub fn iniciarMedicao(_: *Profiler) std.time.Timer {
        return std.time.Timer.start() catch unreachable;
    }

    pub fn finalizarMedicao(self: *Profiler, id: usize, timer: std.time.Timer) void {
        const elapsed = timer.read();
        self.zonas[id].total_ns += elapsed;
        self.zonas[id].chamadas += 1;
        self.zonas[id].min_ns = @min(self.zonas[id].min_ns, elapsed);
        self.zonas[id].max_ns = @max(self.zonas[id].max_ns, elapsed);
    }

    pub fn relatorio(self: *Profiler) void {
        std.debug.print("\n=== Relatorio de Performance ===\n", .{});
        std.debug.print("{s:<30} {s:>10} {s:>10} {s:>10} {s:>10} {s:>10}\n", .{
            "Zona", "Chamadas", "Total(ms)", "Media(us)", "Min(us)", "Max(us)",
        });
        std.debug.print("{s:-<90}\n", .{""});

        for (self.zonas[0..self.num_zonas]) |zona| {
            const total_ms = zona.total_ns / std.time.ns_per_ms;
            const media_us = if (zona.chamadas > 0)
                zona.total_ns / zona.chamadas / std.time.ns_per_us
            else
                0;
            const min_us = zona.min_ns / std.time.ns_per_us;
            const max_us = zona.max_ns / std.time.ns_per_us;

            std.debug.print("{s:<30} {d:>10} {d:>10} {d:>10} {d:>10} {d:>10}\n", .{
                zona.nome, zona.chamadas, total_ms, media_us, min_us, max_us,
            });
        }
    }
};

var profiler = Profiler{};

// Uso global
const ZONA_PROCESSAR = blk: {
    break :blk 0;
};

fn processarComProfile(dados: []const u8) void {
    const timer = profiler.iniciarMedicao();
    defer profiler.finalizarMedicao(0, timer);

    // ... codigo real ...
    _ = dados;
}
```

## Identificando Hotspots Comuns

### 1. Alocacoes Excessivas

```zig
// LENTO: aloca e desaloca em cada iteracao
fn processarLento(items: []const Item, allocator: std.mem.Allocator) !void {
    for (items) |item| {
        const resultado = try allocator.alloc(u8, item.tamanho);
        defer allocator.free(resultado);
        // ... processar ...
    }
}

// RAPIDO: reutilizar buffer
fn processarRapido(items: []const Item, allocator: std.mem.Allocator) !void {
    var buffer = std.ArrayList(u8).init(allocator);
    defer buffer.deinit();

    for (items) |item| {
        buffer.clearRetainingCapacity();
        try buffer.resize(item.tamanho);
        // ... processar usando buffer.items ...
    }
}
```

### 2. Copias Desnecessarias

```zig
// LENTO: copia a struct inteira
fn processarStruct(s: MinhaStructGrande) void {
    // s e uma copia — pode ser 256+ bytes
    _ = s;
}

// RAPIDO: passa por referencia
fn processarStructRef(s: *const MinhaStructGrande) void {
    // s e um ponteiro — 8 bytes
    _ = s;
}
```

### 3. Branch Mispredictions

```zig
// LENTO: branch imprevisivel
fn filtrarSlow(dados: []const u32) u64 {
    var soma: u64 = 0;
    for (dados) |v| {
        if (v > 128) { // Branch imprevisivel para dados aleatorios
            soma += v;
        }
    }
    return soma;
}

// RAPIDO: branchless com bitmask
fn filtrarFast(dados: []const u32) u64 {
    var soma: u64 = 0;
    for (dados) |v| {
        // Sem branch: mascara e 0 ou 0xFFFFFFFF
        const mask: u32 = if (v > 128) 0xFFFFFFFF else 0;
        soma += v & mask;
    }
    return soma;
}
```

## Conclusao

Profiling nao e opcional — e o unico caminho confiavel para otimizacao eficaz. Use `perf` para analise de CPU e cache no Linux, Tracy para profiling em tempo real de aplicacoes interativas, e Valgrind para analise profunda de memoria. Combine essas ferramentas com benchmarking robusto e voce tera uma visao completa de onde seu codigo Zig pode melhorar.

## Proximo Artigo

No [Artigo 5: Otimizacao Real](/tutoriais/zig-performance/artigo-5-real-world-optimization/), aplicamos todas as tecnicas desta serie em um estudo de caso real, com medicoes antes e depois.

## Conteudo Relacionado

- [SIMD e Vetorizacao](/tutoriais/zig-performance/artigo-3-simd-vetorizacao/) — Artigo anterior
- [Otimizacao Real](/tutoriais/zig-performance/artigo-5-real-world-optimization/) — Proximo artigo
- [Zig Debugging](/tutoriais/zig-debugging/) — Depuracao
- [Profiling e Benchmarks](/tutoriais/zig-profiling-benchmarks/) — Tutorial basico
- [Ferramentas de Desenvolvimento](/artigos/zig-devtools-produtividade/) — DevTools
