• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Copyright 2020 The TensorFlow Authors. All Rights Reserved.
2 
3 Licensed under the Apache License, Version 2.0 (the "License");
4 you may not use this file except in compliance with the License.
5 You may obtain a copy of the License at
6 
7     http://www.apache.org/licenses/LICENSE-2.0
8 
9 Unless required by applicable law or agreed to in writing, software
10 distributed under the License is distributed on an "AS IS" BASIS,
11 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 See the License for the specific language governing permissions and
13 limitations under the License.
14 ==============================================================================*/
15 #include "tensorflow/lite/delegates/external/external_delegate.h"
16 
17 #include <string>
18 #include <vector>
19 
20 #include "tensorflow/lite/minimal_logging.h"
21 #include "tensorflow/lite/shared_library.h"
22 
23 namespace tflite {
24 namespace {
25 
26 // External delegate library construct
27 struct ExternalLib {
28   using CreateDelegatePtr = std::add_pointer<TfLiteDelegate*(
29       const char**, const char**, size_t,
30       void (*report_error)(const char*))>::type;
31   using DestroyDelegatePtr = std::add_pointer<void(TfLiteDelegate*)>::type;
32 
33   // Open a given delegate library and load the create/destroy symbols
loadtflite::__anonbe5b70390111::ExternalLib34   bool load(const std::string library) {
35     void* handle = SharedLibrary::LoadLibrary(library.c_str());
36     if (handle == nullptr) {
37       TFLITE_LOG(TFLITE_LOG_INFO, "Unable to load external delegate from : %s",
38                  library.c_str());
39     } else {
40       create =
41           reinterpret_cast<decltype(create)>(SharedLibrary::GetLibrarySymbol(
42               handle, "tflite_plugin_create_delegate"));
43       destroy =
44           reinterpret_cast<decltype(destroy)>(SharedLibrary::GetLibrarySymbol(
45               handle, "tflite_plugin_destroy_delegate"));
46       return create && destroy;
47     }
48     return false;
49   }
50 
51   CreateDelegatePtr create{nullptr};
52   DestroyDelegatePtr destroy{nullptr};
53 };
54 
55 // An ExternalDelegateWrapper is responsibile to manage a TFLite delegate
56 // initialized from a shared library. It creates a delegate from the given
57 // option and storages it to external_delegate_ member variable. On the
58 // destruction, it conducts necessary clean up process.
59 class ExternalDelegateWrapper {
60  public:
61   explicit ExternalDelegateWrapper(
62       const TfLiteExternalDelegateOptions* options);
63   ~ExternalDelegateWrapper();
64 
65   // Return a TfLiteDelegate which is created from
66   // tflite_plugin_create_delegate() of an external delegate logic.
tflite_external_delegate()67   TfLiteDelegate* tflite_external_delegate() { return external_delegate_; }
68 
69   // Return a TfLiteDelegate which is convertibile to this class.
tflite_wrapper_delegate()70   TfLiteDelegate* tflite_wrapper_delegate() { return &wrapper_delegate_; }
71 
72  private:
73   ExternalLib external_lib_;
74 
75   // external delegate instance owned by external delegate logic.
76   // It's created by "tflite_plugin_destroy_delegate()" function in the external
77   // delegate logic And it should be released by
78   // "tflite_plugin_destroy_delegate()" function.
79   TfLiteDelegate* external_delegate_;
80 
81   // TfLiteDelegate representation of this ExternalDelegateWrapper object.
82   TfLiteDelegate wrapper_delegate_;
83 };
84 
85 // Converts the given TfLiteDelegate to an ExternalDelegateWrapper instance.
GetExternalDelegateWrapper(TfLiteDelegate * delegate)86 inline ExternalDelegateWrapper* GetExternalDelegateWrapper(
87     TfLiteDelegate* delegate) {
88   return reinterpret_cast<ExternalDelegateWrapper*>(delegate->data_);
89 }
90 
91 // Relay Prepare() call to the associated external TfLiteDelegate object.
DelegatePrepare(TfLiteContext * context,TfLiteDelegate * delegate)92 TfLiteStatus DelegatePrepare(TfLiteContext* context, TfLiteDelegate* delegate) {
93   auto external_delegate_wrapper = GetExternalDelegateWrapper(delegate);
94   TfLiteDelegate* external_delegate =
95       external_delegate_wrapper->tflite_external_delegate();
96   return external_delegate->Prepare(context, external_delegate);
97 }
98 
99 // Relay CopyFromBufferHandle() call to the associated external TfLiteDelegate
100 // object.
DelegateCopyFromBufferHandle(TfLiteContext * context,struct TfLiteDelegate * delegate,TfLiteBufferHandle buffer_handle,TfLiteTensor * tensor)101 TfLiteStatus DelegateCopyFromBufferHandle(TfLiteContext* context,
102                                           struct TfLiteDelegate* delegate,
103                                           TfLiteBufferHandle buffer_handle,
104                                           TfLiteTensor* tensor) {
105   auto external_delegate_wrapper = GetExternalDelegateWrapper(delegate);
106   TfLiteDelegate* external_delegate =
107       external_delegate_wrapper->tflite_external_delegate();
108   return external_delegate->CopyFromBufferHandle(context, delegate,
109                                                  buffer_handle, tensor);
110 }
111 
112 // Relay CopyToBufferHandle() call to the associated external TfLiteDelegate
113 // object.
DelegateCopyToBufferHandle(TfLiteContext * context,struct TfLiteDelegate * delegate,TfLiteBufferHandle buffer_handle,TfLiteTensor * tensor)114 TfLiteStatus DelegateCopyToBufferHandle(TfLiteContext* context,
115                                         struct TfLiteDelegate* delegate,
116                                         TfLiteBufferHandle buffer_handle,
117                                         TfLiteTensor* tensor) {
118   auto external_delegate_wrapper = GetExternalDelegateWrapper(delegate);
119   TfLiteDelegate* external_delegate =
120       external_delegate_wrapper->tflite_external_delegate();
121   return external_delegate->CopyToBufferHandle(context, delegate, buffer_handle,
122                                                tensor);
123 }
124 
125 // Relay FreeBufferHandle() call to the associated external TfLiteDelegate
126 // object.
DelegateFreeBufferHandle(TfLiteContext * context,struct TfLiteDelegate * delegate,TfLiteBufferHandle * handle)127 void DelegateFreeBufferHandle(TfLiteContext* context,
128                               struct TfLiteDelegate* delegate,
129                               TfLiteBufferHandle* handle) {
130   auto external_delegate_wrapper = GetExternalDelegateWrapper(delegate);
131   TfLiteDelegate* external_delegate =
132       external_delegate_wrapper->tflite_external_delegate();
133   return external_delegate->FreeBufferHandle(context, delegate, handle);
134 }
135 
ExternalDelegateWrapper(const TfLiteExternalDelegateOptions * options)136 ExternalDelegateWrapper::ExternalDelegateWrapper(
137     const TfLiteExternalDelegateOptions* options) {
138   external_delegate_ = nullptr;
139   if (external_lib_.load(options->lib_path)) {
140     std::vector<const char*> ckeys, cvalues;
141     for (int i = 0; i < options->count; i++) {
142       ckeys.push_back(options->keys[i]);
143       cvalues.push_back(options->values[i]);
144     }
145 
146     external_delegate_ = external_lib_.create(ckeys.data(), cvalues.data(),
147                                               ckeys.size(), nullptr);
148     if (external_delegate_) {
149       wrapper_delegate_ = {
150           .data_ = reinterpret_cast<void*>(this),
151           .Prepare = DelegatePrepare,
152           .CopyFromBufferHandle = nullptr,
153           .CopyToBufferHandle = nullptr,
154           .FreeBufferHandle = nullptr,
155           .flags = external_delegate_->flags,
156       };
157       if (external_delegate_->CopyFromBufferHandle) {
158         wrapper_delegate_.CopyFromBufferHandle = DelegateCopyFromBufferHandle;
159       }
160       if (external_delegate_->CopyToBufferHandle) {
161         wrapper_delegate_.CopyToBufferHandle = DelegateCopyToBufferHandle;
162       }
163       if (external_delegate_->FreeBufferHandle) {
164         wrapper_delegate_.FreeBufferHandle = DelegateFreeBufferHandle;
165       }
166     }
167   }
168 }
169 
~ExternalDelegateWrapper()170 ExternalDelegateWrapper::~ExternalDelegateWrapper() {
171   if (external_delegate_ != nullptr) {
172     external_lib_.destroy(external_delegate_);
173   }
174 }
175 
176 }  // namespace
177 }  // namespace tflite
178 
179 // TfLiteExternalDelegateOptionsInsert adds key/value to the given
180 // TfLiteExternalDelegateOptions instance.
TfLiteExternalDelegateOptionsInsert(TfLiteExternalDelegateOptions * options,const char * key,const char * value)181 TfLiteStatus TfLiteExternalDelegateOptionsInsert(
182     TfLiteExternalDelegateOptions* options, const char* key,
183     const char* value) {
184   if (options->count >= kMaxOptions) {
185     return kTfLiteError;
186   }
187   options->keys[options->count] = key;
188   options->values[options->count] = value;
189   options->count++;
190   return kTfLiteOk;
191 }
192 
TfLiteExternalDelegateOptionsDefault(const char * lib_path)193 TfLiteExternalDelegateOptions TfLiteExternalDelegateOptionsDefault(
194     const char* lib_path) {
195   // As 'keys' and 'values' don't need to be set here, using designated
196   // initializers may cause a compiling error as "non-trivial designated
197   // initializers not supported" by some compiler.
198   TfLiteExternalDelegateOptions options;
199   options.lib_path = lib_path;
200   options.count = 0;
201   options.insert = TfLiteExternalDelegateOptionsInsert;
202   return options;
203 }
204 
TfLiteExternalDelegateCreate(const TfLiteExternalDelegateOptions * options)205 TfLiteDelegate* TfLiteExternalDelegateCreate(
206     const TfLiteExternalDelegateOptions* options) {
207   auto* external_delegate_wrapper =
208       new tflite::ExternalDelegateWrapper(options);
209   if (external_delegate_wrapper) {
210     return external_delegate_wrapper->tflite_wrapper_delegate();
211   }
212   return nullptr;
213 }
214 
TfLiteExternalDelegateDelete(TfLiteDelegate * delegate)215 void TfLiteExternalDelegateDelete(TfLiteDelegate* delegate) {
216   delete tflite::GetExternalDelegateWrapper(delegate);
217 }
218