Import TBBT (NFS trace replay).
[bluesky.git] / TBBT / trace_play / sfs_c_chd.3thread.c
diff --git a/TBBT/trace_play/sfs_c_chd.3thread.c b/TBBT/trace_play/sfs_c_chd.3thread.c
new file mode 100644 (file)
index 0000000..195beb0
--- /dev/null
@@ -0,0 +1,3815 @@
+/* Try to change thread scheduling and uses three threads */
+#ifndef lint
+static char sfs_c_chdSid[] = "@(#)sfs_c_chd.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_chd.c -------------------------
+ *
+ *      The sfs child.  Routines to initialize child parameters,
+ *     initialize test directories, and generate load.
+ *
+ *.Exported_Routines
+ *     void child(int, float, int, char *);
+ *     void init_fileinfo(void);
+ *     void init_counters(void);
+ *     sfs_fh_type * randfh(int, int, uint_t, sfs_state_type,
+ *                             sfs_file_type);
+ *     int check_access(struct *stat)
+ *     int check_fh_access();
+ *
+ *.Local_Routines
+ *     void check_call_rate(void);
+ *     void init_targets(void);
+ *     void init_dirlayout(void);
+ *     void init_rpc(void);
+ *     void init_testdir(void);
+ *     int do_op(void);
+ *     int op(int);
+ *
+ *.Revision_History
+ *     21-Aug-92       Wittle          randfh() uses working set files array.
+ *                                     init_fileinfo() sets up working set.
+ *      02-Jul-92      Teelucksingh    Target file size now based on peak load
+ *                                     instead of BTDT.
+ *     04-Jan-92       Pawlowski       Added raw data dump hooks.
+ *     16-Dec-91       Wittle          Created.
+ */
+
+
+/*
+ * -------------------------  Include Files  -------------------------
+ */
+
+/*
+ * ANSI C headers
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <math.h>
+#include <signal.h>
+
+#include <sys/types.h>
+#include <sys/stat.h> 
+#include <unistd.h>
+
+#include "sfs_c_def.h"
+#include "sfs_m_def.h"
+#include "rfs_c_def.h"
+#include "generic_hash.h"
+#include "nfsd_nfsfh_cust.h"
+
+extern struct hostent   *Server_hostent;
+
+#define PROB_SCALE 1000L
+#define _M_MODULUS 2147483647L /* (2**31)-1 */
+
+#define _GROUP_DIVISOR 500
+#define _FILES_PER_GROUP 4
+#define _MIN_GROUPS 12
+#define _WORKING_SET_AT_25_OPS_PER_SEC 975
+
+
+/*
+ * -----------------------  External Definitions  -----------------------
+ */
+extern uint32_t    biod_clnt_call(CLIENT *, uint32_t, xdrproc_t, void *);
+extern enum clnt_stat proc_header(CLIENT *cl, xdrproc_t xdr_results, void *results_ptr);
+extern int  biod_poll_wait(CLIENT *, uint32_t);
+extern enum clnt_stat get_areply_udp (CLIENT * cl, uint32_t *xid, struct timeval *timeout);
+extern char * parse_name (char * t, char * buf);
+
+/* forward definitions for local functions */
+static int init_rpc(void);
+
+/* RFS: forward definitions for local functions */
+void init_ops(void);
+static void init_signal();
+extern void init_file_system (void);
+extern void init_dep_tab (void);
+static int read_trace(void);
+static void read_fh_map();
+static void init_play (char * mount_point);
+static void trace_play(void);
+void print_result(void);
+static int get_nextop(void);
+static int check_timeout(void);
+static struct biod_req * get_biod_req(int dep_tab_index);
+static int lookup_biod_req (int xid);
+static void init_time_offset(void);
+void adjust_play_window (int flag, int * poll_timeout_arg);
+static int poll_and_get_reply (int usecs);
+static char * nfs3_strerror(int status);
+static void check_clock(void);
+static double time_so_far1(void);
+static double get_resolution(void);
+static void usage(void);
+void init_dep_tab_entry (int dep_index);
+extern inline fh_map_t * lookup_fh (char * trace_fh );
+static void finish_request (int biod_index, int dep_index, int status, int dep_flag);
+static inline void add_new_file_system_object (int proc, int dep_index, char * line, char * reply_line);
+static inline char * find_lead_trace_fh(int proc, char * line);
+static inline char * find_reply_trace_fh (char * line);
+
+/*
+ * -------------  Per Child Load Generation Rate Variables  -----------
+ */
+static uint_t Calls_this_period; /* calls made during the current run period */
+static uint_t Calls_this_test; /* calls made during the test so far */
+static uint_t Reqs_this_period;        /* reqs made during the current run period */
+static uint_t Reqs_this_test;  /* reqs made during the test so far */
+static uint_t Sleep_msec_this_test; /* msec slept during the test so far */
+static uint_t Sleep_msec_this_period;
+static uint_t Previous_chkpnt_msec; /* beginning time of current run period */
+static int Target_sleep_mspc;  /* targeted sleep time per call */
+
+static char io_buf[BUFSIZ];    /* io buffer for print out messages */
+
+char * sfs_Myname;
+int     Log_fd;                         /* log fd */
+char    Logname[NFS_MAXNAMLEN];         /* child processes sync logfile */
+int    Validate = 0;                                   /* fake variable */
+int Child_num = 0;                                             /* fake: child index */
+int Tcp = 0;                                                   /* We implement UDP first */
+int Client_num = 1;                                            /* fake: number of client */
+uid_t Real_uid;
+gid_t Cur_gid;
+uid_t Cur_uid;
+/* as long as the inital value is different, then it's OK */
+int recv_num = 0;
+int timeout_num = 0;
+int send_num = 0;
+int exit_flag = 0;
+int async_rpc_sem;
+int no_progress_flag = 0;
+int num_out_reqs_statistics[MAX_OUTSTANDING_REQ+1];
+int num_out_reqs_statistics_at_timeout[MAX_OUTSTANDING_REQ+1];
+
+/*
+ * -------------------------  SFS Child  -------------------------
+ */
+
+static int nfs2proc_to_rfsproc[18] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 
+                                                                       10, 11, 12, 13, 14, 15, 16, 17};
+static int nfs3proc_to_rfsproc[NFS3_PROCEDURE_COUNT] = {0, 1, 2, 4, 18, 5, 6, 8, 9, 14, 
+                                                                                                       13, 21, 10, 15, 11, 12, 16, 23, 17, 20, 
+                                                                                                       22, 19};
+void print_usage(int pos, int argc, char ** argv)
+{
+       int i;
+       printf("sfs3 hostname:mount_dir trace_file|stdin fh_map_file play_scale warmup_time(in seconds) \n");
+       printf("sfs3 -pair_trace trace_file\n");
+       printf("sfs3 -pair_write trace_file\n");
+       printf("sfs3 -help\n");
+       printf ("pos %d argc %d", pos, argc);
+       for (i=0; i<argc; i++) {
+               printf(" %s", argv[i]);
+       } 
+       printf ("\n");
+       exit;
+}
+
+void print_cyclic_buffers ()
+{
+       CYCLIC_PRINT(memory_trace_index);
+       CYCLIC_PRINT(dep_tab_index);
+       CYCLIC_PRINT(dep_window_index);
+}
+
+void add_to_dep_tab(int i)
+{
+       char * trace_fh;
+       fh_map_t * fh_map_entry;
+       dep_tab_t * ent;
+
+    trace_fh = strstr (memory_trace[i].line, "fh");
+    if (!trace_fh)
+       printf ("memory_trace[%d].line %s\n", i, memory_trace[i].line);
+    RFS_ASSERT (trace_fh);
+    trace_fh += 3;
+    fh_map_entry = lookup_fh (trace_fh);
+    if (fh_map_entry && (fh_map_entry->flag==FH_MAP_FLAG_DISCARD) )  {
+        req_num_with_discard_fh ++;
+               return;
+       }
+    if (fh_map_entry)
+        req_num_with_init_fh ++;
+    else
+        req_num_with_new_fh ++;
+                                                                                                                              
+       RFS_ASSERT (!CYCLIC_FULL(dep_tab_index));
+       ent = &(dep_tab[dep_tab_index.head]);
+
+    ent->disk_index = memory_trace[i].disk_index;
+       ent->memory_index = i;
+#ifdef REDUCE_MEMORY_TRACE_SIZE
+    ent->trace_status = memory_trace[i].trace_status;
+    ent->reply_trace_fh = memory_trace[i].reply_trace_fh;
+#endif
+    ent->line = memory_trace[i].line;
+    init_dep_tab_entry(dep_tab_index.head);
+
+    if (rfs_debug && (i%100000)==0)
+       printf ("dep_tab[%d].disk_index %d = memory_trace[%d].disk_index %d\n", dep_tab_index.head, ent->disk_index, i, memory_trace[i].disk_index);
+    CYCLIC_MOVE_HEAD(memory_trace_index);
+    CYCLIC_MOVE_HEAD(dep_tab_index);
+}
+
+void init_profile_variables ()
+{
+       init_profile ("total_profile", &total_profile);
+       init_profile ("execute_next_request_profile", &execute_next_request_profile);
+       init_profile ("valid_get_nextop_profile", &valid_get_nextop_profile);
+       init_profile ("invalid_get_nextop_profile",&invalid_get_nextop_profile);
+       init_profile ("prepare_argument_profile", &prepare_argument_profile);
+       init_profile ("biod_clnt_call_profile", &biod_clnt_call_profile);
+       init_profile ("receive_next_reply_profile", &receive_next_reply_profile);
+       init_profile ("valid_poll_and_get_reply_profile", &valid_poll_and_get_reply_profile);
+       init_profile ("invalid_poll_and_get_reply_profile", &invalid_poll_and_get_reply_profile);
+       init_profile ("decode_reply_profile", &decode_reply_profile);
+       init_profile ("check_reply_profile", &check_reply_profile);
+       init_profile ("add_create_object_profile", &add_create_object_profile);
+       init_profile ("check_timeout_profile", &check_timeout_profile);
+       init_profile ("adjust_play_window_profile",&adjust_play_window_profile);
+       init_profile ("fgets_profile",&fgets_profile);
+       init_profile ("read_line_profile",&read_line_profile);
+       init_profile ("read_trace_profile",&read_trace_profile);
+}
+
+static char trace_file[256]="anon-lair62-011130-1200.txt";
+int print_memory_usage()
+{
+       printf("size of fh_map_t %d size of fh_map %d\n", sizeof(fh_map_t), sizeof(fh_map));
+       printf("sizeof dep_tab_t %d sizeof dep_tab %d\n", sizeof(dep_tab_t), sizeof(dep_tab));
+       printf("size of memory_trace_ent_t %d sizeof memory_trace %d\n", sizeof(memory_trace_ent_t), sizeof(memory_trace));
+       printf("size of CREATE3args %d\n", sizeof( CREATE3args));
+       printf("size of MKDIR3args %d\n", sizeof( MKDIR3args));
+       printf("size of READ3args %d\n", sizeof( READ3args));
+       printf("size of WRITE3args %d\n", sizeof( WRITE3args));
+       printf("size of RENAME3args %d\n", sizeof( RENAME3args));
+       printf("size of GETATTR3args %d\n", sizeof( GETATTR3args));
+       printf("size of SETATTR3args %d\n", sizeof( SETATTR3args));
+       printf("size of LINK3args %d\n", sizeof( LINK3args));
+       printf("size of SYMLINK3args %d\n", sizeof( SYMLINK3args));
+       printf("size of MKNOD3args %d\n", sizeof( MKNOD3args));
+       printf("size of RMDIR3args %d\n", sizeof( RMDIR3args));
+       printf("size of REMOVE3args %d\n", sizeof( REMOVE3args));
+       printf("size of LOOKUP3args %d\n", sizeof( LOOKUP3args));
+       printf("size of READDIR3args %d\n", sizeof( READDIR3args));
+       printf("size of READDIRPLUS3args %d\n", sizeof( READDIRPLUS3args));
+       printf("size of FSSTAT3args %d\n", sizeof( FSSTAT3args));
+       printf("size of FSINFO3args %d\n", sizeof( FSINFO3args));
+       printf("size of COMMIT3args %d\n", sizeof( COMMIT3args));
+       printf("size of ACCESS3args %d\n", sizeof( ACCESS3args));
+       printf("size of READLINK3args %d\n", sizeof( READLINK3args));
+
+
+}
+
+void recv_thread()
+{
+       int last_print_time = -1;
+       int busy_flag;
+
+       while (send_num ==0) {
+               usleep(1000);
+       }
+
+       //while (!CYCLIC_EMPTY(dep_tab_index)) {
+       while (!exit_flag) {
+               if ((total_profile.in.tv_sec - last_print_time >= 10)) {
+                       static int recv_num_before_10_seconds = 0;
+                       last_print_time = total_profile.in.tv_sec;
+                       fprintf (stdout, "<<<<< recv_thread recv_num %d time %d num_out_reqs %d \n", recv_num, total_profile.in.tv_sec, num_out_reqs);
+                       if (recv_num == recv_num_before_10_seconds) {
+                               no_progress_flag = 1;
+                               RFS_ASSERT (0);
+                       } else 
+                               recv_num_before_10_seconds = recv_num;
+               }
+               //start_profile (&check_timeout_profile);
+               check_timeout();
+               //end_profile (&check_timeout_profile);
+
+               pthread_yield();
+               //usleep(1000);
+               start_profile (&receive_next_reply_profile);
+               /* actually the performance of two policy seems to be same */
+//#define SEND_HIGHER_PRIORITY_POLICY
+#define SEND_RECEIVE_EQUAL_PRIORITY_POLICY     
+#ifdef SEND_HIGHER_PRIORITY_POLICY
+               receive_next_reply(IDLE);
+#endif
+#ifdef SEND_RECEIVE_EQUAL_PRIORITY_POLICY
+               busy_flag = IDLE;
+               while (receive_next_reply(busy_flag)!=-1) {
+                       busy_flag = BUSY;
+               }
+#endif
+               end_profile (&receive_next_reply_profile);
+       }
+       printf ("<<<< recv thread EXIT\n");
+       exit_flag = 2;
+}
+
+int io_thread ()
+{
+/* number of seconds the I/O thread pauses after each time trying to read the requests */
+#define IO_THREAD_PAUSE_TIME 1
+
+       int i;
+       int j = 0;
+
+       disk_io_status = read_trace ();
+       while (disk_io_status == TRACE_BUF_FULL) {
+
+               usleep (10000);
+        if ((j++%1000)==0) {
+                printf("&&&&&&&&&& io thread, sleep %d seconds\n", j/100);
+        }
+
+               disk_io_status = read_trace ();
+               //printf ("io_thread, after read_trace, disk_index %d\n", disk_index);
+
+#ifdef SEQUEN_READ
+               for (i=0; i<SEQUEN_READ_NUM; i++) {
+                       add_to_dep_tab(CYCLIC_MINUS(memory_trace_index.head,1,memory_trace_index.size));
+               }
+#endif
+               //printf ("***************** IO THREAD SLEEP 1 s\n");
+               //print_cyclic_buffers();
+               //pthread_yield();
+       }
+       RFS_ASSERT (disk_io_status == TRACE_FILE_END);
+       printf("io_thread EXIT\n");
+}
+
+int execute_thread()
+{
+       int i;
+       struct timeval playstart_time, playend_time;
+
+       sleep (10);             /* first let io_thread to run for a while */
+       printf ("trace_play\n");
+
+       gettimeofday(&playstart_time, NULL);
+
+       init_time_offset();
+       trace_play ();
+
+       gettimeofday(&playend_time, NULL);
+
+       {
+               int usec, sec;
+               sec = playend_time.tv_sec - playstart_time.tv_sec;
+               usec = sec * 1000000 + (playend_time.tv_usec - playstart_time.tv_usec);
+               sec = usec / 1000000;
+               usec = usec % 1000000;
+               printf("Total play time: %d sec %d usec\n", sec, usec);
+               if (sec > WARMUP_TIME)
+                       print_result();
+               else
+                       printf ("the trace play time %d is less than WARMUP_TIME %d, no statistical results\n");
+       }
+#ifdef RECV_THREAD
+       exit_flag = 1;
+       while (exit_flag == 1) {
+               usleep (1000);
+       }
+#endif
+
+    clnt_destroy(NFS_client);
+    biod_term();
+}
+
+int init_thread ()
+{
+       pthread_attr_t  attr;
+       int arg;
+       int ret = 0;
+       pthread_t io_thread_var;
+#ifdef RECV_THREAD
+       pthread_t recv_thread_var;
+#endif
+       pthread_t execute_thread_var;
+
+       ret = pthread_attr_init (&attr);
+       if (ret!=0) {
+               perror("pthread_attr_init attr");
+               return ret;
+       }
+#ifdef IO_THREAD
+       ret = pthread_create (&(io_thread_var), &attr, &io_thread, (void *)&arg );
+       if (ret!=0) {
+               perror("io_pthread_attr_init");
+               return ret;
+       }
+#endif
+
+#ifdef RECV_THREAD
+       ret = pthread_create (&(recv_thread_var), &attr, &recv_thread, (void *)&arg );
+       if (ret!=0) {
+               perror("recv_pthread_attr_init");
+               return ret;
+       }
+#endif
+
+/*
+       ret = pthread_create (&(execute_thread_var), &attr, &execute_thread, (void *)&arg );
+       if (ret!=0) {
+               perror("io_pthread_attr_init");
+               return ret;
+       }
+*/
+}
+
+void init_buffers()
+{
+       CYCLIC_INIT("memory_trace_index",memory_trace_index,MAX_MEMORY_TRACE_LINES);
+       CYCLIC_INIT("dep_tab_index     ",dep_tab_index,DEP_TAB_SIZE);
+       CYCLIC_INIT("dep_window_index  ",dep_window_index,DEP_TAB_SIZE);
+}
+
+int main(int argc, char ** argv)
+{
+       extern char * optarg;
+       int i;
+       struct timeval in={1000000, 100};
+       
+       init_profile_variables();
+       if ((argc==1) || (argc==2 && !strcmp(argv[1],"-help"))) {
+               print_usage(0, argc, argv);
+               exit(0);
+       }
+       if (!strcmp(argv[1], "-pair_write")) {
+               if (argc==3) 
+                       strcpy(trace_file, argv[2]);
+               else
+                       strcpy(trace_file, "stdin");
+               pair_write(trace_file);
+               exit(0);
+       }
+       if (!strcmp(argv[1], "-pair_trace")) {
+               if (argc==3) 
+                       strcpy(trace_file, argv[2]);
+               else
+                       strcpy(trace_file, "stdin");
+               pair_trace(trace_file);
+               exit(0);
+       }
+       if (!strcmp(argv[1], "-check_aging")) {
+               if (argc!=3) {
+                       print_usage(3, argc, argv);
+                       exit(0);
+               }
+               strcpy(trace_file, argv[2]);
+               check_aging (trace_file);
+               exit(0);
+       }
+       if (!strcmp(argv[1], "-check_statistics")) {
+               if (argc!=3) {
+                       print_usage(1, argc, argv);
+                       exit(0);
+               }
+               strcpy(trace_file, argv[2]);
+               memset(fh_htable, 0, sizeof (fh_htable));
+               check_statistics (trace_file);
+               exit(0);
+       }
+
+       if (argc!=6) {
+               print_usage(2, argc, argv);
+               exit(0);
+       }
+
+       PLAY_SCALE = atoi (argv[4]);
+       RFS_ASSERT (PLAY_SCALE >=1 && PLAY_SCALE <=10000);
+
+       WARMUP_TIME = atoi (argv[5]);
+       RFS_ASSERT (WARMUP_TIME >=0 && WARMUP_TIME <=1000);
+       
+       print_memory_usage();
+       check_clock();
+    getmyhostname(lad_hostname, HOSTNAME_LEN);
+
+    init_ops();
+       /*
+        * Get the uid and gid information.
+        */
+       Real_uid = getuid();
+       Cur_gid = getgid();
+       //Real_uid = 513;
+       //Cur_gid = 513;
+
+       Nfs_timers = Nfs_udp_timers;
+
+       init_semaphores();
+       init_file_system ();
+       init_signal();
+       init_play (argv[1]);
+       //init_play ("capella:/p5/RFSFS");
+       init_fh_map();
+       read_fh_map (argv[3]);
+       //read_fh_map ("fh-path-map-play");
+       strcpy(trace_file, argv[2]);
+
+/* If ordered by TIMESTAMP,
+ * memory_trace_index.tail <= dep_tab_index.tail < dep_window_max <=
+ * dep_tab_index.head <= memory_trace_index.head
+ */
+
+       init_global_variables();
+       init_buffers();
+       init_thread();
+       pthread_yield();
+       execute_thread();
+}
+
+int init_global_variables()
+{
+       memset (num_out_reqs_statistics, 0, sizeof(num_out_reqs_statistics));
+       memset (num_out_reqs_statistics_at_timeout, 0, sizeof(num_out_reqs_statistics_at_timeout));
+}
+
+int init_semaphores()
+{
+       async_rpc_sem = dest_and_init_sem (ASYNC_RPC_SEM_KEY, 1, "async_rpc_sem");
+}
+
+void init_ops (void)
+{
+       Ops = nfsv3_Ops;
+       nfs_version = NFS_V3;
+}
+
+/* Set up the signal handlers for all signals */
+void init_signal()
+{
+#if (defined(_XOPEN_SOURCE) || defined(USE_POSIX_SIGNALS))
+       struct sigaction sig_act, old_sig_act;
+
+       /* use XOPEN signal handling */
+
+       sig_act.sa_handler = generic_catcher;
+       (void)sigemptyset(&sig_act.sa_mask);
+       sig_act.sa_flags = 0;
+
+       /* signals handlers for signals used by sfs */
+       sig_act.sa_handler = sfs_cleanup;
+       if (sigaction(SIGINT,&sig_act,&old_sig_act) == -1) {
+           perror("sigaction failed: SIGINT");
+           exit(135);
+       }
+
+       sig_act.sa_handler = sfs_cleanup;
+       if (sigaction(SIGTERM,&sig_act,&old_sig_act) != 0)  {
+           perror("sigaction failed: SIGTERM");
+           exit(137);
+       }
+#else
+    /* signals handlers for signals used by sfs */
+    (void) signal(SIGINT, sfs_cleanup);
+    // RFS (void) signal(SIGALRM, sfs_alarm);
+       (void) signal(SIGTERM, sfs_cleanup);
+#endif
+}
+
+void
+init_play (
+    char       * mount_point)          /* Mount point for remote FS */
+{
+    char       namebuf[NFS_MAXNAMLEN] = "trace_play";  /* unique name for this program */
+    CLIENT *   mount_client_ptr;       /* Mount client handle */
+
+       if (!rfs_debug);
+       (void) setvbuf(stderr, io_buf, _IOLBF, BUFSIZ);
+
+    sfs_Myname = namebuf;
+
+    /*
+     * May require root priv to perform bindresvport operation
+     */
+    mount_client_ptr = lad_getmnt_hand(mount_point);
+    if (mount_client_ptr == NULL) {
+               exit(145);
+    }
+
+    /*
+     * should be all done doing priv port stuff
+     */
+
+    if (init_rpc() == -1) {
+               (void) fprintf(stderr, "%s: rpc initialization failed\n", sfs_Myname);
+               (void) generic_kill(0, SIGINT);
+               exit(146);
+    }
+
+
+    /*
+     * finish all priv bindresvport calls
+     * reset uid
+     */
+    if (setuid(Real_uid) != (uid_t)0) {
+       (void) fprintf(stderr,"%s: %s%s", sfs_Myname,
+           "cannot perform setuid operation.\n",
+           "Do `make install` as root.\n");
+    }
+
+    init_mount_point(0, mount_point, mount_client_ptr);
+
+
+    /*
+     * Cleanup client handle for mount point
+     */
+    clnt_destroy(mount_client_ptr);
+
+       init_counters();
+}
+
+#ifdef REDUCE_MEMORY_TRACE_SIZE
+void inline format_line (char * line_before, char * line)
+{
+       char * pv = line_before;
+       char * pl = line;
+       char * p;
+       int i;
+       
+       //printf("format_line before %s\n", line_before);
+       p = strstr (pv, "fh");
+       while (p!=NULL) {
+               while (pv<=p)
+                       *pl++ = *pv++;
+               *pl++ = *pv++;
+               if (*pv==2) {
+                       *pl++ = *pv++;
+               }
+               *pl++ = *pv++;
+               i = 0;
+               while (*pv !=' ') {
+                       RFS_ASSERT ((*pv >='0' && *pv <='9') || (*pv >='a' && *pv<='f'));
+                       *pl++ = *pv++;
+                       i++;
+               }
+               RFS_ASSERT ((i==48) || (i==40) || (i==24));
+               while (i<48) {
+                       *pl++ = '0';
+                       i++;
+               }
+               p = strstr (pv, "fh");
+       }
+       while ((*pv)!=NULL) {
+               *pl++ = *pv++;
+       }
+       //printf("format_line after %s\n", line);
+}
+
+char * read_line (int disk_index)
+{
+       static FILE * fp=NULL;
+       static int start=0;
+       static int start_disk_index=0;
+       int i;
+       static int finish_flag = 0;
+       static int varfh_flag = 0;
+#define READ_LINE_BUF_SIZE (MAX_COMMAND_REPLY_DISTANCE_FOR_PAIR+2)
+#define SAFE_BYTES 1000
+#define READ_LINE_LENGTH (MAX_TRACE_LINE_LENGTH+SAFE_BYTES)
+
+       static char line_buf[READ_LINE_BUF_SIZE][READ_LINE_LENGTH];
+       char varfh_line_buf[READ_LINE_LENGTH];
+
+       start_profile (&read_line_profile);
+
+       if (fp==NULL) {
+               if (strcmp(trace_file, "stdin")) {
+                       fp = fopen(trace_file, "r");
+
+                       if (strstr(trace_file, ".varfh")) {
+                               varfh_flag = 1;
+                       };
+                       if (strstr(trace_file, ".fmt1")) {
+                               TRACE_COMMAND_REPLY_FLAG_POS += 12;
+                               TRACE_VERSION_POS +=12;
+                               TRACE_MSGID_POS +=12;
+                               TRACE_FH_SIZE =48;
+                       }
+                       if (!fp) {
+                               printf("can not open files %s\n", fp);
+                               perror("open");
+                       }
+               } else {
+                       fp = stdin;
+               }
+               RFS_ASSERT (fp!=NULL);
+               for (i=0; i<READ_LINE_BUF_SIZE; i++) {
+                       start_profile(&fgets_profile);
+                       if (varfh_flag) {
+                               if (!fgets(varfh_line_buf, READ_LINE_LENGTH, fp)) {
+                                       RFS_ASSERT (0);
+                               }
+                               format_line (varfh_line_buf, line_buf[i]);
+                       } else {
+                               if (!fgets(line_buf[i], READ_LINE_LENGTH, fp)) {
+                                       RFS_ASSERT (0);
+                               }
+                       }
+                       end_profile(&fgets_profile);
+                       //printf ("read_line, line_buf[%d]:%s", i, line_buf[i]);
+               }
+       }
+       
+       if (disk_index > start_disk_index+READ_LINE_BUF_SIZE) {
+               printf ("disk_index %d start_disk_index %d READ_LINE_BUF_SIZE %d\n", 
+                       disk_index, start_disk_index, READ_LINE_BUF_SIZE);
+       }
+       RFS_ASSERT (disk_index <= start_disk_index+READ_LINE_BUF_SIZE)
+       if (disk_index==(start_disk_index+READ_LINE_BUF_SIZE)) {
+               if (finish_flag) {
+                       return NULL;
+               }
+               start_profile(&fgets_profile);
+               if (!fgets(line_buf[start], READ_LINE_LENGTH, fp)) {
+                       end_profile(&fgets_profile);
+                       finish_flag = 1;
+                       return NULL;
+               }
+               end_profile(&fgets_profile);
+               //printf ("read_line, line_buf[%d]:%s", start, line_buf[start]);
+               start = (start+1) % READ_LINE_BUF_SIZE;
+               start_disk_index ++;
+       }
+       RFS_ASSERT (disk_index < start_disk_index+READ_LINE_BUF_SIZE)
+       i = (start+disk_index-start_disk_index)%READ_LINE_BUF_SIZE;
+
+/*
+       if (!(strlen(line_buf[i])>80)) {
+               printf ("start %d start_disk_index %d disk_index %d strlen %d line_buf[%d] %s\n", start, start_disk_index, disk_index, strlen(line_buf[i]), i, line_buf[i]);
+               RFS_ASSERT (strlen(line_buf[i])>80);
+       }
+       if (!((strlen(line_buf[i])>80) && (strlen(line_buf[i])<MAX_TRACE_LINE_LENGTH)))
+               printf ("disk_index %d strlen %d line_buf[%d] %s\n", disk_index, strlen(line_buf[i]), i, line_buf[i]);
+       RFS_ASSERT ((strlen(line_buf[i])>80) && (strlen(line_buf[i])<MAX_TRACE_LINE_LENGTH));
+*/
+
+       end_profile (&read_line_profile);
+       return (line_buf[i]);
+}
+
+#define OPS_FLAG_INC 0
+#define OPS_FLAG_PRINT 1
+int read_write_fh_statistics (int flag, char * buf, int timestamp)
+{
+       static FILE * fp = NULL;
+       char * p;
+       char c;
+       if (!fp) {
+               fp = fopen ("read_write_fh.output", "w");
+               RFS_ASSERT (fp);
+       }
+       if (flag == OPS_FLAG_INC) {
+               p = strstr (buf, "fh");
+               RFS_ASSERT (p);
+               c = p[40+3];
+               p[40+3]=0;
+               fprintf(fp, "%s\n", p+3+24);
+               p[40+3]=c;
+       };
+       if (flag == OPS_FLAG_PRINT) { 
+               int disk_index = (int) buf;
+               fprintf(fp, "###### disk_index %d timestamp %d\n", disk_index, timestamp);
+       }
+}
+
+int write_statistics(int flag, char * buf, char * reply_buf, int trace_status)
+{
+       static FILE * fp = NULL;
+       int pre_size, size, count;
+       char * p = reply_buf;
+       if (!fp) {
+               fp = fopen ("write.output", "w");
+               RFS_ASSERT (fp);
+       }
+       if (flag == OPS_FLAG_INC) {
+               p = strstr (p, "pre-size");
+               RFS_ASSERT (p);
+               sscanf (p, "pre-size %x", &pre_size); 
+               p += strlen("pre-size");
+               p = strstr (p, "size");
+               RFS_ASSERT (p);
+               sscanf (p, "size %x", &size); 
+               p = strstr (p, "count");
+               if (!p) 
+                       fprintf (fp, "%s status %x pre-size %x size %x count %x\n", buf, trace_status, pre_size, size, count);
+               RFS_ASSERT (p);
+               sscanf (p, "count %x", &count); 
+               fprintf (fp, "%s status %x pre-size %x size %x count %x\n", buf, trace_status, pre_size, size, count);
+       }
+       if (flag == OPS_FLAG_PRINT) {
+               int disk_index = (int) buf;
+               int timestamp = (int) reply_buf;
+               fprintf(fp, "###### disk_index %d timestamp %d\n", disk_index, timestamp);
+       }
+}
+
+void ops_statistics (int ops_flag, int proc, int timestamp)
+{
+       static FILE * fp = NULL;
+       static struct {
+               int count;
+               int count_K;
+               int update_flag;
+               char name[32];
+       } ops[NOPS]={{0, 0, 0, "NULL"},{0, 0, 0, "GETATTR"},{0, 0, 1, "SETATTR"},{0, 0, 0, "ROOT"},
+                                 {0, 0, 0, "LOOKUP"},{0, 0, 0, "READLINK"},{0, 0, 0, "READ"},{0, 0, 1, "WRCACHE"},
+                                 {0, 0, 1, "WRITE"}, {0, 0, 1, "CREATE"},{0, 0, 1, "REMOVE"},{0, 0, 1, "RENAME"},
+                                 {0, 0, 1, "LINK"}, {0, 0, 1, "SYMLINK"},{0, 0, 1, "MKDIR"},{0, 0, 1, "RMDIR"},
+                                 {0, 0, 0, "READDIR"},{0, 0, 0, "FSSTAT"},{0, 0, 0, "ACCESS"},{0, 0, 0, "COMMIT"},
+                                 {0, 0, 0, "FSINFO"},{0, 0, 1, "MKNOD"}, {0, 0, 0, "PATHCONF"}, {0, 0, 0, "READDIRPLUS"}};
+
+       if (ops_flag == OPS_FLAG_INC) {
+               RFS_ASSERT (proc>=0 && proc<NOPS);
+               ops[proc].count ++;
+               if (ops[proc].count == 1000) {
+                       ops[proc].count_K ++;
+                       ops[proc].count = 0;
+               }
+       }
+       if (ops_flag == OPS_FLAG_PRINT) {
+               int i;
+               int update_K=0, update=0, total_K=0, total=0;
+               float f1, f2;
+               int disk_index = proc;
+
+               if (!fp) {
+                       fp = fopen ("mix.output", "w");
+                       RFS_ASSERT (fp);
+               }
+               for (i=0; i<NOPS; i++) {
+                       total_K += ops[i].count_K;
+                       total += ops[i].count;
+                       if (ops[i].update_flag) {
+                               update_K += ops[i].count_K;
+                               update += ops[i].count;
+                       }
+               }
+               update_K += update/1000;
+               update = update%1000;
+               total_K += total/1000;
+               total = total%1000;
+
+               f1 = total_K;
+               f1 = f1*1000+total;
+               for (i=0; i<NOPS; i++) {
+                       f2 = ops[i].count_K;
+                       f2 = f2*1000+ops[i].count;
+                       fprintf (fp, "%12s %8d,%03d %3.2f\%\n", ops[i].name, ops[i].count_K, ops[i].count, f2*100/f1);  
+                       fprintf (stderr, "%12s %8d,%03d %3.2f\%\n", ops[i].name, ops[i].count_K, ops[i].count, f2*100/f1);      
+               }
+               f2 = update_K;
+               f2 = f2*1000+update;
+               fprintf (fp, "       total %8d,%03d\n", total_K, total);
+               fprintf (stderr, "       total %8d,%03d\n", total_K, total);
+               fprintf (fp, "      update %8d,%03d %2.2f\%\n", update_K, update, f2*100/f1);   
+               fprintf (stderr, "      update %8d,%03d %2.2f\%\n", update_K, update, f2*100/f1);       
+               fprintf(fp, "###### disk_index %d timestamp %d\n", disk_index, timestamp);
+               fprintf(stderr, "###### disk_index %d timestamp %d\n", disk_index, timestamp);
+       }
+}
+
+
+void truncate_statistics (int flag, int proc, char * buf, char * reply_buf) 
+{
+#define TRACE_FH_SIZE2 16
+#define BLOCK_SIZE 4096
+       static int no_size_num = 0;
+       static int have_size_num = 0;
+       static int equal_size_num = 0;
+       static int first_size_num = 0;
+       static int truncate_num = 0;
+       static int truncate_size = 0;
+       static int truncate_KB = 0;
+       static int truncate_block_num = 0;
+       static int padding_num = 0;
+       static int padding_KB = 0;
+       static int padding_size = 0;
+       static FILE * fp = NULL;
+       char * p;
+       char * trace_fh;
+       int pre_size, size, count;
+       struct generic_entry * ent;
+
+       if (flag == OPS_FLAG_PRINT) {
+               int disk_index = proc;
+               int timestamp = (int)buf;
+               if (!fp) {
+                       fp = fopen ("truncate.output", "w");
+                       RFS_ASSERT (fp);
+               }
+               truncate_KB += truncate_size/1000;
+               truncate_size %= 1000;
+               padding_KB += padding_size/1000;
+               padding_size %= 1000;
+               fprintf(fp, "###### disk_index %d timestamp %d no_size_req %d have_size_req %d equal_size_req %d trunc_req %d trunc_KB %d trunc_block_num %d padding_num %d padding_KB %d\n", disk_index, timestamp, no_size_num, have_size_num, equal_size_num, truncate_num, truncate_KB, truncate_block_num, padding_num, padding_KB);
+               fprintf(stderr, "###### disk_index %d timestamp %d no_size_req %d have_size_req %d equal_size_req %d trunc_req %d trunc_KB %d trunc_block_num %d padding_num %d padding_KB %d\n", disk_index, timestamp, no_size_num, have_size_num, equal_size_num, truncate_num, truncate_KB, truncate_block_num, padding_num, padding_KB);
+               return;
+       }
+
+       p = strstr (&buf[TRACE_MSGID_POS], "fh");
+       RFS_ASSERT (p);
+       p+=3; 
+       trace_fh = p;
+               
+       if (proc==SETATTR) {
+               p = strstr (buf, " size ");
+       } else {
+               RFS_ASSERT (proc==WRITE);
+               p = strstr (reply_buf, " ftype 1 ");
+               RFS_ASSERT (p);
+               p = strstr (p, " size ");
+               RFS_ASSERT (p);
+               if (strstr(p, " ftype 1 ")) {
+                       fprintf (fp, "#### %s%s\n", buf, reply_buf);
+                       fprintf (stderr, "#### %s%s\n", buf, reply_buf);
+               }
+               RFS_ASSERT (!strstr(p, " ftype 1 "));
+       }
+       if (!p) {
+               no_size_num ++;
+               return;
+       }
+       have_size_num ++;
+
+       sscanf (p, " size %x", &size); 
+       if (size <0 || size > 2000000000) {
+               fprintf (fp, "#### size too big %x %s %s\n", size, buf, reply_buf);
+               fprintf (stderr, "#### size too big %x %s %s\n", size, buf, reply_buf);
+       }
+                                                       
+       RFS_ASSERT (size >=0 && size <2000000000);              
+       ent = generic_lookup (trace_fh+24, TRACE_FH_SIZE2, 0, fh_htable, FH_HTABLE_SIZE);
+       if (ent) {
+               if (ent->key3 != size) {
+                       if (proc==SETATTR) {
+                               //printf ("%s\n", buf);
+                               //printf ("size change fh %s pre-size %x size %x\n", trace_fh, ent->key3, size);
+                               if (ent->key3 > size) {
+                                       truncate_num ++;
+                                       truncate_size += ent->key3 - size;
+                                       truncate_block_num += (ent->key3+BLOCK_SIZE-1)/BLOCK_SIZE;
+                                       if (size!=0) {
+                                               //fprintf (stderr, "truncate: pre_size %x size %x %s\n", ent->key3, size, buf);
+                                               //fprintf (fp, "truncate: pre_size %x size %x %s\n", ent->key3, size, buf);
+                                               truncate_block_num -= (size + BLOCK_SIZE-1)/BLOCK_SIZE;
+                                       }
+                                       if (truncate_size > 1000000000) {
+                                               truncate_KB += truncate_size/1000;
+                                               truncate_size %= 1000;
+                                       }
+                               } else {
+                                       padding_num ++; 
+                                       //printf ("%s\n", buf);
+                                       //printf ("padding fh %s pre-size %x size %x\n", trace_fh, ent->key3, size);
+                                       padding_size += size - ent->key3;
+                                       if (padding_size > 1000000000) {
+                                               padding_KB += padding_size/1000;
+                                               padding_size %= 1000;
+                                       }
+                               }
+                       }
+                       ent->key3 = size; 
+               }else 
+                       equal_size_num++;
+       } else {
+               generic_insert(trace_fh+24, TRACE_FH_SIZE2, size, fh_htable, FH_HTABLE_SIZE);
+               first_size_num ++;
+       }
+};
+
+int get_timestamp_usec (char * buf)
+{
+       char str[128];
+       int ret;
+       strncpy(str, buf, 100);
+       RFS_ASSERT (str[10]=='.');
+       RFS_ASSERT (str[17]==' ');
+       str[17]=0;
+       ret = atoi(&str[11]);
+       RFS_ASSERT (ret >=0 && ret <=999999);
+       return ret;
+}
+
+int get_timestamp_sec (char * buf)
+{
+       char str[128];
+       int ret;
+       strncpy(str, buf, 100);
+       RFS_ASSERT (str[10]=='.');
+       str[10]=0;
+       ret = atoi(str);
+       RFS_ASSERT (ret >1000000000 && ret <2000000000);
+       return ret;
+}
+
+int check_aging (char * tracefile)
+{
+       int disk_index=-1;
+       char *buf; 
+       char *reply_buf;
+       int i;
+       int trace_status;
+       int debug = 0;
+       int nfs3proc, msgid, proc;
+
+       while ((buf=read_line(++disk_index))!=NULL) {
+               if (buf[TRACE_COMMAND_REPLY_FLAG_POS]!='C') 
+                       continue;
+               if (buf[TRACE_VERSION_POS]!='3') 
+                       continue;
+               sscanf (&buf[TRACE_MSGID_POS], "%x %x", &msgid, &nfs3proc);
+               
+               RFS_ASSERT (nfs3proc>=0 && nfs3proc<NFS3_PROCEDURE_COUNT);
+               
+               proc = nfs3proc_to_rfsproc[nfs3proc];
+               ops_statistics (OPS_FLAG_INC, proc, -1);
+               
+               switch (proc) {
+               int off, count, size;
+               char * t;
+               case CREATE: printf("%s\n", "create"); break;
+               case MKDIR: printf("%s\n", "mkdir"); break;
+               case REMOVE: printf("%s\n", "remove"); break;
+               case RMDIR: printf("%s\n", "rmdir"); break;
+               case WRITE: 
+                       t = buf;
+                       t = strstr (t, "off");
+               RFS_ASSERT (t);
+                   t+=4;
+                       sscanf (t, "%x", &off);
+                       RFS_ASSERT (off>=0 && off<0x7FFFFFFF)
+                       t = strstr (t, "count");
+                   RFS_ASSERT (t);
+                       t+=6;
+                       sscanf (t, "%x", &count);
+                       RFS_ASSERT (count <= 32768);
+                       printf("%s off %x count %x\n", "write", off, count); 
+                       //printf("%s count %x\n", "write", count); 
+                       break;
+               case SETATTR: 
+                       t = strstr (buf, " size ");
+                       if (t) {
+                               sscanf (t, " size %x", &size);
+                               printf ("%s size %x\n", "setattr", size);
+                       }
+               }
+               if ((disk_index%10000)==0) {
+                       fprintf(stderr, "%d disk trace passed\n", disk_index);
+               }
+       };
+
+       fprintf(stderr, "%d disk trace parsed\n", disk_index);
+       ops_statistics (OPS_FLAG_PRINT, disk_index, -1);
+}
+
+
+int check_statistics (char * tracefile)
+{
+       int disk_index=-1;
+       char *buf; 
+       char *reply_buf;
+       int i;
+       char * p;
+       int trace_status;
+       int debug = 0;
+       int nfs3proc, msgid, proc;
+       static int last_timestamp_sec = -1;
+       int timestamp_sec;
+       int memory_trace_size = 0;
+
+       while ((buf=read_line(++disk_index))!=NULL) {
+               if (buf[TRACE_COMMAND_REPLY_FLAG_POS]!='C') 
+                       continue;
+               if (buf[TRACE_VERSION_POS]!='3') 
+                       continue;
+               sscanf (&buf[TRACE_MSGID_POS], "%x %x", &msgid, &nfs3proc);
+               
+               RFS_ASSERT (nfs3proc>=0 && nfs3proc<NFS3_PROCEDURE_COUNT);
+               timestamp_sec = get_timestamp_sec(buf);
+               
+               proc = nfs3proc_to_rfsproc[nfs3proc];
+               ops_statistics (OPS_FLAG_INC, proc, -1);
+               
+               if (proc!= WRITE && proc!=SETATTR && proc!=READ) {
+                       continue;
+               }
+               RFS_ASSERT (buf[strlen(buf)-1]=='\n');
+               buf [strlen(buf)-1] = 0;
+               if (!((strlen(buf)>80) && (strlen(buf)<MAX_TRACE_LINE_LENGTH)))
+                       printf("disk_index %d strlen(buf) %d buf %s \n", disk_index, strlen(buf), buf);
+               RFS_ASSERT ((strlen(buf)>80) && (strlen(buf)<MAX_TRACE_LINE_LENGTH));
+               if (debug)
+                       printf("read line disk_index %d %s\n", disk_index, buf);
+
+               trace_status = NFS3ERR_RFS_MISS;
+               for (i=disk_index+1; i<disk_index+MAX_COMMAND_REPLY_DISTANCE; i++) {
+                       reply_buf = read_line(i);
+                       if (debug)
+                               printf("searching for reply: read line %s\n", reply_buf);
+                       if (!reply_buf)
+                               break;
+                       if (reply_buf[TRACE_COMMAND_REPLY_FLAG_POS]=='R') {
+                       p = strchr (&reply_buf[TRACE_MSGID_POS], ' ');
+                       RFS_ASSERT (p);
+                       if (!strncmp(&reply_buf[TRACE_MSGID_POS], &buf[TRACE_MSGID_POS], p-&(reply_buf[TRACE_MSGID_POS]))) {
+                       trace_status = find_reply_status(reply_buf);
+                                       if (trace_status == NFS3_OK) {
+                                               if (proc==READ || proc==WRITE) 
+                                                       read_write_fh_statistics (OPS_FLAG_INC, buf, 0);
+                                               if (proc == WRITE)
+                                                       write_statistics (OPS_FLAG_INC, buf, reply_buf, trace_status);
+                                               if (proc==WRITE || proc==SETATTR) 
+                                                       truncate_statistics (OPS_FLAG_INC, proc, buf, reply_buf);
+                                       }
+                               };
+               }
+               }
+               //if (memory_trace[memory_trace_size].trace_status == NFS3ERR_RFS_MISS)
+               if (trace_status == NFS3ERR_RFS_MISS) {
+                       //printf ("%s no reply\n", buf);
+                       missing_reply_num ++;
+               }
+
+#if    0       /* commented out by G. Jason Peng */
+               if *
+               if ((missing_reply_num > memory_trace_size/10) && (missing_reply_num > 100)) {
+                       printf ("missing_reply_num %d too high for memory_trace_size %d\n", missing_reply_num, memory_trace_size);
+                       exit (0);
+               }
+#endif
+
+               memory_trace_size ++;
+
+               if (last_timestamp_sec == -1) {
+                       last_timestamp_sec = timestamp_sec;
+               } else if (timestamp_sec - last_timestamp_sec >=3600) {
+                       ops_statistics (OPS_FLAG_PRINT, disk_index, timestamp_sec);
+                       truncate_statistics (OPS_FLAG_PRINT, disk_index, (char *)timestamp_sec, NULL);
+                       read_write_fh_statistics(OPS_FLAG_PRINT, (char *)disk_index, timestamp_sec);
+                       write_statistics(OPS_FLAG_PRINT, (char *)disk_index, (char *)timestamp_sec, -1);
+                       last_timestamp_sec = timestamp_sec;
+               }
+/*
+               if ((memory_trace_size%10000)==0) {
+                       fprintf(stderr, "%d disk trace parsed, missing_reply %d\n", disk_index, missing_reply_num);
+                       ops_statistics (OPS_FLAG_PRINT, -1);
+                       truncate_statistics (OPS_FLAG_PRINT, -1, NULL, NULL);
+               }
+*/
+       };
+
+       fprintf(stderr, "%d disk trace parsed, missing_reply %d\n", disk_index, missing_reply_num);
+       ops_statistics (OPS_FLAG_PRINT, disk_index, timestamp_sec);
+       truncate_statistics (OPS_FLAG_PRINT, disk_index, (char *)timestamp_sec, NULL);
+       read_write_fh_statistics(OPS_FLAG_PRINT, (char *)disk_index, timestamp_sec);
+       write_statistics(OPS_FLAG_PRINT, (char *)disk_index, (char *)timestamp_sec, -1);
+}
+
+
+/* This routine output all the requests, together with their replies */
+int pair_trace (char * tracefile)
+{
+       int disk_index=-1;
+       char *buf; 
+       char *reply_buf;
+       int i;
+       char * p;
+       int trace_status;
+       int debug = 0;
+       int nfs3proc, msgid;
+       int ops[NFS3_PROCEDURE_COUNT]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
+       int memory_trace_size = 0;
+       FILE * outputfp;
+       char output_file[1024];
+
+       strcpy (output_file, tracefile);
+       strcat (output_file, ".pair");
+       outputfp = fopen (output_file, "w");
+       RFS_ASSERT (outputfp);
+
+       while ((buf=read_line(++disk_index))!=NULL) {
+               if (disk_index == 258)
+                       f();
+               if (buf[TRACE_COMMAND_REPLY_FLAG_POS]!='C') 
+                       continue;
+               if (buf[TRACE_VERSION_POS]!='3') 
+                       continue;
+               sscanf (&buf[TRACE_MSGID_POS], "%x %x", &msgid, &nfs3proc);
+               
+               RFS_ASSERT (nfs3proc>=0 && nfs3proc<NFS3_PROCEDURE_COUNT);
+               ops[nfs3proc]++;
+
+               buf [strlen(buf)-1] = 0;
+               if (!((strlen(buf)>80) && (strlen(buf)<MAX_TRACE_LINE_LENGTH)))
+                       printf("disk_index %d strlen(buf) %d buf %s \n", disk_index, strlen(buf), buf);
+               RFS_ASSERT ((strlen(buf)>80) && (strlen(buf)<MAX_TRACE_LINE_LENGTH));
+               if (debug)
+                       printf("read line disk_index %d %s\n", disk_index, buf);
+               fprintf (outputfp, "%s\n", buf);
+
+               trace_status = NFS3ERR_RFS_MISS;
+               for (i=disk_index+1; i<disk_index+MAX_COMMAND_REPLY_DISTANCE_FOR_PAIR; i++) {
+                       reply_buf = read_line(i);
+                       if (debug)
+                               printf("searching for reply: read line %s\n", reply_buf);
+                       if (!reply_buf)
+                               break;
+                       if (reply_buf[TRACE_COMMAND_REPLY_FLAG_POS]=='R') {
+                       p = strchr (&reply_buf[TRACE_MSGID_POS], ' ');
+                       RFS_ASSERT (p);
+                       if (!strncmp(&reply_buf[TRACE_MSGID_POS], &buf[TRACE_MSGID_POS], p-&(reply_buf[TRACE_MSGID_POS]))) {
+                                       fprintf(outputfp, "%s", reply_buf);
+                                       trace_status = find_reply_status(reply_buf);
+                                       if (debug)
+                                               fprintf(stderr, "reply found trace_status %d\n", find_reply_status(reply_buf));
+                                       break;
+                               };
+               }
+               }
+
+               if (trace_status == NFS3ERR_RFS_MISS) {
+                       fprintf (stderr, "%s no reply\n", buf);
+                       fprintf(outputfp, "missing_reply\n");
+                       missing_reply_num ++;
+               }
+
+               if (missing_reply_num > memory_trace_size/10 && missing_reply_num >100) {
+                       fprintf (stderr, "missing_reply_num %d too high for memory_trace_size %d\n", missing_reply_num, memory_trace_size);
+                       exit (0);
+               }
+
+               memory_trace_size ++;
+
+               if ((memory_trace_size%10000)==0)
+                       fprintf(stderr, "total %d disk lines %d memory lines missing_reply_num %d\n", disk_index, memory_trace_size, missing_reply_num );
+       };
+
+       fprintf(stderr, "total %d disk lines %d memory lines missing_reply_num %d\n", disk_index, memory_trace_size, missing_reply_num );
+    //fprintf (stderr, "init_dep_tab, req_num_with_init_fh %d req_num_with_new_fh %d discard %d\n", req_num_with_init_fh, req_num_with_new_fh, req_num_with_discard_fh);
+
+}
+/* This routine output all the write requests, together with their replies. It is used for
+ * analysis of write requests: appended bytes, overwrite bytes etc
+ */
+int pair_write (char * tracefile)
+{
+       int disk_index=-1;
+       char *buf; 
+       char *reply_buf;
+       int i;
+       char * p;
+       int trace_status;
+       int pair_write_debug = 0;
+       int nfs3proc, msgid;
+       int ops[NFS3_PROCEDURE_COUNT]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
+       int memory_trace_size = 0;
+
+       while ((buf=read_line(++disk_index))!=NULL) {
+               if (buf[TRACE_COMMAND_REPLY_FLAG_POS]!='C') 
+                       continue;
+               if (buf[TRACE_VERSION_POS]!='3') 
+                       continue;
+               sscanf (&buf[TRACE_MSGID_POS], "%x %x", &msgid, &nfs3proc);
+               
+               RFS_ASSERT (nfs3proc>=0 && nfs3proc<NFS3_PROCEDURE_COUNT);
+               ops[nfs3proc]++;
+
+               if (!strstr(buf, "write")) 
+                       continue;
+
+               buf [strlen(buf)-1] = 0;
+               if (!((strlen(buf)>80) && (strlen(buf)<MAX_TRACE_LINE_LENGTH)))
+                       printf("disk_index %d strlen(buf) %d buf %s \n", disk_index, strlen(buf), buf);
+               RFS_ASSERT ((strlen(buf)>80) && (strlen(buf)<MAX_TRACE_LINE_LENGTH));
+               if (pair_write_debug)
+                       printf("read line disk_index %d %s\n", disk_index, buf);
+
+               /* store the request to memory */
+               //strcpy (memory_trace[memory_trace_size].line, buf);
+               //memory_trace[memory_trace_size].disk_index = disk_index;
+
+               /* find and store the reply status and reply fhandle to memory */
+               //memory_trace[memory_trace_size].trace_status = NFS3ERR_RFS_MISS;
+               trace_status = NFS3ERR_RFS_MISS;
+               for (i=disk_index+1; i<disk_index+MAX_COMMAND_REPLY_DISTANCE_FOR_PAIR; i++) {
+                       reply_buf = read_line(i);
+                       if (pair_write_debug)
+                               printf("searching for reply: read line %s\n", reply_buf);
+                       if (!reply_buf)
+                               break;
+                       if (reply_buf[TRACE_COMMAND_REPLY_FLAG_POS]=='R') {
+                       p = strchr (&reply_buf[TRACE_MSGID_POS], ' ');
+                       RFS_ASSERT (p);
+                       if (!strncmp(&reply_buf[TRACE_MSGID_POS], &buf[TRACE_MSGID_POS], p-&(reply_buf[TRACE_MSGID_POS]))) {
+                                       int pre_size, size, count;
+                               //memory_trace[memory_trace_size].trace_status = find_reply_status(reply_buf);
+                                       if (pair_write_debug)
+                                               printf("reply found trace_status %d\n", find_reply_status(reply_buf));
+                                               //break;
+                       trace_status = find_reply_status(reply_buf);
+                                       if (trace_status == NFS3_OK) {
+                                               p = strstr (p, "pre-size");
+                                               RFS_ASSERT (p);
+                                               sscanf (p, "pre-size %x", &pre_size); 
+                                               p += strlen("pre-size");
+                                               p = strstr (p, "size");
+                                               RFS_ASSERT (p);
+                                               sscanf (p, "size %x", &size); 
+                                               p = strstr (p, "count");
+                                               if (!p) 
+                                                       printf ("%s status %x pre-size %x size %x count %x\n", buf, trace_status, pre_size, size, count);
+                                               RFS_ASSERT (p);
+                                               sscanf (p, "count %x", &count); 
+                                               printf ("%s status %x pre-size %x size %x count %x\n", buf, trace_status, pre_size, size, count);
+                                               break;
+                                       }
+                               };
+               }
+               }
+               //if (memory_trace[memory_trace_size].trace_status == NFS3ERR_RFS_MISS)
+               if (trace_status == NFS3ERR_RFS_MISS) {
+                       printf ("%s no reply\n", buf);
+                       missing_reply_num ++;
+               }
+
+#if    0       /* commented out by G. Jason Peng */
+               if (missing_reply_num > memory_trace_size/10) {
+                       printf ("missing_reply_num %d too high for memory_trace_size %d\n", missing_reply_num, memory_trace_size);
+                       exit (0);
+               }
+#endif
+
+               memory_trace_size ++;
+
+               /*
+               if (memory_trace_size >= MAX_MEMORY_TRACE_LINES) {
+                       fprintf (stderr, "memory trace size %d is not enough\n", MAX_MEMORY_TRACE_LINES);
+                       break;
+               }
+               */
+               if ((memory_trace_size%10000)==0)
+                       fprintf(stderr, "total %d disk lines %d memory lines missing_reply_num %d\n", disk_index, memory_trace_size, missing_reply_num );
+       };
+
+       fprintf(stderr, "total %d disk lines %d memory lines missing_reply_num %d\n", disk_index, memory_trace_size, missing_reply_num );
+    //fprintf (stderr, "init_dep_tab, req_num_with_init_fh %d req_num_with_new_fh %d discard %d\n", req_num_with_init_fh, req_num_with_new_fh, req_num_with_discard_fh);
+
+}
+
+#ifdef notdef
+/* This function is not finished writing */
+int calculate_performance()
+{
+       char *buf; 
+       char *reply_buf;
+       int i;
+       char * p;
+       int debug = 0;
+
+typedef struct {
+       struct timeval start;
+       struct timeval stop;
+       int trace_status;
+       int op;
+} trace_performance_ent_t;
+
+       struct timeval req_time;
+       struct timeval reply_time;
+
+       trace_performance_ent_t * ent = NULL;
+
+       while (!CYCLIC_FULL(memory_trace_index)) {
+
+               if (ent!=NULL && (ent->trace_status == NFS3ERR_RFS_MISS))
+                       buf = reply_buf;
+               if ((buf=read_line(++disk_index))==NULL) {
+END:           fprintf(stderr, "total %d disk lines %d memory lines missing_reply_num %d\n", disk_index, CYCLIC_NUM(memory_trace_index), missing_reply_num );
+               fprintf (stderr, "init_dep_tab, req_num_with_init_fh %d req_num_with_new_fh %d discard %d\n", req_num_with_init_fh, req_num_with_new_fh, req_num_with_discard_fh);
+                       end_profile (&read_trace_profile);
+                       return TRACE_FILE_END;
+               }
+
+               get_timestamp (&ent->req_time, buf);
+               if (MAX_COMMAND_REPLY_DISTANCE ==1) {
+                       ent->trace_status == NFS3ERR_RFS_MISS;
+               } else {
+                       reply_buf=read_line(++disk_index);
+                       RFS_ASSERT (reply_buf);
+                       if (!strcmp(reply_buf, "missing_reply\n")) {
+                               ent->trace_status == NFS3ERR_RFS_MISS;
+                       } else {
+                               get_timestamp (&ent->reply_time, buf);
+                               ent->trace_status = find_reply_status(reply_buf);
+                       }
+               }
+       }
+}
+#endif
+
+int read_trace ()
+{
+       char *buf; 
+       char *reply_buf;
+       int i;
+       char * p;
+       int debug = 0;
+       memory_trace_ent_t * ent=NULL;
+
+       start_profile (&read_trace_profile);
+
+       while (!CYCLIC_FULL(memory_trace_index)) {
+               if (ent!=NULL && (ent->trace_status == NFS3ERR_RFS_MISS))
+                       buf = reply_buf;
+               if ((buf=read_line(++disk_index))==NULL) {
+END:           fprintf(stderr, "total %d disk lines %d memory lines missing_reply_num %d\n", disk_index, CYCLIC_NUM(memory_trace_index), missing_reply_num );
+               fprintf (stderr, "init_dep_tab, req_num_with_init_fh %d req_num_with_new_fh %d discard %d\n", req_num_with_init_fh, req_num_with_new_fh, req_num_with_discard_fh);
+                       end_profile (&read_trace_profile);
+                       return TRACE_FILE_END;
+               }
+       
+               if (rfs_debug)
+                       printf ("disk_index %d %s\n", disk_index, buf);
+
+               if (disk_index==0) {
+                       trace_timestamp1 = get_timestamp_sec (buf);
+                       trace_starttime.sec = get_timestamp_sec (buf);
+                       trace_starttime.usec = get_timestamp_usec (buf);
+                       trace_starttime.esec = 0;
+                       printf ("trace starttime %d %d %d\n", trace_starttime.sec, trace_starttime.usec, trace_starttime.esec);
+               } else
+                       trace_timestamp2 = get_timestamp_sec (buf);
+
+               /* store the request to memory */
+               ent = &(memory_trace[memory_trace_index.head]);
+               strcpy (ent->line, buf);
+               ent->disk_index = disk_index;
+
+               if (MAX_COMMAND_REPLY_DISTANCE ==1) {
+                       ent->trace_status == NFS3ERR_RFS_MISS;
+               } else {
+                       reply_buf=read_line(++disk_index);
+                       RFS_ASSERT (reply_buf);
+                       if (!strcmp(reply_buf, "missing_reply\n")) {
+                               ent->trace_status == NFS3ERR_RFS_MISS;
+                       } else {
+                               ent->trace_status = find_reply_status(reply_buf);
+                       }
+               };
+
+               if (ent->trace_status == NFS3ERR_RFS_MISS)
+                       missing_reply_num ++;
+
+               if (MAX_COMMAND_REPLY_DISTANCE > 1) {
+                       if ((missing_reply_num > disk_index/5) && (missing_reply_num > 100)) {
+                               printf ("missing_reply_num %d too high for disk_index %d\n", missing_reply_num, disk_index);
+                               exit (0);
+                       }
+               }
+
+               /* find and store the reply trace fhandle for create-class requests */
+               if (ent->trace_status==NFS3_OK) {
+                       if (strstr(buf, "create") || strstr(buf, "mkdir") 
+                               || (strstr(buf, "symlink") && (buf[TRACE_VERSION_POS]!='2')) 
+                               || strstr(buf, "mknod") ) {
+                               p = find_reply_trace_fh(reply_buf);
+                               if (p==NULL) {
+                                       printf("skip line disk_index %d %s \n", disk_index, buf);
+                                       continue;
+                               }
+                               memcpy(ent->reply_trace_fh, p, TRACE_FH_SIZE);
+                       } else
+                               memset(ent->reply_trace_fh, 0, TRACE_FH_SIZE);
+               }
+
+               add_to_dep_tab(memory_trace_index.head);
+
+               if (((disk_index+1)%20000)==0) {
+                       fprintf(stderr, "%d disk trace parsed \n", disk_index+1);
+               };
+       };
+
+       end_profile (&read_trace_profile);
+       return TRACE_BUF_FULL;
+}
+#else  /* not defined REDUCE_MEMORY_TRACE_SIZE */
+int read_trace ()
+{
+       FILE * fp;
+       char buf[1024];
+       // char * t=buf;        
+       int disk_index=0;
+
+       fp = fopen(trace_file, "r");
+       RFS_ASSERT (fp!=NULL);
+       while (fgets(buf, MAX_TRACE_LINE_LENGTH, fp)) {
+               if (!((strlen(buf)>80) && (strlen(buf)<MAX_TRACE_LINE_LENGTH)))
+                       printf("strlen(buf) %d buf %s \n", strlen(buf), buf);
+               RFS_ASSERT ((strlen(buf)>80) && (strlen(buf)<MAX_TRACE_LINE_LENGTH));
+
+               /* store the request to memory */
+               strcpy (memory_trace[memory_trace_size].line, buf);
+               memory_trace[memory_trace_size].disk_index = disk_index;
+               memory_trace_size ++;
+
+               if (memory_trace_size >= MAX_MEMORY_TRACE_LINES) {
+                       fprintf (stderr, "memory trace size %d is not enough\n", MAX_MEMORY_TRACE_LINES);
+                       break;
+               }
+               if ((disk_index%100000)==0)
+                       fprintf(stderr, "%d disk trace parsed, store %d trace lines to memory\n", disk_index, memory_trace_size);
+               disk_index ++;
+       }
+
+       fprintf(stderr, "total %d disk lines %d memory lines \n", disk_index, memory_trace_size );
+}
+#endif
+
+
+#ifdef REDUCE_MEMORY_TRACE_SIZE
+inline int disk_index_to_memory_index (int disk_index)
+{
+       static int memory_index = 0;
+
+       RFS_ASSERT (!CYCLIC_EMPTY(memory_trace_index));
+       RFS_ASSERT (memory_trace[memory_trace_index.tail].disk_index <= disk_index);
+       RFS_ASSERT (memory_trace[CYCLIC_MINUS(memory_trace_index.head,1,memory_trace_index.size)].disk_index >=disk_index);
+       if (disk_index > memory_trace[memory_index].disk_index) {
+               while (memory_trace[memory_index].disk_index < disk_index) {
+                       memory_index = CYCLIC_ADD(memory_index,1,memory_trace_index.size);
+               }
+       };
+       if (disk_index < memory_trace[memory_index].disk_index) {
+               while (memory_trace[memory_index].disk_index > disk_index) {
+                       memory_index = CYCLIC_MINUS(memory_index,1,memory_trace_index.size);
+               }
+       };
+
+       RFS_ASSERT (disk_index == memory_trace[memory_index].disk_index);
+       return memory_index;
+}
+#else
+#define disk_index_to_memory_index(disk_index) disk_index
+#endif
+
+#define get_line_by_disk_index(disk_index) \
+       memory_trace[disk_index_to_memory_index(disk_index)].line
+
+inline char * find_reply_line (char * command_line, int cur_disk_index)
+{
+       int i;
+       char * line;
+       char * p;
+       int request_memory_index = disk_index_to_memory_index (cur_disk_index);
+       for (i=request_memory_index+1; i<request_memory_index+MAX_COMMAND_REPLY_DISTANCE && i<MAX_MEMORY_TRACE_LINES; i++) {
+               line = memory_trace[i].line;
+               if (line[TRACE_COMMAND_REPLY_FLAG_POS]=='R') {
+               p = strchr (&line[TRACE_MSGID_POS], ' ');
+           RFS_ASSERT (p);
+                       if (!strncmp(&line[TRACE_MSGID_POS], &command_line[TRACE_MSGID_POS], p-&(line[TRACE_MSGID_POS]))) 
+                               return line;
+               }
+       }
+       return NULL;
+}
+
+inline int find_reply_status (char * line)
+{
+       char * p;
+       int i=0;
+
+       if (rfs_debug)
+               printf ("line %s  flag %c\n", line, line[TRACE_COMMAND_REPLY_FLAG_POS]);
+       if (!(line[TRACE_COMMAND_REPLY_FLAG_POS]=='R')) {
+               printf ("disk_index %d %s\n", disk_index, line);
+       };
+       RFS_ASSERT (line[TRACE_COMMAND_REPLY_FLAG_POS]=='R');
+       p = line+TRACE_MSGID_POS+2;     /* at least one letter for msgid and one letter for space */
+       if (strstr(p, "OK"))
+               return NFS3_OK;
+       if (strstr(p, "lookup 2") || strstr(p, "lookup   2"))
+               return 0x2;
+       if (strstr(p, "create d"))
+               return 0xd;
+       if (strstr(p, "setattr 1"))
+               return 0x1;
+       if (strstr(p, "setattr 2712")) /* 10002 NFS3ERR_NOT_SYNC */
+               return 0x2712;
+       if (strstr(p, "lookup d"))
+               return 0xd;
+       if (strstr(p, "read d"))
+               return 0xd;
+       if (strstr(p, "write d"))
+               return 0xd;
+       if (strstr(p, "write 46"))
+               return 0x46;
+       if (strstr(p, "getattr 46"))
+               return 0x46;
+       if (strstr(p, "mkdir d"))
+               return 0xd;
+       printf ("line %s  flag %c return value weird\n", line, line[TRACE_COMMAND_REPLY_FLAG_POS]);
+       printf ("!!!!!!!!!!!!!!!!!!!!!!!!\n");
+       fprintf (stderr, "line %s  flag %c return value weird\n", line, line[TRACE_COMMAND_REPLY_FLAG_POS]);
+       fprintf (stderr, "!!!!!!!!!!!!!!!!!!!!!!!!\n");
+}
+
+inline int find_reply_status_old (char * line)
+{
+       char * p;
+       int i=0;
+
+       //printf ("line %s  flag %c\n", line, line[TRACE_COMMAND_REPLY_FLAG_POS]);
+       RFS_ASSERT (line[TRACE_COMMAND_REPLY_FLAG_POS]=='R');
+       if (!strstr(line, "OK")) {
+               p=strstr(line, " 6 read ");
+               if (p) {
+                       p+=strlen(" 6 read ");
+               } else {
+                       p = strstr (line, "status=XXX");
+                       RFS_ASSERT (p);
+                       p--;
+                       RFS_ASSERT (*p==' ');
+                       while (*p==' ')
+                               p--;
+                       while (*p!=' ') {
+                               p--;
+                       }
+                       p++;
+               }
+               sscanf (p, "%x", &i);
+               if ((i<=0) || (i>10000))
+                       printf("line %s\n", line);
+               RFS_ASSERT (i>0 && i<10009);
+       }
+       return i;
+}
+
+inline char * find_reply_trace_fh (char * line)
+{
+       char * p;       
+       p = strstr (line, "OK fh");
+       if (!p) {
+               printf ("disk_index %d find_reply_trace_fh line %s\n", disk_index, line);
+               return NULL;
+       } else
+               return p+6;
+}
+
+#ifndef NO_DEPENDENCY_TABLE
+inline int disk_index_to_dep_index(int cur_dep_index, int disk_index)
+{
+       int i;
+       for (i=cur_dep_index; i>min_dep_index; i--) {
+               if (dep_tab[i].disk_index == disk_index)
+                       return i;
+       } 
+       RFS_ASSERT (0);
+}
+#endif
+
+inline int is_play_candidate (int dep_index)
+{
+       int proc = dep_tab[dep_index].proc;
+       int status = dep_tab[dep_index].status;
+       int trace_status = dep_tab[dep_index].trace_status;
+
+#ifndef TAKE_CARE_CREATE_MODE_BY_DAN
+       /* for a failed create in trace, trace_replay just ignore many time the trace create fail
+        * due to access control, but trace_play will success because our access control
+        * may be loose (all uid/gid is mapped to single one 513:513, so we just skip these requests 
+        */
+       if ((proc==CREATE || proc==MKDIR) && (trace_status!=NFS3_OK) && (status!=NFS3ERR_RFS_MISS)) {
+               if (dependency_debug)
+                       printf ("disk[%d] ignore failed create/mkdir in trace, trace_status %d line %s", 
+                               dep_tab[dep_index].disk_index, trace_status, dep_tab[dep_index].line);
+               failed_create_command_num ++;
+               return FALSE;
+       }
+#endif
+#ifndef TAKE_CARE_OTHER_FAILED_COMMAND
+       if (((trace_status == NFS3ERR_ACCES) && (proc==READ || proc==WRITE || proc==LOOKUP)) || 
+           ((trace_status == NFS3ERR_PERM) && (proc==SETATTR))                                                                         ){
+               if (dependency_debug)
+                       printf ("disk[%d] ignore other failed command in trace, trace_status %d line %s", 
+                               dep_tab[dep_index].disk_index, trace_status, dep_tab[dep_index].line);
+               
+               failed_other_command_num ++;
+               return FALSE;
+       }
+#endif
+#ifndef TAKE_CARE_SYMBOLIC_LINK
+       if ((dep_tab[dep_index].proc==READLINK) ) { /* send request */
+               skipped_readlink_command_num ++;
+               return FALSE;
+       }
+#endif
+/* This is actually take care in get_nextop by checking fh_map error when dep_index==min_dep_index */
+#ifndef TAKE_CARE_CUSTOM_COMMAND
+       /* this line has a file handle which should belong to discard but it is not
+        * the file handle directly appears as parent directory in a lookup request
+        * the return value is NOENT, the parent directory should have been initialized
+        * but the initialization code just ignored all lookup request which didn't success
+        * including NOENT even though the parent directory is still valid.
+        */
+/*
+       if ((    ((dep_tab[dep_index].disk_index==262213) || (dep_tab[dep_index].disk_index==214402))
+                 && !(strcmp(trace_file, "anon-lair62-011130-1100.txt")) 
+               ) || 
+               (        ((dep_tab[dep_index].disk_index==238460) || (dep_tab[dep_index].disk_index ==238470))
+                 && !(strcmp(trace_file, "anon-lair62-011130-1000.txt"))
+               )) {
+               skipped_custom_command_num++;
+               return FALSE;
+       }
+*/
+       if ((    ((dep_tab[dep_index].disk_index==423727) || (0))
+                 && !(strncmp(trace_file, "anon-lair62-011130-1500.txt", strlen("anon-lair62-011130-1500.txt"))) 
+               ) || 
+               (        ((dep_tab[dep_index].disk_index==238460) || (dep_tab[dep_index].disk_index ==238470))
+                 && !(strcmp(trace_file, "anon-lair62-011130-1000.txt"))
+               )) {
+               skipped_custom_command_num++;
+               return FALSE;
+       }
+       /* this line is about the mkdir 116d9d originally in anon-lair62-011130-1400.txt */
+       if (!strncmp(dep_tab[dep_index].line, "1007147245.194201", strlen("1007147245.194201"))) {
+               skipped_custom_command_num++;
+               return FALSE;
+       }
+#endif
+#ifndef TAKE_CARE_FSSTAT_COMMAND
+       /* the file handle used in this command is not processed properly by pre-processing */
+       if (proc==FSSTAT) {
+               char * trace_fh = find_lead_trace_fh(proc, dep_tab[dep_index].line);
+               fh_map_t * fh = lookup_fh (trace_fh);
+               if (!fh) {
+                       skipped_fsstat_command_num++;
+                       return FALSE;
+               }
+       }
+#endif
+       return TRUE;
+}
+
+inline int is_dir_op (int proc)
+{
+       switch (proc) {
+       case MKDIR:
+       case CREATE:
+       case LINK:
+       case SYMLINK:
+       case MKNOD:
+       case REMOVE:
+       case RMDIR:
+       case RENAME:
+               return 1;
+       default:
+               return 0;
+       }
+}      
+
+inline int is_create_op (int proc)
+{
+       if (proc==CREATE || proc==MKDIR || proc==LINK || proc==SYMLINK || proc==MKNOD || proc==RENAME)
+               return 1;
+       return 0;
+}
+
+inline int is_delete_op (int proc)
+{
+       if (proc==REMOVE || proc==RMDIR || proc==RENAME)
+               return 1;
+       return 0;
+}      
+
+static inline char * find_lead_trace_fh(int proc, char * line)
+{
+       char * p;
+       /* check the file handle availability */ 
+       p = strstr (line, "fh");
+       RFS_ASSERT (p);
+       p+=3; //printf ("check dependency dep_tab[%d] trace_fh %s line %s \n", dep_index, trace_fh, line);
+       return p;
+}
+
+inline char * find_another_trace_fh(int proc, char * line)
+{
+       char * p;
+       /* check the file handle availability */ 
+       p = strstr (line, "fh2");
+       RFS_ASSERT (p);
+       p+=4; //printf ("check dependency dep_tab[%d] trace_fh %s line %s \n", dep_index, trace_fh, line);
+       return p;
+}
+
+/* return the index of next request in dep_tab.
+ * Return -1 if there is no suitable request to send
+ */
+inline int get_nextop(void)
+{
+       int i,j, k;
+       int * t;
+       static int dep_index = -2;
+       char * line;
+       char * p;
+#define INIT_MIN_WAIT_VALUE -999
+       static int min_wait_fhandle_dep_index = INIT_MIN_WAIT_VALUE;
+       int proc;
+       int flag;
+
+       if (min_wait_fhandle_dep_index == -999)
+               min_wait_fhandle_dep_index = dep_window_index.head;
+
+       for (i=0; i<CYCLIC_NUM(dep_window_index); i++) {
+               dep_index = (dep_window_index.tail+i) % dep_window_index.size;
+       
+               proc = dep_tab[dep_index].proc;
+               flag = dep_tab[dep_index].flag;
+
+               if (dependency_debug)
+                       printf ("get_nextop check dep_tab[%d].disk_index %d\n", dep_index, dep_tab[dep_index].disk_index);
+#ifdef NO_DEPENDENCY_TABLE
+               if (dep_tab[dep_index].flag == DEP_FLAG_INIT) {
+                       if (is_play_candidate(dep_index)==TRUE) {
+                               /* the trace_fh is the file handle for the operation directory, trace_fh_2 is other file handle
+                                * used in the request */
+                               if (proc==LINK || proc==RENAME) {
+                                       dep_tab[dep_index].trace_fh = find_another_trace_fh (proc, dep_tab[dep_index].line);
+                                       dep_tab[dep_index].trace_fh_2 = find_lead_trace_fh(proc, dep_tab[dep_index].line);
+                                       dep_tab[dep_index].fh = 0;
+                                       dep_tab[dep_index].fh_2 = 0;
+                               } else {
+                                       dep_tab[dep_index].trace_fh = find_lead_trace_fh(proc, dep_tab[dep_index].line);
+                                       dep_tab[dep_index].fh = 0;
+                                       dep_tab[dep_index].fh_2 = (fh_map_t *)1;
+                               };
+                               dep_tab[dep_index].flag = DEP_FLAG_CANDIDATE;
+#ifdef TIME_PLAY
+                               dep_tab[dep_index].skip_sec = skip_sec;
+#endif
+                               if (dependency_debug)
+                                       printf ("disk[%d] state DEP_FLAG_INIT to DEP_FLAG_CANDIDATE\n", dep_tab[dep_index].disk_index);
+                       } else {
+                               if (dependency_debug)
+                                       printf ("disk[%d] state DEP_FLAG_INIT to DEP_FLAG_DONE\n", dep_tab[dep_index].disk_index);
+                               dep_tab[dep_index].flag = DEP_FLAG_DONE;
+                               continue;
+                       }
+               }
+
+               if ((dep_tab[dep_index].flag == DEP_FLAG_CANDIDATE) || (dep_tab[dep_index].flag == DEP_FLAG_WAIT_FHANDLE) ) {
+
+                       if (!dep_tab[dep_index].fh)
+                               dep_tab[dep_index].fh = lookup_fh (dep_tab[dep_index].trace_fh);
+                       if (!dep_tab[dep_index].fh_2)
+                               dep_tab[dep_index].fh_2 = lookup_fh (dep_tab[dep_index].trace_fh_2);
+
+                       /* need to wait for file handle */
+                       if ((!dep_tab[dep_index].fh) || (!dep_tab[dep_index].fh_2)) {
+                               if (dependency_debug)
+                                       printf("disk[%d] can not lookup file handle\n", dep_tab[dep_index].disk_index);
+                               if (dep_tab[dep_index].flag == DEP_FLAG_CANDIDATE) {
+                                       if (dependency_debug)
+                                               printf ("disk[%d] state DEP_FLAG_CANDIDATE to DEP_FLAG_WAIT_FHANDLE\n", dep_tab[dep_index].disk_index);
+                                       dep_tab[dep_index].flag = DEP_FLAG_WAIT_FHANDLE;
+                                       sfs_gettime (&dep_tab[dep_index].start);
+                                       if (CYCLIC_LESS(dep_tab_index,dep_index,min_wait_fhandle_dep_index)) 
+                                               min_wait_fhandle_dep_index = dep_index;
+                               } else {
+                                       struct ladtime tmp;
+                                       if (dep_index==dep_window_index.tail) {
+                                               if (!profile_debug) 
+                                                       printf ("fh_path_map error disk[%d] state DEP_FLAG_WAIT_FHANDLE to DEP_FLAG_DONE\n", dep_tab[dep_index].disk_index);
+                                               fh_path_map_err_num ++;
+                                               dep_tab[dep_index].flag = DEP_FLAG_DONE;
+                                               continue;
+                                       }
+                                       sfs_gettime (&tmp);
+                                       SUBTIME (tmp, dep_tab[dep_index].start);
+#define DEPENDENCY_TIMEOUT 50
+#ifdef TIME_PLAY
+                                       RFS_ASSERT (tmp.sec < DEPENDENCY_TIMEOUT + (skip_sec - dep_tab[dep_index].skip_sec));   
+#else
+                                       if (tmp.sec >= DEPENDENCY_TIMEOUT) {
+                                               printf("dep_tab[%d].flag %d disk_index %d line %s\n", dep_index,
+                                                       dep_tab[dep_index].flag, dep_tab[dep_index].disk_index,
+                                                       dep_tab[dep_index].line);
+                                       }
+                                       RFS_ASSERT (tmp.sec < DEPENDENCY_TIMEOUT );     
+#endif
+                               }
+                               continue;
+                       }
+
+                       /* file handle ready, adjust_min_wait_fhandle_dep_index */
+                       if ((dep_tab[dep_index].flag == DEP_FLAG_WAIT_FHANDLE)) {
+                               if (dep_index == min_wait_fhandle_dep_index) {
+                                       min_wait_fhandle_dep_index = dep_window_index.head;
+                                       for (j=CYCLIC_ADD(dep_index,1,dep_window_index.size); CYCLIC_LESS(dep_window_index,j,dep_window_index.head); j++) {
+                                               if (dep_tab[j].flag ==DEP_FLAG_WAIT_FHANDLE) {
+                                                       min_wait_fhandle_dep_index = j;
+                                                       break;
+                                               }
+                                       }
+                               }
+                       }
+                       if (dependency_debug)
+                               printf("disk[%d] found file handle\n", dep_tab[dep_index].disk_index);
+                       dep_tab[dep_index].flag = DEP_FLAG_FHANDLE_READY;
+
+                       /* the normal file operation can be executed now */
+                       if (!is_dir_op (dep_tab[dep_index].proc)) {
+                               if (dependency_debug)
+                                       printf ("return disk[%d]\n", dep_tab[dep_index].disk_index);
+                               return dep_index;
+                       }
+
+                       if (dependency_debug)
+                               printf("disk[%d] directory operation \n", dep_tab[dep_index].disk_index);
+                       /* the directory operation need to lock the directory first */
+                       if (dep_tab[dep_index].fh->lock) {
+                               if (dependency_debug)
+                                       printf ("disk[%d] state %d to DEP_FLAG_WAIT_DIRECTORY\n", dep_tab[dep_index].disk_index, dep_tab[dep_index].flag);
+                               dep_tab[dep_index].flag = DEP_FLAG_WAIT_DIRECTORY;
+                               continue;
+                       }
+               }
+                               
+               if ((dep_tab[dep_index].flag == DEP_FLAG_FHANDLE_READY) || (dep_tab[dep_index].flag == DEP_FLAG_WAIT_DIRECTORY)) {
+                       int j = dep_tab[dep_index].fh - fh_map;
+                       if (dependency_debug) {
+                               printf ("dep_tab[%d].disk_index %d, fh_map[%d] lock=%d\n",dep_index, dep_tab[dep_index].disk_index, j, dep_tab[dep_index].fh->lock);
+                               printf ("trace_fh %s path %s\n", dep_tab[dep_index].fh->trace_fh, dep_tab[dep_index].fh->path);
+                               printf ("trace_fh %s path %s\n", fh_map[j].trace_fh, fh_map[j].path);
+                       }
+                       if ((dep_tab[dep_index].fh->lock) || ((proc==RENAME) && (dep_tab[dep_index].fh_2->lock)) ) {
+                               if (dependency_debug) 
+                                       printf ("continue to wait for directory lock\n");
+                               continue;
+                       }
+                       if (dependency_debug) 
+                               printf ("dep_tab[%d] disk index %d LOCK fh_map[%d] \n", dep_index, dep_tab[dep_index].disk_index, j);
+                       dep_tab[dep_index].fh->lock = 1;
+                       if (proc==RENAME)
+                               dep_tab[dep_index].fh_2->lock = 1;
+
+                       /* the non-delete directory operation can proceed now */
+                       if (!is_delete_op (dep_tab[dep_index].proc)) {
+                               if (dependency_debug) 
+                                       printf ("return disk[%d]\n", dep_tab[dep_index].disk_index);
+                               return dep_index;
+                       }
+
+                       /* the delete operation can proceed if nobody ahead is waiting for fhandle */
+                       /* probably this condition is not strong enough */
+//                     if ((min_wait_fhandle_dep_index<dep_index) ) {
+                       if (dep_index!=dep_window_index.tail) {
+                               if (dependency_debug) 
+                                       printf ("disk[%d] state %d to DEP_FLAG_WAIT_DELETE\n", dep_tab[dep_index].disk_index, dep_tab[dep_index].flag);
+                               dep_tab[dep_index].flag = DEP_FLAG_WAIT_DELETE;
+                               continue;
+                       } 
+                       dep_tab[dep_index].flag = DEP_FLAG_DIRECTORY_READY;
+               }
+
+               if ((dep_tab[dep_index].flag == DEP_FLAG_DIRECTORY_READY) || (dep_tab[dep_index].flag == DEP_FLAG_WAIT_DELETE)) {
+//                     if (min_wait_fhandle_dep_index > dep_index) {
+                       if (dep_index==dep_window_index.tail) {
+                               if (dependency_debug) 
+                                       printf ("return disk[%d]\n", dep_tab[dep_index].disk_index);
+                               return dep_index;
+                       }
+               }
+#else /*NO_DEPENDENCY_TABLE undefined */
+       /* this part of code will be invalid after CYCLIC buffer design */
+               if (dep_tab[dep_index].flag == DEP_FLAG_INIT){
+                       for (j=0, t=&(dep_tab[dep_index].dep_ops[0]);
+                               (j<dep_tab[dep_index].init_dep_num) && (dep_tab[dep_index].cur_dep_num>0); 
+                               j++, t++) {
+                               if (*t !=-1) {
+                                       if (dep_tab[disk_index_to_dep_index(dep_index, *t)].flag == DEP_FLAG_DONE) { 
+                                               /* The depended request has been finished */ 
+                                               *t = -1;
+                                               dep_tab[dep_index].cur_dep_num --;
+                                       }
+                               } 
+                       }
+
+                       if (dep_tab[dep_index].cur_dep_num == 0) {
+                               return dep_index;
+                       }
+               }
+#endif
+       }
+
+       if (dependency_debug) 
+               printf ("get_nexop return -1\n");
+       return -1;
+}
+
+int check_timeout(void)
+{
+       static int biod_index = 0;
+       int i;
+       int dep_index;  /* index into dep_tab */
+       int proc;
+       sfs_op_type *op_ptr;            /* per operation info */
+       struct ladtime timeout;
+       struct ladtime current_time;
+
+       sfs_gettime (&current_time);    
+
+       for (i=0; i<max_biod_reqs; i++, biod_index = (biod_index+1)%max_biod_reqs) {
+               if (biod_reqp[biod_index].in_use==TRUE) {
+                       timeout = biod_reqp[biod_index].timeout;
+                       if ((current_time.sec>timeout.sec) ||
+                               ((current_time.sec==timeout.sec) && (current_time.usec>timeout.usec))) {
+
+                               dep_index = biod_reqp[biod_index].dep_tab_index;
+                               proc = dep_tab[dep_index].proc;
+                               op_ptr = &Ops[proc];
+                               op_ptr->results.timeout_calls++;
+                               Ops[TOTAL].results.timeout_calls++;
+
+
+                               if (is_create_op(proc)) {
+                                       dep_tab[dep_index].flag = DEP_FLAG_CANDIDATE;
+                                       printf ("resend dep_tab[%d], disk_index %d\n", dep_index, dep_tab[dep_index].disk_index);
+                                       finish_request (biod_index, dep_index, NFS3ERR_RFS_TIMEOUT, DEP_FLAG_CANDIDATE);
+                               } else {
+                                       finish_request (biod_index, dep_index, NFS3ERR_RFS_TIMEOUT, DEP_FLAG_DONE);
+                               }
+                               timeout_num ++;
+                               num_out_reqs_statistics_at_timeout[num_out_reqs]++;
+
+                               //RFS_ASSERT (!is_create_op(proc));
+
+                               if (per_packet_debug)
+                                       printf ("timeout request: disk_index %d, dep_index %d biod_reqp[%d].start %d:%d timeout %d:%d current %d:%d\n", dep_tab[dep_index].disk_index, dep_index, biod_index, biod_reqp[biod_index].start.sec, biod_reqp[biod_index].start.usec, timeout.sec, timeout.usec, current.sec, current.usec);
+                       }
+               }
+       }
+}
+
+/* Allocate a biod_req entry to send and receive request dep_tab[dep_index]
+ * build the cross reference between dep_tab entry and biod_req entry
+ */
+struct biod_req * get_biod_req(int dep_index) /* index into dep_tab */
+{
+       static int biod_index = 0;
+       int i;
+       for (i=0; i<max_biod_reqs; i++, biod_index = (biod_index+1)%max_biod_reqs) {
+               if (!biod_reqp[biod_index].in_use) {
+                       biod_reqp[biod_index].in_use = 1;
+                       biod_reqp[biod_index].dep_tab_index = dep_index;
+                       dep_tab[dep_index].biod_req_index = biod_index;
+               num_out_reqs++;
+                       return &(biod_reqp[biod_index]);
+               }
+       }
+       return NULL;
+}
+
+/* Return index into biod_reqp
+ * return -1 upon failure 
+ */
+int lookup_biod_req (int xid)
+{
+       static int biod_index = 0;
+       int i;
+       for (i=0; i<max_biod_reqs; i++, biod_index = (biod_index+1)%max_biod_reqs) {
+               /* give a NULL as timeout pointer may cause indefinitely block */
+               if ((biod_reqp[biod_index].in_use == TRUE) &&( biod_reqp[biod_index].xid == xid)) {
+                       return biod_index;
+               }
+       }
+       return -1;
+}
+
+extern struct ladtime test_start;
+void init_time_offset(void)
+{
+       struct ladtime tmp1;
+       struct ladtime tmp2;
+
+       test_start.sec = 0;
+       test_start.usec = 0;
+       sfs_gettime (&tmp1);            /* called at initial time: tmp1 = play_starttime */
+#ifdef SPEED_UP
+       DIVTIME (tmp1, PLAY_SCALE) /* tmp1 = play_starttime / SCALE */
+#endif
+#ifdef SLOW_DOWN
+       MULTIME (tmp1, PLAY_SCALE) /* tmp1 = play_starttime * SCALE */
+#endif
+
+       tmp2 = trace_starttime; /* tmp2 = trace_starttime */
+       SUBTIME (tmp2, tmp1);   /* tmp2 = trace_starttime - play_starttime *|/ SCALE */
+       time_offset = tmp2;             /* time_offset = trace_starttime - play_starttime *|/ SCALE */ 
+}
+
+/* initialize timestamp and proc field of dep_tab entry */
+void init_dep_tab_entry (int dep_index)
+{
+       char * line;
+       int version;
+       int nfsproc;
+       int msgid;
+
+       //line = get_line_by_disk_index (dep_tab[dep_index].disk_index);
+       line = dep_tab[dep_index].line;
+       sscanf (line, "%d.%d", &(dep_tab[dep_index].timestamp.tv_sec), &(dep_tab[dep_index].timestamp.tv_usec));
+       sscanf (&line[TRACE_MSGID_POS], "%x %x", &msgid, &nfsproc);
+       //printf ("msgid %x nfsproc %x\n", msgid, nfsproc);
+       if (line[TRACE_VERSION_POS]=='2') {
+               dep_tab[dep_index].proc = nfs2proc_to_rfsproc[nfsproc];
+               RFS_ASSERT (nfsproc <18);
+       } else {
+               /* This is for debug purpose */
+               if (line[TRACE_VERSION_POS] !='3') {
+                       fprintf(stderr, "line[TRACE_VERSION_POS] %c line %s\n", line[TRACE_VERSION_POS], line);
+                       line = get_line_by_disk_index (dep_tab[dep_index].disk_index-1);
+                       if (!line)
+                               line = get_line_by_disk_index (dep_tab[dep_index].disk_index-2);
+                       RFS_ASSERT (line);
+                       fprintf(stderr, "previousline %s\n", line);
+               }
+               RFS_ASSERT (line[TRACE_VERSION_POS] =='3');
+               if (nfsproc >= NFS3_PROCEDURE_COUNT) {
+                       fprintf(stderr, "proc %d line %s\n", nfsproc, line);
+                       
+               }
+               RFS_ASSERT (nfsproc <NFS3_PROCEDURE_COUNT);
+               dep_tab[dep_index].proc = nfs3proc_to_rfsproc[nfsproc];
+       }
+       RFS_ASSERT (dep_tab[dep_index].proc >= 0 && dep_tab[dep_index].proc < NOPS);
+       dep_tab[dep_index].flag = DEP_FLAG_INIT;
+}
+
+void adjust_play_window (int flag, int * poll_timeout_arg)
+{
+       struct ladtime max_window_time;
+       static struct ladtime max_poll_time = {0, 2000, 0};
+       struct ladtime t;
+       int i;
+       char * line;
+       cyclic_index_t old_dep_window_index = dep_window_index;
+
+#ifdef notdef
+       printf ("^^^^^^^^^^^^^^^ adjust_play_window, begin\n");
+       CYCLIC_PRINT (dep_tab_index);
+       printf ("dep_tab[%d].memory_index %d\n", dep_tab_index.tail, dep_tab[dep_tab_index.tail].memory_index);
+       CYCLIC_PRINT (dep_window_index);
+       CYCLIC_PRINT (memory_trace_index);
+       printf ("                adjust_play_window, begin\n");
+#endif
+
+       while ((!CYCLIC_EMPTY(dep_window_index)) && (dep_tab[dep_window_index.tail].flag == DEP_FLAG_DONE)) {
+#ifdef notdef
+               //CYCLIC_PRINT (memory_trace_index);
+               //printf("MOVE_TAIL_TO memory_index %d\n", dep_tab[dep_tab_index.tail].memory_index);
+               RFS_ASSERT (!CYCLIC_EMPTY(memory_trace_index)); 
+               RFS_ASSERT (CYCLIC_LESS (memory_trace_index, dep_tab[dep_tab_index.tail].memory_index, memory_trace_index.head));
+               printf("%d is done\n", dep_window_index.tail);
+#endif
+               CYCLIC_MOVE_TAIL(dep_tab_index);
+               CYCLIC_MOVE_TAIL(dep_window_index);
+
+#ifdef notdef
+               CYCLIC_PRINT (dep_tab_index);
+               CYCLIC_PRINT (dep_window_index);
+
+               if (! (dep_tab_index.tail == dep_window_index.tail)) {
+                       CYCLIC_PRINT(dep_tab_index);
+                       CYCLIC_PRINT(dep_window_index);
+               };
+               RFS_ASSERT ( dep_tab_index.tail == dep_window_index.tail);
+#endif
+
+               if (!CYCLIC_EMPTY(dep_tab_index)) {
+#ifdef notdef
+                       RFS_ASSERT (!CYCLIC_EMPTY(memory_trace_index)); 
+                       if (!(CYCLIC_LESS (memory_trace_index, dep_tab[dep_tab_index.tail].memory_index, memory_trace_index.head))) {
+                               CYCLIC_PRINT(memory_trace_index);
+                               CYCLIC_PRINT(dep_tab_index);
+                               printf("dep_tab[head-1].memory_index, %d [tail].memory_index %d\n", 
+                                       dep_tab[CYCLIC_MINUS(dep_tab_index.head,1,dep_tab_index.size)].memory_index,
+                                       dep_tab[dep_tab_index.tail].memory_index);
+                       }
+                       RFS_ASSERT (CYCLIC_LESS (memory_trace_index, dep_tab[dep_tab_index.tail].memory_index, memory_trace_index.head));
+#endif
+                       CYCLIC_SET_TAIL_TO(&memory_trace_index, dep_tab[dep_tab_index.tail].memory_index);
+                       //printf ("set memory_trace_index to %d=%d, dep_tab_index.tail %d\n", memory_trace_index.tail, dep_tab[dep_tab_index.tail].memory_index, dep_tab_index.tail);
+               } else {
+               //      CYCLIC_MOVE_TAIL (memory_trace_index);
+               }
+       }
+
+       while (CYCLIC_EMPTY(dep_tab_index)) {
+               
+               if (disk_io_status == TRACE_FILE_END) 
+                       return;
+               else {
+                       //printf ("************** ADJUST_PLAY_WINDOW sleep 1 s\n"); 
+                       //print_cyclic_buffers();
+                       //pthread_yield();
+                       //usleep (1000);
+               }
+       }
+
+       /* max_trace_window_time = current *|/ SCALE + trace_starttime */
+       sfs_gettime (&current);
+
+#ifdef TIME_PLAY
+#ifdef SPEED_UP
+       MULTIME (current, PLAY_SCALE);
+#endif
+#ifdef SLOW_DOWN
+       DIVTIME (current, PLAY_SCALE);
+#endif
+       ADDTIME (current, trace_starttime);
+       max_window_time = current;
+
+       /* Right now it is not clear how to deal with the situation where MAX_PLAY_WINDOW is reached */
+       if (CYCLIC_NUM(dep_window_index) == MAX_PLAY_WINDOW) {
+               //printf ("can not catch up the speed, dep_tab_size %d dep_window_max %d reach min_dep_index %d+MAX_PLAY_WINDOW\n", dep_tab_size, dep_window_max, min_dep_index);
+               //printf (".");
+               can_not_catch_speed_num ++;
+       }
+       while ((CYCLIC_NUM(dep_window_index) < MAX_PLAY_WINDOW) &&
+                  (CYCLIC_NUM(dep_window_index) < CYCLIC_NUM(dep_tab_index)) ) {
+               struct ladtime t;
+               int dep_index = (dep_window_index.tail+i) % dep_window_index.size;
+        t.sec = dep_tab[dep_index].timestamp.tv_sec;
+        t.usec = dep_tab[dep_index].timestamp.tv_usec;
+               if ((t.sec>max_window_time.sec)||(t.sec==max_window_time.sec && t.usec>max_window_time.usec))
+            break;
+               CYCLIC_MOVE_HEAD(dep_window_index);
+       }
+#else
+       ADDTIME (current, trace_starttime);
+       max_window_time = current;
+       while ((CYCLIC_NUM(dep_window_index) < MAX_PLAY_WINDOW) &&
+                  (CYCLIC_NUM(dep_window_index) < CYCLIC_NUM(dep_tab_index)) ) {
+               CYCLIC_MOVE_HEAD(dep_window_index);
+       }
+#endif
+
+       if (flag == BUSY)
+               *poll_timeout_arg = 0;
+       else if (CYCLIC_NUM(dep_window_index)==CYCLIC_NUM(dep_tab_index)) {
+               *poll_timeout_arg = 1000;       /* poll_timeout set to 1 second for the last request */
+       } else {
+#ifdef TIME_PLAY
+               struct ladtime tmp;
+               struct ladtime tmp1;
+               tmp.sec = dep_tab[dep_window_index.head].timestamp.tv_sec;
+               tmp.usec = dep_tab[dep_window_index.head].timestamp.tv_usec;
+               if (adjust_play_window_debug>=2)
+                       printf ("dep_tab[dep_window_index.head %d].timestamp %d:%d, max_window_time %d:%d\n",
+                               dep_window_index.head, tmp.sec, tmp.usec, max_window_time.sec, max_window_time.usec);
+
+               SUBTIME (tmp, max_window_time);
+#ifdef SPEED_UP
+               DIVTIME (tmp, PLAY_SCALE);
+#endif
+#ifdef SLOW_DOWN
+               MULTIME (tmp, PLAY_SCALE);
+#endif
+/*
+               tmp1 = tmp;
+
+               if (tmp.sec > max_poll_time.sec) {
+
+                       if (rfs_debug) 
+                               printf ("dep_tab[%d].timestamp %d:%d, max_window_time %d:%d\n",
+                               dep_window_max, dep_tab[dep_window_max].timestamp.tv_sec, dep_tab[dep_window_max].timestamp.tv_usec, max_window_time.sec, max_window_time.usec);
+                       printf ("skip %d seconds\n", tmp.sec-max_poll_time.sec);
+                       SUBTIME (tmp, max_poll_time);
+                       tmp.usec = 0;
+                       skip_sec += tmp.sec;
+                       SUBTIME (test_start, tmp);
+                       tmp = max_poll_time;
+               }
+*/
+
+               //RFS_ASSERT ((tmp.sec < 1000));
+               if (tmp.sec > 1000)
+                       tmp.sec = 1000;
+               if ((tmp.sec ==0) && (tmp.usec==0)) {
+                       *poll_timeout_arg = 0;
+               } else
+                       *poll_timeout_arg = tmp.sec*1000000+tmp.usec;
+#else 
+               /*
+               struct ladtime tmp;
+               struct ladtime tmp1;
+               tmp.sec = dep_tab[dep_window_max].timestamp.tv_sec;
+               tmp.usec = dep_tab[dep_window_max].timestamp.tv_usec;
+               tmp1.sec = dep_tab[dep_window_max-1].timestamp.tv_sec;
+               tmp1.usec = dep_tab[dep_window_max-1].timestamp.tv_usec;
+               SUBTIME (tmp, tmp1);
+               RFS_ASSERT ((tmp.sec < 1000));
+               RFS_ASSERT ((tmp.sec>0) || ((tmp.sec==0) && (tmp.usec>0)));
+               *poll_timeout = tmp.sec*1000000+tmp.usec;
+               */
+
+               *poll_timeout_arg = 100000;
+#endif
+       }       
+       if (rfs_debug)
+               printf ("adjust_play_window: flag %d min %d -> %d, max %d -> %d poll_timeout_arg %d \n", 
+               flag, old_dep_window_index.tail, dep_window_index.tail, old_dep_window_index.head,
+               dep_window_index.head, *poll_timeout_arg);
+
+#ifdef notdef
+       printf ("^^^^^^^^^^^^^^^ adjust_play_window, end\n");
+       CYCLIC_PRINT (dep_tab_index);
+       printf ("dep_tab[%d].memory_index %d\n", dep_tab_index.tail, dep_tab[dep_tab_index.tail].memory_index);
+       CYCLIC_PRINT (dep_window_index);
+       CYCLIC_PRINT (memory_trace_index);
+       printf ("        adjust_play_window, end\n\n");
+#endif
+       //CYCLIC_ASSERT(4);
+}
+
+/* poll for usecs and receive, after receive one reply,
+ * return index in biod_reqp of the corresponding request
+ */
+int poll_and_get_reply (int usecs)
+{
+       int biod_index = -1;
+       int xid;
+       int error;
+       struct timeval zero_time = {0, 0}; /* Immediately return */
+
+#ifdef RECV_THREAD
+       //printf("recv thread waitsem 1\n");
+       waitsem (async_rpc_sem);
+       //printf("recv thread got sem 1\n");
+#endif
+       do {
+               error = biod_poll_wait (NFS_client, usecs);
+               switch (error) {
+               case -1:
+                       if (errno == EINTR) {
+                               error = 1;
+                               continue;
+                       }
+                       if (rfs_debug) {
+                               (void) fprintf(stderr, "biod_poll_wait error\n");
+                               perror ("");
+                           (void) fflush(stderr);
+                       }
+                       break;
+               case 0:
+                       break;
+               default:
+#ifdef UDP
+                       //printf("recv thread waitsem 2\n");
+                       //waitsem (async_rpc_sem);
+                       //printf("recv thread got sem 2\n");
+                       error = get_areply_udp (NFS_client, &xid, &zero_time);
+                       //postsem (async_rpc_sem);
+                       //printf("recv thread postsem 2\n");
+                       // RFS_ASSERT (error!= RPC_TIMEOUT);    /* we have polled and know there is data */
+                       // RFS_ASSERT (error!= RPC_CANTRECV);
+                       RFS_ASSERT (error == RPC_SUCCESS);
+
+                       biod_index = lookup_biod_req (xid);
+                       sfs_gettime (&(biod_reqp[biod_index].stop));
+#else
+                       RFS_ASSERT (0);
+#endif
+               }
+       } while (0);
+#ifdef RECV_THREAD
+       postsem (async_rpc_sem);
+       //printf("recv thread postsem 1\n");
+#endif
+       return biod_index;
+}
+
+void print_result(void)
+{
+       int i, j;
+       struct ladtime t;
+       int dep_index;
+       int avg_msecs;
+       unsigned long long tmp;
+       int avg_usecs;
+
+    if (DEBUG_CHILD_GENERAL) {
+               (void) fprintf(stdout, "trace play result:\n");
+               (void) fprintf(stdout, "\t    percentage good_cnt bad_cnt timeout_cnt\telapsed time\t\t\taverage time\n");
+               for (i=0; i<NOPS+1; i++) {
+                       if (Ops[i].results.good_calls==0) {
+                               avg_msecs = 0;
+                               avg_usecs = 0;
+                       } else {
+                               tmp = Ops[i].results.time.sec*1000000 + Ops[i].results.time.usec;
+                               avg_msecs = 0;
+                               avg_usecs = tmp/Ops[i].results.good_calls;
+/*
+                               avg_msecs = (Ops[i].results.time.sec*1000 + Ops[i].results.time.usec/1000)/Ops[i].results.good_calls;
+                               avg_usecs = (Ops[i].results.time.usec%1000)/Ops[i].results.good_calls;
+*/
+                       }
+                       (void) fprintf(stdout,  "%11s\t%4.1f\t%4d\t%4d\t%4d\t\tsec %8d usec %8d \tusec %8d\n", 
+                               Ops[i].name, 
+                               (float)(100*Ops[i].results.good_calls)/(float)Ops[TOTAL].results.good_calls, 
+                               Ops[i].results.good_calls, Ops[i].results.bad_calls, Ops[i].results.timeout_calls,
+                               Ops[i].results.time.sec, Ops[i].results.time.usec, avg_msecs*1000+avg_usecs);
+               }
+               (void) fflush (stdout);
+    }
+
+#if    0       /* commented out by G. Jason Peng */
+       RFS_ASSERT (read_data_owe_GB==0);
+       printf("read_data_total %d GB and %d bytes, owe %d GB and %d bytes, %d percent, adjusted %d times \n",read_data_total_GB, read_data_total, read_data_owe_GB, read_data_owe, (read_data_owe)/(read_data_total/100), read_data_adjust_times);
+       printf("write_data_total %d GB and %d bytes, owe %d GB and %d bytes, %d percent, adjusted %d times \n",write_data_total_GB, write_data_total, write_data_owe_GB, write_data_owe, (write_data_owe)/(write_data_total/100), write_data_adjust_times);
+       printf("poll_timeout_0_num %d poll_timeout_pos_num %d\n", poll_timeout_0_num, poll_timeout_pos_num);
+       printf("failed_create_command_num_in_original_trace %d\nfailed_other_command_num_in_original_trace %d\nskipped_readlink_command_num %d\nskipped_custom_command_num %d\nfh_path_map_err_num %d\nskipped_fsstat_command_num %d\nmissing_reply_num %d\nrename_rmdir_noent_reply_num %d\nrmdir_not_empty_reply_num %d\nloose_access_control_reply_num %d\nlookup_err_due_to_rename %d\nlookup_err_due_to_parallel_remove %d\nlookup_eaccess_enoent_mismatch %d\nread_io_err_num %d\nstale_fhandle_err_num %d abnormal_EEXIST_num %d abnormal_ENOENT_num %d proper_reply_num %d run_stage_proper_reply_num %d\n", 
+                       failed_create_command_num,
+                       failed_other_command_num,
+                       skipped_readlink_command_num, 
+                       skipped_custom_command_num,
+                       fh_path_map_err_num, 
+                       skipped_fsstat_command_num, 
+                       missing_reply_num, 
+                       rename_rmdir_noent_reply_num, 
+                       rmdir_not_empty_reply_num, 
+                       loose_access_control_reply_num, 
+                       lookup_err_due_to_rename_num, 
+                       lookup_err_due_to_parallel_remove_num,
+                       lookup_eaccess_enoent_mismatch_num, 
+                       read_io_err_num, 
+                       stale_fhandle_err_num,
+                       abnormal_EEXIST_num,
+                       abnormal_ENOENT_num,
+                       proper_reply_num, run_stage_proper_reply_num);
+#endif
+
+//  print_dump(Client_num, Child_num);
+} 
+
+/*
+ * allocate and initialize client handles
+ */
+static int
+init_rpc(void)
+{
+       int dummy = 0;
+
+    /*
+     * Set up the client handles.  We get them all before trying one
+     * out to insure that the client handle for LOOKUP class is allocated
+     * before calling op_getattr().
+     */
+    if (DEBUG_CHILD_GENERAL) {
+       (void) fprintf(stderr, "%s: set up client handle\n", sfs_Myname);
+    }
+
+    NFS_client = lad_clnt_create(Tcp? 1: 0, Server_hostent,
+                                       (uint32_t) NFS_PROGRAM,
+                                       (uint32_t) nfs_version,
+                                       RPC_ANYSOCK, &Nfs_timers[0]);
+               
+    if (NFS_client  == ((CLIENT *) NULL)) {
+        return(-1);
+    }
+
+    /*
+     * create credentials using the REAL uid
+     */
+    NFS_client->cl_auth = authunix_create(lad_hostname, (int)Real_uid,
+                                     (int)Cur_gid, 0, NULL);
+
+       if (biod_init(dummy, dummy) == -1) {
+                   return(-1);
+       }
+
+    return(0);
+} /* init_rpc */
+
+void
+init_counters(void)
+{
+    uint_t i;
+    uint_t start_msec;
+
+    /* Ready to go - initialize operation counters */
+    for (i = 0; i < NOPS + 1; i++) {
+       Ops[i].req_cnt = 0;
+       Ops[i].results.good_calls = 0;
+       Ops[i].results.bad_calls = 0;
+       Ops[i].results.timeout_calls = 0;       // RFS
+       Ops[i].results.fast_calls = 0;
+       Ops[i].results.time.sec = 0;
+       Ops[i].results.time.usec = 0;
+       Ops[i].results.msec2 = 0;
+    }
+
+    /* initialize timers and period variables */
+    sfs_gettime(&Starttime);
+    Cur_time = Starttime;
+    start_msec = (Starttime.sec * 1000) + (Starttime.usec / 1000);
+    Previous_chkpnt_msec = start_msec;
+    Calls_this_period = 0;
+    Reqs_this_period = 0;
+    Sleep_msec_this_period = 0;
+    Calls_this_test = 0;
+    Reqs_this_test = 0;
+    Sleep_msec_this_test = 0;
+}
+
+static char *
+nfs3_strerror(int status)
+{
+    static char str[40];
+    switch (status) {
+       case NFS3_OK:
+           (void) strcpy(str, "no error");
+           break;
+       case NFS3ERR_PERM:
+           (void) strcpy(str, "Not owner");
+           break;
+       case NFS3ERR_NOENT:
+           (void) strcpy(str, "No such file or directory");
+           break;
+       case NFS3ERR_IO:
+           (void) strcpy(str, "I/O error");
+           break;
+       case NFS3ERR_NXIO:
+           (void) strcpy(str, "No such device or address");
+           break;
+       case NFS3ERR_ACCES:
+           (void) strcpy(str, "Permission denied");
+           break;
+       case NFS3ERR_EXIST:
+           (void) strcpy(str, "File exists");
+           break;
+       case NFS3ERR_XDEV:
+           (void) strcpy(str, "Cross-device link");
+           break;
+       case NFS3ERR_NODEV:
+           (void) strcpy(str, "No such device");
+           break;
+       case NFS3ERR_NOTDIR:
+           (void) strcpy(str, "Not a directory");
+           break;
+       case NFS3ERR_ISDIR:
+           (void) strcpy(str, "Is a directory");
+           break;
+       case NFS3ERR_INVAL:
+           (void) strcpy(str, "Invalid argument");
+           break;
+       case NFS3ERR_FBIG:
+           (void) strcpy(str, "File too large");
+           break;
+       case NFS3ERR_NOSPC:
+           (void) strcpy(str, "No space left on device");
+           break;
+       case NFS3ERR_ROFS:
+           (void) strcpy(str, "Read-only file system");
+           break;
+       case NFS3ERR_MLINK:
+           (void) strcpy(str, "Too many links");
+           break;
+       case NFS3ERR_NAMETOOLONG:
+           (void) strcpy(str, "File name too long");
+           break;
+       case NFS3ERR_NOTEMPTY:
+           (void) strcpy(str, "Directory not empty");
+           break;
+       case NFS3ERR_DQUOT:
+           (void) strcpy(str, "Disc quota exceeded");
+           break;
+       case NFS3ERR_STALE:
+           (void) strcpy(str, "Stale NFS file handle");
+           break;
+       case NFS3ERR_REMOTE:
+           (void) strcpy(str, "Object is remote");
+           break;
+       case NFS3ERR_BADHANDLE:
+           (void) strcpy(str, "Bad file handle");
+           break;
+       case NFS3ERR_NOT_SYNC:
+           (void) strcpy(str, "Not sync write");
+           break;
+       case NFS3ERR_BAD_COOKIE:
+           (void) strcpy(str, "Bad cookie");
+           break;
+       case NFS3ERR_NOTSUPP:
+           (void) strcpy(str, "Operation not supported");
+           break;
+       case NFS3ERR_TOOSMALL:
+           (void) strcpy(str, "Value too small");
+           break;
+       case NFS3ERR_SERVERFAULT:
+           (void) strcpy(str, "Server fault");
+           break;
+       case NFS3ERR_BADTYPE:
+           (void) strcpy(str, "Bad type");
+           break;
+       case NFS3ERR_JUKEBOX:
+           (void) strcpy(str, "Jukebox");
+           break;
+       case NFS3ERR_RFS_TIMEOUT:
+               (void) strcpy(str, "Timeout");
+               break;
+       default:
+           (void) sprintf(str, "Unknown status %d", status);
+           break;
+    }
+    return (str);
+}
+
+/*
+ * Check the gettimeofday() resolution. If the resolution
+ * is in chunks bigger than SFS_MIN_RES then the client
+ * does not have a usable resolution for running the 
+ * benchmark.
+ */
+static void
+check_clock(void)
+{
+       double time_res;
+       char tmp_hostname[HOSTNAME_LEN];
+
+       time_res = get_resolution();
+       getmyhostname(tmp_hostname, HOSTNAME_LEN);
+       if( time_res > (double)SFS_MIN_RES )
+       {
+               (void) fprintf(stderr,
+               "\n%s: Clock resolution too poor to obtain valid results.\n",
+                       tmp_hostname);
+               (void) fprintf(stderr,
+               "%s: Clock resolution %f Micro seconds.\n", tmp_hostname,
+                       time_res);
+               exit(175);
+       }
+       else
+       {
+               (void) fprintf(stderr,
+               "\n%s: Good clock resolution [ %f ] Micro seconds.\n", 
+                       tmp_hostname, time_res);
+       }
+}
+
+/*
+ * Lifted code from Iozone with permission from author. (Don Capps)
+ * Returns the resolution of the gettimeofday() function 
+ * in microseconds.
+ */
+static double
+get_resolution(void)
+{
+        double starttime, finishtime, besttime;
+        long  j,delay;
+       int k;
+
+        finishtime=time_so_far1(); /* Warm up the instruction cache */
+        starttime=time_so_far1();  /* Warm up the instruction cache */
+        delay=j=0;                 /* Warm up the data cache */
+       for(k=0;k<10;k++)
+       {
+               while(1)
+                       {
+                               starttime=time_so_far1();
+                               for(j=0;j< delay;j++)
+                               ;
+                               finishtime=time_so_far1();
+                               if(starttime==finishtime)
+                                       delay++;
+                               else
+                       {
+                               if(k==0)
+                                       besttime=(finishtime-starttime);
+                               if((finishtime-starttime) < besttime)
+                                       besttime=(finishtime-starttime);
+                                       break;
+                       }
+               }
+        }
+         return(besttime);
+}
+
+/*
+ * Lifted code from Iozone with permission from author. (Don Capps)
+ * Returns current result of gettimeofday() in microseconds.
+ */
+/************************************************************************/
+/* Time measurement routines.                                           */
+/* Return time in microseconds                                          */
+/************************************************************************/
+
+static double
+time_so_far1(void)
+{
+        /* For Windows the time_of_day() is useless. It increments in 55 */
+       /* milli second increments. By using the Win32api one can get */
+       /* access to the high performance measurement interfaces. */
+       /* With this one can get back into the 8 to 9 microsecond */
+       /* resolution.  */
+#ifdef Windows
+        LARGE_INTEGER freq,counter;
+        double wintime;
+        double bigcounter;
+
+        QueryPerformanceFrequency(&freq);
+        QueryPerformanceCounter(&counter);
+        bigcounter=(double)counter.HighPart *(double)0xffffffff +
+                (double)counter.LowPart;
+        wintime = (double)(bigcounter/(double)freq.LowPart);
+        return((double)wintime*1000000.0);
+#else
+#if defined (OSFV4) || defined(OSFV3) || defined(OSFV5)
+  struct timespec gp;
+
+  if (getclock(TIMEOFDAY, (struct timespec *) &gp) == -1)
+    perror("getclock");
+  return (( (double) (gp.tv_sec)*1000000.0) +
+    ( ((float)(gp.tv_nsec)) * 0.001 ));
+#else
+  struct timeval tp;
+
+  if (gettimeofday(&tp, (struct timezone *) NULL) == -1)
+    perror("gettimeofday");
+  return ((double) (tp.tv_sec)*1000000.0) +
+    (((double) tp.tv_usec) );
+#endif
+#endif
+}
+
+static void
+usage(void)
+{
+       fprintf(stderr, "trace play usage");
+}
+extern void init_file_system (void)
+{
+       return;
+}
+
+void show_fhandle (nfs_fh3 * fhp)
+{
+       struct knfs_fh * kfhp = (struct knfs_fh *)fhp;
+
+       int dev;
+
+       if (quiet_flag)
+               return;
+               
+       RFS_ASSERT (kfhp->fh_version == 1);
+       RFS_ASSERT (kfhp->fh_fsid_type == 0);
+       RFS_ASSERT (kfhp->fh_auth_type == 0);
+
+       dev = ntohs(kfhp->fh_dev_major);
+       dev = dev<<8;
+       dev = dev + ntohs(kfhp->fh_dev_minor);
+
+       /* kfhp->fh_dev_ino hold the inode number of export point of the mounted
+        * file system. For example, if /tmp/t1 is exported, /tmp/t1/t2 is mounted,
+        * then fh_dev_ino hold the inode number of t1, not t2
+        */
+
+       switch (kfhp->fh_fileid_type) {
+               case 0:
+                       printf("fh:type 0 root dev 0x%x dev_ino %d\n", dev, kfhp->fh_dev_ino); 
+                       break;
+               case 1:
+                       printf("fh:type 1 %d %x dev %x dev_ino %x\n", 
+                               kfhp->fh_ino, kfhp->fh_generation, dev, kfhp->fh_dev_ino);
+                       break;
+               case 2:
+                       printf("fh:type2 %d %x dirino %d dev 0x%x dev_ino %x\n", 
+                               kfhp->fh_ino, kfhp->fh_generation, kfhp->fh_dirino, dev, kfhp->fh_dev_ino);
+                       break;
+               default:
+                       RFS_ASSERT (0);
+       }
+}
+
+nfs_fh3 zero_fhandle;
+int init_fh_map ()
+{
+       memset (fh_map, 0, sizeof (fh_map));
+       memset(fh_htable, 0, sizeof (fh_htable));
+       memset (&zero_fhandle, 0, sizeof(nfs_fh3));
+       printf ("SIZE of fh map %d KB\n", sizeof (fh_map)/1000);
+       fh_i = 0;
+}
+
+int add_fh (int map_flag, char * trace_fh, char * path, nfs_fh3 * play_fh)
+{
+       char * old_trace_fh;
+
+       /* first lookup if the entry for fh is already in the table */
+    struct generic_entry * p;
+
+    p = generic_lookup (trace_fh, TRACE_FH_SIZE, 0, fh_htable, FH_HTABLE_SIZE);
+       if (p) {
+               RFS_ASSERT (fh_map[p->key3].flag = FH_MAP_FLAG_PARTIAL);
+               RFS_ASSERT (map_flag ==FH_MAP_FLAG_COMPLETE);
+               fh_map[p->key3].flag = map_flag;
+               //RFS_ASSERT (!memcmp(fh_map[p->key3].trace_fh, trace_fh, TRACE_FH_SIZE));
+               if (memcmp(fh_map[p->key3].trace_fh, trace_fh, TRACE_FH_SIZE)) {
+                       int i;
+                       printf ("fh_map[%d].trace_fh %s trace_fh %s", p->key3, fh_map[p->key3].trace_fh, trace_fh);
+                       for (i=0; i<fh_i; i++) {
+                               int * p1 = (int *)&(fh_map[i].play_fh);
+#ifdef COMPRESS_TRACE_FH
+                               int * p = (int *)fh_map[i].trace_fh;
+                               printf("fh_map[%d].trace_fh %8x%8x%8x%8x%8x%8x%8x%8x path %s \nnew_filehandle %8x%8x%8x%8x%8x%8x%8x%8x\n",
+                                i, *p, *(p+1), *(p+2), *(p+3), *(p+4), *(p+5), *(p+6), *(p+7), fh_map[i].path,
+                                *p1, *(p1+1), *(p1+2), *(p1+3), *(p1+4), *(p1+5), *(p1+6), *(p1+7));
+#else
+                               printf("fh_map[%d].trace_fh %s path %s \nnew_filehandle %8x%8x%8x%8x%8x%8x%8x%8x\n",
+                                i, fh_map[i].trace_fh, fh_map[i].path,
+                                *p1, *(p1+1), *(p1+2), *(p1+3), *(p1+4), *(p1+5), *(p1+6), *(p1+7));
+                       }
+#endif
+                       RFS_ASSERT (0);
+               }
+               RFS_ASSERT (!strcmp(fh_map[p->key3].path, path));
+               /* It's possible that in fh-path-map, many trace_fh are corresponding to one path
+                * some of it may be the result of lookup after symlink, which is not handled
+                * properly as new created objects 
+                */
+#ifdef TAKE_CARE_SYMBOLIC_LINK
+               RFS_ASSERT (!memcmp(&fh_map[p->key3].play_fh, &zero_fhandle, sizeof(nfs_fh3)));
+#endif
+               memcpy (&fh_map[p->key3].play_fh, play_fh, sizeof (nfs_fh3));
+               if ((fh_map_debug==1)) // || (stage ==TRACE_PLAY_STAGE)) 
+                       printf ("update the play_fh for trace_fh %s path %s \n", trace_fh, path);
+               return 0;
+       }
+
+       fh_map[fh_i].flag = map_flag;
+       fh_map[fh_i].lock = 0;
+       strncpy(fh_map[fh_i].trace_fh, trace_fh, TRACE_FH_SIZE);
+
+       RFS_ASSERT (strlen(path) < MAX_PLAY_PATH_SIZE);
+       strcpy (fh_map [fh_i].path, path);
+       if (map_flag==FH_MAP_FLAG_COMPLETE)
+               memcpy (&fh_map[fh_i].play_fh, play_fh, sizeof(nfs_fh3));
+       else 
+               memset (&fh_map[fh_i].play_fh, 0, sizeof(nfs_fh3));
+
+       if ((fh_map_debug==1)) { // || (stage ==TRACE_PLAY_STAGE)) {
+               printf ("insert trace_fh %s path %s play_fh:\n", trace_fh, path);
+               if (map_flag == FH_MAP_FLAG_COMPLETE) {
+                       //show_fhandle(play_fh);
+               } else 
+                       printf("null\n");
+       }
+
+/*
+       if (map_flag == FH_MAP_FLAG_DISCARD)
+               printf ("insert flag %d trace_fh %s path %s play_fh:\n", map_flag, trace_fh, path);
+*/
+
+    generic_insert(trace_fh, TRACE_FH_SIZE, fh_i, fh_htable, FH_HTABLE_SIZE);
+       
+       fh_i = (fh_i+1);
+       RFS_ASSERT (fh_i < FH_MAP_SIZE);
+
+    return 0;
+};
+
+inline fh_map_t * lookup_fh (char * trace_fh )
+{
+    struct generic_entry * p;
+    p = generic_lookup (trace_fh, TRACE_FH_SIZE, 0, fh_htable, FH_HTABLE_SIZE);
+       if (fh_map_debug==1)
+               printf ("lookup trace_fh %s\n", trace_fh);
+
+    if (p) {
+               if (fh_map_debug==1) {
+                       printf ("found: fh_i[%d] trace_fh %s path %s play_fh:\n", p->key3, fh_map[p->key3].trace_fh, fh_map[p->key3].path);
+                       //show_fhandle(&fh_map[p->key3].play_fh);
+               }
+               RFS_ASSERT (!memcmp(fh_map[p->key3].trace_fh, trace_fh, TRACE_FH_SIZE));
+        return (&(fh_map[p->key3]));
+    } else {
+               //printf ("lookup_fh %s not found\n", trace_fh);
+               if (stage != READ_DEP_TAB_STAGE && (fh_map_debug==1)) {
+                       printf ("lookup not found trace_fh %s\n", trace_fh);
+               }
+        return NULL;
+       }
+       RFS_ASSERT (0);
+}
+
+int delete_fh (char * trace_fh, int fh_map_index)
+{
+    generic_delete (trace_fh, TRACE_FH_SIZE, fh_map_index, fh_htable, FH_HTABLE_SIZE);
+    return 0;
+};
+
+int lookup_init_filesystem (nfs_fh3 * parent, char * name, nfs_fh3 * result)
+{
+    LOOKUP3args                args;
+    LOOKUP3res         reply;          /* the reply */
+    enum clnt_stat     rpc_stat;       /* result from RPC call */
+    struct ladtime     start;
+    struct ladtime     stop;
+       static int i=0;
+
+    /* set up the arguments */
+    (void) memcpy((char *) &args.what.dir, (char *) parent,
+                                                       sizeof (nfs_fh3));
+    args.what.name = name;
+    (void) memset((char *) &reply.resok.object, '\0', sizeof (nfs_fh3));
+
+    /* make the call */
+    sfs_gettime(&start);
+    rpc_stat = clnt_call(NFS_client, NFSPROC3_LOOKUP,
+                       xdr_LOOKUP3args, (char *) &args,
+                       xdr_LOOKUP3res, (char *) &reply,
+                       Nfs_timers[Init]);
+    sfs_gettime(&stop);
+
+       if (rpc_stat !=RPC_SUCCESS) {
+               printf("rpc_stat %d\n", rpc_stat);
+               perror("");
+       }
+    RFS_ASSERT (rpc_stat == RPC_SUCCESS);
+       (void) memcpy((char *) result, (char *) &reply.resok.object, sizeof (nfs_fh3));
+       return (reply.status);
+}
+
+void read_fh_map(char * fh_map_file)
+{
+       FILE * fp;
+       int i = 0;
+       char buf[1024];
+       char trace_fh[MAX_TRACE_FH_SIZE];
+       char intbuf[9];
+       char * trace_path;
+       char * p;
+       int map_flag;
+#define MAX_PATH_DEPTH 20
+       nfs_fh3 parents[MAX_PATH_DEPTH];
+       char * lookup_path_ptr[MAX_PATH_DEPTH];
+       char lookup_path [MAX_PLAY_PATH_SIZE];
+       int depth;
+       int new_dir_flag = 0;
+       int lineno = 0;
+
+       depth = 0;
+       memset(lookup_path_ptr, 0, sizeof(lookup_path_ptr));
+       memcpy(&parents[depth], &(Export_dir.fh_data->sfs_fh_un.f_fh3), sizeof(nfs_fh3));
+       strcpy(lookup_path, "/");
+       lookup_path_ptr[depth]=&lookup_path[0];
+
+       fp = fopen(fh_map_file, "r");
+       if (!fp) {
+               printf ("can not opern %s\n", fh_map_file);
+               perror("open");
+               exit (0);
+       }
+       RFS_ASSERT (fp!=NULL);
+       if (strstr(fh_map_file, "fmt1")) {
+               TRACE_FH_SIZE = 48;
+       }
+       
+       intbuf[8]=0;
+
+       memset(buf, 0, sizeof(buf));
+       while (fgets(buf, 1024, fp)) {
+               lineno ++;
+               if (fh_i % 10000==0)
+                       printf("%d fh_map entry read\n", fh_i);
+
+               RFS_ASSERT (buf[strlen(buf)-1]=='\n');
+               buf[strlen(buf)-1]=0;
+               if (fh_map_debug) {
+                       printf("%d fgets return %s\n", fh_i, buf);
+                       printf("depth %d lookup_path %s\n", depth, lookup_path);
+               }
+               //for (i=0; i<=depth; i++) 
+                       //printf("lookup_path_ptr[%d] %s ", i, lookup_path_ptr[i]);
+               //printf("\n");
+#ifdef COMPRESS_TRACE_FH 
+               for (i=0; i<TRACE_FH_SIZE/8; i++) {
+                       strncpy(intbuf, buf+i*8, 8);
+                       sscanf(intbuf, "%x", trace_fh+i*8); // maybe it should be 4, anyway we don't compress for now 
+               }
+               trace_path = buf+TRACE_FH_SIZE*2+1;             /* +1 the trace contains only initial file handle */
+#else
+               memcpy(trace_fh, buf, TRACE_FH_SIZE);
+               trace_path = buf + TRACE_FH_SIZE +1;
+#endif
+#ifdef TRACE_CONTAIN_LATER_FHANDLE
+               trace_path = +=2;       /* +3 if the trace contains both initial and later created file handle */
+#endif
+
+#ifdef NO_DEPENDENCY_TABLE
+               if (!strncmp (trace_path, "DISCARD", 7) ||
+                       !strncmp (trace_path, "LN", 2)                  ) {
+                       map_flag = FH_MAP_FLAG_DISCARD;
+                       add_fh (map_flag, buf, trace_path, 0);
+                       continue;
+               }
+#endif
+               
+               p = trace_path+strlen(trace_path)-2;
+               while (*p!='/')
+                       p--;
+               p++;
+               //RFS_ASSERT (p-trace_path<=strlen(lookup_path)+1);
+               //RFS_ASSERT (p>trace_path);
+
+               if (strncmp(lookup_path, trace_path, p-trace_path)) {
+                       printf("strncmp lookup_path %s trace_path %s for length %d\n", lookup_path, trace_path, p-trace_path);
+               }
+               RFS_ASSERT (!strncmp(lookup_path, trace_path, p-trace_path));
+               //while (strncmp(lookup_path, trace_path, p-trace_path)) {      /* one step deeper */
+               while (strlen(lookup_path)>p-trace_path && depth>0) {
+                       //printf("depth--\n");
+                       if (depth<=0) 
+                               printf ("lookup_path %s trace_path %s p-trace_path %d depth %d\n", lookup_path, trace_path, p-trace_path, depth);
+                       RFS_ASSERT (depth>0);
+                       *lookup_path_ptr[depth]=0;
+                       lookup_path_ptr[depth]=0;
+                       depth--;
+               }
+               RFS_ASSERT (strlen(lookup_path)==(p-trace_path) || (depth==0));
+
+
+#ifdef TRACE_CONTAIN_LATER_FHANDLE
+               if (buf[TRACE_FH_SIZE*2+1]=='Y') {
+                       map_flag = FH_MAP_FLAG_COMPLETE;
+               } else {
+                       map_flag = FH_MAP_FLAG_PARTIAL;
+                       RFS_ASSERT (buf[TRACE_FH_SIZE*2+1]=='N');
+               }
+#else
+               map_flag = FH_MAP_FLAG_COMPLETE;
+#endif
+               if ((*(p+strlen(p)-1))=='/') {
+                       *(p+strlen(p)-1)=0;
+                       new_dir_flag = 1;
+               } else 
+                       new_dir_flag = 0;
+
+               if (map_flag == FH_MAP_FLAG_COMPLETE) {
+                       int ret = lookup_init_filesystem (&parents[depth], p, &parents[depth+1]);               
+                       if (ret!=NFS3_OK) {
+                               printf ("lineno %d %s\n", lineno, buf);
+                       }
+                       RFS_ASSERT (ret == NFS3_OK);
+                       add_fh (map_flag, buf, trace_path, &parents[depth+1]);  
+               } else 
+                       add_fh (map_flag, buf, trace_path, 0);
+
+               if (new_dir_flag) {
+                       /* the new fhandle is of a directory */
+                       lookup_path_ptr[depth+1] = lookup_path+strlen(lookup_path);
+                       strcat (lookup_path, p);
+                       strcat (lookup_path, "/");
+
+                       //printf("depth++\n");
+                       depth++;
+               }
+
+               memset(buf, 0, sizeof(buf));
+       }
+                       
+       if (fh_map_debug) {
+               for (i=0; i<fh_i; i++) {
+                       int * p1 = (int *)&(fh_map[i].play_fh);
+#ifdef COMPRESS_TRACE_FH
+                       int * p = (int *)fh_map[i].trace_fh;
+                       printf("fh_map[%d].trace_fh %8x%8x%8x%8x%8x%8x%8x%8x path %s \nnew_filehandle %8x%8x%8x%8x%8x%8x%8x%8x\n",
+                        i, *p, *(p+1), *(p+2), *(p+3), *(p+4), *(p+5), *(p+6), *(p+7), fh_map[i].path,
+                        *p1, *(p1+1), *(p1+2), *(p1+3), *(p1+4), *(p1+5), *(p1+6), *(p1+7));
+#else
+                       printf("fh_map[%d].trace_fh %s path %s \nnew_filehandle %8x%8x%8x%8x%8x%8x%8x%8x\n",
+                        i, fh_map[i].trace_fh, fh_map[i].path,
+                        *p1, *(p1+1), *(p1+2), *(p1+3), *(p1+4), *(p1+5), *(p1+6), *(p1+7));
+               }
+#endif
+
+               fprintf(stderr, "total %d requests \n", i);
+       }
+}
+
+int f()
+{
+       return 1;
+}
+
+inline free_biod_req (int biod_index)
+{
+       RFS_ASSERT (biod_reqp[biod_index].in_use == TRUE);
+       biod_reqp[biod_index].in_use = FALSE;
+       num_out_reqs --;
+}
+
+void finish_request (int biod_index, int dep_index, int status, int dep_flag)
+{
+       static int i = 0;
+       /* the ending operation, same as when a request time out */
+
+       dep_tab[dep_index].stop = biod_reqp[biod_index].stop;   /* RFS: to dump data */
+       free_biod_req (biod_index);
+
+       dep_tab[dep_index].status = status;
+
+       if (event_order_index < EVENT_ORDER_SIZE)
+               event_order[event_order_index++] = -dep_tab[dep_index].disk_index;
+
+       dep_tab[dep_index].flag = dep_flag;
+       if (is_dir_op(dep_tab[dep_index].proc)) {
+               int j;
+               RFS_ASSERT (dep_tab[dep_index].fh->lock = 1);
+               dep_tab[dep_index].fh->lock = 0;
+               if (dep_tab[dep_index].proc==RENAME)
+                       dep_tab[dep_index].fh_2->lock = 0;
+               j = dep_tab[dep_index].fh-fh_map;
+               if (dependency_debug) {
+                       printf ("fh_map[%d] is UNlocked\n",j);
+                       printf ("trace_fh %d path %s\n", dep_tab[dep_index].fh->trace_fh, dep_tab[dep_index].fh->path);
+                       printf ("trace_fh %d path %s\n", fh_map[j].trace_fh, fh_map[j].path);
+               }
+       }
+}
+
+/* the request argument may have pointers pointing to buffers, e.g. the name in lookup, 
+ * the target of symlink, the write data */
+char arg_res[MAX_ARG_RES_SIZE];
+char buf1 [MAX_BUF1_SIZE]; 
+char buf2 [MAX_BUF2_SIZE];
+
+int execute_next_request ()
+{
+       int dep_index;
+       int proc;
+       char * line;
+       struct biod_req * reqp;
+       sfs_op_type *op_ptr;            /* per operation info */
+       struct ladtime call_timeout;
+       static int last_print_time = -1;
+
+       if (num_out_reqs == max_biod_reqs) {
+               return -1;
+       }
+
+       start_profile (&valid_get_nextop_profile);
+       start_profile (&invalid_get_nextop_profile);
+       dep_index = get_nextop();
+       if (dep_index == -1) {
+               end_profile (&invalid_get_nextop_profile);
+               return dep_index;
+       };
+       end_profile (&valid_get_nextop_profile);
+
+       start_profile (&prepare_argument_profile);
+       line = dep_tab[dep_index].line;
+
+       if (per_packet_debug)
+               fprintf (stdout, "time %d processing dep_tab[%d] disk_index %d num_out_reqs %d can_not_catch_speed_num %d PLAY_SCALE %d \n", total_profile.in.tv_sec, dep_index, dep_tab[dep_index].disk_index, num_out_reqs, can_not_catch_speed_num, PLAY_SCALE);
+
+       end_profile(&total_profile);
+       if ((total_profile.in.tv_sec - last_print_time >= 10)) {
+               last_print_time = total_profile.in.tv_sec;
+               //fprintf (stdout, "time %d processing dep_tab[%d] disk_index %d num_out_reqs %d can_not_catch_speed_num %d PLAY_SCALE %d \n", total_profile.in.tv_sec, dep_index, dep_tab[dep_index].disk_index, num_out_reqs, can_not_catch_speed_num, PLAY_SCALE);
+/*
+               CYCLIC_PRINT (dep_tab_index);
+               {
+                       int tmp = CYCLIC_MINUS(dep_tab_index.head,1,dep_tab_index.size);
+                       printf("dep_tab_index.head-1 %d disk_index %d tail %d disk_index %d\n", tmp, dep_tab[tmp].disk_index,
+                       dep_tab_index.tail, dep_tab[dep_tab_index.tail].disk_index);
+               }
+*/
+#ifdef TIME_PLAY
+#ifdef SPEED_UP
+/*
+               if (can_not_catch_speed_num < 2000) {
+                       PLAY_SCALE ++;
+                       printf ("set PLAY_SCALE to %d\n", PLAY_SCALE);
+               };
+               if (can_not_catch_speed_num > 50000) {
+                       PLAY_SCALE /= 2;
+               } else {
+                       if (can_not_catch_speed_num > 5000) {
+                               PLAY_SCALE -= 2;
+                               if (PLAY_SCALE < 1)
+                                       PLAY_SCALE = 1;
+                       }
+               }
+*/
+#endif
+               if ((total_profile.in.tv_sec > 100)) {
+                       can_not_catch_speed_num_total += can_not_catch_speed_num;
+               }
+               can_not_catch_speed_num = 0;
+#endif
+       }
+       if (rfs_debug)
+               printf ("processing dep_tab[%d] disk_index %d %s\n", dep_index, dep_tab[dep_index].disk_index, line);
+
+       proc = dep_tab[dep_index].proc;
+       rfs_Ops[proc].setarg (dep_index, line, arg_res, buf1, buf2);
+
+       op_ptr = &Ops[proc];
+       reqp = get_biod_req (dep_index);
+       RFS_ASSERT (reqp);
+
+#ifdef notdef  /* place to set request timeout. G. Jason Peng */
+       call_timeout.sec = 2; //Nfs_timers[op_ptr->call_class].tv_sec;
+       call_timeout.usec = Nfs_timers[op_ptr->call_class].tv_usec;
+#else
+       call_timeout.sec = 0;
+       call_timeout.usec = 300000;
+       //call_timeout.usec = 14000;
+       //call_timeout.usec = 13000;
+       //call_timeout.usec = 6000;
+       //call_timeout.usec = 8000;
+       //call_timeout.usec = 10000;
+#endif
+
+    /* make the call */
+    sfs_gettime(&(reqp->start));
+       end_profile (&prepare_argument_profile);
+       start_profile (&biod_clnt_call_profile);
+#define REAL_PLAY
+#ifdef REAL_PLAY
+
+#ifdef RECV_THREAD
+       //printf ("send thread waitsem\n");
+       waitsem(async_rpc_sem);
+       //printf ("send thread got sem\n");
+#endif
+    reqp->xid = biod_clnt_call(NFS_client, rfs_Ops[proc].nfsv3_proc, 
+                                       rfs_Ops[proc].xdr_arg, arg_res);
+#ifdef RECV_THREAD
+       postsem(async_rpc_sem);
+       //printf ("send thread postsem\n");
+#endif
+
+#else  // REAL_PLAY
+       reqp->xid = dep_index+1;        /* just fake a message id and let it expire */
+#endif
+    RFS_ASSERT (reqp->xid != 0);
+    reqp->timeout = reqp->start;
+    ADDTIME (reqp->timeout, call_timeout);
+    dep_tab[dep_index].flag = DEP_FLAG_SENT;
+       if (event_order_index < EVENT_ORDER_SIZE)
+               event_order[event_order_index++] = dep_tab[dep_index].disk_index;
+
+       dep_tab[dep_index].start = reqp->start; /* RFS: to dump data */
+       end_profile (&biod_clnt_call_profile);
+
+       send_num ++;
+}
+
+void check_reply (int proc, int biod_index, int dep_index, int status, char * errmsg, int trace_status)
+{
+       if (((status!=trace_status)) && (status!=NFS3_OK) && (trace_status!=NFS3ERR_RFS_MISS)) {
+               if (!profile_debug)
+                       printf ("receive problem reply, xid %x nfs_ret %d %s trace_status %d start %d:%d stop %d:%d command disk index %d\n", biod_reqp[biod_index].xid, status, errmsg, trace_status, biod_reqp[biod_index].start.sec, biod_reqp[biod_index].start.usec, biod_reqp[biod_index].stop.sec, biod_reqp[biod_index].stop.usec, dep_tab[dep_index].disk_index); 
+#ifndef TAKE_CARE_UNLOOKED_UP_NON_NEW_FILES
+               /* these files is not looked up and is not create/mkdir/symlink/link/mknod ed before they
+                * are refered by name through rename, remove
+                */
+               if ((proc==RENAME || proc==REMOVE) && (status==NFS3ERR_NOENT) && (trace_status ==0)) {
+                       /* current initialization doesnot take care of rename source, if there is no
+                        * create or lookup before that source, the source object will not exist when
+                        * rename occurs
+                        */
+                       rename_rmdir_noent_reply_num++;
+               } else 
+#endif
+#ifndef TAKE_CARE_SYMBOLIC_LINK
+               if ((proc==LOOKUP) && (status==NFS3_OK) && (trace_status==NFS3ERR_NOENT)) {
+                       /* in the original trace, first lookup return NOENT, then symlink is executed, then lookup return OK
+                        * the initialization considers only the lookup return OK and created the file in the initialization
+                        * so in trace play the first lookup return OK
+                        */
+                       RFS_ASSERT (1);
+               } else // if ((proc==SYMLINK) && (status == NFS3ERR_EXIST) && (trace_status == 0)) {
+                               /* trace_status could be EAGAIN */
+                       if ((proc==SYMLINK) && (status == NFS3ERR_EXIST) ) {
+                       /* due to similar reason as above, the initialization code initializes the symbolic link as a normal
+                        * file already
+                        */
+                       RFS_ASSERT (1);
+               } else
+#endif
+#ifndef TAKE_CARE_NOEMPTY_RMDIR
+               /* the remove packet seems got lost in the trace capture, so replay can not finish */
+               if ((proc==RMDIR) && (status==NFS3ERR_NOTEMPTY)) {
+                       RENAME3args             args;
+                       RENAME3res              reply;          /* the reply */
+                       RMDIR3args * rmdir_argp;
+                       enum clnt_stat rpc_stat;        /* result from RPC call */
+
+                       rfs_Ops[proc].setarg (dep_index, dep_tab[dep_index].line, arg_res, buf1, buf2);
+                       rmdir_argp = (RMDIR3args *)arg_res;
+
+                       memcpy(&args.from, &(rmdir_argp->object), sizeof (diropargs3));
+                       memcpy(&args.to.dir, &(Export_dir.fh_data->sfs_fh_un.f_fh3), sizeof(nfs_fh3));
+                       args.from.name = buf1;  /* the buf1 is already filled when parsing rmdir */
+                       args.to.name = buf2;
+                       sprintf(buf2, "rmdir_%d_%s", dep_tab[dep_index].disk_index, rmdir_argp->object.name);
+
+                       rpc_stat = clnt_call(NFS_client, NFSPROC3_RENAME,
+                       xdr_RENAME3args, (char *) &args,
+                       xdr_RENAME3res, (char *) &reply,
+                               Nfs_timers[Init]);
+                       RFS_ASSERT (rpc_stat == RPC_SUCCESS);
+                       if (reply.status!=NFS3_OK)
+                               printf ("change rmdir into rename, reply.status %d\n", reply.status);
+                       RFS_ASSERT (reply.status==NFS3_OK);
+                       rmdir_not_empty_reply_num ++;
+#endif
+#ifndef TAKE_CARE_ACCESS_ERROR
+               } else if ((status==0) && (trace_status==NFS3ERR_ACCES)) {
+                       loose_access_control_reply_num ++;
+#endif
+#ifdef NO_DEPENDENCY_TABLE 
+               } else if ((proc==LOOKUP) && (status==NFS3ERR_NOENT) && (trace_status==NFS3_OK)) {
+                       lookup_err_due_to_rename_num ++;
+               } else if ((proc==LOOKUP) && (status==NFS3_OK) && (trace_status == NFS3ERR_NOENT)) {
+                       /* if there is a remove in front of the lookup, but it is
+                        * actually executed later than the lookup
+                        */
+                       lookup_err_due_to_parallel_remove_num ++;
+#endif
+#ifndef TAKE_CARE_LOOKUP_EACCESS_ENOENT_MISMATCH
+               /* if the looked return EACCESS in the trace, means the object still exists
+                * should have initialized, right not don't initialize it, hence play status 
+                * could be ENOENT
+                */
+               } else if ((proc==LOOKUP) && (status==NFS3ERR_NOENT) && (trace_status==NFS3ERR_ACCES)) {
+                       lookup_eaccess_enoent_mismatch_num ++;
+#endif
+#ifdef TOLERANT_READ_IO_ERR
+               } else if ((proc==READ) && (status==NFS3ERR_IO) && (trace_status==NFS3_OK)) {
+                       read_io_err_num ++;
+#endif
+#ifdef TOLERANT_STALE_FHANDLE_ERR
+               } else if ((status==NFS3ERR_STALE) && (trace_status==NFS3_OK)) {
+                       printf ("!!!!!!! STALE FILE HANDLE \n");
+                       //sleep(1);
+                       stale_fhandle_err_num ++;
+#endif
+               } else {
+                       int i;
+                       for (i=dep_window_index.tail; CYCLIC_LESS(dep_window_index,i,dep_window_index.head); i++) {
+                               if (dep_tab[i].flag!=1)
+                                       printf ("dep_tab[%d].disk_index %d, flag %d line %s\n", i, dep_tab[i].disk_index, dep_tab[i].flag, dep_tab[i].line);
+                       }
+
+                       if (status==EEXIST) {
+                               abnormal_EEXIST_num ++;
+                       } else if (status == ENOENT) {
+                               abnormal_ENOENT_num ++;
+                       } else {
+                               printf ("!!!!!!!!!!!!!1 should fail\n");
+                               //RFS_ASSERT (0);
+                       }
+               }
+       } else {
+               proper_reply_num ++;
+               if (total_profile.in.tv_sec >= WARMUP_TIME) 
+                       run_stage_proper_reply_num ++;
+       }
+
+}
+
+/* return -1 if there is no reply being received 
+ * return the dep_index if the corresponding reply has been received
+ */
+int receive_next_reply (int busy_flag)
+{
+       int dep_index;
+       int biod_index;
+       int proc;
+       char * line;
+       char * reply_line;
+       sfs_op_type *op_ptr;            /* per operation info */
+       int ret;
+       int status;
+       int trace_status;
+       char * errmsg;
+       int poll_timeout = 0;           /* timeout in usecs */
+
+       /* wait for reply */
+       start_profile (&valid_poll_and_get_reply_profile);
+       start_profile (&invalid_poll_and_get_reply_profile);
+
+       if (busy_flag == BUSY) {
+               poll_timeout = 0;
+               poll_timeout_0_num ++;
+       } else {
+               poll_timeout = 2000;    /* 10000 or 2000 is a better number in non-debugging state */
+               //poll_timeout = 0;     /* 10000 or 2000 is a better number in non-debugging state */
+               poll_timeout_pos_num ++;
+       }
+
+       biod_index = poll_and_get_reply (poll_timeout);
+       if (biod_index==-1) {
+               end_profile (&invalid_poll_and_get_reply_profile);
+               return -1;
+       };
+       end_profile (&valid_poll_and_get_reply_profile);
+
+       start_profile (&decode_reply_profile);
+       /* check the corresponding request */
+       dep_index = biod_reqp[biod_index].dep_tab_index;
+       if (biod_reqp[biod_index].in_use==1) {
+               RFS_ASSERT (dep_tab[dep_index].biod_req_index == biod_index);
+       } else {
+               printf ("biod_index %d reply received but the request has been time out\n", biod_index);
+               return -1;
+       }
+
+       proc = dep_tab[dep_index].proc;
+       op_ptr = &Ops[proc];
+
+       if (dep_tab[dep_index].flag != DEP_FLAG_SENT) {
+               printf("dep_tab[%d].flag %d proc %d status %d start %d:%d stop %d:%d\n",
+                       dep_index, dep_tab[dep_index].flag, proc, dep_tab[dep_index].status, 
+                       dep_tab[dep_index].start.sec, dep_tab[dep_index].start.usec,
+                       dep_tab[dep_index].stop.sec, dep_tab[dep_index].stop.usec );
+               printf ("received reply for timeout requests dep_tab[%d].disk_index %d\n", dep_index, dep_tab[dep_index].disk_index);
+               return dep_index;
+       }
+       RFS_ASSERT (dep_tab[dep_index].flag == DEP_FLAG_SENT);
+
+       /* decode the reply */
+       rfs_Ops[proc].setres (arg_res, buf1);
+       ret = proc_header (NFS_client, rfs_Ops[proc].xdr_res, arg_res);
+       RFS_ASSERT (ret == RPC_SUCCESS);
+       status = *((int *)arg_res);
+       errmsg = nfs3_strerror (status);
+       end_profile (&decode_reply_profile);
+
+       start_profile (&check_reply_profile);
+       /* compare with the reply in the trace */
+       line = dep_tab[dep_index].line;
+       reply_line = dep_tab[dep_index].reply_line;
+       trace_status = dep_tab[dep_index].trace_status;
+
+       if (per_packet_debug || rfs_debug )
+               fprintf (stdout, "dep_tab[%d], disk_index %d, receive reply, rpc_ret %d xid %x nfs_ret %d %s trace_status %d start %d:%d stop %d:%d \n", dep_index, dep_tab[dep_index].disk_index, ret, biod_reqp[biod_index].xid, status, errmsg, trace_status, biod_reqp[biod_index].start.sec, biod_reqp[biod_index].start.usec, biod_reqp[biod_index].stop.sec, biod_reqp[biod_index].stop.usec);
+
+       /* error checking */
+       check_reply (proc, biod_index, dep_index, status, errmsg, trace_status);
+
+       /* free resources */
+       finish_request (biod_index, dep_index, status, DEP_FLAG_DONE);
+       recv_num ++;
+       
+       /* we set 100 seconds warm up time */
+       if ((total_profile.in.tv_sec >= WARMUP_TIME)) {
+       /* get statistics */
+       if (status == trace_status || (status==NFS3_OK && trace_status==NFS3ERR_RFS_MISS) ) {
+               op_ptr->results.good_calls++;
+               Ops[TOTAL].results.good_calls++;
+       } else {
+               op_ptr->results.bad_calls++;
+               Ops[TOTAL].results.bad_calls++;
+       }
+       sfs_elapsedtime (op_ptr, &(biod_reqp[biod_index].start), &(biod_reqp[biod_index].stop));
+       end_profile (&check_reply_profile);
+       }
+       
+       //start_profile (&add_create_object_profile);
+
+       if (trace_status == NFS3_OK && (proc==CREATE || proc==MKDIR || proc==SYMLINK || proc==MKNOD)) {
+#ifndef REDUCE_MEMORY_TRACE_SIZE
+               RFS_ASSERT (reply_line);
+#endif
+               if (status!=NFS3_OK) {
+                       /* commented out for 1022 */
+                       printf ("!!!!!! Should have been an ASSERTION FAILURE \n");
+                       RFS_ASSERT (proc==SYMLINK);
+                       RFS_ASSERT (0);
+               } else {
+                       if (proc!=SYMLINK || line[TRACE_VERSION_POS]!='2')
+                               add_new_file_system_object(proc, dep_index, line, reply_line);
+               }
+       }
+       //end_profile (&add_create_object_profile);
+}
+
+inline void add_new_file_system_object (int proc, int dep_index, char * line, char * reply_line)
+{
+       char * child_trace_fh;
+       fh_map_t * parent_entryp;
+       char component_name[MAX_PLAY_PATH_SIZE];
+       char * parent_trace_fh;
+       char child_path[MAX_PLAY_PATH_SIZE];
+       post_op_fh3 * post_op_fh3_child;
+       char * reply_trace_fh;
+       nfs_fh3 * child_fh3;
+
+       parent_trace_fh = strstr (line, "fh");
+       RFS_ASSERT (parent_trace_fh);
+       parent_trace_fh +=3;
+       parent_entryp = lookup_fh (parent_trace_fh);
+       RFS_ASSERT (parent_entryp);
+       parse_name (parent_trace_fh+65, component_name);
+       strcpy (child_path, parent_entryp->path);
+       strcat (child_path, "/");
+       strcat (child_path, component_name);
+                               
+       /* find the corresponding create request */
+       //printf ("before find reply trace_fh reply_line %s\n", reply_line);
+#ifdef REDUCE_MEMORY_TRACE_SIZE
+       reply_trace_fh = dep_tab[dep_index].reply_trace_fh;
+#else
+       reply_trace_fh = find_reply_trace_fh (reply_line);
+#endif
+       RFS_ASSERT (reply_trace_fh != NULL);
+       switch (proc) {
+       case CREATE:
+               RFS_ASSERT (((CREATE3res *)arg_res)->res_u.ok.obj.handle_follows==TRUE);
+               child_fh3 = &((CREATE3res *)arg_res)->res_u.ok.obj.handle;
+               break;
+       case MKDIR:
+               RFS_ASSERT (((MKDIR3res *)arg_res)->res_u.ok.obj.handle_follows==TRUE);
+               child_fh3 = &((MKDIR3res *)arg_res)->res_u.ok.obj.handle;
+               break;
+       case SYMLINK:
+               RFS_ASSERT (((SYMLINK3res *)arg_res)->res_u.ok.obj.handle_follows==TRUE);
+               child_fh3 = &((SYMLINK3res *)arg_res)->res_u.ok.obj.handle;
+               break;
+       case MKNOD:
+               RFS_ASSERT (((MKNOD3res *)arg_res)->res_u.ok.obj.handle_follows==TRUE);
+               child_fh3 = &((MKNOD3res *)arg_res)->res_u.ok.obj.handle;
+               break;
+       case LOOKUP:
+               RFS_ASSERT (proc==LOOKUP);
+               child_fh3 = &((LOOKUP3res *)arg_res)->res_u.ok.object;
+               break;
+       default:
+               RFS_ASSERT (0);
+       }
+#ifndef REDUCE_MEMORY_TRACE_SIZE
+       RFS_ASSERT (reply_trace_fh[TRACE_FH_SIZE]==' ');
+#endif
+       reply_trace_fh[TRACE_FH_SIZE] = 0;
+       add_fh (FH_MAP_FLAG_COMPLETE, reply_trace_fh, child_path, child_fh3);   /* exist flag is not used now, set to 1 */
+#ifndef REDUCE_MEMORY_TRACE_SIZE
+       /* just to preserve the original reply line not changed */
+       reply_trace_fh[TRACE_FH_SIZE] = ' ';
+#endif
+}
+
+/* initialize timestamp and proc field of dep_tab entry */
+void trace_play(void)
+{
+       
+       /* The flag to indicate whether trace_player is BUSY. Trace_player is BUSY
+        * when either there is request to send or there is reply being
+        * received. Otherwise it is IDLE. The timeout for polling replies 
+        * is set to 0 when BUSY, it is set to the waiting time to the first
+        * request outside of current <min_dep_index, dep_window_max> window when IDLE.
+        */
+       int busy_flag = BUSY;           
+       //int dep_index;                /* index into dependency table: dep_tab */
+       //int biod_index;       /* index into outstanding requests: biod_reqp */
+       static int last_print_time = -1;
+       int poll_timeout = 0;
+
+#ifndef IO_THREAD
+       disk_io_status = read_trace();
+#endif
+
+       RFS_ASSERT (!CYCLIC_EMPTY(dep_tab_index));
+       CYCLIC_MOVE_HEAD(dep_window_index);
+
+       adjust_play_window(busy_flag, &poll_timeout);
+
+       start_profile (&total_profile);
+       while (!CYCLIC_EMPTY(dep_tab_index)) {
+               end_profile(&total_profile);
+               if ((total_profile.in.tv_sec - last_print_time >= 10)) {
+                       int i;
+
+                       last_print_time = total_profile.in.tv_sec;
+                       fprintf (stdout, ">>>> sendng thread: time %d send_num %d recv_num %d timeout_num %d num_out_reqs %d can_not_catch_speed_num %d PLAY_SCALE %d \n", total_profile.in.tv_sec, send_num, recv_num, timeout_num, num_out_reqs, can_not_catch_speed_num, PLAY_SCALE);
+                       for (i=0; i<=MAX_OUTSTANDING_REQ; i++) {
+                               if (num_out_reqs_statistics[i]!=0) {
+                                       printf("num_out_req[%d]=%d,", i, num_out_reqs_statistics[i]);
+                                       num_out_reqs_statistics[i]=0;
+                               }
+                       }
+                       printf("\n");
+                       for (i=0; i<=MAX_OUTSTANDING_REQ; i++) {
+                               if (num_out_reqs_statistics_at_timeout[i]!=0) {
+                                       printf("num_out_req_at_timeout[%d]=%d,", i, num_out_reqs_statistics_at_timeout[i]);
+                                       num_out_reqs_statistics_at_timeout[i]=0;
+                               }
+                       }
+                       printf("\n");
+                       //      CYCLIC_PRINT(dep_tab_index);
+               }
+
+               if ((total_profile.in.tv_sec > 6000)) {
+                       printf ("the process has run for more than 600 seconds, exit\n");
+                       goto END;
+               }
+
+               if (busy_flag == IDLE) {
+#ifndef RECV_THREAD
+                       //start_profile (&check_timeout_profile);
+                       check_timeout();
+                       //end_profile (&check_timeout_profile);
+#endif
+#ifndef IO_THREAD
+                       if (disk_io_status!=TRACE_FILE_END) {
+                               disk_io_status = read_trace();
+                       };
+#endif
+               }
+
+               //start_profile (&adjust_play_window_profile);
+               adjust_play_window (busy_flag, &poll_timeout);
+               if (rfs_debug)
+                       printf("num_out_reqs %d\n", num_out_reqs);
+               num_out_reqs_statistics[num_out_reqs]++;
+               busy_flag = IDLE;
+               //end_profile (&adjust_play_window_profile);
+
+               start_profile (&execute_next_request_profile);
+               while (execute_next_request()!=-1) {
+                       busy_flag = BUSY;
+               }
+               end_profile (&execute_next_request_profile);
+
+#ifndef RECV_THREAD
+               start_profile (&receive_next_reply_profile);
+               /* actually the performance of two policy seems to be same */
+//#define SEND_HIGHER_PRIORITY_POLICY
+#define SEND_RECEIVE_EQUAL_PRIORITY_POLICY     
+
+#ifdef SEND_HIGHER_PRIORITY_POLICY
+               receive_next_reply(IDLE);
+#endif
+#ifdef SEND_RECEIVE_EQUAL_PRIORITY_POLICY
+               busy_flag = IDLE;
+               while (receive_next_reply(busy_flag)!=-1)
+                       busy_flag = BUSY;
+#endif
+               end_profile (&receive_next_reply_profile);
+#endif
+               CYCLIC_ASSERT (0);
+       }
+       end_profile (&total_profile);
+
+       RFS_ASSERT (disk_io_status == TRACE_FILE_END);
+       if (num_out_reqs !=0 ) {
+               printf ("num_out_reqs %d\n", num_out_reqs);
+               CYCLIC_PRINT(dep_tab_index);
+       }
+       RFS_ASSERT(num_out_reqs==0);
+
+END:
+       printf ("trace starttime %d, trace_end_time %d trace_duration %d\n", trace_timestamp1, trace_timestamp2,
+               trace_timestamp2 - trace_timestamp1);
+       printf ("can_not_catch_speed_num_total %d can_not_catch_speed_num_last_10_seconds %d", 
+               can_not_catch_speed_num_total, can_not_catch_speed_num);
+       printf ("total_profile.about: %s\n", total_profile.about);
+       print_profile ("total_profile", &total_profile);
+       printf("\n");
+       //print_profile ("check_timeout", &check_timeout_profile);
+       //printf("\n");
+       //print_profile ("adjust_play_window", &adjust_play_window_profile);
+       //printf("\n");
+       print_profile ("execute_next_request_profile", &execute_next_request_profile);
+       print_profile ("valid_get_nextop_profile", &valid_get_nextop_profile);
+       print_profile ("invalid_get_nextop_profile", &invalid_get_nextop_profile);
+       print_profile ("prepare_argument_profile", &prepare_argument_profile);
+       print_profile ("biod_clnt_call_profile", &biod_clnt_call_profile);
+       printf("\n");
+       print_profile ("receive_next_reply_profile", &receive_next_reply_profile);
+       print_profile ("valid_poll_and_get_reply_profile", &valid_poll_and_get_reply_profile);
+       print_profile ("invalid_poll_and_get_reply_profile", &invalid_poll_and_get_reply_profile);
+       print_profile ("decode_reply_profile", &decode_reply_profile);
+       print_profile ("check_reply_profile", &check_reply_profile);
+       print_profile ("fgets_profile", &fgets_profile);
+       print_profile ("read_line_profile", &read_line_profile);
+       print_profile ("read_trace_profile", &read_trace_profile);
+       //print_profile ("add_create_object", &add_create_object_profile);
+       printf("\n");
+       
+       printf ("dep_tab_index.tail %d dep_tab_index.head %d num_out_reqs %d\n", dep_tab_index.tail, dep_tab_index.head, num_out_reqs);
+}
+
+
+int CYCLIC_SET_TAIL_TO(cyclic_index_t * index, int dest) 
+{ 
+       cyclic_index_t indextmp, indextmp2;
+       int oldnum, num;
+       indextmp = *index;
+       indextmp2 = indextmp;
+       oldnum = CYCLIC_NUM(indextmp); 
+
+       if (! ((dest>=0) && (dest<indextmp.size))) {
+               CYCLIC_PRINT(indextmp);
+               printf("dest %d\n", dest);
+       }
+       RFS_ASSERT ((dest>=0) && (dest<indextmp.size));
+       index->tail = dest; 
+       indextmp2.tail = dest;
+       num = CYCLIC_NUM(indextmp2); 
+
+       if (num > oldnum) { 
+               CYCLIC_PRINT(indextmp);
+               CYCLIC_PRINT(indextmp2);
+               printf("dest %d old_num %d num %d\n", dest, oldnum, num);
+       }
+       RFS_ASSERT (num <= oldnum);
+}
+
+int flush_junk()
+{
+       int i;
+       for (i=0; i<500; i++) {
+               printf ("*************************************************************\n");
+       }
+       fflush(stdout);
+}
+
+int CYCLIC_ASSERT (int i)
+{
+       int j;
+       if (!(dep_tab_index.tail == dep_window_index.tail)) {
+               printf("%s head %d tail %d, size %d\n", dep_tab_index.name, dep_tab_index.head, dep_tab_index.tail, dep_tab_index.size);
+               printf("%s head %d tail %d, size %d\n", dep_window_index.name, dep_window_index.head, dep_window_index.tail, dep_window_index.size);
+               printf("pos %d\n", i); 
+               flush_junk();
+               sleep (10);
+               RFS_ASSERT (0);
+       };
+       if (!((dep_window_index.head == dep_tab_index.head) || 
+                  CYCLIC_LESS(dep_tab_index, dep_window_index.head, dep_tab_index.head ) )) {
+               printf("%s head %d tail %d, size %d\n", dep_tab_index.name, dep_tab_index.head, dep_tab_index.tail, dep_tab_index.size);
+               printf("%s head %d tail %d, size %d\n", dep_window_index.name, dep_window_index.head, dep_window_index.tail, dep_window_index.size);
+               printf("pos %d\n", i); 
+               flush_junk();
+               sleep (10);
+               RFS_ASSERT (0);
+       };
+       for (i=0, j=0; i<max_biod_reqs; i++) {
+               if (biod_reqp[i].in_use == 1)
+                       j++;
+       }
+#ifndef RECV_THREAD
+       RFS_ASSERT (num_out_reqs==j);
+#endif
+/*
+               RFS_ASSERT ((dep_window_index.head == dep_tab_index.head) || 
+                          CYCLIC_LESS(dep_tab_index, dep_window_index.head, dep_tab_index.head ));
+*/
+}
+
+/* sfs_c_chd.c */