use crate::Engine;
use crate::dsv4_gpu::Dsv4SampleCfg;
use crate::dsv4_sampler::Dsv4DeviceSampler;
use cudarc::driver::{CudaSlice, CudaStream, DevicePtr};
use memra_sampling::SamplerConfig;
use std::sync::Arc;
type Res<T> = Result<T, Box<dyn std::error::Error>>;
fn parse_requested(value: Option<&str>) -> Result<bool, &'static str> {
match value {
None | Some("0") => Ok(false),
Some("1") => Ok(true),
_ => Err("expected 0 or 1"),
}
}
pub fn requested() -> bool {
static ON: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
*ON.get_or_init(|| {
let value = std::env::var_os("MEMRA_GLM5_TP_DEVICE_SAMPLE");
let parsed = match &value {
None => parse_requested(None),
Some(v) => v
.to_str()
.ok_or("non-Unicode flag value")
.and_then(|v| parse_requested(Some(v))),
};
parsed.unwrap_or_else(|reason| {
eprintln!("[glm5-tp-device-sample] refused: {reason}; host fallback");
false
})
})
}
#[derive(Clone, Copy, Debug)]
pub struct Glm5TpSampleConfig {
cfg: Dsv4SampleCfg,
greedy: bool,
}
impl Glm5TpSampleConfig {
pub fn for_request(
cfg: &SamplerConfig,
glm_tp_plain: bool,
host_logits: bool,
) -> Result<Self, &'static str> {
if !glm_tp_plain {
return Err("route is not GLM TP-2 plain");
}
if host_logits {
return Err("request requires host logits (constraints, logprobs or capture)");
}
if cfg.penalty_repeat != 1.0 || cfg.penalty_freq != 0.0 || cfg.penalty_present != 0.0 {
return Err("non-neutral penalties");
}
if cfg.min_p != 0.0 {
return Err("min-p is not supported by the nucleus device sampler");
}
if !cfg.temperature.is_finite() || !(cfg.top_p > 0.0 && cfg.top_p <= 1.0) {
return Err("invalid device temperature or top-p");
}
Ok(Self {
cfg: Dsv4SampleCfg {
temperature: cfg.temperature,
top_p: cfg.top_p,
top_k: cfg.top_k,
seed: cfg.seed,
},
greedy: cfg.temperature <= 0.0 || cfg.top_k == 1,
})
}
}
enum Scratch {
Greedy(CudaSlice<u32>),
Sampled(Box<Dsv4DeviceSampler>),
}
pub struct Glm5TpDeviceSampler {
stream: Arc<CudaStream>,
n: usize,
cfg: Glm5TpSampleConfig,
scratch: Scratch,
calls: u64,
}
impl Glm5TpDeviceSampler {
pub fn new(e: &Engine, n: usize, cfg: Glm5TpSampleConfig) -> Res<Self> {
if n == 0 || n > (1 << 24) {
return Err("GLM device sampler vocabulary outside 1..=2^24".into());
}
let stream = e.stream();
let scratch = if cfg.greedy {
Scratch::Greedy(stream.alloc_zeros(1)?)
} else {
Scratch::Sampled(Box::new(Dsv4DeviceSampler::new(stream.clone(), n)?))
};
Ok(Self {
stream,
n,
cfg,
scratch,
calls: 0,
})
}
pub fn engagements(&self) -> u64 {
self.calls
}
pub fn sample_host_row(&mut self, e: &Engine, row: &[f32], pos: usize) -> Res<u32> {
let logits = e.htod(row)?;
self.sample(e, &logits, pos)
}
pub fn sample(&mut self, e: &Engine, logits: &CudaSlice<f32>, pos: usize) -> Res<u32> {
if !Arc::ptr_eq(&self.stream, &e.stream())
|| !Arc::ptr_eq(&self.stream, logits.stream())
|| logits.len() != self.n
{
return Err("GLM device sampler stream or vocabulary mismatch".into());
}
let token = match &mut self.scratch {
Scratch::Greedy(out) => {
e.argmax_token_device_into(logits, out, self.n)?;
let mut token = [0u32];
self.stream.memcpy_dtoh(out, &mut token)?;
self.stream.synchronize()?;
token[0]
}
Scratch::Sampled(sampler) => {
sampler.validate_source(&self.stream, self.n)?;
let (ptr, _record) = logits.device_ptr(&self.stream);
unsafe { sampler.sample_ptr(ptr as *const f32, pos, &self.cfg.cfg, &[], None)? }
}
};
if token as usize >= self.n {
return Err("GLM device sampler returned an invalid token (nonfinite row)".into());
}
self.calls += 1;
Ok(token)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn glm5_tp_sample_args_and_refusals() {
assert_eq!(parse_requested(None), Ok(false));
assert_eq!(parse_requested(Some("0")), Ok(false));
assert_eq!(parse_requested(Some("1")), Ok(true));
assert!(parse_requested(Some("device")).is_err());
let cfg = SamplerConfig {
temperature: 0.7,
top_p: 0.95,
top_k: 40,
seed: 20260908,
..Default::default()
};
let parsed = Glm5TpSampleConfig::for_request(&cfg, true, false).unwrap();
assert_eq!(parsed.cfg.temperature, cfg.temperature);
assert_eq!(parsed.cfg.top_p, cfg.top_p);
assert_eq!(parsed.cfg.top_k, cfg.top_k);
assert_eq!(parsed.cfg.seed, cfg.seed);
assert!(!parsed.greedy);
assert!(Glm5TpSampleConfig::for_request(&cfg, false, false).is_err());
assert!(Glm5TpSampleConfig::for_request(&cfg, true, true).is_err());
for bad in [
SamplerConfig {
penalty_repeat: 1.1,
..cfg.clone()
},
SamplerConfig {
penalty_freq: 0.1,
..cfg.clone()
},
SamplerConfig {
penalty_present: 0.1,
..cfg.clone()
},
SamplerConfig {
min_p: 0.1,
..cfg.clone()
},
SamplerConfig {
temperature: f32::NAN,
..cfg.clone()
},
SamplerConfig {
top_p: 0.0,
..cfg.clone()
},
SamplerConfig {
top_p: f32::NAN,
..cfg.clone()
},
SamplerConfig {
top_p: 1.1,
..cfg.clone()
},
] {
assert!(Glm5TpSampleConfig::for_request(&bad, true, false).is_err());
}
for greedy in [
SamplerConfig {
temperature: 0.0,
..cfg.clone()
},
SamplerConfig { top_k: 1, ..cfg },
] {
assert!(
Glm5TpSampleConfig::for_request(&greedy, true, false)
.unwrap()
.greedy
);
}
}
fn host_nucleus(row: &[f32], cfg: &SamplerConfig) -> Vec<u32> {
let inv = 1.0 / cfg.temperature;
let mut p: Vec<_> = row
.iter()
.enumerate()
.map(|(i, x)| (i as u32, x * inv))
.collect();
if cfg.top_k > 0 && cfg.top_k < p.len() {
p.sort_unstable_by(|a, b| b.1.total_cmp(&a.1));
p.truncate(cfg.top_k);
}
let max = p.iter().map(|x| x.1).fold(f32::NEG_INFINITY, f32::max);
let mut sum = 0.0f32;
for x in &mut p {
x.1 = (x.1 - max).exp();
sum += x.1;
}
let inv_sum = 1.0 / sum;
for x in &mut p {
x.1 *= inv_sum;
}
p.sort_unstable_by(|a, b| b.1.total_cmp(&a.1));
let mut mass = 0.0f32;
let mut ids = Vec::new();
for (id, probability) in p {
ids.push(id);
mass += probability;
if mass >= cfg.top_p {
break;
}
}
ids
}
#[test]
#[ignore = "requires an exclusively owned CUDA box; never run on the local rig"]
fn glm5_tp_device_sampler_gpu_oracles() -> Res<()> {
let e = Engine::new(0)?;
let mut state = 20260908u64;
let mut row: Vec<f32> = (0..154_880)
.map(|_| {
state = state.wrapping_mul(6364136223846793005).wrapping_add(1);
((state >> 40) as f32 / (1u32 << 24) as f32) * 16.0 - 8.0
})
.collect();
for tied in [false, true] {
if tied {
row[17] = 10.0;
row[4097] = 10.0;
}
let host = memra_sampling::Sampler::new(SamplerConfig::default()).sample(&row);
let logits = e.htod(&row)?;
for cfg in [
SamplerConfig::default(),
SamplerConfig {
temperature: 1.0,
top_k: 1,
..Default::default()
},
] {
let cfg = Glm5TpSampleConfig::for_request(&cfg, true, false)?;
let mut device = Glm5TpDeviceSampler::new(&e, row.len(), cfg)?;
assert_eq!(device.sample(&e, &logits, 23)?, host);
assert_eq!(device.sample_host_row(&e, &row, 23)?, host);
assert_eq!(device.engagements(), 2);
}
}
for (temperature, top_p, top_k) in [(1.0, 0.95, 0), (0.7, 0.8, 40), (1.3, 0.5, 0)] {
let cfg = SamplerConfig {
temperature,
top_p,
top_k,
seed: 20260908,
..Default::default()
};
let nucleus = host_nucleus(&row, &cfg);
let parsed = Glm5TpSampleConfig::for_request(&cfg, true, false)?;
let mut device = Glm5TpDeviceSampler::new(&e, row.len(), parsed)?;
let logits = e.htod(&row)?;
let mut draws = std::collections::HashSet::new();
for pos in 0..256 {
let id = device.sample(&e, &logits, pos)?;
assert!(
nucleus.contains(&id),
"token {id} outside host nucleus at {pos}"
);
assert_eq!(
device.sample(&e, &logits, pos)?,
id,
"seed/position determinism"
);
if pos < 4 {
assert_eq!(
device.sample_host_row(&e, &row, pos)?,
id,
"prefill/restore adapter"
);
}
draws.insert(id);
}
assert!(draws.len() > 1, "sampled arm must not collapse to greedy");
eprintln!(
"GLM sampler oracle: T={temperature} top_p={top_p} top_k={top_k} nucleus={} distinct_draws={} engagements={}",
nucleus.len(),
draws.len(),
device.engagements()
);
}
Ok(())
}
}