core24 min studyLesson 134 in Engineering

What must survive a task switch

Follow a thread across descheduling and resumption, separating architectural state, address spaces, and cache effects.

On this page

What you’ll understand

  • Distinguish a privilege transition from a scheduler context switch.
  • Identify the state needed to resume a suspended thread correctly.
  • Build an overhead budget without treating one benchmark as a universal switching cost.

A context switch is a transfer of execution from one schedulable task to another while preserving the ability to resume both correctly. Imagine pausing a calculation at an instruction boundary where switching is permitted, lending the CPU to another calculation, and later continuing without changing the first calculation's answer. The operating system must preserve the relevant execution state and install the next task's environment. Understanding that contract explains why a fast system call can involve no task switch, why two threads sharing an address space still need scheduling, and why switching cost is more than register copying.

The continuation that must survive

A thread's continuation includes an instruction location, stack state, register values, and the kernel bookkeeping that identifies its execution context. The exact division between an entry frame, a kernel stack, and explicitly saved switch state depends on architecture and the path into the scheduler. Do not imagine that one portable function blindly copies every register on every switch. Some values have already been saved by an interrupt or system-call entry sequence; other state is preserved according to architecture-specific conventions. Correctness means the resumed task observes its promised machine state, rather than prescribing one universal implementation of that promise.

The stack deserves special attention because suspended kernel calls may retain local variables and return addresses. Suppose a thread waits for a socket to become readable. Its execution has entered the kernel, determined that progress requires an external event, and blocked. Another task can now use the processor. When the socket event wakes the first thread, it becomes runnable; it does not necessarily resume immediately. Eventually the scheduler restores the continuation that lets its waiting operation recheck conditions and proceed. A wakeup therefore changes eligibility, while dispatch actually transfers execution. Confusing these events makes latency traces difficult to interpret.

Tresponse=Tblocked+Trunnable+TrunningT_{\mathrm{response}}=T_{\mathrm{blocked}}+T_{\mathrm{runnable}}+T_{\mathrm{running}}
For a simplified nonoverlapping partition of one thread response interval, wall time in seconds is divided into blocked time, runnable waiting time, and actual running time. Running time includes any charged kernel execution; the accounting convention must be stated.↔ Scroll wide equations horizontally.

Execution state is not the whole machine

A switch between threads in the same process can retain the same address-space mappings while changing stacks and thread-specific state. Switching between different address spaces may require installing different translation context. Translation caches complicate the picture: address-space identifiers can allow entries to coexist, while invalidations remain necessary when mappings change. It is incorrect to claim that every context switch always flushes every cache. Ordinary data caches usually contain reusable contents tagged by physical location, but the incoming workload may displace the outgoing workload's useful data. A resumed task can therefore pay indirect locality costs even when the switch path itself was short.

Floating-point and vector extensions add another layer. Their architectural state can be large, and enabled features differ across CPUs and operating-system configurations. Linux's x86 documentation discusses extended state and dynamically enabled features such as AMX; this is a concrete reason to record hardware and kernel configuration alongside measurements. Separately, entering the kernel may change page-table context for isolation even when the same thread returns immediately. That security transition is not proof that another task ran. Keep three questions separate: did privilege change, did address-space translation context change, and did the identity of the running task change?

Measure a boundary and a consequence

Define the measured boundary before reporting a cost. A ping-pong benchmark between two threads includes synchronization, scheduler decisions, handoff, and possibly cache-line transfer. Dividing total time by the number of handoffs yields a useful benchmark-specific average, not an architecture-independent constant. A production request may instead experience long runnable delay before any actual switch occurs. Record elapsed time, task CPU time, scheduling events, affinity, and competing load where possible. Compare repeated distributions under the same conditions. If a new configuration reduces handoff time but lengthens queueing, the request can still become slower despite a technically faster switching path.

A first-order capacity budget can treat the measured direct cost per switch as constant over a narrowly defined experiment. This lets you ask whether switching consumes a negligible or material fraction of one CPU-second. It cannot predict cache recovery, simultaneous multithreading interference, or long-tail dispatch delay. In the lab, compare two separate fixed-rate capacity assumptions: arrival 2 with service 3, then arrival 2 with service 1. Before each run, press Reset, re-set both desired rates, predict the direction of change from four work units, then press Play or Step. Editing a control pauses but retains elapsed time, so it does not enact an overhead change along the previous trajectory. Each fresh run changes backlog with its own fixed arrival-minus-service rate. It has no tasks, registers, run queues, or context-switch events; use it to inspect capacity sensitivity, then return to scheduler traces to test the real mechanism.

