X-Git-Url: http://git.vrable.net/?a=blobdiff_plain;f=TBBT%2Ftrace_play%2Fsfs_c_chd.c.old.2;fp=TBBT%2Ftrace_play%2Fsfs_c_chd.c.old.2;h=a8c71f712d92b2633d0f3258f36238217e170731;hb=adc8816a09e5b6be2e58f4a7c28d2418a74cce9c;hp=0000000000000000000000000000000000000000;hpb=145b4756946bbd443452ec1b2081984795de70d0;p=bluesky.git diff --git a/TBBT/trace_play/sfs_c_chd.c.old.2 b/TBBT/trace_play/sfs_c_chd.c.old.2 new file mode 100644 index 0000000..a8c71f7 --- /dev/null +++ b/TBBT/trace_play/sfs_c_chd.c.old.2 @@ -0,0 +1,2294 @@ +#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 +#include +#include +#include +#include +#include + +#include +#include + +#include + +#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 void read_trace(char * trace_file); +static void read_fh_map(); +static void init_play (char * mount_point); +static void trace_play(void); +static 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); +static void adjust_play_window (int flag, int * poll_timeout); +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 fh_map_t * lookup_fh (char * trace_fh ); +static inline void finish_request (int biod_index, int dep_index, int status); +static void add_new_file_system_object (int proc, int dep_index, char * line, char * reply_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; +/* + * ------------------------- SFS Child ------------------------- + */ + +void print_usage() +{ + printf("sfs3 hostname:mount_dir trace_file fh_map_file\n"); + exit; +} + +void read_dep_tab() +{ +#ifdef NO_DEPENDENCY_TABLE + int i; + char * line; + char * trace_fh; + fh_map_t * fh_map_entry; + int req_num_with_new_fh = 0; + int req_num_with_discard_fh = 0; + int req_num_with_init_fh =0; + + for (i=0; iflag==FH_MAP_FLAG_DISCARD) ) { + req_num_with_discard_fh ++; + continue; + } + if (fh_map_entry) + req_num_with_init_fh ++; + else + req_num_with_new_fh ++; + + dep_tab[dep_tab_size].disk_index = memory_trace[i].disk_index; + dep_tab[dep_tab_size].line = memory_trace[i].line; + if ((dep_tab_size%100000)==0) + printf ("dep_tab[%d].disk_index %d = memory_trace[%d].disk_index %d\n", dep_tab_size, dep_tab[dep_tab_size].disk_index, i, memory_trace[i].disk_index); + dep_tab_size ++; + } + } +#else + RFS_ASSERT (0); +#endif + printf ("read_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); +} + +void init_profile() +{ + memset (&total_profile, 0, sizeof(total_profile)); + + memset (&execute_next_request_profile, 0, sizeof(execute_next_request_profile)); + memset (&valid_get_nextop_profile, 0, sizeof(valid_get_nextop_profile)); + memset (&invalid_get_nextop_profile, 0, sizeof(invalid_get_nextop_profile)); + memset (&prepare_argument_profile, 0, sizeof(prepare_argument_profile)); + memset (&biod_clnt_call_profile, 0, sizeof(biod_clnt_call_profile)); + + memset (&receive_next_reply_profile, 0, sizeof(receive_next_reply_profile)); + memset (&valid_poll_and_get_reply_profile, 0, sizeof(valid_poll_and_get_reply_profile)); + memset (&invalid_poll_and_get_reply_profile, 0, sizeof(invalid_poll_and_get_reply_profile)); + memset (&decode_reply_profile, 0, sizeof(decode_reply_profile)); + memset (&check_reply_profile, 0, sizeof(check_reply_profile)); + memset (&add_create_object_profile, 0, sizeof(add_create_object_profile)); + + memset (&check_timeout_profile, 0, sizeof(check_timeout_profile)); + memset (&adjust_play_window_profile, 0, sizeof(adjust_play_window_profile)); +} + +int main(int argc, char ** argv) +{ + extern char * optarg; + char tracefile[256]; + int i; + int memory_trace_size; + + if (argc==2 && !strcmp(argv[1],"-help")) { + print_usage(); + exit(0); + } + + 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_file_system (); + + init_signal(); + //init_play (argv[1]); + init_play ("capella:/p5/RFSFS"); + init_profile(); + init_fh_map(); + //read_fh_map (argv[3]); + read_fh_map ("fh-path-map"); + init_dep_tab(); /* and dep_tab_size */ + //read_trace (argv[2]); + read_trace ("anon-lair62-011130-1100.txt"); + stage = READ_DEP_TAB_STAGE; + read_dep_tab(); + + for (i=0; i80) && (strlen(buf)80) && (strlen(buf)= MAX_MEMORY_TRACE_LINES) { + printf ("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); +#ifdef REDUCE_MEMORY_TRACE_SIZE + } else { + RFS_ASSERT (buf[TRACE_COMMAND_REPLY_FLAG_POS]=='R'); + } +#endif + disk_index ++; + }; + + fprintf(stderr, "total %d disk lines %d memory lines \n", disk_index, memory_trace_size ); + +} + + +#ifdef REDUCE_MEMORY_TRACE_SIZE +inline int disk_index_to_memory_index (int disk_index) +{ + static int memory_index = 0; + if (disk_index > memory_trace[memory_index].disk_index) { + while (memory_trace[memory_index].disk_index < disk_index) { + memory_index++; + RFS_ASSERT (memory_index < MAX_MEMORY_TRACE_LINES); + } + }; + if (disk_index < memory_trace[memory_index].disk_index) { + while (memory_trace[memory_index].disk_index > disk_index) { + memory_index--; + RFS_ASSERT (memory_index >=0); + } + }; + + 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; i10000)) + 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 ("find_reply_trace_fh line %s\n", line); + RFS_ASSERT (p); + return p+6; +} + +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); +} + +inline int is_play_candidate (int dep_index) +{ +#ifndef TAKE_CARE_CREATE_MODE_BY_DAN + int trace_reply_status; + char * reply_line; + if ((dep_tab[dep_index].proc==CREATE)) { + /* for a failed create in trace, trace_replay just ignore */ + reply_line = find_reply_line (dep_tab[dep_index].line, dep_tab[dep_index].disk_index); + if (reply_line == NULL) { + if (dependency_debug) + printf ("disk[%d] can not find the reply line, assume trace_reply_status OK\n", dep_tab[dep_index].disk_index); + trace_reply_status = NFS3_OK; + } else + trace_reply_status = find_reply_status (reply_line); + /* 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 ((dep_tab[dep_index].proc == CREATE) && (trace_reply_status!=NFS3_OK)) { + if (dependency_debug) + printf ("disk[%d] ignore failed create in trace, trace_reply_status %d line %s", dep_tab[dep_index].disk_index, trace_reply_status, dep_tab[dep_index].line); + failed_create_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 +#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 )) { + skipped_custom_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; +} + +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; + static int min_wait_fhandle_dep_index = DEP_TAB_SIZE; + int proc; + int flag; + + //if (dep_index < min_dep_index-1) + // dep_index = min_dep_index-1; + + dep_index = min_dep_index-1; + for (i=0; ilock) { + 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==min_dep_index) { + if (dependency_debug) + printf ("return disk[%d]\n", dep_tab[dep_index].disk_index); + return dep_index; + } + } +#else + if (dep_tab[dep_index].flag == DEP_FLAG_INIT){ + for (j=0, t=&(dep_tab[dep_index].dep_ops[0]); + (j0); + 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; + + sfs_gettime (¤t); + + for (i=0; itimeout.sec) || + ((current.sec==timeout.sec) && (current.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++; + + finish_request (biod_index, dep_index, NFS3ERR_RFS_TIMEOUT); + + 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); + } + //RFS_ASSERT (!is_create_op(proc)); + + //printf ("timeout request: biod_reqp[%d].start %d:%d timeout %d:%d current %d:%d\n", 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= NFS3_PROCEDURE_COUNT) { + fprintf(stderr, "proc %d line %s\n", nfsproc, line); + + } + RFS_ASSERT (nfsproc = 0 && dep_tab[dep_index].proc < NOPS); + dep_tab[dep_index].flag = DEP_FLAG_INIT; +} + +/* initialize status, reply status, reply lines in one shot is probably better ???????????????? + +static void adjust_play_window (int flag, int * poll_timeout) +{ + struct ladtime max_window_time; + static struct ladtime max_poll_time = {0, 2000, 0}; + struct ladtime t; + int old_min = min_dep_index; + int old_max = max_dep_index; + int i; + char * line; + + for (; (dep_tab[min_dep_index].flag == DEP_FLAG_DONE) && (min_dep_indexmax_window_time.sec)||(t.sec==max_window_time.sec && t.usec>max_window_time.usec)) + break; + + max_dep_index++; + } + + /* Right now it is not clear how to deal with the situation where MAX_PLAY_WINDOW is reached */ + if (max_dep_index == min_dep_index+MAX_PLAY_WINDOW) { + //printf ("can not catch up the speed, max_dep_index %d reach min_dep_index %d+MAX_PLAY_WINDOW\n", max_dep_index, min_dep_index); + //printf ("."); + can_not_catch_speed_num ++; + } + //RFS_ASSERT (max_dep_index < min_dep_index+MAX_PLAY_WINDOW); +#else + ADDTIME (current, trace_starttime); + max_window_time = current; + max_dep_index = min_dep_index + MAX_PLAY_WINDOW; + if (max_dep_index >dep_tab_size) + max_dep_index = dep_tab_size; +#endif + + if (flag == BUSY) + *poll_timeout = 0; + else if (max_dep_index == dep_tab_size) { + *poll_timeout = 1000000; /* poll_timeout set to 1 second for the last request */ + } else { +#ifdef TIME_PLAY + struct ladtime tmp; + struct ladtime tmp1; + tmp.sec = dep_tab[max_dep_index].timestamp.tv_sec; + tmp.usec = dep_tab[max_dep_index].timestamp.tv_usec; + if (adjust_play_window_debug) + printf ("dep_tab[max_dep_index %d].timestamp %d:%d, max_window_time %d:%d\n", + max_dep_index, 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", + max_dep_index, dep_tab[max_dep_index].timestamp.tv_sec, dep_tab[max_dep_index].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 ==0) && (tmp.usec==0)) { + *poll_timeout = 0; + } else + *poll_timeout = tmp.sec*1000000+tmp.usec; +#else + /* + struct ladtime tmp; + struct ladtime tmp1; + tmp.sec = dep_tab[max_dep_index].timestamp.tv_sec; + tmp.usec = dep_tab[max_dep_index].timestamp.tv_usec; + tmp1.sec = dep_tab[max_dep_index-1].timestamp.tv_sec; + tmp1.usec = dep_tab[max_dep_index-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 = 100000; +#endif + } + if (rfs_debug) + printf ("adjust_play_window: flag %d min %d -> %d, max %d -> %d poll_timeout %d \n", flag, old_min, min_dep_index, old_max, max_dep_index, *poll_timeout); +} + +/* 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 */ + + 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 + error = get_areply_udp (NFS_client, &xid, &zero_time); + // 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); + 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; + + printf("read_data_bytes %d owe %d GB and %d bytes, adjusted %d times \n",read_data_total, read_data_owe_GB, read_data_owe, read_data_adjust_times); + printf("write_data_bytes %d owe %d GB and %d bytes, adjusted %d times \n",write_data_total, write_data_owe_GB, write_data_owe, write_data_adjust_times); + printf("failed_create_command_num %d skipped_readlink_command_num %d skipped_custom_command_num %d\n missing_reply_num %d rename_rmdir_noent_reply_num %d rmdir_not_empty_reply_num %d\n loose_access_control_reply_num %d, proper_reply_num %d, lookup_err_due_to_rename %d\n", + failed_create_command_num, skipped_readlink_command_num, skipped_custom_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, proper_reply_num ); + + 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; i0) + printf ("[%4d] %s \tstart %4d:%6d \n", + dep_index, Ops[dep_tab[dep_index].proc].name, dep_tab[dep_index].start.sec, dep_tab[dep_index].start.usec); + else { + dep_index = -dep_index; + t=dep_tab[dep_index].stop; + SUBTIME (t, dep_tab[dep_index].start); + printf ("\t\t\t\t\t[%4d] %s stop %4d:%6d\tinterval %4d:%6d %s\n", + dep_index, Ops[dep_tab[dep_index].proc].name, dep_tab[dep_index].stop.sec, dep_tab[dep_index].stop.usec, t.sec, t.usec, nfs3_strerror(dep_tab[dep_index].status)); + } + } +/* + + for (i=0, j=0; icl_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; +} + +extern void init_dep_tab (void) +{ + int i; + memset (&dep_tab, 0, sizeof(dep_tab)); +#ifdef notdef + dep_tab[0].disk_index = 0; + dep_tab[1].disk_index = 2; + dep_tab[2].disk_index = 3; + dep_tab[3].disk_index = 5; + dep_tab[4].disk_index = 7; + dep_tab[5].disk_index = 9; + dep_tab[6].disk_index = 11; + dep_tab[7].disk_index = 12; + dep_tab[8].disk_index = 15; + dep_tab[9].disk_index = 17; + dep_tab[10].disk_index = 18; + dep_tab[11].disk_index = 20; + dep_tab_size = 12; + //dep_tab_size = 2; +#endif +} + +extern void init_dep_tab_old (void) +{ + int i; + + Cur_file_ptr = &Export_dir; + Cur_uid = Real_uid; + + for (i=0; i<5; i++) { + dep_tab[i].flag = DEP_FLAG_INIT; + dep_tab[i].proc = CREATE; + dep_tab[i].timestamp.tv_sec = trace_starttime.sec; + dep_tab[i].timestamp.tv_usec = trace_starttime.usec+i*10; + dep_tab[i].init_dep_num = 0; + dep_tab[i].cur_dep_num = 0; + } + + for (i=5; i<10; i++) { + dep_tab[i].flag = DEP_FLAG_INIT; + dep_tab[i].proc = CREATE; + dep_tab[i].timestamp.tv_sec = trace_starttime.sec+i; + dep_tab[i].timestamp.tv_usec = trace_starttime.usec; + dep_tab[i].init_dep_num = 0; + dep_tab[i].cur_dep_num = 0; + } + + dep_tab[2].init_dep_num = 2; + dep_tab[2].cur_dep_num = 2; + dep_tab[2].dep_ops[0] = 0; + dep_tab[2].dep_ops[1] = 1; + + // printf ("trace_starttime (%d %d)\n", trace_starttime.sec, trace_starttime.usec); + + /* + for (i=2; i<4; i++) { + dep_tab[i].flag = DEP_FLAG_INIT; + dep_tab[i].proc = CREATE; + dep_tab[i].timestamp.tv_sec = trace_starttime.sec+i*10; + dep_tab[i].timestamp.tv_usec = trace_starttime.usec; + dep_tab[i].init_dep_num = 0; + dep_tab[i].cur_dep_num = 0; + } + */ + + dep_tab_size = 10; + + for (i=0; ifh_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)); + RFS_ASSERT (!strcmp(fh_map[p->key3].path, path)); + RFS_ASSERT (!memcmp(&fh_map[p->key3].play_fh, &zero_fhandle, sizeof(nfs_fh3))); + 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; + memcpy(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; +}; + +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 path %s play_fh:", p->key3, fh_map[p->key3].path); + show_fhandle(&fh_map[p->key3].play_fh); + } + 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; +}; + +void 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); + RFS_ASSERT (reply.status == NFS3_OK); + (void) memcpy((char *) result, (char *) &reply.resok.object, sizeof (nfs_fh3)); +} + +void read_fh_map(char * fh_map_file) +{ + FILE * fp; + int i = 0; + char buf[1024]; + char trace_fh[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; + + 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"); + RFS_ASSERT (fp!=NULL); + + intbuf[8]=0; + + memset(buf, 0, sizeof(buf)); + while (fgets(buf, 1024, fp)) { + + 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; itrace_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) { + lookup_init_filesystem (&parents[depth], p, &parents[depth+1]); + 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; ilock = 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); + } + } + num_out_reqs --; +} + +/* 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]; +int poll_timeout = 0; /* timeout in usecs */ +char buf1 [MAX_BUF1_SIZE]; +char buf2 [MAX_BUF2_SIZE]; +#define NFS3_REPLY_MISS -1 + +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; + + 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 ((dep_index%(10000))==0) { +#ifndef TIME_PLAY + fprintf (stderr, "processing dep_tab[%d] disk_index %d num_out_reqs %d \n", dep_index, dep_tab[dep_index].disk_index, num_out_reqs); +#else + fprintf (stderr, "processing dep_tab[%d] disk_index %d num_out_reqs %d can_not_catch_speed_num %d PLAY_SCALE %d \n", dep_index, dep_tab[dep_index].disk_index, num_out_reqs, can_not_catch_speed_num, PLAY_SCALE); +#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 + 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); + + call_timeout.sec = 4; //Nfs_timers[op_ptr->call_class].tv_sec; + call_timeout.usec = Nfs_timers[op_ptr->call_class].tv_usec; + + /* make the call */ + sfs_gettime(&(reqp->start)); + end_profile (&prepare_argument_profile); + start_profile (&biod_clnt_call_profile); +#define REAL_PLAY +#ifdef REAL_PLAY + reqp->xid = biod_clnt_call(NFS_client, rfs_Ops[proc].nfsv3_proc, + rfs_Ops[proc].xdr_arg, arg_res); +#else + + reqp->xid = dep_index+1; /* just fake a message id and let it expire */ +#endif + if (reqp->xid != 0) { + reqp->timeout = reqp->start; + ADDTIME (reqp->timeout, call_timeout); + num_out_reqs++; + dep_tab[dep_index].flag = DEP_FLAG_SENT; + event_order[event_order_index++] = dep_index; + } else + RFS_ASSERT (0); + + dep_tab[dep_index].start = reqp->start; /* RFS: to dump data */ + end_profile (&biod_clnt_call_profile); +} + +void check_reply (int proc, int biod_index, int dep_index, int status, char * errmsg, int trace_reply_status) +{ + if (((status!=trace_reply_status)) && (trace_reply_status!=NFS3_REPLY_MISS)) { + if (rfs_debug) + printf ("receive problem reply, xid %x nfs_ret %d %s trace_reply_status %d start %d:%d stop %d:%d command disk index %d\n", biod_reqp[biod_index].xid, status, errmsg, trace_reply_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_reply_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 + */ + RFS_ASSERT (1); + rename_rmdir_noent_reply_num++; + } else +#endif +#ifndef TAKE_CARE_SYMBOLIC_LINK + if ((proc==LOOKUP) && (status==NFS3_OK) && (trace_reply_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_reply_status == 0)) { + /* 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_reply_status==NFS3ERR_ACCES)) { + loose_access_control_reply_num ++; +#endif +#ifdef NO_DEPENDENCY_TABLE + } else if ((proc==LOOKUP) && (status==NFS3ERR_NOENT) && (trace_reply_status==NFS3_OK)) { + lookup_err_due_to_rename_num ++; +#endif + } else { + int i; + for (i=min_dep_index; iresults.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); +#ifndef TAKE_CARE_SYMBOLIC_LINK + if (trace_reply_status == NFS3_OK && (proc==CREATE || proc==MKDIR || proc==MKNOD)) { +#else + if (trace_reply_status == NFS3_OK && (proc==CREATE || proc==MKDIR || proc==SYMLINK || proc==MKNOD)) { +#endif + RFS_ASSERT (status == NFS_OK); + RFS_ASSERT (reply_line); + add_new_file_system_object(proc, dep_index, line, reply_line); + } + //end_profile (&add_create_object_profile); +} + +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); + reply_trace_fh = find_reply_trace_fh (reply_line); + 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); + } + RFS_ASSERT (reply_trace_fh[TRACE_FH_SIZE]==' '); + 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 */ + reply_trace_fh[TRACE_FH_SIZE] = ' '; +} + +/* 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 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 */ + + int count = 0; + min_dep_index = 0; + max_dep_index = 0; + adjust_play_window(busy_flag, &poll_timeout); + + start_profile (&total_profile); + while ((min_dep_index0)) { + + if (busy_flag == IDLE) { + //start_profile (&check_timeout_profile); + check_timeout(); + //end_profile (&check_timeout_profile); + } + + //start_profile (&adjust_play_window_profile); + //adjust_play_window (flag, &poll_timeout); + //adjust_play_window (flag+(max_dep_index-min_dep_index), &poll_timeout); + adjust_play_window (busy_flag, &poll_timeout); + if (rfs_debug) + printf("num_out_reqs %d\n", 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); + + start_profile (&receive_next_reply_profile); + while (receive_next_reply(busy_flag)!=-1) + busy_flag = BUSY; + end_profile (&receive_next_reply_profile); + } + end_profile (&total_profile); + + 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", &prepare_argument_profile); + print_profile ("biod_clnt_call", &biod_clnt_call_profile); + printf("\n"); + print_profile ("receive_next_reply", &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", &decode_reply_profile); + print_profile ("check_reply", &check_reply_profile); + print_profile ("add_create_object", &add_create_object_profile); + printf("\n"); + + printf ("min_dep_index %d dep_tab_size %d num_out_reqs %d\n", min_dep_index, dep_tab_size, num_out_reqs); +} +/* sfs_c_chd.c */