Import TBBT (NFS trace replay).
[bluesky.git] / TBBT / trace_play / sfs_c_dmp.c
diff --git a/TBBT/trace_play/sfs_c_dmp.c b/TBBT/trace_play/sfs_c_dmp.c
new file mode 100644 (file)
index 0000000..82d9a38
--- /dev/null
@@ -0,0 +1,298 @@
+#ifndef lint
+static char sfs_c_dmpSid[] = "@(#)sfs_c_dmp.c  2.1     97/10/23";
+#endif
+
+/*
+ *   Copyright (c) 1992-1997,2001 by Standard Performance Evaluation Corporation
+ *     All rights reserved.
+ *             Standard Performance Evaluation Corporation (SPEC)
+ *             6585 Merchant Place, Suite 100
+ *             Warrenton, VA 20187
+ *
+ *     This product contains benchmarks acquired from several sources who
+ *     understand and agree with SPEC's goal of creating fair and objective
+ *     benchmarks to measure computer performance.
+ *
+ *     This copyright notice is placed here only to protect SPEC in the
+ *     event the source is misused in any manner that is contrary to the
+ *     spirit, the goals and the intent of SPEC.
+ *
+ *     The source code is provided to the user or company under the license
+ *     agreement for the SPEC Benchmark Suite for this product.
+ */
+
+/*****************************************************************
+ *                                                               *
+ *     Copyright 1991,1992  Legato Systems, Inc.                *
+ *     Copyright 1991,1992  Auspex Systems, Inc.                *
+ *     Copyright 1991,1992  Data General Corporation            *
+ *     Copyright 1991,1992  Digital Equipment Corporation       *
+ *     Copyright 1991,1992  Interphase Corporation              *
+ *     Copyright 1991,1992  Sun Microsystems, Inc.              *
+ *                                                               *
+ *****************************************************************/
+
+/*
+ * ---------------------- sfs_c_dmp.c ---------------------
+ *
+ *      Raw data dump routines for SFS.
+ *
+ *     The routines contained here capture and dump the raw data
+ *     points (operation, response time) to allow the researcher
+ *     to perform detailed analysis on the response time characteristics
+ *     of an NFS server.
+ *
+ *.Exported Routines
+ *     void log_dump(ladtime *, ladtime *, int)
+ *     void print_dump(int, int)
+ *
+ *.Local Routines
+ *     None.
+ *
+ *.Revision_History
+ *     11-Jul-94       ChakChung Ng    Add codes for NFS/v3
+ *     03-Feb-92       0.0.20 Pawlowski
+ *                                     Use of "Current_test_phase"
+ *                                     obviates need for dump init
+ *                                     routine, so it has been deleted.
+ *     10-Jan-92       0.0.19 Teelucksingh
+ *                                     Changed dump file names to be
+ *                                     < 14 chars. Added header to
+ *                                     output.
+ *      04-Jan-92      0.0.18 Pawlowski
+ *                                     Added raw data dump code.
+ */
+
+/*
+ * -------------------------  Include Files  -------------------------
+ */
+
+/*
+ * ANSI C headers
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h> 
+
+#include "sfs_c_def.h"
+
+struct savedata {
+    struct savedata    *next;
+    int32_t    rtv_sec;        /* The response time */
+    int32_t    rtv_usec;
+    int32_t    stv_sec;        /* The start time */
+    int32_t    stv_usec;
+    uint32_t   count;          /* Used only for read and write */
+    uint32_t   offset;         /* Used only for read and write */
+    uint32_t   length;         /* Used only for read and write */
+    uint16_t   unique_num;     /* unique id for file */
+    unsigned int flags;                /* Things like whether truncating, etc. */
+    int16_t    op;
+};
+
+uint32_t       Dump_count;     /* place to put read and write count */
+uint32_t       Dump_offset;    /* place to put r/w offset */
+uint32_t       Dump_length;    /* place to put r/w offset */
+int            Dump_data;      /* Flag set by command line option */
+int            dump_create_existing_file = FALSE;
+int            dump_truncate_op = FALSE;
+
+/*
+ * ----------------------  Static Declarations  ----------------------
+ */
+
+static struct savedata *saveary = 0;
+
+/*
+ * --------------------------  Constants  --------------------------
+ */
+
+/* flags bit values */
+#define CREATE_OF_EXISTING_FILE        0x0001
+#define TRUNCATE_OPERATION     0x0002
+
+/*
+ * ----------------------  Dump Routines  ----------------------
+ */
+
+/*
+ * log_dump()
+ *
+ * This function is called on the completion of every operation
+ * to log the data point. We log the operation and the elapsed time
+ * (storing the microsecond component also).
+ *
+ * The data is kept in a singly linked list, elements dynamically
+ * allocated as needed.
+ *
+ * Dynamic allocation of elements using malloc and single link list
+ * pointer adds overhead to the storage space for the data for each
+ * point. Dynamic allocation can result in system calls to get more
+ * space for elements, adding to execution overhead. However, if you're
+ * doing a raw data dump run, you assume costs are negligible.
+ */
+
+void
+log_dump(
+    struct ladtime *start,
+    struct ladtime *elapsed,
+    int op)
+{
+    static struct savedata *saveptr = 0;
+
+    if (!Dump_data || Current_test_phase != Testrun_phase)
+       return;
+
+    if (saveary == (struct savedata *)NULL) {
+       if ((saveary = (struct savedata *)
+                       malloc(sizeof(struct savedata)))
+                               == (struct savedata *)NULL) {
+           (void) fprintf(stderr, "Unable to allocate dump element\n");
+           return;
+       }
+       saveptr = saveary;
+    } else {
+       if ((saveptr->next = (struct savedata *)
+                       malloc(sizeof(struct savedata)))
+                               == (struct savedata *)NULL) {
+           (void) fprintf(stderr, "Unable to allocate dump element\n");
+           return;
+       }
+       saveptr = saveptr->next;
+    }
+    saveptr->next = (struct savedata *)NULL;
+    saveptr->flags = 0;
+    saveptr->op = op;
+    saveptr->rtv_sec = elapsed->sec;
+    saveptr->rtv_usec = elapsed->usec;
+    saveptr->stv_sec = start->sec;
+    saveptr->stv_usec = start->usec;
+    saveptr->unique_num = Cur_file_ptr->unique_num;
+    if (op == NFSPROC3_READ || op == NFSPROC3_WRITE ||
+       op == NFSPROC_READ || op == NFSPROC_WRITE) {
+       saveptr->count = (uint16_t) Dump_count;
+       saveptr->offset = Dump_offset;
+       saveptr->length = Dump_length;
+    }
+
+    if (dump_create_existing_file == TRUE) {
+       saveptr->flags |= CREATE_OF_EXISTING_FILE;
+       dump_create_existing_file = FALSE;
+    }
+
+    if (dump_truncate_op == TRUE) {
+       saveptr->flags |= TRUNCATE_OPERATION;
+       dump_truncate_op = FALSE;
+    }
+}
+
+/*
+ * print_dump()
+ *
+ * Dumps the raw data to a file in the format:
+ *
+ *     opcode  sec.msec  sec.msec file-unique-id <length> <offset> <count>
+ *     opcode  sec.msec  sec.msec file-unique-id
+ *          . . .
+ *
+ * The opcode is the numeric NFS operation code as defined in the
+ * NFS protocol specification. The first "sec.msec" field is the
+ * response time of the operation. The second "sec.msec" field
+ * is the start time of the operation. For read and write calls,
+ * the "length", "offset" and "count" from the operation arguments are put out
+ * as the fourth, fifth, and sixth field.
+ *
+ * This simple (x, y) pairing should be suitable input for a wide variety
+ * of plotting programs.
+ *
+ * Note that the raw data is precious! Several points to be observed:
+ *
+ *     1. The raw data for each individual child is dumped to
+ *        its own data file. So each individual child process
+ *        data can be inspected (possibly useful to debug client
+ *        load generation per child process anomalies).
+ *
+ *     2. More importantly, each raw data dump file presents
+ *        the operations generated by the child in their exact
+ *        order of generation. This can be used to analyze possible
+ *        time dependent behaviour of the server.
+ *
+ * Client process output files can be merged for analysis using cat(1).
+ *
+ * If any other data (additional fields) are added to raw data dump
+ * file, please add those fields after primary fields. awk(1) scripts
+ * and the like can be used to re-arrange data files, but it would
+ * be nice if the primary (x, y) data points are the default format.
+ */
+
+void
+print_dump(
+    int clientnum,
+    int childnum)
+{
+    char buf[256];
+    FILE *datap;
+    struct savedata *p = saveary;
+
+    buf[0] = 0;
+
+    if (!Dump_data)
+       return;
+
+    /*
+     * We write raw data files to the /tmp directory, and
+     * the manager will retrieve to the prime client.
+     *
+     * Removed preladraw prefix from file names to fit
+     * in 14 chars - K.T.
+     */
+
+    (void) sprintf(buf, "/tmp/c%3.3d-p%3.3d", clientnum, childnum);
+
+    if ((datap = fopen(buf, "w")) == NULL) {
+       (void) fprintf(stderr, "couldn't open %s for writing\n", buf);
+       return;
+    }
+
+    (void) fprintf(datap,"%s\n%s\n%s\n%s\n",
+"-----------------------------------------------------------------------------",
+"         Op Response           Start         Unique  File",
+"       Code     Time            Time        File Id  Length  Offset  Size",
+"-----------------------------------------------------------------------------");
+
+    p = saveary;
+    while(p) {
+       (void) fprintf(datap, "%11s %8.3f %19.3f %8d",
+               Ops[p->op].name,
+               (p->rtv_sec * 1000.0) + (p->rtv_usec / 1000.0),
+               (p->stv_sec * 1000.0) + (p->stv_usec / 1000.0),
+               p->unique_num);
+       if (p->op == NFSPROC3_READ || p->op == NFSPROC3_WRITE ||
+               p->op == NFSPROC_READ || p->op == NFSPROC_WRITE) {
+           (void) fprintf(datap,
+               " %8d %8d %5d\n", p->length, p->offset, p->count);
+       }
+       else if (p->op == NFSPROC3_SETATTR || p->op == NFSPROC3_CREATE ||
+               p->op == NFSPROC_SETATTR || p->op == NFSPROC_CREATE) {
+           if (p->flags & TRUNCATE_OPERATION) {
+               (void) fprintf(datap, "  %s", "TRUNCATE");
+           }
+           if (p->flags & CREATE_OF_EXISTING_FILE) {
+               (void) fprintf(datap, "  %s", "CREATE_EXISTING");
+           }
+           (void) fprintf(datap, "\n");
+       }
+       else {
+               (void) fprintf(datap, "\n");
+       }
+       p = p->next;
+    }
+
+    (void) fprintf(datap,
+"-----------------------------------------------------------------------------\n\n");
+    (void) fclose(datap);
+}