Permalink
Browse files

run tests in parallel with make -jN

  • Loading branch information...
1 parent 1c88fed commit b238874a0df845de481df862275b37ccdb043f42 @kr committed Dec 12, 2012
Showing with 113 additions and 41 deletions.
  1. +1 −1 Makefile
  2. +7 −2 Readme.md
  3. +102 −36 ct/ct.c
  4. +2 −2 ct/gen
  5. +1 −0 ct/internal.h
View
@@ -12,7 +12,7 @@ hello: hello.o $(objs)
.PHONY: check
check: ct/_ctcheck
- ct/_ctcheck
+ +ct/_ctcheck
ct/ct.o: ct/ct.h
View
@@ -18,13 +18,18 @@ global state from one test will not affect another.
in the group will be killed after the test finishes. This
means your test can fork without having to worry about
cleaning up its descendants.
+- CT participates in GNU make's jobserver protocol. If you
+put a `+` in front of the _ctcheck command (as in the sample
+makefile) and run make with its `-jN` flag, for example
+`make -j16 check`, CT will run tests concurrently (and
+hopefully in parallel).
## Terminal Output
Running `make check` in the example supplied looks like this:
```
-~/Projects/ct[master]: make check
+~/Projects/ct[master]: make -j4 check
cc -Werror -Wall -c -o msg-test.o msg-test.c
ct/gen msg-test.o > ct/_ctcheck.c.part
mv ct/_ctcheck.c.part ct/_ctcheck.c
@@ -33,7 +38,7 @@ cc -Werror -Wall -c -o ct/ct.o ct/ct.c
cc -Werror -Wall -c -o msg.o msg.c
cc ct/_ctcheck.o ct/ct.o msg.o msg-test.o -o ct/_ctcheck
ct/_ctcheck
-.EFFE.
+E..FEF
cttestexit: error (exit status 2)
View
@@ -8,11 +8,15 @@
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
+#include <fcntl.h>
#include <errno.h>
#include "internal.h"
#include "ct.h"
+static int rjobfd = -1, wjobfd = -1;
+
+
void
ctlogpn(char *p, int n, char *fmt, ...)
{
@@ -59,49 +63,77 @@ failed(int s)
static void
-run(T t[])
+waittest(void)
{
- int pid;
- FILE *out;
+ T *t;
+ int pid, stat;
- for (; t->f; t++) {
- out = tmpfile();
- if (!out) {
- die(1, errno, "tmpfile");
- }
- t->fd = fileno(out);
- pid = fork();
- if (pid < 0) {
- die(1, errno, "fork");
- } else if (!pid) {
- setpgid(0, 0);
- if (dup2(t->fd, 1) == -1) {
- die(3, errno, "dup2");
- }
- if (close(t->fd) == -1) {
- die(3, errno, "fclose");
- }
- if (dup2(1, 2) == -1) {
- die(3, errno, "dup2");
+ pid = wait3(&stat, 0, 0);
+ if (pid == -1) {
+ die(3, errno, "wait");
+ }
+ killpg(pid, 9);
+
+ for (t=ctmain; t->f; t++) {
+ if (t->pid == pid) {
+ t->status = stat;
+ if (!t->status) {
+ putchar('.');
+ } else if (failed(t->status)) {
+ putchar('F');
+ } else {
+ putchar('E');
}
- t->f();
- exit(0);
+ fflush(stdout);
}
- setpgid(pid, pid);
+ }
+}
+
- if (waitpid(pid, &t->status, 0) != pid) {
- die(3, errno, "wait");
+static void
+start(T *t)
+{
+ FILE *out;
+ out = tmpfile();
+ if (!out) {
+ die(1, errno, "tmpfile");
+ }
+ t->fd = fileno(out);
+ t->pid = fork();
+ if (t->pid < 0) {
+ die(1, errno, "fork");
+ } else if (!t->pid) {
+ setpgid(0, 0);
+ if (dup2(t->fd, 1) == -1) {
+ die(3, errno, "dup2");
+ }
+ if (close(t->fd) == -1) {
+ die(3, errno, "fclose");
}
- killpg(pid, 9);
+ if (dup2(1, 2) == -1) {
+ die(3, errno, "dup2");
+ }
+ t->f();
+ exit(0);
+ }
+ setpgid(t->pid, t->pid);
+}
- if (!t->status) {
- putchar('.');
- } else if (failed(t->status)) {
- putchar('F');
- } else {
- putchar('E');
+
+static void
+runall(T t[], int limit)
+{
+ int nrun = 0;
+ for (; t->f; t++) {
+ if (nrun >= limit) {
+ waittest();
+ nrun--;
}
- fflush(stdout);
+ start(t);
+ nrun++;
+ }
+ for (; nrun; nrun--) {
+ waittest();
}
}
@@ -161,8 +193,42 @@ report(T t[])
int
+readtokens()
+{
+ int n = 1;
+ char c, *s;
+ if ((s = strstr(getenv("MAKEFLAGS"), " --jobserver-fds="))) {
+ rjobfd = (int)strtol(s+17, &s, 10); // skip " --jobserver-fds="
+ wjobfd = (int)strtol(s+1, NULL, 10); // skip comma
+ }
+ if (rjobfd >= 0) {
+ fcntl(rjobfd, F_SETFL, fcntl(rjobfd, F_GETFL)|O_NONBLOCK);
+ while (read(rjobfd, &c, 1) > 0) {
+ n++;
+ }
+ }
+ return n;
+}
+
+
+void
+writetokens(int n)
+{
+ char c = '+';
+ if (wjobfd >= 0) {
+ fcntl(wjobfd, F_SETFL, fcntl(wjobfd, F_GETFL)|O_NONBLOCK);
+ for (; n>1; n--) {
+ write(wjobfd, &c, 1); // ignore error; nothing we can do anyway
+ }
+ }
+}
+
+
+int
main()
{
- run(ctmain);
+ int n = readtokens();
+ runall(ctmain, n);
+ writetokens(n);
return report(ctmain);
}
View
@@ -26,9 +26,9 @@ gen() {
printf 'T ctmain[] = {\n'
for t in "$@"
- do printf ' {%s, "%s", 0, 0},\n' $t $t
+ do printf ' {%s, "%s", 0, 0, 0},\n' $t $t
done
- printf ' {0, 0, 0, 0},\n'
+ printf ' {0, 0, 0, 0, 0},\n'
printf '};\n'
}
View
@@ -5,6 +5,7 @@ struct T {
char *name;
int status;
int fd;
+ int pid;
};
extern T ctmain[];

0 comments on commit b238874

Please sign in to comment.