Hardware accelerated transcode

While reading the Linux Magazine on the bowl this morning, I discovered that ffmpeg has hardware support for decoding and encoding. Since I do that quite often, I figured it’s time to try it out. Lo and behold, it works better than I expected! Not on hadante, though. ffmpeg just segfaulted, because the card is way too old and the kernel module doesn’t seem to support it.

On othalla (my almost 4 year old laptop), it works like a charm. ffmpeg said encoding  at 5.5 times the original speed, even over NFS!

The command line I used:

$ ffmpeg -hwaccel cuvid -c:v h264_cuvid -resize 1280x720\
-i in.mkv -acodec copy -scodec copy\
-c:v h264_nvenc -preset slow -b:v 4000K -minrate 4000K out.mkv

It has a NVIDIA GPU, as well as an Intel pixel manager, but cuvid and nvenc only works the (proprietary) NVIDIA driver. Anyhow, as always it’s important where you place the options. Any options before -i is for decoding, anything after is for encoding. This makes:

-hwaccel cuvid -c:v h264_cuvid -resize 1280x720

ffmpeg decode everything via cuvid on the GPU and resize it to 720p. Source was 1080p.

-acodec copy -scodec copy

says: Just copy the audio stream and the subtitle stream to output. Now comes the important:

-c:v h264_nvenc -preset slow -b:v 4000K -minrate 4000K

tells it to let the GPU encode it to x264, preset slow and a minimum bitrate of 4000K. If I do the same via software decoder and encoder, I get barely more than real time speed, perhaps 1.1 or 1.2, depending on the source. With cuvid I get 5.5. Even Hadante with its 12 processors and 32GB only gets a speed of 2.0 to 2.2 max, and it’s hardware is much more current! Like it!

Dusting off the Array! (Part 8)

What now?

Well, forget Part 7 (fortunately). The SSD-Raid is working fine! It always assembled itself after several reboots. That’s good news, I guess!

In the meanwhile I fucked up again. I ordered an external USB-casing without a disk recently. While trying to get it up and running, I accidentally disconnected the USB-thingy connected to my external drives from power. Since then the kernel complains about the 2.5″ USB drive without power supply, but I got it up and running again.

Right now I’m copying all data from that drive to a member of the failed HGST-Array. Hopefully it’s not the failed drive, but we’ll see…

Creating a physical volume with pvcreate didn’t work out of the box. The command bailed out saying that it couldn’t open the device exclusively. At first I thought that it was because of the pre-existing PV-Signature, so I zeroed out the first GB, but that didn’t help, either.  Check-MK came to help, telling me that md127 was in a degraded state.

Of course! The drive contained a RAID-Superblock, so the kernel tried to start the the RAID, but couldn’t. Nevertheless, that kept the drive busy. Stopping it with

# mdadm -S /dev/md127

should have helped, I guess…

Anyway, wrote 1.1TB to the drive without errors. So, chances are that it isn’t the defective drive.

Dusting off the Array! (Part 7)

What happened

Oh my, I really hope this is the final chapter of this fucking story… On Feb. 20th, 2018, one of the HGST disks failed (what a surprise!). Since the serial number reported by hdparm bears absolutely no resemblance to the serial number printed on the label of the disk (thanks a bunch HGST, BTW), I pulled the wrong disk, inserted the spare, started the rebuild and… Lo and behold! The failing disk still failed! My attempts to recover the RAID destroyed it completely.

It was already kaputt when I thought of a way to identify the failing disk’s slot:

# badblocks <reported device by kernel>

This should light up the LED permanently on the external SATA casing.

I was so fed up that I ordered 4 2TB SSD-Disks shortly after that. Yesterday (Mar. 2nd, 2018) I finally had time to install them. Of course this setup has its quirks, too, but at least I can identify the disks via hdparm. The serial reported is actually the serial on the label:

HDD1: SerialNo 1744197E67EE
HDD2: SerialNo 1744197E7B92
HDD3: SerialNo 1744197E7104
HDD4: SerialNo 1744197E836D

The Quirks

Of course it didn’t just work out of the box™. When I booted with the shiny, new SSD disks, hadante got stuck at the BIOS splash screen while HDD3 was throwing a shining, red light. I pulled HDD3 and HDD4, rebooted and got a login prompt. Since SATA is hot-pluggable, I inserted HDD3 and 4. Fortunately, they showed up on the SCSI-Bus (cries of joy!).

I created a RAID5 with:

# mdadm --create /dev/md1 --level=5 --raid-devices=4 /dev/sd[efgh]

