2 static char sccsid[] = "@(#)sfs_m_prm.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 *****************************************************************/
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.
42 * int main(int, char **)
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)
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.
79 * 23-Sep-91 0.00.11 Teelucksingh
80 * Modified the format of sfs_prime output
81 * 17-Jun-91 Teelucksingh Created.
88 * ------------------------- Include Files -------------------------
102 #include <sys/types.h>
103 #include <sys/stat.h>
105 #include <sys/file.h>
110 #include "sfs_c_def.h"
111 #include "sfs_m_def.h"
113 #if !defined(_XOPEN_SOURCE)
114 #include <sys/socket.h>
120 * ----------------------- External Definitions -----------------------
124 /* sfs_mpr.c function declarations */
125 /* external sfs routines */
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);
137 * ----------------------- Static Definitions -----------------------
140 #define EXTRA_INIT_TIME 3600 /* extra time to initialize before timing out */
142 int Debug_level = 0; /* flag indicates prime client debug mode */
143 char *sfs_Myname; /* program name */
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 */
157 * the Prime_client only uses the P_* variables
158 * for calculating and reporting the Aggregate
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 */
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;
180 * --------------------- Biod Simulation Variables ---------------------
182 static int P_biod_max_outstanding_reads = DEFAULT_BIOD_MAX_READ;
183 static int P_biod_max_outstanding_writes = DEFAULT_BIOD_MAX_WRITE;
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" };
195 * -------------------------- Prime-client --------------------------
200 * SIGINT Signal Handler
201 * - rpc to all clients to cleanup and exit
207 /* wake up this process if asleep */
209 (void) generic_kill(0,SIGALRM);
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)
216 (void) fprintf(stderr,"done\n");
217 (void) fflush(stderr);
218 (void) close(Pc_log_fd);
219 (void) unlink(SFS_PRIME_SYNC_LOG);
222 } /* multi_cleanup */
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
245 char monitor_cmd[SFS_MAXPATHLEN+5];
246 int nsigs = 32; /* reasonable default */
249 #if (defined(_XOPEN_SOURCE) || defined(USE_POSIX_SIGNALS))
250 struct sigaction sig_act, old_sig_act;
254 * Place pid in pid log file
256 if ((pid_fp = fopen(SFS_PRM_PID, "a+")) == NULL) {
260 (void) fprintf(pid_fp, "%d\n", getpid());
261 (void) fclose(pid_fp);
263 (void) fprintf(stderr, "\nSPEC SFS Benchmark Version %s, Creation - %s\n",
264 SFS_VERSION_NUM, SFS_VERSION_DATE);
265 (void) fflush(stderr);
267 /* initialize variables, parse input, etc. */
268 do_initialize(argc, argv);
271 * setup value of nsigs
282 #if defined(SOLARIS2) && !defined(_sys_nsig)
283 nsigs = _sys_siglistn;
286 /* trap for all signals */
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) {
295 (void) fprintf (stderr,
296 "WARNING: nsigs not defined, no extra signals caught\n");
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) {
303 (void) fprintf (stderr,
304 "Skipping invalid signal %d\n", i);
306 perror("sigaction failed");
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");
322 if (DEBUG_PARENT_GENERAL) {
324 (void) fprintf (stderr,
325 "WARNING: nsigs not defined, no extra signals caught\n");
327 for (i = 1; i < nsigs; i++) {
328 (void) signal(i, generic_catcher);
332 /* set up SIGINT signal handler */
333 (void) signal(SIGINT, multi_cleanup);
335 #endif /* USE_POSIX_SIGNALS */
337 (void) fprintf(stderr, "Executing SFS Benchmark on %d Client(s).\n",
339 (void) fflush(stderr);
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);
347 sync_PC_with_clients(); /* wait for clients DONE-MOUNT */
349 (void) fprintf(stderr, "%s Received.\n", lad_timestamp());
350 (void) fflush(stderr);
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)
358 (void) fprintf(stderr, "%s Completed.\n", lad_timestamp());
359 (void) fflush(stderr);
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);
368 * add an extra time to time_out value.
369 * initializing the SFS testdirs on clients can take a while.
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 */
375 (void) fprintf(stderr, "%s Received.\n", lad_timestamp());
376 (void) fflush(stderr);
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)
384 (void) fprintf(stderr, "%s Completed.\n", lad_timestamp());
385 (void) fflush(stderr);
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);
392 (void) sleep(P_warmuptime);
394 sync_PC_with_clients(); /* wait for clients READY */
396 (void) fprintf(stderr, "%s Received.\n", lad_timestamp());
397 (void) fflush(stderr);
400 * call the program to trigger START of external monitoring
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;
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.
419 (void) sleep(Prime_sleep_time);
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)
427 (void) fprintf(stderr, "%s Completed.\n", lad_timestamp());
428 (void) fflush(stderr);
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.
435 /* set the Asleep flag go to sleep while clients are executing sfs */
437 (void) sleep(Prime_runtime);
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)
445 (void) fprintf(stderr, "%s Completed.\n", lad_timestamp());
446 (void) fflush(stderr);
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);
458 * call the program to trigger STOP of external monitoring
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;
471 /* give enough time to stop external performance monitoring utilities. */
472 (void) sleep(Prime_sleep_time);
475 * send MOVE-DATA message to Clients to move data across
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)
482 (void) fprintf(stderr, "%s Completed.\n", lad_timestamp());
483 (void) fflush(stderr);
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);
494 /* summarize and print aggregate results */
495 print_multi_results();
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);
506 * initialize control variables, open logfiles etc.
521 sfs_Myname = argv[0];
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)
529 case 'a': /* Percent of file set to access;
530 * used in aggregate report.
532 if (!isdigit(optarg[0])) {
533 (void) fprintf(stderr, "%s: illegal acces value %s\n",
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",
546 case 'A': /* Percent of writes that append;
547 * used in aggregate report.
549 if (!isdigit(optarg[0])) {
550 (void) fprintf(stderr, "%s: illegal append value %s\n",
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",
563 case 'b': /* Set block size distribution table file
564 * used in aggregate report.
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);
572 P_iodist_file = optarg;
573 (void) fclose(check_fp);
577 case 'B': /* Set the per packet maximum block size
578 * used in aggregate reporting only.
580 if (!isdigit(optarg[0])) {
581 (void) fprintf(stderr, "%s: illegal block size value %s\n",
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",
595 * Set summary result file
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);
609 Debug_level = set_debug_level(optarg);
612 case 'f': /* Percent change in file set size
613 * used in aggregate reporting only.
615 if (!isdigit(optarg[0])) {
616 (void) fprintf(stderr, "%s: illegal file set delta value %s\n",
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",
630 * program to start and stop external
631 * performance monitoring. Called at start
632 * and completion of core load generation period.
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);
641 P_script_name = optarg;
642 (void) fclose(check_fp);
646 * Command-line parameters for the external monitor
647 * (see the "-k" option, above)
649 P_script_args = optarg;
652 case 'l': /* Set load
653 * used in aggregate reporting only.
655 if (!isdigit(optarg[0])) {
656 (void) fprintf(stderr, "%s: illegal load value %s\n",
660 P_total_load = atoi(optarg);
661 if (P_total_load < 0) {
662 (void) fprintf(stderr, "%s: load must be > 0\n", sfs_Myname);
667 case 'm': /* Set mix from a file
668 * used in aggregate reporting only.
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);
677 (void) fclose(check_fp);
680 case 'p': /* Set number of child processes
681 * used in aggregate reporting only.
683 if (!isdigit(optarg[0])) {
684 (void) fprintf(stderr, "%s: illegal procs value %s\n",
688 P_children = atoi(optarg);
689 if (P_children < 0) {
690 (void) fprintf(stderr, "%s: number of children must be > 0\n",
696 case 'Q': /* Set NFS/TCP behaviour */
700 case 'R': /* set maximum async read concurrency level
701 * used in aggregate reporting only.
703 if (!isdigit(optarg[0])) {
704 (void) fprintf(stderr, "%s: illegal read count value %s\n",
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",
718 * Set sleep time so external processes will
719 * have time to startup
721 if (!isdigit(optarg[0])) {
722 (void) fprintf(stderr, "%s: illegal sleep value %s\n",
726 Prime_sleep_time = atoi(optarg);
729 case 't': /* Set SFS Runtime value */
730 if (!isdigit(optarg[0])) {
731 (void) fprintf(stderr, "%s: illegal time value %s\n",
735 Prime_runtime = atoi(optarg);
736 if (Prime_runtime < 0) {
737 (void) fprintf(stderr, "%s: run time must be >= 0\n",
743 case 'T': /* Set Test mode operation
744 * used in aggregate reporting only.
746 if (!isdigit(optarg[0])) {
747 (void) fprintf(stderr, "%s: illegal time_out value %s\n",
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);
759 case 'W': /* set maximum async write concurrency level
760 * used in aggregate reporting only.
762 if (!isdigit(optarg[0])) {
763 (void) fprintf(stderr, "%s: illegal write count value %s\n",
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",
775 case 'w': /* Set warmup time
776 * used in aggregate reporting only.
778 if (!isdigit(optarg[0])) {
779 (void) fprintf(stderr, "%s: illegal warmup value %s\n",
783 P_warmuptime = atoi(optarg);
784 if (P_warmuptime < 0) {
785 (void) fprintf(stderr, "%s: warmup time must be >= 0\n",
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",
798 Prime_time_out = atoi(optarg);
801 case 'z': /* Do raw data dumps
802 * used in aggregate reporting only.
810 } /* end switch on argument */
812 Num_clients = argc - optind;
815 * allocate space and store clients names
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 **));
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]);
833 if (sum_result_fp == NULL)
834 sum_result_fp = stdout;
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);
842 } /* do_initialize */
846 * Small utility routine to pretty print out the names
847 * of the clients which did not respond to the message.
850 printdeadclients(void)
857 if ((clients = (int *)malloc(sizeof(int) * Num_clients)) == NULL) {
858 (void) fprintf(stderr, "%s: malloc failed\n", sfs_Myname);
859 (void) fflush(stderr);
863 for (i = 0; i < Num_clients; i++) {
867 fd = fopen(SFS_PRIME_SYNC_LOG, "r");
869 (void) fprintf(stderr,"%s: Cannot open %s\n",
870 sfs_Myname, SFS_PRIME_SYNC_LOG);
871 (void) fflush(stderr);
875 while(fread(&client, sizeof(int), 1, fd) == 1) {
876 if (client > 0 && client <= Num_clients)
877 clients[client - 1] = 1;
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);
892 * monitor Logfile until all Clients write to it.
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.
899 sync_PC_with_clients(void)
901 struct stat statb; /* for fstat */
902 int num_secs; /* keep count of time */
903 int clientsremaining;
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);
914 clientsremaining = Num_clients - (statb.st_size / sizeof(int));
915 } while ( (clientsremaining > 0) && (num_secs < Prime_time_out));
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);
923 /* send message to clients to stop */
924 (int) signal_sfs_clients("PRIME_STOP");
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");
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");
951 } /* sync_PC_with_clients */
954 #ifdef CLOSE_CLNT_HANDLE
955 static int close_clnt_handle = 1;
957 static int close_clnt_handle = 0;
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.
965 signal_sfs_clients(char *message)
967 static int Transac_num = 0; /* transaction number */
968 static CLIENT ** sfs_clnt_handle = NULL;
969 static int *sfs_socket = NULL;
972 sync_string sync_signal;
973 char transaction_string[MAX_STR1_LEN];
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;
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",
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",
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;
1006 sfs_socket[i] = RPC_ANYSOCK;
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;
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.
1022 sfs_clnt_handle[i] = clnttcp_create(&clnt_addr, SFS_SYNCPROG,
1023 SFS_SYNCVERS, &sfs_socket[i],
1024 MAX_STR2_LEN, MAX_STR2_LEN);
1026 if (sfs_clnt_handle[i] == (CLIENT *) NULL) {
1028 * Couldn't establish connection with the sfs Client.
1029 * print error message and return status
1031 clnt_pcreateerror(Client_names[i]);
1032 return((int) RPC_FAILED);
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.
1041 if (clnt_control(sfs_clnt_handle[i], CLGET_FD, (char *)&fd) ==
1043 clnt_pcreateerror(Client_names[i]);
1044 return((int) RPC_FAILED);
1046 if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1) {
1048 return((int) RPC_FAILED);
1051 } /* end no client handle */
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
1058 sync_signal.clnt_id = i + 1;
1059 result = signal_sfs_1(&sync_signal, sfs_clnt_handle[i]);
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);
1067 /* Okay, we successfully called the remote procedure. */
1070 * remote procedure was unable to write to its sync file.
1071 * Print error message and return failure.
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);
1079 if (close_clnt_handle) {
1080 clnt_destroy(sfs_clnt_handle[i]);
1081 sfs_clnt_handle[i] = NULL;
1083 } /* end for each client */
1087 } /* signal_sfs_clients */
1091 * summarize and print multi-client results
1094 print_multi_results(void)
1096 FILE * fd; /* results files */
1099 char res_file[SFS_MAXPATHLEN]; /* results filename */
1100 char str[MAX_LINE_LEN];
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;
1107 double sq_conf_interval_msec;
1108 double conf_interval_msec;
1112 #define MAXOPNAME 19
1113 struct client_stats {
1117 int num_access_io_files;
1118 int num_non_io_files;
1122 struct client_op_stats {
1131 float squared_time_msec;
1135 float sum_calls_sec;
1136 float sum_msec_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;
1148 * malloc space for statistics
1149 * Note last entry is for running totals.
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",
1156 (void) fflush(stderr);
1160 totals = Num_clients;
1162 * Read each client file one at a time gathering statistics
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);
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.
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);
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);
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;
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);
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);
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",
1236 (void) fflush(stderr);
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);
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);
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;
1279 } /* for Num_clients */
1281 nfs_version = client_stats[0].version;
1284 * print the aggregate test parameters
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);
1298 (void) fprintf(stdout, "%s%d\n%s%d\n",
1299 " Warm-up time (seconds) = ", P_warmuptime,
1300 " Run time (seconds) = ", Prime_runtime);
1302 (void) fprintf(stdout,"%s%s\n", " NFS Mixfile = ", P_mix_file);
1304 (void) fprintf(stdout,"%s%s\n", " Block Size Distribution file = ",
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,
1320 (void) fprintf(stdout, "%s%10d%s\n", " ",
1321 client_stats[totals].num_dirs,
1323 (void) fprintf(stdout, "%s%s\n", " ",
1324 " Additional non-I/O files created as necessary\n");
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);
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);
1345 /* print per operation statistics */
1346 for (k = 0; k < NOPS; k++) {
1355 tot_squared_time_msec = 0;
1357 /* total the results from each client */
1358 for (i = 0; i < Num_clients; i++) {
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;
1371 } /* end for each client */
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.
1379 if (tot_want == 0 && tot_calls == 0 && tot_errors == 0)
1382 /* compute the standard deviation for the mean response time */
1383 if (tot_calls <= 1) {
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)) /
1391 if(var_msec == 0.0) {
1394 stdev_msec = sqrt(var_msec);
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);
1407 conf_interval_msec = 0.0;
1409 conf_interval_msec = sqrt(sq_conf_interval_msec);
1411 conf_interval_msec = 0.0;
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 */
1427 } /* end for each op */
1429 (void) fprintf(stdout,
1430 "------------------------------------------------------------------------------\n");
1432 /* check and report client INVALID RUN */
1433 for (i = 0; i < Num_clients; i++) {
1434 if (client_stats[i].client_invalid_flag != 0) {
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]);
1442 (void) fprintf(stdout,
1443 "INVALID RUN, ILLEGAL PARAMETER: Non-standard %s\n",
1444 invalid_str[client_stats[i].client_invalid_flag]);
1449 (void) fprintf(stdout, "\n");
1450 (void) fprintf(stdout,
1451 " --------------------------------------------------------\n");
1452 (void) fprintf(stdout,
1453 " | SPEC SFS VERSION %6s AGGREGATE RESULTS SUMMARY |\n",
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);
1462 (void) fprintf(stdout, "%s PROTOCOL\n", P_tcp ? "TCP" : "UDP");
1463 (void) fprintf(stdout, "NFS MIXFILE:");
1465 (void) fprintf(stdout,"%s\n", P_mix_file);
1467 (void) fprintf(stdout," [ SFS default ]\n");
1469 (void) fprintf(stdout, "AGGREGATE REQUESTED LOAD: %d Ops/Sec \n",
1470 (Num_clients * P_total_load));
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");
1489 (void) fprintf(stdout,
1490 "------------------------------------------------------------------------");
1491 (void) fprintf(stdout,"\n\n");
1492 (void) fflush(stdout);
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
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,
1510 (unsigned long)client_stats[totals].total_fss_bytes,
1513 P_biod_max_outstanding_reads,
1514 P_biod_max_outstanding_writes,
1516 (void) fflush(sum_result_fp);
1518 (void) free(client_stats);
1519 } /* print_multi_results */
1524 (void) fprintf(stderr,
1525 "Usage: %s [-a access_pcnt] [-A append_pcnt] [-b blocksz_file] [-B block_size]\n",
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");
1539 (void) fflush(stderr);
1540 (int) signal_sfs_clients("PRIME_STOP");