tiny.profiling.host.counters
Defined in host.
API (14)
Actions
Public operations.
Types and contracts
Public types and contracts.
Values and defaults
Public values and defaults.
Source
Source: src/profiling/host/counters.zig
zig
const std = @import("std");const capture = @import("capture");const sys = @import("sys");const root = @import("root.zig");pub const tool = "perf";pub const kind = "perf_stat";pub const default_events = "page-faults,{cycles,instructions,task-clock},{branches,branch-misses}";pub const energy_events = "duration_time,power/energy-pkg/";pub const default_repeat: u32 = 3;pub const max_group_size: u32 = 100;const max_capture_bytes = 64 * 1024 * 1024;pub const Options = struct { events: []const u8 = default_events, repeat: u32 = default_repeat, group_size: u32 = 0, system_wide: bool = false, pub fn validate(self: Options) !void { if (std.mem.trim(u8, self.events, " \t\r\n").len == 0) return error.InvalidCounterEvents; if (!root.process.validRepeat(self.repeat)) return error.InvalidCounterRepeat; if (self.group_size > max_group_size) return error.InvalidCounterGroupSize; }};pub const Run = struct { group_index: u32, repetition_index: u32, events: []const u8, csv_path: []const u8,};pub const Lane = struct { csv_path: []const u8, summary_path: []const u8, event_groups: []const capture.perfstat.EventGroup, event_expression: []const u8, kernel_event_groups: []const capture.perfstat.KernelEventGroup, runs: []const Run, repetition_csv_paths: []const []const u8, system_wide: bool,};pub fn plan(allocator: std.mem.Allocator, options: Options, workload_root: []const u8) !Lane { try options.validate(); const csv_path = try std.fs.path.join(allocator, &.{ workload_root, "perf.stat.csv" }); const event_expression = try capture.perfstat.normalizeEventExpression( allocator, options.events, ); const groups = try capture.perfstat.eventGroups( allocator, event_expression, options.group_size, ); const grouped = groups.len > 1; const repeated = options.repeat > 1; const runs = try planRuns(allocator, options, workload_root, groups); const repetition_csv_paths = try planRepetitionCsvPaths( allocator, workload_root, runs, options.repeat, grouped, repeated, ); try attachGroupCsvPaths( allocator, workload_root, csv_path, groups, runs, grouped, repeated, ); return .{ .csv_path = csv_path, .summary_path = try std.fs.path.join( allocator, &.{ workload_root, "perf.stat.summary.json" }, ), .event_groups = groups, .event_expression = event_expression, .kernel_event_groups = try capture.perfstat.kernelEventGroups( allocator, event_expression, ), .runs = runs, .repetition_csv_paths = repetition_csv_paths, .system_wide = options.system_wide, };}fn planRuns( allocator: std.mem.Allocator, options: Options, workload_root: []const u8, groups: []const capture.perfstat.EventGroup,) ![]const Run { const execution_count = std.math.mul( usize, groups.len, @as(usize, options.repeat), ) catch return error.TooManyCounterExecutions; if (execution_count > root.process.max_executions) return error.TooManyCounterExecutions; const grouped = groups.len > 1; const repeated = options.repeat > 1; const runs = try allocator.alloc(Run, execution_count); var run_index: usize = 0; for (0..options.repeat) |repetition_index| { for (groups) |group| { const name = try runCsvName( allocator, grouped, repeated, group.index, @intCast(repetition_index + 1), ); runs[run_index] = .{ .group_index = group.index, .repetition_index = @intCast(repetition_index + 1), .events = group.events, .csv_path = try std.fs.path.join(allocator, &.{ workload_root, name }), }; run_index += 1; } } return runs;}fn planRepetitionCsvPaths( allocator: std.mem.Allocator, workload_root: []const u8, runs: []const Run, repeat: u32, grouped: bool, repeated: bool,) ![]const []const u8 { const repetition_csv_paths = try allocator.alloc( []const u8, if (repeated) repeat else 0, ); for (repetition_csv_paths, 0..) |*csv_path, repetition_index| { if (grouped) { const name = try std.fmt.allocPrint( allocator, "perf.stat.repeat.{d}.csv", .{repetition_index + 1}, ); csv_path.* = try std.fs.path.join(allocator, &.{ workload_root, name }); } else { csv_path.* = runs[repetition_index].csv_path; } } return repetition_csv_paths;}fn attachGroupCsvPaths( allocator: std.mem.Allocator, workload_root: []const u8, csv_path: []const u8, groups: []capture.perfstat.EventGroup, runs: []const Run, grouped: bool, repeated: bool,) !void { for (groups, 0..) |*group, group_index| { if (!grouped) { group.csv_path = csv_path; } else if (!repeated) { group.csv_path = runs[group_index].csv_path; } else { const name = try std.fmt.allocPrint( allocator, "perf.stat.group.{d}.csv", .{group.index}, ); group.csv_path = try std.fs.path.join(allocator, &.{ workload_root, name }); } }}fn runCsvName( allocator: std.mem.Allocator, grouped: bool, repeated: bool, group_index: u32, repetition_index: u32,) ![]const u8 { if (grouped and repeated) return try std.fmt.allocPrint( allocator, "perf.stat.group.{d}.repeat.{d}.csv", .{ group_index, repetition_index }, ); if (grouped) return try std.fmt.allocPrint( allocator, "perf.stat.group.{d}.csv", .{group_index}, ); if (repeated) return try std.fmt.allocPrint( allocator, "perf.stat.repeat.{d}.csv", .{repetition_index}, ); return "perf.stat.csv";}pub fn wrapArgv(allocator: std.mem.Allocator, options: Options, argv: []const []const u8, lane: Lane) ![]const []const u8 { return try wrapRunArgv(allocator, options, argv, lane, 0);}pub fn wrapRunArgv( allocator: std.mem.Allocator, options: Options, argv: []const []const u8, lane: Lane, run_index: usize,) ![]const []const u8 { try options.validate(); std.debug.assert(run_index < lane.runs.len); const run = lane.runs[run_index]; return try capture.perfstat.command( allocator, tool, argv, run.csv_path, run.events, .{ .system_wide = options.system_wide }, );}pub fn summarize( allocator: std.mem.Allocator, lane: Lane, exit_code: i64, stderr_path: []const u8, tool_available: bool,) !root.Capture { if (!tool_available) return missingTool(lane); var summaries: std.ArrayList(capture.perfstat.Summary) = .empty; for (lane.runs) |run| { const summary = capture.perfstat.parseCsv(allocator, run.csv_path) catch |err| switch (err) { error.FileNotFound => return try failed(allocator, lane, exit_code, stderr_path), else => |actual| return actual, }; if (summary.counters.len == 0) return try failed(allocator, lane, exit_code, stderr_path); try summaries.append(allocator, summary); } var summary = try mergeLaneSummaries(allocator, lane, summaries.items); summary.event_expression = lane.event_expression; summary.kernel_event_groups = lane.kernel_event_groups; if (lane.system_wide) summary = try addSystemWideCaveat(allocator, summary); try capture.perfstat.writeSummaryFile(lane.summary_path, summary); const evidence_caveat = capture.perfstat.counterEvidenceCaveat(summary); return .{ .kind = kind, .tool = tool, .capture_path = lane.csv_path, .summary_path = lane.summary_path, .state = "summary_written", .caveat_kind = if (evidence_caveat) |row| row.kind else null, .caveat_message = if (evidence_caveat) |row| row.message else null, };}fn mergeLaneSummaries( allocator: std.mem.Allocator, lane: Lane, summaries: []const capture.perfstat.Summary,) !capture.perfstat.Summary { const grouped = lane.event_groups.len > 1; const repeated = lane.repetition_csv_paths.len > 1; if (!grouped and !repeated) return summaries[0]; try writeCombinedCsv(allocator, lane.csv_path, summaries); if (!grouped) return try capture.perfstat.mergeRepeatedSummaries( allocator, lane.csv_path, summaries, ); if (!repeated) return try capture.perfstat.mergeSummaries( allocator, lane.csv_path, lane.event_groups, summaries, ); return try mergeGroupedRepetitions(allocator, lane, summaries);}fn mergeGroupedRepetitions( allocator: std.mem.Allocator, lane: Lane, summaries: []const capture.perfstat.Summary,) !capture.perfstat.Summary { const group_count = lane.event_groups.len; var repetition_summaries: std.ArrayList(capture.perfstat.Summary) = .empty; for (lane.repetition_csv_paths, 0..) |csv_path, repetition_index| { const start = repetition_index * group_count; const end = start + group_count; try writeCombinedCsv(allocator, csv_path, summaries[start..end]); try repetition_summaries.append( allocator, try capture.perfstat.mergeSummaries( allocator, csv_path, try repetitionGroups(allocator, lane, repetition_index), summaries[start..end], ), ); } var group_summaries: std.ArrayList(capture.perfstat.Summary) = .empty; for (lane.event_groups, 0..) |group, group_index| { group_summaries.clearRetainingCapacity(); for (0..lane.repetition_csv_paths.len) |repetition_index| { try group_summaries.append( allocator, summaries[repetition_index * group_count + group_index], ); } try writeCombinedCsv(allocator, group.csv_path, group_summaries.items); } return try capture.perfstat.mergeGroupedRepeatedSummaries( allocator, lane.csv_path, lane.event_groups, repetition_summaries.items, );}fn addSystemWideCaveat( allocator: std.mem.Allocator, summary: capture.perfstat.Summary,) !capture.perfstat.Summary { var result = summary; const caveats = try allocator.alloc(capture.perfstat.Caveat, summary.caveats.len + 1); @memcpy(caveats[0..summary.caveats.len], summary.caveats); caveats[summary.caveats.len] = .{ .event = "perf.stat", .kind = "system_wide_scope", .message = "system-wide counters include concurrent host activity and " ++ "are not attributed exclusively to the workload process", .value_text = "", .running_percent = null, }; result.caveats = caveats; return result;}fn repetitionGroups( allocator: std.mem.Allocator, lane: Lane, repetition_index: usize,) ![]const capture.perfstat.EventGroup { const groups = try allocator.alloc(capture.perfstat.EventGroup, lane.event_groups.len); const start = repetition_index * lane.event_groups.len; for (groups, lane.event_groups, 0..) |*destination, source, group_index| { destination.* = source; destination.csv_path = lane.runs[start + group_index].csv_path; } return groups;}fn writeCombinedCsv( allocator: std.mem.Allocator, path: []const u8, summaries: []const capture.perfstat.Summary,) !void { var file = try sys.fs.cwd().createFile(std.Options.debug_io, path, .{ .truncate = true }); defer file.close(std.Options.debug_io); var buffer: [8192]u8 = undefined; var file_writer = file.writer(std.Options.debug_io, &buffer); const writer = &file_writer.interface; for (summaries) |summary| { const text = try sys.fs.readFileAlloc(allocator, summary.csv_path, max_capture_bytes); defer allocator.free(text); try writer.writeAll(text); if (text.len == 0 or text[text.len - 1] != '\n') try writer.writeByte('\n'); } try writer.flush();}fn missingTool(lane: Lane) root.Capture { return .{ .kind = kind, .tool = tool, .capture_path = lane.csv_path, .summary_path = lane.summary_path, .state = "tool_missing", .caveat_kind = "tool_unavailable", .caveat_message = "perf is not runnable on this host; counters were not captured", };}fn failed(allocator: std.mem.Allocator, lane: Lane, exit_code: i64, stderr_path: []const u8) !root.Capture { const row = try capture.caveat.classifyCommandCapture(allocator, .{ .phase = kind, .exit_code = if (exit_code == 0) 1 else exit_code, .timed_out = false, .capture_path = stderr_path, }) orelse capture.caveat.classifyCommandText(.{ .phase = kind, .exit_code = exit_code, .timed_out = false, .capture_path = stderr_path, }, ""); return .{ .kind = kind, .tool = tool, .capture_path = lane.csv_path, .summary_path = lane.summary_path, .state = "tool_failed", .caveat_kind = row.kind, .caveat_message = row.message, };}test "profiling counters wrap workload argv in perf stat" { var arena_state = std.heap.ArenaAllocator.init(std.testing.allocator); defer arena_state.deinit(); const allocator = arena_state.allocator(); try std.testing.expectEqualStrings( "page-faults,{cycles,instructions,task-clock},{branches,branch-misses}", default_events, ); try std.testing.expectEqual(@as(u32, 3), default_repeat); const lane = try plan(allocator, .{}, "zig-out/profiling/run/workloads/w"); const argv = [_][]const u8{ "zig", "build", "bench" }; const wrapped = try wrapArgv(allocator, .{}, &argv, lane); try std.testing.expectEqualStrings("perf", wrapped[0]); try std.testing.expectEqualStrings("stat", wrapped[1]); try std.testing.expectEqual(@as(usize, default_repeat), lane.runs.len); try std.testing.expectEqualStrings(default_events, lane.runs[0].events); try std.testing.expectEqualStrings(default_events, lane.event_expression); try std.testing.expectEqual(@as(usize, 2), lane.kernel_event_groups.len); try std.testing.expectEqual( capture.perfstat.KernelGroupConstraint.strong, lane.kernel_event_groups[0].constraint, ); try std.testing.expectEqualStrings(default_events, wrapped[5]); try std.testing.expectEqualStrings(lane.runs[0].csv_path, wrapped[7]); try std.testing.expectEqualStrings("zig", wrapped[wrapped.len - 3]); try std.testing.expectEqualStrings("zig-out/profiling/run/workloads/w/perf.stat.csv", lane.csv_path);}test "profiling energy counters use system wide perf scope" { var arena_state = std.heap.ArenaAllocator.init(std.testing.allocator); defer arena_state.deinit(); const allocator = arena_state.allocator(); const options = Options{ .events = energy_events, .system_wide = true, }; const lane = try plan(allocator, options, "zig-out/profiling/run/workloads/w"); const argv = [_][]const u8{"workload"}; const wrapped = try wrapArgv(allocator, options, &argv, lane); try std.testing.expect(lane.system_wide); try std.testing.expectEqualStrings("-a", wrapped[2]); try std.testing.expectEqualStrings(energy_events, wrapped[6]); try std.testing.expectEqualStrings("workload", wrapped[wrapped.len - 1]);}test "profiling counters plan bounded default repetitions" { var arena_state = std.heap.ArenaAllocator.init(std.testing.allocator); defer arena_state.deinit(); const allocator = arena_state.allocator(); const options = Options{}; const lane = try plan(allocator, options, "zig-out/profiling/run/workloads/w"); try std.testing.expectEqual(@as(usize, default_repeat), lane.runs.len); try std.testing.expectEqualStrings( "zig-out/profiling/run/workloads/w/perf.stat.repeat.1.csv", lane.runs[0].csv_path, ); try std.testing.expectEqualStrings( "zig-out/profiling/run/workloads/w/perf.stat.repeat.3.csv", lane.runs[2].csv_path, ); const argv = [_][]const u8{ "zig", "build", "bench" }; const wrapped = try wrapRunArgv(allocator, options, &argv, lane, 1); try std.testing.expectEqualStrings(lane.runs[1].csv_path, wrapped[7]); try std.testing.expectError(error.InvalidCounterRepeat, (Options{ .repeat = 0 }).validate()); try std.testing.expectError(error.InvalidCounterRepeat, (Options{ .repeat = root.process.max_repeat + 1 }).validate());}test "profiling counters plan bounded event group repetition matrix" { var arena_state = std.heap.ArenaAllocator.init(std.testing.allocator); defer arena_state.deinit(); const allocator = arena_state.allocator(); const options = Options{ .events = "task-clock,{cycles,instructions},branches", .repeat = 2, .group_size = 1, }; const lane = try plan(allocator, options, "zig-out/profiling/run/workloads/w"); try std.testing.expectEqual(@as(usize, 3), lane.event_groups.len); try std.testing.expectEqual(@as(usize, 1), lane.kernel_event_groups.len); try std.testing.expectEqualStrings( "cycles,instructions", lane.kernel_event_groups[0].events, ); try std.testing.expectEqual(@as(usize, 6), lane.runs.len); try std.testing.expectEqualStrings("task-clock", lane.runs[0].events); try std.testing.expectEqualStrings("{cycles,instructions}", lane.runs[1].events); try std.testing.expectEqual(@as(u32, 2), lane.runs[3].repetition_index); try std.testing.expectEqualStrings( "zig-out/profiling/run/workloads/w/perf.stat.group.3.repeat.2.csv", lane.runs[5].csv_path, ); try std.testing.expectEqualStrings( "zig-out/profiling/run/workloads/w/perf.stat.group.2.csv", lane.event_groups[1].csv_path, ); try std.testing.expectEqualStrings( "zig-out/profiling/run/workloads/w/perf.stat.repeat.2.csv", lane.repetition_csv_paths[1], ); try std.testing.expectError( error.TooManyCounterExecutions, plan(allocator, .{ .events = "a,b", .repeat = root.process.max_repeat, .group_size = 1 }, "root"), ); try std.testing.expectError( error.InvalidCounterGroupSize, (Options{ .group_size = max_group_size + 1 }).validate(), ); try std.testing.expectError( error.InvalidCounterEvents, (Options{ .events = " \t" }).validate(), );}test "profiling counters summarize a captured csv" { var tmp = std.testing.tmpDir(.{}); defer tmp.cleanup(); var arena_state = std.heap.ArenaAllocator.init(std.testing.allocator); defer arena_state.deinit(); const allocator = arena_state.allocator(); const dir = try std.fs.path.join(allocator, &.{ ".zig-cache", "tmp", tmp.sub_path[0..] }); const lane = try plan(allocator, .{ .repeat = 1 }, dir); try sys.fs.writeFile(lane.csv_path, \\# started on Fri Jul 4 10:00:00 2026 \\1000.50,msec,task-clock,1000500000,100.00,1.000,CPUs utilized \\2000000,,instructions,1000500000,100.00,2.00,insn per cycle \\ ); const stderr_path = try std.fs.path.join(allocator, &.{ dir, "stderr.txt" }); try sys.fs.writeFile(stderr_path, ""); const row = try summarize(allocator, lane, 0, stderr_path, true); try std.testing.expectEqualStrings("summary_written", row.state); try std.testing.expectEqualStrings("add_counter_repetitions", row.caveat_kind.?); try std.testing.expectEqualStrings( "perf counter values are single-execution point estimates; add repetitions", row.caveat_message.?, ); try std.testing.expect(sys.fs.exists(lane.summary_path)); const summary = try capture.perfstat.parseSummaryFile(allocator, lane.summary_path); const schedule = capture.perfstat.counterSchedule(summary); try std.testing.expectEqualStrings("strong_kernel_groups", schedule.status); try std.testing.expectEqualStrings(default_events, schedule.event_expression.?); try std.testing.expectEqual(@as(u64, 2), schedule.strong_group_count); try std.testing.expectEqual(@as(u64, 5), schedule.grouped_event_count);}test "profiling system wide counters retain attribution caveat" { var tmp = std.testing.tmpDir(.{}); defer tmp.cleanup(); var arena_state = std.heap.ArenaAllocator.init(std.testing.allocator); defer arena_state.deinit(); const allocator = arena_state.allocator(); const dir = try std.fs.path.join(allocator, &.{ ".zig-cache", "tmp", tmp.sub_path[0..] }); const lane = try plan(allocator, .{ .events = energy_events, .repeat = 1, .system_wide = true, }, dir); try sys.fs.writeFile(lane.csv_path, \\1000000000,,duration_time,1,100.00,, \\10,Joules,power/energy-pkg/u,0,100.00,, \\ ); const stderr_path = try std.fs.path.join(allocator, &.{ dir, "stderr.txt" }); try sys.fs.writeFile(stderr_path, ""); _ = try summarize(allocator, lane, 0, stderr_path, true); const summary = try capture.perfstat.parseSummaryFile(allocator, lane.summary_path); try std.testing.expectEqualStrings("system_wide_scope", summary.caveats[0].kind); try std.testing.expect(std.mem.indexOf( u8, summary.caveats[0].message, "not attributed exclusively", ) != null);}test "profiling counters surface excluded kernel evidence caveats" { var tmp = std.testing.tmpDir(.{}); defer tmp.cleanup(); var arena_state = std.heap.ArenaAllocator.init(std.testing.allocator); defer arena_state.deinit(); const allocator = arena_state.allocator(); const dir = try std.fs.path.join(allocator, &.{ ".zig-cache", "tmp", tmp.sub_path[0..] }); const lane = try plan(allocator, .{ .events = "context-switches,cpu-migrations,page-faults", .repeat = 1, }, dir); try sys.fs.writeFile(lane.runs[0].csv_path, \\0,,context-switches:u,100,100.00,, \\0,,cpu-migrations:u,100,100.00,, \\90,,page-faults:u,100,100.00,, \\ ); const stderr_path = try std.fs.path.join(allocator, &.{ dir, "stderr.txt" }); try sys.fs.writeFile(stderr_path, ""); const row = try summarize(allocator, lane, 0, stderr_path, true); try std.testing.expectEqualStrings("summary_written", row.state); try std.testing.expectEqualStrings("excluded_kernel_events", row.caveat_kind.?); try std.testing.expect(std.mem.indexOf( u8, row.caveat_message.?, "request kernel access", ) != null);}test "profiling counters leave ready repeated evidence uncaveated" { var tmp = std.testing.tmpDir(.{}); defer tmp.cleanup(); var arena_state = std.heap.ArenaAllocator.init(std.testing.allocator); defer arena_state.deinit(); const allocator = arena_state.allocator(); const dir = try std.fs.path.join(allocator, &.{ ".zig-cache", "tmp", tmp.sub_path[0..] }); const lane = try plan(allocator, .{ .events = "instructions", .repeat = 3 }, dir); for (lane.runs) |run| try sys.fs.writeFile( run.csv_path, "100,,instructions:u,100,100.00,,\n", ); const stderr_path = try std.fs.path.join(allocator, &.{ dir, "stderr.txt" }); try sys.fs.writeFile(stderr_path, ""); const row = try summarize(allocator, lane, 0, stderr_path, true); try std.testing.expectEqualStrings("summary_written", row.state); try std.testing.expect(row.caveat_kind == null); try std.testing.expect(row.caveat_message == null);}test "profiling counters summarize separate event groups" { var tmp = std.testing.tmpDir(.{}); defer tmp.cleanup(); var arena_state = std.heap.ArenaAllocator.init(std.testing.allocator); defer arena_state.deinit(); const allocator = arena_state.allocator(); const dir = try std.fs.path.join(allocator, &.{ ".zig-cache", "tmp", tmp.sub_path[0..] }); const lane = try plan(allocator, .{ .events = "instructions,branches", .repeat = 1, .group_size = 1, }, dir); for (lane.runs, [_]u64{ 100, 40 }) |run, value| { try sys.fs.writeFile( run.csv_path, try std.fmt.allocPrint(allocator, "{d},,{s},100,100.00,,\n", .{ value, run.events }), ); } const stderr_path = try std.fs.path.join(allocator, &.{ dir, "stderr.txt" }); try sys.fs.writeFile(stderr_path, ""); const row = try summarize(allocator, lane, 0, stderr_path, true); try std.testing.expectEqualStrings("summary_written", row.state); const summary = try capture.perfstat.parseSummaryFile(allocator, lane.summary_path); try std.testing.expectEqual(@as(usize, 2), summary.event_groups.len); try std.testing.expectEqual(@as(usize, 0), summary.repetitions.len); try std.testing.expectEqual(@as(usize, 2), summary.counters.len); try std.testing.expectEqual(@as(usize, 1), summary.caveats.len); try std.testing.expectEqualStrings( "grouped_point_estimates_separate_executions", capture.perfstat.measurementDesign(summary).status, );}test "profiling counters summarize raw repetitions" { var tmp = std.testing.tmpDir(.{}); defer tmp.cleanup(); var arena_state = std.heap.ArenaAllocator.init(std.testing.allocator); defer arena_state.deinit(); const allocator = arena_state.allocator(); const dir = try std.fs.path.join(allocator, &.{ ".zig-cache", "tmp", tmp.sub_path[0..] }); const lane = try plan(allocator, .{ .repeat = 2 }, dir); try sys.fs.writeFile(lane.runs[0].csv_path, \\100,,instructions,100,100.00,, \\ ); try sys.fs.writeFile(lane.runs[1].csv_path, \\120,,instructions,100,100.00,, \\ ); const stderr_path = try std.fs.path.join(allocator, &.{ dir, "stderr.txt" }); try sys.fs.writeFile(stderr_path, ""); const row = try summarize(allocator, lane, 0, stderr_path, true); try std.testing.expectEqualStrings("summary_written", row.state); try std.testing.expect(sys.fs.exists(lane.csv_path)); const summary = try capture.perfstat.mergeRepeatedSummaries(allocator, lane.csv_path, &.{ try capture.perfstat.parseCsv(allocator, lane.runs[0].csv_path), try capture.perfstat.parseCsv(allocator, lane.runs[1].csv_path), }); try std.testing.expectEqual(@as(u64, 2), summary.counter_stability[0].samples); try std.testing.expectEqual(@as(f64, 110), summary.counters[0].value.?);}test "profiling counters summarize grouped raw repetitions" { var tmp = std.testing.tmpDir(.{}); defer tmp.cleanup(); var arena_state = std.heap.ArenaAllocator.init(std.testing.allocator); defer arena_state.deinit(); const allocator = arena_state.allocator(); const dir = try std.fs.path.join(allocator, &.{ ".zig-cache", "tmp", tmp.sub_path[0..] }); const lane = try plan(allocator, .{ .events = "instructions,branches", .repeat = 2, .group_size = 1, }, dir); const values = [_]u64{ 100, 40, 120, 60 }; for (lane.runs, values) |run, value| { try sys.fs.writeFile( run.csv_path, try std.fmt.allocPrint(allocator, "{d},,{s},100,100.00,,\n", .{ value, run.events }), ); } const stderr_path = try std.fs.path.join(allocator, &.{ dir, "stderr.txt" }); try sys.fs.writeFile(stderr_path, ""); const row = try summarize(allocator, lane, 0, stderr_path, true); try std.testing.expectEqualStrings("summary_written", row.state); const summary = try capture.perfstat.parseSummaryFile(allocator, lane.summary_path); try std.testing.expectEqual(@as(usize, 2), summary.event_groups.len); try std.testing.expectEqual(@as(usize, 2), summary.repetitions.len); try std.testing.expectEqual(@as(usize, 2), summary.repetitions[0].counters.len); try std.testing.expectEqual(@as(u64, 2), summary.counter_stability[0].samples); try std.testing.expectEqual(@as(usize, 1), summary.caveats.len); try std.testing.expectEqualStrings( "grouped_repeated_separate_executions", capture.perfstat.measurementDesign(summary).status, ); try std.testing.expectEqual(@as(u64, 4), capture.perfstat.measurementDesign(summary).execution_count); try std.testing.expect(sys.fs.exists(lane.event_groups[0].csv_path)); try std.testing.expect(sys.fs.exists(lane.repetition_csv_paths[0]));}test "profiling counters classify a failed capture" { var tmp = std.testing.tmpDir(.{}); defer tmp.cleanup(); var arena_state = std.heap.ArenaAllocator.init(std.testing.allocator); defer arena_state.deinit(); const allocator = arena_state.allocator(); const dir = try std.fs.path.join(allocator, &.{ ".zig-cache", "tmp", tmp.sub_path[0..] }); const lane = try plan(allocator, .{}, dir); const stderr_path = try std.fs.path.join(allocator, &.{ dir, "stderr.txt" }); try sys.fs.writeFile(stderr_path, "perf stat: Permission denied\n"); const row = try summarize(allocator, lane, 1, stderr_path, true); try std.testing.expectEqualStrings("tool_failed", row.state); try std.testing.expectEqualStrings("permission_denied", row.caveat_kind.?);}test "profiling counters report missing tools as caveats" { var arena_state = std.heap.ArenaAllocator.init(std.testing.allocator); defer arena_state.deinit(); const allocator = arena_state.allocator(); const lane = try plan(allocator, .{}, "zig-out/profiling/run/workloads/w"); const row = try summarize(allocator, lane, 0, "missing-stderr.txt", false); try std.testing.expectEqualStrings("tool_missing", row.state); try std.testing.expectEqualStrings("tool_unavailable", row.caveat_kind.?);}Source: src/profiling/host/root.zig:3
zig
pub const counters = runtime.counters;Complete caller list for host.counters.plan
19 direct callers.
src.profiling.command.plannedMeasuredArtifactCount[function] — private; no exact target atsrc/profiling/command.zig:1060in nearest public ownertiny.profiling.commandsrc.profiling.command.test_profiling_CLI_falls_back_from_unavailable_counter_lane_artifact_counts[function] — test; no exact target atsrc/profiling/command.zig:1292in nearest public ownertiny.profiling.commandsrc.profiling.command.writeRunDryRunCounterMetadata[function] — private; no exact target atsrc/profiling/command.zig:740in nearest public ownertiny.profiling.commandsrc.profiling.driver.test.test_profiling_driver_resets_successful_counter_and_capture_control_children[function] — test; no exact target atsrc/profiling/driver/test.zig:244in nearest public ownersrc.profiling.driver.testsrc.profiling.host.counters.test_profiling_counters_classify_a_failed_capture[function] — test; no exact target atsrc/profiling/host/counters.zig:742in nearest public ownertiny.profiling.host.counterssrc.profiling.host.counters.test_profiling_counters_leave_ready_repeated_evidence_uncaveated[function] — test; no exact target atsrc/profiling/host/counters.zig:622in nearest public ownertiny.profiling.host.counterssrc.profiling.host.counters.test_profiling_counters_plan_bounded_default_repetitions[function] — test; no exact target atsrc/profiling/host/counters.zig:464in nearest public ownertiny.profiling.host.counterssrc.profiling.host.counters.test_profiling_counters_plan_bounded_event_group_repetition_matrix[function] — test; no exact target atsrc/profiling/host/counters.zig:486in nearest public ownertiny.profiling.host.counterssrc.profiling.host.counters.test_profiling_counters_report_missing_tools_as_caveats[function] — test; no exact target atsrc/profiling/host/counters.zig:757in nearest public ownertiny.profiling.host.counterssrc.profiling.host.counters.test_profiling_counters_summarize_a_captured_csv[function] — test; no exact target atsrc/profiling/host/counters.zig:532in nearest public ownertiny.profiling.host.counterssrc.profiling.host.counters.test_profiling_counters_summarize_grouped_raw_repetitions[function] — test; no exact target atsrc/profiling/host/counters.zig:704in nearest public ownertiny.profiling.host.counterssrc.profiling.host.counters.test_profiling_counters_summarize_raw_repetitions[function] — test; no exact target atsrc/profiling/host/counters.zig:675in nearest public ownertiny.profiling.host.counterssrc.profiling.host.counters.test_profiling_counters_summarize_separate_event_groups[function] — test; no exact target atsrc/profiling/host/counters.zig:642in nearest public ownertiny.profiling.host.counterssrc.profiling.host.counters.test_profiling_counters_surface_excluded_kernel_evidence_caveats[function] — test; no exact target atsrc/profiling/host/counters.zig:593in nearest public ownertiny.profiling.host.counterssrc.profiling.host.counters.test_profiling_counters_wrap_workload_argv_in_perf_stat[function] — test; no exact target atsrc/profiling/host/counters.zig:419in nearest public ownertiny.profiling.host.counterssrc.profiling.host.counters.test_profiling_energy_counters_use_system_wide_perf_scope[function] — test; no exact target atsrc/profiling/host/counters.zig:447in nearest public ownertiny.profiling.host.counterssrc.profiling.host.counters.test_profiling_system_wide_counters_retain_attribution_caveat[function] — test; no exact target atsrc/profiling/host/counters.zig:564in nearest public ownertiny.profiling.host.counterssrc.profiling.host.runtime.descriptor[function] — private; no exact target atsrc/profiling/host/runtime.zig:276in nearest public ownersrc.profiling.host.runtimetiny.profiling.host.wrap[function] atsrc/profiling/host/runtime.zig:138
Complete caller list for host.counters.summarize
10 direct callers.
src.profiling.host.counters.test_profiling_counters_classify_a_failed_capture[function] — test; no exact target atsrc/profiling/host/counters.zig:742in nearest public ownertiny.profiling.host.counterssrc.profiling.host.counters.test_profiling_counters_leave_ready_repeated_evidence_uncaveated[function] — test; no exact target atsrc/profiling/host/counters.zig:622in nearest public ownertiny.profiling.host.counterssrc.profiling.host.counters.test_profiling_counters_report_missing_tools_as_caveats[function] — test; no exact target atsrc/profiling/host/counters.zig:757in nearest public ownertiny.profiling.host.counterssrc.profiling.host.counters.test_profiling_counters_summarize_a_captured_csv[function] — test; no exact target atsrc/profiling/host/counters.zig:532in nearest public ownertiny.profiling.host.counterssrc.profiling.host.counters.test_profiling_counters_summarize_grouped_raw_repetitions[function] — test; no exact target atsrc/profiling/host/counters.zig:704in nearest public ownertiny.profiling.host.counterssrc.profiling.host.counters.test_profiling_counters_summarize_raw_repetitions[function] — test; no exact target atsrc/profiling/host/counters.zig:675in nearest public ownertiny.profiling.host.counterssrc.profiling.host.counters.test_profiling_counters_summarize_separate_event_groups[function] — test; no exact target atsrc/profiling/host/counters.zig:642in nearest public ownertiny.profiling.host.counterssrc.profiling.host.counters.test_profiling_counters_surface_excluded_kernel_evidence_caveats[function] — test; no exact target atsrc/profiling/host/counters.zig:593in nearest public ownertiny.profiling.host.counterssrc.profiling.host.counters.test_profiling_system_wide_counters_retain_attribution_caveat[function] — test; no exact target atsrc/profiling/host/counters.zig:564in nearest public ownertiny.profiling.host.counterstiny.profiling.host.summarize[function] atsrc/profiling/host/runtime.zig:210
Audit
| Definitions | 15 |
|---|---|
| Public names | 15 |
| Members | 16 |
| Version | 26.7.0 |
| Revision | daab053ee433 |