and waited until today (Mar. 3rd, 2018) for the rebuild to finish. After that I tested the setup:

  • Power off hadante
  • Turn off the external casing
  • Wait about 30 seconds
  • Turn on the external casing and then hadante
  • Wait eagerly…

… and watch the kernel error messages scrolling down the screen 🙁

The solution

Note the (not really) failing drive by staring at the LEDs of the external casing. Power off hadante and pull the failing drive and any other non-failing drive! It’s important to pull 2 drives, so the kernel cannot assemble the RAID! Then reboot and stop failing the RAID:

# mdadm -S /dev/md?

Now hot-plug the missing drives, reboot again and be amazed how everything magically works again 🙂

From my observations the drives in the external bay are recognized until you cut the power, but that’s just a guess.

Ryzen, Part 5

Well, well, well, after 71 days uptime the system can be considered stable:

Disabling the C6-sleep-state did it:

zenstates.py --c6-disable

Since last reboot the spectre/meltdown disaster happened. DKMS didn’t work any more, because archlinux updated gcc to 7.3 with retpoline support, so it blatantly refused to compile the nvidia module with a different compiler than the kernel was compiled with. That wasn’t really a problem, because X still restarted properly.

But there were other problems like systemd asking for passwords when it shouldn’t, dbus out of date and so on. Well, that’s what you get when running a rolling distribution. So I thought it was time to schedule a kernel re-compile and a reboot.

The re-compile was harder than expected. To put it short:

  • When following the official documentation, do the checkout in an empty directory
  • edit prepare() to do make oldconfig and make menuconfig in this order
  • Don’t forget to uncomment and change pkgbase to linux-ryzen!
  • Don’t makpkg -s on an encrypted volume 🙂
  • If DKMS complains about a compiler mismatch on pacman -U, do IGNORE_CC_MISMATCH=1 pacman -U …

After a successful reboot I decided to install the fallow 16 GB of ram I initially purchased, since RAM timings weren’t really the problem. Now I have a workstation with whopping 32GB RAM:

# free -m 
       total        used        free...
Mem:   32167        5521        8478...
Swap:  16382           0       16382

I kept the RCU_* setting, so let’s see how it turns out. Keeping fingers crossed!

The whole SheBang!

How to create a QIcon with Qt programmatically

First, create a 32×32 QImage and make it transparent (or whatever background color you need):

QImage img(32, 32, QImage::Format_ARGB32);
img.fill(QColor(0, 0, 0, 0));

I use QImage instead of QPixmap, because the documentation says that QImage is optimized for I/O, e.g. painting, and the first attempts with QPixmap looked like crap. Next, create a QPainter for the QPaintDevice and set some render hints to make it look nice:

QPainter *p = new QPainter(&img);
p->setRenderHint(QPainter::Antialiasing);
p->setRenderHint(QPainter::TextAntialiasing);
p->setRenderHint(QPainter::SmoothPixmapTransform);

QPainter::setBrush() sets the background color for shapes, QPainter::setPen() the foreground color for text:

p->setBrush(QColor(Qt::red));
p->setPen(QColor(Qt::white));

Then select a font the size of our future Icon:

QFont f("courier new");
f.setPixelSize(32);
p->setFont(f);

Now we need some background. White on transparent isn’t really readable, so let’s draw a circle:

p->drawEllipse(img.rect());

Since our QImage is actually a square and not an rectangle, QPainter::drawEllipse will draw a circle. Print the QChar, letter, or whatever:

p->drawText(img.rect(), Qt::AlignCenter, QChar(char));

Now clean up and return the QImage as QIcon:

delete p;
return QIcon(QPixmap::fromImage(img));

The whole shebang can be marveled at here. It looks like this:

Have fun!

IPv4 to IPv6 Forwarding

Why? Imagine you have an IPv6-only VM on an IPv4 and IPv6 enabled Host, or for some reason IPv4 is routed differently on the VM than IPv6 (think VPN). Then you want to access your VM from an IPv4-only internet access point. Pretty much impossible, you’d think. But fear not! socat comes to rescue 🙂

SOcket CAT is the swiss army knife for network sockets, even when iptables can’t help you any more:

socat TCP4-LISTEN:<LPORT>,fork TCP6:[2001:db8::8]:<DPORT>

<LPORT> is the listen port on the Host. It can be anything, but if you want to run socat as a non-privileged user, it should be > 1024. <DPORT> is the destination port on the IPv6-only VM to forward <LPORT> to. Of course this is not arbitrary. The parameter fork makes socat keep listening after a connection is established. Otherwise it would exit after the connection is closed.

