[Plugin/Test] Plugin test refactoring
authorDongju Chae <dongju.chae@samsung.com>
Tue, 13 Jul 2021 02:31:58 +0000 (11:31 +0900)
committer채동주/On-Device Lab(SR)/Staff Engineer/삼성전자 <dongju.chae@samsung.com>
Tue, 13 Jul 2021 06:14:46 +0000 (15:14 +0900)
This patch changes plugin test program paths.

Signed-off-by: Dongju Chae <dongju.chae@samsung.com>
packaging/npu-engine.spec
plugins/npumgr/meson.build
plugins/npumgr/tests/meson.build [deleted file]
plugins/npumgr/tests/npumgr_test.cc [deleted file]
tests/plugins/meson.build
tests/plugins/nnstreamer/meson.build [new file with mode: 0644]
tests/plugins/nnstreamer/nnstreamer_test.cc [new file with mode: 0644]
tests/plugins/nnstreamer_test.cc [deleted file]
tests/plugins/npumgr/meson.build [new file with mode: 0644]
tests/plugins/npumgr/npumgr_test.cc [new file with mode: 0644]

index 12062cfa07a77aa19859f4aea222348871b90ddf..fc9eb42ef0ca3816a77099213748dc8a70f76d1a 100644 (file)
@@ -108,12 +108,29 @@ Example application package for NPU Engine, including UnitTests and AppTest with
 Requires:      npu-engine = %{version}-%{release}
 Summary:       NPU Engine Example Package
 %description utils
