|
|
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);
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.