A systemd-unit would look like this:

[Unit]
Description=Forward Port to IPv6
Requires=sys-subsystem-net-devices-br0.device
After=sys-subsystem-net-devices-br0.device

[Service]
User=nobody
ExecStart=/usr/bin/socat TCP4-LISTEN:44444,fork TCP6:[2001:db8::8]:3389
 
[Install] 
WantedBy=multi-user.target

The Requires and After order the service after the network bridge (br0) for your VM. Change it accordingly.

If your use case would be RDP (like above), and your favorite RDP client is rdpk, you can add a Host <IPv4-Address-of-Host>:44444 to rdpk and be done! Luckily rdpk passes the Hostname verbatim to xfreerdp /v: 🙂

Psiori Weihnachtsfeier 2017

Anreise

Dieses Mal ist die Weihnachtsfeier an einem Donnerstag. Kein Problem, da ich vom 30. November bis zum 8. Januar Urlaub habe. Leider habe ich Rücken, aber es geht. Tags zuvor habe ich eine Pille eingeworfen und mit einer Wärmflasche auf dem Sofa gesessen. Am Abreisetag bin ich morgens zwar noch etwas steif, aber nach einer weiteren Pille geht es einigermaßen. Nicht perfekt, aber gut genug, um das Auto abzuholen und Getränke zu kaufen. Ich bekomme einen Ford Mondeo Kombi Diesel, vollgetankt! Perfekt!

Um 9:15 Uhr habe ich alles erledigt und mache mich auf die Reise. Der Navi will mich über Oldenburg und Ahlhorn auf die A1 Richtung Osnabrück schicken, aber stattdessen fahre ich über Bremen. Dort geht es quer durch die Stadt, aber ich komme gut durch. Muss sich um ein Versehen handeln. Es regnet die die ganze Zeit.

Komme gut durch bis ich in die Berge komme. Dort schneit es heftig, so dass die 3. Spur teilweise unbenutzbar, weil zugeschneit ist. Sind so um die 0°C, aber zum Glück ist gestreut. Mit 100-110km/h komme ich recht gut durch. Je tiefer ich komme, desto besser wird es. Ich bekomme sogar ein paar Sonnenstrahlen ab, und es hört auf zu regnen! Um ca. 16:40 Uhr habe ich die Merzhauser Straße 144 erreicht. 7.5 Stunden ist gar nicht so schlecht für die Strecke.

Die Feier

Während wir auf das Taxi warten, trinke ich zwei Bier, da Sascha noch in einer Besprechung ist. Dann geht es zum Essen in die Wolfshöhle. Das Restaurant hat einen Michelin-Stern, es gibt ein 5-Gänge-Menü mit Weinen aus der Region. Auch ich habe Wein getrunken, obwohl ich eigentlich gar nicht wollte. Zur Begrüßung gab es Erdbeer-Blubberwasser und eine kleine Frikadelle auf Schwarzwurzeln. Mutters Frikadellen sind zwar besser, aber unglaublich, was man daraus machen kann.

Der nächste Gang war ein Salat mit Melonen und Artischocken. Den Rest habe ich vergessen, aber egal. Geschmacklich 1A. Dazu einen Riesling aus der Region. Dann Hummerravioli an einer Pilzsoße mit einem anderen Weißwein. Auch nicht schlecht. Danach der Hauptgang: Semmelknödel mit butterweichem Schweinefleisch und einer guten Soße, dazu Rotwein. Letzterer war nicht so gut, aber damit konnte ich leben. Dann der Nachtisch mit einem weiteren Weißwein. Sehr aufwändig, aber gut! Seit langem habe ich mal wieder Schokolade gegessen. War gar nicht süß!

Danach geht es weiter ins Hemingway, eine Raucherkneipe, die hauptsächlich Cocktails serviert. Patrick und ich freuen uns, dass sie auch Bier haben. Ich gehe öfters mal mit ihm raus, um nichtzurauchen. Mittlerweile hat er seine Stimme fast verloren. Um 2:00 Uhr geben wir die letzte Bestellung auf, um ca. 3:00 Uhr werden wir rausgeworfen.

Irgendjemand kommt auf die dumme Idee, noch in der Hotelbar vom Motel One einzukehren, um Lars dort vor seiner Abreise mit der Rechnung zu belästigen. Sein Zug geht um 5:52 Uhr, also nur noch 2 Stunden, bis er aufstehen muss. Er hat uns zwar gehört, aber gemieden. Verständlich. Wir waren alle ziemlich voll. Um ca. 6:00 Uhr werden wir auch dort rausgefegt, weil es Frühstück gibt. Dann geht es mit dem Taxi zu Sascha. Er hat zwar Frühstück für 9:30 Uhr in der Firma angesetzt, aber das schaffen wir nicht.

