Windows AUS Dual boot Umgebung auch in VM booten

Vorgeschichte

Vor kurzem habe ich mir ein neues ThinkPad zugelegt. Da ich mehr unter Linux (Fedora 34) arbeite, aber ab und zu auch Windows für Photo/Video und 3D brauche, war ich mir zu Anfang unschlüssig wie ich Windows installieren sollte. Parallel oder nur in eine VM. Habe mich dann entschlossen Windows parallel im dual Boot Modus zu verwenden.

Windows war ja schon vorinstalliert, daher habe ich nur die Partition verkleinert und Fedora zusätzlich installiert. Vorher hatte ich mir noch Images von der Boot-, Recovery- und 16MB großen Windows Reserved Partition, mit dd gezogen.

Um die Systeme besser zu trennen, mehr Platz zu haben und Windows auch zusätzlich mittels KVM in einer VM zu laden, habe ich mich entschlossen eine zweite M.2 SSD zu kaufen. Diese passt sehr gut in den Slot, der eigentlich für ein WWAN Modul gedacht ist. Wichtig ist nur, dass das ein 2242 Modul ist und mit B-Key ausgestattet ist. M und B Key geht auch… Habe hier das SN520 SSD 256GB M.2 2242 PCIe genommen.

Probleme über Probleme

Der Einbau ging noch sehr gut von Statten, das ThinkPad hatte sogar schon eine M.2 Schraube drin.

Bei der Installation habe ich jedoch, gefühlt, alles falsch gemacht, was man falsch machen kann. Ich habe die Partitionstabelle der zusätzliche M.2 nicht geprüft. Als ich die Platte in GParted angeschaut habe, hatte ich nur gesehen, dass schon eine 1GB große Boot-Partition drauf war. Daher hatte ich mir hier keine weiteren Gedanken gemacht. Dummerweise war die Tabelle MBR und nicht GPT.

Auch habe ich zu früh mit den bestehenden EFI Boot Dateien rumgespielt, wodurch immer wieder der Dual Boot kaputt ging.

Um es zu verkürzen, hier nun nur die Schritten, die sofort zum Erfolg führen sollten:

Vorgehensweise

Voraussetzung ist, dass schon Windows und Fedora auf der original Partition installiert sind und sich im Dualboot auch starten lassen. Auch sollte nun schon die zweite M.2 eingebaut sein.

An dieser Stelle noch mal in das Windows booten und die UUID dort auslesen und notieren. Im Terminal das ausführen:

wmic csproduct get UUID

Partitionen anlegen und kopieren

Jetzt geht ihr her und erstellt euch ein GParted Live USB Stick und bootet von dort.

Wählt in GParted die zweite M.2 aus und erstellt eine GPT Partitionstabelle. Anschließend erstellt ihr am Anfang der Festplatte eine 260MiB große Fat32 Partition mit der Bezeichnung „System„. Wenn die Partition erstellt ist, bekommt sie die Markierung: Boot, esp und hidden.

Als nächstes habe ich eine 16MB große, unformatierte Partition erstellt, ohne Bezeichnung und der Markierung: msftres. Ob die wirklich benötigt wird, müsst ihr selber noch mal recherchieren.

Nun kopiert ihr die Windows Partition von der original M.2 (/dev/nvme0n1) und fügt sich hinter die zuletzt erstellte Reserved Partition.

Zu guter Letzt kopiert ihr noch die Windows Recovery Partition. Ich habe sie ganz ans Ende der neuen M.2 eingefügt um die Windows Partition vergrößern zu können. Markierung sollte hier sein: hidden und diag.

Zum Schluss könnt ihr die alte Windows Partition auf der original M.2 löschen. Wenn ihr wollt könnt auch auch gleich die Fedora Partition verschieben und vergrößern.

Fedora präparieren

Wir müssen die neue M.2 blacklisten, damit Fedora hier kein Blödsinn mit anstellt und wir das Modul sauber per „PCI Passthrough“ durch reichen können.

