7 ms·
There are about 180 registers in the register file already. There are only names for 16 or so registers, the CPU internally does renaming for them. It would be
by exDM69 10y ago
There are about 180 registers in the register file already. There are only names for 16 or so registers, the CPU internally does renaming for them. It would be possible to specify an API that leaves a part of the named registers reserved for kernel, but that wouldn't really help.
When an interrupt or system call happens, all the registers get pushed to the stack. The stack is typically in L1 cache (and subject to various CPU optimizations), so it's really fast to push the 16*64 bit registers to the stack.
System calls, interrupts and context switches are "slow" not because they have trivial overhead like pushing registers. What's really consuming the time is secondary effects like TLB flushes, changes to the page tables, polluting the branch predictor, etc. It takes a very long time for the CPU to "warm up" again after a context switch.
- xxs 10y agoSystem calls are mode switch that's way faster than a context (i.e. process) switch. The latter virtually always has cold caches. I've made the remark because it's fairly common to mistake mode and context switches.
- exDM69 10y agoYes, and the x86-64 has a fast SYSCALL instruction.
- monocasa 10y agoFast being in the thousands of cycles last time I checked.
- the_mitsuhiko 10y agoThe whole syscall maybe but certainly not the method of invoking it.
- deleted 10y ago[deleted]
- joseraul 10y agoit's really fast to push the 16*64 bit registers to the stack Since the CPU has 180 registers (with only 16 names), why don't we need to push all 180 to store context?
- exDM69 10y agoBecause the CPU works "as if" there were only 16.
- Dylan16807 10y agoAll that extra state is there to help overlap instructions on a time scale of nanoseconds. Every instruction has its own name->register mapping. If you're switching to kernel mode or maybe if you miss a branch or for whatever other reason, the CPU consolidates you back down to running one instruction. Once that happens, you only have one name->register mapping and all the registers have their correct values. The hidden state is reduced to nothing and you only have to save the "real" state of those 16.
- cfallin 10y agoTo expand on another answer here -- there are more values in the PRF than there are names because "old" instructions in flight can refer to outdated versions of architectural registers (the names). But a new instruction can only see the latest versions of the architectural registers, so only those 16 actually matter w.r.t. future execution: when we switch back to the task, its new instructions will ony need the 16 live values.
- bogomipz 10y agoCan you elaborate on both there being 180 registers and the CPU does renaming of them? Surely the RAX register in an X86_64 CPU is always the same physical location no?
- ikeyany 10y agoI am not who you responded to, but: the registers are always in the same physical location, but internally, they are virtually renamed for efficient reuse and to avoid resource contention. If the CPU knows the stream of assembly instructions to be executed, it can abstract away actual register names and show a larger number of registers than what's physically available.
- Tuna-Fish 10y ago> Surely the RAX register in an X86_64 CPU is always the same physical location no? No, it is not. Modern CPUs all use Physical Register Files or PRFs for implementing OoO. The way they work is that there is one backing register file of ~150-200 registers, and a naming table in the frontend. Each register file in the backing table can be in one of 3 states -- waiting for data, contains data, or clean. Every time an instruction that writes data to a register is executed, during the register rename stage the renamer picks one register from the clean set, assigns that as the output of the uop and the current value of the logical register, and sets it as waiting for data. That is, let's say you execute: add RAX, RAX and the current value of RAX in the rename table was PRF#1, with PRF#1 carrying data and all other physical registers clean. In the renamer, this would then turn into: add PRF#2, PRF#1, PRF#1 if this instruction was immediately followed by another add, RAX, RAX, it would then turn into: add, PRF#3, PRF#2, PRF2, and after renaming that instruction RAX points to PRF#3. and so on. In PRF machines, architectural registers only exist as pointers into the PRF. The reason for this design is that it makes OoO execution simple, and reduces unnecessary data movement. An instruction is ready to execute once all it's inputs have data in the PRF, and when it executes there is no need to move data into some special architectural register. Registers are reaped from the "haves data" set into the clean set once no instruction or architectural register points at them. Note that multiple architectural registers can point to the same physical register: mov rax, rbx is resolved in the frontend just by pointing rax to the same register as rbx, and there is typically a special register for the value 0 that all common register-clearing operations use.
- Symmetry 10y agoA larger cost would be from the extra bits in the instruction stream it takes to specify the new registers and the resultant extra icache pressure.
- bogomipz 10y agoBut modern CPU TLBs even have context process IDs(CPIDs)now so many times the whole cache doesn't totally need to "warm up" again.