[Lguest] [PATCH RFC/RFB] x86_64, i386: interrupt dispatch changes

Ingo Molnar mingo at elte.hu
Wed Nov 5 01:00:30 EST 2008


* Alexander van Heukelum <heukelum at fastmail.fm> wrote:

> On Tue, 4 Nov 2008 13:42:42 +0100, "Ingo Molnar" <mingo at elte.hu> said:
> > 
> > * Alexander van Heukelum <heukelum at mailshack.com> wrote:
> > 
> > > Hi all,
> > > 
> > > An x86 processor handles an interrupt (from an external source, 
> > > software generated or due to an exception), depending on the 
> > > contents if the IDT. Normally the IDT contains mostly interrupt 
> > > gates. Linux points each interrupt gate to a unique function. Some 
> > > are specific to some task (handling traps, IPI's, ...), the others 
> > > are stubs that push the interrupt number to the stack and jump to 
> > > 'common_interrupt'.
> > > 
> > > This patch removes the need for the stubs.
> > 
> > hm, the cost would be this new code:
> > 
> > > +.p2align
> > > +ENTRY(maininterrupt)
> > >  	RING0_INT_FRAME
> > > -vector=0
> > > -.rept NR_VECTORS
> > > -	ALIGN
> > > - .if vector
> > > -	CFI_ADJUST_CFA_OFFSET -4
> > > - .endif
> > > -1:	pushl $~(vector)
> > > -	CFI_ADJUST_CFA_OFFSET 4
> > > +	push %eax
> > > +	push %eax
> > > +	mov %cs,%eax
> > > +	shr $3,%eax
> > > +	and $0xff,%eax
> > > +	not %eax
> > > +	mov %eax,4(%esp)
> > > +	pop %eax
> > >  	jmp common_interrupt
> > 
> > .. which we were able to avoid before. A couple of segment register 
> > accesses, shifts, etc to calculate the vector - each of which can be 
> > quite costly (especially the segment register access - this is a 
> > relatively rare instruction pattern).
> 
> The way it is written now is just so I did not have to change 
> common_interrupt (to keep changes small). All those accesses so 
> close together will cost some cycles, but much can be avoided if it 
> is integrated. If the precise content of the stack can be changed, 
> this could be as simple as "push %cs". Even that can be delayed, 
> because the content of the cs register will still be there.
> 
> Note that the specialized interrupts (including page fault, etc.) 
> will not go via this path. As far as I understand now, it is only 
> the interrupts from external devices that normally go via 
> common_interrupt. There I think the overhead is really tiny compared 
> to the rest of the handling of the interrupt.

no complaints from me about the cleanup/simplification effect - that's 
really great. To make the reasoning all iron-clad please post timings 
of "push %cs" costs measured via RDTSC or so - can be done in 
user-space as well. (you can simulate the entry+exit sequence in 
user-space as well and prove that the overhead is near zero.) In the 
end it could all even be faster (perhaps), besides smaller.

( another advantage is that the 6 bytes GDT descriptor is more 
  compressed and hence uses up less L1/L2 cache footprint than the 
  larger (~7 byte) trampolines we have at the moment. )

plus it's possible to observe the typical cost of irqs from user-space 
as well: run a task on a single CPU and save away all the RDTSC deltas 
that are larger than ~10 cycles - these will be the IRQ entry costs. 
Print out these deltas after 60 seconds of runtime (or something like 
that), and look at the histogram.

	Ingo



More information about the Lguest mailing list