Das machen wir jetzt erst mal temporär, da wir später noch mal die Windows M.2 dem Grub Bootmanager hinzufügen wollen.

Um das zu bewerkstelligen, müssen wir erst einige Kernel Module aktivieren und Optionen setzen. Erstelle eine Datei: /etc/modprobe.d/kvm.conf mit dem Inhalt:

options kvm_intel nested=1
options kvm_intel emulate_invalid_guest_state=0
options kvm ignore_msrs=1 report_ignored_msrs=0

Und eine Datei: /etc/modules-load.d/vfio.conf:

vfio
vfio-pci
vfio_virqfd
vfio-iommu-type1

Dann passt die Grub Datei an: /etc/default/grub und ergänzt die Zeile GRUB_CMDLINE_LINUX mit:

intel_iommu=on iommu=pt rd.driver.pre=vfio-pci

Jetzt die Module und Einstellungen aktivieren:

dracut -f --kver $(uname -r)
grub2-mkconfig > /etc/grub2-efi.cfg

Nun das System einmal neu startet und wieder in Fedora booten.

Dann können wir die PCI ID auslesen, um die M.2 zu blacklisten:

for g in /sys/kernel/iommu_groups/; do echo "IOMMU Group ${g##/}:"; for d in $g/devices/; do echo -e "\t$(lspci -nns ${d##/})"; done; done

Bei mir taucht unter anderem dieser Eintrag auf:

IOMMU Group 16:
    08:00.0 Non-Volatile memory controller [0108]: Sandisk Corp PC SN520 NVMe SSD [15b7:5005] (rev 01)

Hier brauche ich die ID: 15b7:5005

In einer neuen Datei: /etc/modprobe.d/vfio.conf schreiben wir dies hinein:

options vfio-pci ids=15b7:5005

Jetzt wieder Kernel neu konfigurieren:

dracut -f --kver $(uname -r)

Und System neu starten.

VM einrichten

Wenn KVM noch nicht installiert ist, können wir das nun tun:

dnf install @virtualization edk2-ovmf

Mit virt-manager können wir die VM anlegen, aber ohne Festplatte, diese fügen wir als PCI Host-Gerät an und wählen dort unsere Windows M.2 aus. Gleich zu Anfang sollte auch die Firmware auf: OVMF_CODE.fd gestellt werden. Bei der CPU ist es wichtig, nur einen Sockel auszuwählen und dann Kerne und Threads zu vergeben.

Jetzt die VM nicht starten, sondern das XML von ihr bearbeiten. Am besten einen Dump machen:

virsh dumpxml win10 > win10.xml

Dann die XML bearbeiten und die ID, die wir vom original Windows notiert haben, gleich am Anfang unter <uuid> einfügen.

Unter <vcpu>*</vcpu> fügen wir noch diesen Block ein:

<sysinfo type="smbios">
    <bios>
      <entry name="vendor">[vendor]</entry>
      <entry name="version">[version]</entry>
    </bios>
    <system>
      <entry name="manufacturer">[manufacturer]</entry>
      <entry name="product">[product]</entry>
      <entry name="version">[version]</entry>
      <entry name="uuid">[uuid]</entry>
      <entry name="sku">[sku]</entry>
      <entry name="family">[family]</entry>
    </system>
    <baseboard>
      <entry name="manufacturer">[manufacturer]</entry>
      <entry name="product">[product]</entry>
      <entry name="version">[version]</entry>
      <entry name="serial">[serial]</entry>
    </baseboard>
    <chassis>
      <entry name="manufacturer">[manufacturer]</entry>
      <entry name="serial">[serial]</entry>
    </chassis>
  </sysinfo>

Die Infos dafür bekommt ihr mit dem Tool: dmidecode.

Mit dem fertigen XML definiert ihr die Windows VM neu. Dieser Eintrag simuliert in der VM die gleiche Hardware, wie der physische PC und kann daher unter anderem Lizenzprobleme vorbeugen.

Windows Bootmanager in VM installieren