-This probides utility packages for NPU Engine, including metadata extraction of model files.
+This provides utility packages for NPU Engine, including metadata extraction of model files.
 %files utils
 %manifest npu-engine.manifest
 %defattr(-,root,root,-)
 %{neexampledir}/utils/*
 
+%if ( 0%{?npumgr_plugin} || 0%{?nns_plugin} )
+%package example-plugins
+Requires:      npu-engine = %{version}-%{release}
+Summary:       NPU Engine Example Package for Plugins
+%description example-plugins
+Example application package for NPU Engine plugins
+%files example-plugins
+%manifest npu-engine.manifest
+%defattr(-,root,root,-)
+%if 0%{?npumgr_plugin}
+%{neexampledir}/plugins/npumgr/*
+%endif
+%if 0%{?nns_plugin}
+%{neexampledir}/plugins/nnstreamer/*
+%endif
+%endif
+
 %if 0%{?npumgr_plugin}
 %package -n npumgr-srnpu
 Summary:       Tizen NPU Manager plugin for SR-NPU device family
@@ -122,7 +139,6 @@ Requires:   npu-engine
 Reference implementation of Tizen NPU Manager TRIV2 plugin, including a dummy NPU Manager module.
 %files -n npumgr-srnpu
 %manifest npu-engine.manifest
-%{neexampledir}/plugins/npumgr/*
 %{_libdir}/libnpumgr*.so
 %{_datadir}/dbus-1/system.d/*
 %endif
@@ -136,8 +152,6 @@ Requires:   nnstreamer
 Reference implementation of NNStreamer filter subplugin for SR-NPU (for now, TRIV2 only).
 %files -n nnstreamer-srnpu
 %manifest npu-engine.manifest
-# Uncomment below when test-cases are ready
-# %{neexampledir}/plugins/nnstreamer/*
 %{_prefix}/lib/nnstreamer/filters/libnnstreamer_filter_srnpu.so
 %endif
 
index c67c380623f5f30855fbf41fdbd427244f2c1d9f..9b00aa4f385ca64198ad1651fea9f8c9d9312f9a 100644 (file)
@@ -3,4 +3,3 @@ npumgr_common_inc = include_directories('common')
 
 # dummy npu manager
 subdir('dummy')
-subdir('tests')
diff --git a/plugins/npumgr/tests/meson.build b/plugins/npumgr/tests/meson.build
deleted file mode 100644 (file)
index 918a998..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-# npu manager test program
-executable ('apptest_npumgr',
-  'npumgr_test.cc',
-  include_directories : [npumgr_common_inc],
-  dependencies : [glib_dep, ne_test_utils_common_dep, npumgr_dep],
-  install : true,
-  install_rpath : ne_libdir,
-  install_dir : join_paths(ne_bindir, 'plugins', 'npumgr')
-)
diff --git a/plugins/npumgr/tests/npumgr_test.cc b/plugins/npumgr/tests/npumgr_test.cc
deleted file mode 100644 (file)
index 682abd6..0000000
+++ /dev/null
@@ -1,291 +0,0 @@
-/**
- * Proprietary
- * Copyright (C) 2021 Samsung Electronics
- * Copyright (C) 2021 Dongju Chae <dongju.chae@samsung.com>
- */
-/**
- * @file npumgr_test.cc
- * @date 09 Apr 2021
- * @brief AppTest to test the I/F of VD NPU Manager
- * @author Dongju Chae <dongju.chae@samsung.com>
- * @bug No known bugs except for NYI items
- */
-
-#include <iostream>
-
-#include <fcntl.h>
-#include <unistd.h>
-
-#include <glib.h>
-#include <ne_test_utils_common.h>
-
-#include <npumgr_api.h>
-#include <npumgr_common.h>
-
-using namespace std;
-
-static int
-start_npumgr_test (int fd, const string &dir) {
-  npumgr_devices_id list;
-  npumgr_status_e status;
-
-  npumgr_context context;
-  npumgr_network network;
-
-  npumgr_buffer *input_bufs = NULL;
-  npumgr_buffer *output_bufs = NULL;
-  npumgr_query_inout_num inout_num = {0};
-
-  npumgr_network_defn input_files[] = {{NPUMGR_NETWORK_FILE_TVN, fd}};
-  const char *input_tensor_names[] = {"input"};
-  const char *output_tensor_names[] = {"output"};
-  npumgr_query_tensor_attr attr;
-
-  status = npumgr_device_get_available_list (&list);
-  if (status != NPUMGR_STATUS_SUCCESS) {
-    cerr << "Unable to get available device list, " << status << "\n";
-    return status;
-  }
-
-  /* TODO: find the first NPU device */
-  bool found = false;
-  uint32_t id;
-
-  for (int i = 0; i < list.n_devices; i++) {
-    if (list.types[i] == NPUMGR_DEVICE_TYPE_NPU) {
-      found = true;
-      id = list.id[i];
-      break;
-    }
-  }
-
-  if (!found) {
-    cerr << "No available device\n";
-    return NPUMGR_STATUS_ERR_DEVICE_UNAVAILABLE;
-  }
-
-  status = npumgr_context_create (id, NPUMGR_FLAG_PRIORITY_DEFAULT, &context);
-  if (status != NPUMGR_STATUS_SUCCESS) {
-    cerr << "Unable to create a npumgr context, " << status << "\n";
-    return NPUMGR_STATUS_ERR_FAIL;
-  }
-
-  status = npumgr_network_create (
-      context, 1, input_files, NPUMGR_BUF_TYPE_DRIVER, 1, input_tensor_names,
-      NPUMGR_BUF_TYPE_DRIVER, 1, output_tensor_names, &network);
-  if (status != NPUMGR_STATUS_SUCCESS) {
-    cerr << "Unable to create a npumgr network, " << status << "\n";
-    goto destroy_ctx;
-  }
-
-  status = npumgr_query_network (context, network, &inout_num);
-  if (status != NPUMGR_STATUS_SUCCESS) {
-    cerr << "Unable to query network info, " << status << "\n";
-    goto destroy_nw;
-  }
-
-  input_bufs = g_new0 (npumgr_buffer, inout_num.n_input);
-  output_bufs = g_new0 (npumgr_buffer, inout_num.n_output);
-
-  for (int i = 0; i < inout_num.n_input; i++) {
-    string file_path = dir + "/input_fmap_" + to_string (i) + ".bin";
-    FILE *f = fopen (file_path.c_str (), "rb");
-    void *data = NULL;
-
-    if (f == NULL) {
-      cerr << "Unable to find input file, " << file_path << "\n";
-      fclose (f);
-      goto destroy_all;
-    }
-
-    status = npumgr_query_input (context, network, i, &attr);
-    if (status != NPUMGR_STATUS_SUCCESS) {
-      cerr << "Unable to query input info, " << status << "\n";
-      fclose (f);
-      goto destroy_all;
-    }
-
-    /** TODO: currently, support NHWC format only */
-    if (attr.fmt != NPUMGR_TENSOR_FMT_NHWC) {
-      cerr << "Other format is not supported yet, " << attr.fmt << "\n";
-      fclose (f);
-      goto destroy_all;
-    }
-
-    status = npumgr_buffer_create (context, &attr, &input_bufs[i]);
-    if (status != NPUMGR_STATUS_SUCCESS) {
-      cerr << "Unable to create input buffer, " << status << "\n";
-      fclose (f);
-      goto destroy_all;
-    }
-
-    status = npumgr_buffer_map (context, &input_bufs[i], (uint8_t **) &data);
-    if (status != NPUMGR_STATUS_SUCCESS) {
-      cerr << "Unable to map input buffer, " << status << "\n";
-      fclose (f);
-      goto destroy_all;
-    }
-
-    size_t read_bytes = fread (data, 1, input_bufs[i].buf_size, f);
-    if (read_bytes != input_bufs[i].buf_size) {
-      cerr << "Unable to read input data, " << read_bytes << " vs. "
-           << input_bufs[i].buf_size << "\n";
-      fclose (f);
-      goto destroy_all;
-    }
-    fclose (f);
-
-    /** TODO: How unmap works? */
-#if 0
-    status = npumgr_buffer_unmap (context, &input_bufs[i]);
-    if (status != NPUMGR_STATUS_SUCCESS) {
-      cerr << "Unable to unmap buffer, " << status << "\n";
-      goto destroy_all;
-    }
-#else
-    munmap (data, ALIGNED_SIZE (input_bufs[i].buf_size));
-#endif
-
-    status = npumgr_network_set_input (context, network, i, &input_bufs[i]);
-    if (status != NPUMGR_STATUS_SUCCESS) {
-      cerr << "Unable to set input, " << status << "\n";
-      goto destroy_all;
-    }
-  }
-
-  for (int i = 0; i < inout_num.n_output; i++) {
-    status = npumgr_query_output (context, network, i, &attr);
-    if (status != NPUMGR_STATUS_SUCCESS) {
-      cerr << "Unable to query output info, " << status << "\n";
-      goto destroy_all;
-    }
-
-    /** TODO: currently, support NHWC format only */
-    if (attr.fmt != NPUMGR_TENSOR_FMT_NHWC) {
-      cerr << "Other format is not supported yet, " << attr.fmt << "\n";
-      goto destroy_all;
-    }
-
-    status = npumgr_buffer_create (context, &attr, &output_bufs[i]);
-    if (status != NPUMGR_STATUS_SUCCESS) {
-      cerr << "Unable to create output buffer, " << status << "\n";
-      goto destroy_all;
-    }
-
-    status = npumgr_network_set_output (context, network, i, &output_bufs[i]);
-    if (status != NPUMGR_STATUS_SUCCESS) {
-      cerr << "Unable to set output, " << status << "\n";
-      goto destroy_all;
-    }
-  }
-
-  status = npumgr_network_prepare (context, network);
-  if (status != NPUMGR_STATUS_SUCCESS) {
-    goto destroy_all;
-  }
-
-  status = npumgr_execute_run (context, network);
-  if (status != NPUMGR_STATUS_SUCCESS) {
-    cerr << "Unable to execute the network, " << status << "\n";
-    goto destroy_all;
-  }
-
-  for (int i = 0; i < inout_num.n_output; i++) {
-    string file_path = string (dir) + "/output_fmap_" + to_string (i) + ".bin";
-    void *data = NULL;
-
-    status = npumgr_buffer_map (context, &output_bufs[i], (uint8_t **) &data);
-    if (status != NPUMGR_STATUS_SUCCESS) {
-      cerr << "Unable to map output buffer, " << status << "\n";
-      goto destroy_all;
-    }
-
-    if (compare_data (file_path.c_str (), (const char *) data,
-                      output_bufs[i].buf_size) != 0) {
-      cerr << "Failed to get valid output data\n";
-      goto destroy_all;
-    }
-
-    /** TODO: How unmap works? */
-#if 0
-    status = npumgr_buffer_unmap (context, &output_bufs[i]);
-    if (status != NPUMGR_STATUS_SUCCESS) {
-      cerr << "Unable to unmap output buffer, " << status << "\n";
-      goto destroy_all;
-    }
-#else
-    munmap (data, ALIGNED_SIZE (output_bufs[i].buf_size));
-#endif
-  }
-
-destroy_all:
-  if (input_bufs) {
-    for (int i = 0; i < inout_num.n_input; i++) {
-      if (input_bufs[i].buf_handle == 0)
-        continue;
-
-      status = npumgr_buffer_destroy (context, &input_bufs[i]);
-      if (status != NPUMGR_STATUS_SUCCESS)
-        cerr << "Unable to destroy the buffer, " << status << "\n";
-    }
-  }
-
-  if (output_bufs) {
-    for (int i = 0; i < inout_num.n_output; i++) {
-      if (output_bufs[i].buf_handle == 0)
-        continue;
-
-      status = npumgr_buffer_destroy (context, &output_bufs[i]);
-      if (status != NPUMGR_STATUS_SUCCESS)
-        cerr << "Unable to destroy the buffer, " << status << "\n";
-    }
-  }
-
-destroy_nw:
-  status = npumgr_network_destroy (context, network);
-  if (status != NPUMGR_STATUS_SUCCESS)
-    cerr << "Unable to destroy the npumgr network, " << status << "\n";
-
-destroy_ctx:
-  status = npumgr_context_destroy (context);
-  if (status != NPUMGR_STATUS_SUCCESS)
-    cerr << "Unable to destroy the npumgr context, " << status << "\n";
-
-  return status;
-}
-
-int
-main (int argc, char **argv) {
-  int fd, ret = -EINVAL;
-
-  if (argc != 2) {
-    cerr << "Please provide model datapath (i.e., including .tvn and .bin)\n";
-    cerr << "[APPTEST] " << argv[0] << ": SKIPPED\n";
-    return 0;
-  }
-
-  string dir (argv[1]);
-  string model_path = dir + "/model.tvn";
-
-  if (!g_file_test (dir.c_str (), G_FILE_TEST_IS_DIR)) {
-    cerr << "Invalid model datapath: " << dir << "\n";
-    goto out;
-  }
-
-  fd = open (model_path.c_str (), O_RDONLY);
-  if (fd < 0) {
-    cerr << "Unable to open file " << dir << "\n";
-    goto out;
-  }
-
-  ret = start_npumgr_test (fd, dir);
-  close (fd);
-
-out:
-  if (ret == 0)
-    cerr << "[APPTEST] " << argv[0] << ": PASSED\n";
-  else
-    cerr << "[APPTEST] " << argv[0] << ": FAILED (" << ret << ")\n";
-
-  return ret;
-}
index d02580fa74c3f25e982b8e4f7630dae8d8cd0ad4..ce5dc4ce0c9039df9c78547e1576e9a7bfc1f697 100644 (file)
@@ -1,15 +1,6 @@
-if ne_test_utils_gtest_dep.found()
-  testenv = environment()
-  testenv.set('LD_LIBRARY_PATH', ne_libdir)
-
-  if get_option('enable_plugin_nns')
-    plugintest_nnstreamer = executable('plugintest_nnstreamer',
-      ['nnstreamer_test.cc'],
-      dependencies: [ne_test_utils_gtest_dep, glib_dep, gst_dep],
-      install : true,
-      install_rpath : ne_libdir,
-      install_dir : join_paths(ne_bindir, 'plugins')
-    )
-    test('plugintest_nnstreamer', plugintest_nnstreamer, env: testenv)
-  endif
+if get_option('enable_plugin_nns')
+  subdir('nnstreamer')
+endif
+if get_option('enable_plugin_npumgr')
+  subdir('npumgr')
 endif
