Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
119 changes: 119 additions & 0 deletions zigux/tests/phase1_rbtree_cached_bench_replay.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
const std = @import("std");
const rbtree = @import("rbtree");

const iterations_rbtree = 4_000;

const RbEntry = struct {
key: i32,
node: rbtree.Node = .{},
};

fn less(a: *const rbtree.Node, b: *const rbtree.Node) bool {
const lhs: *const RbEntry = @fieldParentPtr("node", a);
const rhs: *const RbEntry = @fieldParentPtr("node", b);
return lhs.key < rhs.key;
}

const CachedReplay = struct {
checksum: u64,
initial_leftmost_key: i32,
erase_non_leftmost_returned_leftmost: bool,
promoted_leftmost_key: i32,
replacement_leftmost_key: i32,
inserted_leftmost_key: i32,
add_cached_leftmost_keys: [3]i32,
};

fn runCachedReplay() CachedReplay {
var cached_entries = [_]RbEntry{
.{ .key = 10 },
.{ .key = 5 },
.{ .key = 20 },
.{ .key = 15 },
};
var cached_replacement = RbEntry{ .key = 10 };
var new_leftmost = RbEntry{ .key = 3 };
var cached_root = rbtree.RootCached.init();
var add_cached_leftmost_keys = [_]i32{ -1, -1, -1 };
var add_cached_leftmost_count: usize = 0;

for (&cached_entries) |*entry| {
if (rbtree.addCached(&entry.node, &cached_root, less)) |leftmost| {
const leftmost_entry: *const RbEntry = @fieldParentPtr("node", leftmost);
add_cached_leftmost_keys[add_cached_leftmost_count] = leftmost_entry.key;
add_cached_leftmost_count += 1;
}
}

const initial_leftmost_entry: *const RbEntry = @fieldParentPtr(
"node",
rbtree.firstCached(&cached_root).?,
);
const erase_non_leftmost_returned_leftmost =
rbtree.eraseCached(&cached_entries[2].node, &cached_root) == null;
const still_leftmost_entry: *const RbEntry = @fieldParentPtr(
"node",
rbtree.firstCached(&cached_root).?,
);
std.debug.assert(still_leftmost_entry.key == initial_leftmost_entry.key);

const promoted_leftmost = rbtree.eraseCached(&cached_entries[1].node, &cached_root) orelse unreachable;
const promoted_leftmost_entry: *const RbEntry = @fieldParentPtr("node", promoted_leftmost);

rbtree.replaceNodeCached(&cached_entries[0].node, &cached_replacement.node, &cached_root);
const replacement_leftmost_entry: *const RbEntry = @fieldParentPtr(
"node",
rbtree.firstCached(&cached_root).?,
);

if (rbtree.addCached(&new_leftmost.node, &cached_root, less)) |leftmost| {
const leftmost_entry: *const RbEntry = @fieldParentPtr("node", leftmost);
add_cached_leftmost_keys[add_cached_leftmost_count] = leftmost_entry.key;
add_cached_leftmost_count += 1;
}
const inserted_leftmost_entry: *const RbEntry = @fieldParentPtr(
"node",
rbtree.firstCached(&cached_root).?,
);

var checksum: u64 = 0;
checksum +%= @as(u64, @intFromBool(rbtree.first(&cached_root.root) == rbtree.firstCached(&cached_root)));
checksum +%= @intCast(initial_leftmost_entry.key);
checksum +%= @as(u64, @intFromBool(erase_non_leftmost_returned_leftmost));
checksum +%= @intCast(still_leftmost_entry.key);
checksum +%= @intCast(promoted_leftmost_entry.key);
checksum +%= @as(u64, @intFromBool(rbtree.first(&cached_root.root) == rbtree.firstCached(&cached_root)));
checksum +%= @intCast(replacement_leftmost_entry.key);
checksum +%= @intCast(inserted_leftmost_entry.key);
checksum +%= @as(u64, @intFromBool(rbtree.first(&cached_root.root) == rbtree.firstCached(&cached_root)));

return .{
.checksum = checksum,
.initial_leftmost_key = initial_leftmost_entry.key,
.erase_non_leftmost_returned_leftmost = erase_non_leftmost_returned_leftmost,
.promoted_leftmost_key = promoted_leftmost_entry.key,
.replacement_leftmost_key = replacement_leftmost_entry.key,
.inserted_leftmost_key = inserted_leftmost_entry.key,
.add_cached_leftmost_keys = add_cached_leftmost_keys,
};
}

test "phase1 rbtree cached bench replay keeps leftmost-return semantics explicit" {
const replay = runCachedReplay();
try std.testing.expectEqual(@as(i32, 5), replay.initial_leftmost_key);
try std.testing.expect(replay.erase_non_leftmost_returned_leftmost);
try std.testing.expectEqual(@as(i32, 10), replay.promoted_leftmost_key);
try std.testing.expectEqual(@as(i32, 10), replay.replacement_leftmost_key);
try std.testing.expectEqual(@as(i32, 3), replay.inserted_leftmost_key);
try std.testing.expectEqual([3]i32{ 10, 5, 3 }, replay.add_cached_leftmost_keys);
try std.testing.expectEqual(@as(u64, 37), replay.checksum);
}

test "phase1 rbtree cached bench replay matches the bench checksum packet" {
var checksum: u64 = 0;
var idx: usize = 0;
while (idx < iterations_rbtree) : (idx += 1) {
checksum +%= runCachedReplay().checksum;
}
try std.testing.expectEqual(@as(u64, 148_000), checksum);
}
39 changes: 39 additions & 0 deletions zigux/tests/phase1_rbtree_cached_bench_replay_build.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
const std = @import("std");

pub fn build(b: *std.Build) void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});

const root_module = b.createModule(.{
.root_source_file = b.path("phase1_rbtree_cached_bench_replay.zig"),
.target = target,
.optimize = optimize,
});
const rbtree_module = b.createModule(.{
.root_source_file = b.path("../../tools/lib/rbtree.zig"),
.target = target,
.optimize = optimize,
});

root_module.addImport("rbtree", rbtree_module);

const replay_tests = b.addTest(.{
.name = "phase1-rbtree-cached-bench-replay",
.root_module = root_module,
});
const run_replay = b.addRunArtifact(replay_tests);

const replay_step = b.step(
"phase1-rbtree-cached-bench-replay",
"Run the focused Phase 1 rbtree cached bench replay from zigux/tests",
);
replay_step.dependOn(&run_replay.step);

const test_step = b.step(
"test",
"Run the focused Phase 1 rbtree cached bench replay from zigux/tests",
);
test_step.dependOn(&run_replay.step);

b.default_step.dependOn(test_step);
}
Loading