Bug of the day: 2017-10-13

I made some changes near the source of the pipeline, essentially processing some metadata. The result: RTSP preview worked, but the files written were 0-sized. Well, that sounds like cleaning up your kitchen and causing your bathroom sink to start leaking, except the bathroom is at the other side of the apartment, and your shower is working just fine.

I traced it back to a few lines of code that were supposed to be a small improvement, but harmless at worst. They were about buffer meta, which is just what it says on the box: metadata that goes together with the buffer. Timecodes in GStreamer are such metadata. Another metadata is “reference timestamp”: they have some caps, which just act as a label, and a timestamp. Our buffers used to have only one reference timestamp in the past: stream time. Recently we added also hardware time. (Don’t try to understand those, they’re just labels for what it’s worth in this context). When getting the reference timestamp for a buffer, I used to just leave the caps (the label) NULL, meaning “give me whatever is first”. But now we also had hardware time, so I had replaced the NULL with a proper caps description. NULL worked, I could create files. With the proper caps description, I couldn’t. That sounds like going to a bar, getting a beer when you ask for a drink, but getting nothing when you ask for a beer. Makes no sense, does it?

I started tracing back the buffers to see where the problem started. The muxer wasn’t outputting any data. It received video, but it didn’t receive audio. Hmm, suspicious. Kind of makes sense though, the RTSP preview is video-only. We were getting notifications about audio levels though, so something must have gotten lost along the way. Weird. I tried seeing where the audio buffers get lost, and it turned out to be at the exact spot where the aforementioned lines of code were. Okay, now it’s at least really starting to make sense. That part was synchronising audio with video though. It wasn’t supposed to eat bread with buffers instead of bread with butter. So what’s wrong here?

A small investigation showed that, while audio buffers had both stream and hardware reference timestamps, video buffers had only hardware reference timestamps at that point. I tried passing NULL to see what would happen, and the log file happily reported “I found the first reference timestamp for both audio and video. It’s a hardware timestamp in both cases!”… Well, okay, at least synchronisation worked in that case, but it was a pure coincidence. I then looked at the code that added the reference timestamps, and, surprise of all surprises, it was identical for both audio and video. I even added an assertion right afterwards to make sure that they both existed for video. They did. But my video buffers genuinely had no stream reference timestamps when I was trying to get that information. So where does the meta go?

I took a look at my pipeline, to see if there were any elements that would delete the meta. There weren’t. The only element that did anything with meta was timecodestamper: it was configured to remove any existing timecode meta and insert its own. It looked a bit far-fetched to imagine that it would remove the reference timestamp meta as well, but everything else made even less sense, so I gave that a try. There was a function that checked all metas and removed the timecode one. I checked that one, but nope, they were both still intact after its call. What I did find, though, made even less sense. The function to add a timecode meta was removing one of the two other metas!

God enlightened me to talk to Sebastian at that point. He said “oh, Mathieu fixed that one a few days ago”:
https://bugzilla.gnome.org/show_bug.cgi?id=788617

It was essentially a bug in a homegrown linked list implementation, and took him a lot of head scratching and hair pulling to figure it out. It manifested at a completely different place, too. That bug had existed since something like 2012 and nobody had ever run into it in the past. Until Mathieu did, a few days ago. And now I also did. Think about the odds of that.

Bug of the day: 2017-03-30

We had a pipeline that would capture 4K video, convert it using a high quality but low compression ratio codec, mux it into a .mov container together with raw audio, and write it into a file at a networked drive. The drive is fast enough to easily make use of the 10GB Ethernet card.

One 4K session was running fine. Two 4K sessions were freezing. CPU and memory usage were fine – nothing that seemed to cause things to lock up I tried taking pipeline dumps of the freeze: the queue right before the encoder was full. It was 600ms and qtmux shouldn’t need more than that for interleaving, so why is the queue getting full? So I examined the timestamps of all incoming buffers. Turns out that audio and video were off by more than 600ms … but WHY? (Thursday night is here)

