validate: allow config to check for minimum buffer frequency on pads

This change allow tests to check performance of elements by checking the
frequency at which buffers are pushed on src pads.
I re-used most of the logic from fpsdisplaysink to compute the
frequency.

We can now uses something like:
  GST_VALIDATE_CONFIG='core,min-buffer-frequency=60,target-element-factory-name=v4l2src'

The 'buffer-frequency-start' optional field can be used to ignore the
frequency during the start of the pipeline. This is useful when testing live
pipelines where configuring and setting up elements can take some time slowing
down the first buffers.
This commit is contained in:
Guillaume Desmottes 2019-02-07 15:36:41 +01:00
parent 40f263e857
commit b20f73099f
5 changed files with 169 additions and 0 deletions

View file

@ -116,6 +116,44 @@
Note that you will still need to set <envar>GST_DEBUG_DUMP_DOT_DIR</envar>.
</informalexample>
<informalexample>
You can also check that a src pad is pushing buffers at a
minimum frequency. For example to check if <literal>v4l2src</literal> is
producing at least 60 frames per second you can do:
<programlisting>
core,min-buffer-frequency=60,target-element-factory-name=v4l2src
</programlisting>
This config accepts the following fields:
<itemizedlist>
<listitem>
<para><literal>min-buffer-frequency</literal>: the expected minimum
rate, in buffers per second, at which buffers are pushed on the pad
</para>
</listitem>
<listitem>
<para><literal>target-element-{factory-name,name,klass}</literal>:
the factory-name, object name or class of the element to check
</para>
</listitem>
<listitem>
<para><literal>name</literal>: (optional) only check the frequency if
the src pad has this name
</para>
</listitem>
<listitem>
<para><literal>buffer-frequency-start</literal>: (optional) if defined,
validate will ignore the frequency of the pad during the time specified
in this field, in ns.
This can be useful when testing live pipelines where
configuring and setting up elements can take some time slowing
down the first buffers until the pipeline reaches its cruising
speed.
</para>
</listitem>
</itemizedlist>
</informalexample>
<para>
For more examples you can look at the ssim GstValidate plugin documentation to
see how to configure that plugin.

View file

