Skip to content

Instantly share code, notes, and snippets.

@ayufan

ayufan/taskset.sh

Last active Apr 25, 2021
Embed
What would you like to do?
KVM CPU pinning for Proxmox VE
#!/bin/bash
set -eo pipefail
VMID=200
cpu_tasks() {
expect <<EOF | sed -n 's/^.* CPU .*thread_id=\(.*\)$/\1/p' | tr -d '\r' || true
spawn qm monitor $VMID
expect ">"
send "info cpus\r"
expect ">"
EOF
}
VCPUS=($(cpu_tasks))
VCPU_COUNT="${#VCPUS[@]}"
if [[ $VCPU_COUNT -eq 0 ]]; then
echo "* No VCPUS for VM$VMID"
exit 1
fi
echo "* Detected ${#VCPUS[@]} assigned to VM$VMID..."
echo "* Resetting cpu shield..."
for CPU_INDEX in "${!VCPUS[@]}"
do
CPU_TASK="${VCPUS[$CPU_INDEX]}"
echo "* Assigning $CPU_INDEX to $CPU_TASK..."
taskset -pc "$CPU_INDEX" "$CPU_TASK"
done
@GuyNoIRQ

This comment has been minimized.

Copy link

@GuyNoIRQ GuyNoIRQ commented Mar 26, 2021

Hacked up something based on this for PCs with 2 NUMA nodes. Hope this helps someone. I'm hoping it helps with the quite poor performance I'm getting in some games with GPU passthrough. I'll report back here if it does anything.
`root@ProxMox01:~# cat PinVM.sh
#!/bin/bash

set -eo pipefail

VMID=$1
OffSet=$2

cpu_tasks() {
expect <<EOF | sed -n 's/^.* CPU .thread_id=(.)$/\1/p' | tr -d '\r' || true
spawn qm monitor $VMID
expect ">"
send "info cpus\r"
expect ">"
EOF
}

VCPUs=($(cpu_tasks));

if ! [ ${VCPUs} ]; then
echo "* No VCPUS for VM$VMID";
exit 1;
fi

if ! (( ${2} % 2 )); then
NumaCPUs=($(lscpu | grep "NUMA node[0-9]" | awk '{print $4}' | head -n1 | sed 's/,/ /g'));
else
NumaCPUs=($(lscpu | grep "NUMA node[0-9]" | awk '{print $4}' | tail -n1 | sed 's/,/ /g'));
fi

echo -e "\nVCPU PIDs: ${VCPUs[@]}\n";
lscpu | grep "NUMA node. CPU"
echo -e "\nCores per Numa Boundary: ${#NumaCPUs[@]}";
echo "Number of VCPUs: ${#VCPUs[@]}";
echo "Defined Core offset: $2";

if [[ $(( ${#NumaCPUs[@]} + 1 )) < $(( $2 + ${#VCPUs[@]} )) ]]; then
echo -e "\nOffset too great for number of CPU cores. Exiting\n";
exit 1;
fi;

VCPUCount="${#VCPUS[@]}";
VCPUCount=$(( ${VCPUCount} - 1 ));

if [[ $2 = 0 ]]; then
Index=0;
else
Index=$(( $2 - 1 ));
fi;

for VCPU in ${VCPUs[@]}; do
NumaCPU="${NumaCPUs[$CPUIndex]}";
echo "VCPU PID: $VCPU assigned to CORE: ${NumaCPUs[$Index]}";
taskset -pc "${NumaCPUs[$Index]}" "${VCPU}" 2>&1 > /dev/null;
Index=$(( $Index + 1 ));
done`

Executed like:
./PinVM.sh

Sample output:
`root@ProxMox01:~# ./PinVM.sh 103 0

VCPU PIDs: 35681 35682 35683 35684 35685 35686 35687 35688 35689 35690 35691 35692

NUMA node0 CPU(s): 0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30
NUMA node1 CPU(s): 1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31

Cores per Numa Boundary: 16
Number of VCPUs: 12
Defined Core offset: 0
VCPU PID: 35681 assigned to CORE: 0
VCPU PID: 35682 assigned to CORE: 2
VCPU PID: 35683 assigned to CORE: 4
VCPU PID: 35684 assigned to CORE: 6
VCPU PID: 35685 assigned to CORE: 8
VCPU PID: 35686 assigned to CORE: 10
VCPU PID: 35687 assigned to CORE: 12
VCPU PID: 35688 assigned to CORE: 14
VCPU PID: 35689 assigned to CORE: 16
VCPU PID: 35690 assigned to CORE: 18
VCPU PID: 35691 assigned to CORE: 20
VCPU PID: 35692 assigned to CORE: 22`

And if you try to set too large an offset you get an error:
`root@ProxMox01:~# ./PinVM.sh 103 7

VCPU PIDs: 35681 35682 35683 35684 35685 35686 35687 35688 35689 35690 35691 35692

NUMA node0 CPU(s): 0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30
NUMA node1 CPU(s): 1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31

Cores per Numa Boundary: 16
Number of VCPUs: 12
Defined Core offset: 7

Offset too great for number of CPU cores. Exiting`

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment