What a system call is and costs
“What is a system call, what happens on the CPU when you make one, and what does it cost? When does the number of syscalls become the bottleneck?”
What this tests
- The user/kernel boundary and why it exists
- The mechanism: syscall number, trap instruction, mode switch, argument validation, return
- Cost: a mode switch is not a context switch; mitigations changed the numbers
- Recognising syscall storms and the batching fixes
Answers by level
Read the beginner answer first and notice what is missing.
User code runs with the CPU in a restricted mode: it cannot touch device registers, other processes’ memory or the kernel’s, and it cannot change page tables. Everything that needs those is done by the kernel on the program’s behalf, and the system call is the only door: a controlled entry point where the kernel runs its own code with your arguments (User Mode vs Kernel Mode).
Mechanically (label: Linux x86-64): the libc wrapper puts the syscall number in a register and the arguments in others, executes the syscall instruction, and the CPU switches to kernel mode and jumps to the kernel’s entry point. The kernel saves user registers, dispatches on the number, validates and copies arguments from user memory (it must never trust a user pointer), does the work, and returns with sysret — back in user mode, with the result in a register and errno set by the wrapper on failure (System Calls).
That round trip is a mode switch, not a context switch — the same thread continues, no address space changes, no scheduler runs. A trivial call like getpid costs on the order of 100–300 ns; with Spectre/Meltdown mitigations (KPTI) it can be 1 µs or more. The *work* usually dominates: a read() that must go to disk blocks for 100 µs; a write() to a socket copies bytes into the kernel’s buffer. Some calls avoid the kernel entirely through the vDSO — clock_gettime and gettimeofday read a shared page.
Syscalls become the bottleneck when the work per call is tiny: writing a log line with one write() per byte, reading a file 1 byte at a time, stat-ing thousands of paths per request. strace -c or perf trace counts them; a process with high sys time and millions of calls per second is paying the entry cost repeatedly. The fixes are all batching: buffered I/O (stdio, BufferedReader), writev/readv, sendfile, larger buffers, and on Linux io_uring, which submits many operations through a shared ring with one or zero syscalls (Everything Is I/O).
Green flags · Red flags
- Explains why the boundary exists (protection) before how it works
- Describes number, trap instruction, mode switch, argument validation
- Says a syscall is a mode switch, not a context switch, with numbers
- Names strace -c / perf trace and batching fixes
- Knows vDSO or io_uring
- Thinks a syscall is a function call into a library
- Calls it a context switch
- Cannot name any cost or any tool
Follow-up questions
clock_gettime so cheap on Linux?write at 2M calls/s. Fix?Scenario
sys. Explain what the kernel is doing and what change would restore the CPU without losing the logs.