tiny.profiling.baseline
Defined in tiny.profiling.
API (17)
Actions
Public operations.
Types and contracts
Public types and contracts.
Values and defaults
Public values and defaults.
Source
Source: src/profiling/baseline.zig
zig
const std = @import("std");const pretty = @import("pretty");const sys = @import("sys");const json = @import("json.zig");const record = @import("record.zig");const pretty_json = pretty.json;pub const schema = "tiny.profiling.baseline/v1";pub const default_dir = "zig-out/profiling/baselines";pub const RunRef = struct { run_id: []const u8, root: []const u8, manifest_path: []const u8, results_path: []const u8, suite: ?[]const u8 = null, git_sha: ?[]const u8 = null, git_branch: ?[]const u8 = null,};pub const Entry = struct { name: []const u8, run: RunRef,};pub const DetailedEntry = struct { entry: Entry, path: []const u8, mtime_ns: i128,};pub const PruneOptions = struct { keep_last: ?usize = null, older_than_ns: ?i128 = null, dry_run: bool = false,};pub const Pruned = struct { entry: Entry, path: []const u8, mtime_ns: i128, deleted: bool,};fn entry_name_ascending(_: void, left: Entry, right: Entry) bool { return std.mem.order(u8, left.name, right.name) == .lt;}fn detailed_entry_name_ascending(_: void, left: DetailedEntry, right: DetailedEntry) bool { return std.mem.order(u8, left.entry.name, right.entry.name) == .lt;}fn detailed_entry_recent_first(_: void, left: DetailedEntry, right: DetailedEntry) bool { if (left.mtime_ns == right.mtime_ns) { return std.mem.order(u8, left.entry.name, right.entry.name) == .lt; } return left.mtime_ns > right.mtime_ns;}pub fn save(allocator: std.mem.Allocator, name: []const u8, input: []const u8) !Entry { try validateName(name); const run = try resolveRun(allocator, input); try sys.fs.createDirPath(default_dir); const path = try entryPath(allocator, name); const body = try renderEntry(allocator, name, run); defer allocator.free(body); try sys.fs.writeFile(path, body); return .{ .name = name, .run = run };}pub fn list(allocator: std.mem.Allocator) ![]Entry { const detailed = try listDetailed(allocator); var result: std.ArrayList(Entry) = .empty; for (detailed) |entry| try result.append(allocator, entry.entry); std.mem.sort(Entry, result.items, {}, entry_name_ascending); return try result.toOwnedSlice(allocator);}pub fn listDetailed(allocator: std.mem.Allocator) ![]DetailedEntry { const entries = sys.fs.listDirAlloc(allocator, default_dir) catch |err| switch (err) { error.FileNotFound => return &.{}, else => |actual| return actual, }; defer sys.fs.freeEntries(allocator, entries); var result: std.ArrayList(DetailedEntry) = .empty; for (entries) |entry| { if (entry.kind != .file) continue; if (!std.mem.endsWith(u8, entry.name, ".json")) continue; const stat = sys.fs.statFile(entry.path) catch continue; try result.append(allocator, .{ .entry = try parseEntryFile(allocator, entry.path), .path = try allocator.dupe(u8, entry.path), .mtime_ns = stat.mtime.nanoseconds, }); } std.mem.sort(DetailedEntry, result.items, {}, detailed_entry_name_ascending); return try result.toOwnedSlice(allocator);}pub fn prune(allocator: std.mem.Allocator, options: PruneOptions) ![]Pruned { if (options.keep_last == null and options.older_than_ns == null) return error.MissingPruneRule; const entries = try listDetailed(allocator); std.mem.sort(DetailedEntry, entries, {}, detailed_entry_recent_first); const now_ns = sys.time.realNanoTimestamp(); var result: std.ArrayList(Pruned) = .empty; for (entries, 0..) |entry, index| { if (!shouldPrune(index, entry.mtime_ns, now_ns, options)) continue; if (!options.dry_run) try sys.fs.deleteFile(entry.path); try result.append(allocator, .{ .entry = entry.entry, .path = entry.path, .mtime_ns = entry.mtime_ns, .deleted = !options.dry_run, }); } return try result.toOwnedSlice(allocator);}pub fn delete(allocator: std.mem.Allocator, name: []const u8) !Entry { try validateName(name); const path = try entryPath(allocator, name); const entry = try parseEntryFile(allocator, path); try sys.fs.deleteFile(path); return entry;}pub fn resolveRun(allocator: std.mem.Allocator, input: []const u8) !RunRef { if (std.mem.endsWith(u8, input, "results.jsonl")) { return .{ .run_id = std.fs.path.basename(std.fs.path.dirname(input) orelse "."), .root = std.fs.path.dirname(input) orelse ".", .manifest_path = try std.fs.path.join(allocator, &.{ std.fs.path.dirname(input) orelse ".", "manifest.json" }), .results_path = input, }; } if (std.mem.endsWith(u8, input, ".json") and sys.fs.exists(input)) { return try parseRunFile(allocator, input); } const manifest = try std.fs.path.join(allocator, &.{ input, "manifest.json" }); if (sys.fs.exists(manifest)) return try parseManifest(allocator, manifest); const baseline_path = try entryPath(allocator, input); if (sys.fs.exists(baseline_path)) { const entry = try parseEntryFile(allocator, baseline_path); return entry.run; } return error.ProfilingRunNotFound;}pub fn parseEntryFile(allocator: std.mem.Allocator, path: []const u8) !Entry { const text = try sys.fs.readFileAlloc(allocator, path, 8 * 1024 * 1024); const value = try std.json.parseFromSliceLeaky(std.json.Value, allocator, text, .{}); const object = try json.object(value); const actual_schema = json.string(object.get("schema")) orelse return error.InvalidProfilingJson; if (!std.mem.eql(u8, actual_schema, schema)) return error.InvalidProfilingJson; return .{ .name = json.string(object.get("name")) orelse return error.InvalidProfilingJson, .run = try parseRunRef(object), };}pub fn parseManifest(allocator: std.mem.Allocator, path: []const u8) !RunRef { const text = try sys.fs.readFileAlloc(allocator, path, 8 * 1024 * 1024); const value = try std.json.parseFromSliceLeaky(std.json.Value, allocator, text, .{}); const object = try json.object(value); const actual_schema = json.string(object.get("schema")) orelse return error.InvalidProfilingJson; if (!std.mem.eql(u8, actual_schema, record.run_schema)) return error.InvalidProfilingJson; return try parseRunRefFromManifest(allocator, object, path);}pub fn entryPath(allocator: std.mem.Allocator, name: []const u8) ![]const u8 { try validateName(name); const segment = try sanitize(allocator, name); const file = try std.fmt.allocPrint(allocator, "{s}.json", .{segment}); return try std.fs.path.join(allocator, &.{ default_dir, file });}pub fn validateName(name: []const u8) !void { if (name.len == 0) return error.InvalidBaselineName; if (std.mem.eql(u8, name, ".") or std.mem.eql(u8, name, "..")) return error.InvalidBaselineName; for (name) |byte| { if (!(std.ascii.isAlphanumeric(byte) or byte == '.' or byte == '_' or byte == '-')) return error.InvalidBaselineName; }}fn parseRunFile(allocator: std.mem.Allocator, path: []const u8) !RunRef { const text = try sys.fs.readFileAlloc(allocator, path, 8 * 1024 * 1024); const value = try std.json.parseFromSliceLeaky(std.json.Value, allocator, text, .{}); const object = try json.object(value); const actual_schema = json.string(object.get("schema")) orelse return error.InvalidProfilingJson; if (std.mem.eql(u8, actual_schema, schema)) return (try parseEntryFile(allocator, path)).run; if (std.mem.eql(u8, actual_schema, record.run_schema)) return try parseRunRefFromManifest(allocator, object, path); return error.InvalidProfilingJson;}fn parseRunRef(object: std.json.ObjectMap) !RunRef { return .{ .run_id = json.string(object.get("run_id")) orelse return error.InvalidProfilingJson, .root = json.string(object.get("root")) orelse return error.InvalidProfilingJson, .manifest_path = json.string(object.get("manifest_path")) orelse return error.InvalidProfilingJson, .results_path = json.string(object.get("results_path")) orelse return error.InvalidProfilingJson, .suite = json.string(object.get("suite")), .git_sha = json.string(object.get("git_sha")), .git_branch = json.string(object.get("git_branch")), };}fn parseRunRefFromManifest(allocator: std.mem.Allocator, object: std.json.ObjectMap, manifest_path: []const u8) !RunRef { const artifacts = try json.object(object.get("artifacts") orelse return error.InvalidProfilingJson); const selection = if (object.get("selection")) |value| try json.object(value) else null; const environment = if (object.get("environment")) |value| try json.object(value) else null; const git = if (environment) |env| if (env.get("git")) |value| try json.object(value) else null else null; const root = std.fs.path.dirname(manifest_path) orelse json.string(artifacts.get("root")) orelse "."; const results = try std.fs.path.join(allocator, &.{ root, "results.jsonl" }); return .{ .run_id = json.string(object.get("run_id")) orelse std.fs.path.basename(root), .root = root, .manifest_path = manifest_path, .results_path = results, .suite = if (selection) |actual| json.string(actual.get("suite")) else null, .git_sha = if (git) |actual| json.string(actual.get("commit")) else null, .git_branch = if (git) |actual| json.string(actual.get("branch")) else null, };}fn renderEntry(allocator: std.mem.Allocator, name: []const u8, run: RunRef) ![]const u8 { var out: std.Io.Writer.Allocating = .init(allocator); errdefer out.deinit(); var writer = pretty_json.Writer.init(&out.writer, .minified); try writer.beginObject(); try writer.objectField("schema"); try writer.write(schema); try writer.objectField("name"); try writer.write(name); try writer.objectField("run_id"); try writer.write(run.run_id); try writer.objectField("root"); try writer.write(run.root); try writer.objectField("manifest_path"); try writer.write(run.manifest_path); try writer.objectField("results_path"); try writer.write(run.results_path); try writer.objectField("suite"); try writer.write(run.suite); try writer.objectField("git_sha"); try writer.write(run.git_sha); try writer.objectField("git_branch"); try writer.write(run.git_branch); try writer.endObject(); try out.writer.writeByte('\n'); return try out.toOwnedSlice();}fn sanitize(allocator: std.mem.Allocator, value: []const u8) ![]const u8 { const result = try allocator.alloc(u8, value.len); for (value, 0..) |byte, index| { result[index] = if (std.ascii.isAlphanumeric(byte) or byte == '.' or byte == '_' or byte == '-') byte else '_'; } return result;}fn shouldPrune(index: usize, mtime_ns: i128, now_ns: i128, options: PruneOptions) bool { const past_keep = if (options.keep_last) |keep_last| index >= keep_last else false; const old = if (options.older_than_ns) |age| now_ns - mtime_ns >= age else false; if (options.keep_last != null and options.older_than_ns != null) return past_keep and old; return past_keep or old;}test "profiling baseline parses manifest run refs" { var arena_state = std.heap.ArenaAllocator.init(std.testing.allocator); defer arena_state.deinit(); const allocator = arena_state.allocator(); const value = try std.json.parseFromSliceLeaky(std.json.Value, allocator, \\{"schema":"tiny.profiling.run/v1","event":"manifest","run_id":"run-a","selection":{"suite":"smoke"},"environment":{"git":{"commit":"abc","branch":"main"}},"artifacts":{"root":"zig-out/profiling/run-a","results":"zig-out/profiling/run-a/results.jsonl","manifest":"zig-out/profiling/run-a/manifest.json"}} , .{}); const run = try parseRunRefFromManifest(allocator, try json.object(value), "zig-out/profiling/run-a/manifest.json"); try std.testing.expectEqualStrings("run-a", run.run_id); try std.testing.expectEqualStrings("smoke", run.suite.?); try std.testing.expectEqualStrings("abc", run.git_sha.?); try std.testing.expectEqualStrings("zig-out/profiling/run-a", run.root); try std.testing.expectEqualStrings("zig-out/profiling/run-a/results.jsonl", run.results_path);}test "profiling baseline resolves relocated manifests to their actual directory" { var arena_state = std.heap.ArenaAllocator.init(std.testing.allocator); defer arena_state.deinit(); const allocator = arena_state.allocator(); const value = try std.json.parseFromSliceLeaky(std.json.Value, allocator, \\{"schema":"tiny.profiling.run/v1","event":"manifest","run_id":"run-a","artifacts":{"root":"zig-out/profiling/run-a","results":"zig-out/profiling/run-a/results.jsonl","manifest":"zig-out/profiling/run-a/manifest.json"}} , .{}); const run = try parseRunRefFromManifest(allocator, try json.object(value), "zig-out/profiling-baseline/run-a/manifest.json"); try std.testing.expectEqualStrings("run-a", run.run_id); try std.testing.expectEqualStrings("zig-out/profiling-baseline/run-a", run.root); try std.testing.expectEqualStrings("zig-out/profiling-baseline/run-a/results.jsonl", run.results_path);}test "profiling baseline names reject path shapes" { try validateName("main-smoke_1.0"); try std.testing.expectError(error.InvalidBaselineName, validateName("")); try std.testing.expectError(error.InvalidBaselineName, validateName("../main")); try std.testing.expectError(error.InvalidBaselineName, validateName("main smoke"));}test "profiling baseline prune rules keep protected recent entries" { const now: i128 = 10_000; try std.testing.expect(!shouldPrune(0, 0, now, .{ .keep_last = 1, .older_than_ns = 1 })); try std.testing.expect(shouldPrune(1, 0, now, .{ .keep_last = 1, .older_than_ns = 1 })); try std.testing.expect(shouldPrune(1, now - 1_000, now, .{ .keep_last = 1 })); try std.testing.expect(shouldPrune(0, 0, now, .{ .older_than_ns = 1 }));}Source: src/profiling/root.zig:14
zig
pub const baseline = @import("baseline.zig");Audit
| Definitions | 18 |
|---|---|
| Public names | 18 |
| Members | 19 |
| Version | 26.7.0 |
| Revision | daab053ee433 |