mm/zone: add drain

This commit is contained in:
Loïc Grégoire
2026-07-03 23:32:18 -04:00
parent a5d42963ff
commit e993ea711c
+46 -7
View File
@@ -698,7 +698,7 @@ pub const Zone = struct {
/// Periodic updates on the zone. /// Periodic updates on the zone.
/// Updates the working set and trims it if needed (for now, will do magazine resizing later...). /// Updates the working set and trims it if needed (for now, will do magazine resizing later...).
pub fn update(self: *Self) void { fn update(self: *Self) void {
const ipl = self.depot_lock.acquire(); const ipl = self.depot_lock.acquire();
// Update the working set size. // Update the working set size.
@@ -782,7 +782,7 @@ pub const Zone = struct {
return false; return false;
} }
/// Called when memory needs to be reaped from this zone. /// Called periodically to trim our magazines.
/// This frees the excess magazines. /// This frees the excess magazines.
fn trim(self: *Self, trim_depot: bool) void { fn trim(self: *Self, trim_depot: bool) void {
// Note: we do all of this under the zone lock, // Note: we do all of this under the zone lock,
@@ -797,7 +797,7 @@ pub const Zone = struct {
var depot = std.mem.zeroes(Depot); var depot = std.mem.zeroes(Depot);
for (0..ke.ncpus) |i| { for (0..ke.ncpus) |i| {
self.trim_cpu(&self.cpus[i], &depot); trim_cpu(&self.cpus[i], &depot, self.cpu_depot_size);
} }
self.maglist_destroy(depot.empty_mags.list, 0); self.maglist_destroy(depot.empty_mags.list, 0);
@@ -807,6 +807,34 @@ pub const Zone = struct {
self.lock.release(); self.lock.release();
} }
/// Called when memory is low and we need to make memory ASAP.
/// Drains all magazines from the depot.
fn drain(self: *Self) void {
if (!self.use_magazines) return;
// Note: we do all of this under the zone lock,
// but it *should* be a fairly quick operation, even though it is O(ncpus).
self.lock.acquire();
const ipl = self.depot_lock.acquire();
// Take all elements from the zone depot.
var depot = self.depot;
self.depot = std.mem.zeroes(Depot);
self.depot_lock.release(ipl);
// Trim all CPU depots to 0.
for (0..ke.ncpus) |i| {
trim_cpu(&self.cpus[i], &depot, 0);
}
self.maglist_destroy(depot.empty_mags.list, 0);
self.maglist_destroy(depot.full_mags.list, magazine_size);
self.lock.release();
}
fn trim_maglist(self: *Self, maglist: *MagazineList, rounds: usize) void { fn trim_maglist(self: *Self, maglist: *MagazineList, rounds: usize) void {
const ipl = self.depot_lock.acquire(); const ipl = self.depot_lock.acquire();
@@ -844,15 +872,15 @@ pub const Zone = struct {
self.maglist_destroy(removed_head, rounds); self.maglist_destroy(removed_head, rounds);
} }
/// Trim a CPU's depot to `cpu_depot_size`. /// Trim a CPU's depot to `target`.
fn trim_cpu(self: *Self, cpu: *Cpu, depot: *Depot) void { fn trim_cpu(cpu: *Cpu, depot: *Depot, target: usize) void {
const ipl = cpu.lock.acquire(); const ipl = cpu.lock.acquire();
// Split the target (cpu_depot_size) in 2 for each magazine type. // Split the target (cpu_depot_size) in 2 for each magazine type.
// Bias towards full magazines because they are usually more useful // Bias towards full magazines because they are usually more useful
// for us than empty magazines. // for us than empty magazines.
const full_target = (self.cpu_depot_size + 1) / 2; const full_target = (target + 1) / 2;
const empty_target = self.cpu_depot_size / 2; const empty_target = target / 2;
if (cpu.depot.full_mags.num > full_target) { if (cpu.depot.full_mags.num > full_target) {
// Trim the excess full magazines. // Trim the excess full magazines.
@@ -1166,6 +1194,17 @@ pub fn late_init() linksection(r.init) void {
ex.workqueue.enqueue_in(&update_work_item, update_interval); ex.workqueue.enqueue_in(&update_work_item, update_interval);
} }
pub fn drain() void {
zone_list_lock.acquire();
var zone = all_zones;
while (zone) |z| : (zone = z.next) {
z.drain();
}
zone_list_lock.release();
}
// === Global general purpose allocator === // === Global general purpose allocator ===
pub const gpa: std.mem.Allocator = .{ pub const gpa: std.mem.Allocator = .{
.ptr = undefined, .ptr = undefined,