taskset Cheatsheet - CPU Affinity & Core Pinning Guide
taskset answers one question: which CPUs is this process allowed to run on. Three situations call for it. Latency spikes that do not come with high CPU utilisation, often caused by a multi-threaded process migrating across physical cores or touching memory on a remote NUMA node. Benchmark runs where you want to measure the code rather than the scheduler. And shared machines where pinning your workload to idle cores keeps a noisy neighbour from starving it. The mechanism is narrow, it just rewrites the task CPU affinity mask, which is why you can confirm the result at any time by reading Cpus_allowed_list from /proc/<pid>/status or from jobs -l. Pinning is not automatically faster: too few cores cuts parallelism, and pinning only the main thread of a threaded process achieves little, so the sheet lines up list format, hex masks, retargeting running processes, NUMA commands and the isolcpus kernel parameter for comparison.
Typical Use Case
For performance engineers isolating a noisy neighbour. taskset pins a process to a set of logical CPUs, which is the cheapest possible scheduling intervention - no kernel change, no cgroup, instant and reversible on a running PID. This sheet covers reading and writing affinity masks in both list and hexadecimal form, batch-changing every PID of a service, and the important boundary: taskset binds CPUs, not NUMA nodes, and inside a container it only sees the CPUs the cgroup actually granted.
Basic Usage 6
taskset -p <pid>taskset -c -p <pid>taskset -c 0,1 <command>taskset -c 0-3 <command>taskset -p <mask> <pid>taskset -cp 0,1 <pid>CPU Mask & List Format 7
0x000000010x000000030x0000000f-c 0-c 0,2,4-c 0-3,8-11taskset -c 0xff <command>Pin Running Processes 4
taskset -cp 0 $(pgrep nginx)for p in $(pgrep -f app); do taskset -cp 0-3 $p; donetaskset -cp 0-3 <pid>taskset -ap 0-1 <pid>Affinity & System Info 5
cat /proc/<pid>/status | grep Cpus_allowedcat /sys/devices/system/cpu/onlinenproclscpulscpu | grep NUMANUMA Optimization 5
numactl --hardwarenumactl -c 0 -m 0 ./appnumactl --cpunodebind=0 --membind=0 ./appnumastat -p <pid>numactl --interleave=all ./appPractical Scenarios 5
taskset -c 0-3 ./cpu_intensive_apptaskset -c 4-7 ./realtime_apptaskset -c 0 nginxtaskset -c 1,2 mysqlisolcpus=2,3Related Tools 5
htoptop -1mpstat -P ALL 1pidstat -t -p <pid> 1cset shield -c 4-7Parameter matrix
| Parameter | Effect | Example |
|---|---|---|
-c <list> | CPU-list form of the affinity mask; readable, accepts 0,1, 0-3 and mixed ranges | taskset -c 0-3 <command> |
-p <mask> <pid> | Read or rewrite the affinity of a running process, no restart needed | taskset -cp 0,1 <pid> |
0x0000000f | Hexadecimal mask form, equivalent to CPUs 0-3; taskset parses masks by default | taskset -c 0xff <command> |
-a | Apply to every thread of the process, not just the main one - required for threaded services | taskset -ap 0-1 <pid> |
Cpus_allowed_list | The observable field in /proc/<pid>/status that confirms the binding took effect | cat /proc/<pid>/status | grep Cpus_allowed |
Common pitfalls
Symptomtaskset -cp 0,1 <pid> fails with "Invalid argument", or binding an out-of-range CPU fails outright.
CauseInside a container you see host CPU numbers but the real allowance comes from the cgroup; tasks outside it are refused by the kernel.
FixCheck cat /sys/devices/system/cpu/online and cat /proc/<pid>/status | grep Cpus_allowed first, then pick from that set.
SymptomAfter binding a threaded process, htop still shows threads on other cores.
CauseWithout -a only the main thread (the thread-group leader) is affected.
FixUse taskset -ap 0-1 <pid> to cover every thread.
SymptomPinning made latency worse because the process keeps reading memory across nodes.
Causetaskset pins CPUs but not memory; the process runs on node 1 cores while touching node 0 memory.
FixUse numactl -c 0 -m 0 ./app, or the full form numactl --cpunodebind=0 --membind=0 ./app.
Symptomtaskset -c 0-3 <command> refuses to start, saying the affinity set must contain an online CPU.
CauseThe range contains offline CPUs, or online CPU numbers are not contiguous from 0.
FixRead the real set with nproc and cat /sys/devices/system/cpu/online, then re-pick the values.
Troubleshooting
1Confirm the binding actually took effect
cat /proc/<pid>/status | grep Cpus_allowedCpus_allowed is the mask form, Cpus_allowed_list the list form; both must match taskset -p output.
2Change affinity for every process of a service
for p in $(pgrep -f app); do taskset -cp 0-3 $p; donepgrep -f matches the command line; without -a only the main thread moves, so use taskset -ap 0-3 $p.
3Survey CPU and NUMA topology before pinning
nproc && lscpu | grep NUMA && numactl --hardwareYou need the real online CPU set and node count, otherwise the mask is illegal.
4Watch per-core usage after pinning
mpstat -P ALL 1Requires sysstat. Work should spread only across the intended cores; pidstat -t -p <pid> 1 shows thread-level detail.
Command Examples
Confine a CPU-bound application to CPUs 0-3
taskset -c 0-3 ./cpu_intensive_appThe application can never be scheduled outside CPUs 0-3, which effectively isolates it from other workloads on the box.
Pin MySQL to two discrete cores
taskset -c 1,2 mysqlDiscrete entries and ranges can be mixed: write 0-3,8-11 when you want both styles in one mask.
Batch-pin every matching process to CPUs 0-3
for p in $(pgrep -f app); do taskset -cp 0-3 $p; doneWhen one parent spawns several children this changes each of them; pgrep -f matches the whole command line, so check that you are not sweeping in unrelated processes.
Verify the CPU mask a process really ended up with
cat /proc/12345/status | grep Cpus_allowedThe Cpus_allowed_list line is the kernel-side truth, and it settles arguments better than the command you remember typing.
Common Pitfalls
- Record the original mask with taskset -p before you change anything, and restore exactly that value if the change turns out to be bad.
- Always add -a for multithreaded services; pinning only the main thread leaves the remaining threads free to roam every core, so nothing is actually isolated.
- Inside a container taskset can only bind CPUs the cgroup already granted you, and naming a CPU outside that range fails outright with Invalid argument.
- An affinity set must contain at least one online CPU; if every CPU you name is offline, taskset refuses to run.
- Overly tight pinning can backfire because cross-core memory traffic eats the gains, and on NUMA machines use numactl when CPU and memory must share a node.
Tips
- CPU affinity reduces cache misses and boosts performance, but over-pinning can cause uneven load.
- Real-time apps (HFT, A/V processing) suit isolated cores.
- Under NUMA, binding CPU and memory nodes cuts cross-node access latency.
- taskset -c's CPU-list format is more readable than hex masks; use it daily.
- The isolcpus kernel param isolates CPUs at boot — more thorough than taskset but needs a reboot.
- Multi-threaded processes need -a to set all threads, or only the main thread is affected.
FAQ
Does taskset bind CPU cores or NUMA nodes?
It binds a set of logical CPUs. With SMT enabled one physical core shows up as two logical CPUs, and logical CPUs are what taskset operates on. Pinning both CPU and memory to the same NUMA node is a different job entirely: that is numactl territory, for example numactl --cpunodebind=0 --membind=0, and you should read the topology with numactl --hardware before deciding.
What is the difference between taskset -c 0,1 command and taskset -cp 0,1 pid?
The first pins at launch: the process is confined to CPU 0 and 1 for as long as it lives, and the mask disappears when it exits. The second retargets an already running process: hand it an existing PID and the affinity changes immediately, no restart, while the process keeps running. Before you change it, run taskset -p on that PID to record the original mask so you can roll back.
I pinned a multithreaded service, so why does htop still show threads on other CPUs?
Without -a only the main thread gets the new mask; every other thread keeps the affinity it already had. To cover the whole process use taskset -ap 0-1 pid, where -a applies the change to every thread of that PID. To confirm what a thread really has, read Cpus_allowed under /proc/<pid>/status.
Which CPUs does the hex mask 0x0000000f actually cover?
Count from the low bit: bits 0 through 3 are set, so it means CPU 0, 1, 2 and 3, which is exactly the list form 0-3. Along the same logic 0x00000001 is CPU 0 alone, 0x00000003 is CPU 0 and 1, and 0xff covers CPU 0-7. Since masks have to be decoded by hand, the -c list format is the better everyday choice.
How do I confirm an affinity change actually took effect?
Read cat /proc/<pid>/status and grep for Cpus_allowed; the Cpus_allowed_list line is the set of CPUs the process is genuinely allowed on, and it has to match what you asked for. For the wider picture, htop shows per-core usage and mpstat -P ALL 1 shows per-core load in real time, so whether the cores actually separated is the most direct verdict.
Official References
Each command links to its official documentation below, so you can verify the latest usage and read deeper.
Maintained by LaoHand
Publicly updated on Jul 21, 2026, continuously proofread against official docs.
Contact Us
Wrong command or description? Send us corrections, business inquiries or product feedback by email.
Contact Us