tiny.profiling.capture.memtrace
Defined in capture.
API (7)
Actions
Public operations.
Types and contracts
Public types and contracts.
Values and defaults
Public values and defaults.
Source
Source: src/profiling/capture/memtrace.zig
zig
const std = @import("std");const memtrace = @import("memtrace");const pretty_json = @import("pretty").json;const sys = @import("sys");const host = @import("../root.zig").host;const fs_io = sys.fs.debugIo();const max_repetition_row_bytes = 8 * 1024;const fixture_version = std.fmt.comptimePrint( "{d}", .{memtrace.event.format_version},);pub const kind = "allocation_trace";pub const tool = "lib/memtrace";pub const repetition_schema = "tiny.profiling.allocation-repetition/v1";pub const Options = struct { enabled: bool, exit_code: i64, capture_path: []const u8, summary_path: []const u8,};pub const RepetitionOptions = struct { enabled: bool, exit_code: i64, execution_index: usize, capture_path: []const u8, repetitions_path: []const u8,};const RenderedSummary = struct { bytes: []const u8, integrity: memtrace.CaptureIntegrity,};pub fn appendCapture( allocator: std.mem.Allocator, captures: []const host.Capture, options: Options,) ![]const host.Capture { if (!options.enabled or options.exit_code != 0) return captures; const integrity = summarize(allocator, options) catch |err| switch (err) { error.OutOfMemory => return err, error.FileNotFound => return try appendRow( allocator, captures, missingCapture(options), ), else => return try appendRow(allocator, captures, invalidCapture(options)), }; return try appendRow(allocator, captures, captureForIntegrity(options, integrity));}pub fn recordRepetition( allocator: std.mem.Allocator, options: RepetitionOptions,) !void { if (!options.enabled) return; std.debug.assert(options.execution_index > 0); if (options.exit_code != 0) { return writeRepetition(options, "workload_failed", null); } var summary_storage: [max_repetition_row_bytes]u8 = undefined; const rendered = renderSummary( allocator, options.capture_path, &summary_storage, ) catch |err| switch (err) { error.OutOfMemory => return err, error.FileNotFound => return writeRepetition(options, "capture_missing", null), else => return writeRepetition(options, "summary_invalid", null), }; try writeRepetition(options, "summary_written", rendered.bytes);}fn summarize( allocator: std.mem.Allocator, options: Options,) !memtrace.CaptureIntegrity { var storage: [max_repetition_row_bytes]u8 = undefined; const rendered = try renderSummary(allocator, options.capture_path, &storage); try sys.fs.writeFile(options.summary_path, rendered.bytes); return rendered.integrity;}fn renderSummary( allocator: std.mem.Allocator, capture_path: []const u8, storage: *[max_repetition_row_bytes]u8,) !RenderedSummary { var output = std.Io.Writer.fixed(storage); const integrity = try memtrace.analysis.writeSummaryJsonlFromJsonlPath( allocator, capture_path, &output, .{ .top = 0, .include_zero_live = true }, ); return .{ .bytes = output.buffered(), .integrity = integrity, };}fn writeRepetition( options: RepetitionOptions, state: []const u8, summary_bytes: ?[]const u8,) !void { var storage: [max_repetition_row_bytes]u8 = undefined; var output = std.Io.Writer.fixed(&storage); var stream = pretty_json.Writer.init(&output, .minified); const object = try stream.object(); try object.field("schema", repetition_schema); try object.field("execution_index", options.execution_index); try object.field("exit_code", options.exit_code); try object.field("state", state); if (summary_bytes) |bytes| { const summary = std.mem.trim(u8, bytes, " \t\r\n"); std.debug.assert(std.mem.indexOfScalar(u8, summary, '\n') == null); try object.raw("summary", summary); } else { try object.field("summary", null); } try object.endLine(); if (options.execution_index == 1) { try sys.fs.writeFile(options.repetitions_path, output.buffered()); } else { try sys.fs.appendFile(options.repetitions_path, &.{output.buffered()}); }}fn appendRow( allocator: std.mem.Allocator, captures: []const host.Capture, row: host.Capture,) ![]const host.Capture { const result = try allocator.alloc(host.Capture, captures.len + 1); @memcpy(result[0..captures.len], captures); result[captures.len] = row; return result;}fn captureForIntegrity( options: Options, integrity: memtrace.CaptureIntegrity,) host.Capture { const complete = std.mem.eql(u8, integrity.status, "complete"); return .{ .kind = kind, .tool = tool, .scope = host.direct_scope, .capture_path = options.capture_path, .summary_path = options.summary_path, .state = "summary_written", .caveat_kind = if (complete) null else integrity.status, .caveat_message = if (complete) null else integrity.message, };}fn missingCapture(options: Options) host.Capture { return .{ .kind = kind, .tool = tool, .scope = host.direct_scope, .capture_path = options.capture_path, .summary_path = options.summary_path, .state = "capture_missing", .caveat_kind = "allocation_trace_missing", .caveat_message = "allocation tracing was requested but produced no trace artifact", };}fn invalidCapture(options: Options) host.Capture { return .{ .kind = kind, .tool = tool, .scope = host.direct_scope, .capture_path = options.capture_path, .summary_path = options.summary_path, .state = "summary_invalid", .caveat_kind = "invalid_allocation_trace", .caveat_message = "allocation trace does not contain valid memtrace evidence", };}test "allocation trace capture writes complete canonical integrity" { var arena_state = std.heap.ArenaAllocator.init(std.testing.allocator); defer arena_state.deinit(); const allocator = arena_state.allocator(); var tmp = std.testing.tmpDir(.{}); defer tmp.cleanup(); const trace = "{\"v\":" ++ fixture_version ++ ",\"seq\":1,\"kind\":\"trace.start\"}\n" ++ "{\"v\":" ++ fixture_version ++ ",\"seq\":2,\"kind\":\"allocator\",\"allocator_id\":0}\n" ++ "{\"v\":" ++ fixture_version ++ ",\"seq\":3,\"kind\":\"trace.stop\"}\n"; try tmp.dir.writeFile(fs_io, .{ .sub_path = "allocations.jsonl", .data = trace }); const root = try tmp.dir.realPathFileAlloc(fs_io, ".", allocator); const capture_path = try std.fs.path.join(allocator, &.{ root, "allocations.jsonl" }); const summary_path = try std.fs.path.join(allocator, &.{ root, "summary.jsonl" }); const rows = try appendCapture(allocator, &.{}, .{ .enabled = true, .exit_code = 0, .capture_path = capture_path, .summary_path = summary_path, }); try std.testing.expectEqualStrings("summary_written", rows[0].state); try std.testing.expect(rows[0].caveat_kind == null); const summary = try sys.fs.readFileAlloc(allocator, summary_path, 64 * 1024); try std.testing.expect(std.mem.indexOf(u8, summary, "\"status\":\"complete\"") != null);}test "allocation trace capture surfaces tail truncation and missing artifacts" { var arena_state = std.heap.ArenaAllocator.init(std.testing.allocator); defer arena_state.deinit(); const allocator = arena_state.allocator(); var tmp = std.testing.tmpDir(.{}); defer tmp.cleanup(); const trace = "{\"v\":" ++ fixture_version ++ ",\"seq\":1,\"kind\":\"trace.start\"}\n" ++ "{\"v\":" ++ fixture_version ++ ",\"seq\":2,\"kind\":\"allocator\",\"allocator_id\":0}\n"; try tmp.dir.writeFile(fs_io, .{ .sub_path = "truncated.jsonl", .data = trace }); const root = try tmp.dir.realPathFileAlloc(fs_io, ".", allocator); const capture_path = try std.fs.path.join(allocator, &.{ root, "truncated.jsonl" }); const summary_path = try std.fs.path.join(allocator, &.{ root, "summary.jsonl" }); const partial = try appendCapture(allocator, &.{}, .{ .enabled = true, .exit_code = 0, .capture_path = capture_path, .summary_path = summary_path, }); try std.testing.expectEqualStrings("missing_stop_event", partial[0].caveat_kind.?); const missing = try appendCapture(allocator, &.{}, .{ .enabled = true, .exit_code = 0, .capture_path = "missing.jsonl", .summary_path = summary_path, }); try std.testing.expectEqualStrings("capture_missing", missing[0].state);}test "allocation trace retains every process repetition summary" { var arena_state = std.heap.ArenaAllocator.init(std.testing.allocator); defer arena_state.deinit(); const allocator = arena_state.allocator(); var tmp = std.testing.tmpDir(.{}); defer tmp.cleanup(); const trace = "{\"v\":" ++ fixture_version ++ ",\"seq\":1,\"kind\":\"trace.start\"}\n" ++ "{\"v\":" ++ fixture_version ++ ",\"seq\":2,\"kind\":\"allocator\",\"allocator_id\":0}\n" ++ "{\"v\":" ++ fixture_version ++ ",\"seq\":3,\"kind\":\"trace.stop\"}\n"; try tmp.dir.writeFile(fs_io, .{ .sub_path = "allocations.jsonl", .data = trace }); const root = try tmp.dir.realPathFileAlloc(fs_io, ".", allocator); const capture_path = try std.fs.path.join(allocator, &.{ root, "allocations.jsonl" }); const repetitions_path = try std.fs.path.join( allocator, &.{ root, "allocations.repetitions.jsonl" }, ); for (1..3) |execution_index| try recordRepetition(allocator, .{ .enabled = true, .exit_code = 0, .execution_index = execution_index, .capture_path = capture_path, .repetitions_path = repetitions_path, }); const rows = try sys.fs.readFileAlloc(allocator, repetitions_path, 16 * 1024); try std.testing.expectEqual(@as(usize, 2), std.mem.count(u8, rows, repetition_schema)); try std.testing.expect(std.mem.indexOf(u8, rows, "\"execution_index\":1") != null); try std.testing.expect(std.mem.indexOf(u8, rows, "\"execution_index\":2") != null); try std.testing.expect(std.mem.indexOf(u8, rows, "\"resizes\":0") != null); try std.testing.expect(std.mem.indexOf(u8, rows, "\"remaps\":0") != null);}test "allocation repetition summarization survives every allocation failure" { var arena_state = std.heap.ArenaAllocator.init(std.testing.allocator); defer arena_state.deinit(); const allocator = arena_state.allocator(); var tmp = std.testing.tmpDir(.{}); defer tmp.cleanup(); const trace = "{\"v\":" ++ fixture_version ++ ",\"seq\":1,\"kind\":\"trace.start\"}\n" ++ "{\"v\":" ++ fixture_version ++ ",\"seq\":2,\"kind\":\"allocator\",\"allocator_id\":0}\n" ++ "{\"v\":" ++ fixture_version ++ ",\"seq\":3,\"kind\":\"trace.stop\"}\n"; try tmp.dir.writeFile(fs_io, .{ .sub_path = "allocations.jsonl", .data = trace }); const root = try tmp.dir.realPathFileAlloc(fs_io, ".", allocator); const capture_path = try std.fs.path.join(allocator, &.{ root, "allocations.jsonl" }); const repetitions_path = try std.fs.path.join(allocator, &.{ root, "repetitions.jsonl" }); try std.testing.checkAllAllocationFailures( std.testing.allocator, recordRepetition, .{RepetitionOptions{ .enabled = true, .exit_code = 0, .execution_index = 1, .capture_path = capture_path, .repetitions_path = repetitions_path, }}, );}Source: src/profiling/capture/root.zig:2
zig
pub const memtrace = @import("memtrace.zig");Audit
| Definitions | 8 |
|---|---|
| Public names | 8 |
| Members | 9 |
| Version | 26.7.0 |
| Revision | daab053ee433 |