This patch performs refactoring for input services.
Signed-off-by: Dongju Chae <dongju.chae@samsung.com>
'ne-handler.cc',
'ne-profiler.cc',
'ne-scheduler.cc',
+ 'ne-request.cc',
'ne-host-input-service.cc',
'ne-hw-input-service.cc',
'ne-thread-pool.cc'
return -ENOENT;
}
- if (req->isSubmitted ()) {
+ if (req->isSubmitted () && req->getOpmode () != NPUINPUT_HW_RECURRING) {
logerr (TAG, "The request is not handled yet\n");
return -EBUSY;
}
- if (req->getOpmode () == NPUINPUT_HW_RECURRING) {
- int status = api_->stop_target (req_id);
- if (status != 0) {
- logerr (TAG, "Unable to stop the target request %d\n", req_id);
- return status;
- }
- }
-
scheduler_->removeRequest (req);
return 0;
}
std::unique_ptr<HostInputService> HostInputService::instance_;
std::once_flag HostInputService::once_flag_;
+/**
+ * @brief get singleton instance
+ */
HostInputService &
HostInputService::getInstance () {
call_once (once_flag_, []() { instance_.reset (new HostInputService); });
return *(instance_.get ());
}
-int
-HostInputService::submit (const DriverAPI *api, int id, const Model *model,
- 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, param);
- } else if (dynamic_cast<SegmentTable *> (data)) {
- if (model == nullptr)
- return -EINVAL;
- return submit_segt (api, id, model, dynamic_cast<SegmentTable *> (data),
- callback, param);
- } else {
- return -EINVAL;
- }
-}
-
/**
* @brief submit the request to the thread pool
- * @param[in] api the driver API
- * @param[in] id the request id
- * @param[in] model the target model
- * @param[in] buffer the target buffer
+ * @param[in] api device driver api
+ * @param[in] req request instance
* @param[in] callback output callback
- * @return task id if no error, otherwise a negative errno.
+ * @return 0 if no error, otherwise a negative errno
*/
int
-HostInputService::submit_buffer (const DriverAPI *api, int id,
- const Model *model, Buffer *buffer,
- outputCallback callback,
- const npumgr_param *param) {
- taskFunc func = std::bind (&HostInputService::invoke_buffer, this, api, model,
- buffer, callback, id, param);
- ThreadTask *task = new ThreadTask (id, func);
+HostInputService::submit (const DriverAPI *api, const Request *req,
+ outputCallback callback) {
+ if (api == nullptr || req == nullptr) {
+ logerr (TAG, "Invalid arguments\n");
+ return -EINVAL;
+ }
- return ThreadPool::getInstance ().enqueueTask (task);
-}
+ if (req->getOpmode () != NPUINPUT_HOST) {
+ logerr (TAG, "Unmatched opmode\n");
+ return -EINVAL;
+ }
-/**
- * @brief submit the request to the thread pool
- * @param[in] api the driver API
- * @param[in] id the request id
- * @param[in] model the target model
- * @param[in] segt the target segment table
- * @param[in] callback output callback
- * @return 0 if no error, otherwise a negative errno.
- */
-int
-HostInputService::submit_segt (const DriverAPI *api, int id, const Model *model,
- SegmentTable *segt, outputCallback callback,
- const npumgr_param *param) {
- taskFunc func = std::bind (&HostInputService::invoke_segt, this, api, model,
- segt, callback, id, param);
- ThreadTask *task = new ThreadTask (id, func);
+ if (req->getInferData () == nullptr) {
+ logerr (TAG, "inference data is not set\n");
+ return -EINVAL;
+ }
+ taskFunc func =
+ std::bind (&HostInputService::invoke, this, api, req, callback);
+ ThreadTask *task = new ThreadTask (req->getID (), func);
return ThreadPool::getInstance ().enqueueTask (task);
}
/**
* @brief remove the submitted request (if possible)
+ * @param[in] api device driver api
* @param[in] id the request id to be removed
* @return 0 if no erorr. otherwise a negative errno
*/
int
-HostInputService::remove (int id) {
+HostInputService::remove (const DriverAPI *api, int id) {
return ThreadPool::getInstance ().removeTask (id);
}
/**
- * @brief invoke the request using APIs
- * @param[in] api the driver API
- * @param[in] model the target model
- * @param[in] buffer the target buffer
- * @param[in] callback output callback
- * @return 0 if no error, otherwise a negative errno
- * @note this function should be used with TRIV driver!
+ * @brief invoke inference with the buffer (TRIV-1)
+ * @param[in] api device driver api
+ * @param[in] req request instance
+ * @return 0 if no erorr. otherwise a negative errno
*/
-int
-HostInputService::invoke_buffer (const DriverAPI *api, const Model *model,
- Buffer *buffer, outputCallback callback,
- int req_id, const npumgr_param *param) {
- input_config_t input_config;
- device_state_t state;
- int ret = -EINVAL;
-
- state = api->isReady ();
- if (state != device_state_t::TRINITY_STATE_READY) {
- logerr (TAG, "device is not available to run inference %d\n", state);
- goto handle_callback;
- }
-
+static int
+invoke_buffer (const DriverAPI *api, const Request *req) {
/** internal logic error */
- assert (buffer != nullptr);
+ assert (api != nullptr);
+ assert (req != nullptr);
- if (model != nullptr) {
- /** consider NOP cases */
- if (model->getProgramData () == nullptr) {
- ret = 0;
- goto handle_callback;
- }
+ Buffer *buffer = dynamic_cast<Buffer *> (req->getInferData ());
+ assert (buffer != nullptr);
- input_config.model_id = model->getInternalID ();
- } else {
- input_config.model_id = 0;
- }
+ const Model *model = req->getModel ();
+ assert (model != nullptr);
+ input_config_t input_config;
+ input_config.model_id = model->getInternalID ();
input_config.dbuf_fd = buffer->getDmabuf ();
+ input_config.req_id = req->getID ();
input_config.activation_offset_addr0 = buffer->getOffset ();
input_config.activation_offset_addr1 = buffer->getOffset ();
- input_config.req_id = req_id;
+
+ /** npumgr-specific parameters */
+ const npumgr_param *param = req->getNpumgrParam ();
+ 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;
+ }
/** run the inference with the input */
- ret = api->runInput (&input_config);
+ int ret = api->runInput (&input_config);
if (ret < 0 && ret != -ECANCELED)
logerr (TAG, "Failed to run the NPU inference: %d\n", ret);
-handle_callback:
- /** should call the callback regardless of failure, to avoid deadlock */
- if (callback != nullptr)
- callback ();
-
return ret;
}
/**
- * @brief invoke the request using APIs
- * @param[in] api the driver API
- * @param[in] model the target model
- * @param[in] segt the target segment table
- * @param[in] callback output callback
- * @return 0 if no error, otherwise a negative errno
- * @note this function should be used with TRIV2 driver!
+ * @brief invoke inference with the segment table (TRIV-2)
+ * @param[in] api device driver api
+ * @param[in] req request instance
+ * @return 0 if no erorr. otherwise a negative errno
*/
-int
-HostInputService::invoke_segt (const DriverAPI *api, const Model *model,
- SegmentTable *segt, outputCallback callback,
- int req_id, const npumgr_param *param) {
- input_config_t input_config;
- device_state_t state;
- npuConstraint constraint;
- int ret = -EINVAL;
+static int
+invoke_segt (const DriverAPI *api, const Request *req) {
+ /** internal logic error */
+ assert (api != nullptr);
+ assert (req != nullptr);
- state = api->isReady ();
- if (state != device_state_t::TRINITY_STATE_READY) {
- logerr (TAG, "device is not available to run inference %d\n", state);
- goto handle_callback;
- }
+ SegmentTable *segt = dynamic_cast<SegmentTable *> (req->getInferData ());
+ assert (segt != nullptr);
- /** internal logic error */
+ const Model *model = req->getModel ();
assert (model != nullptr);
- assert (segt != nullptr);
- /** consider NOP cases */
- if (model->getProgramData () == nullptr) {
- ret = 0;
- goto handle_callback;
- }
+ input_config_t input_config;
+ input_config.model_id = model->getInternalID ();
+ input_config.dbuf_fd = segt->getDmabuf ();
+ input_config.req_id = req->getID ();
+ input_config.num_segments = segt->getNumTotalSegments ();
- /** npumgr parameter setting if exists */
+ /** npumgr-specific parameters */
+ const npumgr_param *param = req->getNpumgrParam ();
if (param != nullptr) {
input_config.task_handle = param->task_handle;
input_config.subtask_idx = param->subtask_idx;
input_config.subtask_idx = UINT32_MAX;
}
- input_config.model_id = model->getInternalID ();
- input_config.dbuf_fd = segt->getDmabuf ();
- input_config.num_segments = segt->getNumTotalSegments ();
-
/** set constraints */
- constraint = model->getConstraint ();
+ npu_constraint constraint = model->getConstraint ();
input_config.timeout_ms = constraint.timeout_ms;
input_config.priority = constraint.priority;
-
/** input handling by CPU. host inputservice only supports CPU mode */
input_config.input_mode = TRINITY_INPUT_CPU;
-
/** output handling by CPU, host inputservice only supports either interrupt or polling */
if (constraint.notimode == NPU_POLLING) {
input_config.output_mode = TRINITY_OUTPUT_CPU_POLL;
input_config.output_mode = TRINITY_OUTPUT_CPU_INTR;
}
- input_config.req_id = req_id;
/** run the inference with the input */
- ret = api->runInput (&input_config);
+ int ret = api->runInput (&input_config);
if (ret < 0 && ret != -ECANCELED)
logerr (TAG, "Failed to run the NPU inference: %d\n", ret);
+ return ret;
+}
+
+/**
+ * @brief invoke the given request using the driver API
+ * @param[in] api device driver api
+ * @param[in] req request instance
+ * @param[in] callback output callback
+ * @return 0 if no error, otherwise a negative errno
+ */
+int
+HostInputService::invoke (const DriverAPI *api, const Request *req,
+ outputCallback callback) {
+ device_state_t state;
+ const Model *model;
+ HWmem *data;
+ int ret = -EINVAL;
+
+ /** internal logic error */
+ assert (api != nullptr);
+ assert (req != nullptr);
+
+ model = req->getModel ();
+ if (model == nullptr) {
+ logerr (TAG, "unable to find the target model\n");
+ goto handle_callback;
+ }
+
+ state = api->isReady ();
+ if (state != device_state_t::TRINITY_STATE_READY) {
+ logerr (TAG, "device is not available to run inference %d\n", state);
+ goto handle_callback;
+ }
+
+ if (model->getProgramData () == nullptr) {
+ ret = 0;
+ goto handle_callback;
+ }
+
+ data = req->getInferData ();
+ if (dynamic_cast<Buffer *> (data))
+ ret = invoke_buffer (api, req);
+ else if (dynamic_cast<SegmentTable *> (data))
+ ret = invoke_segt (api, req);
+ else /* no inference data; skip */
+ ret = 0;
+
handle_callback:
- /** should call the callback regardless of failure, to avoid deadlock */
if (callback != nullptr)
callback ();
}
/**
- * @brief submit the request to the thread pool
- * @param[in] api the driver API
- * @param[in] id the request id
- * @param[in] model the target model
- * @param[in] data the inference data
+ * @brief submit the request directly
+ * @param[in] api device driver api
+ * @param[in] req request instance
* @param[in] callback output callback
- * @return req_id if no error, otherwise a negative errno.
+ * @return 0 if no error, otherwise a negativ errno
*/
int
-HwInputService::submit (const DriverAPI *api, int id, const Model *model,
- HWmem *data, outputCallback callback,
- const npumgr_param *param) {
- if (api == nullptr || model == nullptr)
+HwInputService::submit (const DriverAPI *api, const Request *req,
+ outputCallback callback) {
+ if (api == nullptr || req == nullptr) {
+ logerr (TAG, "Invalid arguments\n");
return -EINVAL;
+ }
+
+ if (req->getOpmode () != NPUINPUT_HW_RECURRING) {
+ logerr (TAG, "Unmatched opmode\n");
+ return -EINVAL;
+ }
- SegmentTable *segt = dynamic_cast<SegmentTable *> (data);
- if (segt == nullptr)
+ if (req->getInferData () == nullptr) {
+ logerr (TAG, "inference data is not set\n");
return -EINVAL;
+ }
- return invoke (api, model, segt, callback, id, param);
+ return invoke (api, req, callback);
}
/**
- * @brief invoke the request using APIs
- * @param[in] api the driver API
- * @param[in] model the target model
- * @param[in] segt the target segment table
- * @param[in] callback output callback
- * @return req_id if no error, otherwise a negative errno
+ * @brief remove the submitted request (if possible)
+ * @param[in] api device driver api
+ * @param[in] id the request id to be removed
+ * @return 0 if no erorr. otherwise a negative errno
*/
int
-HwInputService::invoke (const DriverAPI *api, const Model *model,
- SegmentTable *segt, outputCallback callback, int req_id,
- const npumgr_param *param) {
- input_config_t input_config;
- device_state_t state;
- npuConstraint constraint;
- int ret = -EINVAL;
-
- state = api->isReady ();
- if (state != device_state_t::TRINITY_STATE_READY) {
- logerr (TAG, "device is not available to run inference %d\n", state);
- goto handle_callback;
+HwInputService::remove (const DriverAPI *api, int id) {
+ if (api == nullptr || id < 0) {
+ logerr (TAG, "Invalid arguments\n");
+ return -EINVAL;
}
- if (model == nullptr) {
- logerr (TAG, "No valid model provided\n");
- goto handle_callback;
- }
+ return api->stop_target (id);
+}
- /** consider NOP cases */
- if (model->getProgramData () == nullptr) {
- ret = 0;
- goto handle_callback;
- }
+/**
+ * @brief invoke inference with the segment table (TRIV-2)
+ * @param[in] api device driver api
+ * @param[in] req request instance
+ * @return 0 if no erorr. otherwise a negative errno
+ */
+static int
+invoke_segt (const DriverAPI *api, const Request *req) {
+ /** internal logic error */
+ assert (api != nullptr);
+ assert (req != nullptr);
+ SegmentTable *segt = dynamic_cast<SegmentTable *> (req->getInferData ());
+ assert (segt != nullptr);
+
+ const Model *model = req->getModel ();
+ assert (model != nullptr);
+
+ input_config_t input_config;
input_config.model_id = model->getInternalID ();
- if (segt != nullptr) {
- input_config.dbuf_fd = segt->getDmabuf ();
- input_config.num_segments = segt->getNumTotalSegments ();
+ input_config.dbuf_fd = segt->getDmabuf ();
+ input_config.req_id = req->getID ();
+ input_config.num_segments = segt->getNumTotalSegments ();
+
+ /** npumgr-specific parameters */
+ const npumgr_param *param = req->getNpumgrParam ();
+ if (param != nullptr) {
+ input_config.task_handle = param->task_handle;
+ input_config.subtask_idx = param->subtask_idx;
} else {
- /** some instructions do not require the segment table (e.g., nop) */
- input_config.dbuf_fd = -1;
- input_config.num_segments = 0;
+ input_config.task_handle = UINT32_MAX;
+ input_config.subtask_idx = UINT32_MAX;
}
/** set constraints */
- constraint = model->getConstraint ();
input_config.timeout_ms = 0; /* immediatedly handled */
input_config.priority = NPU_PRIORITY_HIGH;
input_config.input_mode = TRINITY_INPUT_HW;
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;
- }
- input_config.req_id = req_id;
-
/** run the inference with the input */
- ret = api->runInput (&input_config);
+ int ret = api->runInput (&input_config);
if (ret < 0 && ret != -ECANCELED)
logerr (TAG, "Failed to run the NPU inference: %d\n", ret);
+ return ret;
+}
+
+/**
+ * @brief invoke the given request using the driver API
+ * @param[in] api device driver api
+ * @param[in] req request instance
+ * @param[in] callback output callback
+ * @return req_id if no error, otherwise a negative errno
+ */
+int
+HwInputService::invoke (const DriverAPI *api, const Request *req,
+ outputCallback callback) {
+ device_state_t state;
+ const Model *model;
+ HWmem *data;
+ int ret = -EINVAL;
+
+ /** internal logic error */
+ assert (api != nullptr);
+ assert (req != nullptr);
+
+ model = req->getModel ();
+ if (model == nullptr || model->getProgramData () == nullptr) {
+ logerr (TAG, "unable to find the target model\n");
+ goto handle_callback;
+ }
+
+ state = api->isReady ();
+ if (state != device_state_t::TRINITY_STATE_READY) {
+ logerr (TAG, "device is not available to run inference %d\n", state);
+ goto handle_callback;
+ }
+
+ data = req->getInferData ();
+ if (dynamic_cast<SegmentTable *> (data))
+ ret = invoke_segt (api, req);
+ else /* no inference data; skip */
+ ret = 0;
+
handle_callback:
- /** should call the callback regardless of failure, to avoid deadlock */
if (callback != nullptr)
callback ();
#include "ne-model.h"
#include "ne-buffer.h"
#include "ne-segment-table.h"
+#include "ne-request.h"
#include <memory>
#include <mutex>
class InputService {
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,
- const npumgr_param *param = nullptr) {
+ virtual int submit (const DriverAPI *api, const Request *request,
+ outputCallback callback = nullptr) {
return -EPERM;
}
- /** @brief [OPTIONAL] remove the submitted request (if possible) */
- virtual int remove (int request_id) { return -EINVAL; }
-
+ /** @brief remove the submitted request (if possible) */
+ virtual int remove (const DriverAPI *api, int request_id) { return -EPERM; }
virtual ~InputService () {}
protected:
public:
static HostInputService &getInstance ();
- int submit (const DriverAPI *api, int request_id, const Model *model,
- HWmem *data, outputCallback callback = nullptr,
- const npumgr_param *param = nullptr);
- int remove (int request_id);
+ int submit (const DriverAPI *api, const Request *request,
+ outputCallback callback = nullptr);
+ int remove (const DriverAPI *api, int request_id);
private:
- int submit_buffer (const DriverAPI *api, int request_id, const Model *model,
- 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,
- 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,
- const npumgr_param *param);
- int invoke_segt (const DriverAPI *api, const Model *model, SegmentTable *segt,
- outputCallback callback, int task_id,
- const npumgr_param *param);
-
+ int invoke (const DriverAPI *api, const Request *request,
+ outputCallback callback = nullptr);
+ /** singleton pattern */
static std::unique_ptr<HostInputService> instance_;
static std::once_flag once_flag_;
};
public:
static HwInputService &getInstance ();
- int submit (const DriverAPI *api, int request_id, const Model *model,
- HWmem *data, outputCallback callback = nullptr,
- const npumgr_param *param = nullptr);
+ int submit (const DriverAPI *api, const Request *request,
+ outputCallback callback = nullptr);
+ int remove (const DriverAPI *api, int request_id);
private:
- /** do not allow to directly call invoke () */
- int invoke (const DriverAPI *api, const Model *model, SegmentTable *segt,
- outputCallback callback, int task_id,
- const npumgr_param *param = nullptr);
-
+ int invoke (const DriverAPI *api, const Request *request,
+ outputCallback callback = nullptr);
+ /** singleton pattern */
static std::unique_ptr<HwInputService> instance_;
static std::once_flag once_flag_;
};
--- /dev/null
+/**
+ * Proprietary
+ * Copyright (C) 2021 Samsung Electronics
+ * Copyright (C) 2021 Dongju Chae <dongju.chae@samsung.com>
+ */
+/**
+ * @file ne-request.cc
+ * @date 30 June 2021
+ * @brief Implementation of the request class
+ * @author Dongju Chae <dongju.chae@samsung.com>
+ * @bug No known bugs except for NYI items
+ */
+
+#include "ne-request.h"
+
+std::atomic<int> Request::global_request_id_ (1);
+
+/** @brief constructor of request class */
+Request::Request ()
+ : opmode_ (NPUINPUT_HOST),
+ force_stop_ (false),
+ stopped_ (false),
+ preserved_ (false),
+ submitted_ (false),
+ model_ (nullptr),
+ data_ (nullptr),
+ cb_ (nullptr),
+ out_bufs_ (nullptr),
+ infer_mode_ (NPU_INFER_BLOCKING /* default */),
+ npumgr_param_ (nullptr) {
+ request_id_ = Request::global_request_id_.fetch_add (1);
+}
+
+/** @brief destructor of request class */
+Request::~Request () {
+ if (npumgr_param_ != nullptr)
+ delete npumgr_param_;
+
+ if (data_ != nullptr)
+ delete data_;
+}
--- /dev/null
+/**
+ * Proprietary
+ * Copyright (C) 2021 Samsung Electronics
+ * Copyright (C) 2021 Dongju Chae <dongju.chae@samsung.com>
+ */
+/**
+ * @file ne-request.h
+ * @date 30 June 2021
+ * @brief Internal data structure for requests.
+ * @see https://code.sec.samsung.net/confluence/display/ODLC/2020+Overall+Software+Stack
+ * @author Dongju Chae <dongju.chae@samsung.com>
+ * @bug No known bugs except for NYI items
+ */
+#ifndef NE_REQUEST_H__
+#define NE_REQUEST_H__
+
+#include <atomic>
+
+#include <typedef.h>
+
+#include "ne-model.h"
+#include "ne-hwmem.h"
+
+/** @brief class def. of requests created from host handler */
+
+class Request {
+ public:
+ Request ();
+ ~Request ();
+
+ void setModel (const Model *model) { model_ = model; }
+ const Model *getModel () const { return model_; }
+
+ void setInferData (HWmem *data) { data_ = data; }
+ HWmem *getInferData () const { return data_; }
+
+ void setCallback (outputCallback cb) { cb_ = cb; }
+ outputCallback getCallback () const { return cb_; }
+
+ void setForceStop (bool force_stop) { force_stop_ = force_stop; }
+ bool getForceStop () const { return force_stop_; }
+
+ void setPreserved (bool preserved) { preserved_ = preserved; }
+ bool isPreserved () const { return preserved_; }
+
+ void setSubmitted (bool submitted) { submitted_ = submitted; }
+ bool isSubmitted () const { return submitted_; }
+
+ void setOpmode (npu_input_opmode opmode) { opmode_ = opmode; }
+ npu_input_opmode getOpmode () const { return opmode_; }
+ int getID () const { return request_id_; }
+
+ void setStopped () { stopped_ = true; }
+ bool isStopped () const { return stopped_; }
+
+ void setHwDevice (std::string hw_dev) { hw_dev_ = hw_dev; }
+ std::string getHwDevice () const { return hw_dev_; }
+
+ void setOutputBuffers (output_buffers *out_bufs) { out_bufs_ = out_bufs; }
+ output_buffers *getOutputBuffers () const { return out_bufs_; }
+
+ void setInferMode (npu_infer_mode infer_mode) { infer_mode_ = infer_mode; }
+ npu_infer_mode getInferMode () const { return infer_mode_; }
+
+ void setNpumgrParam (const npumgr_param ¶m) {
+ if (npumgr_param_ == nullptr)
+ npumgr_param_ = new npumgr_param;
+ memcpy (npumgr_param_, ¶m, sizeof (npumgr_param));
+ }
+ const npumgr_param *getNpumgrParam () const { return npumgr_param_; }
+
+ private:
+ static std::atomic<int> global_request_id_;
+ int request_id_; /**< request id */
+
+ npu_input_opmode opmode_; /**< opmode of the request */
+ bool force_stop_; /**< indicates force stop */
+ bool stopped_; /**< stopped request */
+ bool preserved_; /**< preserved request */
+ bool submitted_; /**< submitted request */
+
+ const Model *model_; /**< model of the request */
+ HWmem *data_; /**< inference data of the request */
+
+ 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_;
+};
+
+#endif /* NE_REQUEST_H__ */
#define TAG _N3
-std::atomic<int> Request::global_request_id_ (1);
-
-/** @brief constructor of request class */
-Request::Request ()
- : opmode_ (NPUINPUT_HOST),
- force_stop_ (false),
- stopped_ (false),
- preserved_ (false),
- submitted_ (false),
- model_ (nullptr),
- data_ (nullptr),
- cb_ (nullptr),
- out_bufs_ (nullptr),
- infer_mode_ (NPU_INFER_BLOCKING /* default */),
- npumgr_param_ (nullptr) {
- request_id_ = Request::global_request_id_.fetch_add (1);
-}
-
-/** @brief destructor of request class */
-Request::~Request () {
- if (npumgr_param_ != nullptr)
- delete npumgr_param_;
-
- if (data_ != nullptr)
- delete data_;
-}
-
/** @brief destructor of scheduler class */
Scheduler::~Scheduler () {
/** wait until all callbacks are called */
int
Scheduler::handleStop (Request *req) {
if (req->getForceStop ()) {
- std::function<bool(Request *)> functor = [](Request *r) -> bool {
+ std::function<bool(Request *)> functor = [this](Request *r) -> bool {
InputService *service = getInputService (r->getOpmode ());
/* remove a request if it's not scheduled */
- if (service->remove (r->getID ()) != 0) {
+ if (service->remove (api_, r->getID ()) != 0) {
/* In case of already-served requests, let's mark it as stopped */
r->setStopped ();
return false;
}
/**
- * @brief handle inference request with input data from host
- * @param[in] req the request instance
- * @param[in] service the input service
- * @return 0 if no error. otherwise a negative errno.
- */
-int
-Scheduler::handleHostInput (Request *req, InputService *service) {
- int req_id = req->getID ();
- const Model *model = req->getModel ();
- HWmem *data = req->getInferData ();
- auto callback = std::bind (&Scheduler::handleCallback, this, req);
- const npumgr_param *param = req->getNpumgrParam ();
-
- req->setSubmitted (true);
-
- int status = service->submit (api_, req_id, model, data, callback, param);
- if (status < 0)
- req->setSubmitted (false);
-
- return status;
-}
-
-/**
- * @brief handle inference request with input data from hw device
- * @param[in] req the request instance
- * @param[in] service the input service
- * @return 0 if no error. otherwise a negative errno.
- */
-int
-Scheduler::handleHwInput (Request *req, InputService *service) {
- int req_id = req->getID ();
- const Model *model = req->getModel ();
- HWmem *data = req->getInferData ();
- auto callback = std::bind (&Scheduler::handleCallback, this, req);
- const npumgr_param *param = req->getNpumgrParam ();
-
- /* task id is obtained from a device driver */
- return service->submit (api_, req_id, model, data, callback, param);
-}
-
-/**
* @brief create a request to be scheduled
* @return new request instance
*/
*/
void
Scheduler::removeRequest (Request *req) {
- if (req)
- request_map_.remove (req->getID ());
+ if (!req)
+ return;
+
+ InputService *service;
+ int req_id = req->getID ();
+
+ service = getInputService (req->getOpmode ());
+ if (service)
+ service->remove (api_, req_id);
+ request_map_.remove (req_id);
}
/**
}
npu_input_opmode opmode = req->getOpmode ();
- InputService *service = getInputService (opmode);
+ if (opmode == NPUINPUT_STOP)
+ return handleStop (req);
- switch (opmode) {
- case NPUINPUT_STOP:
- return handleStop (req);
- case NPUINPUT_HOST:
- return handleHostInput (req, service);
- break;
- case NPUINPUT_HW_RECURRING:
- return handleHwInput (req, service);
- break;
- default:
- return -EINVAL;
+ InputService *service = getInputService (opmode);
+ if (!service) {
+ logerr (TAG, "No available input service for opmode %d\n", opmode);
+ return -ENOENT;
}
+
+ req->setSubmitted (true);
+ int ret = service->submit (api_, req,
+ std::bind (&Scheduler::handleCallback, this, req));
+ if (ret != 0)
+ req->setSubmitted (false);
+
+ return ret;
}
/**
#include "ne-utils.h"
#include "ne-common.h"
#include "ne-inputservice.h"
+#include "ne-request.h"
#include <atomic>
-/** @brief class def. of requests created from host handler */
-
-class Request {
- public:
- Request ();
- ~Request ();
-
- void setModel (const Model *model) { model_ = model; }
- const Model *getModel () { return model_; }
-
- void setInferData (HWmem *data) { data_ = data; }
- HWmem *getInferData () { return data_; }
-
- void setCallback (outputCallback cb) { cb_ = cb; }
- outputCallback getCallback () { return cb_; }
-
- void setForceStop (bool force_stop) { force_stop_ = force_stop; }
- bool getForceStop () { return force_stop_; }
-
- void setPreserved (bool preserved) { preserved_ = preserved; }
- bool isPreserved () { return preserved_; }
-
- void setSubmitted (bool submitted) { submitted_ = submitted; }
- bool isSubmitted () { return submitted_; }
-
- void setOpmode (npu_input_opmode opmode) { opmode_ = opmode; }
- npu_input_opmode getOpmode () { return opmode_; }
- int getID () { return request_id_; }
-
- void setStopped () { stopped_ = true; }
- bool isStopped () { return stopped_; }
-
- void setHwDevice (std::string hw_dev) { hw_dev_ = hw_dev; }
- std::string getHwDevice () { return hw_dev_; }
-
- 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) {
- if (npumgr_param_ == nullptr)
- npumgr_param_ = new npumgr_param;
- 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 */
-
- npu_input_opmode opmode_; /**< opmode of the request */
- bool force_stop_; /**< indicates force stop */
- bool stopped_; /**< stopped request */
- bool preserved_; /**< preserved request */
- bool submitted_; /**< submitted request */
-
- const Model *model_; /**< model of the request */
- HWmem *data_; /**< inference data of the request */
-
- 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 */
class Scheduler {
public:
}
/**
- * @brief test features of submit() with a buffer
+ * @brief test features of submit() with host input service
*/
-TEST (ne_core_inputservice_test, host_submit) {
+TEST (ne_core_inputservice_test, submit_host_service) {
std::unique_ptr<DriverAPI> api;
+ npu_input_opmode opmode = NPUINPUT_HOST;
api = DriverAPI::createDriverAPI (NPUCOND_TRIV2_CONN_SOCIP, 0);
ASSERT_NE (api.get (), nullptr);
- /** create dummy model & buffer */
-
- Model *model = new Model (new HWmemDevice);
+ /** create dummy model */
+ std::unique_ptr<Model> model (new Model (new HWmemDevice));
model->setDriverAPI (api.get ());
EXPECT_EQ (model->alloc (4096), 0);
- Buffer *buffer = new Buffer (new HWmemDevice);
- buffer->setDriverAPI (api.get ());
- EXPECT_EQ (buffer->alloc (4096), 0);
+ std::unique_ptr<Request> req (new Request ());
+ req->setOpmode (opmode);
+ req->setModel (model.get ());
+ req->setInferData (new SegmentTable (new HWmemDevice));
HostInputService &service = HostInputService::getInstance ();
- EXPECT_EQ (service.submit (api.get (), 1, model, buffer), 0);
+ EXPECT_EQ (service.submit (api.get (), req.get ()), 0);
usleep (TEST_SLEEP_MS);
std::mutex m;
auto callback = std::bind (test_callback, &num_called, &m, &cv);
- EXPECT_EQ (service.submit (api.get (), 2, model, buffer, callback), 0);
- EXPECT_EQ (service.submit (api.get (), 3, model, buffer, callback), 0);
- EXPECT_EQ (service.submit (api.get (), 4, model, buffer, callback), 0);
+
+ EXPECT_EQ (service.submit (api.get (), req.get (), callback), 0);
+
+ std::unique_ptr<Request> req2 (new Request ());
+ req2->setOpmode (opmode);
+ req2->setModel (model.get ());
+ req2->setInferData (new Buffer (new HWmemDevice));
+
+ EXPECT_EQ (service.submit (api.get (), req2.get (), callback), 0);
+
+ std::unique_ptr<Request> req3 (new Request ());
+ req3->setOpmode (opmode);
+ req3->setModel (model.get ());
+ req3->setInferData (new SegmentTable (new HWmemDevice));
+
+ EXPECT_EQ (service.submit (api.get (), req3.get (), callback), 0);
wait_callbacks (num_called, 3, m, cv);
EXPECT_EQ (num_called, 3);
-
- delete model;
- delete buffer;
}
/**
* @brief test features of submit() with error handling
*/
-TEST (ne_core_inputservice_test, host_submit_args_n) {
+TEST (ne_core_inputservice_test, submit_host_service_args_n) {
std::unique_ptr<DriverAPI> api;
+ npu_input_opmode opmode = NPUINPUT_HOST;
+
api = DriverAPI::createDriverAPI (NPUCOND_TRIV2_CONN_SOCIP, 0);
ASSERT_NE (api.get (), nullptr);
/** create dummy model */
- Model *model = new Model (new HWmemDevice);
+ std::unique_ptr<Model> model (new Model (new HWmemDevice));
model->setDriverAPI (api.get ());
EXPECT_EQ (model->alloc (4096), 0);
HostInputService &service = HostInputService::getInstance ();
+ /** using buffer */
+ std::unique_ptr<Request> req (new Request ());
+ req->setOpmode (opmode);
+ req->setModel (model.get ());
+
+ EXPECT_NE (service.submit (nullptr, nullptr), 0);
+ EXPECT_NE (service.submit (api.get (), nullptr), 0);
+ EXPECT_NE (service.submit (nullptr, req.get ()), 0);
+ EXPECT_NE (service.submit (api.get (), req.get ()), 0);
+
Buffer *buffer = new Buffer (new HWmemDevice);
buffer->setDriverAPI (api.get ());
EXPECT_EQ (buffer->alloc (4096), 0);
- EXPECT_NE (service.submit (nullptr, 0, nullptr, buffer), 0);
- EXPECT_NE (service.submit (nullptr, 0, model, buffer), 0);
- EXPECT_EQ (service.submit (api.get (), 0, nullptr, buffer), 0);
- EXPECT_EQ (service.submit (api.get (), 1, model, buffer), 0);
+ req->setInferData (buffer);
+ EXPECT_EQ (service.submit (api.get (), req.get ()), 0);
+
+ /** using segment table */
+ std::unique_ptr<Request> req2 (new Request ());
+ req2->setOpmode (opmode);
+ req2->setModel (model.get ());
+
+ EXPECT_NE (service.submit (nullptr, nullptr), 0);
+ EXPECT_NE (service.submit (api.get (), nullptr), 0);
+ EXPECT_NE (service.submit (nullptr, req2.get ()), 0);
+ EXPECT_NE (service.submit (api.get (), req2.get ()), 0);
SegmentTable *segt = new SegmentTable (new HWmemDevice);
segt->setDriverAPI (api.get ());
EXPECT_EQ (segt->alloc (4096), 0);
- EXPECT_NE (service.submit (nullptr, 2, nullptr, segt), 0);
- EXPECT_NE (service.submit (nullptr, 2, model, segt), 0);
- EXPECT_NE (service.submit (api.get (), 2, nullptr, segt), 0);
- EXPECT_EQ (service.submit (api.get (), 2, model, segt), 0);
+ req2->setInferData (segt);
+ EXPECT_EQ (service.submit (api.get (), req2.get ()), 0);
usleep (TEST_SLEEP_MS);
-
- delete model;
- delete buffer;
- delete segt;
-}
-
-class TestInputService : public InputService {
- public:
- TestInputService (){};
-};
-
-/**
- * @brief test features of submit() with unsupported input service
- */
-TEST (ne_core_inputservice_test, host_submit_unsupported_n) {
- InputService *service = new TestInputService;
-
- EXPECT_NE (service->submit (nullptr, 0, nullptr, (Buffer *) nullptr), 0);
- EXPECT_NE (service->submit (nullptr, 0, nullptr, (SegmentTable *) nullptr),
- 0);
-
- delete service;
}
/**
* @brief test features of submit() with error handling
*/
-TEST (ne_core_inputservice_test, host_submit_same_id_n) {
+TEST (ne_core_inputservice_test, submit_hw_service_args_n) {
std::unique_ptr<DriverAPI> api;
+ npu_input_opmode opmode = NPUINPUT_HW_RECURRING;
+
api = DriverAPI::createDriverAPI (NPUCOND_TRIV2_CONN_SOCIP, 0);
ASSERT_NE (api.get (), nullptr);
/** create dummy model */
- Model *model = new Model (new HWmemDevice);
+ std::unique_ptr<Model> model (new Model (new HWmemDevice));
model->setDriverAPI (api.get ());
EXPECT_EQ (model->alloc (4096), 0);
- HostInputService &service = HostInputService::getInstance ();
+ HwInputService &service = HwInputService::getInstance ();
- int num_called = 0;
- std::condition_variable cv;
- std::mutex m;
+ /** using segment table */
+ std::unique_ptr<Request> req (new Request ());
+ req->setOpmode (opmode);
+ req->setModel (model.get ());
- auto callback = std::bind (test_callback_sleep, &num_called, &m, &cv);
+ EXPECT_NE (service.submit (nullptr, nullptr), 0);
+ EXPECT_NE (service.submit (api.get (), nullptr), 0);
+ EXPECT_NE (service.submit (nullptr, req.get ()), 0);
+ EXPECT_NE (service.submit (api.get (), req.get ()), 0);
- /** saturate requests up to the maximum (in thread pool) */
- uint32_t num_threads = ThreadPool::getInstance ().getNumThreads ();
+ SegmentTable *segt = new SegmentTable (new HWmemDevice);
+ segt->setDriverAPI (api.get ());
+ EXPECT_EQ (segt->alloc (4096), 0);
- Buffer *buffer = new Buffer (new HWmemDevice);
- buffer->setDriverAPI (api.get ());
- EXPECT_EQ (buffer->alloc (4096), 0);
+ req->setInferData (segt);
+ EXPECT_NE (service.submit (api.get (), req.get ()), 0);
+}
- for (uint32_t i = 0; i < num_threads + 1; i++)
- EXPECT_EQ (service.submit (api.get (), i, model, buffer, callback), 0);
+class TestInputService : public InputService {
+ public:
+ TestInputService (){};
+};
- /** there's a pending task with the same ID */
- EXPECT_NE (service.submit (api.get (), num_threads, model, buffer, callback),
- 0);
- EXPECT_NE (service.submit (api.get (), num_threads, model, buffer, callback),
- 0);
+/**
+ * @brief test features of submit() with unsupported input service
+ */
+TEST (ne_core_inputservice_test, host_submit_unsupported_n) {
+ InputService *service = new TestInputService;
- wait_callbacks (num_called, num_threads + 1, m, cv);
+ EXPECT_EQ (service->submit (nullptr, nullptr), -EPERM);
+ EXPECT_EQ (service->remove (nullptr, 0), -EPERM);
- delete model;
- delete buffer;
+ delete service;
}
/**
ASSERT_NE (api.get (), nullptr);
/** create dummy model */
- Model *model = new Model (new HWmemDevice);
+ std::unique_ptr<Model> model (new Model (new HWmemDevice));
model->setDriverAPI (api.get ());
EXPECT_EQ (model->alloc (4096), 0);
HostInputService &service = HostInputService::getInstance ();
+ npu_input_opmode opmode = NPUINPUT_HOST;
int num_called = 0;
std::condition_variable cv;
/** saturate requests up to the maximum (in thread pool) */
uint32_t num_threads = ThreadPool::getInstance ().getNumThreads ();
+ int req_id = 0;
+ for (uint32_t i = 0; i < num_threads + 1; i++) {
+ std::unique_ptr<Request> req (new Request ());
+ req->setOpmode (opmode);
+ req->setModel (model.get ());
+ req->setInferData (new SegmentTable (new HWmemDevice));
- Buffer *buffer = new Buffer (new HWmemDevice);
- buffer->setDriverAPI (api.get ());
- EXPECT_EQ (buffer->alloc (4096), 0);
-
- for (uint32_t i = 0; i < num_threads + 1; i++)
- EXPECT_EQ (service.submit (api.get (), i, model, buffer, callback), 0);
+ req_id = req->getID ();
+ EXPECT_EQ (service.submit (api.get (), req.get (), callback), 0);
+ }
/** remove un-resolved task */
- EXPECT_EQ (service.remove (num_threads), 0);
+ EXPECT_EQ (service.remove (nullptr, req_id), 0);
wait_callbacks (num_called, num_threads, m, cv);
-
- delete model;
- delete buffer;
}
/**
HostInputService &service = HostInputService::getInstance ();
/** no such tasks */
- EXPECT_NE (service.remove (0), 0);
- EXPECT_NE (service.remove (1), 0);
- EXPECT_NE (service.remove (2), 0);
-}
-
-/**
- * TODO: add testcases for HwInputService when implemeneted
- */
-
-/**
- * @brief test features of HW inputservice's submit()
- */
-TEST (ne_core_inputservice_test, hw_recurring_submit) {
- std::unique_ptr<DriverAPI> api;
- api = DriverAPI::createDriverAPI (NPUCOND_TRIV2_CONN_SOCIP, 0);
- ASSERT_NE (api.get (), nullptr);
-
- /** create dummy model */
- Model *model = new Model (new HWmemDevice);
- model->setDriverAPI (api.get ());
- EXPECT_EQ (model->alloc (4096), 0);
-
- HwInputService &service = HwInputService::getInstance ();
-
- int num_called = 0;
- std::condition_variable cv;
- std::mutex m;
-
- auto callback = std::bind (test_callback_sleep, &num_called, &m, &cv);
-
- SegmentTable *segt = new SegmentTable (new HWmemDevice);
- segt->setDriverAPI (api.get ());
- EXPECT_EQ (segt->alloc (4096), 0);
-
- EXPECT_EQ (service.submit (api.get (), 0, model, segt, callback), 0);
- EXPECT_EQ (service.submit (api.get (), 1, model, segt, callback), 0);
- EXPECT_EQ (service.submit (api.get (), 2, model, segt, nullptr), 0);
-
- /** remove is unsupported (it's designed to handle high priority tasks) */
- EXPECT_NE (service.remove (0), 0);
-
- wait_callbacks (num_called, 2, m, cv);
-
- delete model;
- delete segt;
-}
-
-/**
- * @brief test features of HW inputservice with error handling
- */
-TEST (ne_core_inputservice_test, hw_recurring_n) {
- std::unique_ptr<DriverAPI> api;
- api = DriverAPI::createDriverAPI (NPUCOND_TRIV2_CONN_SOCIP, 0);
- ASSERT_NE (api.get (), nullptr);
-
- /** create dummy model */
- Model *model = new Model (new HWmemDevice);
- model->setDriverAPI (api.get ());
- EXPECT_EQ (model->alloc (4096), 0);
-
- HwInputService &service = HwInputService::getInstance ();
-
- int num_called = 0;
- std::condition_variable cv;
- std::mutex m;
-
- auto callback = std::bind (test_callback_sleep, &num_called, &m, &cv);
-
- SegmentTable *segt = new SegmentTable (new HWmemDevice);
- segt->setDriverAPI (api.get ());
- EXPECT_EQ (segt->alloc (4096), 0);
-
- EXPECT_NE (service.submit (nullptr, 0, nullptr, segt, nullptr), 0);
- EXPECT_NE (service.submit (api.get (), 0, nullptr, segt, callback), 0);
- EXPECT_EQ (service.submit (api.get (), 0, model, segt, callback), 0);
- /** remove is unsupported (it's designed to handle high priority tasks) */
- EXPECT_NE (service.remove (0), 0);
-
- wait_callbacks (num_called, 1, m, cv);
-
- delete model;
- delete segt;
+ EXPECT_NE (service.remove (nullptr, 0), 0);
+ EXPECT_NE (service.remove (nullptr, 1), 0);
+ EXPECT_NE (service.remove (nullptr, 2), 0);
}
/**