[Apptest] Add apptest for multiple inferences (againg test)
authorDongju Chae <dongju.chae@samsung.com>
Wed, 23 Jun 2021 03:32:17 +0000 (12:32 +0900)
committer채동주/On-Device Lab(SR)/Staff Engineer/삼성전자 <dongju.chae@samsung.com>
Wed, 23 Jun 2021 09:36:08 +0000 (18:36 +0900)
This patch adds apptest for multiple inferences.

Signed-off-by: Dongju Chae <dongju.chae@samsung.com>
tests/apptests/meson.build
tests/apptests/tvn_triv2.cc
tests/apptests/tvn_triv2_aging.cc [new file with mode: 0644]
tests/apptests/tvn_triv2_bulk.cc
tests/apptests/tvn_triv2_preempt.cc
tests/apptests/tvn_triv2_profile.cc
tests/apptests/tvn_triv2_xml.cc
tests/utils/ne_test_utils.cc
tests/utils/ne_test_utils.h

index 550c720c1e2a92a46ee81fb2d941d4eb2d363e56..c39a2a6189cfb62cff4e804d28a3e0a147079788 100644 (file)
@@ -117,6 +117,16 @@ executable ('apptest_tvn_triv2_preempt',
   install_dir : join_paths(ne_bindir, 'apptests')
 )
 
+executable ('apptest_tvn_triv2_aging',
+  'tvn_triv2_aging.cc',
+  include_directories : ne_apptest_inc,
+  dependencies : ne_test_utils_dep,
+  link_with : ne_library_shared,
+  install : true,
+  install_rpath : ne_libdir,
+  install_dir : join_paths(ne_bindir, 'apptests')
+)
+
 # npumgr is available on tizen env.
 if target_platform == 'tizen'
   subdir('npumgr')