diff --git a/tests/plugins/nnstreamer/meson.build b/tests/plugins/nnstreamer/meson.build
new file mode 100644 (file)
index 0000000..2d88763
--- /dev/null
@@ -0,0 +1,15 @@
+if ne_test_utils_gtest_dep.found()
+  testenv = environment()
+  testenv.set('LD_LIBRARY_PATH', ne_libdir)
+
+  if get_option('enable_plugin_nns')
+    plugintest_nnstreamer = executable('plugintest_nnstreamer',
+      ['nnstreamer_test.cc'],
+      dependencies: [ne_test_utils_gtest_dep, glib_dep, gst_dep],
+      install : true,
+      install_rpath : ne_libdir,
+      install_dir : join_paths(ne_bindir, 'plugins', 'nnstreamer')
+    )
+    test('plugintest_nnstreamer', plugintest_nnstreamer, env: testenv)
+  endif
+endif
diff --git a/tests/plugins/nnstreamer/nnstreamer_test.cc b/tests/plugins/nnstreamer/nnstreamer_test.cc
new file mode 100644 (file)
index 0000000..dbc41a9
--- /dev/null
@@ -0,0 +1,134 @@
+/**
+ * Proprietary
+ * Copyright (C) 2021 Samsung Electronics
+ * Copyright (C) 2021 Dongju Chae <dongju.chae@samsung.com>
+ */
+/**
+ * @file nnstreamer_test.cc
+ * @date 07 July 2021
+ * @brief Test NNStreamer filter sub-plugin for TRIV2
+ * @author Dongju Chae <dongju.chae@samsung.com>
+ * @bug No known bugs except for NYI items
+ */
+
+#include <ne_test_utils_gtest.h>
+
+#include <glib.h>
+#include <gst/gst.h>
+
+#define STATECHANGE_TIMEOUT 100000 /* 100s */
+
+typedef enum {
+  MODEL_CONV_2D_000 = 0,
+  MODEL_MOBILENET_V1,
+  MODEL_END
+} srnpu_model;
+
+static const gchar *model_names[MODEL_END] = {
+    [MODEL_CONV_2D_000] = "CONV_2D_000",
+    [MODEL_MOBILENET_V1] = "MOBILENET_V1",
+};
+
+static const gchar *input_dims[MODEL_END] = {
+    [MODEL_CONV_2D_000] = "64:1:1:1",
+    [MODEL_MOBILENET_V1] = "3:224:224:1",
+};
+
+static const gchar *output_dims[MODEL_END] = {
+    [MODEL_CONV_2D_000] = "64:1:1:1",
+    [MODEL_MOBILENET_V1] = "1000:1:1:1",
+};
+
+static int
+set_pipeline_state_sync (GstElement *pipeline, GstState state,
+                         uint32_t timeout_ms) {
+  GstState cur_state = GST_STATE_VOID_PENDING;
+  GstStateChangeReturn ret;
+  gint counter = 0;
+
+  ret = gst_element_set_state (pipeline, state);
+  if (ret == GST_STATE_CHANGE_FAILURE)
+    return -EPIPE;
+
+  do {
+    ret = gst_element_get_state (pipeline, &cur_state, NULL, 10 * GST_MSECOND);
+    if (ret == GST_STATE_CHANGE_FAILURE)
+      return -EPIPE;
+    if (cur_state == state)
+      return 0;
+    g_usleep (10000); /* 10 ms */
+  } while ((timeout_ms / 20) > counter++);
+
+  return -ETIME;
+}
+
+static gchar *
+make_pipeline_srnpu (srnpu_model model) {
+  if (model < 0 || model >= MODEL_END)
+    return nullptr;
+
+  const gchar *input_dim = input_dims[model];
+  const gchar *output_dim = output_dims[model];
+  gchar *model_path = g_strdup_printf ("%s/testdata/TRIV235_2TOPS/%s",
+                                       NE_DATADIR, model_names[model]);
+  gchar *pipeline = g_strdup_printf (
+      "filesrc location=%s/input_fmap_0.bin blocksize=-1 ! "
+      "application/octet-stream "
+      "! tensor_converter input-dim=%s input-type=uint8 "
+      "! tensor_filter framework=srnpu accelerator=true:npu.sr "
+      "model=%s/model.tvn "
+      "  input=%s inputtype=uint8 inputlayout=NHWC "
+      "  output=%s outputtype=uint8 outputlayout=NHWC "
+      "! fakesink",
+      model_path, input_dim, model_path, input_dim, output_dim);
+
+  g_free (model_path);
+  return pipeline;
+}
+
+TEST (nnstreamer_test, launch_conv_2d) {
+  gchar *pipeline;
+  GstElement *gstpipe;
+  GError *err = NULL;
+
+  pipeline = make_pipeline_srnpu (MODEL_CONV_2D_000);
+  gstpipe = gst_parse_launch (pipeline, &err);
+  EXPECT_NE (gstpipe, nullptr);
+
+  EXPECT_EQ (
+      set_pipeline_state_sync (gstpipe, GST_STATE_PLAYING, STATECHANGE_TIMEOUT),
+      0);
+  EXPECT_EQ (
+      set_pipeline_state_sync (gstpipe, GST_STATE_NULL, STATECHANGE_TIMEOUT),
+      0);
+
+  gst_object_unref (gstpipe);
+  g_free (pipeline);
+}
+
+TEST (nnstreamer_test, launch_mobilenet_v1) {
+  gchar *pipeline;
+  GstElement *gstpipe;
+  GError *err = NULL;
+
+  pipeline = make_pipeline_srnpu (MODEL_MOBILENET_V1);
+  gstpipe = gst_parse_launch (pipeline, &err);
+  EXPECT_NE (gstpipe, nullptr);
+
+  EXPECT_EQ (
+      set_pipeline_state_sync (gstpipe, GST_STATE_PLAYING, STATECHANGE_TIMEOUT),
+      0);
+  EXPECT_EQ (
+      set_pipeline_state_sync (gstpipe, GST_STATE_NULL, STATECHANGE_TIMEOUT),
+      0);
+
+  gst_object_unref (gstpipe);
+  g_free (pipeline);
+}
+
+/** @brief plugintest main */
+int
+main (int argc, char **argv) {
+  gst_init (&argc, &argv);
+  return start_gtest (argc, argv);
+}
diff --git a/tests/plugins/nnstreamer_test.cc b/tests/plugins/nnstreamer_test.cc
deleted file mode 100644 (file)
index dbc41a9..0000000
+++ /dev/null
@@ -1,134 +0,0 @@
-/**
- * Proprietary
- * Copyright (C) 2021 Samsung Electronics
- * Copyright (C) 2021 Dongju Chae <dongju.chae@samsung.com>
- */
-/**
- * @file nnstreamer_test.cc
- * @date 07 July 2021
- * @brief Test NNStreamer filter sub-plugin for TRIV2
- * @author Dongju Chae <dongju.chae@samsung.com>
- * @bug No known bugs except for NYI items
- */
-
-#include <ne_test_utils_gtest.h>
-
-#include <glib.h>
-#include <gst/gst.h>
-
-#define STATECHANGE_TIMEOUT 100000 /* 100s */
-
-typedef enum {
-  MODEL_CONV_2D_000 = 0,
-  MODEL_MOBILENET_V1,
-  MODEL_END
-} srnpu_model;
-
-static const gchar *model_names[MODEL_END] = {
-    [MODEL_CONV_2D_000] = "CONV_2D_000",
-    [MODEL_MOBILENET_V1] = "MOBILENET_V1",
-};
-
-static const gchar *input_dims[MODEL_END] = {
-    [MODEL_CONV_2D_000] = "64:1:1:1",
-    [MODEL_MOBILENET_V1] = "3:224:224:1",
-};
-
-static const gchar *output_dims[MODEL_END] = {
-    [MODEL_CONV_2D_000] = "64:1:1:1",
-    [MODEL_MOBILENET_V1] = "1000:1:1:1",
-};
-
-static int
-set_pipeline_state_sync (GstElement *pipeline, GstState state,
-                         uint32_t timeout_ms) {
-  GstState cur_state = GST_STATE_VOID_PENDING;
-  GstStateChangeReturn ret;
-  gint counter = 0;
-
-  ret = gst_element_set_state (pipeline, state);
-  if (ret == GST_STATE_CHANGE_FAILURE)
-    return -EPIPE;
-
-  do {
-    ret = gst_element_get_state (pipeline, &cur_state, NULL, 10 * GST_MSECOND);
-    if (ret == GST_STATE_CHANGE_FAILURE)
-      return -EPIPE;
-    if (cur_state == state)
-      return 0;
-    g_usleep (10000); /* 10 ms */
-  } while ((timeout_ms / 20) > counter++);
-
-  return -ETIME;
-}
-
-static gchar *
-make_pipeline_srnpu (srnpu_model model) {
-  if (model < 0 || model >= MODEL_END)
-    return nullptr;
-
-  const gchar *input_dim = input_dims[model];
-  const gchar *output_dim = output_dims[model];
-  gchar *model_path = g_strdup_printf ("%s/testdata/TRIV235_2TOPS/%s",
-                                       NE_DATADIR, model_names[model]);
-  gchar *pipeline = g_strdup_printf (
-      "filesrc location=%s/input_fmap_0.bin blocksize=-1 ! "
-      "application/octet-stream "
-      "! tensor_converter input-dim=%s input-type=uint8 "
-      "! tensor_filter framework=srnpu accelerator=true:npu.sr "
-      "model=%s/model.tvn "
-      "  input=%s inputtype=uint8 inputlayout=NHWC "
-      "  output=%s outputtype=uint8 outputlayout=NHWC "
-      "! fakesink",
-      model_path, input_dim, model_path, input_dim, output_dim);
-
-  g_free (model_path);
-  return pipeline;
-}
-
-TEST (nnstreamer_test, launch_conv_2d) {
-  gchar *pipeline;
-  GstElement *gstpipe;
-  GError *err = NULL;
-
-  pipeline = make_pipeline_srnpu (MODEL_CONV_2D_000);
-  gstpipe = gst_parse_launch (pipeline, &err);
-  EXPECT_NE (gstpipe, nullptr);
-
-  EXPECT_EQ (
-      set_pipeline_state_sync (gstpipe, GST_STATE_PLAYING, STATECHANGE_TIMEOUT),
-      0);
-  EXPECT_EQ (
-      set_pipeline_state_sync (gstpipe, GST_STATE_NULL, STATECHANGE_TIMEOUT),
-      0);
-
-  gst_object_unref (gstpipe);
-  g_free (pipeline);
-}
-
-TEST (nnstreamer_test, launch_mobilenet_v1) {
-  gchar *pipeline;
-  GstElement *gstpipe;
-  GError *err = NULL;
-
-  pipeline = make_pipeline_srnpu (MODEL_MOBILENET_V1);
-  gstpipe = gst_parse_launch (pipeline, &err);
-  EXPECT_NE (gstpipe, nullptr);
-
-  EXPECT_EQ (
-      set_pipeline_state_sync (gstpipe, GST_STATE_PLAYING, STATECHANGE_TIMEOUT),
-      0);
-  EXPECT_EQ (
-      set_pipeline_state_sync (gstpipe, GST_STATE_NULL, STATECHANGE_TIMEOUT),
-      0);
-
-  gst_object_unref (gstpipe);
-  g_free (pipeline);
-}
-
-/** @brief plugintest main */
-int
-main (int argc, char **argv) {
-  gst_init (&argc, &argv);
-  return start_gtest (argc, argv);
-}
diff --git a/tests/plugins/npumgr/meson.build b/tests/plugins/npumgr/meson.build
new file mode 100644 (file)
index 0000000..6b44d34
--- /dev/null
@@ -0,0 +1,13 @@
+testenv = environment()
+testenv.set('LD_LIBRARY_PATH', ne_libdir)
+
+# npu manager test program
+plugintest_npumgr = executable ('plugintest_npumgr',
+  ['npumgr_test.cc'],
+  include_directories : [npumgr_common_inc],
+  dependencies : [glib_dep, ne_test_utils_common_dep, npumgr_dep],
+  install : true,
+  install_rpath : ne_libdir,
+  install_dir : join_paths(ne_bindir, 'plugins', 'npumgr')
+)
+test('plugintest_npumgr', plugintest_npumgr, env: testenv)
diff --git a/tests/plugins/npumgr/npumgr_test.cc b/tests/plugins/npumgr/npumgr_test.cc
new file mode 100644 (file)
index 0000000..682abd6
--- /dev/null
@@ -0,0 +1,291 @@
+/**
+ * Proprietary
+ * Copyright (C) 2021 Samsung Electronics
+ * Copyright (C) 2021 Dongju Chae <dongju.chae@samsung.com>
+ */
+/**
+ * @file npumgr_test.cc
+ * @date 09 Apr 2021
+ * @brief AppTest to test the I/F of VD NPU Manager
+ * @author Dongju Chae <dongju.chae@samsung.com>
+ * @bug No known bugs except for NYI items
+ */
+
+#include <iostream>
+
+#include <fcntl.h>
+#include <unistd.h>
+
+#include <glib.h>
+#include <ne_test_utils_common.h>
+
+#include <npumgr_api.h>
+#include <npumgr_common.h>
+
+using namespace std;
+
+static int
+start_npumgr_test (int fd, const string &dir) {
+  npumgr_devices_id list;
+  npumgr_status_e status;
+
+  npumgr_context context;
+  npumgr_network network;
+
+  npumgr_buffer *input_bufs = NULL;
+  npumgr_buffer *output_bufs = NULL;
+  npumgr_query_inout_num inout_num = {0};
+
+  npumgr_network_defn input_files[] = {{NPUMGR_NETWORK_FILE_TVN, fd}};
+  const char *input_tensor_names[] = {"input"};
+  const char *output_tensor_names[] = {"output"};
+  npumgr_query_tensor_attr attr;
+
+  status = npumgr_device_get_available_list (&list);
+  if (status != NPUMGR_STATUS_SUCCESS) {
+    cerr << "Unable to get available device list, " << status << "\n";
+    return status;
+  }
+
+  /* TODO: find the first NPU device */
+  bool found = false;
+  uint32_t id;
+
+  for (int i = 0; i < list.n_devices; i++) {
+    if (list.types[i] == NPUMGR_DEVICE_TYPE_NPU) {
+      found = true;
+      id = list.id[i];
+      break;
+    }
+  }
+
+  if (!found) {
+    cerr << "No available device\n";
+    return NPUMGR_STATUS_ERR_DEVICE_UNAVAILABLE;
+  }
+
+  status = npumgr_context_create (id, NPUMGR_FLAG_PRIORITY_DEFAULT, &context);
+  if (status != NPUMGR_STATUS_SUCCESS) {
+    cerr << "Unable to create a npumgr context, " << status << "\n";
+    return NPUMGR_STATUS_ERR_FAIL;
+  }
+
+  status = npumgr_network_create (
+      context, 1, input_files, NPUMGR_BUF_TYPE_DRIVER, 1, input_tensor_names,
+      NPUMGR_BUF_TYPE_DRIVER, 1, output_tensor_names, &network);
+  if (status != NPUMGR_STATUS_SUCCESS) {
+    cerr << "Unable to create a npumgr network, " << status << "\n";
+    goto destroy_ctx;
+  }
+
+  status = npumgr_query_network (context, network, &inout_num);
+  if (status != NPUMGR_STATUS_SUCCESS) {
+    cerr << "Unable to query network info, " << status << "\n";
+    goto destroy_nw;
+  }
+
+  input_bufs = g_new0 (npumgr_buffer, inout_num.n_input);
+  output_bufs = g_new0 (npumgr_buffer, inout_num.n_output);
+
+  for (int i = 0; i < inout_num.n_input; i++) {
+    string file_path = dir + "/input_fmap_" + to_string (i) + ".bin";
+    FILE *f = fopen (file_path.c_str (), "rb");
+    void *data = NULL;
+
+    if (f == NULL) {
+      cerr << "Unable to find input file, " << file_path << "\n";
+      fclose (f);
+      goto destroy_all;
+    }
+
+    status = npumgr_query_input (context, network, i, &attr);
+    if (status != NPUMGR_STATUS_SUCCESS) {
+      cerr << "Unable to query input info, " << status << "\n";
+      fclose (f);
+      goto destroy_all;
+    }
+
+    /** TODO: currently, support NHWC format only */
+    if (attr.fmt != NPUMGR_TENSOR_FMT_NHWC) {
+      cerr << "Other format is not supported yet, " << attr.fmt << "\n";
+      fclose (f);
+      goto destroy_all;
+    }
+
+    status = npumgr_buffer_create (context, &attr, &input_bufs[i]);
+    if (status != NPUMGR_STATUS_SUCCESS) {
+      cerr << "Unable to create input buffer, " << status << "\n";
+      fclose (f);
+      goto destroy_all;
+    }
+
+    status = npumgr_buffer_map (context, &input_bufs[i], (uint8_t **) &data);
+    if (status != NPUMGR_STATUS_SUCCESS) {
+      cerr << "Unable to map input buffer, " << status << "\n";
+      fclose (f);
+      goto destroy_all;
+    }
+
+    size_t read_bytes = fread (data, 1, input_bufs[i].buf_size, f);
+    if (read_bytes != input_bufs[i].buf_size) {
+      cerr << "Unable to read input data, " << read_bytes << " vs. "
+           << input_bufs[i].buf_size << "\n";
+      fclose (f);
+      goto destroy_all;
+    }
+    fclose (f);
+
+    /** TODO: How unmap works? */
+#if 0
+    status = npumgr_buffer_unmap (context, &input_bufs[i]);
+    if (status != NPUMGR_STATUS_SUCCESS) {
+      cerr << "Unable to unmap buffer, " << status << "\n";
+      goto destroy_all;
+    }
+#else
+    munmap (data, ALIGNED_SIZE (input_bufs[i].buf_size));
+#endif
+
+    status = npumgr_network_set_input (context, network, i, &input_bufs[i]);
+    if (status != NPUMGR_STATUS_SUCCESS) {
+      cerr << "Unable to set input, " << status << "\n";
+      goto destroy_all;
+    }
+  }
+
+  for (int i = 0; i < inout_num.n_output; i++) {
+    status = npumgr_query_output (context, network, i, &attr);
+    if (status != NPUMGR_STATUS_SUCCESS) {
+      cerr << "Unable to query output info, " << status << "\n";
+      goto destroy_all;
+    }
+
+    /** TODO: currently, support NHWC format only */
+    if (attr.fmt != NPUMGR_TENSOR_FMT_NHWC) {
+      cerr << "Other format is not supported yet, " << attr.fmt << "\n";
+      goto destroy_all;
+    }
+
+    status = npumgr_buffer_create (context, &attr, &output_bufs[i]);
+    if (status != NPUMGR_STATUS_SUCCESS) {
+      cerr << "Unable to create output buffer, " << status << "\n";
+      goto destroy_all;
+    }
+
+    status = npumgr_network_set_output (context, network, i, &output_bufs[i]);
+    if (status != NPUMGR_STATUS_SUCCESS) {
+      cerr << "Unable to set output, " << status << "\n";
+      goto destroy_all;
+    }
+  }
+
+  status = npumgr_network_prepare (context, network);
+  if (status != NPUMGR_STATUS_SUCCESS) {
+    goto destroy_all;
+  }
+
+  status = npumgr_execute_run (context, network);
+  if (status != NPUMGR_STATUS_SUCCESS) {
+    cerr << "Unable to execute the network, " << status << "\n";
+    goto destroy_all;
+  }
+
+  for (int i = 0; i < inout_num.n_output; i++) {
+    string file_path = string (dir) + "/output_fmap_" + to_string (i) + ".bin";
+    void *data = NULL;
+
+    status = npumgr_buffer_map (context, &output_bufs[i], (uint8_t **) &data);
+    if (status != NPUMGR_STATUS_SUCCESS) {
+      cerr << "Unable to map output buffer, " << status << "\n";
+      goto destroy_all;
+    }
+
+    if (compare_data (file_path.c_str (), (const char *) data,
+                      output_bufs[i].buf_size) != 0) {
+      cerr << "Failed to get valid output data\n";
+      goto destroy_all;
+    }
+
+    /** TODO: How unmap works? */
+#if 0
+    status = npumgr_buffer_unmap (context, &output_bufs[i]);
+    if (status != NPUMGR_STATUS_SUCCESS) {
+      cerr << "Unable to unmap output buffer, " << status << "\n";
+      goto destroy_all;
+    }
+#else
+    munmap (data, ALIGNED_SIZE (output_bufs[i].buf_size));
+#endif
+  }
+
+destroy_all:
+  if (input_bufs) {
+    for (int i = 0; i < inout_num.n_input; i++) {
+      if (input_bufs[i].buf_handle == 0)
+        continue;
+
+      status = npumgr_buffer_destroy (context, &input_bufs[i]);
+      if (status != NPUMGR_STATUS_SUCCESS)
+        cerr << "Unable to destroy the buffer, " << status << "\n";
+    }
+  }
+
+  if (output_bufs) {
+    for (int i = 0; i < inout_num.n_output; i++) {
+      if (output_bufs[i].buf_handle == 0)
+        continue;
+
+      status = npumgr_buffer_destroy (context, &output_bufs[i]);
+      if (status != NPUMGR_STATUS_SUCCESS)
+        cerr << "Unable to destroy the buffer, " << status << "\n";
+    }
+  }
+
+destroy_nw:
+  status = npumgr_network_destroy (context, network);
+  if (status != NPUMGR_STATUS_SUCCESS)
+    cerr << "Unable to destroy the npumgr network, " << status << "\n";
+
+destroy_ctx:
+  status = npumgr_context_destroy (context);
+  if (status != NPUMGR_STATUS_SUCCESS)
+    cerr << "Unable to destroy the npumgr context, " << status << "\n";
+
+  return status;
+}
+
+int
+main (int argc, char **argv) {
+  int fd, ret = -EINVAL;
+
+  if (argc != 2) {
+    cerr << "Please provide model datapath (i.e., including .tvn and .bin)\n";
+    cerr << "[APPTEST] " << argv[0] << ": SKIPPED\n";
+    return 0;
+  }
+
+  string dir (argv[1]);
+  string model_path = dir + "/model.tvn";
+
+  if (!g_file_test (dir.c_str (), G_FILE_TEST_IS_DIR)) {
+    cerr << "Invalid model datapath: " << dir << "\n";
+    goto out;
+  }
+
+  fd = open (model_path.c_str (), O_RDONLY);
+  if (fd < 0) {
+    cerr << "Unable to open file " << dir << "\n";
+    goto out;
+  }
+
+  ret = start_npumgr_test (fd, dir);
+  close (fd);
+
+out:
+  if (ret == 0)
+    cerr << "[APPTEST] " << argv[0] << ": PASSED\n";
+  else
+    cerr << "[APPTEST] " << argv[0] << ": FAILED (" << ret << ")\n";
+
+  return ret;
+}