1use std::any::Any;
15use std::cell::{Cell, RefCell};
16use std::collections::HashMap;
17use std::rc::Rc;
18use std::sync::Arc;
19
20use pagesift_infer::{Conv2d, Tensor};
21
22use crate::Gpu;
23use crate::buffer::{Args, DeviceBuffer};
24use crate::driver::{DevPtr, Handle};
25use crate::ops::{BLOCK_1D, blocks_1d};
26use crate::pool::{OOM_TAG, Pool, bytes, capacity_class};
27
28pub type Owner = Arc<dyn Any + Send + Sync>;
30
31struct Cached<'g> {
33 buf: DeviceBuffer<'g>,
34 _owner: Owner,
36}
37
38pub struct Ctx<'g> {
40 pub(crate) gpu: &'g Gpu,
41 pub(crate) pool: RefCell<Pool<'g>>,
42 weights: RefCell<HashMap<(usize, usize), Cached<'g>>>,
43 pub(crate) hashed: RefCell<HashMap<u64, DeviceBuffer<'g>>>,
44 weight_bytes: Cell<u64>,
45}
46
47impl<'g> Ctx<'g> {
48 pub fn new(gpu: &'g Gpu) -> Ctx<'g> {
49 Ctx {
50 gpu,
51 pool: RefCell::new(Pool::new()),
52 weights: RefCell::new(HashMap::new()),
53 hashed: RefCell::new(HashMap::new()),
54 weight_bytes: Cell::new(0),
55 }
56 }
57
58 pub fn gpu(&self) -> &'g Gpu {
59 self.gpu
60 }
61
62 pub fn exec<'c>(&'c self, n: usize, owner: Owner) -> BatchExec<'c, 'g> {
64 BatchExec::new(self, n, owner, false)
65 }
66
67 pub fn dry<'c>(&'c self, n: usize, owner: Owner) -> BatchExec<'c, 'g> {
69 BatchExec::new(self, n, owner, true)
70 }
71
72 pub fn peak_bytes(&self) -> u64 {
74 self.pool.borrow().peak() + self.weight_bytes.get()
75 }
76
77 pub fn needed_bytes(&self) -> u64 {
79 self.pool.borrow().in_use_peak() + self.weight_bytes.get()
80 }
81
82 pub fn reset_peak(&self) {
83 self.pool.borrow_mut().reset_peak();
84 }
85
86 pub fn available_bytes(&self) -> Result<u64, String> {
88 Ok(self.gpu.memory_free()? + self.pool.borrow().idle())
89 }
90
91 fn weight(
93 &self,
94 key: (usize, usize),
95 make: impl FnOnce() -> Vec<f32>,
96 owner: &Owner,
97 ) -> Result<DevPtr, String> {
98 if let Some(c) = self.weights.borrow().get(&key) {
99 return Ok(c.buf.ptr());
100 }
101 let data = make();
102 let buf = self.upload_or_trim(&data)?;
103 let ptr = buf.ptr();
104 self.count_weight(data.len());
105 self.weights.borrow_mut().insert(
106 key,
107 Cached {
108 buf,
109 _owner: owner.clone(),
110 },
111 );
112 Ok(ptr)
113 }
114
115 pub(crate) fn count_weight(&self, len: usize) {
117 self.weight_bytes.set(self.weight_bytes.get() + bytes(len));
118 }
119
120 pub(crate) fn upload_or_trim(&self, data: &[f32]) -> Result<DeviceBuffer<'g>, String> {
122 self.gpu.upload(data).or_else(|_| {
123 self.pool.borrow_mut().trim();
124 self.gpu.upload(data).map_err(|e| {
125 format!(
126 "{OOM_TAG}: uploading {} bytes of weights failed ({e})",
127 bytes(data.len())
128 )
129 })
130 })
131 }
132}
133
134#[derive(Default)]
136struct DryStats {
137 live: Cell<u64>,
138 peak: Cell<u64>,
139}
140
141pub struct DevTensor<'c, 'g> {
143 buf: Option<DeviceBuffer<'g>>,
145 cap: usize,
146 pool: &'c RefCell<Pool<'g>>,
147 dry: Option<Rc<DryStats>>,
148 pub(crate) shape: Vec<usize>,
149 pub(crate) widths: Rc<Vec<u32>>,
151}
152
153impl DevTensor<'_, '_> {
154 pub(crate) fn ptr(&self) -> DevPtr {
156 self.buf.as_ref().map_or(0, |b| b.ptr())
157 }
158}
159
160impl Drop for DevTensor<'_, '_> {
161 fn drop(&mut self) {
162 if let Some(b) = self.buf.take() {
163 self.pool.borrow_mut().give(self.cap, b);
164 }
165 if let Some(d) = &self.dry {
166 d.live.set(d.live.get() - bytes(self.cap));
167 }
168 }
169}
170
171pub struct BatchExec<'c, 'g> {
173 pub(crate) ctx: &'c Ctx<'g>,
174 pub(crate) n: usize,
175 owner: Owner,
176 dry: Option<Rc<DryStats>>,
177 dry_weights: RefCell<HashMap<usize, u64>>,
179 err: RefCell<Option<String>>,
180 masks: RefCell<HashMap<Vec<u32>, DeviceBuffer<'g>>>,
182}
183
184impl Drop for BatchExec<'_, '_> {
185 fn drop(&mut self) {
186 if self.dry.is_none() {
188 self.ctx.pool.borrow_mut().end_batch();
189 }
190 }
191}
192
193impl<'c, 'g> BatchExec<'c, 'g> {
194 fn new(ctx: &'c Ctx<'g>, n: usize, owner: Owner, dry: bool) -> BatchExec<'c, 'g> {
195 BatchExec {
196 ctx,
197 n,
198 owner,
199 dry: dry.then(Rc::default),
200 dry_weights: RefCell::new(HashMap::new()),
201 err: RefCell::new(None),
202 masks: RefCell::new(HashMap::new()),
203 }
204 }
205
206 pub(crate) fn live(&self) -> bool {
208 self.dry.is_none() && self.err.borrow().is_none()
209 }
210
211 pub(crate) fn fail(&self, e: String) {
213 self.err.borrow_mut().get_or_insert(e);
214 }
215
216 pub(crate) fn check(&self, r: Result<(), String>) {
217 if let Err(e) = r {
218 self.fail(e);
219 }
220 }
221
222 pub fn finish(&self) -> Result<(), String> {
224 if self.live() {
225 self.check(self.ctx.gpu.synchronize());
226 }
227 match self.err.borrow().as_ref() {
228 Some(e) => Err(e.clone()),
229 None => Ok(()),
230 }
231 }
232
233 pub fn dry_usage(&self) -> (u64, u64) {
235 let peak = self.dry.as_ref().map_or(0, |d| d.peak.get());
236 (peak, self.dry_weights.borrow().values().sum())
237 }
238
239 pub(crate) fn alloc(
241 &self,
242 len: usize,
243 shape: Vec<usize>,
244 widths: Rc<Vec<u32>>,
245 ) -> DevTensor<'c, 'g> {
246 let cap = capacity_class(len);
247 if len > u32::MAX as usize {
248 self.fail(format!(
249 "{OOM_TAG}: tensor of {len} elements exceeds the kernels' u32 indices"
250 ));
251 }
252 let mut t = DevTensor {
253 buf: None,
254 cap,
255 pool: &self.ctx.pool,
256 dry: None,
257 shape,
258 widths,
259 };
260 if let Some(d) = &self.dry {
261 d.live.set(d.live.get() + bytes(cap));
262 d.peak.set(d.peak.get().max(d.live.get()));
263 t.dry = Some(d.clone());
264 } else if self.live() {
265 match self.ctx.pool.borrow_mut().take(self.ctx.gpu, cap) {
266 Ok(b) => t.buf = Some(b),
267 Err(e) => self.fail(e),
268 }
269 }
270 t
271 }
272
273 pub(crate) fn weight(&self, data: &[f32]) -> DevPtr {
275 self.weight_keyed(data.as_ptr() as usize, data.len(), || data.to_vec())
276 }
277
278 pub(crate) fn weight_kernel_first(&self, l: &Conv2d) -> DevPtr {
280 let w = &l.weight;
281 let (o, c, kh, kw) = (w.shape[0], w.shape[1], w.shape[2], w.shape[3]);
282 self.weight_keyed(w.data.as_ptr() as usize + 1, w.data.len(), || {
283 let mut out = vec![0f32; w.data.len()];
284 for ko in 0..kh * kw {
285 for oc in 0..o {
286 for ic in 0..c {
287 out[(ko * o + oc) * c + ic] = w.data[(oc * c + ic) * kh * kw + ko];
288 }
289 }
290 }
291 out
292 })
293 }
294
295 fn weight_keyed(&self, addr: usize, len: usize, make: impl FnOnce() -> Vec<f32>) -> DevPtr {
296 let key = (addr, len);
297 if self.dry.is_some() {
298 if !self.ctx.weights.borrow().contains_key(&key) {
299 self.dry_weights.borrow_mut().insert(addr, bytes(len));
300 }
301 return 0;
302 }
303 if !self.live() {
304 return 0;
305 }
306 self.ctx.weight(key, make, &self.owner).unwrap_or_else(|e| {
307 self.fail(e);
308 0
309 })
310 }
311
312 pub fn upload(&self, x: &Tensor) -> DevTensor<'c, 'g> {
314 assert_eq!(self.n, 1, "upload 只用于批大小 1,拼批用 upload_batch");
315 let width = *x.shape.last().expect("张量至少一维") as u32;
316 let width = if x.shape.len() == 2 {
318 x.shape[0] as u32
319 } else {
320 width
321 };
322 let t = self.alloc(x.data.len(), x.shape.clone(), Rc::new(vec![width]));
323 self.write(&t, &x.data);
324 t
325 }
326
327 pub fn placeholder(&self, shape: Vec<usize>) -> DevTensor<'c, 'g> {
329 let width = *shape.last().expect("张量至少一维") as u32;
330 self.alloc(
331 self.n * shape.iter().product::<usize>(),
332 shape,
333 Rc::new(vec![width; self.n]),
334 )
335 }
336
337 pub fn upload_batch(&self, xs: &[&Tensor]) -> DevTensor<'c, 'g> {
339 assert_eq!(xs.len(), self.n, "样本数和批大小不同");
340 let (c, h, _) = xs[0].chw();
341 let widths: Vec<u32> = xs.iter().map(|x| x.chw().2 as u32).collect();
342 let wmax = *widths.iter().max().expect("空批") as usize;
343 let t = self.alloc(
344 self.n * c * h * wmax,
345 vec![c, h, wmax],
346 Rc::new(widths.clone()),
347 );
348 if self.live() {
349 let mut host = vec![0f32; self.n * c * h * wmax];
350 for (z, (x, &w)) in xs.iter().zip(&widths).enumerate() {
351 assert_eq!(x.chw().0, c, "同一批的通道数不同");
352 assert_eq!(x.chw().1, h, "同一批的高度不同");
353 let (w, base) = (w as usize, z * c * h * wmax);
354 for r in 0..c * h {
355 let src = &x.data[r * w..(r + 1) * w];
356 host[base + r * wmax..base + r * wmax + w].copy_from_slice(src);
357 }
358 }
359 self.write(&t, &host);
360 }
361 t
362 }
363
364 fn write(&self, t: &DevTensor<'_, 'g>, data: &[f32]) {
365 if let (true, Some(b)) = (self.live(), t.buf.as_ref()) {
366 self.check(b.write_prefix(data));
367 }
368 }
369
370 pub fn download(&self, t: &DevTensor<'_, 'g>) -> Result<Vec<f32>, String> {
372 self.finish()?;
373 let mut v = vec![0f32; self.n * t.shape.iter().product::<usize>()];
374 if let Some(b) = t.buf.as_ref() {
375 b.read_prefix(&mut v)?;
376 }
377 Ok(v)
378 }
379
380 pub(crate) fn d1(&self, f: Handle, total: usize, args: Args) {
382 if self.live() {
383 self.check(
384 self.ctx
385 .gpu
386 .launch(f, (blocks_1d(total), 1, 1), (BLOCK_1D, 1, 1), args),
387 );
388 }
389 }
390
391 pub(crate) fn widths_ptr(&self, w: &[u32]) -> DevPtr {
393 if !self.live() {
394 return 0;
395 }
396 if let Some(b) = self.masks.borrow().get(w) {
397 return b.ptr();
398 }
399 let bits: Vec<f32> = w.iter().map(|&v| f32::from_bits(v)).collect();
400 match self.ctx.upload_or_trim(&bits) {
401 Ok(b) => {
402 let p = b.ptr();
403 self.masks.borrow_mut().insert(w.to_vec(), b);
404 p
405 }
406 Err(e) => {
407 self.fail(e);
408 0
409 }
410 }
411 }
412
413 pub(crate) fn mask(&self, x: &DevTensor<'_, 'g>) {
415 let (c, h, w) = (x.shape[0], x.shape[1], x.shape[2]);
416 if x.widths.iter().all(|&v| v as usize == w) {
417 return;
418 }
419 let per = c * h * w;
420 let args = Args::default()
421 .raw_ptr(x.ptr())
422 .raw_ptr(self.widths_ptr(&x.widths))
423 .u32(per)
424 .u32(w)
425 .u32(self.n * per);
426 self.d1(self.ctx.gpu.k.zero_cols, self.n * per, args);
427 }
428}