DragonflyBSD fast syscall support and x86 improvements
Matthew Dillon
dillon at apollo.backplane.com
Fri Jun 23 12:38:17 PDT 2006
:Hi all,
:first of all, I have to say I'm not too much familiar with
:DragonFlyBSD kernel (so I have no idea if this is completely new for
:the project), but I contributed some for FreeBSD kernel and I'm rather
:experienced with IA32.
:
:What I would like to work on are some x86 'improvements' to DFLY
:kernel. For improvements I mean adding different versions of some
:critical functions for different versions of the CPU (i.e.: in P4 you
:could just implement an atomic memory barrier using mov + *fence
:instructions against using xchg or stubs like these).
:
:First of all, a good discussion point is about optimizations
:activation: do you prefer compile-times stubs or run-time patching?
:Actually, I'm planning to improve and add a run-time patching concept
:inherited from Linux to FreeBSD, and maybe you would be interested in
:its port. Run-time patching is very useful, but on the other side it
:faces a lot of problems (inlined functions can't fit and it deals with
:dimensions problems), if we don't want to loose performance matters.
:Compile time stubs are simpler and possibly quicker but the kernel
:needs re-compilation in order to get benefits, that is not so nice.
:So, some feedbacks about this is very appreciated.
Well, insofar as preformance goes I only worry about 'modern' cpus,
meaning relatively recent cpus (last few years). So, for example,
I would consider trying to optimize for a P4 a waste of time.
I do have some concerns re: getting reasonably equitable performance
across cpu vendors. My main experience is with AMD parts, and
generally speaking all synchronizing instructions cost about the same.
An SFENCE operation, for example, costs exactly the same as a locked
xchgl when the cpu has data it needs to flush (which is always if you
are trying to integrate a memory barrier with a locking mechanism of
some sort).
Procedural patching has some merit, especially since both the CALL and
RET can be subsumed by the branch prediction cache, but my preference
is to inline a reasonably optimal operation and have it conditionally
call a procedure if it 'fails'. For example, take a look at our
spinlock functions in sys/spinlock2.h.
Procedural patching makes more sense for more complex procedures such
as bcopy(), and we use it for that.
:Once that we have choicen a method in order to apply changes, the
:first thing I would like to add (BTW, I don't know if it exists
:alredy) is sysenter/sysexit support replacing interrupt 0x80 (I have
:an item in the FreeBSD list for volounteers about it, since I think I
:would like to add it there too)
Hmm. Well, I'm not keen on the idea, unless a significant savings
in time -- at least 50ns, can be demonstrated. Even with
SYSENTER/SYSEXIT we still have to save most registers.
However, I do think this might be viable if combined with argument
registerization as you describe below. I am *NOT* keen on using
FP registers for this, though. If a system call has too many arguments
to fit into normal registers I'd rather just leave them on the stack.
:and possibly evaluating the usage of
:FPU/MMX/XMM registers in order to gather syscalls parameters.
:Feedbacks about it are very appreciated too. I have other ongoing
:projects we can discuss later, but they are very architecture
:dependant so, since maybe they can fit in FreeBSD, they cannot in
:DragonflyBSD.
:
:Thanks for your time,
:Attilio
I think some degree of registerization might be beneficial, but with
the provisio that all we are doing here is passing the system call
arguments themselves in registers, not attempting to reimplement
the libc functions as registerized calls.
So for example the libc 'read' system call would look something like
this:
read: (libc)
pushl %ebx
movl 8(%esp),%edx
movl 12(%esp),%ecx
movl 16(%esp),%ebx
movl $SYS_read,%eax
sysenter/syscall/whatever
addl $16,%esp
ret
The kernel entry point would save the register set as per normal,
using 'pushal', but instead of then doing a copyin() of the arguments
the kernel syscall2() function would simply map them from the pushed
registers.
However, I have a provisio on doing things this way.... the system
call arguments MUST match existing syscall argument structures. That
is, whatever order 'pushal' pushes registers onto the stack, mapping
them into memory, must match the argument order that we already
specify in our system call argument structure for any given system
call.
The exception code would almost certainly also have to reserve space
on the stack for the rest of the system call structure... see
sys/sysproto.h for an example. The 'header' (struct sysmsg) needs
space reserved so the exception code can provide a pointer to the
'*_args' structure directly to syscall2() (or whatever).
-Matt
Matthew Dillon
<dillon at xxxxxxxxxxxxx>
More information about the Kernel
mailing list