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 "ModelBuilder"
18
19#include "ModelBuilder.h"
20
21#include "CompilationBuilder.h"
22#include "Utils.h"
23#include "ValidateHal.h"
24
25#include <map>
26#include <utility>
27
28namespace android {
29namespace nn {
30
31// The maximum number of operands and operations that a model may have.
32const uint32_t MAX_NUMBER_OF_OPERANDS = 0xFFFFFFFE;
33const uint32_t MAX_NUMBER_OF_OPERATIONS = 0xFFFFFFFE;
34
35bool ModelBuilder::badState(const char* name) {
36    if (mCompletedModel) {
37        LOG(ERROR) << "ANeuralNetworksModel_" << name << " can't modify after model finished";
38        return true;
39    }
40    if (mInvalidModel) {
41        LOG(ERROR) << "ANeuralNetworksModel_" << name << " can't modify an invalid model";
42        return true;
43    }
44    return false;
45}
46
47int ModelBuilder::addOperand(const ANeuralNetworksOperandType& type) {
48    if (badState("addOperand")) {
49        return ANEURALNETWORKS_BAD_STATE;
50    }
51
52    int n = validateOperandType(type, "ANeuralNetworksModel_addOperand", true);
53    if (n != ANEURALNETWORKS_NO_ERROR) {
54        return n;
55    }
56    size_t idx = mOperands.size();
57    if (idx >= MAX_NUMBER_OF_OPERANDS) {
58        LOG(ERROR) << "ANeuralNetworksModel_addOperand exceed max operands";
59        return ANEURALNETWORKS_BAD_DATA;
60    }
61    mOperands.push_back({
62        .type = static_cast<OperandType>(type.type),
63        .dimensions = hidl_vec<uint32_t>(type.dimensions, type.dimensions + type.dimensionCount),
64        .numberOfConsumers = 0,
65        .scale = type.scale,
66        .zeroPoint = type.zeroPoint,
67        .lifetime = OperandLifeTime::TEMPORARY_VARIABLE,
68        .location = {.poolIndex = 0, .offset = 0, .length = 0},
69    });
70    return ANEURALNETWORKS_NO_ERROR;
71}
72
73int ModelBuilder::setOperandValue(uint32_t index, const void* buffer, size_t length) {
74    VLOG(MODEL) << __func__ << " for operand " << index << " size " << length;
75    if (badState("setOperandValue")) {
76        return ANEURALNETWORKS_BAD_STATE;
77    }
78
79    if (index >= operandCount()) {
80        LOG(ERROR) << "ANeuralNetworksModel_setOperandValue setting operand " << index << " of "
81                   << operandCount();
82        return ANEURALNETWORKS_BAD_DATA;
83    }
84    Operand& operand = mOperands[index];
85    if (buffer == nullptr) {
86        if (length) {
87            LOG(ERROR) << "ANeuralNetworksModel_setOperandValue buffer is nullptr but length is "
88                          "not 0";
89            return ANEURALNETWORKS_BAD_DATA;
90        }
91        operand.lifetime = OperandLifeTime::NO_VALUE;
92        // The location is unused and is set to zeros.
93        operand.location = {.poolIndex = 0,
94                            .offset = 0,
95                            .length = 0};
96    } else {
97        if (length > 0xFFFFFFFF) {
98            LOG(ERROR) << "ANeuralNetworksModel_setOperandValue value length of " << length
99                       << " exceeds max size";
100            return ANEURALNETWORKS_BAD_DATA;
101        }
102        uint32_t valueLength = static_cast<uint32_t>(length);
103        uint32_t neededLength = sizeOfData(operand.type, operand.dimensions);
104        if (operand.type != OperandType::OEM && neededLength != valueLength) {
105            LOG(ERROR) << "ANeuralNetworksModel_setOperandValue setting " << valueLength
106                       << " bytes when needing " << neededLength;
107            return ANEURALNETWORKS_BAD_DATA;
108        }
109        if (valueLength <= ANEURALNETWORKS_MAX_SIZE_OF_IMMEDIATELY_COPIED_VALUES) {
110            uint32_t existingSize = static_cast<uint32_t>(mSmallOperandValues.size());
111            uint32_t extraBytes = alignBytesNeeded(existingSize, valueLength);
112            mSmallOperandValues.resize(existingSize + extraBytes + valueLength);
113            operand.lifetime = OperandLifeTime::CONSTANT_COPY;
114            operand.location = {
115                .poolIndex = 0, .offset = existingSize + extraBytes, .length = valueLength};
116            memcpy(&mSmallOperandValues[operand.location.offset], buffer, valueLength);
117            VLOG(MODEL) << "Copied small value to offset " << operand.location.offset;
118        } else {
119            VLOG(MODEL) << "Saving large value";
120            operand.lifetime = OperandLifeTime::CONSTANT_REFERENCE;
121            // The values for poolIndex and offset will be set when the model is finished.
122            typedef decltype(operand.location.poolIndex) PoolIndexType;
123            typedef decltype(operand.location.offset) OffsetType;
124            operand.location = {.poolIndex = ~PoolIndexType(0), .offset = ~OffsetType(0),
125                                .length = valueLength};
126            // We keep track of the buffers. We'll allocate the shared memory only
127            // once we know the total size, to avoid needless copies.
128            mLargeOperandValues.push_back(LargeValue{.operandIndex = index, .buffer = buffer});
129        }
130    }
131    return ANEURALNETWORKS_NO_ERROR;
132}
133
134int ModelBuilder::copyLargeValuesToSharedMemory() {
135    VLOG(MODEL) << __func__ << " has " << mLargeOperandValues.size() << " values.";
136    if (!mLargeOperandValues.empty()) {
137        // Calculate the size of the shared memory needed for all the large values.
138        // Also sets the offset for each value within the memory.
139        size_t poolSize = 0;
140        for (LargeValue& l: mLargeOperandValues) {
141            Operand& operand = mOperands[l.operandIndex];
142            nnAssert(operand.lifetime == OperandLifeTime::CONSTANT_REFERENCE);
143            poolSize += alignBytesNeeded(poolSize, operand.location.length);
144            operand.location.offset = poolSize;
145            poolSize += operand.location.length;
146        }
147
148        // Allocated the shared memory.
149        int n = mLargeValueMemory.create(poolSize);
150        if (n != ANEURALNETWORKS_NO_ERROR) {
151            return n;
152        }
153        uint8_t* memoryPointer = nullptr;
154        n = mLargeValueMemory.getPointer(&memoryPointer);
155        if (n != ANEURALNETWORKS_NO_ERROR) {
156            return n;
157        }
158        uint32_t poolIndex = mMemories.add(&mLargeValueMemory);
159        VLOG(MODEL) << "Allocated large value pool of size " << poolSize << " at index "
160                    << poolIndex;
161
162        // Copy the values to this memory.
163        for (LargeValue& l: mLargeOperandValues) {
164            Operand& operand = mOperands[l.operandIndex];
165            operand.location.poolIndex = poolIndex;
166            memcpy(memoryPointer + operand.location.offset, l.buffer, operand.location.length);
167        }
168    }
169    return ANEURALNETWORKS_NO_ERROR;
170}
171
172int ModelBuilder::setOperandValueFromMemory(uint32_t index, const Memory* memory, uint32_t offset,
173                                            size_t length) {
174    VLOG(MODEL) << __func__ << " for operand " << index << " offset " << offset << " size " << length;
175    if (badState("setOperandValueFromMemory")) {
176        return ANEURALNETWORKS_BAD_STATE;
177    }
178
179    if (index >= operandCount()) {
180        LOG(ERROR) << "ANeuralNetworksModel_setOperandValueFromMemory setting operand " << index
181                   << " of " << operandCount();
182        return ANEURALNETWORKS_BAD_DATA;
183    }
184    Operand& operand = mOperands[index];
185    uint32_t neededLength = sizeOfData(operand.type, operand.dimensions);
186    if (neededLength != length) {
187        LOG(ERROR) << "ANeuralNetworksModel_setOperandValueFromMemory setting " << length
188                   << " bytes when needing " << neededLength;
189        return ANEURALNETWORKS_BAD_DATA;
190    }
191    if (!memory->validateSize(offset, length)) {
192        return ANEURALNETWORKS_BAD_DATA;
193    }
194    operand.lifetime = OperandLifeTime::CONSTANT_REFERENCE;
195    operand.location = {
196                .poolIndex = mMemories.add(memory), .offset = offset, .length = neededLength};
197    return ANEURALNETWORKS_NO_ERROR;
198}
199
200int ModelBuilder::addOperation(ANeuralNetworksOperationType type, uint32_t inputCount,
201                               const uint32_t* inputs, uint32_t outputCount,
202                               const uint32_t* outputs) {
203    if (badState("addOperation")) {
204        return ANEURALNETWORKS_BAD_STATE;
205    }
206
207    if (!validCode(kNumberOfOperationTypes, kNumberOfOperationTypesOEM, type)) {
208        LOG(ERROR) << "ANeuralNetworksModel_addOperation invalid operations type " << type;
209        return ANEURALNETWORKS_BAD_DATA;
210    }
211    int n = validateOperation(type, inputCount, inputs,
212                              outputCount, outputs, mOperands);
213    if (n != ANEURALNETWORKS_NO_ERROR) {
214        return n;
215    }
216
217    uint32_t operationIndex = operationCount();
218    if (operationIndex >= MAX_NUMBER_OF_OPERATIONS) {
219        LOG(ERROR) << "ANeuralNetworksModel_addOperation exceed max operations";
220        return ANEURALNETWORKS_BAD_DATA;
221    }
222
223    mOperations.push_back({
224        .type = static_cast<OperationType>(type),
225        .inputs = hidl_vec<uint32_t>(inputs, inputs + inputCount),
226        .outputs = hidl_vec<uint32_t>(outputs, outputs + outputCount),
227    });
228    for (uint32_t i : mOperations.back().inputs) {
229        mOperands[i].numberOfConsumers++;
230    }
231
232    return ANEURALNETWORKS_NO_ERROR;
233}
234
235int ModelBuilder::identifyInputsAndOutputs(uint32_t inputCount, const uint32_t* inputs,
236                                      uint32_t outputCount, const uint32_t* outputs) {
237    if (badState("identifyInputsAndOutputs")) {
238        return ANEURALNETWORKS_BAD_STATE;
239    }
240
241    int n = validateOperandList(inputCount, inputs, operandCount(),
242                                "ANeuralNetworksModel_identifyInputsAndOutputs inputs");
243    if (n != ANEURALNETWORKS_NO_ERROR) {
244        return n;
245    }
246    n = validateOperandList(outputCount, outputs, operandCount(),
247                            "ANeuralNetworksModel_identifyInputsAndOutputs outputs");
248    if (n != ANEURALNETWORKS_NO_ERROR) {
249        return n;
250    }
251
252    // Makes a copy of the index list, validates the arguments, and changes
253    // the lifetime info of the corresponding operand.
254    auto setArguments = [&](std::vector<uint32_t>* indexVector, uint32_t indexCount,
255                            const uint32_t* indexList, OperandLifeTime lifetime) -> bool {
256        indexVector->resize(indexCount);
257        for (uint32_t i = 0; i < indexCount; i++) {
258            const uint32_t operandIndex = indexList[i];
259            if (operandIndex >= mOperands.size()) {
260                LOG(ERROR) << "ANeuralNetworksModel_identifyInputsAndOutputs Can't set input or output "
261                              "to be "
262                           << operandIndex << " as this exceeds the numbe of operands "
263                           << mOperands.size();
264                return false;
265            }
266            (*indexVector)[i] = operandIndex;
267            Operand& operand = mOperands[operandIndex];
268            if (operand.lifetime != OperandLifeTime::TEMPORARY_VARIABLE) {
269                LOG(ERROR) << "ANeuralNetworksModel_identifyInputsAndOutputs Can't set operand "
270                           << operandIndex
271                           << " to be an input or output.  Check that it's not a constant or "
272                              "already an input or output";
273                return false;
274            }
275            operand.lifetime = lifetime;
276        }
277        return true;
278    };
279
280    if (!setArguments(&mInputIndexes, inputCount, inputs, OperandLifeTime::MODEL_INPUT) ||
281        !setArguments(&mOutputIndexes, outputCount, outputs, OperandLifeTime::MODEL_OUTPUT)) {
282        return ANEURALNETWORKS_BAD_DATA;
283    }
284
285    return ANEURALNETWORKS_NO_ERROR;
286}
287
288int ModelBuilder::relaxComputationFloat32toFloat16(bool allow) {
289    if (badState("relaxComputationFloat32toFloat16")) {
290        return ANEURALNETWORKS_BAD_STATE;
291    }
292
293    mRelaxComputationFloat32toFloat16 = allow;
294
295    return ANEURALNETWORKS_NO_ERROR;
296}
297
298int ModelBuilder::createCompilation(CompilationBuilder** compilation) {
299    if (!mCompletedModel || mInvalidModel) {
300        LOG(ERROR) << "ANeuralNetworksCompilation_create passed an unfinished or invalid model";
301        *compilation = nullptr;
302        return ANEURALNETWORKS_BAD_STATE;
303    }
304    *compilation = new (std::nothrow) CompilationBuilder(this);
305    return (*compilation ? ANEURALNETWORKS_NO_ERROR : ANEURALNETWORKS_OUT_OF_MEMORY);
306}
307
308int ModelBuilder::finish() {
309    if (mCompletedModel) {
310        LOG(ERROR) << "ANeuralNetworksModel_finish called more than once";
311        return ANEURALNETWORKS_BAD_STATE;
312    }
313    if (mInvalidModel) {
314        LOG(ERROR) << "ANeuralNetworksModel_finish called on an invalid model";
315        return ANEURALNETWORKS_BAD_STATE;
316    }
317
318    int n = copyLargeValuesToSharedMemory();
319    if (n != ANEURALNETWORKS_NO_ERROR) {
320        return n;
321    }
322
323    // TODO: Modify validation so that it can be called without creating a HAL Model.
324    // NOTE: Must copyLargeValuesToSharedMemory() before validation; otherwise,
325    //       a CONSTANT_REFERENCE operand will not have correct .poolIndex, and
326    //       validation will not work properly.
327    Model modelForValidation;
328    setHidlModel(&modelForValidation);
329    if (!validateModel(modelForValidation)) {
330        LOG(ERROR) << "ANeuralNetworksModel_finish called on invalid model";
331        mInvalidModel = true;
332        return ANEURALNETWORKS_BAD_DATA;
333    }
334
335    // We sort the operations so that they will be in the appropriate
336    // order for a single-threaded, op at a time execution.
337    // TODO: we don't need this if we always run the partitioner.
338    sortIntoRunOrder();
339    mCompletedModel = true;
340    return ANEURALNETWORKS_NO_ERROR;
341}
342
343void ModelBuilder::sortIntoRunOrder() {
344    // Tracks the operations that can be executed.
345    std::vector<uint32_t> opsReadyToRun;
346    std::vector<Operation> runOrder;
347
348    // Tracks how many inputs are needed for each operation to be ready to run.
349    std::multimap<uint32_t, uint32_t> operandToOperations;
350    std::vector<uint32_t> unknownInputCount(operationCount());
351    for (uint32_t operationIndex = 0; operationIndex < operationCount(); operationIndex++) {
352        uint32_t& count = unknownInputCount[operationIndex];
353        count = 0;
354        for (uint32_t operandIndex : mOperations[operationIndex].inputs) {
355            auto lifetime = mOperands[operandIndex].lifetime;
356            if (lifetime == OperandLifeTime::TEMPORARY_VARIABLE ||
357                lifetime == OperandLifeTime::MODEL_OUTPUT) {
358                count++;
359                operandToOperations.insert(
360                            std::pair<uint32_t, uint32_t>(operandIndex, operationIndex));
361            }
362        }
363        if (count == 0) {
364            opsReadyToRun.push_back(operationIndex);
365        }
366    }
367
368    while (opsReadyToRun.size() > 0) {
369        // Execute the next op
370        int opIndex = opsReadyToRun.back();
371        opsReadyToRun.pop_back();
372        const Operation& operation = mOperations[opIndex];
373
374        runOrder.push_back(mOperations[opIndex]);
375
376        // Mark all its outputs as known.
377        for (uint32_t operandIndex : operation.outputs) {
378            auto range = operandToOperations.equal_range(operandIndex);
379            for (auto i = range.first; i != range.second; i++) {
380                uint32_t& count = unknownInputCount[i->second];
381                if (--count == 0) {
382                    opsReadyToRun.push_back(i->second);
383                }
384            }
385        }
386    }
387    mOperations = runOrder;
388}
389
390void ModelBuilder::setHidlModel(Model* model) const {
391    model->operands = mOperands;
392    model->operations = mOperations;
393    model->inputIndexes = mInputIndexes;
394    model->outputIndexes = mOutputIndexes;
395    model->operandValues = mSmallOperandValues;
396    model->relaxComputationFloat32toFloat16 = mRelaxComputationFloat32toFloat16;
397
398    uint32_t count = mMemories.size();
399    model->pools.resize(count);
400    for (uint32_t i = 0; i < count; i++) {
401        model->pools[i] = mMemories[i]->getHidlMemory();
402    }
403}
404
405}  // namespace nn
406}  // namespace android
407