diff mbox

[v0,1/2] lease01: add new "lease01" test

Message ID 1424355794-30736-2-git-send-email-daniel.wagner@bmw-carit.de (mailing list archive)
State New, archived
Headers show

Commit Message

Daniel Wagner Feb. 19, 2015, 2:23 p.m. UTC
Add a microbench mark which test the performance of taking and
releasing a read lease in a tight loop.

Based on posix01.

Signed-off-by: Daniel Wagner <daniel.wagner@bmw-carit.de>
---
 Makefile.am |   2 +-
 lease01.c   | 177 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 178 insertions(+), 1 deletion(-)
 create mode 100644 lease01.c
diff mbox

Patch

diff --git a/Makefile.am b/Makefile.am
index 2ece31b..b0a2851 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -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
+bin_PROGRAMS = flock01 flock02 posix01 posix02 posix03 lease01
 
 SUBDIRS = lib/
diff --git a/lease01.c b/lease01.c
new file mode 100644
index 0000000..f3a2ae9
--- /dev/null
+++ b/lease01.c
@@ -0,0 +1,177 @@ 
+/*
+ * LEASE performance test 1
+ *
+ * Fork off a given number of children who attempt to repeatedly
+ * acquire a read lock over the whole file and then release it for a
+ * given number of times. Time this to get a rough indication of lease
+ * locking performance for a single, contended whole-file lock.
+ */
+
+#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 <stdbool.h>
+#include <sched.h>
+
+#include "timespec.h"
+
+#define NRPROC (128)
+#define NRLOCK (10240)
+
+static struct timespec *diff;
+
+static int
+leaseunlease(const char *name, int nrlock, struct timespec *slot,
+		bool verbose, bool yield)
+{
+	int fd, i, ret = 0;
+	struct timespec start, end;
+	pid_t pid = getpid();
+
+	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");
+			return ret;
+		}
+
+		if (verbose)
+			printf("pid:%u\n", pid);
+
+		ret = fcntl(fd, F_SETLEASE, F_UNLCK);
+		ret = clock_gettime(CLOCK_MONOTONIC_RAW, &end);
+		if (ret) {
+			perror("clock_gettime");
+			return ret;
+		}
+
+		/* yield CPU to give another worker a chance */
+		if (yield)
+			sched_yield();
+	}
+
+	clock_gettime(CLOCK_MONOTONIC_RAW, &end);
+	if (ret) {
+		perror("clock_gettime");
+		return ret;
+	}
+
+	close(fd);
+	*slot = timespec_sub(end, start);
+
+	return 0;
+}
+
+void
+usage(char *prog)
+{
+	printf("usage: %s [-n nr_procs] [-l nr_locks] [-v] [-y] filename\n", prog);
+}
+
+int
+main(int argc, char **argv)
+{
+	bool verbose = false, yield = false;
+	int i, opt, valid = 0;
+	int nproc = NRPROC;
+	int nlock = NRLOCK;
+	pid_t *pids;
+	struct timespec total = { .tv_sec = 0,
+				  .tv_nsec = 0 };
+
+
+	while ((opt = getopt(argc, argv, "l:n:vy")) != -1) {
+		switch (opt) {
+		case 'l':
+			nlock = atoi(optarg);
+			break;
+		case 'n':
+			nproc = atoi(optarg);
+			break;
+		case 'v':
+			verbose = true;
+			break;
+		default:
+			usage(argv[0]);
+			return 1;
+		}
+	}
+
+	if (!argv[optind]) {
+		usage(argv[0]);
+		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(argv[optind], nlock,
+						&diff[i], verbose, yield);
+	}
+
+	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;
+}