xref: /aosp_15_r20/external/executorch/runtime/executor/program.h (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 #pragma once
10 
11 #include <cinttypes>
12 #include <cstdint>
13 
14 #include <executorch/runtime/core/data_loader.h>
15 #include <executorch/runtime/core/error.h>
16 #include <executorch/runtime/core/event_tracer.h>
17 #include <executorch/runtime/core/freeable_buffer.h>
18 #include <executorch/runtime/core/result.h>
19 #include <executorch/runtime/executor/memory_manager.h>
20 #include <executorch/runtime/executor/method.h>
21 #include <executorch/runtime/executor/method_meta.h>
22 #include <executorch/runtime/platform/compiler.h>
23 
24 // Forward declare flatbuffer types. This is a public header and must not
25 // include the generated flatbuffer header.
26 namespace executorch_flatbuffer {
27 struct Program;
28 } // namespace executorch_flatbuffer
29 
30 namespace executorch {
31 namespace runtime {
32 
33 namespace testing {
34 // Provides test access to private Program methods.
35 class ProgramTestFriend;
36 } // namespace testing
37 
38 namespace deserialization {
39 // Provides Tensor deserializaiton access to private Program methods.
40 class TensorParser;
41 } // namespace deserialization
42 
43 /**
44  * A deserialized ExecuTorch program binary.
45  */
46 class Program final {
47  public:
48   /**
49    * Types of validation that the Program can do before parsing the data.
50    */
51   enum class Verification : uint8_t {
52     /**
53      * Do minimal verification of the data, ensuring that the header appears
54      * correct.
55      *
56      * Has minimal runtime overhead.
57      */
58     Minimal,
59     /**
60      * Do full verification of the data, ensuring that internal pointers are
61      * self-consistent and that the data has not been truncated or obviously
62      * corrupted. May not catch all types of corruption, but should guard
63      * against illegal memory operations during parsing.
64      *
65      * Will have higher runtime overhead, scaling with the complexity of the
66      * proram data.
67      */
68     InternalConsistency,
69   };
70 
71   /**
72    * Loads a Program from the provided loader. The Program will hold a pointer
73    * to the loader, which must outlive the returned Program instance.
74    *
75    * @param[in] loader The source to load program data from. The Program will
76    *     hold a pointer to this loader, which must outlive the returned Program
77    *     instance.
78    * @param[in] verification The type of verification to do before returning
79    *     success.
80    */
81   ET_NODISCARD static Result<Program> load(
82       DataLoader* loader,
83       Verification verification = Verification::Minimal);
84 
85   /// DEPRECATED: Use the lowercase `load()` instead.
86   ET_DEPRECATED ET_NODISCARD static Result<Program> Load(
87       DataLoader* loader,
88       Verification verification = Verification::Minimal) {
89     return load(loader, verification);
90   }
91 
92   // Movable, to be compatible with Result.
93   Program(Program&&) noexcept = default;
94   ~Program() = default;
95 
96   /**
97    * Get the constant buffer inside Program with index buffer_idx.
98    * @param[in] buffer_idx the index of the buffer in the constant_buffer.
99    * @param[in] nbytes the number of bytes to read from the buffer.
100    * @return The buffer with corresponding index.
101    */
102   Result<const void*> get_constant_buffer_data(size_t buffer_idx, size_t nbytes)
103       const;
104 
105   /**
106    * Returns the number of methods in the program.
107    */
108   size_t num_methods() const;
109 
110   /**
111    * Returns the name of the method at particular index.
112    *
113    * @param[in] method_index The index of the method name to retrieve. Must be
114    * less than the value returned by `num_methods()`.
115    *
116    * @returns The name of the requested method. The pointer is owned by the
117    * Program, and has the same lifetime as the Program.
118    */
119   Result<const char*> get_method_name(size_t method_index) const;
120 
121   /**
122    * Loads the named method and prepares it for execution.
123    *
124    * @param[in] method_name The name of the method to load.
125    * @param[in] memory_manager The allocators to use during initialization and
126    *     execution of the loaded method. If `memory_manager.temp_allocator()` is
127    *     null, the runtime will allocate temp memory using `et_pal_allocate()`.
128    * @param[in] event_tracer The event tracer to use for this method run.
129    *
130    * @returns The loaded method on success, or an error on failure.
131    */
132   Result<Method> load_method(
133       const char* method_name,
134       MemoryManager* memory_manager,
135       EventTracer* event_tracer = nullptr) const;
136 
137   /**
138    * Gathers metadata for the named method.
139    *
140    * @param[in] method_name The name of the method to get metadata for.
141    */
142   Result<MethodMeta> method_meta(const char* method_name) const;
143 
144   /**
145    * DEPRECATED: Get the pytree encoding string for the output. Deprecated as
146    * this functionality will eventually move out of the core program into a
147    * higher level structure, but that does not exist at this time.
148    * @param[in] method_name The name of the method to get the encoding for.
149    *
150    * @return The pytree encoding string for the output
151    */
152   ET_DEPRECATED Result<const char*> get_output_flattening_encoding(
153       const char* method_name = "forward") const;
154 
155   /**
156    * Describes the presence of an ExecuTorch program header.
157    */
158   enum HeaderStatus {
159     /**
160      * An ExecuTorch program header is present, and its version is compatible
161      * with this version of the runtime.
162      */
163     CompatibleVersion,
164 
165     /**
166      * An ExecuTorch program header is present, but its version is not
167      * compatible with this version of the runtime.
168      */
169     IncompatibleVersion,
170 
171     /**
172      * An ExecuTorch program header is not present.
173      */
174     NotPresent,
175 
176     /**
177      * The data provided was too short to find the program header.
178      */
179     ShortData,
180   };
181 
182   /**
183    * The minimum number of bytes necessary for calls to `check_header`.
184    */
185   static constexpr size_t kMinHeadBytes = 64;
186 
187   /**
188    * Looks for an ExecuTorch program header in the provided data.
189    *
190    * @param[in] data The data from the beginning of a file that might contain
191    *     an ExecuTorch program.
192    * @param[in] size The size of `data` in bytes. Must be >= `kMinHeadBytes`.
193    *
194    * @returns A value describing the presence of a header in the data.
195    */
196   static HeaderStatus check_header(const void* data, size_t size);
197 
198  private:
199   // Let some classes call these private methods.
200   friend class BackendDelegate;
201   friend class Executor;
202   friend class Method;
203   friend class deserialization::TensorParser;
204   friend class testing::ProgramTestFriend;
205 
get_internal_program()206   const executorch_flatbuffer::Program* get_internal_program() const {
207     return internal_program_;
208   }
209 
210   // Used by Method to look up entries in the delegate data table.
211   Error get_backend_delegate_data(
212       size_t index,
213       const void** out_data,
214       size_t* out_size) const;
215 
216   /**
217    * Loads a segment by index.
218    *
219    * @param[in] segment_info Struct containing an index to load from the
220    * Program.segments list. The other fields of the struct, such as
221    * `segment_type` and `descriptor`, need to also be correct.
222    *
223    * @returns The data as a FreeableBuffer, if the index is valid.
224    * @retval Error::NotFound The program does not contain any segments or the
225    *     index is out of range.
226    * @returns Other errors depending on the implementation of
227    *     DataLoader: The Program.segment table is inconsistent, or the
228    *     data cannot be accessed.
229    */
230   ET_NODISCARD Result<FreeableBuffer> LoadSegment(
231       const DataLoader::SegmentInfo& segment_info) const;
232 
233   /**
234    * Loads a portion of a mutable segment into the provided buffer.
235    *
236    * @param[in] mutable_data_segments_index The index into the
237    * mutable_data_segments_array.
238    * @param[in] offset_index The index into the segment's offsets array.
239    * @param[in] size The number of bytes to load.
240    * @param[in] buffer The buffer to load data into. Must point to at least
241    * `size` bytes of memory.
242    *
243    * @returns An error code on if the load was successful.
244    * @retval Error::Ok The load was successful.
245    * @retval Error::NotFound The program does not contain any segments or the
246    *     indices are out of range.
247    * @returns Other errors depending on the implementation of
248    *     DataLoader: The Program.segment table is inconsistent, or the
249    *     data cannot be accessed.
250    */
251   ET_NODISCARD Error load_mutable_subsegment_into(
252       size_t mutable_data_segments_index,
253       size_t offset_index,
254       size_t size,
255       void* buffer) const;
256 
257  private:
Program(DataLoader * loader,size_t segment_base_offset,FreeableBuffer && program_data,const executorch_flatbuffer::Program * internal_program,FreeableBuffer && constant_segment_data)258   Program(
259       DataLoader* loader,
260       size_t segment_base_offset,
261       FreeableBuffer&& program_data,
262       const executorch_flatbuffer::Program* internal_program,
263       FreeableBuffer&& constant_segment_data)
264       : program_data_(std::move(program_data)),
265         // Don't need the loader if there are no segments.
266         loader_(segment_base_offset > 0 ? loader : nullptr),
267         internal_program_(internal_program),
268         segment_base_offset_(segment_base_offset),
269         constant_segment_data_(std::move(constant_segment_data)) {}
270 
271   // Not copyable or assignable.
272   Program(const Program& rhs) = delete;
273   Program& operator=(Program&& rhs) noexcept = delete;
274   Program& operator=(const Program& rhs) = delete;
275 
276   /// The serialized program data. Tensors will point directly into this buffer.
277   FreeableBuffer program_data_;
278 
279   /// Used to load segment data. Null if there are no segments.
280   DataLoader* loader_;
281 
282   /// The flatbuffer representation of the program. Must not be exposed to
283   /// users.
284   const executorch_flatbuffer::Program* internal_program_;
285 
286   /// The offset to the first segment, in bytes. If zero, no segments should
287   /// be present in internal_program_.
288   size_t segment_base_offset_;
289 
290   /// Constant segment data.
291   FreeableBuffer constant_segment_data_;
292 };
293 
294 } // namespace runtime
295 } // namespace executorch
296 
297 namespace torch {
298 namespace executor {
299 // TODO(T197294990): Remove these deprecated aliases once all users have moved
300 // to the new `::executorch` namespaces.
301 using ::executorch::runtime::Program;
302 } // namespace executor
303 } // namespace torch
304