home *** CD-ROM | disk | FTP | other *** search
/ Garbo / Garbo.cdr / pc / source / byteunix.lzh / byte.3 / big.c < prev    next >
C/C++ Source or Header  |  1990-05-11  |  14KB  |  584 lines

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