This patch implements decoupled APIs for network inferencing.
It allows for users to configure their requests before submission.
Signed-off-by: Dongju Chae <dongju.chae@samsung.com>
* @param[in] model_id The model to be inferred.
* @param[out] req_id The ID of created request
* @return 0 if no error. Otherwise a negative errno
- * @note the created request is not submitted until runNPU_request is called
+ * @note The created request is not submitted until runNPU_request is called.
+ * Also, it's automatically destroyed when submitted.
*/
int createNPU_request (npudev_h dev, uint32_t model_id, int *req_id);
int setNPU_requestMode (npudev_h dev, int req_id, npu_infer_mode mode);
/**
- * @brief [OPTIONAL] Set the request's inference mode
+ * @brief [OPTIONAL] Set the request's constraint
* @param[in] dev The NPU device handle
* @param[in] req_id The request ID
* @param[in] constraint inference constraint (e.g., timeout, priority)
};
/**
+ * @brief Create NPU inferance request
+ * @param[in] model_id The model to be inferred.
+ * @param[out] req_id The ID of created request
+ * @return 0 if no error. Otherwise a negative errno
+ */
+int
+HostHandler::createRequest (uint32_t model_id, int *req_id) {
+ Model *model = getModel (model_id);
+ if (model == nullptr) {
+ logerr (TAG, "Unable to find a model with model id (0x%x)\n", model_id);
+ return -ENOENT;
+ }
+
+ return device_->createRequest (model, req_id);
+}
+
+/**
+ * @brief Set request's input/output data
+ * @param[in] req_id The request ID
+ * @param[in] input The input data buffers
+ * @param[in] in_info The input data info (format, type)
+ * @param[in] output The output data buffers
+ * @param[in] out_info The output data info (format, type)
+ * @return 0 if no error. Otherwise a negative errno
+ */
+int
+HostHandler::setRequestData (int req_id, input_buffers *input,
+ tensors_data_info *in_info, output_buffers *output,
+ tensors_data_info *out_info) {
+ return device_->setRequestData (req_id, input, in_info, output, out_info);
+}
+
+/**
+ * @brief Set output callback of the request
+ * @param[in] req_id The request ID
+ * @param[in] cb The output callback handler
+ * @param[in] [nullable] data The data to pass to callback handler
+ * @return 0 if no error. Otherwise a negative errno
+ */
+int
+HostHandler::setRequestCallback (int req_id, npuOutputNotify cb, void *data) {
+ return device_->setRequestCallback (req_id, cb, data);
+}
+
+/**
+ * @brief Set the request's inference mode
+ * @param[in] req_id The request ID
+ * @param[in] mode Configures how this inference works.
+ * @return 0 if no error. Otherwise a negative errno
+ */
+int
+HostHandler::setRequestMode (int req_id, npu_infer_mode mode) {
+ return device_->setRequestMode (req_id, mode);
+}
+
+/**
+ * @brief Set the request's constraint
+ * @param[in] dev The NPU device handle
+ * @param[in] req_id The request ID
+ * @param[in] constraint inference constraint (e.g., timeout, priority)
+ * @return 0 if no error. Otherwise a negative errno
+ */
+int
+HostHandler::setRequestConstraint (int req_id, npu_constraint constraint) {
+ return device_->setRequestConstraint (req_id, constraint);
+}
+
+/**
+ * @brief Set the request's VD NPU manager parameter
+ * @param[in] req_id The request ID
+ * @param[in] param npumgr parameter
+ * @return 0 if no error. Otherwise a negative errno
+ */
+int
+HostHandler::setRequestNpumgrParam (int req_id, npumgr_param param) {
+ return device_->setRequestNpumgrParam (req_id, param);
+}
+
+/**
+ * @brief Submit the request to the NPU
+ * @param[in] req_id The request ID
+ * @return 0 if no error. Otherwise a negative errno
+ */
+int
+HostHandler::submitRequest (int req_id) {
+ return device_->submitRequest (req_id);
+}
+
+/**
* @brief Execute inference.
* @param[in] model_id The model id to be inferred
* @param[in] mode Configures how this inference works.
}
}
- Request *req = new Request (opmode);
+ Request *req = scheduler_->createRequest (opmode);
+
req->setModel (model);
req->setInferData (segt);
req->setOutputBuffers (output);
return -EINVAL;
}
- Request *req = new Request (opmode);
+ Request *req = scheduler_->createRequest (opmode);
+
req->setModel (model);
req->setInferData (segt);
req->setHwDevice (hw_dev);
delete segt;
}
+int
+TrinityVision2::createRequest (const Model *model, int *req_id) {
+ Request *req;
+
+ if (model == nullptr || req_id == nullptr) {
+ logerr (TAG, "Invalid arguments detected\n");
+ return -EINVAL;
+ }
+
+ req = scheduler_->createRequest (NPUINPUT_HOST);
+ req->setModel (model);
+
+ *req_id = req->getID ();
+
+ return 0;
+}
+
+int
+TrinityVision2::setRequestData (int req_id, input_buffers *input,
+ tensors_data_info *in_info,
+ output_buffers *output,
+ tensors_data_info *out_info) {
+ Request *req = scheduler_->findRequest (req_id);
+ if (req == nullptr) {
+ logerr (TAG, "Unable to find the request with ID (%d)\n", req_id);
+ return -ENOENT;
+ }
+
+ const Model *model = req->getModel ();
+ if (model == nullptr) {
+ logerr (TAG, "Unable to find the target model\n");
+ return -EINVAL;
+ }
+
+ if (input == nullptr || in_info == nullptr || output == nullptr ||
+ out_info == nullptr) {
+ logerr (TAG, "Invalid arguments detected\n");
+ return -EINVAL;
+ }
+
+ /* FIXME: should be per request, not per model */
+ const_cast<Model *> (model)->setDataInfo (in_info, out_info);
+
+ /** this device uses segment table */
+ SegmentTable *segt = prepareSegmentTable (model, input, output);
+ if (segt == nullptr) {
+ logerr (TAG, "Failed to create segment table instance\n");
+ return -EINVAL;
+ }
+
+ /** extract input data */
+ for (uint32_t idx = 0; idx < input->num_buffers; idx++) {
+ if (!segt->getInputSegment (idx)->isExternal ()) {
+ uint32_t seg_offset = segt->getInputSegmentOffset (idx);
+ auto func = std::bind (TrinityVision2::manipulateData, model, idx, true,
+ std::placeholders::_1, std::placeholders::_2,
+ std::placeholders::_3);
+ int status = comm_.extractGenericBuffer (
+ &input->bufs[idx],
+ segt->getInputSegment (idx)->getData () + seg_offset, func);
+ if (status != 0) {
+ logerr (TAG, "Failed to feed input segment: %d\n", status);
+ return status;
+ }
+ }
+ }
+
+ req->setInferData (segt);
+ req->setOutputBuffers (output);
+
+ return 0;
+}
+
+int
+TrinityVision2::setRequestCallback (int req_id, npuOutputNotify cb,
+ void *data) {
+ Request *req = scheduler_->findRequest (req_id);
+ if (req == nullptr) {
+ logerr (TAG, "Unable to find the request with ID (%d)\n", req_id);
+ return -ENOENT;
+ }
+
+ req->setCallback (std::bind (&TrinityVision2::callback, this, req, cb, data));
+
+ return 0;
+}
+
+int
+TrinityVision2::setRequestMode (int req_id, npu_infer_mode mode) {
+ Request *req = scheduler_->findRequest (req_id);
+ if (req == nullptr) {
+ logerr (TAG, "Unable to find the request with ID (%d)\n", req_id);
+ return -ENOENT;
+ }
+
+ req->setInferMode (mode);
+
+ return 0;
+}
+
+int
+TrinityVision2::setRequestConstraint (int req_id, npu_constraint constraint) {
+ Request *req = scheduler_->findRequest (req_id);
+ if (req == nullptr) {
+ logerr (TAG, "Unable to find the request with ID (%d)\n", req_id);
+ return -ENOENT;
+ }
+
+ const Model *model = req->getModel ();
+ if (model == nullptr) {
+ logerr (TAG, "Unable to find the target model\n");
+ return -EINVAL;
+ }
+
+ /* FIXME: should be per request, not per model */
+ const_cast<Model *> (model)->setConstraint (constraint);
+
+ return 0;
+}
+
+int
+TrinityVision2::setRequestNpumgrParam (int req_id, npumgr_param param) {
+ Request *req = scheduler_->findRequest (req_id);
+ if (req == nullptr) {
+ logerr (TAG, "Unable to find the request with ID (%d)\n", req_id);
+ return -ENOENT;
+ }
+
+ req->setNpumgrParam (param);
+
+ return 0;
+}
+
+int
+TrinityVision2::submitRequest (int req_id) {
+ Request *req = scheduler_->findRequest (req_id);
+ if (req == nullptr) {
+ logerr (TAG, "Unable to find the request with ID (%d)\n", req_id);
+ return -ENOENT;
+ }
+
+ int status = -EINVAL;
+
+ switch (req->getInferMode ()) {
+ case NPU_INFER_BLOCKING: {
+ callbackSync sync;
+
+ if (req->getCallback () != nullptr)
+ logwarn (TAG, "Blocking call don't use user callback...\n");
+
+ req->setCallback (std::bind (&TrinityVision2::callback, this, req,
+ (npuOutputNotify) callbackSync::callback,
+ static_cast<void *> (&sync)));
+
+ status = scheduler_->submitRequest (req);
+ if (status >= 0)
+ sync.wait ();
+ } break;
+ case NPU_INFER_NON_BLOCKING:
+ if (req->getCallback () == nullptr) {
+ logwarn (TAG, "inferencing without output callback...\n");
+ req->setCallback (
+ std::bind (&TrinityVision2::callback, this, req, nullptr, nullptr));
+ }
+ status = scheduler_->submitRequest (req);
+ break;
+ default:
+ logerr (TAG, "Unknown inference mode\n");
+ }
+
+ return status;
+}
+
/** Implement data manipulation (each device may have different impl.) */
#ifdef ENABLE_MANIP
std::string hw_dev);
int stopInternal (int id);
+ int createRequest (uint32_t model_id, int *req_id);
+ int setRequestData (int req_id, input_buffers *input,
+ tensors_data_info *in_info, output_buffers *output,
+ tensors_data_info *out_info);
+ int setRequestCallback (int req_id, npuOutputNotify cb, void *data);
+ int setRequestMode (int req_id, npu_infer_mode mode);
+ int setRequestConstraint (int req_id, npu_constraint constraint);
+ int setRequestNpumgrParam (int req_id, npumgr_param param);
+ int submitRequest (int req_id);
+
/** @brief get statistics */
int getMemoryStatus (size_t *alloc_total, size_t *free_total);
int getDeviceStatus (npu_status *status, uint32_t *num_requests);
return -EPERM;
}
+ virtual int createRequest (const Model *model, int *req_id) = 0;
+ virtual int setRequestData (int req_id, input_buffers *input,
+ tensors_data_info *in_info,
+ output_buffers *output,
+ tensors_data_info *out_info) = 0;
+ virtual int setRequestCallback (int req_id, npuOutputNotify cb,
+ void *data) = 0;
+ virtual int setRequestMode (int req_id, npu_infer_mode mode) = 0;
+ virtual int setRequestConstraint (int req_id, npu_constraint constraint) = 0;
+ virtual int setRequestNpumgrParam (int req_id, npumgr_param param) = 0;
+ virtual int submitRequest (int req_id) = 0;
+
protected:
/** the device instance has ownership of all related components */
std::unique_ptr<DriverAPI> api_; /**< device api */
int runInternal (npu_input_opmode opmode, const Model *model,
std::string hw_dev);
+ int createRequest (const Model *model, int *req_id);
+ int setRequestData (int req_id, input_buffers *input,
+ tensors_data_info *in_info, output_buffers *output,
+ tensors_data_info *out_info);
+ int setRequestCallback (int req_id, npuOutputNotify cb, void *data);
+ int setRequestMode (int req_id, npu_infer_mode mode);
+ int setRequestConstraint (int req_id, npu_constraint constraint);
+ int setRequestNpumgrParam (int req_id, npumgr_param param);
+ int submitRequest (int req_id);
+
private:
void callback (Request *req, npuOutputNotify cb, void *cb_data);
};
int
HostInputService::submit (const DriverAPI *api, int id, const Model *model,
- HWmem *data, outputCallback callback) {
+ HWmem *data, outputCallback callback,
+ const npumgr_param *param) {
if (api == nullptr)
return -EINVAL;
if (dynamic_cast<Buffer *> (data)) {
/* empty model is possible */
return submit_buffer (api, id, model, dynamic_cast<Buffer *> (data),
- callback);
+ callback, param);
} else if (dynamic_cast<SegmentTable *> (data)) {
if (model == nullptr)
return -EINVAL;
return submit_segt (api, id, model, dynamic_cast<SegmentTable *> (data),
- callback);
+ callback, param);
} else {
return -EINVAL;
}
int
HostInputService::submit_buffer (const DriverAPI *api, int id,
const Model *model, Buffer *buffer,
- outputCallback callback) {
+ outputCallback callback,
+ const npumgr_param *param) {
taskFunc func = std::bind (&HostInputService::invoke_buffer, this, api, model,
- buffer, callback, id);
+ buffer, callback, id, param);
ThreadTask *task = new ThreadTask (id, func);
return ThreadPool::getInstance ().enqueueTask (task);
*/
int
HostInputService::submit_segt (const DriverAPI *api, int id, const Model *model,
- SegmentTable *segt, outputCallback callback) {
+ SegmentTable *segt, outputCallback callback,
+ const npumgr_param *param) {
taskFunc func = std::bind (&HostInputService::invoke_segt, this, api, model,
- segt, callback, id);
+ segt, callback, id, param);
ThreadTask *task = new ThreadTask (id, func);
return ThreadPool::getInstance ().enqueueTask (task);
int
HostInputService::invoke_buffer (const DriverAPI *api, const Model *model,
Buffer *buffer, outputCallback callback,
- int req_id) {
+ int req_id, const npumgr_param *param) {
input_config_t input_config;
device_state_t state;
int ret = -EINVAL;
int
HostInputService::invoke_segt (const DriverAPI *api, const Model *model,
SegmentTable *segt, outputCallback callback,
- int req_id) {
+ int req_id, const npumgr_param *param) {
input_config_t input_config;
device_state_t state;
npuConstraint constraint;
goto handle_callback;
}
+ /** npumgr parameter setting if exists */
+ if (param != nullptr) {
+ input_config.task_handle = param->task_handle;
+ input_config.subtask_idx = param->subtask_idx;
+ } else {
+ input_config.task_handle = UINT32_MAX;
+ input_config.subtask_idx = UINT32_MAX;
+ }
+
input_config.model_id = model->getInternalID ();
input_config.dbuf_fd = segt->getDmabuf ();
input_config.num_segments = segt->getNumTotalSegments ();
*/
int
HwInputService::submit (const DriverAPI *api, int id, const Model *model,
- HWmem *data, outputCallback callback) {
+ HWmem *data, outputCallback callback,
+ const npumgr_param *param) {
if (api == nullptr || model == nullptr)
return -EINVAL;
if (segt == nullptr)
return -EINVAL;
- return invoke (api, model, segt, callback, id);
+ return invoke (api, model, segt, callback, id, param);
}
/**
*/
int
HwInputService::invoke (const DriverAPI *api, const Model *model,
- SegmentTable *segt, outputCallback callback,
- int req_id) {
+ SegmentTable *segt, outputCallback callback, int req_id,
+ const npumgr_param *param) {
input_config_t input_config;
device_state_t state;
npuConstraint constraint;
input_config.hw_input_seg = model->getMetadata ()->getInputSegmentIndex (0);
input_config.hw_output_seg = model->getMetadata ()->getOutputSegmentIndex (0);
+ /** npumgr parameter setting if exists */
+ if (param != nullptr) {
+ input_config.task_handle = param->task_handle;
+ input_config.subtask_idx = param->subtask_idx;
+ } else {
+ input_config.task_handle = UINT32_MAX;
+ input_config.subtask_idx = UINT32_MAX;
+ }
+
#ifndef ENABLE_EMUL
struct stat devnode_stat;
int fd;
public:
/** @brief submit request to somewhere (depends on each impl.) */
virtual int submit (const DriverAPI *api, int request_id, const Model *model,
- HWmem *data, outputCallback callback = nullptr) {
+ HWmem *data, outputCallback callback = nullptr,
+ const npumgr_param *param = nullptr) {
return -EPERM;
}
/** @brief [OPTIONAL] remove the submitted request (if possible) */
static HostInputService &getInstance ();
int submit (const DriverAPI *api, int request_id, const Model *model,
- HWmem *data, outputCallback callback = nullptr);
+ HWmem *data, outputCallback callback = nullptr,
+ const npumgr_param *param = nullptr);
int remove (int request_id);
private:
int submit_buffer (const DriverAPI *api, int request_id, const Model *model,
- Buffer *buffer, outputCallback callback = nullptr);
+ Buffer *buffer, outputCallback callback = nullptr,
+ const npumgr_param *param = nullptr);
int submit_segt (const DriverAPI *api, int request_id, const Model *model,
- SegmentTable *segt, outputCallback callback = nullptr);
+ SegmentTable *segt, outputCallback callback = nullptr,
+ const npumgr_param *param = nullptr);
/** do not allow to directly call invoke () */
int invoke_buffer (const DriverAPI *api, const Model *model, Buffer *buffer,
- outputCallback callback, int task_id);
+ outputCallback callback, int task_id,
+ const npumgr_param *param);
int invoke_segt (const DriverAPI *api, const Model *model, SegmentTable *segt,
- outputCallback callback, int task_id);
+ outputCallback callback, int task_id,
+ const npumgr_param *param);
static std::unique_ptr<HostInputService> instance_;
static std::once_flag once_flag_;
static HwInputService &getInstance ();
int submit (const DriverAPI *api, int request_id, const Model *model,
- HWmem *data, outputCallback callback = nullptr);
+ HWmem *data, outputCallback callback = nullptr,
+ const npumgr_param *param = nullptr);
private:
/** do not allow to directly call invoke () */
int invoke (const DriverAPI *api, const Model *model, SegmentTable *segt,
- outputCallback callback, int task_id);
+ outputCallback callback, int task_id,
+ const npumgr_param *param = nullptr);
static std::unique_ptr<HwInputService> instance_;
static std::once_flag once_flag_;
#include "ne-inputservice.h"
#include <assert.h>
+#include <unistd.h>
#define TAG _N3
model_ (nullptr),
data_ (nullptr),
cb_ (nullptr),
- out_bufs_ (nullptr) {
+ out_bufs_ (nullptr),
+ infer_mode_ (NPU_INFER_BLOCKING /* default */),
+ npumgr_param_ (nullptr) {
request_id_ = Request::global_request_id_.fetch_add (1);
}
int
Scheduler::handleHostInput (Request *req, InputService *service) {
int req_id = req->getID ();
- int status = request_map_.insert (req_id, req);
- assert (status ==
- 0); /** request ID is atomic value. So, should be successful */
-
const Model *model = req->getModel ();
HWmem *data = req->getInferData ();
auto callback = std::bind (&Scheduler::handleCallback, this, req);
+ const npumgr_param *param = req->getNpumgrParam ();
- status = service->submit (api_, req_id, model, data, callback);
+ int status = service->submit (api_, req_id, model, data, callback, param);
if (status < 0)
return status;
int
Scheduler::handleHwInput (Request *req, InputService *service) {
int req_id = req->getID ();
- int status = request_map_.insert (req_id, req);
- assert (status ==
- 0); /** request ID is atomic value. So, should be successful */
-
const Model *model = req->getModel ();
HWmem *data = req->getInferData ();
auto callback = std::bind (&Scheduler::handleCallback, this, req);
}
/**
+ * @brief create a request to be scheduled
+ * @param[in] opmode operation mode
+ * @return new request instance
+ */
+Request *
+Scheduler::createRequest (npu_input_opmode opmode) {
+ Request *req = new Request (opmode);
+ /** request ID is atomic value. So, should be successful */
+ assert (request_map_.insert (req->getID (), req) == 0);
+ return req;
+}
+
+/**
+ * @brief remove the request submitted
+ * @param[in] req the request instance
+ */
+void
+Scheduler::removeRequest (Request *req) {
+ if (req)
+ request_map_.remove (req->getID ());
+}
+
+/**
* @brief submit request to inference engine
* @param[in] req the request instance
* @return 0 or positive value if no error. otherwise a negative errno.
+ * @note the request is destroyed only when its submission is sucessful.
*/
int
Scheduler::submitRequest (Request *req) {
npu_input_opmode opmode = req->getOpmode ();
InputService *service = getInputService (opmode);
- int status = 0;
switch (opmode) {
case NPUINPUT_STOP:
return handleStop (req);
case NPUINPUT_HOST:
- status = handleHostInput (req, service);
+ return handleHostInput (req, service);
break;
case NPUINPUT_HW_RECURRING:
- status = handleHwInput (req, service);
+ return handleHwInput (req, service);
break;
default:
return -EINVAL;
}
-
- /** if failed to invoke input service, directly handle callback (if exists) */
- if (status < 0)
- handleCallback (req);
-
- return status;
}
/**
callback ();
/** the request instance is also deleted here */
- request_map_.remove (req->getID ());
+ removeRequest (req);
+}
+
+/**
+ * @brief find request using id
+ * @return the target request if exists. Otherwise nullptr
+ */
+Request *
+Scheduler::findRequest (int req_id) {
+ /* thread-safe map */
+ return request_map_.find (req_id);
}
#include <atomic>
/** @brief class def. of requests created from host handler */
+
class Request {
public:
Request (npu_input_opmode opmode);
void setOutputBuffers (output_buffers *out_bufs) { out_bufs_ = out_bufs; }
output_buffers *getOutputBuffers () { return out_bufs_; }
+ void setInferMode (npu_infer_mode infer_mode) { infer_mode_ = infer_mode; }
+ npu_infer_mode getInferMode () { return infer_mode_; }
+
+ void setNpumgrParam (const npumgr_param ¶m) {
+ memcpy (npumgr_param_, ¶m, sizeof (npumgr_param));
+ }
+ const npumgr_param *getNpumgrParam () { return npumgr_param_; }
+
private:
static std::atomic<int> global_request_id_;
int request_id_; /**< request id */
outputCallback cb_; /**< request callback */
output_buffers *out_bufs_; /**< output buffers */
std::string hw_dev_; /**< HW device path */
+
+ npu_infer_mode infer_mode_;
+ npumgr_param *npumgr_param_;
};
/** @brief class def. of scheduler to handle requests */
~Scheduler ();
/** @brief submit the request */
+ Request *createRequest (npu_input_opmode opmode);
+ void removeRequest (Request *req);
int submitRequest (Request *req);
+ Request *findRequest (int req_id);
private:
/**
this->munmap (segt, PAGE_SIZE);
}
- /**
- * TODO: this value is an indicator whether to use VD NPU Scheduler.
- * When VD NPU manager is available, set this value properly.
- */
- input_config->task_handle = UINT32_MAX;
-
ret = ioctl (this->getDeviceFD (), TRINITY_IOCTL_RUN_INPUT, input_config);
if (ret < 0)
IOCTL_RETURN_ERRNO (TRINITY_IOCTL_RUN_INPUT);
*/
int
createNPU_request (npudev_h dev, uint32_t model_id, int *req_id) {
- /* NYI */
- return -EPERM;
+ INIT_HOST_HANDLER (host_handler, dev);
+
+ return host_handler->createRequest (model_id, req_id);
}
/**
setNPU_requestData (npudev_h dev, int req_id, input_buffers *input,
tensors_data_info *in_info, output_buffers *output,
tensors_data_info *out_info) {
- /* NYI */
- return -EPERM;
+ INIT_HOST_HANDLER (host_handler, dev);
+
+ return host_handler->setRequestData (req_id, input, in_info, output,
+ out_info);
}
/**
int
setNPU_requestCallback (npudev_h dev, int req_id, npuOutputNotify cb,
void *data) {
- /* NYI */
- return -EPERM;
+ INIT_HOST_HANDLER (host_handler, dev);
+
+ return host_handler->setRequestCallback (req_id, cb, data);
}
/**
*/
int
setNPU_requestMode (npudev_h dev, int req_id, npu_infer_mode mode) {
- /* NYI */
- return -EPERM;
+ INIT_HOST_HANDLER (host_handler, dev);
+
+ return host_handler->setRequestMode (req_id, mode);
}
/**
- * @brief [OPTIONAL] Set the request's inference mode
+ * @brief [OPTIONAL] Set the request's constraint
* @param[in] dev The NPU device handle
* @param[in] req_id The request ID
* @param[in] constraint inference constraint (e.g., timeout, priority)
*/
int
setNPU_requestConstraint (npudev_h dev, int req_id, npu_constraint constraint) {
- /* NYI */
- return -EPERM;
+ INIT_HOST_HANDLER (host_handler, dev);
+
+ return host_handler->setRequestConstraint (req_id, constraint);
}
/**
*/
int
setNPU_requestNpumgrParam (npudev_h dev, int req_id, npumgr_param param) {
- /* NYI */
- return -EPERM;
+ INIT_HOST_HANDLER (host_handler, dev);
+
+ return host_handler->setRequestNpumgrParam (req_id, param);
}
/**
*/
int
submitNPU_request (npudev_h dev, int req_id) {
- /* NYI */
- return -EPERM;
+ INIT_HOST_HANDLER (host_handler, dev);
+
+ return host_handler->submitRequest (req_id);
}
* @brief test set/get primitives of request
*/
TEST (ne_core_sched_test, request_set_get_primitives) {
+ std::unique_ptr<DriverAPI> api;
+ api = DriverAPI::createDriverAPI (NPUCOND_TRIV2_CONN_SOCIP, 0);
+ ASSERT_NE (api.get (), nullptr);
+
/** create dummy model & buffer */
std::unique_ptr<Model> model (new Model (new HWmemDevice));
std::unique_ptr<Buffer> buffer (new Buffer (new HWmemDevice));
auto callback = std::bind (test_callback, &num_called, &m, &cv);
bool force_stop = true;
- Request *req = new Request (NPUINPUT_HOST);
+ Scheduler *sched = new Scheduler (api.get ());
+ Request *req = sched->createRequest (NPUINPUT_HOST);
+ ASSERT_NE (req, nullptr);
EXPECT_EQ (req->getOpmode (), NPUINPUT_HOST);
EXPECT_GT (req->getID (), (uint32_t) 0);
* @brief test set, get api with null value
*/
TEST (ne_core_sched_test, request_set_get_args_n) {
+ std::unique_ptr<DriverAPI> api;
+ api = DriverAPI::createDriverAPI (NPUCOND_TRIV2_CONN_SOCIP, 0);
+ ASSERT_NE (api.get (), nullptr);
+
bool force_stop = false;
std::string hwDevice = "";
- Request *req = new Request (NPUINPUT_HOST);
+ Scheduler *sched = new Scheduler (api.get ());
+ Request *req = sched->createRequest (NPUINPUT_HOST);
+ ASSERT_NE (req, nullptr);
EXPECT_EQ (req->getOpmode (), NPUINPUT_HOST);
EXPECT_GT (req->getID (), (uint32_t) 0);
std::mutex m;
auto callback = std::bind (test_callback, &num_called, &m, &cv);
- Request *req = new Request (NPUINPUT_HOST);
+ Scheduler *sched = new Scheduler (api.get ());
+
+ Request *req = sched->createRequest (NPUINPUT_HOST);
+ ASSERT_NE (req, nullptr);
req->setModel (model.get ());
req->setInferData (buffer.get ());
req->setCallback (callback);
- Request *req2 = new Request (NPUINPUT_HOST);
+ Request *req2 = sched->createRequest (NPUINPUT_HOST);
+ ASSERT_NE (req2, nullptr);
req2->setModel (model.get ());
req2->setInferData (buffer.get ());
req2->setCallback (callback);
- Request *req3 = new Request (NPUINPUT_HOST);
+ Request *req3 = sched->createRequest (NPUINPUT_HOST);
+ ASSERT_NE (req3, nullptr);
req3->setModel (model.get ());
req3->setInferData (buffer.get ());
/** it's fine to have no callback */
- Scheduler *sched;
-
- sched = new Scheduler (api.get ());
EXPECT_EQ (sched->submitRequest (req), req->getID ());
EXPECT_EQ (sched->submitRequest (req2), req2->getID ());
EXPECT_EQ (sched->submitRequest (req3), req3->getID ());
std::mutex m;
auto callback = std::bind (test_callback, &num_called, &m, &cv);
- Request *req = new Request (NPUINPUT_HOST);
+ /** no API provided */
+ Scheduler *sched = new Scheduler (nullptr);
+ Request *req = sched->createRequest (NPUINPUT_HOST);
+ ASSERT_NE (req, nullptr);
+
req->setModel (model.get ());
req->setInferData (buffer.get ());
req->setCallback (callback);
- Scheduler *sched;
- /** no API provided */
- sched = new Scheduler (nullptr);
- EXPECT_NE (sched->submitRequest (req), 0);
+ EXPECT_LT (sched->submitRequest (req), 0);
+ sched->removeRequest (req);
delete sched;
/** no request provided */
sched = new Scheduler (api.get ());
+ req = sched->createRequest (NPUINPUT_HOST);
+ ASSERT_NE (req, nullptr);
+
+ req->setModel (model.get ());
+ req->setInferData (buffer.get ());
+ req->setCallback (callback);
+
EXPECT_NE (sched->submitRequest (nullptr), 0);
EXPECT_EQ (sched->submitRequest (req), req->getID ());
buffer->alloc (4096);
Scheduler *sched = new Scheduler (api.get ());
-
Request *req;
+
/** requests with not-supported opmode */
- req = new Request (NPUINPUT_INTERNAL_CAM);
+ req = sched->createRequest (NPUINPUT_INTERNAL_CAM);
+ ASSERT_NE (req, nullptr);
+
req->setModel (model.get ());
req->setInferData (buffer.get ());
- EXPECT_NE (sched->submitRequest (req), 0);
+ EXPECT_LT (sched->submitRequest (req), 0);
+ sched->removeRequest (req);
+
+ req = sched->createRequest (NPUINPUT_I2S_MIC);
+ ASSERT_NE (req, nullptr);
- req = new Request (NPUINPUT_I2S_MIC);
req->setModel (model.get ());
req->setInferData (buffer.get ());
- EXPECT_NE (sched->submitRequest (req), 0);
+ EXPECT_LT (sched->submitRequest (req), 0);
+ sched->removeRequest (req);
delete sched;
}
+
/**
* @brief test submitRequest() with empty request
*/
ASSERT_NE (api.get (), nullptr);
Scheduler *sched = new Scheduler (api.get ());
- Request *req = new Request (NPUINPUT_HOST);
-
- EXPECT_NE (sched->submitRequest (req), 0);
+ Request *req = sched->createRequest (NPUINPUT_HOST);
+ ASSERT_NE (req, nullptr);
+ EXPECT_LT (sched->submitRequest (req), 0);
+ sched->removeRequest (req);
delete sched;
}
+
/**
* @brief main function for unit test
*/
putNPUdevice (dev);
}
+typedef struct {
+ std::mutex m;
+ std::condition_variable cv;
+ bool done;
+} test_sync;
+
+static void
+test_callback (output_buffers *output, int req_id, void *data) {
+ test_sync *sync = static_cast<test_sync *> (data);
+
+ free (output->bufs[0].addr);
+
+ std::unique_lock<std::mutex> lock (sync->m);
+ sync->done = true;
+ sync->cv.notify_one ();
+}
+
+/**
+ * @brief test request decoupled APIs
+ */
+TEST (ne_libnpuhost_test, request_decoupled_apis) {
+ npudev_h dev;
+ uint32_t modelid;
+
+ std::string model_dir (NE_DATADIR);
+ model_dir += "/testdata/TRIV235_2TOPS/CONV_2D_000";
+
+ std::string model_path = model_dir + "/model.tvn";
+
+ off_t model_size = get_file_size (model_path.c_str ());
+ if (model_size <= 0)
+ /* skip */
+ return;
+
+ generic_buffer modelfile;
+ modelfile.type = BUFFER_FILE;
+ modelfile.filepath = model_path.c_str ();
+ modelfile.size = model_size;
+
+ ASSERT_EQ (getNPUdeviceByTypeAny (&dev, NPUCOND_TRIV2_CONN_SOCIP, 2), 0);
+ ASSERT_EQ (registerNPUmodel (dev, &modelfile, &modelid), 0);
+
+ /* tensor input/output data */
+ generic_buffers input, output = {0};
+ std::string input_path = model_dir + "/input_fmap_0.bin";
+ std::string output_path = model_dir + "/output_fmap_0.bin";
+
+ input.num_buffers = 1;
+ input.bufs[0].size = get_file_size (input_path.c_str ());
+ input.bufs[0].filepath = input_path.c_str ();
+ input.bufs[0].type = BUFFER_FILE;
+
+ /* tensor data info */
+ tensors_data_info info_in, info_out;
+
+ info_in.num_info = 1;
+ info_in.info[0].layout = DATA_LAYOUT_NHWC;
+ info_in.info[0].type = DATA_TYPE_QASYMM8;
+
+ info_out.num_info = 1;
+ info_out.info[0].layout = DATA_LAYOUT_NHWC;
+ info_out.info[0].type = DATA_TYPE_QASYMM8;
+
+ /* misc (optional) */
+ npu_constraint constraint;
+
+ constraint.timeout_ms = 1000;
+ constraint.priority = NPU_PRIORITY_MID;
+ constraint.notimode = NPU_INTERRUPT;
+
+ /* actual testing (blocking) */
+ int req_id;
+ EXPECT_EQ (createNPU_request (dev, modelid, &req_id), 0);
+ EXPECT_EQ (
+ setNPU_requestData (dev, req_id, &input, &info_in, &output, &info_out),
+ 0);
+ EXPECT_EQ (setNPU_requestMode (dev, req_id, NPU_INFER_BLOCKING), 0);
+ EXPECT_EQ (setNPU_requestConstraint (dev, req_id, constraint), 0);
+ EXPECT_GE (submitNPU_request (dev, req_id), 0);
+
+ /* actual testing (non-blocking) */
+ test_sync sync;
+ sync.done = false;
+
+ EXPECT_EQ (createNPU_request (dev, modelid, &req_id), 0);
+ EXPECT_EQ (
+ setNPU_requestData (dev, req_id, &input, &info_in, &output, &info_out),
+ 0);
+ EXPECT_EQ (setNPU_requestMode (dev, req_id, NPU_INFER_NON_BLOCKING), 0);
+ EXPECT_EQ (setNPU_requestCallback (dev, req_id, test_callback, &sync), 0);
+ EXPECT_EQ (setNPU_requestConstraint (dev, req_id, constraint), 0);
+ EXPECT_GE (submitNPU_request (dev, req_id), 0);
+
+ std::unique_lock<std::mutex> lock (sync.m);
+ sync.cv.wait (lock, [&]() { return sync.done == true; });
+
+ putNPUdevice (dev);
+}
+
/**
* @brief main function for unit test
*/