Die Rückreise

Ich werde um ca. 11:00 Uhr wach, weil Sascha im Bad rumort. Kurz darauf Patrick. Ich döse noch ein wenig weiter, kann aber nicht mehr schlafen. Also stehe ich auch auf und verabschiede Patrick. Während ich noch in Unterhose im Wohnzimmer stehe, kommt die Haushaltshilfe. Wir starren uns gegenseitig an, sagen “Guten Tag”, und dann ist sie auch schon wieder verschwunden. Nachdem ich geduscht und mich angezogen habe, lese ich Saschas SMS, dass die Haushaltshilfe heute kommt. Zu spät!

Ich entschließe mich, diesen Abend nicht mehr ins Crash zu gehen, um das Konzert von Cypecore zu sehen, da ich ziemlich fertig bin. Außerdem hat man mir am Abend zuvor gesagt, dass es ein ziemlich übler Laden sein soll. Ich sammle meine Siebensachen zusammen und fahre mit dem Zug zum Freiburger Hauptbahnhof. Dort treffe ich Patrick wieder, weil er seinen Zug verpasst hat. Immer noch ohne Stimme.

Er erklärt mir, welche Straßenbahn ich nehmen muss, um zur Merzhauser Straße zu kommen: Die Vauban (Linie 3 Richtung Innsbrucker Straße). Ich unterhalte mich noch 15 Minuten mit Sascha, bis ich mich verabschiede. Ich tanke in Freiburg noch voll für 1.17€/l, dann geht es auf die Bahn. Nach ein paar Kilometern schon Stop-And-Go, und so ging es weiter. Als es dreispurig wurde, ging es einigermaßen voran, aber aus BW rauszukommen war gar nicht so einfach: Ich habe diverse Bundes- und Landesstraßen bereist. Dann Stau auf der A5, Unfall. Nachdem ich an dem ersten Wrack vorbei war, dachte ich, dass es weiter geht, aber nein, es waren mehrere Autos beteiligt. Weiter im Schritttempo.

Endlich auf der A7 wurde ich 2 Mal umgeleitet. Unter anderem war ich in Hildesheim, weil ich eine Auffahrt verpasst habe. Frankfurt habe ich wirklich weiträumig umfahren, unter Anderem war ich auf der A3 Richtung München, die komplett falsche Richtung. Über die A66 bin ich dann irgendwann wieder auf der A5 gelandet.

Ich war schon in oder um Hannover als das Verkehrsleitsystem mich plötzlich auf 120, 100, 60 und dann 40 wegen eines Unfalls herunterbremste. Aber weit und breit nichts zu sehen, und der Navi hat auch nichts gesagt, also weiter. Als ich Rücklichter der stehenden Autos sah, war es leider zu spät. Ich war drin! Kein vor oder zurück.

Ich vertreibe mir die Zeit, lese ein wenig Propagandaschau und surfe im Internet auf dem Handy, bis irgendwann ein Polizist an mein Fenster klopft und mir sagt, dass ich umdrehen darf. Das erste Mal, dass ich Geisterfahrer war! Der Unfall war in einem AK, so dass ich einfach hätte an dem Unfall vorbeifahren können, wenn ich die Ausfahrt genommen hätte und durchgefahren wäre. Wo ist Selma, wenn man sie braucht?

Egal, Karl, einen kurzen Tankstopp später (für 1.38€/l Diesel, Splash and Dash, nur 10l) geht es weiter Richtung A27, Tempomat auf 190. Die Autobahn ist mittlerweile wie ausgestorben. Um 23:20 Uhr bin ich endlich zu Hause. Wow, fast 9 Stunden. Nachdem ich meine Sachen ausgepackt habe, schaue ich noch 2 Folgen Haven mit einer Wärmflasche im Rücken, aber bei der letzte Folge fallen mir fast die Augen zu. Dennoch: Freiburg ist immer eine Reise wert!

Ryzen, Part 4

Take 4

Well, I didn’t have to wait long. The box crashed right under my fingers only hours after the last changes. So, instead of enabling “Global C-States” in the BIOS, I disabled it explicitly.

Additionally, I used zenstates.py to disable C6 for good, hopefully:

