lease02: add new "lease02" test
authorDaniel Wagner <daniel.wagner@bmw-carit.de>
Thu, 19 Feb 2015 14:23:14 +0000 (15:23 +0100)
committerJeff Layton <jeff.layton@primarydata.com>
Thu, 19 Feb 2015 20:52:07 +0000 (15:52 -0500)
Add a microbench mark which test the performance of taking and
releasing a read lease with many processes in a tight loop.

Based on posix02.

Signed-off-by: Daniel Wagner <daniel.wagner@bmw-carit.de>
Makefile.am
lease02.c [new file with mode: 0644]

index b0a2851a86deffa650315afc3ae4f5e67c38d996..4a2ae9831202098e7f45db5f77fc55a55fb4a506 100644 (file)
@@ -4,6 +4,6 @@ ACLOCAL_AMFLAGS = -I m4
 EXTRA_DIST = m4/gnulib-cache.m4
 LDADD = lib/libgnu.a -lrt
 
-bin_PROGRAMS = flock01 flock02 posix01 posix02 posix03 lease01
+bin_PROGRAMS = flock01 flock02 posix01 posix02 posix03 lease01 lease02
 
 SUBDIRS = lib/
diff --git a/lease02.c b/lease02.c
new file mode 100644 (file)
index 0000000..0fa33e4
--- /dev/null
+++ b/lease02.c
@@ -0,0 +1,178 @@
+/*
+ * Lease performance test 2
+ *
+ * Fork off a given number of children who each open their own
+ * file. Then have each child take a read lease and release the lease
+ * for the given number of times.
+ *
+ * Time this to measure lease performance for lease heavy workloads where the
+ * locks are generally uncontended.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <stdlib.h>
+#include <time.h>
+#include <sys/mman.h>
+
+#include "timespec.h"
+
+#define NRPROC (128)
+#define NRLOCK (20480)
+
+static struct timespec *diff;
+
+static int
+leaseunlease(int nrlock, struct timespec *slot)
+{
+       int fd, i, ret;
+       pid_t pid = getpid();
+       char name[10]; /* big enough for pid_t in hex + NULL */
+       struct timespec start, end;
+
+       ret = snprintf(name, sizeof(name), "%x", pid);
+       if (ret >= (int)sizeof(name)) {
+               perror("sprintf");
+               return 1;
+       }
+
+       fd = open(name, O_CREAT|O_RDONLY, 0644);
+       if (fd < 0) {
+               perror("open");
+               return fd;
+       }
+
+       ret = clock_gettime(CLOCK_MONOTONIC_RAW, &start);
+       if (ret) {
+               perror("clock_gettime");
+               return ret;
+       }
+
+       for (i = 0; i < nrlock; ++i) {
+               ret = fcntl(fd, F_SETLEASE, F_RDLCK);
+               if (ret < 0) {
+                       perror("fcntl");
+                       break;
+               }
+               ret = fcntl(fd, F_SETLEASE, F_RDLCK);
+               if (ret < 0) {
+                       perror("fcntl");
+                       break;
+               }
+       }
+
+       ret = clock_gettime(CLOCK_MONOTONIC_RAW, &end);
+       if (ret) {
+               perror("clock_gettime");
+               return ret;
+       }
+
+       close(fd);
+       *slot = timespec_sub(end, start);
+       return ret;
+}
+
+void
+usage(char *prog)
+{
+       printf("usage: %s [-n nr_procs] [-l nr_locks] directory\n", prog);
+}
+
+int
+main(int argc, char **argv)
+{
+       int i, opt, valid = 0;
+       int nproc = NRPROC;
+       int nlock = NRLOCK;
+       pid_t *pids;
+       char *dirname;
+       struct timespec total = { .tv_sec = 0,
+                                 .tv_nsec = 0 };
+
+       while ((opt = getopt(argc, argv, "l:n:")) != -1) {
+               switch (opt) {
+               case 'l':
+                       nlock = atoi(optarg);
+                       break;
+               case 'n':
+                       nproc = atoi(optarg);
+                       break;
+               default:
+                       usage(argv[0]);
+                       return 1;
+               }
+       }
+
+       dirname = argv[optind];
+       if (!dirname) {
+               usage(argv[0]);
+               return 1;
+       }
+
+       if (mkdir(dirname, S_IRWXU)) {
+               perror("mkdir");
+               return 1;
+       }
+
+       if (chdir(dirname)) {
+               perror("chdir");
+               return 1;
+       }
+
+       pids = calloc(nproc, sizeof(pid_t));
+       if (!pids) {
+               fprintf(stderr, "Unable to allocate pids array!");
+               return 1;
+       }
+
+       diff = mmap(0, nproc * sizeof(*diff), PROT_READ | PROT_WRITE,
+                       MAP_ANONYMOUS | MAP_SHARED, -1, 0);
+       if (diff == (struct timespec *)-1) {
+               fprintf(stderr, "Unable to allocate timespec array!");
+               return 1;
+       }
+
+       for (i = 0; i < nproc; ++i) {
+               pids[i] = fork();
+               if (!pids[i])
+                       return leaseunlease(nlock, &diff[i]);
+       }
+
+       for (i = 0; i < nproc; ++i) {
+               int status;
+
+               if (pids[i] < 0) {
+                       fprintf(stderr, "process %d failed to fork\n", i);
+                       continue;
+               }
+               if (waitpid(pids[i], &status, 0) < 0) {
+                       fprintf(stderr, "unable to reap pid %d\n", pids[i]);
+                       continue;
+               }
+               if (!WIFEXITED(status) || WEXITSTATUS(status)) {
+                       fprintf(stderr, "pid %d exited abnormally(0x%x)\n", pids[i],status);
+                       continue;
+               }
+               total = timespec_add(total, diff[i]);
+               ++valid;
+       }
+
+       if (valid != nproc) {
+               fprintf(stderr, "Some children didn't run properly -- "
+                               "requested %d but only got %d\n", nproc, valid);
+               return 1;
+       }
+
+       printf("%ld.%ld\n", total.tv_sec, total.tv_nsec);
+       return 0;
+}