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.
/// 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();
// Update the working set size.
@@ -782,7 +782,7 @@ pub const Zone = struct {
return false;
}
/// Called when memory needs to be reaped from this zone.
/// Called periodically to trim our magazines.
/// This frees the excess magazines.
fn trim(self: *Self, trim_depot: bool) void {
// Note: we do all of this under the zone lock,
@@ -797,7 +797,7 @@ pub const Zone = struct {
var depot = std.mem.zeroes(Depot);
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);
@@ -807,6 +807,34 @@ pub const Zone = struct {
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 {
const ipl = self.depot_lock.acquire();
@@ -844,15 +872,15 @@ pub const Zone = struct {
self.maglist_destroy(removed_head, rounds);
}
/// Trim a CPU's depot to `cpu_depot_size`.
fn trim_cpu(self: *Self, cpu: *Cpu, depot: *Depot) void {
/// Trim a CPU's depot to `target`.
fn trim_cpu(cpu: *Cpu, depot: *Depot, target: usize) void {
const ipl = cpu.lock.acquire();
// Split the target (cpu_depot_size) in 2 for each magazine type.
// Bias towards full magazines because they are usually more useful
// for us than empty magazines.
const full_target = (self.cpu_depot_size + 1) / 2;
const empty_target = self.cpu_depot_size / 2;
const full_target = (target + 1) / 2;
const empty_target = target / 2;
if (cpu.depot.full_mags.num > full_target) {
// 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);
}
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 ===
pub const gpa: std.mem.Allocator = .{
.ptr = undefined,