Add proper per-file copyright notices/licenses and top-level license.
[bluesky.git] / TBBT / trace_play / sfs_c_dmp.c
1 #ifndef lint
2 static char sfs_c_dmpSid[] = "@(#)sfs_c_dmp.c   2.1     97/10/23";
3 #endif
4
5 /*
6  *   Copyright (c) 1992-1997,2001 by Standard Performance Evaluation Corporation
7  *      All rights reserved.
8  *              Standard Performance Evaluation Corporation (SPEC)
9  *              6585 Merchant Place, Suite 100
10  *              Warrenton, VA 20187
11  *
12  *      This product contains benchmarks acquired from several sources who
13  *      understand and agree with SPEC's goal of creating fair and objective
14  *      benchmarks to measure computer performance.
15  *
16  *      This copyright notice is placed here only to protect SPEC in the
17  *      event the source is misused in any manner that is contrary to the
18  *      spirit, the goals and the intent of SPEC.
19  *
20  *      The source code is provided to the user or company under the license
21  *      agreement for the SPEC Benchmark Suite for this product.
22  */
23
24 /*****************************************************************
25  *                                                               *
26  *      Copyright 1991,1992  Legato Systems, Inc.                *
27  *      Copyright 1991,1992  Auspex Systems, Inc.                *
28  *      Copyright 1991,1992  Data General Corporation            *
29  *      Copyright 1991,1992  Digital Equipment Corporation       *
30  *      Copyright 1991,1992  Interphase Corporation              *
31  *      Copyright 1991,1992  Sun Microsystems, Inc.              *
32  *                                                               *
33  *****************************************************************/
34
35 /*
36  * ---------------------- sfs_c_dmp.c ---------------------
37  *
38  *      Raw data dump routines for SFS.
39  *
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
43  *      of an NFS server.
44  *
45  *.Exported Routines
46  *      void log_dump(ladtime *, ladtime *, int)
47  *      void print_dump(int, int)
48  *
49  *.Local Routines
50  *      None.
51  *
52  *.Revision_History
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
61  *                                      output.
62  *      04-Jan-92       0.0.18 Pawlowski
63  *                                      Added raw data dump code.
64  */
65
66 /*
67  * -------------------------  Include Files  -------------------------
68  */
69
70 /*
71  * ANSI C headers
72  */
73 #include <stdio.h>
74 #include <stdlib.h>
75 #include <string.h>
76 #include <errno.h>
77  
78 #include <sys/types.h>
79 #include <sys/stat.h> 
80
81 #include "sfs_c_def.h"
82
83 struct savedata {
84     struct savedata     *next;
85     int32_t     rtv_sec;        /* The response time */
86     int32_t     rtv_usec;
87     int32_t     stv_sec;        /* The start time */
88     int32_t     stv_usec;
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. */
94     int16_t     op;
95 };
96
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;
103
104 /*
105  * ----------------------  Static Declarations  ----------------------
106  */
107
108 static struct savedata *saveary = 0;
109
110 /*
111  * --------------------------  Constants  --------------------------
112  */
113
114 /* flags bit values */
115 #define CREATE_OF_EXISTING_FILE 0x0001
116 #define TRUNCATE_OPERATION      0x0002
117
118 /*
119  * ----------------------  Dump Routines  ----------------------
120  */
121
122 /*
123  * log_dump()
124  *
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).
128  *
129  * The data is kept in a singly linked list, elements dynamically
130  * allocated as needed.
131  *
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.
137  */
138
139 void
140 log_dump(
141     struct ladtime *start,
142     struct ladtime *elapsed,
143     int op)
144 {
145     static struct savedata *saveptr = 0;
146
147     if (!Dump_data || Current_test_phase != Testrun_phase)
148         return;
149
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");
155             return;
156         }
157         saveptr = saveary;
158     } else {
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");
163             return;
164         }
165         saveptr = saveptr->next;
166     }
167     saveptr->next = (struct savedata *)NULL;
168     saveptr->flags = 0;
169     saveptr->op = op;
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;
180     }
181
182     if (dump_create_existing_file == TRUE) {
183         saveptr->flags |= CREATE_OF_EXISTING_FILE;
184         dump_create_existing_file = FALSE;
185     }
186
187     if (dump_truncate_op == TRUE) {
188         saveptr->flags |= TRUNCATE_OPERATION;
189         dump_truncate_op = FALSE;
190     }
191 }
192
193 /*
194  * print_dump()
195  *
196  * Dumps the raw data to a file in the format:
197  *
198  *      opcode  sec.msec  sec.msec file-unique-id <length> <offset> <count>
199  *      opcode  sec.msec  sec.msec file-unique-id
200  *           . . .
201  *
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.
208  *
209  * This simple (x, y) pairing should be suitable input for a wide variety
210  * of plotting programs.
211  *
212  * Note that the raw data is precious! Several points to be observed:
213  *
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).
218  *
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.
223  *
224  * Client process output files can be merged for analysis using cat(1).
225  *
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.
230  */
231
232 void
233 print_dump(
234     int clientnum,
235     int childnum)
236 {
237     char buf[256];
238     FILE *datap;
239     struct savedata *p = saveary;
240
241     buf[0] = 0;
242
243     if (!Dump_data)
244         return;
245
246     /*
247      * We write raw data files to the /tmp directory, and
248      * the manager will retrieve to the prime client.
249      *
250      * Removed preladraw prefix from file names to fit
251      * in 14 chars - K.T.
252      */
253
254     (void) sprintf(buf, "/tmp/c%3.3d-p%3.3d", clientnum, childnum);
255
256     if ((datap = fopen(buf, "w")) == NULL) {
257         (void) fprintf(stderr, "couldn't open %s for writing\n", buf);
258         return;
259     }
260
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 "-----------------------------------------------------------------------------");
266
267     p = saveary;
268     while(p) {
269         (void) fprintf(datap, "%11s %8.3f %19.3f %8d",
270                 Ops[p->op].name,
271                 (p->rtv_sec * 1000.0) + (p->rtv_usec / 1000.0),
272                 (p->stv_sec * 1000.0) + (p->stv_usec / 1000.0),
273                 p->unique_num);
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);
278         }
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");
283             }
284             if (p->flags & CREATE_OF_EXISTING_FILE) {
285                 (void) fprintf(datap, "  %s", "CREATE_EXISTING");
286             }
287             (void) fprintf(datap, "\n");
288         }
289         else {
290                 (void) fprintf(datap, "\n");
291         }
292         p = p->next;
293     }
294
295     (void) fprintf(datap,
296 "-----------------------------------------------------------------------------\n\n");
297     (void) fclose(datap);
298 }