xref: /aosp_15_r20/external/executorch/devtools/etdump/emitter.cpp (revision 523fa7a60841cd1ecfb9cc4201f1ca8b03ed023a)
1 /*
2  * Copyright (c) Meta Platforms, Inc. and affiliates.
3  * All rights reserved.
4  *
5  * This source code is licensed under the BSD-style license found in the
6  * LICENSE file in the root directory of this source tree.
7  */
8 
9 #include <executorch/devtools/etdump/emitter.h>
10 
11 #include <cstdint>
12 #include <cstring>
13 
14 #include <executorch/devtools/etdump/etdump_flatcc.h>
15 #include <executorch/runtime/platform/assert.h>
16 
17 #include <flatcc/flatcc_builder.h>
18 
19 using executorch::etdump::internal::ETDumpStaticAllocator;
20 
21 namespace executorch {
22 namespace etdump {
23 namespace internal {
24 
25 namespace {
26 
allocator_fn(void * alloc_context,flatcc_iovec_t * b,size_t request,int zero_fill,int hint)27 int allocator_fn(
28     void* alloc_context,
29     flatcc_iovec_t* b,
30     size_t request,
31     int zero_fill,
32     int hint) {
33   void* p;
34   size_t n;
35 
36   ETDumpStaticAllocator* state =
37       reinterpret_cast<ETDumpStaticAllocator*>(alloc_context);
38 
39   // This allocator doesn't support freeing memory.
40   if (request == 0) {
41     if (b->iov_base) {
42       b->iov_base = nullptr;
43       b->iov_len = 0;
44     }
45     return 0;
46   }
47 
48   switch (hint) {
49     case flatcc_builder_alloc_ds:
50       n = 256;
51       break;
52     case flatcc_builder_alloc_ht:
53       /* Should be exact size, or space size is just wasted. */
54       n = request;
55       break;
56     case flatcc_builder_alloc_fs:
57       n = sizeof(__flatcc_builder_frame_t) * 8;
58       break;
59     case flatcc_builder_alloc_us:
60       n = 64;
61       break;
62     case flatcc_builder_alloc_vd:
63       n = 64;
64       break;
65     default:
66       /*
67        * We have many small structures - vs stack for tables with few
68        * elements, and few offset fields in patch log. No need to
69        * overallocate in case of busy small messages.
70        */
71       n = 32;
72       break;
73   }
74 
75   while (n < request) {
76     n *= 2;
77   }
78 
79   if (b->iov_base != nullptr) {
80     if (request > b->iov_len) {
81       // We don't support reallocating larger buffers.
82       if (((uintptr_t)b->iov_base + b->iov_len) ==
83           (uintptr_t)&state->data[state->allocated]) {
84         if ((state->allocated + n - b->iov_len) > state->data_size) {
85           return -1;
86         }
87         state->allocated += n - b->iov_len;
88       } else {
89         if ((state->allocated + n) > state->data_size) {
90           return -1;
91         }
92         memcpy((void*)&state->data[state->allocated], b->iov_base, b->iov_len);
93         b->iov_base = &state->data[state->allocated];
94         state->allocated += n;
95       }
96       if (zero_fill) {
97         memset((uint8_t*)b->iov_base + b->iov_len, 0, n - b->iov_len);
98       }
99       b->iov_len = n;
100     }
101 
102     // Ignore request to resize buffers down.
103     return 0;
104   }
105 
106   if ((state->allocated + n) > state->data_size) {
107     return -1;
108   }
109 
110   p = &state->data[state->allocated];
111   state->allocated += n;
112 
113   if (zero_fill) {
114     memset((void*)p, 0, n);
115   }
116 
117   b->iov_base = p;
118   b->iov_len = n;
119 
120   return 0;
121 }
122 
123 // This emitter implementation emits to a fixed size buffer and will fail if it
124 // runs out of room on either end.
emitter_fn(void * emit_context,const flatcc_iovec_t * iov,int iov_count,flatbuffers_soffset_t offset,size_t len)125 int emitter_fn(
126     void* emit_context,
127     const flatcc_iovec_t* iov,
128     int iov_count,
129     flatbuffers_soffset_t offset,
130     size_t len) {
131   ETDumpStaticAllocator* E =
132       reinterpret_cast<ETDumpStaticAllocator*>(emit_context);
133   uint8_t* p;
134 
135   if (offset < 0) {
136     if (len > E->front_left) {
137       return -1;
138     }
139     E->front_cursor -= len;
140     E->front_left -= len;
141     p = E->front_cursor;
142   } else {
143     ET_CHECK_MSG(
144         0, "Moving the back pointer is currently not supported in ETDump.");
145   }
146 
147   while (iov_count--) {
148     memcpy(p, iov->iov_base, iov->iov_len);
149     p += iov->iov_len;
150     ++iov;
151   }
152 
153   return 0;
154 }
155 
156 } // namespace
157 
etdump_flatcc_custom_init(flatcc_builder_t * builder,struct ETDumpStaticAllocator * alloc)158 int etdump_flatcc_custom_init(
159     flatcc_builder_t* builder,
160     struct ETDumpStaticAllocator* alloc) {
161   return flatcc_builder_custom_init(
162       builder, emitter_fn, alloc, allocator_fn, alloc);
163 }
164 
165 } // namespace internal
166 } // namespace etdump
167 } // namespace executorch
168