2 static char sfs_c_dmpSid[] = "@(#)sfs_c_dmp.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 * ---------------------- sfs_c_dmp.c ---------------------
38 * Raw data dump routines for SFS.
40 * The routines contained here capture and dump the raw data
41 * points (operation, response time) to allow the researcher
42 * to perform detailed analysis on the response time characteristics
46 * void log_dump(ladtime *, ladtime *, int)
47 * void print_dump(int, int)
53 * 11-Jul-94 ChakChung Ng Add codes for NFS/v3
54 * 03-Feb-92 0.0.20 Pawlowski
55 * Use of "Current_test_phase"
56 * obviates need for dump init
57 * routine, so it has been deleted.
58 * 10-Jan-92 0.0.19 Teelucksingh
59 * Changed dump file names to be
60 * < 14 chars. Added header to
62 * 04-Jan-92 0.0.18 Pawlowski
63 * Added raw data dump code.
67 * ------------------------- Include Files -------------------------
78 #include <sys/types.h>
81 #include "sfs_c_def.h"
84 struct savedata *next;
85 int32_t rtv_sec; /* The response time */
87 int32_t stv_sec; /* The start time */
89 uint32_t count; /* Used only for read and write */
90 uint32_t offset; /* Used only for read and write */
91 uint32_t length; /* Used only for read and write */
92 uint16_t unique_num; /* unique id for file */
93 unsigned int flags; /* Things like whether truncating, etc. */
97 uint32_t Dump_count; /* place to put read and write count */
98 uint32_t Dump_offset; /* place to put r/w offset */
99 uint32_t Dump_length; /* place to put r/w offset */
100 int Dump_data; /* Flag set by command line option */
101 int dump_create_existing_file = FALSE;
102 int dump_truncate_op = FALSE;
105 * ---------------------- Static Declarations ----------------------
108 static struct savedata *saveary = 0;
111 * -------------------------- Constants --------------------------
114 /* flags bit values */
115 #define CREATE_OF_EXISTING_FILE 0x0001
116 #define TRUNCATE_OPERATION 0x0002
119 * ---------------------- Dump Routines ----------------------
125 * This function is called on the completion of every operation
126 * to log the data point. We log the operation and the elapsed time
127 * (storing the microsecond component also).
129 * The data is kept in a singly linked list, elements dynamically
130 * allocated as needed.
132 * Dynamic allocation of elements using malloc and single link list
133 * pointer adds overhead to the storage space for the data for each
134 * point. Dynamic allocation can result in system calls to get more
135 * space for elements, adding to execution overhead. However, if you're
136 * doing a raw data dump run, you assume costs are negligible.
141 struct ladtime *start,
142 struct ladtime *elapsed,
145 static struct savedata *saveptr = 0;
147 if (!Dump_data || Current_test_phase != Testrun_phase)
150 if (saveary == (struct savedata *)NULL) {
151 if ((saveary = (struct savedata *)
152 malloc(sizeof(struct savedata)))
153 == (struct savedata *)NULL) {
154 (void) fprintf(stderr, "Unable to allocate dump element\n");
159 if ((saveptr->next = (struct savedata *)
160 malloc(sizeof(struct savedata)))
161 == (struct savedata *)NULL) {
162 (void) fprintf(stderr, "Unable to allocate dump element\n");
165 saveptr = saveptr->next;
167 saveptr->next = (struct savedata *)NULL;
170 saveptr->rtv_sec = elapsed->sec;
171 saveptr->rtv_usec = elapsed->usec;
172 saveptr->stv_sec = start->sec;
173 saveptr->stv_usec = start->usec;
174 saveptr->unique_num = Cur_file_ptr->unique_num;
175 if (op == NFSPROC3_READ || op == NFSPROC3_WRITE ||
176 op == NFSPROC_READ || op == NFSPROC_WRITE) {
177 saveptr->count = (uint16_t) Dump_count;
178 saveptr->offset = Dump_offset;
179 saveptr->length = Dump_length;
182 if (dump_create_existing_file == TRUE) {
183 saveptr->flags |= CREATE_OF_EXISTING_FILE;
184 dump_create_existing_file = FALSE;
187 if (dump_truncate_op == TRUE) {
188 saveptr->flags |= TRUNCATE_OPERATION;
189 dump_truncate_op = FALSE;
196 * Dumps the raw data to a file in the format:
198 * opcode sec.msec sec.msec file-unique-id <length> <offset> <count>
199 * opcode sec.msec sec.msec file-unique-id
202 * The opcode is the numeric NFS operation code as defined in the
203 * NFS protocol specification. The first "sec.msec" field is the
204 * response time of the operation. The second "sec.msec" field
205 * is the start time of the operation. For read and write calls,
206 * the "length", "offset" and "count" from the operation arguments are put out
207 * as the fourth, fifth, and sixth field.
209 * This simple (x, y) pairing should be suitable input for a wide variety
210 * of plotting programs.
212 * Note that the raw data is precious! Several points to be observed:
214 * 1. The raw data for each individual child is dumped to
215 * its own data file. So each individual child process
216 * data can be inspected (possibly useful to debug client
217 * load generation per child process anomalies).
219 * 2. More importantly, each raw data dump file presents
220 * the operations generated by the child in their exact
221 * order of generation. This can be used to analyze possible
222 * time dependent behaviour of the server.
224 * Client process output files can be merged for analysis using cat(1).
226 * If any other data (additional fields) are added to raw data dump
227 * file, please add those fields after primary fields. awk(1) scripts
228 * and the like can be used to re-arrange data files, but it would
229 * be nice if the primary (x, y) data points are the default format.
239 struct savedata *p = saveary;
247 * We write raw data files to the /tmp directory, and
248 * the manager will retrieve to the prime client.
250 * Removed preladraw prefix from file names to fit
254 (void) sprintf(buf, "/tmp/c%3.3d-p%3.3d", clientnum, childnum);
256 if ((datap = fopen(buf, "w")) == NULL) {
257 (void) fprintf(stderr, "couldn't open %s for writing\n", buf);
261 (void) fprintf(datap,"%s\n%s\n%s\n%s\n",
262 "-----------------------------------------------------------------------------",
263 " Op Response Start Unique File",
264 " Code Time Time File Id Length Offset Size",
265 "-----------------------------------------------------------------------------");
269 (void) fprintf(datap, "%11s %8.3f %19.3f %8d",
271 (p->rtv_sec * 1000.0) + (p->rtv_usec / 1000.0),
272 (p->stv_sec * 1000.0) + (p->stv_usec / 1000.0),
274 if (p->op == NFSPROC3_READ || p->op == NFSPROC3_WRITE ||
275 p->op == NFSPROC_READ || p->op == NFSPROC_WRITE) {
276 (void) fprintf(datap,
277 " %8d %8d %5d\n", p->length, p->offset, p->count);
279 else if (p->op == NFSPROC3_SETATTR || p->op == NFSPROC3_CREATE ||
280 p->op == NFSPROC_SETATTR || p->op == NFSPROC_CREATE) {
281 if (p->flags & TRUNCATE_OPERATION) {
282 (void) fprintf(datap, " %s", "TRUNCATE");
284 if (p->flags & CREATE_OF_EXISTING_FILE) {
285 (void) fprintf(datap, " %s", "CREATE_EXISTING");
287 (void) fprintf(datap, "\n");
290 (void) fprintf(datap, "\n");
295 (void) fprintf(datap,
296 "-----------------------------------------------------------------------------\n\n");
297 (void) fclose(datap);