1 /*******************************************************************************
2 * The BYTE UNIX Benchmarks - Release 3
3 * Module: big.c SID: 3.3 5/15/91 19:30:18
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 * dummy code for execl test [ old version of makework.c ]
19 *
20 * makework [ -r rate ] [ -c copyfile ] nusers
21 *
22 * job streams are specified on standard input with lines of the form
23 * full_path_name_for_command [ options ] [ <standard_input_file ]
24 *
25 * "standard input" is send to all nuser instances of the commands in the
26 * job streams at a rate not in excess of "rate" characters per second
27 * per command
28 *
29 */
30 /* this code is included in other files and therefore has no SCCSid */
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <unistd.h>
34 #include <sys/types.h>
35 #include <signal.h>
36 #include <fcntl.h>
37 #include <time.h>
38 #include <string.h>
39 #include <sys/wait.h>
40
41
42 #define DEF_RATE 5.0
43 #define GRANULE 5
44 #define CHUNK 60
45 #define MAXCHILD 12
46 #define MAXWORK 10
47
48 void wrapup(const char *);
49 void onalarm(int);
50 void pipeerr();
51 void grunt();
52 void getwork(void);
53 #if debug
54 void dumpwork(void);
55 #endif
56 void fatal(const char *s);
57
58 float thres;
59 float est_rate = DEF_RATE;
60 int nusers; /* number of concurrent users to be simulated by
61 * this process */
62 int firstuser; /* ordinal identification of first user for this
63 * process */
64 int nwork = 0; /* number of job streams */
65 int exit_status = 0; /* returned to parent */
66 int sigpipe; /* pipe write error flag */
67
68 struct st_work {
69 char *cmd; /* name of command to run */
70 char **av; /* arguments to command */
71 char *input; /* standard input buffer */
72 int inpsize; /* size of standard input buffer */
73 char *outf; /* standard output (filename) */
74 } work[MAXWORK];
75
76 struct {
77 int xmit; /* # characters sent */
78 char *bp; /* std input buffer pointer */
79 int blen; /* std input buffer length */
80 int fd; /* stdin to command */
81 int pid; /* child PID */
82 char *line; /* start of input line */
83 int firstjob; /* inital piece of work */
84 int thisjob; /* current piece of work */
85 } child[MAXCHILD], *cp;
86
main(argc,argv)87 int main(argc, argv)
88 int argc;
89 char *argv[];
90 {
91 int i;
92 int l;
93 int fcopy = 0; /* fd for copy output */
94 int master = 1; /* the REAL master, == 0 for clones */
95 int nchild; /* no. of children for a clone to run */
96 int done; /* count of children finished */
97 int output; /* aggregate output char count for all
98 children */
99 int c;
100 int thiswork = 0; /* next job stream to allocate */
101 int nch; /* # characters to write */
102 int written; /* # characters actully written */
103 char logname[32]; /* name of the log file(s) */
104 int pvec[2]; /* for pipes */
105 char *p;
106 char *prog; /* my name */
107
108 #if ! debug
109 freopen("masterlog.00", "a", stderr);
110 #endif
111 prog = argv[0];
112 while (argc > 1 && argv[1][0] == '-') {
113 p = &argv[1][1];
114 argc--;
115 argv++;
116 while (*p) {
117 switch (*p) {
118 case 'r':
119 est_rate = atoi(argv[1]);
120 sscanf(argv[1], "%f", &est_rate);
121 if (est_rate <= 0) {
122 fprintf(stderr, "%s: bad rate, reset to %.2f chars/sec\n", prog, DEF_RATE);
123 est_rate = DEF_RATE;
124 }
125 argc--;
126 argv++;
127 break;
128
129 case 'c':
130 fcopy = open(argv[1], 1);
131 if (fcopy < 0)
132 fcopy = creat(argv[1], 0600);
133 if (fcopy < 0) {
134 fprintf(stderr, "%s: cannot open copy file '%s'\n",
135 prog, argv[1]);
136 exit(2);
137 }
138 lseek(fcopy, 0L, 2); /* append at end of file */
139 argc--;
140 argv++;
141 break;
142
143 default:
144 fprintf(stderr, "%s: bad flag '%c'\n", prog, *p);
145 exit(4);
146 }
147 p++;
148 }
149 }
150
151 if (argc < 2) {
152 fprintf(stderr, "%s: missing nusers\n", prog);
153 exit(4);
154 }
155
156 nusers = atoi(argv[1]);
157 if (nusers < 1) {
158 fprintf(stderr, "%s: impossible nusers (%d<-%s)\n", prog, nusers, argv[1]);
159 exit(4);
160 }
161 fprintf(stderr, "%d Users\n", nusers);
162 argc--;
163 argv++;
164
165 /* build job streams */
166 getwork();
167 #if debug
168 dumpwork();
169 #endif
170
171 /* clone copies of myself to run up to MAXCHILD jobs each */
172 firstuser = MAXCHILD;
173 fprintf(stderr, "master pid %d\n", getpid());
174 fflush(stderr);
175 while (nusers > MAXCHILD) {
176 fflush(stderr);
177 if (nusers >= 2*MAXCHILD)
178 /* the next clone must run MAXCHILD jobs */
179 nchild = MAXCHILD;
180 else
181 /* the next clone must run the leftover jobs */
182 nchild = nusers - MAXCHILD;
183 if ((l = fork()) == -1) {
184 /* fork failed */
185 fatal("** clone fork failed **\n");
186 goto bepatient;
187 } else if (l > 0) {
188 fprintf(stderr, "master clone pid %d\n", l);
189 /* I am the master with nchild fewer jobs to run */
190 nusers -= nchild;
191 firstuser += MAXCHILD;
192 continue;
193 } else {
194 /* I am a clone, run MAXCHILD jobs */
195 #if ! debug
196 sprintf(logname, "masterlog.%02d", firstuser/MAXCHILD);
197 freopen(logname, "w", stderr);
198 #endif
199 master = 0;
200 nusers = nchild;
201 break;
202 }
203 }
204 if (master)
205 firstuser = 0;
206
207 close(0);
208 for (i = 0; i < nusers; i++ ) {
209 fprintf(stderr, "user %d job %d ", firstuser+i, thiswork);
210 if (pipe(pvec) == -1) {
211 /* this is fatal */
212 fatal("** pipe failed **\n");
213 goto bepatient;
214 }
215 fflush(stderr);
216 if ((child[i].pid = fork()) == 0) {
217 int fd;
218 /* the command */
219 if (pvec[0] != 0) {
220 close(0);
221 dup(pvec[0]);
222 }
223 #if ! debug
224 sprintf(logname, "userlog.%02d", firstuser+i);
225 freopen(logname, "w", stderr);
226 #endif
227 for (fd = 3; fd < 24; fd++)
228 close(fd);
229 if (work[thiswork].outf[0] != '\0') {
230 /* redirect std output */
231 char *q;
232 for (q = work[thiswork].outf; *q != '\n'; q++) ;
233 *q = '\0';
234 if (freopen(work[thiswork].outf, "w", stdout) == NULL) {
235 fprintf(stderr, "makework: cannot open %s for std output\n",
236 work[thiswork].outf);
237 fflush(stderr);
238 }
239 *q = '\n';
240 }
241 execv(work[thiswork].cmd, work[thiswork].av);
242 /* don't expect to get here! */
243 fatal("** exec failed **\n");
244 goto bepatient;
245 }
246 else if (child[i].pid == -1) {
247 fatal("** fork failed **\n");
248 goto bepatient;
249 }
250 else {
251 close(pvec[0]);
252 child[i].fd = pvec[1];
253 child[i].line = child[i].bp = work[thiswork].input;
254 child[i].blen = work[thiswork].inpsize;
255 child[i].thisjob = thiswork;
256 child[i].firstjob = thiswork;
257 fprintf(stderr, "pid %d pipe fd %d", child[i].pid, child[i].fd);
258 if (work[thiswork].outf[0] != '\0') {
259 char *q;
260 fprintf(stderr, " > ");
261 for (q=work[thiswork].outf; *q != '\n'; q++)
262 fputc(*q, stderr);
263 }
264 fputc('\n', stderr);
265 thiswork++;
266 if (thiswork >= nwork)
267 thiswork = 0;
268 }
269 }
270 fflush(stderr);
271
272 srand(time(0));
273 thres = 0;
274 done = output = 0;
275 for (i = 0; i < nusers; i++) {
276 if (child[i].blen == 0)
277 done++;
278 else
279 thres += est_rate * GRANULE;
280 }
281 est_rate = thres;
282
283 signal(SIGALRM, onalarm);
284 signal(SIGPIPE, pipeerr);
285 alarm(GRANULE);
286 while (done < nusers) {
287 for (i = 0; i < nusers; i++) {
288 cp = &child[i];
289 if (cp->xmit >= cp->blen) continue;
290 l = rand() % CHUNK + 1; /* 1-CHUNK chars */
291 if (l == 0) continue;
292 if (cp->xmit + l > cp->blen)
293 l = cp->blen - cp->xmit;
294 p = cp->bp;
295 cp->bp += l;
296 cp->xmit += l;
297 #if debug
298 fprintf(stderr, "child %d, %d processed, %d to go\n", i, cp->xmit, cp->blen - cp->xmit);
299 #endif
300 while (p < cp->bp) {
301 if (*p == '\n' || (p == &cp->bp[-1] && cp->xmit >= cp->blen)) {
302 /* write it out */
303 nch = p - cp->line + 1;
304 if ((written = write(cp->fd, cp->line, nch)) != nch) {
305 /* argh! */
306 cp->line[nch] = '\0';
307 fprintf(stderr, "user %d job %d cmd %s ",
308 firstuser+i, cp->thisjob, cp->line);
309 fprintf(stderr, "write(,,%d) returns %d\n", nch, written);
310 if (sigpipe)
311 fatal("** SIGPIPE error **\n");
312 else
313 fatal("** write error **\n");
314 goto bepatient;
315
316 }
317 if (fcopy)
318 write(fcopy, cp->line, p - cp->line + 1);
319 #if debug
320 fprintf(stderr, "child %d gets \"", i);
321 {
322 char *q = cp->line;
323 while (q <= p) {
324 if (*q >= ' ' && *q <= '~')
325 fputc(*q, stderr);
326 else
327 fprintf(stderr, "\\%03o", *q);
328 q++;
329 }
330 }
331 fputc('"', stderr);
332 #endif
333 cp->line = &p[1];
334 }
335 p++;
336 }
337 if (cp->xmit >= cp->blen) {
338 done++;
339 close(cp->fd);
340 #if debug
341 fprintf(stderr, "child %d, close std input\n", i);
342 #endif
343 }
344 output += l;
345 }
346 while (output > thres) {
347 pause();
348 #if debug
349 fprintf(stderr, "after pause: output, thres, done %d %.2f %d\n", output, thres, done);
350 #endif
351 }
352 }
353
354 bepatient:
355 alarm(0);
356 /****
357 * If everything is going OK, we should simply be able to keep
358 * looping unitil 'wait' fails, however some descendent process may
359 * be in a state from which it can never exit, and so a timeout
360 * is used.
361 * 5 minutes should be ample, since the time to run all jobs is of
362 * the order of 5-10 minutes, however some machines are painfully slow,
363 * so the timeout has been set at 20 minutes (1200 seconds).
364 ****/
365 signal(SIGALRM, grunt);
366 alarm(1200);
367 while ((c = wait(&l)) != -1) {
368 for (i = 0; i < nusers; i++) {
369 if (c == child[i].pid) {
370 fprintf(stderr, "user %d job %d pid %d done", firstuser+i, child[i].thisjob, c);
371 if (l != 0) {
372 if (l & 0x7f)
373 fprintf(stderr, " status %d", l & 0x7f);
374 if (l & 0xff00)
375 fprintf(stderr, " exit code %d", (l>>8) & 0xff);
376 exit_status = 4;
377 }
378 fputc('\n', stderr);
379 c = child[i].pid = -1;
380 break;
381 }
382 }
383 if (c != -1) {
384 fprintf(stderr, "master clone done, pid %d ", c);
385 if (l != 0) {
386 if (l & 0x7f)
387 fprintf(stderr, " status %d", l & 0x7f);
388 if (l & 0xff00)
389 fprintf(stderr, " exit code %d", (l>>8) & 0xff);
390 exit_status = 4;
391 }
392 fputc('\n', stderr);
393 }
394 }
395 alarm(0);
396 wrapup("Finished waiting ...");
397
398 exit(0);
399 }
400
onalarm(int foo)401 void onalarm(int foo)
402 {
403 thres += est_rate;
404 signal(SIGALRM, onalarm);
405 alarm(GRANULE);
406 }
407
grunt()408 void grunt()
409 {
410 /* timeout after label "bepatient" in main */
411 exit_status = 4;
412 wrapup("Timed out waiting for jobs to finish ...");
413 }
414
pipeerr()415 void pipeerr()
416 {
417 sigpipe++;
418 }
419
wrapup(const char * reason)420 void wrapup(const char *reason)
421 {
422 int i;
423 int killed = 0;
424 fflush(stderr);
425 for (i = 0; i < nusers; i++) {
426 if (child[i].pid > 0 && kill(child[i].pid, SIGKILL) != -1) {
427 if (!killed) {
428 killed++;
429 fprintf(stderr, "%s\n", reason);
430 fflush(stderr);
431 }
432 fprintf(stderr, "user %d job %d pid %d killed off\n", firstuser+i, child[i].thisjob, child[i].pid);
433 fflush(stderr);
434 }
435 }
436 exit(exit_status);
437 }
438
439 #define MAXLINE 512
getwork(void)440 void getwork(void)
441 {
442 int i;
443 int f;
444 int ac=0;
445 char *lp = (void *)0;
446 char *q = (void *)0;
447 struct st_work *w = (void *)0;
448 char line[MAXLINE];
449
450 while (fgets(line, MAXLINE, stdin) != NULL) {
451 if (nwork >= MAXWORK) {
452 fprintf(stderr, "Too many jobs specified, .. increase MAXWORK\n");
453 exit(4);
454 }
455 w = &work[nwork];
456 lp = line;
457 i = 1;
458 while (*lp && *lp != ' ') {
459 i++;
460 lp++;
461 }
462 w->cmd = (char *)malloc(i);
463 strncpy(w->cmd, line, i-1);
464 w->cmd[i-1] = '\0';
465 w->inpsize = 0;
466 w->input = "";
467 /* start to build arg list */
468 ac = 2;
469 w->av = (char **)malloc(2*sizeof(char *));
470 q = w->cmd;
471 while (*q) q++;
472 q--;
473 while (q >= w->cmd) {
474 if (*q == '/') {
475 q++;
476 break;
477 }
478 q--;
479 }
480 w->av[0] = q;
481 while (*lp) {
482 if (*lp == ' ') {
483 /* space */
484 lp++;
485 continue;
486 }
487 else if (*lp == '<') {
488 /* standard input for this job */
489 q = ++lp;
490 while (*lp && *lp != ' ') lp++;
491 *lp = '\0';
492 if ((f = open(q, 0)) == -1) {
493 fprintf(stderr, "cannot open input file (%s) for job %d\n",
494 q, nwork);
495 exit(4);
496 }
497 /* gobble input */
498 w->input = (char *)malloc(512);
499 while ((i = read(f, &w->input[w->inpsize], 512)) > 0) {
500 w->inpsize += i;
501 w->input = (char *)realloc(w->input, w->inpsize+512);
502 }
503 w->input = (char *)realloc(w->input, w->inpsize);
504 close(f);
505 /* extract stdout file name from line beginning "C=" */
506 w->outf = "";
507 for (q = w->input; q < &w->input[w->inpsize-10]; q++) {
508 if (*q == '\n' && strncmp(&q[1], "C=", 2) == 0) {
509 w->outf = &q[3];
510 break;
511 }
512 }
513 #if debug
514 if (*w->outf) {
515 fprintf(stderr, "stdout->");
516 for (q=w->outf; *q != '\n'; q++)
517 fputc(*q, stderr);
518 fputc('\n', stderr);
519 }
520 #endif
521 }
522 else {
523 /* a command option */
524 ac++;
525 w->av = (char **)realloc(w->av, ac*sizeof(char *));
526 q = lp;
527 i = 1;
528 while (*lp && *lp != ' ') {
529 lp++;
530 i++;
531 }
532 w->av[ac-2] = (char *)malloc(i);
533 strncpy(w->av[ac-2], q, i-1);
534 w->av[ac-2][i-1] = '\0';
535 }
536 }
537 w->av[ac-1] = (char *)0;
538 nwork++;
539 }
540 }
541
542 #if debug
dumpwork(void)543 void dumpwork(void)
544 {
545 int i;
546 int j;
547
548 for (i = 0; i < nwork; i++) {
549 fprintf(stderr, "job %d: cmd: %s\n", i, work[i].cmd);
550 j = 0;
551 while (work[i].av[j]) {
552 fprintf(stderr, "argv[%d]: %s\n", j, work[i].av[j]);
553 j++;
554 }
555 fprintf(stderr, "input: %d chars text: ", work[i].inpsize);
556 if (work[i].input == (char *)0)
557 fprintf(stderr, "<NULL>\n");
558 else {
559 register char *pend;
560 char *p;
561 char c;
562 p = work[i].input;
563 while (*p) {
564 pend = p;
565 while (*pend && *pend != '\n')
566 pend++;
567 c = *pend;
568 *pend = '\0';
569 fprintf(stderr, "%s\n", p);
570 *pend = c;
571 p = &pend[1];
572 }
573 }
574 }
575 }
576 #endif
577
fatal(const char * s)578 void fatal(const char *s)
579 {
580 int i;
581 fprintf(stderr, "%s", s);
582 fflush(stderr);
583 perror("Reason?");
584 fflush(stderr);
585 for (i = 0; i < nusers; i++) {
586 if (child[i].pid > 0 && kill(child[i].pid, SIGKILL) != -1) {
587 fprintf(stderr, "pid %d killed off\n", child[i].pid);
588 fflush(stderr);
589 }
590 }
591 exit_status = 4;
592 }
593