Skip to documentation
SLOP

tiny.profiling.capture.coz

Reference tiny.profiling capture coz

Defined in capture.

API (13)

Actions

Public operations.

Types and contracts

Public types and contracts.

Values and defaults

Public values and defaults.

No direct callersNo direct callscapturecoz
Static calls · unresolved targets: unknown · external targets: unknown.

Source

Called byCallstest; no linksrc.profiling.capture.coztest: profiling coz maps complete and...test; no linksrc.profiling.capture.coztest: profiling coz marks missing and...driver.artifactcollectCapturesprivate; no linksrc.profiling.capture.cozappendCaptureRowprivate; no linksrc.profiling.capture.cozcaptureForIntegrityprivate; no linksrc.profiling.capture.cozinvalidCaptureprivate; no linksrc.profiling.capture.cozmissingCaptureprivate; no linksrc.profiling.capture.cozreadIntegritycapture.cozappendCapture
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsNo direct callstest; no linksrc.profiling.capture.coztest: profiling coz parses analysis r...private; no linksrc.profiling.priorityappendTimingItemprivate; no linksrc.profiling.priorityappendWallItemcapture.cozbestSupportedProgramSpeedup
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsprivate; no linksrc.profiling.analyze.loadloadWorkloadtest; no linksrc.profiling.capture.coztest: profiling coz parses analysis r...test; no linksrc.profiling.capture.coztest: profiling coz rejects a repeate...test; no linksrc.profiling.capture.coztest: profiling coz tolerates empty a...private; no linksrc.profiling.capture.cozparseResultjsonarrayjsonobjectcapture.cozload
Static calls · unresolved targets: 3 · external targets: 4.

Source: src/profiling/capture/coz.zig