Jetzt braucht ihr eine aktuelle Windows 10 ISO, die ihr der VM zuweisen müsst und von dieser auch booten sollt.

Ihr wählt nun statt Installation, Computerreparaturoptionen, dann Problembehandlungen und dort Eingabeaufforderung.

Im Terminal gebt ihr diskpart ein und vergibt so die Laufwerkbuchstaben, dass Windows C hat und die SYSTEM Boot Partition K hat. Weiter Infos dazu hier: repair-efi-gpt-bootloader.

Dann könnt ihr den Bootloader installieren:

bcdboot C:\Windows /l de-DE /s k: /f ALL

Jetzt sollte die Windows VM bootfähig sein.

Dual Boot reparieren und Windows zu Grub hinzufügen

Zu diesem Zeitpunkt lässt sich Windows nicht mehr normal booten. Um das zu beheben, müssen wir die neue M.2, die geblacklistet ist, wieder für Fedora aktivieren. Also die Datei /etc/modprobe.d/vfio.conf wieder öffnen und die Option kommentieren. Kernelmodule wieder konfigurieren:

dracut -f --kver $(uname -r)

System neu starten. Dann mit efibootmgr den Windows Booteintrag entfernen. Z.B. mit: efibootmgr -b 0000 -B. Vorher aber ID prüfen, mit efibootmgr -v.

Nun die neue Bootpartition auf der neuen M.2 dem EFI Menü hinzufügen:

efibootmgr -c  -L "Windows Boot Manager" -l "\EFI\Microsoft\Boot\bootmgfw.efi" -d /dev/nvme1n1 -p 1

Und die Grub Konfig neu schreiben:

grub2-mkconfig > /etc/grub2-efi.cfg

Jetzt wieder die Windows M.2 blacklisten, booten und kontrollieren, ob Windows auch normal gestartet werden kann.

Das war’s…

Anhang und Haftungsausschluss

Ich möchte hier noch mal drauf hinweisen, dass ich keine Haftung für eventuelle Schäden übernehme. Bei dieser Anleitung handelt es sich lediglich um ein mögliches Szenario was nicht alle Hürden und Fehler abdeckt. Auch muss eventuelle Lizenzprobleme der Windows Installation geprüft werden.

Quellen:

https://gist.github.com/jb-alvarado/d6aef18ddb965939442838d7310c5b31
https://superuser.com/questions/1507636/how-to-create-from-0-a-bootable-disk-partition-for-windows-10
https://bobcares.com/blog/repair-efi-gpt-bootloader/
https://recoverit.wondershare.com/partition-tips/repair-efi-bootloader-in-windows.html
https://www.linuxbabe.com/command-line/how-to-use-linux-efibootmgr-examples
https://www.nextofwindows.com/the-best-way-to-uniquely-identify-a-windows-machine

KVM: PCI Passthrough

Besitzt CPU und Chipset die VT-d Erweiterung, lassen sich mittel KVM Hardware zur VM durch reichen. Das geht mit Grafikkarten, Netzwerkkarte, Decklink SDI Karten usw.

Um das zu ermöglichen muss Ubuntu dafür vorbereitet werden:

1. Module lasen:

nano /etc/modules

# KVM hardware passthrugh
pci_stub
vfio
vfio_iommu_type1
vfio_pci
kvm
kvm_intel

2. Grub Bootlader anpassen:

nano /etc/default/grub

GRUB_CMDLINE_LINUX_DEFAULT="intel_iommu=on"

update-grub
reboot

3. Hardware die weitergereicht werden soll ermitteln und eintragen:

lspci -nn

Ausgabe z.B.: 04:00.0 Multimedia video controller [0400]: Blackmagic Design DeckLink SDI/Duo/Quad [bdbd:a11b]

nano /etc/initramfs-tools/modules

pci_stub ids=bdbd:a11b

sudo update-initramfs -u

reboot

Nach Reboot prüfen ob Hardware deaktiviert ist:

dmesg | grep pci-stub

Wenn in etwa soetwas raus kommt:

