Imported Upstream version 1.25.0
[platform/core/ml/nnfw.git] / runtime / service / npud / backend / trix / TrixBackend.cc
1 /*
2  * Copyright (c) 2022 Samsung Electronics Co., Ltd. All Rights Reserved
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 #include "TrixBackend.h"
18
19 #include <algorithm>
20
21 #if defined(__linux__)
22 extern "C" {
23 using namespace ::npud::backend::trix;
24
25 TrixBackend *allocate() { return new TrixBackend(); }
26
27 void deallocate(TrixBackend *trix) { delete trix; }
28 }
29 #endif
30
31 namespace npud
32 {
33 namespace backend
34 {
35 namespace trix
36 {
37
38 TrixBackend::TrixBackend() : _devType(NPUCOND_TRIV2_CONN_SOCIP)
39 {
40   auto coreNum = getnumNPUdeviceByType(_devType);
41   if (coreNum <= 0)
42   {
43     return;
44   }
45
46   std::vector<npudev_h> handles;
47   for (int i = 0; i < coreNum; ++i)
48   {
49     npudev_h handle;
50     if (getNPUdeviceByType(&handle, _devType, i) < 0)
51     {
52       // Note Run for all cores.
53       continue;
54     }
55     handles.emplace_back(handle);
56   }
57
58   if (handles.size() == 0)
59   {
60     return;
61   }
62
63   _dev = std::make_unique<TrixDevice>();
64   _dev->handles = std::move(handles);
65 }
66
67 TrixBackend::~TrixBackend()
68 {
69   for (const auto &ctx : _dev->ctxs)
70   {
71     npudev_h handle = _dev->handles.at(ctx->defaultCore);
72     for (const auto id : ctx->requests)
73     {
74       removeNPU_request(handle, id);
75     }
76   }
77
78   for (const auto &handle : _dev->handles)
79   {
80     unregisterNPUmodel_all(handle);
81     putNPUdevice(handle);
82   }
83 }
84
85 NpuStatus TrixBackend::getVersion(std::string &version)
86 {
87   // TODO Implement details
88   return NPU_STATUS_ERROR_NOT_SUPPORTED;
89 }
90
91 NpuStatus TrixBackend::createContext(int deviceId, int priority, NpuContext **ctx)
92 {
93   if (deviceId >= _dev->handles.size())
94   {
95     return NPU_STATUS_ERROR_INVALID_ARGUMENT;
96   }
97   auto context = std::make_unique<NpuContext>();
98   context->defaultCore = deviceId;
99   // TODO Consider priority.
100   *ctx = context.get();
101   _dev->ctxs.emplace_back(std::move(context));
102   return NPU_STATUS_SUCCESS;
103 }
104
105 NpuStatus TrixBackend::destroyContext(NpuContext *ctx)
106 {
107   if (ctx == nullptr)
108   {
109     return NPU_STATUS_ERROR_INVALID_ARGUMENT;
110   }
111
112   auto citer = std::find_if(_dev->ctxs.begin(), _dev->ctxs.end(),
113                             [&](std::unique_ptr<NpuContext> &c) { return c.get() == ctx; });
114   if (citer == _dev->ctxs.end())
115   {
116     return NPU_STATUS_ERROR_INVALID_ARGUMENT;
117   }
118
119   npudev_h handle = _dev->handles.at(ctx->defaultCore);
120
121   for (auto &&rid : ctx->requests)
122   {
123     if (removeNPU_request(handle, rid) < 0)
124     {
125       return NPU_STATUS_ERROR_OPERATION_FAILED;
126     }
127     _dev->requests.erase(rid);
128   }
129
130   for (auto &&mid : ctx->models)
131   {
132     auto &minfo = _dev->models.at(mid);
133     if (--minfo->refCount == 0)
134     {
135       if (unregisterNPUmodel(handle, mid) < 0)
136       {
137         return NPU_STATUS_ERROR_OPERATION_FAILED;
138       }
139       _dev->models.erase(mid);
140     }
141   }
142
143   _dev->ctxs.erase(citer);
144   return NPU_STATUS_SUCCESS;
145 }
146
147 NpuStatus TrixBackend::createBuffer(NpuContext *ctx, GenericBuffer *buffer)
148 {
149   // TODO Implement details
150   return NPU_STATUS_ERROR_NOT_SUPPORTED;
151 }
152
153 NpuStatus TrixBackend::destroyBuffer(NpuContext *ctx, GenericBuffer *buffer)
154 {
155   // TODO Implement details
156   return NPU_STATUS_ERROR_NOT_SUPPORTED;
157 }
158
159 NpuStatus TrixBackend::registerModel(NpuContext *ctx, const std::string &modelPath,
160                                      ModelID *modelId)
161 {
162   if (ctx == nullptr)
163   {
164     return NPU_STATUS_ERROR_INVALID_ARGUMENT;
165   }
166
167   ModelID id = 0;
168   auto iter =
169     std::find_if(_dev->models.begin(), _dev->models.end(),
170                  [&](const std::pair<const ModelID, std::unique_ptr<TrixModelInfo>> &p) {
171                    return p.second->core == ctx->defaultCore && p.second->path == modelPath;
172                  });
173   // Already registered model.
174   if (iter != _dev->models.end())
175   {
176     _dev->models.at(iter->first)->refCount++;
177     ctx->models.emplace_back(iter->first);
178   }
179   else
180   {
181     auto meta = getNPUmodel_metadata(modelPath.c_str(), false);
182     if (meta == nullptr)
183     {
184       return NPU_STATUS_ERROR_OPERATION_FAILED;
185     }
186
187     generic_buffer fileInfo;
188     fileInfo.type = BUFFER_FILE;
189     fileInfo.filepath = modelPath.c_str();
190     fileInfo.size = meta->size;
191
192     npudev_h handle = _dev->handles.at(ctx->defaultCore);
193     if (registerNPUmodel(handle, &fileInfo, &id) < 0)
194     {
195       return NPU_STATUS_ERROR_OPERATION_FAILED;
196     }
197
198     _dev->models.insert(std::make_pair(id, std::unique_ptr<TrixModelInfo>(new TrixModelInfo{
199                                              id, modelPath, ctx->defaultCore, meta, 1})));
200     ctx->models.emplace_back(id);
201   }
202
203   *modelId = id;
204   return NPU_STATUS_SUCCESS;
205 }
206
207 NpuStatus TrixBackend::unregisterModel(NpuContext *ctx, ModelID modelId)
208 {
209   if (ctx == nullptr)
210   {
211     return NPU_STATUS_ERROR_INVALID_ARGUMENT;
212   }
213
214   auto miter = std::find(ctx->models.begin(), ctx->models.end(), modelId);
215   if (miter == ctx->models.end())
216   {
217     return NPU_STATUS_ERROR_INVALID_MODEL;
218   }
219
220   npudev_h handle = _dev->handles.at(ctx->defaultCore);
221
222   for (auto riter = ctx->requests.begin(); riter != ctx->requests.end();)
223   {
224     auto &rinfo = _dev->requests.at(*riter);
225     if (rinfo->modelId == modelId)
226     {
227       if (removeNPU_request(handle, rinfo->id) < 0)
228       {
229         return NPU_STATUS_ERROR_OPERATION_FAILED;
230       }
231       _dev->requests.erase(rinfo->id);
232       riter = ctx->requests.erase(riter);
233     }
234     else
235     {
236       ++riter;
237     }
238   }
239
240   auto &minfo = _dev->models.at(modelId);
241   if (--minfo->refCount == 0)
242   {
243     if (unregisterNPUmodel(handle, modelId) < 0)
244     {
245       return NPU_STATUS_ERROR_OPERATION_FAILED;
246     }
247     _dev->models.erase(modelId);
248   }
249
250   ctx->models.erase(miter);
251   return NPU_STATUS_SUCCESS;
252 }
253
254 NpuStatus TrixBackend::createRequest(NpuContext *ctx, ModelID modelId, RequestID *requestId)
255 {
256   if (ctx == nullptr)
257   {
258     return NPU_STATUS_ERROR_INVALID_ARGUMENT;
259   }
260
261   auto miter = std::find(ctx->models.begin(), ctx->models.end(), modelId);
262   if (miter == ctx->models.end())
263   {
264     return NPU_STATUS_ERROR_INVALID_MODEL;
265   }
266
267   int id = 0;
268   npudev_h handle = _dev->handles.at(ctx->defaultCore);
269   if (createNPU_request(handle, modelId, &id) < 0)
270   {
271     return NPU_STATUS_ERROR_OPERATION_FAILED;
272   }
273
274   _dev->requests.insert(std::make_pair(id, std::unique_ptr<TrixRequestInfo>(new TrixRequestInfo{
275                                              static_cast<RequestID>(id), modelId})));
276   ctx->requests.emplace_back(id);
277
278   *requestId = id;
279   return NPU_STATUS_SUCCESS;
280 }
281
282 NpuStatus TrixBackend::destroyRequest(NpuContext *ctx, RequestID requestId)
283 {
284   if (ctx == nullptr)
285   {
286     return NPU_STATUS_ERROR_INVALID_ARGUMENT;
287   }
288
289   auto riter = std::find(ctx->requests.begin(), ctx->requests.end(), requestId);
290   if (riter == ctx->requests.end())
291   {
292     return NPU_STATUS_ERROR_INVALID_ARGUMENT;
293   }
294
295   npudev_h handle = _dev->handles.at(ctx->defaultCore);
296   if (removeNPU_request(handle, requestId) < 0)
297   {
298     return NPU_STATUS_ERROR_OPERATION_FAILED;
299   }
300
301   _dev->requests.erase(requestId);
302   ctx->requests.erase(riter);
303   return NPU_STATUS_SUCCESS;
304 }
305
306 NpuStatus TrixBackend::setRequestData(NpuContext *ctx, RequestID requestId, InputBuffers *inputBufs,
307                                       TensorDataInfos *inputInfos, OutputBuffers *outputBufs,
308                                       TensorDataInfos *outputInfos)
309 {
310   auto citer = std::find_if(_dev->ctxs.begin(), _dev->ctxs.end(),
311                             [&](std::unique_ptr<NpuContext> &c) { return c.get() == ctx; });
312   if (citer == _dev->ctxs.end())
313   {
314     return NPU_STATUS_ERROR_INVALID_ARGUMENT;
315   }
316
317   auto riter = std::find(ctx->requests.begin(), ctx->requests.end(), requestId);
318   if (riter == ctx->requests.end())
319   {
320     return NPU_STATUS_ERROR_INVALID_ARGUMENT;
321   }
322
323   auto &req = _dev->requests.at(requestId);
324   auto miter = std::find(ctx->models.begin(), ctx->models.end(), req->modelId);
325   if (miter == ctx->models.end())
326   {
327     return NPU_STATUS_ERROR_INVALID_MODEL;
328   }
329
330   // TODO Exception controll of `at`
331   auto &minfo = _dev->models.at(req->modelId);
332   if (minfo->meta->input_seg_num != inputBufs->numBuffers ||
333       minfo->meta->output_seg_num != outputBufs->numBuffers)
334   {
335     return NPU_STATUS_ERROR_INVALID_DATA;
336   }
337
338   auto &inInfos = req->inInfos;
339   auto &outInfos = req->outInfos;
340
341   inInfos->num_info = inputBufs->numBuffers;
342   for (auto i = 0; i < inInfos->num_info; ++i)
343   {
344     inInfos->info[i].layout = DATA_LAYOUT_MODEL;
345     inInfos->info[i].type = minfo->meta->input_seg_quant_type[i];
346   }
347
348   outInfos->num_info = outputBufs->numBuffers;
349   for (auto i = 0; i < outInfos->num_info; ++i)
350   {
351     outInfos->info[i].layout = DATA_LAYOUT_MODEL;
352     outInfos->info[i].type = minfo->meta->output_seg_quant_type[i];
353   }
354
355   auto &inBufs = req->inBufs;
356   auto &outBufs = req->outBufs;
357
358   inBufs->num_buffers = inputBufs->numBuffers;
359   for (auto i = 0; i < inBufs->num_buffers; ++i)
360   {
361     if (inputBufs->buffers[i].type == NPU_BUFFER_MAPPED)
362     {
363       inBufs->bufs[i].addr = inputBufs->buffers[i].addr;
364     }
365     else if (inputBufs->buffers[i].type == NPU_BUFFER_DMABUF)
366     {
367       // TODO Implement details
368       // inBufs.bufs[i].dmabuf = inputBufs->buffers[i].dmabuf;
369       // inBufs.bufs[i].offset = inputBufs->buffers[i].offset;
370     }
371     else
372     {
373       continue;
374     }
375     inBufs->bufs[i].size = inputBufs->buffers[i].size;
376     inBufs->bufs[i].type = static_cast<buffer_types>(inputBufs->buffers[i].type);
377   }
378
379   outBufs->num_buffers = outputBufs->numBuffers;
380   for (auto i = 0; i < outBufs->num_buffers; ++i)
381   {
382     if (outputBufs->buffers[i].type == NPU_BUFFER_MAPPED)
383     {
384       outBufs->bufs[i].addr = outputBufs->buffers[i].addr;
385     }
386     else if (outputBufs->buffers[i].type == NPU_BUFFER_DMABUF)
387     {
388       // TODO Implement details
389       // outBufs.bufs[i].dmabuf = outputBufs->buffers[i].dmabuf;
390       // outBufs.bufs[i].offset = outputBufs->buffers[i].offset;
391     }
392     else
393     {
394       continue;
395     }
396     outBufs->bufs[i].size = outputBufs->buffers[i].size;
397     outBufs->bufs[i].type = static_cast<buffer_types>(outputBufs->buffers[i].type);
398   }
399
400   npudev_h handle = _dev->handles.at(ctx->defaultCore);
401   if (setNPU_requestData(handle, requestId, inBufs.get(), inInfos.get(), outBufs.get(),
402                          outInfos.get()) < 0)
403   {
404     return NPU_STATUS_ERROR_OPERATION_FAILED;
405   }
406
407   return NPU_STATUS_SUCCESS;
408 }
409
410 NpuStatus TrixBackend::submitRequest(NpuContext *ctx, RequestID requestId)
411 {
412   // TODO Implement details
413   return NPU_STATUS_ERROR_NOT_SUPPORTED;
414 }
415
416 } // namespace trix
417 } // namespace backend
418 } // namespace npud