2 static char sfs_c_pntSid[] = "@(#)sfs_c_pnt.c 2.1 97/10/23";
6 * Copyright (c) 1992-1997,2001 by Standard Performance Evaluation Corporation
8 * Standard Performance Evaluation Corporation (SPEC)
9 * 6585 Merchant Place, Suite 100
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.
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.
20 * The source code is provided to the user or company under the license
21 * agreement for the SPEC Benchmark Suite for this product.
24 /*****************************************************************
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. *
33 *****************************************************************/
38 * void parent(int, int, char *, char *)
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 *)
49 * 10-Jan-92 Teelucksingh
50 * Client passes standard deviation compute
51 * values to Prime-Client as well as an
54 * 16-Dec-91 Wittle Created.
58 * ------------------------- Include Files -------------------------
73 #include <sys/types.h>
79 #include "sfs_c_def.h"
80 #include "sfs_m_def.h"
82 #if !defined(_XOPEN_SOURCE)
83 #include <sys/socket.h>
89 * ------------------------- External Definitions -------------------------
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);
101 /* Aggregate results storage */
102 static char Client_results[(NOPS+3)*MAX_LINE_LEN];
105 * ------------------------- SFS Parent Code -------------------------
109 * Parent: wait for kids to get ready, start them, wait for them to
110 * finish, read and accumulate results.
119 char string[80]; /* for interactive startup */
121 int invalid_run; /* holds INVALID RUN status */
122 int runtime_val; /* store Runtime value to be printed later */
125 #if (defined(_XOPEN_SOURCE) || defined(USE_POSIX_SIGNALS))
126 struct sigaction sig_act, old_sig_act;
130 * Setup a SIGCHLD handler in case one of our beloved children dies
133 #if (defined(_XOPEN_SOURCE) || defined(USE_POSIX_SIGNALS))
134 /* use XOPEN signal handling */
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");
144 (void) signal(SIGCHLD, sfs_reaper);
147 /* Change my name for error logging */
148 if ((nameptr = strrchr(sfs_Myname, '/')) != NULL)
149 sfs_Myname = ++nameptr;
152 * store the Runtime value; to be printed in results
155 runtime_val = Runtime - MULTICLIENT_OFFSET;
156 else runtime_val = Runtime;
158 /* print logfile header information */
159 (void) fprintf(stdout,"\n");
160 (void) fprintf(stdout,
161 "************************************************************************");
162 (void) fprintf(stdout,"\n");
163 (void) fflush(stdout);
165 /* print sfs information */
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",
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);
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());
186 * if multi-client execution then tell Prime-Client I'm done mounting
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);
195 (int) signal_Prime_Client("CLIENT_SIGNAL", ""))
196 == (int) RPC_SUCCESS) {
197 (void) fprintf(stderr, "%s Completed.",lad_timestamp());
198 (void) fflush(stderr);
200 (void) fprintf(stderr, "\n");
201 (void) fprintf(stderr,
202 "%s: error %d sending DONE-MOUNT message to Prime Client\n",
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");
214 (void) signal(SIGCHLD, SIG_DFL);
216 (void) generic_kill(0, SIGINT);
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);
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
233 (void) fprintf(stderr, "%s Received.",lad_timestamp());
234 (void) fflush(stderr);
236 } /* send DONE-MOUNT and got DO-INIT message */
238 /* initialize test directories */
239 (void) fprintf(stderr, "\n");
240 (void) fprintf(stderr, "%s Initializing test directories.\n",
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);
250 * if multi-client execution then tell Prime-Client I'm done initializing
251 * and wait for synchronized do warmupmessage.
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);
259 (int) signal_Prime_Client("CLIENT_SIGNAL",""))
260 == (int) RPC_SUCCESS) {
261 (void) fprintf(stderr, "%s Completed.",lad_timestamp());
262 (void) fflush(stderr);
264 (void) fprintf(stderr, "\n");
265 (void) fprintf(stderr,
266 "%s: error %d sending DONE-INIT message to Prime Client\n",
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");
278 (void) signal(SIGCHLD, SIG_DFL);
280 (void) generic_kill(0, SIGINT);
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);
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
296 (void) fprintf(stderr, "%s Received.",lad_timestamp());
297 (void) fflush(stderr);
299 } /* send DONE-INIT and got DO-WARMUP message */
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");
312 (void) signal(SIGCHLD, SIG_DFL);
314 (void) generic_kill(0, SIGUSR1);
315 while (wait((int *) 0) != -1) {
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);
333 (void) fprintf(stderr, "\n");
334 (void) fprintf(stderr, "Hit <return> when ready to start test ...");
335 (void) fgets(string,10,stdin);
339 * if multi-client execution then tell Prime-Client I'm done warm-up
340 * and wait for synchronized Start message.
343 (void) fprintf(stderr, "\n");
344 (void) fprintf(stderr,
345 "%s Sending READY message to Prime Client(%s).\n",
346 lad_timestamp(), Prime_client);
348 (int) signal_Prime_Client("CLIENT_SIGNAL",""))
349 == (int) RPC_SUCCESS) {
350 (void) fprintf(stderr, "%s Completed.",lad_timestamp());
351 (void) fflush(stderr);
353 (void) fprintf(stderr, "\n");
354 (void) fprintf(stderr,
355 "%s: error %d sending READY message to Prime Client\n",
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");
367 (void) signal(SIGCHLD, SIG_DFL);
369 (void) generic_kill(0, SIGINT);
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);
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
386 (void) fprintf(stderr, "%s Received.",lad_timestamp());
387 (void) fflush(stderr);
389 } /* send READY and got START message */
391 (void) fprintf(stderr, "\n");
394 (void) fprintf(stderr, "%s Starting %d seconds test run.\n",
395 lad_timestamp(), Runtime - MULTICLIENT_OFFSET);
397 (void) fprintf(stderr, "%s Starting %d seconds test run.\n",
398 lad_timestamp(), Runtime);
401 (void) fprintf(stderr, "%s Starting %d call test run.\n",
402 lad_timestamp(), Ops[TOTAL].target_calls);
404 (void) fflush(stderr);
406 /* signal child processes to go */
407 (void) generic_kill(0, SIGUSR1);
410 (void) sleep(Runtime);
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");
421 (void) signal(SIGCHLD, SIG_DFL);
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.
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.
439 (void) generic_kill(0, SIGUSR2); /* tell children to finish */
442 /* Wait for all the children to finish/die */
443 while (wait((int *) 0) != -1) {
447 (void) fprintf(stderr, "%s Completed.", lad_timestamp());
448 (void) fflush(stdout);
449 (void) fflush(stderr);
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);
456 /* print test results */
457 print_results(children, load, mix_file,
458 invalid_run, runtime_val, iodist_file);
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
466 (void) fprintf(stderr,
467 "%s Sending DONE-TEST message to Prime Client(%s).\n",
468 lad_timestamp(), Prime_client);
470 (int) signal_Prime_Client("CLIENT_SIGNAL",""))
471 == (int) RPC_SUCCESS) {
472 (void) fprintf(stderr, "%s Completed.", lad_timestamp());
473 (void) fflush(stderr);
476 (void) fprintf(stderr, "\n");
477 (void) fprintf(stderr,
478 "%s: error %d sending DONE-TEST message to Prime Client\n",
481 perror("signal_Prime_Client");
482 /* cleanup and exit */
483 (void) generic_kill(0, SIGINT);
488 * wait for MOVE-DATA message from Prime Client before
489 * sending send results.
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);
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);
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);
510 (void) fprintf(stderr, "\n");
511 (void) fprintf(stderr,
512 "%s: error %d sending client's result to Prime Client\n",
515 perror("signal_Prime_Client");
516 /* cleanup and exit */
517 (void) generic_kill(0, SIGINT);
520 } /* sent done, got move-data and sent data */
522 (void) fprintf(stdout,"\n");
523 (void) fprintf(stdout,
524 "************************************************************************");
525 (void) fprintf(stdout,"\n");
531 * ------------------------ Utility Routines --------------------------
536 * Monitor Logfile until its size reaches 'children' bytes.
537 * This means that all of the children are waiting for the next instruction.
540 synchronize_children(
543 struct stat statb; /* for fstat */
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);
552 } while (statb.st_size < children);
555 * Truncate the log file
558 Log_fd = open(Logname, (O_RDWR | O_CREAT | O_TRUNC | O_APPEND), 0666);
560 (void) fprintf(stderr, "%s: can't truncate log %s",
561 sfs_Myname, Logname);
562 (void) generic_kill(0, SIGINT);
566 } /* synchronize_children */
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'.
581 static CLIENT * clnt_handle = NULL;
582 static int transaction_id = 0;
585 sync_string sync_signal;
586 char transaction_string[MAX_STR1_LEN];
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),
594 return((int)RPC_CANTENCODEARGS);
597 if (clnt_handle == NULL) {
598 struct sockaddr_in prime_addr;
599 struct hostent * host_info;
601 socket = RPC_ANYSOCK;
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);
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);
614 prime_addr.sin_family = AF_INET;
615 prime_addr.sin_port = 0;
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.
622 clnt_handle = clnttcp_create(&prime_addr, SFS_SYNCPROG,
623 SFS_SYNCVERS, &socket, MAX_STR2_LEN, MAX_STR2_LEN);
625 if (clnt_handle == ((CLIENT *) NULL)) {
627 * Couldn't establish connection with the Prime_Client.
628 * Print error message and return error.
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);
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;
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) {
649 * An error occurred while making RPC to the Prime Client.
650 * Print error message and return error.
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);
658 /* OK, we successfully called the remote procedure. */
661 * remote procedure was unable to successfully perform required
662 * operation on the Prime Client.
663 * Print error message and return error.
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);
671 /* remote procedure success - wrote to Prime Client sync file */
672 return((int) RPC_SUCCESS);
674 } /* signal_Prime_Client */
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.
689 sfs_results_report_type report; /* final results log */
692 if (fstat(Log_fd, &statb) == -1) {
694 (void) fprintf(stderr, "%s: can't stat log %s ", sfs_Myname, Logname);
697 (void) generic_kill(0, SIGINT);
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);
708 if (lseek(Log_fd, 0L, 0) == -1) {
710 (void) fprintf(stderr, "%s: can't lseek log %s ", sfs_Myname, Logname);
713 (void) generic_kill(0, SIGINT);
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;
730 for (i = 0; i < children; i++) {
731 if (read(Log_fd, (char *) &report, sizeof(report)) == -1) {
733 (void) fprintf(stderr, "%s: can't read log %s", sfs_Myname, Logname);
736 (void) generic_kill(0, SIGINT);
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;
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;
753 } /* collect_counters */
757 * Check the parameters for validity.
770 if (iodist_file != NULL) {
771 retval = INVALID_IODIST;
773 if (mix_file != NULL) {
774 retval = INVALID_MIX;
776 if (runtime_val != DEFAULT_RUNTIME) {
777 (void) sprintf(detail, "%d != %d", runtime_val, DEFAULT_RUNTIME);
778 retval = INVALID_RUNTIME;
780 if (Access_percent != DEFAULT_ACCESS) {
781 (void) sprintf(detail, "%d != %d", Access_percent, DEFAULT_ACCESS);
782 retval = INVALID_ACCESS;
784 if (Append_percent != DEFAULT_APPEND) {
785 (void) sprintf(detail, "%d != %d", Append_percent, DEFAULT_APPEND);
786 retval = INVALID_APPEND;
788 if (Kb_per_block != DEFAULT_KB_PER_BLOCK) {
789 (void) sprintf(detail, "%d != %d", Kb_per_block, DEFAULT_KB_PER_BLOCK);
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;
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;
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;
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;
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;
816 if (Warmuptime != DEFAULT_WARMUP) {
817 (void) sprintf(detail, "%d != %d",
818 Warmuptime, DEFAULT_WARMUP);
819 retval = INVALID_WARMUP;
823 (void) fprintf(stdout,
824 "%s: INVALID RUN, ILLEGAL PARAMETER: Non-standard %s %s\n",
825 sfs_Myname, invalid_str[retval], detail);
830 * Check the results in Ops[] for validity.
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;
845 if (Ops[TOTAL].results.good_calls != 0)
846 bad_pcnt = (Ops[TOTAL].results.bad_calls * 100)
847 / Ops[TOTAL].results.good_calls;
852 (void) fprintf(stdout, "%s: INVALID RUN, %d%% %s\n",
854 sfs_Myname, bad_pcnt,
855 invalid_str[INVALID_FAILEDRPC]);
856 ret = INVALID_FAILEDRPC;
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);
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",
872 sfs_Myname, Ops[i].name, Ops[i].mix_pcnt, mix_pcnt,
873 invalid_str[INVALID_NOTMIX]);
874 ret = INVALID_NOTMIX;
881 } /* check_counters */
885 * Print the test run results, for 'load' load, the operation percentages
886 * in 'mixfile' percentages, and 'children' processes.
903 double squared_time_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];
914 /* compute total time for all ops combined */
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;
922 * Report statistics based on successful calls only. The per
923 * operation routines accumulate time and count only good_calls.
925 total_calls = Ops[TOTAL].results.good_calls;
929 * Print the client's test parameters
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",
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);
942 (void) fprintf(stderr,"\tNFS Mixfile = %s\n", mix_file);
944 (void) fprintf(stderr,"\tBlock Size Distribution file = %s\n",
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)
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");
959 (void) sprintf(Client_results,"%d %d %d %d %d %d\n",
961 (Tot_client_num_io_files/children + 1) * children,
962 (((Tot_client_num_io_files/children + 1) * Access_percent)
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);
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);
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",
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);
992 /* print per operation statistics */
993 for (i = 0; i < NOPS; i++) {
995 squared_time_msec = 0.0;
1002 results_ptr = &op_ptr->results;
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);
1009 /* compute the standard deviation for the mean response time */
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;
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) {
1025 stdev_msec = sqrt(var_msec);
1028 /* compute the confidence interval */
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;
1034 conf_interval_msec = sqrt(sq_conf_interval_msec);
1036 conf_interval_msec = 0.0;
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 */
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 */
1051 total_msec ? ((double)msec / total_msec) * 100 : 0.0);
1052 (void) fflush(stdout);
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
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 */
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 */
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);
1080 } /* end for each op */
1082 (void) fprintf(stdout,
1083 "----------------------------------------------------------------------------\n\n");
1084 (void) fflush(stdout);
1086 /* Average child runtime. (should this be the longest runtime?) */
1087 runtime = Ops[TOTAL].results.time.sec / children;
1090 (void) fprintf(stdout,
1091 " ------------------------------------------------------------\n");
1092 (void) fprintf(stdout,
1093 " | SPEC SFS VERSION %6s SINGLE CLIENT RESULTS SUMMARY |\n",
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: ");
1108 (void) fprintf(stdout,"%s\n", mix_file);
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",
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);
1129 * store client summary results and Invalid run indicator
1130 * to send to the 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);
1148 } /* print_results */
1156 (void) fprintf(stderr, "%s: caught unexpected SIGCHLD. Exiting...\n",
1158 /* cleanup and exit */
1159 (void) signal_Prime_Client("CLIENT_STOP", "");
1160 (void) generic_kill(0, SIGINT);