tiny.profiling.host.dhat
Defined in host.
API (8)
Actions
Public operations.
Types and contracts
Public types and contracts.
Values and defaults
Public values and defaults.
Source
Source: src/profiling/host/dhat.zig
zig
const std = @import("std");const capture = @import("capture");const sys = @import("sys");const root = @import("root.zig");pub const tool = "valgrind";pub const kind = "dhat";pub const mode = "heap";const allocator_traffic_unobserved = "allocator_traffic_unobserved";pub const Options = struct {};pub const Lane = struct { capture_path: []const u8, out_path: []const u8, summary_path: []const u8,};pub fn plan(allocator: std.mem.Allocator, options: Options, workload_root: []const u8) !Lane { _ = options; return .{ .capture_path = try std.fs.path.join(allocator, &.{ workload_root, "dhat.capture.txt" }), .out_path = try std.fs.path.join(allocator, &.{ workload_root, "dhat.out" }), .summary_path = try std.fs.path.join(allocator, &.{ workload_root, "dhat.summary.json" }), };}pub fn wrapArgv(allocator: std.mem.Allocator, options: Options, argv: []const []const u8, lane: Lane) ![]const []const u8 { _ = options; var wrapped: std.ArrayList([]const u8) = .empty; try wrapped.appendSlice(allocator, &.{ tool, "--tool=dhat", try std.fmt.allocPrint(allocator, "--log-file={s}", .{lane.capture_path}), try std.fmt.allocPrint(allocator, "--dhat-out-file={s}", .{lane.out_path}), }); try wrapped.appendSlice(allocator, argv); return try wrapped.toOwnedSlice(allocator);}pub fn summarize( allocator: std.mem.Allocator, lane: Lane, exit_code: i64, stderr_path: []const u8, tool_available: bool, max_benchmark_allocated_bytes: ?u64,) !root.Capture { if (!tool_available) return missingTool(lane); var summary = capture.dhat.summarizeCaptureFile( allocator, lane.capture_path, lane.out_path, mode, ) catch |err| switch (err) { error.FileNotFound => return try failed( allocator, lane, exit_code, stderr_path, lane.capture_path, ), else => |actual| return actual, }; if (contradictsOwnedAllocations(summary, max_benchmark_allocated_bytes)) { summary.failure = allocator_traffic_unobserved; try capture.dhat.writeSummaryFile(lane.summary_path, summary); return unobservedAllocatorTraffic(lane); } if (!std.mem.eql(u8, summary.state(), "summary_parsed")) { return try failed(allocator, lane, exit_code, stderr_path, lane.capture_path); } try capture.dhat.writeSummaryFile(lane.summary_path, summary); return .{ .kind = kind, .tool = tool, .capture_path = lane.capture_path, .summary_path = lane.summary_path, .state = "summary_written", };}fn contradictsOwnedAllocations( summary: capture.dhat.Summary, max_benchmark_allocated_bytes: ?u64,) bool { const owned_bytes = max_benchmark_allocated_bytes orelse return false; if (owned_bytes == 0 or summary.failure != null) return false; if (!std.mem.eql(u8, summary.mode, mode)) return false; return summary.total_allocated.bytes == 0;}fn unobservedAllocatorTraffic(lane: Lane) root.Capture { return .{ .kind = kind, .tool = tool, .capture_path = lane.capture_path, .summary_path = lane.summary_path, .state = "evidence_invalid", .caveat_kind = allocator_traffic_unobserved, .caveat_message = "DHAT reported zero allocations while owned benchmark counters " ++ "reported allocator traffic", };}fn missingTool(lane: Lane) root.Capture { return .{ .kind = kind, .tool = tool, .capture_path = lane.capture_path, .summary_path = lane.summary_path, .state = "tool_missing", .caveat_kind = "tool_unavailable", .caveat_message = "valgrind is not runnable on this host; heap evidence was not captured", };}fn failed( allocator: std.mem.Allocator, lane: Lane, exit_code: i64, stderr_path: []const u8, capture_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 = capture_path, }) orelse try capture.caveat.classifyCommandCapture(allocator, .{ .phase = kind, .exit_code = 1, .timed_out = false, .capture_path = stderr_path, }) orelse capture.caveat.classifyCommandText(.{ .phase = kind, .exit_code = exit_code, .timed_out = false, .capture_path = capture_path, }, ""); return .{ .kind = kind, .tool = tool, .capture_path = lane.capture_path, .summary_path = lane.summary_path, .state = "tool_failed", .caveat_kind = row.kind, .caveat_message = row.message, };}test "profiling dhat wraps direct binaries in valgrind" { 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 argv = [_][]const u8{ "zig-out/bin/mprompt-bench", "--workers", "128" }; const wrapped = try wrapArgv(allocator, .{}, &argv, lane); try std.testing.expectEqualStrings("valgrind", wrapped[0]); try std.testing.expectEqualStrings("--tool=dhat", wrapped[1]); try std.testing.expectEqualStrings("--log-file=zig-out/profiling/run/workloads/w/dhat.capture.txt", wrapped[2]); try std.testing.expectEqualStrings("--dhat-out-file=zig-out/profiling/run/workloads/w/dhat.out", wrapped[3]); try std.testing.expectEqualStrings("zig-out/bin/mprompt-bench", wrapped[4]); try std.testing.expectEqualStrings("--workers", wrapped[wrapped.len - 2]);}test "profiling dhat summarizes a valgrind 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); try sys.fs.writeFile(lane.capture_path, \\==100== DHAT, a dynamic heap analysis tool \\==100== Total: 1,000 bytes in 10 blocks \\==100== At t-gmax: 600 bytes in 4 blocks \\==100== At t-end: 0 bytes in 0 blocks \\==100== Reads: 2,000 bytes \\==100== Writes: 1,500 bytes \\ ); 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, 4_096); try std.testing.expectEqualStrings("summary_written", row.state); try std.testing.expect(row.caveat_kind == null); try std.testing.expect(sys.fs.exists(lane.summary_path));}test "profiling dhat classifies a missing 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, ""); const row = try summarize(allocator, lane, 1, stderr_path, true, null); try std.testing.expectEqualStrings("tool_failed", row.state); try std.testing.expect(row.caveat_kind != null);}test "profiling dhat reports 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, null, ); try std.testing.expectEqualStrings("tool_missing", row.state); try std.testing.expectEqualStrings("tool_unavailable", row.caveat_kind.?);}test "profiling dhat rejects zero totals contradicted by owned allocations" { 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); try sys.fs.writeFile( lane.capture_path, "==100== Total: 0 bytes in 0 blocks\n", ); const stderr_path = try std.fs.path.join(allocator, &.{ dir, "stderr.txt" }); try sys.fs.writeFile(stderr_path, ""); const uncorroborated = try summarize( allocator, lane, 0, stderr_path, true, null, ); try std.testing.expectEqualStrings("summary_written", uncorroborated.state); const row = try summarize(allocator, lane, 0, stderr_path, true, 4_096); try std.testing.expectEqualStrings("evidence_invalid", row.state); try std.testing.expectEqualStrings( allocator_traffic_unobserved, row.caveat_kind.?, ); const summary = try sys.fs.readFileAlloc(allocator, lane.summary_path, 8 * 1024); try std.testing.expect(std.mem.indexOf( u8, summary, "\"failure\": \"allocator_traffic_unobserved\"", ) != null);}Source: src/profiling/host/root.zig:5
zig
pub const dhat = runtime.dhat;Complete caller list for host.dhat.plan
7 direct callers.
src.profiling.host.dhat.test_profiling_dhat_classifies_a_missing_capture[function] — test; no exact target atsrc/profiling/host/dhat.zig:193in nearest public ownertiny.profiling.host.dhatsrc.profiling.host.dhat.test_profiling_dhat_rejects_zero_totals_contradicted_by_owned_allocations[function] — test; no exact target atsrc/profiling/host/dhat.zig:225in nearest public ownertiny.profiling.host.dhatsrc.profiling.host.dhat.test_profiling_dhat_reports_missing_tools_as_caveats[function] — test; no exact target atsrc/profiling/host/dhat.zig:208in nearest public ownertiny.profiling.host.dhatsrc.profiling.host.dhat.test_profiling_dhat_summarizes_a_valgrind_capture[function] — test; no exact target atsrc/profiling/host/dhat.zig:168in nearest public ownertiny.profiling.host.dhatsrc.profiling.host.dhat.test_profiling_dhat_wraps_direct_binaries_in_valgrind[function] — test; no exact target atsrc/profiling/host/dhat.zig:153in nearest public ownertiny.profiling.host.dhatsrc.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
Audit
| Definitions | 9 |
|---|---|
| Public names | 9 |
| Members | 3 |
| Version | 26.7.0 |
| Revision | daab053ee433 |