Skip to content

Commit 75445f0

Browse files
committed
Refill run queue directly from overflow
1 parent efc1b6a commit 75445f0

1 file changed

Lines changed: 43 additions & 9 deletions

File tree

src/utils/local_run_queue.zig

Lines changed: 43 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -244,16 +244,14 @@ pub fn LocalRunQueue(comptime T: type, comptime stealable: bool) type {
244244
const t = self.ownTail();
245245
const h = self.loadHead();
246246
const space: usize = capacity - (t -% h);
247-
var buf: [64]*T = undefined;
248-
const want = @min(space, @min(max, buf.len));
247+
const max_batch = 64;
248+
const start: usize = t & mask;
249+
const contiguous = capacity - start;
250+
const want = @min(contiguous, @min(space, @min(max, max_batch)));
249251
if (want == 0) return;
250-
const got = self.overflow.popBatch(buf[0..want]);
251-
var tt = t;
252-
for (buf[0..got]) |node| {
253-
self.buffer[tt & mask] = node;
254-
tt +%= 1;
255-
}
256-
if (got > 0) self.storeTail(tt);
252+
253+
const got = self.overflow.popBatch(self.buffer[start .. start + want]);
254+
if (got > 0) self.storeTail(t +% @as(u32, @intCast(got)));
257255
}
258256

259257
/// Number of tasks currently in the ring (used for maybeYield fairness).
@@ -414,6 +412,42 @@ test "LocalRunQueue: non-stealable variant pushes, pops, and overflows" {
414412
try testing.expect(q.isEmpty());
415413
}
416414

415+
test "LocalRunQueue: refill writes directly on both sides of ring wrap" {
416+
var ov: TestOverflow = .{};
417+
var q = TestLocalQueue.init(&ov);
418+
var nodes: [270]TestNode = undefined;
419+
420+
// Advance both cursors near the physical end while leaving the ring empty.
421+
for (nodes[0..250], 0..) |*node, id| {
422+
node.* = .{ .id = id };
423+
_ = q.push(node);
424+
}
425+
for (0..250) |id| {
426+
try testing.expectEqual(id, (q.pop() orelse return error.Unexpected).id);
427+
}
428+
429+
// The first refill stops at the physical end of the ring.
430+
for (nodes[250..], 250..) |*node, id| {
431+
node.* = .{ .id = id };
432+
ov.push(node);
433+
}
434+
q.refill(20);
435+
try testing.expectEqual(6, q.len());
436+
try testing.expectEqual(14, ov.len());
437+
for (250..256) |id| {
438+
try testing.expectEqual(id, (q.pop() orelse return error.Unexpected).id);
439+
}
440+
441+
// Once tail wraps, the next refill writes directly at the ring's start.
442+
q.refill(20);
443+
try testing.expectEqual(14, q.len());
444+
try testing.expect(ov.isEmpty());
445+
for (256..270) |id| {
446+
try testing.expectEqual(id, (q.pop() orelse return error.Unexpected).id);
447+
}
448+
try testing.expect(q.isEmpty());
449+
}
450+
417451
test "LocalRunQueue: steal takes half into the thief and returns one" {
418452
var ov1: TestOverflow = .{};
419453
var ov2: TestOverflow = .{};

0 commit comments

Comments
 (0)