Path: utzoo!attcan!utgpu!news-server.csri.toronto.edu!rutgers!cs.utexas.edu!know!samsung!munnari.oz.au!metro!ipso!runxtsa!brucee From: brucee@runxtsa.runx.oz.au (Bruce Evans) Newsgroups: comp.os.minix Subject: Re: Performance Tuning Message-ID: <2102@runxtsa.runx.oz.au> Date: 5 Aug 90 14:31:30 GMT References: <26628@nigel.ee.udel.edu> Organization: RUNX Unix Timeshare. Sydney, Australia. Lines: 128 In article <26628@nigel.ee.udel.edu> bunnell@udel.edu () writes: >[System works better with a smaller quantum.] The problem is really that when a user does a system call, it is rescheduled to the back of the queue. So a user doing only system calls, in competition with a hog doing none, in the `best' case where no waiting for physical i/o is necessary, will run for time user_epsilon + system epsilon while the hog will run for the quantum. On an infinitely fast processor, the user making system calls will still take (nr_system_calls * quantum). Another data point (for a 20MHz 386 and everthing in the cache): for the hog process (while :; do :; done), ls -l /bin takes 53 sec with the normal quantum of 100 msec, and 9 sec with a quantum of 17 msec. Without the hog, it takes 1 or 2 sec. With the hog and the enclosed patch, it takes 2 or 3 sec. A simple (hasty) fix is enclosed. Terence Holm told me about this a long time ago, but I was worried about the accompanying bug and didn't put it in immediately, and then forgot about it. The fix just puts freshly ready users on the head of the queue instead of the tail. For a system call that does not have to wait for the hardware, this restores the old queue order, so must be right. It is weighted towards a LIFO order for processes that have been waiting. This is back to front. Note that server tasks are getting in the way again ;-) by obscuring the original process context. I have made another change (not included) to proc.c, to remember the last user for better accounting. It might be better to use the head of the queue only for the last user. This would penalize users doing physical i/o. But they would have to wait a relatively long time anyway, and hopefully this case is rare. This works well with 16 hog processes and ls -l /bin - the ls process gets slightly more that 1/17 of the time. It is still nice to have a small quantum. A response time of 17 * 100 msec feels awful while 17 * 17 msec is passable, much like a slow terminal. A 10MHz 286 should be able to handle a quantum of 1 msec with an overhead of 2% to 5%, but not with the current clock driver. (In real mode, it takes 2% to save the registers, load a new process pointer, and reload the registers.) The bug is that a race condition with signals is enhanced. It shows up for the `term' program. This forks into 3 processes. 2 of the children do a kill(0, SIGINT) to terminate. With the new scheduling, these children get to run before the main shell. (Processing for the first kill usually handles the parent first, then the other child. The LIFO scheduling causes the other child to run first, and it does another kill.) The main shell attempts to catch SIGINTs. It is scheduled to catch the first, but is terminated by the sceond before it has a chance to run. This is not just the fault of the new scheduling. A FIFO scheduling order would fail when then parent process slot is greater than the 2nd child's, instead of less than. > system-loaded system-idle >Quantum times(real/user/sys) times(real/user/sys) > 0.100 85.0/0.0/6.7 15.0/0.1/8.3 > 0.050 45.0/0.0/6.0 16.0/0.2/8.3 Note the zero user times and reduced system times for the loaded case. These are caused by reschuling in synchronization with accounting. The process is often forced to wait before it has consumed even 1 tick. The effect is reduced by the new scheduling. >see them posted. In fact, a little tutorial on system tuning (things that >do not require redesign of the operating system :-) from one of the >real gurus would be just wonderful. I think the obvious things have mostly been done. There is a barrier marked `64K' that stops you having to worry about how to partition memory (though not on the ST - I am surprised not to have seen more on tuning the cache/ RAM disk sizes from ST people). Some of the program sizes need tuning. E.g., in fixbin.sh, cron is chmem'ed to 64000, it should be 4K. make, nm and patch sometimes need a lot more than the defaults. ps only needs 16K. Sed can only use 16K. That's about all it gets with the 64K barrier, but it is given 60000, mostly wasted on the ST. I use 5120 for term and 2560 for update. Some programs use malloc a lot and some (like sed) allocate everything in the bss so it is hard to tell how much they need or can use. Better sizes could be obtained by having MM write the final heap size to a database whenever a process exits. A daemon could convert this to a list of maximum sizes ever used. #! /bin/sh # Contents: proc.c.cdif # Wrapped by src@besplex on Sun Aug 5 22:41:50 1990 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f 'proc.c.cdif' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'proc.c.cdif'\" else echo shar: Extracting \"'proc.c.cdif'\" \(604 characters\) sed "s/^X//" >'proc.c.cdif' <<'END_OF_FILE' X*** dist/proc.c Mon Feb 12 03:24:19 1990 X--- proc.c Sun Aug 5 22:17:53 1990 X*************** X*** 358,363 **** X--- 406,412 ---- X return; X } X #endif X+ #if 0 X if (rdy_head[USER_Q] != NIL_PROC) X rdy_tail[USER_Q]->p_nextready = rp; X else X*************** X*** 364,369 **** X--- 413,424 ---- X rdy_head[USER_Q] = rp; X rdy_tail[USER_Q] = rp; X rp->p_nextready = NIL_PROC; X+ #else X+ /* Better to add users to the *beginning* of the queue. */ X+ rp->p_nextready = rdy_head[USER_Q]; X+ if (rdy_head[USER_Q] == NIL_PROC) rdy_tail[USER_Q] = rp; X+ rdy_head[USER_Q] = rp; X+ #endif X } X X END_OF_FILE if test 604 -ne `wc -c <'proc.c.cdif'`; then echo shar: \"'proc.c.cdif'\" unpacked with wrong size! fi # end of 'proc.c.cdif' fi echo shar: End of shell archive. exit 0 -- Bruce Evans Internet: brucee@runxtsa.runx.oz.au UUCP: uunet!runxtsa.runx.oz.au!brucee (My other address (evans@ditsyda.oz.au) no longer works)