fdirect=rswitch tswitchf_{\mathrm{direct}}=r_{\mathrm{switch}}\,t_{\mathrm{switch}}
For one CPU, switch rate in switches per second multiplied by assumed direct seconds per switch gives a dimensionless CPU-time fraction. This simplified estimate excludes indirect locality penalties and requires consistent event counting.↔ Scroll wide equations horizontally.

Budgeting direct switch overhead

In a fictional single-CPU experiment, a nonoverlapping direct-switch measurement gives 2 microseconds per switch and a workload causes 20,000 switches per second. Assume that measured cost is constant and excludes cache recovery. Estimate the direct CPU-time fraction.

  1. Convert 2 microseconds to 0.000002 seconds per switch.

  2. Multiply 20,000 switches per second by 0.000002 seconds per switch to obtain 0.04 CPU-seconds per wall-clock second.

  3. Express the dimensionless fraction 0.04 as 4%; the remaining 96% is only an accounting remainder, not a guaranteed application throughput.

fdirect=20,000×2×10−6=0.04f_{\mathrm{direct}}=20{,}000\times 2\times10^{-6}=0.04
The switch units cancel, leaving CPU seconds per second.↔ Scroll wide equations horizontally.
The result

Direct switching consumes an estimated 4% of one CPU under these assumptions. Indirect cache costs and queueing are separate measurements.

Explore the model

Interactive lab

Interactive lab · queue

Usable capacity after overhead

Compare separate fixed-rate runs at λ=2, μ=3 and λ=2, μ=1. Each time, press Reset, re-set both rates, predict growth or drainage from four work units, then Play or Step. The second run has its own fresh backlog; editing μ alone retains elapsed time rather than modeling a live capacity reduction. Service is assumed usable capacity, not a context-switch or CPU scheduler simulation.

Usable capacity after overheadFluid backlog starts at 4 and follows max(0, 4 + (λ − μ)t). The separate M/M/1 residence-time formula assumes Poisson arrivals, exponential service and λ < μ. Current readings: Fluid backlog: 4; Net rate · λ − μ: −1 /s; M/M/1 mean residence: 1 s. All parameters are adjustable with the labeled controls below.02.557.51001.534.56Elapsed time · sFluid backlogλ < μ
Fluid backlogCurrent time
Fluid backlog
4
Net rate · λ − μ
−1 /s
M/M/1 mean residence
1 s
t = 0 s

Fluid backlog starts at 4 and follows max(0, 4 + (λ − μ)t). The separate M/M/1 residence-time formula assumes Poisson arrivals, exponential service and λ < μ. Parameter changes pause playback and recompute the model at the current elapsed time. Reset restores both parameters and returns time to zero. Playback starts paused. Adjust either parameter, then choose Play or Step.

Look forSmall capacity reductions can change whether backlog drains. The separate M/M/1 residence-time readout requires its stochastic assumptions and arrival rate below service rate.

Check your understanding

A thread enters a system call and returns to userspace without any other task running on that CPU. Which conclusion is justified?

Try it yourself

A hypothetical one-CPU trace contains 12,000 directly measured switches per second, each costing 3 microseconds under the stated measurement boundary. Estimate the direct fraction and name one missing cost.

Take a moment to make a prediction or work it out on paper. Open a hint when you need one.

Give me a hint

Convert microseconds to seconds, then multiply rate by cost. Consider what the resumed application must reload.

Compare with the solution

The estimate is 12,000 × 0.000003 = 0.036, or 3.6% of one CPU. Cache or translation recovery after resumption is a possible missing indirect cost; runnable waiting time is another distinct latency component.

f=12,000 (3×10−6)=0.036f=12{,}000\,(3\times10^{-6})=0.036
This estimate uses the same constant-cost, one-CPU accounting assumptions as the worked example.↔ Scroll wide equations horizontally.

Take it with you

  • A resumable continuation is architecture-specific state, not merely a process identifier.
  • Kernel entry, address-space changes, and scheduler task switches are different events.
  • Separate direct handoff cost, indirect locality loss, and runnable waiting time when measuring latency.

Read further

Original sources and deeper explanations to follow at your own pace.

Optional progress, saved in this browser when available. Revisit any lesson at any time.

Lesson not marked complete.