diff options
Diffstat (limited to 'runtimes/nn/runtime/ModelBuilder.cpp')
-rw-r--r-- | runtimes/nn/runtime/ModelBuilder.cpp | 386 |
1 files changed, 0 insertions, 386 deletions
diff --git a/runtimes/nn/runtime/ModelBuilder.cpp b/runtimes/nn/runtime/ModelBuilder.cpp deleted file mode 100644 index 3e142501e..000000000 --- a/runtimes/nn/runtime/ModelBuilder.cpp +++ /dev/null @@ -1,386 +0,0 @@ -/* - * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -#include "ModelBuilder.h" - -#include "CompilationBuilder.h" - -namespace nnfw { -namespace rt { - -// The maximum number of operands and operations that a model may have. -const uint32_t MAX_NUMBER_OF_OPERANDS = 0xFFFFFFFE; -const uint32_t MAX_NUMBER_OF_OPERATIONS = 0xFFFFFFFE; - -bool ModelBuilder::badState(const char* name) { - if (mCompletedModel) { - LOG(ERROR) << "ANeuralNetworksModel_" << name << " can't modify after model finished"; - return true; - } - if (mInvalidModel) { - LOG(ERROR) << "ANeuralNetworksModel_" << name << " can't modify an invalid model"; - return true; - } - return false; -} - -int ModelBuilder::addOperand(const ANeuralNetworksOperandType& type) { - if (badState("addOperand")) { - return ANEURALNETWORKS_BAD_STATE; - } - - int n = validateOperandType(type, "ANeuralNetworksModel_addOperand", true); - if (n != ANEURALNETWORKS_NO_ERROR) { - return n; - } - size_t idx = mOperands.size(); - if (idx >= MAX_NUMBER_OF_OPERANDS) { - LOG(ERROR) << "ANeuralNetworksModel_addOperand exceed max operands"; - return ANEURALNETWORKS_BAD_DATA; - } - mOperands.resize(idx + 1); - auto& operand = mOperands[idx]; - operand.type = static_cast<OperandType>(type.type); - setFromIntList(&operand.dimensions, type.dimensionCount, type.dimensions); - operand.numberOfConsumers = 0; - operand.scale = type.scale; - operand.zeroPoint = type.zeroPoint; - operand.lifetime = OperandLifeTime::TEMPORARY_VARIABLE; - operand.location = {.poolIndex = 0, .offset = 0, .length = 0}; - return ANEURALNETWORKS_NO_ERROR; -} - -int ModelBuilder::setOperandValue(uint32_t index, const void* buffer, size_t length) { - if (badState("setOperandValue")) { - return ANEURALNETWORKS_BAD_STATE; - } - - VLOG(MODEL) << __func__ << " for operand " << index << " size " << length; - if (index >= operandCount()) { - LOG(ERROR) << "ANeuralNetworksModel_setOperandValue setting operand " << index << " of " - << operandCount(); - return ANEURALNETWORKS_BAD_DATA; - } - Operand& operand = mOperands[index]; - if (buffer == nullptr) { - if (length) { - LOG(ERROR) << "ANeuralNetworksModel_setOperandValue buffer is nullptr but length is " - "not 0"; - return ANEURALNETWORKS_BAD_DATA; - } - operand.lifetime = OperandLifeTime::NO_VALUE; - // The location is unused and is set to zeros. - operand.location = {.poolIndex = 0, - .offset = 0, - .length = 0}; - } else { - if (length > 0xFFFFFFFF) { - LOG(ERROR) << "ANeuralNetworksModel_setOperandValue value length of " << length - << " exceeds max size"; - return ANEURALNETWORKS_BAD_DATA; - } - uint32_t valueLength = static_cast<uint32_t>(length); - uint32_t neededLength = sizeOfData(operand.type, operand.dimensions); - if (neededLength != valueLength) { - LOG(ERROR) << "ANeuralNetworksModel_setOperandValue setting " << valueLength - << " bytes when needing " << neededLength; - return ANEURALNETWORKS_BAD_DATA; - } - if (valueLength <= ANEURALNETWORKS_MAX_SIZE_OF_IMMEDIATELY_COPIED_VALUES) { - uint32_t existingSize = static_cast<uint32_t>(mSmallOperandValues.size()); - uint32_t extraBytes = alignBytesNeeded(existingSize, valueLength); - mSmallOperandValues.resize(existingSize + extraBytes + valueLength); - operand.lifetime = OperandLifeTime::CONSTANT_COPY; - operand.location = { - .poolIndex = 0, .offset = existingSize + extraBytes, .length = neededLength}; - memcpy(&mSmallOperandValues[operand.location.offset], buffer, valueLength); - VLOG(MODEL) << "Copied small value to offset " << operand.location.offset; - } else { - VLOG(MODEL) << "Saving large value"; - operand.lifetime = OperandLifeTime::CONSTANT_REFERENCE; - // The values for poolIndex and offset will be set when the model is finished. - operand.location = {.poolIndex = 0, .offset = 0, .length = valueLength}; - // We keep track of the buffers. We'll allocate the shared memory only - // once we know the total size, to avoid needless copies. - mLargeOperandValues.push_back(LargeValue{.operandIndex = index, .buffer = buffer}); - } - } - return ANEURALNETWORKS_NO_ERROR; -} - -int ModelBuilder::copyLargeValuesToSharedMemory() { - VLOG(MODEL) << __func__ << " has " << mLargeOperandValues.size() << " values."; - if (!mLargeOperandValues.empty()) { - // Calculate the size of the shared memory needed for all the large values. - // Also sets the offset for each value within the memory. - size_t poolSize = 0; - for (LargeValue& l: mLargeOperandValues) { - Operand& operand = mOperands[l.operandIndex]; - nnAssert(operand.lifetime == OperandLifeTime::CONSTANT_REFERENCE); - poolSize += alignBytesNeeded(poolSize, operand.location.length); - operand.location.offset = poolSize; - poolSize += operand.location.length; - } - - // Allocated the shared memory. - int n = mLargeValueMemory.create(poolSize); - if (n != ANEURALNETWORKS_NO_ERROR) { - return n; - } - uint8_t* memoryPointer = nullptr; - n = mLargeValueMemory.getPointer(&memoryPointer); - if (n != ANEURALNETWORKS_NO_ERROR) { - return n; - } - uint32_t poolIndex = mMemories.add(&mLargeValueMemory); - VLOG(MODEL) << "Allocated large value pool of size " << poolSize << " at index " - << poolIndex; - - // Copy the values to this memory. - for (LargeValue& l: mLargeOperandValues) { - Operand& operand = mOperands[l.operandIndex]; - operand.location.poolIndex = poolIndex; - memcpy(memoryPointer + operand.location.offset, l.buffer, operand.location.length); - } - } - return ANEURALNETWORKS_NO_ERROR; -} -int ModelBuilder::setOperandValueFromMemory(uint32_t index, const Memory* memory, uint32_t offset, - size_t length) { - VLOG(MODEL) << __func__ << " for operand " << index << " offset " << offset << " size " << length; - if (index >= operandCount()) { - LOG(ERROR) << "ANeuralNetworksModel_setOperandValueFromMemory setting operand " << index - << " of " << operandCount(); - return ANEURALNETWORKS_BAD_DATA; - } - Operand& operand = mOperands[index]; - uint32_t neededLength = sizeOfData(operand.type, operand.dimensions); - if (neededLength != length) { - LOG(ERROR) << "ANeuralNetworksModel_setOperandValueFromMemory setting " << length - << " bytes when needing " << neededLength; - return ANEURALNETWORKS_BAD_DATA; - } - // TODO validate does not exceed length of memory - operand.lifetime = OperandLifeTime::CONSTANT_REFERENCE; - operand.location = { - .poolIndex = mMemories.add(memory), .offset = offset, .length = neededLength}; - return ANEURALNETWORKS_NO_ERROR; -} - -int ModelBuilder::addOperation(ANeuralNetworksOperationType type, uint32_t inputCount, - const uint32_t* inputs, uint32_t outputCount, - const uint32_t* outputs) { - - if (badState("addOperation")) { - return ANEURALNETWORKS_BAD_STATE; - } - - if (!validCode(kNumberOfOperationTypes, kNumberOfOperationTypesOEM, type)) { - LOG(ERROR) << "ANeuralNetworksModel_addOperation invalid operations type " << type; - return ANEURALNETWORKS_BAD_DATA; - } - int n = validateOperandList(inputCount, inputs, operandCount(), - "ANeuralNetworksModel_addOperation inputs"); - if (n != ANEURALNETWORKS_NO_ERROR) { - return n; - } - n = validateOperandList(outputCount, outputs, operandCount(), - "ANeuralNetworksModel_addOperation outputs"); - if (n != ANEURALNETWORKS_NO_ERROR) { - return n; - } - - uint32_t operationIndex = operationCount(); - if (operationIndex >= MAX_NUMBER_OF_OPERATIONS) { - LOG(ERROR) << "ANeuralNetworksModel_addOperation exceed max operations"; - return ANEURALNETWORKS_BAD_DATA; - } - mOperations.resize(operationIndex + 1); - auto& entry = mOperations[operationIndex]; - entry.type = static_cast<OperationType>(type); - - setFromIntList(&entry.inputs, inputCount, inputs); - setFromIntList(&entry.outputs, outputCount, outputs); - for (uint32_t i : entry.inputs) { - mOperands[i].numberOfConsumers++; - // TODO mOperands[i].consumers.push_back(operationIndex); - } - return ANEURALNETWORKS_NO_ERROR; -} - -int ModelBuilder::identifyInputsAndOutputs(uint32_t inputCount, const uint32_t* inputs, - uint32_t outputCount, const uint32_t* outputs) { - if (badState("identifyInputsAndOutputs")) { - return ANEURALNETWORKS_BAD_STATE; - } - - int n = validateOperandList(inputCount, inputs, operandCount(), - "ANeuralNetworksModel_identifyInputsAndOutputs inputs"); - if (n != ANEURALNETWORKS_NO_ERROR) { - return n; - } - n = validateOperandList(outputCount, outputs, operandCount(), - "ANeuralNetworksModel_identifyInputsAndOutputs outputs"); - if (n != ANEURALNETWORKS_NO_ERROR) { - return n; - } - - // Makes a copy of the index list, validates the arguments, and changes - // the lifetime info of the corresponding operand. - auto setArguments = [&](std::vector<uint32_t>* indexVector, uint32_t indexCount, - const uint32_t* indexList, OperandLifeTime lifetime) -> bool { - indexVector->resize(indexCount); - for (uint32_t i = 0; i < indexCount; i++) { - const uint32_t operandIndex = indexList[i]; - if (operandIndex >= mOperands.size()) { - LOG(ERROR) << "ANeuralNetworksModel_identifyInputsAndOutputs Can't set input or output " - "to be " - << operandIndex << " as this exceeds the numbe of operands " - << mOperands.size(); - return false; - } - (*indexVector)[i] = operandIndex; - Operand& operand = mOperands[operandIndex]; - if (operand.lifetime != OperandLifeTime::TEMPORARY_VARIABLE) { - LOG(ERROR) << "ANeuralNetworksModel_identifyInputsAndOutputs Can't set operand " - << operandIndex - << " to be an input or output. Check that it's not a constant or " - "already an input or output"; - return false; - } - operand.lifetime = lifetime; - } - return true; - }; - - if (!setArguments(&mInputIndexes, inputCount, inputs, OperandLifeTime::MODEL_INPUT) || - !setArguments(&mOutputIndexes, outputCount, outputs, OperandLifeTime::MODEL_OUTPUT)) { - return ANEURALNETWORKS_BAD_DATA; - } - - return ANEURALNETWORKS_NO_ERROR; -} - -int ModelBuilder::createCompilation(CompilationBuilder** compilation) { - if (!mCompletedModel || mInvalidModel ) { - LOG(ERROR) << "ANeuralNetworksCompilation_create passed an unfinished model"; - *compilation = nullptr; - return ANEURALNETWORKS_BAD_STATE; - } - *compilation = new CompilationBuilder(this); - return (*compilation ? ANEURALNETWORKS_NO_ERROR : ANEURALNETWORKS_OUT_OF_MEMORY); -} - -int ModelBuilder::finish() { - if (mCompletedModel) { - LOG(ERROR) << "ANeuralNetworksModel_finish called more than once"; - return ANEURALNETWORKS_BAD_STATE; - } - if (mInvalidModel) { - LOG(ERROR) << "ANeuralNetworksModel_finish called on an invalid model"; - return ANEURALNETWORKS_BAD_STATE; - } - - int n = copyLargeValuesToSharedMemory(); - if (n != ANEURALNETWORKS_NO_ERROR) { - return n; - } - - // TODO: Modify validation so that it can be called without creating a HAL Model. - // NOTE: Must copyLargeValuesToSharedMemory() before validation; otherwise, - // a CONSTANT_REFERENCE operand will not have correct .poolIndex, and - // validation will not work properly. - Model modelForValidation; - setHidlModel(&modelForValidation); - if (!validateModel(modelForValidation)) { - LOG(ERROR) << "ANeuralNetworksModel_finish called on invalid model"; - mInvalidModel = true; - return ANEURALNETWORKS_BAD_DATA; - } - - // We sort the operations so that they will be in the appropriate - // order for a single-threaded, op at a time execution. - // TODO: we don't need this if we always run the partitioner. - sortIntoRunOrder(); - mCompletedModel = true; - return ANEURALNETWORKS_NO_ERROR; -} - -void ModelBuilder::sortIntoRunOrder() { - // Tracks the operations that can be executed. - std::vector<uint32_t> opsReadyToRun; - std::vector<Operation> runOrder; - - // Tracks how many inputs are needed for each operation to be ready to run. - std::multimap<uint32_t, uint32_t> operandToOperations; - std::vector<uint32_t> unknownInputCount(operationCount()); - for (uint32_t operationIndex = 0; operationIndex < operationCount(); operationIndex++) { - uint32_t& count = unknownInputCount[operationIndex]; - count = 0; - for (uint32_t operandIndex : mOperations[operationIndex].inputs) { - auto lifetime = mOperands[operandIndex].lifetime; - if (lifetime == OperandLifeTime::TEMPORARY_VARIABLE || - lifetime == OperandLifeTime::MODEL_OUTPUT) { - count++; - operandToOperations.insert( - std::pair<uint32_t, uint32_t>(operandIndex, operationIndex)); - } - } - if (count == 0) { - opsReadyToRun.push_back(operationIndex); - } - } - - while (opsReadyToRun.size() > 0) { - // Execute the next op - int opIndex = opsReadyToRun.back(); - opsReadyToRun.pop_back(); - const Operation& operation = mOperations[opIndex]; - - runOrder.push_back(mOperations[opIndex]); - - // Mark all its outputs as known. - for (uint32_t operandIndex : operation.outputs) { - auto range = operandToOperations.equal_range(operandIndex); - for (auto i = range.first; i != range.second; i++) { - uint32_t& count = unknownInputCount[i->second]; - if (--count == 0) { - opsReadyToRun.push_back(i->second); - } - } - } - } - mOperations = runOrder; -} - -void ModelBuilder::setHidlModel(Model* model) const { - model->operands = mOperands; - model->operations = mOperations; - model->inputIndexes = mInputIndexes; - model->outputIndexes = mOutputIndexes; - model->operandValues = mSmallOperandValues; - - uint32_t count = mMemories.size(); - model->pools.resize(count); - for (uint32_t i = 0; i < count; i++) { - model->pools[i] = mMemories[i]->getHidlMemory(); - } -} - -} // namespace rt -} // namespace nnfw |