index 917aad389a140b40ac6e8fa794c2b725696c9dcb..e9d70548b944e4c1470091355bba7bf516cb8edc 100644 (file)
@@ -67,13 +67,13 @@ main (int argc, char **argv) {
   Tester tester;
   char *dir;
   int status;
+  int index;
 
-  status = tester.parseArgs (argc, argv, &dir, "[model dir]");
-  if (status == test_ret_skipped || dir == nullptr)
+  status = tester.parseArgs (argc, argv, "model_path", &index);
+  if (status == test_ret_skipped || index < 0)
     goto skip;
-  else if (status != test_ret_success)
-    goto err;
 
+  dir = argv[index];
   /** initialize triv2 device */
   status = tester.init (dir);
   if (status < test_ret_success)
diff --git a/tests/apptests/tvn_triv2_aging.cc b/tests/apptests/tvn_triv2_aging.cc
new file mode 100644 (file)
index 0000000..fe8b432
--- /dev/null
@@ -0,0 +1,112 @@
+/**
+ * Proprietary
+ * Copyright (C) 2020 Samsung Electronics
+ * Copyright (C) 2020 Dongju Chae <dongju.chae@samsung.com>
+ */
+/**
+ * @file tvn_triv2_aging.cc
+ * @date 23 June 2021
+ * @brief AppTest to test multiple inferences for TRIV2 device
+ * @author Dongju Chae <dongju.chae@samsung.com>
+ * @bug No known bugs except for NYI items
+ */
+
+#include <ne_test_utils.h>
+
+#define NPU_TIMEOUT_MS 5000
+
+using namespace std;
+
+/** @brief C++ class to describe how to use npu-engine library */
+class Tester : public UtilTRIV2 {
+ public:
+  Tester () : model_id_ (0), num_iter_ (0) {}
+
+  /** @brief initilize the device handle */
+  int init (string model_dir, string num_dir) {
+    if (model_dir == "" || num_dir == "")
+      return -EINVAL;
+
+    errno = 0;
+    num_iter_ = strtoul (num_dir.c_str (), NULL, 10);
+    if (errno != 0)
+      return -errno;
+
+    string model_path = model_dir + "/model.tvn";
+    npubin_meta *meta = getNPUmodel_metadata (model_path.c_str (), false);
+    if (meta == nullptr)
+      return -EINVAL;
+
+    uint32_t tops = NPU_VERSION_TOPS (meta->npu_version);
+    free (meta);
+
+    int status = UtilTRIV2::init (tops);
+    if (status != test_ret_success) {
+      cerr << "Failed to initialize\n";
+      return status;
+    }
+
+    return UtilTRIV2::loadModel (model_dir, &model_id_, NPU_PRIORITY_MID,
+                                 NPU_TIMEOUT_MS);
+  }
+
+  /** @brief run the inference */
+  int run () {
+    if (model_id_ == 0)
+      return test_ret_failure;
+
+    int req_id = UtilTRIV2::createRequest (model_id_);
+    if (req_id < 0)
+      return req_id;
+
+    for (uint32_t i = 0; i < num_iter_; i++)
+      UtilTRIV2::submitRequest (model_id_);
+
+    UtilTRIV2::removeRequest (req_id);
+    return wait () == num_iter_ ? test_ret_success : test_ret_failure;
+  }
+
+ private:
+  uint32_t model_id_;
+  uint32_t num_iter_;
+};
+
+/** @brief apptest main  */
+int
+main (int argc, char **argv) {
+  const char *help = "model_dir num_iterations";
+  Tester tester;
+  int status;
+  int index;
+
+  status = tester.parseArgs (argc, argv, help, &index);
+  if (status == test_ret_skipped || index < 0)
+    goto skip;
+
+  if (argc < index + 2) {
+    cerr << "Need additional argument..\n";
+    tester.printUsage (argv[0], help);
+    goto skip;
+  }
+
+  /** initialize triv2 device */
+  status = tester.init (argv[index], argv[index + 1]);
+  if (status < test_ret_success)
+    goto err;
+
+  /** run the inference with the device */
+  status = tester.run ();
+  if (status < test_ret_success)
+    goto err;
+
+  cerr << "[APPTEST] " << argv[0] << ": PASSED\n";
+  return 0;
+
+err:
+  cerr << "[APPTEST] " << argv[0] << ": FAILED (" << status << ")\n";
+  return status;
+
+skip:
+  cerr << "[APPTEST] " << argv[0] << ": SKIPPED\n";
+  return 0;
+}
index 18241bcffaf7bfee1f86888ff29fdc617e7f96d4..60734fe91001488cf8dd2334593f25d6efe2ad6e 100644 (file)
@@ -71,18 +71,17 @@ main (int argc, char **argv) {
   Tester tester;
   char *dir_str;
   int status;
+  int index;
 
   std::ios_base::fmtflags f (cerr.flags ());
 
-  status = tester.parseArgs (argc, argv, &dir_str, "[models' dir]");
-  if (status == test_ret_skipped || dir_str == nullptr) {
+  status = tester.parseArgs (argc, argv, "models_path", &index);
+  if (status == test_ret_skipped || index < 0) {
     cerr << "[APPTEST] " << argv[0] << ": SKIPPED\n";
     return 0;
-  } else if (status != test_ret_success) {
-    cerr << "[APPTEST] " << argv[0] << ": FAILED (" << status << ")\n";
-    return status;
   }
 
+  dir_str = argv[index];
   DIR *d = opendir (dir_str);
   if (!d) {
     cerr << "Failed to open " << dir_str << "\n";
index 26ba0478778d52c721f89c499c915d32de6064d3..4abf0a667867e7744032fb27399578f2a55d3faf 100644 (file)
@@ -111,13 +111,13 @@ main (int argc, char **argv) {
   Tester tester;
   char *dir;
   int status;
+  int index;
 
-  status = tester.parseArgs (argc, argv, &dir, "[models' dir]");
-  if (status == test_ret_skipped || dir == nullptr)
+  status = tester.parseArgs (argc, argv, "models_path", &index);
+  if (status == test_ret_skipped || index < 0)
     goto skip;
-  else if (status != test_ret_success)
-    goto err;
 
+  dir = argv[index];
   /** initialize triv2 device */
   status = tester.init (dir);
   if (status < test_ret_success)
index 9adf7ca85cd8f236a4e49bc01745289aae1de407..e81ee64aadf96d0eb57c65b7f2e9129640bd8c5a 100644 (file)
@@ -111,13 +111,15 @@ main (int argc, char **argv) {
   Tester tester;
   char *dir;
   int status;
+  int index;
 
-  status = tester.parseArgs (argc, argv, &dir, "[model dir]");
-  if (status == test_ret_skipped || dir == nullptr)
+  status = tester.parseArgs (argc, argv, "model_path", &index);
+  if (status == test_ret_skipped || index < 0)
     goto skip;
   else if (status != test_ret_success)
     goto err;
 
+  dir = argv[index];
   /** initialize triv2 device */
   status = tester.init (dir);
   if (status < test_ret_success)
index 6bd1f7bcce4fa489c4a6acca9db6a83b866271ad..8c863c812bb3e3edd45defb1a1ec8bfdc5dbbda4 100644 (file)
@@ -112,13 +112,13 @@ main (int argc, char **argv) {
   Tester tester;
   char *xml_file;
   int status;
+  int index;
 
-  status = tester.parseArgs (argc, argv, &xml_file, "[.xml file]");
-  if (status == test_ret_skipped || xml_file == nullptr)
+  status = tester.parseArgs (argc, argv, "xml_file_path", &index);
+  if (status == test_ret_skipped || index < 0)
     goto skip;
-  else if (status != test_ret_success)
-    goto err;
 
+  xml_file = argv[index];
   /** initialize triv2 device */
   status = tester.init (xml_file);
   if (status < test_ret_success)
index 41d03b153aac5871847010e7791a30ad4e17b70f..872ddd99b8794fbf465cc0e933f8a54a1bd432ff 100644 (file)
@@ -231,13 +231,13 @@ UtilTrinity::~UtilTrinity () {
 /** @brief device instance cleanup */
 void
 UtilTrinity::clear () {
+  models_.clear ();
+
   if (dev_ != nullptr) {
     unregisterNPUmodel_all (dev_);
     putNPUdevice (dev_);
     dev_ = nullptr;
   }
-
-  models_.clear ();
 }
 
 /** @brief initialize trinity device and get the device handle */
@@ -318,10 +318,13 @@ UtilTrinity::setProfLevel (const std::string level) {
 }
 /** @brief parse/set arguments and get working directory */
 int
-UtilTrinity::parseArgs (int argc, char **argv, char **param,
-                        const char *param_str) {
+UtilTrinity::parseArgs (int argc, char **argv, const char *param_str,
+                        int *index) {
   int c;
 
+  if (index != nullptr)
+    *index = -1;
+
   optind = 0;
   opterr = 0;
   while ((c = getopt (argc, argv, "d:n:p:tmsho")) != -1) {
@@ -353,18 +356,14 @@ UtilTrinity::parseArgs (int argc, char **argv, char **param,
         else
           std::cerr << "Unknown flag: " << c;
         std::cerr << std::endl;
-        printUsage (argv[0], param_str);
-        return test_ret_failure;
       case 'h':
         printUsage (argv[0], param_str);
         return test_ret_skipped;
     }
   }
 
-  if (optind < argc)
-    *param = argv[optind];
-  else
-    *param = nullptr;
+  if (index != nullptr && optind < argc)
+    *index = optind;
 
   return test_ret_success;
 }
@@ -405,7 +404,7 @@ UtilTrinity::loadModel (std::string dirpath, uint32_t *model_id_ptr,
   if (status != 0)
     goto free_meta;
 
-  model = new UtilModel;
+  model = new UtilModel (dev_);
   model->setMetadata (meta);
   model->setDirpath (dirpath);
   model->setModelID (model_id);
@@ -479,9 +478,9 @@ UtilTrinity::callbackVerify (output_buffers *output, int req_id, void *data) {
           fclose (dump_fp);
         }
       }
+    } else {
+      free (output->bufs[idx].addr);
     }
-
-    free (output->bufs[idx].addr);
   }
 
   std::unique_lock<std::mutex> lock (m_);
@@ -494,8 +493,12 @@ UtilTrinity::callbackVerify (output_buffers *output, int req_id, void *data) {
 /** @brief callback without verification */
 void
 UtilTrinity::callback (output_buffers *output, int req_id, void *data) {
-  for (uint32_t idx = 0; idx < output->num_buffers; idx++)
-    free (output->bufs[idx].addr);
+  UtilModel *model = static_cast<UtilModel *> (data);
+
+  if (model == nullptr) {
+    for (uint32_t idx = 0; idx < output->num_buffers; idx++)
+      free (output->bufs[idx].addr);
+  }
 
   std::unique_lock<std::mutex> lock (m_);
   done_++;
@@ -523,11 +526,13 @@ UtilTrinity::run_each (UtilModel *model, bool sync) {
   }
 
   if (sync) {
-    output_buffers output;
+    output_buffers *cb_output;
 
     if (model) {
+      cb_output = model->getOutput ();
       status =
-          runNPU_sync (dev_, model->getModelID (), model->getInput (), &output);
+          runNPU_model (dev_, model->getModelID (), NPU_INFER_BLOCKING,
+                        model->getInput (), model->getOutput (), NULL, NULL);
     } else {
       /* TODO: revise this when TRIA is implemented */
       input_buffers input;
@@ -539,6 +544,8 @@ UtilTrinity::run_each (UtilModel *model, bool sync) {
       if (status != 0)
         return status;
 
+      output_buffers output;
+      cb_output = &output;
       status = runNPU_sync (dev_, 0, &input, &output);
       cleanNPU_inputBuffers (dev_, &input);
     }
@@ -549,12 +556,13 @@ UtilTrinity::run_each (UtilModel *model, bool sync) {
         total_++;
       }
 
-      cb (&output, 0, cb_data);
+      cb (cb_output, 0, cb_data);
     }
   } else {
     if (model) {
-      status = runNPU_async (dev_, model->getModelID (), model->getInput (), cb,
-                             NULL, cb_data, NPUASYNC_WAIT);
+      status =
+          runNPU_model (dev_, model->getModelID (), NPU_INFER_NON_BLOCKING,
+                        model->getInput (), model->getOutput (), cb, cb_data);
     } else {
       /* TODO: revise this when TRIA is implemented */
       input_buffers input;
@@ -579,6 +587,60 @@ UtilTrinity::run_each (UtilModel *model, bool sync) {
   return status;
 }
 
+/** @brief create request */
+int
+UtilTrinity::createRequest (uint32_t model_id) {
+  UtilModel *model = findModel (model_id);
+  int status, req_id;
+
+  if (model == nullptr)
+    return -ENOENT;
+
+  status = createNPU_request (dev_, model_id, &req_id);
+  if (status != 0)
+    return status;
+
+  status = setNPU_requestData (dev_, req_id, model->getInput (), nullptr,
+                               model->getOutput (), nullptr);
+  if (status != 0) {
+    removeNPU_request (dev_, req_id);
+    return status;
+  }
+
+  return req_id;
+}
+
+/** @brief submit request */
+int
+UtilTrinity::submitRequest (int req_id) {
+  UtilModel *model;
+  uint32_t model_id;
+  int status;
+
+  status = getNPU_requestModel (dev_, req_id, &model_id);
+  if (status != 0)
+    return status;
+
+  model = findModel (model_id);
+  if (model == nullptr)
+    return -ENOENT;
+
+  status = submitNPU_request (dev_, req_id);
+  if (status == 0) {
+    total_++;
+    UtilTrinity::callbackVerify (model->getOutput (), req_id,
+                                 static_cast<void *> (model));
+  }
+
+  return status;
+}
+
+/** @brief remove request */
+int
+UtilTrinity::removeRequest (int req_id) {
+  return removeNPU_request (dev_, req_id);
+}
+
 /** @brief run inference with the given model id (default sync) */
 int
 UtilTrinity::run (uint32_t model_id) {
@@ -707,6 +769,8 @@ UtilTRIV2::set_data_info (npubin_meta *meta, uint32_t model_id) {
 int
 UtilTRIV2::prepare_model (UtilModel *model) {
   input_buffers *input = model->getInput ();
+  output_buffers *output = model->getOutput ();
+
   npubin_meta *meta = model->getMetadata ();
   std::string dirpath = model->getDirpath ();
 
@@ -723,5 +787,14 @@ UtilTRIV2::prepare_model (UtilModel *model) {
     input->bufs[idx].type = BUFFER_FILE;
   }
 
-  return 0;
+  output->num_buffers = meta->output_seg_num;
+
+  for (uint32_t idx = 0; idx < meta->output_seg_num; idx++) {
+    const char *output_path = model->getOutputPath (idx);
+
+    output->bufs[idx].size = get_file_size (output_path);
+    output->bufs[idx].type = BUFFER_MAPPED;
+  }
+
+  return allocNPU_genericBuffers (dev_, output);
 }
index 7d5dc1b81febb0ce4ea7375a89369d59406717ff..f7d3ad8c7b5abdcd767193199bf2a3bc4883dd09 100644 (file)
 /** @brief utility to access test model */
 class UtilModel {
  public:
-  UtilModel () : meta_ (nullptr), model_id_ (0) {
+  UtilModel (npudev_h dev) : dev_ (dev), meta_ (nullptr), model_id_ (0) {
     memset (&input_, '\x00', sizeof (input_buffers));
+    memset (&output_, '\x00', sizeof (output_buffers));
   }
   ~UtilModel () {
+    if (output_.num_buffers > 0)
+      cleanNPU_genericBuffers (dev_, &output_);
+
     if (meta_)
       free (meta_);
   }
@@ -74,14 +78,19 @@ class UtilModel {
   std::string &getDirpath () { return dirpath_; }
   uint32_t getModelID () { return model_id_; }
   input_buffers *getInput () { return &input_; }
+  output_buffers *getOutput () { return &output_; }
 
  private:
+  npudev_h dev_;
+
   npubin_meta *meta_;
   uint32_t model_id_;
 
   std::string dirpath_;
 
   input_buffers input_;
+  output_buffers output_;
+
   std::vector<std::string> inpath_;
   std::vector<std::string> outpath_;
 };
@@ -105,12 +114,16 @@ class UtilTrinity {
   int init (uint32_t tops = default_tops);
   void clear ();
   void printUsage (const char *prog_name, const char *param_str = nullptr);
-  int parseArgs (int argc, char **argv, char **param,
-                 const char *param_str = nullptr);
+  int parseArgs (int argc, char **argv, const char *param_str = nullptr,
+                 int *index = nullptr);
   int loadModel (std::string dirpath, uint32_t *model_id,
                  npu_priority priority = NPU_PRIORITY_MID,
                  uint32_t timeout = 5000);
 
+  int createRequest (uint32_t model_id);
+  int submitRequest (int req_id);
+  int removeRequest (int req_id);
+
   int run (uint32_t model_id);
   int run (uint32_t model_id, bool sync);
   int runAll ();