Commit 3a6b724d by FritzFlorian

Add alternative context switch implementation (similar to boost).

parent 540fb8ed
Pipeline #1377 failed with stages
in 37 seconds
...@@ -44,6 +44,7 @@ add_subdirectory(app/benchmark_matrix) ...@@ -44,6 +44,7 @@ add_subdirectory(app/benchmark_matrix)
add_subdirectory(app/benchmark_prefix) add_subdirectory(app/benchmark_prefix)
add_subdirectory(app/benchmark_pipeline) add_subdirectory(app/benchmark_pipeline)
add_subdirectory(app/benchmark_fib) add_subdirectory(app/benchmark_fib)
add_subdirectory(app/context_switch)
# Add optional tests # Add optional tests
option(PACKAGE_TESTS "Build the tests" ON) option(PACKAGE_TESTS "Build the tests" ON)
......
...@@ -7,7 +7,7 @@ else () ...@@ -7,7 +7,7 @@ else ()
endif () endif ()
add_executable(playground main.cpp ${SWITCH_ASSEMBLY}) add_executable(context_switch main.cpp ${SWITCH_ASSEMBLY} fiber_call_x86_64.s fiber_continue_x86_64.s)
# Example for adding the library to your app (as a cmake project dependency) # Example for adding the library to your app (as a cmake project dependency)
target_link_libraries(playground) target_link_libraries(context_switch)
.file "fiber_call_x86_64.s"
.text
.global fiber_call
.type fiber_call, @function
.align 16
fiber_call:
# rdi = address of new stack top and to store current stack top (parameter to function)
# r12 temporary for restoring old stack (callee saved, so we can take a 'fast' return path)
############### Register State Storage ################
# make space for all register state we will store
leaq -0x38(%rsp), %rsp
# store calee saved general registers
movq %r12, 0x00(%rsp)
movq %r13, 0x08(%rsp)
movq %r14, 0x10(%rsp)
movq %r15, 0x18(%rsp)
movq %rbx, 0x20(%rsp)
movq %rbp, 0x28(%rsp)
# store MMX control- and status-word
stmxcsr 0x30(%rsp)
# store x87 control-word
fnstcw 0x34(%rsp)
############### Stack Pointer Manipulation #############
# keep the old stack pointer in a callee-saved register for 'fast' return path
movq %rsp, %r12
# switch to new stack pointer
movq (%rdi), %rsp
# store old stack pointer
movq %r12, (%rdi)
############# Function Call ############################
# perform actual function call, this will now be on the new stack
call callback
# If someone else continued/jumped into this stored context we must not return here,
# thus we will never execute the rest of the function.
# Otherwise we can return out of the function as if it was a simple function call.
############ Stack Pointer Manipulation ################
# restore stack pointer that we had before
movq %r12, %rsp
############ Restore State Storage (as needed) #########
# ...we don't need to restore most registers (as they are calee saved).
# We only used %r12, so restore that and move back the stack pointer.
movq 0x00(%rsp), %r12
# release the space we used for storage
leaq 0x38(%rsp), %rsp
# just return back from the call
ret
.file "fiber_continue_x86_64.s"
.text
.global fiber_continue
.type fiber_continue, @function
.align 16
fiber_continue:
# rdi = address of new stack top and to store current stack top (parameter to function)
############### Register State Storage ################
# make space for all register state we will store
leaq -0x38(%rsp), %rsp
# store calee saved general registers
movq %r12, 0x00(%rsp)
movq %r13, 0x08(%rsp)
movq %r14, 0x10(%rsp)
movq %r15, 0x18(%rsp)
movq %rbx, 0x20(%rsp)
movq %rbp, 0x28(%rsp)
# store MMX control- and status-word
stmxcsr 0x30(%rsp)
# store x87 control-word
fnstcw 0x34(%rsp)
############### Stack Pointer Manipulation #############
# keep the old stack
movq %rsp, %r12
# switch to new stack pointer
movq (%rdi), %rsp
# store old stack pointer
movq %r12, (%rdi)
# We stored our old execution context and are now on the target stack
# on which we would like to contiune our execution.
############ Restore State Storage (as needed) #########
# restore calee saved general registers
movq 0x00(%rsp), %r12
movq 0x08(%rsp), %r13
movq 0x10(%rsp), %r14
movq 0x18(%rsp), %r15
movq 0x20(%rsp), %rbx
movq 0x28(%rsp), %rbp
# restore MMX control- and status-word
ldmxcsr 0x30(%rsp)
# restore x87 control-word
fldcw 0x34(%rsp)
# Free space for restored state
leaq 0x38(%rsp), %rsp
# just return back from the call
ret
...@@ -7,7 +7,7 @@ using namespace std; ...@@ -7,7 +7,7 @@ using namespace std;
// Settings for stack and benchmark // Settings for stack and benchmark
const unsigned int NUM_RUNS = 100000; const unsigned int NUM_RUNS = 100000;
const unsigned int STACK_SIZE = 512 * 1; const unsigned int STACK_SIZE = 512 * 8;
const unsigned char MAGIC_NUMBER = (unsigned char) 0xAB; const unsigned char MAGIC_NUMBER = (unsigned char) 0xAB;
// Memory for custom stack and continuation semantics // Memory for custom stack and continuation semantics
...@@ -18,6 +18,9 @@ jmp_buf buffer; ...@@ -18,6 +18,9 @@ jmp_buf buffer;
extern "C" { extern "C" {
void custom_stack_callback(void *); void custom_stack_callback(void *);
void fiber_call(void *);
void fiber_continue(void *);
void __attribute__ ((noinline)) callback() { void __attribute__ ((noinline)) callback() {
static volatile int tmp; static volatile int tmp;
tmp = 0; // Force at least a single memory write tmp = 0; // Force at least a single memory write
...@@ -65,6 +68,16 @@ long __attribute__ ((noinline)) measure_continuation_and_jump() { ...@@ -65,6 +68,16 @@ long __attribute__ ((noinline)) measure_continuation_and_jump() {
return chrono::duration_cast<chrono::nanoseconds>(end_time - start_time).count(); return chrono::duration_cast<chrono::nanoseconds>(end_time - start_time).count();
} }
long __attribute__ ((noinline)) measure_fiber_call() {
auto start_time = chrono::steady_clock::now();
for (unsigned int i = 0; i < NUM_RUNS; i++) {
void *stack_pointer = custom_stack;
fiber_call(&stack_pointer);
}
auto end_time = chrono::steady_clock::now();
return chrono::duration_cast<chrono::nanoseconds>(end_time - start_time).count();
}
int main() { int main() {
memset(custom_stack, MAGIC_NUMBER, STACK_SIZE); memset(custom_stack, MAGIC_NUMBER, STACK_SIZE);
...@@ -72,6 +85,7 @@ int main() { ...@@ -72,6 +85,7 @@ int main() {
auto time_cont = measure_continuation(); auto time_cont = measure_continuation();
auto time_stack = measure_stack_switch(); auto time_stack = measure_stack_switch();
auto time_func = measure_function_call(); auto time_func = measure_function_call();
auto time_fiber = measure_fiber_call();
for (unsigned int i = 0; i < STACK_SIZE; i++) { for (unsigned int i = 0; i < STACK_SIZE; i++) {
if (custom_stack[i] != MAGIC_NUMBER) { if (custom_stack[i] != MAGIC_NUMBER) {
...@@ -84,6 +98,7 @@ int main() { ...@@ -84,6 +98,7 @@ int main() {
printf("Stack Switching : %10ld, %5.5f\n", time_stack, ((float) time_stack / NUM_RUNS)); printf("Stack Switching : %10ld, %5.5f\n", time_stack, ((float) time_stack / NUM_RUNS));
printf("Full Continuation: %10ld, %5.5f\n", time_cont, ((float) time_cont / NUM_RUNS)); printf("Full Continuation: %10ld, %5.5f\n", time_cont, ((float) time_cont / NUM_RUNS));
printf("Jump Continuation: %10ld, %5.5f\n", time_cont_jump, ((float) time_cont_jump / NUM_RUNS)); printf("Jump Continuation: %10ld, %5.5f\n", time_cont_jump, ((float) time_cont_jump / NUM_RUNS));
printf("Fiber Call : %10ld, %5.5f\n", time_fiber, ((float) time_fiber / NUM_RUNS));
return 0; return 0;
} }
#include <cstdio>
#include <csetjmp>
int main() { int main() {
printf("Buffer Size: %u\n", sizeof(jmp_buf));
printf("Big Buffer Size: %u\n", sizeof(sigjmp_buf));
return 0; return 0;
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment