Add proper per-file copyright notices/licenses and top-level license.
[bluesky.git] / TBBT / trace_play / sfs_m_prm.c
1 #ifndef lint
2 static char sccsid[] = "@(#)sfs_m_prm.c 2.1     97/10/23";
3 #endif
4
5 /*
6  *   Copyright (c) 1992-1997,2001 by Standard Performance Evaluation Corporation
7  *      All rights reserved.
8  *              Standard Performance Evaluation Corporation (SPEC)
9  *              6585 Merchant Place, Suite 100
10  *              Warrenton, VA 20187
11  *
12  *      This product contains benchmarks acquired from several sources who
13  *      understand and agree with SPEC's goal of creating fair and objective
14  *      benchmarks to measure computer performance.
15  *
16  *      This copyright notice is placed here only to protect SPEC in the
17  *      event the source is misused in any manner that is contrary to the
18  *      spirit, the goals and the intent of SPEC.
19  *
20  *      The source code is provided to the user or company under the license
21  *      agreement for the SPEC Benchmark Suite for this product.
22  */
23
24 /*****************************************************************
25  *                                                               *
26  *      Copyright 1991,1992  Legato Systems, Inc.                *
27  *      Copyright 1991,1992  Auspex Systems, Inc.                *
28  *      Copyright 1991,1992  Data General Corporation            *
29  *      Copyright 1991,1992  Digital Equipment Corporation       *
30  *      Copyright 1991,1992  Interphase Corporation              *
31  *      Copyright 1991,1992  Sun Microsystems, Inc.              *
32  *                                                               *
33  *****************************************************************/
34
35 /*
36  * This program is started from sfs_mgr.  It runs on some system
37  * designated as the Prime Client and synchronizes the the different
38  * phases of a SFS benchmark execution amongst multiple clients by
39  * means of RPCs.  The Prime client can also be running SFS.
40  *
41  *.Exported_routines
42  *      int main(int, char **)
43  *
44  *.Local_routines
45  *      void multi_cleanup(int)
46  *      void do_initialize(int, char **)
47  *      void sync_PC_with_clients(void)
48  *      int signal_sfs_clients(char *, int)
49  *      void print_multi_results(void)
50  *      void prog_usage(void)
51  *      void printdeadclients(void)
52  *
53  *.Revision_history
54  *      11-Jul-94       ChakChung Ng    Add codes for NFS/v3
55  *      02-Jul-92       0.1.9   Teelucksingh
56  *                              Use tcp handles for synchronization
57  *                              instead of udp ones. Added code to make
58  *                              call to shell script to start and stop
59  *                              external monitoring (no longer creates
60  *                              /tmp/SFS_START and /tmp/SFS_DONE).
61  *      10-Jan-92       0.00.19 Teelucksingh
62  *                              Added code for the Prime-Client to report
63  *                              'INVALID RUN' from any of the clients.
64  *                              Also added code to compute and report
65  *                              the aggregate 'average response time
66  *                              standard deviation values'.
67  *      04-Jan-92       0.00.18 Pawlowski
68  *                              Add hooks for raw data dump support.
69  *      04-Dec-91       0.00.15 Keith
70  *                              Include string.h for SYSV/SVR4
71  *      28-Nov-91       0.00.13 Teelucksingh
72  *                              Fixed 'multiple signals' problem.
73  *                              Sync rpcs now pass a 'transaction id'
74  *                              to 'sfs_syncd', the sync server.
75  *                              'sfs_syncd' keeps track of previous rpc
76  *                              calls that successfully executed.
77  *                              Added ANSI C features.
78  *
79  *      23-Sep-91       0.00.11 Teelucksingh
80  *                              Modified the format of sfs_prime output
81  *      17-Jun-91       Teelucksingh    Created.
82  *
83  *
84  */
85
86
87 /*
88  * -------------------------  Include Files  -------------------------
89  */
90
91 /*
92  * ANSI C headers
93  */
94 #include <stdio.h>
95 #include <stdlib.h>
96 #include <string.h>
97 #include <errno.h>
98 #include <math.h>
99 #include <ctype.h>
100 #include <signal.h>
101
102 #include <sys/types.h>
103 #include <sys/stat.h> 
104  
105 #include <sys/file.h>
106 #include <fcntl.h>
107
108 #include <unistd.h>
109
110 #include "sfs_c_def.h"
111 #include "sfs_m_def.h"
112
113 #if !defined(_XOPEN_SOURCE)
114 #include <sys/socket.h>
115 #else
116 #define AF_INET         2
117 #endif
118
119 /*
120  * -----------------------  External Definitions  -----------------------
121  */
122
123
124 /* sfs_mpr.c function declarations */
125 /* external sfs routines */
126
127 /* forward definitions for local routines */
128 static void multi_cleanup(int);
129 static void do_initialize(int, char **);
130 static void sync_PC_with_clients(void);
131 static int signal_sfs_clients(char *);
132 static void print_multi_results(void);
133 static void prog_usage(void);
134 static void printdeadclients(void);
135
136 /*
137  * -----------------------  Static Definitions  -----------------------
138  */
139
140 #define EXTRA_INIT_TIME 3600  /* extra time to initialize before timing out */
141
142 int Debug_level = 0;            /* flag indicates prime client debug mode */
143 char *sfs_Myname;                       /* program name */
144 int nfs_version;
145
146 static int Asleep = 0;          /* flag: parent sfs process is asleep */
147 static int Pc_log_fd;                  /* Prime client sync log fd */
148 static int Num_clients = 0;            /* number of clients used in run */
149 static char **Client_names; /* [HOSTNAME_LEN];   array of clients host names */
150                              /* sleep period before issuing a go ahead signal */
151 static int Prime_sleep_time = 0;
152                              /* time to wait before exiting with error */
153 static int Prime_time_out = 400;
154 static int Prime_runtime = DEFAULT_RUNTIME; /* seconds in benchmark run */
155
156 /*
157  * the Prime_client only uses the P_* variables
158  * for calculating and reporting the Aggregate
159  * run parameters.
160  */
161 static int P_children = DEFAULT_NPROCS; /* processes per client */
162 static int P_total_load = DEFAULT_LOAD; /* NFS operations per second */
163 static int P_percent_append = DEFAULT_APPEND; /* % of writes that append */
164 static int P_percent_access = DEFAULT_ACCESS; /* % of file set accessed */
165 static int P_kb_per_block = DEFAULT_KB_PER_BLOCK; /* i/o pkt block sz in KB */
166 static int P_dump_data = 0;             /* raw output switch */
167 static int P_testop = -1;               /* test mode operation number */
168 static int P_percent_fss_delta =        /* allowed change to file set */
169                                 DEFAULT_DELTA_FSS;
170                                         /* allowed change to file set */
171 static int P_warmuptime = DEFAULT_WARMUP; /* seconds to warmup */
172 static char *P_iodist_file = 0;         /* block io dist table file */
173 static char *P_mix_file = 0;            /* mix file */
174 static char *P_script_name = 0;         /* external script name */
175 static char *P_script_args = "";        /* external script parameters */
176 static int P_tcp = 0;                   /* TCP */
177 static FILE *sum_result_fp = NULL;
178
179 /*
180  * ---------------------  Biod Simulation Variables ---------------------
181  */
182 static int P_biod_max_outstanding_reads = DEFAULT_BIOD_MAX_READ;
183 static int P_biod_max_outstanding_writes = DEFAULT_BIOD_MAX_WRITE;
184
185 /* list of nfs operations - used to verify results file */
186 static char *Ops_name[NOPS] = { "null", "getattr", "setattr", "root", "lookup",
187                                 "readlink", "read", "wrcache", "write",
188                                 "create", "remove", "rename", "link",
189                                 "symlink", "mkdir", "rmdir", "readdir",
190                                 "fsstat", "access", "commit", "fsinfo",
191                                 "mknod", "pathconf", "readdirplus" };
192
193
194 /*
195  * --------------------------  Prime-client  --------------------------
196  */
197
198
199 /*
200  * SIGINT Signal Handler
201  * - rpc to all clients to cleanup and exit
202  */
203 static void
204 multi_cleanup(
205     int         sig_id)
206 {
207     /* wake up this process if asleep */
208     if (Asleep == 1) {
209         (void) generic_kill(0,SIGALRM);
210     }
211     (void) fprintf(stderr,"\n%s: Caught Signal %d SIGINT\n", sfs_Myname, sig_id);
212     (void) fprintf(stderr,"\nSending interupt signal to clients ... ");
213     (void) fflush(stderr);
214     if ((int) signal_sfs_clients("PRIME_STOP") !=0)
215         exit(9);
216     (void) fprintf(stderr,"done\n");
217     (void) fflush(stderr);
218     (void) close(Pc_log_fd);
219     (void) unlink(SFS_PRIME_SYNC_LOG);
220     exit(10);
221
222 } /* multi_cleanup */
223
224
225 /*
226  * main
227  * synchronizes multi-client sfs run
228  * - wait for 'DONE-MOUNT' from all clients
229  * - tell them to `DO-INIT`
230  * - wait for `DONE-INIT` from all clients
231  * - tell them to `DO-WARMUP`
232  * - wait for 'READY from all clients
233  * - tells them to 'START' and goes to sleep
234  * - wakes up and tells clients to 'STOP'
235  * - wait for 'DONE-TEST' from all clients
236  * - tells clients to 'MOVE-DATA'
237  * - averages multi-client data and exits
238  */
239 int
240 main(
241     int         argc,
242     char *      argv[])
243 {
244     int         i;
245     char        monitor_cmd[SFS_MAXPATHLEN+5];
246     int         nsigs = 32;             /* reasonable default */
247     FILE        *pid_fp;
248
249 #if (defined(_XOPEN_SOURCE) || defined(USE_POSIX_SIGNALS))
250     struct sigaction sig_act, old_sig_act;
251 #endif
252
253     /*
254      * Place pid in pid log file
255      */  
256     if ((pid_fp = fopen(SFS_PRM_PID, "a+")) == NULL) {
257         perror(SFS_PRM_PID);
258         exit(1);
259     }
260     (void) fprintf(pid_fp, "%d\n", getpid());
261     (void) fclose(pid_fp);
262
263     (void) fprintf(stderr, "\nSPEC SFS Benchmark Version %s, Creation - %s\n",
264                                 SFS_VERSION_NUM, SFS_VERSION_DATE);
265     (void) fflush(stderr);
266
267     /* initialize variables, parse input, etc.  */
268     do_initialize(argc, argv);
269
270     /*
271      * setup value of nsigs
272      */
273 #ifdef __NSIG
274     nsigs = __NSIG;
275 #endif
276 #ifdef _NSIG
277     nsigs = _NSIG;
278 #endif
279 #ifdef NSIG
280     nsigs = NSIG;
281 #endif
282 #if defined(SOLARIS2) && !defined(_sys_nsig)
283     nsigs = _sys_siglistn;
284 #endif
285
286     /* trap for all signals */
287
288 #if (defined(_XOPEN_SOURCE) || defined(USE_POSIX_SIGNALS))
289     /* use XOPEN signal handling */
290     sig_act.sa_handler = generic_catcher;
291     (void)sigemptyset(&sig_act.sa_mask);
292     sig_act.sa_flags = 0;
293     if (DEBUG_PARENT_GENERAL) {
294         if (nsigs == 0) {
295             (void) fprintf (stderr,
296                     "WARNING: nsigs not defined, no extra signals caught\n");
297         }
298         for (i = 1; i < nsigs; i++) {
299      /* attempt to set up signal handler for these signals gives an error. */
300             if (i!=SIGCHLD && i!=SIGKILL && i!=SIGSTOP && i!=SIGCONT) {
301                 if (sigaction(i,&sig_act,&old_sig_act) == -1) {
302                         if (errno == EINVAL)
303                                 (void) fprintf (stderr,
304                                         "Skipping invalid signal %d\n", i);
305                         else {
306                                 perror("sigaction failed");
307                                 exit(11);
308                         }
309                 }
310             }
311         }
312     }
313
314     /* signals handlers for signals used by sfs_prime */
315     sig_act.sa_handler = multi_cleanup;
316     if (sigaction(SIGINT,&sig_act,&old_sig_act) != 0) {
317                 perror("sigaction failed: SIGINT");
318                 exit(12);
319     }
320 #else
321
322     if (DEBUG_PARENT_GENERAL) {
323         if (nsigs == 0) {
324             (void) fprintf (stderr,
325                     "WARNING: nsigs not defined, no extra signals caught\n");
326         }
327         for (i = 1; i < nsigs; i++) {
328             (void) signal(i, generic_catcher);
329         }
330     }
331
332     /* set up SIGINT signal handler */
333     (void) signal(SIGINT, multi_cleanup);
334
335 #endif /* USE_POSIX_SIGNALS */
336
337     (void) fprintf(stderr, "Executing SFS Benchmark on %d Client(s).\n",
338                     Num_clients);
339     (void) fflush(stderr);
340
341     /* wait for 'DONE-MOUNT message from the clients */
342     (void) fprintf(stderr,
343            "%s Waiting on DONE-MOUNT message from %d client(s).\n",
344                     lad_timestamp(), Num_clients);
345     (void) fflush(stderr);
346
347     sync_PC_with_clients();             /* wait for clients DONE-MOUNT */
348
349     (void) fprintf(stderr, "%s Received.\n", lad_timestamp());
350     (void) fflush(stderr);
351
352     /* send DO-INIT message to all the clients  */
353     (void) fprintf(stderr, "%s Sending DO-INIT message to %d client(s).\n",
354                     lad_timestamp(), Num_clients);
355     (void) fflush(stderr);
356     if ((int) signal_sfs_clients("PRIME_SIGNAL") !=0)
357         exit(13);
358     (void) fprintf(stderr, "%s Completed.\n", lad_timestamp());
359     (void) fflush(stderr);
360
361     /* wait for 'DONE-INIT' message from the clients */
362     (void) fprintf(stderr,
363            "%s Waiting on DONE-INIT message from %d client(s).\n",
364                     lad_timestamp(), Num_clients);
365     (void) fflush(stderr);
366
367     /*
368      * add an extra time to time_out value.
369      * initializing the SFS testdirs on clients can take a while.
370      */
371     Prime_time_out += EXTRA_INIT_TIME;
372     sync_PC_with_clients();             /* wait for clients DONE-INIT */
373     Prime_time_out -= EXTRA_INIT_TIME;        /* reset time_out */
374
375     (void) fprintf(stderr, "%s Received.\n", lad_timestamp());
376     (void) fflush(stderr);
377
378     /* send DO-WARMUP message to all the clients  */
379     (void) fprintf(stderr, "%s Sending DO-WARMUP message to %d client(s).\n",
380                     lad_timestamp(), Num_clients);
381     (void) fflush(stderr);
382     if ((int) signal_sfs_clients("PRIME_SIGNAL") !=0)
383         exit(14);
384     (void) fprintf(stderr, "%s Completed.\n", lad_timestamp());
385     (void) fflush(stderr);
386
387     /* wait for 'READY' message from the clients */
388     (void) fprintf(stderr, "%s Waiting on READY message from %d client(s).\n",
389                     lad_timestamp(), Num_clients);
390     (void) fflush(stderr);
391
392     (void) sleep(P_warmuptime);
393
394     sync_PC_with_clients();             /* wait for clients READY */
395
396     (void) fprintf(stderr, "%s Received.\n", lad_timestamp());
397     (void) fflush(stderr);
398
399     /*
400      * call the program to trigger START of external monitoring
401      */
402      if (P_script_name) {
403         (void) sprintf(monitor_cmd,"%s %s %s",P_script_name,
404                         "START",P_script_args);
405         if (system(monitor_cmd) != 0) {
406                 (void) fprintf(stderr,"%s: external monitoring command (%s) failed - %d - continuing.\n ",
407                         sfs_Myname, monitor_cmd, errno);
408                 (void) fflush(stderr);
409                 P_script_name = NULL;
410         }
411
412      }
413
414     /*
415      * wait period before telling clients to START - gives external
416      * performance monitoring utilities enough time to start up.
417      * Value set in sfs_rc (PRIME_SLEEP) - default is 0 seconds.
418      */
419     (void) sleep(Prime_sleep_time);
420
421     /* send START message to all the clients  */
422     (void) fprintf(stderr, "%s Sending START message to %d client(s).\n",
423                     lad_timestamp(), Num_clients);
424     (void) fflush(stderr);
425     if ((int) signal_sfs_clients("PRIME_SIGNAL") !=0)
426         exit(15);
427     (void) fprintf(stderr, "%s Completed.\n", lad_timestamp());
428     (void) fflush(stderr);
429
430     /*
431      * Sleep for <Prime_runtime> seconds
432      * and then send STOP message to tell the sfs clients
433      * that is time to wrap things up.
434      */
435     /* set the Asleep flag go to sleep while clients are executing sfs */
436     Asleep = 1;
437     (void) sleep(Prime_runtime);
438     Asleep = 0;
439
440     (void) fprintf(stderr, "%s Sending STOP message to %d client(s).\n",
441                         lad_timestamp(), Num_clients);
442     (void) fflush(stderr);
443     if ((int) signal_sfs_clients("PRIME_ALARM") !=0)
444         exit(16);
445     (void) fprintf(stderr, "%s Completed.\n", lad_timestamp());
446     (void) fflush(stderr);
447
448
449     /* wait for DONE-TEST message from clients indicating they completed run */
450     (void) fprintf(stderr, "%s Waiting on DONE-TEST message from %d client(s).\n",
451                     lad_timestamp(), Num_clients);
452     (void) fflush(stderr);
453     sync_PC_with_clients();
454     (void) fprintf(stderr, "%s Received.\n", lad_timestamp());
455     (void) fflush(stderr);
456
457     /*
458      * call the program to trigger STOP of external monitoring
459      */
460      if (P_script_name) {
461         (void) sprintf(monitor_cmd,"%s %s %s",P_script_name,
462                         "DONE",P_script_args);
463         if (system(monitor_cmd) != 0) {
464                 (void) fprintf(stderr,"%s: external monitoring command (%s) failed - %d - continuing.\n ",
465                         sfs_Myname, monitor_cmd, errno);
466                 (void) fflush(stderr);
467                 P_script_name = NULL;
468         }
469      }
470
471     /* give enough time to stop external performance monitoring utilities.  */
472     (void) sleep(Prime_sleep_time);
473
474     /*
475      * send MOVE-DATA message to Clients to move data across
476      */
477     (void) fprintf(stderr, "%s Sending MOVE-DATA message to %d client(s).\n",
478                     lad_timestamp(), Num_clients);
479     (void) fflush(stderr);
480     if ((int) signal_sfs_clients("PRIME_SIGNAL") !=0)
481         exit(17);
482     (void) fprintf(stderr, "%s Completed.\n", lad_timestamp());
483     (void) fflush(stderr);
484
485     /* wait for SEND-DATA message from all the clients */
486     (void) fprintf(stderr,
487                     "%s Waiting on SEND-DATA message from %d client(s).\n",
488                     lad_timestamp(), Num_clients);
489     (void) fflush(stderr);
490     sync_PC_with_clients();
491     (void) fprintf(stderr, "%s Received.\n", lad_timestamp());
492     (void) fflush(stderr);
493
494     /* summarize and print aggregate results */
495     print_multi_results();
496
497     /* close files and exit success */
498     (void) close(Pc_log_fd);
499     (void) unlink(SFS_PRIME_SYNC_LOG);
500     (void) unlink(SFS_PRM_PID);
501     return(0);
502
503 }  /* main */
504
505 /*
506  * initialize control variables, open logfiles etc.
507  */
508 static void
509 do_initialize(
510     int         argc,
511     char        *argv[])
512 {
513     int         c;
514     FILE        *check_fp;
515     int i;
516     char        *cp;
517     extern char *optarg;
518     extern int optind;
519
520
521     sfs_Myname = argv[0];
522     if (argc <= 1) {
523         prog_usage();
524         /* NOTREACHED */
525     }
526
527     while ((c = getopt(argc, argv, "a:A:b:B:C:d:f:k:K:l:m:p:QR:s:t:T:W:w:x:z")) != EOF)
528         switch (c) {
529         case 'a': /* Percent of file set to access;
530                    * used in aggregate report.
531                    */
532             if (!isdigit(optarg[0])) {
533                 (void) fprintf(stderr, "%s: illegal acces value %s\n",
534                                         sfs_Myname, optarg);
535                 exit(18);
536             }
537             P_percent_access = atoi(optarg);
538             if (P_percent_access < 0 || P_percent_access > 100) {
539                 (void) fprintf(stderr,
540                        "%s: %% access must be between 0 and 100\n",
541                         sfs_Myname);
542                 exit(19);
543             }
544             break;
545
546         case 'A': /* Percent of writes that append;
547                    * used in aggregate report.
548                    */
549             if (!isdigit(optarg[0])) {
550                 (void) fprintf(stderr, "%s: illegal append value %s\n",
551                                         sfs_Myname, optarg);
552                 exit(20);
553             }
554             P_percent_append = atoi(optarg);
555             if (P_percent_append < 0 || P_percent_append > 100) {
556                 (void) fprintf(stderr,
557                                "%s: %% append must be between 0 and 100\n",
558                                 sfs_Myname);
559                 exit(21);
560             }
561             break;
562
563         case 'b': /* Set block size distribution table file
564                    * used in aggregate report.
565                    */
566             if ((check_fp = fopen(optarg, "r")) == NULL) {
567                 cp = strerror(errno);
568                 (void) fprintf(stderr, "%s: bad block size file %s: %s\n",
569                                         sfs_Myname, optarg, cp);
570                 exit(22);
571             }
572             P_iodist_file = optarg;
573             (void) fclose(check_fp);
574             break;
575
576
577         case 'B': /* Set the per packet maximum block size
578                    * used in aggregate reporting only.
579                    */
580             if (!isdigit(optarg[0])) {
581                 (void) fprintf(stderr, "%s: illegal block size value %s\n",
582                                         sfs_Myname, optarg);
583                 exit(23);
584             }
585             P_kb_per_block = atoi(optarg);
586             if ((P_kb_per_block < 1) ||
587                         (P_kb_per_block > (DEFAULT_MAX_BUFSIZE/1024))) {
588                 (void) fprintf(stderr, "%s: illegal block size value %s\n",
589                                         sfs_Myname, optarg);
590                 exit(24);
591             }
592             break;
593
594         case 'C': /*
595                    * Set summary result file
596                    */
597             if ((sum_result_fp = fopen(optarg, "a+")) == NULL) {
598                 cp = strerror(errno);
599                 (void) fprintf(stderr,
600                         "%s: Unable to create summary result file %s: %s\n",
601                                         sfs_Myname, optarg, cp);
602                 exit(222);
603             }
604             break;
605
606         case 'd': /*
607                    * Set Debug_level
608                    */
609             Debug_level = set_debug_level(optarg);
610             break;
611
612         case 'f': /* Percent change in file set size
613                    * used in aggregate reporting only.
614                    */
615             if (!isdigit(optarg[0])) {
616                 (void) fprintf(stderr, "%s: illegal file set delta value %s\n",
617                                         sfs_Myname, optarg);
618                 exit(26);
619             }
620             P_percent_fss_delta = atoi(optarg);
621             if (P_percent_fss_delta < 0 || P_percent_fss_delta > 100) {
622                 (void) fprintf(stderr,
623                            "%s: %% file set delta must be between 0 and 100\n",
624                             sfs_Myname);
625                 exit(27);
626             }
627             break;
628
629         case 'k': /*
630                    * program to start and stop external
631                    * performance monitoring. Called at start
632                    * and completion of core load generation period.
633                    */
634             if ((check_fp = fopen(optarg, "r")) == NULL) {
635                 cp = strerror(errno);
636                 (void) fprintf(stderr,
637                         "%s: program %s protected or missing: %s\n",
638                         sfs_Myname, optarg, cp);
639                 exit(28);
640             }
641             P_script_name = optarg;
642             (void) fclose(check_fp);
643             break;
644
645         case 'K': /*
646                    * Command-line parameters for the external monitor
647                    * (see the "-k" option, above)
648                    */
649             P_script_args = optarg;
650             break;
651
652         case 'l': /* Set load
653                    * used in aggregate reporting only.
654                    */
655             if (!isdigit(optarg[0])) {
656                 (void) fprintf(stderr, "%s: illegal load value %s\n",
657                                         sfs_Myname, optarg);
658                 exit(29);
659             }
660             P_total_load = atoi(optarg);
661             if (P_total_load < 0) {
662                 (void) fprintf(stderr, "%s: load must be > 0\n", sfs_Myname);
663                 exit(30);
664             }
665             break;
666
667         case 'm': /* Set mix from a file
668                    * used in aggregate reporting only.
669                    */
670             if ((check_fp = fopen(optarg, "r")) == NULL) {
671                 cp = strerror(errno);
672                 (void) fprintf(stderr, "%s: bad mix file: %s: %s\n",
673                                 sfs_Myname, optarg, cp);
674                 exit(31);
675             }
676             P_mix_file = optarg;
677             (void) fclose(check_fp);
678             break;
679
680         case 'p': /* Set number of child processes
681                    * used in aggregate reporting only.
682                    */
683             if (!isdigit(optarg[0])) {
684                 (void) fprintf(stderr, "%s: illegal procs value %s\n",
685                                         sfs_Myname, optarg);
686                 exit(32);
687             }
688             P_children = atoi(optarg);
689             if (P_children < 0) {
690                 (void) fprintf(stderr, "%s: number of children must be > 0\n",
691                                 sfs_Myname);
692                 exit(33);
693             }
694             break;
695
696         case 'Q': /* Set NFS/TCP behaviour */
697             P_tcp = 1;
698             break;
699
700         case 'R': /* set maximum async read concurrency level
701                    * used in aggregate reporting only.
702                    */
703             if (!isdigit(optarg[0])) {
704                 (void) fprintf(stderr, "%s: illegal read count value %s\n",
705                                 sfs_Myname, optarg);
706                 exit(34);
707             }
708             P_biod_max_outstanding_reads = atoi(optarg);
709             if (P_biod_max_outstanding_reads < 0) {
710                 (void) fprintf(stderr, "%s: read count must be >= 0\n",
711                                 sfs_Myname);
712                 exit(35);
713             }
714             break;
715
716         case 's':
717              /*
718               * Set sleep time so external processes will
719               * have time to startup
720               */
721               if (!isdigit(optarg[0])) {
722                   (void) fprintf(stderr, "%s: illegal sleep value %s\n",
723                                   sfs_Myname, optarg);
724                   exit(36);
725               }
726               Prime_sleep_time = atoi(optarg);
727               break;
728
729         case 't': /* Set SFS Runtime value */
730             if (!isdigit(optarg[0])) {
731                 (void) fprintf(stderr, "%s: illegal time value %s\n",
732                                 sfs_Myname, optarg);
733                 exit(37);
734             }
735             Prime_runtime = atoi(optarg);
736             if (Prime_runtime < 0) {
737                 (void) fprintf(stderr, "%s: run time must be >= 0\n",
738                                 sfs_Myname);
739                 exit(38);
740             }
741             break;
742
743         case 'T': /* Set Test mode operation
744                    * used in aggregate reporting only.
745                    */
746             if (!isdigit(optarg[0])) {
747                 (void) fprintf(stderr, "%s: illegal time_out value %s\n",
748                                 sfs_Myname, optarg);
749                exit(39);
750             }
751             P_testop = atoi(optarg);
752             if (P_testop >= NOPS) {
753                 (void) fprintf(stderr, "%s: illegal test value %d\n",
754                                         sfs_Myname, P_testop);
755                 exit(40);
756             }
757             break;
758
759         case 'W': /* set maximum async write concurrency level
760                    * used in aggregate reporting only.
761                    */
762             if (!isdigit(optarg[0])) {
763                 (void) fprintf(stderr, "%s: illegal write count value %s\n",
764                                         sfs_Myname, optarg);
765                 exit(41);
766             }
767             P_biod_max_outstanding_writes = atoi(optarg);
768             if (P_biod_max_outstanding_writes < 0) {
769                 (void) fprintf(stderr, "%s: write count must be >= 0\n",
770                                 sfs_Myname);
771                 exit(42);
772             }
773             break;
774
775         case 'w': /* Set warmup time
776                    * used in aggregate reporting only.
777                    */
778             if (!isdigit(optarg[0])) {
779                 (void) fprintf(stderr, "%s: illegal warmup value %s\n",
780                                 sfs_Myname, optarg);
781                 exit(43);
782             }
783             P_warmuptime = atoi(optarg);
784             if (P_warmuptime < 0) {
785                 (void) fprintf(stderr, "%s: warmup time must be >= 0\n",
786                                 sfs_Myname);
787                 exit(44);
788             }
789             break;
790
791         case 'x': /* Set Prime-Client time_out value */
792             if (!isdigit(optarg[0])) {
793                 (void) fprintf(stderr,
794                                 "%s: illegal time_out value %s\n",
795                                 sfs_Myname, optarg);
796                exit(45);
797             }
798             Prime_time_out = atoi(optarg);
799             break;
800
801         case 'z': /* Do raw data dumps
802                    *  used in aggregate reporting only.
803                    */
804             P_dump_data++;
805             break;
806
807         default:
808             prog_usage();
809             /* NOTREACHED */
810         } /* end switch on argument */
811
812     Num_clients = argc - optind;
813
814     /*
815      * allocate space and store clients names
816      */
817     Client_names = (char **) malloc(Num_clients * sizeof(char *));
818     if (Client_names == (char **) 0) {
819         (void) fprintf(stderr, "%s: client name malloc %d bytes failed",
820                     sfs_Myname, Num_clients * sizeof(char **));
821         exit(46);
822     }
823
824     for (i = 0; optind < argc; i++, optind++) {
825         Client_names[i] = argv[optind];
826         if (gethostbyname(argv[optind]) == NULL) {
827             (void) fprintf(stderr, "\n%s: unknown client - %s\n",
828                         sfs_Myname, argv[optind]);
829             exit(47);
830         }
831     }
832
833     if (sum_result_fp == NULL)
834         sum_result_fp = stdout;
835
836     Pc_log_fd = open(SFS_PRIME_SYNC_LOG, (O_RDWR | O_CREAT), 0666);
837     if (Pc_log_fd == -1) {
838         perror(SFS_PRIME_SYNC_LOG);
839         exit(48);
840     }
841
842 } /* do_initialize */
843
844
845 /*
846  * Small utility routine to pretty print out the names
847  * of the clients which did not respond to the message.
848  */
849 static void
850 printdeadclients(void)
851 {
852     int *clients;
853     int client;
854     int i;
855     FILE *fd;
856
857     if ((clients = (int *)malloc(sizeof(int) * Num_clients)) == NULL) {
858         (void) fprintf(stderr, "%s: malloc failed\n", sfs_Myname);
859         (void) fflush(stderr);
860         return;
861     }
862
863     for (i = 0; i < Num_clients; i++) {
864         clients[i] = 0;
865     }
866
867     fd = fopen(SFS_PRIME_SYNC_LOG, "r");
868     if (fd == NULL) {
869         (void) fprintf(stderr,"%s: Cannot open %s\n",
870             sfs_Myname, SFS_PRIME_SYNC_LOG);
871         (void) fflush(stderr);
872         return;
873     }
874
875     while(fread(&client, sizeof(int), 1, fd) == 1) {
876         if (client > 0 && client <= Num_clients)
877                 clients[client - 1] = 1;
878     }
879
880     for (i = 0; i < Num_clients; i++) {
881         if (clients[i] == 0) {
882             (void) fprintf(stderr, "\n%s: Did not get signal from client %s\n",
883                     sfs_Myname, Client_names[i]);
884             (void) fflush(stderr);
885         }
886     }
887     (void) fclose(fd);
888     free (clients);
889 }
890
891 /*
892  * monitor Logfile until all Clients write to it.
893  *
894  * Each client appends its client id to the file. So the size
895  * of the log file divided by sizeof(int) is the number of
896  * clients that have responded.
897  */
898 static void
899 sync_PC_with_clients(void)
900 {
901     struct stat         statb;          /* for fstat */
902     int                 num_secs;       /* keep count of time */
903     int                 clientsremaining;
904
905     num_secs = 0;
906     do {
907         (void) sleep(1);
908         if (fstat(Pc_log_fd, &statb) == -1) {
909             (void) fprintf(stderr, "%s: can't stat Prime Client log %s",
910                                     sfs_Myname, SFS_PRIME_SYNC_LOG);
911             exit(49);
912         }
913         num_secs++;
914         clientsremaining = Num_clients - (statb.st_size / sizeof(int));
915     } while ( (clientsremaining > 0) && (num_secs < Prime_time_out));
916
917     /* if clients not responding then terminate experiment */
918     if (clientsremaining > 0) {
919         (void) fprintf(stderr,
920         "\n%s: Prime Client timeout - did not get signal from %d client(s)\n",
921                         sfs_Myname, clientsremaining);
922         printdeadclients();
923         /* send message to clients to stop */
924         (int) signal_sfs_clients("PRIME_STOP");
925         exit(50);
926     }
927
928     /* if more clients than exist responded then syncd is telling us to exit */
929     if (clientsremaining < 0) {
930         (void) fprintf(stderr,
931         "\n%s: Prime Client got too many signals - expected %d got %ld\n",
932                 sfs_Myname, Num_clients, statb.st_size / sizeof(int));
933         /* send message to clients to stop */
934         (int) signal_sfs_clients("PRIME_STOP");
935         exit(51);
936     }
937
938     /* success, so go ahead and truncate the sync logfile */
939     (void)close(Pc_log_fd);
940     Pc_log_fd = open(SFS_PRIME_SYNC_LOG,
941                         (O_RDWR | O_CREAT | O_TRUNC | O_APPEND), 0666);
942     if (Pc_log_fd == -1) {
943         /* problem in truncating sync logfile - stop experiment */
944         (void) fprintf(stderr, "%s: can't truncate Prime Client log %s",
945                        sfs_Myname, SFS_PRIME_SYNC_LOG);
946         (void) fflush(stderr);
947         (int) signal_sfs_clients("PRIME_STOP");
948         exit(52);
949     }
950
951 } /* sync_PC_with_clients */
952
953
954 #ifdef CLOSE_CLNT_HANDLE
955 static int close_clnt_handle = 1;
956 #else
957 static int close_clnt_handle = 0;
958 #endif
959 /*
960  * makes RPC to all clients, dependent on message
961  * Save the client handles to keep from doing unnecessary portmapper calls.
962  * This can help if we have to route through the busy server.
963  */
964 static int
965 signal_sfs_clients(char *message)
966 {
967     static int Transac_num = 0;            /* transaction number */
968     static CLIENT **    sfs_clnt_handle = NULL;
969     static int          *sfs_socket = NULL;
970     int *               result;
971     int                 i;
972     sync_string         sync_signal;
973     char                transaction_string[MAX_STR1_LEN];
974
975     (void) sprintf(transaction_string,"Prime_%i",++Transac_num);
976     sync_signal.clnt_type = message;
977     sync_signal.clnt_data = "";
978     sync_signal.clnt_transaction = transaction_string;
979
980     if (sfs_clnt_handle == NULL) {
981         sfs_socket = (int *) calloc(Num_clients, sizeof(int));
982         if (sfs_socket == (int *) 0) {
983            (void) fprintf(stderr, "%s: socket malloc failed.\n",
984                           sfs_Myname);
985            exit(53);
986         }
987
988         /* allocate space for tcp handles */
989         sfs_clnt_handle =  (CLIENT **) calloc(Num_clients, sizeof(CLIENT));
990         if (sfs_clnt_handle == (CLIENT **)0 ) {
991              (void) fprintf(stderr, "%s: clnttcp_create out of memory\n",
992                         sfs_Myname);
993              exit(54);
994         }
995     }
996
997     /* set up the tcp handles for all the clients */
998     for (i = 0; i < Num_clients; i++) {
999         if (sfs_clnt_handle[i] == NULL) {
1000             struct hostent      *host_info;
1001             struct sockaddr_in  clnt_addr;
1002 #ifdef SUNOS
1003             int fd;
1004 #endif
1005
1006             sfs_socket[i] = RPC_ANYSOCK;
1007
1008             if ((host_info = gethostbyname(Client_names[i])) == NULL)
1009                  return((int) RPC_UNKNOWNHOST);
1010             (void) memset((char *) &clnt_addr, '\0', sizeof(clnt_addr));
1011             (void) memmove((char *) &clnt_addr.sin_addr,
1012                                 (char *) host_info->h_addr,
1013                                 host_info->h_length);
1014             clnt_addr.sin_family = AF_INET;
1015             clnt_addr.sin_port =  0;
1016
1017             /*
1018              * Create client "handle" used for calling CL_MESSAGEPROG on the
1019              * sfs client(s). We tell the RPC package to use the "tcp"
1020              * protocol when contacting the clients.
1021              */
1022             sfs_clnt_handle[i] = clnttcp_create(&clnt_addr, SFS_SYNCPROG,
1023                                         SFS_SYNCVERS, &sfs_socket[i],
1024                                         MAX_STR2_LEN, MAX_STR2_LEN);
1025
1026             if (sfs_clnt_handle[i] == (CLIENT *) NULL) {
1027                 /*
1028                  * Couldn't establish connection with the sfs Client.
1029                  * print error message and return status
1030                  */
1031                 clnt_pcreateerror(Client_names[i]);
1032                 return((int) RPC_FAILED);
1033             }
1034 #ifdef SUNOS
1035             /*
1036              * Some commands in 4.X will fail if there are too many file
1037              * descriptors open, if the sfs_ext_mon uses one
1038              * of those then it will fail.  We set the close-on-exec
1039              * flag to help them.
1040              */
1041             if (clnt_control(sfs_clnt_handle[i], CLGET_FD, (char *)&fd) ==
1042                         FALSE) {
1043                 clnt_pcreateerror(Client_names[i]);
1044                 return((int) RPC_FAILED);
1045             }
1046             if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1) {
1047                 perror("F_SETFD");
1048                 return((int) RPC_FAILED);
1049             }
1050 #endif
1051         } /* end no client handle */
1052
1053         /*
1054          * Call the remote procedure "signal_sfs_cl_1" on each of the clients
1055          * pass the client number so sfs_syncd will know which client files
1056          * to look for in a shared /tmp area
1057          */
1058         sync_signal.clnt_id = i + 1;
1059         result = signal_sfs_1(&sync_signal, sfs_clnt_handle[i]);
1060
1061         if (result == NULL) {
1062             /* Error occurred.  Print error message and return error. */
1063             clnt_perror(sfs_clnt_handle[i], Client_names[i]);
1064             return((int) RPC_CANTSEND);
1065         }
1066
1067         /* Okay, we successfully called the remote procedure.  */
1068         if (*result == 0) {
1069             /*
1070              * remote procedure was unable to write to its sync file.
1071              * Print error message and return failure.
1072              */
1073             (void) fprintf(stderr,
1074                         "\n%s: Unable to perform remote procedure on %s . \n",
1075                             sfs_Myname, Client_names[i]);
1076             (void) fflush(stderr);
1077             return((int) RPC_FAILED);
1078         }
1079         if (close_clnt_handle) {
1080                 clnt_destroy(sfs_clnt_handle[i]);
1081                 sfs_clnt_handle[i] = NULL;
1082         }
1083     } /* end for each client */
1084
1085     return(0);
1086
1087 } /* signal_sfs_clients */
1088
1089
1090 /*
1091  * summarize and print multi-client results
1092  */
1093 static void
1094 print_multi_results(void)
1095 {
1096     FILE *      fd;             /* results files */
1097     int         i;
1098     int         k;
1099     char        res_file[SFS_MAXPATHLEN];               /* results filename */
1100     char        str[MAX_LINE_LEN];
1101
1102     double      stdev_msec, var_msec;
1103     float       tot_squared_time_msec, tot_sum2_msec;
1104     float       tot_got, tot_secs, tot_msec_calls, tot_res_time;
1105     int         tot_want, tot_calls, tot_errors;
1106
1107     double      sq_conf_interval_msec;
1108     double      conf_interval_msec;
1109     int         totals;
1110     int         invalid = 0;
1111
1112 #define MAXOPNAME       19
1113     struct client_stats {
1114         /* First line */
1115         int     version;
1116         int     num_io_files;
1117         int     num_access_io_files;
1118         int     num_non_io_files;
1119         int     num_symlinks;
1120         int     num_dirs;
1121         /* NOPS lines */
1122         struct client_op_stats {
1123                 char    op[MAXOPNAME];
1124                 int     want;
1125                 float   got;
1126                 int     calls;
1127                 int     errors;
1128                 float   secs;
1129                 float   msec_calls;
1130                 float   res_time;
1131                 float   squared_time_msec;
1132                 float   sum2_msec;
1133         } op_stats[NOPS];
1134         /* Last line */
1135         float   sum_calls_sec;
1136         float   sum_msec_calls;
1137         int     sum_secs;
1138         int     sum_calls;
1139         int     client_invalid_flag;
1140         uint32_t total_fss_bytes;
1141         uint32_t least_fss_bytes;
1142         uint32_t most_fss_bytes;
1143         uint32_t base_fss_bytes;
1144     } *client_stats;
1145
1146
1147     /*
1148      * malloc space for statistics
1149      *  Note last entry is for running totals.
1150      */
1151      client_stats = (struct client_stats *) calloc(Num_clients+1,
1152                                                 sizeof(struct client_stats));
1153      if (client_stats == (struct client_stats *)0) {
1154         (void) fprintf(stderr, "%s: client_stats malloc failed.\n",
1155                       sfs_Myname);
1156         (void) fflush(stderr);
1157         exit(55);
1158      }
1159
1160     totals = Num_clients;
1161     /*
1162      * Read each client file one at a time gathering statistics
1163      */
1164     for (i = 0; i < Num_clients;i++) {
1165         (void) sprintf(res_file, "%s%i", PRIME_RESULTS_LOG, i + 1);
1166         fd = fopen(res_file, "r");
1167         if (fd == (FILE *)NULL) {
1168             (void) fprintf(stderr, "%s: Cannot open results file - %s\n",
1169                             sfs_Myname, res_file);
1170             (void) fflush(stderr);
1171             exit(56);
1172         }
1173
1174         /*
1175          * the SFS clients compute its File set info. at runtime;
1176          * the clients pass back the computed value in the results
1177          * (RPC) info. Get the fileset info used by the clients and compute
1178          * the aggregate value.
1179          */
1180         if (fgets(str, MAX_LINE_LEN, fd) == NULL) {
1181             (void) fprintf(stderr,"%s: can't read data in results file - %s\n",
1182                                 sfs_Myname, res_file);
1183             (void) fflush(stderr);
1184             exit(57);
1185         }
1186         if (sscanf(str,"%d %d %d %d %d %d",
1187                                 &client_stats[i].version,
1188                                 &client_stats[i].num_io_files,
1189                                 &client_stats[i].num_access_io_files,
1190                                 &client_stats[i].num_non_io_files,
1191                                 &client_stats[i].num_symlinks,
1192                                 &client_stats[i].num_dirs) != 6) {
1193             (void) fprintf(stderr,"%s: data in results file unparseable - %s\n",
1194                                 sfs_Myname, res_file);
1195             (void) fflush(stderr);
1196             exit(58);
1197         }
1198
1199         client_stats[totals].num_io_files += client_stats[i].num_io_files;
1200         client_stats[totals].num_access_io_files +=
1201                                         client_stats[i].num_access_io_files;
1202         client_stats[totals].num_non_io_files +=
1203                                         client_stats[i].num_non_io_files;
1204         client_stats[totals].num_symlinks +=
1205                                         client_stats[i].num_symlinks;
1206         client_stats[totals].num_dirs += client_stats[i].num_dirs;
1207
1208         /* Gather per operation statistics */
1209         for (k = 0; k < NOPS; k++) {
1210             if (fgets(str, MAX_LINE_LEN, fd) == NULL) {
1211                 (void) fprintf(stderr,
1212                                 "%s: can't read data in results file - %s\n",
1213                                 sfs_Myname, res_file);
1214                 (void) fflush(stderr);
1215                 exit(59);
1216             }
1217             if (sscanf(str, "%s %d%% %f%% %d %d %f %f %f%% %f %f",
1218                         client_stats[i].op_stats[k].op,
1219                         &client_stats[i].op_stats[k].want,
1220                         &client_stats[i].op_stats[k].got,
1221                         &client_stats[i].op_stats[k].calls,
1222                         &client_stats[i].op_stats[k].errors,
1223                         &client_stats[i].op_stats[k].secs,
1224                         &client_stats[i].op_stats[k].msec_calls,
1225                         &client_stats[i].op_stats[k].res_time,
1226                         &client_stats[i].op_stats[k].squared_time_msec,
1227                         &client_stats[i].op_stats[k].sum2_msec) != 10) {
1228                 (void) fprintf(stderr,"%s: data in results file unparseable - %s\n",
1229                                 sfs_Myname, res_file);
1230                 (void) fflush(stderr);
1231                 exit(60);
1232             }
1233             if (strcmp(client_stats[i].op_stats[k].op,Ops_name[k]) != 0) {
1234                 (void) fprintf(stderr, "%s: bad data in results file\n",
1235                                     sfs_Myname);
1236                 (void) fflush(stderr);
1237                 exit(61);
1238             }
1239         }
1240
1241         if (fgets(str, 100, fd) == NULL) {
1242             (void) fprintf(stderr,"%s: can't read data in results file - %s\n",
1243                                 sfs_Myname, res_file);
1244                 (void) fflush(stderr);
1245             exit(62);
1246         }
1247         if (sscanf(str,"%f %f %d %d %d %u %u %u %u",
1248                 &client_stats[i].sum_calls_sec,
1249                 &client_stats[i].sum_msec_calls,
1250                 &client_stats[i].sum_secs,
1251                 &client_stats[i].sum_calls,
1252                 &client_stats[i].client_invalid_flag,
1253                 &client_stats[i].total_fss_bytes,
1254                 &client_stats[i].least_fss_bytes,
1255                 &client_stats[i].most_fss_bytes,
1256                 &client_stats[i].base_fss_bytes) != 9) {
1257             (void) fprintf(stderr,"%s: data in results file unparseable - %s\n",
1258                                 sfs_Myname, res_file);
1259             (void) fflush(stderr);
1260             exit(63);
1261         }
1262
1263         client_stats[totals].sum_secs += client_stats[i].sum_secs;
1264         client_stats[totals].sum_calls += client_stats[i].sum_calls;
1265         client_stats[totals].sum_calls_sec +=
1266                                         client_stats[i].sum_calls_sec;
1267         client_stats[totals].sum_msec_calls +=
1268                                         client_stats[i].sum_msec_calls;
1269         client_stats[totals].total_fss_bytes +=
1270                                         client_stats[i].total_fss_bytes;
1271         client_stats[totals].least_fss_bytes +=
1272                                         client_stats[i].least_fss_bytes;
1273         client_stats[totals].most_fss_bytes +=
1274                                         client_stats[i].most_fss_bytes;
1275         client_stats[totals].base_fss_bytes +=
1276                                         client_stats[i].base_fss_bytes;
1277
1278         (void) fclose(fd);
1279     } /* for Num_clients */
1280
1281     nfs_version = client_stats[0].version;
1282
1283     /*
1284      * print the aggregate test parameters
1285      */
1286     (void) fprintf(stdout, "\nAggregate Test Parameters: \n");
1287     (void) fprintf(stdout, "    Number of processes = %d\n",
1288                    P_children * Num_clients);
1289     (void) fprintf(stdout, "    Requested Load (NFS V%d operations/second) = %d\n",
1290                         nfs_version, P_total_load * Num_clients);
1291     (void) fprintf(stdout, "%s%d\n",
1292                     "    Maximum number of outstanding biod writes = ",
1293                     P_biod_max_outstanding_writes);
1294     (void) fprintf(stdout, "%s%d\n",
1295                     "    Maximum number of outstanding biod reads = ",
1296                     P_biod_max_outstanding_reads);
1297
1298     (void) fprintf(stdout, "%s%d\n%s%d\n",
1299                     "    Warm-up time (seconds) = ", P_warmuptime,
1300                     "    Run time (seconds) = ", Prime_runtime);
1301     if (P_mix_file)
1302         (void) fprintf(stdout,"%s%s\n", "    NFS Mixfile = ", P_mix_file);
1303     if (P_iodist_file)
1304         (void) fprintf(stdout,"%s%s\n", "    Block Size Distribution file = ",
1305                         P_iodist_file);
1306
1307
1308     (void) fprintf(stdout, "%s%6d%s\n", "    File Set = ",
1309                 client_stats[totals].num_io_files,
1310                 " Files created for I/O operations");
1311     (void) fprintf(stdout, "%s%10d%s\n", "           ",
1312                 client_stats[totals].num_access_io_files,
1313                 " Files accessed for I/O operations");
1314     (void) fprintf(stdout, "%s%10d%s\n", "           ",
1315                 client_stats[totals].num_non_io_files,
1316                 " Files for non-I/O operations");
1317     (void) fprintf(stdout, "%s%10d%s\n", "           ",
1318                 client_stats[totals].num_symlinks,
1319                 " Symlinks");
1320     (void) fprintf(stdout, "%s%10d%s\n", "           ",
1321                 client_stats[totals].num_dirs,
1322                 " Directories");
1323     (void) fprintf(stdout, "%s%s\n", "           ",
1324                 "           Additional non-I/O files created as necessary\n");
1325
1326
1327     (void) fprintf(stdout,"SFS Aggregate Results for %d Client(s), %s\n",
1328                     Num_clients, lad_timestamp());
1329     (void) fprintf(stderr, "SPEC SFS Benchmark Version %s, Creation - %s\n",
1330                                 SFS_VERSION_NUM, SFS_VERSION_DATE);
1331     (void) fprintf(stdout, "NFS Protocol Version %d\n", nfs_version);
1332
1333     /* print column headers for per operation statistics */
1334     (void) fprintf(stdout,
1335 "------------------------------------------------------------------------------");
1336 (void) fprintf(stdout, "\n");
1337 (void) fprintf(stdout,"%s\n%s\n%s\n%s\n%s\n",
1338 "NFS         Target Actual     NFS    NFS    Mean    Std Dev  Std Error   Pcnt ",
1339 "Op           NFS    NFS       Op     Op    Response Response of Mean,95%  of  ",
1340 "Type         Mix    Mix     Success Error   Time     Time    Confidence  Total",
1341 "             Pcnt   Pcnt     Count  Count  Msec/Op  Msec/Op  +- Msec/Op  Time ",
1342 "------------------------------------------------------------------------------");
1343     (void) fflush(stdout);
1344
1345     /* print per operation statistics */
1346     for (k = 0; k < NOPS; k++) {
1347         tot_got = 0;
1348         tot_secs = 0;
1349         tot_msec_calls = 0;
1350         tot_res_time =  0;
1351         tot_want = 0;
1352         tot_calls = 0;
1353         tot_errors = 0;
1354         tot_sum2_msec = 0;
1355         tot_squared_time_msec = 0;
1356
1357         /* total the results from each client */
1358         for (i = 0; i < Num_clients; i++) {
1359
1360             tot_want += client_stats[i].op_stats[k].want;
1361             tot_got += client_stats[i].op_stats[k].got;
1362             tot_calls += client_stats[i].op_stats[k].calls;
1363             tot_errors += client_stats[i].op_stats[k].errors;
1364             tot_secs += client_stats[i].op_stats[k].secs;
1365             tot_msec_calls += client_stats[i].op_stats[k].msec_calls;
1366             tot_res_time += client_stats[i].op_stats[k].res_time;
1367             tot_squared_time_msec +=
1368                         client_stats[i].op_stats[k].squared_time_msec;
1369             tot_sum2_msec += client_stats[i].op_stats[k].sum2_msec;
1370
1371         } /* end for each client */
1372
1373         /*
1374          * If the total wanted is zero and no operations succeeded or
1375          * errored don't print out the
1376          * summary.  However leave it in the individual client logs
1377          * in case there is some interesting error.
1378          */
1379         if (tot_want == 0 && tot_calls == 0 && tot_errors == 0)
1380             continue;
1381
1382         /* compute the standard deviation for the mean response time */
1383         if (tot_calls <= 1) {
1384             stdev_msec = 0;
1385             var_msec = 0;
1386         } else {
1387             /* variance = 1/(n-1) * (sum(x^2) - 1/n * (sum(x))^2)  */
1388             var_msec = (tot_squared_time_msec - (tot_sum2_msec / tot_calls)) /
1389                         (tot_calls-1);
1390
1391             if(var_msec == 0.0) {
1392                 stdev_msec = 0.0;
1393             } else
1394                 stdev_msec = sqrt(var_msec);
1395         }
1396
1397         /* compute the confidence interval */
1398         if (tot_calls > 0) {
1399             sq_conf_interval_msec = DEFAULT_CHI_SQR_CI *
1400                                     (stdev_msec / tot_calls);
1401             if (sq_conf_interval_msec == 0.0) {
1402                 if (DEBUG_PARENT_GENERAL) {
1403                     (void) fprintf(stderr,
1404                         "Error computing confidence interval for mean\n");
1405                     (void) fflush(stderr);
1406                 }
1407                 conf_interval_msec = 0.0;
1408             } else
1409                 conf_interval_msec = sqrt(sq_conf_interval_msec);
1410         } else {
1411             conf_interval_msec = 0.0;
1412         }
1413
1414         /* print the per op statistics */
1415         (void) fprintf(stdout,
1416             "%-12s%3d%%  %5.1f%%   %7d %5d %8.2f %8.2f  %8.2f    %5.1f%%\n",
1417             Ops_name[k],                                        /* op name */
1418             tot_want / Num_clients,                             /* target mix */
1419             tot_got / Num_clients,                              /* actual mix */
1420             tot_calls,                                          /* successes */
1421             tot_errors,                                         /* errors */
1422             tot_msec_calls / Num_clients,                       /* mean */
1423             stdev_msec,                                         /* std dev */
1424             conf_interval_msec,                                 /* conf int */
1425             tot_res_time / Num_clients);                        /* % of time */
1426
1427     } /* end for each op */
1428
1429     (void) fprintf(stdout,
1430 "------------------------------------------------------------------------------\n");
1431
1432     /* check and report client INVALID RUN */
1433     for (i = 0; i < Num_clients; i++) {
1434         if (client_stats[i].client_invalid_flag != 0) {
1435             invalid++;
1436             (void) fprintf(stdout,"INVALID RUN reported for Client %d (%s).\n",
1437                    i+1, Client_names[i]);
1438             if (client_stats[i].client_invalid_flag >= INVALID_GOODCALLS) {
1439                 (void) fprintf(stdout,"INVALID RUN, %s\n",
1440                         invalid_str[client_stats[i].client_invalid_flag]);
1441             } else {
1442                 (void) fprintf(stdout,
1443                         "INVALID RUN, ILLEGAL PARAMETER: Non-standard %s\n",
1444                         invalid_str[client_stats[i].client_invalid_flag]);
1445             }
1446         }
1447     }
1448
1449     (void) fprintf(stdout, "\n");
1450     (void) fprintf(stdout,
1451         "        --------------------------------------------------------\n");
1452     (void) fprintf(stdout,
1453         "        | SPEC SFS VERSION %6s AGGREGATE RESULTS SUMMARY    |\n",
1454                                                         SFS_VERSION_NUM);
1455     (void) fprintf(stdout,
1456         "        --------------------------------------------------------\n");
1457     (void) fprintf(stdout, "NFS V%d THROUGHPUT: ", nfs_version);
1458     (void) fprintf(stdout,"%7.0f Ops/Sec   AVG. RESPONSE TIME: %7.1f Msec/Op\n",
1459         client_stats[totals].sum_calls_sec,
1460         client_stats[totals].sum_msec_calls / Num_clients);
1461
1462     (void) fprintf(stdout, "%s PROTOCOL\n", P_tcp ? "TCP" : "UDP");
1463     (void) fprintf(stdout, "NFS MIXFILE:");
1464     if (P_mix_file)
1465         (void) fprintf(stdout,"%s\n", P_mix_file);
1466     else (void)
1467         (void) fprintf(stdout," [ SFS default ]\n");
1468
1469     (void) fprintf(stdout, "AGGREGATE REQUESTED LOAD: %d Ops/Sec \n",
1470                     (Num_clients * P_total_load));
1471
1472     (void) fprintf(stdout,"TOTAL NFS OPERATIONS: %8d      TEST TIME: %d Sec \n",
1473                     client_stats[totals].sum_calls,
1474                     client_stats[totals].sum_secs / Num_clients);
1475     (void) fprintf(stdout,"NUMBER OF SFS CLIENTS: %d\n", Num_clients);
1476     (void) fprintf(stdout,
1477                 "TOTAL FILE SET SIZE CREATED: %6.1f MB\n" ,
1478                 client_stats[totals].total_fss_bytes/1024.0);
1479     (void) fprintf(stdout,
1480                 "TOTAL FILE SET SIZE ACCESSED: %6.1f - %6.1f MB  (%lu%% to %lu%% of Base)\n",
1481                 client_stats[totals].least_fss_bytes/1024.0,
1482                 client_stats[totals].most_fss_bytes/1024.0,
1483                 (100 * client_stats[totals].least_fss_bytes) /
1484                         client_stats[totals].base_fss_bytes,
1485                 (100 * client_stats[totals].most_fss_bytes) /
1486                         client_stats[totals].base_fss_bytes);
1487     (void) fprintf(stdout, "\n");
1488
1489     (void) fprintf(stdout,
1490     "------------------------------------------------------------------------");
1491     (void) fprintf(stdout,"\n\n");
1492     (void) fflush(stdout);
1493
1494     /*
1495      * Summary results file format:
1496      *                 response total   elps                  prcs biod  vers
1497      *  load   thruput time     ops     time V P fileset_sz clnt   rd wr
1498      * DDDDDDD FFFFFFF FFFFFFF DDDDDDDD DDDD D C DDDDDDDDDD DDD DD DD DD SSSS
1499      */
1500     (void) fprintf(sum_result_fp,
1501 "%7s %7d %7.0f %7.1f %8d %4d %1d %c %10lu %3d %2d %2d %2d %s\n",
1502                         invalid ? "INVALID" : "",
1503                         Num_clients * P_total_load,
1504                         client_stats[totals].sum_calls_sec,
1505                         client_stats[totals].sum_msec_calls / Num_clients,
1506                         client_stats[totals].sum_calls,
1507                         client_stats[totals].sum_secs / Num_clients,
1508                         nfs_version,
1509                         P_tcp ? 'T' : 'U',
1510                         (unsigned long)client_stats[totals].total_fss_bytes,
1511                         Num_clients,
1512                         P_children,
1513                         P_biod_max_outstanding_reads,
1514                         P_biod_max_outstanding_writes,
1515                         SFS_VERSION_NUM);
1516     (void) fflush(sum_result_fp);
1517
1518     (void) free(client_stats);
1519 } /* print_multi_results */
1520
1521 static void
1522 prog_usage(void)
1523 {
1524    (void) fprintf(stderr,
1525       "Usage: %s [-a access_pcnt] [-A append_pcnt] [-b blocksz_file] [-B block_size]\n",
1526         sfs_Myname);
1527     (void) fprintf(stderr,
1528       "\t[-C summary_file] [-d debug_level] [-f file_set_delta]\n");
1529     (void) fprintf(stderr,
1530       "\t[-k script_name] [-K script_args] [-l load] [-m mix_file]\n");
1531     (void) fprintf(stderr,
1532       "\t[-p procs] [-Q] [-R biod_reads] [-s sleeptime]\n");
1533     (void) fprintf(stderr,
1534       "\t[-t time] [-T op_num] [-w warmup] [-x timeout]\n");
1535     (void) fprintf(stderr,
1536       "\t[-W biod_writes] [-z] <hostname1> [<hostname2>...]\n");
1537
1538
1539     (void) fflush(stderr);
1540     (int) signal_sfs_clients("PRIME_STOP");
1541     exit(64);
1542     /* NOTREACHED */
1543 } /* prog_usage */
1544
1545 /* sfs_m_prm.c */