<h2>Profiling: Medindo o Tempo de Execução</h2>
<p>Profiling é o processo de medir onde seu código gasta tempo e recursos. Em Rust, a forma mais direta é usar <code>std::time::Instant</code> para medir trechos específicos. Isso permite identificar gargalos sem ferramentas externas, sendo especialmente útil durante desenvolvimento.</p>
<pre><code class="language-rust">use std::time::Instant;
fn algoritmo_lento(n: usize) -> u64 {
let mut sum = 0u64;
for i in 0..n {
sum = sum.wrapping_add((i * i) as u64);
}
sum
}
fn main() {
let start = Instant::now();
let resultado = algoritmo_lento(1_000_000_000);
let duration = start.elapsed();
println!("Resultado: {}", resultado);
println!("Tempo: {:.2?}", duration);
}</code></pre>
<p>Para profiling mais profundo, use <code>perf</code> no Linux. Compile seu projeto com informações de debug (<code>cargo build --release</code> preserva símbolos) e execute: <code>perf record ./target/release/seu_binario</code>. O comando <code>perf report</code> mostra exatamente quais funções consomem mais CPU. Essa abordagem revela gargalos que medições manuais podem perder.</p>
<h3>Ferramentas Integradas do Rust</h3>
<p>O Rust oferece <code>cargo flamegraph</code> para visualizar onde o tempo é gasto. Instale com <code>cargo install flamegraph</code>, depois execute <code>cargo flamegraph --release</code>. Isso gera um SVG interativo mostrando a pilha de chamadas com tempo proporcional à largura. Invaluável para entender comportamento em aplicações complexas.</p>
<h2>Benchmarking: Comparando Abordagens</h2>
<p>Benchmarking mede a performance relativa entre implementações. O Rust inclui um framework nativo (unstable) no <code>libtest</code>, mas a crate <code>criterion</code> é o padrão da indústria por ser mais robusta e estatisticamente confiável.</p>
<pre><code class="language-rust">// Cargo.toml
[dev-dependencies]
criterion = "0.5"
// benches/my_benchmark.rs
use criterion::{black_box, criterion_group, criterion_main, Criterion};
fn busca_linear(haystack: &[i32], needle: i32) -> bool {
haystack.iter().any(|&x| x == needle)
}
fn busca_binaria(haystack: &[i32], needle: i32) -> bool {
haystack.binary_search(&needle).is_ok()
}
fn benchmark_searches(c: &mut Criterion) {
let vec: Vec<i32> = (0..10000).collect();
let needle = 5000;
c.bench_function("linear_search", | b | { b.iter(|| busca_linear(black_box(&vec), black_box(needle)))
});
c.bench_function("binary_search", | b | { b.iter(|| busca_binaria(black_box(&vec), black_box(needle)))
});
}
criterion_group!(benches, benchmark_searches);
criterion_main!(benches);</code></pre>
<p>Execute com <code>cargo bench</code>. A saída mostra tempo médio, desvio padrão e detecta regressões automaticamente. O <code>black_box()</code> previne otimizações indevidas do compilador que invalidariam o teste. Sempre use-o com valores de entrada.</p>
<h3>Evitando Armadilhas Comuns</h3>
<p>Benchmarks falsos ocorrem quando o compilador otimiza código demais. Se um benchmark mostra tempo zero, provavelmente o resultado é constante em tempo de compilação. Use <code>black_box()</code> para entradas e <code>assert!()</code> para resultados. Outra armadilha: medir alocação sem considerar reuso de memória. Benchmarks devem refletir uso real—se seu código em produção reutiliza buffers, seu benchmark deve fazer o mesmo.</p>
<h2>Otimizações Práticas Baseadas em Dados</h2>
<p>Depois de identificar gargalos via profiling, aplique otimizações. A regra de ouro: sempre meça antes e depois. Nunca otimize por intuição em Rust.</p>
<pre><code class="language-rust">// Versão lenta: concatenação de strings em loop
fn versao_lenta(linhas: &[&str]) -> String {
let mut resultado = String::new();
for linha in linhas {
resultado = resultado + linha + "\n";
}
resultado
}
// Versão otimizada: pré-aloca capacidade
fn versao_otimizada(linhas: &[&str]) -> String {
let tamanho_total: usize = linhas.iter().map(|l| l.len() + 1).sum();
let mut resultado = String::with_capacity(tamanho_total);
for linha in linhas {
resultado.push_str(linha);
resultado.push('\n');
}
resultado
}
// Versão mais rápida: use collect
fn versao_ideal(linhas: &[&str]) -> String {
linhas.iter().map(|l| format!("{}\n", l)).collect()
}</code></pre>
<p>O exemplo acima mostra como pré-alocar memória (<code>with_capacity</code>) evita realocações. Em Rust, alocações dinâmicas são caras. Benchmarks revelam que a versão ideal geralmente vence porque <code>collect()</code> otimiza internamente. Sempre considere iteradores funcionais—compilador as otimiza melhor que loops manuais.</p>
<h3>Profiling de Memória</h3>
<p>Memória é tão importante quanto CPU. Use <code>valgrind</code> ou <code>heaptrack</code> para detectar vazamentos. No Linux, execute: <code>valgrind --tool=massif ./target/release/seu_binario</code>. Para Rust especificamente, <code>cargo valgrind</code> simplifica o processo. Ferramentas revelam picos de alocação e padrões ineficientes de reuso.</p>
<pre><code class="language-rust">// Ineficiente: cria Vec desnecessariamente
fn processar_ineficiente(dados: &[u8]) -> Vec<u8> {
let mut temp = Vec::new();
for &byte in dados {
temp.push(byte * 2);
}
temp
}
// Eficiente: usa iterador sem alocar
fn processar_eficiente(dados: &[u8]) -> impl Iterator<Item = u8> + '_ {
dados.iter().map(|&b| b * 2)
}</code></pre>
<p>Quando a saída precisa de <code>Vec</code>, aloque uma única vez. Quando pode ser iterador, prefira isso—zero alocações extras. Esse padrão é fundamental em código crítico.</p>
<h2>Conclusão</h2>
<p><strong>Três pilares aprendidos:</strong> Primeiro, profiling (medir com <code>Instant</code>, <code>perf</code>, <code>flamegraph</code>) identifica onde otimizar. Segundo, benchmarking com <code>criterion</code> compara objetivamente soluções, evitando otimizações inúteis. Terceiro, otimizações baseadas em dados concretos—pré-alocação, iteradores, evitar clones—multiplicam performance sem especulação. Combine essas técnicas sistematicamente: perfil → benchmark → otimize → re-benchmark. Rust permite escrever código rápido por design; essas ferramentas garantem que o seja.</p>
<h2>Referências</h2>
<ul>
<li><a href="https://doc.rust-lang.org/book/ch13-04-performance.html" target="_blank" rel="noopener noreferrer">The Rust Book: Performance</a></li>
<li><a href="https://bheisler.github.io/criterion.rs/book/criterion_rs.html" target="_blank" rel="noopener noreferrer">Criterion.rs Documentation</a></li>
<li><a href="https://nnethercote.github.io/perf-book/introduction.html" target="_blank" rel="noopener noreferrer">Rust Performance Book</a></li>
<li><a href="https://www.brendangregg.com/perf.html" target="_blank" rel="noopener noreferrer">Linux perf Examples</a></li>
<li><a href="https://www.brendangregg.com/flamegraphs.html" target="_blank" rel="noopener noreferrer">Flamegraph for Rust</a></li>
</ul>