tiny.profiling.order
Defined in tiny.profiling.
API (24)
Actions
Public operations.
Blocked.validContext.methodContext.validInterleaved.validMethod.acquisitionNameMethod.nameMethod.parseinterleavedContextparsesameDesignschedulevalidateDesignwriteJson
Types and contracts
Public types and contracts.
Namespaces
Public namespaces.
Values and defaults
Public values and defaults.
Source
Source: src/profiling/order.zig
zig
const std = @import("std");const pretty = @import("pretty");const host = @import("host/root.zig");const json = @import("json.zig");const plan = @import("plan.zig");const pretty_json = pretty.json;pub const contrast = @import("contrast.zig");pub const max_schedule_entries = plan.max_workloads_per_run * host.process.max_executions;pub const schedule_algorithm = "xoshiro256_flat_multiset_fisher_yates";pub const setup_order = "selected_workload_order_before_measurement";pub const warmup_placement = "before_first_scheduled_measurement";pub const failure_policy = "skip_failed_workload_remaining_positions";pub const Method = enum { blocked, random_interleaved, pub fn parse(value: []const u8) ?Method { return std.meta.stringToEnum(Method, value); } pub fn name(self: Method) []const u8 { return @tagName(self); } pub fn acquisitionName(self: Method) []const u8 { return switch (self) { .blocked => "fixed_plan_order", .random_interleaved => "random_interleaved", }; }};pub const Blocked = struct { position: usize = 1, workload_count: usize = 1, predecessors: []const []const u8 = &.{}, pub fn valid(self: Blocked) bool { return self.position > 0 and self.position == self.predecessors.len + 1 and self.workload_count >= self.position and self.workload_count <= plan.max_workloads_per_run; }};pub const Interleaved = struct { seed: u64, repeat_count: u32, workload_count: usize, selected_workloads: []const []const u8, positions: []const usize, pub fn valid(self: Interleaved) bool { if (validateDesign(self.workload_count, self.repeat_count)) |_| {} else |_| { return false; } if (self.selected_workloads.len != self.workload_count or self.positions.len != self.repeat_count) { return false; } for (self.selected_workloads, 0..) |name, index| { if (name.len == 0) return false; for (self.selected_workloads[0..index]) |previous| { if (std.mem.eql(u8, name, previous)) return false; } } const schedule_len = self.workload_count * @as(usize, self.repeat_count); var previous: usize = 0; for (self.positions) |position| { if (position <= previous or position > schedule_len) return false; previous = position; } return true; }};pub const Context = union(Method) { blocked: Blocked, random_interleaved: Interleaved, pub fn method(self: Context) Method { return std.meta.activeTag(self); } pub fn valid(self: Context) bool { return switch (self) { .blocked => |value| value.valid(), .random_interleaved => |value| value.valid(), }; }};pub const Entry = struct { workload_index: usize, repetition_index: u32, position: usize,};pub fn validateDesign(workload_count: usize, repeat_count: u32) !void { if (workload_count < 2 or workload_count > plan.max_workloads_per_run) { return error.InvalidInterleaveWorkloadCount; } if (repeat_count < 2 or repeat_count > host.process.max_repeat) { return error.InvalidInterleaveRepeat; } const entry_count = std.math.mul( usize, workload_count, @as(usize, repeat_count), ) catch return error.InvalidInterleaveSchedule; if (entry_count > max_schedule_entries) return error.InvalidInterleaveSchedule;}pub fn schedule( allocator: std.mem.Allocator, workload_count: usize, repeat_count: u32, seed: u64,) ![]Entry { try validateDesign(workload_count, repeat_count); const entry_count = workload_count * @as(usize, repeat_count); const entries = try allocator.alloc(Entry, entry_count); for (0..workload_count) |workload_index| { for (0..repeat_count) |repeat_index| { const index = workload_index * @as(usize, repeat_count) + repeat_index; entries[index] = .{ .workload_index = workload_index, .repetition_index = 0, .position = 0, }; } } var prng = std.Random.Xoshiro256.init(seed); const random = prng.random(); var remaining = entries.len; while (remaining > 1) { const index = random.uintLessThan(usize, remaining); remaining -= 1; std.mem.swap(Entry, &entries[index], &entries[remaining]); } var repetitions: [plan.max_workloads_per_run]u32 = @splat(0); for (entries, 0..) |*entry, index| { entry.position = index + 1; entry.repetition_index = repetitions[entry.workload_index]; repetitions[entry.workload_index] += 1; } return entries;}pub fn interleavedContext( allocator: std.mem.Allocator, selected_workloads: []const []const u8, entries: []const Entry, workload_index: usize, repeat_count: u32, seed: u64,) !Context { try validateDesign(selected_workloads.len, repeat_count); if (workload_index >= selected_workloads.len or entries.len != selected_workloads.len * @as(usize, repeat_count)) { return error.InvalidInterleaveSchedule; } const positions = try allocator.alloc(usize, repeat_count); var position_index: usize = 0; for (entries) |entry| { if (entry.workload_index != workload_index) continue; if (position_index >= positions.len) return error.InvalidInterleaveSchedule; positions[position_index] = entry.position; position_index += 1; } if (position_index != positions.len) return error.InvalidInterleaveSchedule; const result = Context{ .random_interleaved = .{ .seed = seed, .repeat_count = repeat_count, .workload_count = selected_workloads.len, .selected_workloads = selected_workloads, .positions = positions, } }; if (!result.valid()) return error.InvalidInterleaveSchedule; return result;}pub fn sameDesign(baseline: Context, candidate: Context) bool { std.debug.assert(baseline.valid()); std.debug.assert(candidate.valid()); return switch (baseline) { .blocked => |base| switch (candidate) { .blocked => |actual| sameBlocked(base, actual), .random_interleaved => false, }, .random_interleaved => |base| switch (candidate) { .blocked => false, .random_interleaved => |actual| sameInterleavedDesign(base, actual), }, };}fn sameBlocked(baseline: Blocked, candidate: Blocked) bool { if (baseline.position != candidate.position or baseline.predecessors.len != candidate.predecessors.len) { return false; } return sameStrings(baseline.predecessors, candidate.predecessors);}fn sameInterleavedDesign(baseline: Interleaved, candidate: Interleaved) bool { return baseline.repeat_count == candidate.repeat_count and baseline.workload_count == candidate.workload_count and sameStrings(baseline.selected_workloads, candidate.selected_workloads);}fn sameStrings(baseline: []const []const u8, candidate: []const []const u8) bool { if (baseline.len != candidate.len) return false; for (baseline, candidate) |base, actual| { if (!std.mem.eql(u8, base, actual)) return false; } return true;}pub fn parse(allocator: std.mem.Allocator, value: std.json.Value) !Context { const object = try json.object(value); const method = if (json.string(object.get("method"))) |name| method: { if (!std.mem.eql(u8, name, Method.random_interleaved.name())) { return error.InvalidProfilingJson; } break :method Method.random_interleaved; } else Method.blocked; const result = switch (method) { .blocked => Context{ .blocked = .{ .position = std.math.cast( usize, json.asU64(object.get("position")) orelse return error.InvalidProfilingJson, ) orelse return error.InvalidProfilingJson, .workload_count = std.math.cast( usize, json.asU64(object.get("workload_count")) orelse return error.InvalidProfilingJson, ) orelse return error.InvalidProfilingJson, .predecessors = try parseStrings(allocator, object, "predecessors"), } }, .random_interleaved => interleaved: { try requireToken(object, "schedule_algorithm", schedule_algorithm); try requireToken(object, "setup_order", setup_order); try requireToken(object, "warmup_placement", warmup_placement); try requireToken(object, "failure_policy", failure_policy); break :interleaved Context{ .random_interleaved = .{ .seed = json.asU64(object.get("seed")) orelse return error.InvalidProfilingJson, .repeat_count = std.math.cast( u32, json.asU64(object.get("repeat_count")) orelse return error.InvalidProfilingJson, ) orelse return error.InvalidProfilingJson, .workload_count = std.math.cast( usize, json.asU64(object.get("workload_count")) orelse return error.InvalidProfilingJson, ) orelse return error.InvalidProfilingJson, .selected_workloads = try parseStrings( allocator, object, "selected_workloads", ), .positions = try parsePositions(allocator, object), } }; }, }; if (!result.valid()) return error.InvalidProfilingJson; return result;}fn requireToken( object: std.json.ObjectMap, field: []const u8, expected: []const u8,) !void { const actual = json.string(object.get(field)) orelse return error.InvalidProfilingJson; if (!std.mem.eql(u8, actual, expected)) return error.InvalidProfilingJson;}fn parseStrings( allocator: std.mem.Allocator, object: std.json.ObjectMap, field: []const u8,) ![]const []const u8 { const value = object.get(field) orelse return error.InvalidProfilingJson; const rows = try json.array(value); const strings = try json.strings(allocator, value); if (strings.len != rows.items.len) return error.InvalidProfilingJson; return strings;}fn parsePositions( allocator: std.mem.Allocator, object: std.json.ObjectMap,) ![]const usize { const rows = try json.array(object.get("positions") orelse return error.InvalidProfilingJson); if (rows.items.len > host.process.max_executions) { return error.InvalidProfilingJson; } const positions = try allocator.alloc(usize, rows.items.len); for (rows.items, 0..) |value, index| { positions[index] = std.math.cast( usize, json.asU64(value) orelse return error.InvalidProfilingJson, ) orelse return error.InvalidProfilingJson; } return positions;}pub fn writeJson(out: *pretty_json.Writer, context: Context) !void { std.debug.assert(context.valid()); try out.beginObject(); switch (context) { .blocked => |value| { try out.objectField("position"); try out.write(value.position); try out.objectField("workload_count"); try out.write(value.workload_count); try out.objectField("predecessors"); try writeStrings(out, value.predecessors); }, .random_interleaved => |value| { try out.objectField("method"); try out.write(Method.random_interleaved.name()); try out.objectField("schedule_algorithm"); try out.write(schedule_algorithm); try out.objectField("setup_order"); try out.write(setup_order); try out.objectField("warmup_placement"); try out.write(warmup_placement); try out.objectField("failure_policy"); try out.write(failure_policy); try out.objectField("seed"); try out.write(value.seed); try out.objectField("repeat_count"); try out.write(value.repeat_count); try out.objectField("workload_count"); try out.write(value.workload_count); try out.objectField("selected_workloads"); try writeStrings(out, value.selected_workloads); try out.objectField("positions"); try out.beginArray(); for (value.positions) |position| try out.write(position); try out.endArray(); }, } try out.endObject();}fn writeStrings(out: *pretty_json.Writer, values: []const []const u8) !void { try out.beginArray(); for (values) |value| try out.write(value); try out.endArray();}test "profiling order builds deterministic complete interleavings" { const allocator = std.testing.allocator; const first = try schedule(allocator, 3, 4, 42); defer allocator.free(first); const second = try schedule(allocator, 3, 4, 42); defer allocator.free(second); try std.testing.expectEqual(first.len, second.len); var counts: [3]u32 = @splat(0); for (first, second, 0..) |left, right, index| { try std.testing.expectEqual(left, right); try std.testing.expectEqual(index + 1, left.position); try std.testing.expectEqual(counts[left.workload_index], left.repetition_index); counts[left.workload_index] += 1; } for (counts) |count| try std.testing.expectEqual(@as(u32, 4), count);}test "profiling order retains per-workload positions" { const allocator = std.testing.allocator; const entries = try schedule(allocator, 2, 3, 7); defer allocator.free(entries); const context = try interleavedContext( allocator, &.{ "a", "b" }, entries, 1, 3, 7, ); defer allocator.free(context.random_interleaved.positions); try std.testing.expect(context.valid()); try std.testing.expectEqual(@as(usize, 3), context.random_interleaved.positions.len); for (context.random_interleaved.positions) |position| { try std.testing.expectEqual(@as(usize, 1), entries[position - 1].workload_index); }}test "profiling order compares designs without coupling independent seeds" { const baseline = Context{ .random_interleaved = .{ .seed = 1, .repeat_count = 2, .workload_count = 2, .selected_workloads = &.{ "a", "b" }, .positions = &.{ 1, 4 }, } }; const candidate = Context{ .random_interleaved = .{ .seed = 2, .repeat_count = 2, .workload_count = 2, .selected_workloads = &.{ "a", "b" }, .positions = &.{ 2, 3 }, } }; try std.testing.expect(sameDesign(baseline, candidate)); try std.testing.expect(!sameDesign( baseline, .{ .blocked = .{ .position = 1, .workload_count = 2 } }, ));}test "profiling order parses retained interleaving context" { var arena_state = std.heap.ArenaAllocator.init(std.testing.allocator); defer arena_state.deinit(); const allocator = arena_state.allocator(); const value = try std.json.parseFromSliceLeaky( std.json.Value, allocator, \\{"method":"random_interleaved","schedule_algorithm":"xoshiro256_flat_multiset_fisher_yates","setup_order":"selected_workload_order_before_measurement","warmup_placement":"before_first_scheduled_measurement","failure_policy":"skip_failed_workload_remaining_positions","seed":42,"repeat_count":3,"workload_count":2,"selected_workloads":["a","b"],"positions":[1,3,6]} , .{}, ); const context = try parse(allocator, value); try std.testing.expectEqual(Method.random_interleaved, context.method()); try std.testing.expectEqual(@as(u64, 42), context.random_interleaved.seed); try std.testing.expectEqualStrings( "b", context.random_interleaved.selected_workloads[1], ); try std.testing.expectEqual(@as(usize, 6), context.random_interleaved.positions[2]);}Source: src/profiling/root.zig:34
zig
pub const order = @import("order.zig");Audit
| Definitions | 24 |
|---|---|
| Public names | 24 |
| Members | 15 |
| Version | 26.7.0 |
| Revision | daab053ee433 |