[Tizen/nnfw] Add open/close callbacks for tensor_filter
authorMyungJoo Ham <myungjoo.ham@samsung.com>
Tue, 1 Oct 2019 10:36:47 +0000 (19:36 +0900)
committerMyungJoo Ham <myungjoo.ham@samsung.com>
Mon, 7 Oct 2019 07:55:29 +0000 (16:55 +0900)
This validates integration mechanisms for nnfw-runtime of Tizen.

Signed-off-by: MyungJoo Ham <myungjoo.ham@samsung.com>
ext/nnstreamer/tensor_filter/meson.build
ext/nnstreamer/tensor_filter/tensor_filter_nnfw.c
packaging/nnstreamer.spec
tests/meson.build
tests/tizen_nnfw_runtime/meson.build [new file with mode: 0644]
tests/tizen_nnfw_runtime/unittest_tizen_nnfw_runtime_raw.cpp [new file with mode: 0644]

index 74a71db..2af4ce0 100644 (file)
@@ -7,31 +7,28 @@ if get_option('enable-nnfw-runtime')
   endforeach
 
   nnfw_dep = dependency('nnfw', required: false)
-  add_args = ''
-  nnstreamer_filter_nnfw_deps = [glib_dep, gst_dep, nnstreamer_dep]
-
-  if nnfw_dep.found()
-    nnstreamer_filter_nnfw_deps += nnfw_dep
-  else
+  if not nnfw_dep.found()
     # Until nnfw supports pkg-config, we need to do this primitively.
-    add_args = '-lnnfw-dev'
+    nnfw_dep = cc.find_library('nnfw-dev')
   endif
