Estimate context switch overhead and its impact on effective CPU throughput.
Every context switch costs real CPU time — saving and restoring register state, and often invalidating CPU caches and the TLB, which causes additional indirect slowdown beyond the switch itself. Multiplying the observed switch rate (the 'cs' column from vmstat) by a typical per-switch cost gives the total time per second spent switching; dividing that by the total CPU time available across all cores (1,000,000 microseconds per core per second) yields the percentage of raw CPU capacity consumed purely by switching overhead rather than doing useful work. A high rate of context switching, often caused by excessive thread counts, lock contention, or overly fine-grained I/O, can meaningfully erode throughput even when 'CPU usage' as reported by top looks moderate.
Context switch overhead percentage
overhead% = (switches_per_sec × cost_per_switch_us) / (cores × 1,000,000) × 100
There is no universal 'normal' number since it scales with core count and workload type, but a well-behaved multi-core server commonly sees anywhere from a few thousand to tens of thousands of switches per second; rates climbing into the hundreds of thousands or millions per second, especially per core, usually indicate a specific problem like excessive thread contention.
Common causes include far more runnable threads than available cores causing constant preemption, heavy lock contention forcing threads to block and wake repeatedly, misconfigured thread pools that are much larger than the workload needs, and interrupt-heavy I/O patterns (many small network packets or disk operations) that each trigger scheduling activity.
Right-size thread and worker pool counts closer to the actual core count for CPU-bound work, reduce lock contention through finer-grained or lock-free data structures, batch I/O operations to reduce interrupt frequency, and consider CPU affinity (taskset) to keep related threads on the same core to preserve cache locality.