[API] Add API to submit requests for kernel modules
authorDongju Chae <dongju.chae@samsung.com>
Fri, 18 Jun 2021 08:22:12 +0000 (17:22 +0900)
committer채동주/On-Device Lab(SR)/Staff Engineer/삼성전자 <dongju.chae@samsung.com>
Tue, 22 Jun 2021 02:08:57 +0000 (11:08 +0900)
This patch adds API to submit requests for kernel modules.

Signed-off-by: Dongju Chae <dongju.chae@samsung.com>
include/host/libnpuhost.h
src/core/ne-handler.cc
src/core/ne-handler.h
src/core/ne-scheduler.cc
src/core/ne-scheduler.h
src/host/ne-host.cc
tests/unittests/ne_libnpuhost_test.cc

index 3374cfc..cdf5e37 100644 (file)
@@ -513,6 +513,7 @@ int createNPU_request (npudev_h dev, uint32_t model_id, int *req_id);
  * @note The data and its data info are user-expected ones. When data format/type are
  *       different from the model-assumed ones, npu-engine performs data manipulation
  *       internally (e.g., NHWC <-> TRIV2).
+ * @note it's not necessary if you're going to use submitNPU_requestKernel()
  */
 int setNPU_requestData (npudev_h dev, int req_id, input_buffers *input,
                         tensors_data_info *in_info, output_buffers *output,
@@ -525,6 +526,7 @@ int setNPU_requestData (npudev_h dev, int req_id, input_buffers *input,
  * @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
+ * @note it's not necessary if you're going to use submitNPU_requestKernel()
  */
 int setNPU_requestCallback (npudev_h dev, int req_id, npuOutputNotify cb,
                             void *data);
@@ -535,6 +537,7 @@ int setNPU_requestCallback (npudev_h dev, int req_id, npuOutputNotify cb,
  * @param[in] req_id The request ID
  * @param[in] mode Configures how this inference works.
  * @return 0 if no error. Otherwise a negative errno
+ * @note it's not necessary if you're going to use submitNPU_requestKernel()
  */
 int setNPU_requestMode (npudev_h dev, int req_id, npu_infer_mode mode);
 
@@ -566,6 +569,26 @@ int setNPU_requestNpumgrParam (npudev_h dev, int req_id, npumgr_param param);
  */
 int submitNPU_request (npudev_h dev, int req_id);
 
+/**
+ * @brief Submit the request to the NPU working with kernel modules
+ * @param[in] dev The NPU device handle
+ * @param[in] req_id The request ID
+ * @return 0 if no error. Otherwise a negative errno
+ * @note this API ignores user-provided input and output data/info because
+ *       the reserved kernel modules may provide input and output buffers.
+ *       Also, data manipulation is not supported.
+ */
+int submitNPU_requestKernel (npudev_h dev, int req_id);
+
+/**
+ * @brief Stop the request submitted by submitNPU_requestKernel
+ * @param[in] dev The NPU device handle
+ * @param[in] req_id The request ID
+ * @return 0 if no error. Otherwise a negative errno
+ * @note after calling this, the request will be no longer valid.
+ */
+int stopNPU_requestKernel (npudev_h dev, int req_id);
+
 #if defined(__cplusplus)
 }
 #endif
index 6b0efb2..63b91bf 100644 (file)
@@ -388,6 +388,26 @@ HostHandler::submitRequest (int req_id) {
 }
 
 /**
+ * @brief Submit the request to the NPU working with kernel modules
+ * @param[in] req_id The request ID
+ * @return 0 if no error. Otherwise a negative errno
+ */
+int
+HostHandler::submitRequestKernel (int req_id) {
+  return device_->submitRequestKernel (req_id);
+}
+
+/**
+ * @brief Stop the request submitted by submitRequsetKernel
+ * @param[in] req_id The request ID
+ * @return 0 if no error. Otherwise a negative errno
+ * @note after calling this, the request will be no longer valid.
+ */
+int
+HostHandler::stopRequestKernel (int req_id) {
+  return device_->stopRequestKernel (req_id);
+}
+/**
  * @brief Execute inference.
  * @param[in] model_id The model id to be inferred
  * @param[in] mode Configures how this inference works.
@@ -1369,6 +1389,51 @@ TrinityVision2::submitRequest (int req_id) {
   return status;
 }
 
+int
+TrinityVision2::submitRequestKernel (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;
+  }
+
+  const Model *model = req->getModel ();
+  SegmentTable *segt = dynamic_cast<SegmentTable *> (req->getInferData ());
+  if (segt != nullptr) {
+    logwarn (TAG, "Segment table with user-provided data is destroyed\n");
+    delete segt;
+  }
+
+  /* dummy input/ouput */
+  input_buffers input = {0};
+  output_buffers output = {0};
+
+  input.num_buffers = 1;
+  input.bufs[0].type = BUFFER_DMABUF;
+  input.bufs[0].dmabuf = -1; /* indicator of kernel input */
+
+  output.num_buffers = 1;
+  output.bufs[0].type = BUFFER_DMABUF;
+  output.bufs[0].dmabuf = -2; /* indicator of kernel output */
+
+  segt = prepareSegmentTable (model, &input, &output);
+
+  req->setInferData (segt);
+  req->setPreserved (true);
+  return scheduler_->submitRequest (req);
+}
+
+int
+TrinityVision2::stopRequestKernel (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;
+  }
+
+  return scheduler_->stopRequestKernel (req);
+}
+
 /** Implement data manipulation (each device may have different impl.) */
 
 #ifdef ENABLE_MANIP
