[utils] add stress_test option for async test
authorYelin Jeong <yelini.jeong@samsung.com>
Mon, 9 Oct 2023 23:55:57 +0000 (08:55 +0900)
committerWook Song <wook16.song@samsung.com>
Tue, 18 Mar 2025 07:28:09 +0000 (16:28 +0900)
This patch adds async test to stress_test.
With 'c' option, non-blocking requests submited concurrently.

Signed-off-by: Yelin Jeong <yelini.jeong@samsung.com>
utils/trinity_test/stress_test.cc
utils/trinity_test/stress_test.h

index cadc184ffbe932ca3ec539eb1178dfd504d37e91..91ff3e7613a6742ea2a3ffaa38eae42890729c5c 100644 (file)
@@ -28,6 +28,113 @@ StressTester::printUsage (char* argv) {
   std::cout << "\tInference\n";
   std::cout << "\t-m model_path      : inference model path\n";
   std::cout << "\t-f # of inference  : number of inference\n";
+  std::cout << "\t-c # of async req  : number of requests with non_blocking option\n";
+}
+
+static void
+cb (output_buffers* output, int req_id, void* data) {
+  test_sync* sync = static_cast<test_sync*> (data);
+  std::unique_lock<std::mutex> lock (sync->m);
+  sync->end++;
+  sync->cv.notify_one ();
+}
+
+generic_buffers*
+StressTester::createBuffer (bool isInput) {
+  generic_buffers* buffers = new generic_buffers;
+
+  std::vector<std::string>* path;
+  std::string prefix;
+
+  if (isInput) {
+    buffers->num_buffers = meta_->input_seg_num;
+    path = &inpath_;
+    prefix = "input";
+  } else {
+    buffers->num_buffers = meta_->output_seg_num;
+    path = &outpath_;
+    prefix = "output";
+  }
+
+  if (NPUBIN_VERSION (meta_->magiccode) <= 1) {
+    path->resize (1);
+    path->at (0) = model_dir_ + "/" + prefix + "_fmap.bin";
+    buffers->bufs[0].filepath = path->at (0).c_str ();
+    buffers->bufs[0].size = get_file_size (path->at (0).c_str ());
+    buffers->bufs[0].type = isInput ? BUFFER_FILE : BUFFER_MAPPED;
+  } else {
+    path->resize (buffers->num_buffers);
+    for (uint32_t i = 0; i < buffers->num_buffers; i++) {
+      path->at (i) = model_dir_ + "/" + prefix + "_fmap_" + std::to_string (i) + ".bin";
+      buffers->bufs[i].filepath = path->at (i).c_str ();
+      buffers->bufs[i].size = get_file_size (path->at (i).c_str ());
+      buffers->bufs[i].type = isInput ? BUFFER_FILE : BUFFER_MAPPED;
+    }
+  }
+
+  for (uint32_t i = 0; i < buffers->num_buffers; i++) {
+    if (buffers->bufs[i].size == 0) {
+      std::cerr << "Failed to find " << prefix << "_fmap" << std::endl;
+      goto clear;
+    }
+  }
+
+  return buffers;
+
+clear:
+  delete buffers;
+  return nullptr;
+}
+
+int
+StressTester::addRequest () {
+  int status, req_id;
+  input_buffers* input_buffer;
+  output_buffers* output_buffer;
+
+  input_buffer = createBuffer (true);
+  output_buffer = createBuffer (false);
+
+  if (input_buffer == nullptr || output_buffer == nullptr) {
+    std::cerr << "Failed to create buffers" << std::endl;
+    return -EINVAL;
+  }
+
+  status = allocNPU_genericBuffers (dev_, output_buffer);
+  if (status < 0) {
+    std::cerr << "Failed to alloc output buffers : " << status << std::endl;
+    return -EINVAL;
+  }
+
+  status = createNPU_request (dev_, model_id_, &req_id);
+  if (status < 0) {
+    std::cerr << "Failed to create request : " << status << std::endl;
+    goto clean_output;
+  }
+
+  status = setNPU_requestData (dev_, req_id, input_buffer, NULL, output_buffer, NULL);
+  if (status < 0) {
+    std::cerr << "Failed to set input data : " << status << std::endl;
+    goto remove_request;
+  }
+
+  if (async_mode_) {
+    status = setNPU_requestCallback (dev_, req_id, cb, &sync);
+    status = setNPU_requestMode (dev_, req_id, NPU_INFER_NON_BLOCKING);
+  }
+
+  inputs_.push_back (input_buffer);
+  outputs_.push_back (output_buffer);
+  req_ids_.push_back (req_id);
+
+  return 0;
+
+remove_request:
+  removeNPU_request (dev_, req_id);
+clean_output:
+  cleanNPU_genericBuffers (dev_, output_buffer);
+
+  return status;
 }
 
 int
