1 /* 2 * Copyright (C) 2020 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 // Provides C++ classes to more easily use the Neural Networks API. 18 // TODO(b/117845862): this should be auto generated from NeuralNetworksWrapper.h. 19 20 #ifndef ANDROID_PACKAGES_MODULES_NEURALNETWORKS_SL_SUPPORT_LIBRARY_WRAPPER_H 21 #define ANDROID_PACKAGES_MODULES_NEURALNETWORKS_SL_SUPPORT_LIBRARY_WRAPPER_H 22 23 #include <android-base/unique_fd.h> 24 #include <android/hardware_buffer.h> 25 #include <math.h> 26 #include <unistd.h> 27 28 #include <algorithm> 29 #include <memory> 30 #include <optional> 31 #include <string> 32 #include <utility> 33 #include <vector> 34 35 #include "NeuralNetworksWrapper.h" 36 #include "SupportLibrary.h" 37 38 using namespace ::android::nn::wrapper; 39 40 namespace android { 41 namespace nn { 42 namespace sl_wrapper { 43 44 using ::android::nn::wrapper::Duration; 45 using ::android::nn::wrapper::OperandType; 46 using ::android::nn::wrapper::Result; 47 48 class Memory { 49 public: 50 // Takes ownership of a ANeuralNetworksMemory Memory(const NnApiSupportLibrary * nnapi,ANeuralNetworksMemory * memory)51 Memory(const NnApiSupportLibrary* nnapi, ANeuralNetworksMemory* memory) 52 : mNnApi(nnapi), mMemory(memory), mSize(0) {} 53 54 // Create from a FD and may takes ownership of the fd. 55 Memory(const NnApiSupportLibrary* nnapi, size_t size, int protect, int fd, size_t offset, 56 bool ownsFd = false) mNnApi(nnapi)57 : mNnApi(nnapi), mOwnedFd(ownsFd ? std::optional<int>{fd} : std::nullopt), mSize(size) { 58 mValid = mNnApi->getFL5()->ANeuralNetworksMemory_createFromFd( 59 size, protect, fd, offset, &mMemory) == ANEURALNETWORKS_NO_ERROR; 60 } 61 62 // Create from a buffer, may take ownership. Memory(const NnApiSupportLibrary * nnapi,AHardwareBuffer * buffer,bool ownAHWB,size_t size)63 Memory(const NnApiSupportLibrary* nnapi, AHardwareBuffer* buffer, bool ownAHWB, size_t size) 64 : mNnApi(nnapi), mOwnedAHWB(ownAHWB ? buffer : nullptr), mSize(size) { 65 mValid = mNnApi->getFL5()->ANeuralNetworksMemory_createFromAHardwareBuffer( 66 buffer, &mMemory) == ANEURALNETWORKS_NO_ERROR; 67 } 68 69 // Create from a desc Memory(const NnApiSupportLibrary * nnapi,ANeuralNetworksMemoryDesc * desc,size_t size)70 Memory(const NnApiSupportLibrary* nnapi, ANeuralNetworksMemoryDesc* desc, size_t size) 71 : mNnApi(nnapi), mSize(size) { 72 mValid = mNnApi->getFL5()->ANeuralNetworksMemory_createFromDesc(desc, &mMemory) == 73 ANEURALNETWORKS_NO_ERROR; 74 } 75 ~Memory()76 virtual ~Memory() { 77 if (mMemory) { 78 mNnApi->getFL5()->ANeuralNetworksMemory_free(mMemory); 79 } 80 if (mOwnedFd) { 81 close(*mOwnedFd); 82 } 83 if (mOwnedAHWB) { 84 AHardwareBuffer_release(mOwnedAHWB); 85 } 86 } 87 88 // Disallow copy semantics to ensure the runtime object can only be freed 89 // once. Copy semantics could be enabled if some sort of reference counting 90 // or deep-copy system for runtime objects is added later. 91 Memory(const Memory&) = delete; 92 Memory& operator=(const Memory&) = delete; 93 94 // Move semantics to remove access to the runtime object from the wrapper 95 // object that is being moved. This ensures the runtime object will be 96 // freed only once. Memory(Memory && other)97 Memory(Memory&& other) { *this = std::move(other); } 98 Memory& operator=(Memory&& other) { 99 if (this != &other) { 100 if (mMemory) { 101 mNnApi->getFL5()->ANeuralNetworksMemory_free(mMemory); 102 } 103 if (mOwnedFd) { 104 close(*mOwnedFd); 105 } 106 if (mOwnedAHWB) { 107 AHardwareBuffer_release(mOwnedAHWB); 108 } 109 110 mMemory = other.mMemory; 111 mValid = other.mValid; 112 mNnApi = other.mNnApi; 113 mOwnedFd = other.mOwnedFd; 114 mOwnedAHWB = other.mOwnedAHWB; 115 other.mMemory = nullptr; 116 other.mValid = false; 117 other.mOwnedFd.reset(); 118 other.mOwnedAHWB = nullptr; 119 } 120 return *this; 121 } 122 get()123 ANeuralNetworksMemory* get() const { return mMemory; } isValid()124 bool isValid() const { return mValid; } getSize()125 size_t getSize() const { return mSize; } copyTo(Memory & other)126 Result copyTo(Memory& other) { 127 return static_cast<Result>( 128 mNnApi->getFL5()->ANeuralNetworksMemory_copy(mMemory, other.mMemory)); 129 } 130 131 private: 132 const NnApiSupportLibrary* mNnApi = nullptr; 133 ANeuralNetworksMemory* mMemory = nullptr; 134 bool mValid = true; 135 std::optional<int> mOwnedFd; 136 AHardwareBuffer* mOwnedAHWB = nullptr; 137 size_t mSize; 138 }; 139 140 class Model { 141 public: Model(const NnApiSupportLibrary * nnapi)142 Model(const NnApiSupportLibrary* nnapi) : mNnApi(nnapi) { 143 mValid = mNnApi->getFL5()->ANeuralNetworksModel_create(&mModel) == ANEURALNETWORKS_NO_ERROR; 144 } ~Model()145 ~Model() { 146 if (mModel) { 147 mNnApi->getFL5()->ANeuralNetworksModel_free(mModel); 148 } 149 } 150 151 // Disallow copy semantics to ensure the runtime object can only be freed 152 // once. Copy semantics could be enabled if some sort of reference counting 153 // or deep-copy system for runtime objects is added later. 154 Model(const Model&) = delete; 155 Model& operator=(const Model&) = delete; 156 157 // Move semantics to remove access to the runtime object from the wrapper 158 // object that is being moved. This ensures the runtime object will be 159 // freed only once. Model(Model && other)160 Model(Model&& other) { *this = std::move(other); } 161 Model& operator=(Model&& other) { 162 if (this != &other) { 163 if (mModel != nullptr) { 164 mNnApi->getFL5()->ANeuralNetworksModel_free(mModel); 165 } 166 mNnApi = other.mNnApi; 167 mModel = other.mModel; 168 mNextOperandId = other.mNextOperandId; 169 mValid = other.mValid; 170 mRelaxed = other.mRelaxed; 171 mFinished = other.mFinished; 172 mOperands = std::move(other.mOperands); 173 mInputs = std::move(other.mInputs); 174 mOutputs = std::move(other.mOutputs); 175 other.mModel = nullptr; 176 other.mNextOperandId = 0; 177 other.mValid = false; 178 other.mRelaxed = false; 179 other.mFinished = false; 180 } 181 return *this; 182 } 183 finish()184 Result finish() { 185 if (mValid) { 186 auto result = 187 static_cast<Result>(mNnApi->getFL5()->ANeuralNetworksModel_finish(mModel)); 188 if (result != Result::NO_ERROR) { 189 mValid = false; 190 } 191 mFinished = true; 192 return result; 193 } else { 194 return Result::BAD_STATE; 195 } 196 } 197 addOperand(const OperandType * type)198 uint32_t addOperand(const OperandType* type) { 199 if (mNnApi->getFL5()->ANeuralNetworksModel_addOperand(mModel, &type->operandType) != 200 ANEURALNETWORKS_NO_ERROR) { 201 mValid = false; 202 } else { 203 mOperands.push_back(*type); 204 } 205 206 if (type->channelQuant) { 207 if (mNnApi->getFL5()->ANeuralNetworksModel_setOperandSymmPerChannelQuantParams( 208 mModel, mNextOperandId, &type->channelQuant.value().params) != 209 ANEURALNETWORKS_NO_ERROR) { 210 mValid = false; 211 } 212 } 213 214 return mNextOperandId++; 215 } 216 217 template <typename T> addConstantOperand(const OperandType * type,const T & value)218 uint32_t addConstantOperand(const OperandType* type, const T& value) { 219 static_assert(sizeof(T) <= ANEURALNETWORKS_MAX_SIZE_OF_IMMEDIATELY_COPIED_VALUES, 220 "Values larger than ANEURALNETWORKS_MAX_SIZE_OF_IMMEDIATELY_COPIED_VALUES " 221 "not supported"); 222 uint32_t index = addOperand(type); 223 setOperandValue(index, &value); 224 return index; 225 } 226 addModelOperand(const Model * value)227 uint32_t addModelOperand(const Model* value) { 228 OperandType operandType(Type::MODEL, {}); 229 uint32_t operand = addOperand(&operandType); 230 setOperandValueFromModel(operand, value); 231 return operand; 232 } 233 setOperandValue(uint32_t index,const void * buffer,size_t length)234 void setOperandValue(uint32_t index, const void* buffer, size_t length) { 235 if (mNnApi->getFL5()->ANeuralNetworksModel_setOperandValue(mModel, index, buffer, length) != 236 ANEURALNETWORKS_NO_ERROR) { 237 mValid = false; 238 } 239 } 240 241 template <typename T> setOperandValue(uint32_t index,const T * value)242 void setOperandValue(uint32_t index, const T* value) { 243 static_assert(!std::is_pointer<T>(), "No operand may have a pointer as its value"); 244 return setOperandValue(index, value, sizeof(T)); 245 } 246 setOperandValueFromMemory(uint32_t index,const Memory * memory,uint32_t offset,size_t length)247 void setOperandValueFromMemory(uint32_t index, const Memory* memory, uint32_t offset, 248 size_t length) { 249 if (mNnApi->getFL5()->ANeuralNetworksModel_setOperandValueFromMemory( 250 mModel, index, memory->get(), offset, length) != ANEURALNETWORKS_NO_ERROR) { 251 mValid = false; 252 } 253 } 254 setOperandValueFromModel(uint32_t index,const Model * value)255 void setOperandValueFromModel(uint32_t index, const Model* value) { 256 if (mNnApi->getFL5()->ANeuralNetworksModel_setOperandValueFromModel( 257 mModel, index, value->mModel) != ANEURALNETWORKS_NO_ERROR) { 258 mValid = false; 259 } 260 } 261 setOperandValueFromModel(uint32_t index,ANeuralNetworksModel * value)262 void setOperandValueFromModel(uint32_t index, ANeuralNetworksModel* value) { 263 if (mNnApi->getFL5()->ANeuralNetworksModel_setOperandValueFromModel(mModel, index, value) != 264 ANEURALNETWORKS_NO_ERROR) { 265 mValid = false; 266 } 267 } 268 addOperation(ANeuralNetworksOperationType type,const std::vector<uint32_t> & inputs,const std::vector<uint32_t> & outputs)269 void addOperation(ANeuralNetworksOperationType type, const std::vector<uint32_t>& inputs, 270 const std::vector<uint32_t>& outputs) { 271 if (mNnApi->getFL5()->ANeuralNetworksModel_addOperation( 272 mModel, type, static_cast<uint32_t>(inputs.size()), inputs.data(), 273 static_cast<uint32_t>(outputs.size()), 274 outputs.data()) != ANEURALNETWORKS_NO_ERROR) { 275 mValid = false; 276 } 277 } identifyInputsAndOutputs(const std::vector<uint32_t> & inputs,const std::vector<uint32_t> & outputs)278 void identifyInputsAndOutputs(const std::vector<uint32_t>& inputs, 279 const std::vector<uint32_t>& outputs) { 280 if (mNnApi->getFL5()->ANeuralNetworksModel_identifyInputsAndOutputs( 281 mModel, static_cast<uint32_t>(inputs.size()), inputs.data(), 282 static_cast<uint32_t>(outputs.size()), 283 outputs.data()) != ANEURALNETWORKS_NO_ERROR) { 284 mValid = false; 285 } else { 286 mInputs = inputs; 287 mOutputs = outputs; 288 } 289 } 290 relaxComputationFloat32toFloat16(bool isRelax)291 void relaxComputationFloat32toFloat16(bool isRelax) { 292 if (mNnApi->getFL5()->ANeuralNetworksModel_relaxComputationFloat32toFloat16( 293 mModel, isRelax) == ANEURALNETWORKS_NO_ERROR) { 294 mRelaxed = isRelax; 295 } 296 } 297 getExtensionOperandType(const std::string & extensionName,uint16_t operandCodeWithinExtension,int32_t * type)298 void getExtensionOperandType(const std::string& extensionName, 299 uint16_t operandCodeWithinExtension, int32_t* type) { 300 if (mNnApi->getFL5()->ANeuralNetworksModel_getExtensionOperandType( 301 mModel, extensionName.c_str(), operandCodeWithinExtension, type) != 302 ANEURALNETWORKS_NO_ERROR) { 303 mValid = false; 304 } 305 } 306 getExtensionOperationType(const std::string & extensionName,uint16_t operandCodeWithinExtension,ANeuralNetworksOperationType * type)307 void getExtensionOperationType(const std::string& extensionName, 308 uint16_t operandCodeWithinExtension, 309 ANeuralNetworksOperationType* type) { 310 if (mNnApi->getFL5()->ANeuralNetworksModel_getExtensionOperationType( 311 mModel, extensionName.c_str(), operandCodeWithinExtension, type) != 312 ANEURALNETWORKS_NO_ERROR) { 313 mValid = false; 314 } 315 } 316 setOperandExtensionData(int32_t operandId,const void * data,size_t length)317 void setOperandExtensionData(int32_t operandId, const void* data, size_t length) { 318 if (mNnApi->getFL5()->ANeuralNetworksModel_setOperandExtensionData( 319 mModel, operandId, data, length) != ANEURALNETWORKS_NO_ERROR) { 320 mValid = false; 321 } 322 } 323 getHandle()324 ANeuralNetworksModel* getHandle() const { return mModel; } isValid()325 bool isValid() const { return mValid; } isRelaxed()326 bool isRelaxed() const { return mRelaxed; } isFinished()327 bool isFinished() const { return mFinished; } 328 getInputs()329 const std::vector<uint32_t>& getInputs() const { return mInputs; } getOutputs()330 const std::vector<uint32_t>& getOutputs() const { return mOutputs; } getOperands()331 const std::vector<OperandType>& getOperands() const { return mOperands; } 332 333 protected: 334 const NnApiSupportLibrary* mNnApi = nullptr; 335 ANeuralNetworksModel* mModel = nullptr; 336 // We keep track of the operand ID as a convenience to the caller. 337 uint32_t mNextOperandId = 0; 338 // We keep track of the operand datatypes/dimensions as a convenience to the caller. 339 std::vector<OperandType> mOperands; 340 std::vector<uint32_t> mInputs; 341 std::vector<uint32_t> mOutputs; 342 bool mValid = true; 343 bool mRelaxed = false; 344 bool mFinished = false; 345 }; 346 347 class Compilation { 348 public: 349 // On success, createForDevice(s) will return Result::NO_ERROR and the created compilation; 350 // otherwise, it will return the error code and Compilation object wrapping a nullptr handle. createForDevice(const NnApiSupportLibrary * nnapi,const Model * model,const ANeuralNetworksDevice * device)351 static std::pair<Result, Compilation> createForDevice(const NnApiSupportLibrary* nnapi, 352 const Model* model, 353 const ANeuralNetworksDevice* device) { 354 return createForDevices(nnapi, model, {device}); 355 } createForDevices(const NnApiSupportLibrary * nnapi,const Model * model,const std::vector<const ANeuralNetworksDevice * > & devices)356 static std::pair<Result, Compilation> createForDevices( 357 const NnApiSupportLibrary* nnapi, const Model* model, 358 const std::vector<const ANeuralNetworksDevice*>& devices) { 359 ANeuralNetworksCompilation* compilation = nullptr; 360 const Result result = 361 static_cast<Result>(nnapi->getFL5()->ANeuralNetworksCompilation_createForDevices( 362 model->getHandle(), devices.empty() ? nullptr : devices.data(), 363 devices.size(), &compilation)); 364 return {result, Compilation(nnapi, compilation)}; 365 } 366 ~Compilation()367 ~Compilation() { mNnApi->getFL5()->ANeuralNetworksCompilation_free(mCompilation); } 368 369 // Disallow copy semantics to ensure the runtime object can only be freed 370 // once. Copy semantics could be enabled if some sort of reference counting 371 // or deep-copy system for runtime objects is added later. 372 Compilation(const Compilation&) = delete; 373 Compilation& operator=(const Compilation&) = delete; 374 375 // Move semantics to remove access to the runtime object from the wrapper 376 // object that is being moved. This ensures the runtime object will be 377 // freed only once. Compilation(Compilation && other)378 Compilation(Compilation&& other) { *this = std::move(other); } 379 Compilation& operator=(Compilation&& other) { 380 if (this != &other) { 381 mNnApi = other.mNnApi; 382 mNnApi->getFL5()->ANeuralNetworksCompilation_free(mCompilation); 383 mCompilation = other.mCompilation; 384 other.mCompilation = nullptr; 385 } 386 return *this; 387 } 388 setPreference(ExecutePreference preference)389 Result setPreference(ExecutePreference preference) { 390 return static_cast<Result>(mNnApi->getFL5()->ANeuralNetworksCompilation_setPreference( 391 mCompilation, static_cast<int32_t>(preference))); 392 } 393 setPriority(ExecutePriority priority)394 Result setPriority(ExecutePriority priority) { 395 return static_cast<Result>(mNnApi->getFL5()->ANeuralNetworksCompilation_setPriority( 396 mCompilation, static_cast<int32_t>(priority))); 397 } 398 setTimeout(uint64_t durationNs)399 Result setTimeout(uint64_t durationNs) { 400 return static_cast<Result>( 401 mNnApi->getFL5()->ANeuralNetworksCompilation_setTimeout(mCompilation, durationNs)); 402 } 403 setCaching(const std::string & cacheDir,const std::vector<uint8_t> & token)404 Result setCaching(const std::string& cacheDir, const std::vector<uint8_t>& token) { 405 if (token.size() != ANEURALNETWORKS_BYTE_SIZE_OF_CACHE_TOKEN) { 406 return Result::BAD_DATA; 407 } 408 return static_cast<Result>(mNnApi->getFL5()->ANeuralNetworksCompilation_setCaching( 409 mCompilation, cacheDir.c_str(), token.data())); 410 } 411 setCachingFromFds(const std::vector<int> & modelCacheFds,const std::vector<int> & dataCacheFds,const std::vector<uint8_t> & token)412 Result setCachingFromFds(const std::vector<int>& modelCacheFds, 413 const std::vector<int>& dataCacheFds, 414 const std::vector<uint8_t>& token) { 415 if (token.size() != ANEURALNETWORKS_BYTE_SIZE_OF_CACHE_TOKEN) { 416 return Result::BAD_DATA; 417 } 418 return static_cast<Result>( 419 mNnApi->getFL5()->SL_ANeuralNetworksCompilation_setCachingFromFds( 420 mCompilation, modelCacheFds.data(), modelCacheFds.size(), 421 dataCacheFds.data(), dataCacheFds.size(), token.data())); 422 } 423 setCachingFromFds(const std::vector<base::unique_fd> & modelCacheOwnedFds,const std::vector<base::unique_fd> & dataCacheOwnedFds,const std::vector<uint8_t> & token)424 Result setCachingFromFds(const std::vector<base::unique_fd>& modelCacheOwnedFds, 425 const std::vector<base::unique_fd>& dataCacheOwnedFds, 426 const std::vector<uint8_t>& token) { 427 std::vector<int> modelCacheFds, dataCacheFds; 428 for (const auto& fd : modelCacheOwnedFds) { 429 modelCacheFds.push_back(fd.get()); 430 } 431 for (const auto& fd : dataCacheOwnedFds) { 432 dataCacheFds.push_back(fd.get()); 433 } 434 return setCachingFromFds(modelCacheFds, dataCacheFds, token); 435 } 436 finish()437 Result finish() { 438 return static_cast<Result>( 439 mNnApi->getFL5()->ANeuralNetworksCompilation_finish(mCompilation)); 440 } 441 getPreferredMemoryAlignmentForInput(uint32_t index,uint32_t * alignment)442 Result getPreferredMemoryAlignmentForInput(uint32_t index, uint32_t* alignment) const { 443 return static_cast<Result>( 444 mNnApi->getFL5()->ANeuralNetworksCompilation_getPreferredMemoryAlignmentForInput( 445 mCompilation, index, alignment)); 446 }; 447 getPreferredMemoryPaddingForInput(uint32_t index,uint32_t * padding)448 Result getPreferredMemoryPaddingForInput(uint32_t index, uint32_t* padding) const { 449 return static_cast<Result>( 450 mNnApi->getFL5()->ANeuralNetworksCompilation_getPreferredMemoryPaddingForInput( 451 mCompilation, index, padding)); 452 }; 453 getPreferredMemoryAlignmentForOutput(uint32_t index,uint32_t * alignment)454 Result getPreferredMemoryAlignmentForOutput(uint32_t index, uint32_t* alignment) const { 455 return static_cast<Result>( 456 mNnApi->getFL5()->ANeuralNetworksCompilation_getPreferredMemoryAlignmentForOutput( 457 mCompilation, index, alignment)); 458 }; 459 getPreferredMemoryPaddingForOutput(uint32_t index,uint32_t * padding)460 Result getPreferredMemoryPaddingForOutput(uint32_t index, uint32_t* padding) const { 461 return static_cast<Result>( 462 mNnApi->getFL5()->ANeuralNetworksCompilation_getPreferredMemoryPaddingForOutput( 463 mCompilation, index, padding)); 464 }; 465 addExtensionAttribute(const std::string & extensionName,uint16_t attributeCodeWithinExtension,const std::vector<uint8_t> & extensionAttributeData)466 Result addExtensionAttribute(const std::string& extensionName, 467 uint16_t attributeCodeWithinExtension, 468 const std::vector<uint8_t>& extensionAttributeData) { 469 return static_cast<Result>( 470 mNnApi->getFL8()->ANeuralNetworksCompilation_addExtensionAttribute( 471 mCompilation, extensionName.c_str(), attributeCodeWithinExtension, 472 extensionAttributeData.data(), extensionAttributeData.size())); 473 } 474 getHandle()475 ANeuralNetworksCompilation* getHandle() const { return mCompilation; } 476 477 protected: 478 // Takes the ownership of ANeuralNetworksCompilation. Compilation(const NnApiSupportLibrary * nnapi,ANeuralNetworksCompilation * compilation)479 Compilation(const NnApiSupportLibrary* nnapi, ANeuralNetworksCompilation* compilation) 480 : mNnApi(nnapi), mCompilation(compilation) {} 481 482 const NnApiSupportLibrary* mNnApi = nullptr; 483 ANeuralNetworksCompilation* mCompilation = nullptr; 484 }; 485 486 class Execution { 487 public: Execution(const NnApiSupportLibrary * nnapi,const Compilation * compilation)488 Execution(const NnApiSupportLibrary* nnapi, const Compilation* compilation) 489 : mNnApi(nnapi), mCompilation(compilation->getHandle()) { 490 int result = mNnApi->getFL5()->ANeuralNetworksExecution_create(compilation->getHandle(), 491 &mExecution); 492 if (result != 0) { 493 // TODO Handle the error 494 } 495 } 496 ~Execution()497 ~Execution() { 498 if (mExecution) { 499 mNnApi->getFL5()->ANeuralNetworksExecution_free(mExecution); 500 } 501 } 502 503 // Disallow copy semantics to ensure the runtime object can only be freed 504 // once. Copy semantics could be enabled if some sort of reference counting 505 // or deep-copy system for runtime objects is added later. 506 Execution(const Execution&) = delete; 507 Execution& operator=(const Execution&) = delete; 508 509 // Move semantics to remove access to the runtime object from the wrapper 510 // object that is being moved. This ensures the runtime object will be 511 // freed only once. Execution(Execution && other)512 Execution(Execution&& other) { *this = std::move(other); } 513 Execution& operator=(Execution&& other) { 514 if (this != &other) { 515 if (mExecution != nullptr) { 516 mNnApi->getFL5()->ANeuralNetworksExecution_free(mExecution); 517 } 518 mNnApi = other.mNnApi; 519 mCompilation = other.mCompilation; 520 mExecution = other.mExecution; 521 other.mCompilation = nullptr; 522 other.mExecution = nullptr; 523 } 524 return *this; 525 } 526 527 Result setInput(uint32_t index, const void* buffer, size_t length, 528 const ANeuralNetworksOperandType* type = nullptr) { 529 return static_cast<Result>(mNnApi->getFL5()->ANeuralNetworksExecution_setInput( 530 mExecution, index, type, buffer, length)); 531 } 532 533 template <typename T> 534 Result setInput(uint32_t index, const T* value, 535 const ANeuralNetworksOperandType* type = nullptr) { 536 static_assert(!std::is_pointer<T>(), "No operand may have a pointer as its value"); 537 return setInput(index, value, sizeof(T), type); 538 } 539 540 Result setInputFromMemory(uint32_t index, const Memory* memory, uint32_t offset, 541 uint32_t length, const ANeuralNetworksOperandType* type = nullptr) { 542 return static_cast<Result>(mNnApi->getFL5()->ANeuralNetworksExecution_setInputFromMemory( 543 mExecution, index, type, memory->get(), offset, length)); 544 } 545 546 Result setOutput(uint32_t index, void* buffer, size_t length, 547 const ANeuralNetworksOperandType* type = nullptr) { 548 return static_cast<Result>(mNnApi->getFL5()->ANeuralNetworksExecution_setOutput( 549 mExecution, index, type, buffer, length)); 550 } 551 552 template <typename T> 553 Result setOutput(uint32_t index, T* value, const ANeuralNetworksOperandType* type = nullptr) { 554 static_assert(!std::is_pointer<T>(), "No operand may have a pointer as its value"); 555 return setOutput(index, value, sizeof(T), type); 556 } 557 558 Result setOutputFromMemory(uint32_t index, const Memory* memory, uint32_t offset, 559 uint32_t length, const ANeuralNetworksOperandType* type = nullptr) { 560 return static_cast<Result>(mNnApi->getFL5()->ANeuralNetworksExecution_setOutputFromMemory( 561 mExecution, index, type, memory->get(), offset, length)); 562 } 563 setLoopTimeout(uint64_t duration)564 Result setLoopTimeout(uint64_t duration) { 565 return static_cast<Result>( 566 mNnApi->getFL5()->ANeuralNetworksExecution_setLoopTimeout(mExecution, duration)); 567 } 568 setMeasureTiming(bool measure)569 Result setMeasureTiming(bool measure) { 570 return static_cast<Result>( 571 mNnApi->getFL5()->ANeuralNetworksExecution_setMeasureTiming(mExecution, measure)); 572 } 573 setTimeout(uint64_t duration)574 Result setTimeout(uint64_t duration) { 575 return static_cast<Result>( 576 mNnApi->getFL5()->ANeuralNetworksExecution_setTimeout(mExecution, duration)); 577 } 578 getDuration(Duration durationCode,uint64_t * duration)579 Result getDuration(Duration durationCode, uint64_t* duration) { 580 return static_cast<Result>(mNnApi->getFL5()->ANeuralNetworksExecution_getDuration( 581 mExecution, static_cast<int32_t>(durationCode), duration)); 582 } 583 enableInputAndOutputPadding(bool enable)584 Result enableInputAndOutputPadding(bool enable) { 585 return static_cast<Result>( 586 mNnApi->getFL5()->ANeuralNetworksExecution_enableInputAndOutputPadding(mExecution, 587 enable)); 588 } 589 setReusable(bool reusable)590 Result setReusable(bool reusable) { 591 return static_cast<Result>( 592 mNnApi->getFL5()->ANeuralNetworksExecution_setReusable(mExecution, reusable)); 593 } 594 595 // By default, compute() uses the synchronous API. Either an argument or 596 // setComputeMode() can be used to change the behavior of compute() to 597 // use the burst API 598 // Returns the previous ComputeMode. 599 enum class ComputeMode { SYNC, BURST, FENCED }; setComputeMode(ComputeMode mode)600 static ComputeMode setComputeMode(ComputeMode mode) { 601 ComputeMode oldComputeMode = mComputeMode; 602 mComputeMode = mode; 603 return oldComputeMode; 604 } getComputeMode()605 static ComputeMode getComputeMode() { return mComputeMode; } 606 607 Result compute(ComputeMode computeMode = mComputeMode) { 608 switch (computeMode) { 609 case ComputeMode::SYNC: { 610 return static_cast<Result>( 611 mNnApi->getFL5()->ANeuralNetworksExecution_compute(mExecution)); 612 } 613 case ComputeMode::BURST: { 614 ANeuralNetworksBurst* burst = nullptr; 615 Result result = static_cast<Result>( 616 mNnApi->getFL5()->ANeuralNetworksBurst_create(mCompilation, &burst)); 617 if (result != Result::NO_ERROR) { 618 return result; 619 } 620 result = static_cast<Result>( 621 mNnApi->getFL5()->ANeuralNetworksExecution_burstCompute(mExecution, burst)); 622 mNnApi->getFL5()->ANeuralNetworksBurst_free(burst); 623 return result; 624 } 625 case ComputeMode::FENCED: { 626 ANeuralNetworksEvent* event = nullptr; 627 Result result = static_cast<Result>( 628 mNnApi->getFL5()->ANeuralNetworksExecution_startComputeWithDependencies( 629 mExecution, nullptr, 0, 0, &event)); 630 if (result != Result::NO_ERROR) { 631 return result; 632 } 633 result = static_cast<Result>(mNnApi->getFL5()->ANeuralNetworksEvent_wait(event)); 634 mNnApi->getFL5()->ANeuralNetworksEvent_free(event); 635 return result; 636 } 637 } 638 return Result::BAD_DATA; 639 } 640 startComputeWithDependencies(const std::vector<const ANeuralNetworksEvent * > & deps,uint64_t duration,Event * event)641 Result startComputeWithDependencies(const std::vector<const ANeuralNetworksEvent*>& deps, 642 uint64_t duration, Event* event) { 643 ANeuralNetworksEvent* ev = nullptr; 644 Result result = static_cast<Result>( 645 NNAPI_CALL(ANeuralNetworksExecution_startComputeWithDependencies( 646 mExecution, deps.data(), deps.size(), duration, &ev))); 647 event->set(ev); 648 return result; 649 } 650 getOutputOperandDimensions(uint32_t index,std::vector<uint32_t> * dimensions)651 Result getOutputOperandDimensions(uint32_t index, std::vector<uint32_t>* dimensions) { 652 uint32_t rank = 0; 653 Result result = 654 static_cast<Result>(mNnApi->getFL5()->ANeuralNetworksExecution_getOutputOperandRank( 655 mExecution, index, &rank)); 656 dimensions->resize(rank); 657 if ((result != Result::NO_ERROR && result != Result::OUTPUT_INSUFFICIENT_SIZE) || 658 rank == 0) { 659 return result; 660 } 661 result = static_cast<Result>( 662 mNnApi->getFL5()->ANeuralNetworksExecution_getOutputOperandDimensions( 663 mExecution, index, dimensions->data())); 664 return result; 665 } 666 addExtensionAttribute(const std::string & extensionName,uint16_t attributeCodeWithinExtension,const std::vector<uint8_t> & extensionAttributeData)667 Result addExtensionAttribute(const std::string& extensionName, 668 uint16_t attributeCodeWithinExtension, 669 const std::vector<uint8_t>& extensionAttributeData) { 670 return static_cast<Result>(mNnApi->getFL8()->ANeuralNetworksExecution_addExtensionAttribute( 671 mExecution, extensionName.c_str(), attributeCodeWithinExtension, 672 extensionAttributeData.data(), extensionAttributeData.size())); 673 } 674 getHandle()675 ANeuralNetworksExecution* getHandle() { return mExecution; }; 676 677 private: 678 const NnApiSupportLibrary* mNnApi = nullptr; 679 ANeuralNetworksCompilation* mCompilation = nullptr; 680 ANeuralNetworksExecution* mExecution = nullptr; 681 682 // Initialized to ComputeMode::SYNC in TestNeuralNetworksWrapper.cpp. 683 static ComputeMode mComputeMode; 684 }; 685 686 } // namespace sl_wrapper 687 } // namespace nn 688 } // namespace android 689 690 #endif // ANDROID_PACKAGES_MODULES_NEURALNETWORKS_SL_SUPPORT_LIBRARY_WRAPPER_H 691