Skip to content

Implement per-processor data areas for i386.

Jeremy Fitzhardinge lkml 1 version In review

Get series with b4
b4 am [email protected]

Versions newest first

  1. v1 Latest8 patches 11 repliesIn review

Patches in v1 No applies recorded yet

#Subject and filesSizeRepliesApplied
1/8Use asm-offsets for the offsets of registers into the pt_regs struct, rather than having hard-coded constants.arch/i386/kernel/asm-offsets.c arch/i386/kernel/entry.S+68 -670 replies
2/8Basic definitions for i386-pdaarch/i386/kernel/asm-offsets.c arch/i386/kernel/head.S include/asm-i386/pda.h +1 more+76 -20 replies
3/8Initialize the per-CPU data area.arch/i386/kernel/cpu/common.c arch/i386/kernel/smpboot.c include/asm-i386/processor.h+125 -450 replies
4/8Use %gs as the PDA base-segment in the kernel.arch/i386/kernel/asm-offsets.c arch/i386/kernel/cpu/common.c arch/i386/kernel/entry.S +6 more+91 -570 replies
5/8Fix places where using %gs changes the usermode ABI.arch/i386/kernel/process.c arch/i386/kernel/ptrace.c include/asm-i386/elf.h +1 more+11 -166 replies
6/8Update sys_vm86 to cope with changed pt_regs and %gs usage.arch/i386/kernel/vm86.c include/asm-i386/vm86.h+78 -640 replies
7/8Implement smp_processor_id() with the PDA.arch/i386/kernel/asm-offsets.c arch/i386/kernel/cpu/common.c include/asm-i386/smp.h +1 more+29 -65 replies
8/8Implement "current" with the PDA.arch/i386/kernel/cpu/common.c arch/i386/kernel/smpboot.c include/asm-i386/current.h+23 -100 replies

Reviews trailers per patch

No Reviewed-by, Acked-by or Tested-by trailers for v1 yet.

Read the v1 thread

Cover letter [PATCH 0/8] Implement per-processor data areas for i386.

(Changes since previous post:
- now works
- fixed sys_vm86
- performance measurements)

Implement per-processor data areas for i386.

This patch implements per-processor data areas by using %gs as the base segment of the per-processor memory. This has two principle advantages:

- It allows very simple direct access to per-processor data by effectively using an effective address of the form %gs:offset, where offset is the offset into struct i386_pda. These sequences are faster and smaller than the current mechanism using current_thread_info().

- It also allows per-CPU data to be allocated as each CPU is brought up, rather than statically allocating it based on the maximum number of CPUs which could be brought up. (Though the existing per-cpu mechanism could be changed to do this.)

Performance:

I've done some simple performance tests on an Intel Core Duo running at 1GHz (to emphisize any performance delta). The results for the lmbench null syscall latency test, which should show the most negative effect from this change, show a ~8-9ns decline (.237uS -> .245uS). This corresponds to around 9 CPU cycles, and correlates well with the addition of the push/load/pop %gs into the hot path.

I have not yet measured the effect on other typees of processor or more complex syscalls (though I would expect the push/pop overhead would be drowned by longer times spent in the kernel, and mitigated by actual use of the PDA).

The size improvements on the kernel text are nice as well:

    2889361 -> 2883936 = 5425 bytes saved

Some background for people unfamiliar with x86 segmentation:

This uses the x86 segmentation stuff in a way similar to NPTL's way of implementing Thread-Local Storage. It relies on the fact that each CPU has its own Global Descriptor Table (GDT), which is basically an array of base-length pairs (with some extra stuff). When a segment register is loaded with a descriptor (approximately, an index in the GDT), and you use that segment register for memory access, the address has the base added to it, and the resulting address is used.

In other words, if you imagine the GDT containing an entry:

	Index	Offset
	123:	0xc0211000 (allocated PDA)
and you load %gs with this selector:
	mov $123, %gs
and then use GS later on:
	mov %gs:4, %eax
This has the effect of
	mov 0xc0211004, %eax

and because the GDT is per-CPU, the offset (= 0xc0211000 = memory allocated for this CPU's PDA) can be a CPU-specific value while leaving everything else constant.

This means that something like "current" or "smp_processor_id()" can collapse to a single instruction:
mov %gs:PDA_current, %reg

TODO:
- Modify more things to use the PDA. The more that uses it, the more the cost of the %gs save/restore is amortized. smp_processor_id and current are the obvious first choices, which are implemented in this series.
--