Now some information on how qtmux works: Raw audio has no timestamps. It just assumes that it’s progressing at the given rate. If there’s a gap, the data that comes afterwards just gets squeezed and essentially gets converted to earlier timestamps, messing up A/V sync in the meantime.

So, keeping in mind the above, we noticed that several chunks of audio and/or video were going missing, and that’s what was causing the queue to get full. But why would they go missing? (Friday night is here)

Examining the data as it came from the capture card, we noticed that the callback that fed us the audio/video data was just forgetting to be called. It would get called at very regular intervals, until BOOM, a spike of maybe half a second or even one second happens. What’s worse – the drivers have no internal buffering. If you take too long to process the incoming data, you lose the next frame. We thought that the scheduler might be messing things up, but setting the capture thread to real-time priority didn’t seem to have any effect either. The thread itself was doing nothing much, it was just putting the data into a buffer and leaving, so it wasn’t spending more than 1ms in there. No locking or anything else was happening. CPU usage was still OK, no queues were really full at that point, so what could be wrong? We had this wild idea: does it run out of buffers in the pool? YES! But why? (Monday night is here)

On Tuesday we examined the situation with the buffer pool, looking at pipeline graphs and processing log files. Turns out that the queue right before the file sink was getting full first. After this, the queues between encoder and muxer would also get full. Then the queue before the encoder would also get full. Everything was zero-copy until there in my tests, so that’s what caused the capture card drivers to run out of buffers in their pool. Eventually the situation downstream of the encoder would slowly stabilize, but that was too late because then we had the gap that made everything explode. But why on Earth would the file sink refuse to write any further buffers? That was on Tuesday. I tried several things but nothing really seemed to help.

Yesterday we also enlisted a colleague, and he examined the system parameters in /proc etc. He optimized a lot of things – for example, the throughput with “dd” has pretty much doubled now. However, even with all these changes, the situation became better, but didn’t really solve itself.

Today (Thursday) I examined some graphs of how long the writev() call needed versus how long it took for it to be called again. Turns out that writev() could take up to half a second! Then it would get called again almost immediately. After a quick search, I ran into this issue here: https://github.com/netty/netty/issues/5360 We had already tried increasing the buffering in the filesink earlier, but it had no real effect. Turns out that we weren’t using proper values: even the 4MB we tried is maybe smaller than one video frame. So I gave it some thought and then set the filesink buffer size to 128MB (it won’t actually write the data into the file before that). AND IT WORKS!!!

Bug of the day: 2016-12-22

Somewhere, I was receiving an integer and I had to return a filename based on it, where the integer was the sequence number, e.g. 0, 1, 2, etc. I needed to use that integer in a callback, so I was passing it as user_data with a GUINT_TO_POINTER (type casting with some sanity checks) and getting it back with GPOINTER_TO_UINT on the other side. The first file was being written normally, but the second failed. I tried inspecting why and saw this line in the callback:

MyElement *self = MY_ELEMENT (user_data);

where “self” wasn’t needed in that callback, I just added it out of habit, because usually user_data is self. It does have some sanity checks there, so the first time worked because user_data was just 0x0 – so self is NULL, alright. The second time, self was becoming (MyElement *) 0x1, so the sanity check was failing, and kaboom.

Bug of the day: 2016-12-14

The previous day, I was looking at the debug logs and noticed a general teardown of the pipeline (setting state to NULL, removing elements, etc) when something crashed (e.g. wrong parameters => failed to link). I was thinking it absolutely shouldn’t happen and went to fix it. I could reproduce the pipeline crashing completely, but not the teardown. In any case, I pushed some fixes for it to fail more gracefully and went to sleep.