index fb18e23..6133859 100644 (file)
@@ -72,6 +72,8 @@ class HostHandler {
   int setRequestConstraint (int req_id, npu_constraint constraint);
   int setRequestNpumgrParam (int req_id, npumgr_param param);
   int submitRequest (int req_id);
+  int submitRequestKernel (int req_id);
+  int stopRequestKernel (int req_id);
 
   /** @brief get statistics */
   int getMemoryStatus (size_t *alloc_total, size_t *free_total);
@@ -159,6 +161,8 @@ class Device {
   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;
+  virtual int submitRequestKernel (int req_id) = 0;
+  virtual int stopRequestKernel (int req_id) = 0;
 
  protected:
   /** the device instance has ownership of all related components */
@@ -219,6 +223,8 @@ class TrinityVision2 : public Device {
   int setRequestConstraint (int req_id, npu_constraint constraint);
   int setRequestNpumgrParam (int req_id, npumgr_param param);
   int submitRequest (int req_id);
+  int submitRequestKernel (int req_id);
+  int stopRequestKernel (int req_id);
 
  private:
   void callback (Request *req, npuOutputNotify cb, void *cb_data);
index 6a37520..247497f 100644 (file)
@@ -26,6 +26,7 @@ Request::Request (npu_input_opmode opmode)
     : opmode_ (opmode),
       force_stop_ (false),
       stopped_ (false),
+      preserved_ (false),
       model_ (nullptr),
       data_ (nullptr),
       cb_ (nullptr),
@@ -214,7 +215,8 @@ Scheduler::handleCallback (Request *req) {
     callback ();
 
   /** the request instance is also deleted here */
-  removeRequest (req);
+  if (!req->isPreserved ())
+    removeRequest (req);
 }
 
 /**
@@ -226,3 +228,20 @@ Scheduler::findRequest (int req_id) {
   /* thread-safe map */
   return request_map_.find (req_id);
 }
+
+int
+Scheduler::stopRequestKernel (Request *req) {
+  if (req == nullptr) {
+    logerr (TAG, "Invalid request to stop\n");
+    return -EINVAL;
+  }
+
+  SegmentTable *segt = dynamic_cast<SegmentTable *> (req->getInferData ());
+  if (segt != nullptr)
+    delete segt;
+  else
+    logwarn (TAG, "Unable to find the request's segment table\n");
+
+  removeRequest (req);
+  return 0;
+}
index 5911660..9c6946f 100644 (file)
@@ -46,6 +46,9 @@ class Request {
   void setForceStop (bool force_stop) { force_stop_ = force_stop; }
   bool getForceStop () { return force_stop_; }
 
+  void setPreserved (bool preserved) { preserved_ = preserved; }
+  bool isPreserved () { return preserved_; }
+
   npu_input_opmode getOpmode () { return opmode_; }
   int getID () { return request_id_; }
 
@@ -75,6 +78,7 @@ class Request {
   npu_input_opmode opmode_; /**< opmode of the request */
   bool force_stop_;         /**< indicates force stop */
   bool stopped_;            /**< stopped request */
+  bool preserved_;          /**< preserved request */
 
   const Model *model_; /**< model of the request */
   HWmem *data_;        /**< inference data of the request */
@@ -98,6 +102,7 @@ class Scheduler {
   void removeRequest (Request *req);
   int submitRequest (Request *req);
   Request *findRequest (int req_id);
+  int stopRequestKernel (Request *req);
 
  private:
   /**
index 9f8d501..ca1df71 100644 (file)
@@ -835,3 +835,33 @@ submitNPU_request (npudev_h dev, int req_id) {
 
   return host_handler->submitRequest (req_id);
 }
+
+/**
+ * @brief Submit the request to the NPU working with kernel modules
+ * @param[in] dev The NPU device handle
+ * @param[in] req_id The request ID
+ * @return 0 if no error. Otherwise a negative errno
+ * @note this API ignores user-provided input and output data/info because
+ *       the reserved kernel modules may provide input and output buffers.
+ *       Also, data manipulation is not supported.
+ */
+int
+submitNPU_requestKernel (npudev_h dev, int req_id) {
+  INIT_HOST_HANDLER (host_handler, dev);
+
+  return host_handler->submitRequestKernel (req_id);
+}
+
+/**
+ * @brief Stop the request submitted by submitNPU_requestKernel
+ * @param[in] dev The NPU device handle
+ * @param[in] req_id The request ID
+ * @return 0 if no error. Otherwise a negative errno
+ * @note after calling this, the request will be no longer valid.
+ */
+int
+stopNPU_requestKernel (npudev_h dev, int req_id) {
+  INIT_HOST_HANDLER (host_handler, dev);
+
+  return host_handler->stopRequestKernel (req_id);
+}
index aa2cc0f..7845bfe 100644 (file)
@@ -863,6 +863,24 @@ TEST (ne_libnpuhost_test, request_decoupled_apis) {
   std::unique_lock<std::mutex> lock (sync.m);
   sync.cv.wait (lock, [&]() { return sync.done == true; });
 
+#ifndef ENABLE_EMUL
+  /* actual testing (kernel) */
+  constraint.priority = NPU_PRIORITY_HIGH;
+
+  /* dummy param */
+  npumgr_param param = {.task_handle = 1, .subtask_idx = 0};
+
+  EXPECT_EQ (createNPU_request (dev, modelid, &req_id), 0);
+  EXPECT_EQ (setNPU_requestConstraint (dev, req_id, constraint), 0);
+  EXPECT_EQ (setNPU_requestNpumgrParam (dev, req_id, param), 0);
+  EXPECT_GE (submitNPU_requestKernel (dev, req_id), 0);
+
+  sleep (1);
+
+  EXPECT_EQ (stopNPU_requestKernel (dev, req_id), 0);
+#endif
+
+  ASSERT_EQ (unregisterNPUmodel (dev, modelid), 0);
   putNPUdevice (dev);
 }