Add proper per-file copyright notices/licenses and top-level license.
[bluesky.git] / TBBT / trace_play / sfs_c_pnt.c
1 #ifndef lint
2 static char sfs_c_pntSid[] = "@(#)sfs_c_pnt.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  *
37  *.Exported_Routines
38  *      void parent(int, int, char *, char *)
39  *
40  *.Local_Routines
41  *      void synchronize_children(int)
42  *      int signal_Prime_Client(char *, char *)
43  *      void collect_counters(int)
44  *      int check_parameters(char *, char *, int)
45  *      int check_counters(void)
46  *      void print_results(int, int, char *, int, int, char *)
47  *
48  *.Revision_History
49  *      10-Jan-92       Teelucksingh
50  *                              Client passes standard deviation compute
51  *                              values to Prime-Client as well as an
52  *                              "INVALID RUN" flag.
53  *
54  *      16-Dec-91       Wittle          Created.
55  */
56
57 /*
58  * -------------------------  Include Files  -------------------------
59  */
60
61 /*
62  * ANSI C headers
63  */
64 #include <stdio.h>
65 #include <stdlib.h>
66 #include <string.h>
67 #include <errno.h>
68 #include <math.h>
69 #include <signal.h>
70
71 #include <fcntl.h>
72
73 #include <sys/types.h>
74 #include <sys/stat.h> 
75  
76 #include <unistd.h>
77 #include <sys/wait.h>
78
79 #include "sfs_c_def.h"
80 #include "sfs_m_def.h"
81
82 #if !defined(_XOPEN_SOURCE)
83 #include <sys/socket.h>
84 #else
85 #define AF_INET         2
86 #endif
87
88 /*
89  * -------------------------  External Definitions  -------------------------
90  */
91
92 /* forward definitions for local routines */
93 static void synchronize_children(int);
94 static int signal_Prime_Client(char *, char *);
95 static void collect_counters(int);
96 static int check_parameters(char *, char *, int);
97 static int check_counters(void);
98 static void print_results(int, int, char *, int, int, char *);
99 static void sfs_reaper(int);
100
101 /* Aggregate results storage */
102 static char Client_results[(NOPS+3)*MAX_LINE_LEN];
103
104 /*
105  * -------------------------  SFS Parent Code  -------------------------
106  */
107
108 /*
109  * Parent: wait for kids to get ready, start them, wait for them to
110  * finish, read and accumulate results.
111  */
112 void
113 parent(
114     int         children,
115     int         load,
116     char *      mix_file,
117     char *      iodist_file)
118 {
119     char        string[80];     /* for interactive startup */
120     int         result;
121     int         invalid_run;    /* holds INVALID RUN status */
122     int         runtime_val;    /* store Runtime value to be printed later */
123     int         Saveerrno;
124     char        *nameptr;
125 #if (defined(_XOPEN_SOURCE) || defined(USE_POSIX_SIGNALS))
126     struct sigaction sig_act, old_sig_act;
127 #endif
128
129     /*
130      * Setup a SIGCHLD handler in case one of our beloved children dies
131      * before its time.
132      */
133 #if (defined(_XOPEN_SOURCE) || defined(USE_POSIX_SIGNALS))
134     /* use XOPEN signal handling */
135
136     sig_act.sa_handler = sfs_reaper;
137     (void)sigemptyset(&sig_act.sa_mask);
138     sig_act.sa_flags = 0;
139     if (sigaction(SIGCHLD,&sig_act,&old_sig_act) == -1) {
140         perror("sigaction failed: SIGCHLD");
141         exit(66);
142     }
143 #else
144     (void) signal(SIGCHLD, sfs_reaper);
145 #endif
146
147     /* Change my name for error logging */
148     if ((nameptr = strrchr(sfs_Myname, '/')) != NULL)
149         sfs_Myname = ++nameptr;
150
151     /*
152      * store the Runtime value; to be printed in results
153      */
154     if (Prime_client)
155         runtime_val = Runtime - MULTICLIENT_OFFSET;
156     else runtime_val = Runtime;
157
158     /* print logfile header information */
159     (void) fprintf(stdout,"\n");
160     (void) fprintf(stdout,
161     "************************************************************************");
162     (void) fprintf(stdout,"\n");
163     (void) fflush(stdout);
164
165     /* print sfs information */
166     if (Prime_client) {
167         (void) fprintf(stderr,
168                 "\nSFS NFS Version %d Benchmark Client Logfile, %s\n",
169                         nfs_version, lad_timestamp());
170         (void) fprintf(stderr, "\tClient hostname = %s\n", lad_hostname);
171         (void) fprintf(stderr, "\tPrime Client hostname = %s\n",
172                         Prime_client);
173     }
174
175     (void) fprintf(stderr, "\nSPEC SFS Benchmark Version %s, Creation - %s\n",
176                                 SFS_VERSION_NUM, SFS_VERSION_DATE);
177     (void) fprintf(stderr, "NFS Protocol Version %d\n", nfs_version);
178
179     /* mount test directories */
180     (void) fprintf(stderr, "%s Mounting %d remote test directories.\n",
181                 lad_timestamp(), children);
182     synchronize_children(children);
183     (void) fprintf(stderr, "%s Completed.", lad_timestamp());
184
185     /*
186      * if multi-client execution then tell Prime-Client I'm done mounting
187      * test directories.
188      */
189     if (Prime_client) {
190         (void) fprintf(stderr, "\n");
191         (void) fprintf(stderr,
192                        "%s Sending DONE-MOUNT message to Prime Client(%s).\n",
193                         lad_timestamp(), Prime_client);
194         if ((result =
195             (int) signal_Prime_Client("CLIENT_SIGNAL", ""))
196                 == (int) RPC_SUCCESS) {
197             (void) fprintf(stderr, "%s Completed.",lad_timestamp());
198             (void) fflush(stderr);
199         } else {
200             (void) fprintf(stderr, "\n");
201             (void) fprintf(stderr,
202                 "%s:  error %d sending DONE-MOUNT message to Prime Client\n",
203                 sfs_Myname, result);
204             /* cleanup and exit */
205 #if (defined(_XOPEN_SOURCE) || defined(USE_POSIX_SIGNALS))
206             sig_act.sa_handler = SIG_DFL;
207             (void)sigemptyset(&sig_act.sa_mask);
208             sig_act.sa_flags = 0;
209             if (sigaction(SIGCHLD,&sig_act,&old_sig_act) == -1) {
210                 perror("sigaction failed: SIGCHLD");
211                 exit(67);
212             }
213 #else
214             (void) signal(SIGCHLD, SIG_DFL);
215 #endif
216             (void) generic_kill(0, SIGINT);
217             exit(68);
218         }
219
220         (void) fprintf(stderr, "\n");
221         (void) fprintf(stderr,
222                     "%s Waiting on DO-INIT message from Prime Client(%s).\n",
223                     lad_timestamp(), Prime_client);
224         (void) fflush(stderr);
225
226         /*
227          * wait for DO-INIT message from Prime Client
228          * sfs_syncd (rpc server) sends a SIGUSR1 signal;
229          * user can also terminate experiment anytime they wish
230          * with SIGINT or SIGTERM signal
231          */
232         (void) pause();
233         (void) fprintf(stderr, "%s Received.",lad_timestamp());
234         (void) fflush(stderr);
235
236     } /* send DONE-MOUNT and got DO-INIT message */
237
238     /* initialize test directories */
239     (void) fprintf(stderr, "\n");
240     (void) fprintf(stderr, "%s Initializing test directories.\n",
241                     lad_timestamp());
242
243     /* send SIGUSR1 to child processes */
244     (void) generic_kill(0, SIGUSR1);
245     synchronize_children(children);
246     (void) fprintf(stderr, "%s Completed.", lad_timestamp());
247     (void) fflush(stderr);
248
249     /*
250      * if multi-client execution then tell Prime-Client I'm done initializing
251      * and wait for synchronized do warmupmessage.
252      */
253     if (Prime_client) {
254         (void) fprintf(stderr, "\n");
255         (void) fprintf(stderr,
256                     "%s Sending DONE-INIT message to Prime Client(%s).\n",
257                         lad_timestamp(), Prime_client);
258         if ((result =
259             (int) signal_Prime_Client("CLIENT_SIGNAL",""))
260                 == (int) RPC_SUCCESS) {
261             (void) fprintf(stderr, "%s Completed.",lad_timestamp());
262             (void) fflush(stderr);
263         } else {
264             (void) fprintf(stderr, "\n");
265             (void) fprintf(stderr,
266                     "%s:  error %d sending DONE-INIT message to Prime Client\n",
267                     sfs_Myname, result);
268             /* cleanup and exit */
269 #if (defined(_XOPEN_SOURCE) || defined(USE_POSIX_SIGNALS))
270             sig_act.sa_handler = SIG_DFL;
271             (void)sigemptyset(&sig_act.sa_mask);
272             sig_act.sa_flags = 0;
273             if (sigaction(SIGCHLD,&sig_act,&old_sig_act) == -1) {
274                 perror("sigaction failed: SIGCHLD");
275                 exit(69);
276             }
277 #else
278             (void) signal(SIGCHLD, SIG_DFL);
279 #endif
280             (void) generic_kill(0, SIGINT);
281             exit(70);
282         }
283         (void) fprintf(stderr, "\n");
284         (void) fprintf(stderr,
285                   "%s Waiting on DO-WARMUP message from Prime Client(%s).\n",
286                     lad_timestamp(), Prime_client);
287         (void) fflush(stderr);
288
289         /*
290          * wait for DO-WARMUP message from Prime Client
291          * sfs_syncd (rpc server) sends a SIGUSR1 signal;
292          * user can also terminate experiment anytime they wish
293          * with SIGINT or SIGTERM signal
294          */
295         (void) pause();
296         (void) fprintf(stderr, "%s Received.",lad_timestamp());
297         (void) fflush(stderr);
298
299     } /* send DONE-INIT and got DO-WARMUP message */
300
301     if (Populate_only) {
302         (void) fprintf(stderr, "\nPopulating directories and exiting.\n");
303 #if (defined(_XOPEN_SOURCE) || defined(USE_POSIX_SIGNALS))
304         sig_act.sa_handler = SIG_DFL;
305         (void)sigemptyset(&sig_act.sa_mask);
306         sig_act.sa_flags = 0;
307         if (sigaction(SIGCHLD,&sig_act,&old_sig_act) == -1) {
308             perror("sigaction failed: SIGCHLD");
309             exit(71);
310         }
311 #else
312         (void) signal(SIGCHLD, SIG_DFL);
313 #endif
314         (void) generic_kill(0, SIGUSR1);
315         while (wait((int *) 0) != -1) {
316             /* nop */
317         }
318         return;
319     }
320
321     /* do warm-up */
322     if (Warmuptime) {
323         (void) fprintf(stderr, "\n");
324         (void) fprintf(stderr, "%s Performing %d seconds pretest warmup.\n",
325                 lad_timestamp(), Warmuptime);
326         (void) generic_kill(0, SIGUSR1);
327         (void) sleep(Warmuptime);
328         (void) fprintf(stderr, "%s Completed.", lad_timestamp());
329         (void) fflush(stderr);
330     }
331
332     if (Interactive) {
333         (void) fprintf(stderr, "\n");
334         (void) fprintf(stderr, "Hit <return> when ready to start test ...");
335         (void) fgets(string,10,stdin);
336     }
337
338     /*
339      * if multi-client execution then tell Prime-Client I'm done warm-up
340      * and wait for synchronized Start message.
341      */
342     if (Prime_client) {
343         (void) fprintf(stderr, "\n");
344         (void) fprintf(stderr,
345                         "%s Sending READY message to Prime Client(%s).\n",
346                         lad_timestamp(), Prime_client);
347         if ((result =
348             (int) signal_Prime_Client("CLIENT_SIGNAL",""))
349                 == (int) RPC_SUCCESS) {
350             (void) fprintf(stderr, "%s Completed.",lad_timestamp());
351             (void) fflush(stderr);
352         } else {
353             (void) fprintf(stderr, "\n");
354             (void) fprintf(stderr,
355                     "%s:  error %d sending READY message to Prime Client\n",
356                     sfs_Myname, result);
357             /* cleanup and exit */
358 #if (defined(_XOPEN_SOURCE) || defined(USE_POSIX_SIGNALS))
359             sig_act.sa_handler = SIG_DFL;
360             (void)sigemptyset(&sig_act.sa_mask);
361             sig_act.sa_flags = 0;
362             if (sigaction(SIGCHLD,&sig_act,&old_sig_act) == -1) {
363                 perror("sigaction failed: SIGCHLD");
364                 exit(72);
365             }
366 #else
367             (void) signal(SIGCHLD, SIG_DFL);
368 #endif
369             (void) generic_kill(0, SIGINT);
370             exit(73);
371         }
372
373         (void) fprintf(stderr, "\n");
374         (void) fprintf(stderr,
375                     "%s Waiting on START message from Prime Client(%s).\n",
376                     lad_timestamp(), Prime_client);
377         (void) fflush(stderr);
378
379         /*
380          * wait for START message from Prime Client
381          * sfs_syncd (rpc server) sends a SIGUSR1 signal;
382          * user can also terminate experiment anytime they wish
383          * with SIGINT or SIGTERM signal
384          */
385         (void) pause();
386         (void) fprintf(stderr, "%s Received.",lad_timestamp());
387         (void) fflush(stderr);
388
389     } /* send READY and got START message */
390
391     (void) fprintf(stderr, "\n");
392     if (Timed_run) {
393         if (Prime_client) {
394             (void) fprintf(stderr, "%s Starting %d seconds test run.\n",
395                     lad_timestamp(), Runtime - MULTICLIENT_OFFSET);
396         } else {
397             (void) fprintf(stderr, "%s Starting %d seconds test run.\n",
398                     lad_timestamp(), Runtime);
399         }
400     } else {
401         (void) fprintf(stderr, "%s Starting %d call test run.\n",
402                 lad_timestamp(), Ops[TOTAL].target_calls);
403     }
404     (void) fflush(stderr);
405
406     /* signal child processes to go */
407     (void) generic_kill(0, SIGUSR1);
408
409     if (Timed_run)
410         (void) sleep(Runtime);
411
412 #if (defined(_XOPEN_SOURCE) || defined(USE_POSIX_SIGNALS))
413     sig_act.sa_handler = SIG_DFL;
414     (void)sigemptyset(&sig_act.sa_mask);
415     sig_act.sa_flags = 0;
416     if (sigaction(SIGCHLD,&sig_act,&old_sig_act) == -1) {
417         perror("sigaction failed: SIGCHLD");
418         exit(74);
419     }
420 #else
421     (void) signal(SIGCHLD, SIG_DFL);
422 #endif
423
424     if (Timed_run) {
425         /*
426          * The parent and the prime are both sleeping for Runtime.
427          * If the parent wakes up first, he'll tell the children to stop.
428          * If the prime wakes up first, he'll send an SIGALRM (via syncd)
429          * to the parent.  That alarm may arrive while the parent is still
430          * asleep, which is ok, or after he has starting running.  Since
431          * the parent SIGARLM catcher does nothing, there is no harm done
432          * by the extra signal in this case.
433          *
434          * Perhaps, if running multi we should just wait (pause()) for
435          * the STOP signal, like we waited for the start signal.  It would
436          * be more obvious.  The only drawback is the OTW rpc delay in
437          * receiving the stop signal from the prime.
438          */
439         (void) generic_kill(0, SIGUSR2); /* tell children to finish */
440     }
441
442     /* Wait for all the children to finish/die */
443     while (wait((int *) 0) != -1) {
444         /* nop */
445     }
446
447     (void) fprintf(stderr, "%s Completed.", lad_timestamp());
448     (void) fflush(stdout);
449     (void) fflush(stderr);
450
451     /* Initialize and sum up counters */
452     collect_counters(children);
453     if ((invalid_run = check_counters()) == 0)
454         invalid_run = check_parameters(iodist_file, mix_file, runtime_val);
455
456     /* print test results */
457     print_results(children, load, mix_file,
458                   invalid_run, runtime_val, iodist_file);
459
460     /*
461      * if multi-client execution then tell Prime client that
462      * I'm done with 'real' work and wait for move-data message
463      * and send data across
464      */
465     if (Prime_client) {
466         (void) fprintf(stderr,
467                         "%s Sending DONE-TEST message to Prime Client(%s).\n",
468                         lad_timestamp(), Prime_client);
469         if ((result =
470             (int) signal_Prime_Client("CLIENT_SIGNAL",""))
471                 == (int) RPC_SUCCESS) {
472             (void) fprintf(stderr, "%s Completed.", lad_timestamp());
473             (void) fflush(stderr);
474         } else {
475             Saveerrno = errno;
476             (void) fprintf(stderr, "\n");
477             (void) fprintf(stderr,
478                     "%s:  error %d sending DONE-TEST message to Prime Client\n",
479                     sfs_Myname, result);
480             errno = Saveerrno;
481             perror("signal_Prime_Client");
482             /* cleanup and exit */
483             (void) generic_kill(0, SIGINT);
484             exit(75);
485         }
486
487         /*
488          * wait for MOVE-DATA message from Prime Client before
489          * sending send results.
490          */
491         (void) fprintf(stderr, "\n");
492         (void) fprintf(stderr,
493                 "%s Waiting on MOVE-DATA message from Prime Client(%s).\n",
494                 lad_timestamp(), Prime_client);
495         (void) fflush(stderr);
496         (void) pause();
497         (void) fprintf(stderr, "%s Received.", lad_timestamp());
498         (void) fprintf(stderr, "\n");
499         (void) fprintf(stderr, "%s Sending results to Prime Client(%s)\n",
500                 lad_timestamp(), Prime_client);
501         (void) fflush(stderr);
502
503
504         if ((result = (int) signal_Prime_Client("CLIENT_DATA",
505             Client_results)) == (int) RPC_SUCCESS) {
506             (void) fprintf(stderr, "%s Completed.\n", lad_timestamp());
507             (void) fflush(stderr);
508         } else {
509             Saveerrno = errno;
510             (void) fprintf(stderr, "\n");
511             (void) fprintf(stderr,
512                     "%s: error %d sending client's result to Prime Client\n",
513                     sfs_Myname, result);
514             errno = Saveerrno;
515             perror("signal_Prime_Client");
516             /* cleanup and exit */
517             (void) generic_kill(0, SIGINT);
518             exit(76);
519         }
520     } /* sent done, got move-data and sent data */
521
522     (void) fprintf(stdout,"\n");
523     (void) fprintf(stdout,
524     "************************************************************************");
525     (void) fprintf(stdout,"\n");
526
527 } /* parent */
528
529
530 /*
531  * ------------------------  Utility Routines  --------------------------
532  */
533
534
535 /*
536  * Monitor Logfile until its size reaches 'children' bytes.
537  * This means that all of the children are waiting for the next instruction.
538  */
539 static void
540 synchronize_children(
541     int         children)
542 {
543     struct stat statb;  /* for fstat */
544
545     do {
546         (void) sleep(1);
547         if (fstat(Log_fd, &statb) == -1) {
548             (void) fprintf(stderr, "%s: can't stat log %s", sfs_Myname, Logname);
549             (void) generic_kill(0, SIGINT);
550             exit(77);
551         }
552     } while (statb.st_size < children);
553
554     /*
555      * Truncate the log file
556      */
557     (void)close(Log_fd);
558     Log_fd = open(Logname, (O_RDWR | O_CREAT | O_TRUNC | O_APPEND), 0666);
559     if (Log_fd == -1) {
560         (void) fprintf(stderr, "%s: can't truncate log %s",
561                                 sfs_Myname, Logname);
562         (void) generic_kill(0, SIGINT);
563         exit(78);
564     }
565
566 }  /* synchronize_children */
567
568
569 /*
570  * Multi-client execution support routine.
571  * Call remote procedure on Prime client
572  * to send message to sfs_prime_clnt program.
573  * The message will contain a type field set to 'type',
574  * and a data field set to 'data'.
575  */
576 static int
577 signal_Prime_Client(
578     char *              type,
579     char *              data)
580 {
581     static CLIENT *     clnt_handle = NULL;
582     static int          transaction_id = 0;
583     int *               result;
584     static int          socket;
585     sync_string         sync_signal;
586     char                transaction_string[MAX_STR1_LEN];
587     char                buf[128];
588
589     if ((int)strlen(data) > MAX_STR2_LEN) {
590         (void) fprintf(stderr,
591                         "%s: %s too much data len = %d max = %d\n",
592                         sfs_Myname, Prime_client, strlen(data),
593                         MAX_STR2_LEN);
594         return((int)RPC_CANTENCODEARGS);
595     }
596
597     if (clnt_handle == NULL) {
598         struct sockaddr_in      prime_addr;
599         struct hostent *        host_info;
600
601         socket = RPC_ANYSOCK;
602
603         /* get host information for prime_client */
604         if ((host_info = gethostbyname(Prime_client)) == NULL) {
605             (void) fprintf(stderr, "%s: %s is unknown host\n",
606                         sfs_Myname, Prime_client);
607             return ((int) RPC_UNKNOWNHOST);
608         }
609
610         (void) memset((char *) &prime_addr, '\0', sizeof(prime_addr));
611         (void) memmove((char *) &prime_addr.sin_addr,
612                         (char *) host_info->h_addr, host_info->h_length);
613
614         prime_addr.sin_family = AF_INET;
615         prime_addr.sin_port =  0;
616
617         /*
618          * Create client "handle" used for calling SFS_SYNCPROG on the
619          * Prime Client. We tell the RPC package to use the "tcp"
620          * protocol when contacting the prime_client.
621          */
622         clnt_handle = clnttcp_create(&prime_addr, SFS_SYNCPROG,
623                         SFS_SYNCVERS, &socket, MAX_STR2_LEN, MAX_STR2_LEN);
624
625         if (clnt_handle == ((CLIENT *) NULL)) {
626             /*
627              * Couldn't establish connection with the Prime_Client.
628              * Print error message and return error.
629              */
630             clnt_pcreateerror(Prime_client);
631             (void) fprintf(stderr,
632                 "%s: %s Could not establish client handle to contact %s\n",
633                 lad_timestamp(), sfs_Myname, Prime_client);
634             return((int) RPC_FAILED);
635         }
636     }
637
638     /* fill up xdr structure with data to send to Prime Client */
639     (void) sprintf(transaction_string,"%d_%i", Client_num, ++transaction_id);
640     sync_signal.clnt_type = type;
641     sync_signal.clnt_id = Client_num;
642     sync_signal.clnt_data = data;
643     sync_signal.clnt_transaction = transaction_string;
644
645     /* Call the remote procedure "signal_sfs_1" on the Prime Client */
646     result = signal_sfs_1(&sync_signal, clnt_handle);
647     if (result == NULL) {
648         /*
649          * An error occurred while making RPC to the Prime Client.
650          * Print error message and return error.
651          */
652         sprintf(buf, "%s Transaction %s: Could not call prime client %s",
653                         lad_timestamp(), transaction_string, Prime_client);
654         clnt_perror(clnt_handle, buf);
655         return((int) RPC_CANTSEND);
656     }
657
658     /* OK, we successfully called the remote procedure. */
659     if (*result == 0) {
660         /*
661          * remote procedure was unable to successfully perform required
662          * operation on the Prime Client.
663          * Print error message and return error.
664          */
665         (void) fprintf(stderr,
666                         "%s: %s Prime Client couldn't write to PC_sync file \n",
667                         sfs_Myname, Prime_client);
668         return((int) RPC_FAILED);
669     }
670
671     /* remote procedure success - wrote to Prime Client sync file */
672     return((int) RPC_SUCCESS);
673
674 } /* signal_Prime_Client */
675
676
677 /*
678  * Read results arrays for 'children' children from Logfile
679  * and accumulate them in "Ops".
680  * Complain about any problems we see with the log file.
681  */
682 static void
683 collect_counters(
684     int                 children)
685 {
686     int                         i;
687     int                         j;
688     struct stat                 statb;
689     sfs_results_report_type     report; /* final results log */
690     int                         Saveerrno;
691
692     if (fstat(Log_fd, &statb) == -1) {
693         Saveerrno = errno;
694         (void) fprintf(stderr, "%s: can't stat log %s ", sfs_Myname, Logname);
695         errno = Saveerrno;
696         perror(Logname);
697         (void) generic_kill(0, SIGINT);
698         exit(79);
699     }
700
701     if (statb.st_size != (children * sizeof(report))) {
702         (void) fprintf(stderr, "%s: log file %s has bad format\n",
703                         sfs_Myname, Logname);
704         (void) generic_kill(0, SIGINT);
705         exit(80);
706     }
707
708     if (lseek(Log_fd, 0L, 0) == -1) {
709         Saveerrno = errno;
710         (void) fprintf(stderr, "%s: can't lseek log %s ", sfs_Myname, Logname);
711         errno = Saveerrno;
712         perror("lseek");
713         (void) generic_kill(0, SIGINT);
714         exit(81);
715     }
716
717     for (j = 0; j < NOPS + 1; j++) {
718         Ops[j].results.good_calls = 0;
719         Ops[j].results.bad_calls = 0;
720         Ops[j].results.fast_calls = 0;
721         Ops[j].results.time.sec = 0;
722         Ops[j].results.time.usec = 0;
723         Ops[j].results.msec2 = 0;
724     }
725     Total_fss_bytes = 0;
726     Least_fss_bytes = 0;
727     Most_fss_bytes = 0;
728     Base_fss_bytes = 0;
729
730     for (i = 0; i < children; i++) {
731         if (read(Log_fd, (char *) &report, sizeof(report)) == -1) {
732             Saveerrno = errno;
733             (void) fprintf(stderr, "%s: can't read log %s", sfs_Myname, Logname);
734             errno = Saveerrno;
735             perror("Logname");
736             (void) generic_kill(0, SIGINT);
737             exit(82);
738         }
739
740         for (j = 0; j < NOPS + 1; j++) {
741             Ops[j].results.good_calls += report.results_buf[j].good_calls;
742             Ops[j].results.bad_calls += report.results_buf[j].bad_calls;
743             Ops[j].results.fast_calls += report.results_buf[j].fast_calls;
744             ADDTIME(Ops[j].results.time, report.results_buf[j].time);
745             Ops[j].results.msec2 += report.results_buf[j].msec2;
746         }
747         Total_fss_bytes += report.total_fss_bytes;
748         Least_fss_bytes += report.least_fss_bytes;
749         Most_fss_bytes += report.most_fss_bytes;
750         Base_fss_bytes += report.base_fss_bytes;
751     }
752
753 } /* collect_counters */
754
755
756 /*
757  * Check the parameters for validity.
758  */
759 static int
760 check_parameters(
761 char *  iodist_file,
762 char *  mix_file,
763 int     runtime_val)
764 {
765     int retval = 0;
766     char detail[40];
767
768     detail[0] = '\0';
769
770     if (iodist_file != NULL) {
771         retval = INVALID_IODIST;
772     }
773     if (mix_file != NULL) {
774         retval = INVALID_MIX;
775     }
776     if (runtime_val != DEFAULT_RUNTIME) {
777         (void) sprintf(detail, "%d != %d", runtime_val, DEFAULT_RUNTIME);
778         retval = INVALID_RUNTIME;
779     }
780     if (Access_percent != DEFAULT_ACCESS) {
781         (void) sprintf(detail, "%d != %d", Access_percent, DEFAULT_ACCESS);
782         retval = INVALID_ACCESS;
783     }
784     if (Append_percent != DEFAULT_APPEND) {
785         (void) sprintf(detail, "%d != %d", Append_percent, DEFAULT_APPEND);
786         retval = INVALID_APPEND;
787     }
788     if (Kb_per_block != DEFAULT_KB_PER_BLOCK) {
789         (void) sprintf(detail, "%d != %d", Kb_per_block, DEFAULT_KB_PER_BLOCK);
790         retval = INVALID_KB;
791     }
792     if (Files_per_dir != DEFAULT_FILES_PER_DIR) {
793         (void) sprintf(detail, "%d != %d", Files_per_dir, DEFAULT_FILES_PER_DIR);
794         retval = INVALID_NDIRS;
795     }
796     if (Fss_delta_percent != DEFAULT_DELTA_FSS) {
797         (void) sprintf(detail, "%d != %d",
798                                 Fss_delta_percent, DEFAULT_DELTA_FSS);
799         retval = INVALID_FSS;
800     }
801     if (Biod_max_outstanding_reads < DEFAULT_BIOD_MAX_READ) {
802         (void) sprintf(detail, "%d < %d",
803                         Biod_max_outstanding_reads, DEFAULT_BIOD_MAX_READ);
804         retval = INVALID_BIODREAD;
805     }
806     if (Tot_client_num_symlinks != DEFAULT_NSYMLINKS) {
807         (void) sprintf(detail, "%d != %d",
808                         Tot_client_num_symlinks, DEFAULT_NSYMLINKS);
809         retval = INVALID_NSYMLINKS;
810     }
811     if (Biod_max_outstanding_writes < DEFAULT_BIOD_MAX_WRITE) {
812         (void) sprintf(detail, "%d < %d",
813                         Biod_max_outstanding_writes, DEFAULT_BIOD_MAX_WRITE);
814         retval = INVALID_BIODWRITE;
815     }
816     if (Warmuptime != DEFAULT_WARMUP) {
817         (void) sprintf(detail, "%d != %d",
818                         Warmuptime, DEFAULT_WARMUP);
819         retval = INVALID_WARMUP;
820     }
821
822     if (retval != 0)
823         (void) fprintf(stdout,
824                 "%s: INVALID RUN, ILLEGAL PARAMETER: Non-standard %s %s\n",
825                 sfs_Myname, invalid_str[retval], detail);
826     return (retval);
827 }
828
829 /*
830  * Check the results in Ops[] for validity.
831  */
832 static int
833 check_counters(void)
834 {
835     double      mix_pcnt;
836     int         bad_pcnt;
837     int         i;
838     int         ret = 0;
839
840     if (Ops[TOTAL].results.good_calls <= 0) {
841         (void) fprintf(stdout, "%s: INVALID RUN %s\n",
842                                 sfs_Myname, invalid_str[INVALID_GOODCALLS]);
843         ret = INVALID_GOODCALLS;
844     }
845     if (Ops[TOTAL].results.good_calls != 0)
846         bad_pcnt = (Ops[TOTAL].results.bad_calls * 100)
847                / Ops[TOTAL].results.good_calls;
848     else
849         bad_pcnt = 100;
850
851     if (bad_pcnt >= 1) {
852         (void) fprintf(stdout, "%s: INVALID RUN, %d%% %s\n",
853
854                         sfs_Myname, bad_pcnt,
855                         invalid_str[INVALID_FAILEDRPC]);
856         ret = INVALID_FAILEDRPC;
857     }
858
859     if (Ops[TOTAL].results.good_calls == 0) {
860         (void) fprintf(stdout, "%s: INVALID RUN, no good calls\n", sfs_Myname);
861         return (INVALID_NOTMIX);
862     }
863
864     for (i = 0; i < NOPS; i++) {
865         mix_pcnt = ((double)Ops[i].results.good_calls /
866                                         Ops[TOTAL].results.good_calls) * 100.0;
867         if (mix_pcnt != (double)Ops[i].mix_pcnt) {
868             if ((mix_pcnt - (double)Ops[i].mix_pcnt > 1.5) ||
869                 ((double)Ops[i].mix_pcnt - mix_pcnt > 1.5)) {
870                 (void) fprintf(stdout, "%s: INVALID RUN, %s target %d%% actual %4.1f%% %s\n",
871
872                         sfs_Myname, Ops[i].name, Ops[i].mix_pcnt, mix_pcnt,
873                         invalid_str[INVALID_NOTMIX]);
874                 ret = INVALID_NOTMIX;
875             }
876         }
877     }
878
879     return (ret);
880
881 } /* check_counters */
882
883
884 /*
885  * Print the test run results, for 'load' load, the operation percentages
886  * in 'mixfile' percentages, and 'children' processes.
887  */
888 static void
889 print_results(
890     int                         children,
891     int                         load,
892     char *                      mix_file,
893     int                         invalid_flag,
894     int                         runtime_val,
895     char *                      iodist_file)
896 {
897     uint_t                      runtime;
898     uint_t                      total_msec;
899     uint_t                      msec;
900     uint_t                      total_calls;
901     uint_t                      calls;
902     int                         i;
903     double                      squared_time_msec;
904     double                      sum2_msec;
905     double                      var_msec;
906     double                      stdev_msec;
907     double                      sq_conf_interval_msec;
908     double                      conf_interval_msec;
909     sfs_op_type *               op_ptr;
910     sfs_results_type *          results_ptr;
911     char                        result_string[MAX_LINE_LEN];
912
913
914     /* compute total time for all ops combined */
915     total_msec = 0;
916     for (i = 0; i < NOPS; i++) {
917         total_msec += Ops[i].results.time.sec * 1000;
918         total_msec += Ops[i].results.time.usec / 1000;
919     }
920
921     /*
922      * Report statistics based on successful calls only.  The per
923      * operation routines accumulate time and count only good_calls.
924      */
925     total_calls = Ops[TOTAL].results.good_calls;
926
927
928     /*
929      * Print the client's test parameters
930      */
931     (void) fprintf(stderr, "\n\nClient Test Parameters: \n");
932     (void) fprintf(stderr, "\tNumber of processes = %d\n", children);
933     (void) fprintf(stderr, "\tRequested Load (NFS V%d operations/second) = %d\n",
934                     nfs_version, load);
935     (void) fprintf(stderr, "\tMaximum number of outstanding biod writes = %d\n",
936                     Biod_max_outstanding_writes);
937     (void) fprintf(stderr, "\tMaximum number of outstanding biod reads = %d\n",
938                     Biod_max_outstanding_reads);
939     (void) fprintf(stderr, "\tWarm-up time (seconds) = %d\n\tRun time (seconds) = %d\n",
940                     Warmuptime, runtime_val);
941     if (mix_file)
942         (void) fprintf(stderr,"\tNFS Mixfile = %s\n", mix_file);
943     if (iodist_file)
944         (void) fprintf(stderr,"\tBlock Size Distribution file = %s\n",
945                         iodist_file);
946     (void) fprintf(stderr, "\tFile Set = %4d Files created for I/O operations\n",
947                 (Tot_client_num_io_files/children + 1) * children);
948     (void) fprintf(stderr, "\t\t   %4d Files accessed for I/O operations\n",
949                 (((Tot_client_num_io_files/children + 1) * Access_percent)
950                    / 100) * children);
951     (void) fprintf(stderr, "\t\t   %4d Files for non-I/O operations\n",
952                 (Tot_client_num_non_io_files/children + 1) * children);
953     (void) fprintf(stderr, "\t\t   %4d Symlinks\n",
954                 (Tot_client_num_symlinks/children + 1) * children);
955     (void) fprintf(stderr, "\t\t   %4d Directories\n",
956                 ((Tot_client_num_io_files/children + 1) / Files_per_dir ) * children);
957     (void) fprintf(stderr, "\t\t\tAdditional non-I/O files created as necessary\n\n");
958
959     (void) sprintf(Client_results,"%d %d %d %d %d %d\n",
960         nfs_version,
961         (Tot_client_num_io_files/children + 1) * children,
962         (((Tot_client_num_io_files/children + 1) * Access_percent)
963                 / 100) *children,
964         (Tot_client_num_non_io_files/children + 1) * children,
965         (Tot_client_num_symlinks/children + 1) * children,
966         ((Tot_client_num_io_files/children + 1) / Files_per_dir ) * children);
967
968     /* print the client's results header information */
969     (void) fprintf(stderr, "\nSPEC SFS Benchmark Version %s, Creation - %s\n",
970                                 SFS_VERSION_NUM, SFS_VERSION_DATE);
971     (void) fprintf(stdout, "SFS Single Client (%s) Results, %s\n",
972                     lad_hostname, lad_timestamp());
973     (void) fflush(stdout);
974
975     /* print column headers for per operation statistics */
976     (void) fprintf(stdout,
977 "----------------------------------------------------------------------------\n");
978     (void) fprintf(stdout, "\n");
979     (void) fprintf(stdout,
980 "NFS V%d     Target Actual   NFS    NFS    Mean     Std Dev  Std Error   Pcnt \n",
981 nfs_version);
982     (void) fprintf(stdout,
983 "Op           NFS    NFS     Op     Op    Response Response of Mean,95%%  of  \n");
984     (void) fprintf(stdout,
985 "Type         Mix    Mix   Success Error   Time     Time    Confidence  Total\n");
986     (void) fprintf(stdout,
987 "             Pcnt   Pcnt   Count  Count  Msec/Op  Msec/Op  +- Msec/Op  Time \n");
988     (void) fprintf(stdout,
989 "----------------------------------------------------------------------------\n");
990     (void) fflush(stdout);
991
992     /* print per operation statistics */
993     for (i = 0; i < NOPS; i++) {
994         /* init to 0 */
995         squared_time_msec = 0.0;
996         sum2_msec = 0.0;
997         calls = 0;
998         msec = 0;
999         stdev_msec = 0;
1000
1001         op_ptr = &Ops[i];
1002         results_ptr = &op_ptr->results;
1003
1004         /* get the number successful calls and total time */
1005         calls = op_ptr->results.good_calls;
1006         msec = (results_ptr->time.sec * 1000)
1007                + (results_ptr->time.usec / 1000);
1008
1009         /* compute the standard deviation for the mean response time */
1010         if (calls <= 1)
1011             stdev_msec = 0;
1012         else {
1013             /* get the standard deviation */
1014             squared_time_msec = results_ptr->msec2;
1015             /* compute the square of the total elapsed time */
1016             sum2_msec = (results_ptr->time.sec * 1000.0)
1017                          + (results_ptr->time.usec / 1000.0);
1018             sum2_msec *= sum2_msec;
1019
1020             /* variance = 1/(n-1) * (sum(x^2) - 1/n * (sum(x))^2) */
1021             var_msec = (squared_time_msec - (sum2_msec / calls)) / (calls-1);
1022             if (var_msec == 0.0) {
1023                 stdev_msec = 0.0;
1024             } else
1025                 stdev_msec = sqrt(var_msec);
1026         }
1027
1028         /* compute the confidence interval */
1029         if (calls != 0) {
1030             sq_conf_interval_msec = DEFAULT_CHI_SQR_CI * (stdev_msec / calls);
1031             if (sq_conf_interval_msec == 0.0) {
1032                 conf_interval_msec = 0.0;
1033             } else
1034                 conf_interval_msec = sqrt(sq_conf_interval_msec);
1035         } else
1036             conf_interval_msec = 0.0;
1037
1038         /* print the per op statistics */
1039         (void) fprintf(stdout,
1040         "%-12s%3d%%   %4.1f%%   %5d %5d %5.2f %8.2f  %8.2f    %3.1f%%\n",
1041             op_ptr->name,                                       /* op name */
1042             op_ptr->mix_pcnt,                                   /* target mix */
1043                                                                 /* actual mix */
1044             total_calls ? ((double)calls / total_calls) * 100.0 : 0.0,
1045             results_ptr->good_calls,                            /* successes */
1046             results_ptr->bad_calls,                             /* errors */
1047             calls ? ((double)msec / calls) : 0.0,               /* msec/call */
1048             stdev_msec,                                         /* std dev */
1049             conf_interval_msec,                                 /* conf int */
1050                                                                 /* % of time */
1051             total_msec ? ((double)msec / total_msec) * 100 : 0.0);
1052         (void) fflush(stdout);
1053
1054         /*
1055          * Store client data in result_string.
1056          * This string is different from client result display.
1057          * The  squared_time_msec and sum2_msec values are passed along
1058          * to be used by the prime client to calculate the stddev value for
1059          * each operation.
1060          */
1061         if (Prime_client) {
1062         (void) sprintf(result_string,
1063         "%-12s   %3d%% %3.1f%% %5d  %5d %4ld.%1ld %6.2f  %3.1f%% %f %f\n",
1064             op_ptr->name,                                       /* op name */
1065             op_ptr->mix_pcnt,                                   /* target mix */
1066                                                                 /* actual mix */
1067             total_calls ? ((double)calls / total_calls) * 100.0 : 0.0,
1068             results_ptr->good_calls,                            /* successes */
1069             results_ptr->bad_calls,                             /* errors */
1070             results_ptr->time.sec,                              /* total time1*/
1071             results_ptr->time.usec / 100000,                    /* total time2*/
1072             calls ? ((double)msec / calls) : 0.0,               /* msec/call */
1073                                                                 /* % of time */
1074             total_msec ? ((double)msec / total_msec) * 100 : 0.0,
1075             squared_time_msec,                                  /* sum of sqs */
1076             sum2_msec);                                         /* sq of sums */
1077             (void) strcat(Client_results, result_string);
1078         }
1079
1080     } /* end for each op */
1081
1082     (void) fprintf(stdout,
1083 "----------------------------------------------------------------------------\n\n");
1084     (void) fflush(stdout);
1085
1086     /* Average child runtime.  (should this be the longest runtime?) */
1087     runtime = Ops[TOTAL].results.time.sec / children;
1088
1089     /* Print summary */
1090     (void) fprintf(stdout,
1091         "      ------------------------------------------------------------\n");
1092     (void) fprintf(stdout,
1093         "      | SPEC SFS VERSION %6s SINGLE CLIENT RESULTS SUMMARY    |\n",
1094                                                         SFS_VERSION_NUM);
1095     (void) fprintf(stdout,
1096         "      ------------------------------------------------------------\n");
1097     (void) fprintf(stdout, "NFS V%d THROUGHPUT: ", nfs_version);
1098     (void) fprintf(stdout,
1099                     "%4d.%02d Ops/Sec   AVG. RESPONSE TIME: %4d.%02d Msec/Op\n",
1100                     runtime ? (total_calls / runtime) : 0,
1101                     runtime ? ((total_calls % runtime) * 100 / runtime) : 0,
1102                     total_calls ? (total_msec / total_calls) : 0,
1103                     total_calls ? ((total_msec % total_calls) * 100 / total_calls) : 0);
1104     (void) fprintf(stdout, "%s PROTOCOL\n", Tcp ? "TCP" : "UDP");
1105     (void) fprintf(stdout, "FAST CALLS: %d\n", Ops[TOTAL].results.fast_calls);
1106     (void) fprintf(stdout, "NFS MIXFILE: ");
1107     if (mix_file)
1108         (void) fprintf(stdout,"%s\n", mix_file);
1109     else
1110         (void) fprintf(stdout,"[ SFS Default ]\n");
1111     (void) fprintf(stdout, "CLIENT REQUESTED LOAD: %d Ops/Sec \n", load);
1112     (void) fprintf(stdout,
1113                         "TOTAL NFS OPERATIONS: %-6d      TEST TIME: %d Sec \n",
1114                         total_calls, runtime);
1115     (void) fprintf(stdout, "FILE SET SIZE CREATED: %d KB\n",
1116                                                         Total_fss_bytes);
1117     (void) fprintf(stdout,
1118                 "FILE SET SIZE ACCESSED: %d - %d KB  (%d%% to %d%% of Base)\n",
1119                 Least_fss_bytes, Most_fss_bytes,
1120                 (100 * Least_fss_bytes) / Base_fss_bytes,
1121                 (100 * Most_fss_bytes) / Base_fss_bytes);
1122     (void) fprintf(stdout, "\n");
1123     (void) fprintf(stdout,
1124     "------------------------------------------------------------------------");
1125     (void) fprintf(stdout, "\n\n");
1126     (void) fflush(stdout);
1127
1128     /*
1129      * store client summary results and Invalid run indicator
1130      * to send to the Prime_client
1131      */
1132     if (Prime_client) {
1133         (void) sprintf(result_string,"%d.%02d %d.%02d %d %d %d %d %d %d %d\n",
1134             runtime ? (total_calls / runtime) : 0,          /* ops/sec1 */
1135             runtime ? ((total_calls % runtime) * 100 / runtime) : 0, /* ops/sec2 */
1136             total_calls ? (total_msec / total_calls) : 0,       /* mean1 */
1137             total_calls ? ((total_msec % total_calls) * 100 / total_calls) : 0, /* mean2 */
1138             runtime,                                        /* run time */
1139             total_calls,                                    /* # ops */
1140             invalid_flag,                                   /* valid flag */
1141             Total_fss_bytes,                                /* total fileset */
1142             Least_fss_bytes,                                /* fileset low */
1143             Most_fss_bytes,                                 /* fileset high */
1144             Base_fss_bytes);                                /* fileset base */
1145         (void) strcat(Client_results, result_string);
1146     }
1147
1148 } /* print_results */
1149
1150
1151 /* ARGSUSED */
1152 static void
1153 sfs_reaper(
1154     int         sig_id)
1155 {
1156     (void) fprintf(stderr, "%s: caught unexpected SIGCHLD. Exiting...\n",
1157                        sfs_Myname);
1158     /* cleanup and exit */
1159     (void) signal_Prime_Client("CLIENT_STOP", "");
1160     (void) generic_kill(0, SIGINT);
1161     exit(83);
1162 }
1163 /* sfs_c_pnt.c */