Under certain circumstances, you may find that when 2 or 3 uucicos are running on your system, they are eating up all the CPU time, and system performance suffers horribly. If this is your problem, you can do a "vmstat 5" and watch the system calls and context switches counters. If they are both very high whenever 2 or more uucicos are running (100-200 system calls/second, over 100 context switches), chances are that the problem is as follows: When another system is sending you a file, your uucico reads characters from the line. The read returns whatever is there waiting, or if nothing is waiting, waits for one character and returns. Since uucico usually wants 64 characters at a time, at 1200 baud it's quite common to read these in 1 or 2 character pieces. Each uucico will read 1 or 2 characters, wake up the user process, go back for more, there won't be any, so it hangs and gives up the CPU. A very short time later, (often within the same clock tick) there will be a character available, the process will wake up, read one character, and try again. This modification is very simple. If the first read returned fewer characters than requested, before doing another read, the process will sleep for one second. Then, when it wakes up, there will probably be as many characters waiting as it needs. This modification makes a big difference when you are RECEIVING a file from another system. It won't make much difference when you are SENDING a file, because the user process doesn't usually have to hang to write to the line, and when it does, the high/low water mark mechanism in the tty driver keeps it from waking up too often. This change is intended for a V7 or 4BSD system. It may not help much on System V, because uucp uses a USG tty driver feature to make it wake up only every 6 characters. The amount this fix helps depends a LOT on the baud rate. Since it is sleeping while it had been reading characters, it is reasonable to expect the file to get transferred more slowly than before. This might, in turn, lead to increased phone bills. Some experimentation receiving a file over a hardwired link is detailed here. The file received is /etc/termcap, which is 66405 bytes long. The local system is a 4.1BSD VAX 11/750, the remote system is a UNIX 5.0 VAX 11/750. The link is over a develcon dataswitch. Both systems were almost idle, although when another uucico did start up, it didn't seem to affect the numbers. The commands uucp -r othersys!~/termcap ~uucp/termcap time /usr/lib/uucp/uucico -r1 -sothersys were given. "type" is the type of uucico run: "old" is without the sleep, "sleep" has a sleep(1) added after every short read, "nap" is the same as sleep except that at 4800 baud and higher the sleep is for less than one second (the parameter is the number of milliseconds). "user" and "sys" are the user and system CPU times from the time command, in seconds. "elapsed" is the time, in seconds, to transfer the file, taken from /usr/spool/uucp/SYSLOG. (Elapsed time does not include time to get the connection going or close it down, just to transfer the file.) "%" is the percentage of the system the uucico command took, from the time command. type speed user sys elapsed % old 1200 35.3 120.8 606 21% sleep 1200 14.2 35.9 609 7% old 2400 27.4 115.8 305 31% sleep 2400 13.2 35.0 351 9% old 4800 23.9 116.0 152 57% sleep 4800 14.4 40.3 338 12% old 9600 14.4 68.1 79 42% nap 60 9600 14.6 52.7 97 39% nap 100 9600 14.9 48.5 113 32% nap 200 9600 15.0 47.1 127 37% sleep 9600 12.0 46.1 279 15% It is clear that at 2400 baud or less, the load on the system was cut considerably, while the penalty in slower transfer speed is negligible. At 9600 baud, the sleep version (equivalent to nap 1000) cut the system load by about 1/3, the elapsed time shot way up. (It takes much less than 1 second to accumulate 64 characters at 9600 baud.) At 4800 baud the results are somewhere in between. The system time was cut by a factor of 3, but the elapsed time doubled. Putting in shorter naps at 9600 baud brought the elapsed time down, while increasing the system load moderately. Essentially, the system time remained constant when any sleeping was done. The difference in percentage of the system used shows that, in effect, the same work was spread out over different lengths of time. This results in a tradeoff that can only be evaluated by each system in terms of their priorities. An added complication is that most V7 and 4BSD systems do not have a way to sleep for less than a second. 4.2BSD has the select system call, or you may have installed a nap system call or the Cornell fast timer driver. Otherwise, your only choices are either sleep(1) or nothing. The napms call below calls a routine in the new curses, to sleep for around 1 clock tick (60 ms). If your top priority is to keep system response good, it is recommended that you do the sleep(1) no matter what the baud rate is. If your top priority is to make 9600 baud transfers go as quickly as possible, you should do the sleep for 1200 baud or less, and otherwise do nothing. If you want a well balanced compromise and have a high resolution sleep or nap or select available, the changes shown here are appropriate. This change is trivial except for the change to conn.c to make the baud rate available to the packet driver. The code dealing with the speed is different in different versions of UUCP. If you have trouble with conn.c, search for the string "speed" and look for a conveniently available integer version of the speed. The variable linebaudrate is a global integer, exported to pk1.c for purposes of this test. The changes shown here are for the 4.1BSD version of UUCP. *** conn.c Wed Jun 4 01:47:12 1980 --- conn.c.new Sat Apr 2 18:13:25 1983 *************** *** 85,90 char *D_calldev; int D_speed; } Devs [MAXDEV]; char Devbuff[MAXDCH]; --- 85,91 ----- char *D_calldev; int D_speed; } Devs [MAXDEV]; + int linebaudrate; char Devbuff[MAXDCH]; *************** *** 344,349 alarm(0); fflush(stdout); fixline(dcf, pd->D_speed); DEBUG(4, "Forked %d ", pid); DEBUG(4, "Wait got %d ", nw); DEBUG(4, "Status %o\n", lt); --- 345,351 ----- alarm(0); fflush(stdout); fixline(dcf, pd->D_speed); + linebaudrate = pd->D_speed; DEBUG(4, "Forked %d ", pid); DEBUG(4, "Wait got %d ", nw); DEBUG(4, "Status %o\n", lt); *** pk1.c Mon May 28 00:44:06 1979 --- pk1.c.new Sat Apr 2 18:16:02 1983 [This is routine pkcget, near the end of pk1.c.] *************** *** 335,340 char *b; { int nchars, ret; if (setjmp(Getjbuf)) { Ntimeout++; --- 335,341 ----- char *b; { int nchars, ret; + extern int linebaudrate; if (setjmp(Getjbuf)) { Ntimeout++; *************** *** 343,349 } signal(SIGALRM, cgalarm); ! for (nchars = 0; nchars < n; nchars += ret) { alarm(PKTIME); ret = read(fn, b, n - nchars); if (ret == 0) { --- 344,350 ----- } signal(SIGALRM, cgalarm); ! for (nchars = 0; nchars < n; ) { alarm(PKTIME); ret = read(fn, b, n - nchars); if (ret == 0) { *************** *** 352,357 } PKASSERT(ret > 0, "PKCGET READ %d", ret); b += ret; } alarm(0); return(0); --- 353,364 ----- } PKASSERT(ret > 0, "PKCGET READ %d", ret); b += ret; + nchars += ret; + if (nchars < n) + if (linebaudrate > 0 && linebaudrate < 4800) + sleep(1); + else + napms(60); } alarm(0); return(0);