[TRIV2.3/API] Add new API to get a device instance with tops info
authorDongju Chae <dongju.chae@samsung.com>
Tue, 5 Jan 2021 01:23:03 +0000 (10:23 +0900)
committer채동주/On-Device Lab(SR)/Staff Engineer/삼성전자 <dongju.chae@samsung.com>
Tue, 5 Jan 2021 09:45:14 +0000 (18:45 +0900)
This patch adds new API to get a device instance with tops info.
It tries to find any available device with the given tops.

Signed-off-by: Dongju Chae <dongju.chae@samsung.com>
13 files changed:
include/common/typedef.h
include/host/libnpuhost.h
src/host/ne-host.cc
tests/apptests/meson.build
tests/apptests/tvn_triv2.cc
tests/apptests/tvn_triv2_bulk.c [deleted file]
tests/apptests/tvn_triv2_bulk.cc [new file with mode: 0644]
tests/apptests/tvn_triv2_bulk_gem.c
tests/apptests/tvn_triv2_dmabuf.cc
tests/apptests/tvn_triv2_recurring.cc
tests/utils/ne_test_utils.cc
tests/utils/ne_test_utils.h
utils/trinity_smi/trinity-smi.cc

index d75dba4..b8bdc36 100644 (file)
@@ -225,6 +225,7 @@ typedef struct {
 static const uint32_t default_timeout = 3000;
 static const npu_priority default_priority = NPU_PRIORITY_MID;
 static const npu_notimode default_notimode = NPU_INTERRUPT;
+static const uint32_t default_tops = 8; /** TODO: change to 2-TOPS when testdata is ready */
 
 /**
  * @brief Description of npu device status
index 05bcd37..caa7b75 100644 (file)
@@ -44,6 +44,7 @@ void getVersion (uint32_t *major, uint32_t *minor, uint32_t *extra);
 
 /**
  * @brief Returns the number of available NPU devices.
+ * @param[in] type the device type
  * @return @c The number of available NPU devices.
  * @note this number indicates the range of device IDs in getNPUdeviceByType ().
 */
@@ -52,6 +53,7 @@ int getnumNPUdeviceByType (dev_type type);
 /**
  * @brief Returns the handle of the chosen NPU devices.
  * @param[out] dev The NPU device handle
+ * @param[in] type the NPU device type
  * @param[in] id The NPU id to get the handle. 0 <= id < getnumNPUdeviceByType().
  * @return @c 0 if no error. otherwise a negative error value
  * @note the caller should call putNPUdevice() to release the device handle
@@ -59,6 +61,16 @@ int getnumNPUdeviceByType (dev_type type);
 int getNPUdeviceByType (npudev_h *dev, dev_type type, uint32_t id);
 
 /**
+ * @brief Returns the handle of any available device with the given type and tops.
+ * @param[out] dev The NPU device handle
+ * @param[in] type the NPU device type
+ * @param[in] tops the device's computing power (Tera Operations Per Sec)
+ * @return @c 0 if no error. otherwise a negative error value
+ * @note the caller should call putNPUdevice() to release the device handle
+ */
+int getNPUdeviceByTypeAny (npudev_h *dev, dev_type type, uint32_t tops);
+
+/**
  * @brief release the NPU device instance obtained by getDevice ()
  * @param[in] dev the NPU device handle
  */
index ddc9d71..eb6ce7c 100644 (file)
@@ -64,6 +64,46 @@ int getNPUdeviceByType (npudev_h *dev, dev_type type, uint32_t id)
 }
 
 /**
+ * @brief Returns the handle of any available device with the given type and tops.
+ * @param[out] dev The NPU device handle
+ * @param[in] type the NPU device type
+ * @param[in] tops the device's computing power (Tera Operations Per Sec)
+ * @return @c 0 if no error. otherwise a negative error value
+ * @note the caller should call putNPUdevice() to release the device handle
+ */
+int getNPUdeviceByTypeAny (npudev_h *dev, dev_type type, uint32_t tops)
+{
+  int num_devices = getnumNPUdeviceByType (type);
+
+  if (tops == 0)
+    tops = default_tops;
+
+#ifdef ENABLE_EMUL
+  if (num_devices > 0)
+    return HostHandler::getDevice (dev, type, 0);
+#else
+  for (int id = 0; id < num_devices; id++) {
+    int status = HostHandler::getDevice (dev, type, id);
+    if (status == 0) {
+      uint32_t tops_ = 0;
+      status = getNPU_tops (*dev, &tops_);
+      if (status != 0 || tops_ != tops) {
+        putNPUdevice (*dev);
+        *dev = nullptr;
+      } else {
+        return 0;
+      }
+    } else {
+      return status;
+    }
+  }
+#endif
+
+  logwarn (TAG, "No available NPU device detected");
+  return -ENODEV;
+}
+
+/**
  * @brief release the NPU device instance obtained by getDevice ()
  * @param[in] dev the NPU device handle
  */
