From 2c5a2a47290b3c827bd7a5b7a339e4cd33e099bc Mon Sep 17 00:00:00 2001 From: "jijoong.moon" Date: Wed, 21 Nov 2018 10:46:32 +0900 Subject: [PATCH] [Repo/Push] Use Has Table to handle repo & add slot_id property - Instead of single linked list, Hash table is used to manage repo's data. Hash Table is "key [slot_id], GstTensorData*" where slot_id is given by user when the tensor_repopush is used. - Slot Id is added to use as key for hash table. This should be same with tensor_repopop element. "tensor_repopop" will withdraw the data according to this slot_id. **Self evaluation:** 1. Build test: [X]Passed [ ]Failed [ ]Skipped 2. Run test: [X]Passed [ ]Failed [ ]Skipped Signed-off-by: jijoong.moon --- gst/nnstreamer/tensor_repo.c | 61 +++++++++++++++++------- gst/nnstreamer/tensor_repo.h | 35 ++++++++------ gst/tensor_repopush/tensor_repopush.c | 87 +++++++++++------------------------ gst/tensor_repopush/tensor_repopush.h | 1 + 4 files changed, 95 insertions(+), 89 deletions(-) diff --git a/gst/nnstreamer/tensor_repo.c b/gst/nnstreamer/tensor_repo.c index 6e44032..c2e8c51 100644 --- a/gst/nnstreamer/tensor_repo.c +++ b/gst/nnstreamer/tensor_repo.c @@ -1,5 +1,5 @@ /** - * NNStreamer Common Header + * NNStreamer Tensor Repo Header's Contents * Copyright (C) 2018 Jijoong Moon * * This library is free software; you can redistribute it and/or @@ -16,7 +16,7 @@ /** * @file tensor_repo.c * @date 17 Nov 2018 - * @brief tensor repo header file for NNStreamer, the GStreamer plugin for neural networks + * @brief tensor repo file for NNStreamer, the GStreamer plugin for neural networks * @see https://github.com/nnsuite/nnstreamer * @author Jijoong Moon * @bug No known bugs except for NYI items @@ -24,11 +24,18 @@ */ #include +#include + +#ifndef DBG +#define DBG TRUE +#endif + +#define _print_log(...) if (DBG) g_message(__VA_ARGS__) /** * @brief tensor repo global variable with init. */ -GstTensorRepo _repo = {.num_data = 0,.tensorsdata = NULL,.initialized = FALSE }; +GstTensorRepo _repo = {.num_data = 0,.initialized = FALSE }; /** * @brief getter to get nth GstTensorData @@ -36,35 +43,50 @@ GstTensorRepo _repo = {.num_data = 0,.tensorsdata = NULL,.initialized = FALSE }; GstTensorData * gst_tensor_repo_get_tensor (guint nth) { - return g_slist_nth_data (_repo.tensorsdata, nth); + GstTensorData *data; + gpointer *p = g_hash_table_lookup (_repo.hash, GINT_TO_POINTER (nth)); + data = (GstTensorData *) p; + g_return_val_if_fail (data != NULL, NULL); + return data; } /** * @brief add GstTensorData into repo */ -guint -gst_tensor_repo_add_data (GstTensorData * data) +gboolean +gst_tensor_repo_add_data (GstTensorData * data, guint myid) { - guint id = _repo.num_data; + gboolean ret = FALSE; + + if (!_repo.initialized) + gst_tensor_repo_init (); + GST_REPO_LOCK (); - _repo.tensorsdata = g_slist_append (_repo.tensorsdata, data); + ret = g_hash_table_insert (_repo.hash, GINT_TO_POINTER (myid), data); + g_assert (ret); + + _print_log ("Successfully added in hash table with key[%d]", myid); + _repo.num_data++; GST_REPO_UNLOCK (); - return id; + return ret; } /** * @brief push GstBuffer into repo */ -void +gboolean gst_tensor_repo_push_buffer (guint nth, GstBuffer * buffer) { GST_TENSOR_REPO_LOCK (nth); GstTensorData *data = gst_tensor_repo_get_tensor (nth); + g_return_val_if_fail (data != NULL, FALSE); + data->buffer = buffer; GST_TENSOR_REPO_BROADCAST (nth); GST_TENSOR_REPO_UNLOCK (nth); + return TRUE; } /** @@ -76,7 +98,7 @@ gst_tensor_repopop_buffer (guint nth) GST_TENSOR_REPO_LOCK (nth); GstTensorData *current_data, *data; - current_data = g_slist_nth_data (_repo.tensorsdata, nth); + current_data = gst_tensor_repo_get_tensor (nth); while (!current_data) GST_TENSOR_REPO_WAIT (nth); @@ -90,16 +112,23 @@ gst_tensor_repopop_buffer (guint nth) /** * @brief remove nth GstTensorData from GstTensorRepo */ -void +gboolean gst_tensor_repo_remove_data (guint nth) { + gboolean ret; GST_REPO_LOCK (); - GSList *data = g_slist_nth (_repo.tensorsdata, nth); g_mutex_clear (GST_TENSOR_REPO_GET_LOCK (nth)); g_cond_clear (GST_TENSOR_REPO_GET_COND (nth)); - _repo.tensorsdata = g_slist_delete_link (_repo.tensorsdata, data); - _repo.num_data--; + + ret = g_hash_table_remove (_repo.hash, GINT_TO_POINTER (nth)); + + if (ret) { + _repo.num_data--; + _print_log ("key[%d] is removed\n", nth); + } + GST_REPO_UNLOCK (); + return ret; } /** @@ -110,6 +139,6 @@ gst_tensor_repo_init () { _repo.num_data = 0; g_mutex_init (&_repo.repo_lock); - _repo.tensorsdata = NULL; + _repo.hash = g_hash_table_new (g_direct_hash, g_direct_equal); _repo.initialized = TRUE; } diff --git a/gst/nnstreamer/tensor_repo.h b/gst/nnstreamer/tensor_repo.h index 1474965..2468e4d 100644 --- a/gst/nnstreamer/tensor_repo.h +++ b/gst/nnstreamer/tensor_repo.h @@ -1,5 +1,5 @@ /** - * NNStreamer Common Header + * NNStreamer Tensor Repo Header * Copyright (C) 2018 Jijoong Moon * * This library is free software; you can redistribute it and/or @@ -39,6 +39,7 @@ G_BEGIN_DECLS * GstTensorRepo has GSlist of GstTensorData. * */ + typedef struct { GstTensorConfig *config; @@ -50,15 +51,13 @@ typedef struct /** * @brief GstTensorRepo data structure. */ -struct GstTensorRepo_s +typedef struct { gint num_data; GMutex repo_lock; - GSList *tensorsdata; + GHashTable* hash; gboolean initialized; -}; - -typedef struct GstTensorRepo_s GstTensorRepo; +} GstTensorRepo; /** * @brief getter to get nth GstTensorData @@ -66,26 +65,36 @@ typedef struct GstTensorRepo_s GstTensorRepo; GstTensorData * gst_tensor_repo_get_tensor (guint nth); -guint -gst_tensor_repo_add_data(GstTensorData *data); +/** + * @brief add GstTensorData into repo + */ +/* guint */ +gboolean +gst_tensor_repo_add_data (GstTensorData * data, guint myid); -void -gst_tensor_repo_push_buffer(guint nth, GstBuffer *buffer); +/** + * @brief push GstBuffer into repo + */ +gboolean +gst_tensor_repo_push_buffer (guint nth, GstBuffer * buffer); +/** + * @brief pop GstTensorData from repo + */ GstTensorData * -gst_tensor_repopop_buffer(guint nth); +gst_tensor_repopop_buffer (guint nth); /** * @brief remove nth GstTensorData from GstTensorRepo */ -void +gboolean gst_tensor_repo_remove_data (guint nth); /** * @brief GstTensorRepo initialization */ void -gst_tensor_repo_init(); +gst_tensor_repo_init (); /** diff --git a/gst/tensor_repopush/tensor_repopush.c b/gst/tensor_repopush/tensor_repopush.c index 6dd34dc..cde3af7 100644 --- a/gst/tensor_repopush/tensor_repopush.c +++ b/gst/tensor_repopush/tensor_repopush.c @@ -35,22 +35,10 @@ #include "tensor_repopush.h" /** - * @brief Macro for debug mode. - */ -#ifndef DBG -#define DBG (!self->silent) -#endif - -/** * @brief tensor repository */ extern GstTensorRepo _repo; -/** - * @brief Macro for debug message. - */ -#define silent_debug(...) \ - debug_print (DBG, __VA_ARGS__) GST_DEBUG_CATEGORY_STATIC (gst_tensor_repopush_debug); #define GST_CAT_DEFAULT gst_tensor_repopush_debug @@ -62,12 +50,14 @@ enum { PROP_0, PROP_SIGNAL_RATE, + PROP_SLOT, PROP_SILENT }; #define DEFAULT_SIGNAL_RATE 0 #define DEFAULT_SILENT TRUE #define DEFAULT_QOS TRUE +#define DEFAULT_INDEX 0 /** * @brief tensor_repopush sink template @@ -122,6 +112,11 @@ gst_tensor_repopush_class_init (GstTensorRepoPushClass * klass) "New data signals per second (0 for unlimited, max 500)", 0, 500, DEFAULT_SIGNAL_RATE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_SLOT, + g_param_spec_uint ("slot-index", "Slot Index", "repository slot index", + 0, UINT_MAX, DEFAULT_INDEX, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_SILENT, g_param_spec_boolean ("silent", "Silent", "Produce verbose output", DEFAULT_SILENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); @@ -150,19 +145,19 @@ gst_tensor_repopush_class_init (GstTensorRepoPushClass * klass) static void gst_tensor_repopush_init (GstTensorRepoPush * self) { + gboolean ret = FALSE; GstBaseSink *basesink; basesink = GST_BASE_SINK (self); - if (!_repo.initialized) - gst_tensor_repo_init (); - self->data.config = NULL; self->data.buffer = NULL; g_mutex_init (&self->data.lock); g_cond_init (&self->data.cond); - self->myid = gst_tensor_repo_add_data (&self->data); + ret = gst_tensor_repo_add_data (&self->data, self->myid); + g_assert (ret); + self->silent = DEFAULT_SILENT; self->signal_rate = DEFAULT_SIGNAL_RATE; @@ -189,6 +184,9 @@ gst_tensor_repopush_set_property (GObject * object, guint prop_id, case PROP_SILENT: self->silent = g_value_get_boolean (value); break; + case PROP_SLOT: + self->myid = g_value_get_uint (value); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -211,6 +209,9 @@ gst_tensor_repopush_get_property (GObject * object, guint prop_id, case PROP_SILENT: g_value_set_boolean (value, self->silent); break; + case PROP_SLOT: + g_value_set_uint (value, self->myid); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -223,9 +224,13 @@ gst_tensor_repopush_get_property (GObject * object, guint prop_id, static void gst_tensor_repopush_dispose (GObject * object) { + gboolean ret; GstTensorRepoPush *self; self = GST_TENSOR_REPOPUSH (object); - gst_tensor_repo_remove_data (self->myid); + ret = gst_tensor_repo_remove_data (self->myid); + if (!ret) + GST_ELEMENT_ERROR (self, RESOURCE, WRITE, + ("Cannot remove [key: %d] in repo", self->myid), NULL); } /** @@ -252,14 +257,11 @@ gst_tensor_repopush_stop (GstBaseSink * sink) static gboolean gst_tensor_repopush_query (GstBaseSink * sink, GstQuery * query) { - GstTensorRepoPush *self; GstQueryType type; GstFormat format; - self = GST_TENSOR_REPOPUSH (sink); type = GST_QUERY_TYPE (query); - silent_debug ("received query %s", GST_QUERY_TYPE_NAME (query)); switch (type) { case GST_QUERY_SEEKING: /** tensor sink does not support seeking */ @@ -306,8 +308,12 @@ gst_tensor_repopush_render_buffer (GstTensorRepoPush * self, GstBuffer * buffer) } if (notify) { + gboolean ret = FALSE; self->last_render_time = now; - gst_tensor_repo_push_buffer (self->myid, buffer); + ret = gst_tensor_repo_push_buffer (self->myid, buffer); + if (!ret) + GST_ELEMENT_ERROR (self, RESOURCE, WRITE, + ("Cannot push buffer into repo [key: %d]", self->myid), NULL); } } @@ -361,21 +367,6 @@ gst_tensor_repopush_set_caps (GstBaseSink * sink, GstCaps * caps) gst_caps_replace (&self->in_caps, caps); GST_TENSOR_REPO_UNLOCK (self->myid); - if (DBG) { - guint caps_size, i; - - caps_size = gst_caps_get_size (caps); - silent_debug ("set caps, size is %d", caps_size); - - for (i = 0; i < caps_size; i++) { - GstStructure *structure = gst_caps_get_structure (caps, i); - gchar *str = gst_structure_to_string (structure); - - silent_debug ("[%d] %s", i, str); - g_free (str); - } - } - return TRUE; } @@ -419,27 +410,3 @@ NNSTREAMER_PLUGIN_INIT (tensor_repopush) return gst_element_register (plugin, "tensor_repopush", GST_RANK_NONE, GST_TYPE_TENSOR_REPOPUSH); } - -#ifndef SINGLE_BINARY -/** - * @brief Definition for identifying tensor_sink plugin. - * - * PACKAGE: this is usually set by autotools depending on some _INIT macro - * in configure.ac and then written into and defined in config.h, but we can - * just set it ourselves here in case someone doesn't use autotools to - * compile this code. GST_PLUGIN_DEFINE needs PACKAGE to be defined. - */ -#ifndef PACKAGE -#define PACKAGE "nnstreamer" -#endif - -/** - * @brief Macro to define the entry point of the plugin. - */ -GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, - GST_VERSION_MINOR, - tensor_repopush, - "Push element to handle tensor repository", - gst_tensor_repopush_plugin_init, VERSION, "LGPL", "nnstreamer", - "https://github.com/nnsuite/nnstreamer"); -#endif diff --git a/gst/tensor_repopush/tensor_repopush.h b/gst/tensor_repopush/tensor_repopush.h index 31840a3..b688220 100644 --- a/gst/tensor_repopush/tensor_repopush.h +++ b/gst/tensor_repopush/tensor_repopush.h @@ -61,6 +61,7 @@ struct _GstTensorRepoPush GstCaps *in_caps; GstTensorData data; guint myid; + guint slot_index; }; -- 2.7.4