diff options
author | Andrew Tridgell <tridge@samba.org> | 2004-03-09 02:13:13 +0000 |
---|---|---|
committer | Andrew Tridgell <tridge@samba.org> | 2004-03-09 02:13:13 +0000 |
commit | 2d9a8bf0c93d0f4c8c02b3dfe074f59dba97009b (patch) | |
tree | 0d5dd71caf5e51d941b36ad8b8b2aaa9150c3c3e /source4/torture | |
parent | 1b71c60c36f0e2dc70b83688194c7aa3512623e2 (diff) | |
download | samba-2d9a8bf0c93d0f4c8c02b3dfe074f59dba97009b.tar.gz samba-2d9a8bf0c93d0f4c8c02b3dfe074f59dba97009b.tar.bz2 samba-2d9a8bf0c93d0f4c8c02b3dfe074f59dba97009b.zip |
greatly improved NBENCH netbench simulator
- more accurate request simulation using Samba4 raw client library
- now checks for correct status on all requests
- timelimit based benchmarking, default of 600 seconds
(This used to be commit a46c009c0459658784d7d7b3b0502dc20958043a)
Diffstat (limited to 'source4/torture')
-rwxr-xr-x | source4/torture/config.m4 | 7 | ||||
-rw-r--r-- | source4/torture/nbench/nbench.c | 192 | ||||
-rw-r--r-- | source4/torture/nbench/nbio.c | 579 | ||||
-rw-r--r-- | source4/torture/nbio.c | 287 | ||||
-rw-r--r-- | source4/torture/torture.c | 188 |
5 files changed, 805 insertions, 448 deletions
diff --git a/source4/torture/config.m4 b/source4/torture/config.m4 index 0d6e375bca..f7ad78611c 100755 --- a/source4/torture/config.m4 +++ b/source4/torture/config.m4 @@ -16,9 +16,12 @@ SMB_SUBSYSTEM(TORTURE_RPC,[], torture/rpc/scanner.o torture/rpc/autoidl.o torture/rpc/netlogon.o], torture/rpc/torture_rpc_public_proto.h) +SMB_SUBSYSTEM(TORTURE_NBENCH,[], + [torture/nbench/nbio.o torture/nbench/nbench.o]) + SMB_SUBSYSTEM(TORTURE,[], - [torture/torture.o torture/torture_util.o torture/nbio.o torture/scanner.o \ + [torture/torture.o torture/torture_util.o torture/scanner.o \ torture/utable.o torture/denytest.o torture/mangle_test.o \ torture/aliases.o libcli/raw/clirewrite.o \$(TORTURE_RAW_OBJS) \ - \$(TORTURE_RPC_OBJS)], + \$(TORTURE_RPC_OBJS) \$(TORTURE_NBENCH_OBJS)], torture/torture_public_proto.h) diff --git a/source4/torture/nbench/nbench.c b/source4/torture/nbench/nbench.c new file mode 100644 index 0000000000..6b0e78e1ab --- /dev/null +++ b/source4/torture/nbench/nbench.c @@ -0,0 +1,192 @@ +/* + Unix SMB/CIFS implementation. + SMB torture tester - NBENCH test + Copyright (C) Andrew Tridgell 1997-2004 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "includes.h" + +int nbench_line_count = 0; +static int timelimit = 300; +static const char *loadfile; + +#define ival(s) strtol(s, NULL, 0) + +/* run a test that simulates an approximate netbench client load */ +static BOOL run_netbench(struct cli_state *cli, int client) +{ + int i; + pstring line; + char *cname; + FILE *f; + fstring params[20]; + const char *p; + BOOL correct = True; + + nb_setup(cli, client); + + asprintf(&cname, "client%d", client); + + f = fopen(loadfile, "r"); + + if (!f) { + perror(loadfile); + return False; + } + +again: + while (fgets(line, sizeof(line)-1, f)) { + NTSTATUS status; + + if (end_timer() >= timelimit) { + goto done; + } + + nbench_line_count++; + + line[strlen(line)-1] = 0; + + all_string_sub(line,"client1", cname, sizeof(line)); + + p = line; + for (i=0; + i<19 && next_token(&p, params[i], " ", sizeof(fstring)); + i++) ; + + params[i][0] = 0; + + if (i < 2 || params[0][0] == '#') continue; + + if (!strncmp(params[0],"SMB", 3)) { + printf("ERROR: You are using a dbench 1 load file\n"); + exit(1); + } + + if (strncmp(params[i-1], "NT_STATUS_", 10) != 0) { + printf("Badly formed status at line %d\n", nbench_line_count); + continue; + } + + status = nt_status_string_to_code(params[i-1]); + + DEBUG(9,("run_netbench(%d): %s %s\n", client, params[0], params[1])); + + if (!strcmp(params[0],"NTCreateX")) { + nb_createx(params[1], ival(params[2]), ival(params[3]), + ival(params[4]), status); + } else if (!strcmp(params[0],"Close")) { + nb_close(ival(params[1]), status); + } else if (!strcmp(params[0],"Rename")) { + nb_rename(params[1], params[2], status); + } else if (!strcmp(params[0],"Unlink")) { + nb_unlink(params[1], ival(params[2]), status); + } else if (!strcmp(params[0],"Deltree")) { + nb_deltree(params[1]); + } else if (!strcmp(params[0],"Rmdir")) { + nb_rmdir(params[1], status); + } else if (!strcmp(params[0],"QUERY_PATH_INFORMATION")) { + nb_qpathinfo(params[1], ival(params[2]), status); + } else if (!strcmp(params[0],"QUERY_FILE_INFORMATION")) { + nb_qfileinfo(ival(params[1]), ival(params[2]), status); + } else if (!strcmp(params[0],"QUERY_FS_INFORMATION")) { + nb_qfsinfo(ival(params[1]), status); + } else if (!strcmp(params[0],"SET_FILE_INFORMATION")) { + nb_sfileinfo(ival(params[1]), ival(params[2]), status); + } else if (!strcmp(params[0],"FIND_FIRST")) { + nb_findfirst(params[1], ival(params[2]), + ival(params[3]), ival(params[4]), status); + } else if (!strcmp(params[0],"WriteX")) { + nb_writex(ival(params[1]), + ival(params[2]), ival(params[3]), ival(params[4]), + status); + } else if (!strcmp(params[0],"Write")) { + nb_write(ival(params[1]), + ival(params[2]), ival(params[3]), ival(params[4]), + status); + } else if (!strcmp(params[0],"LockX")) { + nb_lockx(ival(params[1]), + ival(params[2]), ival(params[3]), status); + } else if (!strcmp(params[0],"UnlockX")) { + nb_unlockx(ival(params[1]), + ival(params[2]), ival(params[3]), status); + } else if (!strcmp(params[0],"ReadX")) { + nb_readx(ival(params[1]), + ival(params[2]), ival(params[3]), ival(params[4]), + status); + } else if (!strcmp(params[0],"Flush")) { + nb_flush(ival(params[1]), status); + } else { + printf("[%d] Unknown operation %s\n", nbench_line_count, params[0]); + } + } + + rewind(f); + goto again; + +done: + fclose(f); + nb_cleanup(cname); + + if (!torture_close_connection(cli)) { + correct = False; + } + + return correct; +} + + +/* run a test that simulates an approximate netbench client load */ +BOOL torture_nbench(int dummy) +{ + double t; + BOOL correct = True; + extern int torture_nprocs; + struct cli_state *cli; + char *p; + + p = lp_parm_string(-1, "torture", "timelimit"); + if (p && *p) { + timelimit = atoi(p); + } + + loadfile = lp_parm_string(-1, "torture", "loadfile"); + if (!loadfile || !*loadfile) { + loadfile = "client.txt"; + } + + if (!torture_open_connection(&cli)) { + return False; + } + + nb_setup(cli, -1); + nb_deltree("\\clients"); + + nbio_shmem(torture_nprocs); + + printf("Running for %d seconds with load '%s'\n", timelimit, loadfile); + + signal(SIGALRM, SIGNAL_CAST nb_alarm); + alarm(1); + t = torture_create_procs(run_netbench, &correct); + alarm(0); + + printf("\nThroughput %g MB/sec\n", + 1.0e-6 * nbio_total() / t); + return correct; +} + + diff --git a/source4/torture/nbench/nbio.c b/source4/torture/nbench/nbio.c new file mode 100644 index 0000000000..819383b7d8 --- /dev/null +++ b/source4/torture/nbench/nbio.c @@ -0,0 +1,579 @@ +#define NBDEBUG 0 + +/* + Unix SMB/CIFS implementation. + SMB torture tester + Copyright (C) Andrew Tridgell 1997-1998 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "includes.h" + +#define MAX_FILES 1000 + +extern int nbench_line_count; +static int nbio_id; +static int nprocs; +static BOOL bypass_io; + +static struct { + int fd; + int handle; +} ftable[MAX_FILES]; + +static struct { + double bytes_in, bytes_out; + int line; + int done; +} *children; + +double nbio_total(void) +{ + int i; + double total = 0; + for (i=0;i<nprocs;i++) { + total += children[i].bytes_out + children[i].bytes_in; + } + return total; +} + +void nb_alarm(void) +{ + int i; + int lines=0, num_clients=0; + double t; + + if (nbio_id != -1) return; + + for (i=0;i<nprocs;i++) { + lines += children[i].line; + if (!children[i].done) num_clients++; + } + + t = end_timer(); + + printf("%4d %8d %.2f MB/sec t=%.0f \r", + num_clients, lines/nprocs, + 1.0e-6 * nbio_total() / t, + t); + + signal(SIGALRM, nb_alarm); + alarm(1); +} + +void nbio_shmem(int n) +{ + nprocs = n; + children = shm_setup(sizeof(*children) * nprocs); + if (!children) { + printf("Failed to setup shared memory!\n"); + exit(1); + } +} + +static int find_handle(int handle) +{ + int i; + children[nbio_id].line = nbench_line_count; + for (i=0;i<MAX_FILES;i++) { + if (ftable[i].handle == handle) return i; + } + printf("(%d) ERROR: handle %d was not found\n", + nbench_line_count, handle); + exit(1); + + return -1; /* Not reached */ +} + + +static struct cli_state *c; + +void nb_setup(struct cli_state *cli, int id) +{ + nbio_id = id; + c = cli; + start_timer(); + if (children) { + children[nbio_id].done = 0; + } + if (bypass_io) + printf("skipping I/O\n"); +} + + +static void check_status(const char *op, NTSTATUS status, NTSTATUS ret) +{ + if (!NT_STATUS_IS_OK(status) && NT_STATUS_IS_OK(ret)) { + printf("[%d] Error: %s should have failed with %s\n", + nbench_line_count, op, nt_errstr(status)); + exit(1); + } + + if (NT_STATUS_IS_OK(status) && !NT_STATUS_IS_OK(ret)) { + printf("[%d] Error: %s should have succeeded - %s\n", + nbench_line_count, op, nt_errstr(ret)); + exit(1); + } + + if (!NT_STATUS_EQUAL(status, ret)) { + printf("[%d] Warning: got status %s but expected %s\n", + nbench_line_count, nt_errstr(ret), nt_errstr(status)); + } +} + + +void nb_unlink(const char *fname, int attr, NTSTATUS status) +{ + struct smb_unlink io; + NTSTATUS ret; + + io.in.pattern = fname; + + io.in.attrib = FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN; + if (strchr(fname, '*') == 0) { + io.in.attrib |= FILE_ATTRIBUTE_DIRECTORY; + } + + ret = smb_raw_unlink(c->tree, &io); + + check_status("Unlink", status, ret); +} + + +void nb_createx(const char *fname, + unsigned create_options, unsigned create_disposition, int handle, + NTSTATUS status) +{ + union smb_open io; + int i; + uint32 desired_access; + NTSTATUS ret; + TALLOC_CTX *mem_ctx; + + mem_ctx = talloc_init("raw_open"); + + if (create_options & NTCREATEX_OPTIONS_DIRECTORY) { + desired_access = SA_RIGHT_FILE_READ_DATA; + } else { + desired_access = + SA_RIGHT_FILE_READ_DATA | + SA_RIGHT_FILE_WRITE_DATA | + SA_RIGHT_FILE_READ_ATTRIBUTES | + SA_RIGHT_FILE_WRITE_ATTRIBUTES; + } + + io.ntcreatex.level = RAW_OPEN_NTCREATEX; + io.ntcreatex.in.flags = 0; + io.ntcreatex.in.root_fid = 0; + io.ntcreatex.in.access_mask = desired_access; + io.ntcreatex.in.file_attr = 0; + io.ntcreatex.in.alloc_size = 0; + io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE; + io.ntcreatex.in.open_disposition = create_disposition; + io.ntcreatex.in.create_options = create_options; + io.ntcreatex.in.impersonation = 0; + io.ntcreatex.in.security_flags = 0; + io.ntcreatex.in.fname = fname; + + ret = smb_raw_open(c->tree, mem_ctx, &io); + + talloc_destroy(mem_ctx); + + check_status("NTCreateX", status, ret); + + if (!NT_STATUS_IS_OK(ret)) return; + + for (i=0;i<MAX_FILES;i++) { + if (ftable[i].handle == 0) break; + } + if (i == MAX_FILES) { + printf("(%d) file table full for %s\n", nbench_line_count, + fname); + exit(1); + } + ftable[i].handle = handle; + ftable[i].fd = io.ntcreatex.out.fnum; +} + +void nb_writex(int handle, int offset, int size, int ret_size, NTSTATUS status) +{ + union smb_write io; + int i; + NTSTATUS ret; + char *buf; + + i = find_handle(handle); + + if (bypass_io) return; + + buf = malloc(size); + memset(buf, 0xab, size); + + io.writex.level = RAW_WRITE_WRITEX; + io.writex.in.fnum = ftable[i].fd; + io.writex.in.wmode = 0; + io.writex.in.remaining = 0; + io.writex.in.offset = offset; + io.writex.in.count = size; + io.writex.in.data = buf; + + ret = smb_raw_write(c->tree, &io); + + free(buf); + + check_status("WriteX", status, ret); + + if (io.writex.out.nwritten != ret_size) { + printf("[%d] Warning: WriteX got count %d expected %d\n", + nbench_line_count, + io.writex.out.nwritten, ret_size); + } + + children[nbio_id].bytes_out += ret_size; +} + + +void nb_write(int handle, int offset, int size, int ret_size, NTSTATUS status) +{ + union smb_write io; + int i; + NTSTATUS ret; + char *buf; + + i = find_handle(handle); + + if (bypass_io) return; + + buf = malloc(size); + + memset(buf, 0x12, size); + + io.write.level = RAW_WRITE_WRITE; + io.write.in.fnum = ftable[i].fd; + io.write.in.remaining = 0; + io.write.in.offset = offset; + io.write.in.count = size; + io.write.in.data = buf; + + ret = smb_raw_write(c->tree, &io); + + free(buf); + + check_status("Write", status, ret); + + if (io.write.out.nwritten != ret_size) { + printf("[%d] Warning: Write got count %d expected %d\n", + nbench_line_count, + io.write.out.nwritten, ret_size); + } + + children[nbio_id].bytes_out += ret_size; +} + + +void nb_lockx(int handle, unsigned offset, int size, NTSTATUS status) +{ + union smb_lock io; + int i; + NTSTATUS ret; + struct smb_lock_entry lck; + + i = find_handle(handle); + + lck.pid = getpid(); + lck.offset = offset; + lck.count = size; + + io.lockx.level = RAW_LOCK_LOCKX; + io.lockx.in.fnum = ftable[i].fd; + io.lockx.in.mode = 0; + io.lockx.in.timeout = 0; + io.lockx.in.ulock_cnt = 0; + io.lockx.in.lock_cnt = 1; + io.lockx.in.locks = &lck; + + ret = smb_raw_lock(c->tree, &io); + + check_status("LockX", status, ret); +} + +void nb_unlockx(int handle, unsigned offset, int size, NTSTATUS status) +{ + union smb_lock io; + int i; + NTSTATUS ret; + struct smb_lock_entry lck; + + i = find_handle(handle); + + lck.pid = getpid(); + lck.offset = offset; + lck.count = size; + + io.lockx.level = RAW_LOCK_LOCKX; + io.lockx.in.fnum = ftable[i].fd; + io.lockx.in.mode = 0; + io.lockx.in.timeout = 0; + io.lockx.in.ulock_cnt = 1; + io.lockx.in.lock_cnt = 0; + io.lockx.in.locks = &lck; + + ret = smb_raw_lock(c->tree, &io); + + check_status("UnlockX", status, ret); +} + +void nb_readx(int handle, int offset, int size, int ret_size, NTSTATUS status) +{ + union smb_read io; + int i; + NTSTATUS ret; + char *buf; + + i = find_handle(handle); + + if (bypass_io) return; + + buf = malloc(size); + + io.readx.level = RAW_READ_READX; + io.readx.in.fnum = ftable[i].fd; + io.readx.in.offset = offset; + io.readx.in.mincnt = size; + io.readx.in.maxcnt = size; + io.readx.in.remaining = 0; + io.readx.out.data = buf; + + ret = smb_raw_read(c->tree, &io); + + free(buf); + + check_status("ReadX", status, ret); + + if (io.readx.out.nread != ret_size) { + printf("[%d] Warning: ReadX got count %d expected %d\n", + nbench_line_count, + io.readx.out.nread, ret_size); + } + + children[nbio_id].bytes_in += ret_size; +} + +void nb_close(int handle, NTSTATUS status) +{ + int i; + NTSTATUS ret; + union smb_close io; + + i = find_handle(handle); + + io.close.level = RAW_CLOSE_CLOSE; + io.close.in.fnum = ftable[i].fd; + io.close.in.write_time = 0; + + ret = smb_raw_close(c->tree, &io); + + check_status("Close", status, ret); + + if (NT_STATUS_IS_OK(ret)) { + ftable[i].handle = 0; + } +} + +void nb_rmdir(const char *dname, NTSTATUS status) +{ + NTSTATUS ret; + struct smb_rmdir io; + + io.in.path = dname; + + ret = smb_raw_rmdir(c->tree, &io); + + check_status("Rmdir", status, ret); +} + +void nb_rename(const char *old, const char *new, NTSTATUS status) +{ + NTSTATUS ret; + union smb_rename io; + + io.generic.level = RAW_RENAME_RENAME; + io.rename.in.attrib = FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_DIRECTORY; + io.rename.in.pattern1 = old; + io.rename.in.pattern2 = new; + + ret = smb_raw_rename(c->tree, &io); + + check_status("Rename", status, ret); +} + + +void nb_qpathinfo(const char *fname, int level, NTSTATUS status) +{ + union smb_fileinfo io; + TALLOC_CTX *mem_ctx; + NTSTATUS ret; + + mem_ctx = talloc_init("nb_qpathinfo"); + + io.generic.level = level; + io.generic.in.fname = fname; + + ret = smb_raw_pathinfo(c->tree, mem_ctx, &io); + + talloc_destroy(mem_ctx); + + check_status("Pathinfo", status, ret); +} + + +void nb_qfileinfo(int fnum, int level, NTSTATUS status) +{ + union smb_fileinfo io; + TALLOC_CTX *mem_ctx; + NTSTATUS ret; + int i; + + i = find_handle(fnum); + + mem_ctx = talloc_init("nb_qfileinfo"); + + io.generic.level = level; + io.generic.in.fnum = ftable[i].fd; + + ret = smb_raw_fileinfo(c->tree, mem_ctx, &io); + + talloc_destroy(mem_ctx); + + check_status("Fileinfo", status, ret); +} + +void nb_sfileinfo(int fnum, int level, NTSTATUS status) +{ + union smb_setfileinfo io; + NTSTATUS ret; + int i; + + if (level != RAW_SFILEINFO_BASIC_INFORMATION) { + printf("[%d] Warning: setfileinfo level %d not handled\n", nbench_line_count, level); + return; + } + + ZERO_STRUCT(io); + + i = find_handle(fnum); + + io.generic.level = level; + io.generic.file.fnum = ftable[i].fd; + unix_to_nt_time(&io.basic_info.in.create_time, time(NULL)); + unix_to_nt_time(&io.basic_info.in.access_time, 0); + unix_to_nt_time(&io.basic_info.in.write_time, 0); + unix_to_nt_time(&io.basic_info.in.change_time, 0); + io.basic_info.in.attrib = 0; + + ret = smb_raw_setfileinfo(c->tree, &io); + + check_status("Setfileinfo", status, ret); +} + +void nb_qfsinfo(int level, NTSTATUS status) +{ + union smb_fsinfo io; + TALLOC_CTX *mem_ctx; + NTSTATUS ret; + + mem_ctx = talloc_init("cli_dskattr"); + + io.generic.level = level; + ret = smb_raw_fsinfo(c->tree, mem_ctx, &io); + + talloc_destroy(mem_ctx); + + check_status("Fsinfo", status, ret); +} + +/* callback function used for trans2 search */ +static BOOL findfirst_callback(void *private, union smb_search_data *file) +{ + return True; +} + +void nb_findfirst(const char *mask, int level, int maxcnt, int count, NTSTATUS status) +{ + union smb_search_first io; + TALLOC_CTX *mem_ctx; + NTSTATUS ret; + + mem_ctx = talloc_init("cli_dskattr"); + + io.t2ffirst.level = level; + io.t2ffirst.in.max_count = maxcnt; + io.t2ffirst.in.search_attrib = FILE_ATTRIBUTE_DIRECTORY; + io.t2ffirst.in.pattern = mask; + io.t2ffirst.in.flags = FLAG_TRANS2_FIND_CLOSE; + io.t2ffirst.in.storage_type = 0; + + ret = smb_raw_search_first(c->tree, mem_ctx, &io, NULL, findfirst_callback); + + talloc_destroy(mem_ctx); + + check_status("Search", status, ret); + + if (io.t2ffirst.out.count != count) { + printf("[%d] Warning: got count %d expected %d\n", + nbench_line_count, + io.t2ffirst.out.count, count); + } +} + +void nb_flush(int fnum, NTSTATUS status) +{ + struct smb_flush io; + NTSTATUS ret; + int i; + i = find_handle(fnum); + + io.in.fnum = ftable[i].fd; + + ret = smb_raw_flush(c->tree, &io); + + check_status("Flush", status, ret); +} + +void nb_deltree(const char *dname) +{ + int total_deleted; + + total_deleted = cli_deltree(c->tree, dname); + + if (total_deleted == -1) { + printf("Failed to cleanup tree %s - exiting\n", dname); + exit(1); + } + + cli_rmdir(c->tree, dname); +} + +void nb_cleanup(const char *cname) +{ + char *dname = NULL; + smb_raw_exit(c->session); + asprintf(&dname, "\\clients\\%s", cname); + nb_deltree(dname); + free(dname); + cli_rmdir(c->tree, "clients"); + children[nbio_id].done = 1; +} diff --git a/source4/torture/nbio.c b/source4/torture/nbio.c deleted file mode 100644 index 65584b1852..0000000000 --- a/source4/torture/nbio.c +++ /dev/null @@ -1,287 +0,0 @@ -#define NBDEBUG 0 - -/* - Unix SMB/CIFS implementation. - SMB torture tester - Copyright (C) Andrew Tridgell 1997-1998 - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include "includes.h" - -#define MAX_FILES 1000 - -static char buf[70000]; -extern int line_count; -extern int nbio_id; -static int nprocs; -static BOOL bypass_io; - -static struct { - int fd; - int handle; -} ftable[MAX_FILES]; - -static struct { - double bytes_in, bytes_out; - int line; - int done; -} *children; - -double nbio_total(void) -{ - int i; - double total = 0; - for (i=0;i<nprocs;i++) { - total += children[i].bytes_out + children[i].bytes_in; - } - return total; -} - -void nb_alarm(void) -{ - int i; - int lines=0, num_clients=0; - if (nbio_id != -1) return; - - for (i=0;i<nprocs;i++) { - lines += children[i].line; - if (!children[i].done) num_clients++; - } - - printf("%4d %8d %.2f MB/sec\r", num_clients, lines/nprocs, 1.0e-6 * nbio_total() / end_timer()); - - signal(SIGALRM, nb_alarm); - alarm(1); -} - -void nbio_shmem(int n) -{ - nprocs = n; - children = shm_setup(sizeof(*children) * nprocs); - if (!children) { - printf("Failed to setup shared memory!\n"); - exit(1); - } -} - -static int find_handle(int handle) -{ - int i; - children[nbio_id].line = line_count; - for (i=0;i<MAX_FILES;i++) { - if (ftable[i].handle == handle) return i; - } - printf("(%d) ERROR: handle %d was not found\n", - line_count, handle); - exit(1); - - return -1; /* Not reached */ -} - - -static struct cli_state *c; - -static void sigsegv(int sig) -{ - char line[200]; - printf("segv at line %d\n", line_count); - slprintf(line, sizeof(line), "/usr/X11R6/bin/xterm -e gdb /proc/%d/exe %d", - (int)getpid(), (int)getpid()); - system(line); - exit(1); -} - -void nb_setup(struct cli_state *cli) -{ - signal(SIGSEGV, sigsegv); - c = cli; - start_timer(); - children[nbio_id].done = 0; - if (bypass_io) - printf("skipping I/O\n"); -} - - -void nb_unlink(const char *fname) -{ - if (NT_STATUS_IS_ERR(cli_unlink(c->tree, fname))) { -#if NBDEBUG - printf("(%d) unlink %s failed (%s)\n", - line_count, fname, cli_errstr(c)); -#endif - } -} - - -void nb_createx(const char *fname, - unsigned create_options, unsigned create_disposition, int handle) -{ - int fd, i; - uint32 desired_access; - - if (create_options & NTCREATEX_OPTIONS_DIRECTORY) { - desired_access = SA_RIGHT_FILE_READ_DATA; - } else { - desired_access = SA_RIGHT_FILE_READ_DATA | SA_RIGHT_FILE_WRITE_DATA; - } - - fd = cli_nt_create_full(c->tree, fname, 0, - desired_access, - 0x0, - NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE, - create_disposition, - create_options, 0); - if (fd == -1 && handle != -1) { - printf("ERROR: cli_nt_create_full failed for %s - %s\n", - fname, cli_errstr(c->tree)); - exit(1); - } - if (fd != -1 && handle == -1) { - printf("ERROR: cli_nt_create_full succeeded for %s\n", fname); - exit(1); - } - if (fd == -1) return; - - for (i=0;i<MAX_FILES;i++) { - if (ftable[i].handle == 0) break; - } - if (i == MAX_FILES) { - printf("(%d) file table full for %s\n", line_count, - fname); - exit(1); - } - ftable[i].handle = handle; - ftable[i].fd = fd; -} - -void nb_writex(int handle, int offset, int size, int ret_size) -{ - int i; - - if (buf[0] == 0) memset(buf, 1, sizeof(buf)); - - i = find_handle(handle); - if (!bypass_io && cli_write(c->tree, ftable[i].fd, 0, buf, offset, size) != ret_size) { - printf("(%d) ERROR: write failed on handle %d, fd %d \ -errno %d (%s)\n", line_count, handle, ftable[i].fd, errno, strerror(errno)); - exit(1); - } - - children[nbio_id].bytes_out += ret_size; -} - -void nb_readx(int handle, int offset, int size, int ret_size) -{ - int i, ret; - - i = find_handle(handle); - if (!bypass_io && (ret=cli_read(c->tree, ftable[i].fd, buf, offset, size)) != ret_size) { - printf("(%d) ERROR: read failed on handle %d ofs=%d size=%d res=%d fd %d errno %d (%s)\n", - line_count, handle, offset, size, ret, ftable[i].fd, errno, strerror(errno)); - exit(1); - } - children[nbio_id].bytes_in += ret_size; -} - -void nb_close(int handle) -{ - int i; - i = find_handle(handle); - if (NT_STATUS_IS_ERR(cli_close(c->tree, ftable[i].fd))) { - printf("(%d) close failed on handle %d\n", line_count, handle); - exit(1); - } - ftable[i].handle = 0; -} - -void nb_rmdir(const char *fname) -{ - if (NT_STATUS_IS_ERR(cli_rmdir(c->tree, fname))) { - printf("ERROR: rmdir %s failed (%s)\n", - fname, cli_errstr(c->tree)); - exit(1); - } -} - -void nb_rename(const char *old, const char *new) -{ - if (NT_STATUS_IS_ERR(cli_rename(c->tree, old, new))) { - printf("ERROR: rename %s %s failed (%s)\n", - old, new, cli_errstr(c->tree)); - exit(1); - } -} - - -void nb_qpathinfo(const char *fname) -{ - cli_qpathinfo(c->tree, fname, NULL, NULL, NULL, NULL, NULL); -} - -void nb_qfileinfo(int fnum) -{ - int i; - i = find_handle(fnum); - cli_qfileinfo(c->tree, ftable[i].fd, NULL, NULL, NULL, NULL, NULL, NULL, NULL); -} - -void nb_qfsinfo(int level) -{ - int bsize, total, avail; - /* this is not the right call - we need cli_qfsinfo() */ - cli_dskattr(c->tree, &bsize, &total, &avail); -} - -static void find_fn(file_info *finfo, const char *name, void *state) -{ - /* noop */ -} - -void nb_findfirst(const char *mask) -{ - cli_list(c->tree, mask, 0, find_fn, NULL); -} - -void nb_flush(int fnum) -{ - struct smb_flush io; - int i; - i = find_handle(fnum); - io.in.fnum = ftable[i].fd; - smb_raw_flush(c->tree, &io); -} - -void nb_deltree(const char *dname) -{ - int total_deleted; - - total_deleted = cli_deltree(c->tree, dname); - - if (total_deleted == -1) { - printf("Failed to cleanup tree %s - exiting\n", dname); - exit(1); - } - - if (total_deleted > 0) printf("WARNING: Cleaned up %d files\n", total_deleted); -} - - -void nb_cleanup(void) -{ - cli_rmdir(c->tree, "clients"); - children[nbio_id].done = 1; -} diff --git a/source4/torture/torture.c b/source4/torture/torture.c index a770e98c5f..bd804539c0 100644 --- a/source4/torture/torture.c +++ b/source4/torture/torture.c @@ -20,7 +20,7 @@ #include "includes.h" -static int nprocs=4; +int torture_nprocs=4; int torture_numops=100; int torture_entries=1000; int torture_failures=1; @@ -28,13 +28,10 @@ static int procnum; /* records process count number when forking */ static struct cli_state *current_cli; static BOOL use_oplocks; static BOOL use_level_II_oplocks; -static const char *client_txt = "client_oplocks.txt"; static BOOL use_kerberos; BOOL torture_showall = False; -static double create_procs(BOOL (*fn)(int), BOOL *result); - #define CHECK_MAX_FAILURES(label) do { if (++failures >= torture_failures) goto label; } while (0) static struct cli_state *open_nbt_connection(void) @@ -298,13 +295,10 @@ static BOOL rw_torture(struct cli_state *c) return correct; } -static BOOL run_torture(int dummy) +static BOOL run_torture(struct cli_state *cli, int dummy) { - struct cli_state *cli; BOOL ret; - cli = current_cli; - ret = rw_torture(cli); if (!torture_close_connection(cli)) { @@ -525,13 +519,10 @@ static BOOL run_readwritetest(int dummy) return (test1 && test2); } -static BOOL run_readwritemulti(int dummy) +static BOOL run_readwritemulti(struct cli_state *cli, int dummy) { - struct cli_state *cli; BOOL test; - cli = current_cli; - test = rw_torture3(cli, "\\multitest.txt"); if (!torture_close_connection(cli)) { @@ -542,128 +533,6 @@ static BOOL run_readwritemulti(int dummy) } -int line_count = 0; -int nbio_id; - -#define ival(s) strtol(s, NULL, 0) - -/* run a test that simulates an approximate netbench client load */ -static BOOL run_netbench(int client) -{ - struct cli_state *cli; - int i; - pstring line; - char *cname; - FILE *f; - const char *params[20]; - BOOL correct = True; - - cli = current_cli; - - nbio_id = client; - - nb_setup(cli); - - asprintf(&cname, "client%d", client); - - f = fopen(client_txt, "r"); - - if (!f) { - perror(client_txt); - return False; - } - - while (fgets(line, sizeof(line)-1, f)) { - line_count++; - - line[strlen(line)-1] = 0; - - /* printf("[%d] %s\n", line_count, line); */ - - all_string_sub(line,"client1", cname, sizeof(line)); - - /* parse the command parameters */ - params[0] = strtok(line," "); - i = 0; - while (params[i]) params[++i] = strtok(NULL," "); - - params[i] = ""; - - if (i < 2) continue; - - if (!strncmp(params[0],"SMB", 3)) { - printf("ERROR: You are using a dbench 1 load file\n"); - exit(1); - } - DEBUG(9,("run_netbench(%d): %s %s\n", client, params[0], params[1])); - - if (!strcmp(params[0],"NTCreateX")) { - nb_createx(params[1], ival(params[2]), ival(params[3]), - ival(params[4])); - } else if (!strcmp(params[0],"Close")) { - nb_close(ival(params[1])); - } else if (!strcmp(params[0],"Rename")) { - nb_rename(params[1], params[2]); - } else if (!strcmp(params[0],"Unlink")) { - nb_unlink(params[1]); - } else if (!strcmp(params[0],"Deltree")) { - nb_deltree(params[1]); - } else if (!strcmp(params[0],"Rmdir")) { - nb_rmdir(params[1]); - } else if (!strcmp(params[0],"QUERY_PATH_INFORMATION")) { - nb_qpathinfo(params[1]); - } else if (!strcmp(params[0],"QUERY_FILE_INFORMATION")) { - nb_qfileinfo(ival(params[1])); - } else if (!strcmp(params[0],"QUERY_FS_INFORMATION")) { - nb_qfsinfo(ival(params[1])); - } else if (!strcmp(params[0],"FIND_FIRST")) { - nb_findfirst(params[1]); - } else if (!strcmp(params[0],"WriteX")) { - nb_writex(ival(params[1]), - ival(params[2]), ival(params[3]), ival(params[4])); - } else if (!strcmp(params[0],"ReadX")) { - nb_readx(ival(params[1]), - ival(params[2]), ival(params[3]), ival(params[4])); - } else if (!strcmp(params[0],"Flush")) { - nb_flush(ival(params[1])); - } else { - printf("Unknown operation %s\n", params[0]); - exit(1); - } - } - fclose(f); - - nb_cleanup(); - - if (!torture_close_connection(cli)) { - correct = False; - } - - return correct; -} - - -/* run a test that simulates an approximate netbench client load */ -static BOOL run_nbench(int dummy) -{ - double t; - BOOL correct = True; - - nbio_shmem(nprocs); - - nbio_id = -1; - - signal(SIGALRM, SIGNAL_CAST nb_alarm); - alarm(1); - t = create_procs(run_netbench, &correct); - alarm(0); - - printf("\nThroughput %g MB/sec\n", - 1.0e-6 * nbio_total() / t); - return correct; -} - - /* This test checks for two things: @@ -1852,17 +1721,14 @@ static BOOL run_unlinktest(int dummy) /* test how many open files this server supports on the one socket */ -static BOOL run_maxfidtest(int dummy) +static BOOL run_maxfidtest(struct cli_state *cli, int dummy) { - struct cli_state *cli; const char *template = "\\maxfid.%d.%d"; char *fname; int fnums[0x11000], i; int retries=4; BOOL correct = True; - cli = current_cli; - if (retries <= 0) { printf("failed to connect\n"); return False; @@ -3837,39 +3703,39 @@ static void sigcont(void) { } -static double create_procs(BOOL (*fn)(int), BOOL *result) +double torture_create_procs(BOOL (*fn)(struct cli_state *, int), BOOL *result) { int i, status; volatile pid_t *child_status; volatile BOOL *child_status_out; int synccount; int tries = 8; - double start_time_limit = 10 + (nprocs * 1.5); + double start_time_limit = 10 + (torture_nprocs * 1.5); synccount = 0; signal(SIGCONT, sigcont); - child_status = (volatile pid_t *)shm_setup(sizeof(pid_t)*nprocs); + child_status = (volatile pid_t *)shm_setup(sizeof(pid_t)*torture_nprocs); if (!child_status) { printf("Failed to setup shared memory\n"); return -1; } - child_status_out = (volatile BOOL *)shm_setup(sizeof(BOOL)*nprocs); + child_status_out = (volatile BOOL *)shm_setup(sizeof(BOOL)*torture_nprocs); if (!child_status_out) { printf("Failed to setup result status shared memory\n"); return -1; } - for (i = 0; i < nprocs; i++) { + for (i = 0; i < torture_nprocs; i++) { child_status[i] = 0; child_status_out[i] = True; } start_timer(); - for (i=0;i<nprocs;i++) { + for (i=0;i<torture_nprocs;i++) { procnum = i; if (fork() == 0) { char *myname; @@ -3899,38 +3765,38 @@ static double create_procs(BOOL (*fn)(int), BOOL *result) _exit(1); } - child_status_out[i] = fn(i); + child_status_out[i] = fn(current_cli, i); _exit(0); } } do { synccount = 0; - for (i=0;i<nprocs;i++) { + for (i=0;i<torture_nprocs;i++) { if (child_status[i]) synccount++; } - if (synccount == nprocs) break; + if (synccount == torture_nprocs) break; msleep(100); } while (end_timer() < start_time_limit); - if (synccount != nprocs) { - printf("FAILED TO START %d CLIENTS (started %d)\n", nprocs, synccount); + if (synccount != torture_nprocs) { + printf("FAILED TO START %d CLIENTS (started %d)\n", torture_nprocs, synccount); *result = False; return end_timer(); } - printf("Starting %d clients\n", nprocs); + printf("Starting %d clients\n", torture_nprocs); /* start the client load */ start_timer(); - for (i=0;i<nprocs;i++) { + for (i=0;i<torture_nprocs;i++) { child_status[i] = 0; } kill(0, SIGCONT); - printf("%d clients started\n", nprocs); + printf("%d clients started\n", torture_nprocs); - for (i=0;i<nprocs;i++) { + for (i=0;i<torture_nprocs;i++) { int ret; while ((ret=waitpid(0, &status, 0)) == -1 && errno == EINTR) /* noop */ ; if (ret == -1 || WEXITSTATUS(status) != 0) { @@ -3940,7 +3806,7 @@ static double create_procs(BOOL (*fn)(int), BOOL *result) printf("\n"); - for (i=0;i<nprocs;i++) { + for (i=0;i<torture_nprocs;i++) { if (!child_status_out[i]) { *result = False; } @@ -3969,7 +3835,7 @@ static struct { {"MAXFID", run_maxfidtest, FLAG_MULTIPROC}, {"TORTURE",run_torture, FLAG_MULTIPROC}, {"NEGNOWAIT", run_negprot_nowait, 0}, - {"NBENCH", run_nbench, 0}, + {"NBENCH", torture_nbench, 0}, {"DIR", run_dirtest, 0}, {"DIR1", run_dirtest1, 0}, {"DENY1", torture_denytest1, 0}, @@ -4067,7 +3933,7 @@ static BOOL run_test(const char *name) printf("Running %s\n", torture_ops[i].name); if (torture_ops[i].flags & FLAG_MULTIPROC) { BOOL result; - t = create_procs(torture_ops[i].fn, &result); + t = torture_create_procs(torture_ops[i].fn, &result); if (!result) { ret = False; printf("TEST %s FAILED!\n", torture_ops[i].name); @@ -4130,6 +3996,7 @@ static void usage(void) printf("\t-m maximum protocol\n"); printf("\t-L use oplocks\n"); printf("\t-c CLIENT.TXT specify client load file for NBENCH\n"); + printf("\t-t timelimit specify NBENCH time limit (seconds)\n"); printf("\t-A showall\n"); printf("\t-p port\n"); printf("\t-s seed\n"); @@ -4211,7 +4078,7 @@ static void usage(void) srandom(time(NULL)); - while ((opt = getopt(argc, argv, "p:hW:U:n:N:O:o:e:m:Ld:Ac:ks:f:s:")) != EOF) { + while ((opt = getopt(argc, argv, "p:hW:U:n:N:O:o:e:m:Ld:Ac:ks:f:s:t:")) != EOF) { switch (opt) { case 'p': lp_set_cmdline("smb ports", optarg); @@ -4236,7 +4103,7 @@ static void usage(void) srandom(atoi(optarg)); break; case 'N': - nprocs = atoi(optarg); + torture_nprocs = atoi(optarg); break; case 'o': torture_numops = atoi(optarg); @@ -4251,7 +4118,10 @@ static void usage(void) torture_showall = True; break; case 'c': - client_txt = optarg; + lp_set_cmdline("torture:loadfile", optarg); + break; + case 't': + lp_set_cmdline("torture:timelimit", optarg); break; case 'k': #ifdef HAVE_KRB5 |