From: Junhwan Kim Date: Thu, 19 Aug 2021 08:45:10 +0000 (+0900) Subject: [Test] Unittest for filter shared key X-Git-Tag: accepted/tizen/unified/20221115.172908~18 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=fde742f7b5c89d4146e2334c8652ac0e5bc13ae6;p=platform%2Fupstream%2Fnnstreamer.git [Test] Unittest for filter shared key Unittest to validate filter with shared key Signed-off-by: Junhwan Kim --- diff --git a/tests/meson.build b/tests/meson.build index b93401b..1aec936 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -302,6 +302,17 @@ if gtest_dep.found() if nnstreamer_edge_support_is_available subdir('nnstreamer_edge') endif + + if tflite_support_is_available + unittest_filter_shared_model = executable('unittest_filter_shared_model', + join_paths('nnstreamer_filter_shared_model', 'unittest_filter_shared_model.cc'), + dependencies: [nnstreamer_unittest_deps, unittest_util_dep], + install: get_option('install-test'), + install_dir: unittest_install_dir + ) + + test('unittest_filter_shared_model', unittest_filter_shared_model, timeout: 30, env: testenv) + endif endif # gtest_dep.found() tensor_filter_ext_enabled = tflite_support_is_available or \ diff --git a/tests/nnstreamer_filter_shared_model/unittest_filter_shared_model.cc b/tests/nnstreamer_filter_shared_model/unittest_filter_shared_model.cc new file mode 100644 index 0000000..c8d60f0 --- /dev/null +++ b/tests/nnstreamer_filter_shared_model/unittest_filter_shared_model.cc @@ -0,0 +1,231 @@ +/** + * Copyright (C) 2021 Junhwan Kim + * + * @file unittest_filter_shared_model.cc + * @date 19 Aug 2021 + * @brief Unit test for nnstreamer filter shared model features. + * @author Junhwan Kim + * @see http://github.com/nnstreamer/nnstreamer + * @bug No known bugs + */ + +#include +#include +#include +#include +#include +#include + +static const gchar model_name1[] = "mobilenet_v1_1.0_224_quant.tflite"; +static const gchar model_name2[] = "mobilenet_v2_1.0_224_quant.tflite"; +static const gchar data_name[] = "orange.png"; +static const gchar shared_key[] = "mobilenet"; +static guint res[2]; + +/** + * @brief callback for tensor sink to get arg max + */ +static void +_new_data_cb (GstElement *element, GstBuffer *buffer, gpointer user_data) +{ + GstMemory *mem; + GstMapInfo info; + gsize i, max_i = 0; + guint8 max_val = 0; + gint idx = *(gint*)user_data; + UNUSED (element); + + mem = gst_buffer_get_memory (buffer, 0); + ASSERT_TRUE (gst_memory_map (mem, &info, GST_MAP_READ)); + + for (i = 0; i < info.size; ++i) { + if (info.data[i] > max_val) { + max_val = info.data[i]; + max_i = i; + } + } + res[idx] = (guint) max_i; + gst_memory_unmap (mem, &info); + gst_memory_unref (mem); +} + +/** + * @brief helper to get base pipeline string + */ +static void _get_pipeline_str (gchar **str, const gchar *model1, const gchar *model2) +{ + const gchar *src_root = g_getenv ("NNSTREAMER_SOURCE_ROOT_PATH"); + gchar *root_path = src_root ? g_strdup (src_root) : g_get_current_dir (); + gchar *model_path1 = g_build_filename ( + root_path, "tests", "test_models", "models", model1, NULL); + gchar *model_path2 = g_build_filename ( + root_path, "tests", "test_models", "models", model2, NULL); + gchar *image_path = g_build_filename ( + root_path, "tests", "test_models", "data", data_name, NULL); + + ASSERT_TRUE (g_file_test (model_path1, G_FILE_TEST_EXISTS)); + ASSERT_TRUE (g_file_test (model_path2, G_FILE_TEST_EXISTS)); + ASSERT_TRUE (g_file_test (image_path, G_FILE_TEST_EXISTS)); + + *str = g_strdup_printf ( + "filesrc location=%s ! pngdec ! videoscale ! imagefreeze ! videoconvert ! " + "video/x-raw,format=RGB,framerate=10/1 ! tensor_converter ! tee name=t t. ! " + "queue ! tensor_filter name=filter1 framework=tensorflow-lite model=%s is-updatable=TRUE " + "shared-tensor-filter-key=%s ! tensor_sink name=sink1 t. ! " + "queue ! tensor_filter name=filter2 framework=tensorflow-lite model=%s is-updatable=TRUE " + "shared-tensor-filter-key=%s ! tensor_sink name=sink2", + image_path, model_path1, shared_key, model_path2, shared_key); + g_free (root_path); + g_free (model_path1); + g_free (model_path2); + g_free (image_path); +} + +/** + * @brief Test filters share key but have different model paths. + */ +TEST (nnstreamerFilterSharedModel, tfliteSharedModelNotEqual_n) +{ + gchar *pipeline_str; + GstElement *pipeline; + _get_pipeline_str (&pipeline_str, model_name1, model_name2); + pipeline = gst_parse_launch (pipeline_str, NULL); + + EXPECT_EQ (setPipelineStateSync (pipeline, GST_STATE_PLAYING, UNITTEST_STATECHANGE_TIMEOUT), 0); + g_usleep (TEST_DEFAULT_SLEEP_TIME); + EXPECT_EQ (setPipelineStateSync (pipeline, GST_STATE_NULL, UNITTEST_STATECHANGE_TIMEOUT), 0); + + g_free (pipeline_str); + gst_object_unref (pipeline); +} + +/** + * @brief Test filter has invalid shape for shared model + */ +TEST (nnstreamerFilterSharedModel, tfliteInvalidShape_n) +{ + const gchar *src_root = g_getenv ("NNSTREAMER_SOURCE_ROOT_PATH"); + gchar *root_path = src_root ? g_strdup (src_root) : g_get_current_dir (); + gchar *model_path1 = g_build_filename ( + root_path, "tests", "test_models", "models", model_name1, NULL); + gchar *image_path = g_build_filename ( + root_path, "tests", "test_models", "data", data_name, NULL); + gchar *pipeline_str; + GstElement *pipeline; + ASSERT_TRUE (g_file_test (model_path1, G_FILE_TEST_EXISTS)); + ASSERT_TRUE (g_file_test (image_path, G_FILE_TEST_EXISTS)); + + pipeline_str = g_strdup_printf ( + "filesrc location=%s ! pngdec ! videoscale ! imagefreeze ! videoconvert ! video/x-raw,format=RGB,framerate=0/1 ! tee name=t t. ! " + "queue ! videoscale ! videoconvert ! video/x-raw ! " + "tensor_converter ! tensor_filter name=filter1 framework=tensorflow-lite model=%s is-updatable=TRUE " + "shared-tensor-filter-key=%s ! tensor_sink name=sink1 t. ! " + "queue ! videoscale ! videoconvert ! video/x-raw,width=30,height=30 ! " + "tensor_converter ! tensor_filter name=filter2 framework=tensorflow-lite model=%s is-updatable=TRUE " + "shared-tensor-filter-key=%s ! tensor_sink name=sink2", + image_path, model_path1, shared_key, model_path1, shared_key); + g_free (root_path); + g_free (model_path1); + g_free (image_path); + + pipeline = gst_parse_launch (pipeline_str, NULL); + + EXPECT_NE (setPipelineStateSync (pipeline, GST_STATE_PLAYING, UNITTEST_STATECHANGE_TIMEOUT), 0); + g_usleep (TEST_DEFAULT_SLEEP_TIME); + EXPECT_EQ (setPipelineStateSync (pipeline, GST_STATE_NULL, UNITTEST_STATECHANGE_TIMEOUT), 0); + + g_free (pipeline_str); + gst_object_unref (pipeline); +} + +/** + * @brief Test filters to reload new model + */ +TEST (nnstreamerFilterSharedModel, tfliteSharedReload) +{ + gchar *pipeline_str; + GstElement *pipeline, *filter1, *filter2, *sink1, *sink2; + gint idx0=0, idx1=1; + const gchar *src_root = g_getenv ("NNSTREAMER_SOURCE_ROOT_PATH"); + gchar *root_path = src_root ? g_strdup (src_root) : g_get_current_dir (); + gchar *new_model_path = g_build_filename ( + root_path, "tests", "test_models", "models", model_name2, NULL); + gchar *path; + g_free (root_path); + + _get_pipeline_str (&pipeline_str, model_name1, model_name1); + pipeline = gst_parse_launch (pipeline_str, NULL); + g_free (pipeline_str); + memset (res, 0, sizeof(res)); + + filter1 = gst_bin_get_by_name (GST_BIN (pipeline), "filter1"); + ASSERT_TRUE (filter1 != NULL); + filter2 = gst_bin_get_by_name (GST_BIN (pipeline), "filter2"); + ASSERT_TRUE (filter2 != NULL); + + sink1 = gst_bin_get_by_name (GST_BIN (pipeline), "sink1"); + EXPECT_NE (sink1, nullptr); + g_signal_connect (sink1, "new-data", (GCallback) _new_data_cb, (gpointer)&idx0); + sink2 = gst_bin_get_by_name (GST_BIN (pipeline), "sink2"); + EXPECT_NE (sink2, nullptr); + g_signal_connect (sink2, "new-data", (GCallback) _new_data_cb, (gpointer)&idx1); + + EXPECT_EQ (setPipelineStateSync (pipeline, GST_STATE_PLAYING, UNITTEST_STATECHANGE_TIMEOUT), 0); + g_usleep (TEST_DEFAULT_SLEEP_TIME); + EXPECT_EQ (setPipelineStateSync (pipeline, GST_STATE_PAUSED, UNITTEST_STATECHANGE_TIMEOUT), 0); + g_usleep (TEST_DEFAULT_SLEEP_TIME); + + /* check two filters have same output */ + EXPECT_NE (res[0], 0U); + EXPECT_EQ (res[0], res[1]); + memset (res, 0, sizeof(res)); + + /* reload filter */ + g_object_set (filter1, "model", new_model_path, NULL); + g_object_get (filter1, "model", &path, NULL); + EXPECT_STREQ (new_model_path, path); + g_free (new_model_path); + g_free (path); + + EXPECT_EQ (setPipelineStateSync (pipeline, GST_STATE_PLAYING, UNITTEST_STATECHANGE_TIMEOUT), 0); + g_usleep (TEST_DEFAULT_SLEEP_TIME); + EXPECT_EQ (setPipelineStateSync (pipeline, GST_STATE_PAUSED, UNITTEST_STATECHANGE_TIMEOUT), 0); + g_usleep (TEST_DEFAULT_SLEEP_TIME); + + /* same output with new model */ + EXPECT_NE (res[0], 0U); + EXPECT_EQ (res[0], res[1]); + + EXPECT_EQ (setPipelineStateSync (pipeline, GST_STATE_NULL, UNITTEST_STATECHANGE_TIMEOUT), 0); + + gst_object_unref (filter1); + gst_object_unref (filter2); + gst_object_unref (sink1); + gst_object_unref (sink2); + gst_object_unref (pipeline); +} + +/** + * @brief Main gtest + */ +int +main (int argc, char **argv) +{ + int result = -1; + + try { + testing::InitGoogleTest (&argc, argv); + } catch (...) { + g_warning ("catch 'testing::internal::::ClassUniqueToAlwaysTrue'"); + } + + gst_init (&argc, &argv); + + try { + result = RUN_ALL_TESTS (); + } catch (...) { + g_warning ("catch `testing::internal::GoogleTestFailureException`"); + } + + return result; +}