Advertisement
Guest User

Virtual DAW Libvirt Hook

a guest
Aug 27th, 2021
465
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Bash 4.61 KB | None | 0 0
  1. #!/usr/bin/env bash
  2.  
  3. ###
  4. ## libvirt qemu hooks for virtual DAW. Check this reddit post for more information:
  5. ## https://www.reddit.com/r/VFIO/comments/pckwz1/guideline_virtual_daw_linux_host_windows_guest/
  6. ##
  7. ## Licensed under WTFPL (http://www.wtfpl.net/)
  8. ##
  9. ###
  10.  
  11. ## Change the following variables to fit your configuration.
  12. logfile="/var/log/libvirt-hook.log"
  13.  
  14. # Set this to the name of your VM
  15. my_guest_name="my-fancy-vm"
  16.  
  17. # Guest RAM to reserve exclusively (in GiB)
  18. guest_ram_gb=16
  19.  
  20. # Cores to isolate (shield), zero-indexed
  21. cores_to_shield="4-8"
  22.  
  23. # Reset the USB controller that was passed to the guest. Leave empty if you don't do such things.
  24. usb_controller_to_reset="0000:03:00.0"
  25.  
  26. # The total hugepage scaling factor in percent (should usually be between 102-105% of the actual guest memory)
  27. hugepage_scale_factor=102
  28.  
  29. # Don't change anything down from here
  30. all_cores="0-$[$(nproc)-1]"
  31. guest_name=$1
  32. mode=$2
  33. level=$3
  34. slice_name="$(echo "$my_guest_name" | tr '[:upper:]' '[:lower:]')"
  35.  
  36. # Redirect all the output of the script to the log file.
  37. exec &>> ${logfile}
  38.  
  39. # Calculates the hugepage size required to start the VM by inspecting the guest settings.
  40. get_hugepage_size() {
  41.     vmid=$1
  42.    
  43. #   TODO: Autodetection does not work because virsh is not available in hook scripts.
  44. #   ram_in_kb=$(virsh dumpxml $vmid | grep currentMemory | grep -o -E '[0-9]+')
  45. #   guest_ram_gb=$[ram_in_kb / 1024 / 1024]
  46.  
  47.     guest_ram=$[(guest_ram_gb * 1024)/2] # Calculate byte size
  48.     guest_ram=$[(guest_ram * 102) / 100] # Apply extra
  49.  
  50.     echo $guest_ram
  51. }
  52.  
  53. shield_vm() {
  54.     echo "Shielding VM ..."
  55.  
  56.     echo 3F > /sys/bus/workqueue/devices/writeback/cpumask
  57.  
  58.     cset -m set -c ${all_cores} -s machine.slice
  59.     cset -m shield --kthread on --cpu ${cores_to_shield} --userset=${slice_name}
  60. }
  61.  
  62. unshield_vm() {
  63.     echo "Unshielding VM ..."
  64.  
  65.     echo "${unshielded_cores}" > /sys/fs/cgroup/cpuset/machine.slice/cpuset.cpus
  66.  
  67.     echo FFF > /sys/bus/workqueue/devices/writeback/cpumask
  68.  
  69.     cset -m shield --reset --userset=${slice_name}
  70. }
  71.  
  72. echo "Hook $mode ($level) was called for machine $guest_name."
  73.  
  74. if [ "$guest_name" != "$my_guest_name" ]; then
  75.     echo "Ignoring hooks for $guest_name."
  76.     exit
  77. fi
  78.  
  79. if [ "$mode" = "diag" ]; then
  80.     echo "Diagnostics for VM $guest_name"
  81.  
  82.     echo "Guest RAM: ${guest_ram_gb} GiB"
  83.     echo "Calculated hugepage size: $(get_hugepage_size $guest_name)"
  84. fi
  85.  
  86. if [ "$mode" = "stopped" ]; then
  87.     echo "Stopped."
  88.  
  89.     # Reset hugepages
  90.     echo "Disabling hugepages ..."
  91.     sysctl vm.nr_hugepages=0
  92.  
  93.     # Reset frequency scaling.
  94.     echo "Restoring default CPU frequency scaling."
  95.     cpupower -c ${cores_to_shield} frequency-set -g powersave
  96.  
  97.     # Reset all of those other weird stuff.
  98.     echo "Restoring system stuff."
  99.    
  100.     sysctl vm.stat_interval=1
  101.     sysctl -w kernel.watchdog=1
  102.  
  103.     echo always > /sys/kernel/mm/transparent_hugepage/enabled
  104.     echo 1 > /sys/bus/workqueue/devices/writeback/numa
  105.  
  106.     # Finally unshield the cores.
  107.     echo "Unshielding cores."
  108.     unshield_vm
  109. fi
  110.  
  111. if [ "$mode" = "prepare" ]; then
  112.     echo "Setting up system stuff."
  113.    
  114.     sync # For USB
  115.  
  116.     # I wish I knew what all this stuff does. On second thought I don't.
  117.     echo 3 > /proc/sys/vm/drop_caches
  118.     echo 1 > /proc/sys/vm/compact_memory
  119.    
  120.     sysctl vm.stat_interval=120
  121.     sysctl -w kernel.watchdog=0
  122.  
  123.     echo never > /sys/kernel/mm/transparent_hugepage/enabled
  124.     echo 0 > /sys/bus/workqueue/devices/writeback/numa
  125.  
  126.     # Make the shared memory for a looking glass session accessible for the kvm group and all other users on the system.
  127.     echo "Setting up permissions for looking glass session."
  128.     sudo -u nobody touch /dev/shm/looking-glass
  129.     chown nobody:kvm /dev/shm/looking-glass
  130.     chmod 770 /dev/shm/looking-glass
  131.  
  132.     # Disable frequency scaling for the shielded cores.
  133.     echo "Enabling performance mode for guest cores."
  134.     cpupower -c ${cores_to_shield} frequency-set -g performance
  135.  
  136.     # Shield the cores.
  137.     echo "Shielding cores."
  138.     shield_vm
  139.  
  140.     # Adjust the hugepage size.
  141.     echo "Enabling hugepages."
  142.     nr_hugepages=$(get_hugepage_size $guest_name)
  143.     echo "Calculated hugepage count: $nr_hugepages"
  144.  
  145.     sysctl vm.nr_hugepages=$nr_hugepages
  146. fi
  147.  
  148. if [ "$mode" == "release" ]; then
  149.     if [[ "${usb_controller_to_reset}" != "" ]]; then
  150.         # Reload the USB controller.
  151.         echo "Releasing USB controller ${usb_controller_to_reset}."
  152.                 echo -n "${usb_controller_to_reset}" | tee /sys/bus/pci/drivers/xhci_hcd/unbind
  153.         echo -n "${usb_controller_to_reset}" | tee /sys/bus/pci/drivers/xhci_hcd/bind
  154.  
  155.         # This makes pulse redetect the device.
  156.         pacmd unload-module module-udev-detect && pacmd load-module module-udev-detect
  157.     fi
  158. fi
  159.  
  160. echo "Hook '$mode' completed."
  161.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement