Commit 540fb8ed by FritzFlorian

Extend context switch example for arm32.

parent 5490e966
Pipeline #1376 failed with stages
in 34 seconds
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)
.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 */
.file "custom_stack_callback.s"
.file "custom_stack_callback_x86_64.s"
.text
.global custom_stack_callback
.type custom_stack_callback, @function
......
#include <cstdio>
#include <csetjmp>
#include <cstring>
#include <chrono>
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<chrono::nanoseconds>(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<chrono::nanoseconds>(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<chrono::nanoseconds>(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<chrono::nanoseconds>(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;
}
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)
#include <cstdio>
#include <csetjmp>
#include <cstring>
#include <chrono>
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<chrono::nanoseconds>(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<chrono::nanoseconds>(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<chrono::nanoseconds>(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;
}
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