Next day, the pipeline started crashing for no apparent reason when I was trying to debug something else. I opened the log and, sure enough, there was a teardown. I also thought I could see some “child process killed” debug output on stdout, but that was running under screen, and “how do I scroll under screen?” should turned into “meh, that must have been just my idea, I can see the teardown here – plus I’m not getting a core dump”. I tried debugging where it could come from, but it ended up coming from a user command. However, my colleague insisted that the pipeline was just crashing.

Upon closer inspection, I noticed two processes doing teardown simultaneously. I asked my colleague and he said “yes, I was running four RTSP previews at once, but I was only recording to a file on one channel”. I tried seeing which process had the filesink in it, and I noticed it was yet another process, the last line of which was something completely normal and non-error. At that point I scrolled up and, sure enough, the “child process killed” message was there. It was even signal 9 (SIGKILL), which explained the absence of a core dump.

What had really happened: I was already debugging something else, so I had set debug log level to a high value. My colleague was running four channels at once, which means four different RTSP sessions, which encoded their streams four times, on a CPU encoder. When the time came for one of these four sessions to start encoding again in order to write it on the file, the machine simply couldn’t handle the load, the child process took longer than the configured timeout to respond and ended up getting killed as “probably deadlocked”.

Οι ποδηλάτες της Θεσσαλονίκης (και όχι μόνο) σε κατηγορίες

“Το πειρατικό του Κάπτεν Τζίμη”

(που μ’αυτό θα φύγετε κι εσείς, είναι φορτωμένο με χασίς, κι έχει τα φανάρια του στην πρύμνη)
Ο εν λόγω ποδηλάτης φροντίζει να έχει το κόκκινο φανάρι μπροστά και το άσπρο πίσω. Έτσι, τον βλέπετε στη λωρίδα σας και απορείτε ποιος είναι αυτός ο αφηρημένος που πάει ανάποδα, ή (ακόμα χειρότερα) τον βλέπετε στην αντίθετη λωρίδα και νομίζετε ότι έχετε χρόνο, μέχρι που σας κάνει ένα ΤΖΑ! Για περισσότερες παρατηρήσεις επιφυλάσσομαι, γιατί πάντα ξεφυτρώνει εκεί που δεν τον περιμένεις και δεν προλαβαίνεις να δεις πολλά.

Ο Νίντζα

Είναι ο ποδηλάτης που έχει αναλάβει μια μυστική αποστολή από τον πανίσχυρο μεγιστάνα, με τον όρο να μην τον παρατηρήσει κανείς· αν τυχόν τον πάρει χαμπάρι κάποιος, πρέπει να το πληρώσει με τη ζωή του. Ο Νίντζα, λοιπόν, κινείται απαραιτήτως το βράδυ χωρίς φώτα, φορώντας μαύρα ρούχα, και βάφει μαύρο ακόμα και το πρόσωπο και τα χέρια του. Αν τον δεις, θα τον δεις τελευταία στιγμή, επειδή ξέχασε να καλύψει τα μεταλλικά μέρη του ποδηλάτου με πανιά και γυάλισαν λίγο. Το πλεονέκτημα είναι ότι, αν χρειαστεί όντως να θυσιάσει τη ζωή του, θα φανεί σαν ατύχημα.

“Μαμά, μαμά, χωρίς δόντια!”

Σε αντίθεση με τον Νίντζα, ο “Χωρίς δόντια” ανιχνεύεται ακόμα και από δορυφόρο, λόγω της σιγμοειδούς πορείας που ακολουθεί, έχοντας τα χέρια του εκτός τιμονιού και το μυαλό του απασχολημένο. Μπορεί να οδηγεί στη μεσαία λωρίδα της λεωφόρου μέρα μεσημέρι παίζοντας Πόκεμον, μπορεί να βγάζει ρομαντικές σέλφι ποδηλατώντας στο ηλιοβασίλεμα, ή μπορεί απλά να τρώει φιστίκια, περιμένοντας να τα σκορπίσει στο οδόστρωμα όταν χρειαστεί να φρενάρει απότομα. [Ντισκλαίημερ: Τα παραπάνω παραδείγματα δεν αποτελούν αποκύημα της φαντασίας μου, κάθε ομοιότητα με πραγματικά γεγονότα και καταστάσεις δεν είναι καθόλου συμπτωματική]

