use std::cmp::{Ordering, Reverse};
use std::collections::BinaryHeap;
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct WeightedWorkItem {
pub id: usize,
pub cost: u64,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct DeviceLoad {
pub device_index: usize,
pub queued_cost: u64,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Partition {
pub device_index: usize,
pub item_ids: Vec<usize>,
pub total_cost: u64,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
struct PartitionHeapEntry {
total_cost: u64,
device_index: usize,
partition_index: usize,
}
impl Ord for PartitionHeapEntry {
fn cmp(&self, other: &Self) -> Ordering {
self.total_cost
.cmp(&other.total_cost)
.then_with(|| self.device_index.cmp(&other.device_index))
.then_with(|| self.partition_index.cmp(&other.partition_index))
}
}
impl PartialOrd for PartitionHeapEntry {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
pub fn partition_work_stealing(
devices: &[DeviceLoad],
items: &[WeightedWorkItem],
) -> Result<Vec<Partition>, String> {
validate_inputs(devices, items)?;
let mut partitions = Vec::new();
vyre_driver::allocation::try_reserve_vec_to_capacity(&mut partitions, devices.len()).map_err(|error| {
format!(
"partition table allocation failed for {} GPU devices: {error}. Fix: lower the adapter fanout or memory pressure before scheduling.",
devices.len()
)
})?;
let mut least_loaded = BinaryHeap::new();
vyre_foundation::allocation::try_reserve_binary_heap_to_capacity(
&mut least_loaded,
devices.len(),
)
.map_err(|error| {
format!(
"partition heap allocation failed for {} GPU devices: {error}. Fix: lower the adapter fanout or memory pressure before scheduling.",
devices.len()
)
})?;
let target_item_capacity = items.len().div_ceil(devices.len());
for device in devices {
let partition_index = partitions.len();
let mut item_ids = Vec::new();
vyre_driver::allocation::try_reserve_vec_to_capacity(&mut item_ids, target_item_capacity).map_err(|error| {
format!(
"partition assignment allocation failed for GPU device {} and {} target work slots: {error}. Fix: split the multi-GPU batch.",
device.device_index, target_item_capacity
)
})?;
partitions.push(Partition {
device_index: device.device_index,
item_ids,
total_cost: device.queued_cost,
});
least_loaded.push(Reverse(PartitionHeapEntry {
total_cost: device.queued_cost,
device_index: device.device_index,
partition_index,
}));
}
let mut ordered = Vec::new();
vyre_driver::allocation::try_reserve_vec_to_capacity(&mut ordered, items.len()).map_err(|error| {
format!(
"partition work-order allocation failed for {} items: {error}. Fix: split the multi-GPU batch.",
items.len()
)
})?;
ordered.extend(items.iter());
ordered.sort_by(|left, right| {
right
.cost
.cmp(&left.cost)
.then_with(|| left.id.cmp(&right.id))
});
for item in ordered {
let Some(mut target) = least_loaded.pop().map(|entry| entry.0) else {
return Err(
"partition target not found. Fix: validate non-empty device list before partitioning."
.to_string()
);
};
let partition = &mut partitions[target.partition_index];
ensure_vec_spare(&mut partition.item_ids, 1, "partition assignment list")?;
partition.item_ids.push(item.id);
partition.total_cost = partition.total_cost.checked_add(item.cost).ok_or_else(|| {
"partition cost overflow. Fix: split the batch before multi-GPU scheduling.".to_string()
})?;
target.total_cost = partition.total_cost;
least_loaded.push(Reverse(target));
}
Ok(partitions)
}
fn validate_inputs(devices: &[DeviceLoad], items: &[WeightedWorkItem]) -> Result<(), String> {
if devices.is_empty() {
return Err(
"no GPU devices supplied. Fix: probe adapters before partitioning.".to_string(),
);
}
let mut seen = rustc_hash::FxHashSet::default();
vyre_foundation::allocation::try_reserve_hash_set_to_capacity(&mut seen, devices.len()).map_err(|error| {
format!(
"GPU device validation allocation failed for {} devices: {error}. Fix: lower adapter fanout or memory pressure before scheduling.",
devices.len()
)
})?;
for device in devices {
if !seen.insert(device.device_index) {
return Err(format!(
"duplicate GPU device index {}. Fix: pass each adapter exactly once.",
device.device_index
));
}
}
for item in items {
if item.cost == 0 {
return Err(format!(
"work item {} has zero cost. Fix: assign at least one cost unit or remove it.",
item.id
));
}
}
let mut seen_items = rustc_hash::FxHashSet::default();
vyre_foundation::allocation::try_reserve_hash_set_to_capacity(&mut seen_items, items.len()).map_err(|error| {
format!(
"work item validation allocation failed for {} items: {error}. Fix: split the multi-GPU batch.",
items.len()
)
})?;
for item in items {
if !seen_items.insert(item.id) {
return Err(format!(
"duplicate work item id {}. Fix: assign a unique stable id to every multi-GPU work item.",
item.id
));
}
}
Ok(())
}
fn ensure_vec_spare<T>(vec: &mut Vec<T>, additional: usize, label: &str) -> Result<(), String> {
let spare = vec.capacity().saturating_sub(vec.len());
if spare >= additional {
return Ok(());
}
vec.try_reserve_exact(additional - spare).map_err(|error| {
format!(
"{label} allocation failed while extending by {additional} entries: {error}. Fix: split the multi-GPU batch."
)
})
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn multi_gpu_partition_unit() {
let devices = [
DeviceLoad {
device_index: 0,
queued_cost: 0,
},
DeviceLoad {
device_index: 1,
queued_cost: 4,
},
];
let items = [
WeightedWorkItem { id: 10, cost: 9 },
WeightedWorkItem { id: 11, cost: 4 },
WeightedWorkItem { id: 12, cost: 4 },
WeightedWorkItem { id: 13, cost: 1 },
];
let partitions = partition_work_stealing(&devices, &items)
.expect("Fix: valid synthetic device loads must partition");
let mut assigned = partitions
.iter()
.flat_map(|partition| partition.item_ids.iter().copied())
.collect::<Vec<_>>();
assigned.sort_unstable();
assert_eq!(assigned, vec![10, 11, 12, 13]);
let spread = partitions
.iter()
.map(|partition| partition.total_cost)
.max()
.zip(
partitions
.iter()
.map(|partition| partition.total_cost)
.min(),
)
.map(|(max, min)| max - min)
.expect("Fix: partitions must be non-empty");
assert!(
spread <= 5,
"synthetic work stealing left an avoidable load spread: {partitions:?}"
);
}
#[test]
fn rejects_duplicate_device_ordinals() {
let devices = [
DeviceLoad {
device_index: 0,
queued_cost: 0,
},
DeviceLoad {
device_index: 0,
queued_cost: 1,
},
];
let error = partition_work_stealing(&devices, &[WeightedWorkItem { id: 1, cost: 1 }])
.expect_err("Fix: duplicate synthetic device indices must be rejected");
assert!(error.contains("duplicate GPU device index"));
}
#[test]
fn partition_source_has_no_release_path_infallible_allocation() {
let source = include_str!("partition.rs");
let production = source
.split("#[cfg(test)]")
.next()
.expect("Fix: partition production source must precede tests");
assert!(
!production.contains("Vec::with_capacity")
&& !production.contains("BinaryHeap::with_capacity")
&& !production.contains("with_capacity_and_hasher"),
"Fix: WGPU multi-GPU partitioning must report allocation pressure instead of aborting on infallible capacity constructors."
);
assert!(
production.contains("try_reserve_vec_to_capacity")
&& production.contains("try_reserve_binary_heap_to_capacity")
&& production.contains("try_reserve_hash_set_to_capacity")
&& production.contains("ensure_vec_spare"),
"Fix: WGPU multi-GPU partitioning must use fallible allocation for schedule tables and per-device assignments."
);
}
}