
Estoy usando muchas máquinas virtuales VirtualBox con diferentes sistemas operativos en un host Ubuntu Linux para el desarrollo. A veces mis scripts se equivocan y comienzan a cargar el 100% de la CPU de la VM. Y cuando una VM carga el 100% de la CPU, ni siquiera puedo usar el sistema host, ¡es lento!
Luego tengo que abrir la parte superior (muy lentamente), ver que el proceso de VirtualBox está usando el 240% de la CPU, luego abrir todas las ventanas de la VM hasta encontrar la VM que carga la CPU y finalizar el proceso. No quiero acabar con todo el proceso de VirtualBox que utiliza mucha CPU.
Todas mis máquinas virtuales están configuradas para usar solo un núcleo de CPU, con un límite de ejecución del 100%. Mi CPU es AMD FX 8370 (8 núcleos, 16 subprocesos), mi host se ejecuta en SSD raid 10 con sistemas de archivos correctamente alineados. ¿Estoy en un entorno de host de Windows? ¡Por supuesto que no! Entonces, ¿por qué experimento desaceleraciones?
¿Quizás porque a todas las máquinas virtuales de VirtualBox solo se les asigna el primer núcleo (como suele hacer Windows)? ¿Cómo comprobar eso y cómo hacer que cada VM utilice cada núcleo? ¿Quizás algunas otras conjeturas?
Quizás esta pregunta sea simplemente: ¿Cómo asignar cualquier aplicación a un núcleo específico en Linux?
Respuesta1
No tengo respuesta a tu pregunta, pero al menos puedo aliviar tu dolor.
Si inicia cada VM desde la línea de comando, por ejemplo como
VBoxManage startvm Name_of_VM --type headless
luego, el comando superior con la opción -c
mostrará también el comando completo que inició el proceso. De esta manera, puede identificar inmediatamente el proceso culpable y eliminarlo con la k
opción dentro de top
sí mismo (deberá proporcionar el número del proceso que desea eliminar, que acaba de identificar).
Lo bueno es, esto funciona incluso si inicia todas sus máquinas virtuales desde la GUI, no desde la CLI.
EDITAR:
Pensándolo bien, quizás sepa la respuesta a tu pregunta. No estoy seguro de que esto sea realmente lo que estás buscando. En este caso, dímelo.
La utilidad de Linux para limitar la ejecución de un proceso a un núcleo preespecificado es taskset
. Deberías tenerlo por defecto, si no, revisa el paquete util-linux
. Puedes visualizar el proceso.afinidad(es decir, la lista de CPU en las que se permite ejecutar) mediante
taskset -cp Process_ID
(La p
bandera especifica que lo que sigue es un número de proceso, la c
bandera sustituye una cadena de caracteres en la representación hexadecimal de los núcleos de CPU, que sería la opción predeterminada).
Puede asignar un proceso que ya se está ejecutando para que se ejecute solo en los núcleos 0 y 1, por ejemplo, mediante
taskset -cp 0,1 Process_ID
o lanzar un nuevo programa en el núcleo 0 únicamente mediante:
taskset -c 0 VBoxManage startvm Name_of_VM --type headless
Dos advertencias: en primer lugar, el hecho de que haya limitado el proceso a ejecutarse en una única CPU no significa que será el único proceso que se ejecute en ella: todos los procesos cuya afinidad incluya esa CPU se ejecutarán, durante una fracción del tiempo, en él. Si desea reservar una CPU determinada para el uso exclusivo de un proceso que configuró con taskset
, deberá usar el parámetro isolcpus
queaísla la CPU dada del programador del kernel. Simplemente agregue el parámetro isolcpus=[cpu_number] a la línea de comando del kernel de Linux para el cargador de arranque.
Además, se le debe advertir que limitar un proceso a una sola CPU no tiene por qué ser lo total solution
que parece pensar. Las CPU utilizan periféricos de cualquier tipo y, en determinadas circunstancias, pueden atascarse porque el periférico en cuestión deja de estar disponible, lo que hace que la CPU realice un bucle en sus solicitudes y el bus y quizás también el periférico se sobrecarguen con las solicitudes. ¿Un ejemplo? Utilizo el controlador Sonos que se ejecuta en Wine; cuando activo una VPN, se desconecta de su base de operaciones en California y sigue inundando mi sistema con solicitudes de red. Esto no tiene nada que ver con el confinamiento a una sola CPU.
Respuesta2
Con la ayuda de la respuesta de MariusMatutiae, finalmente logré escribir el script "esparcidor" que distribuye todas las máquinas virtuales de virtualbox lanzadas a diferentes núcleos. Además, también hace lo mismo con las máquinas virtuales VMware.
Para utilizar este script, todas sus máquinas virtuales deben ser de un solo núcleo (eso se puede configurar en la configuración). De lo contrario, puede excluirlos modificando grep regexp.
#!/bin/bash
#getting possible affinity lists
AFFINITY=($(taskset -cp 1 | sed 's/.*\([0-9]\)\+[-]\([0-9]\+\).*/\1 \2/'))
echo Detected min_cpu: ${AFFINITY[0]}, max_cpu: ${AFFINITY[1]}.
CURRENT_AFFINITY=${AFFINITY[1]};
ps -Af | grep -i "[V]irtualBox.*comment\|.*[.]vm[x]" | awk -F" " '{ print $2}' |
# Iterating backwards because I think that farther cpus are less loaded. Maybe I am wrong
while read pid
do
echo Setting $pid to cpu $CURRENT_AFFINITY
taskset -cp $CURRENT_AFFINITY $pid
#loop stuff
let CURRENT_AFFINITY=CURRENT_AFFINITY-1;
if [[ "$CURRENT_AFFINITY" -lt ${AFFINITY[0]} ]];
then
CURRENT_AFFINITY=${AFFINITY[1]};
fi
done
Si desea que funcione solo con máquinas virtuales VirutalBox, elimínelo [V]irtualBox.*comment\|
del patrón grep. Si desea que funcione solo con máquinas virtuales VMware, elimínelo \|.*[.]vm[x]
del patrón grep.
Justo después de aplicar este script, puedes ver algunos retrasos en todas las máquinas virtuales durante varios segundos. Entonces todo vuelve a estar bien y funciona como se esperaba.
Ahora las máquinas virtuales no pueden consumir mi CPU incluso cuando están sobrecargadas, y Firefox está muy feliz de comérselo todo. Pero esa es otra historia... :/