# modprobe msr
# ./zenstates.py --c6-disable 
Disabling C6 state
# ./zenstates.py -l 
P0 - Enabled [...]
P1 - Enabled [...]
P2 - Enabled [...]
P3 - Disabled 
P4 - Disabled 
P5 - Disabled 
P6 - Disabled 
P7 - Disabled 
C6 State - Package - Disabled 
C6 State - Core - Disabled

As suggested here, I also disabled ASLR:

# echo 0 > /proc/sys/kernel/randomize_va_space

Changes so far:

  • Buy new Memory:  16GB G.Skill Flare X schwarz DDR4-3200 DIMM CL14 Dual Kit instead of 16GB Corsair Vengeance LPX schwarz DDR4-3000 DIMM CL15 Dual Kit.  Didn’t help at all, since it’s not a memory timing problem, but a linux problem. About 200€ wasted, yay! The bright side: If the other changes make my system stable, I could install the other 16GB, too. That would be a whopping 32GB for a desktop system 🙂
  • Various BIOS updates.
  • Play with D.O.C.P. settings. Didn’t help, see above.
  • Find out that linux doesn’t like AMD Ryzen processors and build a custom kernel with RCU_NOCB_CPU enabled. Still crashes 🙁
  • Disable C6 with zenstates.py (see above)
  • Disable ASLR (also see above)

Keeping my fingers crossed. If all this doesn’t help, my last option would be to change to Intel. I don’t expect much from my system, just that it runs stable. Very disappointing that AMD can’t get it right…

The whole SheBang!

Ryzen, Part 3

Take 3

Of course neither the new memory nor the BIOS update fixed the random crashes, but fortunately I’ve got another hint: Maybe it’s a linux-specific problem, and not one with memory timing. This post suggests that it’s a problem with C-States and RCU. Adding the following kernel command line parameters should help:

processor.max_cstate=1
rcu_nocbs=0-11

As always, nothing is as simple as it seems 🙁

The C-States

For max_cstate to take effect, I had to actually enable Global C-State-Control in the UEFI-thingy of my mobo! The default was Auto, which in turn defaulted to Disabled. After enabling it, dmesg reported this:

ACPI: ACPI: processor limited to max C-state 1

Before that, there was no mentioning of C-states in the kernel log, so I doubt that it has any impact, but one should never give up hope!

The RCU-Thingy

What it is (quoting Paul E. McKenney from LKML):

Read-copy update (RCU) is a synchronization mechanism that was added to the Linux kernel in October of 2002. RCU achieves scalability improvements by allowing reads to occur concurrently with updates.

It’s much more likely to be the cause of the problem since I once saw something like this after a reboot on the console:

NMI watchdog: BUG: soft lockup - CPU#12 stuck for 23s! [DOM Worker:1364]

The process was “systemd” instead of “DOM Worker”, but that shouldn’t matter. Anyway, the parameter rcu_nocbs=0-11 has no effect if the kernel config option CONFIG_RCU_NOCB_CPU is not set. Guess what, in the stock archlinux kernel it’s unset, lucky me!

So I ventured out to compile a custom kernel for arch. That turned out to be disappointingly easy! The available documentation just works ™! Four hints, though:

  1. Uncomment “make menuconfig”
  2. Edit /etc/makepkg.conf and set MAKEFLAGS to “-j<no-processors+1>” to get parallel builds
  3. If you have a nvidia graphics card and use the proprietary driver, keep in mind that you have to rebuild that one, too. Once again, that was ridiculously easy. Just install nvidia-dkms before updating the kernel with pacman -U and it will be built automagically when you install the new kernel! Detailed instructions are here.
  4. Don’t forget to update your grub-config with grub-mkconfig before rebooting!
Offload RCU callbacks from CPUs: 0-11.

should be in dmesg after a reboot, otherwise it didn’t work. I’m waiting with baited breath how it turns out!

Previous parts of my adventure: Part 1, Part 2.

Backup with Borg

Yes, resistance is futile! Borg is a descendant of attic with is a descendant of obnam. Development of the latter has ceased, so I needed a new victim. borg is a compressing, deduplicating, file based backup program which does more or less the same than obnam.

Despite its lineage borg is a bit different. It kinda does not work via ssh, only by FUSE and a sshfs-usermount, which is quite a bad choice, as I learned. It’s much faster if you run borg on the source, i.e. “where the data is” and transfer the result to the backup repository. Thinking about it, that’s not much of a surprise.

If you use sshfs, the destination has to pull all data for deduplication and compression, so no bandwidth is spared. If you run a borg server and only send the result of deduplication and compression over the wire, it’s much faster, what a surprise! So, always run borg at the source!