zig
const std = @import("std");const coz = @import("coz");const sys = @import("sys");const host = @import("../root.zig").host;const json = @import("../root.zig").json;const fs_io = sys.fs.debugIo();pub const analysis_schema = coz.analysis.schema;pub const support_method = coz.analysis.support_method;pub const capture_kind = "causal_profile";pub const capture_tool = "lib/coz";const max_analysis_bytes = 128 * 1024 * 1024;pub const CaptureOptions = struct {    enabled: bool,    exit_code: i64,    capture_path: []const u8,    summary_path: []const u8,};const Integrity = struct {    status: []const u8,    message: ?[]const u8,};pub const Measurement = struct {    virtual_speedup: f64,    program_speedup: f64,    experiment_count: u64,};pub const SupportStatus = coz.analysis.SupportStatus;pub const Support = coz.analysis.Support;pub const supportAction = coz.analysis.supportAction;pub const Result = struct {    workload: []const u8,    kind: []const u8,    file: []const u8,    line: u64,    progress_point: []const u8,    min_program_speedup: f64,    max_program_speedup: f64,    slope: ?f64,    total_selected_samples: u64,    support: Support,    measurements: []const Measurement = &.{},};pub fn load(allocator: std.mem.Allocator, workload_name: []const u8, path: ?[]const u8) ![]const Result {    const actual_path = path orelse return &.{};    const text = sys.fs.readFileAlloc(allocator, actual_path, max_analysis_bytes) catch |err| switch (err) {        error.FileNotFound => return &.{},        else => |actual| return actual,    };    defer allocator.free(text);    const trimmed = std.mem.trim(u8, text, " \t\r\n");    if (trimmed.len == 0) return &.{};    var parsed = std.json.parseFromSlice(std.json.Value, allocator, trimmed, .{}) catch return &.{};    defer parsed.deinit();    const object = json.object(parsed.value) catch return &.{};    const schema_name = json.string(object.get("schema")) orelse return &.{};    if (!std.mem.eql(u8, schema_name, analysis_schema)) return &.{};    const results_value = object.get("results") orelse return &.{};    const results = json.array(results_value) catch return &.{};    var rows: std.ArrayList(Result) = .empty;    for (results.items) |item| {        const row = json.object(item) catch continue;        if (try parseResult(allocator, workload_name, row)) |result| try rows.append(allocator, result);    }    std.mem.sort(Result, rows.items, {}, resultDescending);    return try rows.toOwnedSlice(allocator);}fn resultDescending(_: void, left: Result, right: Result) bool {    const left_supported = left.support.status == .within_run_repeated_curve;    const right_supported = right.support.status == .within_run_repeated_curve;    if (left_supported != right_supported) return left_supported;    if (left.max_program_speedup != right.max_program_speedup) {        return left.max_program_speedup > right.max_program_speedup;    }    const file_order = std.mem.order(u8, left.file, right.file);    if (file_order != .eq) return file_order == .lt;    if (left.line != right.line) return left.line < right.line;    return std.mem.lessThan(u8, left.progress_point, right.progress_point);}pub fn bestSupportedProgramSpeedup(results: []const Result, workload_name: []const u8) ?f64 {    var best: ?f64 = null;    for (results) |result| {        if (!std.mem.eql(u8, result.workload, workload_name)) continue;        if (result.support.status != .within_run_repeated_curve) continue;        if (result.max_program_speedup <= 0) continue;        if (best == null or result.max_program_speedup > best.?) best = result.max_program_speedup;    }    return best;}pub fn appendCapture(    allocator: std.mem.Allocator,    captures: []const host.Capture,    options: CaptureOptions,) ![]const host.Capture {    if (!options.enabled or options.exit_code != 0) return captures;    const integrity = readIntegrity(allocator, options.summary_path) catch |err| switch (err) {        error.OutOfMemory => return err,        error.FileNotFound => return try appendCaptureRow(            allocator,            captures,            missingCapture(options),        ),        else => return try appendCaptureRow(allocator, captures, invalidCapture(options)),    };    return try appendCaptureRow(allocator, captures, captureForIntegrity(options, integrity));}fn readIntegrity(allocator: std.mem.Allocator, path: []const u8) !Integrity {    const text = try sys.fs.readFileAlloc(allocator, path, max_analysis_bytes);    defer allocator.free(text);    const trimmed = std.mem.trim(u8, text, " \t\r\n");    if (trimmed.len == 0) return error.InvalidCozAnalysis;    var parsed = std.json.parseFromSlice(std.json.Value, allocator, trimmed, .{}) catch {        return error.InvalidCozAnalysis;    };    defer parsed.deinit();    const object = json.object(parsed.value) catch return error.InvalidCozAnalysis;    const schema_name = json.string(object.get("schema")) orelse return error.InvalidCozAnalysis;    if (!std.mem.eql(u8, schema_name, analysis_schema)) return error.InvalidCozAnalysis;    const integrity_value = object.get("capture_integrity") orelse {        return error.InvalidCozAnalysis;    };    const integrity = json.object(integrity_value) catch {        return error.InvalidCozAnalysis;    };    const status = json.string(integrity.get("status")) orelse return error.InvalidCozAnalysis;    const method = json.string(integrity.get("method")) orelse return error.InvalidCozAnalysis;    const action = json.string(integrity.get("action")) orelse return error.InvalidCozAnalysis;    if (status.len == 0 or method.len == 0 or action.len == 0) return error.InvalidCozAnalysis;    const complete = std.mem.eql(u8, status, "complete");    const message = optionalString(integrity.get("message")) catch {        return error.InvalidCozAnalysis;    };    if (complete and message != null) return error.InvalidCozAnalysis;    if (!complete and message == null) return error.InvalidCozAnalysis;    const owned_status = try allocator.dupe(u8, status);    errdefer allocator.free(owned_status);    return .{        .status = owned_status,        .message = if (message) |value| try allocator.dupe(u8, value) else null,    };}fn optionalString(value: ?std.json.Value) !?[]const u8 {    const actual = value orelse return error.InvalidCozAnalysis;    return switch (actual) {        .null => null,        .string => |text| text,        else => error.InvalidCozAnalysis,    };}fn appendCaptureRow(    allocator: std.mem.Allocator,    captures: []const host.Capture,    row: host.Capture,) ![]const host.Capture {    const result = try allocator.alloc(host.Capture, captures.len + 1);    @memcpy(result[0..captures.len], captures);    result[captures.len] = row;    return result;}fn captureForIntegrity(options: CaptureOptions, integrity: Integrity) host.Capture {    const complete = std.mem.eql(u8, integrity.status, "complete");    return .{        .kind = capture_kind,        .tool = capture_tool,        .scope = host.direct_scope,        .capture_path = options.capture_path,        .summary_path = options.summary_path,        .state = "summary_written",        .caveat_kind = if (complete) null else integrity.status,        .caveat_message = if (complete) null else integrity.message,    };}fn missingCapture(options: CaptureOptions) host.Capture {    return .{        .kind = capture_kind,        .tool = capture_tool,        .scope = host.direct_scope,        .capture_path = options.capture_path,        .summary_path = options.summary_path,        .state = "capture_missing",        .caveat_kind = "causal_profile_missing",        .caveat_message = "causal profiling was requested but produced no analysis artifact",    };}fn invalidCapture(options: CaptureOptions) host.Capture {    return .{        .kind = capture_kind,        .tool = capture_tool,        .scope = host.direct_scope,        .capture_path = options.capture_path,        .summary_path = options.summary_path,        .state = "summary_invalid",        .caveat_kind = "invalid_causal_profile",        .caveat_message = "causal profile analysis does not contain valid " ++            "sampling integrity evidence",    };}fn parseResult(allocator: std.mem.Allocator, workload_name: []const u8, row: std.json.ObjectMap) !?Result {    const selected = json.object(row.get("selected") orelse return null) catch return null;    const file = json.string(selected.get("file")) orelse return null;    const progress_point = json.string(row.get("progress_point")) orelse return null;    const max_program_speedup = json.asF64(row.get("max_program_speedup")) orelse return null;    const baseline_virtual_speedup = json.asF64(        row.get("baseline_virtual_speedup"),    ) orelse return null;    const support = parseSupport(row.get("support") orelse return null) orelse return null;    var measurements: std.ArrayList(Measurement) = .empty;    defer measurements.deinit(allocator);    if (row.get("measurements")) |value| {        if (json.array(value) catch null) |array| {            for (array.items) |item| {                const measurement = json.object(item) catch continue;                try measurements.append(allocator, .{                    .virtual_speedup = json.asF64(measurement.get("virtual_speedup")) orelse continue,                    .program_speedup = json.asF64(measurement.get("program_speedup")) orelse continue,                    .experiment_count = json.asU64(                        measurement.get("experiment_count"),                    ) orelse continue,                });            }        }    }    if (!supportMatchesMeasurements(support, baseline_virtual_speedup, measurements.items)) {        return null;    }    return .{        .workload = try allocator.dupe(u8, workload_name),        .kind = try allocator.dupe(u8, json.string(row.get("kind")) orelse "throughput"),        .file = try allocator.dupe(u8, file),        .line = json.asU64(selected.get("line")) orelse 0,        .progress_point = try allocator.dupe(u8, progress_point),        .min_program_speedup = json.asF64(row.get("min_program_speedup")) orelse 0,        .max_program_speedup = max_program_speedup,        .slope = json.asF64(row.get("slope")),        .total_selected_samples = json.asU64(row.get("total_selected_samples")) orelse 0,        .support = support,        .measurements = try measurements.toOwnedSlice(allocator),    };}fn supportMatchesMeasurements(    support: Support,    baseline_virtual_speedup: f64,    measurements: []const Measurement,) bool {    if (support.speedup_point_count != @as(u64, @intCast(measurements.len))) return false;    var experiment_count: u64 = 0;    var baseline_experiment_count: u64 = 0;    var minimum_experiments_per_point: u64 = if (measurements.len == 0)        0    else        std.math.maxInt(u64);    for (measurements) |measurement| {        if (measurement.experiment_count == 0) return false;        experiment_count +|= measurement.experiment_count;        minimum_experiments_per_point = @min(            minimum_experiments_per_point,            measurement.experiment_count,        );        if (measurement.virtual_speedup == baseline_virtual_speedup) {            baseline_experiment_count = measurement.experiment_count;        }    }    const expected_status: SupportStatus = if (measurements.len < 2)        .point_only    else if (minimum_experiments_per_point < 2)        .unreplicated_curve    else        .within_run_repeated_curve;    return support.status == expected_status and        support.experiment_count == experiment_count and        support.baseline_experiment_count == baseline_experiment_count and        support.minimum_experiments_per_point == minimum_experiments_per_point;}fn parseSupport(value: std.json.Value) ?Support {    const object = json.object(value) catch return null;    const status_name = json.string(object.get("status")) orelse return null;    const status = std.meta.stringToEnum(SupportStatus, status_name) orelse return null;    const method = json.string(object.get("method")) orelse return null;    if (!std.mem.eql(u8, method, support_method)) return null;    const action = json.string(object.get("action")) orelse return null;    if (!std.mem.eql(u8, action, supportAction(status))) return null;    return .{        .status = status,        .speedup_point_count = json.asU64(object.get("speedup_point_count")) orelse return null,        .experiment_count = json.asU64(object.get("experiment_count")) orelse return null,        .baseline_experiment_count = json.asU64(            object.get("baseline_experiment_count"),        ) orelse return null,        .minimum_experiments_per_point = json.asU64(            object.get("minimum_experiments_per_point"),        ) orelse return null,    };}const supported_analysis_fixture =    \\{"schema":"coz.analysis/v2","results":[    \\  {"selected":{"file":"src/hot.zig","line":9},    \\   "progress_point":"bench.sample","kind":"throughput",    \\   "baseline_virtual_speedup":0,"min_program_speedup":0,    \\   "max_program_speedup":0.9,"total_selected_samples":512,"slope":1.8,    \\   "support":{"status":"unreplicated_curve",    \\    "method":"within_run_experiment_counts",    \\    "action":"collect_repeated_experiments_per_point","speedup_point_count":2,    \\    "experiment_count":2,"baseline_experiment_count":1,    \\    "minimum_experiments_per_point":1},    \\   "measurements":[    \\    {"virtual_speedup":0,"program_speedup":0,"experiment_count":1},    \\    {"virtual_speedup":0.5,"program_speedup":0.9,"experiment_count":1}]},    \\  {"selected":{"file":"src/eval.zig","line":42},    \\   "progress_point":"bench.sample","kind":"throughput",    \\   "baseline_virtual_speedup":0,"min_program_speedup":-0.02,    \\   "max_program_speedup":0.35,"total_selected_samples":128,"slope":0.7,    \\   "support":{"status":"within_run_repeated_curve",    \\    "method":"within_run_experiment_counts",    \\    "action":"validate_with_independent_runs","speedup_point_count":2,    \\    "experiment_count":4,"baseline_experiment_count":2,    \\    "minimum_experiments_per_point":2},    \\   "measurements":[    \\    {"virtual_speedup":0,"program_speedup":0,"experiment_count":2},    \\    {"virtual_speedup":0.2,"program_speedup":0.2,"experiment_count":2}]}    \\]};const inconsistent_support_fixture =    \\{"schema":"coz.analysis/v2","results":[{    \\  "selected":{"file":"src/eval.zig","line":42},    \\  "progress_point":"bench.sample","kind":"throughput",    \\  "baseline_virtual_speedup":0,"max_program_speedup":0.9,    \\  "support":{"status":"within_run_repeated_curve",    \\   "method":"within_run_experiment_counts",    \\   "action":"validate_with_independent_runs","speedup_point_count":2,    \\   "experiment_count":2,"baseline_experiment_count":1,    \\   "minimum_experiments_per_point":1},    \\  "measurements":[    \\   {"virtual_speedup":0,"program_speedup":0,"experiment_count":1},    \\   {"virtual_speedup":0.5,"program_speedup":0.9,"experiment_count":1}]    \\}]};test "profiling coz parses analysis results" {    var arena_state = std.heap.ArenaAllocator.init(std.testing.allocator);    defer arena_state.deinit();    const allocator = arena_state.allocator();    try sys.fs.writeFile(".zig-cache/profile-coz-test.json", supported_analysis_fixture);    const results = try load(allocator, "fixture.accy", ".zig-cache/profile-coz-test.json");    try std.testing.expectEqual(@as(usize, 2), results.len);    try std.testing.expectEqualStrings("fixture.accy", results[0].workload);    try std.testing.expectEqualStrings("src/eval.zig", results[0].file);    try std.testing.expectEqual(@as(u64, 42), results[0].line);    try std.testing.expectEqual(@as(f64, 0.35), results[0].max_program_speedup);    try std.testing.expectEqual(@as(usize, 2), results[0].measurements.len);    try std.testing.expectEqual(@as(f64, 0), results[0].measurements[0].virtual_speedup);    try std.testing.expectEqual(@as(f64, 0.2), results[0].measurements[1].program_speedup);    try std.testing.expectEqual(@as(u64, 2), results[0].measurements[0].experiment_count);    try std.testing.expectEqual(SupportStatus.within_run_repeated_curve, results[0].support.status);    try std.testing.expectEqual(SupportStatus.unreplicated_curve, results[1].support.status);    try std.testing.expectEqual(@as(f64, 0.9), results[1].max_program_speedup);    try std.testing.expectEqual(        @as(f64, 0.35),        bestSupportedProgramSpeedup(results, "fixture.accy").?,    );    try std.testing.expect(bestSupportedProgramSpeedup(results, "other") == null);    sys.fs.deleteFile(".zig-cache/profile-coz-test.json") catch {};}test "profiling coz rejects a repeated label without matching experiment counts" {    var arena_state = std.heap.ArenaAllocator.init(std.testing.allocator);    defer arena_state.deinit();    const allocator = arena_state.allocator();    const path = ".zig-cache/profile-coz-inconsistent.json";    try sys.fs.writeFile(path, inconsistent_support_fixture);    defer sys.fs.deleteFile(path) catch {};    try std.testing.expectEqual(@as(usize, 0), (try load(allocator, "w", path)).len);}test "profiling coz tolerates empty and missing analyses" {    var arena_state = std.heap.ArenaAllocator.init(std.testing.allocator);    defer arena_state.deinit();    const allocator = arena_state.allocator();    try std.testing.expectEqual(@as(usize, 0), (try load(allocator, "w", null)).len);    try std.testing.expectEqual(@as(usize, 0), (try load(allocator, "w", ".zig-cache/profile-coz-missing.json")).len);    try sys.fs.writeFile(".zig-cache/profile-coz-empty.json",        \\{"schema":"coz.analysis/v2","results":[]}    );    try std.testing.expectEqual(@as(usize, 0), (try load(allocator, "w", ".zig-cache/profile-coz-empty.json")).len);    try sys.fs.writeFile(".zig-cache/profile-coz-junk.json", "not json");    try std.testing.expectEqual(@as(usize, 0), (try load(allocator, "w", ".zig-cache/profile-coz-junk.json")).len);    sys.fs.deleteFile(".zig-cache/profile-coz-empty.json") catch {};    sys.fs.deleteFile(".zig-cache/profile-coz-junk.json") catch {};}test "profiling coz maps complete and partial capture integrity" {    var arena_state = std.heap.ArenaAllocator.init(std.testing.allocator);    defer arena_state.deinit();    const allocator = arena_state.allocator();    var tmp = std.testing.tmpDir(.{});    defer tmp.cleanup();    try tmp.dir.writeFile(fs_io, .{        .sub_path = "complete.json",        .data = "{\"schema\":\"coz.analysis/v2\",\"capture_integrity\":{" ++            "\"status\":\"complete\",\"method\":\"audit\"," ++            "\"action\":\"use_profile\",\"message\":null},\"results\":[]}",    });    try tmp.dir.writeFile(fs_io, .{        .sub_path = "partial.json",        .data = "{\"schema\":\"coz.analysis/v2\",\"capture_integrity\":{" ++            "\"status\":\"sample_loss\",\"method\":\"audit\"," ++            "\"action\":\"rerun\",\"message\":\"repeat at a lower rate\"}," ++            "\"results\":[]}",    });    const root = try tmp.dir.realPathFileAlloc(fs_io, ".", allocator);    const complete_path = try std.fs.path.join(allocator, &.{ root, "complete.json" });    const partial_path = try std.fs.path.join(allocator, &.{ root, "partial.json" });    const complete = try appendCapture(allocator, &.{}, .{        .enabled = true,        .exit_code = 0,        .capture_path = "profile.jsonl",        .summary_path = complete_path,    });    const partial = try appendCapture(allocator, complete, .{        .enabled = true,        .exit_code = 0,        .capture_path = "profile.jsonl",        .summary_path = partial_path,    });    try std.testing.expectEqualStrings("summary_written", complete[0].state);    try std.testing.expect(complete[0].caveat_kind == null);    try std.testing.expectEqualStrings("sample_loss", partial[1].caveat_kind.?);    try std.testing.expect(std.mem.indexOf(        u8,        partial[1].caveat_message.?,        "lower rate",    ) != null);}test "profiling coz marks missing and invalid capture summaries" {    var arena_state = std.heap.ArenaAllocator.init(std.testing.allocator);    defer arena_state.deinit();    const allocator = arena_state.allocator();    var tmp = std.testing.tmpDir(.{});    defer tmp.cleanup();    try tmp.dir.writeFile(fs_io, .{ .sub_path = "invalid.json", .data = "{}" });    const root = try tmp.dir.realPathFileAlloc(fs_io, ".", allocator);    const invalid_path = try std.fs.path.join(allocator, &.{ root, "invalid.json" });    const missing_path = try std.fs.path.join(allocator, &.{ root, "missing.json" });    const invalid = try appendCapture(allocator, &.{}, .{        .enabled = true,        .exit_code = 0,        .capture_path = "profile.jsonl",        .summary_path = invalid_path,    });    const missing = try appendCapture(allocator, &.{}, .{        .enabled = true,        .exit_code = 0,        .capture_path = "profile.jsonl",        .summary_path = missing_path,    });    try std.testing.expectEqualStrings("summary_invalid", invalid[0].state);    try std.testing.expectEqualStrings("capture_missing", missing[0].state);}

Source: src/profiling/capture/root.zig:1

zig
pub const coz = @import("coz.zig");

Audit

Definitions14
Public names14
Members18
Version26.7.0
Revisiondaab053ee433