[    1.437427] pci-stub: add BDBD:A11B sub=FFFFFFFF:FFFFFFFF cls=00000000/00000000
[    1.437482] pci-stub 0000:04:00.0: claimed by stub

hat alles geklappt. Nun kann in virt-manager die Hardware dem Guest zugewiesen werden.

 

Referenzen:

https://www.pugetsystems.com/labs/articles/Multiheaded-NVIDIA-Gaming-using-Ubuntu-14-04-KVM-585/

https://wiki.debian.org/VGAPassthrough

How to configure PCI-passthrough on virt-manager

http://vfio.blogspot.de/2015/05/vfio-gpu-how-to-series-part-1-hardware.html

 

Videostreaming per Multipath TCP

Dieser Artikel sollte mehr als „Proof of Concept“ verstanden werden. Ich bin weder ein Netzwerkspezialist, noch habe ich tiefgreifende Erfahrung mit Linux Kernel kompilieren.

Vorausgesetzt werden mindestens zwei Internetverbindungen, die Multipath TCP Verbindungen zulassen. Bei Internet über Kabel (Kabel Deutschland), hatte ich z.B. Probleme. Telekom sollte hier keine Probleme machen. Schreibt gerne auch, wenn ihr hier Erfahrungen gemacht habt.

Basis System ist Ubuntu 16.04, benötigt werden diese Pakete:

sudo apt install build-essential libssl-dev libncurses-dev ncurses-dev

Anschließend holt man sich den Kernel von github:

git clone --depth=1 git://github.com/multipath-tcp/mptcp.git

Konfiguriert ihn mit:

make menuconfig

Es sollten folgende Optionen aktiviert sein:

  • Networking support->Networking options->TCP/IP networking->MPTCP protocol (MPTCP)
  • Networking support->Networking options->TCP/IP networking->MPTCP: advanced scheduler control
    (alle aktivieren)
  • Networking support->Networking options->TCP: advanced congestion control->MPTCP Linked Increase
    (default habe ich hier: lia)
  • Networking support->Networking options->IP: advanced router->IP: policy routing (IP_MULTIPLE_TABLES)

Hier ist meine config: https://gist.github.com/jb-alvarado

Zum kompilieren verwende ich dieses Script:

#!/bin/bash

cd /usr/local/src/
rm -f *.deb

cd /usr/local/src/mptcp

sed -i 's/CONFIG_DEBUG_INFO=y/CONFIG_DEBUG_INFO=n/g' .config

DATE=`date "+%Y-%m-%d"`
KVERS=`make kernelversion`
make -j 3 deb-pkg DEBEMAIL='christoph.paasch@gmail.com' DEBFULLNAME='Christoph Paasch' LOCALVERSION=.mptcp KDEB_PKGVERSION=${DATE}

cd /usr/local/src/

# Create meta-package
rm -Rf linux-mptcp

mkdir linux-mptcp
mkdir linux-mptcp/DEBIAN
chmod -R a-s linux-mptcp
ctrl="linux-mptcp/DEBIAN/control"
touch $ctrl

echo "Package: linux-mptcp" >> $ctrl
echo "Version: ${DATE}" >> $ctrl
echo "Section: main" >> $ctrl
echo "Priority: optional" >> $ctrl
echo "Architecture: all" >> $ctrl
echo "Depends: linux-headers-${KVERS}.mptcp, linux-image-${KVERS}.mptcp" >> $ctrl
echo "Installed-Size:" >> $ctrl
echo "Maintainer: Christoph Paasch <christoph.paasch@gmail.com>" >> $ctrl
echo "Description: A meta-package for linux-mptcp" >> $ctrl

dpkg --build linux-mptcp

mv linux-mptcp.deb linux-mptcp_${DATE}_all.deb

Quelle: https://github.com/multipath-tcp/mptcp-scripts/blob/master/scripts/debian_build/create_kernel.sh

Pfade nach Bedürfnis anpassen.

Nach dem Kompilieren installieren:

