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