std.time em Zig — Referência e Exemplos

std.time — Tempo e Medição de Performance

O módulo std.time fornece funcionalidades para trabalhar com tempo no Zig, incluindo medição de alta resolução, timestamps, conversões de unidades e delays. É fundamental para benchmarking, profiling, timeouts e qualquer operação que precise de referência temporal precisa.

Visão Geral

const std = @import("std");
const time = std.time;

O std.time usa nanossegundos como unidade base e fornece constantes de conversão para trabalhar com diferentes escalas temporais.

Constantes de Conversão

pub const ns_per_us: u64 = 1_000;           // nanossegundos por microssegundo
pub const ns_per_ms: u64 = 1_000_000;       // nanossegundos por milissegundo
pub const ns_per_s: u64 = 1_000_000_000;    // nanossegundos por segundo
pub const ns_per_min: u64 = 60 * ns_per_s;  // nanossegundos por minuto
pub const us_per_ms: u64 = 1_000;            // microssegundos por milissegundo
pub const us_per_s: u64 = 1_000_000;         // microssegundos por segundo
pub const ms_per_s: u64 = 1_000;             // milissegundos por segundo
pub const s_per_min: u64 = 60;
pub const s_per_hour: u64 = 3_600;
pub const s_per_day: u64 = 86_400;

Funções Principais

// Timestamp em nanossegundos (relógio monotônico)
pub fn nanoTimestamp() i128

// Timestamp em milissegundos desde epoch
pub fn milliTimestamp() i64

// Timestamp em segundos desde epoch
pub fn timestamp() i64

// Suspende a execução por N nanossegundos
pub fn sleep(ns: u64) void

// Timer de alta resolução
pub const Timer = struct {
    pub fn start() Timer
    pub fn read(self: Timer) u64   // nanossegundos decorridos
    pub fn reset(self: *Timer) void
    pub fn lap(self: *Timer) u64   // lê e reseta
};

// Instant para medição monotônica
pub const Instant = struct {
    pub fn now() ?Instant
    pub fn since(self: Instant, earlier: Instant) u64
};

Exemplo 1: Timestamps e Conversões

const std = @import("std");

pub fn main() !void {
    const stdout = std.io.getStdOut().writer();

    // Diferentes resoluções de timestamp
    const ts_s = std.time.timestamp();
    const ts_ms = std.time.milliTimestamp();
    const ts_ns = std.time.nanoTimestamp();

    try stdout.writeAll("=== Timestamps ===\n");
    try stdout.print("Segundos desde epoch:      {d}\n", .{ts_s});
    try stdout.print("Milissegundos desde epoch:  {d}\n", .{ts_ms});
    try stdout.print("Nanossegundos desde epoch:  {d}\n", .{ts_ns});

    // Conversão para componentes legíveis
    const epoch_seconds: u64 = @intCast(ts_s);
    const dias = epoch_seconds / std.time.s_per_day;
    const horas_restantes = (epoch_seconds % std.time.s_per_day) / std.time.s_per_hour;
    const minutos_restantes = (epoch_seconds % std.time.s_per_hour) / std.time.s_per_min;
    const segundos_restantes = epoch_seconds % std.time.s_per_min;

    try stdout.print("\nDias desde epoch: {d}\n", .{dias});
    try stdout.print("Hora UTC: {d:0>2}:{d:0>2}:{d:0>2}\n", .{
        horas_restantes,
        minutos_restantes,
        segundos_restantes,
    });

    // Epoch para data simples (cálculo aproximado)
    const anos_aprox = dias / 365;
    try stdout.print("Anos desde 1970: ~{d}\n", .{anos_aprox});
}

Exemplo 2: Timer de Alta Resolução

const std = @import("std");

fn fibonacci(n: u64) u64 {
    if (n <= 1) return n;
    var a: u64 = 0;
    var b: u64 = 1;
    for (2..n + 1) |_| {
        const temp = a + b;
        a = b;
        b = temp;
    }
    return b;
}

fn bubbleSort(arr: []i32) void {
    if (arr.len <= 1) return;
    for (0..arr.len - 1) |i| {
        for (0..arr.len - 1 - i) |j| {
            if (arr[j] > arr[j + 1]) {
                const temp = arr[j];
                arr[j] = arr[j + 1];
                arr[j + 1] = temp;
            }
        }
    }
}

