Import TBBT (NFS trace replay).
[bluesky.git] / TBBT / trace_play / sfs_c_pnt.c
diff --git a/TBBT/trace_play/sfs_c_pnt.c b/TBBT/trace_play/sfs_c_pnt.c
new file mode 100644 (file)
index 0000000..cab4f43
--- /dev/null
@@ -0,0 +1,1163 @@
+#ifndef lint
+static char sfs_c_pntSid[] = "@(#)sfs_c_pnt.c  2.1     97/10/23";
+#endif
+
+/*
+ *   Copyright (c) 1992-1997,2001 by Standard Performance Evaluation Corporation
+ *     All rights reserved.
+ *             Standard Performance Evaluation Corporation (SPEC)
+ *             6585 Merchant Place, Suite 100
+ *             Warrenton, VA 20187
+ *
+ *     This product contains benchmarks acquired from several sources who
+ *     understand and agree with SPEC's goal of creating fair and objective
+ *     benchmarks to measure computer performance.
+ *
+ *     This copyright notice is placed here only to protect SPEC in the
+ *     event the source is misused in any manner that is contrary to the
+ *     spirit, the goals and the intent of SPEC.
+ *
+ *     The source code is provided to the user or company under the license
+ *     agreement for the SPEC Benchmark Suite for this product.
+ */
+
+/*****************************************************************
+ *                                                               *
+ *     Copyright 1991,1992  Legato Systems, Inc.                *
+ *     Copyright 1991,1992  Auspex Systems, Inc.                *
+ *     Copyright 1991,1992  Data General Corporation            *
+ *     Copyright 1991,1992  Digital Equipment Corporation       *
+ *     Copyright 1991,1992  Interphase Corporation              *
+ *     Copyright 1991,1992  Sun Microsystems, Inc.              *
+ *                                                               *
+ *****************************************************************/
+
+/*
+ *
+ *.Exported_Routines
+ *     void parent(int, int, char *, char *)
+ *
+ *.Local_Routines
+ *     void synchronize_children(int)
+ *     int signal_Prime_Client(char *, char *)
+ *     void collect_counters(int)
+ *     int check_parameters(char *, char *, int)
+ *     int check_counters(void)
+ *     void print_results(int, int, char *, int, int, char *)
+ *
+ *.Revision_History
+ *     10-Jan-92       Teelucksingh
+ *                             Client passes standard deviation compute
+ *                             values to Prime-Client as well as an
+ *                             "INVALID RUN" flag.
+ *
+ *     16-Dec-91       Wittle          Created.
+ */
+
+/*
+ * -------------------------  Include Files  -------------------------
+ */
+
+/*
+ * ANSI C headers
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <math.h>
+#include <signal.h>
+
+#include <fcntl.h>
+
+#include <sys/types.h>
+#include <sys/stat.h> 
+#include <unistd.h>
+#include <sys/wait.h>
+
+#include "sfs_c_def.h"
+#include "sfs_m_def.h"
+
+#if !defined(_XOPEN_SOURCE)
+#include <sys/socket.h>
+#else
+#define        AF_INET         2
+#endif
+
+/*
+ * -------------------------  External Definitions  -------------------------
+ */
+
+/* forward definitions for local routines */
+static void synchronize_children(int);
+static int signal_Prime_Client(char *, char *);
+static void collect_counters(int);
+static int check_parameters(char *, char *, int);
+static int check_counters(void);
+static void print_results(int, int, char *, int, int, char *);
+static void sfs_reaper(int);
+
+/* Aggregate results storage */
+static char Client_results[(NOPS+3)*MAX_LINE_LEN];
+
+/*
+ * -------------------------  SFS Parent Code  -------------------------
+ */
+
+/*
+ * Parent: wait for kids to get ready, start them, wait for them to
+ * finish, read and accumulate results.
+ */
+void
+parent(
+    int                children,
+    int                load,
+    char *     mix_file,
+    char *     iodist_file)
+{
+    char       string[80];     /* for interactive startup */
+    int                result;
+    int                invalid_run;    /* holds INVALID RUN status */
+    int                runtime_val;    /* store Runtime value to be printed later */
+    int                Saveerrno;
+    char       *nameptr;
+#if (defined(_XOPEN_SOURCE) || defined(USE_POSIX_SIGNALS))
+    struct sigaction sig_act, old_sig_act;
+#endif
+
+    /*
+     * Setup a SIGCHLD handler in case one of our beloved children dies
+     * before its time.
+     */
+#if (defined(_XOPEN_SOURCE) || defined(USE_POSIX_SIGNALS))
+    /* use XOPEN signal handling */
+
+    sig_act.sa_handler = sfs_reaper;
+    (void)sigemptyset(&sig_act.sa_mask);
+    sig_act.sa_flags = 0;
+    if (sigaction(SIGCHLD,&sig_act,&old_sig_act) == -1) {
+        perror("sigaction failed: SIGCHLD");
+        exit(66);
+    }
+#else
+    (void) signal(SIGCHLD, sfs_reaper);
+#endif
+
+    /* Change my name for error logging */
+    if ((nameptr = strrchr(sfs_Myname, '/')) != NULL)
+        sfs_Myname = ++nameptr;
+
+    /*
+     * store the Runtime value; to be printed in results
+     */
+    if (Prime_client)
+       runtime_val = Runtime - MULTICLIENT_OFFSET;
+    else runtime_val = Runtime;
+
+    /* print logfile header information */
+    (void) fprintf(stdout,"\n");
+    (void) fprintf(stdout,
+    "************************************************************************");
+    (void) fprintf(stdout,"\n");
+    (void) fflush(stdout);
+
+    /* print sfs information */
+    if (Prime_client) {
+       (void) fprintf(stderr,
+               "\nSFS NFS Version %d Benchmark Client Logfile, %s\n",
+                       nfs_version, lad_timestamp());
+       (void) fprintf(stderr, "\tClient hostname = %s\n", lad_hostname);
+       (void) fprintf(stderr, "\tPrime Client hostname = %s\n",
+                       Prime_client);
+    }
+
+    (void) fprintf(stderr, "\nSPEC SFS Benchmark Version %s, Creation - %s\n",
+                               SFS_VERSION_NUM, SFS_VERSION_DATE);
+    (void) fprintf(stderr, "NFS Protocol Version %d\n", nfs_version);
+
+    /* mount test directories */
+    (void) fprintf(stderr, "%s Mounting %d remote test directories.\n",
+               lad_timestamp(), children);
+    synchronize_children(children);
+    (void) fprintf(stderr, "%s Completed.", lad_timestamp());
+
+    /*
+     * if multi-client execution then tell Prime-Client I'm done mounting
+     * test directories.
+     */
+    if (Prime_client) {
+       (void) fprintf(stderr, "\n");
+       (void) fprintf(stderr,
+                      "%s Sending DONE-MOUNT message to Prime Client(%s).\n",
+                       lad_timestamp(), Prime_client);
+       if ((result =
+           (int) signal_Prime_Client("CLIENT_SIGNAL", ""))
+               == (int) RPC_SUCCESS) {
+           (void) fprintf(stderr, "%s Completed.",lad_timestamp());
+           (void) fflush(stderr);
+       } else {
+           (void) fprintf(stderr, "\n");
+           (void) fprintf(stderr,
+               "%s:  error %d sending DONE-MOUNT message to Prime Client\n",
+               sfs_Myname, result);
+           /* cleanup and exit */
+#if (defined(_XOPEN_SOURCE) || defined(USE_POSIX_SIGNALS))
+           sig_act.sa_handler = SIG_DFL;
+           (void)sigemptyset(&sig_act.sa_mask);
+           sig_act.sa_flags = 0;
+           if (sigaction(SIGCHLD,&sig_act,&old_sig_act) == -1) {
+               perror("sigaction failed: SIGCHLD");
+               exit(67);
+           }
+#else
+           (void) signal(SIGCHLD, SIG_DFL);
+#endif
+           (void) generic_kill(0, SIGINT);
+           exit(68);
+       }
+
+       (void) fprintf(stderr, "\n");
+       (void) fprintf(stderr,
+                   "%s Waiting on DO-INIT message from Prime Client(%s).\n",
+                   lad_timestamp(), Prime_client);
+       (void) fflush(stderr);
+
+       /*
+        * wait for DO-INIT message from Prime Client
+        * sfs_syncd (rpc server) sends a SIGUSR1 signal;
+        * user can also terminate experiment anytime they wish
+        * with SIGINT or SIGTERM signal
+        */
+       (void) pause();
+       (void) fprintf(stderr, "%s Received.",lad_timestamp());
+       (void) fflush(stderr);
+
+    } /* send DONE-MOUNT and got DO-INIT message */
+
+    /* initialize test directories */
+    (void) fprintf(stderr, "\n");
+    (void) fprintf(stderr, "%s Initializing test directories.\n",
+                   lad_timestamp());
+
+    /* send SIGUSR1 to child processes */
+    (void) generic_kill(0, SIGUSR1);
+    synchronize_children(children);
+    (void) fprintf(stderr, "%s Completed.", lad_timestamp());
+    (void) fflush(stderr);
+
+    /*
+     * if multi-client execution then tell Prime-Client I'm done initializing
+     * and wait for synchronized do warmupmessage.
+     */
+    if (Prime_client) {
+       (void) fprintf(stderr, "\n");
+       (void) fprintf(stderr,
+                   "%s Sending DONE-INIT message to Prime Client(%s).\n",
+                       lad_timestamp(), Prime_client);
+       if ((result =
+           (int) signal_Prime_Client("CLIENT_SIGNAL",""))
+               == (int) RPC_SUCCESS) {
+           (void) fprintf(stderr, "%s Completed.",lad_timestamp());
+           (void) fflush(stderr);
+       } else {
+           (void) fprintf(stderr, "\n");
+           (void) fprintf(stderr,
+                   "%s:  error %d sending DONE-INIT message to Prime Client\n",
+                   sfs_Myname, result);
+           /* cleanup and exit */
+#if (defined(_XOPEN_SOURCE) || defined(USE_POSIX_SIGNALS))
+           sig_act.sa_handler = SIG_DFL;
+           (void)sigemptyset(&sig_act.sa_mask);
+           sig_act.sa_flags = 0;
+           if (sigaction(SIGCHLD,&sig_act,&old_sig_act) == -1) {
+               perror("sigaction failed: SIGCHLD");
+               exit(69);
+           }
+#else
+           (void) signal(SIGCHLD, SIG_DFL);
+#endif
+           (void) generic_kill(0, SIGINT);
+           exit(70);
+       }
+       (void) fprintf(stderr, "\n");
+       (void) fprintf(stderr,
+                 "%s Waiting on DO-WARMUP message from Prime Client(%s).\n",
+                   lad_timestamp(), Prime_client);
+       (void) fflush(stderr);
+
+       /*
+        * wait for DO-WARMUP message from Prime Client
+        * sfs_syncd (rpc server) sends a SIGUSR1 signal;
+        * user can also terminate experiment anytime they wish
+        * with SIGINT or SIGTERM signal
+        */
+       (void) pause();
+       (void) fprintf(stderr, "%s Received.",lad_timestamp());
+       (void) fflush(stderr);
+
+    } /* send DONE-INIT and got DO-WARMUP message */
+
+    if (Populate_only) {
+       (void) fprintf(stderr, "\nPopulating directories and exiting.\n");
+#if (defined(_XOPEN_SOURCE) || defined(USE_POSIX_SIGNALS))
+       sig_act.sa_handler = SIG_DFL;
+       (void)sigemptyset(&sig_act.sa_mask);
+       sig_act.sa_flags = 0;
+       if (sigaction(SIGCHLD,&sig_act,&old_sig_act) == -1) {
+           perror("sigaction failed: SIGCHLD");
+           exit(71);
+       }
+#else
+       (void) signal(SIGCHLD, SIG_DFL);
+#endif
+       (void) generic_kill(0, SIGUSR1);
+       while (wait((int *) 0) != -1) {
+           /* nop */
+       }
+       return;
+    }
+
+    /* do warm-up */
+    if (Warmuptime) {
+       (void) fprintf(stderr, "\n");
+       (void) fprintf(stderr, "%s Performing %d seconds pretest warmup.\n",
+               lad_timestamp(), Warmuptime);
+       (void) generic_kill(0, SIGUSR1);
+       (void) sleep(Warmuptime);
+       (void) fprintf(stderr, "%s Completed.", lad_timestamp());
+       (void) fflush(stderr);
+    }
+
+    if (Interactive) {
+       (void) fprintf(stderr, "\n");
+       (void) fprintf(stderr, "Hit <return> when ready to start test ...");
+       (void) fgets(string,10,stdin);
+    }
+
+    /*
+     * if multi-client execution then tell Prime-Client I'm done warm-up
+     * and wait for synchronized Start message.
+     */
+    if (Prime_client) {
+       (void) fprintf(stderr, "\n");
+       (void) fprintf(stderr,
+                       "%s Sending READY message to Prime Client(%s).\n",
+                       lad_timestamp(), Prime_client);
+       if ((result =
+           (int) signal_Prime_Client("CLIENT_SIGNAL",""))
+               == (int) RPC_SUCCESS) {
+           (void) fprintf(stderr, "%s Completed.",lad_timestamp());
+           (void) fflush(stderr);
+       } else {
+           (void) fprintf(stderr, "\n");
+           (void) fprintf(stderr,
+                   "%s:  error %d sending READY message to Prime Client\n",
+                   sfs_Myname, result);
+           /* cleanup and exit */
+#if (defined(_XOPEN_SOURCE) || defined(USE_POSIX_SIGNALS))
+           sig_act.sa_handler = SIG_DFL;
+           (void)sigemptyset(&sig_act.sa_mask);
+           sig_act.sa_flags = 0;
+           if (sigaction(SIGCHLD,&sig_act,&old_sig_act) == -1) {
+               perror("sigaction failed: SIGCHLD");
+               exit(72);
+           }
+#else
+           (void) signal(SIGCHLD, SIG_DFL);
+#endif
+           (void) generic_kill(0, SIGINT);
+           exit(73);
+       }
+
+       (void) fprintf(stderr, "\n");
+       (void) fprintf(stderr,
+                   "%s Waiting on START message from Prime Client(%s).\n",
+                   lad_timestamp(), Prime_client);
+       (void) fflush(stderr);
+
+       /*
+        * wait for START message from Prime Client
+        * sfs_syncd (rpc server) sends a SIGUSR1 signal;
+        * user can also terminate experiment anytime they wish
+        * with SIGINT or SIGTERM signal
+        */
+       (void) pause();
+       (void) fprintf(stderr, "%s Received.",lad_timestamp());
+       (void) fflush(stderr);
+
+    } /* send READY and got START message */
+
+    (void) fprintf(stderr, "\n");
+    if (Timed_run) {
+       if (Prime_client) {
+           (void) fprintf(stderr, "%s Starting %d seconds test run.\n",
+                   lad_timestamp(), Runtime - MULTICLIENT_OFFSET);
+       } else {
+           (void) fprintf(stderr, "%s Starting %d seconds test run.\n",
+                   lad_timestamp(), Runtime);
+       }
+    } else {
+       (void) fprintf(stderr, "%s Starting %d call test run.\n",
+               lad_timestamp(), Ops[TOTAL].target_calls);
+    }
+    (void) fflush(stderr);
+
+    /* signal child processes to go */
+    (void) generic_kill(0, SIGUSR1);
+
+    if (Timed_run)
+       (void) sleep(Runtime);
+
+#if (defined(_XOPEN_SOURCE) || defined(USE_POSIX_SIGNALS))
+    sig_act.sa_handler = SIG_DFL;
+    (void)sigemptyset(&sig_act.sa_mask);
+    sig_act.sa_flags = 0;
+    if (sigaction(SIGCHLD,&sig_act,&old_sig_act) == -1) {
+        perror("sigaction failed: SIGCHLD");
+        exit(74);
+    }
+#else
+    (void) signal(SIGCHLD, SIG_DFL);
+#endif
+
+    if (Timed_run) {
+       /*
+        * The parent and the prime are both sleeping for Runtime.
+        * If the parent wakes up first, he'll tell the children to stop.
+        * If the prime wakes up first, he'll send an SIGALRM (via syncd)
+        * to the parent.  That alarm may arrive while the parent is still
+        * asleep, which is ok, or after he has starting running.  Since
+        * the parent SIGARLM catcher does nothing, there is no harm done
+        * by the extra signal in this case.
+        *
+        * Perhaps, if running multi we should just wait (pause()) for
+        * the STOP signal, like we waited for the start signal.  It would
+        * be more obvious.  The only drawback is the OTW rpc delay in
+        * receiving the stop signal from the prime.
+        */
+       (void) generic_kill(0, SIGUSR2); /* tell children to finish */
+    }
+
+    /* Wait for all the children to finish/die */
+    while (wait((int *) 0) != -1) {
+       /* nop */
+    }
+
+    (void) fprintf(stderr, "%s Completed.", lad_timestamp());
+    (void) fflush(stdout);
+    (void) fflush(stderr);
+
+    /* Initialize and sum up counters */
+    collect_counters(children);
+    if ((invalid_run = check_counters()) == 0)
+       invalid_run = check_parameters(iodist_file, mix_file, runtime_val);
+
+    /* print test results */
+    print_results(children, load, mix_file,
+                 invalid_run, runtime_val, iodist_file);
+
+    /*
+     * if multi-client execution then tell Prime client that
+     * I'm done with 'real' work and wait for move-data message
+     * and send data across
+     */
+    if (Prime_client) {
+       (void) fprintf(stderr,
+                       "%s Sending DONE-TEST message to Prime Client(%s).\n",
+                       lad_timestamp(), Prime_client);
+       if ((result =
+           (int) signal_Prime_Client("CLIENT_SIGNAL",""))
+               == (int) RPC_SUCCESS) {
+           (void) fprintf(stderr, "%s Completed.", lad_timestamp());
+           (void) fflush(stderr);
+       } else {
+           Saveerrno = errno;
+           (void) fprintf(stderr, "\n");
+           (void) fprintf(stderr,
+                   "%s:  error %d sending DONE-TEST message to Prime Client\n",
+                   sfs_Myname, result);
+           errno = Saveerrno;
+           perror("signal_Prime_Client");
+           /* cleanup and exit */
+           (void) generic_kill(0, SIGINT);
+           exit(75);
+       }
+
+       /*
+        * wait for MOVE-DATA message from Prime Client before
+        * sending send results.
+        */
+       (void) fprintf(stderr, "\n");
+       (void) fprintf(stderr,
+               "%s Waiting on MOVE-DATA message from Prime Client(%s).\n",
+               lad_timestamp(), Prime_client);
+       (void) fflush(stderr);
+       (void) pause();
+       (void) fprintf(stderr, "%s Received.", lad_timestamp());
+       (void) fprintf(stderr, "\n");
+       (void) fprintf(stderr, "%s Sending results to Prime Client(%s)\n",
+               lad_timestamp(), Prime_client);
+       (void) fflush(stderr);
+
+
+       if ((result = (int) signal_Prime_Client("CLIENT_DATA",
+           Client_results)) == (int) RPC_SUCCESS) {
+           (void) fprintf(stderr, "%s Completed.\n", lad_timestamp());
+           (void) fflush(stderr);
+       } else {
+           Saveerrno = errno;
+           (void) fprintf(stderr, "\n");
+           (void) fprintf(stderr,
+                   "%s: error %d sending client's result to Prime Client\n",
+                   sfs_Myname, result);
+           errno = Saveerrno;
+           perror("signal_Prime_Client");
+           /* cleanup and exit */
+           (void) generic_kill(0, SIGINT);
+           exit(76);
+       }
+    } /* sent done, got move-data and sent data */
+
+    (void) fprintf(stdout,"\n");
+    (void) fprintf(stdout,
+    "************************************************************************");
+    (void) fprintf(stdout,"\n");
+
+} /* parent */
+
+
+/*
+ * ------------------------  Utility Routines  --------------------------
+ */
+
+
+/*
+ * Monitor Logfile until its size reaches 'children' bytes.
+ * This means that all of the children are waiting for the next instruction.
+ */
+static void
+synchronize_children(
+    int                children)
+{
+    struct stat        statb;  /* for fstat */
+
+    do {
+       (void) sleep(1);
+       if (fstat(Log_fd, &statb) == -1) {
+           (void) fprintf(stderr, "%s: can't stat log %s", sfs_Myname, Logname);
+           (void) generic_kill(0, SIGINT);
+           exit(77);
+       }
+    } while (statb.st_size < children);
+
+    /*
+     * Truncate the log file
+     */
+    (void)close(Log_fd);
+    Log_fd = open(Logname, (O_RDWR | O_CREAT | O_TRUNC | O_APPEND), 0666);
+    if (Log_fd == -1) {
+       (void) fprintf(stderr, "%s: can't truncate log %s",
+                               sfs_Myname, Logname);
+       (void) generic_kill(0, SIGINT);
+       exit(78);
+    }
+
+}  /* synchronize_children */
+
+
+/*
+ * Multi-client execution support routine.
+ * Call remote procedure on Prime client
+ * to send message to sfs_prime_clnt program.
+ * The message will contain a type field set to 'type',
+ * and a data field set to 'data'.
+ */
+static int
+signal_Prime_Client(
+    char *             type,
+    char *             data)
+{
+    static CLIENT *    clnt_handle = NULL;
+    static int         transaction_id = 0;
+    int *              result;
+    static int         socket;
+    sync_string                sync_signal;
+    char               transaction_string[MAX_STR1_LEN];
+    char               buf[128];
+
+    if ((int)strlen(data) > MAX_STR2_LEN) {
+       (void) fprintf(stderr,
+                       "%s: %s too much data len = %d max = %d\n",
+                       sfs_Myname, Prime_client, strlen(data),
+                       MAX_STR2_LEN);
+       return((int)RPC_CANTENCODEARGS);
+    }
+
+    if (clnt_handle == NULL) {
+       struct sockaddr_in      prime_addr;
+       struct hostent *        host_info;
+
+       socket = RPC_ANYSOCK;
+
+       /* get host information for prime_client */
+       if ((host_info = gethostbyname(Prime_client)) == NULL) {
+           (void) fprintf(stderr, "%s: %s is unknown host\n",
+                       sfs_Myname, Prime_client);
+           return ((int) RPC_UNKNOWNHOST);
+       }
+
+       (void) memset((char *) &prime_addr, '\0', sizeof(prime_addr));
+       (void) memmove((char *) &prime_addr.sin_addr,
+                       (char *) host_info->h_addr, host_info->h_length);
+
+       prime_addr.sin_family = AF_INET;
+       prime_addr.sin_port =  0;
+
+       /*
+        * Create client "handle" used for calling SFS_SYNCPROG on the
+        * Prime Client. We tell the RPC package to use the "tcp"
+        * protocol when contacting the prime_client.
+        */
+       clnt_handle = clnttcp_create(&prime_addr, SFS_SYNCPROG,
+                       SFS_SYNCVERS, &socket, MAX_STR2_LEN, MAX_STR2_LEN);
+
+       if (clnt_handle == ((CLIENT *) NULL)) {
+           /*
+            * Couldn't establish connection with the Prime_Client.
+            * Print error message and return error.
+            */
+           clnt_pcreateerror(Prime_client);
+           (void) fprintf(stderr,
+               "%s: %s Could not establish client handle to contact %s\n",
+               lad_timestamp(), sfs_Myname, Prime_client);
+           return((int) RPC_FAILED);
+       }
+    }
+
+    /* fill up xdr structure with data to send to Prime Client */
+    (void) sprintf(transaction_string,"%d_%i", Client_num, ++transaction_id);
+    sync_signal.clnt_type = type;
+    sync_signal.clnt_id = Client_num;
+    sync_signal.clnt_data = data;
+    sync_signal.clnt_transaction = transaction_string;
+
+    /* Call the remote procedure "signal_sfs_1" on the Prime Client */
+    result = signal_sfs_1(&sync_signal, clnt_handle);
+    if (result == NULL) {
+       /*
+        * An error occurred while making RPC to the Prime Client.
+        * Print error message and return error.
+        */
+       sprintf(buf, "%s Transaction %s: Could not call prime client %s",
+                       lad_timestamp(), transaction_string, Prime_client);
+       clnt_perror(clnt_handle, buf);
+       return((int) RPC_CANTSEND);
+    }
+
+    /* OK, we successfully called the remote procedure. */
+    if (*result == 0) {
+       /*
+        * remote procedure was unable to successfully perform required
+        * operation on the Prime Client.
+        * Print error message and return error.
+        */
+       (void) fprintf(stderr,
+                       "%s: %s Prime Client couldn't write to PC_sync file \n",
+                       sfs_Myname, Prime_client);
+       return((int) RPC_FAILED);
+    }
+
+    /* remote procedure success - wrote to Prime Client sync file */
+    return((int) RPC_SUCCESS);
+
+} /* signal_Prime_Client */
+
+
+/*
+ * Read results arrays for 'children' children from Logfile
+ * and accumulate them in "Ops".
+ * Complain about any problems we see with the log file.
+ */
+static void
+collect_counters(
+    int                        children)
+{
+    int                                i;
+    int                                j;
+    struct stat                        statb;
+    sfs_results_report_type    report; /* final results log */
+    int                                Saveerrno;
+
+    if (fstat(Log_fd, &statb) == -1) {
+       Saveerrno = errno;
+       (void) fprintf(stderr, "%s: can't stat log %s ", sfs_Myname, Logname);
+       errno = Saveerrno;
+       perror(Logname);
+       (void) generic_kill(0, SIGINT);
+       exit(79);
+    }
+
+    if (statb.st_size != (children * sizeof(report))) {
+       (void) fprintf(stderr, "%s: log file %s has bad format\n",
+                       sfs_Myname, Logname);
+       (void) generic_kill(0, SIGINT);
+       exit(80);
+    }
+
+    if (lseek(Log_fd, 0L, 0) == -1) {
+       Saveerrno = errno;
+       (void) fprintf(stderr, "%s: can't lseek log %s ", sfs_Myname, Logname);
+       errno = Saveerrno;
+       perror("lseek");
+       (void) generic_kill(0, SIGINT);
+       exit(81);
+    }
+
+    for (j = 0; j < NOPS + 1; j++) {
+       Ops[j].results.good_calls = 0;
+       Ops[j].results.bad_calls = 0;
+       Ops[j].results.fast_calls = 0;
+       Ops[j].results.time.sec = 0;
+       Ops[j].results.time.usec = 0;
+       Ops[j].results.msec2 = 0;
+    }
+    Total_fss_bytes = 0;
+    Least_fss_bytes = 0;
+    Most_fss_bytes = 0;
+    Base_fss_bytes = 0;
+
+    for (i = 0; i < children; i++) {
+       if (read(Log_fd, (char *) &report, sizeof(report)) == -1) {
+           Saveerrno = errno;
+           (void) fprintf(stderr, "%s: can't read log %s", sfs_Myname, Logname);
+           errno = Saveerrno;
+           perror("Logname");
+           (void) generic_kill(0, SIGINT);
+           exit(82);
+       }
+
+       for (j = 0; j < NOPS + 1; j++) {
+           Ops[j].results.good_calls += report.results_buf[j].good_calls;
+           Ops[j].results.bad_calls += report.results_buf[j].bad_calls;
+           Ops[j].results.fast_calls += report.results_buf[j].fast_calls;
+           ADDTIME(Ops[j].results.time, report.results_buf[j].time);
+           Ops[j].results.msec2 += report.results_buf[j].msec2;
+       }
+       Total_fss_bytes += report.total_fss_bytes;
+       Least_fss_bytes += report.least_fss_bytes;
+       Most_fss_bytes += report.most_fss_bytes;
+       Base_fss_bytes += report.base_fss_bytes;
+    }
+
+} /* collect_counters */
+
+
+/*
+ * Check the parameters for validity.
+ */
+static int
+check_parameters(
+char * iodist_file,
+char * mix_file,
+int    runtime_val)
+{
+    int retval = 0;
+    char detail[40];
+
+    detail[0] = '\0';
+
+    if (iodist_file != NULL) {
+       retval = INVALID_IODIST;
+    }
+    if (mix_file != NULL) {
+       retval = INVALID_MIX;
+    }
+    if (runtime_val != DEFAULT_RUNTIME) {
+       (void) sprintf(detail, "%d != %d", runtime_val, DEFAULT_RUNTIME);
+       retval = INVALID_RUNTIME;
+    }
+    if (Access_percent != DEFAULT_ACCESS) {
+       (void) sprintf(detail, "%d != %d", Access_percent, DEFAULT_ACCESS);
+       retval = INVALID_ACCESS;
+    }
+    if (Append_percent != DEFAULT_APPEND) {
+       (void) sprintf(detail, "%d != %d", Append_percent, DEFAULT_APPEND);
+       retval = INVALID_APPEND;
+    }
+    if (Kb_per_block != DEFAULT_KB_PER_BLOCK) {
+       (void) sprintf(detail, "%d != %d", Kb_per_block, DEFAULT_KB_PER_BLOCK);
+       retval = INVALID_KB;
+    }
+    if (Files_per_dir != DEFAULT_FILES_PER_DIR) {
+       (void) sprintf(detail, "%d != %d", Files_per_dir, DEFAULT_FILES_PER_DIR);
+       retval = INVALID_NDIRS;
+    }
+    if (Fss_delta_percent != DEFAULT_DELTA_FSS) {
+       (void) sprintf(detail, "%d != %d",
+                               Fss_delta_percent, DEFAULT_DELTA_FSS);
+       retval = INVALID_FSS;
+    }
+    if (Biod_max_outstanding_reads < DEFAULT_BIOD_MAX_READ) {
+       (void) sprintf(detail, "%d < %d",
+                       Biod_max_outstanding_reads, DEFAULT_BIOD_MAX_READ);
+       retval = INVALID_BIODREAD;
+    }
+    if (Tot_client_num_symlinks != DEFAULT_NSYMLINKS) {
+       (void) sprintf(detail, "%d != %d",
+                       Tot_client_num_symlinks, DEFAULT_NSYMLINKS);
+       retval = INVALID_NSYMLINKS;
+    }
+    if (Biod_max_outstanding_writes < DEFAULT_BIOD_MAX_WRITE) {
+       (void) sprintf(detail, "%d < %d",
+                       Biod_max_outstanding_writes, DEFAULT_BIOD_MAX_WRITE);
+       retval = INVALID_BIODWRITE;
+    }
+    if (Warmuptime != DEFAULT_WARMUP) {
+       (void) sprintf(detail, "%d != %d",
+                       Warmuptime, DEFAULT_WARMUP);
+       retval = INVALID_WARMUP;
+    }
+
+    if (retval != 0)
+       (void) fprintf(stdout,
+               "%s: INVALID RUN, ILLEGAL PARAMETER: Non-standard %s %s\n",
+               sfs_Myname, invalid_str[retval], detail);
+    return (retval);
+}
+
+/*
+ * Check the results in Ops[] for validity.
+ */
+static int
+check_counters(void)
+{
+    double     mix_pcnt;
+    int                bad_pcnt;
+    int                i;
+    int                ret = 0;
+
+    if (Ops[TOTAL].results.good_calls <= 0) {
+       (void) fprintf(stdout, "%s: INVALID RUN %s\n",
+                               sfs_Myname, invalid_str[INVALID_GOODCALLS]);
+       ret = INVALID_GOODCALLS;
+    }
+    if (Ops[TOTAL].results.good_calls != 0)
+        bad_pcnt = (Ops[TOTAL].results.bad_calls * 100)
+              / Ops[TOTAL].results.good_calls;
+    else
+       bad_pcnt = 100;
+
+    if (bad_pcnt >= 1) {
+       (void) fprintf(stdout, "%s: INVALID RUN, %d%% %s\n",
+
+                       sfs_Myname, bad_pcnt,
+                       invalid_str[INVALID_FAILEDRPC]);
+       ret = INVALID_FAILEDRPC;
+    }
+
+    if (Ops[TOTAL].results.good_calls == 0) {
+       (void) fprintf(stdout, "%s: INVALID RUN, no good calls\n", sfs_Myname);
+       return (INVALID_NOTMIX);
+    }
+
+    for (i = 0; i < NOPS; i++) {
+       mix_pcnt = ((double)Ops[i].results.good_calls /
+                                       Ops[TOTAL].results.good_calls) * 100.0;
+       if (mix_pcnt != (double)Ops[i].mix_pcnt) {
+           if ((mix_pcnt - (double)Ops[i].mix_pcnt > 1.5) ||
+               ((double)Ops[i].mix_pcnt - mix_pcnt > 1.5)) {
+               (void) fprintf(stdout, "%s: INVALID RUN, %s target %d%% actual %4.1f%% %s\n",
+
+                       sfs_Myname, Ops[i].name, Ops[i].mix_pcnt, mix_pcnt,
+                       invalid_str[INVALID_NOTMIX]);
+               ret = INVALID_NOTMIX;
+           }
+       }
+    }
+
+    return (ret);
+
+} /* check_counters */
+
+
+/*
+ * Print the test run results, for 'load' load, the operation percentages
+ * in 'mixfile' percentages, and 'children' processes.
+ */
+static void
+print_results(
+    int                                children,
+    int                                load,
+    char *                     mix_file,
+    int                                invalid_flag,
+    int                                runtime_val,
+    char *                     iodist_file)
+{
+    uint_t                     runtime;
+    uint_t                     total_msec;
+    uint_t                     msec;
+    uint_t                     total_calls;
+    uint_t                     calls;
+    int                                i;
+    double                     squared_time_msec;
+    double                     sum2_msec;
+    double                     var_msec;
+    double                     stdev_msec;
+    double                     sq_conf_interval_msec;
+    double                     conf_interval_msec;
+    sfs_op_type *              op_ptr;
+    sfs_results_type *         results_ptr;
+    char                       result_string[MAX_LINE_LEN];
+
+
+    /* compute total time for all ops combined */
+    total_msec = 0;
+    for (i = 0; i < NOPS; i++) {
+       total_msec += Ops[i].results.time.sec * 1000;
+       total_msec += Ops[i].results.time.usec / 1000;
+    }
+
+    /*
+     * Report statistics based on successful calls only.  The per
+     * operation routines accumulate time and count only good_calls.
+     */
+    total_calls = Ops[TOTAL].results.good_calls;
+
+
+    /*
+     * Print the client's test parameters
+     */
+    (void) fprintf(stderr, "\n\nClient Test Parameters: \n");
+    (void) fprintf(stderr, "\tNumber of processes = %d\n", children);
+    (void) fprintf(stderr, "\tRequested Load (NFS V%d operations/second) = %d\n",
+                   nfs_version, load);
+    (void) fprintf(stderr, "\tMaximum number of outstanding biod writes = %d\n",
+                   Biod_max_outstanding_writes);
+    (void) fprintf(stderr, "\tMaximum number of outstanding biod reads = %d\n",
+                   Biod_max_outstanding_reads);
+    (void) fprintf(stderr, "\tWarm-up time (seconds) = %d\n\tRun time (seconds) = %d\n",
+                   Warmuptime, runtime_val);
+    if (mix_file)
+       (void) fprintf(stderr,"\tNFS Mixfile = %s\n", mix_file);
+    if (iodist_file)
+       (void) fprintf(stderr,"\tBlock Size Distribution file = %s\n",
+                       iodist_file);
+    (void) fprintf(stderr, "\tFile Set = %4d Files created for I/O operations\n",
+               (Tot_client_num_io_files/children + 1) * children);
+    (void) fprintf(stderr, "\t\t   %4d Files accessed for I/O operations\n",
+               (((Tot_client_num_io_files/children + 1) * Access_percent)
+                  / 100) * children);
+    (void) fprintf(stderr, "\t\t   %4d Files for non-I/O operations\n",
+               (Tot_client_num_non_io_files/children + 1) * children);
+    (void) fprintf(stderr, "\t\t   %4d Symlinks\n",
+               (Tot_client_num_symlinks/children + 1) * children);
+    (void) fprintf(stderr, "\t\t   %4d Directories\n",
+               ((Tot_client_num_io_files/children + 1) / Files_per_dir ) * children);
+    (void) fprintf(stderr, "\t\t\tAdditional non-I/O files created as necessary\n\n");
+
+    (void) sprintf(Client_results,"%d %d %d %d %d %d\n",
+       nfs_version,
+       (Tot_client_num_io_files/children + 1) * children,
+       (((Tot_client_num_io_files/children + 1) * Access_percent)
+               / 100) *children,
+       (Tot_client_num_non_io_files/children + 1) * children,
+       (Tot_client_num_symlinks/children + 1) * children,
+       ((Tot_client_num_io_files/children + 1) / Files_per_dir ) * children);
+
+    /* print the client's results header information */
+    (void) fprintf(stderr, "\nSPEC SFS Benchmark Version %s, Creation - %s\n",
+                                SFS_VERSION_NUM, SFS_VERSION_DATE);
+    (void) fprintf(stdout, "SFS Single Client (%s) Results, %s\n",
+                   lad_hostname, lad_timestamp());
+    (void) fflush(stdout);
+
+    /* print column headers for per operation statistics */
+    (void) fprintf(stdout,
+"----------------------------------------------------------------------------\n");
+    (void) fprintf(stdout, "\n");
+    (void) fprintf(stdout,
+"NFS V%d     Target Actual   NFS    NFS    Mean     Std Dev  Std Error   Pcnt \n",
+nfs_version);
+    (void) fprintf(stdout,
+"Op           NFS    NFS     Op     Op    Response Response of Mean,95%%  of  \n");
+    (void) fprintf(stdout,
+"Type         Mix    Mix   Success Error   Time     Time    Confidence  Total\n");
+    (void) fprintf(stdout,
+"             Pcnt   Pcnt   Count  Count  Msec/Op  Msec/Op  +- Msec/Op  Time \n");
+    (void) fprintf(stdout,
+"----------------------------------------------------------------------------\n");
+    (void) fflush(stdout);
+
+    /* print per operation statistics */
+    for (i = 0; i < NOPS; i++) {
+       /* init to 0 */
+       squared_time_msec = 0.0;
+       sum2_msec = 0.0;
+       calls = 0;
+       msec = 0;
+       stdev_msec = 0;
+
+       op_ptr = &Ops[i];
+       results_ptr = &op_ptr->results;
+
+       /* get the number successful calls and total time */
+       calls = op_ptr->results.good_calls;
+       msec = (results_ptr->time.sec * 1000)
+              + (results_ptr->time.usec / 1000);
+
+       /* compute the standard deviation for the mean response time */
+       if (calls <= 1)
+           stdev_msec = 0;
+       else {
+           /* get the standard deviation */
+           squared_time_msec = results_ptr->msec2;
+           /* compute the square of the total elapsed time */
+           sum2_msec = (results_ptr->time.sec * 1000.0)
+                        + (results_ptr->time.usec / 1000.0);
+           sum2_msec *= sum2_msec;
+
+           /* variance = 1/(n-1) * (sum(x^2) - 1/n * (sum(x))^2) */
+           var_msec = (squared_time_msec - (sum2_msec / calls)) / (calls-1);
+           if (var_msec == 0.0) {
+               stdev_msec = 0.0;
+           } else
+               stdev_msec = sqrt(var_msec);
+       }
+
+       /* compute the confidence interval */
+       if (calls != 0) {
+           sq_conf_interval_msec = DEFAULT_CHI_SQR_CI * (stdev_msec / calls);
+           if (sq_conf_interval_msec == 0.0) {
+               conf_interval_msec = 0.0;
+           } else
+               conf_interval_msec = sqrt(sq_conf_interval_msec);
+       } else
+           conf_interval_msec = 0.0;
+
+       /* print the per op statistics */
+       (void) fprintf(stdout,
+       "%-12s%3d%%   %4.1f%%   %5d %5d %5.2f %8.2f  %8.2f    %3.1f%%\n",
+           op_ptr->name,                                       /* op name */
+           op_ptr->mix_pcnt,                                   /* target mix */
+                                                               /* actual mix */
+           total_calls ? ((double)calls / total_calls) * 100.0 : 0.0,
+           results_ptr->good_calls,                            /* successes */
+           results_ptr->bad_calls,                             /* errors */
+           calls ? ((double)msec / calls) : 0.0,               /* msec/call */
+           stdev_msec,                                         /* std dev */
+           conf_interval_msec,                                 /* conf int */
+                                                               /* % of time */
+           total_msec ? ((double)msec / total_msec) * 100 : 0.0);
+       (void) fflush(stdout);
+
+       /*
+        * Store client data in result_string.
+        * This string is different from client result display.
+        * The  squared_time_msec and sum2_msec values are passed along
+        * to be used by the prime client to calculate the stddev value for
+        * each operation.
+        */
+       if (Prime_client) {
+       (void) sprintf(result_string,
+       "%-12s   %3d%% %3.1f%% %5d  %5d %4ld.%1ld %6.2f  %3.1f%% %f %f\n",
+           op_ptr->name,                                       /* op name */
+           op_ptr->mix_pcnt,                                   /* target mix */
+                                                               /* actual mix */
+           total_calls ? ((double)calls / total_calls) * 100.0 : 0.0,
+           results_ptr->good_calls,                            /* successes */
+           results_ptr->bad_calls,                             /* errors */
+           results_ptr->time.sec,                              /* total time1*/
+           results_ptr->time.usec / 100000,                    /* total time2*/
+           calls ? ((double)msec / calls) : 0.0,               /* msec/call */
+                                                               /* % of time */
+           total_msec ? ((double)msec / total_msec) * 100 : 0.0,
+           squared_time_msec,                                  /* sum of sqs */
+           sum2_msec);                                         /* sq of sums */
+           (void) strcat(Client_results, result_string);
+       }
+
+    } /* end for each op */
+
+    (void) fprintf(stdout,
+"----------------------------------------------------------------------------\n\n");
+    (void) fflush(stdout);
+
+    /* Average child runtime.  (should this be the longest runtime?) */
+    runtime = Ops[TOTAL].results.time.sec / children;
+
+    /* Print summary */
+    (void) fprintf(stdout,
+       "      ------------------------------------------------------------\n");
+    (void) fprintf(stdout,
+       "      | SPEC SFS VERSION %6s SINGLE CLIENT RESULTS SUMMARY    |\n",
+                                                       SFS_VERSION_NUM);
+    (void) fprintf(stdout,
+       "      ------------------------------------------------------------\n");
+    (void) fprintf(stdout, "NFS V%d THROUGHPUT: ", nfs_version);
+    (void) fprintf(stdout,
+                   "%4d.%02d Ops/Sec   AVG. RESPONSE TIME: %4d.%02d Msec/Op\n",
+                   runtime ? (total_calls / runtime) : 0,
+                   runtime ? ((total_calls % runtime) * 100 / runtime) : 0,
+                   total_calls ? (total_msec / total_calls) : 0,
+                   total_calls ? ((total_msec % total_calls) * 100 / total_calls) : 0);
+    (void) fprintf(stdout, "%s PROTOCOL\n", Tcp ? "TCP" : "UDP");
+    (void) fprintf(stdout, "FAST CALLS: %d\n", Ops[TOTAL].results.fast_calls);
+    (void) fprintf(stdout, "NFS MIXFILE: ");
+    if (mix_file)
+       (void) fprintf(stdout,"%s\n", mix_file);
+    else
+       (void) fprintf(stdout,"[ SFS Default ]\n");
+    (void) fprintf(stdout, "CLIENT REQUESTED LOAD: %d Ops/Sec \n", load);
+    (void) fprintf(stdout,
+                       "TOTAL NFS OPERATIONS: %-6d      TEST TIME: %d Sec \n",
+                       total_calls, runtime);
+    (void) fprintf(stdout, "FILE SET SIZE CREATED: %d KB\n",
+                                                       Total_fss_bytes);
+    (void) fprintf(stdout,
+               "FILE SET SIZE ACCESSED: %d - %d KB  (%d%% to %d%% of Base)\n",
+               Least_fss_bytes, Most_fss_bytes,
+               (100 * Least_fss_bytes) / Base_fss_bytes,
+               (100 * Most_fss_bytes) / Base_fss_bytes);
+    (void) fprintf(stdout, "\n");
+    (void) fprintf(stdout,
+    "------------------------------------------------------------------------");
+    (void) fprintf(stdout, "\n\n");
+    (void) fflush(stdout);
+
+    /*
+     * store client summary results and Invalid run indicator
+     * to send to the Prime_client
+     */
+    if (Prime_client) {
+       (void) sprintf(result_string,"%d.%02d %d.%02d %d %d %d %d %d %d %d\n",
+           runtime ? (total_calls / runtime) : 0,          /* ops/sec1 */
+           runtime ? ((total_calls % runtime) * 100 / runtime) : 0, /* ops/sec2 */
+           total_calls ? (total_msec / total_calls) : 0,       /* mean1 */
+           total_calls ? ((total_msec % total_calls) * 100 / total_calls) : 0, /* mean2 */
+           runtime,                                        /* run time */
+           total_calls,                                    /* # ops */
+           invalid_flag,                                   /* valid flag */
+           Total_fss_bytes,                                /* total fileset */
+           Least_fss_bytes,                                /* fileset low */
+           Most_fss_bytes,                                 /* fileset high */
+           Base_fss_bytes);                                /* fileset base */
+       (void) strcat(Client_results, result_string);
+    }
+
+} /* print_results */
+
+
+/* ARGSUSED */
+static void
+sfs_reaper(
+    int                sig_id)
+{
+    (void) fprintf(stderr, "%s: caught unexpected SIGCHLD. Exiting...\n",
+                      sfs_Myname);
+    /* cleanup and exit */
+    (void) signal_Prime_Client("CLIENT_STOP", "");
+    (void) generic_kill(0, SIGINT);
+    exit(83);
+}
+/* sfs_c_pnt.c */