index 5236da4..5de59cc 100644 (file)
@@ -84,7 +84,7 @@ executable ('apptest_tvn_triv_bulk',
 )
 
 executable ('apptest_tvn_triv2_bulk',
-  'tvn_triv2_bulk.c',
+  'tvn_triv2_bulk.cc',
   include_directories : ne_apptest_inc,
   dependencies : ne_test_utils_dep,
   link_with : ne_library_shared,
index cdefd36..9e4a927 100644 (file)
@@ -25,7 +25,18 @@ class Tester : public UtilTRIV2
 
     /** @brief initilize the device handle */
     int init (std::string model_dir) {
-      int status = UtilTRIV2::init ();
+      if (model_dir == "")
+        return -EINVAL;
+
+      std::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;
diff --git a/tests/apptests/tvn_triv2_bulk.c b/tests/apptests/tvn_triv2_bulk.c
deleted file mode 100644 (file)
index 15df4f5..0000000
+++ /dev/null
@@ -1,219 +0,0 @@
-/**
- * Proprietary
- * Copyright (C) 2020 Samsung Electronics
- * Copyright (C) 2020 Dongju Chae <dongju.chae@samsung.com>
- */
-/**
- * @file tvn_triv2_bulk.c
- * @date 14 May 2020
- * @brief AppTest to test example visa binaries (triv2/npubinfmt v3)
- * @author Dongju Chae <dongju.chae@samsung.com>
- * @bug No known bugs except for NYI items
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <assert.h>
-#include <errno.h>
-
-#include <libnpuhost.h>
-#include <npubinfmt.h>
-#include <ne_test_utils.h>
-
-#define MAX_FILE_LEN 256
-#define NPU_MODEL_NAME "model.tvn"
-#define NPU_TIMEOUT_MS  5000
-
-static int enable_output_dump = 0;
-
-/** @brief compare output buffers */
-static int
-compare_output_buffers (const npubin_meta *meta, const char *base_path,
-    const char *target, output_buffers *output)
-{
-  char golden_path[MAX_FILE_LEN];
-  char *output_data;
-  off_t output_size;
-  int err = 0;
-  uint32_t idx;
-
-  for (idx = 0; idx < output->num_buffers; idx++) {
-    output_data = output->bufs[idx].addr;
-    output_size = output->bufs[idx].size;
-
-    snprintf (golden_path, MAX_FILE_LEN, "%s/%s/output_fmap_%d.bin",
-        base_path, target, idx);
-
-    err = compare_data (golden_path, output_data, output_size);
-
-    if (enable_output_dump == 1) {
-      char output_path[MAX_FILE_LEN];
-      FILE *f;
-
-      snprintf (output_path, MAX_FILE_LEN, "%s/%s/obtained_fmap_%d.bin",
-          base_path, target, idx);
-      f = fopen (output_path, "wb");
-      if (f != NULL) {
-        fwrite (output_data, output_size, 1, f);
-        fclose (f);
-      }
-    }
-
-    assert (output->bufs[idx].type == BUFFER_MAPPED);
-    free (output->bufs[idx].addr);
-
-    if (err != 0)
-      break;
-  }
-
-  return err;
-}
-
-/** @brief run inference for each target visa binary (on sync mode) */
-static int
-run_inference_each (npudev_h dev, const char *base_path, const char *target)
-{
-  generic_buffer model;
-  input_buffers input;
-  output_buffers output;
-
-  char model_path[MAX_FILE_LEN];
-  char input_path[MAX_TENSORS][MAX_FILE_LEN];
-  off_t input_size;
-
-  npuConstraint constraint;
-  npubin_meta *meta;
-  uint32_t model_id;
-  uint32_t idx;
-  int err = 0;
-
-  /** 1: setup model (not dmabuf) */
-  memset (model_path, '\x00', MAX_FILE_LEN);
-  snprintf (model_path, MAX_FILE_LEN, "%s/%s/%s",
-      base_path, target, NPU_MODEL_NAME);
-
-  meta = getNPUmodel_metadata (model_path, false);
-  if (meta == NULL) {
-    fprintf (stderr, "Fail to get the metadata of %s\n", model_path);
-    return -EINVAL;
-  }
-
-  model.size = get_file_size (model_path);
-  model.filepath = model_path;
-  model.type = BUFFER_FILE;
-
-  /** 2: setup input buffers */
-  if (NPUBIN_VERSION (meta->magiccode) != 3) {
-    fprintf (stderr, "Support only npubinfmt v3\n");
-    err = -EINVAL;
-    goto out_free_meta;
-  }
-
-  for (idx = 0; idx < meta->input_seg_num; idx++) {
-    memset (input_path[idx], '\x00', MAX_FILE_LEN);
-    snprintf (input_path[idx], MAX_FILE_LEN, "%s/%s/input_fmap_%d.bin",
-        base_path, target, idx);
-
-    input_size = get_file_size (input_path[idx]);
-    if (input_size <= 0) {
-      fprintf (stderr, "Wrong metadata; need %d input tensors\n", meta->input_seg_num);
-      err = -EINVAL;
-      goto out_free_meta;
-    }
-
-    input.bufs[idx].size = input_size;
-    input.bufs[idx].type = BUFFER_FILE;
-    input.bufs[idx].filepath = input_path[idx];
-  }
-
-  input.num_buffers = meta->input_seg_num;
-
-  /** 3: allocate input buffers (it's not mandatory to use this API) */
-  if ((err = allocNPU_inputBuffers (dev, &input)) != 0) {
-    fprintf (stderr, "Fail to allocate NPU input buffer (errno %d)\n", err);
-    goto out_free_meta;
-  }
-
-  /** 4: register the model to NPU Engine */
-  if ((err = registerNPUmodel (dev, &model, &model_id)) != 0) {
-    fprintf (stderr, "Fail to registerNPU model (errno %d)\n", err);
-    goto out_clean;
-  }
-
-  /** 4-1: provide additional information to NPU Engine */
-  {
-    tensors_data_info info_in;
-    tensors_data_info info_out;
-
-    /* No data manipulation & quantization in this test */
-
-    info_in.num_info = meta->input_seg_num;
-    for (idx = 0; idx < info_in.num_info; idx++) {
-      info_in.info[idx].layout = DATA_LAYOUT_TRIV2;
-      info_in.info[idx].type = DATA_TYPE_QASYMM8;
-    }
-
-    info_out.num_info = meta->output_seg_num;
-    for (idx = 0; idx < info_out.num_info; idx++) {
-      info_out.info[idx].layout = DATA_LAYOUT_TRIV2;
-      info_out.info[idx].type = DATA_TYPE_QASYMM8;
-    }
-
-    if ((err = setNPU_dataInfo (dev, model_id, &info_in, &info_out)) != 0) {
-      fprintf (stderr, "Failed to set the information for NPU data\n");
-      goto out_unregister;
-    }
-  }
-
-  /** 4-2: set constraints */
-  constraint.timeout_ms = NPU_TIMEOUT_MS;
-  constraint.priority = NPU_PRIORITY_MID;
-  constraint.notimode = NPU_INTERRUPT;
-  if ((err = setNPU_constraint (dev, model_id, constraint)) != 0)
-    goto out_unregister;
-
-  /** 5: run NPU inference (sync) */
-  if ((err = runNPU_sync (dev, model_id, &input, &output)) != 0)
-    goto out_unregister;
-
-  /** 6: compare output buffers */
-  err = compare_output_buffers (meta, base_path, target, &output);
-
-out_unregister:
-  unregisterNPUmodel (dev, model_id);
-out_clean:
-  cleanNPU_inputBuffers (dev, &input);
-out_free_meta:
-  free (meta);
-
-  /** ensure that all memory (allocated by libnpuhost APIs) are successfully freed */
-  if (err == 0)
-    check_memory_leak (dev);
-
-  return err;
-}
-
-/** @brief apptest main  */
-int
-main (int argc, char **argv)
-{
-  dev_type type = NPUCOND_TRIV2_CONN_SOCIP;
-  npudev_h dev;
-
-  if (argc < 2) {
-    fprintf (stderr, "[APPTEST] %s: SKIPPED\n", argv[0]);
-    return 0;
-  }
-
-  if (argc == 3)
-    enable_output_dump = atoi(argv[2]);
-
-  if (!(getnumNPUdeviceByType (type) > 0 &&
-        getNPUdeviceByType (&dev, type, 0) == 0)) {
-    fprintf(stderr, "No available TRIV2 device\n");
-    return -1;
-  }
-
-  return run_apptest (dev, argv, &run_inference_each);
-}
diff --git a/tests/apptests/tvn_triv2_bulk.cc b/tests/apptests/tvn_triv2_bulk.cc
new file mode 100644 (file)
index 0000000..838042f
--- /dev/null
@@ -0,0 +1,130 @@
+/**
+ * Proprietary
+ * Copyright (C) 2020 Samsung Electronics
+ * Copyright (C) 2020 Dongju Chae <dongju.chae@samsung.com>
+ */
+/**
+ * @file tvn_triv2.cc
+ * @date 09 Jul 2020
+ * @brief AppTest to test a single inference for TRIV2 device
+ * @author Dongju Chae <dongju.chae@samsung.com>
+ * @bug No known bugs except for NYI items
+ */
+
+#include <ne_test_utils.h>
+
+#include <iomanip>
+
+#include <sys/types.h>
+#include <dirent.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) {}
+
+    /** @brief initilize the device handle */
+    int init (std::string model_dir) {
+      std::string model_path = model_dir + "/model.tvn";
+      npubin_meta * meta = getNPUmodel_metadata (model_path.c_str(), false);
+      if (meta == nullptr) {
+        cerr << "Failed to get the model metadata\n";
+        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 the device\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 task_id = UtilTRIV2::run (model_id_);
+      if (task_id < 0)
+        return task_id;
+
+      return wait () == 1 ? test_ret_success : test_ret_failure;
+    }
+
+  private:
+    uint32_t model_id_;
+};
+
+/** @brief apptest main  */
+int
+main (int argc, char **argv)
+{
+  Tester tester;
+  char * dir_str;
+  int status;
+
+  status = tester.parseArgs (argc, argv, &dir_str, "[models' dir]");
+  if (status == test_ret_skipped || dir_str == nullptr) {
+    cerr << "[APPTEST] " << argv[0] << ": SKIPPED\n";
+    return 0;
+  } else if (status != test_ret_success) {
+    cerr << "[APPTEST] " << argv[0] << ": FAILED (" << status << ")\n";
+    return status;
+  }
+
+  DIR *d = opendir (dir_str);
+  if (!d) {
+    cerr << "Failed to open " << dir_str << "\n";
+    return -errno;
+  }
+
+  uint32_t total_succs, total_fails;
+  struct dirent *dir;
+
+  total_succs = total_fails = 0;
+  while ((dir = readdir (d)) != NULL) {
+    /** a target binary and data are in each sub-directory */
+    if (dir->d_type != DT_DIR)
+      continue;
+    if (dir->d_name[0] == '.')
+      continue;
+
+    cerr << "[APPTEST] " << left << setw (40) << dir->d_name << " Running... ";
+
+    /** initialize triv2 device */
+    string path (dir_str);
+    status = tester.init (path + "/" + dir->d_name);
+    if (status == test_ret_success) {
+      /** run the inference with the device */
+      status = tester.run ();
+      if (status == test_ret_success) {
+        cerr << "PASSED\n";
+        total_succs++;
+      } else {
+        cerr << "FAILED\n";
+        total_fails++;
+      }
+
+      tester.clear ();
+    } else {
+      cerr << "FAILED\n";
+      total_fails++;
+    }
+  }
+
+  cerr << "[APPTEST] " << argv[0] << ": PASSED (" << total_succs << "), "
+       << "FAILED (" << total_fails << ")\n";
+
+  return 0;
+}
index 9cbc862..dd13652 100644 (file)
@@ -309,8 +309,7 @@ main (int argc, char **argv)
   if (argc == 3)
     enable_output_dump = atoi(argv[2]);
 
-  if (!(getnumNPUdeviceByType (type) > 0 &&
-        getNPUdeviceByType (&dev, type, 0) == 0)) {
+  if (getNPUdeviceByTypeAny (&dev, type, default_tops) != 0) {
     fprintf(stderr, "No available TRIV2 device\n");
     return -1;
   }
index 6aab7bd..7f78da5 100644 (file)
@@ -56,15 +56,8 @@ class TesterTRIV2 {
 
     /** @brief initilize the device handle */
     int init (const std::string dir) {
-      int num_devices = getnumNPUdeviceByType (TRIV2_TYPE);
-      if (num_devices <= 0)
-        return -ENODEV;
-
-      /** use any available TRIV2 device. (0 <= dev_id < num_devices) */
-      int dev_id = num_devices - 1;
-
       dir_ = dir;
-      return getNPUdeviceByType (&dev_, TRIV2_TYPE, dev_id);
+      return getNPUdeviceByTypeAny (&dev_, TRIV2_TYPE, default_tops);
     }
 
     /** @brief run the inference (with dummy data) */
index c6deb5a..b6c8df5 100644 (file)
@@ -51,7 +51,7 @@ class ThirdPartyHW {
 
     int init (const npubin_meta *meta) {
       /** let's emulate an external dmabuf using TRIV2 */
-      int status = getNPUdeviceByType (&dev_, TRIV2_TYPE, 0);
+      int status = getNPUdeviceByTypeAny (&dev_, TRIV2_TYPE, default_tops);
       if (status != 0)
         return status;
 
index 46e0532..6d41262 100644 (file)
@@ -300,24 +300,24 @@ UtilTrinity::UtilTrinity (dev_type type, bool need_model, bool verify)
 
 /** @brief destructor of UtilTrinity */
 UtilTrinity::~UtilTrinity () {
+  clear ();
+}
+
+/** @brief device instance cleanup */
+void UtilTrinity::clear () {
   if (dev_ != nullptr) {
     unregisterNPUmodel_all (dev_);
     putNPUdevice (dev_);
+    dev_ = nullptr;
   }
 
   models_.clear ();
 }
 
 /** @brief initialize trinity device and get the device handle */
-int UtilTrinity::init ()
+int UtilTrinity::init (uint32_t tops)
 {
-  int num_devices = getnumNPUdeviceByType (type_);
-  if (num_devices <= 0)
-    return -ENODEV;
-
-  /** use any available device. (0 <= dev_id < num_devices) */
-  int dev_id = num_devices - 1;
-  return getNPUdeviceByType (&dev_, type_, dev_id);
+  return getNPUdeviceByTypeAny (&dev_, type_, tops);
 }
 
 /** @brief print program usage */
index 0afbae0..15eb9e9 100644 (file)
@@ -93,7 +93,8 @@ class UtilTrinity {
     void setMute ();
     void setNotiMode (const std::string mode);
 
-    int init ();
+    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 loadModel (std::string dirpath, uint32_t *model_id,
index fe898e5..e2b56d5 100644 (file)
@@ -202,9 +202,9 @@ TrinitySMI::append_version ()
   ss_ << "|  Trinity System Management Interface                       |\n";
   ss_ << "|  Copyright (C) Samsung Electronics Ltd.                    |\n";
   ss_ << "|                                                            |\n";
-  ss_ << "|  TRINITY-SMI: " << smi_ver;
-  ss_ << "   NPU-ENGINE: " << lib_ver;
-  ss_ << "   DRIVER-API: ";
+  ss_ << "|  TRINITY-SMI: " << left << setw (8) << smi_ver;
+  ss_ << "NPU-ENGINE: " << left << setw (8) << lib_ver;
+  ss_ << "DRIVER-API: ";
   ss_ << setw (3);
 #ifdef ENABLE_EMUL
   ss_ << "SIM";