pub fn main() !void {
    const stdout = std.io.getStdOut().writer();

    try stdout.writeAll("=== Benchmarks com Timer ===\n\n");

    // Benchmark: Fibonacci
    var timer = try std.time.Timer.start();
    const fib_resultado = fibonacci(40);
    const fib_tempo = timer.read();

    try stdout.print("Fibonacci(40) = {d}\n", .{fib_resultado});
    try stdout.print("Tempo: {d} ns ({d:.3} ms)\n\n", .{
        fib_tempo,
        @as(f64, @floatFromInt(fib_tempo)) / @as(f64, @floatFromInt(std.time.ns_per_ms)),
    });

    // Benchmark: Bubble Sort
    var dados: [1000]i32 = undefined;
    var prng = std.Random.DefaultPrng.init(42);
    const random = prng.random();
    for (&dados) |*d| {
        d.* = random.intRangeAtMost(i32, 0, 10000);
    }

    timer.reset();
    bubbleSort(&dados);
    const sort_tempo = timer.read();

    try stdout.print("Bubble Sort (1000 elementos)\n", .{});
    try stdout.print("Tempo: {d} ns ({d:.3} ms)\n", .{
        sort_tempo,
        @as(f64, @floatFromInt(sort_tempo)) / @as(f64, @floatFromInt(std.time.ns_per_ms)),
    });
    try stdout.print("Primeiro: {d}, Último: {d}\n", .{ dados[0], dados[999] });
}

Exemplo 3: Sleep e Intervalos

const std = @import("std");

pub fn main() !void {
    const stdout = std.io.getStdOut().writer();

    try stdout.writeAll("=== Demonstração de Sleep ===\n\n");

    // Sleep preciso com verificação
    const intervalos = [_]struct { nome: []const u8, ns: u64 }{
        .{ .nome = "100ms", .ns = 100 * std.time.ns_per_ms },
        .{ .nome = "250ms", .ns = 250 * std.time.ns_per_ms },
        .{ .nome = "500ms", .ns = 500 * std.time.ns_per_ms },
    };

    for (intervalos) |intervalo| {
        var timer = try std.time.Timer.start();
        std.time.sleep(intervalo.ns);
        const real = timer.read();

        const esperado_ms = @as(f64, @floatFromInt(intervalo.ns)) / @as(f64, @floatFromInt(std.time.ns_per_ms));
        const real_ms = @as(f64, @floatFromInt(real)) / @as(f64, @floatFromInt(std.time.ns_per_ms));
        const desvio = real_ms - esperado_ms;

        try stdout.print("Sleep {s}: esperado={d:.1}ms, real={d:.3}ms, desvio={d:.3}ms\n", .{
            intervalo.nome,
            esperado_ms,
            real_ms,
            desvio,
        });
    }

    // Contagem regressiva
    try stdout.writeAll("\nContagem regressiva: ");
    var count: u8 = 5;
    while (count > 0) : (count -= 1) {
        try stdout.print("{d}... ", .{count});
        std.time.sleep(1 * std.time.ns_per_s);
    }
    try stdout.writeAll("Pronto!\n");
}

Exemplo 4: Medição com Instant

const std = @import("std");

pub fn main() !void {
    const stdout = std.io.getStdOut().writer();

    // Instant fornece tempo monotônico (não afetado por ajustes de relógio)
    const inicio = std.time.Instant.now() orelse {
        try stdout.writeAll("Timer monotônico não disponível nesta plataforma\n");
        return;
    };

    // Simula trabalho
    var soma: u64 = 0;
    for (0..1_000_000) |i| {
        soma +%= i;
    }

    const fim = std.time.Instant.now() orelse return;
    const decorrido = fim.since(inicio);

    try stdout.print("Soma de 0..999999 = {d}\n", .{soma});
    try stdout.print("Tempo decorrido: {d} ns\n", .{decorrido});
    try stdout.print("                 {d:.3} us\n", .{
        @as(f64, @floatFromInt(decorrido)) / @as(f64, @floatFromInt(std.time.ns_per_us)),
    });

    // Operações por segundo
    const ops_por_segundo = @as(f64, 1_000_000.0) /
        (@as(f64, @floatFromInt(decorrido)) / @as(f64, @floatFromInt(std.time.ns_per_s)));
    try stdout.print("Operações por segundo: {d:.0}\n", .{ops_por_segundo});
}

Padrão: Função de Benchmark Reutilizável

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

    for (0..repeticoes) |_| {
        var timer = std.time.Timer.start() catch return .{ .media_ns = 0, .min_ns = 0, .max_ns = 0 };
        _ = @call(.auto, func, args);
        const elapsed = timer.read();
        total += elapsed;
        if (elapsed < min) min = elapsed;
        if (elapsed > max) max = elapsed;
    }

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

Módulos Relacionados

Tutoriais e Receitas Relacionados

Continue aprendendo Zig

Explore mais tutoriais e artigos em português para dominar a linguagem Zig.