xref: /aosp_15_r20/external/XNNPACK/src/runtime.c (revision 4bdc94577ba0e567308109d787f7fec7b531ce36)
1*4bdc9457SAndroid Build Coastguard Worker // Copyright 2020 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 #ifndef __MACH__
7*4bdc9457SAndroid Build Coastguard Worker #define _POSIX_C_SOURCE 199309L
8*4bdc9457SAndroid Build Coastguard Worker #endif
9*4bdc9457SAndroid Build Coastguard Worker 
10*4bdc9457SAndroid Build Coastguard Worker #include <assert.h>
11*4bdc9457SAndroid Build Coastguard Worker #include <math.h>
12*4bdc9457SAndroid Build Coastguard Worker #include <stddef.h>
13*4bdc9457SAndroid Build Coastguard Worker #include <stdint.h>
14*4bdc9457SAndroid Build Coastguard Worker #include <stdio.h> // For snprintf.
15*4bdc9457SAndroid Build Coastguard Worker #include <stdlib.h>
16*4bdc9457SAndroid Build Coastguard Worker 
17*4bdc9457SAndroid Build Coastguard Worker #include <xnnpack.h>
18*4bdc9457SAndroid Build Coastguard Worker #include <xnnpack/allocator.h>
19*4bdc9457SAndroid Build Coastguard Worker #include <xnnpack/cache.h>
20*4bdc9457SAndroid Build Coastguard Worker #include <xnnpack/common.h>
21*4bdc9457SAndroid Build Coastguard Worker #include <xnnpack/log.h>
22*4bdc9457SAndroid Build Coastguard Worker #include <xnnpack/math.h>
23*4bdc9457SAndroid Build Coastguard Worker #include <xnnpack/memory-planner.h>
24*4bdc9457SAndroid Build Coastguard Worker #include <xnnpack/operator.h>
25*4bdc9457SAndroid Build Coastguard Worker #include <xnnpack/params.h>
26*4bdc9457SAndroid Build Coastguard Worker #include <xnnpack/subgraph.h>
27*4bdc9457SAndroid Build Coastguard Worker 
28*4bdc9457SAndroid Build Coastguard Worker #if defined(__EMSCRIPTEN__)
29*4bdc9457SAndroid Build Coastguard Worker #include <emscripten/emscripten.h>
30*4bdc9457SAndroid Build Coastguard Worker #elif XNN_PLATFORM_WINDOWS
31*4bdc9457SAndroid Build Coastguard Worker #include <windows.h>
32*4bdc9457SAndroid Build Coastguard Worker #else
33*4bdc9457SAndroid Build Coastguard Worker #include <errno.h>
34*4bdc9457SAndroid Build Coastguard Worker #include <time.h>
35*4bdc9457SAndroid Build Coastguard Worker #endif
36*4bdc9457SAndroid Build Coastguard Worker 
37*4bdc9457SAndroid Build Coastguard Worker #ifndef XNN_ENABLE_JIT
38*4bdc9457SAndroid Build Coastguard Worker   #error "XNN_ENABLE_JIT is not defined"
39*4bdc9457SAndroid Build Coastguard Worker #endif
40*4bdc9457SAndroid Build Coastguard Worker 
xnn_create_workspace(xnn_workspace_t * workspace_out)41*4bdc9457SAndroid Build Coastguard Worker enum xnn_status xnn_create_workspace(xnn_workspace_t* workspace_out)
42*4bdc9457SAndroid Build Coastguard Worker {
43*4bdc9457SAndroid Build Coastguard Worker   if ((xnn_params.init_flags & XNN_INIT_FLAG_XNNPACK) == 0) {
44*4bdc9457SAndroid Build Coastguard Worker     xnn_log_error("failed to create workspace: XNNPACK is not initialized");
45*4bdc9457SAndroid Build Coastguard Worker     return xnn_status_uninitialized;
46*4bdc9457SAndroid Build Coastguard Worker   }
47*4bdc9457SAndroid Build Coastguard Worker 
48*4bdc9457SAndroid Build Coastguard Worker   struct xnn_workspace* workspace = NULL;
49*4bdc9457SAndroid Build Coastguard Worker   workspace = xnn_allocate_zero_memory(sizeof(struct xnn_workspace));
50*4bdc9457SAndroid Build Coastguard Worker   if (workspace == NULL) {
51*4bdc9457SAndroid Build Coastguard Worker     xnn_log_error("failed to allocate %zu bytes for workspace descriptor", sizeof(struct xnn_workspace));
52*4bdc9457SAndroid Build Coastguard Worker     return xnn_status_out_of_memory;
53*4bdc9457SAndroid Build Coastguard Worker   }
54*4bdc9457SAndroid Build Coastguard Worker   workspace->ref_count = 1;
55*4bdc9457SAndroid Build Coastguard Worker   *workspace_out = workspace;
56*4bdc9457SAndroid Build Coastguard Worker   return xnn_status_success;
57*4bdc9457SAndroid Build Coastguard Worker }
58*4bdc9457SAndroid Build Coastguard Worker 
xnn_retain_workspace(xnn_workspace_t workspace)59*4bdc9457SAndroid Build Coastguard Worker static inline void xnn_retain_workspace(xnn_workspace_t workspace)
60*4bdc9457SAndroid Build Coastguard Worker {
61*4bdc9457SAndroid Build Coastguard Worker   workspace->ref_count++;
62*4bdc9457SAndroid Build Coastguard Worker }
63*4bdc9457SAndroid Build Coastguard Worker 
xnn_release_workspace(xnn_workspace_t workspace)64*4bdc9457SAndroid Build Coastguard Worker enum xnn_status xnn_release_workspace(xnn_workspace_t workspace)
65*4bdc9457SAndroid Build Coastguard Worker {
66*4bdc9457SAndroid Build Coastguard Worker   assert(workspace->ref_count != 0);
67*4bdc9457SAndroid Build Coastguard Worker   if (--workspace->ref_count == 0) {
68*4bdc9457SAndroid Build Coastguard Worker     xnn_release_simd_memory(workspace->data);
69*4bdc9457SAndroid Build Coastguard Worker     xnn_release_memory(workspace);
70*4bdc9457SAndroid Build Coastguard Worker   }
71*4bdc9457SAndroid Build Coastguard Worker   return xnn_status_success;
72*4bdc9457SAndroid Build Coastguard Worker }
73*4bdc9457SAndroid Build Coastguard Worker 
xnn_create_weights_cache_with_size(size_t size,xnn_weights_cache_t * weights_cache_out)74*4bdc9457SAndroid Build Coastguard Worker enum xnn_status xnn_create_weights_cache_with_size(size_t size, xnn_weights_cache_t* weights_cache_out)
75*4bdc9457SAndroid Build Coastguard Worker {
76*4bdc9457SAndroid Build Coastguard Worker   struct xnn_weights_cache* weights_cache = NULL;
77*4bdc9457SAndroid Build Coastguard Worker   enum xnn_status status = xnn_status_uninitialized;
78*4bdc9457SAndroid Build Coastguard Worker 
79*4bdc9457SAndroid Build Coastguard Worker   if ((xnn_params.init_flags & XNN_INIT_FLAG_XNNPACK) == 0) {
80*4bdc9457SAndroid Build Coastguard Worker     xnn_log_error("failed to create weights cache: XNNPACK is not initialized");
81*4bdc9457SAndroid Build Coastguard Worker     goto error;
82*4bdc9457SAndroid Build Coastguard Worker   }
83*4bdc9457SAndroid Build Coastguard Worker 
84*4bdc9457SAndroid Build Coastguard Worker   weights_cache = xnn_allocate_zero_memory(sizeof(struct xnn_weights_cache));
85*4bdc9457SAndroid Build Coastguard Worker   if (weights_cache == NULL) {
86*4bdc9457SAndroid Build Coastguard Worker     xnn_log_error("failed to allocate %zu bytes for weights cache descriptor", sizeof(struct xnn_weights_cache));
87*4bdc9457SAndroid Build Coastguard Worker     goto error;
88*4bdc9457SAndroid Build Coastguard Worker   }
89*4bdc9457SAndroid Build Coastguard Worker 
90*4bdc9457SAndroid Build Coastguard Worker   status = xnn_init_weights_cache_with_size(weights_cache, size);
91*4bdc9457SAndroid Build Coastguard Worker   if (status != xnn_status_success) {
92*4bdc9457SAndroid Build Coastguard Worker     goto error;
93*4bdc9457SAndroid Build Coastguard Worker   }
94*4bdc9457SAndroid Build Coastguard Worker   *weights_cache_out = weights_cache;
95*4bdc9457SAndroid Build Coastguard Worker   return xnn_status_success;
96*4bdc9457SAndroid Build Coastguard Worker 
97*4bdc9457SAndroid Build Coastguard Worker error:
98*4bdc9457SAndroid Build Coastguard Worker   xnn_release_weights_cache(weights_cache);
99*4bdc9457SAndroid Build Coastguard Worker   return status;
100*4bdc9457SAndroid Build Coastguard Worker }
101*4bdc9457SAndroid Build Coastguard Worker 
xnn_create_weights_cache(xnn_weights_cache_t * weights_cache_out)102*4bdc9457SAndroid Build Coastguard Worker enum xnn_status xnn_create_weights_cache(xnn_weights_cache_t* weights_cache_out)
103*4bdc9457SAndroid Build Coastguard Worker {
104*4bdc9457SAndroid Build Coastguard Worker   return xnn_create_weights_cache_with_size(XNN_DEFAULT_WEIGHTS_BUFFER_SIZE, weights_cache_out);
105*4bdc9457SAndroid Build Coastguard Worker }
106*4bdc9457SAndroid Build Coastguard Worker 
xnn_delete_weights_cache(xnn_weights_cache_t weights_cache)107*4bdc9457SAndroid Build Coastguard Worker enum xnn_status xnn_delete_weights_cache(xnn_weights_cache_t weights_cache)
108*4bdc9457SAndroid Build Coastguard Worker {
109*4bdc9457SAndroid Build Coastguard Worker   enum xnn_status status = xnn_release_weights_cache(weights_cache);
110*4bdc9457SAndroid Build Coastguard Worker   if (status != xnn_status_success) {
111*4bdc9457SAndroid Build Coastguard Worker     return status;
112*4bdc9457SAndroid Build Coastguard Worker   }
113*4bdc9457SAndroid Build Coastguard Worker   xnn_release_memory(weights_cache);
114*4bdc9457SAndroid Build Coastguard Worker   return xnn_status_success;
115*4bdc9457SAndroid Build Coastguard Worker }
116*4bdc9457SAndroid Build Coastguard Worker 
xnn_create_runtime(xnn_subgraph_t subgraph,xnn_runtime_t * runtime_out)117*4bdc9457SAndroid Build Coastguard Worker enum xnn_status xnn_create_runtime(
118*4bdc9457SAndroid Build Coastguard Worker   xnn_subgraph_t subgraph,
119*4bdc9457SAndroid Build Coastguard Worker   xnn_runtime_t* runtime_out)
120*4bdc9457SAndroid Build Coastguard Worker {
121*4bdc9457SAndroid Build Coastguard Worker   return xnn_create_runtime_v2(subgraph, NULL /* threadpool */, 0 /* flags */, runtime_out);
122*4bdc9457SAndroid Build Coastguard Worker }
123*4bdc9457SAndroid Build Coastguard Worker 
xnn_create_runtime_v2(xnn_subgraph_t subgraph,pthreadpool_t threadpool,uint32_t flags,xnn_runtime_t * runtime_out)124*4bdc9457SAndroid Build Coastguard Worker enum xnn_status xnn_create_runtime_v2(
125*4bdc9457SAndroid Build Coastguard Worker   xnn_subgraph_t subgraph,
126*4bdc9457SAndroid Build Coastguard Worker   pthreadpool_t threadpool,
127*4bdc9457SAndroid Build Coastguard Worker   uint32_t flags,
128*4bdc9457SAndroid Build Coastguard Worker   xnn_runtime_t* runtime_out)
129*4bdc9457SAndroid Build Coastguard Worker {
130*4bdc9457SAndroid Build Coastguard Worker   return xnn_create_runtime_v3(subgraph, /* weights_cache */ NULL, threadpool, flags, runtime_out);
131*4bdc9457SAndroid Build Coastguard Worker }
132*4bdc9457SAndroid Build Coastguard Worker 
xnn_create_runtime_v3(xnn_subgraph_t subgraph,xnn_weights_cache_t weights_cache,pthreadpool_t threadpool,uint32_t flags,xnn_runtime_t * runtime_out)133*4bdc9457SAndroid Build Coastguard Worker enum xnn_status xnn_create_runtime_v3(
134*4bdc9457SAndroid Build Coastguard Worker   xnn_subgraph_t subgraph,
135*4bdc9457SAndroid Build Coastguard Worker   xnn_weights_cache_t weights_cache,
136*4bdc9457SAndroid Build Coastguard Worker   pthreadpool_t threadpool,
137*4bdc9457SAndroid Build Coastguard Worker   uint32_t flags,
138*4bdc9457SAndroid Build Coastguard Worker   xnn_runtime_t* runtime_out)
139*4bdc9457SAndroid Build Coastguard Worker {
140*4bdc9457SAndroid Build Coastguard Worker   xnn_workspace_t workspace;
141*4bdc9457SAndroid Build Coastguard Worker   enum xnn_status status = xnn_create_workspace(&workspace);
142*4bdc9457SAndroid Build Coastguard Worker   if (status != xnn_status_success) {
143*4bdc9457SAndroid Build Coastguard Worker     return status;
144*4bdc9457SAndroid Build Coastguard Worker   }
145*4bdc9457SAndroid Build Coastguard Worker   status = xnn_create_runtime_v4(subgraph, weights_cache, workspace, threadpool, flags, runtime_out);
146*4bdc9457SAndroid Build Coastguard Worker   // Release workspace regardless of return status of creating runtime.
147*4bdc9457SAndroid Build Coastguard Worker   xnn_release_workspace(workspace);
148*4bdc9457SAndroid Build Coastguard Worker   return status;
149*4bdc9457SAndroid Build Coastguard Worker }
150*4bdc9457SAndroid Build Coastguard Worker 
initialize_workspace_blobs(xnn_subgraph_t subgraph,xnn_runtime_t runtime,struct xnn_value_allocation_tracker * mem_alloc_tracker)151*4bdc9457SAndroid Build Coastguard Worker static enum xnn_status initialize_workspace_blobs(
152*4bdc9457SAndroid Build Coastguard Worker     xnn_subgraph_t subgraph,
153*4bdc9457SAndroid Build Coastguard Worker     xnn_runtime_t runtime,
154*4bdc9457SAndroid Build Coastguard Worker     struct xnn_value_allocation_tracker* mem_alloc_tracker)
155*4bdc9457SAndroid Build Coastguard Worker {
156*4bdc9457SAndroid Build Coastguard Worker   assert(runtime->workspace != NULL);
157*4bdc9457SAndroid Build Coastguard Worker 
158*4bdc9457SAndroid Build Coastguard Worker   size_t mem_arena_size = mem_alloc_tracker->mem_arena_size;
159*4bdc9457SAndroid Build Coastguard Worker   if (mem_arena_size == 0) {
160*4bdc9457SAndroid Build Coastguard Worker     return xnn_status_success;
161*4bdc9457SAndroid Build Coastguard Worker   }
162*4bdc9457SAndroid Build Coastguard Worker   // Sparse microkernels can read up to 2 * XNN_EXTRA_BYTES beyond array bounds.
163*4bdc9457SAndroid Build Coastguard Worker   mem_arena_size += 2 * XNN_EXTRA_BYTES;
164*4bdc9457SAndroid Build Coastguard Worker 
165*4bdc9457SAndroid Build Coastguard Worker   // Records how much the workspace has moved by due to allocating a larger workspace.
166*4bdc9457SAndroid Build Coastguard Worker   ptrdiff_t workspace_data_delta = 0;
167*4bdc9457SAndroid Build Coastguard Worker   // Allocates larger workspace here if needed.
168*4bdc9457SAndroid Build Coastguard Worker   if (runtime->workspace->size < mem_arena_size) {
169*4bdc9457SAndroid Build Coastguard Worker     void* old_workspace_data = runtime->workspace->data;
170*4bdc9457SAndroid Build Coastguard Worker     if (runtime->workspace->size != 0) {
171*4bdc9457SAndroid Build Coastguard Worker       // Free up the workspace's current data. Free first then allocate to keep peak memory usage low.
172*4bdc9457SAndroid Build Coastguard Worker       xnn_release_simd_memory(runtime->workspace->data);
173*4bdc9457SAndroid Build Coastguard Worker     }
174*4bdc9457SAndroid Build Coastguard Worker     void* new_workspace_data = xnn_allocate_simd_memory(mem_arena_size);
175*4bdc9457SAndroid Build Coastguard Worker     if (new_workspace_data == NULL) {
176*4bdc9457SAndroid Build Coastguard Worker       xnn_log_error("failed to allocate %zu bytes for runtime workspace", mem_arena_size);
177*4bdc9457SAndroid Build Coastguard Worker       return xnn_status_out_of_memory;
178*4bdc9457SAndroid Build Coastguard Worker     }
179*4bdc9457SAndroid Build Coastguard Worker     runtime->workspace->data = new_workspace_data;
180*4bdc9457SAndroid Build Coastguard Worker     runtime->workspace->size = mem_arena_size;
181*4bdc9457SAndroid Build Coastguard Worker     // Keep track of how much the workspace data moved.
182*4bdc9457SAndroid Build Coastguard Worker     if (old_workspace_data != NULL) {
183*4bdc9457SAndroid Build Coastguard Worker       workspace_data_delta = (uintptr_t) new_workspace_data - (uintptr_t) old_workspace_data;
184*4bdc9457SAndroid Build Coastguard Worker     }
185*4bdc9457SAndroid Build Coastguard Worker   }
186*4bdc9457SAndroid Build Coastguard Worker 
187*4bdc9457SAndroid Build Coastguard Worker   assert(runtime->workspace->size >= mem_arena_size);
188*4bdc9457SAndroid Build Coastguard Worker 
189*4bdc9457SAndroid Build Coastguard Worker   // Initialize current runtime's blob pointers.
190*4bdc9457SAndroid Build Coastguard Worker   for (size_t i = 0; i < subgraph->num_values; i++) {
191*4bdc9457SAndroid Build Coastguard Worker     const struct xnn_value* value = &subgraph->values[i];
192*4bdc9457SAndroid Build Coastguard Worker     struct xnn_blob* blob = &runtime->blobs[i];
193*4bdc9457SAndroid Build Coastguard Worker     if (value->datatype != xnn_datatype_invalid && value->type == xnn_value_type_dense_tensor) {
194*4bdc9457SAndroid Build Coastguard Worker       if (blob->allocation_type == xnn_allocation_type_workspace) {
195*4bdc9457SAndroid Build Coastguard Worker         // Value is purely internal to the runtime, allocate it in the workspace.
196*4bdc9457SAndroid Build Coastguard Worker         blob->data = (void*) ((uintptr_t) runtime->workspace->data + mem_alloc_tracker->usage[i].alloc_offset);
197*4bdc9457SAndroid Build Coastguard Worker       }
198*4bdc9457SAndroid Build Coastguard Worker     }
199*4bdc9457SAndroid Build Coastguard Worker   }
200*4bdc9457SAndroid Build Coastguard Worker 
201*4bdc9457SAndroid Build Coastguard Worker   // Adjust the blob pointers of all runtimes that share this workspace.
202*4bdc9457SAndroid Build Coastguard Worker   if (workspace_data_delta != 0) {
203*4bdc9457SAndroid Build Coastguard Worker     for (struct xnn_runtime* rt = runtime->workspace->first_user; rt != NULL; rt = rt->next_workspace_user) {
204*4bdc9457SAndroid Build Coastguard Worker       // The current runtime already has the correct offset.
205*4bdc9457SAndroid Build Coastguard Worker       if (rt == runtime) {
206*4bdc9457SAndroid Build Coastguard Worker         continue;
207*4bdc9457SAndroid Build Coastguard Worker       }
208*4bdc9457SAndroid Build Coastguard Worker       for (size_t i = 0; i < rt->num_blobs; i++) {
209*4bdc9457SAndroid Build Coastguard Worker         struct xnn_blob* blob = &rt->blobs[i];
210*4bdc9457SAndroid Build Coastguard Worker         if (blob->allocation_type == xnn_allocation_type_workspace) {
211*4bdc9457SAndroid Build Coastguard Worker           assert(blob->data != NULL);
212*4bdc9457SAndroid Build Coastguard Worker           blob->data = (void*) ((uintptr_t) blob->data + workspace_data_delta);
213*4bdc9457SAndroid Build Coastguard Worker         }
214*4bdc9457SAndroid Build Coastguard Worker       }
215*4bdc9457SAndroid Build Coastguard Worker     }
216*4bdc9457SAndroid Build Coastguard Worker   }
217*4bdc9457SAndroid Build Coastguard Worker 
218*4bdc9457SAndroid Build Coastguard Worker   return xnn_status_success;
219*4bdc9457SAndroid Build Coastguard Worker }
220*4bdc9457SAndroid Build Coastguard Worker 
xnn_create_runtime_v4(xnn_subgraph_t subgraph,xnn_weights_cache_t weights_cache,xnn_workspace_t workspace,pthreadpool_t threadpool,uint32_t flags,xnn_runtime_t * runtime_out)221*4bdc9457SAndroid Build Coastguard Worker enum xnn_status xnn_create_runtime_v4(
222*4bdc9457SAndroid Build Coastguard Worker   xnn_subgraph_t subgraph,
223*4bdc9457SAndroid Build Coastguard Worker   xnn_weights_cache_t weights_cache,
224*4bdc9457SAndroid Build Coastguard Worker   xnn_workspace_t workspace,
225*4bdc9457SAndroid Build Coastguard Worker   pthreadpool_t threadpool,
226*4bdc9457SAndroid Build Coastguard Worker   uint32_t flags,
227*4bdc9457SAndroid Build Coastguard Worker   xnn_runtime_t* runtime_out)
228*4bdc9457SAndroid Build Coastguard Worker {
229*4bdc9457SAndroid Build Coastguard Worker   struct xnn_runtime* runtime = NULL;
230*4bdc9457SAndroid Build Coastguard Worker   enum xnn_status status = xnn_status_uninitialized;
231*4bdc9457SAndroid Build Coastguard Worker 
232*4bdc9457SAndroid Build Coastguard Worker   if ((xnn_params.init_flags & XNN_INIT_FLAG_XNNPACK) == 0) {
233*4bdc9457SAndroid Build Coastguard Worker     xnn_log_error("failed to create runtime: XNNPACK is not initialized");
234*4bdc9457SAndroid Build Coastguard Worker     goto error;
235*4bdc9457SAndroid Build Coastguard Worker   }
236*4bdc9457SAndroid Build Coastguard Worker 
237*4bdc9457SAndroid Build Coastguard Worker   if (workspace == NULL) {
238*4bdc9457SAndroid Build Coastguard Worker     xnn_log_error("failed to create runtime: workspace is NULL");
239*4bdc9457SAndroid Build Coastguard Worker     status = xnn_status_invalid_parameter;
240*4bdc9457SAndroid Build Coastguard Worker     goto error;
241*4bdc9457SAndroid Build Coastguard Worker   }
242*4bdc9457SAndroid Build Coastguard Worker 
243*4bdc9457SAndroid Build Coastguard Worker   const uint32_t optimization_flags = XNN_FLAG_SPARSE_INFERENCE | XNN_FLAG_HINT_FP16_INFERENCE |
244*4bdc9457SAndroid Build Coastguard Worker     XNN_FLAG_FORCE_FP16_INFERENCE | XNN_FLAG_NO_OPERATOR_FUSION;
245*4bdc9457SAndroid Build Coastguard Worker   status = xnn_subgraph_optimize(subgraph, flags & optimization_flags);
246*4bdc9457SAndroid Build Coastguard Worker   if (status != xnn_status_success) {
247*4bdc9457SAndroid Build Coastguard Worker     xnn_log_error("failed to optimize subgraph");
248*4bdc9457SAndroid Build Coastguard Worker     goto error;
249*4bdc9457SAndroid Build Coastguard Worker   }
250*4bdc9457SAndroid Build Coastguard Worker 
251*4bdc9457SAndroid Build Coastguard Worker   status = xnn_status_out_of_memory;
252*4bdc9457SAndroid Build Coastguard Worker 
253*4bdc9457SAndroid Build Coastguard Worker   runtime = xnn_allocate_zero_memory(sizeof(struct xnn_runtime));
254*4bdc9457SAndroid Build Coastguard Worker   if (runtime == NULL) {
255*4bdc9457SAndroid Build Coastguard Worker     xnn_log_error("failed to allocate %zu bytes for runtime descriptor", sizeof(struct xnn_runtime));
256*4bdc9457SAndroid Build Coastguard Worker     goto error;
257*4bdc9457SAndroid Build Coastguard Worker   }
258*4bdc9457SAndroid Build Coastguard Worker 
259*4bdc9457SAndroid Build Coastguard Worker   runtime->opdata = xnn_allocate_zero_memory(sizeof(struct xnn_operator_data) * subgraph->num_nodes);
260*4bdc9457SAndroid Build Coastguard Worker   if (runtime->opdata == NULL) {
261*4bdc9457SAndroid Build Coastguard Worker     xnn_log_error("failed to allocate %zu bytes for opdata descriptors",
262*4bdc9457SAndroid Build Coastguard Worker       sizeof(struct xnn_operator_data) * (size_t) subgraph->num_nodes);
263*4bdc9457SAndroid Build Coastguard Worker     goto error;
264*4bdc9457SAndroid Build Coastguard Worker   }
265*4bdc9457SAndroid Build Coastguard Worker   runtime->num_ops = subgraph->num_nodes;
266*4bdc9457SAndroid Build Coastguard Worker 
267*4bdc9457SAndroid Build Coastguard Worker   if (flags & XNN_FLAG_YIELD_WORKERS) {
268*4bdc9457SAndroid Build Coastguard Worker     struct xnn_node* last_valid_node = NULL;
269*4bdc9457SAndroid Build Coastguard Worker     for (size_t i = 0; i < subgraph->num_nodes; i++) {
270*4bdc9457SAndroid Build Coastguard Worker       struct xnn_node* node = subgraph->nodes + i;
271*4bdc9457SAndroid Build Coastguard Worker       if (node->type != xnn_node_type_invalid) {
272*4bdc9457SAndroid Build Coastguard Worker         last_valid_node = node;
273*4bdc9457SAndroid Build Coastguard Worker       }
274*4bdc9457SAndroid Build Coastguard Worker     }
275*4bdc9457SAndroid Build Coastguard Worker     if (last_valid_node != NULL) {
276*4bdc9457SAndroid Build Coastguard Worker       last_valid_node->flags |= XNN_FLAG_YIELD_WORKERS;
277*4bdc9457SAndroid Build Coastguard Worker     }
278*4bdc9457SAndroid Build Coastguard Worker   }
279*4bdc9457SAndroid Build Coastguard Worker 
280*4bdc9457SAndroid Build Coastguard Worker   struct xnn_code_cache* code_cache = NULL;
281*4bdc9457SAndroid Build Coastguard Worker #if XNN_PLATFORM_JIT && XNN_ENABLE_JIT
282*4bdc9457SAndroid Build Coastguard Worker   code_cache = &runtime->code_cache;
283*4bdc9457SAndroid Build Coastguard Worker   status = xnn_init_code_cache(code_cache);
284*4bdc9457SAndroid Build Coastguard Worker   if (status != xnn_status_success) {
285*4bdc9457SAndroid Build Coastguard Worker     goto error;
286*4bdc9457SAndroid Build Coastguard Worker   }
287*4bdc9457SAndroid Build Coastguard Worker #endif
288*4bdc9457SAndroid Build Coastguard Worker   const struct xnn_caches caches = {
289*4bdc9457SAndroid Build Coastguard Worker     .code_cache = code_cache,
290*4bdc9457SAndroid Build Coastguard Worker     .weights_cache = weights_cache,
291*4bdc9457SAndroid Build Coastguard Worker   };
292*4bdc9457SAndroid Build Coastguard Worker 
293*4bdc9457SAndroid Build Coastguard Worker   struct xnn_value* values = subgraph->values;
294*4bdc9457SAndroid Build Coastguard Worker   for (size_t i = 0; i < subgraph->num_nodes; i++) {
295*4bdc9457SAndroid Build Coastguard Worker     const struct xnn_node* node = subgraph->nodes + i;
296*4bdc9457SAndroid Build Coastguard Worker 
297*4bdc9457SAndroid Build Coastguard Worker     // Ignore fused nodes
298*4bdc9457SAndroid Build Coastguard Worker     if (node->type != xnn_node_type_invalid) {
299*4bdc9457SAndroid Build Coastguard Worker       assert(node->create != NULL);
300*4bdc9457SAndroid Build Coastguard Worker       status = node->create(node, values, subgraph->num_values, runtime->opdata + i, &caches);
301*4bdc9457SAndroid Build Coastguard Worker       if (status != xnn_status_success) {
302*4bdc9457SAndroid Build Coastguard Worker         goto error;
303*4bdc9457SAndroid Build Coastguard Worker       }
304*4bdc9457SAndroid Build Coastguard Worker       runtime->opdata[i].setup = node->setup;
305*4bdc9457SAndroid Build Coastguard Worker     }
306*4bdc9457SAndroid Build Coastguard Worker   }
307*4bdc9457SAndroid Build Coastguard Worker 
308*4bdc9457SAndroid Build Coastguard Worker #if XNN_PLATFORM_JIT && XNN_ENABLE_JIT
309*4bdc9457SAndroid Build Coastguard Worker   xnn_finalize_code_memory(&code_cache->cache.code);
310*4bdc9457SAndroid Build Coastguard Worker #endif
311*4bdc9457SAndroid Build Coastguard Worker 
312*4bdc9457SAndroid Build Coastguard Worker   runtime->blobs = xnn_allocate_zero_memory(sizeof(struct xnn_blob) * subgraph->num_values);
313*4bdc9457SAndroid Build Coastguard Worker   if (runtime->blobs == NULL) {
314*4bdc9457SAndroid Build Coastguard Worker     xnn_log_error("failed to allocate %zu bytes for blob descriptors",
315*4bdc9457SAndroid Build Coastguard Worker       sizeof(struct xnn_blob) * (size_t) subgraph->num_values);
316*4bdc9457SAndroid Build Coastguard Worker     goto error;
317*4bdc9457SAndroid Build Coastguard Worker   }
318*4bdc9457SAndroid Build Coastguard Worker   runtime->num_blobs = subgraph->num_values;
319*4bdc9457SAndroid Build Coastguard Worker 
320*4bdc9457SAndroid Build Coastguard Worker   struct xnn_value_allocation_tracker mem_alloc_tracker;
321*4bdc9457SAndroid Build Coastguard Worker   xnn_init_value_allocation_tracker(&mem_alloc_tracker, subgraph);
322*4bdc9457SAndroid Build Coastguard Worker 
323*4bdc9457SAndroid Build Coastguard Worker   for (uint32_t i = 0; i < subgraph->num_values; i++) {
324*4bdc9457SAndroid Build Coastguard Worker     struct xnn_value* value = &subgraph->values[i];
325*4bdc9457SAndroid Build Coastguard Worker     struct xnn_blob* blob = &runtime->blobs[i];
326*4bdc9457SAndroid Build Coastguard Worker     if (value->datatype != xnn_datatype_invalid && value->type == xnn_value_type_dense_tensor) {
327*4bdc9457SAndroid Build Coastguard Worker       blob->size = xnn_tensor_get_size(subgraph, i);
328*4bdc9457SAndroid Build Coastguard Worker       blob->data = (void*) (uintptr_t) value->data;
329*4bdc9457SAndroid Build Coastguard Worker       if (blob->data == NULL) {
330*4bdc9457SAndroid Build Coastguard Worker         if ((value->flags & (XNN_VALUE_FLAG_EXTERNAL_INPUT | XNN_VALUE_FLAG_EXTERNAL_OUTPUT)) == 0) {
331*4bdc9457SAndroid Build Coastguard Worker           // Value is purely internal to the runtime, and must be allocated in its workspace.
332*4bdc9457SAndroid Build Coastguard Worker           xnn_add_value_allocation_tracker(&mem_alloc_tracker, i, round_up_po2(blob->size, XNN_EXTRA_BYTES));
333*4bdc9457SAndroid Build Coastguard Worker           blob->allocation_type = xnn_allocation_type_workspace;
334*4bdc9457SAndroid Build Coastguard Worker         } else {
335*4bdc9457SAndroid Build Coastguard Worker           // Value is non-static and external to the runtime: must be specified via a call to xnn_setup_runtime.
336*4bdc9457SAndroid Build Coastguard Worker           blob->allocation_type = xnn_allocation_type_external;
337*4bdc9457SAndroid Build Coastguard Worker         }
338*4bdc9457SAndroid Build Coastguard Worker       } else {
339*4bdc9457SAndroid Build Coastguard Worker         blob->allocation_type = xnn_allocation_type_static;
340*4bdc9457SAndroid Build Coastguard Worker       }
341*4bdc9457SAndroid Build Coastguard Worker     }
342*4bdc9457SAndroid Build Coastguard Worker   }
343*4bdc9457SAndroid Build Coastguard Worker   xnn_plan_value_allocation_tracker(&mem_alloc_tracker);
344*4bdc9457SAndroid Build Coastguard Worker 
345*4bdc9457SAndroid Build Coastguard Worker   xnn_retain_workspace(workspace);
346*4bdc9457SAndroid Build Coastguard Worker   runtime->workspace = workspace;
347*4bdc9457SAndroid Build Coastguard Worker   runtime->next_workspace_user = runtime->workspace->first_user;
348*4bdc9457SAndroid Build Coastguard Worker   runtime->workspace->first_user = runtime;
349*4bdc9457SAndroid Build Coastguard Worker 
350*4bdc9457SAndroid Build Coastguard Worker   status = initialize_workspace_blobs(subgraph, runtime, &mem_alloc_tracker);
351*4bdc9457SAndroid Build Coastguard Worker   if (status != xnn_status_success) {
352*4bdc9457SAndroid Build Coastguard Worker     xnn_release_value_allocation_tracker(&mem_alloc_tracker);
353*4bdc9457SAndroid Build Coastguard Worker     goto error;
354*4bdc9457SAndroid Build Coastguard Worker   }
355*4bdc9457SAndroid Build Coastguard Worker 
356*4bdc9457SAndroid Build Coastguard Worker   if (flags & XNN_FLAG_BASIC_PROFILING) {
357*4bdc9457SAndroid Build Coastguard Worker     runtime->profiling = true;
358*4bdc9457SAndroid Build Coastguard Worker   }
359*4bdc9457SAndroid Build Coastguard Worker 
360*4bdc9457SAndroid Build Coastguard Worker   xnn_release_value_allocation_tracker(&mem_alloc_tracker);
361*4bdc9457SAndroid Build Coastguard Worker 
362*4bdc9457SAndroid Build Coastguard Worker   runtime->threadpool = threadpool;
363*4bdc9457SAndroid Build Coastguard Worker 
364*4bdc9457SAndroid Build Coastguard Worker   *runtime_out = runtime;
365*4bdc9457SAndroid Build Coastguard Worker   return xnn_status_success;
366*4bdc9457SAndroid Build Coastguard Worker 
367*4bdc9457SAndroid Build Coastguard Worker error:
368*4bdc9457SAndroid Build Coastguard Worker   xnn_delete_runtime(runtime);
369*4bdc9457SAndroid Build Coastguard Worker   return status;
370*4bdc9457SAndroid Build Coastguard Worker }
371*4bdc9457SAndroid Build Coastguard Worker 
xnn_setup_runtime(xnn_runtime_t runtime,size_t num_external_values,const struct xnn_external_value * external_values)372*4bdc9457SAndroid Build Coastguard Worker enum xnn_status xnn_setup_runtime(
373*4bdc9457SAndroid Build Coastguard Worker   xnn_runtime_t runtime,
374*4bdc9457SAndroid Build Coastguard Worker   size_t num_external_values,
375*4bdc9457SAndroid Build Coastguard Worker   const struct xnn_external_value* external_values)
376*4bdc9457SAndroid Build Coastguard Worker {
377*4bdc9457SAndroid Build Coastguard Worker   // Validate inputs without changing internal state.
378*4bdc9457SAndroid Build Coastguard Worker   // This ensures that runtime stays in consistent state in case validation fails midway.
379*4bdc9457SAndroid Build Coastguard Worker   for (size_t i = 0; i < num_external_values; i++) {
380*4bdc9457SAndroid Build Coastguard Worker     const struct xnn_external_value* external_value = &external_values[i];
381*4bdc9457SAndroid Build Coastguard Worker     const uint32_t value_id = external_value->id;
382*4bdc9457SAndroid Build Coastguard Worker     if (value_id >= runtime->num_blobs) {
383*4bdc9457SAndroid Build Coastguard Worker       xnn_log_error("failed to setup runtime: out-of-bounds ID %" PRIu32 " in external value #%zu",
384*4bdc9457SAndroid Build Coastguard Worker         value_id, i);
385*4bdc9457SAndroid Build Coastguard Worker       return xnn_status_invalid_parameter;
386*4bdc9457SAndroid Build Coastguard Worker     }
387*4bdc9457SAndroid Build Coastguard Worker 
388*4bdc9457SAndroid Build Coastguard Worker     const struct xnn_blob* blob = &runtime->blobs[value_id];
389*4bdc9457SAndroid Build Coastguard Worker     if (blob->allocation_type != xnn_allocation_type_external) {
390*4bdc9457SAndroid Build Coastguard Worker       xnn_log_error("failed to setup runtime: Value %" PRIu32 " is not external", value_id);
391*4bdc9457SAndroid Build Coastguard Worker       return xnn_status_invalid_parameter;
392*4bdc9457SAndroid Build Coastguard Worker     }
393*4bdc9457SAndroid Build Coastguard Worker   }
394*4bdc9457SAndroid Build Coastguard Worker 
395*4bdc9457SAndroid Build Coastguard Worker   // Apply runtime state changes.
396*4bdc9457SAndroid Build Coastguard Worker   for (size_t i = 0; i < num_external_values; i++) {
397*4bdc9457SAndroid Build Coastguard Worker     const struct xnn_external_value* external_value = &external_values[i];
398*4bdc9457SAndroid Build Coastguard Worker     const uint32_t value_id = external_value->id;
399*4bdc9457SAndroid Build Coastguard Worker     struct xnn_blob* blob = &runtime->blobs[value_id];
400*4bdc9457SAndroid Build Coastguard Worker     blob->data = external_value->data;
401*4bdc9457SAndroid Build Coastguard Worker   }
402*4bdc9457SAndroid Build Coastguard Worker 
403*4bdc9457SAndroid Build Coastguard Worker   for (size_t i = 0; i < runtime->num_ops; i++) {
404*4bdc9457SAndroid Build Coastguard Worker     const struct xnn_operator_data* opdata = &runtime->opdata[i];
405*4bdc9457SAndroid Build Coastguard Worker     if (opdata->operator_objects[0] == NULL) {
406*4bdc9457SAndroid Build Coastguard Worker       // Operator was removed during optimization
407*4bdc9457SAndroid Build Coastguard Worker       continue;
408*4bdc9457SAndroid Build Coastguard Worker     }
409*4bdc9457SAndroid Build Coastguard Worker 
410*4bdc9457SAndroid Build Coastguard Worker     // Ensure that weights cache is finalized.
411*4bdc9457SAndroid Build Coastguard Worker     struct xnn_weights_cache* weights_cache = opdata->operator_objects[0]->weights_cache;
412*4bdc9457SAndroid Build Coastguard Worker     if (weights_cache != NULL && !xnn_weights_cache_is_finalized(weights_cache)) {
413*4bdc9457SAndroid Build Coastguard Worker       xnn_log_error("weights cache needs to be finalized before setup/infer");
414*4bdc9457SAndroid Build Coastguard Worker       return xnn_status_invalid_state;
415*4bdc9457SAndroid Build Coastguard Worker     }
416*4bdc9457SAndroid Build Coastguard Worker 
417*4bdc9457SAndroid Build Coastguard Worker     assert(opdata->setup != NULL);
418*4bdc9457SAndroid Build Coastguard Worker     const enum xnn_status status = opdata->setup(opdata, runtime->blobs, runtime->num_blobs, runtime->threadpool);
419*4bdc9457SAndroid Build Coastguard Worker     if (status != xnn_status_success) {
420*4bdc9457SAndroid Build Coastguard Worker       xnn_log_error("failed to setup runtime: error in operator #%zu", i);
421*4bdc9457SAndroid Build Coastguard Worker       return status;
422*4bdc9457SAndroid Build Coastguard Worker     }
423*4bdc9457SAndroid Build Coastguard Worker   }
424*4bdc9457SAndroid Build Coastguard Worker 
425*4bdc9457SAndroid Build Coastguard Worker   return xnn_status_success;
426*4bdc9457SAndroid Build Coastguard Worker }
427*4bdc9457SAndroid Build Coastguard Worker 
xnn_read_timer()428*4bdc9457SAndroid Build Coastguard Worker static xnn_timestamp xnn_read_timer() {
429*4bdc9457SAndroid Build Coastguard Worker   xnn_timestamp timestamp;
430*4bdc9457SAndroid Build Coastguard Worker #ifdef __MACH__
431*4bdc9457SAndroid Build Coastguard Worker   timestamp = clock_gettime_nsec_np(CLOCK_UPTIME_RAW);
432*4bdc9457SAndroid Build Coastguard Worker   if (timestamp == 0) {
433*4bdc9457SAndroid Build Coastguard Worker     xnn_log_warning("clock_gettime failed: error code %d", errno);
434*4bdc9457SAndroid Build Coastguard Worker   }
435*4bdc9457SAndroid Build Coastguard Worker #elif __EMSCRIPTEN__
436*4bdc9457SAndroid Build Coastguard Worker   timestamp = emscripten_get_now();
437*4bdc9457SAndroid Build Coastguard Worker #elif XNN_PLATFORM_WINDOWS
438*4bdc9457SAndroid Build Coastguard Worker   BOOL res = QueryPerformanceCounter(&timestamp);
439*4bdc9457SAndroid Build Coastguard Worker   if (!res) {
440*4bdc9457SAndroid Build Coastguard Worker     xnn_log_error("QueryPerformanceCounter failed: error code %u", GetLastError());
441*4bdc9457SAndroid Build Coastguard Worker     memset(&timestamp, 0, sizeof(timestamp));
442*4bdc9457SAndroid Build Coastguard Worker   }
443*4bdc9457SAndroid Build Coastguard Worker #else
444*4bdc9457SAndroid Build Coastguard Worker   int res = clock_gettime(CLOCK_MONOTONIC, &timestamp);
445*4bdc9457SAndroid Build Coastguard Worker   if (res != 0) {
446*4bdc9457SAndroid Build Coastguard Worker     xnn_log_error("clock_gettime failed: error code %d", errno);
447*4bdc9457SAndroid Build Coastguard Worker     memset(&timestamp, 0, sizeof(timestamp));
448*4bdc9457SAndroid Build Coastguard Worker   }
449*4bdc9457SAndroid Build Coastguard Worker #endif
450*4bdc9457SAndroid Build Coastguard Worker   return timestamp;
451*4bdc9457SAndroid Build Coastguard Worker }
452*4bdc9457SAndroid Build Coastguard Worker 
xnn_get_elapsed_time(const xnn_timestamp * start,const xnn_timestamp * end)453*4bdc9457SAndroid Build Coastguard Worker static inline uint64_t xnn_get_elapsed_time(const xnn_timestamp* start, const xnn_timestamp* end) {
454*4bdc9457SAndroid Build Coastguard Worker #ifdef __MACH__
455*4bdc9457SAndroid Build Coastguard Worker   const uint64_t kMicrosInNanos = 1000;
456*4bdc9457SAndroid Build Coastguard Worker   return (*end - *start) / kMicrosInNanos;
457*4bdc9457SAndroid Build Coastguard Worker #elif __EMSCRIPTEN__
458*4bdc9457SAndroid Build Coastguard Worker   const double kMillisInMicros = 1.0e3;
459*4bdc9457SAndroid Build Coastguard Worker   return (uint64_t) ((*end - *start) * kMillisInMicros);
460*4bdc9457SAndroid Build Coastguard Worker #elif XNN_PLATFORM_WINDOWS
461*4bdc9457SAndroid Build Coastguard Worker   const uint64_t kMicrosInSec = 1000 * 1000;
462*4bdc9457SAndroid Build Coastguard Worker   LARGE_INTEGER frequency;
463*4bdc9457SAndroid Build Coastguard Worker   BOOL res = QueryPerformanceFrequency(&frequency);
464*4bdc9457SAndroid Build Coastguard Worker   if (!res) {
465*4bdc9457SAndroid Build Coastguard Worker     xnn_log_error("QueryPerformanceFrequency failed: error code %u", GetLastError());
466*4bdc9457SAndroid Build Coastguard Worker     return 0;
467*4bdc9457SAndroid Build Coastguard Worker   }
468*4bdc9457SAndroid Build Coastguard Worker   return ((end->QuadPart - start->QuadPart) * kMicrosInSec) / frequency.QuadPart;
469*4bdc9457SAndroid Build Coastguard Worker #else
470*4bdc9457SAndroid Build Coastguard Worker   const uint64_t kNanosInMicro = UINT64_C(1000);
471*4bdc9457SAndroid Build Coastguard Worker   const uint64_t kNanosInSec = UINT64_C(1000000000);
472*4bdc9457SAndroid Build Coastguard Worker   const uint64_t secs = (end->tv_sec - start->tv_sec) * kNanosInSec;
473*4bdc9457SAndroid Build Coastguard Worker   const uint64_t ns_secs = (end->tv_nsec - start->tv_nsec);
474*4bdc9457SAndroid Build Coastguard Worker   return (secs + ns_secs) / kNanosInMicro;
475*4bdc9457SAndroid Build Coastguard Worker #endif
476*4bdc9457SAndroid Build Coastguard Worker }
477*4bdc9457SAndroid Build Coastguard Worker 
xnn_get_runtime_profiling_info(xnn_runtime_t runtime,enum xnn_profile_info param_name,size_t param_value_size,void * param_value,size_t * param_value_size_ret)478*4bdc9457SAndroid Build Coastguard Worker enum xnn_status xnn_get_runtime_profiling_info(xnn_runtime_t runtime,
479*4bdc9457SAndroid Build Coastguard Worker                                                enum xnn_profile_info param_name,
480*4bdc9457SAndroid Build Coastguard Worker                                                size_t param_value_size,
481*4bdc9457SAndroid Build Coastguard Worker                                                void* param_value,
482*4bdc9457SAndroid Build Coastguard Worker                                                size_t* param_value_size_ret)
483*4bdc9457SAndroid Build Coastguard Worker {
484*4bdc9457SAndroid Build Coastguard Worker   if (!runtime->profiling) {
485*4bdc9457SAndroid Build Coastguard Worker     return xnn_status_invalid_state;
486*4bdc9457SAndroid Build Coastguard Worker   }
487*4bdc9457SAndroid Build Coastguard Worker   enum xnn_status status = xnn_status_success;
488*4bdc9457SAndroid Build Coastguard Worker   size_t required_size = 0;
489*4bdc9457SAndroid Build Coastguard Worker   const struct xnn_operator_data* opdata = runtime->opdata;
490*4bdc9457SAndroid Build Coastguard Worker   switch (param_name) {
491*4bdc9457SAndroid Build Coastguard Worker     case xnn_profile_info_num_operators:
492*4bdc9457SAndroid Build Coastguard Worker       required_size = sizeof(size_t);
493*4bdc9457SAndroid Build Coastguard Worker       if (param_value_size < required_size){
494*4bdc9457SAndroid Build Coastguard Worker         *param_value_size_ret = required_size;
495*4bdc9457SAndroid Build Coastguard Worker         status = xnn_status_out_of_memory;
496*4bdc9457SAndroid Build Coastguard Worker       } else {
497*4bdc9457SAndroid Build Coastguard Worker         size_t num_valid_ops = 0;
498*4bdc9457SAndroid Build Coastguard Worker         for (size_t i = 0; i < runtime->num_ops; ++i) {
499*4bdc9457SAndroid Build Coastguard Worker           if (opdata[i].operator_objects[0] != NULL) {
500*4bdc9457SAndroid Build Coastguard Worker             num_valid_ops += 1;
501*4bdc9457SAndroid Build Coastguard Worker           }
502*4bdc9457SAndroid Build Coastguard Worker         }
503*4bdc9457SAndroid Build Coastguard Worker         memcpy(param_value, &num_valid_ops, required_size);
504*4bdc9457SAndroid Build Coastguard Worker       }
505*4bdc9457SAndroid Build Coastguard Worker       break;
506*4bdc9457SAndroid Build Coastguard Worker     case xnn_profile_info_operator_name:
507*4bdc9457SAndroid Build Coastguard Worker       for (size_t i = 0; i < runtime->num_ops; ++i) {
508*4bdc9457SAndroid Build Coastguard Worker         if (opdata[i].operator_objects[0] != NULL) {
509*4bdc9457SAndroid Build Coastguard Worker           const char* op_name = xnn_operator_type_to_string(opdata[i].operator_objects[0]->type);
510*4bdc9457SAndroid Build Coastguard Worker           size_t op_name_len = strlen(op_name) + 1;
511*4bdc9457SAndroid Build Coastguard Worker           if (opdata[i].operator_objects[0]->ukernel.type != xnn_ukernel_type_default ) {
512*4bdc9457SAndroid Build Coastguard Worker             op_name_len += strlen(xnn_ukernel_type_to_string(opdata[i].operator_objects[0]->ukernel.type)) + 1;
513*4bdc9457SAndroid Build Coastguard Worker           }
514*4bdc9457SAndroid Build Coastguard Worker           required_size += op_name_len;
515*4bdc9457SAndroid Build Coastguard Worker         }
516*4bdc9457SAndroid Build Coastguard Worker       }
517*4bdc9457SAndroid Build Coastguard Worker       if (param_value_size < required_size) {
518*4bdc9457SAndroid Build Coastguard Worker         *param_value_size_ret = required_size;
519*4bdc9457SAndroid Build Coastguard Worker         status = xnn_status_out_of_memory;
520*4bdc9457SAndroid Build Coastguard Worker       } else {
521*4bdc9457SAndroid Build Coastguard Worker         char* name_out = (char*) param_value;
522*4bdc9457SAndroid Build Coastguard Worker         for (size_t i = 0; i < runtime->num_ops; ++i) {
523*4bdc9457SAndroid Build Coastguard Worker           if (opdata[i].operator_objects[0] != NULL) {
524*4bdc9457SAndroid Build Coastguard Worker             const char* op_name = xnn_operator_type_to_string(opdata[i].operator_objects[0]->type);
525*4bdc9457SAndroid Build Coastguard Worker             size_t op_name_len = strlen(op_name) + 1;
526*4bdc9457SAndroid Build Coastguard Worker             if (opdata[i].operator_objects[0]->ukernel.type != xnn_ukernel_type_default ) {
527*4bdc9457SAndroid Build Coastguard Worker               const char* ukernel_type = xnn_ukernel_type_to_string(opdata[i].operator_objects[0]->ukernel.type);
528*4bdc9457SAndroid Build Coastguard Worker               op_name_len += strlen(ukernel_type) + 1;
529*4bdc9457SAndroid Build Coastguard Worker               snprintf(name_out, op_name_len, "%s %s", op_name, ukernel_type);
530*4bdc9457SAndroid Build Coastguard Worker             } else {
531*4bdc9457SAndroid Build Coastguard Worker               snprintf(name_out, op_name_len, "%s", op_name);
532*4bdc9457SAndroid Build Coastguard Worker             }
533*4bdc9457SAndroid Build Coastguard Worker             name_out += op_name_len;
534*4bdc9457SAndroid Build Coastguard Worker           }
535*4bdc9457SAndroid Build Coastguard Worker         }
536*4bdc9457SAndroid Build Coastguard Worker       }
537*4bdc9457SAndroid Build Coastguard Worker       break;
538*4bdc9457SAndroid Build Coastguard Worker     case xnn_profile_info_operator_timing:
539*4bdc9457SAndroid Build Coastguard Worker     {
540*4bdc9457SAndroid Build Coastguard Worker       size_t num_valid_ops = 0;
541*4bdc9457SAndroid Build Coastguard Worker       for (size_t i = 0; i < runtime->num_ops; ++i) {
542*4bdc9457SAndroid Build Coastguard Worker         if (opdata[i].operator_objects[0] != NULL) {
543*4bdc9457SAndroid Build Coastguard Worker           num_valid_ops += 1;
544*4bdc9457SAndroid Build Coastguard Worker         }
545*4bdc9457SAndroid Build Coastguard Worker       }
546*4bdc9457SAndroid Build Coastguard Worker       required_size = num_valid_ops * sizeof(uint64_t);
547*4bdc9457SAndroid Build Coastguard Worker       if (param_value_size < required_size) {
548*4bdc9457SAndroid Build Coastguard Worker         *param_value_size_ret = required_size;
549*4bdc9457SAndroid Build Coastguard Worker         status = xnn_status_out_of_memory;
550*4bdc9457SAndroid Build Coastguard Worker       } else {
551*4bdc9457SAndroid Build Coastguard Worker         xnn_timestamp previous_ts = runtime->start_ts;
552*4bdc9457SAndroid Build Coastguard Worker         uint64_t* data = (uint64_t*) param_value;
553*4bdc9457SAndroid Build Coastguard Worker         for (size_t i = 0; i < runtime->num_ops; ++i) {
554*4bdc9457SAndroid Build Coastguard Worker           if (opdata[i].operator_objects[0] != NULL) {
555*4bdc9457SAndroid Build Coastguard Worker             uint64_t op_time = 0;
556*4bdc9457SAndroid Build Coastguard Worker             for (size_t j = 0; j < XNN_MAX_OPERATOR_OBJECTS; j++) {
557*4bdc9457SAndroid Build Coastguard Worker               if (opdata[i].operator_objects[j] != NULL) {
558*4bdc9457SAndroid Build Coastguard Worker                 op_time += xnn_get_elapsed_time(&previous_ts, &opdata[i].end_ts[j]);
559*4bdc9457SAndroid Build Coastguard Worker                 previous_ts = opdata[i].end_ts[j];
560*4bdc9457SAndroid Build Coastguard Worker               }
561*4bdc9457SAndroid Build Coastguard Worker             }
562*4bdc9457SAndroid Build Coastguard Worker             *data++ = op_time;
563*4bdc9457SAndroid Build Coastguard Worker           }
564*4bdc9457SAndroid Build Coastguard Worker         }
565*4bdc9457SAndroid Build Coastguard Worker       }
566*4bdc9457SAndroid Build Coastguard Worker       break;
567*4bdc9457SAndroid Build Coastguard Worker     }
568*4bdc9457SAndroid Build Coastguard Worker     default:
569*4bdc9457SAndroid Build Coastguard Worker       status = xnn_status_invalid_parameter;
570*4bdc9457SAndroid Build Coastguard Worker   }
571*4bdc9457SAndroid Build Coastguard Worker   return status;
572*4bdc9457SAndroid Build Coastguard Worker }
573*4bdc9457SAndroid Build Coastguard Worker 
xnn_invoke_runtime(xnn_runtime_t runtime)574*4bdc9457SAndroid Build Coastguard Worker enum xnn_status xnn_invoke_runtime(
575*4bdc9457SAndroid Build Coastguard Worker   xnn_runtime_t runtime)
576*4bdc9457SAndroid Build Coastguard Worker {
577*4bdc9457SAndroid Build Coastguard Worker   if (runtime->profiling) {
578*4bdc9457SAndroid Build Coastguard Worker     runtime->start_ts = xnn_read_timer();
579*4bdc9457SAndroid Build Coastguard Worker   }
580*4bdc9457SAndroid Build Coastguard Worker   for (size_t i = 0; i < runtime->num_ops; i++) {
581*4bdc9457SAndroid Build Coastguard Worker     for (size_t j = 0; j < XNN_MAX_OPERATOR_OBJECTS; j++) {
582*4bdc9457SAndroid Build Coastguard Worker       if (runtime->opdata[i].operator_objects[j] == NULL) {
583*4bdc9457SAndroid Build Coastguard Worker         // Operator was removed after fusion
584*4bdc9457SAndroid Build Coastguard Worker         continue;
585*4bdc9457SAndroid Build Coastguard Worker       }
586*4bdc9457SAndroid Build Coastguard Worker 
587*4bdc9457SAndroid Build Coastguard Worker       const enum xnn_status status = xnn_run_operator(runtime->opdata[i].operator_objects[j], runtime->threadpool);
588*4bdc9457SAndroid Build Coastguard Worker       if (status != xnn_status_success) {
589*4bdc9457SAndroid Build Coastguard Worker         return status;
590*4bdc9457SAndroid Build Coastguard Worker       }
591*4bdc9457SAndroid Build Coastguard Worker       if (runtime->profiling) {
592*4bdc9457SAndroid Build Coastguard Worker         runtime->opdata[i].end_ts[j] = xnn_read_timer();
593*4bdc9457SAndroid Build Coastguard Worker       }
594*4bdc9457SAndroid Build Coastguard Worker     }
595*4bdc9457SAndroid Build Coastguard Worker   }
596*4bdc9457SAndroid Build Coastguard Worker   return xnn_status_success;
597*4bdc9457SAndroid Build Coastguard Worker }
598*4bdc9457SAndroid Build Coastguard Worker 
xnn_delete_runtime(xnn_runtime_t runtime)599*4bdc9457SAndroid Build Coastguard Worker enum xnn_status xnn_delete_runtime(
600*4bdc9457SAndroid Build Coastguard Worker   xnn_runtime_t runtime)
601*4bdc9457SAndroid Build Coastguard Worker {
602*4bdc9457SAndroid Build Coastguard Worker   if (runtime != NULL) {
603*4bdc9457SAndroid Build Coastguard Worker     if (runtime->opdata != NULL) {
604*4bdc9457SAndroid Build Coastguard Worker       for (size_t i = 0; i < runtime->num_ops; i++) {
605*4bdc9457SAndroid Build Coastguard Worker         for (size_t j = 0; j < XNN_MAX_OPERATOR_OBJECTS; j++) {
606*4bdc9457SAndroid Build Coastguard Worker           xnn_delete_operator(runtime->opdata[i].operator_objects[j]);
607*4bdc9457SAndroid Build Coastguard Worker         }
608*4bdc9457SAndroid Build Coastguard Worker       }
609*4bdc9457SAndroid Build Coastguard Worker       xnn_release_memory(runtime->opdata);
610*4bdc9457SAndroid Build Coastguard Worker 
611*4bdc9457SAndroid Build Coastguard Worker       xnn_release_memory(runtime->blobs);
612*4bdc9457SAndroid Build Coastguard Worker       if (runtime->workspace != NULL) {
613*4bdc9457SAndroid Build Coastguard Worker         // Remove this runtime from the list of users of the workspace.
614*4bdc9457SAndroid Build Coastguard Worker         assert(runtime->workspace->first_user != NULL);
615*4bdc9457SAndroid Build Coastguard Worker         if (runtime->workspace->first_user == runtime) {
616*4bdc9457SAndroid Build Coastguard Worker           runtime->workspace->first_user = runtime->next_workspace_user;
617*4bdc9457SAndroid Build Coastguard Worker         } else {
618*4bdc9457SAndroid Build Coastguard Worker           xnn_runtime_t prev = runtime->workspace->first_user;
619*4bdc9457SAndroid Build Coastguard Worker           xnn_runtime_t curr = prev->next_workspace_user;
620*4bdc9457SAndroid Build Coastguard Worker           while (curr != runtime) {
621*4bdc9457SAndroid Build Coastguard Worker             prev = curr;
622*4bdc9457SAndroid Build Coastguard Worker             curr = curr->next_workspace_user;
623*4bdc9457SAndroid Build Coastguard Worker           }
624*4bdc9457SAndroid Build Coastguard Worker           assert(curr == runtime);
625*4bdc9457SAndroid Build Coastguard Worker           prev->next_workspace_user = curr->next_workspace_user;
626*4bdc9457SAndroid Build Coastguard Worker         }
627*4bdc9457SAndroid Build Coastguard Worker         xnn_release_workspace(runtime->workspace);
628*4bdc9457SAndroid Build Coastguard Worker       }
629*4bdc9457SAndroid Build Coastguard Worker     }
630*4bdc9457SAndroid Build Coastguard Worker #if XNN_PLATFORM_JIT && XNN_ENABLE_JIT
631*4bdc9457SAndroid Build Coastguard Worker     xnn_release_code_cache(&runtime->code_cache);
632*4bdc9457SAndroid Build Coastguard Worker #endif
633*4bdc9457SAndroid Build Coastguard Worker     xnn_release_memory(runtime);
634*4bdc9457SAndroid Build Coastguard Worker   }
635*4bdc9457SAndroid Build Coastguard Worker   return xnn_status_success;
636*4bdc9457SAndroid Build Coastguard Worker }
637