Το Datsun

Τελευταία φορά που κοίταξα τη νομοθεσία, απαγόρευε τη μεταφορά ανθρώπων στην καρότσα ενός αγροτικού. Όπως πολύ καλά ξέρουμε, αυτό δεν αποτρέπει μεγάλες ομάδες ανθρώπων να στοιβάζονται στην καρότσα ενός Datsun. Αντίστοιχα μπορούμε να δούμε ποδηλάτες να κινούνται σε δικάβαλο ή ακόμα και τρικάβαλο, μη διστάζοντας να βγαίνουν και στη λεωφόρο. Όπως είναι λογικό, δεν μπορούν να αναπτύξουν μεγάλη ταχύτητα. Αν χρειαστεί να τους προσπεράσεις, πρέπει να κρατάς τριπλάσια απόσταση, δεδομένου ότι σε μία ενδεχόμενη σύγκρουση είναι βέβαιο ότι θα υποχωρήσει ο πιο λογικός.

Ο Λούης

Είναι ο ποδηλάτης που πιστεύει ότι η παραλία στις ώρες αιχμής είναι το πιο κατάλληλο μέρος για να εξασκηθεί για το Tour de France. Ποδήλατο κουρσάκι, πολύχρωμα λύκρα ρούχα, γυαλιά ηλίου, παγούρι, και ταχύτητες που ίσως και να υπερβαίνουν το όριο των 50 χιλιομέτρων την ώρα σε κατοικημένη περιοχή. Τα σλάλομ που κάνει για να προσπεράσει θα προκαλούσαν το θαυμασμό σε επαγγελματίες σκιέρ. Σύμφωνα με αυτόπτες μάρτυρες, προκειμένου να προσπεράσει, είναι ικανός να ποδηλατήσει επάνω στο νερό του Θερμαϊκού.

Ο Βέγγος

Είναι μια παραλλαγή του Λούη, με τη διαφορά ότι ο Βέγγος δεν τρέχει από σπορ, αλλά για να προλάβει κάτι. Θα τον δείτε με ένα μέτριο ποδήλατο και καθημερινό ρουχισμό να ιδρώνει να σπάσει το φράγμα του ήχου, προκειμένου να προλάβει το μάθημα, ένα κατάστημα, ή τον προαστιακό. Απαραίτητο αξεσουάρ είναι το σακίδιο, στο οποίο κουβαλάει τα βιβλία του, τα ψώνια, ή τις αποσκευές του Σαββατοκύριακου αντιστοίχως. Αν τυχόν βρείτε το Βέγγο χωρίς σακίδιο, σημαίνει ότι βιάζεται να προλάβει κάποιο ραντεβού, χωρίς να τον νοιάζει ότι το έτερό του ήμισυ θα τον δει λουσμένο στον ιδρώτα.

Ο Παγανιστής

Η κατηγορία αυτή θεωρεί ότι, όπως ο Ηρακλής απέκτησε τη ρώμη του λιονταριού της Νεμέας φορώντας τη λεοντή, έτσι κι αυτοί θα αποκτήσουν την ταχύτητα του Λούη, φορώντας τα ίδια ρούχα και οδηγώντας ίδιο ποδήλατο. Οι ταχύτητες που πιάνουν δικαιολογούν εν μέρει το έξοδο, καθώς είναι διπλάσιες απ’αυτές του πεντάχρονου με το τρίκυκλο έξω από τον ποδηλατόδρομο. Το μόνο πράγμα που ο Παγανιστής αγαπά περισσότερο από την ποδηλασία είναι η συζήτηση για την ποδηλασία. Έτσι, θα συγκεντρώνεται με τους ομοϊδεάτες του σε ένα παγκάκι, φιλονικώντας για το ποιος κατάφερε να βρει το μικρότερο λόγο ποιότητας προς τιμή στο ποδήλατο και τον εξοπλισμό τους. Συνήθως, βέβαια, τους ενδιαφέρει μόνο να αυξήσουν τον παρονομαστή του κλάσματος· ο αριθμητής είναι εν γένει αδιάφορος.

