diff --git a/app/context_switch/CMakeLists.txt b/app/context_switch/CMakeLists.txt index 72e6ea9..0722218 100644 --- a/app/context_switch/CMakeLists.txt +++ b/app/context_switch/CMakeLists.txt @@ -3,8 +3,9 @@ add_subdirectory(deboost.context) if (CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64" AND CMAKE_SYSTEM_NAME STREQUAL "Linux") SET(SWITCH_ASSEMBLY "custom_stack_callback_x86_64.s") SET(FIBER_ASSEMBLY "fiber_call_x86_64.s" "fiber_continue_x86_64.s") - #elseif (CMAKE_SYSTEM_PROCESSOR STREQUAL "arm" AND CMAKE_SYSTEM_NAME STREQUAL "Linux") - # SET(SWITCH_ASSEMBLY "custom_stack_callback_arm32.s" fiber_call.h fiber_call.cpp) +elseif (CMAKE_SYSTEM_PROCESSOR STREQUAL "armv7l" AND CMAKE_SYSTEM_NAME STREQUAL "Linux") + SET(SWITCH_ASSEMBLY "custom_stack_callback_arm32.s" fiber_call.h fiber_call.cpp) + SET(FIBER_ASSEMBLY "fiber_call_arm32.s" "fiber_continue_arm32.s") else () MESSAGE(FATAL_ERROR "Platform (${CMAKE_SYSTEM_PROCESSOR} on ${CMAKE_SYSTEM_NAME}) not supported! Please see Readme for instructions to port.") endif () diff --git a/app/context_switch/deboost.context/CMakeLists.txt b/app/context_switch/deboost.context/CMakeLists.txt index bfe782f..f16c2fb 100644 --- a/app/context_switch/deboost.context/CMakeLists.txt +++ b/app/context_switch/deboost.context/CMakeLists.txt @@ -4,18 +4,18 @@ project(fcontext C) if (NOT CMAKE_MODULE_PATH) set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake") -endif() +endif () if (MSVC) enable_language(CXX ASM_MASM) -else() +else () enable_language(CXX ASM) -endif() +endif () -if(MSVC) - add_definitions(-D_ITERATOR_DEBUG_LEVEL=0) - add_definitions(-D_HAS_EXCEPTIONS=0) -endif() +if (MSVC) + add_definitions(-D_ITERATOR_DEBUG_LEVEL=0) + add_definitions(-D_HAS_EXCEPTIONS=0) +endif () add_definitions(-DBOOST_CONTEXT_EXPORT=) set(HEADER "include/fcontext/fcontext.h") @@ -39,33 +39,37 @@ elseif (ANDROID) elseif (${CMAKE_SYSTEM_PROCESSOR} MATCHES "x86_64") set(CPU_ARCH "x86_64") set(ASM_EXT "sysv_elf_gas.S") - endif() + endif () elseif (UNIX) # PC (x86/x64) - if (CMAKE_SIZEOF_VOID_P EQUAL 8) + if (CMAKE_SYSTEM_PROCESSOR STREQUAL "armv7l") + set(CPU_ARCH "arm") + set(ASM_EXT "aapcs_elf_gas.S") # Untested, but should work for linux/unix + elseif (CMAKE_SIZEOF_VOID_P EQUAL 8) set(CPU_ARCH "x86_64") - else() + set(ASM_EXT "sysv_elf_gas.S") # Linux/Unix + else () set(CPU_ARCH "i386") - endif() - set(ASM_EXT "sysv_elf_gas.S") # Linux/Unix + set(ASM_EXT "sysv_elf_gas.S") # Linux/Unix + endif () elseif (WIN32) # Windows PC if (CMAKE_SIZEOF_VOID_P EQUAL 8) set(CPU_ARCH "x86_64") - else() + else () set(CPU_ARCH "i386") - endif() + endif () set(ASM_EXT "ms_pe_masm.asm") -endif() +endif () set(ASM_SOURCES "asm/make_${CPU_ARCH}_${ASM_EXT}" - "asm/jump_${CPU_ARCH}_${ASM_EXT}" - "asm/ontop_${CPU_ARCH}_${ASM_EXT}") + "asm/jump_${CPU_ARCH}_${ASM_EXT}" + "asm/ontop_${CPU_ARCH}_${ASM_EXT}") add_library(fcontext STATIC ${SOURCES} ${ASM_SOURCES}) target_include_directories(fcontext - PRIVATE include/fcontext - INTERFACE include) + PRIVATE include/fcontext + INTERFACE include) set_target_properties(fcontext PROPERTIES FOLDER Deps ${IOS_GENERAL_PROPERTIES}) diff --git a/app/context_switch/fiber_call_arm32.s b/app/context_switch/fiber_call_arm32.s new file mode 100644 index 0000000..03a1c86 --- /dev/null +++ b/app/context_switch/fiber_call_arm32.s @@ -0,0 +1,53 @@ + .arm + .text + .global __fiber_call + .type __fiber_call, %function + +__fiber_call: + /* Parameter List (in order) + * r0 = new stack pointer + * r1 = first parameter to callback + * r2 = callback function pointer + * r3 = new stack limit (not used on most platforms) + * + * Return + * r0 = continuation that returned control back to the caller (null if fallthrough) + * + * Variables + * r4 = temporary for the old stack pointer */ + + /* ========== Save State ========== */ + /* store programm counter for later return */ + push {lr} + /* store callee saved registers */ + push {r4-r12,lr} + /* ========== Save State ========== */ + + /* Perform change to new stack */ + /* Keep old stack as second parameter to our callback function. */ + mov r4, sp + /* Make sure that stack start is properly aligned. */ + and r0, r0, #-16 + /* Switch to new stack pointer. */ + mov sp, r0 + + /* Perform actual function call, this will now be on the new stack */ + /* r0 = first parametor to callback (continuation) */ + /* r1 = second parameter to callback (arbetary pointer) */ + mov r0, r4 + blx r2 + + /* Restore state of returned continuation. */ + /* To do so we first reset the stack pointer (which we get returned in r0). */ + /* After that we execute our standard restore procedere to pop the state from the stack. */ + mov sp, r0 + + /* ========== Restore State ========== */ + /* restore callee saved registers */ + pop {r4-r12,lr} + /* ========== Restore State ========== */ + + /* Just return back from the call. */ + /* This is the end of a fiber, so we have no continuation. */ + eor r0, r0, r0 + pop {pc} diff --git a/app/context_switch/fiber_continue_arm32.s b/app/context_switch/fiber_continue_arm32.s new file mode 100644 index 0000000..8b98314 --- /dev/null +++ b/app/context_switch/fiber_continue_arm32.s @@ -0,0 +1,38 @@ + .arm + .text + .global __fiber_continue + .type __fiber_continue, %function + +__fiber_continue: + /* Parameter List (in order) + * r0 = pointer to continuation (should hold value of target stack will be filled with this continuation) + * + * Return + * r0 = continuation that returned control back to the caller (null if fallthrough) + * + * Variables + * r4 = temporary for the old stack pointer */ + + /* ========== Save State ========== */ + /* store programm counter for later return */ + push {lr} + /* store callee saved registers */ + push {r4-r12,lr} + /* ========== Save State ========== */ + + /* Perform change to new stack */ + /* Keep old stack as result from this function. */ + mov r4, sp + /* Switch to new stack pointer. */ + mov sp, r0 + + + /* ========== Restore State ========== */ + /* restore callee saved registers */ + pop {r4-r12,lr} + /* ========== Restore State ========== */ + + /* Just return back from the call. */ + /* This is the end of a fiber, so we have no continuation. */ + mov r0, r4 + pop {pc} diff --git a/app/context_switch/fiber_continue_x86_64.s b/app/context_switch/fiber_continue_x86_64.s index 8a6ac6d..e91ffcc 100644 --- a/app/context_switch/fiber_continue_x86_64.s +++ b/app/context_switch/fiber_continue_x86_64.s @@ -32,7 +32,7 @@ __fiber_continue: ############### Save State ############### # Perform change to new stack. - # Keep old stack as second parameter to our callback function. + # Keep old stack as result from this function movq %rsp, %r12 # switch to new stack pointer movq %rdi, %rsp diff --git a/app/context_switch/main.cpp b/app/context_switch/main.cpp index 1dad9f4..e77b555 100644 --- a/app/context_switch/main.cpp +++ b/app/context_switch/main.cpp @@ -28,6 +28,16 @@ void __attribute__ ((noinline)) callback() { } } +long measure_loop() { + auto start_time = chrono::steady_clock::now(); + volatile int tmp; + for (unsigned int i = 0; i < NUM_RUNS; i++) { + tmp = 0; + } + auto end_time = chrono::steady_clock::now(); + return chrono::duration_cast(end_time - start_time).count(); +} + long measure_function_call() { auto start_time = chrono::steady_clock::now(); for (unsigned int i = 0; i < NUM_RUNS; i++) { @@ -138,6 +148,7 @@ int main() { auto time_cont = measure_continuation(); auto time_stack = measure_stack_switch(); auto time_func = measure_function_call(); + auto time_loop = measure_loop(); auto time_fcontext_fast = measure_fcontext_fast(); auto time_fcontext_clean = measure_fcontext_clean(); auto time_fcontext_calcc = measure_fcontext_callcc(); @@ -145,6 +156,7 @@ int main() { printf("Base\n"); printf("Function Call : %10ld, %5.5f\n", time_func, ((float) time_func / NUM_RUNS)); + printf("Simple Loop : %10ld, %5.5f\n", time_loop, ((float) time_loop / NUM_RUNS)); printf("Longjmp\n"); 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));