sudo dpkg -i linux-firmware-image-4.4.83.mptcp_2017-08-21_amd64.deb linux-headers-4.4.83.mptcp_2017-08-21_amd64.deb
linux-image-4.4.83.mptcp_2017-08-21_amd64.deb linux-mptcp_2017-08-21_all.deb

und neu starten.

Wenn das System den neuen Kernel nicht als Default einrichtet, muss man das Händisch machen:

grep menuentry /boot/grub/grub.cfg

die Zeilen zählen beginnend mit 0, bis zum gewünschten Kernel. Ist das ganze in dem „Advanced options“ eingeklammert braucht man folgenden Eintrag in der Datei /etc/default/grub:

GRUB_DEFAULT=“1>ZeilenNummer“
# z.B.
GRUB_DEFAULT=“1>7″

Nach dem Neustart sollte mit uname -a in etwas das raus kommen:

Linux <computername> 4.4.83.mptcp #1 SMP Fri Aug 18 12:35:18 CEST 2017 x86_64 x86_64 x86_64 GNU/Linux

Als nächste kann man die multipath tcp Kernel Einstellungen prüfen:

sysctl -a | grep mptcp

Das Ergebnis sollte in etwas so sein:

net.mptcp.mptcp_checksum = 1
net.mptcp.mptcp_debug = 0
net.mptcp.mptcp_enabled = 1
net.mptcp.mptcp_path_manager = fullmesh
net.mptcp.mptcp_scheduler = default
net.mptcp.mptcp_syn_retries = 3
net.mptcp.mptcp_version = 0

Möchte man den default scheduler wechseln geht das mit:

sysctl -w net.mptcp.mptcp_scheduler=roundrobin

Bei mir ging roundrobin nur nach diesem Befehl:

sudo insmod /lib/modules/4.4.83.mptcp/kernel/net/mptcp/mptcp_rr.ko

Laut Doku wird roundrobin nicht empfohlen.

redundant wird nur empfohlen wenn man sehr niedrige Latencen möchte, und verbrauchte mbit keine Rolle spielen.

Weitere Optimierungen gibt es hier: ConfigureMPTCP

Nun braucht es noch ein Routing:

der Einfachheit halber gehen wir von eth0 und eth1 aus. Dann könnte ein Script dafür in etwa so aussehen:

#!/bin/bash

devArr=("eth0" "eth1")
ipArr=("192.168.0.2" "172.20.10.2")
gatArr=("192.168.0.1" "172.20.10.1")