Ο Επιτάφιος

Σε αυτήν την περίπτωση, προηγείται η πομπή, που αποτελείται από τουλάχιστον δύο ποδήλατα, τα οποία κινούνται δίπλα-δίπλα, ώστε να κλείνουν τον ποδηλατόδρομο, και με απελπιστικά μικρή ταχύτητα. Το πιο λογικό είναι να υποθέσουμε ότι από τα στόματά τους, που τα βλέπουμε να κινούνται, ακούγονται ψαλμωδίες. Ακολουθεί ευλαβικά η παρέα τους, η οποία παρακολουθεί συγκινημένη τα γεγονότα, χωρίς όμως να κρατάει κερί, γιατί με τον αέρα έσβησε. Η πομπή ολοκληρώνεται με τους αγανακτισμένους που ακολουθούν στην ίδια ταχύτητα, κοιτώντας στα ημερολόγιά τους, μήπως τυχόν είναι Μεγάλη Παρασκευή και δεν το’χουν πάρει χαμπάρι.

Εύφημη μνεία: Ο αδερφός του Γιωρίκα

Ο Κωστίκας, όταν ανέλαβε το ρόλο του ταξιτζή για τις ανάγκες του καινούριου του ανεκδότου, δήλωνε περήφανος ότι “εγώ κι ο αδερφός μου ο Γιωρίκας περνάμε πάντα με κόκκινο”. Αν μη τι άλλο, είχε τη σύνεση να σταματάει στο πράσινο, ώστε να μην τρακάρει με τον αδερφό του το Γιωρίκα, σε περίπτωση που περνούσε από την άλλη πλευρά. Μια απλή ματιά στους δρόμους της πόλης θα φανερώσει ότι η εν λόγω οικογένεια αριθμεί πολλά μέλη, και μάλιστα δεν είναι όλα τόσο συνετά όσο ο Γιωρίκας και ο αδερφός του, ώστε να σταματάνε αν μη τι άλλο στο πράσινο. Δυστυχώς, θα παρατηρήσει κανείς ότι τα μέλη της οικογένειας δεν περιορίζονται στο ποδήλατο, αλλά πολλές φορές θα τους βρει κανείς να οδηγούν μηχανάκι ή και αυτοκίνητο. Για το λόγο αυτό, δε θα τους συμπεριλάβουμε στις επισημες κατηγορίες, αλλά θα περιοριστούμε σε εύφημη μνεία.

Ποδηλατώντας στη Θεσσαλονίκη – Cycling in Thessaloniki

Κάποιες μέτριες (όχι ιδιαίτερα άσχημες) διαδρομές στη Θεσσαλονίκη με το ποδήλατο. Η ημερομηνία και η ώρα κάτω αριστερά είναι λάθος, δεν είχα ρυθμίσει την ώρα στην κάμερα.

Some average (not really bad) cycling trips in Thessaloniki. The date and time at the bottom left are wrong, I hadn’t configured the time on the camera.

 

Άδεια χρήσης – License:

Μουσική – Music:

River Valley Breakdown Kevin MacLeod (incompetech.com)
Licensed under Creative Commons: By Attribution 3.0 License
http://creativecommons.org/licenses/by/3.0/

Βίντεο – Video:

This work is licensed under a Creative Commons Attribution-ShareAlike 4.0
International License: http://creativecommons.org/licenses/by-sa/4.0/