Annotation of 43BSD/contrib/news/uucp/cpu.speedup, revision 1.1.1.1

1.1       root        1: Under certain circumstances, you may find that when 2 or 3 uucicos
                      2: are running on your system, they are eating up all the CPU time,
                      3: and system performance suffers horribly.  If this is your problem,
                      4: you can do a "vmstat 5" and watch the system calls and context switches
                      5: counters.  If they are both very high whenever 2 or more uucicos
                      6: are running (100-200 system calls/second, over 100 context switches),
                      7: chances are that the problem is as follows:
                      8: 
                      9: When another system is sending you a file, your uucico reads characters
                     10: from the line.  The read returns whatever is there waiting, or if
                     11: nothing is waiting, waits for one character and returns.  Since uucico
                     12: usually wants 64 characters at a time, at 1200 baud it's quite common
                     13: to read these in 1 or 2 character pieces.  Each uucico will read 1 or
                     14: 2 characters, wake up the user process, go back for more, there won't
                     15: be any, so it hangs and gives up the CPU.  A very short time later,
                     16: (often within the same clock tick) there will be a character available,
                     17: the process will wake up, read one character, and try again.
                     18: 
                     19: This modification is very simple.  If the first read returned fewer
                     20: characters than requested, before doing another read, the process
                     21: will sleep for one second.  Then, when it wakes up, there will probably
                     22: be as many characters waiting as it needs.
                     23: 
                     24: This modification makes a big difference when you are RECEIVING a file
                     25: from another system.  It won't make much difference when you are
                     26: SENDING a file, because the user process doesn't usually have to hang
                     27: to write to the line, and when it does, the high/low water mark
                     28: mechanism in the tty driver keeps it from waking up too often.
                     29: This change is intended for a V7 or 4BSD system.  It may not
                     30: help much on System V, because uucp uses a USG tty driver feature
                     31: to make it wake up only every 6 characters.
                     32: 
                     33: The amount this fix helps depends a LOT on the baud rate.  Since it
                     34: is sleeping while it had been reading characters, it is reasonable
                     35: to expect the file to get transferred more slowly than before.  This
                     36: might, in turn, lead to increased phone bills.  Some experimentation
                     37: receiving a file over a hardwired link is detailed here.  The file
                     38: received is /etc/termcap, which is 66405 bytes long.  The local system
                     39: is a 4.1BSD VAX 11/750, the remote system is a UNIX 5.0 VAX 11/750.
                     40: The link is over a develcon dataswitch.  Both systems were almost
                     41: idle, although when another uucico did start up, it didn't seem to
                     42: affect the numbers.  The commands
                     43:        uucp -r othersys!~/termcap ~uucp/termcap
                     44:        time /usr/lib/uucp/uucico -r1 -sothersys
                     45: were given.
                     46: 
                     47: "type" is the type of uucico run: "old" is without the sleep, "sleep"
                     48: has a sleep(1) added after every short read, "nap" is the same as
                     49: sleep except that at 4800 baud and higher the sleep is for less than
                     50: one second (the parameter is the number of milliseconds).  "user" and
                     51: "sys" are the user and system CPU times from the time command, in
                     52: seconds.  "elapsed" is the time, in seconds, to transfer the file,
                     53: taken from /usr/spool/uucp/SYSLOG.  (Elapsed time does not include time to
                     54: get the connection going or close it down, just to transfer the file.)
                     55: "%" is the percentage of the system the uucico command took, from the
                     56: time command.
                     57: 
                     58: type   speed   user    sys     elapsed %
                     59: 
                     60: old    1200    35.3    120.8   606     21%
                     61: sleep  1200    14.2     35.9   609      7%
                     62: 
                     63: old    2400    27.4    115.8   305     31%
                     64: sleep  2400    13.2     35.0   351      9%
                     65: 
                     66: old    4800    23.9    116.0   152     57%
                     67: sleep  4800    14.4     40.3   338     12%
                     68: 
                     69: old    9600    14.4     68.1   79      42%
                     70: nap 60 9600    14.6     52.7   97      39%
                     71: nap 100        9600    14.9     48.5   113     32%
                     72: nap 200        9600    15.0     47.1   127     37%
                     73: sleep  9600    12.0     46.1   279     15%
                     74: 
                     75: It is clear that at 2400 baud or less, the load on the system was
                     76: cut considerably, while the penalty in slower transfer speed is
                     77: negligible.  At 9600 baud, the sleep version (equivalent to nap 1000)
                     78: cut the system load by about 1/3, the elapsed time shot way up.
                     79: (It takes much less than 1 second to accumulate 64 characters at
                     80: 9600 baud.) At 4800 baud the results are somewhere in between.
                     81: The system time was cut by a factor of 3, but the elapsed time doubled.
                     82: 
                     83: Putting in shorter naps at 9600 baud brought the elapsed time down, while
                     84: increasing the system load moderately.  Essentially, the system time
                     85: remained constant when any sleeping was done.  The difference in
                     86: percentage of the system used shows that, in effect, the same work
                     87: was spread out over different lengths of time.  This results in a tradeoff
                     88: that can only be evaluated by each system in terms of their priorities.
                     89: 
                     90: An added complication is that most V7 and 4BSD systems do not have
                     91: a way to sleep for less than a second.  4.2BSD has the select system
                     92: call, or you may have installed a nap system call or the Cornell fast
                     93: timer driver.  Otherwise, your only choices are either sleep(1) or
                     94: nothing.  The napms call below calls a routine in the new curses, to
                     95: sleep for around 1 clock tick (60 ms).
                     96: 
                     97: If your top priority is to keep system response good, it is recommended
                     98: that you do the sleep(1) no matter what the baud rate is.  If your top
                     99: priority is to make 9600 baud transfers go as quickly as possible, you
                    100: should do the sleep for 1200 baud or less, and otherwise do nothing.
                    101: If you want a well balanced compromise and have a high resolution sleep
                    102: or nap or select available, the changes shown here are appropriate.
                    103: 
                    104: This change is trivial except for the change to conn.c to make the
                    105: baud rate available to the packet driver.  The code dealing with the
                    106: speed is different in different versions of UUCP.  If you have trouble
                    107: with conn.c, search for the string "speed" and look for a conveniently
                    108: available integer version of the speed.  The variable linebaudrate is
                    109: a global integer, exported to pk1.c for purposes of this test.  The
                    110: changes shown here are for the 4.1BSD version of UUCP.
                    111: 
                    112: *** conn.c     Wed Jun  4 01:47:12 1980
                    113: --- conn.c.new Sat Apr  2 18:13:25 1983
                    114: ***************
                    115: *** 85,90
                    116:        char *D_calldev;
                    117:        int D_speed;
                    118:        } Devs [MAXDEV];
                    119:   
                    120:   char Devbuff[MAXDCH];
                    121:   
                    122: 
                    123: --- 85,91 -----
                    124:        char *D_calldev;
                    125:        int D_speed;
                    126:        } Devs [MAXDEV];
                    127: + int linebaudrate;
                    128:   
                    129:   char Devbuff[MAXDCH];
                    130:   
                    131: ***************
                    132: *** 344,349
                    133:        alarm(0);
                    134:        fflush(stdout);
                    135:        fixline(dcf, pd->D_speed);
                    136:        DEBUG(4, "Forked %d ", pid);
                    137:        DEBUG(4, "Wait got %d ", nw);
                    138:        DEBUG(4, "Status %o\n", lt);
                    139: 
                    140: --- 345,351 -----
                    141:        alarm(0);
                    142:        fflush(stdout);
                    143:        fixline(dcf, pd->D_speed);
                    144: +      linebaudrate = pd->D_speed;
                    145:        DEBUG(4, "Forked %d ", pid);
                    146:        DEBUG(4, "Wait got %d ", nw);
                    147:        DEBUG(4, "Status %o\n", lt);
                    148: *** pk1.c      Mon May 28 00:44:06 1979
                    149: --- pk1.c.new  Sat Apr  2 18:16:02 1983
                    150: [This is routine pkcget, near the end of pk1.c.]
                    151: ***************
                    152: *** 335,340
                    153:   char *b;
                    154:   {
                    155:        int nchars, ret;
                    156:   
                    157:        if (setjmp(Getjbuf)) {
                    158:                Ntimeout++;
                    159: 
                    160: --- 335,341 -----
                    161:   char *b;
                    162:   {
                    163:        int nchars, ret;
                    164: +      extern int linebaudrate;
                    165:   
                    166:        if (setjmp(Getjbuf)) {
                    167:                Ntimeout++;
                    168: ***************
                    169: *** 343,349
                    170:        }
                    171:        signal(SIGALRM, cgalarm);
                    172:   
                    173: !      for (nchars = 0; nchars < n; nchars += ret) {
                    174:                alarm(PKTIME);
                    175:                ret = read(fn, b, n - nchars);
                    176:                if (ret == 0) {
                    177: 
                    178: --- 344,350 -----
                    179:        }
                    180:        signal(SIGALRM, cgalarm);
                    181:   
                    182: !      for (nchars = 0; nchars < n; ) {
                    183:                alarm(PKTIME);
                    184:                ret = read(fn, b, n - nchars);
                    185:                if (ret == 0) {
                    186: ***************
                    187: *** 352,357
                    188:                }
                    189:                PKASSERT(ret > 0, "PKCGET READ %d", ret);
                    190:                b += ret;
                    191:        }
                    192:        alarm(0);
                    193:        return(0);
                    194: 
                    195: --- 353,364 -----
                    196:                }
                    197:                PKASSERT(ret > 0, "PKCGET READ %d", ret);
                    198:                b += ret;
                    199: +              nchars += ret;
                    200: +              if (nchars < n)
                    201: +                      if (linebaudrate > 0 && linebaudrate < 4800)
                    202: +                              sleep(1);
                    203: +                      else
                    204: +                              napms(60);
                    205:        }
                    206:        alarm(0);
                    207:        return(0);

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.