@@ -117,7 +117,7 @@ void pool_release(void* data_ptr) {
117117
118118namespace detail ::metal {
119119
120- void * metal_alloc (std::size_t bytes) {
120+ void * metal_alloc (std::size_t bytes, int ) {
121121 if (bytes == 0 ) return nullptr ;
122122 ::brotensor::cuda_init ();
123123 @autoreleasepool {
@@ -133,7 +133,7 @@ void pool_release(void* data_ptr) {
133133 }
134134}
135135
136- void metal_free (void * ptr) {
136+ void metal_free (void * ptr, int ) {
137137 if (ptr) metal_impl::pool_release (ptr);
138138}
139139
@@ -142,31 +142,60 @@ void metal_free(void* ptr) {
142142// command buffers asynchronously (see metal_impl::submit), so each transfer
143143// flushes first: a device->host read must observe completed GPU writes, and a
144144// host write must not race a kernel still reading or writing the same buffer.
145- void metal_memcpy_h2d (void * dst, const void * src, std::size_t n) {
145+ void metal_memcpy_h2d (void * dst, const void * src, std::size_t n, int ) {
146146 if (!n) return ;
147147 metal_impl::flush ();
148148 std::memcpy (dst, src, n);
149149}
150- void metal_memcpy_d2h (void * dst, const void * src, std::size_t n) {
150+ void metal_memcpy_d2h (void * dst, const void * src, std::size_t n, int ) {
151151 if (!n) return ;
152152 metal_impl::flush ();
153153 std::memcpy (dst, src, n);
154154}
155- void metal_memcpy_d2d (void * dst, const void * src, std::size_t n) {
155+ void metal_memcpy_d2d (void * dst, const void * src, std::size_t n, int ) {
156+ if (!n) return ;
157+ metal_impl::flush ();
158+ std::memcpy (dst, src, n);
159+ }
160+ void metal_memcpy_peer (void * dst, int , const void * src, int , std::size_t n) {
156161 if (!n) return ;
157162 metal_impl::flush ();
158163 std::memcpy (dst, src, n);
159164}
160165
161- void metal_memset_zero (void * dst, std::size_t n) {
166+ void metal_memset_zero (void * dst, std::size_t n, int ) {
162167 if (!n) return ;
163168 metal_impl::flush ();
164169 std::memset (dst, 0 , n);
165170}
166171
167172// Drain the asynchronous submission queue — wait on the most recent pending
168173// command buffer, which (serial queue) implies all earlier ones are done.
169- void metal_sync () { metal_impl::flush (); }
174+ void metal_sync (int ) { metal_impl::flush (); }
175+
176+ bool metal_mem_info (std::size_t * free_bytes, std::size_t * total_bytes, int ) {
177+ @autoreleasepool {
178+ id <MTLDevice > dev = metal_impl::device ();
179+ if (!dev) return false ;
180+ uint64_t allocated = [dev currentAllocatedSize ];
181+ uint64_t total = [dev recommendedMaxWorkingSetSize ];
182+ if (free_bytes) *free_bytes = (total > allocated) ? (total - allocated) : 0 ;
183+ if (total_bytes) *total_bytes = total;
184+ return true ;
185+ }
186+ }
187+
188+ bool metal_device_name (char * out, std::size_t cap, int ) {
189+ if (!out || cap == 0 ) return false ;
190+ @autoreleasepool {
191+ id <MTLDevice > dev = metal_impl::device ();
192+ if (!dev) return false ;
193+ const char * name = [[dev name ] UTF8String ];
194+ if (!name) return false ;
195+ std::snprintf (out, cap, " %s" , name);
196+ return true ;
197+ }
198+ }
170199
171200const ::brotensor::detail::AllocVTable& metal_alloc_table () {
172201 static const ::brotensor::detail::AllocVTable t = {
@@ -175,8 +204,12 @@ void metal_memset_zero(void* dst, std::size_t n) {
175204 &metal_memcpy_h2d,
176205 &metal_memcpy_d2h,
177206 &metal_memcpy_d2d,
207+ &metal_memcpy_peer,
178208 &metal_memset_zero,
179209 &metal_sync,
210+ &metal_mem_info,
211+ nullptr , // mem_trim
212+ &metal_device_name,
180213 };
181214 return t;
182215}
0 commit comments