# reset all routes
for ((i=0; i < ${#devArr[@]}; i++)); do
        ip route del default dev ${devArr[$i]} 2>/dev/null
        ip rule del from 0/0 to 0/0 table $((i+1)) 2>/dev/null
        ip route flush table $((i+1)) 2>/dev/null
done

# add rules and routes
for ((i=0; i < ${#devArr[@]}; i++)); do
        ip rule add from ${ipArr[$i]} table $((i+1))
        ip route add $( awk -F. '{ print $1"."$2"."$3".0/24" }' <<< ${ipArr[$i]} ) dev ${devArr[$i]} scope link table $((i+1))
        ip route add default via ${gatArr[$i]} dev ${devArr[$i]} table $((i+1))
done

# default route for the selection process of normal internet-traffic
ip route add default scope global nexthop via ${gatArr[0]} dev ${devArr[0]}


exit 0

Ist noch kein schönes Script, besser wären zwei unter /etc/network/if-down.d/ und /etc/network/if-up.d/

Sind die Routen angelegt noch mal prüfen:

$ ip route
default via 192.168.0.1 dev eth0 
172.20.10.0/28 dev eth1  proto kernel  scope link  src 172.20.10.2  metric 100 
192.168.0.0/24 dev eth0  proto kernel  scope link  src 192.168.0.2  metric 600
$ ip rule
0:	from all lookup local 
32764:	from 172.20.10.2 lookup T2 
32765:	from 192.168.0.2 lookup T1 
32766:	from all lookup main 
32767:	from all lookup default
$ ip route show table 1
default via 192.168.0.1 dev eth0 
192.168.0.0/24 dev eth0  scope link 

$ ip route show table 2
default via 172.20.10.1 dev eth1 
172.20.10.0/24 dev eth1  scope link

Um nun eine Videostream über multipath tcp laufen zu lassen, braucht es auf der Empfängerseite noch einen Kernel der auch multipath tcp versteht. Allerdings reicht es hier die kompilierte Version zu installieren und aktivieren. Alles ander kann gespart werden.

Als Streamingserver bietet sich srs an.

Streamen könnte man dann in etwa so:

ffmpeg -re -i test.mp4 -s 320x180 -c:v libx264 -crf 26 -preset slower -c:a aac -b:a 92k -ar 44100 -f flv "rtmp://example.org:1935/live/mptcp"

Anschauen würde so gehen:

ffplay "rtmp://example.org:1935/live/mptcp"

Achtung: streamt man auf einen Domainnamen, braucht man einen korrekten „Reverse DNS Eintrag“, hat man den nicht besser die IP nehmen.

Prüfen ob über beide Verbindungen Traffic läuft kann man auf der Senderseite mit:

sudo tcpdump -i any tcp and dst host example.org and dst port 1935 -nq

und auf der Empfängerseite mit:

sudo tcpdump -i eth0 tcp and dst host 192.168.100.50 and port 1935 -nq

Wird nur über eine IP gesendet, stimmt was nicht, ansonsten hat man es geschafft :).

Wenn wir nun ein Interface blocken, sollte der Stream munter weiter streamen:

iptables -A OUTPUT -o eth0 -j DROP

Wenn das der Fall ist kann die iptables Regel wieder entfernt werden:

iptables -D OUTPUT -o eth0 -j DROP

 

Zweite Route über eine andere Internetverbindung anlegen

Hat man zwei Internetverbindungen kann man für bestimmte Subnetze oder einzelne IPs eine andere Route definieren.

Gehen wir davon aus, dass unsere Default Verbindung über Internet1 geht:

default via 192.168.0.1 dev eth0.10

Möchten wir eine zweite Route für ein ganzes Subnetz erstellen müsste man den IP Bereich definieren, z.B. 192.168.1.0/24. Brauchen wir die Route nur für eine IP nehmen wir einfach die IP.

Zur Umsetzung muss Anfangs eine Tabelle definiert werden. Das geschieht in der Datei: /etc/iproute2/rt_tables

1     T1
2     T2

Die erste Spalte steht für die ID und die zweite für die Tabelle. Wir brauchen später die ID. (Im Prinzip würde auch ein Tabelle reichen.)

Nun füllen wir unsere Tabelle mit der IP die wir umleiten wollen:

ip rule add from 192.168.0.128 table 2

Dann definieren wir über welches Interface die IP kommunizieren soll:

ip route add 192.168.0.128 table 2 dev eth0.11

Und zum Schluss legen wir einen neuen Default Gateway für die Tabelle fest:

ip route add default via 192.168.1.1 table 2

Das Gateway ist in den meisten Fällen das Modem. Möchte man das Default Gateway für alle Verbindungen abfrage kann man das mit: ip route

Und das neue Gateway der Tabelle 2 lässt sich so prüfen: ip route list table 2

Nun sollte die neue Route stehen und Traffic von der IP 192.168.0.128 wird nun über Telekom geleitet.

Möchte man die Regel später wieder löschen (ein Neustart würde sie auch zurücksetzen) nimmt man einfach die gleichen Befehle und ersetzt add mit del.

KVM optimieren

Hier soll eine Sammlung entstehen, wie KVM und deren Gäste optimiert werden können.

Host:

Um VT-d zu nutzen, braucht Grub einen zusätzlichen Eintrag, in der Zeile:

GRUB_CMDLINE_LINUX_DEFAULT=

das anfügen:

intel_iommu=on

und Grub updaten:

sudo update-grub

Es sollte auf dem Host kontrolliert werden ob es Prozesse gibt, die mehrere CPU Kerne in Anspruch nehmen. Z.B. Squid in Kombination mit Spuidguard startet mehrere Instanzen. Das kann zu Latenz Probleme im Guest führen. Auch Apache macht das.

low-latency Kernel kann helfen die VMs performanter zu machen, bzw. die Reaktionszeiten zu verkürzten. Besonders bei Anwendungen die geringe Latenz brauchen, wie Audio/Video Applikationen, ist das von Vorteil. Dadurch wird die Kernel Timer Frequency auf 1000 Hz erhöht und es werden Preemptible Funktionen aktiviert.

Auf Seiten des Host kann die Priorität einer VM, mit Bordmitteln, verändert werden. Ein Script als Cronjob (z.B. alle 10 Minuten) kann hier Abhilfe schaffen:

#!/bin/bash

# Name der zu priorisierenden VM
vmName="$VMName"

# PID, nice Priorität und IO State ermitteln
vmPID="$( ps ax | awk '/qemu-system-x86_64/ && /'"$vmName"'/ && !/awk/{ print $1 }' )"

if [[ -n "$vmPID" ]]; then
        nID="$( ps -o nice -p $vmPID | awk '/[0-9]+/{ p=$NF } END{ print p }' )"
        ioStat="$( ionice -p $vmPID | awk '/none/{ print }' )"
fi

ffPID="$( ps ax | awk '/ffmpeg -nostats -v info -hide_banner -re/ && !/awk/{ print $1 }' )"

if [[ -n "$ffPID" ]]; then
        ffID="$( ps -o nice -p $ffPID | awk '/[0-9]+/{ p=$NF } END{ print p }' )"
        ffioStat="$( ionice -p $ffPID | awk '/none/{ print }' )"
fi

# Priosisierungswerte
vmPrio="-10"
vmIOCl="2"
vmIOPr="0"

# Wenn nice nicht den gewünschten Wert hat, wird dieser gesetzt
if [[ -n "$nID" ]] && (( $nID >= 0 )); then
        renice -n $vmPrio -p $vmPID >/dev/null 2>&1
fi

if [[ -n "$ffID" ]] && (( $ffID >= 0 )); then
        renice -n $vmPrio -p $ffPID >/dev/null 2>&1
fi

# Wenn IO Class 'none' ist, wird diese erhöht
if [[ -n "$ioStat" ]]; then
        ionice -c $vmIOCl -n $vmIOPr -p $vmPID -t >/dev/null 2>&1
fi

if [[ -n "$ffioStat" ]]; then
    ionice -c $vmIOCl -n $vmIOPr -p $ffPID -t >/dev/null 2>&1
fi

exit 0

Disk Performance:

driver name='qemu' type='raw' cache='none' io='native'

Cache none ist das beste, funktioniert aber nicht wenn das VM Image auf einem ZFS Dateisystem liegt. Hier kann auch writeback genommen werden, muss aber mit Vorsicht geschehen. Bei writeback gibt es keine Sicherheit und es kann schnell zu Datenverlust kommen.

Als Image Format ist raw zu bevorzugen. Noch besser ist es eine Festplatte komplett durch zu reichen.

Für VM Images, besonders in Kombination mit Linux bringt das „Deadline“ Scheduling etwas mehr an Festplattenperformance. Muss im Host und im Guest eingestellt werden.

Windows in VM:

Unbedingt virtio Treiber verwende! Schon beim Einrichten der virtueller Hardware virtio wählen.

Für Netzwerkdienste Checksum Offload im Netzwerk Interface deaktivieren (Geräte Manager). Zum testen ob die Checksum korrekt ist, kann ein IP Stream gestartet werden, z.B. mit udp (ffmpeg), auf dem Host kann dann mit tcpdump der Stream geprüft werden:

tcpdump -i ethX -n dst port 1234 -s0 -vv

Taucht bad udp cksum […] auf, muss Checksum Offload deaktiviert werden, in dem Fall für UDP.

KVM beherrscht HyperV Funktionen, diese sollen zusätzlich etwas Leistung bei Windows VMs bringen:

virt-xml $VMNAME --edit --features hyperv_relaxed=on,hyperv_vapic=on,hyperv_spinlocks=on,hyperv_spinlocks_retries=8191

Guest Allgemein:

CPU Pinning kann sinnvoll sein. Wird vor allem bei mehr Prozessor Systemen empfohlen, um zu vermeiden, dass ein Thread auf den Speicher des anderen Prozessors zugreifen muss.

OVMF Bios sollte man im Auge behalten und gegebenenfalls installieren und beim Einrichten der VM auswählen. Für Windows 10 ist es z.B. empfehlenswert ein UEFI Bios zu nutzen, das geht nur mit OVMF

IOthreads zu aktivieren kann bei mehreren HDs Sinn machen. Muss über virsh edit VMName gemacht werden.

Weitere CPU Tuning Optionen sind möglich, z.B. vCPU Scheduling, einfach mal getesten.

AppleScript: Ordner selektieren und an Terminal übergeben

Ausgangspunkt:

In verschiedenen Ordnern liegen MP4 Files. Das AppleScript soll einen Dialog öffnen in dem man die Ordner auswählen kann, ist nur ein Ordner ausgewählt wird geprüft ob sich ein MP4 File in diesem Ordner befindet, wenn ja wird gewarnt dass nur ein Ordner ausgewählt wurde, ist kein MP4 File vorhanden wird darauf hingewiesen und ein neuer Dialog wird geöffnet.

Sind mehrere Ordner ausgewählt werden diese an den Terminal geschickt. Der Terminal führt ein Shell Script aus, welches im AppleScript Verzeichnis (*.app/Contents/Resources/Scripts/) liegt. Das Shell Script soll dann die Ordner weiterverarbeiten.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
set muxer to POSIX path of (path to resource "mxf-muxer" in directory "Scripts")
set foldercount to 0
 
tell application "Finder"
    set FolderPath to (choose folder with prompt "Pick the folders containing the files to process:" with multiple selections allowed)
    
    set foldercount to count FolderPath
    
    if (foldercount = 1) then
        set inPath to POSIX path of FolderPath as text
        set Foldername to name of folder FolderPath as text
        
        set infile to "no"
        tell application "Finder" to if exists inPath & Foldername & ".MP4" as POSIX file then set infile to "yes"
        
        if (infile = "no") then
            display dialog ("There is no file: \"" & inPath & Foldername & ".MP4" as text) & "\". Please select (multiple) folders which contains MP4 files!" buttons {"Cancel", "Select Folders"} default button "Select Folders"
            
            if button returned of result = "Select Folders" then
                set FolderPath to (choose folder with prompt "Pick the folders containing the files to process:" with multiple selections allowed)
            else
                return
            end if
        else
            display dialog "You have only select one folder, are you sure that you only want to process one file?" buttons {"Select Folders", "Continue"} default button "Continue"
            
            if button returned of result = "Select Folders" then
                set FolderPath to (choose folder with prompt "Pick the folders containing the files to process:" with multiple selections allowed)
            end if
        end if
    end if
    
    set filesString to ""
    repeat with file_ in FolderPath
        set filesString to filesString & " " & quoted form of (POSIX path of file_)
    end repeat
    
    tell application "Terminal"
        activate
        do script quoted form of muxer & filesString
    end tell
end tell

 

ffmpeg: 24fps zu 25fps

Möchte man ein 24 fps Clip mittels ffmpeg korrekt umwandeln kann man das in etwa so bewerkstelligen:

ffmpeg -i input.ext -r 25 -vf "setpts=(1/1,04166666666667)*PTS" [codec settings] output.ext

Mit diesem Beispiel würde zusätzlich noch ein Border angefügt:

ffmpeg -i input.ext -r 25 -vf "setpts=(1/1,04166666666667)*PTS" -vf scale=720:436,pad=720:576:0:70 -sws_flags lanczos -c:v mpeg2video -target pal-dvd -aspect:v 16:9 -c:a mp2 -b:a 224k -y output.ext