[API/HwInput] Fix runInternal() API for HW input service
authorDongju Chae <dongju.chae@samsung.com>
Wed, 29 Jul 2020 06:15:10 +0000 (15:15 +0900)
committer송욱/On-Device Lab(SR)/Staff Engineer/삼성전자 <wook16.song@samsung.com>
Wed, 5 Aug 2020 01:18:18 +0000 (10:18 +0900)
This patch fixes runInternal() APi for HW input service.
It requires extra variables in run_input ioctl structure.

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-hw-input-service.cc
src/core/ne-scheduler.cc
src/core/ne-scheduler.h
src/core/ne-segment-table.cc
src/core/ne-segment-table.h
tests/apptests/hw_recurring.cc

index f390e7c..ed836ea 100644 (file)
@@ -243,12 +243,12 @@ typedef void (*npuOutputNotify) (output_buffers *output, uint64_t sequence,
  * @param[in] dev The NPU device handle
  * @param[in] modelid The model to be inferred.
  * @param[in] opmode NPU has different opmode with auto-inputs. Choose one.
- * @param[in] input The input buffer where input data comes.
- * @param[in] output The output buffer where output data is filled.
+ * @param[in] hw_dev The target device feeding input data
  * @return @c 0 or positive id if no error. otherwise a negative error value
+ * @note input and output are handled internally by third-party HW (e.g., DSP)
  */
 int runNPU_internalInput(npudev_h dev, uint32_t modelid, npu_input_opmode opmode,
-    const input_buffers *input, const output_buffers *output);
+    const char * hw_dev);
 
 /**
  * @brief Stop the request with the given id
index a8df60e..8663a78 100644 (file)
@@ -195,16 +195,15 @@ int runNPU_async(npudev_h dev, uint32_t modelid, const input_buffers *input,
  * @param[in] dev The NPU device handle
  * @param[in] modelid The model to be inferred.
  * @param[in] opmode NPU has different opmode with auto-inputs. Choose one.
- * @param[in] input The input buffer where input data comes.
- * @param[in] output The output buffer where output data is filled.
+ * @param[in] hw_dev The target device feeding input data
  * @return @c 0 if no error. otherwise a negative error value
  */
 int runNPU_internalInput(npudev_h dev, uint32_t modelid, npu_input_opmode opmode,
-    const input_buffers *input, const output_buffers *output)
+    const char * hw_dev)
 {
   INIT_HOST_HANDLER (host_handler, dev);
 
-  return host_handler->runInternal (modelid, opmode, input, output);
+  return host_handler->runInternal (modelid, opmode, hw_dev);
 }
 
 /**
@@ -643,13 +642,12 @@ HostHandler::runAsync (uint32_t modelid, const input_buffers *input,
  * @brief Let NPU accept input frames from its internal source continuously
  * @param[in] modelid The model to be inferred.
  * @param[in] opmode NPU has different opmode with auto-inputs. Choose one.
- * @param[in] input The input buffer where input data comes.
- * @param[in] output The output buffer where output data is filled.
+ * @param[in] hw_dev The target device feeding input data
  * @return @c 0 if no error. otherwise a negative error value
  */
 int
 HostHandler::runInternal (uint32_t modelid, npu_input_opmode opmode,
-    const input_buffers *input, const output_buffers *output)
+    std::string hw_dev)
 {
   Model *model = nullptr;
 
@@ -665,7 +663,7 @@ HostHandler::runInternal (uint32_t modelid, npu_input_opmode opmode,
     return -EINVAL;
   }
 
-  return device_->runInternal (opmode, model, input, output);
+  return device_->runInternal (opmode, model, hw_dev);
 }
 
 /**
@@ -1323,14 +1321,14 @@ SegmentTable *
 TrinityVision2::prepareSegmentTable (const Model *model, const input_buffers *input,
     const output_buffers *output)
 {
-  if (model == nullptr || input == nullptr) {
+  if (model == nullptr) {
     logerr (TAG, "Invalid arguments provided\n");
     return nullptr;
   }
 
   const Metadata *meta = model->getMetadata ();
-  if (meta == nullptr ||
-      meta->getInputNum() != input->num_buffers) {
+  if (meta == nullptr || (input != nullptr &&
+        meta->getInputNum() != input->num_buffers)) {
     logerr (TAG, "Invalid metadata info provided\n");
     return nullptr;
   }
@@ -1553,7 +1551,7 @@ TrinityVision2::run (npu_input_opmode opmode, const Model *model,
 /** @brief implementation of TRIV2's runInternal() */
 int
 TrinityVision2::runInternal (npu_input_opmode opmode, const Model *model,
-    const input_buffers *input, const output_buffers *output)
+    std::string hw_dev)
 {
   if (!initialized ()) {
     logerr (TAG, "Uninitialized device; should use libnpuhost APIs\n");
@@ -1564,7 +1562,7 @@ TrinityVision2::runInternal (npu_input_opmode opmode, const Model *model,
     return -EINVAL;
 
   /** this device uses segment table */
-  SegmentTable * segt = prepareSegmentTable (model, input, output);
+  SegmentTable * segt = prepareSegmentTable (model, nullptr, nullptr);
   if (segt == nullptr) {
     logerr (TAG, "Failed to create segment table instance\n");
     return -EINVAL;
@@ -1573,6 +1571,7 @@ TrinityVision2::runInternal (npu_input_opmode opmode, const Model *model,
   Request *req = new Request (opmode);
   req->setModel (model);
   req->setSegmentTable (segt);
+  req->setHwDevice (hw_dev);
 
   return scheduler_->submitRequest (req);
 }
index e08d356..4dd65e9 100644 (file)
@@ -51,8 +51,7 @@ class HostHandler {
     int runAsync (uint32_t modelid, const input_buffers *input,
         npuOutputNotify cb = nullptr, void *cb_data = nullptr,
         npu_async_mode mode = NPUASYNC_WAIT, uint64_t *sequence = nullptr);
-    int runInternal (uint32_t modelid, npu_input_opmode opmode,
-        const input_buffers *input, const output_buffers *output);
+    int runInternal (uint32_t modelid, npu_input_opmode opmode, std::string hw_dev);
     int stopInternal (int id);
 
     /** @brief get statistics */
@@ -114,7 +113,7 @@ class Device {
         void *cb_data = nullptr, uint64_t *sequence = nullptr) = 0;
 
     virtual int runInternal (npu_input_opmode opmode, const Model *model,
-        const input_buffers *input, const output_buffers *output) { return -EPERM; }
+        std::string hw_dev) { return -EPERM; }
 
   protected:
     /** the device instance has ownership of all related components */
@@ -179,8 +178,7 @@ class TrinityVision2 : public Device {
     int run (npu_input_opmode opmode, const Model *model,
         const input_buffers *input, npuOutputNotify cb = nullptr,
         void *cb_data = nullptr, uint64_t *sequence = nullptr);
-    int runInternal (npu_input_opmode opmode, const Model *model,
-        const input_buffers *input, const output_buffers *output);
+    int runInternal (npu_input_opmode opmode, const Model *model, std::string hw_dev);
 
   private:
     void callback (Request *req, npuOutputNotify cb, void *cb_data);
index 4dcf464..017f984 100644 (file)
@@ -59,6 +59,7 @@ int
 HwInputService::invoke (const DriverAPI *api, const Model *model,
     SegmentTable *segt, outputCallback callback)
 {
+  const Metadata * meta = model->getMetadata ();
   input_config_t input_config;
   device_state_t state;
   npuConstraint constraint;
@@ -98,9 +99,15 @@ HwInputService::invoke (const DriverAPI *api, const Model *model,
   input_config.input_mode = INPUT_HW;
   input_config.output_mode = OUTPUT_HW;
 
+  /** Assumption: only a sigle pair of input/output segments in HW input service */
+  input_config.hw_input_seg = meta->getInputSegmentIndex (0);
+  input_config.hw_output_seg = meta->getOutputSegmentIndex (0);
+  input_config.hw_devpath = segt->getHwDevice ().c_str ();
+  input_config.hw_devlen = segt->getHwDevice ().length ();
+
   /** run the inference with the input */
   ret = api->runInput (&input_config);
-  if (ret != 0 && ret != -ECANCELED)
+  if (ret < 0 && ret != -ECANCELED)
     logerr (TAG, "Failed to run the NPU inference: %d\n", ret);
 
 handle_callback:
index 648cac7..78cc14a 100644 (file)
@@ -90,13 +90,15 @@ Scheduler::submitRequest (Request *req)
     auto callback = std::bind (&Scheduler::handleCallback, this, req);
 
     /** consider NOP cases */
-    if (req->getBuffer () != nullptr)
+    if (req->getBuffer () != nullptr) {
       status = InferenceEngine::invokeInputService (api_, req->getOpmode(),
           req->getID(), req->getModel(), req->getBuffer(), callback);
-    else if (req->getSegmentTable () != nullptr)
+    } else if (req->getSegmentTable () != nullptr) {
+      req->getSegmentTable()->setHwDevice (req->getHwDevice ());
+
       status = InferenceEngine::invokeInputService (api_, req->getOpmode(),
           req->getID(), req->getModel(), req->getSegmentTable(), callback);
-    else
+    else
       status = -EINVAL;
 
     if (status != 0) {
index ae970ea..9dae9e5 100644 (file)
@@ -53,6 +53,9 @@ public:
   void setStopped () { stopped_ = true; }
   bool isStopped () { return stopped_; }
 
+  void setHwDevice (std::string hw_dev) { hw_dev_ = hw_dev; }
+  std::string getHwDevice () { return hw_dev_; }
+
 private:
   static std::atomic<uint32_t> global_request_id_;
   uint32_t request_id_;     /**< request id */
@@ -66,6 +69,7 @@ private:
   SegmentTable *segt_;      /**< segment table of the request */
 
   outputCallback cb_;       /**< request callback */
+  std::string hw_dev_;      /**< HW device path */
 };
 
 /** @brief class def. of scheduler to handle requests */
index 221fee3..6b263ef 100644 (file)
@@ -88,8 +88,8 @@ int
 SegmentTable::createSegments (const Model *model,
     const input_buffers *input, const output_buffers *output)
 {
-  if (model == nullptr || input == nullptr) {
-    logerr (TAG, "No model/input provided\n");
+  if (model == nullptr) {
+    logerr (TAG, "No model provided\n");
     return -EINVAL;
   }
 
@@ -149,17 +149,19 @@ SegmentTable::createSegments (const Model *model,
       hwmem->setOffset (0);
     } else {
       /** check input segments */
-      for (uint32_t j = 0; j < meta->getInputNum (); j++) {
-        /** user provides a external segment */
-        if (i == meta->getInputSegmentIndex (j)) {
-          if (input->bufs[j].type == BUFFER_DMABUF) {
-            hwmem = new HWmem (new HWmemExternal);
-            hwmem->setDriverAPI (getDriverAPI ());
-            /** it assume that dmabuf indicates the base address of segment */
-            hwmem->setDmabuf (input->bufs[j].dmabuf);
-            hwmem->setOffset (0);
-            hwmem->setSize (size);
-            break;
+      if (input != nullptr) {
+        for (uint32_t j = 0; j < meta->getInputNum (); j++) {
+          /** user provides a external segment */
+          if (i == meta->getInputSegmentIndex (j)) {
+            if (input->bufs[j].type == BUFFER_DMABUF) {
+              hwmem = new HWmem (new HWmemExternal);
+              hwmem->setDriverAPI (getDriverAPI ());
+              /** it assume that dmabuf indicates the base address of segment */
+              hwmem->setDmabuf (input->bufs[j].dmabuf);
+              hwmem->setOffset (0);
+              hwmem->setSize (size);
+              break;
+            }
           }
         }
       }
index d2b7685..36f46be 100644 (file)
@@ -43,6 +43,9 @@ class SegmentTable : public HWmem {
     uint32_t getNumInputSegments () const { return num_input_segments_; }
     uint32_t getNumOutputSegments () const { return num_output_segments_; }
 
+    std::string getHwDevice () { return hw_dev_; }
+    void setHwDevice (std::string hw_dev) { hw_dev_ = hw_dev; }
+
   private:
     bool setSegmentSlot (HWmem *hwmem, int slot);
 
@@ -59,5 +62,7 @@ class SegmentTable : public HWmem {
     uint32_t num_weight_segments_;    /**< number of weight segments */
     uint32_t num_input_segments_;     /**< number of input segments */
     uint32_t num_output_segments_;    /**< number of output segments */
+
+    std::string hw_dev_;              /**< hw device for recurring task */
 };
 #endif /* __NPU_ENGINE_SEGMENT_TABLE_H__ */
index a5fc231..013ca2e 100644 (file)
@@ -15,6 +15,7 @@
 #include <ne_test_utils.h>
 #include <string.h>
 #include <unistd.h>
+#include <sys/stat.h>
 
 #include <iostream>
 #include <fstream>
@@ -104,8 +105,6 @@ class TesterTRIV2 {
   public:
     TesterTRIV2 () : dev_ (nullptr), meta_ (nullptr), model_id_ (0) {
       model_.size = 0;
-      input_.num_buffers = 0;
-      output_.num_buffers = 0;
       time_ = DEFAULT_TIME;
     }
 
@@ -130,7 +129,11 @@ class TesterTRIV2 {
     }
 
     /** @brief initilize the device handle */
-    int init (const std::string dir) {
+    int init (const std::string dir, const std::string hw_dev) {
+      struct stat stat_buf;
+      if (stat (hw_dev.c_str(), &stat_buf) != 0)
+        return -EEXIST;
+
       int num_devices = getnumNPUdeviceByType (TRIV2_TYPE);
       if (num_devices <= 0)
         return -ENODEV;
@@ -139,6 +142,8 @@ class TesterTRIV2 {
       int dev_id = num_devices - 1;
 
       dir_ = dir;
+      hw_dev_ = hw_dev;
+
       return getNPUdeviceByType (&dev_, TRIV2_TYPE, dev_id);
     }
 
@@ -152,20 +157,12 @@ class TesterTRIV2 {
       if (status != 0)
         return status;
 
-      status = prepare_input ();
-      if (status != 0)
-        return status;
-
-      status = prepare_output ();
-      if (status != 0)
-        return status;
-
       status = set_data_info ();
       if (status != 0)
         return status;
 
       int id = runNPU_internalInput (dev_, model_id_, NPUINPUT_HW_RECURRING,
-          &input_, &output_);
+          hw_dev_.c_str());
       if (id < 0)
         return id;
 
@@ -198,38 +195,6 @@ class TesterTRIV2 {
       return registerNPUmodel (dev_, &model_, &model_id_);
     }
 
-    int prepare_input () {
-      input_.num_buffers = meta_->input_seg_num;
-      for (uint32_t idx = 0; idx < meta_->input_seg_num; idx++) {
-        uint32_t input_seg_idx = meta_->input_seg_idx[idx];
-        uint32_t input_seg_size = meta_->segment_size[input_seg_idx];
-        uint32_t input_seg_off = meta_->input_seg_off[idx];
-
-        input_.bufs[idx].type = BUFFER_DMABUF;
-        input_.bufs[idx].size = input_seg_size - input_seg_off;
-        input_.bufs[idx].offset = input_seg_off;
-        input_.bufs[idx].dmabuf = hw_.get_input_dmabuf (idx);
-      }
-
-      return 0;
-    }
-
-    int prepare_output () {
-      output_.num_buffers = meta_->output_seg_num;
-      for (uint32_t idx = 0; idx < meta_->output_seg_num; idx++) {
-        uint32_t output_seg_idx = meta_->output_seg_idx[idx];
-        uint32_t output_seg_size = meta_->segment_size[output_seg_idx];
-        uint32_t output_seg_off = meta_->output_seg_off[idx];
-
-        output_.bufs[idx].type = BUFFER_DMABUF;
-        output_.bufs[idx].size = output_seg_size - output_seg_off;
-        output_.bufs[idx].offset = output_seg_off;
-        output_.bufs[idx].dmabuf = hw_.get_output_dmabuf (idx);
-      }
-
-      return 0;
-    }
-
     int set_data_info () {
       tensors_data_info info_in;
       tensors_data_info info_out;
@@ -252,39 +217,63 @@ class TesterTRIV2 {
     }
 
     std::string dir_;
+    std::string hw_dev_;
 
     npudev_h dev_;
 
     npubin_meta *meta_;
     uint32_t model_id_;
     generic_buffer model_;
-    input_buffers input_;
-    output_buffers output_;
 
     uint32_t time_;
     ThirdPartyHW hw_;
 };
 
+static void
+print_usage (const char *prog_name)
+{
+  std::cerr << "Usage: " << prog_name << " [options] model_dir target_dev\n";
+  std::cerr << "Options: \n";
+  std::cerr << "  -t <arg> \t Set timeout of recurring task\n";
+  std::cerr << "  -h \t\t Show the usage of this program\n";
+}
+
 /** @brief apptest main  */
 int
 main (int argc, char **argv)
 {
   TesterTRIV2 tester;
-  int status;
+  int c, status;
+
+  optind = 0;
+  opterr = 0;
+  while ((c = getopt (argc, argv, "ht:")) != -1) {
+    switch (c) {
+      case 't':
+        tester.set_time (atoi(optarg));
+        break;
+      case '?':
+        if (optopt == 't')
+          std::cerr << "Option -t requires an extra argument";
+        else
+          std::cerr << "Unknown flag: " << c;
+        std::cerr << std::endl;
+      case 'h':
+        print_usage(argv[0]);
+        return 0;
+    }
+  }
 
-  if (argc < 2) {
+  if (optind + 1 >= argc) {
     std::cerr << "[APPTEST] " << argv[0] << ": SKIPPED\n";
     return 0;
   }
 
   /** initialize triv2 device */
-  status = tester.init (argv[1]);
+  status = tester.init (argv[optind], argv[optind + 1]);
   if (status != 0)
     goto err;
 
-  if (argc > 2)
-    tester.set_time (atoi(argv[2]));
-
   /** run the inference with the device */
   status = tester.run ();
   if (status != 0)