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