2 static char sccsid_hp[] = "@(#)sfs_c_man.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.
25 * Generates an artifical NFS client load based on a given mix of operations,
26 * and block transfer distribution.
28 * Usage: sfs [-l load] [-p procs] [-w warmup] [-t time]
29 * [-m mix_file] [-B block_size] [-b blocksz_file]
30 * [-f file_set_delta] [-a access_pnct]
31 * [-A append_pcnt] [-D dir_cnt] [-F file_cnt] [-S symlink_cnt]
32 * [-d debug_level] [-i] [-P] [-T op_num]
33 * [-V validation_level] [-z] [-Q]
34 * [-R biod_reads] [-W biod_writes]
35 * [-M prime_client_hostname] [-N client_cnt]
37 * NOTE: REFER TO SFS MAN PAGE (sfs.1) FOR A DESCRIPTION OF ALL
41 * Single Client Options
43 * option description default
44 * --------------- ------------------------------------------------ -----------
45 * -a access_pcnt % of file set to access 20% access
46 * -A append_pcnt % of writes that append rather than overwrite 70% append
47 * -b blocksz_file file specifying distribution of block xfer sizes (see below)
48 * -B block_size # of KB in block, up to 8 KB 8 KB
49 * -Q Do TCP connection for NFS rather than UDP off
50 * -d debug_level debug level (higher number gives more output) off
51 * -D dir_cnt # directories used for directory operations 20 dirs
52 * -f fileset_delta % change in file set size allowed 10%
53 * -F file_cnt # files used for read and write operations 100 files
54 * -i interactive; wait for input before starting test off
55 * -l load # NFS calls/second to generate from each client 60 calls/sec
56 * -m mix_file file specifying NFS call distribution (see below)
57 * -p procs # processes used to generate load on each client 7 procs
58 * -P populate test directories, but don't run a test off
59 * -R biod_reads max # of outstanding read requests at one time 2 reqs
60 * -S symlink_cnt # symbolic links used for symlink operations 20 symlinks
61 * -t time # seconds to generate load for the timed test 600 secs
62 * -T op_num test the NFS operation specified one time off
63 * -V validate correctness of server's NFS off
64 * -W biod_writes max # of outstanding writes req at one time 2 reqs
65 * -w warmup # secs to generate load before starting test 60 secs
66 * -z If specified, collect and dump raw data. off
69 * Multi Client Options
71 * option description default
72 * ------------------------ ----------------------------------- -----------
73 * -M prime_client_hostname hostname of prime client no default
74 * -N client_cnt # client machines in test no default
78 * Block Transfer Size Distribution
80 * The block transfer size distribution is specified by a table of values.
81 * The first column gives the percent of operations that will be a
82 * specific block transfer size. The second column gives the number of
83 * blocks units that will be transferred. Normally the block unit size
84 * is 8KB. The third column is a boolean specifying whether a trailing
85 * fragment block should be transferred. The fragment size for each transfer
86 * is a random multiple of 1 KB, up to the block size - 1 KB. Two tables
87 * are needed, one for read operation and one for write operations. The
88 * following table gives the default distributions.
90 * Read - Default Block Transfer Size Distribution Table
91 * percent block count fragment resulting transfer (8KB block size)
92 * ------- ----------- -------- -----------------------------------
94 * 85 1 0 85% 9 - 15 KB
98 * 1 16 1 1% 129 - 135 KB
100 * Write - Default Block Transfer Size Distribution Table
101 * percent block count fragment resulting transfer (8KB block size)
102 * ------- ----------- -------- -----------------------------------
103 * 49 0 1 49% 1 - 7 KB
104 * 36 1 1 36% 9 - 15 KB
105 * 8 2 1 8% 17 - 23 KB
106 * 4 4 1 4% 33 - 39 KB
107 * 2 8 1 2% 65 - 71 KB
108 * 1 16 1 1% 129 - 135 KB
110 * The user may specify a a different distribution by using the '-b' option.
111 * The format for the block size distribution file consists of the first
112 * three columns given above: percent, block count, and fragment. Read
113 * and write distribution tables are identified by the keywords "Read" and
114 * "Write". An example input file, using the default values, is given below:
131 * A second parameter controlled by the block transfer size distribution
132 * table is ethernet packet size. The distribution tables define the
133 * relative proportion of full blocks packets to fragment packets. For
134 * instance, the default tables have been constructed to produce a specific
135 * distribution of ethernet packet sizes for i/o operations by controlling
136 * the amount of data in each packet. The write packets produced consist
137 * of 50% 8-KB packets, and 50% 1-7 KB packets. The read packets consist
138 * of 85% 8-KB packets, and 15% 1-7 KB packets. These figures are
139 * determined by multiplying the percentage for the type of transfer by
140 * the number of blocks and fragments generated, and adding the totals.
141 * These conmputations are performed below for the default block size
142 * distribution tables:
144 * Read blocks fragments
162 * 100 (50%) 100 (50%)
170 * The operation mix is described assigning a percentage to each type
171 * of NFS operation. The default mix of operations is:
194 * The user may specify a a different operation mix by using the '-m' option.
195 * The format for the mix file consists of the output from an nfsstat(1)
196 * command, which lists an operation count and percentage for each NFS
202 * !!! needs to be re-written - mew 8/24
203 * This still needs to be rewritten
204 * - The default number of i/o files is based on load level.
205 * - For non I/O files, the number of initialized versus empty
209 * The file set used by SFS is determined by 2 factors. First,
210 * SFS creates a base set of files. By default this consists of
211 * 100 files for i/o operations, 100 files for non-i/o operations, 20
212 * directories, and 20 symbolic links. These default values can be
213 * changed from the command line by using the "-F", "-D", and "-S" options.
214 * This file set is divided evenly among the set of processes used to
217 * Then, enough resources are allocated to allow for the eventual creation
218 * of new files, directories and symlinks by the creat, link, mkdir,
219 * and symlink operations. The number of extra slots allocated depends
220 * on the mix percentages assigned to each of the create and deletion
221 * operations, multiplied by an estimate of the total number of operations
222 * to be performed. For instance, the default number of extra files names
223 * allocated for non-i/o operations is computed as follows:
224 * 300 secs * 60 ops/sec = 18000 total operations
225 * 2% create * 18000 ops = 360 create ops
226 * 1% remove * 18000 ops = 180 remove ops
227 * 260 creates ops - 180 remove ops = 180 extra files to be created.
228 * These 90 files are distributed evenly among the processes used to
229 * generate load. With the default settings, no extra directories are
230 * created or removed, so no extra allocation is done for directories
231 * beyond the base file set. The same is true for symbolic links.
233 * Thus, the total default file set size is:
234 * 100 files for i/o operations
235 * 280 files for non-i/o operations
239 * By allocating all required space before the test begins, any space
240 * allocation problems encountered by SFS are discovered before the
246 * Strategy: loop for some number of NFS calls doing a random sleep
247 * followed by a call to one of the op generator routines. The routines
248 * are called based on a weighting factor determined by the set of
249 * default percentages or a mix supplied by the user.
251 * The generator routines are able to keep an accurate count of the
252 * NFS operations they are generating by using the NFS protocol
253 * directly and not going through the kernel. This eliminates the
254 * effects of kernel name caches and retry mechanisms that
255 * complicate control of what actually hits the wire. The calling
256 * routine benefits by avoiding having to get the NFS statistics
257 * from the kernel because they KNOW what calls they've made.
259 * By using the NFS protocol directly :
260 * "lookup" operations sidestep the client kernel name cache,
261 * "getattr" operations avoid the client kernel attribute cache,
262 * "read" operations avoid the client kernel buffer cache,
265 * A consequence of not going thru the client kernel is that the sfs
266 * program must maintain a table of file handles rather than open
269 * The parent process starts children to do the real work of generating load.
270 * The parent coordinates them so that they all start at the same time, and
271 * collects statistics from them when they are done. To coordinate the
272 * start up, the parent waits for each child to write one byte into
273 * a common log file (opened in append mode to avoid overwriting).
274 * After they write a byte the children pause, and the parent send SIGUSR1
275 * when it has heard from all of the kids. The children write their statistics
276 * into the same common log file and the parent reads and accumulates the
277 * statistics and prints them out.
281 * int main(int, char*)
284 * void init_logfile(void)
287 * int setiodist(FILE *)
288 * int parseiodist(FILE *, int)
289 * void init_iodist(sfs_io_dist_type *)
290 * void init_fss(void)
291 * void init_filedist(void)
292 * int lad_substr(char *, char *)
295 * 21-Aug-92 0.1.11 Wittle File set access code.
296 * 14-Jul-92 0.1.9 Teelucksingh
297 * Implemented Mark Wittle's proposal to
298 * base File Set Size on peak load value,
299 * added "-L peak_load" option.
300 * 10-Jan-92 0.0.0.19 Teelucksingh
301 * Reworked setpgrp() usage to
302 * better handle BSD vs SYSV variations.
303 * 04-Jan-92 0.0.0.18 Pawlowski
304 * Added raw data dump code.
305 * 04-Dec-91 0.0.0.15 Keith
306 * Include string.h if SVR4.
307 * 28-Nov-91 0.0.0.13 Teelucksingh
308 * Modified code to use unique sfs /tmp
309 * logfiles; sfs can now be used on
310 * clients that have a shared /tmp area.
311 * Added ANSI C features. Fixed 'multiple
312 * signals from the Prime-Client' problem.
313 * Added code to allow clients to
314 * check for and create client specific
315 * directories under each mount point -
316 * clients share partitions. (code from
318 * 22-Nov-91 Wittle Updated program description comment.
319 * Added new op generation code.
320 * Added block_dist_table and block_size
321 * options, removed 8KB packet assumptions.
322 * 04-Oct-91 0.0.0.12 Teelucksingh
323 * Changed SFS sources and executables
324 * to use the "prelad" prefix.
325 * 23-Sep-91 0.0.0.11 Teelucksingh
326 * Changed format of sfs output.
327 * 01-Aug-91 0.0.9 Wiryaman Use the SPEC random number generator.
328 * Since this RNG cannot take seed = 0,
329 * use child_num+1 instead.
330 * 17-Jul-91 0.0.8 Teelucksingh
331 * Enhance multi-client code and
333 * Keith Map "nhfsstone" to "laddis" in
334 * README, nhfsstone_mgr.c. Create
335 * initial DESCR.SFS for SPEC
337 * 15-Jul-91 0.0.8 Wiryaman Add getmnt() for ULTRIX
338 * 25-Jun-91 0.0.7 Wiryaman Added validation option to test all
339 * of the NFS operations.
340 * 17-Jun-91 0.0.7 Teelucksingh
341 * Added multi-client synchronization
342 * support. By designating a client as
343 * "Prime client" you can synchronize
344 * multi-client SFS execution.
345 * 12-May-91 0.0.6 Wittle Fix standard deviation.
346 * 02-May-91 0.0.5 Wittle Fix SunOS signal bug; use default
347 * warmuptime; add local time routine;
348 * check for calls that underflow elapsed
349 * time measurement; add std deviation
350 * statistics; rework verbose output.
351 * fix init invalid protocol rmdir calls;
352 * 15-Apr-91 0.0.4 Wittle Test can be repeated without removing
353 * test directories - initialization
354 * restores base file set count and sizes.
355 * Fix lack of call rate & mix accuracy -
356 * set op_check before artificially
357 * increasing call_targets.
358 * Don't pre-create files/dirs that are
359 * meant to be created during the test.
360 * 10-Mar-91 0.0.3 Wittle Longer RPC timeout while populating
361 * testdir; strstr() bug fix;
362 * '-i' and '-e' options
363 * 06-Mar-91 0.0.2 Wittle Loop forever pre-filling files.
364 * 22-Feb-91 0.0.1 Wittle Use signal(2) instead of sigset(2).
365 * 18-Feb-91 0.0.0 Wittle Change algorythm for determining i/o
366 * sizes, preserve i/o file working set
367 * by using separate files; bugs fixes.
369 * nhfsstone renamed to laddis
371 * 31-Oct-90 2.0.4 Wittle Many bug fixes.
372 * 24-Aug-90 2.0.3 Wittle Output compatible w/graphing tools.
373 * 24-July-90 2.0.2 Wittle Handle mounting below symlinks.
374 * 24-June-90 2.0.1 Wittle Prefill files with data.
375 * 17-May-90 2.0.0 Bean Rewrote the guts to use NFS
377 * Cleaned up self-pacing mechanism.
378 * 08-Nov-89 Guillermo Roa Ported original version to DG/UX.
379 * 07-Jul-89 Legato Systems Created.
383 * ------------------------- Include Files -------------------------
396 #include <sys/types.h>
397 #include <sys/stat.h>
399 #include <sys/signal.h>
401 #include <sys/file.h>
406 extern getmyhostname(char *, int);
408 #include "sfs_c_def.h"
409 #include "sfs_m_def.h"
412 * ------------------------- External Definitions -------------------------
415 /* external routines from RPC and system libraries */
416 #if defined(SETPGRP_BSD)
417 extern int setpgrp(int, int);
418 #endif /* SETPGRP_BSD */
419 #if defined(SETPGRP_SYSV)
420 extern pid_t setpgrp(void);
421 #endif /* SETPGRP_SYSV */
423 /* forward definitions for local routines */
424 static void init_logfile(void);
425 static void usage(void);
426 static int setmix(char *);
427 static int setiodist(FILE *);
428 static int parseiodist(FILE *, int);
429 static void init_iodist(sfs_io_dist_type *);
430 static void init_fss(void);
431 static void init_filedist(void);
432 static int lad_substr(char *, char *);
433 static double time_so_far1(void);
434 static double get_resolution(void);
435 static void check_clock(void);
437 int Tot_client_num_io_files = 0; /* # of files used for i/o per client */
438 int Tot_client_num_non_io_files = /* # of files used for i/o per client */
440 int Files_per_dir = /* # of pre-created dirs */
441 DEFAULT_FILES_PER_DIR;
442 int Tot_client_num_symlinks = /* # of pre-created symlinks/client */
445 char * Prime_client = NULL; /* Prime client hostname */
446 int Client_num = 1; /* My client number */
447 int Tcp = 0; /* Flag set on command line */
448 char *sfs_Myname; /* name program invoked under */
449 int Log_fd; /* log fd */
450 char Logname[NFS_MAXNAMLEN]; /* child processes sync logfile */
451 uid_t Real_uid; /* real uid */
452 uid_t Cur_uid; /* my uid */
453 gid_t Cur_gid; /* my gid list */
455 static char Client_logname[SFS_MAXNAMLEN];
458 * ----------------- SFS Main and Initialization Code -----------------
462 * Read the command line arguments, fork off child processes to
463 * generate NFS load, and perform the local (ie, on this client)
464 * book-keeping for the test and the results.
472 char *mix_file; /* name of mix file */
473 char *iodist_file; /* name of block i/o dist table file */
474 int children; /* number of children */
475 int child_num; /* child index */
476 int total_load; /* total client load factor */
477 float child_load; /* per child load factor */
478 int pid; /* process id */
480 FILE *iodist_fp; /* block io dist table file */
485 int nsigs = 32; /* reasonable default */
490 * Place pid in pid log file
492 if ((pid_fp = fopen(SFS_PNT_PID, "a+")) == NULL) {
497 (void) fprintf(pid_fp, "%d\n", getpid());
499 /* Get program name for stderr printing */
500 sfs_Myname = argv[0];
503 getmyhostname(lad_hostname, HOSTNAME_LEN);
508 * Get the uid and gid information.
514 * Form a new process group so our syncrhonization signals don't
515 * cause our parent shell to exit. Clear the umask.
516 * Default is to use the standard setsid
519 ret = setpgrp3(); /* Work around HP-UX bug */
525 ret = setpgrp(0, getpid());
528 #endif /* SETPGRP_BSD */
529 #endif /* SETPGRP_SYSV */
530 #endif /* SETPGRP3 */
533 (void) fprintf(stderr, "%s: failed on setsid/setpgrp\n",
540 /* Set up default parameters */
543 children = DEFAULT_NPROCS;
544 total_load = DEFAULT_LOAD;
547 Nfs_timers = Nfs_udp_timers;
549 /* Parse command line arguments */
550 while ((c = getopt(argc, argv, "a:A:b:B:cd:D:f:F:il:m:M:N:p:PQR:S:T:t:V:W:w:z")) != EOF)
553 case 'a': /* Percent of files to access */
554 if (!isdigit(optarg[0])) {
555 (void) fprintf(stderr, "%s: illegal access value %s\n",
559 Access_percent = atoi(optarg);
560 if (Access_percent < 0 || Access_percent > 100) {
561 (void) fprintf(stderr,
562 "%s: %% access must be between 0 and 100\n",
568 case 'A': /* Percent of writes that append */
569 if (!isdigit(optarg[0])) {
570 (void) fprintf(stderr, "%s: illegal append value %s\n",
574 Append_percent = atoi(optarg);
575 if (Append_percent < 0 || Append_percent > 100) {
576 (void) fprintf(stderr,
577 "%s: %% append must be between 0 and 100\n",
583 case 'b': /* Set block size distribution table from file */
584 if ((iodist_fp = fopen(optarg, "r")) == NULL) {
586 (void) fprintf(stderr, "%s: bad block size file",
592 if (setiodist(iodist_fp) < 0) {
595 iodist_file = optarg;
596 (void) fclose(iodist_fp);
599 case 'B': /* Set the per packet maximum block size */
600 if (!isdigit(optarg[0])) {
601 (void) fprintf(stderr,
602 "%s: illegal block size value %s\n",
606 Kb_per_block = atoi(optarg);
607 if ((Kb_per_block < 1) ||
608 (Kb_per_block > (DEFAULT_MAX_BUFSIZE/1024))) {
609 (void) fprintf(stderr,
610 "%s: illegal block size value %s\n",
614 Bytes_per_block = Kb_per_block * 1024;
618 case 'c': /* Set number of calls */
619 (void) fprintf(stderr, "%s: '-c option no longer supported\n",
624 case 'd': /* Set debugging level */
625 Debug_level = set_debug_level(optarg);
628 case 'D': /* Set number of directories */
629 if (!isdigit(optarg[0])) {
630 (void) fprintf(stderr, "%s: illegal dirs value %s\n",
634 Files_per_dir = atoi(optarg);
637 case 'f': /* Percent change in file set size */
638 if (!isdigit(optarg[0])) {
639 (void) fprintf(stderr, "%s: illegal file set delta value %s\n",
643 Fss_delta_percent = atoi(optarg);
644 if (Fss_delta_percent < 0 || Fss_delta_percent > 100) {
645 (void) fprintf(stderr,
646 "%s: %% file set delta must be between 0 and 100\n",
652 case 'F': /* Set number of io files */
653 if (!isdigit(optarg[0])) {
654 (void) fprintf(stderr, "%s: illegal files value %s\n",
658 Tot_client_num_io_files = atoi(optarg);
661 case 'i': /* Set interactive mode */
662 if (Prime_client != NULL) {
663 (void) fprintf(stderr,
664 "%s: -i and -M options are incompatible\n",
671 case 'l': /* Set load */
672 if (!isdigit(optarg[0])) {
673 (void) fprintf(stderr, "%s: illegal load value %s\n",
677 total_load = atoi(optarg);
678 if (total_load < 0) {
679 (void) fprintf(stderr, "%s: load must be > 0\n",
685 case 'm': /* Set mix from a file */
687 if (setmix(mix_file) < 0) {
692 case 'M': /* Set prime_client host name for multi-client sync */
694 (void) fprintf(stderr,
695 "%s: -M and -i options are incompatible\n",
699 Prime_client = optarg;
702 case 'N': /* Set client number in multi-client run */
703 Client_num = atoi(optarg);
704 if (Client_num <= 0) {
705 (void) fprintf(stderr,
706 "%s: client number must be > 0\n",
712 case 'p': /* Set number of child processes */
713 if (!isdigit(optarg[0])) {
714 (void) fprintf(stderr, "%s: illegal procs value %s\n",
718 children = atoi(optarg);
720 (void) fprintf(stderr, "%s: number of children must be > 0\n",
726 case 'P': /* Populate only */
730 case 'Q': /* Set NFS/TCP behaviour */
732 Nfs_timers = Nfs_tcp_timers;
735 case 'R': /* set maximum async read concurrency level */
736 if (!isdigit(optarg[0])) {
737 (void) fprintf(stderr, "%s: illegal read count value %s\n",
741 Biod_max_outstanding_reads = atoi(optarg);
742 if (Biod_max_outstanding_reads < 0 ||
743 Biod_max_outstanding_reads > MAX_BIODS) {
744 (void) fprintf(stderr,
745 "%s: read count must be >= 0 and <= %d\n",
746 sfs_Myname, MAX_BIODS);
751 case 'S': /* Set number of symlinks */
752 if (!isdigit(optarg[0])) {
753 (void) fprintf(stderr,
754 "%s: illegal symlinks value %s\n",
758 Tot_client_num_symlinks = atoi(optarg);
761 case 'T': /* Set test mode, number following is opnum */
762 if (!isdigit(optarg[0])) {
763 (void) fprintf(stderr, "%s: illegal test value %s\n",
767 Testop = atoi(optarg);
768 if (Testop >= NOPS) {
769 (void) fprintf(stderr, "%s: illegal test value %d\n",
775 case 't': /* Set run time */
776 if (Ops[TOTAL].target_calls > 0) {
777 (void) fprintf(stderr,
778 "%s: -t and -c options are incompatible\n",
782 if (!isdigit(optarg[0])) {
783 (void) fprintf(stderr, "%s: illegal time value %s\n",
787 Runtime = atoi(optarg);
789 (void) fprintf(stderr, "%s: run time must be >= 0\n",
795 case 'V': /* Set Validate Level */
796 if (!isdigit(optarg[0])) {
797 (void) fprintf(stderr, "%s: illegal validate value %s\n",
801 Validate = atoi(optarg);
802 if (Validate < 1 || Validate > 3) {
803 (void) fprintf(stderr, "%s: validate must be between 1 and 3\n",
809 case 'W': /* set maximum async write concurrency level */
810 if (!isdigit(optarg[0])) {
811 (void) fprintf(stderr, "%s: illegal write count value %s\n",
815 Biod_max_outstanding_writes = atoi(optarg);
816 if (Biod_max_outstanding_writes < 0 ||
817 Biod_max_outstanding_writes > MAX_BIODS) {
818 (void) fprintf(stderr,
819 "%s: write count must be >= 0 and <= %d\n",
820 sfs_Myname, MAX_BIODS);
825 case 'w': /* Set warmup time */
826 if (!isdigit(optarg[0])) {
827 (void) fprintf(stderr, "%s: illegal warmup value %s\n",
831 Warmuptime = atoi(optarg);
832 if (Warmuptime < 0) {
833 (void) fprintf(stderr, "%s: warmup time must be >= 0\n",
839 case 'z': /* Do raw data dumps */
848 } /* end switch on arg */
851 /* compute ops/request for i/o operations */
852 init_iodist(Io_dist_ptr);
854 /* compute bytes/file and number of files */
857 /* validate all the NFS operations that sfs will use */
860 * -F <number of files > or else
863 if (Tot_client_num_io_files == 0) {
864 Tot_client_num_io_files = DEFAULT_NFILES;
866 Num_io_files = Tot_client_num_io_files/children + 1;
867 /* number of non-io files, dir and symlinks base on constants */
868 Num_non_io_files = Tot_client_num_non_io_files/children + 1;
869 Num_dirs = Num_io_files/Files_per_dir + 1;
870 Num_symlinks = Tot_client_num_symlinks/children + 1;
872 /* io operations access a subset of the files */
873 Num_working_io_files = ((Num_io_files * Access_percent) / 100) + 1;
874 /* non-io and other operations access all of the files */
875 Num_working_non_io_files = Num_io_files;
876 Num_working_dirs = Num_dirs;
877 Num_working_symlinks = Num_symlinks;
879 Validate_ops(argc - optind, &argv[optind]);
884 * Initial check on the mount arguments, must be at least an
885 * even multiple of the number of procs.
887 if ((argc - optind) % children) {
888 (void) fprintf(stderr,
889 "%s: Invalid mount point list: Not a multiple of number of procs\n",
895 * -F <number of io files > or else
896 * base files set on load ; this in NON-SPEC though
898 if (Tot_client_num_io_files == 0) {
899 Tot_client_num_io_files = ((DEFAULT_BYTES_PER_OP / 1024 * total_load)
900 / (1024)) * files_per_megabyte;
902 Num_io_files = Tot_client_num_io_files/children + 1;
905 * Number of non-io files scales with load and is set at 2% of all files,
906 * but at least DEFAULT_NFILES worth.
908 Tot_client_num_non_io_files = Tot_client_num_io_files * 0.02;
909 if (Tot_client_num_non_io_files < DEFAULT_NFILES)
910 Tot_client_num_non_io_files = DEFAULT_NFILES;
911 Num_non_io_files = Tot_client_num_non_io_files/children + 1;
913 /* number of dir and symlinks base on constants */
914 Num_dirs = Num_io_files/Files_per_dir + 1;
915 Num_symlinks = Tot_client_num_symlinks/children + 1;
917 /* io operations access a subset of the files */
918 Num_working_io_files = ((Num_io_files * Access_percent) / 100) + 1;
920 /* non-io and other operations access all of the files */
921 Num_working_non_io_files = Num_io_files;
922 Num_working_dirs = Num_dirs;
923 Num_working_symlinks = Num_symlinks;
926 * If we are doing a timed test, we still need an
927 * estimate of how many calls are needed in order to
928 * judge our progress.
929 * If we are doing a test for a number of calls, we still need an
930 * estimate of how long the test will take in order to
931 * establish the time interval between progress checks.
935 * the total number of calls will be divided between the children
936 * when they are forked off.
938 Ops[TOTAL].target_calls = Runtime * total_load;
940 Runtime = (int) ((float) Ops[TOTAL].target_calls / (float) total_load);
944 * multi-client sync support
945 * offset the Runtime value by MULTICLIENT_OFFSET seconds.
946 * This offset prevents the client from finishing before
947 * the Prime Client tells it to 'STOP'. The MULTICLIENT_OFFSET is larger
948 * than the time_out value on the Prime-Client; so in case the client
949 * does not stop when it's told to, the Prime-client should time_out.
951 if (Prime_client && Timed_run)
952 Runtime += MULTICLIENT_OFFSET;
954 /* compute file set sizes */
957 /* Set up synchronization and results log file */
961 * setup value of nsigs
972 #if defined(SOLARIS2) && !defined(_sys_nsig)
973 nsigs = _sys_siglistn;
976 /* Set up the signal handlers for all signals */
978 #if (defined(_XOPEN_SOURCE) || defined(USE_POSIX_SIGNALS))
980 struct sigaction sig_act, old_sig_act;
982 /* use XOPEN signal handling */
984 sig_act.sa_handler = generic_catcher;
985 (void)sigemptyset(&sig_act.sa_mask);
986 sig_act.sa_flags = 0;
988 if (DEBUG_PARENT_GENERAL) {
990 (void) fprintf (stderr,
991 "WARNING: nsigs not defined, no extra signals caught\n");
993 for (i = 1; i < nsigs; i++) {
994 /* attempt to set up signal handler for these signals give an error !! K.T. */
995 if (i!=SIGCHLD && i!=SIGKILL && i!=SIGSTOP && i!=SIGCONT) {
996 if (sigaction(i,&sig_act,&old_sig_act) == -1) {
997 if (errno == EINVAL) {
998 (void) fprintf (stderr,
999 "Skipping invalid signal %d\n", i);
1001 perror("sigaction failed");
1009 /* signals handlers for signals used by sfs */
1010 sig_act.sa_handler = sfs_cleanup;
1011 if (sigaction(SIGINT,&sig_act,&old_sig_act) == -1) {
1012 perror("sigaction failed: SIGINT");
1016 sig_act.sa_handler = sfs_alarm;
1017 if (sigaction(SIGALRM,&sig_act,&old_sig_act) != 0) {
1018 perror("sigaction failed: SIGALRM");
1022 sig_act.sa_handler = sfs_cleanup;
1023 if (sigaction(SIGTERM,&sig_act,&old_sig_act) != 0) {
1024 perror("sigaction failed: SIGTERM");
1028 sig_act.sa_handler = sfs_startup;
1029 if (sigaction(SIGUSR1,&sig_act,&old_sig_act) != 0) {
1030 perror("sigaction failed: SIGUSR1");
1034 sig_act.sa_handler = sfs_stop;
1035 if (sigaction(SIGUSR2,&sig_act,&old_sig_act) != 0) {
1036 perror("sigaction failed: SIGUSR2");
1041 if (DEBUG_PARENT_GENERAL) {
1043 (void) fprintf (stderr,
1044 "WARNING: nsigs not defined, no extra signals caught\n");
1046 for (i = 1; i < nsigs; i++) {
1048 (void) signal(i, generic_catcher);
1051 /* signals handlers for signals used by sfs */
1052 (void) signal(SIGINT, sfs_cleanup);
1053 (void) signal(SIGALRM, sfs_alarm);
1054 (void) signal(SIGTERM, sfs_cleanup);
1055 (void) signal(SIGUSR1, sfs_startup);
1056 (void) signal(SIGUSR2, sfs_stop);
1060 for (child_num = 0; child_num < children; child_num++) {
1064 (void) fprintf(stderr, "%s: can't fork children.", sfs_Myname);
1067 (void) generic_kill(0, SIGINT);
1069 } else if (pid == 0) {
1070 break; /* get out of child creation */
1072 (void) fprintf(pid_fp, "%d\n", pid);
1073 } /* end for forking kids */
1074 (void) fclose(pid_fp);
1077 * Parent: wait for kids to get ready, start them, wait for them to
1078 * finish, read and accumulate results.
1081 if (setuid(Real_uid) != 0) {
1082 (void) fprintf(stderr,"%s: %s%s\n",
1083 sfs_Myname, "cannot perform setuid operation.\n",
1084 "Do `make install` as root.\n");
1087 /* I'm the parent - let the common code signal handlers know it */
1090 parent(children, total_load, mix_file, iodist_file);
1092 /* Clean up and exit. */
1093 (void) close(Log_fd);
1094 (void) unlink(Logname);
1100 * Children : initialize, then notify parent through log file,
1101 * wait to get signal, beat the snot out of the server, write
1102 * stats to the log file, and exit.
1106 /* I'm a child - let the common code signal handlers know it */
1107 Child_num = child_num;
1110 * Determine my share of the calls and load (including any left over)
1111 * The call target for each child differs by at most 1 call.
1112 * The load rate for each child differs by at most 1 call/sec.
1114 Ops[TOTAL].target_calls = Ops[TOTAL].target_calls / children;
1115 if (child_num <= Ops[TOTAL].target_calls % children) {
1116 Ops[TOTAL].target_calls++;
1118 child_load = (float) total_load / (float) children;
1121 * Sleep a bit so the parent can catch up after procreating all us
1126 child(child_num, children, child_load, argc - optind, &argv[optind]);
1131 (void) unlink(SFS_PNT_PID);
1139 * ----------------- Initalization of Parent/Child ---------------------
1143 * Open the multi-client synchronization file with append mode.
1151 (void) sprintf(Logname, "%s%d", CHILD_SYNC_LOG, Client_num);
1152 Log_fd = open(Logname, (O_RDWR | O_CREAT | O_TRUNC | O_APPEND), 0666);
1155 (void) fprintf(stderr, "%s: can't open log file %s ", sfs_Myname, Logname);
1160 if (chown(Logname, Real_uid, Cur_gid) ==-1) {
1162 (void) fprintf(stderr, "%s: chown failed\n", sfs_Myname);
1165 /* if multi-client execution then init client sync log */
1166 if (Prime_client != NULL) {
1167 /* init logfile and write process id */
1168 (void) sprintf(Client_logname, "%s%d",
1169 SFS_CLIENT_SYNC_LOG, Client_num);
1170 cl_log_fd = fopen(Client_logname, "w+");
1171 if (chown(Client_logname, Real_uid, Cur_gid) ==-1) {
1173 (void) fprintf(stderr, "%s: chown failed\n", sfs_Myname);
1175 if (cl_log_fd == NULL) {
1177 (void) fprintf(stderr,
1178 "%s: can't open Client synchronization file %s ",
1179 sfs_Myname, Client_logname);
1181 perror(Client_logname);
1184 /* store parent pid */
1185 (void) fprintf(cl_log_fd, "%d", (int)getpid());
1186 (void) fclose(cl_log_fd);
1188 } /* init multi-client sync log */
1190 } /* init_logfile */
1193 * ------------------------ Utility Routines --------------------------
1198 * Print the program's usage message.
1199 * Usage: sfs [-l load] [-p procs] [-w warmup] [-t time]
1200 * [-m mix_file] [-B block_size] [-b blocksz_file]
1201 * [-f file_set_delta] [-a access_pnct]
1202 * [-A append_pcnt] [-D dir_cnt] [-F file_cnt] [-S symlink_cnt]
1203 * [-d debug_level] [-i] [-P] [-T op_num]
1204 * [-V validation_level] [-z] [-Q]
1205 * [-R biod_reads] [-W biod_writes]
1206 * [-M prime_client_hostname] [-N client_cnt]
1211 (void) fprintf(stderr,
1212 "Usage: %s [-l load] [-p procs] [-w warmup] [-t time]\n", sfs_Myname);
1213 (void) fprintf(stderr,
1214 " [-m mix_file] [-B block_size] [-b blocksz_file]\n");
1215 (void) fprintf(stderr,
1216 " [-f file_set_delta] [-a access_pnct]\n");
1217 (void) fprintf(stderr,
1218 " [-A append_pcnt] [-D dir_cnt] [-F file_cnt] [-S symlink_cnt]\n");
1219 (void) fprintf(stderr,
1220 " [-d debug_level] [-i] [-P] [-T op_num]\n");
1221 (void) fprintf(stderr,
1222 " [-V validation_level] [-z] [-Q]\n");
1223 (void) fprintf(stderr,
1224 " [-R biod_reads] [-W biod_writes]\n");
1225 (void) fprintf(stderr,
1226 " [-M prime_client_hostname] [-N client_cnt]\n");
1232 * -------------- Command Line File Parsing -------------------
1236 * Constants for mix file
1238 #define LINELEN 128 /* max bytes/line in mix file */
1240 #define MIX_DATALINE 1
1242 #define MIX_FIRSTLINE 3
1245 * Parse the operation mix file 'mix_file'.
1247 * ORIGINAL PRE-SFS1.2 format:
1248 * Assumes that the input file is in the same format as
1249 * the output of the nfsstat(8) command.
1251 * Uses a simple state transition to keep track of what to expect.
1252 * Parsing is done a line at a time.
1254 * State Input action New state
1255 * MIX_START ".*nfs:.*" skip one line MIX_FIRSTLINE
1256 * MIX_FIRSTLINE ".*[0-9]*.*" get calls MIX_DATALINE
1257 * MIX_DATALINE "[0-9]* [0-9]*%"X6 get op counts MIX_DATALINE
1258 * MIX_DATALINE "[0-9]* [0-9]*%"X4 get op counts MIX_DONE
1259 * MIX_DONE EOF return
1261 * We read operation counts from the mix file
1262 * and compute our own mix percentages,
1263 * rather than using those in the mix file.
1265 * NEW SFS1.2 format version #2:
1266 * SFS MIXFILE VERSION 2 Version header (must come first line)
1267 * "^#.*" Comment (any line except first)
1268 * "%s [0-9]*%" Op name Op percentage
1274 int state; /* current state of state machine */
1275 int got; /* number of items read from input line */
1276 int opnum; /* operation number index */
1277 int calls; /* total number of calls in mix */
1278 char line[LINELEN]; /* input line buffer */
1279 char op_name[LINELEN]; /* name buffer */
1281 unsigned int len; /* length of input line */
1282 FILE *mix_fp; /* mix file */
1283 int vers; /* mix file version number */
1284 sfs_op_type *op_ptr;
1286 if ((mix_fp = fopen(mix_file, "r")) == NULL) {
1287 (void) fprintf(stderr, "%s: bad mix file", sfs_Myname);
1292 if (fgets(line, LINELEN, mix_fp) == NULL) {
1293 (void) fprintf(stderr, "%s: bad mix format - unexpected empty file\n",
1295 (void) fclose(mix_fp);
1302 * Look for initial version string
1304 got = sscanf(line, "SFS MIXFILE VERSION %d", &vers);
1307 * Check to see if this is old mixfile
1310 if (len < 4 || lad_substr(line, "nfs:") == 0) {
1311 (void) fprintf(stderr, "%s: bad mix format - initial line '%s'\n",
1313 (void) fclose(mix_fp);
1321 * Old style mix file
1324 while (state != MIX_DONE && fgets(line, LINELEN, mix_fp)) {
1329 * Ate first line after nfs:
1331 state = MIX_FIRSTLINE;
1335 got = sscanf(line, "%d", &calls);
1337 (void) fprintf(stderr,
1338 "%s: bad mix format - can't find 'calls' value %d\n",
1340 (void) fclose(mix_fp);
1343 if (fgets(line, LINELEN, mix_fp) == NULL) {
1344 (void) fprintf(stderr,
1345 "%s: bad mix format - unexpected EOF after 'calls'\n",
1347 (void) fclose(mix_fp);
1350 state = MIX_DATALINE;
1355 "%d %*d%% %d %*d%% %d %*d%% %d %*d%% %d %*d%% %d %*d%% %d %*d%%",
1356 &Ops[opnum].mix_pcnt,
1357 &Ops[opnum + 1].mix_pcnt,
1358 &Ops[opnum + 2].mix_pcnt,
1359 &Ops[opnum + 3].mix_pcnt,
1360 &Ops[opnum + 4].mix_pcnt,
1361 &Ops[opnum + 5].mix_pcnt,
1362 &Ops[opnum + 6].mix_pcnt);
1364 if (got == 4 && opnum == 14) {
1365 /* looks like the last line */
1367 } else if (got == 7) {
1369 if (fgets(line, LINELEN, mix_fp) == NULL) {
1370 (void) fprintf(stderr,
1371 "%s: bad mix format - unexpected EOF after 'calls'\n",
1373 (void) fclose(mix_fp);
1377 (void) fprintf(stderr,
1378 "%s: bad mix format - can't find %d op values\n",
1380 (void) fclose(mix_fp);
1386 (void) fprintf(stderr,
1387 "%s: error parsing mix file - bad state %d\n",
1389 (void) fclose(mix_fp);
1391 } /* end switch on state */
1392 } /* end while there are lines to read */
1394 if (state != MIX_DONE) {
1395 (void) fprintf(stderr, "%s: bad mix format - unexpected EOF\n",
1397 (void) fclose(mix_fp);
1400 for (opnum = 0; opnum < NOPS; opnum++) {
1401 Ops[opnum].mix_pcnt = Ops[opnum].mix_pcnt * 100 / calls
1402 + ((Ops[opnum].mix_pcnt * 1000 / calls % 10) >= 5);
1404 (void) fclose(mix_fp);
1409 * New style mix file
1411 while (fgets(line, LINELEN, mix_fp) != NULL) {
1412 if (line[0] == '#') /* Comment line */
1414 got = sscanf(line, "%s %d", op_name, &mix_pcnt);
1416 (void) fprintf(stderr,
1417 "%s: bad mix format - can't find op values: %s\n",
1419 (void) fclose(mix_fp);
1423 while (strcmp(op_ptr->name, "TOTAL") != 0) {
1424 if (strcmp(op_ptr->name, op_name) == 0) {
1425 op_ptr->mix_pcnt = mix_pcnt;
1430 if (strcmp(op_ptr->name, "TOTAL") == 0) {
1431 (void) fprintf(stderr,
1432 "%s: unknown op name: %s\n",
1433 sfs_Myname, op_name);
1434 (void) fclose(mix_fp);
1439 * Make sure that the total mix percentages == 100
1443 while (strcmp(op_ptr->name, "TOTAL") != 0) {
1444 mix_pcnt += op_ptr->mix_pcnt;
1447 if (mix_pcnt != 100) {
1448 (void) fprintf(stderr,
1449 "%s: WARNING total mix percentage %d != 100\n",
1450 sfs_Myname, mix_pcnt);
1452 (void) fclose(mix_fp);
1456 (void) fprintf(stderr, "%s: Unknown mix file version number %d\n",
1458 (void) fclose(mix_fp);
1464 * Parse the block I/O distribution file 'fp'.
1472 /* first, read and parse the i/o distribution file for syntax and size */
1473 if (parseiodist(fp, 1) == -1) {
1476 (void) fseek(fp, 0, SEEK_SET);
1478 /* read the i/o distribution file into the i/o dist table */
1479 if (parseiodist(fp, 2) == -1) {
1483 if (DEBUG_PARENT_GENERAL) {
1484 (void) fprintf(stdout, "I/o Distribution Table\n");
1485 (void) fprintf(stdout, "Read:\n");
1486 (void) fprintf(stdout, "\tpcnt bufs frags\n");
1487 for (i = 0 ; ; i++) {
1488 (void) fprintf(stdout, "\t%4d %4d %5d\n", Io_dist_ptr->read[i].pcnt,
1489 Io_dist_ptr->read[i].bufs, Io_dist_ptr->read[i].frags);
1490 if (Io_dist_ptr->read[i].pcnt == 100)
1494 (void) fprintf(stdout, "Write:\n");
1495 (void) fprintf(stdout, "\tpcnt bufs frags\n");
1496 for (i = 0; ; i++) {
1497 (void) fprintf(stdout, "\t%4d %4d %5d\n",
1498 Io_dist_ptr->write[i].pcnt,
1499 Io_dist_ptr->write[i].bufs,
1500 Io_dist_ptr->write[i].frags);
1501 if (Io_dist_ptr->write[i].pcnt == 100)
1504 (void) fprintf(stdout, "Maximum file size: %d KB (%d * %d KB)\n",
1505 Io_dist_ptr->max_bufs * Kb_per_block,
1506 Io_dist_ptr->max_bufs, Kb_per_block);
1513 * Block/File Distribution file parser.
1514 * Assumes that the input file is in the following format:
1518 * percent block_cnt fragment_flag
1523 * percent block_cnt fragment_flag
1530 * - The READ_KEY_WORD is "Read", the WRITE_KEY_WORD is "Write".
1531 * - For each key word, the percent fields must sum to 100.
1532 * - Fragment is either true (1) or false (0)
1533 * - Maximum file size (and transfer size) is the largest
1534 * eight_k_cnt * 8KB plus 7 Kb for fragments
1537 * Uses a simple state transition to keep track of what to expect.
1538 * Parsing is done a line at a time.
1540 * State Input action New state
1541 * ----- -------------------- ------------- ---------
1542 * START "Read" skip one line READ
1543 * START "Write" skip one line WRITE
1544 * READ "[0-9]* [0-9]* [01]" get values READ
1545 * READ "Write" skip one line WRITE
1546 * WRITE "[0-9]* [0-9]* [01]" get values WRITE
1547 * WRITE "Read" skip one line READ
1550 * Pass 1 reads the file and allocates table space.
1551 * Pass 2 reads the file data into the tables.
1558 int state; /* current state of state machine */
1559 int got; /* number of items read from input line */
1560 int pcnt; /* percent read from input line */
1561 int bufs; /* eight_kb_buffer_cnt read from input line */
1562 int frags; /* fragment flag read from input line */
1563 int rbucket; /* current read distribution table bucket */
1564 int wbucket; /* current write distribution table bucket */
1565 int rpcnt; /* cumulative percent for read buckets */
1566 int wpcnt; /* cumulative percent for write buckets */
1567 char key[5]; /* keyword buffer */
1568 char line[LINELEN]; /* input line buffer */
1572 * Pass 1 reads, sizes, and error checks the input
1573 * and then allocates space for the distribution tables.
1574 * Pass 2 reads the input into the allocated tables.
1581 state = IO_DIST_START;
1583 while (fgets(line, LINELEN, fp)) {
1586 while (nextline == 0) {
1588 if (state == IO_DIST_READ) {
1589 got = sscanf(line, "%d %d %d", &pcnt, &bufs, &frags);
1591 state = IO_DIST_START;
1592 continue; /* same line, but goto new state */
1597 if (frags != 0 && frags != 1) {
1598 (void) fprintf(stderr,
1599 "%s: bad i/o dist format - bad fragment value\n",
1605 Io_dist_ptr->read[rbucket].pcnt = rpcnt;
1606 Io_dist_ptr->read[rbucket].bufs = bufs;
1607 Io_dist_ptr->read[rbucket].frags = frags;
1610 if (DEBUG_CHILD_FILES) {
1611 (void) fprintf(stdout, "p=%d b=%d f=%d rpcnt=%d\n",
1612 pcnt, bufs, frags, rpcnt);
1613 (void) fflush(stdout);
1616 /* read next line in file */
1621 if (state == IO_DIST_WRITE) {
1622 got = sscanf(line, "%d %d %d", &pcnt, &bufs, &frags);
1624 state = IO_DIST_START;
1625 continue; /* same line, but goto new state */
1630 if (frags != 0 && frags != 1) {
1631 (void) fprintf(stderr,
1632 "%s: bad i/o dist format - bad fragment value\n",
1638 Io_dist_ptr->write[wbucket].pcnt = wpcnt;
1639 Io_dist_ptr->write[wbucket].bufs = bufs;
1640 Io_dist_ptr->write[wbucket].frags = frags;
1643 if (DEBUG_CHILD_FILES) {
1644 (void) fprintf(stdout, "p=%d b=%d f=%d wpcnt=%d\n",
1645 pcnt, bufs, frags, wpcnt);
1646 (void) fflush(stdout);
1648 /* read next line in file */
1653 if (state == IO_DIST_START) {
1654 got = sscanf(line, "%s", key);
1655 if (got != 1 || (strlen(key) != 5)){
1656 (void) fprintf(stderr,
1657 "%s: bad i/o dist format - invalid keyword %s\n",
1661 if (!strcmp(key, "Read") || !strcmp(key, "read")) {
1663 (void) fprintf(stderr,
1664 "%s: bad i/o dist format - too many read keywords\n",
1669 state = IO_DIST_READ;
1671 /* read next line in file */
1675 if (!strcmp(key, "Write") || !strcmp(key, "write")) {
1677 (void) fprintf(stderr,
1678 "%s: bad i/o dist format - too many write keywords\n",
1683 state = IO_DIST_WRITE;
1685 /* read next line in file */
1689 (void) fprintf(stderr,
1690 "%s: bad i/o dist format - unknown keyword %s\n",
1695 } /* end while processing this line */
1696 } /* end while more lines */
1700 /* error check the input */
1702 (void) fprintf(stderr,
1703 "%s: bad i/o dist format - no read distribution data\n",
1708 (void) fprintf(stderr,
1709 "%s: bad i/o dist format - read total percent != 100\n",
1714 (void) fprintf(stderr,
1715 "%s: bad i/o dist format - no write distribution data\n",
1720 (void) fprintf(stderr,
1721 "%s: bad i/o dist format - write percent total != 100\n",
1726 /* allocate space for the table */
1727 if ((Io_dist_ptr = (sfs_io_dist_type *)
1728 malloc(sizeof(sfs_io_dist_type))) == NULL) {
1729 (void) fprintf(stderr,
1730 "%s: block i/o distribution table allocation failed\n",
1734 if ((Io_dist_ptr->read = (sfs_io_op_dist_type *)
1735 malloc(rbucket*sizeof(sfs_io_op_dist_type))) == NULL) {
1736 (void) fprintf(stderr,
1737 "%s: read distribution table allocation failed\n", sfs_Myname);
1740 if ((Io_dist_ptr->write = (sfs_io_op_dist_type *)
1741 malloc(wbucket*sizeof(sfs_io_op_dist_type)))==NULL) {
1742 (void) fprintf(stderr,
1743 "%s: write distribution table allocation failed\n", sfs_Myname);
1754 * Compute the max i/o transfer size and average ops per request
1755 * for the block transfer distribution table.
1759 sfs_io_dist_type * io_dist_ptr)
1762 double weighted_ops;
1763 double previous_pcnt;
1767 * compute expected number of ops for multi-op requests.
1768 * the calculation assumes that if a i/o distribution table
1769 * entry specifies that a fragment is to be generated, then
1770 * exactly one OTW operation will result.
1775 previous_pcnt = 0.0;
1776 for (i = 0; ; i++) {
1777 weighted_ops += (io_dist_ptr->read[i].pcnt - previous_pcnt) *
1778 (io_dist_ptr->read[i].bufs + io_dist_ptr->read[i].frags);
1779 previous_pcnt = io_dist_ptr->read[i].pcnt;
1780 if (io_dist_ptr->read[i].bufs > max_bufs)
1781 max_bufs = io_dist_ptr->read[i].bufs;
1782 if (io_dist_ptr->read[i].pcnt == 100)
1785 io_dist_ptr->avg_ops_per_read_req = weighted_ops / 100.0;
1788 previous_pcnt = 0.0;
1789 for (i = 0; ; i++) {
1790 weighted_ops += (io_dist_ptr->write[i].pcnt - previous_pcnt) *
1791 (io_dist_ptr->write[i].bufs + io_dist_ptr->write[i].frags);
1792 previous_pcnt = io_dist_ptr->write[i].pcnt;
1793 if (io_dist_ptr->write[i].bufs > max_bufs)
1794 max_bufs = io_dist_ptr->write[i].bufs;
1795 if (io_dist_ptr->write[i].pcnt == 100)
1798 io_dist_ptr->avg_ops_per_write_req = weighted_ops / 100.0;
1800 io_dist_ptr->max_bufs = max_bufs + 1;
1814 * Calculate the average number of bytes per file
1816 for (i = 0; Default_file_size_dist[i].size != 0; i++) {
1817 cur_pcnt = Default_file_size_dist[i].pcnt - prev_pcnt;
1818 num_files += cur_pcnt;
1819 tot_size += (Default_file_size_dist[i].size * 1024) * cur_pcnt;
1820 prev_pcnt = Default_file_size_dist[i].pcnt;
1823 avg_bytes_per_file = tot_size / num_files;
1824 files_per_megabyte = (((1024*1024) + avg_bytes_per_file) \
1825 / avg_bytes_per_file);
1831 int Delta_fss_bytes;
1833 Base_fss_bytes = Num_working_io_files * (avg_bytes_per_file / 1024);
1834 Total_fss_bytes = Num_io_files * (avg_bytes_per_file / 1024);
1835 Cur_fss_bytes = Base_fss_bytes;
1836 Delta_fss_bytes = (Base_fss_bytes * Fss_delta_percent) / 100;
1837 Limit_fss_bytes = Base_fss_bytes + Delta_fss_bytes;
1838 Most_fss_bytes = Base_fss_bytes;
1839 Least_fss_bytes = Base_fss_bytes;
1843 * return true if 'sp' contains the substring 'subsp', false otherwise
1854 if (sp == NULL || subsp == NULL) {
1858 want = strlen(subsp);
1860 while (*sp != '\0') {
1861 while (*sp != *subsp && *sp != '\0') {
1866 while (*sp == *s2 && *sp != '\0') {
1871 if (found == want) {
1880 * Check the gettimeofday() resolution. If the resolution
1881 * is in chunks bigger than SFS_MIN_RES then the client
1882 * does not have a usable resolution for running the
1889 char tmp_hostname[HOSTNAME_LEN];
1891 time_res = get_resolution();
1892 getmyhostname(tmp_hostname, HOSTNAME_LEN);
1893 if( time_res > (double)SFS_MIN_RES )
1895 (void) fprintf(stderr,
1896 "\n%s: Clock resolution too poor to obtain valid results.\n",
1898 (void) fprintf(stderr,
1899 "%s: Clock resolution %f Micro seconds.\n", tmp_hostname,
1905 (void) fprintf(stderr,
1906 "\n%s: Good clock resolution [ %f ] Micro seconds.\n",
1907 tmp_hostname, time_res);
1912 * Lifted code from Iozone with permission from author. (Don Capps)
1913 * Returns the resolution of the gettimeofday() function
1917 get_resolution(void)
1919 double starttime, finishtime, besttime;
1923 finishtime=time_so_far1(); /* Warm up the instruction cache */
1924 starttime=time_so_far1(); /* Warm up the instruction cache */
1925 delay=j=0; /* Warm up the data cache */
1930 starttime=time_so_far1();
1931 for(j=0;j< delay;j++)
1933 finishtime=time_so_far1();
1934 if(starttime==finishtime)
1939 besttime=(finishtime-starttime);
1940 if((finishtime-starttime) < besttime)
1941 besttime=(finishtime-starttime);
1950 * Lifted code from Iozone with permission from author. (Don Capps)
1951 * Returns current result of gettimeofday() in microseconds.
1953 /************************************************************************/
1954 /* Time measurement routines. */
1955 /* Return time in microseconds */
1956 /************************************************************************/
1961 /* For Windows the time_of_day() is useless. It increments in 55 */
1962 /* milli second increments. By using the Win32api one can get */
1963 /* access to the high performance measurement interfaces. */
1964 /* With this one can get back into the 8 to 9 microsecond */
1967 LARGE_INTEGER freq,counter;
1971 QueryPerformanceFrequency(&freq);
1972 QueryPerformanceCounter(&counter);
1973 bigcounter=(double)counter.HighPart *(double)0xffffffff +
1974 (double)counter.LowPart;
1975 wintime = (double)(bigcounter/(double)freq.LowPart);
1976 return((double)wintime*1000000.0);
1978 #if defined (OSFV4) || defined(OSFV3) || defined(OSFV5)
1981 if (getclock(TIMEOFDAY, (struct timespec *) &gp) == -1)
1983 return (( (double) (gp.tv_sec)*1000000.0) +
1984 ( ((float)(gp.tv_nsec)) * 0.001 ));
1988 if (gettimeofday(&tp, (struct timezone *) NULL) == -1)
1989 perror("gettimeofday");
1990 return ((double) (tp.tv_sec)*1000000.0) +
1991 (((double) tp.tv_usec) );