tests: support building Linux tests in-tree
Previously, you had to manually invoke gcc to build the tests. Now,
anytime you make tests, you'll also get the Linux version. The tests
that are built for both OSes are specified manually in the Makefile.
This will also build any Linux modules in tests/linux/modules/. You'll
need to provide LINUX_KDIR, e.g. in your Makelocal. This is for tests
that need kernel support, such as the upcoming lock_test mcs-kernel mode.
You can also build these programs directly by cd-ing into tests/linux
and running Make. This won't use any of the top-level Makefile
features (including Makelocal settings). It's convenient if you don't
want to build Akaros (toolchain recompile, etc.).
Either way, the test binaries will appear in tests/linux/obj/. The
top-level obj/ is just for Akaros's build output.
Signed-off-by: Barret Rhoden <brho@cs.berkeley.edu>
diff --git a/Makefile b/Makefile
index 70766a6..6b3f1dc 100644
--- a/Makefile
+++ b/Makefile
@@ -195,8 +195,9 @@
HOSTCFLAGS = -Wall -Wno-char-subscripts -Wmissing-prototypes \
-Wstrict-prototypes -O2 -fomit-frame-pointer
HOSTCXXFLAGS = -O2
+HOSTLD = ld
-export CONFIG_SHELL HOSTCC HOSTCXX HOSTCFLAGS HOSTCXXFLAGS
+export CONFIG_SHELL HOSTCC HOSTCXX HOSTCFLAGS HOSTCXXFLAGS HOSTLD
# Beautify output
# ---------------------------------------------------------------------------
diff --git a/Makelocal.template b/Makelocal.template
index 098cf93..e9c4897 100644
--- a/Makelocal.template
+++ b/Makelocal.template
@@ -8,6 +8,13 @@
#CFLAGS_TESTS += -fno-optimize-sibling-calls
export CFLAGS_USER CFLAGS_TESTS
+# For building linux modules, used by some tests on linux, set LINUX_KDIR
+#LINUX_KDIR := /path/to/linux/source
+export LINUX_KDIR
+# You can change the CC too, used for Linux apps and modules.
+# (and Kbuild, a little). Default is just gcc.
+#HOSTCC := gcc-8
+
# The default is num_cpus. Use whatever you want.
# MAKE_JOBS := 100
diff --git a/tests/Makefile b/tests/Makefile
index b8c4095..d7f46f1 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -24,6 +24,8 @@
$(OBJDIR)/$(TESTS_DIR)/%, \
$(TESTS_SRCS_CPP))
+export TESTS_DIR OBJDIR
+
include $(TESTS_DIR)/openmp/Makefrag
include $(TESTS_DIR)/vmm/Makefrag
include $(TESTS_DIR)/dune/Makefrag
@@ -48,7 +50,7 @@
$(Q)$(CPP) $(TESTS_CXXFLAGS) -o $@ $< $(TESTS_LDLIBS)
all: $(TESTS_EXECS)
- @:
+ @cd $(TESTS_DIR)/linux && $(MAKE)
install: $(TESTS_EXECS)
@mkdir -p $(FIRST_KFS_PATH)/bin
@@ -60,5 +62,6 @@
clean:
@echo + clean [TESTS]
@rm -rf $(OBJDIR)/tests/
+ @cd $(TESTS_DIR)/linux && $(MAKE) clean
.PHONY: $(PHONY)
diff --git a/tests/interference.c b/tests/interference.c
index 8196ff7..bcc303d 100644
--- a/tests/interference.c
+++ b/tests/interference.c
@@ -22,31 +22,10 @@
#else
-/* Build on linux from $AKAROS_ROOT:
- * gcc -static --std=gnu99 tests/interference.c -o lin-interference
- */
-
#include <stdio.h>
#include "../user/parlib/include/parlib/tsc-compat.h"
-#include "misc-compat.h"
-
-struct sample_stats {
- int (*get_sample)(void **data, int i, int j, uint64_t *sample);
- uint64_t avg_time;
- uint64_t var_time;
- uint64_t max_time;
- uint64_t min_time;
- unsigned int lat_50;
- unsigned int lat_75;
- unsigned int lat_90;
- unsigned int lat_99;
- uint64_t total_samples;
-};
-
-void compute_stats(void **data, int nr_i, int nr_j, struct sample_stats *stats)
-{
- /* TODO: could try to link against benchutil. */
-}
+#include "../user/benchutil/include/benchutil/measure.h"
+#include "linux/misc-compat.h"
static void os_init(void)
{
diff --git a/tests/linux/Makefile b/tests/linux/Makefile
new file mode 100644
index 0000000..c8f1e59
--- /dev/null
+++ b/tests/linux/Makefile
@@ -0,0 +1,84 @@
+# Builds certain tests for Linux
+#
+# Customize your settings in your Makelocal
+# - LINUX_KDIR: linux source for the module (/path/to/linux/source)
+#
+# You should be able to build the Linux programs without building Akaros by
+# running make in this directory. Set LINUX_KDIR in your environment. Fun!
+
+# Default compiler/tools come from the top-level Makefile. They can be
+# overridden. Also these are used if we were called directly instead of from
+# the top-level makefile.
+HOSTCC ?= gcc
+HOSTCFLAGS ?= -Wall -Wno-char-subscripts -Wmissing-prototypes \
+ -Wstrict-prototypes -O2 -fomit-frame-pointer
+HOSTLD ?= ld
+
+
+USERDIR = ../../user
+# override to our local obj/
+OBJDIR = obj
+
+ifeq ($(TESTS_DIR),)
+# independent build, from this directory
+Q = @
+endif
+# override, regardless
+TESTS_DIR = ..
+
+# defined below
+all:
+
+ifeq ($(LINUX_KDIR),)
+
+mods:
+ $(Q)echo LINUX_KDIR is unset. Set it, Makelocal or env, for Linux mods
+
+mods_clean:
+ @:
+
+else
+
+mods:
+ @cd modules && $(MAKE) -C $(LINUX_KDIR) CC=$(HOSTCC) LD=$(HOSTLD) M=$$PWD modules
+
+mods_clean:
+ @cd modules && $(MAKE) -C $(LINUX_KDIR) M=$$PWD clean
+
+endif
+
+clean: mods_clean
+ @rm -rf $(OBJDIR) .*cmd
+
+# Programs in this directory (if any)
+tests_srcs_c := $(wildcard *.c)
+tests_lddepends_c := %.c
+tests_execs_c = $(patsubst %.c, $(OBJDIR)/%, $(tests_srcs_c))
+
+# Select programs from tests/
+# All programs we build end up in obj/tests/linux/, even the ones from tests/
+sel_progs = lock_test.c interference.c pthread_test.c
+
+sel_progs_srcs_c = $(patsubst %c,$(TESTS_DIR)/%c, $(sel_progs))
+sel_progs_lddepends_c := $(TESTS_DIR)/%.c
+sel_progs_execs_c = $(patsubst %.c, $(OBJDIR)/%, $(sel_progs))
+
+progs = $(tests_execs_c) $(sel_progs_execs_c)
+
+tests_c_deps := $(USERDIR)/benchutil/measure.c
+tests_ldlibs := -lpthread -lm
+
+$(OBJDIR)/%: $(tests_lddepends_c)
+ @echo + cc [LINUX_TESTS] $<
+ @mkdir -p $(@D)
+ $(Q)$(HOSTCC) -static -O2 $< $(tests_c_deps) -o $@ $(tests_ldlibs)
+
+$(OBJDIR)/%: $(sel_progs_lddepends_c)
+ @echo + cc [LINUX_TESTS] $<
+ @mkdir -p $(@D)
+ $(Q)$(HOSTCC) -static -O2 $< $(tests_c_deps) -o $@ $(tests_ldlibs)
+
+all: mods $(progs)
+ @:
+
+.PHONY: $(all mods clean)
diff --git a/tests/linux-lock-hacks.h b/tests/linux/linux-lock-hacks.h
similarity index 98%
rename from tests/linux-lock-hacks.h
rename to tests/linux/linux-lock-hacks.h
index 8596443..6da938b 100644
--- a/tests/linux-lock-hacks.h
+++ b/tests/linux/linux-lock-hacks.h
@@ -21,13 +21,13 @@
return !__sync_lock_test_and_set(&lock->locked, TRUE);
}
-void __attribute__((noinline)) spinlock_lock(spinlock_t *lock)
+void __attribute__((noinline)) spinlock_lock(spinlock_t *lock)
{
while (!spinlock_trylock(lock))
cpu_relax();
}
-void __attribute__((noinline)) spinlock_unlock(spinlock_t *lock)
+void __attribute__((noinline)) spinlock_unlock(spinlock_t *lock)
{
__sync_lock_release(&lock->locked, FALSE);
}
diff --git a/tests/misc-compat.h b/tests/linux/misc-compat.h
similarity index 93%
rename from tests/misc-compat.h
rename to tests/linux/misc-compat.h
index 08f472f..e6832e4 100644
--- a/tests/misc-compat.h
+++ b/tests/linux/misc-compat.h
@@ -1,12 +1,7 @@
#pragma once
-#ifdef __ros__
-
-#include <parlib/timing.h>
-
-#define pthread_id() (pthread_self()->id)
-
-#else
+/* All of these should be in other Akaros headers */
+#ifndef __akaros__
#include <stdbool.h>
#ifndef TRUE
diff --git a/tests/linux/modules/.gitignore b/tests/linux/modules/.gitignore
new file mode 100644
index 0000000..1a86f5e
--- /dev/null
+++ b/tests/linux/modules/.gitignore
@@ -0,0 +1,6 @@
+.cache.mk
+.tmp_versions/
+Module.symvers
+*.ko
+*.mod.c
+modules.order
diff --git a/tests/linux/modules/Kbuild b/tests/linux/modules/Kbuild
new file mode 100644
index 0000000..4517f23
--- /dev/null
+++ b/tests/linux/modules/Kbuild
@@ -0,0 +1 @@
+obj-m += mcs.o
diff --git a/tests/lock_test.c b/tests/lock_test.c
index e1a985d..a02d7fb 100644
--- a/tests/lock_test.c
+++ b/tests/lock_test.c
@@ -3,10 +3,7 @@
* See LICENSE for details.
*
* lock_test: microbenchmark to measure different styles of spinlocks.
- *
- * to build on linux: (hacky)
- * $ gcc -O2 -std=gnu99 -fno-stack-protector -g tests/lock_test.c -lpthread \
- * -lm -o linux_lock_test */
+ */
#define _GNU_SOURCE /* pthread_yield */
@@ -41,11 +38,9 @@
#else
#include "../user/parlib/include/parlib/tsc-compat.h"
-#include "misc-compat.h"
-#include "linux-lock-hacks.h" /* TODO: have a build system and lib / C file */
-
#include "../user/benchutil/include/benchutil/measure.h"
-#include "../user/benchutil/measure.c"
+#include "linux/misc-compat.h"
+#include "linux/linux-lock-hacks.h"
static void os_prep_work(pthread_t *worker_threads, int nr_threads)
{
diff --git a/tests/pthread_switch.c b/tests/pthread_switch.c
index d5bb46b..7ef0e74 100644
--- a/tests/pthread_switch.c
+++ b/tests/pthread_switch.c
@@ -10,7 +10,6 @@
#include <stdlib.h>
#include <unistd.h>
#include <sys/time.h>
-#include "misc-compat.h"
pthread_t th1, th2;
int nr_switch_loops = 100;
diff --git a/tests/pthread_test.c b/tests/pthread_test.c
index e7f568d..0d2b3e0 100644
--- a/tests/pthread_test.c
+++ b/tests/pthread_test.c
@@ -4,9 +4,6 @@
*
* Basic test for pthreading. Spawns a bunch of threads that yield.
*
- * To build on linux, cd into tests and run:
- * $ gcc -O2 -std=gnu99 -fno-stack-protector -g pthread_test.c -lpthread
- *
* Make sure you run it with taskset to fix the number of vcores/cpus. */
#define _GNU_SOURCE /* for pth_yield on linux */
@@ -16,7 +13,10 @@
#include <stdlib.h>
#include <unistd.h>
#include <sys/time.h>
-#include "misc-compat.h" /* OS dependent #incs */
+
+#ifndef __akaros__
+#include "linux/misc-compat.h"
+#endif
/* These are here just to have the compiler test the _INITIALIZERS */
pthread_cond_t dummy_cond = PTHREAD_COND_INITIALIZER;
diff --git a/user/benchutil/measure.c b/user/benchutil/measure.c
index 299024b..d57459f 100644
--- a/user/benchutil/measure.c
+++ b/user/benchutil/measure.c
@@ -17,8 +17,7 @@
#include <parlib/tsc-compat.h>
#include <benchutil/measure.h>
#else
- /* you'll need to do find this manually on linux */
- #include "measure.h"
+ #include "include/benchutil/measure.h"
#endif /* __ros__ */
/* Basic stats computation and printing.
diff --git a/user/pthread/pthread.h b/user/pthread/pthread.h
index d85742e..88b3380 100644
--- a/user/pthread/pthread.h
+++ b/user/pthread/pthread.h
@@ -49,6 +49,7 @@
struct pthread_cleanup_stack cr_stack;
};
typedef struct pthread_tcb* pthread_t;
+#define pthread_id() (pthread_self()->id)
TAILQ_HEAD(pthread_queue, pthread_tcb);
/* Per-vcore data structures to manage syscalls. The ev_q is where we tell the