Skip to documentation
SLOP

tiny.profiling.iteration.batch

Reference tiny.profiling iteration batch

Defined in iteration.

API (8)

Actions

Public operations.

Types and contracts

Public types and contracts.

No direct callersNo direct callsiterationbatch
Static calls · unresolved targets: unknown · external targets: unknown.

Source

Called byCallsprivate; no linksrc.profiling.iteration.runfinishPhaseprivate; no linksrc.profiling.iteration.batchaggregateprivate; no linksrc.profiling.iteration.batchloadDocumentprivate; no linksrc.profiling.iteration.batchparseTestReceiptprivate; no linksrc.profiling.iteration.batchrequireTokenjsonasI128jsonobjectiteration.batchload
Static calls · unresolved targets: 4 · external targets: 2.
Called byCallsprivate; no linksrc.profiling.iteration.runrunCleanPhaseprivate; no linksrc.profiling.iteration.runwaitWatcherPhaseprivate; no linksrc.profiling.iteration.batchloadDocumentprivate; no linksrc.profiling.iteration.batchrequireTokenjsonasI128jsonobjectiteration.batchmarkerAt
Static calls · unresolved targets: 2 · external targets: 3.

Source: src/profiling/iteration/batch.zig

zig
const std = @import("std");const sys = @import("sys");const profiling = @import("../root.zig");const model = @import("model.zig");const json = profiling.json;const fingerprint = profiling.fingerprint;const maximum_receipt_bytes: usize = 4 * 1024 * 1024;pub const Marker = struct {    path: []const u8,    finished_unix_ns: i128,};pub const TestReceipt = struct {    path: []const u8,    zig_version: []const u8,    started_unix_ns: i128,    finished_unix_ns: i128,    shard_count: u64,    shard_index: u64,    selected_test_count: u64,    executed_test_count: u64,    passed_test_count: u64,    skipped_test_count: u64,    failed_test_count: u64,    test_ns_observed: i128,    teardown_ns_observed: i128,    semantic_sha256: fingerprint.Digest,    pub fn semanticHex(self: TestReceipt) fingerprint.Hex {        return std.fmt.bytesToHex(self.semantic_sha256, .lower);    }};pub const Aggregate = struct {    receipt_count: u64 = 0,    selected_test_count: u64 = 0,    executed_test_count: u64 = 0,    passed_test_count: u64 = 0,    skipped_test_count: u64 = 0,    failed_test_count: u64 = 0,    test_ns_observed: i128 = 0,    teardown_ns_observed: i128 = 0,    semantic_sha256: fingerprint.Digest,    pub fn semanticHex(self: Aggregate) fingerprint.Hex {        return std.fmt.bytesToHex(self.semantic_sha256, .lower);    }};pub const Batch = struct {    marker: Marker,    receipts: []const TestReceipt,    aggregate: Aggregate,};const LocatedMarker = struct {    path: []const u8,    finished_unix_ns: i128,};pub fn markerAt(    allocator: std.mem.Allocator,    directory: []const u8,    token: []const u8,    index: usize,) !?Marker {    var markers: std.ArrayList(LocatedMarker) = .empty;    const entries = try sys.fs.listDirAlloc(allocator, directory);    for (entries) |entry| {        if (entry.kind != .file or            !std.mem.endsWith(u8, entry.name, ".json"))        {            continue;        }        const document = try loadDocument(allocator, entry.path);        const object = try json.object(document);        const schema = json.string(object.get("schema")) orelse            return error.InvalidIterationReceipt;        if (!std.mem.eql(u8, schema, model.marker_schema)) continue;        try requireToken(object, token);        try markers.append(allocator, .{            .path = entry.path,            .finished_unix_ns = json.asI128(                object.get("finished_unix_ns"),            ) orelse return error.InvalidIterationMarker,        });    }    std.mem.sort(LocatedMarker, markers.items, {}, markerBefore);    if (index >= markers.items.len) return null;    const selected = markers.items[index];    return .{        .path = try allocator.dupe(u8, selected.path),        .finished_unix_ns = selected.finished_unix_ns,    };}pub fn load(    allocator: std.mem.Allocator,    directory: []const u8,    token: []const u8,    previous_marker_unix_ns: ?i128,    marker: Marker,) !Batch {    var receipts: std.ArrayList(TestReceipt) = .empty;    const entries = try sys.fs.listDirAlloc(allocator, directory);    for (entries) |entry| {        if (entry.kind != .file or            !std.mem.endsWith(u8, entry.name, ".json"))        {            continue;        }        const document = try loadDocument(allocator, entry.path);        const object = try json.object(document);        const schema = json.string(object.get("schema")) orelse            return error.InvalidIterationReceipt;        if (!std.mem.eql(u8, schema, model.test_receipt_schema)) continue;        try requireToken(object, token);        const finished_unix_ns = json.asI128(            object.get("finished_unix_ns"),        ) orelse return error.InvalidTestRunReceipt;        if (finished_unix_ns > marker.finished_unix_ns or            (previous_marker_unix_ns != null and                finished_unix_ns <= previous_marker_unix_ns.?))        {            continue;        }        try receipts.append(            allocator,            try parseTestReceipt(                allocator,                entry.path,                object,                finished_unix_ns,            ),        );    }    std.mem.sort(TestReceipt, receipts.items, {}, receiptBefore);    const summary = try aggregate(allocator, receipts.items);    const owned_receipts = try receipts.toOwnedSlice(allocator);    return .{        .marker = marker,        .receipts = owned_receipts,        .aggregate = summary,    };}fn parseTestReceipt(    allocator: std.mem.Allocator,    path: []const u8,    object: std.json.ObjectMap,    finished_unix_ns: i128,) !TestReceipt {    return .{        .path = try allocator.dupe(u8, path),        .zig_version = try allocator.dupe(            u8,            json.string(object.get("zig_version")) orelse                return error.InvalidTestRunReceipt,        ),        .started_unix_ns = json.asI128(            object.get("started_unix_ns"),        ) orelse return error.InvalidTestRunReceipt,        .finished_unix_ns = finished_unix_ns,        .shard_count = try requiredU64(object, "shard_count"),        .shard_index = try requiredU64(object, "shard_index"),        .selected_test_count = try requiredU64(            object,            "selected_test_count",        ),        .executed_test_count = try requiredU64(            object,            "executed_test_count",        ),        .passed_test_count = try requiredU64(            object,            "passed_test_count",        ),        .skipped_test_count = try requiredU64(            object,            "skipped_test_count",        ),        .failed_test_count = try requiredU64(            object,            "failed_test_count",        ),        .test_ns_observed = json.asI128(            object.get("test_ns_observed"),        ) orelse return error.InvalidTestRunReceipt,        .teardown_ns_observed = json.asI128(            object.get("teardown_ns_observed"),        ) orelse return error.InvalidTestRunReceipt,        .semantic_sha256 = try parseDigest(            json.string(object.get("semantic_sha256")) orelse                return error.InvalidTestRunReceipt,        ),    };}fn aggregate(    allocator: std.mem.Allocator,    receipts: []const TestReceipt,) !Aggregate {    var result = Aggregate{        .semantic_sha256 = undefined,    };    var digests = try allocator.alloc(        fingerprint.Digest,        receipts.len,    );    for (receipts, 0..) |receipt, index| {        result.receipt_count = try add(            result.receipt_count,            1,        );        result.selected_test_count = try add(            result.selected_test_count,            receipt.selected_test_count,        );        result.executed_test_count = try add(            result.executed_test_count,            receipt.executed_test_count,        );        result.passed_test_count = try add(            result.passed_test_count,            receipt.passed_test_count,        );        result.skipped_test_count = try add(            result.skipped_test_count,            receipt.skipped_test_count,        );        result.failed_test_count = try add(            result.failed_test_count,            receipt.failed_test_count,        );        result.test_ns_observed += receipt.test_ns_observed;        result.teardown_ns_observed += receipt.teardown_ns_observed;        digests[index] = receipt.semantic_sha256;    }    std.mem.sort(        fingerprint.Digest,        digests,        {},        digestBefore,    );    var hasher = std.crypto.hash.sha2.Sha256.init(.{});    hasher.update("tiny.profiling.iteration-test-batch/v1");    for (digests) |digest| hasher.update(&digest);    hasher.final(&result.semantic_sha256);    return result;}fn loadDocument(    allocator: std.mem.Allocator,    path: []const u8,) !std.json.Value {    const text = try sys.fs.readFileAlloc(        allocator,        path,        maximum_receipt_bytes,    );    return try std.json.parseFromSliceLeaky(        std.json.Value,        allocator,        text,        .{},    );}fn requireToken(    object: std.json.ObjectMap,    expected: []const u8,) !void {    const actual = json.string(object.get("token")) orelse        return error.InvalidIterationReceipt;    if (!std.mem.eql(u8, actual, expected)) {        return error.IterationReceiptTokenMismatch;    }}fn requiredU64(    object: std.json.ObjectMap,    field: []const u8,) !u64 {    return json.asU64(object.get(field)) orelse        error.InvalidTestRunReceipt;}fn parseDigest(value: []const u8) !fingerprint.Digest {    if (value.len != std.crypto.hash.sha2.Sha256.digest_length * 2) {        return error.InvalidTestRunDigest;    }    var digest: fingerprint.Digest = undefined;    _ = std.fmt.hexToBytes(&digest, value) catch        return error.InvalidTestRunDigest;    return digest;}fn add(left: u64, right: u64) !u64 {    return std.math.add(u64, left, right) catch        return error.IterationCountOverflow;}fn markerBefore(    _: void,    left: LocatedMarker,    right: LocatedMarker,) bool {    return left.finished_unix_ns < right.finished_unix_ns;}fn receiptBefore(    _: void,    left: TestReceipt,    right: TestReceipt,) bool {    if (left.started_unix_ns != right.started_unix_ns) {        return left.started_unix_ns < right.started_unix_ns;    }    return left.shard_index < right.shard_index;}fn digestBefore(    _: void,    left: fingerprint.Digest,    right: fingerprint.Digest,) bool {    return std.mem.order(u8, &left, &right) == .lt;}test "iteration receipt batches aggregate deterministic semantics" {    var arena_state = std.heap.ArenaAllocator.init(std.testing.allocator);    defer arena_state.deinit();    const allocator = arena_state.allocator();    const first_digest = try parseDigest(        "0000000000000000000000000000000000000000000000000000000000000001",    );    const second_digest = try parseDigest(        "0000000000000000000000000000000000000000000000000000000000000002",    );    const receipts = [_]TestReceipt{        .{            .path = "one",            .zig_version = "zig",            .started_unix_ns = 1,            .finished_unix_ns = 2,            .shard_count = 1,            .shard_index = 0,            .selected_test_count = 3,            .executed_test_count = 3,            .passed_test_count = 3,            .skipped_test_count = 0,            .failed_test_count = 0,            .test_ns_observed = 10,            .teardown_ns_observed = 2,            .semantic_sha256 = second_digest,        },        .{            .path = "two",            .zig_version = "zig",            .started_unix_ns = 3,            .finished_unix_ns = 4,            .shard_count = 1,            .shard_index = 0,            .selected_test_count = 2,            .executed_test_count = 2,            .passed_test_count = 2,            .skipped_test_count = 0,            .failed_test_count = 0,            .test_ns_observed = 20,            .teardown_ns_observed = 4,            .semantic_sha256 = first_digest,        },    };    const result = try aggregate(allocator, &receipts);    try std.testing.expectEqual(@as(u64, 5), result.selected_test_count);    try std.testing.expectEqual(@as(i128, 30), result.test_ns_observed);}

Source: src/profiling/iteration/root.zig:1

zig
pub const batch = @import("batch.zig");

Audit

Definitions9
Public names9
Members28
Version26.7.0
Revisiondaab053ee433