Distribua VMs VirtualBox por núcleos

Distribua VMs VirtualBox por núcleos

Estou usando muitas VMs VirtualBox com sistemas operacionais diferentes em um host Ubuntu Linux para desenvolvimento. Às vezes, meus scripts dão errado e começam a carregar 100% da CPU da VM. E quando uma VM carrega 100% da CPU, não consigo nem usar o sistema host - é lento!

Então eu tenho que abrir a parte superior (muito lentamente), ver se o processo do VirtualBox está usando 240% da CPU e, em seguida, abrir todas as janelas da VM até encontrar a VM que carrega a CPU e mata o processo. Não quero matar todo o processo do VirtualBox que está usando muita CPU.

Todas as minhas VMs estão configuradas para usar apenas um núcleo de CPU, com limite de execução de 100%. Minha CPU é AMD FX 8370 (8 núcleos, 16 threads), meu host roda em SSD RAID 10 com sistemas de arquivos alinhados corretamente. Estou no ambiente host do Windows? Claro que não! Então, por que sinto lentidão?

Talvez porque todas as VMs do VirtualBox recebem apenas o primeiro núcleo atribuído (como o Windows costuma fazer)? Como verificar isso e como fazer com que cada VM use cada núcleo? Talvez algumas outras suposições?

Talvez esta questão seja apenas: Como atribuir qualquer aplicativo a um núcleo específico no Linux?

Responder1

Não tenho resposta para sua pergunta, mas pelo menos posso aliviar sua dor.

Se você iniciar cada VM a partir da linha de comando, por exemplo, como

VBoxManage startvm Name_of_VM --type headless

então o comando superior com a opção -cexibirá também o comando completo que iniciou o processo. Desta forma você pode identificar imediatamente o processo culpado, e eliminá-lo com a kopção dentro topde si (você terá que fornecer o número do processo que deseja eliminar, que acabou de identificar).

O bom é, isso funcionará mesmo se você iniciar todas as suas VMs pela GUI, e não pela CLI.

EDITAR:

Pensando bem, talvez eu saiba a resposta à sua pergunta. Não tenho certeza se isso é realmente o que você está procurando; neste caso, por favor, diga-me.

O utilitário Linux para limitar a execução de um processo a um núcleo pré-especificado é o taskset. Você deve tê-lo por padrão, caso contrário, verifique o pacote util-linux. Você pode exibir o processoafinidade(ou seja, a lista de cpus nos quais é permitido executar) por meio de

      taskset -cp Process_ID

(o psinalizador especifica que o que se segue é um número de processo, o csinalizador substitui uma sequência de caracteres na representação hexadecimal dos núcleos da CPU, que seria o padrão).

Você pode atribuir um processo já em execução para ser executado apenas nos núcleos 0 e 1, por exemplo, por meio de

     taskset -cp 0,1 Process_ID

ou lançar um novo programa no núcleo 0 apenas por meio de:

      taskset -c 0 VBoxManage startvm Name_of_VM --type headless

Duas advertências: primeiro, o fato de você ter confinado o processo para rodar em uma única CPU não significa que ele será o único processo em execução nela: todos os processos cuja afinidade inclui aquela CPU serão executados, por alguma fração do tempo, em isto. Se você quiser reservar uma determinada CPU para uso exclusivo de um processo que você configurou taskset, você terá que usar o parâmetro isolcpusqueisola a CPU fornecida do agendador do kernel. Basta adicionar o parâmetro isolcpus=[cpu_number] à linha de comando do kernel Linux para o carregador de boot.

Além disso, você deve estar ciente de que confinar um processo a uma única CPU não precisa ser o total solutionque você pensa. As CPUs usam periféricos de qualquer tipo e, em determinadas circunstâncias, podem ficar presas porque o periférico em questão fica indisponível, o que faz com que a CPU entre em loop em suas solicitações, e o barramento e talvez também o periférico fiquem sobrecarregados com as solicitações. Um exemplo? Eu uso o controlador Sonos rodando no Wine; quando eu ativo uma VPN, ela é desconectada de sua base na Califórnia e continua inundando meu sistema com solicitações de rede. Isso não tem nada a ver com confinamento a uma única CPU.

Responder2

Com a ajuda da resposta de MariusMatutiae, finalmente consegui escrever o script "spreader" que espalha todas as VMs de caixa virtual lançadas para diferentes núcleos. Além disso, também faz a mesma coisa com VMs VMware.

Para usar este script, todas as suas VMs devem ser de núcleo único (que pode ser definido nas configurações). Caso contrário, você pode excluí-los 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

Se você quiser fazê-lo funcionar apenas com VMs VirutalBox, remova [V]irtualBox.*comment\|do padrão grep. Se você quiser que funcione apenas com VMs VMware, remova \|.*[.]vm[x]do padrão grep.

Logo após aplicar este script, você poderá ver alguns atrasos em todas as VMs por vários segundos. Então tudo fica bem e funciona conforme o esperado.

Agora as VMs não podem comer minha CPU mesmo quando sobrecarregadas, e o Firefox fica muito feliz em comer tudo. Mas isso é outra história... :/

informação relacionada