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
16 #include <string>
17 #include <vector>
18
19 #include "tensorflow/lite/delegates/external/external_delegate.h"
20 #include "tensorflow/lite/tools/delegates/delegate_provider.h"
21
22 namespace tflite {
23 namespace tools {
24
25 // Split a given string to a vector of string using a delimiter character
SplitString(const std::string & str,char delimiter)26 std::vector<std::string> SplitString(const std::string& str, char delimiter) {
27 std::vector<std::string> tokens;
28 std::string token;
29 std::istringstream ss(str);
30 while (std::getline(ss, token, delimiter)) {
31 tokens.push_back(token);
32 }
33 return tokens;
34 }
35
36 // External delegate provider used to dynamically load delegate libraries
37 // Note: Assumes the lifetime of the provider exceeds the usage scope of
38 // the generated delegates.
39 class ExternalDelegateProvider : public DelegateProvider {
40 public:
ExternalDelegateProvider()41 ExternalDelegateProvider() {
42 default_params_.AddParam("external_delegate_path",
43 ToolParam::Create<std::string>(""));
44 default_params_.AddParam("external_delegate_options",
45 ToolParam::Create<std::string>(""));
46 }
47
48 std::vector<Flag> CreateFlags(ToolParams* params) const final;
49
50 void LogParams(const ToolParams& params, bool verbose) const final;
51
52 TfLiteDelegatePtr CreateTfLiteDelegate(const ToolParams& params) const final;
53
GetName() const54 std::string GetName() const final { return "EXTERNAL"; }
55 };
56 REGISTER_DELEGATE_PROVIDER(ExternalDelegateProvider);
57
CreateFlags(ToolParams * params) const58 std::vector<Flag> ExternalDelegateProvider::CreateFlags(
59 ToolParams* params) const {
60 std::vector<Flag> flags = {
61 CreateFlag<std::string>("external_delegate_path", params,
62 "The library path for the underlying external."),
63 CreateFlag<std::string>(
64 "external_delegate_options", params,
65 "A list of comma-separated options to be passed to the external "
66 "delegate. Each option is a colon-separated key-value pair, e.g. "
67 "option_name:option_value.")};
68 return flags;
69 }
70
LogParams(const ToolParams & params,bool verbose) const71 void ExternalDelegateProvider::LogParams(const ToolParams& params,
72 bool verbose) const {
73 LOG_TOOL_PARAM(params, std::string, "external_delegate_path",
74 "External delegate path", verbose);
75 LOG_TOOL_PARAM(params, std::string, "external_delegate_options",
76 "External delegate options", verbose);
77 }
78
CreateTfLiteDelegate(const ToolParams & params) const79 TfLiteDelegatePtr ExternalDelegateProvider::CreateTfLiteDelegate(
80 const ToolParams& params) const {
81 TfLiteDelegatePtr delegate(nullptr, [](TfLiteDelegate*) {});
82 std::string lib_path = params.Get<std::string>("external_delegate_path");
83 if (!lib_path.empty()) {
84 auto delegate_options =
85 TfLiteExternalDelegateOptionsDefault(lib_path.c_str());
86
87 // Parse delegate options
88 const std::vector<std::string> options =
89 SplitString(params.Get<std::string>("external_delegate_options"), ';');
90 std::vector<std::string> keys, values;
91 // We reserve the memory here to avoid memory pointer change during
92 // insertion to vectors above.
93 keys.reserve(options.size());
94 values.reserve(options.size());
95 for (const auto& option : options) {
96 auto key_value = SplitString(option, ':');
97 if (key_value.size() == 2) {
98 // The inserted (key,value) pair has to outlive the
99 // TfLiteExternalDelegateCreate call, therefore, we use two vectors
100 // 'keys' and 'values' to achieve this.
101 // Also, we will insert the memory pointer of key and value to
102 // delegate_options later, we have to ensure the pointer won't change by
103 // reserving the memory earlier.
104 keys.emplace_back(key_value[0]);
105 values.emplace_back(key_value[1]);
106 delegate_options.insert(&delegate_options, keys.back().c_str(),
107 values.back().c_str());
108 }
109 }
110
111 auto external_delegate = TfLiteExternalDelegateCreate(&delegate_options);
112 return TfLiteDelegatePtr(external_delegate, [](TfLiteDelegate* delegate) {
113 TfLiteExternalDelegateDelete(delegate);
114 });
115 }
116 return delegate;
117 }
118
119 } // namespace tools
120 } // namespace tflite
121