Context Switch on Linux
This post collects some info regarding thread-level context switch and how to estimate/measure its cost.
In computing, a context switch is the process of storing the state of a process or thread, so that it can be restored and resume execution at a later point, and then restoring a different, previously saved, state.
In C/C++, one can use
getrusage to retrieve #context switches a process/thread has gone through. The two metrics on
context switches are:
- voluntary switch: the current thread becomes blocked from calling some special methods, e.g.
- involuntary switch: the kernel decides that the current thread should be paused, in favor of another thread, possibly because the current thread has used up its CPU quota or another thread has higher priority
Some works involved inside a context switch:
- user to kernel mode transition
- save CPU registers (e.g. stack pointer) for current thread
- if the current thread becomes blocked (e.g. in voluntary switch), update the thread state and remove it from the runnable threads queue
- load CPU registers for next thread
(Here I am focusing only on things inside a single process, ignoring context switches between processes.)
The following is a simple ping-pong example using mutex + condition variable.
$ clang++ -O -std=c++20 context_switch.cpp && taskset -c 0 ./a.out
As a crude approximation, one can assume both kinds of switches have the same cost and each context-switch takes
microseconds. Additionally, the elapsed time includes also use-mode operations (for-loop, accessing
flag, etc), so
this is an overestimate.
One can use
perf to get a quick glance at the user/kernel-mode distribution, reported by
$ clang++ -O -std=c++20 context_switch.cpp && perf stat taskset -c 0 ./a.out
We can see that
user time is ~10% of
sys time. Therefore, the overestimate is roughly off by ~10%, 0.1 microseconds.
Note that “Elapsed time” has increased to 132ms, so the overhead of
perf could have skewed those statistics a bit.
Nonetheless, one can use 1 microsecond as the latency of context switch for a back-of-the-envelope calculation.
Clang : 14