blob: 8b2a26915bbc7ac4a5f0bf79cf21857b154c35af [file] [log] [blame]
David Gross83e24dc2017-09-10 14:31:58 -07001/*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define LOG_TAG "CompilationBuilder"
18
19#include "CompilationBuilder.h"
20
Michael Butlerc82044a2019-06-24 10:36:20 -070021#include <algorithm>
Michael Butler83e406e2019-12-16 18:32:45 -080022#include <limits>
Michael Butlerc82044a2019-06-24 10:36:20 -070023#include <memory>
24#include <string>
25#include <utility>
26#include <vector>
Michael Butler83e406e2019-12-16 18:32:45 -080027
Michael Butler89e99ba2019-01-24 02:36:37 -080028#include "BurstBuilder.h"
David Gross3ced3cf2017-09-13 10:45:21 -070029#include "ExecutionBuilder.h"
Michael Butler89e99ba2019-01-24 02:36:37 -080030#include "ExecutionBurstController.h"
David Gross0b9453e2017-09-22 17:16:51 -070031#include "ExecutionPlan.h"
David Gross1f438152017-09-28 09:18:51 -070032#include "Manager.h"
David Gross0b9453e2017-09-22 17:16:51 -070033#include "ModelBuilder.h"
34#include "Utils.h"
David Gross83e24dc2017-09-10 14:31:58 -070035
36namespace android {
37namespace nn {
38
Michael Butler83e406e2019-12-16 18:32:45 -080039using namespace hal;
40
Miao Wang8e4df912018-10-02 13:29:00 -070041CompilationBuilder::CompilationBuilder(const ModelBuilder* model,
David Gross07c3f752019-03-28 13:38:16 -070042 const std::vector<std::shared_ptr<Device>>& devices,
43 bool explicitDeviceList)
44 : mModel(model),
45 mPartitioning(explicitDeviceList ? DeviceManager::kPartitioningWithoutFallback
46 : DeviceManager::get()->getPartitioning()),
47 mDevices(devices),
48 mExplicitDeviceList(explicitDeviceList) {
Miao Wang820215d2017-10-04 19:45:45 -070049 VLOG(COMPILATION) << "CompilationBuilder::CompilationBuilder";
David Gross83e24dc2017-09-10 14:31:58 -070050}
51
David Gross65aa5562017-09-13 19:24:00 -070052int CompilationBuilder::finish() {
53 if (mFinished) {
54 LOG(ERROR) << "ANeuralNetworksCompilation_finish called more than once";
55 return ANEURALNETWORKS_BAD_STATE;
56 }
Jean-Luc Brouillete127e492017-09-27 23:59:20 -070057 // TODO validate the rest
David Gross65aa5562017-09-13 19:24:00 -070058
Michael Butlerf2091af2020-02-25 11:39:05 -080059 const auto deadline = makeDeadline(mTimeoutDuration);
Michael Butler83e406e2019-12-16 18:32:45 -080060
David Gross65aa5562017-09-13 19:24:00 -070061 mFinished = true;
Xusong Wangd01b6d62019-01-14 18:53:00 -080062 if (mIsCacheInfoProvided) {
63 mPlan.setCaching(&mCacheDir, mToken);
64 }
David Grossc2f1c112017-11-13 10:17:31 -080065 if (mPartitioning) {
Michael Butlerf2091af2020-02-25 11:39:05 -080066 int n = mModel->partitionTheWork(mDevices, mPreference, mPriority, deadline, &mPlan);
Jean-Luc Brouilletfc67d172017-10-12 23:30:10 -070067 switch (n) {
68 case ANEURALNETWORKS_NO_ERROR:
Xusong Wang8e0bbbd2018-10-25 18:49:54 -070069 return n;
Jean-Luc Brouilletfc67d172017-10-12 23:30:10 -070070 case ANEURALNETWORKS_UNEXPECTED_NULL:
71 case ANEURALNETWORKS_BAD_DATA:
72 // The two error codes above should only be used for errors in the user's
73 // request. In case of a user error, we won't try any fallback.
74 // TODO: Document this in NeuralNetworks.h and in the HAL. Make sure
75 // driver writers know which code they can return.
76 return n;
77 default:
78 // The error might be recoverable. Return the error only if falling back
79 // is not allowed.
80 if (!DeviceManager::partitioningAllowsFallback(mPartitioning)) {
81 return n;
82 }
David Grossdc52e6c2018-08-17 12:37:41 -070083 if (mModel->hasOEMOperation()) {
Slava Shklyaeve86a07b2019-01-23 16:09:51 +000084 LOG(ERROR) << "Cannot fall back to CPU because of an OEM operation";
85 return n;
86 }
87 if (mModel->hasExtensionOperation()) {
88 LOG(ERROR) << "Cannot fall back to CPU because of an extension operation";
David Grossdc52e6c2018-08-17 12:37:41 -070089 return n;
90 }
Jean-Luc Brouilletfc67d172017-10-12 23:30:10 -070091 break;
David Gross1f438152017-09-28 09:18:51 -070092 }
David Gross0b9453e2017-09-22 17:16:51 -070093 }
David Gross0b9453e2017-09-22 17:16:51 -070094
Xusong Wang8e0bbbd2018-10-25 18:49:54 -070095 // Fallback to CPU
96 VLOG(COMPILATION) << "CompilationBuilder::finish with CPU fallback";
97 mPlan.reset();
98 mPlan.becomeSingleStep(DeviceManager::getCpuDevice(), mModel);
Michael Butlerf2091af2020-02-25 11:39:05 -080099 return mPlan.finish(mPreference, mPriority, deadline);
David Gross65aa5562017-09-13 19:24:00 -0700100}
101
102int CompilationBuilder::setPreference(int32_t preference) {
103 if (mFinished) {
Michael Butler67e41a52019-07-22 18:59:46 -0700104 LOG(ERROR) << "ANeuralNetworksCompilation_setPreference can't modify after compilation "
105 "finished";
David Gross65aa5562017-09-13 19:24:00 -0700106 return ANEURALNETWORKS_BAD_STATE;
107 }
Jean-Luc Brouillete127e492017-09-27 23:59:20 -0700108 if (preference >= kNumberOfPreferences) {
109 LOG(ERROR) << "ANeuralNetworksCompilation_setPreference invalid preference " << preference;
110 return ANEURALNETWORKS_BAD_DATA;
111 }
112
David Gross65aa5562017-09-13 19:24:00 -0700113 mPreference = preference;
David Gross83e24dc2017-09-10 14:31:58 -0700114 return ANEURALNETWORKS_NO_ERROR;
115}
116
Xusong Wang7481a7a2019-01-14 16:31:15 -0800117int CompilationBuilder::setCaching(const std::string& cacheDir, const uint8_t* token) {
118 if (mFinished) {
119 LOG(ERROR)
120 << "ANeuralNetworksCompilation_setCaching can't modify after compilation finished";
121 return ANEURALNETWORKS_BAD_STATE;
122 }
123 mCacheDir = cacheDir;
124 // Make sure the cache dir can concat with the filename.
125 if (!mCacheDir.empty() && mCacheDir.back() != '/') {
126 mCacheDir.push_back('/');
127 }
Xusong Wangf6d73652019-01-23 21:57:14 -0800128 std::copy(token, token + ANEURALNETWORKS_BYTE_SIZE_OF_CACHE_TOKEN, mToken);
129 mIsCacheInfoProvided = true;
Xusong Wang7481a7a2019-01-14 16:31:15 -0800130 return ANEURALNETWORKS_NO_ERROR;
131}
132
Michael Butler83e406e2019-12-16 18:32:45 -0800133int CompilationBuilder::setPriority(int32_t priority) {
134 if (mFinished) {
135 LOG(ERROR) << "ANeuralNetworksCompilation_setPriority can't modify after compilation "
136 "finished";
137 return ANEURALNETWORKS_BAD_STATE;
138 }
139 if (priority != ANEURALNETWORKS_PRIORITY_LOW && priority != ANEURALNETWORKS_PRIORITY_MEDIUM &&
140 priority != ANEURALNETWORKS_PRIORITY_HIGH) {
141 LOG(ERROR) << "ANeuralNetworksCompilation_setPriority invalid priority " << priority;
142 return ANEURALNETWORKS_BAD_DATA;
143 }
144
145 mPriority = priority;
146 return ANEURALNETWORKS_NO_ERROR;
147}
148
149int CompilationBuilder::setTimeoutDuration(uint64_t duration) {
150 if (mFinished) {
151 LOG(ERROR) << "ANeuralNetworksCompilation_setTimeout can't modify after compilation "
152 "finished";
153 return ANEURALNETWORKS_BAD_STATE;
154 }
155 if (!mExplicitDeviceList || (mDevices.size() != 1)) {
156 LOG(ERROR) << "ANeuralNetworksCompilation_setTimeout called on an "
157 "ANeuralNetworksCompilation that was not created by "
158 "ANeuralNetworksCompilation_createForDevices with numDevices = 1";
159 return ANEURALNETWORKS_BAD_DATA;
160 }
Michael Butler5d1916f2020-02-10 15:45:28 -0800161 if (duration > 0) {
162 mTimeoutDuration = duration;
163 } else {
164 mTimeoutDuration.reset();
165 }
Michael Butler83e406e2019-12-16 18:32:45 -0800166 return ANEURALNETWORKS_NO_ERROR;
167}
168
David Grossc2f1c112017-11-13 10:17:31 -0800169int CompilationBuilder::setPartitioning(uint32_t partitioning) {
170 if (mFinished) {
Michael Butler67e41a52019-07-22 18:59:46 -0700171 LOG(ERROR) << "ANeuralNetworksCompilation_setPartitioning can't modify after compilation "
172 "finished";
David Grossc2f1c112017-11-13 10:17:31 -0800173 return ANEURALNETWORKS_BAD_STATE;
174 }
175
176 mPartitioning = partitioning;
177 return ANEURALNETWORKS_NO_ERROR;
178}
179
Michael Butler67e41a52019-07-22 18:59:46 -0700180int CompilationBuilder::createExecution(ExecutionBuilder** execution) {
David Gross65aa5562017-09-13 19:24:00 -0700181 if (!mFinished) {
182 LOG(ERROR) << "ANeuralNetworksExecution_create passed an unfinished compilation";
183 *execution = nullptr;
184 return ANEURALNETWORKS_BAD_STATE;
185 }
Xusong Wang8e0bbbd2018-10-25 18:49:54 -0700186 if (!mPlan.isValid()) {
187 LOG(ERROR) << "ANeuralNetworksExecution_create passed an invalid compilation";
188 *execution = nullptr;
189 return ANEURALNETWORKS_BAD_STATE;
190 }
Przemyslaw Szczepaniak03d7d982018-04-20 14:22:10 +0100191 *execution = new (std::nothrow) ExecutionBuilder(this);
David Gross3ced3cf2017-09-13 10:45:21 -0700192 return (*execution ? ANEURALNETWORKS_NO_ERROR : ANEURALNETWORKS_OUT_OF_MEMORY);
David Gross83e24dc2017-09-10 14:31:58 -0700193}
194
Michael Butler89e99ba2019-01-24 02:36:37 -0800195int CompilationBuilder::createBurst(BurstBuilder** burst) {
196 if (!mFinished) {
197 LOG(ERROR) << "ANeuralNetworksBurst_create passed an unfinished compilation";
198 *burst = nullptr;
199 return ANEURALNETWORKS_BAD_STATE;
200 }
201 if (!mPlan.isValid()) {
202 LOG(ERROR) << "ANeuralNetworksBurst_create passed an invalid compilation";
203 *burst = nullptr;
204 return ANEURALNETWORKS_BAD_STATE;
205 }
Michael Butlerc82044a2019-06-24 10:36:20 -0700206 std::vector<std::shared_ptr<ExecutionBurstController>> burstControllers =
207 mPlan.makeBursts(mPreference);
Michael Butler89e99ba2019-01-24 02:36:37 -0800208 *burst = new (std::nothrow) BurstBuilder(this, std::move(burstControllers));
209 return (*burst ? ANEURALNETWORKS_NO_ERROR : ANEURALNETWORKS_OUT_OF_MEMORY);
210}
211
Xusong Wangc4b4cca2019-11-27 11:44:03 -0800212int CompilationBuilder::forEachStepRoleOfInput(uint32_t index,
213 const StepRoleCallback& callback) const {
214 if (!mFinished) {
215 LOG(ERROR) << "ANeuralNetworksMemoryDesc_addInputRole passed an unfinished compilation";
216 return ANEURALNETWORKS_BAD_STATE;
217 }
218 if (!mPlan.isValid()) {
219 LOG(ERROR) << "ANeuralNetworksMemoryDesc_addInputRole passed an invalid compilation";
220 return ANEURALNETWORKS_BAD_STATE;
221 }
222 if (index >= mModel->inputCount()) {
223 LOG(ERROR) << "ANeuralNetworksMemoryDesc_addInputRole passed an invalid input index "
224 << index;
225 return ANEURALNETWORKS_BAD_DATA;
226 }
227 mPlan.forEachStepRoleOfInput(index, callback);
228 return ANEURALNETWORKS_NO_ERROR;
229}
230
231int CompilationBuilder::forEachStepRoleOfOutput(uint32_t index,
232 const StepRoleCallback& callback) const {
233 if (!mFinished) {
234 LOG(ERROR) << "ANeuralNetworksMemoryDesc_addOutputRole passed an unfinished compilation";
235 return ANEURALNETWORKS_BAD_STATE;
236 }
237 if (!mPlan.isValid()) {
238 LOG(ERROR) << "ANeuralNetworksMemoryDesc_addOutputRole passed an invalid compilation";
239 return ANEURALNETWORKS_BAD_STATE;
240 }
241 if (index >= mModel->outputCount()) {
242 LOG(ERROR) << "ANeuralNetworksMemoryDesc_addOutputRole passed an invalid output index "
243 << index;
244 return ANEURALNETWORKS_BAD_DATA;
245 }
246 mPlan.forEachStepRoleOfOutput(index, callback);
247 return ANEURALNETWORKS_NO_ERROR;
248}
249
David Gross83e24dc2017-09-10 14:31:58 -0700250} // namespace nn
251} // namespace android