@@ -39,31 +39,33 @@ fn current_pool() -> Option<Arc<MetalTensorPool>> {
3939 POOL_STACK . with ( |stack| stack. borrow ( ) . last ( ) . cloned ( ) . flatten ( ) )
4040}
4141
42- fn pool_registry ( ) -> & ' static Mutex < HashMap < usize , Arc < MetalPoolAllocation > > > {
43- static REGISTRY : OnceLock < Mutex < HashMap < usize , Arc < MetalPoolAllocation > > > > = OnceLock :: new ( ) ;
42+ fn pool_registry ( ) -> & ' static Mutex < HashMap < usize , Vec < Arc < MetalPoolAllocation > > > > {
43+ static REGISTRY : OnceLock < Mutex < HashMap < usize , Vec < Arc < MetalPoolAllocation > > > > > =
44+ OnceLock :: new ( ) ;
4445 REGISTRY . get_or_init ( || Mutex :: new ( HashMap :: new ( ) ) )
4546}
4647
4748fn register_pool_allocation ( buffer : & Arc < Buffer > , allocation : Arc < MetalPoolAllocation > ) {
4849 let ptr = Arc :: as_ptr ( buffer) as usize ;
4950 if let Ok ( mut registry) = pool_registry ( ) . lock ( ) {
50- registry. insert ( ptr, allocation) ;
51+ registry. entry ( ptr) . or_default ( ) . push ( allocation) ;
5152 }
5253}
5354
5455fn take_pool_allocation ( buffer : & Arc < Buffer > ) -> Option < Arc < MetalPoolAllocation > > {
5556 let ptr = Arc :: as_ptr ( buffer) as usize ;
56- pool_registry ( )
57- . lock ( )
58- . ok ( )
59- . and_then ( |mut registry| registry. remove ( & ptr) )
57+ pool_registry ( ) . lock ( ) . ok ( ) . and_then ( |mut registry| {
58+ let entry = registry. get_mut ( & ptr) ?;
59+ let allocation = entry. pop ( ) ;
60+ if entry. is_empty ( ) {
61+ registry. remove ( & ptr) ;
62+ }
63+ allocation
64+ } )
6065}
6166
62- pub fn buffer_o < ' a > ( buffer : & ' a Buffer , l : & Layout , dtype : DType ) -> BufferOffset < ' a > {
63- BufferOffset {
64- buffer,
65- offset_in_bytes : l. start_offset ( ) * dtype. size_in_bytes ( ) ,
66- }
67+ pub fn buffer_o < ' a > ( storage : & ' a MetalStorage , l : & Layout ) -> BufferOffset < ' a > {
68+ storage. buffer_offset ( l)
6769}
6870/// Simple way to catch lock error without
6971/// depending on T
@@ -123,6 +125,7 @@ pub struct MetalStorage {
123125 count : usize ,
124126 /// The dtype is kept since buffers are untyped.
125127 dtype : DType ,
128+ offset_bytes : usize ,
126129 pool_allocation : Option < Arc < MetalPoolAllocation > > ,
127130}
128131
@@ -169,7 +172,7 @@ impl BackendStorage for MetalStorage {
169172
170173 let buffer = device. new_buffer ( el, self . dtype , "affine" ) ?;
171174 let command_buffer = self . device . command_buffer ( ) ?;
172- let src = buffer_o ( & self . buffer , layout, dtype ) ;
175+ let src = buffer_o ( self , layout) ;
173176 if layout. is_contiguous ( ) {
174177 let name = match self . dtype {
175178 DType :: F32 => "affine_f32" ,
@@ -225,7 +228,7 @@ impl BackendStorage for MetalStorage {
225228
226229 let buffer = device. new_buffer ( el, self . dtype , "powf" ) ?;
227230 let command_buffer = self . device . command_buffer ( ) ?;
228- let src = buffer_o ( & self . buffer , layout, dtype ) ;
231+ let src = buffer_o ( self , layout) ;
229232 if layout. is_contiguous ( ) {
230233 let name = match self . dtype {
231234 DType :: F32 => "powf_f32" ,
@@ -277,7 +280,7 @@ impl BackendStorage for MetalStorage {
277280
278281 let buffer = device. new_buffer ( el, self . dtype , "elu" ) ?;
279282 let command_buffer = self . device . command_buffer ( ) ?;
280- let src = buffer_o ( & self . buffer , layout, self . dtype ) ;
283+ let src = buffer_o ( self , layout) ;
281284 if layout. is_contiguous ( ) {
282285 let name = match self . dtype {
283286 DType :: F32 => "elu_f32" ,
@@ -386,7 +389,7 @@ impl BackendStorage for MetalStorage {
386389 let dtype = if return_index { DType :: U32 } else { self . dtype } ;
387390 let buffer = device. new_buffer ( dst_el, dtype, "reduce" ) ?;
388391 let command_buffer = self . device . command_buffer ( ) ?;
389- let src = buffer_o ( & self . buffer , layout, self . dtype ) ;
392+ let src = buffer_o ( self , layout) ;
390393 candle_metal_kernels:: call_reduce_contiguous (
391394 & device. device ,
392395 & command_buffer,
@@ -441,7 +444,7 @@ impl BackendStorage for MetalStorage {
441444 let dtype = if return_index { DType :: U32 } else { self . dtype } ;
442445 let buffer = device. new_buffer ( dst_el, dtype, "reduce" ) ?;
443446 let command_buffer = self . device . command_buffer ( ) ?;
444- let src = buffer_o ( & self . buffer , layout, self . dtype ) ;
447+ let src = buffer_o ( self , layout) ;
445448 candle_metal_kernels:: call_reduce_strided (
446449 & device. device ,
447450 & command_buffer,
@@ -484,7 +487,7 @@ impl BackendStorage for MetalStorage {
484487 let el_count = shape. elem_count ( ) ;
485488 let command_buffer = device. command_buffer ( ) ?;
486489 command_buffer. set_label ( "const-set" ) ;
487- let dst = buffer_o ( & self_. buffer , l, self_ . dtype ) ;
490+ let dst = buffer_o ( self_, l) ;
488491
489492 match ( el_count % 2 , dtype, l. is_contiguous ( ) ) {
490493 ( 0 , DType :: BF16 | DType :: F16 , true ) => {
@@ -585,7 +588,7 @@ impl BackendStorage for MetalStorage {
585588 let el_count = shape. elem_count ( ) ;
586589 let buffer = device. new_buffer ( el_count, dtype, "todtype" ) ?;
587590 let command_buffer = device. command_buffer ( ) ?;
588- let src = buffer_o ( & self . buffer , layout, self . dtype ) ;
591+ let src = buffer_o ( self , layout) ;
589592 if layout. is_contiguous ( ) {
590593 let kernel_name = match ( self . dtype , dtype) {
591594 ( DType :: U32 , DType :: BF16 ) => "cast_u32_bf16" ,
@@ -705,7 +708,7 @@ impl BackendStorage for MetalStorage {
705708 let buffer = device. new_buffer ( el_count, dtype, B :: KERNEL ) ?;
706709 let command_buffer = device. command_buffer ( ) ?;
707710 command_buffer. set_label ( B :: KERNEL ) ;
708- let src = buffer_o ( & self . buffer , layout, self . dtype ) ;
711+ let src = buffer_o ( self , layout) ;
709712
710713 match ( el_count % 2 , dtype, layout. is_contiguous ( ) ) {
711714 ( 0 , DType :: BF16 | DType :: F16 , true ) => {
@@ -983,9 +986,9 @@ impl BackendStorage for MetalStorage {
983986 ( DType :: U8 , DType :: U8 ) => "where_u8_u8" ,
984987 ( left, right) => crate :: bail!( "Metal where_cond {left:?} {right:?} not implemented" ) ,
985988 } ;
986- let src = buffer_o ( & self . buffer , layout, self . dtype ) ;
987- let t = buffer_o ( & t . buffer , t_l, t . dtype ) ;
988- let f = buffer_o ( & f . buffer , f_l, f . dtype ) ;
989+ let src = buffer_o ( self , layout) ;
990+ let t = buffer_o ( t , t_l) ;
991+ let f = buffer_o ( f , f_l) ;
989992 candle_metal_kernels:: call_where_cond_strided (
990993 & device. device ,
991994 & command_buffer,
@@ -1031,7 +1034,7 @@ impl BackendStorage for MetalStorage {
10311034 DType :: F32 => "im2col1d_f32" ,
10321035 dtype => crate :: bail!( "Metal conv1d {dtype:?} not implemented" ) ,
10331036 } ;
1034- let src = buffer_o ( & self . buffer , layout, self . dtype ) ;
1037+ let src = buffer_o ( self , layout) ;
10351038 candle_metal_kernels:: call_im2col1d_strided (
10361039 & self . device . device ,
10371040 & command_buffer,
@@ -1044,13 +1047,7 @@ impl BackendStorage for MetalStorage {
10441047 & dst,
10451048 )
10461049 . map_err ( MetalError :: from) ?;
1047- let col = Self {
1048- buffer : dst,
1049- device,
1050- count : dst_el,
1051- dtype : self . dtype ,
1052- pool_allocation : None ,
1053- } ;
1050+ let col = Self :: new ( dst, device, dst_el, self . dtype ) ;
10541051 let l_out = params. l_out ( ) ;
10551052 let b = params. b_size ;
10561053 let n = params. c_out ;
@@ -1224,7 +1221,7 @@ impl BackendStorage for MetalStorage {
12241221 DType :: U32 => "im2col_u32" ,
12251222 dtype => crate :: bail!( "Metal conv2d {dtype:?} not implemented" ) ,
12261223 } ;
1227- let src = buffer_o ( & self . buffer , layout, self . dtype ) ;
1224+ let src = buffer_o ( self , layout) ;
12281225 candle_metal_kernels:: call_im2col_strided (
12291226 & self . device . device ,
12301227 & command_buffer,
@@ -1237,13 +1234,7 @@ impl BackendStorage for MetalStorage {
12371234 & dst,
12381235 )
12391236 . map_err ( MetalError :: from) ?;
1240- let col = Self {
1241- buffer : dst,
1242- device,
1243- count : dst_el,
1244- dtype : self . dtype ,
1245- pool_allocation : None ,
1246- } ;
1237+ let col = Self :: new ( dst, device, dst_el, self . dtype ) ;
12471238 let h_out = params. out_h ( ) ;
12481239 let w_out = params. out_w ( ) ;
12491240 let b = params. b_size ;
@@ -1451,7 +1442,7 @@ impl BackendStorage for MetalStorage {
14511442 . device
14521443 . new_buffer ( dst_el, self . dtype , "upsample_nearest2d" ) ?;
14531444 let command_buffer = self . device . command_buffer ( ) ?;
1454- let src = buffer_o ( & self . buffer , inp_l, self . dtype ) ;
1445+ let src = buffer_o ( self , inp_l) ;
14551446 candle_metal_kernels:: call_upsample_nearest_2d (
14561447 & self . device . device ,
14571448 & command_buffer,
@@ -1492,8 +1483,8 @@ impl BackendStorage for MetalStorage {
14921483 ( left, right) => crate :: bail!( "Metal gather {left:?} {right:?} not implemented" ) ,
14931484 } ;
14941485 let command_buffer = self . device . command_buffer ( ) ?;
1495- let src = buffer_o ( & self . buffer , src_l, dtype ) ;
1496- let ids = buffer_o ( & ids. buffer , ids_l, ids . dtype ) ;
1486+ let src = buffer_o ( self , src_l) ;
1487+ let ids = buffer_o ( ids, ids_l) ;
14971488 candle_metal_kernels:: call_gather (
14981489 & device. device ,
14991490 & command_buffer,
@@ -1540,9 +1531,9 @@ impl BackendStorage for MetalStorage {
15401531 } ) ?,
15411532 } ;
15421533 let command_buffer = self . device . command_buffer ( ) ?;
1543- let dst = buffer_o ( & self . buffer , l, self . dtype ) ;
1544- let src = buffer_o ( & src. buffer , src_l, src . dtype ) ;
1545- let ids = buffer_o ( & ids. buffer , ids_l, ids . dtype ) ;
1534+ let dst = buffer_o ( self , l) ;
1535+ let src = buffer_o ( src, src_l) ;
1536+ let ids = buffer_o ( ids, ids_l) ;
15461537 candle_metal_kernels:: call_scatter (
15471538 & self . device . device ,
15481539 & command_buffer,
@@ -1589,9 +1580,9 @@ impl BackendStorage for MetalStorage {
15891580 } ) ?,
15901581 } ;
15911582 let command_buffer = self . device . command_buffer ( ) ?;
1592- let dst = buffer_o ( & self . buffer , l, self . dtype ) ;
1593- let src = buffer_o ( & src. buffer , src_l, src . dtype ) ;
1594- let ids = buffer_o ( & ids. buffer , ids_l, ids . dtype ) ;
1583+ let dst = buffer_o ( self , l) ;
1584+ let src = buffer_o ( src, src_l) ;
1585+ let ids = buffer_o ( ids, ids_l) ;
15951586 candle_metal_kernels:: call_scatter (
15961587 & self . device . device ,
15971588 & command_buffer,
@@ -1647,8 +1638,8 @@ impl BackendStorage for MetalStorage {
16471638 }
16481639 } ;
16491640 let command_buffer = self . device . command_buffer ( ) ?;
1650- let src = buffer_o ( & self . buffer , src_l, dtype ) ;
1651- let ids = buffer_o ( & ids. buffer , ids_l, ids . dtype ) ;
1641+ let src = buffer_o ( self , src_l) ;
1642+ let ids = buffer_o ( ids, ids_l) ;
16521643 candle_metal_kernels:: call_index_select (
16531644 & device. device ,
16541645 & command_buffer,
@@ -1711,8 +1702,8 @@ impl BackendStorage for MetalStorage {
17111702 } ) ?,
17121703 } ;
17131704 let command_buffer = self . device . command_buffer ( ) ?;
1714- let src = buffer_o ( & src. buffer , src_l, src . dtype ) ;
1715- let ids = buffer_o ( & ids. buffer , ids_l, ids . dtype ) ;
1705+ let src = buffer_o ( src, src_l) ;
1706+ let ids = buffer_o ( ids, ids_l) ;
17161707 candle_metal_kernels:: call_index_add (
17171708 & self . device . device ,
17181709 & command_buffer,
@@ -1827,8 +1818,8 @@ impl BackendStorage for MetalStorage {
18271818 d2,
18281819 src_s,
18291820 dst_s,
1830- src_o * self . dtype . size_in_bytes ( ) ,
1831- dst_o * self . dtype . size_in_bytes ( ) ,
1821+ self . offset_bytes + src_o * self . dtype . size_in_bytes ( ) ,
1822+ dst . offset_bytes + dst_o * self . dtype . size_in_bytes ( ) ,
18321823 )
18331824 . map_err ( MetalError :: from) ?;
18341825 command_buffer. set_label ( "copy2d" ) ;
@@ -1842,9 +1833,11 @@ impl BackendStorage for MetalStorage {
18421833 command_buffer. set_label ( "copy_contiguous" ) ;
18431834 let blit = command_buffer. new_blit_command_encoder ( ) ;
18441835 blit. set_label ( "copy_contiguous" ) ;
1845- let src_offset = ( src_l. start_offset ( ) * self . dtype . size_in_bytes ( ) ) as NSUInteger ;
1836+ let src_offset = ( self . offset_bytes + src_l. start_offset ( ) * self . dtype . size_in_bytes ( ) )
1837+ as NSUInteger ;
18461838 let length = ( src_l. shape ( ) . elem_count ( ) * self . dtype . size_in_bytes ( ) ) as NSUInteger ;
1847- let dst_offset = ( dst_offset * dst. dtype ( ) . size_in_bytes ( ) ) as NSUInteger ;
1839+ let dst_offset =
1840+ ( dst. offset_bytes + dst_offset * dst. dtype ( ) . size_in_bytes ( ) ) as NSUInteger ;
18481841 blit. copy_from_buffer ( & self . buffer , src_offset, dst. buffer ( ) , dst_offset, length) ;
18491842 blit. end_encoding ( ) ;
18501843 } else {
@@ -1862,10 +1855,10 @@ impl BackendStorage for MetalStorage {
18621855 DType :: U8 => candle_metal_kernels:: unary:: strided:: copy:: U8 ,
18631856 dtype => crate :: bail!( "Metal copy_strided {dtype:?} not implemented" ) ,
18641857 } ;
1865- let src = buffer_o ( & self . buffer , src_l, self . dtype ) ;
1858+ let src = buffer_o ( self , src_l) ;
18661859 let dst = BufferOffset {
18671860 buffer : & dst. buffer ,
1868- offset_in_bytes : dst_offset * dst. dtype . size_in_bytes ( ) ,
1861+ offset_in_bytes : dst . offset_bytes + dst_offset * dst. dtype . size_in_bytes ( ) ,
18691862 } ;
18701863 candle_metal_kernels:: call_unary_strided (
18711864 & self . device . device ,
@@ -1887,11 +1880,16 @@ impl BackendStorage for MetalStorage {
18871880impl MetalStorage {
18881881 pub fn new ( buffer : Arc < Buffer > , device : MetalDevice , count : usize , dtype : DType ) -> Self {
18891882 let pool_allocation = take_pool_allocation ( & buffer) ;
1883+ let offset_bytes = pool_allocation
1884+ . as_ref ( )
1885+ . map ( |alloc| alloc. offset ( ) )
1886+ . unwrap_or ( 0 ) ;
18901887 Self {
18911888 buffer,
18921889 device,
18931890 count,
18941891 dtype,
1892+ offset_bytes,
18951893 pool_allocation,
18961894 }
18971895 }
@@ -1902,6 +1900,13 @@ impl MetalStorage {
19021900 . map ( |allocation| allocation. pool ( ) )
19031901 }
19041902
1903+ fn buffer_offset < ' a > ( & ' a self , layout : & Layout ) -> BufferOffset < ' a > {
1904+ BufferOffset {
1905+ buffer : & self . buffer ,
1906+ offset_in_bytes : self . offset_bytes + layout. start_offset ( ) * self . dtype . size_in_bytes ( ) ,
1907+ }
1908+ }
1909+
19051910 fn determine_pool ( storages : & [ & Self ] ) -> Result < Option < Arc < MetalTensorPool > > > {
19061911 let mut pool: Option < Arc < MetalTensorPool > > = None ;
19071912 for storage in storages {
@@ -1939,8 +1944,8 @@ impl MetalStorage {
19391944 let shape = lhs_l. shape ( ) ;
19401945 let el_count = shape. elem_count ( ) ;
19411946 let command_buffer = device. command_buffer ( ) ?;
1942- let lhs = buffer_o ( & self . buffer , lhs_l, self . dtype ) ;
1943- let rhs = buffer_o ( & rhs. buffer , rhs_l, rhs . dtype ) ;
1947+ let lhs = buffer_o ( self , lhs_l) ;
1948+ let rhs = buffer_o ( rhs, rhs_l) ;
19441949 let ( buffer, dtype) = if lhs_l. is_contiguous ( ) && rhs_l. is_contiguous ( ) && & op[ ..1 ] != "b" {
19451950 use candle_metal_kernels:: binary:: contiguous;
19461951
@@ -2143,7 +2148,13 @@ impl MetalStorage {
21432148 command_buffer. set_label ( "to_cpu" ) ;
21442149 let blit = command_buffer. new_blit_command_encoder ( ) ;
21452150 blit. set_label ( "blit_to_cpu" ) ;
2146- blit. copy_from_buffer ( & self . buffer , 0 , & buffer, 0 , size) ;
2151+ blit. copy_from_buffer (
2152+ & self . buffer ,
2153+ self . offset_bytes as NSUInteger ,
2154+ & buffer,
2155+ 0 ,
2156+ size,
2157+ ) ;
21472158 blit. end_encoding ( ) ;
21482159 }
21492160 self . device . wait_until_completed ( ) ?;
0 commit comments