diff --git a/.gitignore b/.gitignore index fc3de11..4e118a4 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ timectxsw timectxswws timesyscall timetctxsw +timetctxsw2 diff --git a/Makefile b/Makefile index 4a702fd..b532e82 100644 --- a/Makefile +++ b/Makefile @@ -1,11 +1,16 @@ CC = gcc -CFLAGS = -mtune=native -O3 -D_XOPEN_SOURCE=600 -D_GNU_SOURCE -std=c99 \ +CFLAGS = -march=native -O3 -D_XOPEN_SOURCE=600 -D_GNU_SOURCE -std=c99 \ -W -Wall -Werror -LDFLAGS = -lrt +LDFLAGS = -lrt -lpthread + +TARGETS = timectxsw timectxswws timesyscall timetctxsw timetctxsw2 all: bench -bench: timectxsw timectxswws timesyscall timetctxsw +bench: $(TARGETS) ./cpubench.sh +clean: + rm -f $(TARGETS) + .PHONY: all bench diff --git a/README b/README index 41f4f4b..d09c6e5 100644 --- a/README +++ b/README @@ -6,3 +6,14 @@ timectxsw: Benchmarks the overhead of context switching between 2 processes. timetctxsw: Benchmarks the overhead of context switching between 2 threads. timectxswws: Benchmarks the overhead of context switching between 2 processes using a working set of the size specified in argument. +timetctxsw2: Benchmarks the overhead of context switching between 2 threads, + by using a shed_yield() method. + If you do taskset -a 1, all threads should be scheduled on the + same processor, so you are really doing thread context switch. + Then to be sure that you are really doing it, just do: + strace -ff -tt -v taskset -a 1 ./timetctxsw2 + Now why sched_yield() is enough for testing ? Because, it place + the current thread at the end of the ready queue. So the next + ready thread will be scheduled. + I also added sched_setscheduler(SCHED_FIFO) to get the best + performances. diff --git a/cpubench.sh b/cpubench.sh index 3a04493..c60c3b1 100755 --- a/cpubench.sh +++ b/cpubench.sh @@ -28,6 +28,7 @@ runbench() { $* ./timesyscall $* ./timectxsw $* ./timetctxsw + $* ./timetctxsw2 } echo '-- No CPU affinity --' @@ -35,3 +36,6 @@ runbench echo '-- With CPU affinity --' runbench taskset -c $((total - 1)) + +echo '-- With CPU affinity to CPU 0 --' +runbench taskset -a 1 diff --git a/timetctxsw2.c b/timetctxsw2.c new file mode 100644 index 0000000..316836a --- /dev/null +++ b/timetctxsw2.c @@ -0,0 +1,48 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +static inline long long unsigned time_ns(struct timespec* const ts) { + if (clock_gettime(CLOCK_REALTIME, ts)) { + exit(1); + } + return ((long long unsigned) ts->tv_sec) * 1000000000LLU + + (long long unsigned) ts->tv_nsec; +} + +static const int iterations = 500000; + +static void* thread(void*ctx) { + (void)ctx; + for (int i = 0; i < iterations; i++) + sched_yield(); + return NULL; +} + +int main(void) { + struct sched_param param; + param.sched_priority = 1; + if (sched_setscheduler(getpid(), SCHED_FIFO, ¶m)) + fprintf(stderr, "sched_setscheduler(): %s\n", strerror(errno)); + + struct timespec ts; + pthread_t thd; + if (pthread_create(&thd, NULL, thread, NULL)) { + return 1; + } + + long long unsigned start_ns = time_ns(&ts); + for (int i = 0; i < iterations; i++) + sched_yield(); + long long unsigned delta = time_ns(&ts) - start_ns; + + const int nswitches = iterations << 2; + printf("%i thread context switches in %lluns (%.1fns/ctxsw)\n", + nswitches, delta, (delta / (float) nswitches)); + return 0; +}