1 /*******************************************************************************
2 * The BYTE UNIX Benchmarks - Release 3
3 * Module: dummy.c SID: 3.3 5/15/91 19:30:19
4 *
5 *******************************************************************************
6 * Bug reports, patches, comments, suggestions should be sent to:
7 *
8 * Ben Smith, Rick Grehan or Tom Yager
9 * ben@bytepb.byte.com rick_g@bytepb.byte.com tyager@bytepb.byte.com
10 *
11 *******************************************************************************
12 * Modification Log:
13 * 10/22/97 - code cleanup to remove ANSI C compiler warnings
14 * Andy Kahn <kahn@zk3.dec.com>
15 *
16 ******************************************************************************/
17 /*
18 * Hacked up C program for use in the standard shell.? scripts of
19 * the multiuser test. This is based upon makework.c, and is typically
20 * edited using edscript.2 before compilation.
21 *
22 * $Header: dummy.c,v 3.4 87/06/23 15:54:53 kjmcdonell Beta $
23 */
24 char SCCSid[] = "@(#) @(#)dummy.c:3.3 -- 5/15/91 19:30:19";
25
26 #include <stdio.h>
27 #include <signal.h>
28
29 #define DEF_RATE 5.0
30 #define GRANULE 5
31 #define CHUNK 60
32 #define MAXCHILD 12
33 #define MAXWORK 10
34
35 float thres;
36 float est_rate = DEF_RATE;
37 int nusers; /* number of concurrent users to be simulated by
38 * this process */
39 int firstuser; /* ordinal identification of first user for this
40 * process */
41 int nwork = 0; /* number of job streams */
42 int exit_status = 0; /* returned to parent */
43 int sigpipe; /* pipe write error flag */
44
45 struct st_work {
46 char *cmd; /* name of command to run */
47 char **av; /* arguments to command */
48 char *input; /* standard input buffer */
49 int inpsize; /* size of standard input buffer */
50 } work[MAXWORK];
51
52 struct {
53 int xmit; /* # characters sent */
54 char *bp; /* std input buffer pointer */
55 int blen; /* std input buffer length */
56 int fd; /* stdin to command */
57 int pid; /* child PID */
58 char *line; /* start of input line */
59 int firstjob; /* inital piece of work */
60 int thisjob; /* current piece of work */
61 } child[MAXCHILD], *cp;
62
main(argc,argv)63 main(argc, argv)
64 int argc;
65 char *argv[];
66 {
67 int i;
68 int l;
69 int fcopy = 0; /* fd for copy output */
70 int master = 1; /* the REAL master, == 0 for clones */
71 int nchild; /* no. of children for a clone to run */
72 int done; /* count of children finished */
73 int output; /* aggregate output char count for all
74 children */
75 int c;
76 int thiswork = 0; /* next job stream to allocate */
77 int nch; /* # characters to write */
78 int written; /* # characters actully written */
79 char logname[15]; /* name of the log file(s) */
80 void onalarm(void);
81 void pipeerr(void);
82 void wrapup(void);
83 void grunt(void);
84 char *malloc();
85 int pvec[2]; /* for pipes */
86 char *p;
87 char *prog; /* my name */
88
89 #if ! debug
90 freopen("masterlog.00", "a", stderr);
91 #endif
92 fprintf(stderr, "*** New Run *** ");
93 prog = argv[0];
94 while (argc > 1 && argv[1][0] == '-') {
95 p = &argv[1][1];
96 argc--;
97 argv++;
98 while (*p) {
99 switch (*p) {
100 case 'r':
101 /* code DELETED here */
102 argc--;
103 argv++;
104 break;
105
106 case 'c':
107 /* code DELETED here */
108 lseek(fcopy, 0L, 2); /* append at end of file */
109 break;
110
111 default:
112 fprintf(stderr, "%s: bad flag '%c'\n", prog, *p);
113 exit(4);
114 }
115 p++;
116 }
117 }
118
119 if (argc < 2) {
120 fprintf(stderr, "%s: missing nusers\n", prog);
121 exit(4);
122 }
123
124 nusers = atoi(argv[1]);
125 if (nusers < 1) {
126 fprintf(stderr, "%s: impossible nusers (%d<-%s)\n", prog, nusers, argv[1]);
127 exit(4);
128 }
129 fprintf(stderr, "%d Users\n", nusers);
130 argc--;
131 argv++;
132
133 /* build job streams */
134 getwork();
135 #if debug
136 dumpwork();
137 #endif
138
139 /* clone copies of myself to run up to MAXCHILD jobs each */
140 firstuser = MAXCHILD;
141 fprintf(stderr, "master pid %d\n", getpid());
142 fflush(stderr);
143 while (nusers > MAXCHILD) {
144 fflush(stderr);
145 if (nusers >= 2*MAXCHILD)
146 /* the next clone must run MAXCHILD jobs */
147 nchild = MAXCHILD;
148 else
149 /* the next clone must run the leftover jobs */
150 nchild = nusers - MAXCHILD;
151 if ((l = fork()) == -1) {
152 /* fork failed */
153 fatal("** clone fork failed **\n");
154 goto bepatient;
155 } else if (l > 0) {
156 fprintf(stderr, "master clone pid %d\n", l);
157 /* I am the master with nchild fewer jobs to run */
158 nusers -= nchild;
159 firstuser += MAXCHILD;
160 continue;
161 } else {
162 /* I am a clone, run MAXCHILD jobs */
163 #if ! debug
164 sprintf(logname, "masterlog.%02d", firstuser/MAXCHILD);
165 freopen(logname, "w", stderr);
166 #endif
167 master = 0;
168 nusers = nchild;
169 break;
170 }
171 }
172 if (master)
173 firstuser = 0;
174
175 close(0);
176
177 /* code DELETED here */
178
179 fflush(stderr);
180
181 srand(time(0));
182 thres = 0;
183 done = output = 0;
184 for (i = 0; i < nusers; i++) {
185 if (child[i].blen == 0)
186 done++;
187 else
188 thres += est_rate * GRANULE;
189 }
190 est_rate = thres;
191
192 signal(SIGALRM, onalarm);
193 signal(SIGPIPE, pipeerr);
194 alarm(GRANULE);
195 while (done < nusers) {
196 for (i = 0; i < nusers; i++) {
197 cp = &child[i];
198 if (cp->xmit >= cp->blen) continue;
199 l = rand() % CHUNK + 1; /* 1-CHUNK chars */
200 if (l == 0) continue;
201 if (cp->xmit + l > cp->blen)
202 l = cp->blen - cp->xmit;
203 p = cp->bp;
204 cp->bp += l;
205 cp->xmit += l;
206 #if debug
207 fprintf(stderr, "child %d, %d processed, %d to go\n", i, cp->xmit, cp->blen - cp->xmit);
208 #endif
209 while (p < cp->bp) {
210 if (*p == '\n' || (p == &cp->bp[-1] && cp->xmit >= cp->blen)) {
211 /* write it out */
212 nch = p - cp->line + 1;
213 if ((written = write(cp->fd, cp->line, nch)) != nch) {
214
215 /* code DELETED here */
216
217 }
218 if (fcopy)
219 write(fcopy, cp->line, p - cp->line + 1);
220 #if debug
221 fprintf(stderr, "child %d gets \"", i);
222 {
223 char *q = cp->line;
224 while (q <= p) {
225 if (*q >= ' ' && *q <= '~')
226 fputc(*q, stderr);
227 else
228 fprintf(stderr, "\\%03o", *q);
229 q++;
230 }
231 }
232 fputc('"', stderr);
233 #endif
234 cp->line = &p[1];
235 }
236 p++;
237 }
238 if (cp->xmit >= cp->blen) {
239 done++;
240 close(cp->fd);
241 #if debug
242 fprintf(stderr, "child %d, close std input\n", i);
243 #endif
244 }
245 output += l;
246 }
247 while (output > thres) {
248 pause();
249 #if debug
250 fprintf(stderr, "after pause: output, thres, done %d %.2f %d\n", output, thres, done);
251 #endif
252 }
253 }
254
255 bepatient:
256 alarm(0);
257 /****
258 * If everything is going OK, we should simply be able to keep
259 * looping unitil 'wait' fails, however some descendent process may
260 * be in a state from which it can never exit, and so a timeout
261 * is used.
262 * 5 minutes should be ample, since the time to run all jobs is of
263 * the order of 5-10 minutes, however some machines are painfully slow,
264 * so the timeout has been set at 20 minutes (1200 seconds).
265 ****/
266
267 /* code DELETED here */
268
269 }
270
onalarm()271 onalarm()
272 {
273 thres += est_rate;
274 signal(SIGALRM, onalarm);
275 alarm(GRANULE);
276 }
277
grunt()278 grunt()
279 {
280 /* timeout after label "bepatient" in main */
281 exit_status = 4;
282 wrapup();
283 }
284
pipeerr()285 pipeerr()
286 {
287 sigpipe++;
288 }
289
wrapup()290 wrapup()
291 {
292 /* DUMMY, real code dropped */
293 }
294
getwork()295 getwork()
296 {
297
298 /* DUMMY, real code dropped */
299 gets();
300 strncpy();
301 malloc(); realloc();
302 open(); close();
303 }
304
fatal(s)305 fatal(s)
306 char *s;
307 {
308 int i;
309 fprintf(stderr, s);
310 fflush(stderr);
311 perror("Reason?");
312 for (i = 0; i < nusers; i++) {
313 if (child[i].pid > 0 && kill(child[i].pid, SIGKILL) != -1)
314 fprintf(stderr, "pid %d killed off\n", child[i].pid);
315 }
316 fflush(stderr);
317 exit_status = 4;
318 return;
319 }
320