From 540fb8ede68a6d7e0419fb145d37489ed3fc8e8f Mon Sep 17 00:00:00 2001 From: FritzFlorian Date: Mon, 13 Jan 2020 13:11:53 +0100 Subject: [PATCH] Extend context switch example for arm32. --- app/context_switch/CMakeLists.txt | 13 +++++++++++++ app/context_switch/custom_stack_callback_arm32.s | 15 +++++++++++++++ app/context_switch/custom_stack_callback_x86_64.s | 16 ++++++++++++++++ app/context_switch/main.cpp | 89 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ app/playground/CMakeLists.txt | 2 +- app/playground/custom_stack_callback.s | 16 ---------------- app/playground/main.cpp | 70 ---------------------------------------------------------------------- 7 files changed, 134 insertions(+), 87 deletions(-) create mode 100644 app/context_switch/CMakeLists.txt create mode 100644 app/context_switch/custom_stack_callback_arm32.s create mode 100644 app/context_switch/custom_stack_callback_x86_64.s create mode 100644 app/context_switch/main.cpp delete mode 100644 app/playground/custom_stack_callback.s diff --git a/app/context_switch/CMakeLists.txt b/app/context_switch/CMakeLists.txt new file mode 100644 index 0000000..2f4849d --- /dev/null +++ b/app/context_switch/CMakeLists.txt @@ -0,0 +1,13 @@ +if (CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64" AND CMAKE_SYSTEM_NAME STREQUAL "Linux") + SET(SWITCH_ASSEMBLY "custom_stack_callback_x86_64.s") +elseif (CMAKE_SYSTEM_PROCESSOR STREQUAL "arm" AND CMAKE_SYSTEM_NAME STREQUAL "Linux") + SET(SWITCH_ASSEMBLY "custom_stack_callback_arm32.s") +else () + MESSAGE(FATAL_ERROR "Platform (${CMAKE_SYSTEM_PROCESSOR} on ${CMAKE_SYSTEM_NAME}) not supported! Please see Readme for instructions to port.") +endif () + + +add_executable(playground main.cpp ${SWITCH_ASSEMBLY}) + +# Example for adding the library to your app (as a cmake project dependency) +target_link_libraries(playground) diff --git a/app/context_switch/custom_stack_callback_arm32.s b/app/context_switch/custom_stack_callback_arm32.s new file mode 100644 index 0000000..dd81eeb --- /dev/null +++ b/app/context_switch/custom_stack_callback_arm32.s @@ -0,0 +1,15 @@ + .arm + .text + .global custom_stack_callback + .type custom_stack_callback, %function + +.align 4 +custom_stack_callback: + /* r0 new stack adress (passed as parameter) */ + /* r4 temporary for restoring old stack (callee saved, so we get the correct value in case of a return) */ + push {r4, lr} /* store the callee saved register as required and the return address */ + mov r4, sp /* store current stack pointer */ + mov sp, r0 /* update stack pointer to new user level stack */ + bl callback /* enter next tasks (will not return if continuation is stolen) */ + mov sp, r4 /* restore to the old stack pointer */ + pop {r4, pc} /* restore the callee saved register as required and returns */ diff --git a/app/context_switch/custom_stack_callback_x86_64.s b/app/context_switch/custom_stack_callback_x86_64.s new file mode 100644 index 0000000..5a6d71e --- /dev/null +++ b/app/context_switch/custom_stack_callback_x86_64.s @@ -0,0 +1,16 @@ + .file "custom_stack_callback_x86_64.s" + .text + .global custom_stack_callback + .type custom_stack_callback, @function + +.align 16 +custom_stack_callback: + # rdi = new stack adress (passed as parameter) + # r12 temporary for restoring old stack (callee saved, so we get the correct value in case of a return) + push %r12 # store the callee saved register as required + movq %rsp, %r12 # store current stack pointer + movq %rdi, %rsp # update stack pointer to new user level stack + call callback # enter next tasks (will not return if continuation is stolen) + movq %r12, %rsp # restore to the old stack pointer + pop %r12 # restore the callee saved register as required + ret diff --git a/app/context_switch/main.cpp b/app/context_switch/main.cpp new file mode 100644 index 0000000..5fb3c80 --- /dev/null +++ b/app/context_switch/main.cpp @@ -0,0 +1,89 @@ +#include +#include +#include +#include + +using namespace std; + +// Settings for stack and benchmark +const unsigned int NUM_RUNS = 100000; +const unsigned int STACK_SIZE = 512 * 1; +const unsigned char MAGIC_NUMBER = (unsigned char) 0xAB; + +// Memory for custom stack and continuation semantics +unsigned char custom_stack[STACK_SIZE] = {0}; +jmp_buf buffer; + +// Example callback function and declaration of our assembly stack switching routine +extern "C" { +void custom_stack_callback(void *); + +void __attribute__ ((noinline)) callback() { + static volatile int tmp; + tmp = 0; // Force at least a single memory write +} +} + +long __attribute__ ((noinline)) measure_function_call() { + auto start_time = chrono::steady_clock::now(); + for (unsigned int i = 0; i < NUM_RUNS; i++) { + callback(); + } + auto end_time = chrono::steady_clock::now(); + return chrono::duration_cast(end_time - start_time).count(); +} + +long __attribute__ ((noinline)) measure_stack_switch() { + auto start_time = chrono::steady_clock::now(); + for (unsigned int i = 0; i < NUM_RUNS; i++) { + custom_stack_callback(&custom_stack[STACK_SIZE - 16]); + } + auto end_time = chrono::steady_clock::now(); + return chrono::duration_cast(end_time - start_time).count(); +} + +long __attribute__ ((noinline)) measure_continuation() { + auto start_time = chrono::steady_clock::now(); + for (unsigned int i = 0; i < NUM_RUNS; i++) { + if (setjmp(buffer) == 0) { + custom_stack_callback(&custom_stack[STACK_SIZE - 16]); + } + } + auto end_time = chrono::steady_clock::now(); + return chrono::duration_cast(end_time - start_time).count(); +} + +long __attribute__ ((noinline)) measure_continuation_and_jump() { + auto start_time = chrono::steady_clock::now(); + for (unsigned int i = 0; i < NUM_RUNS; i++) { + if (setjmp(buffer) == 0) { + custom_stack_callback(&custom_stack[STACK_SIZE - 16]); + longjmp(buffer, 1); + } + } + auto end_time = chrono::steady_clock::now(); + return chrono::duration_cast(end_time - start_time).count(); +} + +int main() { + memset(custom_stack, MAGIC_NUMBER, STACK_SIZE); + + auto time_cont_jump = measure_continuation_and_jump(); + auto time_cont = measure_continuation(); + auto time_stack = measure_stack_switch(); + auto time_func = measure_function_call(); + + for (unsigned int i = 0; i < STACK_SIZE; i++) { + if (custom_stack[i] != MAGIC_NUMBER) { + printf("Used stack size about %u bytes.\n\n\n", (STACK_SIZE - i)); + break; + } + } + + printf("Function Call : %10ld, %5.5f\n", time_func, ((float) time_func / 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("Jump Continuation: %10ld, %5.5f\n", time_cont_jump, ((float) time_cont_jump / NUM_RUNS)); + + return 0; +} diff --git a/app/playground/CMakeLists.txt b/app/playground/CMakeLists.txt index 9482fb6..4c09641 100644 --- a/app/playground/CMakeLists.txt +++ b/app/playground/CMakeLists.txt @@ -1,4 +1,4 @@ -add_executable(playground main.cpp custom_stack_callback.s) +add_executable(playground main.cpp) # Example for adding the library to your app (as a cmake project dependency) target_link_libraries(playground) diff --git a/app/playground/custom_stack_callback.s b/app/playground/custom_stack_callback.s deleted file mode 100644 index 085350c..0000000 --- a/app/playground/custom_stack_callback.s +++ /dev/null @@ -1,16 +0,0 @@ - .file "custom_stack_callback.s" - .text - .global custom_stack_callback - .type custom_stack_callback, @function - -.align 16 -custom_stack_callback: - # rdi = new stack adress (passed as parameter) - # r12 temporary for restoring old stack (callee saved, so we get the correct value in case of a return) - push %r12 # store the callee saved register as required - movq %rsp, %r12 # store current stack pointer - movq %rdi, %rsp # update stack pointer to new user level stack - call callback # enter next tasks (will not return if continuation is stolen) - movq %r12, %rsp # restore to the old stack pointer - pop %r12 # restore the callee saved register as required - ret diff --git a/app/playground/main.cpp b/app/playground/main.cpp index 8022bfd..18d3906 100644 --- a/app/playground/main.cpp +++ b/app/playground/main.cpp @@ -1,75 +1,5 @@ -#include -#include -#include -#include - -using namespace std; - -// Settings for stack and benchmark -const unsigned int NUM_RUNS = 100000; -const unsigned int STACK_SIZE = 512 * 1; -const unsigned char MAGIC_NUMBER = (unsigned char) 0xAB; - -// Memory for custom stack and continuation semantics -unsigned char custom_stack[STACK_SIZE] = {0}; -jmp_buf buffer; - -// Example callback function and declaration of our assembly stack switching routine -extern "C" { -void custom_stack_callback(void *); - -void __attribute__ ((noinline)) callback() { - static volatile int tmp; - tmp = 0; // Force at least a single memory write -} -} - -long __attribute__ ((noinline)) measure_function_call() { - auto start_time = chrono::steady_clock::now(); - for (unsigned int i = 0; i < NUM_RUNS; i++) { - callback(); - } - auto end_time = chrono::steady_clock::now(); - return chrono::duration_cast(end_time - start_time).count(); -} - -long __attribute__ ((noinline)) measure_stack_switch() { - auto start_time = chrono::steady_clock::now(); - for (unsigned int i = 0; i < NUM_RUNS; i++) { - custom_stack_callback(&custom_stack[STACK_SIZE - 16]); - } - auto end_time = chrono::steady_clock::now(); - return chrono::duration_cast(end_time - start_time).count(); -} - -long __attribute__ ((noinline)) measure_continuation() { - auto start_time = chrono::steady_clock::now(); - for (unsigned int i = 0; i < NUM_RUNS; i++) { - if (setjmp(buffer) == 0) { - custom_stack_callback(&custom_stack[STACK_SIZE - 16]); - } - } - auto end_time = chrono::steady_clock::now(); - return chrono::duration_cast(end_time - start_time).count(); -} int main() { - memset(custom_stack, MAGIC_NUMBER, STACK_SIZE); - - auto time_cont = measure_continuation(); - auto time_stack = measure_stack_switch(); - auto time_func = measure_function_call(); - - for (unsigned int i = 0; i < STACK_SIZE; i++) { - if (custom_stack[i] != MAGIC_NUMBER) { - printf("Used stack size about %u bytes.\n\n\n", (STACK_SIZE - i)); - break; - } - } - - printf("Function Call : %10ld, %5.5f\n", time_func, ((float) time_func / 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)); return 0; } -- libgit2 0.26.0