[master] cb61c369e Implement an optional high performance "cleaner"

Poul-Henning Kamp phk at FreeBSD.org
Fri Feb 8 12:11:08 UTC 2019


commit cb61c369ee6902909c01a92e07b3e8d898176cb4
Author: Poul-Henning Kamp <phk at FreeBSD.org>
Date:   Fri Feb 8 12:08:24 2019 +0000

    Implement an optional high performance "cleaner"
    
    When running really massive runs, "-j180 -n10000" kind of things,
    the "rm -rf" of the tmpdir becomes the limiting factor.
    
    The new -C option sends that int nice(1)'ed child process.

diff --git a/bin/varnishtest/vtc_main.c b/bin/varnishtest/vtc_main.c
index a20a9f6fb..196dd9202 100644
--- a/bin/varnishtest/vtc_main.c
+++ b/bin/varnishtest/vtc_main.c
@@ -108,6 +108,9 @@ int leave_temp;
 int vtc_witness = 0;
 static struct vsb *cbvsb;
 
+static int cleaner_fd = -1;
+static pid_t cleaner_pid;
+
 static struct buf *
 get_buf(void)
 {
@@ -172,6 +175,7 @@ usage(void)
 #define FMT "    %-28s # %s\n"
 	fprintf(stderr, FMT, "-b size",
 	    "Set internal buffer size (default: 1M)");
+	fprintf(stderr, FMT, "-C", "Use cleaner subprocess");
 	fprintf(stderr, FMT, "-D name=val", "Define macro");
 	fprintf(stderr, FMT, "-i", "Find varnish binaries in build tree");
 	fprintf(stderr, FMT, "-j jobs", "Run this many tests in parallel");
@@ -187,6 +191,86 @@ usage(void)
 	exit(1);
 }
 
+/**********************************************************************
+ * When running many tests, cleaning the tmpdir with "rm -rf" becomes
+ * chore which limits our performance.
+ * When the number of tests are above 100, we spawn a child-process
+ * to do that for us.
+ */
+
+static void
+cleaner_do(const char *dirname)
+{
+	char buf[BUFSIZ];
+
+	AZ(memcmp(dirname, tmppath, strlen(tmppath)));
+	if (cleaner_pid > 0) {
+		bprintf(buf, "%s\n", dirname);
+		assert(write(cleaner_fd, buf, strlen(buf)) == strlen(buf));
+		return;
+	}
+	bprintf(buf, "exec /bin/rm -rf %s\n", dirname);
+	AZ(system(buf));
+}
+
+static void
+cleaner_setup(void)
+{
+	int p[2], st;
+	char buf[BUFSIZ];
+	char *q;
+	pid_t pp;
+
+	AZ(pipe(p));
+	assert(p[0] > STDERR_FILENO);
+	assert(p[1] > STDERR_FILENO);
+	cleaner_pid = fork();
+	assert(cleaner_pid >= 0);
+	if (cleaner_pid == 0) {
+		closefd(&p[1]);
+		AZ(nice(1));
+		setbuf(stdin, NULL);
+		AZ(dup2(p[0], STDIN_FILENO));
+		while (fgets(buf, sizeof buf, stdin)) {
+			AZ(memcmp(buf, tmppath, strlen(tmppath)));
+			q = buf + strlen(buf);
+			assert(q > buf);
+			assert(q[-1] == '\n');
+			q[-1] = '\0';
+
+			/* Dont expend a shell on running /bin/rm */
+			pp = fork();
+			assert(pp >= 0);
+			if (pp == 0)
+				exit(execl("/bin/rm", "rm", "-rf", buf, NULL));
+			assert(waitpid(pp, &st, 0) == pp);
+			AZ(st);
+		}
+		exit(0);
+	}
+	closefd(&p[0]);
+	cleaner_fd = p[1];
+}
+
+static void
+cleaner_neuter(void)
+{
+	if (cleaner_pid > 0)
+		closefd(&cleaner_fd);
+}
+
+static void
+cleaner_finish(void)
+{
+	int st;
+
+	if (cleaner_pid > 0) {
+		closefd(&cleaner_fd);
+		assert(waitpid(cleaner_pid, &st, 0) == cleaner_pid);
+		AZ(st);
+	}
+}
+
 /**********************************************************************
  * CallBack
  */
@@ -252,8 +336,7 @@ tst_cb(const struct vev *ve, int what)
 			vtc_fail++;
 
 		if (leave_temp == 0 || (leave_temp == 1 && ecode <= 1)) {
-			bprintf(buf, "rm -rf %s", jp->tmpdir);
-			AZ(system(buf));
+			cleaner_do(jp->tmpdir);
 		} else {
 			bprintf(buf, "%s/LOG", jp->tmpdir);
 			f = fopen(buf, "w");
@@ -332,6 +415,7 @@ start_test(void)
 	jp->child = fork();
 	assert(jp->child >= 0);
 	if (jp->child == 0) {
+		cleaner_neuter();	// Too dangerous to have around
 		AZ(setpgid(getpid(), 0));
 		VFIL_null_fd(STDIN_FILENO);
 		assert(dup2(p[1], STDOUT_FILENO) == STDOUT_FILENO);
@@ -575,6 +659,7 @@ main(int argc, char * const *argv)
 	int ch, i;
 	int ntest = 1;			/* Run tests this many times */
 	int nstart = 0;
+	int use_cleaner = 0;
 	uintmax_t bufsiz;
 	const char *p;
 
@@ -607,7 +692,7 @@ main(int argc, char * const *argv)
 	AN(cbvsb);
 	setbuf(stdout, NULL);
 	setbuf(stderr, NULL);
-	while ((ch = getopt(argc, argv, "b:D:hij:kLln:p:qt:vW")) != -1) {
+	while ((ch = getopt(argc, argv, "b:CD:hij:kLln:p:qt:vW")) != -1) {
 		switch (ch) {
 		case 'b':
 			if (VNUM_2bytes(optarg, &bufsiz, 0)) {
@@ -622,6 +707,9 @@ main(int argc, char * const *argv)
 			}
 			vtc_bufsiz = (unsigned)bufsiz;
 			break;
+		case 'C':
+			use_cleaner = !use_cleaner;
+			break;
 		case 'D':
 			if (!parse_D_opt(optarg)) {
 				fprintf(stderr, "Cannot parse D opt '%s'\n",
@@ -691,6 +779,9 @@ main(int argc, char * const *argv)
 
 	vb = VEV_New();
 
+	if (use_cleaner)
+		cleaner_setup();
+
 	i = 0;
 	while (!VTAILQ_EMPTY(&tst_head) || i) {
 		if (!VTAILQ_EMPTY(&tst_head) && njob < npar) {
@@ -704,6 +795,7 @@ main(int argc, char * const *argv)
 		}
 		i = VEV_Once(vb);
 	}
+	cleaner_finish();
 	if (vtc_continue)
 		fprintf(stderr,
 		    "%d tests failed, %d tests skipped, %d tests passed\n",


More information about the varnish-commit mailing list