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 "GraphDump.h"
23 #include "Manager.h"
24 #include "TypeManager.h"
25 #include "Utils.h"
26 #include "ValidateHal.h"
27 
28 #include <map>
29 #include <utility>
30 
31 namespace android {
32 namespace nn {
33 
34 // The maximum number of operands and operations that a model may have.
35 const uint32_t MAX_NUMBER_OF_OPERANDS = 0xFFFFFFFE;
36 const uint32_t MAX_NUMBER_OF_OPERATIONS = 0xFFFFFFFE;
37 
badState(const char * name)38 bool ModelBuilder::badState(const char* name) {
39     if (mCompletedModel) {
40         LOG(ERROR) << "ANeuralNetworksModel_" << name << " can't modify after model finished";
41         return true;
42     }
43     if (mInvalidModel) {
44         LOG(ERROR) << "ANeuralNetworksModel_" << name << " can't modify an invalid model";
45         return true;
46     }
47     return false;
48 }
49 
getExtensionType(const char * extensionName,uint16_t typeWithinExtension,int32_t * type)50 int ModelBuilder::getExtensionType(const char* extensionName, uint16_t typeWithinExtension,
51                                    int32_t* type) {
52     return TypeManager::get()->getExtensionType(extensionName, typeWithinExtension, type)
53                    ? ANEURALNETWORKS_NO_ERROR
54                    : ANEURALNETWORKS_BAD_DATA;
55 }
56 
addOperand(const ANeuralNetworksOperandType & type)57 int ModelBuilder::addOperand(const ANeuralNetworksOperandType& type) {
58     if (badState("addOperand")) {
59         return ANEURALNETWORKS_BAD_STATE;
60     }
61 
62     OperandType operandType = static_cast<OperandType>(type.type);
63     if (isExtensionOperandType(operandType) && !TypeManager::get()->areExtensionsAllowed()) {
64         LOG(ERROR) << "Extensions are not supported for this process.";
65         return ANEURALNETWORKS_BAD_DATA;
66     }
67     if (operandType == OperandType::OEM || operandType == OperandType::TENSOR_OEM_BYTE) {
68         LOG(WARNING) << "OEM data type is deprecated. Use Extensions instead.";
69     }
70 
71     const Extension::OperandTypeInformation* info = nullptr;
72     if (isExtensionOperandType(operandType) &&
73         !TypeManager::get()->getExtensionOperandTypeInfo(operandType, &info)) {
74         LOG(ERROR) << "Extension operand type " << toString(operandType) << " is not registered";
75         return ANEURALNETWORKS_BAD_DATA;
76     }
77     NN_RETURN_IF_ERROR(validateOperandType(type, info, "ANeuralNetworksModel_addOperand", true));
78     size_t idx = mOperands.size();
79     if (idx >= MAX_NUMBER_OF_OPERANDS) {
80         LOG(ERROR) << "ANeuralNetworksModel_addOperand exceed max operands";
81         return ANEURALNETWORKS_BAD_DATA;
82     }
83 
84     mOperands.push_back({
85             .type = operandType,
86             .dimensions =
87                     hidl_vec<uint32_t>(type.dimensions, type.dimensions + type.dimensionCount),
88             .numberOfConsumers = 0,
89             .scale = type.scale,
90             .zeroPoint = type.zeroPoint,
91             .lifetime = OperandLifeTime::TEMPORARY_VARIABLE,
92             .location = {.poolIndex = 0, .offset = 0, .length = 0},
93             .extraParams = Operand::ExtraParams(),
94     });
95     return ANEURALNETWORKS_NO_ERROR;
96 }
97 
setOperandValue(uint32_t index,const void * buffer,size_t length)98 int ModelBuilder::setOperandValue(uint32_t index, const void* buffer, size_t length) {
99     VLOG(MODEL) << __func__ << " for operand " << index << " size " << length;
100     if (badState("setOperandValue")) {
101         return ANEURALNETWORKS_BAD_STATE;
102     }
103 
104     if (index >= operandCount()) {
105         LOG(ERROR) << "ANeuralNetworksModel_setOperandValue setting operand " << index << " of "
106                    << operandCount();
107         return ANEURALNETWORKS_BAD_DATA;
108     }
109     Operand& operand = mOperands[index];
110     if (buffer == nullptr) {
111         if (length) {
112             LOG(ERROR) << "ANeuralNetworksModel_setOperandValue buffer is nullptr but length is "
113                           "not 0";
114             return ANEURALNETWORKS_BAD_DATA;
115         }
116         operand.lifetime = OperandLifeTime::NO_VALUE;
117         // The location is unused and is set to zeros.
118         operand.location = {.poolIndex = 0, .offset = 0, .length = 0};
119     } else {
120         if (TypeManager::get()->isTensorType(operand.type) &&
121             tensorHasUnspecifiedDimensions(operand)) {
122             LOG(ERROR) << "ANeuralNetworksModel_setOperandValue setting operand " << index
123                        << " which has operand type that is not fully specified";
124             return ANEURALNETWORKS_BAD_DATA;
125         }
126         if (length > 0xFFFFFFFF) {
127             LOG(ERROR) << "ANeuralNetworksModel_setOperandValue value length of " << length
128                        << " exceeds max size";
129             return ANEURALNETWORKS_BAD_DATA;
130         }
131         uint32_t valueLength = static_cast<uint32_t>(length);
132         if (operand.type != OperandType::OEM) {
133             uint32_t neededLength = TypeManager::get()->getSizeOfData(operand);
134             if (neededLength != valueLength) {
135                 LOG(ERROR) << "ANeuralNetworksModel_setOperandValue setting " << valueLength
136                            << " bytes when needing " << neededLength;
137                 return ANEURALNETWORKS_BAD_DATA;
138             }
139         }
140         if (valueLength <= ANEURALNETWORKS_MAX_SIZE_OF_IMMEDIATELY_COPIED_VALUES) {
141             uint32_t existingSize = static_cast<uint32_t>(mSmallOperandValues.size());
142             uint32_t extraBytes = alignBytesNeeded(existingSize, valueLength);
143             mSmallOperandValues.resize(existingSize + extraBytes + valueLength);
144             operand.lifetime = OperandLifeTime::CONSTANT_COPY;
145             operand.location = {
146                     .poolIndex = 0, .offset = existingSize + extraBytes, .length = valueLength};
147             memcpy(&mSmallOperandValues[operand.location.offset], buffer, valueLength);
148             VLOG(MODEL) << "Copied small value to offset " << operand.location.offset;
149         } else {
150             VLOG(MODEL) << "Saving large value";
151             operand.lifetime = OperandLifeTime::CONSTANT_REFERENCE;
152             // The values for poolIndex and offset will be set when the model is finished.
153             typedef decltype(operand.location.poolIndex) PoolIndexType;
154             typedef decltype(operand.location.offset) OffsetType;
155             operand.location = {.poolIndex = ~PoolIndexType(0),
156                                 .offset = ~OffsetType(0),
157                                 .length = valueLength};
158             // We keep track of the buffers. We'll allocate the shared memory only
159             // once we know the total size, to avoid needless copies.
160             mLargeOperandValues.push_back(LargeValue{.operandIndex = index, .buffer = buffer});
161         }
162     }
163     return ANEURALNETWORKS_NO_ERROR;
164 }
165 
setOperandSymmPerChannelQuantParams(uint32_t index,const ANeuralNetworksSymmPerChannelQuantParams & channelQuant)166 int ModelBuilder::setOperandSymmPerChannelQuantParams(
167         uint32_t index, const ANeuralNetworksSymmPerChannelQuantParams& channelQuant) {
168     if (badState("setOperandSymmPerChannelQuantParams")) {
169         return ANEURALNETWORKS_BAD_STATE;
170     }
171 
172     if (index >= operandCount()) {
173         LOG(ERROR) << "ANeuralNetworksModel_setOperandSymmPerChannelQuantParams "
174                    << "setting per-channel quantization parameters for operand " << index << " of "
175                    << operandCount();
176         return ANEURALNETWORKS_BAD_DATA;
177     }
178     Operand& operand = mOperands[index];
179 
180     if (!validateOperandSymmPerChannelQuantParams(
181                 operand, channelQuant,
182                 "ANeuralNetworksModel_setOperandSymmPerChannelQuantParams")) {
183         return ANEURALNETWORKS_BAD_DATA;
184     }
185     switch (operand.type) {
186         case OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL:
187             operand.extraParams.channelQuant({
188                     .scales = hidl_vec<float>(channelQuant.scales,
189                                               channelQuant.scales + channelQuant.scaleCount),
190                     .channelDim = channelQuant.channelDim,
191             });
192             break;
193         default:
194             LOG(ERROR) << "ANeuralNetworksModel_setOperandSymmPerChannelQuantParams "
195                        << "invalid operand type " << static_cast<int32_t>(operand.type);
196             return ANEURALNETWORKS_BAD_DATA;
197     }
198     return ANEURALNETWORKS_NO_ERROR;
199 }
200 
setOperandExtensionData(uint32_t index,const void * data,size_t length)201 int ModelBuilder::setOperandExtensionData(uint32_t index, const void* data, size_t length) {
202     if (badState("setOperandExtensionData")) {
203         return ANEURALNETWORKS_BAD_STATE;
204     }
205 
206     if (index >= operandCount()) {
207         LOG(ERROR) << "ANeuralNetworksModel_setOperandExtensionData "
208                    << "setting extension data for operand " << index << " of " << operandCount();
209         return ANEURALNETWORKS_BAD_DATA;
210     }
211     Operand& operand = mOperands[index];
212 
213     if (data == nullptr && length != 0) {
214         LOG(ERROR) << "ANeuralNetworksModel_setOperandExtensionData data is nullptr but length is "
215                    << length;
216         return ANEURALNETWORKS_BAD_DATA;
217     }
218     if (data != nullptr && length == 0) {
219         LOG(ERROR) << "ANeuralNetworksModel_setOperandExtensionData data is not nullptr but length "
220                    << "is zero";
221         return ANEURALNETWORKS_BAD_DATA;
222     }
223     if (!isExtensionOperandType(operand.type)) {
224         LOG(ERROR) << "ANeuralNetworksModel_setOperandExtensionData "
225                    << "setting extension data for a base operand type "
226                    << static_cast<int32_t>(operand.type);
227         return ANEURALNETWORKS_BAD_DATA;
228     }
229 
230     if (data == nullptr) {
231         operand.extraParams.none();
232     } else {
233         operand.extraParams.extension(
234                 hidl_vec<uint8_t>(reinterpret_cast<const uint8_t*>(data),
235                                   reinterpret_cast<const uint8_t*>(data) + length));
236     }
237     return ANEURALNETWORKS_NO_ERROR;
238 }
239 
copyLargeValuesToSharedMemory()240 int ModelBuilder::copyLargeValuesToSharedMemory() {
241     VLOG(MODEL) << __func__ << " has " << mLargeOperandValues.size() << " values.";
242     if (!mLargeOperandValues.empty()) {
243         // Calculate the size of the shared memory needed for all the large values.
244         // Also sets the offset for each value within the memory.
245         size_t poolSize = 0;
246         for (LargeValue& l : mLargeOperandValues) {
247             Operand& operand = mOperands[l.operandIndex];
248             nnAssert(operand.lifetime == OperandLifeTime::CONSTANT_REFERENCE);
249             poolSize += alignBytesNeeded(poolSize, operand.location.length);
250             operand.location.offset = poolSize;
251             poolSize += operand.location.length;
252         }
253 
254         // Allocated the shared memory.
255         int n = mLargeValueMemory.create(poolSize);
256         if (n != ANEURALNETWORKS_NO_ERROR) {
257             return n;
258         }
259         uint8_t* memoryPointer = nullptr;
260         n = mLargeValueMemory.getPointer(&memoryPointer);
261         if (n != ANEURALNETWORKS_NO_ERROR) {
262             return n;
263         }
264         uint32_t poolIndex = mMemories.add(&mLargeValueMemory);
265         VLOG(MODEL) << "Allocated large value pool of size " << poolSize << " at index "
266                     << poolIndex;
267 
268         // Copy the values to this memory.
269         for (LargeValue& l : mLargeOperandValues) {
270             Operand& operand = mOperands[l.operandIndex];
271             operand.location.poolIndex = poolIndex;
272             memcpy(memoryPointer + operand.location.offset, l.buffer, operand.location.length);
273         }
274     }
275     return ANEURALNETWORKS_NO_ERROR;
276 }
277 
setOperandValueFromMemory(uint32_t index,const Memory * memory,uint32_t offset,size_t length)278 int ModelBuilder::setOperandValueFromMemory(uint32_t index, const Memory* memory, uint32_t offset,
279                                             size_t length) {
280     VLOG(MODEL) << __func__ << " for operand " << index << " offset " << offset << " size "
281                 << length;
282     if (badState("setOperandValueFromMemory")) {
283         return ANEURALNETWORKS_BAD_STATE;
284     }
285 
286     if (index >= operandCount()) {
287         LOG(ERROR) << "ANeuralNetworksModel_setOperandValueFromMemory setting operand " << index
288                    << " of " << operandCount();
289         return ANEURALNETWORKS_BAD_DATA;
290     }
291     Operand& operand = mOperands[index];
292     if (TypeManager::get()->isTensorType(operand.type) && tensorHasUnspecifiedDimensions(operand)) {
293         LOG(ERROR) << "ANeuralNetworksModel_setOperandValueFromMemory setting operand " << index
294                    << " which has operand type that is not fully specified";
295         return ANEURALNETWORKS_BAD_DATA;
296     }
297     // Only BLOB format AHardwareBuffer can be used for constant data.
298     if (memory->getHidlMemory().name() == "hardware_buffer") {
299         LOG(ERROR) << "ANeuralNetworksModel_setOperandValueFromMemory passed an AHardwareBuffer"
300                    << " that is not in AHARDWAREBUFFER_FORMAT_BLOB format";
301         return ANEURALNETWORKS_UNMAPPABLE;
302     }
303     uint32_t neededLength = TypeManager::get()->getSizeOfData(operand);
304     if (neededLength != length) {
305         LOG(ERROR) << "ANeuralNetworksModel_setOperandValueFromMemory setting " << length
306                    << " bytes when needing " << neededLength;
307         return ANEURALNETWORKS_BAD_DATA;
308     }
309     if (!memory->validateSize(offset, length)) {
310         return ANEURALNETWORKS_BAD_DATA;
311     }
312     operand.lifetime = OperandLifeTime::CONSTANT_REFERENCE;
313     operand.location = {.poolIndex = mMemories.add(memory),
314                         .offset = offset,
315                         .length = static_cast<uint32_t>(length)};
316     return ANEURALNETWORKS_NO_ERROR;
317 }
318 
addOperation(ANeuralNetworksOperationType type,uint32_t inputCount,const uint32_t * inputs,uint32_t outputCount,const uint32_t * outputs)319 int ModelBuilder::addOperation(ANeuralNetworksOperationType type, uint32_t inputCount,
320                                const uint32_t* inputs, uint32_t outputCount,
321                                const uint32_t* outputs) {
322     if (badState("addOperation")) {
323         return ANEURALNETWORKS_BAD_STATE;
324     }
325 
326     OperationType operationType = static_cast<OperationType>(type);
327     if (isExtensionOperationType(operationType) && !TypeManager::get()->areExtensionsAllowed()) {
328         LOG(ERROR) << "Extensions are not supported for this process.";
329         return ANEURALNETWORKS_BAD_DATA;
330     }
331     if (operationType == OperationType::OEM_OPERATION) {
332         LOG(WARNING) << "OEM_OPERATION is deprecated. Use Extensions instead.";
333     }
334 
335     if (!isExtensionOperationType(operationType)) {
336         if (!validCode(kNumberOfOperationTypes, kNumberOfOperationTypesOEM, type)) {
337             LOG(ERROR) << "ANeuralNetworksModel_addOperation invalid operation type " << type;
338             return ANEURALNETWORKS_BAD_DATA;
339         }
340     }
341     NN_RETURN_IF_ERROR(validateOperation(type, inputCount, inputs, outputCount, outputs, mOperands,
342                                          HalVersion::LATEST));
343 
344     uint32_t operationIndex = operationCount();
345     if (operationIndex >= MAX_NUMBER_OF_OPERATIONS) {
346         LOG(ERROR) << "ANeuralNetworksModel_addOperation exceed max operations";
347         return ANEURALNETWORKS_BAD_DATA;
348     }
349 
350     mOperations.push_back({
351             .type = operationType,
352             .inputs = hidl_vec<uint32_t>(inputs, inputs + inputCount),
353             .outputs = hidl_vec<uint32_t>(outputs, outputs + outputCount),
354     });
355     for (uint32_t i : mOperations.back().inputs) {
356         mOperands[i].numberOfConsumers++;
357     }
358     mHasOEMOperation |= (operationType == OperationType::OEM_OPERATION);
359     mHasExtensionOperation |= isExtensionOperationType(operationType);
360 
361     return ANEURALNETWORKS_NO_ERROR;
362 }
363 
identifyInputsAndOutputs(uint32_t inputCount,const uint32_t * inputs,uint32_t outputCount,const uint32_t * outputs)364 int ModelBuilder::identifyInputsAndOutputs(uint32_t inputCount, const uint32_t* inputs,
365                                            uint32_t outputCount, const uint32_t* outputs) {
366     if (badState("identifyInputsAndOutputs")) {
367         return ANEURALNETWORKS_BAD_STATE;
368     }
369 
370     int n = validateOperandList(inputCount, inputs, operandCount(),
371                                 "ANeuralNetworksModel_identifyInputsAndOutputs inputs");
372     if (n != ANEURALNETWORKS_NO_ERROR) {
373         return n;
374     }
375     n = validateOperandList(outputCount, outputs, operandCount(),
376                             "ANeuralNetworksModel_identifyInputsAndOutputs outputs");
377     if (n != ANEURALNETWORKS_NO_ERROR) {
378         return n;
379     }
380 
381     // Makes a copy of the index list, validates the arguments, and changes
382     // the lifetime info of the corresponding operand.
383     auto setArguments = [&](std::vector<uint32_t>* indexVector, uint32_t indexCount,
384                             const uint32_t* indexList, OperandLifeTime lifetime) -> bool {
385         indexVector->resize(indexCount);
386         for (uint32_t i = 0; i < indexCount; i++) {
387             const uint32_t operandIndex = indexList[i];
388             if (operandIndex >= mOperands.size()) {
389                 LOG(ERROR) << "ANeuralNetworksModel_identifyInputsAndOutputs Can't set input or "
390                               "output "
391                               "to be "
392                            << operandIndex << " as this exceeds the numbe of operands "
393                            << mOperands.size();
394                 return false;
395             }
396             (*indexVector)[i] = operandIndex;
397             Operand& operand = mOperands[operandIndex];
398             if (operand.lifetime != OperandLifeTime::TEMPORARY_VARIABLE) {
399                 LOG(ERROR) << "ANeuralNetworksModel_identifyInputsAndOutputs Can't set operand "
400                            << operandIndex
401                            << " to be an input or output.  Check that it's not a constant or "
402                               "already an input or output";
403                 return false;
404             }
405             operand.lifetime = lifetime;
406         }
407         return true;
408     };
409 
410     if (!setArguments(&mInputIndexes, inputCount, inputs, OperandLifeTime::MODEL_INPUT) ||
411         !setArguments(&mOutputIndexes, outputCount, outputs, OperandLifeTime::MODEL_OUTPUT)) {
412         return ANEURALNETWORKS_BAD_DATA;
413     }
414 
415     return ANEURALNETWORKS_NO_ERROR;
416 }
417 
relaxComputationFloat32toFloat16(bool allow)418 int ModelBuilder::relaxComputationFloat32toFloat16(bool allow) {
419     if (badState("relaxComputationFloat32toFloat16")) {
420         return ANEURALNETWORKS_BAD_STATE;
421     }
422 
423     mRelaxComputationFloat32toFloat16 = allow;
424 
425     return ANEURALNETWORKS_NO_ERROR;
426 }
427 
createCompilation(CompilationBuilder ** compilation,const std::vector<std::shared_ptr<Device>> & devices,bool explicitDeviceList)428 int ModelBuilder::createCompilation(CompilationBuilder** compilation,
429                                     const std::vector<std::shared_ptr<Device>>& devices,
430                                     bool explicitDeviceList) {
431     if (!mCompletedModel || mInvalidModel) {
432         LOG(ERROR) << "ANeuralNetworksCompilation_create passed an unfinished or invalid model";
433         *compilation = nullptr;
434         return ANEURALNETWORKS_BAD_STATE;
435     }
436     *compilation = new (std::nothrow) CompilationBuilder(this, devices, explicitDeviceList);
437     return (*compilation ? ANEURALNETWORKS_NO_ERROR : ANEURALNETWORKS_OUT_OF_MEMORY);
438 }
439 
finish()440 int ModelBuilder::finish() {
441     if (mCompletedModel) {
442         LOG(ERROR) << "ANeuralNetworksModel_finish called more than once";
443         return ANEURALNETWORKS_BAD_STATE;
444     }
445     if (mInvalidModel) {
446         LOG(ERROR) << "ANeuralNetworksModel_finish called on an invalid model";
447         return ANEURALNETWORKS_BAD_STATE;
448     }
449 
450     int n = copyLargeValuesToSharedMemory();
451     if (n != ANEURALNETWORKS_NO_ERROR) {
452         return n;
453     }
454 
455     // TODO: Modify validation so that it can be called without creating a HAL Model.
456     // NOTE: Must copyLargeValuesToSharedMemory() before validation; otherwise,
457     //       a CONSTANT_REFERENCE operand will not have correct .poolIndex, and
458     //       validation will not work properly.
459     Model modelForValidation;
460     setHidlModel(&modelForValidation);
461     if (!validateModel(modelForValidation)) {
462         LOG(ERROR) << "ANeuralNetworksModel_finish called on invalid model";
463         mInvalidModel = true;
464         return ANEURALNETWORKS_BAD_DATA;
465     }
466     if (VLOG_IS_ON(MODEL)) {
467         graphDump("ModelBuilder::finish", modelForValidation, nullptr);
468     }
469 
470     // We sort the operations so that they will be in the appropriate
471     // order for a single-threaded, op at a time execution.
472     // TODO: we don't need this if we always run the partitioner.
473     sortIntoRunOrder();
474     mCompletedModel = true;
475     return ANEURALNETWORKS_NO_ERROR;
476 }
477 
sortIntoRunOrder()478 void ModelBuilder::sortIntoRunOrder() {
479     if (!mSortedOperationIndexMap.empty()) {
480         LOG(ERROR) << "Operations already in run order.";
481         return;
482     }
483     // Tracks the operations that can be executed.
484     std::vector<uint32_t> opsReadyToRun;
485     std::vector<Operation> runOrder;
486 
487     // Tracks how many inputs are needed for each operation to be ready to run.
488     std::multimap<uint32_t, uint32_t> operandToOperations;
489     std::vector<uint32_t> unknownInputCount(operationCount());
490     for (uint32_t operationIndex = 0; operationIndex < operationCount(); operationIndex++) {
491         uint32_t& count = unknownInputCount[operationIndex];
492         count = 0;
493         for (uint32_t operandIndex : mOperations[operationIndex].inputs) {
494             auto lifetime = mOperands[operandIndex].lifetime;
495             if (lifetime == OperandLifeTime::TEMPORARY_VARIABLE ||
496                 lifetime == OperandLifeTime::MODEL_OUTPUT) {
497                 count++;
498                 operandToOperations.insert(
499                         std::pair<uint32_t, uint32_t>(operandIndex, operationIndex));
500             }
501         }
502         if (count == 0) {
503             opsReadyToRun.push_back(operationIndex);
504         }
505     }
506 
507     while (opsReadyToRun.size() > 0) {
508         // Execute the next op
509         int opIndex = opsReadyToRun.back();
510         opsReadyToRun.pop_back();
511         const Operation& operation = mOperations[opIndex];
512 
513         runOrder.push_back(mOperations[opIndex]);
514         mSortedOperationIndexMap.push_back(opIndex);
515 
516         // Mark all its outputs as known.
517         for (uint32_t operandIndex : operation.outputs) {
518             auto range = operandToOperations.equal_range(operandIndex);
519             for (auto i = range.first; i != range.second; i++) {
520                 uint32_t& count = unknownInputCount[i->second];
521                 if (--count == 0) {
522                     opsReadyToRun.push_back(i->second);
523                 }
524             }
525         }
526     }
527     mOperations = runOrder;
528 }
529 
setHidlModel(Model * model) const530 void ModelBuilder::setHidlModel(Model* model) const {
531     model->operands = mOperands;
532     model->operations = mOperations;
533     model->inputIndexes = mInputIndexes;
534     model->outputIndexes = mOutputIndexes;
535     model->operandValues = mSmallOperandValues;
536     model->relaxComputationFloat32toFloat16 = mRelaxComputationFloat32toFloat16;
537     model->extensionNameToPrefix = getExtensionNameToPrefixMap();
538 
539     uint32_t count = mMemories.size();
540     model->pools.resize(count);
541     for (uint32_t i = 0; i < count; i++) {
542         model->pools[i] = mMemories[i]->getHidlMemory();
543     }
544 }
545 
getExtensionNameToPrefixMap() const546 std::vector<Model::ExtensionNameAndPrefix> ModelBuilder::getExtensionNameToPrefixMap() const {
547     std::vector<Model::ExtensionNameAndPrefix> extensionNameToPrefix;
548     std::set<uint16_t> prefixSet;
549 
550     auto addExtensionWithPrefix = [&extensionNameToPrefix, &prefixSet](uint16_t prefix) {
551         if (!prefixSet.insert(prefix).second) {
552             return;
553         }
554         const Extension* extension;
555         CHECK(TypeManager::get()->getExtensionInfo(prefix, &extension));
556         extensionNameToPrefix.push_back({
557                 .name = extension->name,
558                 .prefix = prefix,
559         });
560     };
561 
562     constexpr uint8_t kLowBitsType =
563             static_cast<uint8_t>(Model::ExtensionTypeEncoding::LOW_BITS_TYPE);
564     for (const auto& operand : mOperands) {
565         if (isExtensionOperandType(operand.type)) {
566             addExtensionWithPrefix(static_cast<uint32_t>(operand.type) >> kLowBitsType);
567         }
568     }
569     for (const auto& operation : mOperations) {
570         if (isExtensionOperationType(operation.type)) {
571             addExtensionWithPrefix(static_cast<uint32_t>(operation.type) >> kLowBitsType);
572         }
573     }
574     return extensionNameToPrefix;
575 }
576 
577 }  // namespace nn
578 }  // namespace android
579