Re: [PATCH RFC 2/8] selftests: add stress testing tool for dcache

2020-05-12 Thread Dave Chinner
On Fri, May 08, 2020 at 03:23:17PM +0300, Konstantin Khlebnikov wrote:
> This tool fills dcache with negative dentries. Between iterations it prints
> statistics and measures time of inotify operation which might degrade.
> 
> Signed-off-by: Konstantin Khlebnikov 
> ---
>  tools/testing/selftests/filesystems/Makefile   |1 
>  .../testing/selftests/filesystems/dcache_stress.c  |  210 
> 

This sort of thing should go into fstests along with test scripts
that use it to exercise the dentry cache. We already have tools like
this in fstests (dirstress, metaperf, etc) for exercising name-based
operations like this, so it would fit right in.

That way it would get run by just about every filesystem developer
and distro QE department automatically and extremely frequently...

Cheers,

Dave.
-- 
Dave Chinner
da...@fromorbit.com


[PATCH RFC 2/8] selftests: add stress testing tool for dcache

2020-05-08 Thread Konstantin Khlebnikov
This tool fills dcache with negative dentries. Between iterations it prints
statistics and measures time of inotify operation which might degrade.

Signed-off-by: Konstantin Khlebnikov 
---
 tools/testing/selftests/filesystems/Makefile   |1 
 .../testing/selftests/filesystems/dcache_stress.c  |  210 
 2 files changed, 211 insertions(+)
 create mode 100644 tools/testing/selftests/filesystems/dcache_stress.c

diff --git a/tools/testing/selftests/filesystems/Makefile 
b/tools/testing/selftests/filesystems/Makefile
index 129880fb42d3..6b5e08617d11 100644
--- a/tools/testing/selftests/filesystems/Makefile
+++ b/tools/testing/selftests/filesystems/Makefile
@@ -3,5 +3,6 @@
 CFLAGS += -I../../../../usr/include/
 TEST_GEN_PROGS := devpts_pts
 TEST_GEN_PROGS_EXTENDED := dnotify_test
+TEST_GEN_FILES += dcache_stress
 
 include ../lib.mk
diff --git a/tools/testing/selftests/filesystems/dcache_stress.c 
b/tools/testing/selftests/filesystems/dcache_stress.c
new file mode 100644
index ..770e8876629e
--- /dev/null
+++ b/tools/testing/selftests/filesystems/dcache_stress.c
@@ -0,0 +1,210 @@
+// SPDX-License-Identifier: GPL-2.0
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+double now(void)
+{
+   struct timespec ts;
+
+   clock_gettime(CLOCK_MONOTONIC, );
+   return ts.tv_sec + ts.tv_nsec * 1e-9;
+}
+
+struct dentry_stat {
+   long nr_dentry;
+   long nr_unused;
+   long age_limit; /* age in seconds */
+   long want_pages;/* pages requested by system */
+   long nr_negative;   /* # of unused negative dentries */
+   long nr_buckets;/* count of dcache hash buckets */
+};
+
+void show_dentry_state(void)
+{
+   struct dentry_stat stat;
+   ssize_t len;
+   FILE *f;
+
+   f = fopen("/proc/sys/fs/dentry-state", "r");
+   if (!f)
+   err(2, "open fs.dentry-state");
+
+   if (fscanf(f, "%ld %ld %ld %ld %ld %ld",
+  _dentry,
+  _unused,
+  _limit,
+  _pages,
+  _negative,
+  _buckets) != 6)
+   err(2, "read fs.dentry-state");
+   fclose(f);
+
+   if (!stat.nr_buckets)
+   stat.nr_buckets = 1 << 20;  // for 8Gb ram
+
+   printf("nr_dentry = %ld\t%.1fM\n", stat.nr_dentry, stat.nr_dentry / 
1e6);
+   printf("nr_buckets = %ld\t%.1f avg\n", stat.nr_buckets, 
(double)stat.nr_dentry / stat.nr_buckets);
+   printf("nr_unused = %ld\t%.1f%%\n", stat.nr_unused, stat.nr_unused * 
100. / stat.nr_dentry);
+   printf("nr_negative = %ld\t%.1f%%\n\n", stat.nr_negative, 
stat.nr_negative * 100. / stat.nr_dentry);
+}
+
+void test_inotify(const char *path)
+{
+   double tm;
+   int fd;
+
+   fd = inotify_init1(0);
+
+   tm = now();
+   inotify_add_watch(fd, path, IN_OPEN);
+   tm = now() - tm;
+
+   printf("inotify time: %f seconds\n\n", tm);
+
+   close(fd);
+}
+
+int main(int argc, char **argv)
+{
+   char dir_name[] = "dcache_stress.XX";
+   char name[4096];
+   char *suffix = name;
+   int nr_iterations = 10;
+   int nr_names = 1 << 20;
+   int iteration, index;
+   int other_dir = -1;
+   int mknod_unlink = 0;
+   int mkdir_chdir = 0;
+   int second_access = 0;
+   long long total_names = 0;
+   double tm;
+   int opt;
+
+   while ((opt = getopt(argc, argv, "i:n:p:o:usdh")) != -1) {
+   switch (opt) {
+   case 'i':
+   nr_iterations = atoi(optarg);
+   break;
+   case 'n':
+   nr_names = atoi(optarg);
+   break;
+   case 'p':
+   strcpy(suffix, optarg);
+   suffix += strlen(suffix);
+   break;
+   case 'o':
+   other_dir = open(optarg, O_RDONLY | O_DIRECTORY);
+   if (other_dir < 0)
+   err(2, "open %s", optarg);
+   break;
+   case 'u':
+   mknod_unlink = 1;
+   break;
+   case 'd':
+   mkdir_chdir = 1;
+   break;
+   case 's':
+   second_access = 1;
+   break;
+   case '?':
+   case 'h':
+   printf("usage: %s [-i ] [-n ] [-p 
] [-o ] [-u] [-s]\n"
+  "  -i  test iterations, default %d\n"
+  "  -n  names at each iterations, default %d\n"
+  "  -p  prefix for names\n"
+  "  -o  interlave with other dir\n"
+  "  -s  touch twice\n"
+  "  -u  mknod-unlink