xref: /aosp_15_r20/external/executorch/runtime/backend/interface.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 <cstring>
12 
13 #include <executorch/runtime/backend/backend_execution_context.h>
14 #include <executorch/runtime/backend/backend_init_context.h>
15 #include <executorch/runtime/core/array_ref.h>
16 #include <executorch/runtime/core/error.h>
17 #include <executorch/runtime/core/evalue.h>
18 #include <executorch/runtime/core/freeable_buffer.h>
19 #include <executorch/runtime/core/memory_allocator.h>
20 #include <executorch/runtime/core/result.h>
21 #include <executorch/runtime/platform/compiler.h>
22 
23 namespace executorch {
24 namespace runtime {
25 
26 struct SizedBuffer {
27   void* buffer;
28   size_t nbytes; // number of bytes of buffer
29 };
30 
31 struct CompileSpec {
32   const char* key; // spec key
33   SizedBuffer value; // spec value
34 };
35 
36 /**
37  * An opaque handle managed by a backend. Typically points to a backend-private
38  * class/struct.
39  */
40 using DelegateHandle = void;
41 
42 class BackendInterface {
43  public:
44   virtual ~BackendInterface() = 0;
45 
46   /**
47    * Returns true if the backend is available to process delegation calls.
48    */
49   ET_NODISCARD virtual bool is_available() const = 0;
50 
51   /**
52    * Responsible to further process (compile/transform/optimize) the compiled
53    * unit that was produced, ahead-of-time, as well as perform any backend
54    * initialization to ready it for execution. This method is called every time
55    * the ExecuTorch program is initialized. Consequently, this is the place to
56    * perform any backend initialization as well as transformations,
57    * optimizations, and even compilation that depend on the target device. As
58    * such, it is strongly encouraged to push as much processing as possible to
59    * the ahead-of-time processing.
60    *
61    * @param[in] processed An opaque (to ExecuTorch) backend-specific compiled
62    *     unit from the preprocessor. Can contain anything the backend needs to
63    *     execute the equivalent semantics of the passed-in Module and its
64    *     method. Often passed unmodified to `execute()` as a `DelegateHandle`,
65    *     unless it needs further processing at init time to be fully executable.
66    *     If the data is not needed after init(), calling processed->Free() can
67    *     reclaim its memory.
68    * @param[in] compile_specs The exact same compiler specification that
69    *     was used ahead-of-time to produce `processed`.
70    *
71    * @returns On success, an opaque handle representing the the method
72    *     implemented by the delegate. This handle is passed to `execute()` and
73    *     `destroy()`, and the memory it points to is owned by the backend.
74    *     Typically points to a backend-private class/struct.
75    * @returns On error, returns an error code other than Error::Ok. If the
76    *     compiled unit (the preprocessed result from ahead of time) is not
77    *     compatible with the current backend runtime, return the error code
78    *     Error::DelegateInvalidCompatibility. Other backend delegate
79    *     specific error codes can be found in error.h.
80    */
81   ET_NODISCARD virtual Result<DelegateHandle*> init(
82       BackendInitContext& context,
83       FreeableBuffer* processed,
84       ArrayRef<CompileSpec> compile_specs) const = 0;
85 
86   /**
87    * Responsible for executing the given method’s handle, as it was produced
88    * by compile.
89    *
90    * @param[in] handle An opaque handle returned by `init()`. Usually a backend
91    *     executable unit. This executable unit should be ready to execute the
92    *     delegate blobs.
93    * @param[in] args The method’s inputs and outputs.
94    * @retval Error::Ok if successful.
95    */
96   ET_NODISCARD virtual Error execute(
97       BackendExecutionContext& context,
98       DelegateHandle* handle,
99       EValue** args) const = 0;
100 
101   /**
102    * Responsible for destroying a handle, if it's required for some backend.
103    * It may be needed for some backends. For example, resources associated with
104    * this handle needs to be released. This method is called when the execution
105    * plan is destroyed (i.e., the program is out of its lifespan).
106    *
107    * @param[in] handle The handle to be destroyed. An opaque handle returned by
108    *     `init()`.
109    */
destroy(ET_UNUSED DelegateHandle * handle)110   virtual void destroy(ET_UNUSED DelegateHandle* handle) const {}
111 };
112 
113 /**
114  * Returns the corresponding object pointer for a given string name.
115  * The mapping is populated using register_backend method.
116  *
117  * @param[in] name Name of the user-defined backend delegate.
118  * @retval Pointer to the appropriate object that implements BackendInterface.
119  *         Nullptr if it can't find anything with the given name.
120  */
121 BackendInterface* get_backend_class(const char* name);
122 
123 /**
124  * A named instance of a backend.
125  */
126 struct Backend {
127   /// The name of the backend. Must match the string used in the PTE file.
128   const char* name;
129   /// The instance of the backend to use when loading and executing programs.
130   BackendInterface* backend;
131 };
132 
133 /**
134  * Registers the Backend object (i.e. string name and BackendInterface pair) so
135  * that it could be called via the name during the runtime.
136  *
137  * @param[in] backend Backend object
138  * @retval Error code representing whether registration was successful.
139  */
140 ET_NODISCARD Error register_backend(const Backend& backend);
141 
142 } // namespace runtime
143 } // namespace executorch
144 
145 namespace torch {
146 namespace executor {
147 // TODO(T197294990): Remove these deprecated aliases once all users have moved
148 // to the new `::executorch` namespaces.
149 using ::executorch::runtime::Backend;
150 using ::executorch::runtime::CompileSpec;
151 using ::executorch::runtime::DelegateHandle;
152 using ::executorch::runtime::get_backend_class;
153 using ::executorch::runtime::register_backend;
154 using ::executorch::runtime::SizedBuffer;
155 using PyTorchBackendInterface = ::executorch::runtime::BackendInterface;
156 } // namespace executor
157 } // namespace torch
158