xref: /aosp_15_r20/external/XNNPACK/src/memory.c (revision 4bdc94577ba0e567308109d787f7fec7b531ce36)
1*4bdc9457SAndroid Build Coastguard Worker // Copyright 2021 Google LLC
2*4bdc9457SAndroid Build Coastguard Worker //
3*4bdc9457SAndroid Build Coastguard Worker // This source code is licensed under the BSD-style license found in the
4*4bdc9457SAndroid Build Coastguard Worker // LICENSE file in the root directory of this source tree.
5*4bdc9457SAndroid Build Coastguard Worker 
6*4bdc9457SAndroid Build Coastguard Worker // Include first for the platform detection macros.
7*4bdc9457SAndroid Build Coastguard Worker #include "xnnpack/common.h"
8*4bdc9457SAndroid Build Coastguard Worker 
9*4bdc9457SAndroid Build Coastguard Worker #if XNN_PLATFORM_WINDOWS
10*4bdc9457SAndroid Build Coastguard Worker #ifndef WIN32_LEAN_AND_MEAN
11*4bdc9457SAndroid Build Coastguard Worker #define WIN32_LEAN_AND_MEAN
12*4bdc9457SAndroid Build Coastguard Worker #endif
13*4bdc9457SAndroid Build Coastguard Worker #include <windows.h>
14*4bdc9457SAndroid Build Coastguard Worker #else
15*4bdc9457SAndroid Build Coastguard Worker // This define needs to come first because errno include features.h and would have defined macros that lead to
16*4bdc9457SAndroid Build Coastguard Worker // sys/mman.h not having mremap.
17*4bdc9457SAndroid Build Coastguard Worker #if !defined(_GNU_SOURCE)
18*4bdc9457SAndroid Build Coastguard Worker #define _GNU_SOURCE
19*4bdc9457SAndroid Build Coastguard Worker #endif
20*4bdc9457SAndroid Build Coastguard Worker #include <errno.h>
21*4bdc9457SAndroid Build Coastguard Worker #include <sys/mman.h>
22*4bdc9457SAndroid Build Coastguard Worker #include <unistd.h>
23*4bdc9457SAndroid Build Coastguard Worker #endif
24*4bdc9457SAndroid Build Coastguard Worker 
25*4bdc9457SAndroid Build Coastguard Worker #include <stddef.h>
26*4bdc9457SAndroid Build Coastguard Worker #include <stdint.h>
27*4bdc9457SAndroid Build Coastguard Worker #include <xnnpack.h>
28*4bdc9457SAndroid Build Coastguard Worker 
29*4bdc9457SAndroid Build Coastguard Worker #include "xnnpack/allocator.h"
30*4bdc9457SAndroid Build Coastguard Worker #include "xnnpack/log.h"
31*4bdc9457SAndroid Build Coastguard Worker #include "xnnpack/math.h"
32*4bdc9457SAndroid Build Coastguard Worker #include "xnnpack/params.h"
33*4bdc9457SAndroid Build Coastguard Worker 
34*4bdc9457SAndroid Build Coastguard Worker // Helpers to allocate/mmap and release memory used by both code and weights cache.
35*4bdc9457SAndroid Build Coastguard Worker 
36*4bdc9457SAndroid Build Coastguard Worker // Maps `size` bytes of memory, returns pointer to allocation, NULL if failed.
allocate_buffer(size_t size)37*4bdc9457SAndroid Build Coastguard Worker static void* allocate_buffer(size_t size) {
38*4bdc9457SAndroid Build Coastguard Worker   xnn_log_debug("allocating buffer of size %zu", size);
39*4bdc9457SAndroid Build Coastguard Worker   assert(size == round_up_po2(size, xnn_params.page_size));
40*4bdc9457SAndroid Build Coastguard Worker #if XNN_PLATFORM_WINDOWS
41*4bdc9457SAndroid Build Coastguard Worker   void* p = VirtualAlloc(NULL, size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
42*4bdc9457SAndroid Build Coastguard Worker   if (p == NULL) {
43*4bdc9457SAndroid Build Coastguard Worker     xnn_log_error("failed to allocate %zu bytes for code/weights buffer, error code: %" PRIu32,
44*4bdc9457SAndroid Build Coastguard Worker                   size, (uint32_t) GetLastError());
45*4bdc9457SAndroid Build Coastguard Worker     return NULL;
46*4bdc9457SAndroid Build Coastguard Worker   }
47*4bdc9457SAndroid Build Coastguard Worker #else
48*4bdc9457SAndroid Build Coastguard Worker   void* p = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
49*4bdc9457SAndroid Build Coastguard Worker   if (p == MAP_FAILED) {
50*4bdc9457SAndroid Build Coastguard Worker     xnn_log_error("failed to allocate %zu bytes for code/weights buffer, error code: %d", size, errno);
51*4bdc9457SAndroid Build Coastguard Worker     return NULL;
52*4bdc9457SAndroid Build Coastguard Worker   }
53*4bdc9457SAndroid Build Coastguard Worker #endif
54*4bdc9457SAndroid Build Coastguard Worker   return p;
55*4bdc9457SAndroid Build Coastguard Worker }
56*4bdc9457SAndroid Build Coastguard Worker 
57*4bdc9457SAndroid Build Coastguard Worker // Releases memory previously mapped by `allocate_buffer`, returns xnn_status_success on success.
release_memory(void * start,size_t capacity)58*4bdc9457SAndroid Build Coastguard Worker static enum xnn_status release_memory(void* start, size_t capacity) {
59*4bdc9457SAndroid Build Coastguard Worker #if XNN_PLATFORM_WINDOWS
60*4bdc9457SAndroid Build Coastguard Worker   // We only decommited any unused capacity, so we release all of it now.
61*4bdc9457SAndroid Build Coastguard Worker   if (!VirtualFree(start, 0, MEM_RELEASE)) {
62*4bdc9457SAndroid Build Coastguard Worker     xnn_log_error("failed to release code/weights buffer, error code: %" PRIu32, (uint32_t) GetLastError());
63*4bdc9457SAndroid Build Coastguard Worker     return xnn_status_invalid_state;
64*4bdc9457SAndroid Build Coastguard Worker   }
65*4bdc9457SAndroid Build Coastguard Worker #else
66*4bdc9457SAndroid Build Coastguard Worker   if (munmap(start, capacity) == -1) {
67*4bdc9457SAndroid Build Coastguard Worker     xnn_log_error("failed to release code/weights buffer, error code: %d", errno);
68*4bdc9457SAndroid Build Coastguard Worker     return xnn_status_invalid_state;
69*4bdc9457SAndroid Build Coastguard Worker   }
70*4bdc9457SAndroid Build Coastguard Worker #endif
71*4bdc9457SAndroid Build Coastguard Worker   return xnn_status_success;
72*4bdc9457SAndroid Build Coastguard Worker }
73*4bdc9457SAndroid Build Coastguard Worker 
74*4bdc9457SAndroid Build Coastguard Worker // Resize a buffer at old_pointer of size old_bytes to new_size. The actual new size of the resized buffer is written to
75*4bdc9457SAndroid Build Coastguard Worker // new_capacity_out, which can be >= new_size due to page alignment requirements.
76*4bdc9457SAndroid Build Coastguard Worker // Returns a pointer to a buffer which might be the same as old_pointer if we can remap virtual memory, otherwise we
77*4bdc9457SAndroid Build Coastguard Worker // allocate a new buffer and copy contents of old_buffer over.
resize_buffer(void * old_pointer,size_t old_size,size_t old_capacity,size_t new_size,size_t * new_capacity_out)78*4bdc9457SAndroid Build Coastguard Worker static void* resize_buffer(
79*4bdc9457SAndroid Build Coastguard Worker   void* old_pointer, size_t old_size, size_t old_capacity, size_t new_size, size_t* new_capacity_out)
80*4bdc9457SAndroid Build Coastguard Worker {
81*4bdc9457SAndroid Build Coastguard Worker   size_t new_capacity = round_up_po2(new_size, xnn_params.page_size);
82*4bdc9457SAndroid Build Coastguard Worker #if XNN_PLATFORM_LINUX
83*4bdc9457SAndroid Build Coastguard Worker   void* new_pointer = mremap(old_pointer, old_size, new_capacity, MREMAP_MAYMOVE, NULL);
84*4bdc9457SAndroid Build Coastguard Worker   if (new_pointer == MAP_FAILED) {
85*4bdc9457SAndroid Build Coastguard Worker     xnn_log_error("mremap failed with errno: %d", errno);
86*4bdc9457SAndroid Build Coastguard Worker     return NULL;
87*4bdc9457SAndroid Build Coastguard Worker   }
88*4bdc9457SAndroid Build Coastguard Worker   xnn_log_debug("resize_buffer: remap, old capacity %zu to new capacity %zu", old_capacity, new_capacity);
89*4bdc9457SAndroid Build Coastguard Worker #else
90*4bdc9457SAndroid Build Coastguard Worker   void* new_pointer = allocate_buffer(new_capacity);
91*4bdc9457SAndroid Build Coastguard Worker   if (new_pointer == NULL) {
92*4bdc9457SAndroid Build Coastguard Worker     xnn_log_error("allocate_buffer failed");
93*4bdc9457SAndroid Build Coastguard Worker     return NULL;
94*4bdc9457SAndroid Build Coastguard Worker   }
95*4bdc9457SAndroid Build Coastguard Worker   memcpy(new_pointer, old_pointer, old_size);
96*4bdc9457SAndroid Build Coastguard Worker   // Release old code_buffer.
97*4bdc9457SAndroid Build Coastguard Worker   enum xnn_status status = release_memory(old_pointer, old_capacity);
98*4bdc9457SAndroid Build Coastguard Worker   if (status != xnn_status_success) {
99*4bdc9457SAndroid Build Coastguard Worker     xnn_log_error("releasing old buffer failed, this could be a leak of %zu bytes", old_capacity);
100*4bdc9457SAndroid Build Coastguard Worker     // Log but proceed as per normal since we successfully allocated a new memory that can be used by the caller.
101*4bdc9457SAndroid Build Coastguard Worker   }
102*4bdc9457SAndroid Build Coastguard Worker   xnn_log_debug("resize_buffer: allocate memory, old capacity %zu to new capacity %zu", old_capacity, new_capacity);
103*4bdc9457SAndroid Build Coastguard Worker #endif
104*4bdc9457SAndroid Build Coastguard Worker   *new_capacity_out = new_capacity;
105*4bdc9457SAndroid Build Coastguard Worker   return new_pointer;
106*4bdc9457SAndroid Build Coastguard Worker }
107*4bdc9457SAndroid Build Coastguard Worker 
xnn_allocate_code_memory(struct xnn_code_buffer * buf,size_t size)108*4bdc9457SAndroid Build Coastguard Worker enum xnn_status xnn_allocate_code_memory(struct xnn_code_buffer* buf, size_t size) {
109*4bdc9457SAndroid Build Coastguard Worker   memset(buf, 0, sizeof(struct xnn_code_buffer));
110*4bdc9457SAndroid Build Coastguard Worker   size_t page_aligned_size = round_up_po2(size, xnn_params.page_size);
111*4bdc9457SAndroid Build Coastguard Worker   buf->start = allocate_buffer(page_aligned_size);
112*4bdc9457SAndroid Build Coastguard Worker   if (buf->start == NULL) {
113*4bdc9457SAndroid Build Coastguard Worker     return xnn_status_out_of_memory;
114*4bdc9457SAndroid Build Coastguard Worker   }
115*4bdc9457SAndroid Build Coastguard Worker 
116*4bdc9457SAndroid Build Coastguard Worker   buf->size = 0;
117*4bdc9457SAndroid Build Coastguard Worker   buf->capacity = page_aligned_size;
118*4bdc9457SAndroid Build Coastguard Worker   return xnn_status_success;
119*4bdc9457SAndroid Build Coastguard Worker }
120*4bdc9457SAndroid Build Coastguard Worker 
121*4bdc9457SAndroid Build Coastguard Worker // Releases unused memory. Will write the new capacity to `capacity`.
release_unused_memory(size_t size,void * start,size_t * capacity)122*4bdc9457SAndroid Build Coastguard Worker static enum xnn_status release_unused_memory(size_t size, void* start, size_t* capacity) {
123*4bdc9457SAndroid Build Coastguard Worker   // Release all unused pages.
124*4bdc9457SAndroid Build Coastguard Worker   const size_t page_aligned_size = round_up_po2(size, xnn_params.page_size);
125*4bdc9457SAndroid Build Coastguard Worker   const uint8_t* mem_start = (uint8_t*) start;
126*4bdc9457SAndroid Build Coastguard Worker   const uint8_t* unused_start = mem_start + page_aligned_size;
127*4bdc9457SAndroid Build Coastguard Worker   assert(*capacity >= page_aligned_size);
128*4bdc9457SAndroid Build Coastguard Worker   const size_t unused_capacity = *capacity - page_aligned_size;
129*4bdc9457SAndroid Build Coastguard Worker 
130*4bdc9457SAndroid Build Coastguard Worker   xnn_log_debug("releasing memory, start %p, used: %zu, capacity: %zu, unused %zu", mem_start, size, *capacity,
131*4bdc9457SAndroid Build Coastguard Worker                 unused_capacity);
132*4bdc9457SAndroid Build Coastguard Worker 
133*4bdc9457SAndroid Build Coastguard Worker   if (unused_capacity != 0) {
134*4bdc9457SAndroid Build Coastguard Worker     // Free unused pages.
135*4bdc9457SAndroid Build Coastguard Worker     #if XNN_PLATFORM_WINDOWS
136*4bdc9457SAndroid Build Coastguard Worker       // We cannot selectively release pages inside the region of pages, so just decommit them.
137*4bdc9457SAndroid Build Coastguard Worker       if (!VirtualFree((void*) unused_start, unused_capacity, MEM_DECOMMIT)) {
138*4bdc9457SAndroid Build Coastguard Worker         xnn_log_error("failed to unmap code/weights buffer, error code: %" PRIu32, (uint32_t) GetLastError());
139*4bdc9457SAndroid Build Coastguard Worker         return xnn_status_invalid_state;
140*4bdc9457SAndroid Build Coastguard Worker       }
141*4bdc9457SAndroid Build Coastguard Worker       *capacity = page_aligned_size;
142*4bdc9457SAndroid Build Coastguard Worker     #elif !XNN_PLATFORM_WEB
143*4bdc9457SAndroid Build Coastguard Worker       // Web does not support partial unmapping.
144*4bdc9457SAndroid Build Coastguard Worker       if (munmap((void*) unused_start, unused_capacity) == -1) {
145*4bdc9457SAndroid Build Coastguard Worker         xnn_log_error("failed to unmap code/weights buffer, error code: %d", errno);
146*4bdc9457SAndroid Build Coastguard Worker         return xnn_status_invalid_state;
147*4bdc9457SAndroid Build Coastguard Worker       }
148*4bdc9457SAndroid Build Coastguard Worker       *capacity = page_aligned_size;
149*4bdc9457SAndroid Build Coastguard Worker     #else
150*4bdc9457SAndroid Build Coastguard Worker       if (unused_capacity == *capacity) {
151*4bdc9457SAndroid Build Coastguard Worker         if (munmap((void*) unused_start, unused_capacity) == -1) {
152*4bdc9457SAndroid Build Coastguard Worker           xnn_log_error("failed to unmap code/weights buffer, error code: %d", errno);
153*4bdc9457SAndroid Build Coastguard Worker           return xnn_status_invalid_state;
154*4bdc9457SAndroid Build Coastguard Worker         } else {
155*4bdc9457SAndroid Build Coastguard Worker           *capacity = 0;
156*4bdc9457SAndroid Build Coastguard Worker         }
157*4bdc9457SAndroid Build Coastguard Worker       }
158*4bdc9457SAndroid Build Coastguard Worker     #endif
159*4bdc9457SAndroid Build Coastguard Worker   }
160*4bdc9457SAndroid Build Coastguard Worker 
161*4bdc9457SAndroid Build Coastguard Worker   return xnn_status_success;
162*4bdc9457SAndroid Build Coastguard Worker }
163*4bdc9457SAndroid Build Coastguard Worker 
164*4bdc9457SAndroid Build Coastguard Worker enum xnn_memory_permission {
165*4bdc9457SAndroid Build Coastguard Worker   xnn_memory_permission_read_only,
166*4bdc9457SAndroid Build Coastguard Worker   xnn_memory_permission_read_execute,
167*4bdc9457SAndroid Build Coastguard Worker };
168*4bdc9457SAndroid Build Coastguard Worker 
set_memory_permission(void * start,size_t size,enum xnn_memory_permission permission)169*4bdc9457SAndroid Build Coastguard Worker static enum xnn_status set_memory_permission(void* start, size_t size, enum xnn_memory_permission permission) {
170*4bdc9457SAndroid Build Coastguard Worker   #if XNN_PLATFORM_WINDOWS
171*4bdc9457SAndroid Build Coastguard Worker     DWORD old = 0, prot = 0;
172*4bdc9457SAndroid Build Coastguard Worker     switch (permission) {
173*4bdc9457SAndroid Build Coastguard Worker       case xnn_memory_permission_read_only:
174*4bdc9457SAndroid Build Coastguard Worker         prot = PAGE_READONLY;
175*4bdc9457SAndroid Build Coastguard Worker         break;
176*4bdc9457SAndroid Build Coastguard Worker       case xnn_memory_permission_read_execute:
177*4bdc9457SAndroid Build Coastguard Worker         prot = PAGE_EXECUTE_READ;
178*4bdc9457SAndroid Build Coastguard Worker         break;
179*4bdc9457SAndroid Build Coastguard Worker       default:
180*4bdc9457SAndroid Build Coastguard Worker         XNN_UNREACHABLE;
181*4bdc9457SAndroid Build Coastguard Worker     }
182*4bdc9457SAndroid Build Coastguard Worker     if (!VirtualProtect(start, size, prot, &old)) {
183*4bdc9457SAndroid Build Coastguard Worker       xnn_log_error(
184*4bdc9457SAndroid Build Coastguard Worker         "failed to set memory permission (%d), error code: %" PRIu32, permission, (uint32_t) GetLastError());
185*4bdc9457SAndroid Build Coastguard Worker       return xnn_status_invalid_state;
186*4bdc9457SAndroid Build Coastguard Worker     }
187*4bdc9457SAndroid Build Coastguard Worker   #elif XNN_PLATFORM_WEB
188*4bdc9457SAndroid Build Coastguard Worker     // Memory protection not supported on Web.
189*4bdc9457SAndroid Build Coastguard Worker     return xnn_status_success;
190*4bdc9457SAndroid Build Coastguard Worker   #else
191*4bdc9457SAndroid Build Coastguard Worker     int prot = 0;
192*4bdc9457SAndroid Build Coastguard Worker     switch (permission) {
193*4bdc9457SAndroid Build Coastguard Worker       case xnn_memory_permission_read_only:
194*4bdc9457SAndroid Build Coastguard Worker         prot = PROT_READ;
195*4bdc9457SAndroid Build Coastguard Worker         break;
196*4bdc9457SAndroid Build Coastguard Worker       case xnn_memory_permission_read_execute:
197*4bdc9457SAndroid Build Coastguard Worker         prot = PROT_READ | PROT_EXEC;
198*4bdc9457SAndroid Build Coastguard Worker         break;
199*4bdc9457SAndroid Build Coastguard Worker       default:
200*4bdc9457SAndroid Build Coastguard Worker         XNN_UNREACHABLE;
201*4bdc9457SAndroid Build Coastguard Worker     }
202*4bdc9457SAndroid Build Coastguard Worker     if (mprotect(start, size, prot) == -1) {
203*4bdc9457SAndroid Build Coastguard Worker       xnn_log_error("failed to set memory permission (%d), error code: %d", permission, errno);
204*4bdc9457SAndroid Build Coastguard Worker       return xnn_status_invalid_state;
205*4bdc9457SAndroid Build Coastguard Worker     }
206*4bdc9457SAndroid Build Coastguard Worker   #endif
207*4bdc9457SAndroid Build Coastguard Worker   return xnn_status_success;
208*4bdc9457SAndroid Build Coastguard Worker }
209*4bdc9457SAndroid Build Coastguard Worker 
210*4bdc9457SAndroid Build Coastguard Worker #if XNN_PLATFORM_JIT
xnn_finalize_code_memory(struct xnn_code_buffer * buf)211*4bdc9457SAndroid Build Coastguard Worker enum xnn_status xnn_finalize_code_memory(struct xnn_code_buffer* buf) {
212*4bdc9457SAndroid Build Coastguard Worker   enum xnn_status status;
213*4bdc9457SAndroid Build Coastguard Worker   status = release_unused_memory(buf->size, buf->start, &buf->capacity);
214*4bdc9457SAndroid Build Coastguard Worker   if (status != xnn_status_success) {
215*4bdc9457SAndroid Build Coastguard Worker     return status;
216*4bdc9457SAndroid Build Coastguard Worker   }
217*4bdc9457SAndroid Build Coastguard Worker 
218*4bdc9457SAndroid Build Coastguard Worker   if (buf->capacity == 0) {
219*4bdc9457SAndroid Build Coastguard Worker     return xnn_status_success;
220*4bdc9457SAndroid Build Coastguard Worker   }
221*4bdc9457SAndroid Build Coastguard Worker 
222*4bdc9457SAndroid Build Coastguard Worker   // Flush icache, do it before changing permissions due to bugs on older ARM64 kernels.
223*4bdc9457SAndroid Build Coastguard Worker   #if (XNN_ARCH_ARM || XNN_ARCH_ARM64) && XNN_PLATFORM_JIT
224*4bdc9457SAndroid Build Coastguard Worker     // iOS toolchain doesn't support this, use sys_icache_invalidate, when we support iOS.
225*4bdc9457SAndroid Build Coastguard Worker     __builtin___clear_cache(buf->start, (void*) ((uint8_t*) buf->start + buf->capacity));
226*4bdc9457SAndroid Build Coastguard Worker   #endif  // (XNN_ARCH_ARM || XNN_ARCH_ARM64) && !XNN_PLATFORM_IOS
227*4bdc9457SAndroid Build Coastguard Worker 
228*4bdc9457SAndroid Build Coastguard Worker   // Set permissions to RX (no write).
229*4bdc9457SAndroid Build Coastguard Worker   #if XNN_PLATFORM_WINDOWS
230*4bdc9457SAndroid Build Coastguard Worker     DWORD old = 0;
231*4bdc9457SAndroid Build Coastguard Worker     if (!VirtualProtect(buf->start, buf->size, PAGE_EXECUTE_READ, &old)) {
232*4bdc9457SAndroid Build Coastguard Worker       xnn_log_error("failed to make code buffer read+execute, error code: %" PRIu32, (uint32_t) GetLastError());
233*4bdc9457SAndroid Build Coastguard Worker       return xnn_status_invalid_state;
234*4bdc9457SAndroid Build Coastguard Worker     }
235*4bdc9457SAndroid Build Coastguard Worker   #else
236*4bdc9457SAndroid Build Coastguard Worker     if (mprotect(buf->start, buf->size, PROT_READ | PROT_EXEC) == -1) {
237*4bdc9457SAndroid Build Coastguard Worker       xnn_log_error("failed to make code buffer read+execute, error code: %d", errno);
238*4bdc9457SAndroid Build Coastguard Worker       return xnn_status_invalid_state;
239*4bdc9457SAndroid Build Coastguard Worker     }
240*4bdc9457SAndroid Build Coastguard Worker   #endif
241*4bdc9457SAndroid Build Coastguard Worker   return set_memory_permission(buf->start, buf->size, xnn_memory_permission_read_execute);
242*4bdc9457SAndroid Build Coastguard Worker }
243*4bdc9457SAndroid Build Coastguard Worker #endif  // XNN_PLATFORM_JIT
244*4bdc9457SAndroid Build Coastguard Worker 
xnn_release_code_memory(struct xnn_code_buffer * buf)245*4bdc9457SAndroid Build Coastguard Worker enum xnn_status xnn_release_code_memory(struct xnn_code_buffer* buf) {
246*4bdc9457SAndroid Build Coastguard Worker   if (buf->capacity == 0) {
247*4bdc9457SAndroid Build Coastguard Worker     return xnn_status_success;
248*4bdc9457SAndroid Build Coastguard Worker   }
249*4bdc9457SAndroid Build Coastguard Worker   const enum xnn_status status = release_memory(buf->start, buf->capacity);
250*4bdc9457SAndroid Build Coastguard Worker   if (status != xnn_status_success) {
251*4bdc9457SAndroid Build Coastguard Worker     return status;
252*4bdc9457SAndroid Build Coastguard Worker   }
253*4bdc9457SAndroid Build Coastguard Worker   memset(buf, 0, sizeof(struct xnn_code_buffer));
254*4bdc9457SAndroid Build Coastguard Worker   return xnn_status_success;
255*4bdc9457SAndroid Build Coastguard Worker }
256*4bdc9457SAndroid Build Coastguard Worker 
xnn_reserve_code_memory(struct xnn_code_buffer * buf,size_t n)257*4bdc9457SAndroid Build Coastguard Worker enum xnn_status xnn_reserve_code_memory(struct xnn_code_buffer* buf, size_t n) {
258*4bdc9457SAndroid Build Coastguard Worker   if (buf->size + n <= buf->capacity) {
259*4bdc9457SAndroid Build Coastguard Worker     return xnn_status_success;
260*4bdc9457SAndroid Build Coastguard Worker   }
261*4bdc9457SAndroid Build Coastguard Worker   xnn_log_debug("reserving code memory of size %zu", n);
262*4bdc9457SAndroid Build Coastguard Worker 
263*4bdc9457SAndroid Build Coastguard Worker   size_t new_capacity = 0;
264*4bdc9457SAndroid Build Coastguard Worker   void* new_start = resize_buffer(buf->start, buf->size, buf->capacity, buf->size + n, &new_capacity);
265*4bdc9457SAndroid Build Coastguard Worker   if (new_start == NULL) {
266*4bdc9457SAndroid Build Coastguard Worker     xnn_log_error("failed to reserve code memory");
267*4bdc9457SAndroid Build Coastguard Worker     return xnn_status_out_of_memory;
268*4bdc9457SAndroid Build Coastguard Worker   }
269*4bdc9457SAndroid Build Coastguard Worker   buf->start = new_start;
270*4bdc9457SAndroid Build Coastguard Worker   buf->capacity = new_capacity;
271*4bdc9457SAndroid Build Coastguard Worker   return xnn_status_success;
272*4bdc9457SAndroid Build Coastguard Worker }
273*4bdc9457SAndroid Build Coastguard Worker 
xnn_allocate_weights_memory(struct xnn_weights_buffer * buf,size_t size)274*4bdc9457SAndroid Build Coastguard Worker enum xnn_status xnn_allocate_weights_memory(struct xnn_weights_buffer* buf, size_t size) {
275*4bdc9457SAndroid Build Coastguard Worker   memset(buf, 0, sizeof(struct xnn_weights_buffer));
276*4bdc9457SAndroid Build Coastguard Worker   size_t page_aligned_size = round_up_po2(size, xnn_params.page_size);
277*4bdc9457SAndroid Build Coastguard Worker   buf->start = allocate_buffer(page_aligned_size);
278*4bdc9457SAndroid Build Coastguard Worker   if (buf->start == NULL) {
279*4bdc9457SAndroid Build Coastguard Worker     return xnn_status_out_of_memory;
280*4bdc9457SAndroid Build Coastguard Worker   }
281*4bdc9457SAndroid Build Coastguard Worker 
282*4bdc9457SAndroid Build Coastguard Worker   buf->size = 0;
283*4bdc9457SAndroid Build Coastguard Worker   buf->capacity = page_aligned_size;
284*4bdc9457SAndroid Build Coastguard Worker   return xnn_status_success;
285*4bdc9457SAndroid Build Coastguard Worker }
286*4bdc9457SAndroid Build Coastguard Worker 
xnn_release_weights_memory(struct xnn_weights_buffer * buf)287*4bdc9457SAndroid Build Coastguard Worker enum xnn_status xnn_release_weights_memory(struct xnn_weights_buffer* buf) {
288*4bdc9457SAndroid Build Coastguard Worker   if (buf->capacity == 0) {
289*4bdc9457SAndroid Build Coastguard Worker     return xnn_status_success;
290*4bdc9457SAndroid Build Coastguard Worker   }
291*4bdc9457SAndroid Build Coastguard Worker   enum xnn_status status = release_memory(buf->start, buf->capacity);
292*4bdc9457SAndroid Build Coastguard Worker   if (status != xnn_status_success) {
293*4bdc9457SAndroid Build Coastguard Worker     return status;
294*4bdc9457SAndroid Build Coastguard Worker   }
295*4bdc9457SAndroid Build Coastguard Worker   memset(buf, 0, sizeof(struct xnn_code_buffer));
296*4bdc9457SAndroid Build Coastguard Worker   return xnn_status_success;
297*4bdc9457SAndroid Build Coastguard Worker }
298*4bdc9457SAndroid Build Coastguard Worker 
xnn_reserve_weights_memory(struct xnn_weights_buffer * buf,size_t n)299*4bdc9457SAndroid Build Coastguard Worker enum xnn_status xnn_reserve_weights_memory(struct xnn_weights_buffer* buf, size_t n) {
300*4bdc9457SAndroid Build Coastguard Worker   if (buf->size + n <= buf->capacity) {
301*4bdc9457SAndroid Build Coastguard Worker     xnn_log_debug("reserving weights memory of size %zu without growing buffer", n);
302*4bdc9457SAndroid Build Coastguard Worker     return xnn_status_success;
303*4bdc9457SAndroid Build Coastguard Worker   }
304*4bdc9457SAndroid Build Coastguard Worker 
305*4bdc9457SAndroid Build Coastguard Worker   size_t new_capacity = 0;
306*4bdc9457SAndroid Build Coastguard Worker   void* new_start = resize_buffer(buf->start, buf->size, buf->capacity, buf->size + n, &new_capacity);
307*4bdc9457SAndroid Build Coastguard Worker   if (new_start == NULL) {
308*4bdc9457SAndroid Build Coastguard Worker     xnn_log_error("failed to reserve weights memory");
309*4bdc9457SAndroid Build Coastguard Worker     return xnn_status_out_of_memory;
310*4bdc9457SAndroid Build Coastguard Worker   }
311*4bdc9457SAndroid Build Coastguard Worker   buf->start = new_start;
312*4bdc9457SAndroid Build Coastguard Worker   buf->capacity = new_capacity;
313*4bdc9457SAndroid Build Coastguard Worker 
314*4bdc9457SAndroid Build Coastguard Worker   return xnn_status_success;
315*4bdc9457SAndroid Build Coastguard Worker }
316*4bdc9457SAndroid Build Coastguard Worker 
xnn_finalize_weights_memory(struct xnn_weights_buffer * buf)317*4bdc9457SAndroid Build Coastguard Worker enum xnn_status xnn_finalize_weights_memory(struct xnn_weights_buffer* buf) {
318*4bdc9457SAndroid Build Coastguard Worker   enum xnn_status status;
319*4bdc9457SAndroid Build Coastguard Worker   status = release_unused_memory(buf->size, buf->start, &buf->capacity);
320*4bdc9457SAndroid Build Coastguard Worker   if (status != xnn_status_success) {
321*4bdc9457SAndroid Build Coastguard Worker     return status;
322*4bdc9457SAndroid Build Coastguard Worker   }
323*4bdc9457SAndroid Build Coastguard Worker 
324*4bdc9457SAndroid Build Coastguard Worker   if (buf->capacity == 0) {
325*4bdc9457SAndroid Build Coastguard Worker     return xnn_status_success;
326*4bdc9457SAndroid Build Coastguard Worker   }
327*4bdc9457SAndroid Build Coastguard Worker 
328*4bdc9457SAndroid Build Coastguard Worker   return set_memory_permission(buf->start, buf->size, xnn_memory_permission_read_only);
329*4bdc9457SAndroid Build Coastguard Worker }
330