tiny.profiling.report.drift
Defined in report.
API (9)
Actions
Public operations.
Types and contracts
Public types and contracts.
Source
Source: src/profiling/report/drift.zig
zig
const std = @import("std");const pretty = @import("pretty");const pretty_usage = @import("pretty_usage");const sys = @import("sys");const catalog = @import("../root.zig").catalog;const execute = @import("../root.zig").execute;const surface = @import("../root.zig").surface;const pretty_json = pretty.json;const scratch_dir = "zig-out/profiling/check";pub const Missing = struct { package: []const u8, step: []const u8,};pub const Stale = struct { workload: []const u8, cwd: []const u8, step: []const u8, kind: []const u8,};pub const Empty = struct { package: []const u8, reason: ?[]const u8 = null,};pub const ExemptionFailureKind = enum { duplicate, orphan, profiled,};pub const ExemptionFailure = struct { package: []const u8, kind: ExemptionFailureKind,};pub const Report = struct { packages: usize, candidate_steps: usize, missing: []const Missing, stale: []const Stale, empty: []const Empty, exemption_failures: []const ExemptionFailure,};/// One build surface, keyed like the registry audit's by package and options.const PackageSteps = struct { package: []const u8, build_options: []const []const u8 = &.{}, steps: []const []const u8, candidates: []const []const u8,};const Exemption = struct { package: []const u8, reason: []const u8,};pub const Scope = union(enum) { all, package: []const u8, fn includes(scope: Scope, package: []const u8) bool { return switch (scope) { .all => true, .package => |selected| std.mem.eql(u8, selected, package), }; }};const RunOptions = struct { scope: Scope, json: bool,};const complete_exemptions = [_]Exemption{ .{ .package = "fun/animation", .reason = "terminal animation is an interactive demo; frame cost is governed by the consuming terminal renderer" }, .{ .package = "fun/icon", .reason = "icon generation is build-time asset production without a runtime latency contract" }, .{ .package = "lib/acp", .reason = "ACP is a protocol model governed by conformance tests; " ++ "live peer latency requires controlled clients", }, .{ .package = "lib/alloc", .reason = "allocator policy selects implementations whose costs are measured by gpalloc, bumpalo, and allocation-sensitive consumers" }, .{ .package = "lib/arrange", .reason = "layout cost is governed through profiled GUI presentation workloads. " ++ "No separate representative tree corpus is reviewed", }, .{ .package = "lib/capture", .reason = "capture is profiling infrastructure exercised by the root profiling harness and host-tool lanes" }, .{ .package = "lib/closure", .reason = "provenance inspection is governed by bounded verification and exact " ++ "receipt gates without a reviewed production artifact corpus", }, .{ .package = "lib/content", .reason = "content capabilities have no reviewed production-scale byte corpus", }, .{ .package = "lib/coz", .reason = "Coz markers are profiling instrumentation exercised by every causal benchmark lane" }, .{ .package = "lib/deadalloc", .reason = "preload instrumentation is diagnostic rather than a standalone benchmark surface" }, .{ .package = "lib/gif", .reason = "the decoder has no reviewed representative corpus or throughput contract", }, .{ .package = "lib/hypothesis", .reason = "the root-owned hypothesis benchmark avoids a dependency cycle through lib/bench" }, .{ .package = "lib/memtrace", .reason = "root-owned record and replay benchmarks avoid a dependency cycle through lib/bench" }, .{ .package = "lib/os", .reason = "boot and image performance requires a controlled emulator lane rather than a host microbenchmark" }, .{ .package = "lib/pdf", .reason = "the document engine has no reviewed representative corpus " ++ "or throughput contract", }, .{ .package = "lib/peer", .reason = "peer identity and ticket operations have no reviewed scale workload", }, .{ .package = "lib/preserves", .reason = "serialization cost is currently governed through profiled protocol consumers" }, .{ .package = "lib/pretty", .reason = "the root-owned pretty benchmark avoids a dependency cycle through lib/bench" }, .{ .package = "lib/quic", .reason = "QUIC has no reviewed traffic trace or controlled peer workload", }, .{ .package = "lib/reducer", .reason = "the reducer is a composition primitive measured through its profiled compiler consumers" }, .{ .package = "lib/repo", .reason = "repository operations are subprocess and filesystem integration exercised by profiled repository tools" }, .{ .package = "lib/reticulum", .reason = "Reticulum is governed by wire conformance and has no reviewed " ++ "transport throughput workload", }, .{ .package = "lib/stabilizer", .reason = "layout stabilization is profiling infrastructure exercised by benchmark suites with randomized layouts" }, .{ .package = "lib/stun", .reason = "STUN has no reviewed message corpus or controlled network workload", }, .{ .package = "lib/syn", .reason = "syntax highlighting lacks a reviewed representative source corpus " ++ "and throughput contract", }, .{ .package = "lib/sys", .reason = "the root-owned boundary benchmarks avoid a dependency cycle " ++ "through lib/bench; remaining platform primitives require " ++ "subsystem-specific controlled peers", }, .{ .package = "lib/termtex", .reason = "terminal texture encoding is measured through the profiled terminal presentation path" }, .{ .package = "lib/tracy", .reason = "Tracy integration is profiling instrumentation exercised by instrumented package workloads" }, .{ .package = "lib/tripwire", .reason = "tripwire is failure instrumentation without a steady-state runtime workload" }, .{ .package = "lib/wayland", .reason = "transport latency requires a controlled compositor peer rather than a host-only microbenchmark" }, .{ .package = "lib/xkb", .reason = "generated lookup tables are governed by conformance and have no reviewed " ++ "interactive trace corpus", }, .{ .package = "research/intent", .reason = "the inverse-planning research package has no reviewed scale workload", }, .{ .package = "research/reppl", .reason = "qed's evaluation suite measures the source libraries; the retained Lean " ++ "semantics and proof modules have no independent runtime workload", }, .{ .package = "tools/ask", .reason = "question latency is bounded by the person answering the form, not by host-only work" }, .{ .package = "tools/tempo", .reason = "execution recorder overhead is qualified with external command conformance and paired capture controls" }, .{ .package = "tools/clip", .reason = "clipboard latency requires controlled terminal, tmux, SSH, and clipboard peers rather than a host-only microbenchmark" }, .{ .package = "tools/concord", .reason = "Concord builds deterministic verification catalogs without a reviewed " ++ "production-scale binding corpus", }, .{ .package = "tools/diagrams", .reason = "diagram rendering is build-time asset production governed through site generation" }, .{ .package = "tools/issue", .reason = "issue operations share the SQL store and have no separate production-scale fixture" }, .{ .package = "tools/licenses", .reason = "manifest verification reads one committed dependency manifest, and " ++ "online verification waits on upstream registries rather than host work", }, .{ .package = "tools/loom", .reason = "Loom coordination depends on host, cache, repository, and remote-worker " ++ "conditions without one reviewed standalone workload", }, .{ .package = "tools/policy", .reason = "repository policy checking is filesystem validation over the working " ++ "tree Git reports, which is not a reviewed corpus", }, .{ .package = "tools/style", .reason = "style checking is a filesystem validation tool without a reviewed " ++ "latency contract", }, .{ .package = "tools/tiny", .reason = "task composition delegates its cost to the issue store and the " ++ "commands it runs, without a self-owned runtime workload", }, .{ .package = "tools/wiring", .reason = "automation reference checking is bounded by the committed workflow " ++ "files and the embedded step catalog", },};const exemptions = projectExemptions(complete_exemptions);const public_package_roots = [_][]const u8{ "lib", "tools", "fun" };const package_roots = public_package_roots ++ (if (surface.research) [_][]const u8{"research"}else [_][]const u8{});fn projectExemptions( comptime source: anytype,) [enabledExemptionCount(source)]Exemption { var result: [enabledExemptionCount(source)]Exemption = undefined; var retained_count: usize = 0; for (source) |exemption| { if (!exemptionEnabled(exemption)) continue; if (retained_count == result.len) { @compileError("profiling exemption projection is incomplete"); } result[retained_count] = exemption; retained_count += 1; } if (retained_count != result.len) { @compileError("profiling exemption projection is incomplete"); } return result;}fn enabledExemptionCount(comptime source: anytype) usize { @setEvalBranchQuota(10_000); var count: usize = 0; for (source) |exemption| { if (exemptionEnabled(exemption)) count += 1; } return count;}fn exemptionEnabled(exemption: Exemption) bool { if (researchPackage(exemption.package)) return surface.research; if (std.mem.eql(u8, exemption.package, "tools/style")) return surface.style; return true;}fn containsExemption(declared: []const Exemption, package: []const u8) bool { for (declared) |exemption| { if (std.mem.eql(u8, exemption.package, package)) return true; } return false;}fn researchPackage(package: []const u8) bool { return std.mem.startsWith(u8, package, "research/");}pub fn run(allocator: std.mem.Allocator, process_io: std.Io, environ_map: ?*const sys.process.Environ.Map, args: []const []const u8) !u8 { const options = try parseRunOptions(args); const report = try check( allocator, process_io, environ_map, execute.zig(environ_map), options.scope, ); if (options.json) { try writeJson(report); } else { try writeText(allocator, report); } return if (reportPassed(report)) 0 else 1;}fn parseRunOptions(args: []const []const u8) !RunOptions { var scope: ?Scope = null; var json = false; for (args) |arg| { if (std.mem.eql(u8, arg, "--json")) { json = true; } else if (std.mem.eql(u8, arg, "--all")) { if (scope != null) return error.ConflictingScope; scope = .all; } else if (std.mem.startsWith(u8, arg, "-")) { return error.UnknownArgument; } else { if (scope != null) return error.ConflictingScope; scope = .{ .package = arg }; } } return .{ .scope = scope orelse return error.MissingScope, .json = json };}pub fn check( allocator: std.mem.Allocator, process_io: std.Io, environ_map: ?*const sys.process.Environ.Map, zig_command: execute.Zig, scope: Scope,) !Report { var selected_package: [1][]const u8 = undefined; const packages = try packagesForScope( allocator, process_io, scope, &selected_package, ); var build_environment = try packageBuildEnvironment(allocator, environ_map); defer build_environment.deinit(); const root_step_text = try discoverBuildStepText( allocator, process_io, &build_environment, zig_command, null, &.{}, ); const root_steps = try parseBuildSteps(allocator, root_step_text); return try checkPackages( allocator, process_io, &build_environment, zig_command, scope, packages, root_steps, );}fn checkPackages( allocator: std.mem.Allocator, process_io: std.Io, build_environment: *const sys.process.Environ.Map, zig_command: execute.Zig, scope: Scope, packages: []const []const u8, root_steps: []const []const u8,) !Report { var missing: std.ArrayList(Missing) = .empty; var stale: std.ArrayList(Stale) = .empty; var empty: std.ArrayList(Empty) = .empty; var package_steps: std.ArrayList(PackageSteps) = .empty; var candidate_steps: usize = 0; for (packages) |package| { const build_path = try std.fs.path.join(allocator, &.{ package, "build.zig" }); if (!sys.fs.exists(build_path)) { try empty.append(allocator, .{ .package = package, .reason = emptyReason(package) }); continue; } const step_text = try discoverBuildStepText( allocator, process_io, build_environment, zig_command, package, &.{}, ); const steps = try parseBuildSteps(allocator, step_text); const candidates = try parseSteps(allocator, step_text); const default_surface = PackageSteps{ .package = package, .steps = steps, .candidates = candidates, }; try package_steps.append(allocator, default_surface); var opt_in_candidates: usize = 0; for (catalog.workloads, 0..) |workload, index| { const options = workload.package_build_options; if (!std.mem.eql(u8, workload.package, package)) continue; if (options.len == 0) continue; if (optionSetDeclaredBefore(package, options, index)) continue; const surface_text = try discoverBuildStepText( allocator, process_io, build_environment, zig_command, package, options, ); const opt_in = try optInSurface(allocator, package, options, candidates, surface_text); try package_steps.append(allocator, opt_in); candidate_steps += opt_in.candidates.len; opt_in_candidates += opt_in.candidates.len; try appendMissing(allocator, opt_in, &missing); } if (candidates.len == 0 and opt_in_candidates == 0) { try empty.append(allocator, .{ .package = package, .reason = emptyReason(package) }); continue; } candidate_steps += candidates.len; try appendMissing(allocator, default_surface, &missing); } try checkCatalogSteps(allocator, scope, root_steps, package_steps.items, &stale); const exemption_failures = try checkExemptions( allocator, &exemptions, scope, packages, package_steps.items, ); return .{ .packages = packages.len, .candidate_steps = candidate_steps, .missing = try missing.toOwnedSlice(allocator), .stale = try stale.toOwnedSlice(allocator), .empty = try empty.toOwnedSlice(allocator), .exemption_failures = exemption_failures, };}fn packagesForScope( allocator: std.mem.Allocator, process_io: std.Io, scope: Scope, selected: *[1][]const u8,) ![]const []const u8 { return switch (scope) { .all => try collectPackages(allocator, process_io), .package => |package| package: { if (!validPackageName(package)) return error.UnknownPackage; const build_path = try std.fs.path.join(allocator, &.{ package, "build.zig" }); if (!sys.fs.exists(build_path)) return error.UnknownPackage; selected[0] = package; break :package selected[0..]; }, };}fn validPackageName(package: []const u8) bool { const slash = std.mem.indexOfScalar(u8, package, '/') orelse return false; if (slash == 0 or slash + 1 == package.len) return false; if (std.mem.indexOfScalar(u8, package[slash + 1 ..], '/') != null) return false; const root = package[0..slash]; const name = package[slash + 1 ..]; if (std.mem.eql(u8, name, ".") or std.mem.eql(u8, name, "..")) return false; return std.mem.eql(u8, root, "lib") or std.mem.eql(u8, root, "tools") or std.mem.eql(u8, root, "fun") or (surface.research and std.mem.eql(u8, root, "research"));}fn collectPackages(allocator: std.mem.Allocator, process_io: std.Io) ![]const []const u8 { const find_arguments = [_][]const u8{"/usr/bin/find"} ++ package_roots ++ [_][]const u8{ "-mindepth", "2", "-maxdepth", "2", "-name", "build.zig", "-type", "f", }; const output = try captureStdout( allocator, process_io, null, &find_arguments, "find", 4 * 1024 * 1024, null, ); var packages: std.ArrayList([]const u8) = .empty; var lines = std.mem.splitScalar(u8, output, '\n'); while (lines.next()) |line| { if (buildPackage(std.mem.trim(u8, line, " \t\r"))) |package| try packages.append(allocator, package); } std.mem.sort([]const u8, packages.items, {}, package_name_ascending); return try packages.toOwnedSlice(allocator);}fn package_name_ascending(_: void, left: []const u8, right: []const u8) bool { return std.mem.order(u8, left, right) == .lt;}fn buildPackage(path: []const u8) ?[]const u8 { const normalized = if (std.mem.startsWith(u8, path, "./")) path[2..] else path; const suffix = "/build.zig"; if (!std.mem.endsWith(u8, normalized, suffix)) return null; const package = normalized[0 .. normalized.len - suffix.len]; if (package.len == 0) return null; return package;}fn reportPassed(report: Report) bool { if (report.missing.len != 0 or report.stale.len != 0 or report.exemption_failures.len != 0) { return false; } for (report.empty) |row| { if (row.reason == null) return false; } return true;}fn checkExemptions( allocator: std.mem.Allocator, declared: []const Exemption, scope: Scope, packages: []const []const u8, package_steps: []const PackageSteps,) ![]const ExemptionFailure { var failures: std.ArrayList(ExemptionFailure) = .empty; for (declared, 0..) |exemption, index| { if (!scope.includes(exemption.package)) continue; if (exemptionDuplicate(declared[0..index], exemption.package)) { try failures.append(allocator, .{ .package = exemption.package, .kind = .duplicate, }); } if (!containsStep(packages, exemption.package)) { try failures.append(allocator, .{ .package = exemption.package, .kind = .orphan, }); } if (packageCandidates(package_steps, exemption.package)) |candidates| { if (candidates.len != 0) { try failures.append(allocator, .{ .package = exemption.package, .kind = .profiled, }); } } } return try failures.toOwnedSlice(allocator);}fn exemptionDuplicate(previous: []const Exemption, package: []const u8) bool { for (previous) |exemption| { if (std.mem.eql(u8, exemption.package, package)) return true; } return false;}fn packageCandidates( package_steps: []const PackageSteps, package: []const u8,) ?[]const []const u8 { for (package_steps) |row| { if (row.build_options.len != 0) continue; if (std.mem.eql(u8, row.package, package)) return row.candidates; } return null;}fn appendMissing( allocator: std.mem.Allocator, package_surface: PackageSteps, missing: *std.ArrayList(Missing),) !void { for (package_surface.candidates) |step| { if (covered(package_surface.package, package_surface.build_options, step)) continue; try missing.append(allocator, .{ .package = package_surface.package, .step = step, }); }}fn optionSetDeclaredBefore( package: []const u8, options: []const []const u8, end: usize,) bool { for (catalog.workloads[0..end]) |workload| { if (!std.mem.eql(u8, workload.package, package)) continue; if (optionsEqual(workload.package_build_options, options)) return true; } return false;}fn optionsEqual(left: []const []const u8, right: []const []const u8) bool { if (left.len != right.len) return false; for (left, right) |left_option, right_option| { if (!std.mem.eql(u8, left_option, right_option)) return false; } return true;}/// An opt-in surface owns only the candidates its options expose; the/// default surface already accounts for every step visible without them.fn optInSurface( allocator: std.mem.Allocator, package: []const u8, options: []const []const u8, default_candidates: []const []const u8, text: []const u8,) !PackageSteps { std.debug.assert(options.len != 0); const listed = try parseSteps(allocator, text); var candidates: std.ArrayList([]const u8) = .empty; for (listed) |step| { if (containsStep(default_candidates, step)) continue; try candidates.append(allocator, step); } return .{ .package = package, .build_options = options, .steps = try parseBuildSteps(allocator, text), .candidates = try candidates.toOwnedSlice(allocator), };}fn discoverBuildStepText( allocator: std.mem.Allocator, process_io: std.Io, build_environment: *const sys.process.Environ.Map, zig_command: execute.Zig, package: ?[]const u8, options: []const []const u8,) ![]const u8 { if (package == null) std.debug.assert(options.len == 0); std.debug.assert(options.len <= catalog.maximum_package_build_options); var argv_buffer: [4 + catalog.maximum_package_build_options][]const u8 = undefined; argv_buffer[0..4].* = .{ zig_command.executable, "build", execute.build_flag, "-l" }; @memcpy(argv_buffer[4..][0..options.len], options); return try captureStdout( allocator, process_io, package, argv_buffer[0 .. 4 + options.len], package orelse "root", 4 * 1024 * 1024, build_environment, );}fn captureStdout( allocator: std.mem.Allocator, process_io: std.Io, cwd: ?[]const u8, argv: []const []const u8, name: []const u8, limit: usize, environ_map: ?*const sys.process.Environ.Map,) ![]const u8 { try sys.fs.createDirPath(scratch_dir); const segment = try sanitize(allocator, name); const path = try std.fmt.allocPrint(allocator, "{s}/{d}-{s}.out", .{ scratch_dir, sys.time.realMilliTimestamp(), segment }); const file = try sys.fs.createFile(path, .{ .truncate = true, .read = true }); defer sys.fs.closeHandle(file); var child = try sys.process.spawn(process_io, .{ .argv = argv, .cwd = if (cwd) |path_value| .{ .path = path_value } else .inherit, .environ_map = environ_map, .stdin = .ignore, .stdout = .{ .file = file }, .stderr = .ignore, }); errdefer sys.process.killAndReap(&child, process_io); const term = try sys.process.wait(&child, process_io); if (sys.process.exitCode(term) != 0) return error.ProfilingCommandFailed; const output = try sys.fs.readFileAlloc(allocator, path, limit); sys.fs.deleteFile(path) catch {}; return output;}fn packageBuildEnvironment( allocator: std.mem.Allocator, inherited: ?*const sys.process.Environ.Map,) !sys.process.Environ.Map { var environment = if (inherited) |base| try base.clone(allocator) else try sys.env.createMap(allocator); _ = environment.swapRemove("ZIG_LOCAL_CACHE_DIR"); return environment;}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 parseSteps(allocator: std.mem.Allocator, text: []const u8) ![]const []const u8 { const listed = try parseBuildSteps(allocator, text); defer allocator.free(listed); var steps: std.ArrayList([]const u8) = .empty; var lines = std.mem.splitScalar(u8, text, '\n'); while (lines.next()) |line| { const trimmed = std.mem.trim(u8, line, " \t\r"); if (trimmed.len == 0) continue; const step = firstToken(trimmed); if (generatedCheckTwin(trimmed, step)) continue; if (checkTwinOfListedStep(listed, step)) continue; if (candidateStep(step)) try steps.append(allocator, step); } return try steps.toOwnedSlice(allocator);}/// A package may write its own `S-check` compile step beside `S`. The/// step `S` carries the workload; an `S-check` without `S` stays a candidate.fn checkTwinOfListedStep(listed: []const []const u8, step: []const u8) bool { const suffix = "-check"; if (!std.mem.endsWith(u8, step, suffix)) return false; const base = step[0 .. step.len - suffix.len]; if (base.len == 0) return false; return containsStep(listed, base);}fn parseBuildSteps(allocator: std.mem.Allocator, text: []const u8) ![]const []const u8 { var steps: std.ArrayList([]const u8) = .empty; var lines = std.mem.splitScalar(u8, text, '\n'); while (lines.next()) |line| { const trimmed = std.mem.trim(u8, line, " \t\r"); if (trimmed.len == 0) continue; const step = firstToken(trimmed); try steps.append(allocator, step); } return try steps.toOwnedSlice(allocator);}fn firstToken(line: []const u8) []const u8 { var index: usize = 0; while (index < line.len and !std.ascii.isWhitespace(line[index])) : (index += 1) {} return line[0..index];}fn generatedCheckTwin(line: []const u8, step: []const u8) bool { const prefix = "Check "; const suffix = " without emitting its products or running its effects"; std.debug.assert(step.len != 0); std.debug.assert(step.len <= line.len); const description = std.mem.trimStart(u8, line[step.len..], " \t"); if (!std.mem.startsWith(u8, description, prefix)) return false; if (!std.mem.endsWith(u8, description, suffix)) return false; return description.len > prefix.len + suffix.len;}fn candidateStep(step: []const u8) bool { if (std.mem.indexOf(u8, step, "test") != null) return false; if (std.mem.indexOf(u8, step, "pbt") != null) return false; if (std.mem.endsWith(u8, step, "-raw")) return false; if (std.mem.endsWith(u8, step, "-bin")) return false; if (std.mem.eql(u8, step, "bench-bin")) return false; return std.mem.indexOf(u8, step, "bench") != null or std.mem.indexOf(u8, step, "profile") != null or std.mem.indexOf(u8, step, "latency") != null or std.mem.indexOf(u8, step, "timing") != null or std.mem.indexOf(u8, step, "attribution") != null;}fn emptyReason(package: []const u8) ?[]const u8 { for (exemptions) |exemption| { if (std.mem.eql(u8, package, exemption.package)) return exemption.reason; } return null;}fn covered(package: []const u8, options: []const []const u8, step: []const u8) bool { for (catalog.workloads) |workload| { if (!std.mem.eql(u8, workload.package, package)) continue; if (!optionsEqual(workload.package_build_options, options)) continue; if (std.mem.eql(u8, workload.localStep(), step)) return true; } return false;}fn checkCatalogSteps( allocator: std.mem.Allocator, scope: Scope, root_steps: []const []const u8, package_steps: []const PackageSteps, stale: *std.ArrayList(Stale),) !void { for (catalog.workloads) |workload| { if (!scope.includes(workload.package)) continue; const cwd = workload.cwd orelse "."; const execution_steps = stepsForCwd( root_steps, package_steps, cwd, workload.buildOptionsFor(cwd), ); if (execution_steps == null or !containsStep(execution_steps.?, workload.step)) { try stale.append(allocator, .{ .workload = workload.name, .cwd = cwd, .step = workload.step, .kind = "execution", }); } if (workload.bin) |bin| { const setup_scope = bin.scope(workload.package); const setup_steps = stepsForCwd( root_steps, package_steps, setup_scope, workload.buildOptionsFor(setup_scope), ); if (setup_steps == null or !containsStep(setup_steps.?, bin.step)) { try stale.append(allocator, .{ .workload = workload.name, .cwd = setup_scope, .step = bin.step, .kind = "binary_setup", }); } } }}fn stepsForCwd( root_steps: []const []const u8, package_steps: []const PackageSteps, cwd: []const u8, options: []const []const u8,) ?[]const []const u8 { if (std.mem.eql(u8, cwd, ".")) { std.debug.assert(options.len == 0); return root_steps; } for (package_steps) |package| { if (!std.mem.eql(u8, package.package, cwd)) continue; if (optionsEqual(package.build_options, options)) return package.steps; } return null;}fn containsStep(steps: []const []const u8, target: []const u8) bool { for (steps) |step| { if (std.mem.eql(u8, step, target)) return true; } return false;}fn writeText(allocator: std.mem.Allocator, report: Report) !void { const terminal = pretty_usage.Terminal.stdout(allocator, .{}); try terminal.writeTextFmt("profile catalog check: {d} package(s), {d} candidate step(s)\n", .{ report.packages, report.candidate_steps }); if (report.missing.len == 0) { try terminal.writeText("missing: none\n"); } else { try terminal.writeText("missing:\n"); for (report.missing) |row| try terminal.writeTextFmt(" {s}: {s}\n", .{ row.package, row.step }); } if (report.stale.len == 0) { try terminal.writeText("stale: none\n"); } else { try terminal.writeText("stale catalog steps:\n"); for (report.stale) |row| try terminal.writeTextFmt(" {s}: {s} step {s} in {s}\n", .{ row.workload, row.kind, row.step, row.cwd }); } if (report.exemption_failures.len == 0) { try terminal.writeText("invalid exemptions: none\n"); } else { try terminal.writeText("invalid exemptions:\n"); for (report.exemption_failures) |row| { try terminal.writeTextFmt( " {s}: {s}\n", .{ row.package, @tagName(row.kind) }, ); } } if (report.empty.len != 0) { try terminal.writeText("no profiling-shaped build steps:\n"); for (report.empty) |row| { try terminal.writeTextFmt(" {s}", .{row.package}); if (row.reason) |reason| try terminal.writeTextFmt(" ({s})", .{reason}); try terminal.writeText("\n"); } }}fn writeJson(report: Report) !void { var buffer: [8192]u8 = undefined; var file_writer = sys.stdio.stdout().writer(std.Options.debug_io, &buffer); defer file_writer.interface.flush() catch {}; var out = pretty_json.Writer.init(&file_writer.interface, .minified); try out.beginObject(); try out.objectField("schema"); try out.write("tiny.profiling.catalog-check/v1"); try out.objectField("packages"); try out.write(report.packages); try out.objectField("candidate_steps"); try out.write(report.candidate_steps); try out.objectField("missing"); try out.beginArray(); for (report.missing) |row| { try out.beginObject(); try out.objectField("package"); try out.write(row.package); try out.objectField("step"); try out.write(row.step); try out.endObject(); } try out.endArray(); try out.objectField("stale"); try out.beginArray(); for (report.stale) |row| { try out.beginObject(); try out.objectField("workload"); try out.write(row.workload); try out.objectField("cwd"); try out.write(row.cwd); try out.objectField("step"); try out.write(row.step); try out.objectField("kind"); try out.write(row.kind); try out.endObject(); } try out.endArray(); try out.objectField("exemption_failures"); try out.beginArray(); for (report.exemption_failures) |row| { try out.beginObject(); try out.objectField("package"); try out.write(row.package); try out.objectField("kind"); try out.write(@tagName(row.kind)); try out.endObject(); } try out.endArray(); try out.objectField("empty"); try out.beginArray(); for (report.empty) |row| { try out.beginObject(); try out.objectField("package"); try out.write(row.package); try out.objectField("reason"); try out.write(row.reason); try out.endObject(); } try out.endArray(); try out.endObject(); try file_writer.interface.writeByte('\n');}test "profiling drift parses profiling-shaped steps" { var arena_state = std.heap.ArenaAllocator.init(std.testing.allocator); defer arena_state.deinit(); const steps = try parseSteps(arena_state.allocator(), \\ bench Run benchmarks \\ bench-bin Install benchmark executable \\ bench-release-raw Run internal ReleaseFast benchmark \\ bench-release-bin-raw Install internal ReleaseFast benchmark \\ phase2-latency Run latency benchmark \\ tests Run tests \\ ); try std.testing.expectEqual(@as(usize, 2), steps.len); try std.testing.expectEqualStrings("bench", steps[0]); try std.testing.expectEqualStrings("phase2-latency", steps[1]);}test "profiling drift isolates package build caches" { var inherited = sys.process.Environ.Map.init(std.testing.allocator); defer inherited.deinit(); try inherited.put("ZIG_LOCAL_CACHE_DIR", "/tmp/shared"); try inherited.put("ZIG_GLOBAL_CACHE_DIR", "/tmp/global"); var environment = try packageBuildEnvironment( std.testing.allocator, &inherited, ); defer environment.deinit(); try std.testing.expect(environment.get("ZIG_LOCAL_CACHE_DIR") == null); try std.testing.expectEqualStrings( "/tmp/global", environment.get("ZIG_GLOBAL_CACHE_DIR").?, ); try std.testing.expectEqualStrings( "/tmp/shared", inherited.get("ZIG_LOCAL_CACHE_DIR").?, );}test "profiling drift authenticates generated check twins" { var arena_state = std.heap.ArenaAllocator.init(std.testing.allocator); defer arena_state.deinit(); const steps = try parseSteps(arena_state.allocator(), \\ bench Run benchmarks \\ bench-check Check bench without emitting its products or running its effects \\ bench-bin Install benchmark executable \\ bench-bin-check Check bench-bin without emitting its products or running its effects \\ profile Run profiling workloads \\ profile-check Check profile without emitting its products or running its effects \\ profile-audit-check Audit profiling output \\ ); try std.testing.expectEqual(@as(usize, 3), steps.len); try std.testing.expectEqualStrings("bench", steps[0]); try std.testing.expectEqualStrings("profile", steps[1]); try std.testing.expectEqualStrings("profile-audit-check", steps[2]);}test "profiling drift excludes hand-written check twins only beside their step" { var arena_state = std.heap.ArenaAllocator.init(std.testing.allocator); defer arena_state.deinit(); const steps = try parseSteps(arena_state.allocator(), \\ bench-timing-pairs Run stage benchmarks with timing disabled and enabled \\ bench-timing-pairs-check Check stage benchmarks compilation without running tests \\ bench-orphan-check Check a benchmark whose run step is absent \\ start-profile Measure start latency \\ ); try std.testing.expectEqual(@as(usize, 3), steps.len); try std.testing.expectEqualStrings("bench-timing-pairs", steps[0]); try std.testing.expectEqualStrings("bench-orphan-check", steps[1]); try std.testing.expectEqualStrings("start-profile", steps[2]);}test "profiling drift parses every build step for stale catalog checks" { var arena_state = std.heap.ArenaAllocator.init(std.testing.allocator); defer arena_state.deinit(); const steps = try parseBuildSteps(arena_state.allocator(), \\ bench Run benchmarks \\ bench-bin Install benchmark executable \\ install Copy build artifacts \\ ); try std.testing.expectEqual(@as(usize, 3), steps.len); try std.testing.expect(containsStep(steps, "bench-bin"));}test "profiling drift maps package build file to package" { try std.testing.expectEqualStrings("lib/gpalloc", buildPackage("./lib/gpalloc/build.zig").?); try std.testing.expect(buildPackage("./build.zig") == null); try std.testing.expect(buildPackage("lib/gpalloc/src/profiling") == null);}test "profiling drift requires one package or every package" { const package_options = try parseRunOptions(&.{ "lib/gpalloc", "--json" }); const package = switch (package_options.scope) { .package => |selected| selected, .all => return error.TestUnexpectedResult, }; try std.testing.expectEqualStrings("lib/gpalloc", package); try std.testing.expect(package_options.json); const all_options = try parseRunOptions(&.{"--all"}); try std.testing.expectEqual(.all, std.meta.activeTag(all_options.scope)); try std.testing.expect(!all_options.json); try std.testing.expectError(error.MissingScope, parseRunOptions(&.{})); try std.testing.expectError( error.ConflictingScope, parseRunOptions(&.{ "lib/gpalloc", "--all" }), ); try std.testing.expectError(error.UnknownArgument, parseRunOptions(&.{"--other"}));}test "profiling drift accepts only package roots" { try std.testing.expect(validPackageName("lib/gpalloc")); try std.testing.expect(validPackageName("tools/smg")); try std.testing.expectEqual( surface.research, validPackageName("research/sai"), ); try std.testing.expect(!validPackageName("src/profiling")); try std.testing.expect(!validPackageName("lib/..")); try std.testing.expect(!validPackageName("lib/gpalloc/src"));}test "profiling drift projects held package ownership" { try std.testing.expectEqual( public_package_roots.len + @intFromBool(surface.research), package_roots.len, ); try std.testing.expectEqual( surface.research, containsExemption(exemptions[0..], "research/intent"), ); try std.testing.expectEqual( surface.style, containsExemption(exemptions[0..], "tools/style"), ); try std.testing.expect(!containsExemption(exemptions[0..], "tools/stardust")); for (exemptions) |exemption| try std.testing.expect(exemptionEnabled(exemption));}test "profiling drift rejects package roots without coverage or an exemption" { const missing_reason = [_]Empty{.{ .package = "lib/example" }}; const explained = [_]Empty{.{ .package = "lib/example", .reason = "no runtime surface" }}; try std.testing.expect(!reportPassed(.{ .packages = 1, .candidate_steps = 0, .missing = &.{}, .stale = &.{}, .empty = &missing_reason, .exemption_failures = &.{} })); try std.testing.expect(reportPassed(.{ .packages = 1, .candidate_steps = 0, .missing = &.{}, .stale = &.{}, .empty = &explained, .exemption_failures = &.{} }));}test "profiling drift rejects duplicate orphan and profiled exemptions" { var arena_state = std.heap.ArenaAllocator.init(std.testing.allocator); defer arena_state.deinit(); const declared = [_]Exemption{ .{ .package = "lib/empty", .reason = "empty" }, .{ .package = "lib/empty", .reason = "duplicate" }, .{ .package = "lib/orphan", .reason = "orphan" }, .{ .package = "lib/profiled", .reason = "profiled" }, }; const packages = [_][]const u8{ "lib/empty", "lib/profiled" }; const package_steps = [_]PackageSteps{ .{ .package = "lib/empty", .steps = &.{"test"}, .candidates = &.{} }, .{ .package = "lib/profiled", .steps = &.{"bench"}, .candidates = &.{"bench"} }, }; const failures = try checkExemptions( arena_state.allocator(), &declared, .all, &packages, &package_steps, ); try std.testing.expectEqual(@as(usize, 3), failures.len); try std.testing.expectEqual(ExemptionFailureKind.duplicate, failures[0].kind); try std.testing.expectEqualStrings("lib/empty", failures[0].package); try std.testing.expectEqual(ExemptionFailureKind.orphan, failures[1].kind); try std.testing.expectEqualStrings("lib/orphan", failures[1].package); try std.testing.expectEqual(ExemptionFailureKind.profiled, failures[2].kind); try std.testing.expectEqualStrings("lib/profiled", failures[2].package); try std.testing.expect(!reportPassed(.{ .packages = packages.len, .candidate_steps = 1, .missing = &.{}, .stale = &.{}, .empty = &.{}, .exemption_failures = failures, }));}test "profiling drift checks exemptions only for the selected package" { var arena_state = std.heap.ArenaAllocator.init(std.testing.allocator); defer arena_state.deinit(); const declared = [_]Exemption{ .{ .package = "lib/selected", .reason = "selected" }, .{ .package = "lib/other", .reason = "other" }, }; const packages = [_][]const u8{"lib/selected"}; const package_steps = [_]PackageSteps{.{ .package = "lib/selected", .steps = &.{"test"}, .candidates = &.{}, }}; const failures = try checkExemptions( arena_state.allocator(), &declared, .{ .package = "lib/selected" }, &packages, &package_steps, ); try std.testing.expectEqual(@as(usize, 0), failures.len);}test "profiling drift keys opt-in package surfaces by their build options" { var arena_state = std.heap.ArenaAllocator.init(std.testing.allocator); defer arena_state.deinit(); const arena = arena_state.allocator(); const options: []const []const u8 = &.{"-Dprofiling=true"}; const default_candidates: []const []const u8 = &.{"latency"}; const opt_in = try optInSurface(arena, "lib/tldr", options, default_candidates, \\ latency Measure default latency \\ bench Run linker benchmarks \\ bench-bin Install linker benchmarks \\ external-bench Compare external linkers \\ ); try std.testing.expectEqual(@as(usize, 2), opt_in.candidates.len); try std.testing.expectEqualStrings("bench", opt_in.candidates[0]); try std.testing.expectEqualStrings("external-bench", opt_in.candidates[1]); try std.testing.expectEqual(@as(usize, 4), opt_in.steps.len); try std.testing.expect(covered("lib/tldr", options, "bench")); try std.testing.expect(covered("lib/tldr", options, "external-bench")); try std.testing.expect(!covered("lib/tldr", &.{}, "bench")); try std.testing.expect(covered("lib/gpalloc", &.{}, "bench")); try std.testing.expect(!covered("lib/gpalloc", options, "bench")); const package_steps = [_]PackageSteps{ .{ .package = "lib/tldr", .steps = &.{"latency"}, .candidates = default_candidates }, opt_in, }; const root_steps: []const []const u8 = &.{"tldr-bench"}; try std.testing.expect(!containsStep(stepsForCwd(root_steps, &package_steps, "lib/tldr", &.{}).?, "bench-bin")); try std.testing.expect(containsStep(stepsForCwd(root_steps, &package_steps, "lib/tldr", options).?, "bench-bin")); try std.testing.expect(containsStep(stepsForCwd(root_steps, &package_steps, ".", &.{}).?, "tldr-bench")); try std.testing.expectEqual(@as(usize, 1), packageCandidates(&package_steps, "lib/tldr").?.len);}Source: src/profiling/report/root.zig:16
zig
pub const drift = @import("drift.zig");Audit
| Definitions | 10 |
|---|---|
| Public names | 10 |
| Members | 21 |
| Version | 26.7.0 |
| Revision | daab053ee433 |