@ -30,6 +30,8 @@
#include "gst-validate-element-monitor.h"
#include "gst-validate-pipeline-monitor.h"
#include "gst-validate-reporter.h"
#include "gst-validate-utils.h"
#include "validate.h"
#include <string.h>
#include <stdarg.h>
@ -970,6 +972,13 @@ gst_validate_pad_monitor_reset (GstValidatePadMonitor * pad_monitor)
/* FIXME : Why BYTES and not UNDEFINED ? */
gst_segment_init (&pad_monitor->segment, GST_FORMAT_BYTES);
pad_monitor->min_buf_freq = 0;
pad_monitor->buffers_pushed = 0;
pad_monitor->last_buffers_pushed = 0;
pad_monitor->min_buf_freq_interval_ts = GST_CLOCK_TIME_NONE;
pad_monitor->min_buf_freq_first_buffer_ts = GST_CLOCK_TIME_NONE;
pad_monitor->min_buf_freq_start = GST_CLOCK_TIME_NONE;
}
static void
@ -2440,6 +2449,62 @@ gst_validate_pad_monitor_activatemode_func (GstPad * pad, GstObject * parent,
return ret;
}
/* The interval between two buffer frequency checks */
#define BUF_FREQ_CHECK_INTERVAL (GST_SECOND)
static void
gst_validate_pad_monitor_check_buffer_freq (GstValidatePadMonitor * monitor,
GstPad * pad)
{
GstClockTime ts;
if (!GST_PAD_IS_SRC (pad))
return;
if (!monitor->min_buf_freq)
return;
ts = gst_util_get_timestamp ();
monitor->buffers_pushed++;
/* Same logic as in fpsdisplaysink to compute the buffer frequency */
if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID
(monitor->min_buf_freq_first_buffer_ts))) {
monitor->min_buf_freq_first_buffer_ts = ts;
monitor->min_buf_freq_interval_ts = ts;
return;
}
if (GST_CLOCK_DIFF (monitor->min_buf_freq_interval_ts,
ts) > BUF_FREQ_CHECK_INTERVAL) {
guint time_diff;
gdouble fps;
time_diff = (gdouble) (ts - monitor->min_buf_freq_interval_ts) / GST_SECOND;
fps =
(gdouble) (monitor->buffers_pushed -
monitor->last_buffers_pushed) / time_diff;
if (fps < monitor->min_buf_freq) {
if (GST_CLOCK_TIME_IS_VALID (monitor->min_buf_freq_start) &&
GST_CLOCK_DIFF (monitor->min_buf_freq_first_buffer_ts,
ts) < monitor->min_buf_freq_start) {
GST_DEBUG_OBJECT (pad,
"buffer frequency is too low (%.2f) but ignore for now (buffer-frequency-start =%"
GST_TIME_FORMAT ")", fps,
GST_TIME_ARGS (monitor->min_buf_freq_start));
} else {
GST_VALIDATE_REPORT (monitor, CONFIG_BUFFER_FREQUENCY_TOO_LOW,
"Buffers are not pushed fast enough on this pad: %.2f/sec (minimum: %.2f)",
fps, monitor->min_buf_freq);
}
}
monitor->last_buffers_pushed = monitor->buffers_pushed;
monitor->min_buf_freq_interval_ts = ts;
}
}
static gboolean
gst_validate_pad_monitor_buffer_probe (GstPad * pad, GstBuffer * buffer,
gpointer udata, gboolean pull_mode)
@ -2496,6 +2561,8 @@ gst_validate_pad_monitor_buffer_probe (GstPad * pad, GstBuffer * buffer,
}
}
gst_validate_pad_monitor_check_buffer_freq (monitor, pad);
GST_VALIDATE_MONITOR_UNLOCK (monitor);
GST_VALIDATE_PAD_MONITOR_PARENT_UNLOCK (monitor);
gst_validate_pad_monitor_buffer_probe_overrides (monitor, buffer);
@ -2748,6 +2815,55 @@ gst_validate_pad_monitor_setcaps_post (GstValidatePadMonitor * pad_monitor,
}
}
static void
gst_validate_pad_monitor_get_min_buffer_frequency (GstValidatePadMonitor *
monitor, GstPad * pad)
{
GList *config, *l;
if (!GST_PAD_IS_SRC (pad))
return;
config = gst_validate_plugin_get_config (NULL);
for (l = config; l != NULL; l = g_list_next (l)) {
GstStructure *s = l->data;
gdouble min_buf_freq;
const gchar *pad_name;
GstElement *element = NULL;
if (!gst_structure_get_double (s, "min-buffer-frequency", &min_buf_freq)) {
gint max_int;
if (!gst_structure_get_int (s, "min-buffer-frequency", &max_int))
goto next;
min_buf_freq = max_int;
}
pad_name = gst_structure_get_string (s, "name");
if (!pad_name)
pad_name = "src";
if (g_strcmp0 (GST_PAD_NAME (pad), pad_name))
goto next;
element = gst_pad_get_parent_element (pad);
if (!gst_validate_element_matches_target (element, s))
goto next;
monitor->min_buf_freq = min_buf_freq;
gst_validate_utils_get_clocktime (s, "buffer-frequency-start",
&monitor->min_buf_freq_start);
GST_DEBUG_OBJECT (pad, "pad has a minimum buffer frequency of %f",
min_buf_freq);
next:
g_clear_object (&element);
}
}
static gboolean
gst_validate_pad_monitor_do_setup (GstValidateMonitor * monitor)
{
@ -2807,6 +2923,8 @@ gst_validate_pad_monitor_do_setup (GstValidateMonitor * monitor)
if (G_UNLIKELY (GST_PAD_PARENT (pad) == NULL))
GST_FIXME ("Saw a pad not belonging to any object");
gst_validate_pad_monitor_get_min_buffer_frequency (pad_monitor, pad);
gst_object_unref (pad);
return TRUE;
}

View file

@ -124,6 +124,14 @@ struct _GstValidatePadMonitor {
/* The GstBuffer that should arrive next in a GList */
GList *current_buf;
gboolean check_buffers;
/* 'min-buffer-frequency' config check */
gdouble min_buf_freq;
gint buffers_pushed;
gint last_buffers_pushed;
GstClockTime min_buf_freq_interval_ts;
GstClockTime min_buf_freq_first_buffer_ts;
GstClockTime min_buf_freq_start;
};
/**

View file

@ -404,6 +404,10 @@ gst_validate_report_load_issues (void)
_
("The number of dropped buffers is higher than the maximum allowed by the scenario"),
NULL);
REGISTER_VALIDATE_ISSUE (CRITICAL, CONFIG_BUFFER_FREQUENCY_TOO_LOW,
_
("Pad buffers push frequency is lower than the minimum required by the config"),
NULL);
REGISTER_VALIDATE_ISSUE (WARNING, G_LOG_WARNING, _("We got a g_log warning"),
NULL);
REGISTER_VALIDATE_ISSUE (CRITICAL, G_LOG_CRITICAL,

View file

@ -123,6 +123,7 @@ typedef enum {
#define CONFIG_LATENCY_TOO_HIGH _QUARK("config::latency-too-high")
#define CONFIG_TOO_MANY_BUFFERS_DROPPED _QUARK("config::too-many-buffers-dropped")
#define CONFIG_BUFFER_FREQUENCY_TOO_LOW _QUARK("config::buffer-frequency-too-low")
#define G_LOG_ISSUE _QUARK("g-log::issue")
#define G_LOG_WARNING _QUARK("g-log::warning")