taskset: Configurando Afinidade de CPU no Linux
O Que Você Vai Aprender
- Como fixar um processo em núcleos de CPU específicos com
taskset - A diferença entre fixação no início (
-c) e reatribuição de um processo em execução (-p) - Padrões práticos para benchmarking, isolamento de núcleos e NUMA
Resumo Rápido
- Fixar no início ->
taskset -c 0,1 ./program - Fixar um processo em execução ->
taskset -cp 0-3 <PID> - Verificar estado atual ->
taskset -cp <PID> - A forma de lista (
-c) é legível; a máscara hexadecimal serve para automação
Pré-requisitos
tasksetvem com o pacoteutil-linux(pré-instalado na maioria das distros)- Números de núcleos começam em
0. Conte-os comnproc - Alterar um processo em execução requer ser dono do processo (ou
root)
O que é afinidade de CPU?
Conclusão: Afinidade de CPU restringe em quais núcleos de CPU um processo ou thread pode executar.
taskseté o comando para visualizar e alterar essa configuração.
Por padrão, o escalonador do Linux pode mover um processo para qualquer núcleo ocioso. Configurar afinidade de CPU significa que o processo só pode executar nos núcleos que você especificar.
As principais razões para fixar são:
- Localidade de cache: evitar invalidação de cache L1/L2 causada por migração de núcleo
- Isolamento de núcleo: dar a um processo sensível a latência um núcleo dedicado, livre de interferência
- Benchmarks reprodutíveis: executar nos mesmos núcleos sempre para reduzir ruído nas medições
Afinidade especifica um conjunto de núcleos permitidos. Restrinja a um núcleo para fixação rigida, ou permita vários e deixe o escalonador escolher dentro desse conjunto.
Verificar contagem e numeração de núcleos
Conclusão: Antes de decidir onde fixar, confirme a contagem de núcleos disponíveis com
nproc. Números de núcleos começam em0.
$ nproc
8
Se imprimir 8, números de núcleos válidos são 0-7. Especificar um núcleo inexistente como taskset -c 8 ... retorna um erro.
Use lscpu quando também precisar do layout físico/lógico.
$ lscpu
Fixar núcleos no início (-c)
Conclusão: Para fixar ao iniciar um comando, use
taskset -c <lista-nucleos> <comando>. A forma de lista aceita0,2(individual) e0-3(intervalo).
A forma básica: iniciar um novo processo fixado em núcleos específicos desde o início.
# Iniciar programa apenas nos nucleos 0 e 1 $ taskset -c 0,1 ./program # Iniciar no intervalo de nucleos 0 a 3 $ taskset -c 0-3 ./program # Fixar rigidamente em um unico nucleo (nucleo 2) $ taskset -c 2 ./program
-c (--cpu-list) permite listar números de núcleos diretamente, facilitando a leitura. Use , para núcleos individuais, - para intervalos, e combine ambos (por exemplo 0,2,4-7).
Passe opções ao comando iniciado adicionando-as normalmente.
taskset -c 0,1 stress-ng --cpu 2 funciona sem necessidade de separador --.
Visualizar e alterar um processo em execução (-p)
Conclusão: Para um processo já em execução, use
-p(--pid):taskset -cp <PID>para verificar,taskset -cp <lista-nucleos> <PID>para alterar.
Verificar a afinidade atual
$ taskset -cp 1234
pid 1234's current affinity list: 0-7
0-7 significa "pode executar em todos os núcleos" (o padrão). Com -c você obtém a forma de lista; sem ele, uma máscara hexadecimal.
Reatribuir um processo em execução
# Reatribuir PID 1234 para nucleos 0 e 1 $ taskset -cp 0,1 1234
pid 1234's current affinity list: 0-7 pid 1234's new affinity list: 0,1
Encontre o PID com ps ou pgrep.
$ pgrep -f program
Atenção a ordem dos argumentos
No modo -p, a lista de núcleos vem primeiro, o PID depois: taskset -cp 0,1 1234, não taskset -cp 1234 0,1. Invertendo, taskset trata o PID como máscara e falha.
Máscara hexadecimal vs forma de lista
Conclusão: Com
-cvocê especifica uma lista de núcleos; sem ele, uma máscara hexadecimal. Na máscara, cada bit mapeia um núcleo (bit 0 = núcleo 0).
Nativamente, taskset especifica núcleos como uma máscara hexadecimal. -c é a opção que troca isso por uma lista legível.
| Núcleos alvo | Forma de lista (-c) | Máscara hex |
|---|---|---|
| Núcleo 0 | 0 |
0x1 |
| Núcleos 0,1 | 0,1 |
0x3 |
| Apenas nucl 1 | 1 |
0x2 |
| Núcleos 0-3 | 0-3 |
0xf |
| Apenas nucl 3 | 3 |
0x8 |
A máscara é mais fácil de ler em binário. O bit menos significativo (mais à direita) é o núcleo 0. 0x3 é 0b0011 (núcleos 0 e 1); 0x8 é 0b1000 (núcleo 3).
# Iniciar com mascara (nucleos 0,1 = 0x3) $ taskset 0x3 ./program # Verificar com mascara (sem -c) $ taskset -p 1234
pid 1234's current affinity mask: ff
Para comandos digitados manualmente, a forma de lista (-c) é mais segura. Um único dígito hexadecimal errado aponta para um núcleo diferente. Recorra à máscara apenas quando um script a gera.
Aplicar a todas as threads (-a)
Conclusão: Para fixar todas as threads de um processo multithread, adicione
-a(--all-tasks). Sem ele, apenas a thread principal e afetada.
Ao operar em um processo em execução com -p, por padrão a afinidade se aplica apenas ao PID dado (a thread principal) e não se propaga para threads filhas existentes. Use -a para fixar todas as threads do processo de uma vez.
# Fixar todas as threads do PID 1234 nos nucleos 0-3 $ taskset -acp 0-3 1234
Mesmo com -a, threads criadas após a mudança herdam a afinidade do processo. -a se aplica a threads existentes; threads futuras herdam de qualquer forma. Não confunda os dois.
Casos de uso reais
Conclusão: Os casos clássicos são benchmarks reprodutíveis, isolamento de processos sensíveis a latência e manter acesso a memória local em NUMA.
Tornar benchmarks reprodutíveis
Medir nos mesmos núcleos toda vez remove a variância de cache-miss causada por migração de núcleo.
$ taskset -c 2,3 ./benchmark
Isolar processos sensíveis a latência
Combine com o parâmetro de boot do kernel isolcpus, que remove núcleos do escalonador do SO, e então coloque apenas seu processo alvo neles com taskset.
Manter memória local em NUMA
Em sistemas NUMA, fixar em núcleos no mesmo nó que a memória evita acesso remoto a memória. Quando também precisar controlar alocação de memória, numactl é mais adequado (taskset só lida com posicionamento de CPU).
A armadilha do excesso de fixação
Fixe de forma muito agressiva e um processo não poderá usar outros núcleos ociosos, o que pode torná-lo mais lento. Fixe apenas após medir e confirmar o benefício. Não fixe cegamente.
Erros comuns e soluções
Conclusão: A maioria envolve um número de núcleo inexistente, permissões insuficientes ou ordem errada de argumentos.
sched_setaffinity: Invalid argument
Você especificou um número de núcleo que não existe. Verifique o intervalo com nproc.
# Apenas 8 nucleos (0-7) existem mas nucleo 8 foi solicitado -> erro $ taskset -c 8 ./program
Operation not permitted
Você está tentando alterar o processo de outro usuário. Execute como o dono do processo ou use sudo.
$ sudo taskset -cp 0,1 1234
command not found: taskset
util-linux está ausente (por exemplo, um container mínimo). No Debian/Ubuntu, instale:
$ sudo apt install util-linux