La risposta è usare cpusets. L'utility python cpuset semplifica la loro configurazione.
Concetti di base
3 set di cpu
root
:presente in tutte le configurazioni e contiene tutte le cpu (unshielded )system
:contiene le cpus usate per le attività di sistema - quelle che devono essere eseguite ma non sono "importanti" (non schermate )user
:contiene le cpus usate per compiti "importanti" - quelli che vogliamo eseguire in modalità "tempo reale" (schermata )
Il shield
command gestisce questi 3 cpusets.
Durante l'installazione sposta tutte le attività mobili nel cpuset non schermato (system
) e durante lo smontaggio sposta tutte le attività mobili nel root
cpuset.Dopo la configurazione, il sottocomando ti consente di spostare le attività nello scudo (user
) cpuset e, inoltre, per spostare attività speciali (thread del kernel) da root
a system
(e quindi fuori dal user
cpuset).
Comandi:
Per prima cosa creiamo uno scudo. Naturalmente il layout dello scudo dipenderà dalla macchina/attività. Ad esempio, supponiamo di avere una macchina non NUMA a 4 core:vogliamo dedicare 3 core allo shield e lascia 1 core per le attività non importanti; poiché non è NUMA, non abbiamo bisogno di specificare alcun parametro del nodo di memoria e lasciamo i thread del kernel in esecuzione nel root
cpuset (ovvero:su tutte le cpu)
$ cset shield --cpu 1-3
Alcuni thread del kernel (quelli che non sono legati a specifiche cpus) possono essere spostati nel system
cpuset. (In generale non è una buona idea spostare i thread del kernel che sono stati associati a una cpu specifica)
$ cset shield --kthread on
Ora elenchiamo cosa è in esecuzione nello shield (user
) o non schermato (system
) cpusets:(-v
per verbose, che elencherà i nomi dei processi) (aggiungi un secondo -v
per visualizzare più di 80 caratteri)
$ cset shield --shield -v
$ cset shield --unshield -v -v
Se vogliamo fermare lo scudo (teardown)
$ cset shield --reset
Ora eseguiamo un processo nello shield (comandi che seguono '--'
vengono passati al comando da eseguire, non a cset
)
$ cset shield --exec mycommand -- -arg1 -arg2
Se abbiamo già un processo in esecuzione che vogliamo spostare nello scudo (nota che possiamo spostare più processi passando un elenco separato da virgole o intervalli (qualsiasi processo nell'intervallo verrà spostato, anche se ci sono spazi vuoti))
$ cset shield --shield --pid 1234
$ cset shield --shield --pid 1234,1236
$ cset shield --shield --pid 1234,1237,1238-1240
Concetti avanzati
cset set/proc
- questi ti danno un controllo più preciso dei cpusets
Imposta
Crea, regola, rinomina, sposta e distruggi cpusets
Comandi
Crea un cpuset, usando cpus 1-3, usa il nodo NUMA 1 e chiamalo "my_cpuset1"
$ cset set --cpu=1-3 --mem=1 --set=my_cpuset1
Cambia "my_cpuset1" per usare solo cpus 1 e 3
$ cset set --cpu=1,3 --mem=1 --set=my_cpuset1
Distruggi un cpuset
$ cset set --destroy --set=my_cpuset1
Rinomina un cpuset esistente
$ cset set --set=my_cpuset1 --newname=your_cpuset1
Crea un cpuset gerarchico
$ cset set --cpu=3 --mem=1 --set=my_cpuset1/my_subset1
Elenca cpusets esistenti (profondità del livello 1)
$ cset set --list
Elenca il cpuset esistente e i suoi figli
$ cset set --list --set=my_cpuset1
Elenca tutti i cpusets esistenti
$ cset set --list --recurse
Elaborazione
Gestisci thread e processi
Comandi
Elenca le attività in esecuzione in un cpuset
$ cset proc --list --set=my_cpuset1 --verbose
Esegue un'attività in un cpuset
$ cset proc --set=my_cpuset1 --exec myApp -- --arg1 --arg2
Spostare un'attività
$ cset proc --toset=my_cpuset1 --move --pid 1234
$ cset proc --toset=my_cpuset1 --move --pid 1234,1236
$ cset proc --toset=my_cpuset1 --move --pid 1238-1340
Spostare un'attività e tutti i suoi fratelli
$ cset proc --move --toset=my_cpuset1 --pid 1234 --threads
Sposta tutte le attività da un cpuset all'altro
$ cset proc --move --fromset=my_cpuset1 --toset=system
Sposta i thread del kernel sbloccati in un cpuset
$ cset proc --kthread --fromset=root --toset=system
Sposta forzatamente i thread del kernel (inclusi quelli che sono collegati a una cpu specifica) in un cpuset (nota:questo potrebbe avere conseguenze disastrose per il sistema - assicurati di sapere cosa stai facendo)
$ cset proc --kthread --fromset=root --toset=system --force
Esempio di gerarchia
Possiamo usare cpusets gerarchici per creare raggruppamenti con priorità
- Crea un
system
cpuset con 1 cpu (0) - Crea un
prio_low
cpuset con 1 cpu (1) - Crea un
prio_met
cpuset con 2 cpu (1-2) - Crea un
prio_high
cpuset con 3 cpu (1-3) - Crea un
prio_all
cpuset con tutte e 4 le cpu (0-3) (si noti che è uguale a root; è considerata una buona pratica mantenere una separazione da root)
Per ottenere quanto sopra, crea prio_all, quindi crea il sottoinsieme prio_high sotto prio_all, ecc
$ cset set --cpu=0 --set=system
$ cset set --cpu=0-3 --set=prio_all
$ cset set --cpu=1-3 --set=/prio_all/prio_high
$ cset set --cpu=1-2 --set=/prio_all/prio_high/prio_med
$ cset set --cpu=1 --set=/prio_all/prio_high/prio_med/prio_low
Ci sono altri due modi in cui posso pensare di farlo (anche se non così elegante come cset, che non sembra avere un fantastico livello di supporto da parte di Redhat):
1) Taskset tutto incluso PID 1 - bello e facile (ma, presumibilmente - non ho mai visto alcun problema da solo - potrebbe causare inefficienze nello scheduler). Lo script seguente (che deve essere eseguito come root) esegue taskset su tutti i processi in esecuzione, incluso init (pid 1); questo bloccherà tutti i processi in esecuzione su uno o più 'nunk core' e, bloccando anche init, assicurerà che tutti i processi futuri vengano avviati anche nell'elenco dei 'junk core':
#!/bin/bash
if [[ -z $1 ]]; then
printf "Usage: %s '<csv list of cores to set as junk in double quotes>'", $0
exit -1;
fi
for i in `ps -eLfad |awk '{ print $4 } '|grep -v PID | xargs echo `; do
taskset -pc $1 $i;
done
2) usa il parametro del kernel isolcpus (ecco la documentazione da https://www.kernel.org/doc/Documentation/kernel-parameters.txt):
isolcpus= [KNL,SMP] Isolate CPUs from the general scheduler.
Format:
<cpu number>,...,<cpu number>
or
<cpu number>-<cpu number>
(must be a positive range in ascending order)
or a mixture
<cpu number>,...,<cpu number>-<cpu number>
This option can be used to specify one or more CPUs
to isolate from the general SMP balancing and scheduling
algorithms. You can move a process onto or off an
"isolated" CPU via the CPU affinity syscalls or cpuset.
<cpu number> begins at 0 and the maximum value is
"number of CPUs in system - 1".
This option is the preferred way to isolate CPUs. The
alternative -- manually setting the CPU mask of all
tasks in the system -- can cause problems and
suboptimal load balancer performance.
Ho usato questi due più i meccanismi cset per diversi progetti (per inciso, scusate la palese autopromozione :-)), ho appena depositato un brevetto per uno strumento chiamato Pontus Vision ThreadManager che fornisce strategie di pinning ottimali per qualsiasi data piattaforma x86 a qualsiasi dato carico di lavoro software; dopo averlo testato presso il sito di un cliente, ho ottenuto ottimi risultati (riduzione del 270% delle latenze di picco), quindi vale la pena eseguire il pinning e l'isolamento della CPU.