• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 
21 #include "BurstBuilder.h"
22 #include "ExecutionBuilder.h"
23 #include "ExecutionBurstController.h"
24 #include "ExecutionPlan.h"
25 #include "Manager.h"
26 #include "ModelBuilder.h"
27 #include "Utils.h"
28 
29 namespace android {
30 namespace nn {
31 
CompilationBuilder(const ModelBuilder * model,const std::vector<std::shared_ptr<Device>> & devices,bool explicitDeviceList)32 CompilationBuilder::CompilationBuilder(const ModelBuilder* model,
33                                        const std::vector<std::shared_ptr<Device>>& devices,
34                                        bool explicitDeviceList)
35     : mModel(model),
36       mPartitioning(explicitDeviceList ? DeviceManager::kPartitioningWithoutFallback
37                                        : DeviceManager::get()->getPartitioning()),
38       mDevices(devices),
39       mExplicitDeviceList(explicitDeviceList) {
40     VLOG(COMPILATION) << "CompilationBuilder::CompilationBuilder";
41 }
42 
finish()43 int CompilationBuilder::finish() {
44     if (mFinished) {
45         LOG(ERROR) << "ANeuralNetworksCompilation_finish called more than once";
46         return ANEURALNETWORKS_BAD_STATE;
47     }
48     // TODO validate the rest
49 
50     mFinished = true;
51     if (mIsCacheInfoProvided) {
52         mPlan.setCaching(&mCacheDir, mToken);
53     }
54     if (mPartitioning) {
55         int n = mModel->partitionTheWork(mDevices, mPreference, &mPlan);
56         switch (n) {
57             case ANEURALNETWORKS_NO_ERROR:
58                 return n;
59             case ANEURALNETWORKS_UNEXPECTED_NULL:
60             case ANEURALNETWORKS_BAD_DATA:
61                 // The two error codes above should only be used for errors in the user's
62                 // request. In case of a user error, we won't try any fallback.
63                 // TODO: Document this in NeuralNetworks.h and in the HAL. Make sure
64                 // driver writers know which code they can return.
65                 return n;
66             default:
67                 // The error might be recoverable. Return the error only if falling back
68                 // is not allowed.
69                 if (!DeviceManager::partitioningAllowsFallback(mPartitioning)) {
70                     return n;
71                 }
72                 if (mModel->hasOEMOperation()) {
73                     LOG(ERROR) << "Cannot fall back to CPU because of an OEM operation";
74                     return n;
75                 }
76                 if (mModel->hasExtensionOperation()) {
77                     LOG(ERROR) << "Cannot fall back to CPU because of an extension operation";
78                     return n;
79                 }
80                 break;
81         }
82     }
83 
84     // Fallback to CPU
85     VLOG(COMPILATION) << "CompilationBuilder::finish with CPU fallback";
86     mPlan.reset();
87     mPlan.becomeSingleStep(DeviceManager::getCpuDevice(), mModel);
88     return mPlan.finish(mModel, mPreference);
89 }
90 
setPreference(int32_t preference)91 int CompilationBuilder::setPreference(int32_t preference) {
92     if (mFinished) {
93         LOG(ERROR) <<
94                 "ANeuralNetworksCompilation_setPreference can't modify after compilation finished";
95         return ANEURALNETWORKS_BAD_STATE;
96     }
97     if (preference >= kNumberOfPreferences) {
98         LOG(ERROR) << "ANeuralNetworksCompilation_setPreference invalid preference " << preference;
99         return ANEURALNETWORKS_BAD_DATA;
100     }
101 
102     mPreference = preference;
103     return ANEURALNETWORKS_NO_ERROR;
104 }
105 
setCaching(const std::string & cacheDir,const uint8_t * token)106 int CompilationBuilder::setCaching(const std::string& cacheDir, const uint8_t* token) {
107     if (mFinished) {
108         LOG(ERROR)
109                 << "ANeuralNetworksCompilation_setCaching can't modify after compilation finished";
110         return ANEURALNETWORKS_BAD_STATE;
111     }
112     mCacheDir = cacheDir;
113     // Make sure the cache dir can concat with the filename.
114     if (!mCacheDir.empty() && mCacheDir.back() != '/') {
115         mCacheDir.push_back('/');
116     }
117     std::copy(token, token + ANEURALNETWORKS_BYTE_SIZE_OF_CACHE_TOKEN, mToken);
118     mIsCacheInfoProvided = true;
119     return ANEURALNETWORKS_NO_ERROR;
120 }
121 
setPartitioning(uint32_t partitioning)122 int CompilationBuilder::setPartitioning(uint32_t partitioning) {
123     if (mFinished) {
124         LOG(ERROR) <<
125                 "ANeuralNetworksCompilation_setPartitioning can't modify after compilation finished";
126         return ANEURALNETWORKS_BAD_STATE;
127     }
128 
129     mPartitioning = partitioning;
130     return ANEURALNETWORKS_NO_ERROR;
131 }
132 
createExecution(ExecutionBuilder ** execution)133 int CompilationBuilder::createExecution(ExecutionBuilder **execution) {
134     if (!mFinished) {
135         LOG(ERROR) << "ANeuralNetworksExecution_create passed an unfinished compilation";
136         *execution = nullptr;
137         return ANEURALNETWORKS_BAD_STATE;
138     }
139     if (!mPlan.isValid()) {
140         LOG(ERROR) << "ANeuralNetworksExecution_create passed an invalid compilation";
141         *execution = nullptr;
142         return ANEURALNETWORKS_BAD_STATE;
143     }
144     *execution = new (std::nothrow) ExecutionBuilder(this);
145     return (*execution ? ANEURALNETWORKS_NO_ERROR : ANEURALNETWORKS_OUT_OF_MEMORY);
146 }
147 
createBurst(BurstBuilder ** burst)148 int CompilationBuilder::createBurst(BurstBuilder** burst) {
149     if (!mFinished) {
150         LOG(ERROR) << "ANeuralNetworksBurst_create passed an unfinished compilation";
151         *burst = nullptr;
152         return ANEURALNETWORKS_BAD_STATE;
153     }
154     if (!mPlan.isValid()) {
155         LOG(ERROR) << "ANeuralNetworksBurst_create passed an invalid compilation";
156         *burst = nullptr;
157         return ANEURALNETWORKS_BAD_STATE;
158     }
159     std::vector<std::shared_ptr<ExecutionBurstController>> burstControllers = mPlan.makeBursts();
160     *burst = new (std::nothrow) BurstBuilder(this, std::move(burstControllers));
161     return (*burst ? ANEURALNETWORKS_NO_ERROR : ANEURALNETWORKS_OUT_OF_MEMORY);
162 }
163 
164 }  // namespace nn
165 }  // namespace android
166