summaryrefslogtreecommitdiff
path: root/source4/torture/raw/lookuprate.c
diff options
context:
space:
mode:
authorJelmer Vernooij <jelmer@samba.org>2008-04-25 10:04:20 +0100
committerJelmer Vernooij <jelmer@samba.org>2008-04-25 10:04:20 +0100
commitcc9c4aaa8d02c4c31c9e9a4bb53e5941683fcc31 (patch)
treed0b116699dee35372ed335834989e1c885e8f94a /source4/torture/raw/lookuprate.c
parentd1432d617e6ed04c33ca214d7f3b0099bdf53065 (diff)
parent240d959005f5fd80a38b3734b39dd5d6e425a566 (diff)
downloadsamba-cc9c4aaa8d02c4c31c9e9a4bb53e5941683fcc31.tar.gz
samba-cc9c4aaa8d02c4c31c9e9a4bb53e5941683fcc31.tar.bz2
samba-cc9c4aaa8d02c4c31c9e9a4bb53e5941683fcc31.zip
Merge branch 'v4-0-test' of ssh://git.samba.org/data/git/samba into v4-0-gmake3
Conflicts: source/Makefile source/auth/config.mk source/auth/gensec/config.mk source/build/m4/public.m4 source/build/make/python.mk source/build/make/rules.mk source/build/smb_build/header.pm source/build/smb_build/main.pl source/build/smb_build/makefile.pm source/dsdb/config.mk source/dsdb/samdb/ldb_modules/config.mk source/kdc/config.mk source/lib/events/config.mk source/lib/events/events.c source/lib/ldb/config.mk source/lib/nss_wrapper/config.mk source/lib/policy/config.mk source/lib/util/config.mk source/libcli/smb2/config.mk source/libnet/config.mk source/librpc/config.mk source/nbt_server/config.mk source/ntptr/ntptr_base.c source/ntvfs/posix/config.mk source/ntvfs/sysdep/config.mk source/param/config.mk source/rpc_server/config.mk source/rpc_server/service_rpc.c source/scripting/ejs/config.mk source/scripting/python/config.mk source/smb_server/config.mk source/smbd/server.c source/torture/config.mk source/torture/smb2/config.mk source/wrepl_server/config.mk (This used to be commit 13bbd420681519894a4036729c43273912c9b402)
Diffstat (limited to 'source4/torture/raw/lookuprate.c')
-rw-r--r--source4/torture/raw/lookuprate.c320
1 files changed, 320 insertions, 0 deletions
diff --git a/source4/torture/raw/lookuprate.c b/source4/torture/raw/lookuprate.c
new file mode 100644
index 0000000000..0e8f002efb
--- /dev/null
+++ b/source4/torture/raw/lookuprate.c
@@ -0,0 +1,320 @@
+/*
+ File lookup rate test.
+
+ Copyright (C) James Peach 2006
+
+ 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 3 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, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "param/param.h"
+#include "system/filesys.h"
+#include "torture/torture.h"
+#include "torture/basic/proto.h"
+#include "libcli/libcli.h"
+#include "torture/util.h"
+#include "lib/cmdline/popt_common.h"
+#include "auth/credentials/credentials.h"
+
+#define BASEDIR "\\lookuprate"
+#define MISSINGNAME BASEDIR "\\foo"
+
+#define FUZZ_PERCENT 10
+
+#define usec_to_sec(s) ((s) / 1000000)
+#define sec_to_usec(s) ((s) * 1000000)
+
+struct rate_record
+{
+ unsigned dirent_count;
+ unsigned querypath_persec;
+ unsigned findfirst_persec;
+};
+
+static struct rate_record records[] =
+{
+ { 0, 0, 0 }, /* Base (optimal) lookup rate. */
+ { 100, 0, 0},
+ { 1000, 0, 0},
+ { 10000, 0, 0},
+ { 100000, 0, 0}
+};
+
+typedef NTSTATUS lookup_function(struct smbcli_tree *tree, const char * path);
+
+/* Test whether rhs is within fuzz% of lhs. */
+static bool fuzzily_equal(unsigned lhs, unsigned rhs, int percent)
+{
+ double fuzz = (double)lhs * (double)percent/100.0;
+
+ if (((double)rhs >= ((double)lhs - fuzz)) &&
+ ((double)rhs <= ((double)lhs + fuzz))) {
+ return true;
+ }
+
+ return false;
+
+}
+
+static NTSTATUS fill_directory(struct smbcli_tree *tree,
+ const char * path, unsigned count)
+{
+ NTSTATUS status;
+ char *fname = NULL;
+ unsigned i;
+ unsigned current;
+
+ struct timeval start;
+ struct timeval now;
+
+ status = smbcli_mkdir(tree, path);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ printf("filling directory %s with %u files... ", path, count);
+ fflush(stdout);
+
+ current = random();
+ start = timeval_current();
+
+ for (i = 0; i < count; ++i) {
+ int fnum;
+
+ ++current;
+ fname = talloc_asprintf(NULL, "%s\\fill%u",
+ path, current);
+
+ fnum = smbcli_open(tree, fname, O_RDONLY|O_CREAT,
+ OPENX_MODE_DENY_NONE);
+ if (fnum < 0) {
+ talloc_free(fname);
+ return smbcli_nt_error(tree);
+ }
+
+ smbcli_close(tree, fnum);
+ talloc_free(fname);
+ }
+
+ if (count) {
+ double rate;
+ now = timeval_current();
+ rate = (double)count / usec_to_sec((double)usec_time_diff(&now, &start));
+ printf("%u/sec\n", (unsigned)rate);
+ } else {
+ printf("done\n");
+ }
+
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS squash_lookup_error(NTSTATUS status)
+{
+ if (NT_STATUS_IS_OK(status)) {
+ return NT_STATUS_OK;
+ }
+
+ /* We don't care if the file isn't there. */
+ if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_PATH_NOT_FOUND)) {
+ return NT_STATUS_OK;
+ }
+
+ if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
+ return NT_STATUS_OK;
+ }
+
+ if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_FILE)) {
+ return NT_STATUS_OK;
+ }
+
+ return status;
+}
+
+/* Look up a pathname using TRANS2_QUERY_PATH_INFORMATION. */
+static NTSTATUS querypath_lookup(struct smbcli_tree *tree, const char * path)
+{
+ NTSTATUS status;
+ time_t ftimes[3];
+ size_t fsize;
+ uint16_t fmode;
+
+ status = smbcli_qpathinfo(tree, path, &ftimes[0], &ftimes[1], &ftimes[2],
+ &fsize, &fmode);
+
+ return squash_lookup_error(status);
+}
+
+/* Look up a pathname using TRANS2_FIND_FIRST2. */
+static NTSTATUS findfirst_lookup(struct smbcli_tree *tree, const char * path)
+{
+ NTSTATUS status = NT_STATUS_OK;
+
+ if (smbcli_list(tree, path, 0, NULL, NULL) < 0) {
+ status = smbcli_nt_error(tree);
+ }
+
+ return squash_lookup_error(status);
+}
+
+static NTSTATUS lookup_rate_convert(struct smbcli_tree *tree,
+ lookup_function lookup, const char * path, unsigned * rate)
+{
+ NTSTATUS status;
+
+ struct timeval start;
+ struct timeval now;
+ unsigned count = 0;
+ int64_t elapsed = 0;
+
+#define LOOKUP_PERIOD_SEC (2)
+
+ start = timeval_current();
+ while (elapsed < sec_to_usec(LOOKUP_PERIOD_SEC)) {
+
+ status = lookup(tree, path);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ ++count;
+ now = timeval_current();
+ elapsed = usec_time_diff(&now, &start);
+ }
+
+#undef LOOKUP_PERIOD_SEC
+
+ *rate = (unsigned)((double)count / (double)usec_to_sec(elapsed));
+ return NT_STATUS_OK;
+}
+
+static bool remove_working_directory(struct smbcli_tree *tree,
+ const char * path)
+{
+ int tries;
+
+ /* Using smbcli_deltree to delete a very large number of files
+ * doesn't work against all servers. Work around this by
+ * retrying.
+ */
+ for (tries = 0; tries < 5; ) {
+ int ret;
+
+ ret = smbcli_deltree(tree, BASEDIR);
+ if (ret == -1) {
+ tries++;
+ printf("(%s) failed to deltree %s: %s\n",
+ __location__, BASEDIR,
+ smbcli_errstr(tree));
+ continue;
+ }
+
+ return true;
+ }
+
+ return false;
+
+}
+
+/* Verify that looking up a file name takes constant time.
+ *
+ * This test samples the lookup rate for a non-existant filename in a
+ * directory, while varying the number of files in the directory. The
+ * lookup rate should continue to approximate the lookup rate for the
+ * empty directory case.
+ */
+bool torture_bench_lookup(struct torture_context *torture)
+{
+ NTSTATUS status;
+ bool result = false;
+
+ int i, tries;
+ struct smbcli_state *cli = NULL;
+
+ if (!torture_open_connection(&cli, torture, 0)) {
+ goto done;
+ }
+
+ remove_working_directory(cli->tree, BASEDIR);
+
+ for (i = 0; i < ARRAY_SIZE(records); ++i) {
+ printf("testing lookup rate with %u directory entries\n",
+ records[i].dirent_count);
+
+ status = fill_directory(cli->tree, BASEDIR,
+ records[i].dirent_count);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("failed to fill directory: %s\n", nt_errstr(status));
+ goto done;
+ }
+
+ status = lookup_rate_convert(cli->tree, querypath_lookup,
+ MISSINGNAME, &records[i].querypath_persec);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("querypathinfo of %s failed: %s\n",
+ MISSINGNAME, nt_errstr(status));
+ goto done;
+ }
+
+ status = lookup_rate_convert(cli->tree, findfirst_lookup,
+ MISSINGNAME, &records[i].findfirst_persec);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("findfirst of %s failed: %s\n",
+ MISSINGNAME, nt_errstr(status));
+ goto done;
+ }
+
+ printf("entries = %u, querypath = %u/sec, findfirst = %u/sec\n",
+ records[i].dirent_count,
+ records[i].querypath_persec,
+ records[i].findfirst_persec);
+
+ if (!remove_working_directory(cli->tree, BASEDIR)) {
+ goto done;
+ }
+ }
+
+ /* Ok. We have run all our tests. Walk through the records we
+ * accumulated and figure out whether the lookups took constant
+ * time of not.
+ */
+ for (i = 0; i < ARRAY_SIZE(records); ++i) {
+ if (!fuzzily_equal(records[0].querypath_persec,
+ records[i].querypath_persec,
+ FUZZ_PERCENT)) {
+ printf("querypath rate for %d entries differed by "
+ "more than %d%% from base rate\n",
+ records[i].dirent_count, FUZZ_PERCENT);
+ result = false;
+ }
+
+ if (!fuzzily_equal(records[0].findfirst_persec,
+ records[i].findfirst_persec,
+ FUZZ_PERCENT)) {
+ printf("findfirst rate for %d entries differed by "
+ "more than %d%% from base rate\n",
+ records[i].dirent_count, FUZZ_PERCENT);
+ result = false;
+ }
+ }
+
+done:
+ if (cli) {
+ remove_working_directory(cli->tree, BASEDIR);
+ talloc_free(cli);
+ }
+
+ return result;
+}
+
+/* vim: set sts=8 sw=8 : */