mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-22 08:17:01 +00:00
gst-stats: Add element latency support
This will output latency information when parsing a log file with gst-stats that has latency trace information. It will show the min, max and mean latency for the pipeline and all its elements. It will also show the reported latency for each element of the pipeline. Output example: Latency Statistics: pulsesrc0_src|fakesink0_sink: mean=190000043 min=190000043 max=190000043 Element Latency Statistics: flacparse0_src: mean=45561281 min=654988 max=90467575 flacenc0_src: mean=89938883 min=81913512 max=97964254 flacdec0_src: mean=45804881 min=228962 max=91380801 Element Reported Latency: pulsesrc0: min=10000000 max=200000000 ts=0:00:00.262846528 flacenc0: min=104489795 max=104489795 ts=0:00:00.262898616 flacparse0: min=0 max=0 ts=0:00:00.262927962
This commit is contained in:
parent
0f0403e5d9
commit
e615a3ddee
1 changed files with 212 additions and 0 deletions
|
@ -37,6 +37,9 @@ static GRegex *ansi_log = NULL;
|
||||||
static GHashTable *threads = NULL;
|
static GHashTable *threads = NULL;
|
||||||
static GPtrArray *elements = NULL;
|
static GPtrArray *elements = NULL;
|
||||||
static GPtrArray *pads = NULL;
|
static GPtrArray *pads = NULL;
|
||||||
|
static GHashTable *latencies = NULL;
|
||||||
|
static GHashTable *element_latencies = NULL;
|
||||||
|
static GQueue *element_reported_latencies = NULL;
|
||||||
static guint64 num_buffers = 0, num_events = 0, num_messages = 0, num_queries =
|
static guint64 num_buffers = 0, num_events = 0, num_messages = 0, num_queries =
|
||||||
0;
|
0;
|
||||||
static guint num_elements = 0, num_bins = 0, num_pads = 0, num_ghostpads = 0;
|
static guint num_elements = 0, num_bins = 0, num_pads = 0, num_ghostpads = 0;
|
||||||
|
@ -44,6 +47,34 @@ static GstClockTime last_ts = G_GUINT64_CONSTANT (0);
|
||||||
static guint total_cpuload = 0;
|
static guint total_cpuload = 0;
|
||||||
static gboolean have_cpuload = FALSE;
|
static gboolean have_cpuload = FALSE;
|
||||||
|
|
||||||
|
static gboolean have_latency = FALSE;
|
||||||
|
static gboolean have_element_latency = FALSE;
|
||||||
|
static gboolean have_element_reported_latency = FALSE;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
/* the number of latencies counted */
|
||||||
|
guint64 count;
|
||||||
|
/* the total of all latencies */
|
||||||
|
guint64 total;
|
||||||
|
/* the min of all latencies */
|
||||||
|
guint64 min;
|
||||||
|
/* the max of all latencies */
|
||||||
|
guint64 max;
|
||||||
|
} GstLatencyStats;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
/* The element name */
|
||||||
|
gchar *element;
|
||||||
|
/* The timestamp of the reported latency */
|
||||||
|
guint64 ts;
|
||||||
|
/* the min reported latency */
|
||||||
|
guint64 min;
|
||||||
|
/* the max reported latency */
|
||||||
|
guint64 max;
|
||||||
|
} GstReportedLatency;
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
/* human readable pad name and details */
|
/* human readable pad name and details */
|
||||||
|
@ -90,6 +121,38 @@ typedef struct
|
||||||
|
|
||||||
/* stats helper */
|
/* stats helper */
|
||||||
|
|
||||||
|
static void
|
||||||
|
latencies_foreach_print_stats (gchar * key, GstLatencyStats * ls, gpointer data)
|
||||||
|
{
|
||||||
|
printf ("\t%s: mean=%" G_GUINT64_FORMAT " min=%" G_GUINT64_FORMAT " max=%"
|
||||||
|
G_GUINT64_FORMAT "\n", key, ls->total / ls->count, ls->min, ls->max);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
reported_latencies_foreach_print_stats (GstReportedLatency * rl, gpointer data)
|
||||||
|
{
|
||||||
|
printf ("\t%s: min=%" G_GUINT64_FORMAT " max=%" G_GUINT64_FORMAT " ts=%"
|
||||||
|
GST_TIME_FORMAT "\n", rl->element, rl->min,
|
||||||
|
rl->max, GST_TIME_ARGS (rl->ts));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
free_latency_stats (gpointer data)
|
||||||
|
{
|
||||||
|
g_slice_free (GstLatencyStats, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
free_reported_latency (gpointer data)
|
||||||
|
{
|
||||||
|
GstReportedLatency *rl = data;
|
||||||
|
|
||||||
|
if (rl->element)
|
||||||
|
g_free (rl->element);
|
||||||
|
|
||||||
|
g_free (data);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
free_element_stats (gpointer data)
|
free_element_stats (gpointer data)
|
||||||
{
|
{
|
||||||
|
@ -410,6 +473,105 @@ do_proc_rusage_stats (GstStructure * s)
|
||||||
have_cpuload = TRUE;
|
have_cpuload = TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
update_latency_table (GHashTable * table, const gchar * key, guint64 time)
|
||||||
|
{
|
||||||
|
/* Find the values in the hash table */
|
||||||
|
GstLatencyStats *ls = g_hash_table_lookup (table, key);
|
||||||
|
if (!ls) {
|
||||||
|
/* Insert the new key if the value does not exist */
|
||||||
|
ls = g_new0 (GstLatencyStats, 1);
|
||||||
|
ls->count = 1;
|
||||||
|
ls->total = time;
|
||||||
|
ls->min = time;
|
||||||
|
ls->max = time;
|
||||||
|
g_hash_table_insert (table, g_strdup (key), ls);
|
||||||
|
} else {
|
||||||
|
/* Otherwise update the existing value */
|
||||||
|
ls->count++;
|
||||||
|
ls->total += time;
|
||||||
|
if (ls->min > time)
|
||||||
|
ls->min = time;
|
||||||
|
if (ls->max < time)
|
||||||
|
ls->max = time;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
do_latency_stats (GstStructure * s)
|
||||||
|
{
|
||||||
|
gchar *key = NULL;
|
||||||
|
const gchar *src = NULL, *sink = NULL;
|
||||||
|
guint64 ts = 0, time = 0;
|
||||||
|
|
||||||
|
/* Get the values from the structure */
|
||||||
|
src = gst_structure_get_string (s, "src");
|
||||||
|
sink = gst_structure_get_string (s, "sink");
|
||||||
|
gst_structure_get (s, "time", G_TYPE_UINT64, &time, NULL);
|
||||||
|
gst_structure_get (s, "ts", G_TYPE_UINT64, &ts, NULL);
|
||||||
|
|
||||||
|
/* Update last_ts */
|
||||||
|
last_ts = MAX (last_ts, ts);
|
||||||
|
|
||||||
|
/* Get the key */
|
||||||
|
key = g_strjoin ("|", src, sink, NULL);
|
||||||
|
|
||||||
|
/* Update the latency in the table */
|
||||||
|
update_latency_table (latencies, key, time);
|
||||||
|
|
||||||
|
/* Clean up */
|
||||||
|
g_free (key);
|
||||||
|
|
||||||
|
have_latency = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
do_element_latency_stats (GstStructure * s)
|
||||||
|
{
|
||||||
|
const gchar *src = NULL;
|
||||||
|
guint64 ts = 0, time = 0;
|
||||||
|
|
||||||
|
/* Get the values from the structure */
|
||||||
|
src = gst_structure_get_string (s, "src");
|
||||||
|
gst_structure_get (s, "time", G_TYPE_UINT64, &time, NULL);
|
||||||
|
gst_structure_get (s, "ts", G_TYPE_UINT64, &ts, NULL);
|
||||||
|
|
||||||
|
/* Update last_ts */
|
||||||
|
last_ts = MAX (last_ts, ts);
|
||||||
|
|
||||||
|
/* Update the latency in the table */
|
||||||
|
update_latency_table (element_latencies, src, time);
|
||||||
|
|
||||||
|
have_element_latency = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
do_element_reported_latency (GstStructure * s)
|
||||||
|
{
|
||||||
|
const gchar *element = NULL;
|
||||||
|
guint64 ts = 0, min = 0, max = 0;
|
||||||
|
GstReportedLatency *rl = NULL;
|
||||||
|
|
||||||
|
/* Get the values from the structure */
|
||||||
|
element = gst_structure_get_string (s, "element");
|
||||||
|
gst_structure_get (s, "min", G_TYPE_UINT64, &min, NULL);
|
||||||
|
gst_structure_get (s, "max", G_TYPE_UINT64, &max, NULL);
|
||||||
|
gst_structure_get (s, "ts", G_TYPE_UINT64, &ts, NULL);
|
||||||
|
|
||||||
|
/* Update last_ts */
|
||||||
|
last_ts = MAX (last_ts, ts);
|
||||||
|
|
||||||
|
/* Insert/Update the key in the table */
|
||||||
|
rl = g_new0 (GstReportedLatency, 1);
|
||||||
|
rl->element = g_strdup (element);
|
||||||
|
rl->ts = ts;
|
||||||
|
rl->min = min;
|
||||||
|
rl->max = max;
|
||||||
|
g_queue_push_tail (element_reported_latencies, rl);
|
||||||
|
|
||||||
|
have_element_reported_latency = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
/* reporting */
|
/* reporting */
|
||||||
|
|
||||||
static gint
|
static gint
|
||||||
|
@ -668,6 +830,11 @@ init (void)
|
||||||
elements = g_ptr_array_new_with_free_func (free_element_stats);
|
elements = g_ptr_array_new_with_free_func (free_element_stats);
|
||||||
pads = g_ptr_array_new_with_free_func (free_pad_stats);
|
pads = g_ptr_array_new_with_free_func (free_pad_stats);
|
||||||
threads = g_hash_table_new_full (NULL, NULL, NULL, free_thread_stats);
|
threads = g_hash_table_new_full (NULL, NULL, NULL, free_thread_stats);
|
||||||
|
latencies = g_hash_table_new_full (g_str_hash, g_str_equal, g_free,
|
||||||
|
free_latency_stats);
|
||||||
|
element_latencies = g_hash_table_new_full (g_str_hash, g_str_equal, g_free,
|
||||||
|
free_latency_stats);
|
||||||
|
element_reported_latencies = g_queue_new ();
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
@ -682,6 +849,21 @@ done (void)
|
||||||
if (threads)
|
if (threads)
|
||||||
g_hash_table_destroy (threads);
|
g_hash_table_destroy (threads);
|
||||||
|
|
||||||
|
if (latencies) {
|
||||||
|
g_hash_table_remove_all (latencies);
|
||||||
|
g_hash_table_destroy (latencies);
|
||||||
|
latencies = NULL;
|
||||||
|
}
|
||||||
|
if (element_latencies) {
|
||||||
|
g_hash_table_remove_all (element_latencies);
|
||||||
|
g_hash_table_destroy (element_latencies);
|
||||||
|
element_latencies = NULL;
|
||||||
|
}
|
||||||
|
if (element_reported_latencies) {
|
||||||
|
g_queue_free_full (element_reported_latencies, free_reported_latency);
|
||||||
|
element_reported_latencies = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
if (raw_log)
|
if (raw_log)
|
||||||
g_regex_unref (raw_log);
|
g_regex_unref (raw_log);
|
||||||
if (ansi_log)
|
if (ansi_log)
|
||||||
|
@ -758,6 +940,30 @@ print_stats (void)
|
||||||
puts ("");
|
puts ("");
|
||||||
g_slist_free (list);
|
g_slist_free (list);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* latency stats */
|
||||||
|
if (have_latency) {
|
||||||
|
puts ("Latency Statistics:");
|
||||||
|
g_hash_table_foreach (latencies, (GHFunc) latencies_foreach_print_stats,
|
||||||
|
NULL);
|
||||||
|
puts ("");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* element latency stats */
|
||||||
|
if (have_element_latency) {
|
||||||
|
puts ("Element Latency Statistics:");
|
||||||
|
g_hash_table_foreach (element_latencies,
|
||||||
|
(GHFunc) latencies_foreach_print_stats, NULL);
|
||||||
|
puts ("");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* element reported latency stats */
|
||||||
|
if (have_element_reported_latency) {
|
||||||
|
puts ("Element Reported Latency:");
|
||||||
|
g_queue_foreach (element_reported_latencies,
|
||||||
|
(GFunc) reported_latencies_foreach_print_stats, NULL);
|
||||||
|
puts ("");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -812,6 +1018,12 @@ collect_stats (const gchar * filename)
|
||||||
do_thread_rusage_stats (s);
|
do_thread_rusage_stats (s);
|
||||||
} else if (!strcmp (name, "proc-rusage")) {
|
} else if (!strcmp (name, "proc-rusage")) {
|
||||||
do_proc_rusage_stats (s);
|
do_proc_rusage_stats (s);
|
||||||
|
} else if (!strcmp (name, "latency")) {
|
||||||
|
do_latency_stats (s);
|
||||||
|
} else if (!strcmp (name, "element-latency")) {
|
||||||
|
do_element_latency_stats (s);
|
||||||
|
} else if (!strcmp (name, "element-reported-latency")) {
|
||||||
|
do_element_reported_latency (s);
|
||||||
} else {
|
} else {
|
||||||
// TODO(ensonic): parse the xxx.class log lines
|
// TODO(ensonic): parse the xxx.class log lines
|
||||||
if (!g_str_has_suffix (data, ".class")) {
|
if (!g_str_has_suffix (data, ".class")) {
|
||||||
|
|
Loading…
Reference in a new issue