ke: optimize TLB shootdowns

This commit is contained in:
Loïc Grégoire
2026-08-09 16:44:41 -04:00
parent 52f62b8354
commit 63cd104616
3 changed files with 61 additions and 19 deletions
+1 -2
View File
@@ -53,7 +53,6 @@ pub fn unicast(
const state = remote.state.swap(.Pending, .release); const state = remote.state.swap(.Pending, .release);
if (state == .Idle) { if (state == .Idle) {
std.log.info("Sent ipi", .{});
pl.send_ipi(cpu); pl.send_ipi(cpu);
} }
@@ -65,7 +64,7 @@ pub fn unicast(
} }
pub fn broadcast(func: *const fn (u32, ?*anyopaque) void, arg: ?*anyopaque) void { pub fn broadcast(func: *const fn (u32, ?*anyopaque) void, arg: ?*anyopaque) void {
const ipl = ke.ipl.raise(.High); const ipl = ke.ipl.raise(.Dispatch);
const curcpu = percpu.local(); const curcpu = percpu.local();
curcpu.func = func; curcpu.func = func;
+48 -14
View File
@@ -38,6 +38,7 @@ const PerCpu = struct {
/// CPUs that have sent this CPU a shootdown. /// CPUs that have sent this CPU a shootdown.
senders: ke.AtomicCpuMask, senders: ke.AtomicCpuMask,
npages: std.atomic.Value(u32),
sync_addr: r.VAddr, sync_addr: r.VAddr,
sync_count: usize, sync_count: usize,
}; };
@@ -118,32 +119,55 @@ pub fn process_shootdowns() void {
const cpu = percpu.local(); const cpu = percpu.local();
const curcpu = ke.cpu.current(); const curcpu = ke.cpu.current();
rtl.barrier.fence(.acquire);
if (cpu.senders.is_all(false, .monotonic)) { if (cpu.senders.is_all(false, .monotonic)) {
// Nothing to do. // Nothing to do.
return; return;
} }
var claimed: [config.ncpus]u64 = @splat(0);
var nreq: usize = 0;
var iter = cpu.senders.iter(.monotonic); var iter = cpu.senders.iter(.monotonic);
// Go through every sender and get their states.
while (iter.next()) |i| { while (iter.next()) |i| {
if (i == curcpu) continue; if (i == curcpu) continue;
cpu.senders.clear(i, .monotonic); cpu.senders.clear(i, .monotonic);
const states = percpu.remote(@truncate(i)).valid_states[curcpu].swap(
0,
.acquire,
);
claimed[i] = states;
nreq += @popCount(states);
}
if (nreq == 0) return;
// npages is just a hint, we don't need it to be accurate.
const full = cpu.npages.load(.monotonic) >= ki.impl.tlb_max_pages;
cpu.npages.store(0, .monotonic);
if (full) {
// Just flush the entire thing.
ki.impl.flush_full_tlb();
}
// Go through every sender and release their states.
// Additionally flush the ranges that didn't get flushed previously.
for (0.., &claimed) |i, states| {
if (states == 0) continue;
const sender = percpu.remote(@truncate(i)); const sender = percpu.remote(@truncate(i));
var bits = states;
while (true) { while (bits != 0) : (bits &= bits - 1) {
var states = sender.valid_states[curcpu].swap(0, .acquire); const state = &sender.states[@ctz(bits)];
if (states == 0) break;
while (states != 0) { if (!full) flush_range(state.base, state.npages);
// Go through each set bit and invalidate the slot.
const bit = @ctz(states);
states &= ~(@as(u64, 1) << @intCast(bit));
const state = &sender.states[bit];
flush_range(state.base, state.npages);
if (state.state.fetchSub(1, .release) == 1) { if (state.state.fetchSub(1, .release) == 1) {
shootdowns.insert(&state.link); shootdowns.insert(&state.link);
@@ -151,6 +175,9 @@ pub fn process_shootdowns() void {
} }
} }
} }
fn process_shootdowns_kick(_: u32, _: ?*anyopaque) void {
process_shootdowns();
} }
/// Submit a shootdown to occur asynchronously on `target_mask`. /// Submit a shootdown to occur asynchronously on `target_mask`.
@@ -171,7 +198,10 @@ pub fn submit(state: ShootdownState, target_mask: ke.CpuMask) !void {
}; };
cpu.states[slot] = state; cpu.states[slot] = state;
cpu.states[slot].state.store(@truncate(target_mask.count()), .release); cpu.states[slot].state.store(
@truncate(target_mask.count()),
.release,
);
var iter = target_mask.iter(); var iter = target_mask.iter();
@@ -183,9 +213,13 @@ pub fn submit(state: ShootdownState, target_mask: ke.CpuMask) !void {
.release, .release,
); );
ki.ipl.set_softint_pending(@truncate(bit), .Dispatch); const remote = percpu.remote(@truncate(bit));
// Tell him we have something for him. // Tell him we have something for him.
percpu.remote(@truncate(bit)).senders.set(curcpu, .release); _ = remote.npages.fetchAdd(state.npages, .monotonic);
remote.senders.set(curcpu, .release);
rtl.barrier.fence(.release);
ki.ipl.set_softint_pending(@truncate(bit), .Dispatch);
} }
} }
+9
View File
@@ -74,6 +74,9 @@ pub fn reclaim_range(space: *mm.Space, va: r.VAddr, size: usize) void {
}, },
}; };
space.lock.release();
const ipl = ke.ipl.raise(.Dispatch);
var mask: ke.CpuMask = .init(false); var mask: ke.CpuMask = .init(false);
for (0..ke.ncpus) |i| { for (0..ke.ncpus) |i| {
@@ -84,6 +87,9 @@ pub fn reclaim_range(space: *mm.Space, va: r.VAddr, size: usize) void {
ke.shootdown.submit(state, mask) catch { ke.shootdown.submit(state, mask) catch {
_ = sync_shootdowns.fetchAdd(1, .monotonic); _ = sync_shootdowns.fetchAdd(1, .monotonic);
ke.ipl.lower(ipl);
space.lock.acquire();
space.arena.free(va, size) catch unreachable; space.arena.free(va, size) catch unreachable;
// Free the physical pages // Free the physical pages
@@ -94,6 +100,9 @@ pub fn reclaim_range(space: *mm.Space, va: r.VAddr, size: usize) void {
); );
return; return;
}; };
ke.ipl.lower(ipl);
space.lock.acquire();
} }
fn activation(_: *rtl.HandoffList) void { fn activation(_: *rtl.HandoffList) void {