use crate::channel::prepared::Prepared;
use crate::engine::gpu::GPU_LOG_TARGET;
use crate::engine::knob::Knob;
use crate::pauli_sum::hash::B_MAX_BITS;
use crate::pauli_sum::storage::desired_bits;
pub const DEFAULT_RECORDS_PER_BLOCK: usize = 4096;
pub const DEFAULT_ARENA_BYTES: usize = 4 << 30;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct GpuLayerOptions {
pub records_per_block: usize,
pub arena_bytes: usize,
pub max_bits: u8,
pub premerge: bool,
pub exchange_bytes: usize,
pub clifford: bool,
}
static EXCHANGE_BYTES: Knob<usize> =
Knob::new("PAULISTRINGS_GPU_EXCHANGE_BYTES", GPU_LOG_TARGET, parse_bytes, || usize::MAX);
pub(super) fn parse_bytes(text: &str) -> Option<usize> {
let (digits, shift) = match text.as_bytes().last() {
Some(b'K' | b'k') => (&text[..text.len() - 1], 10),
Some(b'M' | b'm') => (&text[..text.len() - 1], 20),
Some(b'G' | b'g') => (&text[..text.len() - 1], 30),
_ => (text, 0),
};
digits.parse::<usize>().ok().filter(|&n| n > 0).and_then(|n| n.checked_mul(1usize << shift))
}
impl Default for GpuLayerOptions {
fn default() -> Self {
Self {
records_per_block: DEFAULT_RECORDS_PER_BLOCK,
arena_bytes: DEFAULT_ARENA_BYTES,
max_bits: B_MAX_BITS,
premerge: true,
exchange_bytes: *EXCHANGE_BYTES.get(),
clifford: true,
}
}
}
impl GpuLayerOptions {
pub fn validate(&self) -> Result<(), String> {
if self.records_per_block == 0 {
return Err("records_per_block must be at least 1, got 0".to_string());
}
if self.arena_bytes == 0 {
return Err("arena_bytes must be at least 1, got 0".to_string());
}
if self.max_bits > B_MAX_BITS {
return Err(format!("max_bits must be at most {B_MAX_BITS}, got {}", self.max_bits));
}
Ok(())
}
pub(crate) fn assert_valid(&self) {
if let Err(message) = self.validate() {
panic!("{message}");
}
}
}
pub(crate) fn gpu_desired_bits(
len: usize,
fanout: usize,
records_per_block: usize,
current: u8,
) -> u8 {
desired_bits(len.saturating_mul(fanout.max(1)), records_per_block.max(1), 1)
.max(current)
.min(B_MAX_BITS)
}
pub(crate) fn prepared_fanout<const W: usize>(prepared: &Prepared<W>) -> usize {
match prepared {
Prepared::Local(ptm) => ptm.emitting_entries(),
Prepared::Rotation(_) => 2,
}
}