+  nnstreamer_filter_nnfw_deps = [glib_dep, gst_dep, nnstreamer_dep, nnfw_dep]
 
 
-  shared_library('nnstreamer_filter_nnfw',
+  nnfw_plugin_lib = shared_library('nnstreamer_filter_nnfw',
     nnstreamer_filter_nnfw_sources,
     dependencies: nnstreamer_filter_nnfw_deps,
-    c_args : add_args,
     install: true,
     install_dir: filter_subplugin_install_dir
   )
   static_library('nnstreamer_filter_nnfw',
     nnstreamer_filter_nnfw_sources,
     dependencies: nnstreamer_filter_nnfw_deps,
-    c_args : add_args,
     install: false,
     install_dir: filter_subplugin_install_dir
   )
+
+  nnfw_plugin_dep = declare_dependency(link_with: nnfw_plugin_lib,
+    dependencies: nnstreamer_filter_nnfw_deps)
 endif
 
 if get_option('enable-tensorflow')
index 8ed2eb9..f641b9a 100644 (file)
  *
  * @todo Check if nnfw supports dynamic input dimension. (if so, we need to supply setInputDim)
  * @todo Decide whether to let nnfw allocate output buffers or we will feed output buffers to nnfw.
+ * @todo NYI: configuring backends
  *
  */
 
+#include <string.h>
 #include <glib.h>
 #include <tensor_common.h>
 #include <nnstreamer_plugin_api_filter.h>
 void init_filter_nnfw (void) __attribute__ ((constructor));
 void fini_filter_nnfw (void) __attribute__ ((destructor));
 
+typedef struct
+{
+  nnfw_tensorinfo i_in;
+  nnfw_tensorinfo i_out;
+  nnfw_session *session;
+  gchar *model_path;
+} nnfw_pdata;
+
+static void nnfw_close (const GstTensorFilterProperties * prop,
+    void **private_data);
+
 /**
  * @brief The standard tensor_filter callback
  */
-static int nnfw_open (const GstTensorFilterProperties * prop,
-    void **private_data)
+static int
+nnfw_open (const GstTensorFilterProperties * prop, void **private_data)
 {
+  NNFW_STATUS status;
+  int err = 0;
+  nnfw_pdata *pdata;
+
+  if (*private_data != NULL) {
+    pdata = *private_data;
+    if (strcmp (prop->model_file, pdata->model_path)) {
+      nnfw_close (prop, private_data);  /* "reopen" */
+    } else {
+      return 1;
+    }
+  }
+
+  pdata = g_new0 (nnfw_pdata, 1);
+  if (pdata == NULL)
+    return -ENOMEM;
+
+  *private_data = (void *) pdata;
+
+  status = nnfw_create_session (&pdata->session);
+  if (status != NNFW_STATUS_NO_ERROR) {
+    err = -EINVAL;
+    g_printerr ("Cannot create nnfw-runtime session");
+    goto unalloc_exit;
+  }
+
+  status = nnfw_load_model_from_file (pdata->session, prop->model_file);
+  if (status != NNFW_STATUS_NO_ERROR) {
+    err = -EINVAL;
+    g_printerr ("Cannot load the model file: %s", prop->model_file);
+    goto session_exit;
+  }
+
+  status = nnfw_prepare (pdata->session);
+  if (status != NNFW_STATUS_NO_ERROR) {
+    err = -EINVAL;
+    g_printerr ("nnfw-runtime cannot prepare the session for %s",
+        prop->model_file);
+    goto session_exit;
+  }
+
+  pdata->model_path = g_strdup (prop->model_file);
   return 0;
+
+session_exit:
+  status = nnfw_close_session(pdata->session);
+  if (status != NNFW_STATUS_NO_ERROR)
+    g_printerr ("Closing the session just opened by %s has failed", __func__);
+unalloc_exit:
+  g_free (pdata);
+  *private_data = NULL;
+  return err;
 }
 
 /**
  * @brief The standard tensor_filter callback
+ * @todo Determine if we need to do "assert" for close-failure.
  */
-static void nnfw_close (const GstTensorFilterProperties * prop,
-    void **private_data)
+static void
+nnfw_close (const GstTensorFilterProperties * prop, void **private_data)
 {
+  nnfw_pdata *pdata;
+  pdata = *private_data;
+
+  if (pdata && pdata->session) {
+    NNFW_STATUS status = nnfw_close_session (pdata->session);
+
+    if (status != NNFW_STATUS_NO_ERROR) {
+      g_printerr ("cannot close nnfw-runtime session for %s",
+          pdata->model_path);
+    }
+  } else {
+    g_printerr ("nnfw_close called without proper nnfw_open");
+    if (pdata == NULL)
+      return;
+  }
+  pdata->session = NULL;
+
+  g_free (pdata->model_path);
+  pdata->model_path = NULL;
+
+  g_free (pdata);
+  *private_data = NULL;
 }
 
 /**
  * @brief The standard tensor_filter callback
  */
-static int nnfw_getInputDim (const GstTensorFilterProperties * prop,
-      void **private_data, GstTensorsInfo * info)
+static int
+nnfw_getInputDim (const GstTensorFilterProperties * prop,
+    void **private_data, GstTensorsInfo * info)
 {
   return 0;
 }
@@ -66,8 +154,9 @@ static int nnfw_getInputDim (const GstTensorFilterProperties * prop,
 /**
  * @brief The standard tensor_filter callback
  */
-static int nnfw_getOutputDim (const GstTensorFilterProperties * prop,
-      void **private_data, GstTensorsInfo * info)
+static int
+nnfw_getOutputDim (const GstTensorFilterProperties * prop,
+    void **private_data, GstTensorsInfo * info)
 {
   return 0;
 }
@@ -75,7 +164,8 @@ static int nnfw_getOutputDim (const GstTensorFilterProperties * prop,
 /**
  * @brief The standard tensor_filter callback
  */
-static int nnfw_invoke (const GstTensorFilterProperties * prop,
+static int
+nnfw_invoke (const GstTensorFilterProperties * prop,
     void **private_data, const GstTensorMemory * input,
     GstTensorMemory * output)
 {
index 58b64c1..e48ca28 100644 (file)
@@ -251,6 +251,9 @@ ninja -C build %{?_smp_mflags}
     ./tests/unittest_src_iio --gst-plugin-path=. --gtest_output="xml:unittest_src_iio.xml"
     ./tests/tizen_capi/unittest_tizen_capi --gst-plugin-path=. --gtest_output="xml:unittest_tizen_capi.xml"
     ./tests/tizen_capi/unittest_tizen_capi_single_new --gst-plugin-path=. --gtest_output="xml:unittest_tizen_capi_single_new.xml"
+%if 0%{?enable_nnfw_r}
+    ./tests/tizen_nnfw_runtime/unittest_nnfw_runtime_raw --gst-plugin-path=. --gtest_output="xml:unittest_nnfw_runtime_raw.xml"
+%endif
     popd
     pushd tests
     ssat -n
index ea7bddf..f3ee9bc 100644 (file)
@@ -101,6 +101,10 @@ if get_option('enable-capi')
   subdir('tizen_capi')
 endif
 
+if get_option('enable-nnfw-runtime')
+  subdir('tizen_nnfw_runtime')
+endif
+
 # Install Unittest
 if get_option('install-test')
   install_data('gen24bBMP.py', install_dir: join_paths(unittest_install_dir,'tests'))
diff --git a/tests/tizen_nnfw_runtime/meson.build b/tests/tizen_nnfw_runtime/meson.build
new file mode 100644 (file)
index 0000000..8c83783
--- /dev/null
@@ -0,0 +1,8 @@
+unittest_nnfw_runtime_raw = executable('unittest_nnfw_runtime_raw',
+  'unittest_tizen_nnfw_runtime_raw.cpp',
+  dependencies: [glib_dep, gst_dep, nnstreamer_dep, gtest_dep, nnfw_plugin_dep],
+  install: get_option('install-test'),
+  install_dir: unittest_install_dir,
+)
+
+test('unittest_nnfw_runtime_raw', unittest_nnfw_runtime_raw, args: ['--gst-plugin-path=../..'])
diff --git a/tests/tizen_nnfw_runtime/unittest_tizen_nnfw_runtime_raw.cpp b/tests/tizen_nnfw_runtime/unittest_tizen_nnfw_runtime_raw.cpp
new file mode 100644 (file)
index 0000000..2689fd8
--- /dev/null
@@ -0,0 +1,57 @@
+/**
+ * @file        unittest_tizen_capi.cpp
+ * @date        13 Mar 2019
+ * @brief       Unit test for Tizen CAPI of NNStreamer. Basis of TCT in the future.
+ * @see         https://github.com/nnsuite/nnstreamer
+ * @author      MyungJoo Ham <myungjoo.ham@samsung.com>
+ * @bug         No known bugs
+ */
+
+#include <gtest/gtest.h>
+#include <glib.h>
+#include <glib/gstdio.h>        /* GStatBuf */
+#include <nnstreamer_plugin_api_filter.h>
+
+/**
+ * @brief Test nnfw subplugin existence.
+ */
+TEST (nnstreamer_nnfw_runtime_raw_functions, check_existence)
+{
+  const GstTensorFilterFramework *sp = nnstreamer_filter_find ("nnfw");
+  EXPECT_NE (sp, (void *) NULL);
+}
+
+/**
+ * @brief Test nnfw subplugin with failing open/flose (no model file)
+ */
+TEST (nnstreamer_nnfw_runtime_raw_functions, open_close_00_n)
+{
+  int ret;
+  GstTensorFilterProperties prop = {
+    .fwname = "nnfw",
+    .fw_opened = 0,
+    .model_file = "null.nnfw",
+  };
+  void *data;
+
+  const GstTensorFilterFramework *sp = nnstreamer_filter_find ("nnfw");
+  EXPECT_NE (sp, (void *) NULL);
+
+  ret = sp->open (&prop, &data);
+  EXPECT_NE (ret, 0);
+}
+
+/**
+ * @brief Main gtest
+ */
+int
+main (int argc, char **argv)
+{
+  int result;
+
+  testing::InitGoogleTest (&argc, argv);
+
+  result = RUN_ALL_TESTS ();
+
+  return result;
+}