sim_lib_compute_wgpu/
storage.rs1use std::{
4 any::Any,
5 sync::{Arc, OnceLock},
6};
7
8use sim_kernel::{DefaultFactory, Error, Factory, Result, Symbol, Value};
9use sim_lib_numbers_tensor::{Tensor, TensorLocation, TensorStorage};
10
11use crate::{WgpuArenaAllocation, WgpuMaterializationCache, WgpuResidentSegment};
12
13pub struct WgpuResidentStorage {
15 site: Symbol,
16 allocation: WgpuArenaAllocation,
17 pipeline: Symbol,
18 segments: Arc<[WgpuResidentSegment]>,
19 shape: Arc<[usize]>,
20 dtype: Symbol,
21 cells: Arc<[Value]>,
22 cache: WgpuMaterializationCache,
23 materialized: OnceLock<Result<Arc<dyn TensorStorage>>>,
24}
25
26impl WgpuResidentStorage {
27 pub fn new(
29 site: Symbol,
30 allocation: WgpuArenaAllocation,
31 pipeline: Symbol,
32 segments: Vec<WgpuResidentSegment>,
33 shape: Vec<usize>,
34 dtype: Symbol,
35 cells: Arc<[Value]>,
36 ) -> Self {
37 Self {
38 site,
39 allocation,
40 pipeline,
41 segments: segments.into(),
42 shape: shape.into(),
43 dtype,
44 cells,
45 cache: WgpuMaterializationCache::default(),
46 materialized: OnceLock::new(),
47 }
48 }
49
50 pub fn allocation(&self) -> &WgpuArenaAllocation {
52 &self.allocation
53 }
54
55 pub fn pipeline(&self) -> &Symbol {
57 &self.pipeline
58 }
59
60 pub fn segments(&self) -> &[WgpuResidentSegment] {
62 &self.segments
63 }
64
65 pub fn resident_tensor(&self) -> Option<Tensor> {
67 Tensor::from_storage(
68 self.shape.to_vec(),
69 self.dtype.clone(),
70 Arc::new(BoxedWgpuStorage::new(
71 self.dtype.clone(),
72 self.cells.clone(),
73 )),
74 )
75 .ok()
76 }
77}
78
79impl TensorStorage for WgpuResidentStorage {
80 fn dtype(&self) -> &Symbol {
81 &self.dtype
82 }
83
84 fn len(&self) -> usize {
85 self.cells.len()
86 }
87
88 fn location(&self) -> TensorLocation {
89 TensorLocation::Resident {
90 site: self.site.clone(),
91 allocation: self.allocation.id_symbol(),
92 }
93 }
94
95 fn cell(&self, index: usize) -> Result<Value> {
96 self.materialize()?.cell(index)
97 }
98
99 fn materialize(&self) -> Result<Arc<dyn TensorStorage>> {
100 self.materialized
101 .get_or_init(|| {
102 self.cache
103 .get_or_try_init(|| Ok(Arc::<[u8]>::from([])))
104 .map_err(Error::Eval)?;
105 Ok(Arc::new(BoxedWgpuStorage::new(
106 self.dtype.clone(),
107 self.cells.clone(),
108 )))
109 })
110 .clone()
111 }
112
113 fn as_any(&self) -> &dyn Any {
114 self
115 }
116}
117
118struct BoxedWgpuStorage {
119 dtype: Symbol,
120 cells: Arc<[Value]>,
121}
122
123impl BoxedWgpuStorage {
124 fn new(dtype: Symbol, cells: Arc<[Value]>) -> Self {
125 Self { dtype, cells }
126 }
127}
128
129impl TensorStorage for BoxedWgpuStorage {
130 fn dtype(&self) -> &Symbol {
131 &self.dtype
132 }
133
134 fn len(&self) -> usize {
135 self.cells.len()
136 }
137
138 fn location(&self) -> TensorLocation {
139 TensorLocation::Host
140 }
141
142 fn cell(&self, index: usize) -> Result<Value> {
143 self.cells
144 .get(index)
145 .cloned()
146 .ok_or_else(|| Error::Eval("wgpu tensor cell index was out of bounds".to_owned()))
147 }
148
149 fn materialize(&self) -> Result<Arc<dyn TensorStorage>> {
150 Ok(Arc::new(Self {
151 dtype: self.dtype.clone(),
152 cells: self.cells.clone(),
153 }))
154 }
155
156 fn as_any(&self) -> &dyn Any {
157 self
158 }
159}
160
161impl WgpuArenaAllocation {
162 fn id_symbol(&self) -> Symbol {
163 Symbol::qualified("compute.alloc.wgpu", format!("{:?}", self.id))
164 }
165}
166
167impl sim_kernel::Object for WgpuArenaAllocation {
168 fn display(&self, _cx: &mut sim_kernel::Cx) -> Result<String> {
169 Ok(format!("#<wgpu-allocation {:?}>", self.id))
170 }
171
172 fn as_any(&self) -> &dyn Any {
173 self
174 }
175}
176
177impl sim_kernel::ObjectCompat for WgpuArenaAllocation {
178 fn class(&self, _cx: &mut sim_kernel::Cx) -> Result<sim_kernel::ClassRef> {
179 DefaultFactory.class_stub(
180 sim_kernel::CORE_FUNCTION_CLASS_ID,
181 Symbol::qualified("compute", "WgpuAllocation"),
182 )
183 }
184}