• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "nnrt_device_service.h"
17 
18 #include <hdf_base.h>
19 #include "utils/hdf_log.h"
20 #include "ashmem.h"
21 #include "securec.h"
22 
23 #include "node_registry.h"
24 #include "prepared_model_service.h"
25 #include "shared_buffer_parser.h"
26 #include "validation.h"
27 
28 namespace OHOS {
29 namespace HDI {
30 namespace Nnrt {
31 namespace V1_0 {
NnrtDeviceImplGetInstance(void)32 extern "C" INnrtDevice *NnrtDeviceImplGetInstance(void)
33 {
34     return new (std::nothrow) NnrtDeviceService();
35 }
36 
~NnrtDeviceService()37 NnrtDeviceService::~NnrtDeviceService()
38 {
39     for (auto ash : m_ashmems) {
40         ash.second->UnmapAshmem();
41         ash.second->CloseAshmem();
42     }
43 }
44 
GetDeviceName(std::string & name)45 int32_t NnrtDeviceService::GetDeviceName(std::string& name)
46 {
47     name = "RK3568-CPU";
48     return HDF_SUCCESS;
49 }
50 
GetVendorName(std::string & name)51 int32_t NnrtDeviceService::GetVendorName(std::string& name)
52 {
53     name = "Rockchip";
54     return HDF_SUCCESS;
55 }
56 
GetDeviceType(DeviceType & deviceType)57 int32_t NnrtDeviceService::GetDeviceType(DeviceType& deviceType)
58 {
59     deviceType = DeviceType::CPU;
60     return HDF_SUCCESS;
61 }
62 
GetDeviceStatus(DeviceStatus & status)63 int32_t NnrtDeviceService::GetDeviceStatus(DeviceStatus& status)
64 {
65     status = DeviceStatus::AVAILABLE;
66     return HDF_SUCCESS;
67 }
68 
GetSupportedOperation(const Model & model,std::vector<bool> & ops)69 int32_t NnrtDeviceService::GetSupportedOperation(const Model& model, std::vector<bool>& ops)
70 {
71     size_t nodeSize = model.nodes.size();
72     auto nodes = model.nodes;
73     ops.resize(nodeSize, false);
74     auto& regInstance = NodeRegistry::GetSingleton();
75     for (size_t i = 0; i < nodeSize; i++) {
76         ops[i] = regInstance.IsNodeTypeExist(nodes[i].nodeType);
77     }
78     return HDF_SUCCESS;
79 }
80 
IsFloat16PrecisionSupported(bool & isSupported)81 int32_t NnrtDeviceService::IsFloat16PrecisionSupported(bool& isSupported)
82 {
83     isSupported = true;
84     return HDF_SUCCESS;
85 }
86 
IsPerformanceModeSupported(bool & isSupported)87 int32_t NnrtDeviceService::IsPerformanceModeSupported(bool& isSupported)
88 {
89     isSupported = true;
90     return HDF_SUCCESS;
91 }
92 
IsPrioritySupported(bool & isSupported)93 int32_t NnrtDeviceService::IsPrioritySupported(bool& isSupported)
94 {
95     isSupported = false;
96     return HDF_SUCCESS;
97 }
98 
IsDynamicInputSupported(bool & isSupported)99 int32_t NnrtDeviceService::IsDynamicInputSupported(bool& isSupported)
100 {
101     isSupported = true;
102     return HDF_SUCCESS;
103 }
104 
PrepareModel(const Model & model,const ModelConfig & config,sptr<IPreparedModel> & preparedModel)105 int32_t NnrtDeviceService::PrepareModel(const Model& model, const ModelConfig& config,
106     sptr<IPreparedModel>& preparedModel)
107 {
108     auto ret = ValidateModel(model);
109     if (ret != HDF_SUCCESS) {
110         HDF_LOGE("Model is invalid.");
111         return ret;
112     }
113 
114     auto graph = TransModelToGraph(model);
115     if (graph == nullptr) {
116         HDF_LOGE("Transfrom model to graph failed.");
117         return HDF_ERR_INVALID_PARAM;
118     }
119 
120     ret = ValidateModelConfig(config);
121     if (ret != HDF_SUCCESS) {
122         HDF_LOGE("ModelConfig is invalid.");
123         return ret;
124     }
125 
126     auto context = TransModelConfig(config);
127     sptr<PreparedModelService> service = new (std::nothrow) PreparedModelService(context);
128     if (service == nullptr) {
129         HDF_LOGE("Create new PreparedModelService instance failed.");
130         return HDF_ERR_MALLOC_FAIL;
131     }
132 
133     ret = service->Compile(graph);
134     if (ret != HDF_SUCCESS) {
135         HDF_LOGE("Prepared model failed.");
136         return ret;
137     }
138 
139     preparedModel = service;
140     return HDF_SUCCESS;
141 }
142 
IsModelCacheSupported(bool & isSupported)143 int32_t NnrtDeviceService::IsModelCacheSupported(bool& isSupported)
144 {
145     isSupported = true;
146     return HDF_SUCCESS;
147 }
148 
PrepareModelFromModelCache(const std::vector<SharedBuffer> & modelCache,const ModelConfig & config,sptr<IPreparedModel> & preparedModel)149 int32_t NnrtDeviceService::PrepareModelFromModelCache(const std::vector<SharedBuffer>& modelCache,
150     const ModelConfig& config, sptr<IPreparedModel>& preparedModel)
151 {
152     HDF_LOGD("Using cache to prepare model.");
153 
154     // modelCache must be 1, because PreparedModel only export one cache file.
155     if (modelCache.size() != 1) {
156         HDF_LOGE("The size of modelCache vector is not valid, it should be one elememt in that vector.");
157         return HDF_ERR_INVALID_PARAM;
158     }
159 
160     SharedBufferParser parser;
161     auto ret = parser.Init(modelCache[0]);
162     if (ret != HDF_SUCCESS) {
163         HDF_LOGE("Parse modle buffer failed.");
164         return HDF_ERR_INVALID_PARAM;
165     }
166 
167     void* modelBuffer = parser.GetBufferPtr();
168     auto context = TransModelConfig(config);
169     sptr<PreparedModelService> service = new (std::nothrow) PreparedModelService(context);
170     if (service == nullptr) {
171         HDF_LOGE("Create new instance PreparedModelService failed.");
172         return HDF_ERR_MALLOC_FAIL;
173     }
174 
175     ret = service->Compile(modelBuffer, modelCache[0].dataSize);
176     if (ret != HDF_SUCCESS) {
177         HDF_LOGE("Prepared model failed.");
178         return ret;
179     }
180 
181     preparedModel = service;
182     return HDF_SUCCESS;
183 }
184 
AllocateBuffer(uint32_t length,SharedBuffer & buffer)185 int32_t NnrtDeviceService::AllocateBuffer(uint32_t length, SharedBuffer& buffer)
186 {
187     sptr<Ashmem> ashptr = Ashmem::CreateAshmem("allocateBuffer", length);
188     if (ashptr == nullptr) {
189         HDF_LOGE("Create shared memory failed.");
190         return HDF_FAILURE;
191     }
192 
193     if (!ashptr->MapReadAndWriteAshmem()) {
194         HDF_LOGE("Map allocate buffer failed.");
195         return HDF_FAILURE;
196     }
197 
198     buffer.fd = ashptr->GetAshmemFd();
199     buffer.bufferSize = ashptr->GetAshmemSize();
200     buffer.offset = 0;
201     buffer.dataSize = length;
202 
203     m_ashmems[buffer.fd] = ashptr;
204     return HDF_SUCCESS;
205 }
206 
ReleaseBuffer(const SharedBuffer & buffer)207 int32_t NnrtDeviceService::ReleaseBuffer(const SharedBuffer& buffer)
208 {
209     // parser will close current fd.
210     SharedBufferParser parser;
211     auto ret = parser.Init(buffer);
212     if (ret != HDF_SUCCESS) {
213         HDF_LOGE("Parse buffer failed.");
214         return HDF_ERR_INVALID_PARAM;
215     }
216 
217     for (auto& ash : m_ashmems) {
218         ash.second->UnmapAshmem();
219         ash.second->CloseAshmem();
220     }
221     m_ashmems.clear();
222     return HDF_SUCCESS;
223 }
224 
ValidateModelConfig(const ModelConfig & config) const225 int32_t NnrtDeviceService::ValidateModelConfig(const ModelConfig& config) const
226 {
227     if (!ValidatePerformanceMode(config.mode)) {
228         HDF_LOGE("PerformanceMode is invalid. mode=%d", config.mode);
229         return HDF_ERR_INVALID_PARAM;
230     }
231 
232     if (!ValidatePriority(config.priority)) {
233         HDF_LOGE("Priority is invalid. priority=%d", config.priority);
234         return HDF_ERR_INVALID_PARAM;
235     }
236 
237     return HDF_SUCCESS;
238 }
239 
ValidateModel(const Model & model) const240 int32_t NnrtDeviceService::ValidateModel(const Model& model) const
241 {
242     if (model.allTensors.empty()) {
243         HDF_LOGE("Model has no tensors.");
244         return HDF_ERR_INVALID_PARAM;
245     }
246 
247     if (model.subGraph.empty()) {
248         HDF_LOGE("Model has no subGraphs.");
249         return HDF_ERR_INVALID_PARAM;
250     }
251 
252     if (model.nodes.empty()) {
253         HDF_LOGE("Model has no nodes.");
254         return HDF_ERR_INVALID_PARAM;
255     }
256 
257     if (model.inputIndex.empty()) {
258         HDF_LOGE("Model has no input.");
259         return HDF_ERR_INVALID_PARAM;
260     }
261 
262     if (model.outputIndex.empty()) {
263         HDF_LOGE("Model has no output.");
264         return HDF_ERR_INVALID_PARAM;
265     }
266 
267     size_t tensorSize = model.allTensors.size();
268     for (auto index : model.inputIndex) {
269         if (index > tensorSize) {
270             HDF_LOGE("Input index is invalid, index=%u", index);
271             return HDF_ERR_INVALID_PARAM;
272         }
273     }
274 
275     for (auto index : model.outputIndex) {
276         if (index > tensorSize) {
277             HDF_LOGE("Output index is invalid, index=%u", index);
278             return HDF_ERR_INVALID_PARAM;
279         }
280     }
281 
282     return HDF_SUCCESS;
283 }
284 
TransModelToGraph(const Model & model) const285 std::shared_ptr<mindspore::schema::MetaGraphT> NnrtDeviceService::TransModelToGraph(const Model& model) const
286 {
287     auto metaGraph = std::make_shared<mindspore::schema::MetaGraphT>();
288     metaGraph->name = model.name;
289     metaGraph->version = mindspore::Version();
290 
291     std::unique_ptr<mindspore::schema::TensorT> transTensor{nullptr};
292     for (auto tensor : model.allTensors) {
293         transTensor = TransTensor(tensor);
294         if (transTensor == nullptr) {
295             HDF_LOGE("Transform tensor failed.");
296             return nullptr;
297         }
298         metaGraph->allTensors.emplace_back(std::move(transTensor));
299     }
300     metaGraph->inputIndex = model.inputIndex;
301     metaGraph->outputIndex = model.outputIndex;
302 
303     // Transform node
304     std::unique_ptr<mindspore::schema::CNodeT> transNode {nullptr};
305     for (auto& node : model.nodes) {
306         transNode = TransNode(node);
307         if (transNode == nullptr) {
308             HDF_LOGE("Transform node failed, node name=%{public}s", node.name.c_str());
309             return nullptr;
310         }
311         metaGraph->nodes.emplace_back(std::move(transNode));
312     }
313 
314     // Transform subgraph
315     const size_t numTensor = model.allTensors.size();
316     for (auto graph : model.subGraph) {
317         metaGraph->subGraph.emplace_back(TransSubGraph(graph, numTensor));
318     }
319     return metaGraph;
320 }
321 
TransTensor(const Tensor & tensor) const322 std::unique_ptr<mindspore::schema::TensorT> NnrtDeviceService::TransTensor(const Tensor& tensor) const
323 {
324     if (!ValidateDataType(tensor.dataType)) {
325         HDF_LOGE("DataType of tensor is invalid. dataType=%d", tensor.dataType);
326         return nullptr;
327     }
328 
329     if (!ValidateFormat(tensor.format)) {
330         HDF_LOGE("Format of tensor is invalid. format=%d", tensor.format);
331         return nullptr;
332     }
333 
334     auto schemaTensor = std::make_unique<mindspore::schema::TensorT>();
335     schemaTensor->name = tensor.name;
336     schemaTensor->dataType = static_cast<int32_t>(tensor.dataType);
337     schemaTensor->format = static_cast<mindspore::schema::Format>(tensor.format);
338     schemaTensor->dims = tensor.dims;
339     for (auto param : tensor.quantParams) {
340         auto quantParam = std::make_unique<mindspore::schema::QuantParamT>();
341         quantParam->scale = param.scale;
342         quantParam->zeroPoint = param.zeroPoint;
343         quantParam->numBits = param.numBits;
344         quantParam->inited = true;
345         schemaTensor->quantParams.emplace_back(std::move(quantParam));
346     }
347 
348     if (tensor.data.fd != INVALID_FD) {
349         SharedBufferParser parser;
350         auto ret = parser.Init(tensor.data);
351         if (ret != HDF_SUCCESS) {
352             HDF_LOGE("Parse tensor data failed.");
353             return nullptr;
354         }
355 
356         auto data = parser.GetBufferPtr();
357         schemaTensor->data.resize(tensor.data.dataSize);
358         auto memRet = memcpy_s(const_cast<uint8_t*>(schemaTensor->data.data()),
359                                tensor.data.dataSize, data, tensor.data.dataSize);
360         if (memRet != EOK) {
361             HDF_LOGW("Copy tensor data failed.");
362             return nullptr;
363         }
364     }
365     return schemaTensor;
366 }
367 
TransNode(const Node & node) const368 std::unique_ptr<mindspore::schema::CNodeT> NnrtDeviceService::TransNode(const Node& node) const
369 {
370     auto cnode = std::make_unique<mindspore::schema::CNodeT>();
371     cnode->name = node.name;
372     cnode->inputIndex = node.inputIndex;
373     cnode->outputIndex = node.outputIndex;
374     cnode->quantType = static_cast<mindspore::schema::QuantType>(node.quantType);
375 
376     auto& regInstance = NodeRegistry::GetSingleton();
377     auto parseFunc = regInstance.GetNodeFunc(node.nodeType);
378     auto primitive = parseFunc(node.nodeAttr);
379     if (primitive == nullptr) {
380         HDF_LOGE("Parse primitve data failed. node name=%{public}s", node.name.c_str());
381         return nullptr;
382     }
383 
384     cnode->primitive = std::move(primitive);
385     return cnode;
386 }
387 
TransSubGraph(const SubGraph & graph,const size_t numTensor) const388 std::unique_ptr<mindspore::schema::SubGraphT> NnrtDeviceService::TransSubGraph(const SubGraph& graph,
389     const size_t numTensor) const
390 {
391     auto subGraph = std::make_unique<mindspore::schema::SubGraphT>();
392     subGraph->name = graph.name;
393     subGraph->inputIndices = graph.inputIndices;
394     subGraph->outputIndices = graph.outputIndices;
395     subGraph->nodeIndices = graph.nodeIndices;
396     subGraph->tensorIndices.reserve(numTensor);
397     for (auto i = 0; i < numTensor; i++) {
398         subGraph->tensorIndices.emplace_back(static_cast<uint32_t>(i));
399     }
400     return subGraph;
401 }
402 
TransModelConfig(const ModelConfig & config) const403 std::shared_ptr<mindspore::Context> NnrtDeviceService::TransModelConfig(const ModelConfig& config) const
404 {
405     auto context = std::make_shared<mindspore::Context>();
406     const int cpuThreadNum = 2;
407     const int cpuNoAffinities = 0;
408     const int cpuBigCore = 1;
409     const int cpuLittleCore = 2;
410     context->SetThreadNum(cpuThreadNum);
411 
412     int mode = cpuNoAffinities;
413     switch (config.mode) {
414         case PerformanceMode::PERFORMANCE_LOW:
415         case PerformanceMode::PERFORMANCE_MEDIUM:
416             mode = cpuLittleCore;
417             break;
418         case PerformanceMode::PERFORMANCE_HIGH:
419         case PerformanceMode::PERFORMANCE_EXTREME:
420             mode = cpuBigCore;
421             break;
422         default:
423             mode = cpuNoAffinities;
424     }
425     context->SetThreadAffinity(mode);
426 
427     auto cpuInfo = std::make_shared<mindspore::CPUDeviceInfo>();
428     cpuInfo->SetEnableFP16(config.enableFloat16);
429     auto& deviceInfos = context->MutableDeviceInfo();
430     deviceInfos.emplace_back(cpuInfo);
431     return context;
432 }
433 } // V1_0
434 } // Nnrt
435 } // HDI
436 } // OHOS
437