@@ -75,71 +182,14 @@ StressTester::init () {
     return status;
   }
 
-  input_.num_buffers = meta_->input_seg_num;
-  if (NPUBIN_VERSION (meta_->magiccode) <= 1) {
-    inpath_.resize (1);
-    inpath_[0] = model_dir_ + "/input_fmap.bin";
-    input_.bufs[0].filepath = inpath_[0].c_str ();
-    input_.bufs[0].size = get_file_size (inpath_[0].c_str ());
-    input_.bufs[0].type = BUFFER_FILE;
-  } else {
-    inpath_.resize (input_.num_buffers);
-    for (uint32_t idx = 0; idx < input_.num_buffers; idx++) {
-      inpath_[idx] = model_dir_ + "/input_fmap_" + std::to_string (idx) + ".bin";
-      input_.bufs[idx].filepath = inpath_[idx].c_str ();
-      input_.bufs[idx].size = get_file_size (inpath_[idx].c_str ());
-      input_.bufs[idx].type = BUFFER_FILE;
-    }
-  }
-
-  for (uint32_t idx = 0; idx < input_.num_buffers; idx++) {
-    if (input_.bufs[idx].size == 0) {
-      std::cerr << "Failed to find input_fmap" << std::endl;
-      return -ENOENT;
-    }
-  }
-
-  output_.num_buffers = meta_->output_seg_num;
-  if (NPUBIN_VERSION (meta_->magiccode) <= 1) {
-    outpath_.resize (1);
-    outpath_[0] = model_dir_ + "/output_fmap.bin";
-    output_.bufs[0].filepath = outpath_[0].c_str ();
-    output_.bufs[0].size = get_file_size (outpath_[0].c_str ());
-    output_.bufs[0].type = BUFFER_MAPPED;
-  } else {
-    outpath_.resize (output_.num_buffers);
-    for (uint32_t idx = 0; idx < output_.num_buffers; idx++) {
-      outpath_[idx] = model_dir_ + "/output_fmap_" + std::to_string (idx) + ".bin";
-      output_.bufs[idx].filepath = outpath_[idx].c_str ();
-      output_.bufs[idx].size = get_file_size (outpath_[idx].c_str ());
-      output_.bufs[idx].type = BUFFER_MAPPED;
-    }
-  }
-
-  for (uint32_t idx = 0; idx < output_.num_buffers; idx++) {
-    if (output_.bufs[idx].size == 0) {
-      std::cerr << "Failed to find output_fmap" << std::endl;
-      return -ENOENT;
+  for (int i = 0; i < req_num_; i++) {
+    status = addRequest ();
+    if (status < 0) {
+      std::cerr << "Failed to add request" << std::endl;
+      break;
     }
   }
 
-  status = allocNPU_genericBuffers (dev_, &output_);
-  if (status < 0) {
-    std::cerr << "Failed to alloc output buffers : " << status << std::endl;
-    return status;
-  }
-
-  status = createNPU_request (dev_, model_id_, &req_id_);
-  if (status < 0) {
-    std::cerr << "Failed to create request : " << status << std::endl;
-    return status;
-  }
-
-  status = setNPU_requestData (dev_, req_id_, &input_, NULL, &output_, NULL);
-  if (status < 0) {
-    std::cerr << "Failed to set input data : " << status << std::endl;
-    return status;
-  }
   return 0;
 }
 
@@ -241,26 +291,44 @@ StressTester::runInference () {
     return 0;
 
   start = clock ();
+  std::cerr << "runInference: " << model_dir_ << std::endl;
+
+  for (int i = 0; i < infer_num_; i++) {
+    if (async_mode_) {
+      sync.end = 0;
+      for (int j = 0; j < req_num_; j++) {
+        status = submitNPU_request (dev_, req_ids_[j]);
+        if (status < 0) {
+          std::cerr << "Failed to submit request : " << status << std::endl;
+          return status;
+        } else
+          std::unique_lock<std::mutex> lock (sync.m);
+      }
+
+      std::unique_lock<std::mutex> lock (sync.m);
+      sync.cv.wait (lock, [&] () { return sync.end == req_num_; });
+    } else {
+      status = submitNPU_request (dev_, req_ids_[0]);
+      if (status < 0) {
+        std::cerr << "Failed to submit request : " << status << std::endl;
+        return status;
+      }
+    }
 
-  std::cout << "runInference: " << model_dir_ << std::endl;
-  for (int j = 0; j < infer_num_; j++) {
-    status = submitNPU_request (dev_, req_id_);
-    if (status < 0) {
-      std::cerr << "Failed to submit request : " << status << std::endl;
-      return status;
+    success = true;
+
+    for (int j = 0; j < req_num_; j++) {
+      for (int k = 0; k < outputs_[j]->num_buffers; k++) {
+        const char* path = outpath_[k].c_str ();
+        char* buf = static_cast<char*> (outputs_[j]->bufs[k].addr);
+        size_t size = outputs_[j]->bufs[k].size;
+
+        if (compare_data (path, buf, size) != 0)
+          success = false;
+      }
     }
-  }
-  success = true;
-  for (int j = 0; j < output_.num_buffers; j++) {
-    const char* path = outpath_[j].c_str ();
-    char* buf = static_cast<char*> (output_.bufs[j].addr);
-    size_t size = output_.bufs[j].size;
-
-    if (compare_data (path, buf, size) != 0)
-      success = false;
-  }
-  if (!success) {
-    return -1;
+    if (!success)
+      return -1;
   }
 
   if (print_time_) {
@@ -291,7 +359,7 @@ StressTester::parseArgs (int argc, char** argv) {
 
   optind = 0;
   opterr = 0;
-  while ((c = getopt (argc, argv, "i:s:a:rm:f:pth")) != -1) {
+  while ((c = getopt (argc, argv, "i:s:a:rm:f:pthc:")) != -1) {
     switch (c) {
       case 'i':
         setIterNum (optarg);
@@ -317,9 +385,13 @@ StressTester::parseArgs (int argc, char** argv) {
       case 't':
         setPrintTime (true);
         break;
+      case 'c':
+        setAsyncNum (optarg);
+        break;
       case '?':
-        if (optopt == 's' || optopt == 'a' || optopt == 'i' || optopt == 'm' || optopt == 'f')
-          std::cerr << "Option 's','a','i','m' or 'f' requires an extra argument\n";
+        if (optopt == 's' || optopt == 'a' || optopt == 'i' || optopt == 'm' || optopt == 'f' ||
+            optopt == 'c')
+          std::cerr << "Option 's','a','i','m','f' or 'c' requires an extra argument\n";
         else
           std::cerr << "Unknown flag: " << c << std::endl;
         return -1;
index 33d74e7e1f77015260da87c6005ef83c1b09a5ac..71d6310565e181373aedd2e77f2a6e0a8eba02b1 100644 (file)
 
 #include "ne_test_utils_common.h"
 
+typedef struct {
+  std::mutex m;
+  std::condition_variable cv;
+  int end;
+} test_sync;
+
 class StressTester {
  public:
   StressTester ()
       : dev_ (nullptr),
-        req_id_ (0),
         meta_ (nullptr),
         model_id_ (0),
         print_time_ (false),
         alloc_random_ (false),
-        pause_on_iter_(false),
+        pause_on_iter_ (false),
+        async_mode_ (false),
         buffer_size_ (0),
         alloc_num_ (0),
         iter_num_ (1),
-        infer_num_ (0) {
-    memset (&input_, '\x00', sizeof (input_buffers));
-    memset (&output_, '\x00', sizeof (output_buffers));
-  };
+        infer_num_ (0),
+        req_num_ (1){};
   ~StressTester () {}
 
   int parseArgs (int argc, char** argv);
@@ -50,6 +54,10 @@ class StressTester {
   void setIterNum (std::string iter_num) { iter_num_ = stoi (iter_num); }
   void setModelPath (std::string model_path) { model_dir_ = model_path; }
   void setInferNum (std::string infer_num) { infer_num_ = stoi (infer_num); }
+  void setAsyncNum (std::string async_num) {
+    req_num_ = stoi (async_num);
+    async_mode_ = true;
+  }
   void setPauseOnIter (bool pause_on_iter) { pause_on_iter_ = pause_on_iter; }
   void printUsage (char* argv);
 
@@ -58,14 +66,16 @@ class StressTester {
   int runAllocMemory ();
   int runInference ();
   int cleanup ();
+  generic_buffers* createBuffer (bool isInput);
+  int addRequest ();
 
  private:
   npudev_h dev_;
-  input_buffers input_;
-  output_buffers output_;
+  std::vector<input_buffers*> inputs_;
+  std::vector<output_buffers*> outputs_;
   std::vector<std::string> inpath_;
   std::vector<std::string> outpath_;
-  int req_id_;
+  std::vector<int> req_ids_;
   npubin_meta* meta_;
   std::vector<generic_buffer*> buffers_;
   std::string model_dir_;
@@ -73,8 +83,12 @@ class StressTester {
   bool print_time_;
   bool alloc_random_;
   bool pause_on_iter_;
+  bool async_mode_;
   uint64_t buffer_size_;
   int alloc_num_;
   int iter_num_;
   int infer_num_;
+  int req_num_;
+
+  test_sync sync;
 };