goshen@ccicpg.UUCP (Shmuel Goshen) (08/25/88)
I have been looking recently at ways to reduce the system call overhead. One approach would be to move *simple* system calls form the kernel out to the user. This is quite limited since many kernel data structures cannot be accessed from User Mode. The second approach would be to introduce a simple and quick interface for "light weight" system calls (like getpid(), umask() etc'), which perform simple tasks and never sleep. This quick interface will run in kernel mode, thus enabling access to kernel data structures, but will not include operations like saving the context (setjmp), signal delivery and allowing rescheduling upon return from the call. The net effect is almost as having the system call run in user mode. I am looking for opinions on these approaches. My main concern is side effects caused by eliminating signal delivery and rescheduling until a "software forced exception" or a *heavy* system call is executed by the process. (Consider, for example, a program running getpid() calls in a loop). -- Shmuel Goshen (714) 951-8053 Computer Consoles Inc. (714) 458-7282 Irvine, CA. {allegra!hplabs!felix,seismo!rlgvax}!ccicpg!goshen
vixie@decwrl.dec.com (Paul Vixie) (08/26/88)
In article <21606@ccicpg.UUCP> goshen@ccicpg.UUCP (Shmuel Goshen) writes:
# [...] This quick interface will run
# in kernel mode, thus enabling access to kernel data structures, but
# will not include operations like saving the context (setjmp), signal
# delivery and allowing rescheduling upon return from the call.
# The net effect is almost as having the system call run in user mode.
It depends on the CPU and MMU. If you're changing to supervisor mode,
chances are you're switching memory maps / page tables, which on many
CPU/MMU combos means: kiss your cache goodbye (sorry :-)).
--
Paul Vixie
Digital Equipment Corporation Work: vixie@dec.com Play: paul@vixie.UUCP
Western Research Laboratory uunet!decwrl!vixie uunet!vixie!paul
Palo Alto, California, USA +1 415 853 6600 +1 415 864 7013
jfh@rpp386.UUCP (The Beach Bum) (08/26/88)
In article <21606@ccicpg.UUCP> goshen@ccicpg.UUCP (Shmuel Goshen) writes: [ thoughts on lightening the system overhead of system calls ] >I am looking for opinions on these approaches. My main concern is side >effects caused by eliminating signal delivery and rescheduling until >a "software forced exception" or a *heavy* system call is executed >by the process. (Consider, for example, a program running getpid() >calls in a loop). i did optimization work on trap() to lighten the syscall overhead. the first approximation was to check the number of arguments which where expected and jump around the code which copied the arguments. the second approximation checked the number of return arguments, and so on. i believe the final solution (which i had nothing to do with) added several additional fields to the sysent structure to indicate how comlex the call was. the net result was a big boost in benchmark performance. i don't remember WHICH system call a certain benchmark company used to measure overhead, but that metric was improved by 100%. -- John F. Haugh II (jfh@rpp386.UUCP) HASA, "S" Division "If the code and the comments disagree, then both are probably wrong." -- Norm Schryer
jack@cwi.nl (Jack Jansen) (08/26/88)
I don't think that the solution you pose for simple calls would help anything. First, calls like getuid, getpid, etc. are very rare, and, second, there's a much simpler solution for these calls: just do the call the first time and cache the result. For getpid() you would need some help from fork/vfork, but nothing undoable. This would get the same results, and even cheaper. Now, two calls that *would* benefit from optimization are stat() and ioctl(). From some system call traces I've seen it showed that these calls are done incredibly often: stat() by programs that first check modes before they create a file; and ioctl() by all sorts of shells, etc. that have command line editing. Unfortunately the quick-entry system doesn't work here because both these calls can block.... Jack Jansen, jack@cwi.nl (or jack@mcvax.uucp) The shell is my oyster.
henry@utzoo.uucp (Henry Spencer) (08/27/88)
In article <21606@ccicpg.UUCP> goshen@ccicpg.UUCP (Shmuel Goshen) writes: >I have been looking recently at ways to reduce the system call overhead. >... introduce a simple and quick interface >for "light weight" system calls (like getpid(), umask() etc'), which >perform simple tasks and never sleep... Better profile your system load before putting a lot of effort into this. Or look at the Bach&Gomes paper in the Spring 88 EUUG proceedings, which observes that (after allowing for some oddities on their system) nearly all system calls are file-system-related. The light-weight calls you're talking about simply don't occur frequently enough to be worth much effort. -- Intel CPUs are not defective, | Henry Spencer at U of Toronto Zoology they just act that way. | uunet!attcan!utzoo!henry henry@zoo.toronto.edu
ast@cs.vu.nl (Andy Tanenbaum) (08/29/88)
In article <21606@ccicpg.UUCP> goshen@ccicpg.UUCP (Shmuel Goshen) writes: >I have been looking recently at ways to reduce the system call overhead. I would suggest you look closely at MULTICS and OS/2, which uses many ideas taken straight from MULTICS. In these systems, the entire operating system is contained within the address space of each user process, with appropriate protection mechanisms to keep users from doing naughty things. As a result, a system call is just a procedure call to an operating system routine, and the complete overhead is only slightly more than a normal procedure call. This gets the time down from milliseconds to microseconds. Andy Tanenbaum (ast@cs.vu.nl)
bga@raspail.UUCP (Bruce Albrecht) (08/31/88)
In article <1316@ast.cs.vu.nl>, ast@cs.vu.nl (Andy Tanenbaum) writes: > In article <21606@ccicpg.UUCP> goshen@ccicpg.UUCP (Shmuel Goshen) writes: > >I have been looking recently at ways to reduce the system call overhead. > > I would suggest you look closely at MULTICS and OS/2, which uses many ideas > taken straight from MULTICS. In these systems, the entire operating system is > contained within the address space of each user process, with appropriate > protection mechanisms to keep users from doing naughty things. Control Data's NOS/VE system on their Cyber 180's works the same way. However, this really only works when the memory scheme is based on heirarchial segments. I can't speak for OS/2, but for Multics and NOS/VE, the memory is set up so that each segment has ring attributes associated with it, and the ring attributes determine what accesses are allowed. Most, if not all system data is stored in segments which have ring attributes making them inaccessable to the user's normal ring level, and the system calls are in segments that are accessible to the less protected rings. When a user calls a system procedure, the ring mechanism automatically lowers the working ring (if the system procedure's ring attributes indicate this is necessary), so that the heretofore system data is now accessible. If one is using an architecture that is not segmented (such as the 68000 or NSC 32000), it's pretty hard, if not impossible to automatically make system data accessible for read or read/write with just a subroutine call. Another thing I would like to point out is that containing the entire OS within the user address space, usually cuts down on the maximum user address space. On the Cyber 180, this is not a problem, because the user has access to 2047 segments of size 2**31. If you are working with a 68000, you've only got a single segment of size 2**24 (2**31 for 68020/68030). If you have system data that you think the user should be able to read, but not write, you could map some system data into the user's address space, as part of the system calling mechanisms (run time library), and make those calls that don't modify system data subroutine calls rather than system calls (traps). It is possible to simulate a heirarchial segmented memory schema on a non-segmented processor. Unfortunately, it requires that you trap any call to a ring outside of the current ring, so that you can reset all of the read/write/execute attributes on all of the segments (pages) known to the user. This is likely to be a lot more expensive than system calls, though. Bruce Albrecht ({backbone}!shamash!raspail!bga)
dlm@cuuxb.ATT.COM (Dennis L. Mumaugh) (09/01/88)
In article <7622@boring.cwi.nl> jack@cwi.nl (Jack Jansen) writes:
I don't think that the solution you pose for simple calls
would help anything. First, calls like getuid, getpid,
etc. are very rare, and, second, there's a much simpler
solution for these calls: just do the call the first time
and cache the result.
1). We have a system call trace program that reports on each and
every system call a process makes -- useful for support to figure
out what a program REALLY is doing. The most commonly used
system call seems to be
lseek(fd,0L,1) ==> tell me where I am.
I have seen one program issue 50 of these in a row without
intervening I/O or other system calls. [Result of the standard
I/O system design.]
Caching the lseek and redesign of the I/O library could be a real
win. With the release of the system call tracer in the future as
a standard tool, it will be possible for developers to look at
dynamic program behaviour and catch some of these problems.
Unfortunately the quick-entry system doesn't work here
because both these calls can block....
2). Fix the sysent table with a flag for blocking/non-blocking
syscalls. On guarenteed non-blocking calls use a faster process.
On the WE32100 chip with gate tables, it was possible to specify
different entry points for each system call. The developers
chose to use a single entry point for all system calls, BUT the
hardware does support all different entry points. Thus syscall
handling could be re-written to allow light-weight syscall
handling.
3). Or, map the user's u-block (and proc table entry) into some
funny virtual area of the user's space (read-only). Then many
syscalls could be eliminated in favor of simple code:
Instead of getpid() being a system call it becomes:
#define getpid() (PROC->p_pid)
and similarly:
#define getppid() (PROC->p_ppid)
#define getuid() (UBLOCK->u_uid)
and so forth.
With better design of the users virtual memory space one could
"allow" a lot less kernel activity. The trade-off of course is
the necessity of having enough MMU entries available, kernel
interlocking so the extra pages are there when needed and the
extra setup for a context switch.
--
=Dennis L. Mumaugh
Lisle, IL ...!{att,lll-crg}!cuuxb!dlm OR cuuxb!dlm@arpa.att.com
jpd@usl-pc.usl.edu (DugalJP) (09/06/88)
In article <1316@ast.cs.vu.nl> ast@cs.vu.nl (Andy Tanenbaum) writes: ... >I would suggest you look closely at MULTICS and OS/2, which uses many ideas >taken straight from MULTICS. In these systems, the entire operating system is >contained within the address space of each user process, with appropriate ... I've been a systems analyst on our Multics system for 13 years now, and OS/2 does indeed have great possibilities, BUT only when the superior features of the 386 processor are used. Doesn't OS/2 use only techniques possible on the 286? -- -- James Dugal, N5KNX USENET: ...!{dalsqnt,killer}!usl!jpd Associate Director Internet: jpd@usl.edu Computing Center US Mail: PO Box 42770 Lafayette, LA 70504 University of Southwestern LA. Tel. 318-231-6417 U.S.A.
jerry@olivey.olivetti.com (Jerry Aguirre) (09/07/88)
In article <21606@ccicpg.UUCP> goshen@ccicpg.UUCP (Shmuel Goshen) writes: > >The second approach would be to introduce a simple and quick interface >for "light weight" system calls (like getpid(), umask() etc'), which >perform simple tasks and never sleep. This quick interface will run >in kernel mode, thus enabling access to kernel data structures, but >will not include operations like saving the context (setjmp), signal >delivery and allowing rescheduling upon return from the call. >The net effect is almost as having the system call run in user mode. I once did this for a proprietary OS (not Unix). The general system call and return took slightly more than 300us. I added a test in the software interupt routine to check if the request was a simple one. If it was then the code would preform the service and return directly to the caller. This reduced the time to slightly more than 30us. This was all done with interupts disabled but I calculated that the routine did the requested service and returned in less time than the normal code required to save context and enable interupts. For that OS this was a big win. In effect it had system calls doing system calls so many of the common calls had their overhead multiplied several times doing trivial functions like getting and returning parameters. (This was a result of an attempt to maintain structure while limited to a 16 bit logical address space.) There are certainly several Unix system calls that can be considered trivial (getpid, umask, gettimeofday) but as others have pointed out they are not normally used very often. The exact overhead in checking for trivial services is going to depend on the hardware facilities available. In some cases it may be zero. In others it is going to add a small amount of overhead to every non-trivial call. Only measurements under a "normal" load are going to tell if the result is a net gain. It would certainly look nice on some of the benchmarks though. Jerry Aguirre
james@bigtex.uucp (James Van Artsdalen) (09/08/88)
In article <29@usl-pc.usl.edu>, jpd@usl-pc.UUCP (DugalJP) wrote: > [..] OS/2 does indeed have great possibilities, BUT only when the superior > features of the 386 processor are used. Doesn't OS/2 use only techniques > possible on the 286? Indeed OS/2 uses only 286 features. But this isn't nearly a big a problem as the file system: OS/2 uses the MS-DOS 3.x file system! Not only is this slow, but it limits the capacity of any logical drive to 32meg. Even MS-DOS 4.0 can do better than this.... -- James R. Van Artsdalen ...!uunet!utastro!bigtex!james "Live Free or Die" Home: 512-346-2444 Work: 328-0282; 110 Wild Basin Rd. Ste #230, Austin TX 78746
mouse@mcgill-vision.UUCP (der Mouse) (09/11/88)
In article <28575@oliveb.olivetti.com>, jerry@olivey.olivetti.com (Jerry Aguirre) writes: > In article <21606@ccicpg.UUCP> goshen@ccicpg.UUCP (Shmuel Goshen) writes: >> The second approach would be to introduce a simple and quick >> interface for "light weight" system calls [...]. > I once did this for a proprietary OS (not Unix). [description of how > this was a win in this case.] We have a MicroVAX with an auxiliary CPU in it, something for which very little software appears to exist. We were building some, which involved writing a kernel to run on the auxiliary. In this particular system, there was one syscall which was used very heavily, and it was a very simple one: set a couple of flags and return (except for once in a long while, in which case it did a good deal of work). Well, it turned out that adding a couple of tests to the chmk handler to test for that particular syscall got us a factor of about 5 improvement. Quite a win. (Ultimately, we got an even bigger win my making those particular flags reside in a piece of memory which was made writeable by user mode, so no mode-change was necessary. Turned a full syscall, with all its overhead, into a assign, test, plus a syscall in the "hard" case.) der Mouse old: mcgill-vision!mouse new: mouse@larry.mcrcim.mcgill.edu
rich@eday.pilchuck.Data-IO.COM (Rich Wallick) (09/13/88)
In article <29@usl-pc.usl.edu>, jpd@usl-pc.usl.edu (DugalJP) writes: > OS/2 does indeed have great possibilities, BUT only when the superior > features of the 386 processor are used. Doesn't OS/2 use only techniques > possible on the 286? OS/2 just uses protect mode of the 286; it will (i believe) recognize if it is running on a 386 box and use the 386's ability to switch between protect and real mode. this increases speed of high memory (>1meg) memory access when in the real mode box over the 8042/8047 reset and loadall instruction. i don't see any other 386 capabilities being used. -<<O>>-