int i;
char line[1024];
char *cname;
- char params[20][100];
+ char **sparams, **params;
char *p;
const char *status;
char *fname = NULL;
char *fname2 = NULL;
FILE *f = fopen(loadfile, "r");
pid_t parent = getppid();
+ extern double targetrate;
child->line = 0;
asprintf(&cname,"client%d", child->id);
+ sparams = calloc(20, sizeof(char *));
+ for (i=0;i<20;i++) {
+ sparams[i] = malloc(100);
+ }
+
again:
+ nb_time_reset(child);
+
while (fgets(line, sizeof(line)-1, f)) {
+ params = sparams;
+
if (child->done || kill(parent, 0) == -1) {
goto done;
}
exit(1);
}
- if (strncmp(params[i-1], "NT_STATUS_", 10) != 0) {
+ if (i > 0 && isdigit(params[0][0])) {
+ double targett = strtod(params[0], NULL);
+ if (targetrate != 0) {
+ nb_target_rate(child, targetrate);
+ } else {
+ nb_time_delay(child, targett);
+ }
+ params++;
+ i--;
+ }
+
+ if (strncmp(params[i-1], "NT_STATUS_", 10) != 0 &&
+ strncmp(params[i-1], "0x", 2) != 0) {
printf("Badly formed status at line %d\n", child->line);
continue;
}
static struct timeval tv_start;
static struct timeval tv_end;
static int barrier=-1;
+double targetrate;
#if HAVE_EA_SUPPORT
int ea_enable=0;
" -t timelimit run time in seconds (default 600)\n" \
" -D directory base directory to run in\n" \
" -c loadfile set location of the loadfile\n" \
+ " -R target rate (MByte/sec)\n" \
" -s synchronous file IO\n" \
" -S synchronous directories (mkdir, unlink...)\n" \
" -x enable EA support\n" \
int c;
extern int sync_open;
extern char *server;
+
+ targetrate = 0;
- while ((c = getopt(argc, argv, "vc:sST:t:xD:")) != -1)
+ while ((c = getopt(argc, argv, "vc:sST:t:xD:R:")) != -1)
switch (c) {
case 'c':
loadfile = optarg;
case 'v':
exit(0);
break;
+ case 'R':
+ targetrate = strtod(optarg, NULL);
+ break;
case 'x':
+
#if HAVE_EA_SUPPORT
ea_enable = 1;
#else
const char *directory;
double bytes;
double bytes_done_warmup;
+ double max_latency;
+ struct timeval starttime;
};
int handle;
} ftable[MAX_FILES];
+void nb_target_rate(struct child_struct *child, double rate)
+{
+ static double last_bytes;
+ static struct timeval last_time;
+ double tdelay;
+
+ if (last_bytes == 0) {
+ last_bytes = child->bytes;
+ last_time = timeval_current();
+ return;
+ }
+
+ tdelay = (child->bytes - last_bytes)/(1.0e6*rate) - timeval_elapsed(&last_time);
+ if (tdelay > 0) {
+ msleep(tdelay*1000);
+ } else {
+ child->max_latency = MAX(child->max_latency, -tdelay);
+ }
+
+ last_time = timeval_current();
+ last_bytes = child->bytes;
+}
+
+void nb_time_reset(struct child_struct *child)
+{
+ child->starttime = timeval_current();
+}
+
+void nb_time_delay(struct child_struct *child, double targett)
+{
+ double elapsed = timeval_elapsed(&child->starttime);
+ if (targett > elapsed) {
+ msleep(1000*(targett - elapsed));
+ } else if (elapsed - targett > child->max_latency) {
+ child->max_latency = MAX(elapsed - targett, child->max_latency);
+ }
+}
+
static int find_handle(struct child_struct *child, int handle)
{
int i;
static int expected_status(const char *status)
{
- if (strcmp(status, "NT_STATUS_OK") == 0) return 0;
+ if (strcmp(status, "NT_STATUS_OK") == 0 ||
+ strtoul(status, NULL, 16) == 0) return 0;
return -1;
}
char *p;
struct dirent *d;
+ if (name == NULL) return;
+
if (stat(name, &st) == 0) {
xattr_fname_read_hook(name);
return;
if (create_options & FILE_DIRECTORY_FILE) flags = O_RDONLY|O_DIRECTORY;
fd = open(fname, flags, 0600);
+ if (fd == -1 && errno == EISDIR) {
+ flags = O_RDONLY|O_DIRECTORY;
+ fd = open(fname, flags, 0600);
+ }
if (fd == -1) {
- if (strcmp(status, "NT_STATUS_OK") == 0) {
+ if (expected_status(status) == 0) {
printf("(%d) open %s failed for handle %d (%s)\n",
child->line, fname, fnum, strerror(errno));
}
return;
}
- if (strcmp(status, "NT_STATUS_OK") != 0) {
+ if (expected_status(status) != 0) {
printf("(%d) open %s succeeded for handle %d\n",
child->line, fname, fnum);
close(fd);
{
int i = find_handle(child, handle);
void *buf;
+ struct stat st;
(void)status;
buf = calloc(size, 1);
+ if (size == 1 && fstat(ftable[i].fd, &st) == 0) {
+ if (st.st_size > offset) {
+ unsigned char c;
+ pread(ftable[i].fd, &c, 1, offset);
+ if (c == ((unsigned char *)buf)[0]) {
+ free(buf);
+ child->bytes += size;
+ return;
+ }
+ } else if (((unsigned char *)buf)[0] == 0) {
+ ftruncate(ftable[i].fd, offset+1);
+ free(buf);
+ child->bytes += size;
+ return;
+ }
+ }
+
if (pwrite(ftable[i].fd, buf, size, offset) != ret_size) {
printf("write failed on handle %d (%s)\n", handle, strerror(errno));
exit(1);
do_open(fname, 5000, size);
do_close(5000);
}
+
+
/* The following definitions come from fileio.c */
+void nb_target_rate(struct child_struct *child, double rate);
+void nb_time_reset(struct child_struct *child);
+void nb_time_delay(struct child_struct *child, double targett);
void nb_setup(struct child_struct *child);
void nb_unlink(struct child_struct *child, char *fname, int attr, const char *status);
void nb_mkdir(struct child_struct *child, char *dname, const char *status);
void do_stat(char *fname, int size);
void do_create(char *fname, int size);
+/* The following definitions come from snprintf.c */
+
+
/* The following definitions come from sockio.c */
void nb_setup(struct child_struct *child);
struct timeval timeval_current(void);
double timeval_elapsed(struct timeval *tv);
double timeval_elapsed2(struct timeval *tv1, struct timeval *tv2);
+void msleep(unsigned int t);
#endif /* _PROTO_H_ */
do_packets(8, 8);
}
+
+void nb_target_rate(struct child_struct *child, double rate)
+{
+ static double last_bytes;
+ static struct timeval last_time;
+ double tdelay;
+
+ if (last_bytes == 0) {
+ last_bytes = child->bytes;
+ last_time = timeval_current();
+ return;
+ }
+
+ tdelay = (child->bytes - last_bytes)/(1.0e6*rate) - timeval_elapsed(&last_time);
+ if (tdelay > 0) {
+ msleep(tdelay*1000);
+ } else {
+ child->max_latency = MAX(child->max_latency, -tdelay);
+ }
+
+ last_time = timeval_current();
+ last_bytes = child->bytes;
+}
+
+void nb_time_reset(struct child_struct *child)
+{
+ child->starttime = timeval_current();
+}
+
+void nb_time_delay(struct child_struct *child, double targett)
+{
+ double elapsed = timeval_elapsed(&child->starttime);
+ if (targett > elapsed) {
+ msleep(1000*(targett - elapsed));
+ } else if (elapsed - targett > child->max_latency) {
+ child->max_latency = MAX(elapsed - targett, child->max_latency);
+ }
+}
+
void nb_unlink(struct child_struct *child, char *fname, int attr, const char *status)
{
(void)child;
(tv2->tv_usec - tv1->tv_usec)*1.0e-6;
}
+
+
+/**
+ Sleep for a specified number of milliseconds.
+**/
+void msleep(unsigned int t)
+{
+ struct timeval tval;
+
+ tval.tv_sec = t/1000;
+ tval.tv_usec = 1000*(t%1000);
+ /* this should be the real select - do NOT replace
+ with sys_select() */
+ select(0,NULL,NULL,NULL,&tval);
+}