Huge memory leak sometime after starting a pipeline
Sergei Vorobyov
sergei.vorobyov at facilitylabs.com
Fri Nov 7 08:26:53 PST 2014
> Regarding my comment to simplify your pipeline... try to reproduce the
> leak without rendering video to the screen and just a fakesink. And try
> to reproduce the leak with a much simpler source but displaying on the
> screen. Dividing a problem into subproblems does not only help with
> quicksort ;)
1. > try to reproduce the leak without rendering video to the screen and
just a fakesink...
Do you understand that if you render nothing (fakesink) then evidently the
driver does not work and hence does not leak? I checked it nevertheless for
your pleasure (if I misunderstand something) to confirm the obvious: no
leaks with fakesink.
2. > try to reproduce with a much simpler source
Can't be any simpler: cyclically playing static .jpg and/or .png files
leaks on Intel with vaapisink or autovideosink (but not on NVidia and
Radeon), even repeatedly playing one and the same small randomly chosen
file.
3. > simplify your pipeline...
Can't be any simpler: filesrc location=...! decodebin ! imagefreeze !
videodecode ! vaapisink (implemented in C; see below), just dynamically
changing the location of a .jpg or .png file.
4. > Dividing...
I even know and use more sophisticated things than divide-and-conquer. But
I think with Intel all of it is pointless. They would never answer or
react. The best thing I figured is to dump Intel's HW altogether. Strange
that none of you (mostly working on Intel's) noticed massive memory leak
problems. Do you ever make endurance testing for a few hours or days?
Here's a simple program in question. Try it like this
test vaapisink
(or test <whateversink> for comparison)
on Intel's (I tried Bay Trail and HD4400 IGPs) and watch with top or htop,
for 10-30 minutes or a few hours.
test without arguments defaults to autovideosink
test ximagesink does not leak on Intel.
test <whateversink> does not leak on NVidia nor AMD Radeon
/*
* Adjust the MEDIA_DIR constant as explained below
* Compile with:
* gcc -std=c11 -Wall -pthread test.c -o test `pkg-config --cflags --libs
glib-2.0 gstreamer-1.0 gstreamer-pbutils-1.0 gstreamer-video-1.0`
* Run, giving a sink factory name as an argument, like "test vaapisink"
and enjoy
*/
#include <stdio.h>
#include <stdlib.h>
#include <glib.h>
#include <gst/gst.h>
/*
* This program implements cyclically playing all image files in MEDIA_DIR
* through the pipeline
* filesrc location=... ! decodebin ! imagefreeze ! videoconvert | <sink>
* by setting the location property to different files in MEDIA_DIR
*/
// Modify as needed. Directory should contain only image files: .jpg, .png,
..., one or more.
#define MEDIA_DIR "/home/fl/ads"
static GstBus *bus;
static GstMessage *message;
static GstElement *pipeline, *filesrc, *decodebin, *videoconvert,
*imagefreeze, *sink;
static gchar const *videosink;
static void dynamic_pad_link_cb (GstElement *decbin, GstPad *srcpad,
gpointer imgfreeze) {
gchar *pad_name = gst_pad_get_name (srcpad);
g_print ("dynamically linking %s on pad %s to %s ...\n",
GST_OBJECT_NAME (decbin), pad_name, GST_OBJECT_NAME
(imgfreeze));
g_free (pad_name);
GstCaps *caps = gst_pad_query_caps (srcpad, NULL);
GstPad *sinkpad = gst_element_get_compatible_pad ((GstElement*)
imgfreeze, srcpad, caps);
GstPadLinkReturn pad_link_outcome = gst_pad_link (srcpad, sinkpad);
if (pad_link_outcome == GST_PAD_LINK_OK)
g_print ("dynamic link succeeded!\n");
else {
g_print ("dynamic link failed with code %d\n", pad_link_outcome);
exit (-1);
}
gst_object_unref (sinkpad);
gst_caps_unref (caps);
}
static void build_pipeline () {
pipeline = gst_pipeline_new ("main_pipeline");
filesrc = gst_element_factory_make ("filesrc", "filesrc");
decodebin = gst_element_factory_make ("decodebin", "decodebin");
videoconvert = gst_element_factory_make ("videoconvert",
"videoconvert");
imagefreeze = gst_element_factory_make ("imagefreeze", "imagefreeze");
sink = gst_element_factory_make (videosink, videosink);
if (!sink) {
g_print ("failed to create %s\n", videosink);
exit (-1);
}
gst_bin_add_many (GST_BIN (pipeline), filesrc, decodebin, imagefreeze,
videoconvert, sink, NULL);
gst_element_link (filesrc, decodebin);
g_signal_connect (decodebin, // instance to connect signal to
"pad-added", // detailed signal
G_CALLBACK (dynamic_pad_link_cb), // assoc callback
imagefreeze); // passed as the 3rd arg to the callback
gst_element_link (imagefreeze, videoconvert);
gst_element_link (videoconvert, sink);
bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
}
static void play_media_file (gchar const *fname) {
gchar *full_file_name = g_strdup_printf (MEDIA_DIR G_DIR_SEPARATOR_S
"%s", fname);
g_object_set (filesrc, "location", full_file_name, NULL);
g_print ("playing %s\n", full_file_name);
if (gst_element_set_state (pipeline, GST_STATE_PLAYING) ==
GST_STATE_CHANGE_FAILURE) {
g_print ("failed to set pipeline to PLAYING\n");
exit (-1);
}
message = gst_bus_timed_pop_filtered (bus, 5 * GST_SECOND,
(GstMessageType)(GST_MESSAGE_EOS |
GST_MESSAGE_SEGMENT_DONE |
GST_MESSAGE_ERROR));
if (message == NULL)
g_print ("play time fully expired!\n");
else {
GstMessageType msg_type = GST_MESSAGE_TYPE (message);
gchar const *name = gst_message_type_get_name (msg_type); // a
reference to the static name of the message, don't free
g_print ("received message type=%d, name=%s\n", msg_type, name);
if (msg_type & GST_MESSAGE_EOS)
g_print ("GST_MESSAGE_EOS\n");
else if (msg_type & GST_MESSAGE_ERROR)
g_print ("GST_MESSAGE_ERROR, bad %s\n", full_file_name);
else
g_print ("UNEXPECTED message type %s\n", name);
gst_message_unref (message); // only when != NULL !!!
message = NULL;
}
if (gst_element_set_state (pipeline, GST_STATE_READY) ==
GST_STATE_CHANGE_FAILURE) {
g_print ("failed to set pipeline to state READY\n");
exit (-1);
}
g_free (full_file_name);
gst_element_unlink (decodebin, imagefreeze); // dynamically linked each
time, independently of this unlink
}
gint main (gint argc, gchar** argv) {
gst_init (&argc, &argv);
guint major, minor, micro, nano;
gst_version (&major, &minor, µ, &nano);
g_print ("GStreamer v%d.%d.%d.%d\n", major, minor, micro, nano);
videosink = (argc > 1)? argv[1] : "autovideosink";
g_print ("using %s\n", videosink);
build_pipeline ();
for (gint i=1; ; i++) {
g_print ("*** Cycle #%d through all media files in %s\n", i,
MEDIA_DIR);
GDir *dir = g_dir_open (MEDIA_DIR, 0, NULL);
gchar const *file_name;
while ((file_name = g_dir_read_name(dir))) // file_name must not be
modified or freed
play_media_file (file_name);
g_dir_close(dir);
}
}
On Thu, Nov 6, 2014 at 11:47 AM, Sebastian Dröge <sebastian at centricular.com>
wrote:
> On Do, 2014-11-06 at 11:33 +0100, Sergei Vorobyov wrote:
> > Sorry to say but the universal (on this list) recipe to use valgrind is
> > useless, like a hammer to drive screws.
> >
> > Point is, to see "leaks", you need to stop your application, in which
> case
> > GStreamer produces thousands (miles) of messages of the kind:
> > [...]
> >
> > even though you make a clean exit with _unrefs of all kinds and
> gst_deinit
> > (), and the application does not leak at all (if you don't stop it and
> run
> > indefinitely).
> >
> > Sure (by the end of the day) you can suppress any kind of messages you
> want
> > to ignore, but this hardly approaches you to the solution of the problem.
> > Should you take the above message seriously or ignore? Can you ask
> > GStreamer developers "take seriously or ignore?" about each of 100.000
> such
> > messages?
>
> The big leaks will be at the top, the small ones at the bottom. If
> there's nothing big at the top you have a problem and valgrind's
> memcheck tool won't be useful for you. And as I said last time already,
> valgrind is not solving all problems but it's a good start... and if it
> doesn't help (it does help in like 90% of the cases!) it still gives you
> hints at where *not* to waste your time looking. Debugging memory leaks
> is not trivial, use any help that you can get.
>
> Also try to simplify your pipeline to get a minimal testcase that
> reproduces the problem. And also see my mention of massif, which will be
> useful while the application is running.
>
> > I observed (without valgrind) a curious thing: the same application leaks
> > as hell on Intel's HD4400 IGP (NUC) with Intel's driver, but does not
> leak
> > at all on AMD Radeon, nor on NVidia. As I said, in all three cases
> valgrind
> > uselessly reports miles of possibly and definitely lost blocks, which
> makes
> > all three different cases completely indistinguishable.
> >
> > Check if you are using Intel's graphics HW. Maybe this is the reason.
> > Despite the developers claim that GStreamer runs equally good on any
> > hardware.
>
> Sure there might be a driver bug in the Intel driver. Like there can
> also be driver bugs in the others. Apart from those things GStreamer
> does not care at all what hardware you use, and in general most of us
> are using Intel hardware.
>
> Regarding my comment to simplify your pipeline... try to reproduce the
> leak without rendering video to the screen and just a fakesink. And try
> to reproduce the leak with a much simpler source but displaying on the
> screen. Dividing a problem into subproblems does not only help with
> quicksort ;)
>
> --
> Sebastian Dröge, Centricular Ltd · http://www.centricular.com
>
> _______________________________________________
> gstreamer-devel mailing list
> gstreamer-devel at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/gstreamer-devel
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.freedesktop.org/archives/gstreamer-devel/attachments/20141107/189ce5e7/attachment.html>
More information about the gstreamer-devel
mailing list