tiny.profiling.report.model
Defined in report.
API (11)
Actions
Public operations.
Types and contracts
Public types and contracts.
Source
Source: src/profiling/report/model.zig
zig
const std = @import("std");const capture = @import("capture");const memtrace = @import("memtrace");const pretty = @import("pretty");const sys = @import("sys");const profiling = @import("../root.zig");const analysis = @import("root.zig").analysis;const analyze = profiling.analyze;const environment = profiling.environment;const json = profiling.json;const pretty_json = pretty.json;const fs_io = sys.fs.debugIo();const max_manifest_bytes = 16 * 1024 * 1024;pub const Manifest = struct { run_id: []const u8, started_unix_ns: i128, wall_ns: ?u64, suite: []const u8, git_sha: ?[]const u8, git_branch: ?[]const u8, git_dirty: ?bool, zig_version: ?[]const u8, optimize: ?[]const u8, host: environment.Host,};pub const Entry = struct { dir: []const u8, root: []const u8, manifest: Manifest, run: analyze.Run, recorded: ?analysis.Recorded, pub fn findWorkload(self: *const Entry, name: []const u8) ?*const analyze.Workload { for (self.run.workloads) |*workload| { if (std.mem.eql(u8, workload.name, name)) return workload; } return null; }};pub const MetricHistory = struct { key: []const u8, label: []const u8, primary: []?f64, low: []?f64, high: []?f64,};pub const MemoryHistory = struct { key: []const u8, label: []const u8, unit: []const u8, values: []?f64,};pub const WorkloadHistory = struct { name: []const u8, package: []const u8, wall: []?f64, rss: []?f64, metrics: []MetricHistory, memory: []MemoryHistory,};pub const Site = struct { runs: []Entry, histories: []WorkloadHistory, pub fn latest(self: Site) ?*const Entry { if (self.runs.len == 0) return null; return &self.runs[self.runs.len - 1]; } pub fn findHistory(self: Site, name: []const u8) ?*const WorkloadHistory { for (self.histories) |*history| { if (std.mem.eql(u8, history.name, name)) return history; } return null; }};pub fn load(allocator: std.mem.Allocator, profiling_dir: []const u8) !Site { var entries: std.ArrayList(Entry) = .empty; const listing = sys.fs.listDirAlloc(allocator, profiling_dir) catch |err| switch (err) { error.FileNotFound => return .{ .runs = &.{}, .histories = &.{} }, else => |actual| return actual, }; for (listing) |item| { if (item.kind != .directory) continue; const manifest_path = try std.fs.path.join(allocator, &.{ item.path, "manifest.json" }); if (!sys.fs.exists(manifest_path)) continue; const manifest = (try loadManifest(allocator, manifest_path, item.name)) orelse continue; const run = analyze.loadRun(allocator, item.path) catch continue; try entries.append(allocator, .{ .dir = item.name, .root = item.path, .manifest = manifest, .run = run, .recorded = try analysis.load(allocator, item.path), }); } const runs = try entries.toOwnedSlice(allocator); std.mem.sort(Entry, runs, {}, startedBefore); return .{ .runs = runs, .histories = try buildHistories(allocator, runs), };}fn startedBefore(_: void, left: Entry, right: Entry) bool { return left.manifest.started_unix_ns < right.manifest.started_unix_ns;}fn loadManifest(allocator: std.mem.Allocator, path: []const u8, dir_name: []const u8) !?Manifest { const text = sys.fs.readFileAlloc(allocator, path, max_manifest_bytes) catch |err| switch (err) { error.FileNotFound => return null, else => |actual| return actual, }; const value = std.json.parseFromSliceLeaky(std.json.Value, allocator, text, .{}) catch return null; const object = json.object(value) catch return null; const selection = if (object.get("selection")) |actual| json.object(actual) catch null else null; const environment_object = if (object.get("environment")) |actual| json.object(actual) catch null else null; const summary = if (object.get("summary")) |actual| json.object(actual) catch null else null; const git = if (environment_object) |env| (if (env.get("git")) |actual| json.object(actual) catch null else null) else null; const zig_info = if (environment_object) |env| (if (env.get("zig")) |actual| json.object(actual) catch null else null) else null; const build = if (environment_object) |env| (if (env.get("build")) |actual| json.object(actual) catch null else null) else null; return .{ .run_id = json.string(object.get("run_id")) orelse dir_name, .started_unix_ns = json.asI128(object.get("started_unix_ns")) orelse 0, .wall_ns = if (summary) |actual| json.asU64(actual.get("wall_ns")) else null, .suite = if (selection) |actual| json.string(actual.get("suite")) orelse "unknown" else "unknown", .git_sha = if (git) |actual| json.string(actual.get("commit")) else null, .git_branch = if (git) |actual| json.string(actual.get("branch")) else null, .git_dirty = if (git) |actual| json.asBool(actual.get("dirty")) else null, .zig_version = if (zig_info) |actual| json.string(actual.get("version")) else null, .optimize = if (build) |actual| json.string(actual.get("optimize")) else null, .host = profiling.environment.parse(object.get("environment")), };}fn buildHistories(allocator: std.mem.Allocator, runs: []const Entry) ![]WorkloadHistory { var names: std.StringArrayHashMapUnmanaged(void) = .empty; for (runs, 0..) |entry, run_index| { if (!compatibleWithLatest(runs, run_index)) continue; for (entry.run.workloads) |workload| try names.put(allocator, workload.name, {}); } var histories: std.ArrayList(WorkloadHistory) = .empty; for (names.keys()) |name| { try histories.append(allocator, try buildWorkloadHistory(allocator, runs, name)); } return try histories.toOwnedSlice(allocator);}fn buildWorkloadHistory(allocator: std.mem.Allocator, runs: []const Entry, name: []const u8) !WorkloadHistory { const wall = try allocator.alloc(?f64, runs.len); const rss = try allocator.alloc(?f64, runs.len); var package: []const u8 = ""; var metric_keys: std.StringArrayHashMapUnmanaged([]const u8) = .empty; var memory_keys: std.StringArrayHashMapUnmanaged(MemoryHistory) = .empty; for (runs, 0..) |entry, run_index| { wall[run_index] = null; rss[run_index] = null; if (!compatibleWithLatest(runs, run_index)) continue; const workload = entry.findWorkload(name) orelse continue; if (workload.package.len != 0) package = workload.package; if (workloadComparableWithLatest(runs, run_index, name)) { wall[run_index] = @floatFromInt(workload.wall_ns); if (workload.max_rss_kib) |value| rss[run_index] = @floatFromInt(value); } for (workload.metrics) |metric| { if (metric.primaryNs() == null) continue; if (!metric_keys.contains(metric.key)) try metric_keys.put(allocator, metric.key, metric.label); } for (workload.memory_metrics) |metric| { if (!memory_keys.contains(metric.key)) { try memory_keys.put(allocator, metric.key, .{ .key = metric.key, .label = metric.label, .unit = metric.unit.name(), .values = &.{}, }); } } } var metrics: std.ArrayList(MetricHistory) = .empty; var key_iterator = metric_keys.iterator(); while (key_iterator.next()) |pair| { const primary = try allocator.alloc(?f64, runs.len); const low = try allocator.alloc(?f64, runs.len); const high = try allocator.alloc(?f64, runs.len); for (runs, 0..) |entry, run_index| { primary[run_index] = null; low[run_index] = null; high[run_index] = null; if (!compatibleWithLatest(runs, run_index)) continue; const workload = entry.findWorkload(name) orelse continue; for (workload.metrics) |metric| { if (!std.mem.eql(u8, metric.key, pair.key_ptr.*)) continue; primary[run_index] = metric.primaryNs(); if (metric.primaryInterval()) |interval| { low[run_index] = interval.low_ns; high[run_index] = interval.high_ns; } break; } } try metrics.append(allocator, .{ .key = pair.key_ptr.*, .label = pair.value_ptr.*, .primary = primary, .low = low, .high = high, }); } var memory: std.ArrayList(MemoryHistory) = .empty; var memory_iterator = memory_keys.iterator(); while (memory_iterator.next()) |pair| { const values = try allocator.alloc(?f64, runs.len); for (runs, 0..) |entry, run_index| { values[run_index] = null; if (!compatibleWithLatest(runs, run_index)) continue; const workload = entry.findWorkload(name) orelse continue; for (workload.memory_metrics) |metric| { if (!std.mem.eql(u8, metric.key, pair.key_ptr.*)) continue; values[run_index] = metric.value; break; } } var history = pair.value_ptr.*; history.values = values; try memory.append(allocator, history); } return .{ .name = name, .package = package, .wall = wall, .rss = rss, .metrics = try metrics.toOwnedSlice(allocator), .memory = try memory.toOwnedSlice(allocator), };}fn compatibleWithLatest(runs: []const Entry, run_index: usize) bool { if (runs.len == 0) return false; std.debug.assert(run_index < runs.len); return analyze.comparisonSupport(runs[run_index].run, runs[runs.len - 1].run) == .supported;}fn workloadComparableWithLatest( runs: []const Entry, run_index: usize, name: []const u8,) bool { if (runs.len == 0 or !compatibleWithLatest(runs, run_index)) return false; const workload = runs[run_index].findWorkload(name) orelse return false; const latest = runs[runs.len - 1].findWorkload(name) orelse return false; return analyze.workloadComparisonSupport(workload.*, latest.*) == .supported;}fn writeFixtureSymbolSummary( allocator: std.mem.Allocator, workload_dir: []const u8, quality: ?capture.stackcollapse.Summary,) !void { const symbols_path = try std.fs.path.join( allocator, &.{ workload_dir, "perf.symbols.summary.json" }, ); try capture.perfreport.writeSymbolSummaryFile(symbols_path, .{ .source_path = "perf.symbols.tsv", .total_lost_samples = 0, .sample_count_text = "10", .sample_count_approx = 10, .call_graph = "fp", .sampling_frequency_hz = 99, .minimum_sample_count = 400, .report_percent_limit = 0.5, .maximum_two_sigma_share_half_width_percentage_points = 31.622776601683793, .callchain_quality = quality, .event = "cycles:P", .event_count_approx = 1000, .rows = &.{.{ .overhead_percent = 12.25, .samples = 2, .symbol = "[.] alloc.refill", .shared_object = "gpalloc-bench", .ipc = null, .ipc_coverage_percent = null, }}, });}fn writeFixtureResults( allocator: std.mem.Allocator, root: []const u8, workload_dir: []const u8, run_id: []const u8, started_unix_ns: i128, wall_ns: u64, hostname: []const u8, has_captures: bool,) !void { const results_path = try std.fs.path.join(allocator, &.{ root, "results.jsonl" }); const finished_unix_ns = started_unix_ns + wall_ns; const empty_strings: []const []const u8 = &.{}; const command_argv: []const []const u8 = &.{ "zig", "build", "gpalloc-bench" }; var file = try sys.fs.cwd().createFile(fs_io, results_path, .{ .truncate = true }); defer file.close(fs_io); var buffer: [8192]u8 = undefined; var file_writer = file.writer(fs_io, &buffer); const writer = &file_writer.interface; { var json_writer = pretty_json.Writer.init(writer, .minified); const row = try json_writer.object(); try row.fields(.{ .schema = "tiny.profiling.run/v1", .event = "run_start", .run_id = run_id, .started_unix_ns = started_unix_ns, }); try row.field("selection", .{ .suite = "smoke", .filters = empty_strings, .workload_count = @as(u8, 1), }); try row.field("environment", .{ .build = .{ .optimize = "ReleaseFast" }, .host = .{ .hostname = hostname, .os = "linux", .kernel = "7.0.11", .arch = "x86_64", .cpu_model = "AMD Ryzen 7 7800X3D", .cpu_count = @as(u8, 16), .cpu_frequency_policy = "policy-a", .process_cpu_affinity = "0-15", .process_memory_affinity = "0", }, }); try row.field("artifacts", .{ .root = root, .results = "results.jsonl", .manifest = "manifest.json", }); try row.endLine(); } { var json_writer = pretty_json.Writer.init(writer, .minified); const row = try json_writer.object(); try row.fields(.{ .schema = profiling.record.workload_schema, .event = "workload", .run_id = run_id, .index = @as(u8, 0), }); try row.field("acquisition", .{ .position = @as(u8, 1), .workload_count = @as(u8, 1), .predecessors = empty_strings, }); try row.field("workload", .{ .name = "gpalloc.allocator", .package = "lib/gpalloc", .step = "gpalloc-bench", .surface = "benchmark", }); try row.fields(.{ .scope = "whole-step", .causal = false, .tracy = false, .trace_allocations = false, }); try row.field("command", .{ .text = "zig build gpalloc-bench", .cwd = @as(?[]const u8, null), .argv = command_argv, }); try row.field("status", .{ .state = "passed", .exit_code = @as(u8, 0), }); try row.field("timing", .{ .started_unix_ns = started_unix_ns, .finished_unix_ns = finished_unix_ns, .wall_ns = wall_ns, }); try row.field("resources", .{ .resource_usage_source = "wait4_rusage", .max_rss_kib = @as(u32, 49_836), .user_s = @as(f64, 0.3), .system_s = @as(f64, 0.4), .minor_page_faults = @as(u8, 96), .major_page_faults = @as(u8, 0), .voluntary_context_switches = @as(u8, 2), .involuntary_context_switches = @as(u8, 1), }); const measurement_row = try row.object("measurement"); try measurement_row.fields(.{ .execution_count = @as(u8, 1), .acquisition_order = "fixed_plan_order", .workload_output_retention = "all_measured_executions", .measured_artifact_layout = "workload_root", .allocation_summary_retention = "disabled", }); try measurement_row.field("benchmark_process_domain", .{ .benchmark_surface = true, .direct_execution = false, .host_profiler = has_captures, .tracy = false, .causal = false, .allocation_trace = false, .capture_control = false, }); try measurement_row.field("benchmark_process_reduction", .{ .schema = profiling.reduction.schema, .state = "not_applicable", .process_count = @as(u8, 1), .reason = "outside_direct_benchmark_domain", }); const executions = try measurement_row.array("executions"); const execution = try executions.object(); try execution.fields(.{ .index = @as(u8, 1), .spawn_state = "spawned", .pid = @as(u16, 101), .exit_code = @as(u8, 0), .wall_ns = wall_ns, }); const artifacts = try execution.object("artifacts"); try artifacts.field("root", workload_dir); inline for (.{ .{ "stdout", "/stdout.txt" }, .{ "stderr", "/stderr.txt" }, .{ "bench_jsonl", "/bench.jsonl" }, .{ "coz_jsonl", "/bench.coz.jsonl" }, .{ "coz_analysis", "/bench.coz.analysis.json" }, .{ "tracy_jsonl", "/bench.tracy.jsonl" }, .{ "tracy_summary", "/bench.tracy.summary.jsonl" }, }) |field| { try artifacts.stringParts(field[0], &.{ workload_dir, field[1] }); } try artifacts.stringParts( "structured", &.{ workload_dir, "/structured.jsonl" }, ); try artifacts.stringParts( "allocations", &.{ workload_dir, "/allocations.jsonl" }, ); try artifacts.fields(.{ .structured_rows = @as(u8, 2), .structured_parse_errors = @as(u8, 0), }); try artifacts.end(); try execution.end(); try executions.end(); try measurement_row.end(); const workload_artifacts = try row.object("artifacts"); try workload_artifacts.field("root", workload_dir); try workload_artifacts.end(); const captures = try row.array("captures"); if (has_captures) { const perf = try captures.object(); try perf.fields(.{ .kind = "perf_record", .tool = "perf", .scope = "whole-step", }); try perf.stringParts("capture", &.{ workload_dir, "/perf.data" }); try perf.stringParts( "summary", &.{ workload_dir, "/perf.symbols.summary.json" }, ); try perf.field("state", "summary_written"); try perf.end(); const offcpu = try captures.object(); try offcpu.fields(.{ .kind = "offcpu_time", .tool = "offcputime-bpfcc", .scope = "workload-binary", }); try offcpu.stringParts( "capture", &.{ workload_dir, "/offcpu.time.txt" }, ); try offcpu.stringParts( "summary", &.{ workload_dir, "/offcpu.summary.json" }, ); try offcpu.field("state", "summary_written"); try offcpu.end(); } try captures.end(); try row.endLine(); } { var json_writer = pretty_json.Writer.init(writer, .minified); const row = try json_writer.object(); try row.fields(.{ .schema = "tiny.profiling.run/v1", .event = "run_end", .run_id = run_id, .started_unix_ns = started_unix_ns, }); try row.field("summary", .{ .selected = @as(u8, 1), .ran = @as(u8, 1), .passed = @as(u8, 1), .failed = @as(u8, 0), .stopped_early = false, .exit_code = @as(u8, 0), .started_unix_ns = started_unix_ns, .finished_unix_ns = finished_unix_ns, .wall_ns = wall_ns, }); try row.endLine(); } try writer.flush();}fn writeFixtureCaptureArtifacts( allocator: std.mem.Allocator, workload_dir: []const u8, folded_text: []const u8, callchain_quality: ?capture.stackcollapse.Summary,) !void { const folded_path = try std.fs.path.join( allocator, &.{ workload_dir, "perf.folded.txt" }, ); try sys.fs.writeFile(folded_path, folded_text); try writeFixtureSymbolSummary(allocator, workload_dir, callchain_quality); const children_path = try std.fs.path.join( allocator, &.{ workload_dir, "perf.children.summary.json" }, ); const children_rows = [_]capture.perfreport.ChildrenRow{.{ .children_overhead_percent = 88.5, .self_overhead_percent = 12.25, .samples = 9, .symbol = "[.] alloc.refill", .shared_object = "gpalloc-bench", .ipc = null, .ipc_coverage_percent = null, }}; try capture.perfreport.writeChildrenSummaryFile(children_path, .{ .source_path = "perf.children.tsv", .total_lost_samples = 0, .sample_count_text = "10", .sample_count_approx = 10, .event = "cycles:P", .event_count_approx = 1000, .rows = &children_rows, }); const allocations_path = try std.fs.path.join( allocator, &.{ workload_dir, "allocations.jsonl" }, ); var allocations_file = try sys.fs.cwd().createFile( fs_io, allocations_path, .{ .truncate = true }, ); defer allocations_file.close(fs_io); var allocations_buffer: [8192]u8 = undefined; var allocations_writer = allocations_file.writer(fs_io, &allocations_buffer); const trace_rows = [_]struct { event: memtrace.Event, scope: ?[]const u8 = null, }{ .{ .event = .{ .seq = 1, .kind = .trace_start } }, .{ .event = .{ .seq = 2, .kind = .allocator, .allocator_id = 1, .retains_freed_memory = true, } }, .{ .event = .{ .seq = 3, .kind = .alloc, .allocator_id = 1, .allocation_id = 1, .address = 128, .len = 4096, .return_address = 2748, }, .scope = "root/refill", }, .{ .event = .{ .seq = 4, .kind = .alloc, .allocator_id = 1, .allocation_id = 2, .address = 8320, .len = 1024, .return_address = 2749, }, .scope = "root/free", }, .{ .event = .{ .seq = 5, .kind = .free, .allocator_id = 1, .allocation_id = 2, .address = 8320, .len = 1024, .return_address = 2749, }, .scope = "root/free", }, .{ .event = .{ .seq = 6, .kind = .trace_stop } }, }; for (trace_rows) |row| { try row.event.writeJsonLine(&allocations_writer.interface, null, row.scope); } try allocations_writer.interface.flush(); const srcline_path = try std.fs.path.join( allocator, &.{ workload_dir, "perf.srcline.summary.json" }, ); const srcline_rows = [_]capture.perfreport.SrclineRow{.{ .overhead_percent = 12.25, .samples = 2, .source_line = "heap.zig:212", .symbol = "[.] alloc.refill", .shared_object = "gpalloc-bench", .ipc = null, .ipc_coverage_percent = null, }}; try capture.perfreport.writeSrclineSummaryFile(srcline_path, .{ .source_path = "perf.srcline.tsv", .total_lost_samples = 0, .sample_count_text = "10", .sample_count_approx = 10, .event = "cycles:P", .event_count_approx = 1000, .rows = &srcline_rows, }); const offcpu_path = try std.fs.path.join( allocator, &.{ workload_dir, "offcpu.summary.json" }, ); const blocked_frames: []const []const u8 = &.{ "futex_wait", "do_futex" }; const blocked_rows = [_]capture.offcpu.BlockedRow{.{ .key = "a", .source = "offcputime", .subclass = "synchronization", .task = "gpalloc-bench", .stack_kind = "folded", .weight = 9000, .weight_unit = "nanoseconds", .duration_ns = 9000, .count = null, .frames = blocked_frames, }}; try capture.offcpu.writeBlockedSummaryFile(offcpu_path, .{ .source_path = "offcpu.time.txt", .source = "offcputime", .weight_unit = "nanoseconds", .total_weight = 9000, .total_duration_ns = 9000, .total_count = null, .rows = &blocked_rows, });}fn writeFixtureManifest( allocator: std.mem.Allocator, root: []const u8, run_id: []const u8, started_unix_ns: i128, wall_ns: u64, hostname: []const u8,) !void { const manifest_path = try std.fs.path.join( allocator, &.{ root, "manifest.json" }, ); const finished_unix_ns = started_unix_ns + wall_ns; const empty_strings: []const []const u8 = &.{}; var file = try sys.fs.cwd().createFile(fs_io, manifest_path, .{ .truncate = true }); defer file.close(fs_io); var buffer: [8192]u8 = undefined; var file_writer = file.writer(fs_io, &buffer); const writer = &file_writer.interface; var json_writer = pretty_json.Writer.init(writer, .minified); const document = try json_writer.object(); try document.fields(.{ .schema = "tiny.profiling.run/v1", .event = "manifest", .run_id = run_id, .started_unix_ns = started_unix_ns, }); try document.field("selection", .{ .suite = "smoke", .filters = empty_strings, .workload_count = @as(u8, 1), }); try document.field("environment", .{ .git = .{ .commit = "abcdef123456", .branch = "main", .dirty = false, }, .zig = .{ .version = "0.16.0" }, .build = .{ .optimize = "ReleaseFast" }, .host = .{ .hostname = hostname, .os = "linux", .kernel = "7.0.11", .arch = "x86_64", .cpu_model = "AMD Ryzen 7 7800X3D", .cpu_count = @as(u8, 16), .cpu_frequency_policy = "policy-a", .process_cpu_affinity = "0-15", .process_memory_affinity = "0", }, }); try document.field("summary", .{ .selected = @as(u8, 1), .ran = @as(u8, 1), .passed = @as(u8, 1), .failed = @as(u8, 0), .stopped_early = false, .exit_code = @as(u8, 0), .started_unix_ns = started_unix_ns, .finished_unix_ns = finished_unix_ns, .wall_ns = wall_ns, }); const artifacts = try document.object("artifacts"); try artifacts.field("root", root); try artifacts.stringParts("results", &.{ root, "/results.jsonl" }); try artifacts.stringParts("manifest", &.{ root, "/manifest.json" }); try artifacts.stringParts("workloads", &.{ root, "/workloads" }); try artifacts.end(); try document.end(); try writer.flush();}fn writeFixtureStructured( allocator: std.mem.Allocator, workload_dir: []const u8, median_ns: u64,) !void { const structured_path = try std.fs.path.join( allocator, &.{ workload_dir, "structured.jsonl" }, ); var file = try sys.fs.cwd().createFile(fs_io, structured_path, .{ .truncate = true }); defer file.close(fs_io); var buffer: [8192]u8 = undefined; var file_writer = file.writer(fs_io, &buffer); const writer = &file_writer.interface; try pretty_json.writeMinifiedLine(writer, .{ .schema = "tiny.profiling.structured/v1", .workload = .{ .name = "gpalloc.allocator", .package = "lib/gpalloc", .step = "gpalloc-bench", }, .source = .{ .kind = "bench_jsonl", .path = "x", .line = @as(u8, 1), }, .row = .{ .schema = "tiny.profiling.metric/v1", .family = "timing", .unit = "ns", .id = "alloc-free", .name = "alloc-free", .median_ns = median_ns, .sample_count = @as(u8, 10), .confidence_intervals = .{ .median_ns = .{ .low_ns = median_ns - 5, .high_ns = median_ns + 5, }, }, }, }); try pretty_json.writeMinifiedLine(writer, .{ .schema = "tiny.profiling.structured/v1", .workload = .{ .name = "gpalloc.allocator", .package = "lib/gpalloc", .step = "gpalloc-bench", }, .source = .{ .kind = "bench_jsonl", .path = "x", .line = @as(u8, 2), }, .row = .{ .schema = "tiny.profiling.metric/v1", .family = "memory", .unit = "bytes", .metric = "allocated_bytes", .name = "allocated_bytes", .value = @as(u64, 4096), }, }); try writer.flush();}fn writeFixtureRun( allocator: std.mem.Allocator, profiling_dir: []const u8, run_id: []const u8, started_unix_ns: i128, wall_ns: u64, median_ns: u64, hostname: []const u8, folded: ?[]const u8, callchain_quality: ?capture.stackcollapse.Summary,) !void { const root = try std.fs.path.join(allocator, &.{ profiling_dir, run_id }); const workload_dir = try std.fs.path.join(allocator, &.{ root, "workloads", "gpalloc.allocator" }); try sys.fs.createDirPath(workload_dir); if (folded) |folded_text| { try writeFixtureCaptureArtifacts( allocator, workload_dir, folded_text, callchain_quality, ); } try writeFixtureManifest( allocator, root, run_id, started_unix_ns, wall_ns, hostname, ); try writeFixtureStructured(allocator, workload_dir, median_ns); try writeFixtureResults( allocator, root, workload_dir, run_id, started_unix_ns, wall_ns, hostname, folded != null, );}pub fn writeTestFixture(allocator: std.mem.Allocator, profiling_dir: []const u8) !void { const baseline_folded = \\gpalloc-bench;main;alloc;refill 5 \\gpalloc-bench;main;free 5 \\ ; const baseline_quality: capture.stackcollapse.Summary = .{ .sample_count = 10, .unique_callchain_count = 2, .weighted_frame_count = 25, .resolved_frame_count = 25, .maximum_depth_frames = 3, }; try writeFixtureRun( allocator, profiling_dir, "run-100-aaa", 100_000, 60_000_000, 1_000, "bench-a", baseline_folded, baseline_quality, ); const candidate_folded = \\gpalloc-bench;main;[unknown];alloc;refill 6 \\gpalloc-bench;main;alloc 3 \\gpalloc-bench;main;free 1 \\ ; const candidate_quality: capture.stackcollapse.Summary = .{ .sample_count = 10, .unique_callchain_count = 3, .weighted_frame_count = 32, .resolved_frame_count = 26, .unresolved_frame_count = 6, .samples_with_unresolved_frames = 6, .maximum_depth_frames = 4, }; try writeFixtureRun( allocator, profiling_dir, "run-200-bbb", 200_000, 66_000_000, 1_200, "bench-a", candidate_folded, candidate_quality, );}test "model loads runs chronologically and builds histories" { var arena_state = std.heap.ArenaAllocator.init(std.testing.allocator); defer arena_state.deinit(); const allocator = arena_state.allocator(); const profiling_dir = ".zig-cache/profile-web-model-test"; defer sys.fs.deleteTree(profiling_dir) catch {}; try writeTestFixture(allocator, profiling_dir); const site = try load(allocator, profiling_dir); try std.testing.expectEqual(@as(usize, 2), site.runs.len); try std.testing.expectEqualStrings("run-100-aaa", site.runs[0].manifest.run_id); try std.testing.expectEqualStrings("run-200-bbb", site.runs[1].manifest.run_id); try std.testing.expectEqualStrings("smoke", site.runs[0].manifest.suite); try std.testing.expectEqual(@as(u64, 60_000_000), site.runs[0].manifest.wall_ns.?); try std.testing.expectEqualStrings("bench-a", site.runs[0].manifest.host.hostname.?); try std.testing.expectEqualStrings("policy-a", site.runs[0].manifest.host.cpu_frequency_policy.?); try std.testing.expectEqualStrings("run-200-bbb", site.latest().?.manifest.run_id); try std.testing.expectEqual(@as(usize, 1), site.histories.len); const history = site.findHistory("gpalloc.allocator").?; try std.testing.expectEqualStrings("lib/gpalloc", history.package); try std.testing.expectEqual(@as(usize, 2), history.wall.len); try std.testing.expectEqual(@as(f64, 60_000_000), history.wall[0].?); try std.testing.expectEqual(@as(f64, 66_000_000), history.wall[1].?); try std.testing.expectEqual(@as(usize, 1), history.metrics.len); try std.testing.expectEqual(@as(f64, 1_000), history.metrics[0].primary[0].?); try std.testing.expectEqual(@as(f64, 1_200), history.metrics[0].primary[1].?); try std.testing.expectEqual(@as(f64, 1_205), history.metrics[0].high[1].?); try std.testing.expectEqual(@as(usize, 1), history.memory.len); try std.testing.expectEqual(@as(f64, 4096), history.memory[0].values[1].?); try std.testing.expectEqual(@as(usize, 2), site.runs[0].run.workloads[0].captures.len); try std.testing.expectEqual(@as(usize, 2), site.runs[1].run.workloads[0].captures.len); try std.testing.expectEqualStrings("perf_record", site.runs[1].run.workloads[0].captures[0].kind); try std.testing.expectEqual( @as(usize, 1), site.runs[1].run.workloads[0].acquisition.blocked.position, );}test "model fixture JSON escapes dynamic host strings" { var arena_state = std.heap.ArenaAllocator.init(std.testing.allocator); defer arena_state.deinit(); const allocator = arena_state.allocator(); const profiling_dir = ".zig-cache/profile-web-model-json-escaping-test"; defer sys.fs.deleteTree(profiling_dir) catch {}; try writeFixtureRun( allocator, profiling_dir, "run-escaped", 100_000, 60_000_000, 1_000, "bench\"line\nhost", null, null, ); const site = try load(allocator, profiling_dir); try std.testing.expectEqualStrings( "bench\"line\nhost", site.runs[0].manifest.host.hostname.?, ); try std.testing.expectEqualStrings( "bench\"line\nhost", site.runs[0].run.host.hostname.?, );}test "model retains the process placement envelope" { var arena_state = std.heap.ArenaAllocator.init(std.testing.allocator); defer arena_state.deinit(); const allocator = arena_state.allocator(); const profiling_dir = ".zig-cache/profile-web-model-placement-test"; defer sys.fs.deleteTree(profiling_dir) catch {}; try writeTestFixture(allocator, profiling_dir); const site = try load(allocator, profiling_dir); const host = site.runs[0].manifest.host; try std.testing.expectEqualStrings("0-15", host.process_cpu_affinity.?); try std.testing.expectEqualStrings("0", host.process_memory_affinity.?);}test "model leaves acquisition-context wall history gaps" { const host_value = environment.Host{ .hostname = "bench-a", .os = "linux", .kernel = "7.0.11", .arch = "x86_64", .cpu_model = "CPU", .cpu_count = 8, .cpu_frequency_policy = "policy-a", .process_cpu_affinity = "0-7", .process_memory_affinity = "0", }; const base_workloads = [_]analyze.Workload{.{ .name = "target", .package = "p", .step = "bench", .acquisition = .{ .blocked = .{ .position = 2, .workload_count = 2, .predecessors = &.{"a"}, } }, .status = "passed", .exit_code = 0, .wall_ns = 10, .max_rss_kib = null, .user_s = null, .system_s = null, .result_path = null, }}; const candidate_workloads = [_]analyze.Workload{.{ .name = "target", .package = "p", .step = "bench", .acquisition = .{ .blocked = .{ .position = 2, .workload_count = 2, .predecessors = &.{"b"}, } }, .status = "passed", .exit_code = 0, .wall_ns = 20, .max_rss_kib = null, .user_s = null, .system_s = null, .result_path = null, }}; const entries = [_]Entry{ .{ .dir = "base", .root = "base", .manifest = .{ .run_id = "base", .started_unix_ns = 1, .wall_ns = 1, .suite = "smoke", .git_sha = null, .git_branch = null, .git_dirty = null, .zig_version = null, .optimize = "ReleaseFast", .host = host_value, }, .run = .{ .ref = .{ .run_id = "base", .root = "base", .manifest_path = "base/manifest.json", .results_path = "base/results.jsonl", }, .optimize = "ReleaseFast", .host = host_value, .workloads = &base_workloads, }, .recorded = null, }, .{ .dir = "candidate", .root = "candidate", .manifest = .{ .run_id = "candidate", .started_unix_ns = 2, .wall_ns = 1, .suite = "smoke", .git_sha = null, .git_branch = null, .git_dirty = null, .zig_version = null, .optimize = "ReleaseFast", .host = host_value, }, .run = .{ .ref = .{ .run_id = "candidate", .root = "candidate", .manifest_path = "candidate/manifest.json", .results_path = "candidate/results.jsonl", }, .optimize = "ReleaseFast", .host = host_value, .workloads = &candidate_workloads, }, .recorded = null, }, }; try std.testing.expect(!workloadComparableWithLatest(&entries, 0, "target")); try std.testing.expect(workloadComparableWithLatest(&entries, 1, "target"));}test "model leaves incompatible host runs as trend gaps" { var arena_state = std.heap.ArenaAllocator.init(std.testing.allocator); defer arena_state.deinit(); const allocator = arena_state.allocator(); const profiling_dir = ".zig-cache/profile-web-host-cohort-test"; defer sys.fs.deleteTree(profiling_dir) catch {}; try writeFixtureRun( allocator, profiling_dir, "run-100-aaa", 100_000, 60_000_000, 1_000, "bench-a", null, null, ); try writeFixtureRun( allocator, profiling_dir, "run-200-bbb", 200_000, 66_000_000, 1_200, "bench-b", null, null, ); const site = try load(allocator, profiling_dir); const history = site.findHistory("gpalloc.allocator").?; try std.testing.expectEqual(@as(?f64, null), history.wall[0]); try std.testing.expectEqual(@as(f64, 66_000_000), history.wall[1].?); try std.testing.expectEqual(@as(?f64, null), history.metrics[0].primary[0]); try std.testing.expectEqual(@as(f64, 1_200), history.metrics[0].primary[1].?);}test "model tolerates a missing profiling directory" { var arena_state = std.heap.ArenaAllocator.init(std.testing.allocator); defer arena_state.deinit(); const allocator = arena_state.allocator(); const site = try load(allocator, ".zig-cache/profile-web-does-not-exist"); try std.testing.expectEqual(@as(usize, 0), site.runs.len); try std.testing.expectEqual(@as(usize, 0), site.histories.len);}Source: src/profiling/report/root.zig:5
zig
pub const model = @import("model.zig");Complete caller list for report.model.load
12 direct callers.
src.profiling.report.flame.test_flame_differential_baseline_requires_compatible_host_context[function] — test; no exact target atsrc/profiling/report/flame.zig:614in nearest public ownertiny.profiling.report.flamesrc.profiling.report.model.test_model_fixture_JSON_escapes_dynamic_host_strings[function] — test; no exact target atsrc/profiling/report/model.zig:978in nearest public ownertiny.profiling.report.modelsrc.profiling.report.model.test_model_leaves_incompatible_host_runs_as_trend_gaps[function] — test; no exact target atsrc/profiling/report/model.zig:1127in nearest public ownertiny.profiling.report.modelsrc.profiling.report.model.test_model_loads_runs_chronologically_and_builds_histories[function] — test; no exact target atsrc/profiling/report/model.zig:939in nearest public ownertiny.profiling.report.modelsrc.profiling.report.model.test_model_retains_the_process_placement_envelope[function] — test; no exact target atsrc/profiling/report/model.zig:1006in nearest public ownertiny.profiling.report.modelsrc.profiling.report.model.test_model_tolerates_a_missing_profiling_directory[function] — test; no exact target atsrc/profiling/report/model.zig:1164in nearest public ownertiny.profiling.report.modelsrc.profiling.report.page.test_page_index_renders_lede_trends_and_runs[function] — test; no exact target atsrc/profiling/report/page.zig:2466in nearest public ownertiny.profiling.report.pagesrc.profiling.report.page.test_page_renders_energy_and_power_shifts_with_repetition_ranges[function] — test; no exact target atsrc/profiling/report/page.zig:2559in nearest public ownertiny.profiling.report.pagesrc.profiling.report.page.test_page_renders_exact_skipped_acquisition_contexts[function] — test; no exact target atsrc/profiling/report/page.zig:2520in nearest public ownertiny.profiling.report.pagesrc.profiling.report.page.test_page_renders_unsupported_outer_comparisons_without_a_regression_verdict[function] — test; no exact target atsrc/profiling/report/page.zig:2483in nearest public ownertiny.profiling.report.pagesrc.profiling.report.page.test_page_run_and_workload_render_tables[function] — test; no exact target atsrc/profiling/report/page.zig:3091in nearest public ownertiny.profiling.report.pagetiny.profiling.report.site.generate[function] atsrc/profiling/report/site.zig:133
Complete caller list for report.model.writeTestFixture
10 direct callers.
src.profiling.report.flame.test_flame_differential_baseline_requires_compatible_host_context[function] — test; no exact target atsrc/profiling/report/flame.zig:614in nearest public ownertiny.profiling.report.flamesrc.profiling.report.model.test_model_loads_runs_chronologically_and_builds_histories[function] — test; no exact target atsrc/profiling/report/model.zig:939in nearest public ownertiny.profiling.report.modelsrc.profiling.report.model.test_model_retains_the_process_placement_envelope[function] — test; no exact target atsrc/profiling/report/model.zig:1006in nearest public ownertiny.profiling.report.modelsrc.profiling.report.page.test_page_index_renders_lede_trends_and_runs[function] — test; no exact target atsrc/profiling/report/page.zig:2466in nearest public ownertiny.profiling.report.pagesrc.profiling.report.page.test_page_renders_energy_and_power_shifts_with_repetition_ranges[function] — test; no exact target atsrc/profiling/report/page.zig:2559in nearest public ownertiny.profiling.report.pagesrc.profiling.report.page.test_page_renders_exact_skipped_acquisition_contexts[function] — test; no exact target atsrc/profiling/report/page.zig:2520in nearest public ownertiny.profiling.report.pagesrc.profiling.report.page.test_page_renders_unsupported_outer_comparisons_without_a_regression_verdict[function] — test; no exact target atsrc/profiling/report/page.zig:2483in nearest public ownertiny.profiling.report.pagesrc.profiling.report.page.test_page_run_and_workload_render_tables[function] — test; no exact target atsrc/profiling/report/page.zig:3091in nearest public ownertiny.profiling.report.pagesrc.profiling.report.serve.test_serve_regenerates_and_serves_the_site_over_http[function] — test; no exact target atsrc/profiling/report/serve.zig:195in nearest public ownertiny.profiling.report.servesrc.profiling.report.site.test_site_generates_a_navigable_static_tree[function] — test; no exact target atsrc/profiling/report/site.zig:243in nearest public ownertiny.profiling.report.site
Audit
| Definitions | 12 |
|---|---|
| Public names | 12 |
| Members | 32 |
| Version | 26.7.0 |
| Revision | daab053ee433 |