From 79d25623dad2953c93174e0f3ef8ca3477e4d54d Mon Sep 17 00:00:00 2001 From: Henrik Akira Karlsson Date: Sun, 10 Dec 2023 19:50:24 +0100 Subject: [PATCH] benchmark --- benchmark/dispatch-latency/Makefile | 48 ++++ benchmark/dispatch-latency/app0.ld | 5 + benchmark/dispatch-latency/app0/main.c | 256 +++++++++++++++++++++ benchmark/dispatch-latency/app1.ld | 5 + benchmark/dispatch-latency/app1/main.c | 286 +++++++++++++++++++++++ benchmark/dispatch-latency/app2.ld | 5 + benchmark/dispatch-latency/app2/main.c | 13 ++ benchmark/dispatch-latency/app3.ld | 5 + benchmark/dispatch-latency/app3/main.c | 39 ++++ benchmark/dispatch-latency/build.mk | 68 ++++++ benchmark/dispatch-latency/default.ld | 34 +++ benchmark/dispatch-latency/s3k_conf.h | 35 +++ benchmark/ipc/Makefile | 38 +++ benchmark/ipc/app0.ld | 5 + benchmark/ipc/app0/main.c | 102 +++++++++ benchmark/ipc/app1.ld | 5 + benchmark/ipc/app1/main.c | 51 +++++ benchmark/ipc/build.mk | 69 ++++++ benchmark/ipc/default.ld | 35 +++ benchmark/ipc/s3k_conf.h | 32 +++ benchmark/jitter/Makefile | 48 ++++ benchmark/jitter/app0.ld | 5 + benchmark/jitter/app0/main.c | 248 ++++++++++++++++++++ benchmark/jitter/app1.ld | 5 + benchmark/jitter/app1/main.c | 286 +++++++++++++++++++++++ benchmark/jitter/app2.ld | 5 + benchmark/jitter/app2/main.c | 13 ++ benchmark/jitter/app3.ld | 5 + benchmark/jitter/app3/main.c | 39 ++++ benchmark/jitter/build.mk | 68 ++++++ benchmark/jitter/default.ld | 34 +++ benchmark/jitter/s3k_conf.h | 32 +++ benchmark/wcrt/Makefile | 48 ++++ benchmark/wcrt/app0.ld | 5 + benchmark/wcrt/app0/main.c | 206 +++++++++++++++++ benchmark/wcrt/app1.ld | 5 + benchmark/wcrt/app1/main.c | 305 +++++++++++++++++++++++++ benchmark/wcrt/app2.ld | 5 + benchmark/wcrt/app2/main.c | 13 ++ benchmark/wcrt/build.mk | 68 ++++++ benchmark/wcrt/default.ld | 34 +++ benchmark/wcrt/s3k_conf.h | 35 +++ 42 files changed, 2648 insertions(+) create mode 100644 benchmark/dispatch-latency/Makefile create mode 100644 benchmark/dispatch-latency/app0.ld create mode 100644 benchmark/dispatch-latency/app0/main.c create mode 100644 benchmark/dispatch-latency/app1.ld create mode 100644 benchmark/dispatch-latency/app1/main.c create mode 100644 benchmark/dispatch-latency/app2.ld create mode 100644 benchmark/dispatch-latency/app2/main.c create mode 100644 benchmark/dispatch-latency/app3.ld create mode 100644 benchmark/dispatch-latency/app3/main.c create mode 100644 benchmark/dispatch-latency/build.mk create mode 100644 benchmark/dispatch-latency/default.ld create mode 100644 benchmark/dispatch-latency/s3k_conf.h create mode 100644 benchmark/ipc/Makefile create mode 100644 benchmark/ipc/app0.ld create mode 100644 benchmark/ipc/app0/main.c create mode 100644 benchmark/ipc/app1.ld create mode 100644 benchmark/ipc/app1/main.c create mode 100644 benchmark/ipc/build.mk create mode 100644 benchmark/ipc/default.ld create mode 100644 benchmark/ipc/s3k_conf.h create mode 100644 benchmark/jitter/Makefile create mode 100644 benchmark/jitter/app0.ld create mode 100644 benchmark/jitter/app0/main.c create mode 100644 benchmark/jitter/app1.ld create mode 100644 benchmark/jitter/app1/main.c create mode 100644 benchmark/jitter/app2.ld create mode 100644 benchmark/jitter/app2/main.c create mode 100644 benchmark/jitter/app3.ld create mode 100644 benchmark/jitter/app3/main.c create mode 100644 benchmark/jitter/build.mk create mode 100644 benchmark/jitter/default.ld create mode 100644 benchmark/jitter/s3k_conf.h create mode 100644 benchmark/wcrt/Makefile create mode 100644 benchmark/wcrt/app0.ld create mode 100644 benchmark/wcrt/app0/main.c create mode 100644 benchmark/wcrt/app1.ld create mode 100644 benchmark/wcrt/app1/main.c create mode 100644 benchmark/wcrt/app2.ld create mode 100644 benchmark/wcrt/app2/main.c create mode 100644 benchmark/wcrt/build.mk create mode 100644 benchmark/wcrt/default.ld create mode 100644 benchmark/wcrt/s3k_conf.h diff --git a/benchmark/dispatch-latency/Makefile b/benchmark/dispatch-latency/Makefile new file mode 100644 index 00000000..57905586 --- /dev/null +++ b/benchmark/dispatch-latency/Makefile @@ -0,0 +1,48 @@ +.POSIX: + +export PLATFORM ?=sifive_unleashed +export ROOT :=${abspath ../..} +export BUILD :=${abspath build/${PLATFORM}} +export S3K_CONF_H :=${abspath s3k_conf.h} + +include ${ROOT}/tools.mk +include ${ROOT}/common/plat/${PLATFORM}.mk + +APPS=app0 app1 app2 app3 + +ELFS=${patsubst %, ${BUILD}/%.elf, kernel ${APPS}} + +all: kernel ${APPS} size + +clean: + @${MAKE} -C ${ROOT}/common clean + @${MAKE} -C ${ROOT}/kernel clean + @for prog in ${APPS}; do \ + ${MAKE} -f build.mk PROGRAM=$$prog clean; \ + done + +common: + @${MAKE} -C ${ROOT}/common + +kernel: common + @${MAKE} -C ${ROOT}/kernel + +size: kernel ${APPS} + ${SIZE} ${BUILD}/*.elf + +qemu: kernel ${APPS} + @ELFS="${ELFS}" ${ROOT}/scripts/qemu.sh + +qemu-gdb: kernel ${APPS} + @ELFS="${ELFS}" ${ROOT}/scripts/qemu.sh -gdb tcp::3333 -S + +gdb: kernel ${APPS} + @ELFS="${ELFS}" ${ROOT}/scripts/gdb.sh + +gdb-openocd: kernel ${APPS} + @ELFS="${ELFS}" ${ROOT}/scripts/gdb-openocd.sh + +${APPS}: common + @${MAKE} -f build.mk PROGRAM=$@ + +.PHONY: all clean size qemu qemu-gdb gdb kernel common ${APPS} diff --git a/benchmark/dispatch-latency/app0.ld b/benchmark/dispatch-latency/app0.ld new file mode 100644 index 00000000..03486fa6 --- /dev/null +++ b/benchmark/dispatch-latency/app0.ld @@ -0,0 +1,5 @@ +MEMORY { + RAM (rwx) : ORIGIN = 0x80010000, LENGTH = 0x10000 +} + +__stack_size = 16 * 1024; diff --git a/benchmark/dispatch-latency/app0/main.c b/benchmark/dispatch-latency/app0/main.c new file mode 100644 index 00000000..52f119f2 --- /dev/null +++ b/benchmark/dispatch-latency/app0/main.c @@ -0,0 +1,256 @@ +#include "altc/altio.h" +#include "s3k/s3k.h" + +#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0])) + +#define APP0_PID 0 +#define APP1_PID 1 +#define APP2_PID 2 +#define APP3_PID 3 + +// See plat_conf.h +#define BOOT_PMP 0 +#define RAM_MEM 1 +#define UART_MEM 2 +#define TIME_MEM 3 +#define HART0_TIME 4 +#define HART1_TIME 5 +#define HART2_TIME 6 +#define HART3_TIME 7 +#define MONITOR 8 +#define CHANNEL 9 +#define MONITOR_APP1 10 +#define MONITOR_APP2 11 +#define MONITOR_APP3 12 + +#define ASSERT(x) \ + { \ + s3k_err_t err = (x); \ + if (err) { \ + alt_printf("Failed at %s: err=%d\n", #x, err); \ + while (1) \ + ; \ + } \ + } + +#define L1_TOTAL_SIZE (32 * 1024) +#define L1_LINE_SIZE 64 + +static volatile uint64_t data[L1_TOTAL_SIZE / sizeof(uint64_t)]; + +uint64_t random(void) +{ + static unsigned long x = 123456789, y = 362436069, z = 521288629; + unsigned long t; + x ^= x << 16; + x ^= x >> 5; + x ^= x << 1; + + t = x; + x = y; + y = z; + z = t ^ x ^ y; + + return z; +} + +uint64_t randint(unsigned long min, unsigned long max) +{ + return (random() % (max - min)) + min; +} + +void random_cidx(s3k_cidx_t *idx, int cnt) +{ + for (int i = 0; i < cnt; ++i) { + retry: + idx[i] = random() % S3K_CAP_CNT; + for (int j = 0; j < i; ++j) { + if (idx[j] == idx[i]) + goto retry; + } + } +} + +void flush_data_cache() +{ + // 32 KiB 8-way cache. + for (int i = 0; i < L1_TOTAL_SIZE; i += L1_LINE_SIZE) { + data[i / sizeof(uint64_t)] = random(); + } +} + +void setup_uart(uint64_t uart_idx) +{ + uint64_t uart_addr = s3k_napot_encode(UART0_BASE_ADDR, 0x8); + // Derive a PMP capability for accessing UART + s3k_cap_derive(UART_MEM, uart_idx, s3k_mk_pmp(uart_addr, S3K_MEM_RW)); + // Load the derive PMP capability to PMP configuration + s3k_pmp_load(uart_idx, 1); + // Synchronize PMP unit (hardware) with PMP configuration + // false => not full synchronization. + s3k_sync_mem(); +} + +void teardown(void) +{ + ASSERT(s3k_mon_suspend(MONITOR_APP1, APP1_PID)); + ASSERT(s3k_cap_revoke(MONITOR_APP2)); + ASSERT(s3k_mon_suspend(MONITOR_APP2, APP2_PID)); + ASSERT(s3k_mon_suspend(MONITOR_APP3, APP3_PID)); + ASSERT(s3k_cap_revoke(RAM_MEM)); + ASSERT(s3k_cap_revoke(HART0_TIME)); + ASSERT(s3k_cap_revoke(CHANNEL)); + + s3k_state_t state; + do { + s3k_mon_state_get(MONITOR_APP1, APP1_PID, &state); + } while (state != S3K_PSF_SUSPENDED); + do { + s3k_mon_state_get(MONITOR_APP2, APP2_PID, &state); + } while (state != S3K_PSF_SUSPENDED); + do { + s3k_mon_state_get(MONITOR_APP3, APP3_PID, &state); + } while (state != S3K_PSF_SUSPENDED); + + for (int i = 0; i < S3K_REG_CNT; ++i) { + s3k_mon_reg_write(MONITOR_APP1, APP1_PID, i, 0); + s3k_mon_reg_write(MONITOR_APP2, APP2_PID, i, 0); + } +} + +void setup_active(void) +{ + int tmp = 16; + s3k_cidx_t indices[8]; + random_cidx(indices, ARRAY_SIZE(indices)); + + uint64_t app1_begin = 0x80020000; + uint64_t app1_end = 0x80040000; + uint64_t app2_begin = 0x80040000; + uint64_t app2_end = 0x80060000; + + s3k_cap_t ram1_mem = s3k_mk_memory(app1_begin, app1_end, S3K_MEM_RWX); + s3k_cap_t ram1_pmp = s3k_mk_pmp( + s3k_napot_encode(app1_begin, app1_end - app1_begin), S3K_MEM_RWX); + s3k_cap_t ram2_mem = s3k_mk_memory(app2_begin, app2_end, S3K_MEM_RWX); + s3k_cap_t ram2_pmp = s3k_mk_pmp( + s3k_napot_encode(app2_begin, app2_end - app2_begin), S3K_MEM_RWX); + s3k_cap_t ramX_mem = s3k_mk_memory(app1_end, app2_end, S3K_MEM_RWX); + + ASSERT(s3k_cap_derive(RAM_MEM, tmp, ram1_mem)); + ASSERT(s3k_cap_derive(tmp, tmp + 1, ram1_pmp)); + ASSERT(s3k_cap_derive(RAM_MEM, tmp + 2, ramX_mem)); + ASSERT(s3k_cap_derive(tmp + 2, tmp + 3, ram2_mem)); + ASSERT(s3k_cap_derive(tmp + 3, tmp + 4, ram2_pmp)); + + ASSERT(s3k_mon_cap_move(MONITOR_APP1, APP0_PID, tmp, APP1_PID, + indices[0])); + ASSERT(s3k_mon_cap_move(MONITOR_APP1, APP0_PID, tmp + 1, APP1_PID, + indices[1])); + ASSERT(s3k_mon_cap_move(MONITOR_APP1, APP0_PID, tmp + 2, APP1_PID, + indices[2])); + ASSERT(s3k_mon_pmp_load(MONITOR_APP1, APP1_PID, indices[1], 0)); + + ASSERT(s3k_mon_cap_move(MONITOR_APP2, APP0_PID, tmp + 4, APP2_PID, 0)); + ASSERT(s3k_mon_cap_move(MONITOR_APP2, APP0_PID, tmp + 3, APP2_PID, 1)); + ASSERT(s3k_mon_pmp_load(MONITOR_APP2, APP2_PID, 0, 0)); + + s3k_cap_t hart0_time1 = s3k_mk_time(1, 0, 16); + s3k_cap_t hart0_time2 = s3k_mk_time(1, 0, 4); + + ASSERT(s3k_cap_derive(HART0_TIME, tmp, hart0_time1)); + ASSERT(s3k_cap_derive(tmp, tmp + 1, hart0_time2)); + ASSERT(s3k_mon_cap_move(MONITOR_APP1, APP0_PID, tmp, APP1_PID, + indices[3])); + ASSERT(s3k_mon_cap_move(MONITOR_APP2, APP0_PID, tmp + 1, APP2_PID, 2)); + + s3k_cap_t chan_app1 = s3k_mk_channel(0, S3K_CHAN_CNT); + s3k_cap_t sock_app2 = s3k_mk_socket(0, S3K_IPC_YIELD, 0xF, 0); + s3k_cap_t sock_app1 = s3k_mk_socket(0, S3K_IPC_YIELD, 0xF, 2); + ASSERT(s3k_cap_derive(CHANNEL, tmp, chan_app1)); + ASSERT(s3k_cap_derive(tmp, tmp + 1, sock_app2)); + ASSERT(s3k_cap_derive(tmp + 1, tmp + 2, sock_app1)); + ASSERT(s3k_mon_cap_move(MONITOR_APP1, APP0_PID, tmp, APP1_PID, + indices[4])); + ASSERT(s3k_mon_cap_move(MONITOR_APP2, APP0_PID, tmp + 1, APP2_PID, 3)); + ASSERT(s3k_mon_cap_move(MONITOR_APP1, APP0_PID, tmp + 2, APP1_PID, + indices[5])); + + s3k_mon_reg_write(MONITOR_APP2, APP2_PID, S3K_REG_PC, app2_begin); + + s3k_cap_t mon_app2 = s3k_mk_monitor(2, 3); + ASSERT(s3k_cap_derive(MONITOR_APP2, tmp, mon_app2)); + ASSERT(s3k_mon_cap_move(MONITOR_APP1, APP0_PID, tmp, APP1_PID, + indices[6])); + + s3k_mon_reg_write(MONITOR_APP1, APP1_PID, S3K_REG_PC, app1_begin); +} + +void setup_flush(void) +{ + uint64_t app3_base = 0x80060000; + s3k_cap_t hart0_time = s3k_mk_time(1, 16, 28); + s3k_cap_t ram3_pmp + = s3k_mk_pmp(s3k_napot_encode(app3_base, 0x20000), S3K_MEM_RWX); + ASSERT(s3k_cap_derive(HART0_TIME, 16, hart0_time)); + ASSERT(s3k_mon_cap_move(MONITOR_APP3, APP0_PID, 16, APP3_PID, 1)); + ASSERT(s3k_cap_derive(RAM_MEM, 16, ram3_pmp)); + ASSERT(s3k_mon_cap_move(MONITOR_APP3, APP0_PID, 16, APP3_PID, 0)); + ASSERT(s3k_mon_pmp_load(MONITOR_APP3, APP3_PID, 0, 0)); + ASSERT( + s3k_mon_reg_write(MONITOR_APP3, APP3_PID, S3K_REG_PC, app3_base)); +} + +uint64_t csrr_cycle(void) +{ + register uint64_t cycle; + __asm__ volatile("csrr %0, cycle" : "=r"(cycle)); + return cycle; +} + +#define MEASUREMENTS 10000 + +void measurement(void) +{ + s3k_sleep(0); + for (int i = 0; i < MEASUREMENTS; ++i) { + retry: + teardown(); + setup_active(); + setup_flush(); + s3k_sleep(0); + switch (SCENARIO) { + case SCENARIO_SOLO: + break; + case SCENARIO_ACTIVE: + s3k_mon_resume(MONITOR_APP1, APP1_PID); + break; + case SCENARIO_FLUSH: + s3k_mon_resume(MONITOR_APP3, APP3_PID); + break; + case SCENARIO_ACTIVE_FLUSH: + s3k_mon_resume(MONITOR_APP3, APP3_PID); + s3k_mon_resume(MONITOR_APP1, APP1_PID); + break; + } + s3k_sleep(0); + s3k_sleep(0); + uint64_t latency = csrr_cycle(); + alt_printf("%d\t%D\n", i + 1, latency); + } +} + +int main(void) +{ + s3k_cap_delete(HART1_TIME); + s3k_cap_delete(HART2_TIME); + s3k_cap_delete(HART3_TIME); + // Setup UART access + setup_uart(6); + s3k_cap_t mon = s3k_mk_monitor(1, 3); + ASSERT(s3k_cap_derive(MONITOR, MONITOR_APP1, s3k_mk_monitor(1, 2))); + ASSERT(s3k_cap_derive(MONITOR, MONITOR_APP2, s3k_mk_monitor(2, 3))); + ASSERT(s3k_cap_derive(MONITOR, MONITOR_APP3, s3k_mk_monitor(3, 4))); + + measurement(); +} diff --git a/benchmark/dispatch-latency/app1.ld b/benchmark/dispatch-latency/app1.ld new file mode 100644 index 00000000..bd8ab292 --- /dev/null +++ b/benchmark/dispatch-latency/app1.ld @@ -0,0 +1,5 @@ +MEMORY { + RAM (rwx) : ORIGIN = 0x80020000, LENGTH = 0x20000 +} + +__stack_size = 1024; diff --git a/benchmark/dispatch-latency/app1/main.c b/benchmark/dispatch-latency/app1/main.c new file mode 100644 index 00000000..b1c1c02c --- /dev/null +++ b/benchmark/dispatch-latency/app1/main.c @@ -0,0 +1,286 @@ +#include "altc/altio.h" +#include "s3k/s3k.h" + +#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) + +#define L1_TOTAL_SIZE (32 * 1024) +#define L1_LINE_SIZE 64 + +static volatile uint64_t data[L1_TOTAL_SIZE / sizeof(uint64_t)]; + +uint64_t random(void) +{ + static unsigned long x = 123456789, y = 362436069, z = 521288629; + unsigned long t; + x ^= x << 16; + x ^= x >> 5; + x ^= x << 1; + + t = x; + x = y; + y = z; + z = t ^ x ^ y; + + return z; +} + +uint64_t randint(unsigned long min, unsigned long max) +{ + return (random() % (max - min)) + min; +} + +void flush_data_cache() +{ + // 32 KiB 8-way cache. + for (int i = 0; i < L1_TOTAL_SIZE; i += L1_LINE_SIZE) { + data[i / sizeof(uint64_t)] = random(); + } +} + +void random_data_access(int x) +{ + for (int i = 0; i < x; ++i) { + data[random() % ARRAY_SIZE(data)] = random(); + } +} + +// Known capabilities. +s3k_cap_t caps[S3K_CAP_CNT]; + +void refresh_caps(bool all) +{ + for (int i = 0; i < S3K_CAP_CNT; ++i) { + if (all || caps[i].type != 0) + s3k_cap_read(i, caps + i); + } +} + +void test_get_info(void) +{ + switch (random() % 3) { + case 0: + s3k_get_pid(); + case 1: + s3k_get_time(); + case 2: + s3k_get_timeout(); + } +} + +void test_reg_read(void) +{ + s3k_reg_read(random() % S3K_REG_CNT); +} + +void test_reg_write(void) +{ + s3k_reg_write(random() % S3K_REG_CNT, random()); +} + +void test_sync() +{ + if (random() % 2) { + s3k_sync(); + } else { + s3k_sync_mem(); + } +} + +void test_cap_move(void) +{ + int i, j; +retry: + i = random() % S3K_CAP_CNT; + j = random() % S3K_CAP_CNT; + if (caps[i].type == S3K_CAPTY_NONE || caps[j].type != S3K_CAPTY_NONE) + goto retry; + s3k_cap_move(i, j); + caps[i].raw = 0; + caps[j].raw = caps[j].raw; +} + +void test_cap_delete() +{ + int i; +retry: + i = random() % S3K_CAP_CNT; + s3k_cap_delete(i); + s3k_cap_read(i, caps + i); +} + +void test_cap_revoke() +{ + int i; +retry: + i = random() % S3K_CAP_CNT; + s3k_cap_revoke(i); + refresh_caps(true); +} + +void test_cap_derive_random(void) +{ + int i, j; +retry: + i = random() % S3K_CAP_CNT; + j = random() % S3K_CAP_CNT; + if (caps[i].type == S3K_CAPTY_NONE || caps[j].type != S3K_CAPTY_NONE) + goto retry; + uint64_t raw = random() ^ (random() << 32); + s3k_cap_derive(i, j, (s3k_cap_t){.raw = raw}); +} + +void test_cap_derive(void) +{ + int i, j; +retry: + i = random() % S3K_CAP_CNT; + j = random() % S3K_CAP_CNT; + if (caps[i].type == S3K_CAPTY_NONE || caps[j].type != S3K_CAPTY_NONE) + goto retry; + s3k_cap_t new_cap; + switch (caps[i].type) { + case S3K_CAPTY_TIME: { + new_cap.raw = caps[i].raw; + uint64_t size = (new_cap.time.end - new_cap.time.mrk); + new_cap.time.end -= random() % size; + } break; + case S3K_CAPTY_MEMORY: { + new_cap.raw = caps[i].raw; + uint64_t size = (new_cap.mem.end - new_cap.mem.mrk); + new_cap.mem.end -= random() % size; + new_cap.mem.rwx &= random(); + } break; + case S3K_CAPTY_MONITOR: { + new_cap.raw = caps[i].raw; + uint64_t size = (new_cap.mon.end - new_cap.mon.mrk); + new_cap.mon.end -= random() % size; + } break; + case S3K_CAPTY_CHANNEL: { + new_cap.raw = caps[i].raw; + uint64_t size = (new_cap.chan.end - new_cap.chan.mrk); + new_cap.chan.end -= random() % size; + } break; + default: + goto retry; + } + s3k_cap_derive(i, j, new_cap); + s3k_cap_read(i, caps + i); + s3k_cap_read(j, caps + j); +} + +void test_pmp() +{ + int i, j; +retry: + i = random() % S3K_CAP_CNT; + if (caps[i].type != S3K_CAPTY_PMP) + goto retry; + if (caps[i].pmp.used) { + s3k_pmp_unload(i); + } else { + s3k_pmp_load(i, random() % 8); + } + s3k_cap_read(i, caps + i); +} + +void test_monitor() +{ + int i; +retry: + i = randint(0, S3K_CAP_CNT); + if (caps[i].type != S3K_CAPTY_MONITOR) + goto retry; + uint64_t min = caps[i].mon.mrk; + uint64_t max = caps[i].mon.end; + switch (random() % 7) { + case 0: + s3k_mon_suspend(i, randint(min, max)); + break; + case 1: + s3k_mon_resume(i, randint(min, max)); + break; + case 2: { + s3k_state_t state; + s3k_mon_state_get(i, randint(min, max), &state); + } break; + case 3: { + s3k_cap_t cap; + s3k_mon_cap_read(i, randint(min, max), randint(0, S3K_CAP_CNT), + &cap); + } break; + case 4: { + s3k_cap_t cap; + s3k_mon_cap_move(i, 1, randint(0, S3K_CAP_CNT), + randint(min, max), randint(0, S3K_CAP_CNT)); + } break; + case 5: { + s3k_cap_t cap; + s3k_mon_cap_move(i, randint(min, max), randint(0, S3K_CAP_CNT), + 1, randint(0, S3K_CAP_CNT)); + } break; + case 6: { + s3k_cap_t cap; + s3k_mon_cap_move(i, randint(min, max), randint(0, S3K_CAP_CNT), + randint(min, max), randint(0, S3K_CAP_CNT)); + } break; + case 7: { + s3k_cap_t cap; + s3k_mon_cap_move(i, randint(min, max), randint(0, S3K_CAP_CNT), + randint(min, max), randint(0, S3K_CAP_CNT)); + } break; + case 8: { + s3k_cap_t cap; + s3k_mon_pmp_load(i, randint(min, max), randint(0, S3K_CAP_CNT), + randint(0, 8)); + } break; + case 9: { + s3k_cap_t cap; + s3k_mon_pmp_unload(i, randint(min, max), + randint(0, S3K_CAP_CNT)); + } break; + } +} + +void test_socket() +{ + int i, j; +retry: + i = randint(0, S3K_CAP_CNT); + j = randint(0, S3K_CAP_CNT); + if (caps[i].type != S3K_CAPTY_SOCKET && caps[j].type != S3K_CAPTY_NONE) + goto retry; + s3k_msg_t msg = {.send_cap = 1, .cap_idx = j}; + switch (random() % 2) { + case 0: { + s3k_sock_send(i, &msg); + } break; + case 1: { + s3k_sock_sendrecv(i, &msg); + } break; + } +} + +typedef void (*tester_t)(void); + +tester_t testers[] = {test_get_info, test_reg_read, test_reg_write, + test_sync, test_cap_move, test_cap_delete, + test_cap_revoke, test_cap_derive, test_cap_derive_random, + test_pmp, test_monitor, test_socket}; + +int main(void) +{ + if (random() % 10 == 0) + while (1) + ; + refresh_caps(true); + for (int i = 0; i < ARRAY_SIZE(caps); i++) { + if (caps[i].type == S3K_CAPTY_MONITOR) { + s3k_mon_resume(i, 2); + } + } + s3k_sleep(0); + while (1) { + random_data_access(64); + testers[random() % ARRAY_SIZE(testers)](); + } +} diff --git a/benchmark/dispatch-latency/app2.ld b/benchmark/dispatch-latency/app2.ld new file mode 100644 index 00000000..15430bf0 --- /dev/null +++ b/benchmark/dispatch-latency/app2.ld @@ -0,0 +1,5 @@ +MEMORY { + RAM (rwx) : ORIGIN = 0x80040000, LENGTH = 0x20000 +} + +__stack_size = 1024; diff --git a/benchmark/dispatch-latency/app2/main.c b/benchmark/dispatch-latency/app2/main.c new file mode 100644 index 00000000..e83fcf42 --- /dev/null +++ b/benchmark/dispatch-latency/app2/main.c @@ -0,0 +1,13 @@ +#include "altc/altio.h" +#include "s3k/s3k.h" + +#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) + +int main(void) +{ + s3k_msg_t msg; + do { + msg.cap_idx = 10; + s3k_sock_sendrecv(3, &msg); + } while (1); +} diff --git a/benchmark/dispatch-latency/app3.ld b/benchmark/dispatch-latency/app3.ld new file mode 100644 index 00000000..f121d3b7 --- /dev/null +++ b/benchmark/dispatch-latency/app3.ld @@ -0,0 +1,5 @@ +MEMORY { + RAM (rwx) : ORIGIN = 0x80060000, LENGTH = 0x20000 +} + +__stack_size = 1024; diff --git a/benchmark/dispatch-latency/app3/main.c b/benchmark/dispatch-latency/app3/main.c new file mode 100644 index 00000000..a607c9ab --- /dev/null +++ b/benchmark/dispatch-latency/app3/main.c @@ -0,0 +1,39 @@ +#include "altc/altio.h" +#include "s3k/s3k.h" + +#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) + +#define L1_TOTAL_SIZE (32 * 1024) +#define L1_LINE_SIZE 64 + +static volatile uint64_t data[L1_TOTAL_SIZE / sizeof(uint64_t)]; + +uint64_t random(void) +{ + static unsigned long x = 123456789, y = 362436069, z = 521288629; + unsigned long t; + x ^= x << 16; + x ^= x >> 5; + x ^= x << 1; + + t = x; + x = y; + y = z; + z = t ^ x ^ y; + + return z; +} + +void flush_data_cache() +{ + // 32 KiB 8-way cache. + for (int i = 0; i < L1_TOTAL_SIZE; i += L1_LINE_SIZE) { + data[i / sizeof(uint64_t)] = random(); + } +} + +int main(void) +{ + while (1) + flush_data_cache(); +} diff --git a/benchmark/dispatch-latency/build.mk b/benchmark/dispatch-latency/build.mk new file mode 100644 index 00000000..db917693 --- /dev/null +++ b/benchmark/dispatch-latency/build.mk @@ -0,0 +1,68 @@ +.POSIX: + +BUILD ?=build +PROGRAM ?=a + +include ${ROOT}/tools.mk +include ${ROOT}/common/plat/${PLATFORM}.mk + +C_SRCS:=${wildcard ${PROGRAM}/*.c} +S_SRCS:=${wildcard ${PROGRAM}/*.S} +OBJS :=${patsubst %.c,${BUILD}/%.o,${C_SRCS}} \ + ${patsubst %.S,${BUILD}/%.o,${S_SRCS}} \ + ${STARTFILES}/start.o +DEPS :=${OBJS:.o=.d} + +CFLAGS:=-march=${ARCH} -mabi=${ABI} -mcmodel=${CMODEL} \ + -DPLATFORM_${PLATFORM} \ + -nostdlib \ + -Os -g3 -flto \ + -I${COMMON_INC} -include ${S3K_CONF_H} + +LDFLAGS:=-march=${ARCH} -mabi=${ABI} -mcmodel=${CMODEL} \ + -nostdlib \ + -flto \ + -T${PROGRAM}.ld -Tdefault.ld \ + -Wl,--no-warn-rwx-segments \ + -L${COMMON_LIB} -ls3k -laltc -lplat \ + +ELF:=${BUILD}/${PROGRAM}.elf +BIN:=${ELF:.elf=.bin} +HEX:=${ELF:.elf=.hex} +DA :=${ELF:.elf=.da} + +all: ${ELF} ${BIN} ${HEX} ${DA} + +clean: + rm -f ${ELF} ${OBJS} ${DEPS} + +${BUILD}/${PROGRAM}/%.o: ${PROGRAM}/%.S + @mkdir -p ${@D} + @${CC} -o $@ $< ${CFLAGS} ${INC} -MMD -c + @printf "CC\t$@\n" + +${BUILD}/${PROGRAM}/%.o: ${PROGRAM}/%.c + @mkdir -p ${@D} + @${CC} -o $@ $< ${CFLAGS} ${INC} -MMD -c + @printf "CC\t$@\n" + +%.elf: ${OBJS} + @mkdir -p ${@D} + @${CC} -o $@ ${OBJS} ${LDFLAGS} ${INC} + @printf "CC\t$@\n" + +%.bin: %.elf + @${OBJCOPY} -O binary $< $@ + @printf "OBJCOPY\t$@\n" + +%.hex: %.elf + @${OBJCOPY} -O ihex $< $@ + @printf "OBJCOPY\t$@\n" + +%.da: %.elf + @${OBJDUMP} -D $< > $@ + @printf "OBJDUMP\t$@\n" + +.PHONY: all clean + +-include ${DEPS} diff --git a/benchmark/dispatch-latency/default.ld b/benchmark/dispatch-latency/default.ld new file mode 100644 index 00000000..fe968757 --- /dev/null +++ b/benchmark/dispatch-latency/default.ld @@ -0,0 +1,34 @@ +/* See LICENSE file for copyright and license details. */ +OUTPUT_ARCH(riscv) +ENTRY(_start) + +__global_pointer$ = MIN(_sdata + 0x800, MAX(_data + 0x800, _end - 0x800)); + +SECTIONS { + .text : { + *( .init ) + *( .text .text.* ) + } > RAM + + .data : { + _data = . ; + *( .data ) + *( .data.* ) + _sdata = . ; + *( .sdata ) + *( .sdata.* ) + } > RAM + + .bss : { + _bss = .; + _sbss = .; + *(.sbss .sbss.*) + *(.bss .bss.*) + _end = .; + } > RAM + + .stack ORIGIN(RAM) + LENGTH(RAM) - __stack_size : ALIGN(8) { + . += __stack_size; + __stack_pointer = .; + } +} diff --git a/benchmark/dispatch-latency/s3k_conf.h b/benchmark/dispatch-latency/s3k_conf.h new file mode 100644 index 00000000..8f10e84b --- /dev/null +++ b/benchmark/dispatch-latency/s3k_conf.h @@ -0,0 +1,35 @@ +#pragma once + +#include "plat/config.h" + +// Number of user processes +#define S3K_PROC_CNT 4 + +// Number of capabilities per process. +#define S3K_CAP_CNT 32 + +// Number of IPC channels. +#define S3K_CHAN_CNT 16 + +// Number of slots per period +#define S3K_SLOT_CNT 32ull + +// Length of slots in ticks. +#define S3K_SLOT_LEN (S3K_RTC_HZ / S3K_SLOT_CNT / 100) + +// Scheduler time +#define S3K_SCHED_TIME 8 +//#define NPREMPT + +// If debugging, comment +#define NDEBUG +#define INSTRUMENT_DISPATCH_LATENCY +#define VERBOSITY 2 + +// Selection of scenarios +#define SCENARIO_SOLO 0 +#define SCENARIO_ACTIVE 1 +#define SCENARIO_FLUSH 2 +#define SCENARIO_ACTIVE_FLUSH 3 +// Set SCENARIO to one of the above +#define SCENARIO SCENARIO_FLUSH diff --git a/benchmark/ipc/Makefile b/benchmark/ipc/Makefile new file mode 100644 index 00000000..79a88ee9 --- /dev/null +++ b/benchmark/ipc/Makefile @@ -0,0 +1,38 @@ +.POSIX: + +export PLATFORM ?=sifive_unleashed +export ROOT :=${abspath ../..} +export BUILD :=${abspath build/${PLATFORM}} +export S3K_CONF_H :=${abspath s3k_conf.h} + +APPS=app0 app1 + +ELFS:=${patsubst %, ${BUILD}/%.elf, kernel ${APPS}} + +all: kernel ${APPS} + +clean: + rm -rf ${BUILD} + +common: + @${MAKE} -C ${ROOT}/common + +kernel: common + @${MAKE} -C ${ROOT}/kernel + +${APPS}: common + @${MAKE} -f build.mk PROGRAM=$@ + +qemu: kernel ${APPS} + @ELFS="${ELFS}" ${ROOT}/scripts/qemu.sh + +qemu-gdb: kernel ${APPS} + @ELFS="${ELFS}" ${ROOT}/scripts/qemu.sh -gdb tcp::3333 -S + +gdb: kernel ${APPS} + @ELFS="${ELFS}" ${ROOT}/scripts/gdb.sh + +gdb-openocd: kernel ${APPS} + @ELFS="${ELFS}" ${ROOT}/scripts/gdb-openocd.sh + +.PHONY: all clean qemu qemu-gdb gdb kernel common ${APPS} diff --git a/benchmark/ipc/app0.ld b/benchmark/ipc/app0.ld new file mode 100644 index 00000000..3a47536f --- /dev/null +++ b/benchmark/ipc/app0.ld @@ -0,0 +1,5 @@ +MEMORY { + RAM (rwx) : ORIGIN = 0x80010000, LENGTH = 0x10000 +} + +__stack_size = 1024; diff --git a/benchmark/ipc/app0/main.c b/benchmark/ipc/app0/main.c new file mode 100644 index 00000000..f8c4b5d7 --- /dev/null +++ b/benchmark/ipc/app0/main.c @@ -0,0 +1,102 @@ +#include "altc/altio.h" +#include "altc/string.h" +#include "s3k/s3k.h" + +#define APP0_PID 0 +#define APP1_PID 1 + +// See plat_conf.h +#define BOOT_PMP 0 +#define RAM_MEM 1 +#define UART_MEM 2 +#define TIME_MEM 3 +#define HART1_TIME 4 +#define MONITOR 8 +#define CHANNEL 9 + +void setup_uart(uint64_t uart_idx) +{ + uint64_t uart_addr = s3k_napot_encode(UART0_BASE_ADDR, 0x8); + // Derive a PMP capability for accessing UART + s3k_cap_derive(UART_MEM, uart_idx, s3k_mk_pmp(uart_addr, S3K_MEM_RW)); + // Load the derive PMP capability to PMP configuration + s3k_pmp_load(uart_idx, 1); + // Synchronize PMP unit (hardware) with PMP configuration + s3k_sync_mem(); +} + +void setup_app1(uint64_t tmp) +{ + uint64_t uart_addr = s3k_napot_encode(UART0_BASE_ADDR, 0x8); + uint64_t app1_addr = s3k_napot_encode(0x80020000, 0x10000); + + // Derive a PMP capability for app1 main memory + s3k_cap_derive(RAM_MEM, tmp, s3k_mk_pmp(app1_addr, S3K_MEM_RWX)); + s3k_mon_cap_move(MONITOR, APP0_PID, tmp, APP1_PID, 0); + s3k_mon_pmp_load(MONITOR, APP1_PID, 0, 0); + + // Derive a PMP capability for uart + s3k_cap_derive(UART_MEM, tmp, s3k_mk_pmp(uart_addr, S3K_MEM_RW)); + s3k_mon_cap_move(MONITOR, APP0_PID, tmp, APP1_PID, 1); + s3k_mon_pmp_load(MONITOR, APP1_PID, 1, 1); + + // Wait til start + s3k_sleep(0); + + // give the time slice capability + s3k_mon_cap_move(MONITOR, APP0_PID, HART1_TIME, APP1_PID, 2); + + s3k_mon_cap_move(MONITOR, APP0_PID, RAM_MEM, APP1_PID, 16); + + // Write start PC of app1 to PC + s3k_mon_reg_write(MONITOR, APP1_PID, S3K_REG_PC, 0x80020000); +} + +void setup_socket(uint64_t socket, uint64_t tmp) +{ + uint64_t perm = S3K_IPC_SDATA | S3K_IPC_CDATA; +#if defined(SCENARIO_TIME) || defined(SCENARIO_CAP) + perm |= S3K_IPC_SCAP | S3K_IPC_CCAP; +#endif + s3k_cap_derive(CHANNEL, socket, + s3k_mk_socket(0, S3K_IPC_YIELD, perm, 0)); + s3k_cap_derive(socket, tmp, s3k_mk_socket(0, S3K_IPC_YIELD, perm, 1)); + s3k_mon_cap_move(MONITOR, APP0_PID, tmp, APP1_PID, 3); +} + +#define csrr(reg) \ + ({ \ + register uint64_t __ret; \ + __asm__ volatile("csrr %0," #reg : "=r"(__ret)); \ + __ret; \ + }) + +int main(void) +{ + setup_uart(10); + + alt_puts("starting app0"); + + // Setup app1 capabilities and PC + setup_app1(11); + + // Setup socket capabilities. + setup_socket(11, 12); + + // Resume app1 + s3k_mon_resume(MONITOR, APP1_PID); + + s3k_msg_t msg = {0}; + s3k_reply_t reply; + s3k_reg_write(S3K_REG_SERVTIME, 10); + while (1) { + do { +#if defined(SCENARIO_CAP) || defined(SCENARIO_TIME) + msg.send_cap = 1; + msg.cap_idx = 16; +#endif + reply = s3k_sock_sendrecv(11, &msg); + } while (reply.err); + msg.data[0] = csrr(cycle); + } +} diff --git a/benchmark/ipc/app1.ld b/benchmark/ipc/app1.ld new file mode 100644 index 00000000..7e525b53 --- /dev/null +++ b/benchmark/ipc/app1.ld @@ -0,0 +1,5 @@ +MEMORY { + RAM (rwx) : ORIGIN = 0x80020000, LENGTH = 0x10000 +} + +__stack_size = 1024; diff --git a/benchmark/ipc/app1/main.c b/benchmark/ipc/app1/main.c new file mode 100644 index 00000000..f05564b2 --- /dev/null +++ b/benchmark/ipc/app1/main.c @@ -0,0 +1,51 @@ +#include "altc/altio.h" +#include "altc/string.h" +#include "s3k/s3k.h" + +#include + +#define csrr(reg) \ + ({ \ + register uint64_t __ret; \ + __asm__ volatile("csrr %0," #reg : "=r"(__ret)); \ + __ret; \ + }) + +void measure(uint64_t res[2]) +{ + s3k_msg_t msg = {0}; + s3k_reply_t reply; + uint64_t start, end; +retry: + do { +#if defined(SCENARIO_CAP) + msg.send_cap = 1; + msg.cap_idx = 16; +#elif defined(SCENARIO_TIME) + msg.send_cap = 1; + msg.cap_idx = 2; +#endif + start = csrr(cycle); + reply = s3k_sock_sendrecv(3, &msg); + end = csrr(cycle); + } while (reply.err); + uint64_t call = reply.data[0] - start; + uint64_t sendrecv = end - reply.data[0]; + if (call > 4000 || sendrecv > 4000) + goto retry; + res[0] = call; + res[1] = sendrecv; +} + +int main(void) +{ + uint64_t res[2]; + alt_puts("starting app1"); + + for (int i = 0; i < WARMUP; i++) + measure(res); + for (int i = 0; i < MEASUREMENTS; i++) { + measure(res); + alt_printf("%d\t%D\t%D\n", i + 1, res[0], res[1]); + } +} diff --git a/benchmark/ipc/build.mk b/benchmark/ipc/build.mk new file mode 100644 index 00000000..4a752703 --- /dev/null +++ b/benchmark/ipc/build.mk @@ -0,0 +1,69 @@ +.POSIX: +.SECONDARY: + +BUILD ?=build +PROGRAM ?=a + +include ${ROOT}/tools.mk +include ${ROOT}/common/plat/${PLATFORM}.mk + +C_SRCS:=${wildcard ${PROGRAM}/*.c} +S_SRCS:=${wildcard ${PROGRAM}/*.S} +OBJS :=${patsubst %.c,${BUILD}/%.o,${C_SRCS}} \ + ${patsubst %.S,${BUILD}/%.o,${S_SRCS}} \ + ${STARTFILES}/start.o +DEPS :=${OBJS:.o=.d} + +CFLAGS:=-march=${ARCH} -mabi=${ABI} -mcmodel=${CMODEL} \ + -DPLATFORM_${PLATFORM} \ + -nostdlib \ + -Os -g3 -flto \ + -I${COMMON_INC} -include ${S3K_CONF_H} + +LDFLAGS:=-march=${ARCH} -mabi=${ABI} -mcmodel=${CMODEL} \ + -nostdlib \ + -flto \ + -T${PROGRAM}.ld -Tdefault.ld \ + -Wl,--no-warn-rwx-segments \ + -L${COMMON_LIB} -ls3k -laltc -lplat \ + +ELF:=${BUILD}/${PROGRAM}.elf +BIN:=${ELF:.elf=.bin} +HEX:=${ELF:.elf=.hex} +DA :=${ELF:.elf=.da} + +all: ${ELF} ${BIN} ${HEX} ${DA} + +clean: + rm -f ${ELF} ${OBJS} ${DEPS} + +${BUILD}/${PROGRAM}/%.o: ${PROGRAM}/%.S + @mkdir -p ${@D} + @${CC} -o $@ $< ${CFLAGS} ${INC} -MMD -c + @printf "CC\t$@\n" + +${BUILD}/${PROGRAM}/%.o: ${PROGRAM}/%.c + @mkdir -p ${@D} + @${CC} -o $@ $< ${CFLAGS} ${INC} -MMD -c + @printf "CC\t$@\n" + +%.elf: ${OBJS} + @mkdir -p ${@D} + @${CC} -o $@ ${OBJS} ${LDFLAGS} ${INC} + @printf "CC\t$@\n" + +%.bin: %.elf + @${OBJCOPY} -O binary $< $@ + @printf "OBJCOPY\t$@\n" + +%.hex: %.elf + @${OBJCOPY} -O ihex $< $@ + @printf "OBJCOPY\t$@\n" + +%.da: %.elf + @${OBJDUMP} -D $< > $@ + @printf "OBJDUMP\t$@\n" + +.PHONY: all clean + +-include ${DEPS} diff --git a/benchmark/ipc/default.ld b/benchmark/ipc/default.ld new file mode 100644 index 00000000..e32de601 --- /dev/null +++ b/benchmark/ipc/default.ld @@ -0,0 +1,35 @@ +/* See LICENSE file for copyright and license details. */ +OUTPUT_ARCH(riscv) +ENTRY(_start) + +__global_pointer$ = MIN(_sdata + 0x800, MAX(_data + 0x800, _end - 0x800)); + +SECTIONS { + .text : { + *( .init ) + *( .text .text.* ) + } > RAM + + .data : { + _data = . ; + *( .data ) + *( .data.* ) + _sdata = . ; + *( .sdata ) + *( .sdata.* ) + } > RAM + + .bss : { + _bss = .; + _sbss = .; + *(.sbss .sbss.*) + *(.bss .bss.*) + _end = .; + } > RAM + + .stack : ALIGN(8) { + . += __stack_size; + __stack_pointer = .; + _end = .; + } +} diff --git a/benchmark/ipc/s3k_conf.h b/benchmark/ipc/s3k_conf.h new file mode 100644 index 00000000..5663818a --- /dev/null +++ b/benchmark/ipc/s3k_conf.h @@ -0,0 +1,32 @@ +#pragma once + +#include "plat/config.h" + +// Number of user processes +#define S3K_PROC_CNT 2 + +// Number of capabilities per process. +#define S3K_CAP_CNT 32 + +// Number of IPC channels. +#define S3K_CHAN_CNT 2 + +// Number of slots per period +#define S3K_SLOT_CNT 32ull + +// Length of slots in ticks. +#define S3K_SLOT_LEN (S3K_RTC_HZ / S3K_SLOT_CNT / 100ull) + +// Scheduler time +#define S3K_SCHED_TIME (S3K_SLOT_LEN / 10) + +// If debugging, comment +//#define NDEBUG +#define INSTRUMENT_CYCLE + +#define SCENARIO_DATA +//#define SCENARIO_CAP +//#define SCENARIO_TIME + +#define WARMUP 100 +#define MEASUREMENTS 10000 diff --git a/benchmark/jitter/Makefile b/benchmark/jitter/Makefile new file mode 100644 index 00000000..57905586 --- /dev/null +++ b/benchmark/jitter/Makefile @@ -0,0 +1,48 @@ +.POSIX: + +export PLATFORM ?=sifive_unleashed +export ROOT :=${abspath ../..} +export BUILD :=${abspath build/${PLATFORM}} +export S3K_CONF_H :=${abspath s3k_conf.h} + +include ${ROOT}/tools.mk +include ${ROOT}/common/plat/${PLATFORM}.mk + +APPS=app0 app1 app2 app3 + +ELFS=${patsubst %, ${BUILD}/%.elf, kernel ${APPS}} + +all: kernel ${APPS} size + +clean: + @${MAKE} -C ${ROOT}/common clean + @${MAKE} -C ${ROOT}/kernel clean + @for prog in ${APPS}; do \ + ${MAKE} -f build.mk PROGRAM=$$prog clean; \ + done + +common: + @${MAKE} -C ${ROOT}/common + +kernel: common + @${MAKE} -C ${ROOT}/kernel + +size: kernel ${APPS} + ${SIZE} ${BUILD}/*.elf + +qemu: kernel ${APPS} + @ELFS="${ELFS}" ${ROOT}/scripts/qemu.sh + +qemu-gdb: kernel ${APPS} + @ELFS="${ELFS}" ${ROOT}/scripts/qemu.sh -gdb tcp::3333 -S + +gdb: kernel ${APPS} + @ELFS="${ELFS}" ${ROOT}/scripts/gdb.sh + +gdb-openocd: kernel ${APPS} + @ELFS="${ELFS}" ${ROOT}/scripts/gdb-openocd.sh + +${APPS}: common + @${MAKE} -f build.mk PROGRAM=$@ + +.PHONY: all clean size qemu qemu-gdb gdb kernel common ${APPS} diff --git a/benchmark/jitter/app0.ld b/benchmark/jitter/app0.ld new file mode 100644 index 00000000..03486fa6 --- /dev/null +++ b/benchmark/jitter/app0.ld @@ -0,0 +1,5 @@ +MEMORY { + RAM (rwx) : ORIGIN = 0x80010000, LENGTH = 0x10000 +} + +__stack_size = 16 * 1024; diff --git a/benchmark/jitter/app0/main.c b/benchmark/jitter/app0/main.c new file mode 100644 index 00000000..127d56d7 --- /dev/null +++ b/benchmark/jitter/app0/main.c @@ -0,0 +1,248 @@ +#include "altc/altio.h" +#include "s3k/s3k.h" + +#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0])) + +#define APP0_PID 0 +#define APP1_PID 1 +#define APP2_PID 2 +#define APP3_PID 3 + +// See plat_conf.h +#define BOOT_PMP 0 +#define RAM_MEM 1 +#define UART_MEM 2 +#define TIME_MEM 3 +#define HART1_TIME 4 +#define MONITOR 8 +#define CHANNEL 9 +#define MONITOR_APP1 10 +#define MONITOR_APP2 11 +#define MONITOR_APP3 12 + +#define ASSERT(x) \ + { \ + s3k_err_t err = (x); \ + if (err) { \ + alt_printf("Failed at %s: err=%d\n", #x, err); \ + while (1) \ + ; \ + } \ + } + +#define L1_TOTAL_SIZE (32 * 1024) +#define L1_LINE_SIZE 64 + +static volatile uint64_t data[L1_TOTAL_SIZE / sizeof(uint64_t)]; + +uint64_t random(void) +{ + static unsigned long x = 123456789, y = 362436069, z = 521288629; + unsigned long t; + x ^= x << 16; + x ^= x >> 5; + x ^= x << 1; + + t = x; + x = y; + y = z; + z = t ^ x ^ y; + + return z; +} + +uint64_t randint(unsigned long min, unsigned long max) +{ + return (random() % (max - min)) + min; +} + +void random_cidx(s3k_cidx_t *idx, int cnt) +{ + for (int i = 0; i < cnt; ++i) { + retry: + idx[i] = random() % S3K_CAP_CNT; + for (int j = 0; j < i; ++j) { + if (idx[j] == idx[i]) + goto retry; + } + } +} + +void flush_data_cache() +{ + // 32 KiB 8-way cache. + for (int i = 0; i < L1_TOTAL_SIZE; i += L1_LINE_SIZE) { + data[i / sizeof(uint64_t)] = random(); + } +} + +void setup_uart(uint64_t uart_idx) +{ + uint64_t uart_addr = s3k_napot_encode(UART0_BASE_ADDR, 0x8); + // Derive a PMP capability for accessing UART + s3k_cap_derive(UART_MEM, uart_idx, s3k_mk_pmp(uart_addr, S3K_MEM_RW)); + // Load the derive PMP capability to PMP configuration + s3k_pmp_load(uart_idx, 1); + // Synchronize PMP unit (hardware) with PMP configuration + // false => not full synchronization. + s3k_sync_mem(); +} + +void teardown(void) +{ + ASSERT(s3k_mon_suspend(MONITOR_APP1, APP1_PID)); + ASSERT(s3k_cap_revoke(MONITOR_APP2)); + ASSERT(s3k_mon_suspend(MONITOR_APP2, APP2_PID)); + ASSERT(s3k_mon_suspend(MONITOR_APP3, APP3_PID)); + ASSERT(s3k_cap_revoke(RAM_MEM)); + ASSERT(s3k_cap_revoke(HART1_TIME)); + ASSERT(s3k_cap_revoke(CHANNEL)); + + s3k_state_t state; + do { + s3k_mon_state_get(MONITOR_APP1, APP1_PID, &state); + } while (state != S3K_PSF_SUSPENDED); + do { + s3k_mon_state_get(MONITOR_APP2, APP2_PID, &state); + } while (state != S3K_PSF_SUSPENDED); + do { + s3k_mon_state_get(MONITOR_APP3, APP3_PID, &state); + } while (state != S3K_PSF_SUSPENDED); + + for (int i = 0; i < S3K_REG_CNT; ++i) { + s3k_mon_reg_write(MONITOR_APP1, APP1_PID, i, 0); + s3k_mon_reg_write(MONITOR_APP2, APP2_PID, i, 0); + } +} + +void setup_active(void) +{ + int tmp = 16; + s3k_cidx_t indices[8]; + random_cidx(indices, ARRAY_SIZE(indices)); + + uint64_t app1_begin = 0x80020000; + uint64_t app1_end = 0x80040000; + uint64_t app2_begin = 0x80040000; + uint64_t app2_end = 0x80060000; + + s3k_cap_t ram1_mem = s3k_mk_memory(app1_begin, app1_end, S3K_MEM_RWX); + s3k_cap_t ram1_pmp = s3k_mk_pmp( + s3k_napot_encode(app1_begin, app1_end - app1_begin), S3K_MEM_RWX); + s3k_cap_t ram2_mem = s3k_mk_memory(app2_begin, app2_end, S3K_MEM_RWX); + s3k_cap_t ram2_pmp = s3k_mk_pmp( + s3k_napot_encode(app2_begin, app2_end - app2_begin), S3K_MEM_RWX); + s3k_cap_t ramX_mem = s3k_mk_memory(app1_end, app2_end, S3K_MEM_RWX); + + ASSERT(s3k_cap_derive(RAM_MEM, tmp, ram1_mem)); + ASSERT(s3k_cap_derive(tmp, tmp + 1, ram1_pmp)); + ASSERT(s3k_cap_derive(RAM_MEM, tmp + 2, ramX_mem)); + ASSERT(s3k_cap_derive(tmp + 2, tmp + 3, ram2_mem)); + ASSERT(s3k_cap_derive(tmp + 3, tmp + 4, ram2_pmp)); + + ASSERT(s3k_mon_cap_move(MONITOR_APP1, APP0_PID, tmp, APP1_PID, + indices[0])); + ASSERT(s3k_mon_cap_move(MONITOR_APP1, APP0_PID, tmp + 1, APP1_PID, + indices[1])); + ASSERT(s3k_mon_cap_move(MONITOR_APP1, APP0_PID, tmp + 2, APP1_PID, + indices[2])); + ASSERT(s3k_mon_pmp_load(MONITOR_APP1, APP1_PID, indices[1], 0)); + + ASSERT(s3k_mon_cap_move(MONITOR_APP2, APP0_PID, tmp + 4, APP2_PID, 0)); + ASSERT(s3k_mon_cap_move(MONITOR_APP2, APP0_PID, tmp + 3, APP2_PID, 1)); + ASSERT(s3k_mon_pmp_load(MONITOR_APP2, APP2_PID, 0, 0)); + + s3k_cap_t hart0_time1 = s3k_mk_time(1, 0, 20); + s3k_cap_t hart0_time2 = s3k_mk_time(1, 0, 4); + + ASSERT(s3k_cap_derive(HART1_TIME, tmp, hart0_time1)); + ASSERT(s3k_cap_derive(tmp, tmp + 1, hart0_time2)); + ASSERT(s3k_mon_cap_move(MONITOR_APP1, APP0_PID, tmp, APP1_PID, + indices[3])); + ASSERT(s3k_mon_cap_move(MONITOR_APP2, APP0_PID, tmp + 1, APP2_PID, 2)); + + s3k_cap_t chan_app1 = s3k_mk_channel(0, S3K_CHAN_CNT); + s3k_cap_t sock_app2 = s3k_mk_socket(0, S3K_IPC_YIELD, 0xF, 0); + s3k_cap_t sock_app1 = s3k_mk_socket(0, S3K_IPC_YIELD, 0xF, 2); + ASSERT(s3k_cap_derive(CHANNEL, tmp, chan_app1)); + ASSERT(s3k_cap_derive(tmp, tmp + 1, sock_app2)); + ASSERT(s3k_cap_derive(tmp + 1, tmp + 2, sock_app1)); + ASSERT(s3k_mon_cap_move(MONITOR_APP1, APP0_PID, tmp, APP1_PID, + indices[4])); + ASSERT(s3k_mon_cap_move(MONITOR_APP2, APP0_PID, tmp + 1, APP2_PID, 3)); + ASSERT(s3k_mon_cap_move(MONITOR_APP1, APP0_PID, tmp + 2, APP1_PID, + indices[5])); + + s3k_mon_reg_write(MONITOR_APP2, APP2_PID, S3K_REG_PC, app2_begin); + + s3k_cap_t mon_app2 = s3k_mk_monitor(2, 3); + ASSERT(s3k_cap_derive(MONITOR_APP2, tmp, mon_app2)); + ASSERT(s3k_mon_cap_move(MONITOR_APP1, APP0_PID, tmp, APP1_PID, + indices[6])); + + s3k_mon_reg_write(MONITOR_APP1, APP1_PID, S3K_REG_PC, app1_begin); +} + +void setup_flush(void) +{ + uint64_t app3_base = 0x80060000; + s3k_cap_t hart0_time = s3k_mk_time(1, 20, 28); + s3k_cap_t ram3_pmp + = s3k_mk_pmp(s3k_napot_encode(app3_base, 0x20000), S3K_MEM_RWX); + ASSERT(s3k_cap_derive(HART1_TIME, 16, hart0_time)); + ASSERT(s3k_mon_cap_move(MONITOR_APP3, APP0_PID, 16, APP3_PID, 1)); + ASSERT(s3k_cap_derive(RAM_MEM, 16, ram3_pmp)); + ASSERT(s3k_mon_cap_move(MONITOR_APP3, APP0_PID, 16, APP3_PID, 0)); + ASSERT(s3k_mon_pmp_load(MONITOR_APP3, APP3_PID, 0, 0)); + ASSERT( + s3k_mon_reg_write(MONITOR_APP3, APP3_PID, S3K_REG_PC, app3_base)); +} + +uint64_t csrr_cycle(void) +{ + register uint64_t cycle; + __asm__ volatile("csrr %0, cycle" : "=r"(cycle)); + return cycle; +} + +#define MEASUREMENTS 10000 + +void measurement(void) +{ + uint64_t start, end; + s3k_sleep(0); + for (int i = 0; i < MEASUREMENTS; ++i) { + retry: + teardown(); + setup_active(); + setup_flush(); + flush_data_cache(); + s3k_sleep(0); + start = csrr_cycle(); +#if defined(SCENARIO_SOLO) + /* Nothing */ +#elif defined(SCENARIO_ACTIVE) + s3k_mon_resume(MONITOR_APP1, APP1_PID); +#elif defined(SCENARIO_FLUSH) + s3k_mon_resume(MONITOR_APP3, APP3_PID); +#elif defined(SCENARIO_ACTIVE_FLUSH) + s3k_mon_resume(MONITOR_APP3, APP3_PID); + s3k_mon_resume(MONITOR_APP1, APP1_PID); +#endif + s3k_sleep(0); + end = csrr_cycle(); + alt_printf("%d\t%D\n", i + 1, end - start); + } +} + +int main(void) +{ + // Setup UART access + setup_uart(6); + s3k_cap_t mon = s3k_mk_monitor(1, 3); + ASSERT(s3k_cap_derive(MONITOR, MONITOR_APP1, s3k_mk_monitor(1, 2))); + ASSERT(s3k_cap_derive(MONITOR, MONITOR_APP2, s3k_mk_monitor(2, 3))); + ASSERT(s3k_cap_derive(MONITOR, MONITOR_APP3, s3k_mk_monitor(3, 4))); + + measurement(); +} diff --git a/benchmark/jitter/app1.ld b/benchmark/jitter/app1.ld new file mode 100644 index 00000000..bd8ab292 --- /dev/null +++ b/benchmark/jitter/app1.ld @@ -0,0 +1,5 @@ +MEMORY { + RAM (rwx) : ORIGIN = 0x80020000, LENGTH = 0x20000 +} + +__stack_size = 1024; diff --git a/benchmark/jitter/app1/main.c b/benchmark/jitter/app1/main.c new file mode 100644 index 00000000..88b000e7 --- /dev/null +++ b/benchmark/jitter/app1/main.c @@ -0,0 +1,286 @@ +#include "altc/altio.h" +#include "s3k/s3k.h" + +#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) + +#define L1_TOTAL_SIZE (32 * 1024) +#define L1_LINE_SIZE 64 + +static volatile uint64_t data[L1_TOTAL_SIZE / sizeof(uint64_t)]; + +uint64_t random(void) +{ + static unsigned long x = 123456789, y = 362436069, z = 521288629; + unsigned long t; + x ^= x << 16; + x ^= x >> 5; + x ^= x << 1; + + t = x; + x = y; + y = z; + z = t ^ x ^ y; + + return z; +} + +uint64_t randint(unsigned long min, unsigned long max) +{ + return (random() % (max - min)) + min; +} + +void flush_data_cache() +{ + // 32 KiB 8-way cache. + for (int i = 0; i < L1_TOTAL_SIZE; i += L1_LINE_SIZE) { + data[i / sizeof(uint64_t)] = random(); + } +} + +void random_data_access(int x) +{ + for (int i = 0; i < x; ++i) { + data[random() % ARRAY_SIZE(data)] = random(); + } +} + +// Known capabilities. +s3k_cap_t caps[S3K_CAP_CNT]; + +void refresh_caps(bool all) +{ + for (int i = 0; i < S3K_CAP_CNT; ++i) { + if (all || caps[i].type != 0) + s3k_cap_read(i, caps + i); + } +} + +void test_get_info(void) +{ + switch (random() % 3) { + case 0: + s3k_get_pid(); + case 1: + s3k_get_time(); + case 2: + s3k_get_timeout(); + } +} + +void test_reg_read(void) +{ + s3k_reg_read(random() % S3K_REG_CNT); +} + +void test_reg_write(void) +{ + s3k_reg_write(random() % S3K_REG_CNT, random()); +} + +void test_sync() +{ + if (random() % 2) { + s3k_sync(); + } else { + s3k_sync_mem(); + } +} + +void test_cap_move(void) +{ + int i, j; +retry: + i = random() % S3K_CAP_CNT; + j = random() % S3K_CAP_CNT; + if (caps[i].type == S3K_CAPTY_NONE || caps[j].type != S3K_CAPTY_NONE) + goto retry; + s3k_cap_move(i, j); + caps[i].raw = 0; + caps[j].raw = caps[j].raw; +} + +void test_cap_delete() +{ + int i; +retry: + i = random() % S3K_CAP_CNT; + s3k_cap_delete(i); + s3k_cap_read(i, caps + i); +} + +void test_cap_revoke() +{ + int i; +retry: + i = random() % S3K_CAP_CNT; + s3k_cap_revoke(i); + refresh_caps(true); +} + +void test_cap_derive_random(void) +{ + int i, j; +retry: + i = random() % S3K_CAP_CNT; + j = random() % S3K_CAP_CNT; + if (caps[i].type == S3K_CAPTY_NONE || caps[j].type != S3K_CAPTY_NONE) + goto retry; + uint64_t raw = random() ^ (random() << 32); + s3k_cap_derive(i, j, (s3k_cap_t){.raw = raw}); +} + +void test_cap_derive(void) +{ + int i, j; +retry: + i = random() % S3K_CAP_CNT; + j = random() % S3K_CAP_CNT; + if (caps[i].type == S3K_CAPTY_NONE || caps[j].type != S3K_CAPTY_NONE) + goto retry; + s3k_cap_t new_cap; + switch (caps[i].type) { + case S3K_CAPTY_TIME: { + new_cap.raw = caps[i].raw; + uint64_t size = (new_cap.time.end - new_cap.time.mrk); + new_cap.time.end -= random() % size; + } break; + case S3K_CAPTY_MEMORY: { + new_cap.raw = caps[i].raw; + uint64_t size = (new_cap.mem.end - new_cap.mem.mrk); + new_cap.mem.end -= random() % size; + new_cap.mem.rwx &= random(); + } break; + case S3K_CAPTY_MONITOR: { + new_cap.raw = caps[i].raw; + uint64_t size = (new_cap.mon.end - new_cap.mon.mrk); + new_cap.mon.end -= random() % size; + } break; + case S3K_CAPTY_CHANNEL: { + new_cap.raw = caps[i].raw; + uint64_t size = (new_cap.chan.end - new_cap.chan.mrk); + new_cap.chan.end -= random() % size; + } break; + default: + goto retry; + } + s3k_cap_derive(i, j, new_cap); + s3k_cap_read(i, caps + i); + s3k_cap_read(j, caps + j); +} + +void test_pmp() +{ + int i, j; +retry: + i = random() % S3K_CAP_CNT; + if (caps[i].type != S3K_CAPTY_PMP) + goto retry; + if (caps[i].pmp.used) { + s3k_pmp_unload(i); + } else { + s3k_pmp_load(i, random() % 8); + } + s3k_cap_read(i, caps + i); +} + +void test_monitor() +{ + int i; +retry: + i = randint(0, S3K_CAP_CNT); + if (caps[i].type != S3K_CAPTY_MONITOR) + goto retry; + uint64_t min = caps[i].mon.mrk; + uint64_t max = caps[i].mon.end; + switch (random() % 7) { + case 0: + s3k_mon_suspend(i, randint(min, max)); + break; + case 1: + s3k_mon_resume(i, randint(min, max)); + break; + case 2: { + s3k_state_t state; + s3k_mon_state_get(i, randint(min, max), &state); + } break; + case 3: { + s3k_cap_t cap; + s3k_mon_cap_read(i, randint(min, max), randint(0, S3K_CAP_CNT), + &cap); + } break; + case 4: { + s3k_cap_t cap; + s3k_mon_cap_move(i, 1, randint(0, S3K_CAP_CNT), + randint(min, max), randint(0, S3K_CAP_CNT)); + } break; + case 5: { + s3k_cap_t cap; + s3k_mon_cap_move(i, randint(min, max), randint(0, S3K_CAP_CNT), + 1, randint(0, S3K_CAP_CNT)); + } break; + case 6: { + s3k_cap_t cap; + s3k_mon_cap_move(i, randint(min, max), randint(0, S3K_CAP_CNT), + randint(min, max), randint(0, S3K_CAP_CNT)); + } break; + case 7: { + s3k_cap_t cap; + s3k_mon_cap_move(i, randint(min, max), randint(0, S3K_CAP_CNT), + randint(min, max), randint(0, S3K_CAP_CNT)); + } break; + case 8: { + s3k_cap_t cap; + s3k_mon_pmp_load(i, randint(min, max), randint(0, S3K_CAP_CNT), + randint(0, 8)); + } break; + case 9: { + s3k_cap_t cap; + s3k_mon_pmp_unload(i, randint(min, max), + randint(0, S3K_CAP_CNT)); + } break; + } +} + +void test_socket() +{ + int i, j; +retry: + i = randint(0, S3K_CAP_CNT); + j = randint(0, S3K_CAP_CNT); + if (caps[i].type != S3K_CAPTY_SOCKET && caps[j].type != S3K_CAPTY_NONE) + goto retry; + s3k_msg_t msg = {.send_cap = 1, .cap_idx = j}; + switch (random() % 2) { + case 0: { + s3k_sock_send(i, &msg); + } break; + case 1: { + s3k_sock_sendrecv(i, &msg); + } break; + } +} + +typedef void (*tester_t)(void); + +tester_t testers[] = {test_get_info, test_reg_read, test_reg_write, + test_sync, test_cap_move, test_cap_delete, + test_cap_revoke, test_cap_derive, test_cap_derive_random, + test_pmp, test_monitor, test_socket}; + +int main(void) +{ + if (random() % 3 == 0) + while (1) + ; + refresh_caps(true); + for (int i = 0; i < ARRAY_SIZE(caps); i++) { + if (caps[i].type == S3K_CAPTY_MONITOR) { + s3k_mon_resume(i, 2); + } + } + s3k_sleep(0); + while (1) { + random_data_access(64); + testers[random() % ARRAY_SIZE(testers)](); + } +} diff --git a/benchmark/jitter/app2.ld b/benchmark/jitter/app2.ld new file mode 100644 index 00000000..15430bf0 --- /dev/null +++ b/benchmark/jitter/app2.ld @@ -0,0 +1,5 @@ +MEMORY { + RAM (rwx) : ORIGIN = 0x80040000, LENGTH = 0x20000 +} + +__stack_size = 1024; diff --git a/benchmark/jitter/app2/main.c b/benchmark/jitter/app2/main.c new file mode 100644 index 00000000..e83fcf42 --- /dev/null +++ b/benchmark/jitter/app2/main.c @@ -0,0 +1,13 @@ +#include "altc/altio.h" +#include "s3k/s3k.h" + +#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) + +int main(void) +{ + s3k_msg_t msg; + do { + msg.cap_idx = 10; + s3k_sock_sendrecv(3, &msg); + } while (1); +} diff --git a/benchmark/jitter/app3.ld b/benchmark/jitter/app3.ld new file mode 100644 index 00000000..f121d3b7 --- /dev/null +++ b/benchmark/jitter/app3.ld @@ -0,0 +1,5 @@ +MEMORY { + RAM (rwx) : ORIGIN = 0x80060000, LENGTH = 0x20000 +} + +__stack_size = 1024; diff --git a/benchmark/jitter/app3/main.c b/benchmark/jitter/app3/main.c new file mode 100644 index 00000000..a607c9ab --- /dev/null +++ b/benchmark/jitter/app3/main.c @@ -0,0 +1,39 @@ +#include "altc/altio.h" +#include "s3k/s3k.h" + +#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) + +#define L1_TOTAL_SIZE (32 * 1024) +#define L1_LINE_SIZE 64 + +static volatile uint64_t data[L1_TOTAL_SIZE / sizeof(uint64_t)]; + +uint64_t random(void) +{ + static unsigned long x = 123456789, y = 362436069, z = 521288629; + unsigned long t; + x ^= x << 16; + x ^= x >> 5; + x ^= x << 1; + + t = x; + x = y; + y = z; + z = t ^ x ^ y; + + return z; +} + +void flush_data_cache() +{ + // 32 KiB 8-way cache. + for (int i = 0; i < L1_TOTAL_SIZE; i += L1_LINE_SIZE) { + data[i / sizeof(uint64_t)] = random(); + } +} + +int main(void) +{ + while (1) + flush_data_cache(); +} diff --git a/benchmark/jitter/build.mk b/benchmark/jitter/build.mk new file mode 100644 index 00000000..db917693 --- /dev/null +++ b/benchmark/jitter/build.mk @@ -0,0 +1,68 @@ +.POSIX: + +BUILD ?=build +PROGRAM ?=a + +include ${ROOT}/tools.mk +include ${ROOT}/common/plat/${PLATFORM}.mk + +C_SRCS:=${wildcard ${PROGRAM}/*.c} +S_SRCS:=${wildcard ${PROGRAM}/*.S} +OBJS :=${patsubst %.c,${BUILD}/%.o,${C_SRCS}} \ + ${patsubst %.S,${BUILD}/%.o,${S_SRCS}} \ + ${STARTFILES}/start.o +DEPS :=${OBJS:.o=.d} + +CFLAGS:=-march=${ARCH} -mabi=${ABI} -mcmodel=${CMODEL} \ + -DPLATFORM_${PLATFORM} \ + -nostdlib \ + -Os -g3 -flto \ + -I${COMMON_INC} -include ${S3K_CONF_H} + +LDFLAGS:=-march=${ARCH} -mabi=${ABI} -mcmodel=${CMODEL} \ + -nostdlib \ + -flto \ + -T${PROGRAM}.ld -Tdefault.ld \ + -Wl,--no-warn-rwx-segments \ + -L${COMMON_LIB} -ls3k -laltc -lplat \ + +ELF:=${BUILD}/${PROGRAM}.elf +BIN:=${ELF:.elf=.bin} +HEX:=${ELF:.elf=.hex} +DA :=${ELF:.elf=.da} + +all: ${ELF} ${BIN} ${HEX} ${DA} + +clean: + rm -f ${ELF} ${OBJS} ${DEPS} + +${BUILD}/${PROGRAM}/%.o: ${PROGRAM}/%.S + @mkdir -p ${@D} + @${CC} -o $@ $< ${CFLAGS} ${INC} -MMD -c + @printf "CC\t$@\n" + +${BUILD}/${PROGRAM}/%.o: ${PROGRAM}/%.c + @mkdir -p ${@D} + @${CC} -o $@ $< ${CFLAGS} ${INC} -MMD -c + @printf "CC\t$@\n" + +%.elf: ${OBJS} + @mkdir -p ${@D} + @${CC} -o $@ ${OBJS} ${LDFLAGS} ${INC} + @printf "CC\t$@\n" + +%.bin: %.elf + @${OBJCOPY} -O binary $< $@ + @printf "OBJCOPY\t$@\n" + +%.hex: %.elf + @${OBJCOPY} -O ihex $< $@ + @printf "OBJCOPY\t$@\n" + +%.da: %.elf + @${OBJDUMP} -D $< > $@ + @printf "OBJDUMP\t$@\n" + +.PHONY: all clean + +-include ${DEPS} diff --git a/benchmark/jitter/default.ld b/benchmark/jitter/default.ld new file mode 100644 index 00000000..fe968757 --- /dev/null +++ b/benchmark/jitter/default.ld @@ -0,0 +1,34 @@ +/* See LICENSE file for copyright and license details. */ +OUTPUT_ARCH(riscv) +ENTRY(_start) + +__global_pointer$ = MIN(_sdata + 0x800, MAX(_data + 0x800, _end - 0x800)); + +SECTIONS { + .text : { + *( .init ) + *( .text .text.* ) + } > RAM + + .data : { + _data = . ; + *( .data ) + *( .data.* ) + _sdata = . ; + *( .sdata ) + *( .sdata.* ) + } > RAM + + .bss : { + _bss = .; + _sbss = .; + *(.sbss .sbss.*) + *(.bss .bss.*) + _end = .; + } > RAM + + .stack ORIGIN(RAM) + LENGTH(RAM) - __stack_size : ALIGN(8) { + . += __stack_size; + __stack_pointer = .; + } +} diff --git a/benchmark/jitter/s3k_conf.h b/benchmark/jitter/s3k_conf.h new file mode 100644 index 00000000..6a739210 --- /dev/null +++ b/benchmark/jitter/s3k_conf.h @@ -0,0 +1,32 @@ +#pragma once + +#include "plat/config.h" + +// Number of user processes +#define S3K_PROC_CNT 4 + +// Number of capabilities per process. +#define S3K_CAP_CNT 32 + +// Number of IPC channels. +#define S3K_CHAN_CNT 16 + +// Number of slots per period +#define S3K_SLOT_CNT 32ull + +// Length of slots in ticks. +#define S3K_SLOT_LEN (S3K_RTC_HZ / S3K_SLOT_CNT / 100) + +// Scheduler time +#define S3K_SCHED_TIME 8 +//#define NPREMPT + +// If debugging, comment +#define NDEBUG +#define INSTRUMENT_CYCLE +#define VERBOSITY 2 + +//#define SCENARIO_SOLO +#define SCENARIO_ACTIVE +//#define SCENARIO_FLUSH +//#define SCENARIO_ACTIVE_FLUSH diff --git a/benchmark/wcrt/Makefile b/benchmark/wcrt/Makefile new file mode 100644 index 00000000..c3c29679 --- /dev/null +++ b/benchmark/wcrt/Makefile @@ -0,0 +1,48 @@ +.POSIX: + +export PLATFORM ?=sifive_unleashed +export ROOT :=${abspath ../..} +export BUILD :=${abspath build/${PLATFORM}} +export S3K_CONF_H :=${abspath s3k_conf.h} + +include ${ROOT}/tools.mk +include ${ROOT}/common/plat/${PLATFORM}.mk + +APPS=app0 app1 app2 + +ELFS=${patsubst %, ${BUILD}/%.elf, kernel ${APPS}} + +all: kernel ${APPS} size + +clean: + @${MAKE} -C ${ROOT}/common clean + @${MAKE} -C ${ROOT}/kernel clean + @for prog in ${APPS}; do \ + ${MAKE} -f build.mk PROGRAM=$$prog clean; \ + done + +common: + @${MAKE} -C ${ROOT}/common + +kernel: common + @${MAKE} -C ${ROOT}/kernel + +size: kernel ${APPS} + ${SIZE} ${BUILD}/*.elf + +qemu: kernel ${APPS} + @ELFS="${ELFS}" ${ROOT}/scripts/qemu.sh + +qemu-gdb: kernel ${APPS} + @ELFS="${ELFS}" ${ROOT}/scripts/qemu.sh -gdb tcp::3333 -S + +gdb: kernel ${APPS} + @ELFS="${ELFS}" ${ROOT}/scripts/gdb.sh + +gdb-openocd: kernel ${APPS} + @ELFS="${ELFS}" ${ROOT}/scripts/gdb-openocd.sh + +${APPS}: common + @${MAKE} -f build.mk PROGRAM=$@ + +.PHONY: all clean size qemu qemu-gdb gdb kernel common ${APPS} diff --git a/benchmark/wcrt/app0.ld b/benchmark/wcrt/app0.ld new file mode 100644 index 00000000..03486fa6 --- /dev/null +++ b/benchmark/wcrt/app0.ld @@ -0,0 +1,5 @@ +MEMORY { + RAM (rwx) : ORIGIN = 0x80010000, LENGTH = 0x10000 +} + +__stack_size = 16 * 1024; diff --git a/benchmark/wcrt/app0/main.c b/benchmark/wcrt/app0/main.c new file mode 100644 index 00000000..3f2381b7 --- /dev/null +++ b/benchmark/wcrt/app0/main.c @@ -0,0 +1,206 @@ +#include "altc/altio.h" +#include "s3k/s3k.h" + +#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0])) + +#define APP0_PID 0 +#define APP1_PID 1 +#define APP2_PID 2 + +// See plat_conf.h +#define BOOT_PMP 0 +#define RAM_MEM 1 +#define UART_MEM 2 +#define TIME_MEM 3 +#define HART1_TIME 4 +#define MONITOR 8 +#define CHANNEL 9 +#define MONITOR_APP1 10 +#define MONITOR_APP2 11 + +#define ASSERT(x) \ + { \ + s3k_err_t err = (x); \ + if (err) { \ + alt_printf("Failed at %s: err=%d\n", #x, err); \ + while (1) \ + ; \ + } \ + } + +void setup_uart(uint64_t uart_idx) +{ + uint64_t uart_addr = s3k_napot_encode(UART0_BASE_ADDR, 0x8); + // Derive a PMP capability for accessing UART + s3k_cap_derive(UART_MEM, uart_idx, s3k_mk_pmp(uart_addr, S3K_MEM_RW)); + // Load the derive PMP capability to PMP configuration + s3k_pmp_load(uart_idx, 1); + // Synchronize PMP unit (hardware) with PMP configuration + // false => not full synchronization. + s3k_sync_mem(); +} + +uint64_t random(void) +{ + static unsigned long x = 123456789, y = 362436069, z = 521288629; + unsigned long t; + x ^= x << 16; + x ^= x >> 5; + x ^= x << 1; + + t = x; + x = y; + y = z; + z = t ^ x ^ y; + + return z; +} + +void random_cidx(s3k_cidx_t *idx, int cnt) +{ + for (int i = 0; i < cnt; ++i) { + retry: + idx[i] = random() % S3K_CAP_CNT; + for (int j = 0; j < i; ++j) { + if (idx[j] == idx[i]) + goto retry; + } + } +} + +void teardown(void) +{ + ASSERT(s3k_mon_suspend(MONITOR_APP1, APP1_PID)); + ASSERT(s3k_cap_revoke(MONITOR_APP2)); + ASSERT(s3k_mon_suspend(MONITOR_APP2, APP2_PID)); + ASSERT(s3k_cap_revoke(RAM_MEM)); + ASSERT(s3k_cap_revoke(HART1_TIME)); + ASSERT(s3k_cap_revoke(CHANNEL)); + + s3k_state_t state; + do { + s3k_mon_state_get(MONITOR_APP1, APP1_PID, &state); + } while (state != S3K_PSF_SUSPENDED); + do { + s3k_mon_state_get(MONITOR_APP2, APP2_PID, &state); + } while (state != S3K_PSF_SUSPENDED); + + for (int i = 0; i < S3K_REG_CNT; ++i) { + s3k_mon_reg_write(MONITOR_APP1, APP1_PID, i, 0); + s3k_mon_reg_write(MONITOR_APP2, APP2_PID, i, 0); + } +} + +void setup(void) +{ + int tmp = 12; + s3k_cidx_t indices[8]; + random_cidx(indices, ARRAY_SIZE(indices)); + + uint64_t app1_begin = 0x80020000; + uint64_t app1_end = 0x80040000; + uint64_t app2_begin = 0x80040000; + uint64_t app2_end = 0x80080000; + uint64_t ram_end = 0x80100000; + + s3k_cap_t ram1_mem = s3k_mk_memory(app1_begin, app1_end, S3K_MEM_RWX); + s3k_cap_t ram1_pmp = s3k_mk_pmp( + s3k_napot_encode(app1_begin, app1_end - app1_begin), S3K_MEM_RWX); + s3k_cap_t ram2_mem = s3k_mk_memory(app2_begin, app2_end, S3K_MEM_RWX); + s3k_cap_t ram2_pmp = s3k_mk_pmp( + s3k_napot_encode(app2_begin, app2_end - app2_begin), S3K_MEM_RWX); + s3k_cap_t ramX_mem = s3k_mk_memory(app1_end, ram_end, S3K_MEM_RWX); + + ASSERT(s3k_cap_derive(RAM_MEM, tmp, ram1_mem)); + ASSERT(s3k_cap_derive(tmp, tmp + 1, ram1_pmp)); + ASSERT(s3k_cap_derive(RAM_MEM, tmp + 2, ramX_mem)); + ASSERT(s3k_cap_derive(tmp + 2, tmp + 3, ram2_mem)); + ASSERT(s3k_cap_derive(tmp + 3, tmp + 4, ram2_pmp)); + + ASSERT(s3k_mon_cap_move(MONITOR_APP1, APP0_PID, tmp, APP1_PID, + indices[0])); + ASSERT(s3k_mon_cap_move(MONITOR_APP1, APP0_PID, tmp + 1, APP1_PID, + indices[1])); + ASSERT(s3k_mon_cap_move(MONITOR_APP1, APP0_PID, tmp + 2, APP1_PID, + indices[2])); + ASSERT(s3k_mon_pmp_load(MONITOR_APP1, APP1_PID, indices[1], 0)); + + ASSERT(s3k_mon_cap_move(MONITOR_APP2, APP0_PID, tmp + 4, APP2_PID, 0)); + ASSERT(s3k_mon_cap_move(MONITOR_APP2, APP0_PID, tmp + 3, APP2_PID, 1)); + ASSERT(s3k_mon_pmp_load(MONITOR_APP2, APP2_PID, 0, 0)); + + s3k_cap_t hart0_time1, hart0_time2; + s3k_cap_read(HART1_TIME, &hart0_time1); + hart0_time2.raw = hart0_time1.raw; + hart0_time1.time.end = 28; + hart0_time2.time.end = 4; + ASSERT(s3k_cap_derive(HART1_TIME, tmp, hart0_time1)); + ASSERT(s3k_cap_derive(tmp, tmp + 1, hart0_time2)); + ASSERT(s3k_mon_cap_move(MONITOR_APP1, APP0_PID, tmp, APP1_PID, + indices[3])); + ASSERT(s3k_mon_cap_move(MONITOR_APP2, APP0_PID, tmp + 1, APP2_PID, 2)); + + s3k_cap_t chan_app1 = s3k_mk_channel(0, S3K_CHAN_CNT); + s3k_cap_t sock_app2 = s3k_mk_socket(0, S3K_IPC_YIELD, 0xF, 0); + s3k_cap_t sock_app1 = s3k_mk_socket(0, S3K_IPC_YIELD, 0xF, 2); + ASSERT(s3k_cap_derive(CHANNEL, tmp, chan_app1)); + ASSERT(s3k_cap_derive(tmp, tmp + 1, sock_app2)); + ASSERT(s3k_cap_derive(tmp + 1, tmp + 2, sock_app1)); + ASSERT(s3k_mon_cap_move(MONITOR_APP1, APP0_PID, tmp, APP1_PID, + indices[4])); + ASSERT(s3k_mon_cap_move(MONITOR_APP2, APP0_PID, tmp + 1, APP2_PID, 3)); + ASSERT(s3k_mon_cap_move(MONITOR_APP1, APP0_PID, tmp + 2, APP1_PID, + indices[5])); + + s3k_mon_reg_write(MONITOR_APP2, APP2_PID, S3K_REG_PC, app2_begin); + s3k_mon_resume(MONITOR_APP2, APP2_PID); + + s3k_cap_t mon_app2 = s3k_mk_monitor(2, S3K_PROC_CNT); + ASSERT(s3k_cap_derive(MONITOR_APP2, tmp, mon_app2)); + ASSERT(s3k_mon_cap_move(MONITOR_APP1, APP0_PID, tmp, APP1_PID, + indices[6])); + + s3k_mon_reg_write(MONITOR_APP1, APP1_PID, S3K_REG_PC, app1_begin); +} + +uint64_t csrr_cycle(void) +{ + register uint64_t cycle; + __asm__ volatile("csrr %0, cycle" : "=r"(cycle)); + return cycle; +} + +void measurement(void) +{ + uint64_t max = 0; + s3k_sleep(0); + for (int i = 0; i < MEASUREMENTS; ++i) { + retry: + teardown(); + setup(); + s3k_sleep(0); + s3k_mon_resume(MONITOR_APP1, APP1_PID); + s3k_get_wcet(true); + uint64_t wcet = 0; + uint64_t last_wcet; + do { + last_wcet = wcet; + s3k_sleep(0); + wcet = s3k_get_wcet(false); + } while (wcet > last_wcet); + max = wcet > max ? wcet : max; + alt_printf("%d\t%D\t%D\n", i + 1, wcet, max); + } +} + +int main(void) +{ + // Setup UART access + setup_uart(6); + s3k_cap_t mon = s3k_mk_monitor(1, 3); + ASSERT(s3k_cap_derive(MONITOR, MONITOR_APP1, s3k_mk_monitor(1, 2))); + ASSERT(s3k_cap_derive(MONITOR, MONITOR_APP2, + s3k_mk_monitor(2, S3K_PROC_CNT))); + + measurement(); +} diff --git a/benchmark/wcrt/app1.ld b/benchmark/wcrt/app1.ld new file mode 100644 index 00000000..bd8ab292 --- /dev/null +++ b/benchmark/wcrt/app1.ld @@ -0,0 +1,5 @@ +MEMORY { + RAM (rwx) : ORIGIN = 0x80020000, LENGTH = 0x20000 +} + +__stack_size = 1024; diff --git a/benchmark/wcrt/app1/main.c b/benchmark/wcrt/app1/main.c new file mode 100644 index 00000000..22028d48 --- /dev/null +++ b/benchmark/wcrt/app1/main.c @@ -0,0 +1,305 @@ +#include "altc/altio.h" +#include "s3k/s3k.h" + +#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) + +#define L1_TOTAL_SIZE (32 * 1024) +#define L1_LINE_SIZE 64 + +static volatile uint64_t data[L1_TOTAL_SIZE / sizeof(uint64_t)]; + +uint64_t random(void) +{ + static unsigned long x = 123456789, y = 362436069, z = 521288629; + unsigned long t; + x ^= x << 16; + x ^= x >> 5; + x ^= x << 1; + + t = x; + x = y; + y = z; + z = t ^ x ^ y; + + return z; +} + +uint64_t randint(unsigned long min, unsigned long max) +{ + return (random() % (max - min)) + min; +} + +void flush_data_cache() +{ + // 32 KiB 8-way cache. + for (int i = 0; i < L1_TOTAL_SIZE; i += L1_LINE_SIZE) { + data[i / sizeof(uint64_t)] = random(); + } +} + +void random_data_access(int x) +{ + for (int i = 0; i < x; ++i) { + data[random() % ARRAY_SIZE(data)] = random(); + } +} + +// Known capabilities. +s3k_cap_t caps[S3K_CAP_CNT]; + +void refresh_caps(bool all) +{ + for (int i = 0; i < S3K_CAP_CNT; ++i) { + if (all || caps[i].type != 0) + s3k_cap_read(i, caps + i); + } +} + +void test_get_info(void) +{ + switch (random() % 3) { + case 0: + s3k_get_pid(); + case 1: + s3k_get_time(); + case 2: + s3k_get_timeout(); + } +} + +void test_reg_read(void) +{ + s3k_reg_read(random() % S3K_REG_CNT); +} + +void test_reg_write(void) +{ + s3k_reg_write(random() % S3K_REG_CNT, random()); +} + +void test_sync() +{ + if (random() % 2) { + s3k_sync(); + } else { + s3k_sync_mem(); + } +} + +void test_cap_move(void) +{ + int i, j; +retry: + i = random() % S3K_CAP_CNT; + j = random() % S3K_CAP_CNT; + if (caps[i].type == S3K_CAPTY_NONE || caps[j].type != S3K_CAPTY_NONE) + goto retry; + s3k_cap_move(i, j); + caps[i].raw = 0; + caps[j].raw = caps[j].raw; +} + +void test_cap_delete() +{ + int i; +retry: + i = random() % S3K_CAP_CNT; + s3k_cap_delete(i); + s3k_cap_read(i, caps + i); +} + +void test_cap_revoke() +{ + int i; +retry: + i = random() % S3K_CAP_CNT; + s3k_cap_revoke(i); + refresh_caps(true); +} + +void test_cap_derive_random(void) +{ + int i, j; +retry: + i = random() % S3K_CAP_CNT; + j = random() % S3K_CAP_CNT; + if (caps[i].type == S3K_CAPTY_NONE || caps[j].type != S3K_CAPTY_NONE) + goto retry; + uint64_t raw = random() ^ (random() << 32); + s3k_cap_derive(i, j, (s3k_cap_t){.raw = raw}); +} + +void test_cap_derive(void) +{ + int i, j; +retry: + i = random() % S3K_CAP_CNT; + j = random() % S3K_CAP_CNT; + if (caps[i].type == S3K_CAPTY_NONE || caps[j].type != S3K_CAPTY_NONE) + goto retry; + s3k_cap_t new_cap; + switch (caps[i].type) { + case S3K_CAPTY_TIME: { + new_cap.raw = caps[i].raw; + uint64_t size = (new_cap.time.end - new_cap.time.mrk); + new_cap.time.end -= random() % size; + } break; + case S3K_CAPTY_MEMORY: { + new_cap.raw = caps[i].raw; + uint64_t size = (new_cap.mem.end - new_cap.mem.mrk); + new_cap.mem.end -= random() % size; + new_cap.mem.rwx &= random(); + } break; + case S3K_CAPTY_MONITOR: { + new_cap.raw = caps[i].raw; + uint64_t size = (new_cap.mon.end - new_cap.mon.mrk); + new_cap.mon.end -= random() % size; + } break; + case S3K_CAPTY_CHANNEL: { + new_cap.raw = caps[i].raw; + uint64_t size = (new_cap.chan.end - new_cap.chan.mrk); + new_cap.chan.end -= random() % size; + } break; + default: + goto retry; + } + s3k_cap_derive(i, j, new_cap); + s3k_cap_read(i, caps + i); + s3k_cap_read(j, caps + j); +} + +void test_pmp() +{ + int i, j; +retry: + i = random() % S3K_CAP_CNT; + if (caps[i].type != S3K_CAPTY_PMP) + goto retry; + if (caps[i].pmp.used) { + s3k_pmp_unload(i); + } else { + s3k_pmp_load(i, random() % 8); + } + s3k_cap_read(i, caps + i); +} + +void test_monitor() +{ + int i; +retry: + i = randint(0, S3K_CAP_CNT); + if (caps[i].type != S3K_CAPTY_MONITOR) + goto retry; + uint64_t min = caps[i].mon.mrk; + uint64_t max = caps[i].mon.end; + switch (random() % 7) { + case 0: + s3k_mon_suspend(i, randint(min, max)); + break; + case 1: + s3k_mon_resume(i, randint(min, max)); + break; + case 2: { + s3k_state_t state; + s3k_mon_state_get(i, randint(min, max), &state); + } break; + case 3: { + s3k_cap_t cap; + s3k_mon_cap_read(i, randint(min, max), randint(0, S3K_CAP_CNT), + &cap); + } break; + case 4: { + s3k_cap_t cap; + s3k_mon_cap_move(i, 1, randint(0, S3K_CAP_CNT), + randint(min, max), randint(0, S3K_CAP_CNT)); + } break; + case 5: { + s3k_cap_t cap; + s3k_mon_cap_move(i, randint(min, max), randint(0, S3K_CAP_CNT), + 1, randint(0, S3K_CAP_CNT)); + } break; + case 6: { + s3k_cap_t cap; + s3k_mon_cap_move(i, randint(min, max), randint(0, S3K_CAP_CNT), + randint(min, max), randint(0, S3K_CAP_CNT)); + } break; + case 7: { + s3k_cap_t cap; + s3k_mon_cap_move(i, randint(min, max), randint(0, S3K_CAP_CNT), + randint(min, max), randint(0, S3K_CAP_CNT)); + } break; + case 8: { + s3k_cap_t cap; + s3k_mon_pmp_load(i, randint(min, max), randint(0, S3K_CAP_CNT), + randint(0, 8)); + } break; + case 9: { + s3k_cap_t cap; + s3k_mon_pmp_unload(i, randint(min, max), + randint(0, S3K_CAP_CNT)); + } break; + } +} + +void test_socket() +{ + int i, j; +retry: + i = randint(0, S3K_CAP_CNT); + j = randint(0, S3K_CAP_CNT); + if (caps[i].type != S3K_CAPTY_SOCKET && caps[j].type != S3K_CAPTY_NONE) + goto retry; + s3k_msg_t msg = {.send_cap = 1, .cap_idx = j}; + switch (random() % 2) { + case 0: { + s3k_sock_send(i, &msg); + } break; + case 1: { + s3k_sock_sendrecv(i, &msg); + } break; + } +} + +typedef void (*tester_t)(void); + +// clang-format: disable +tester_t testers[] = { +#if defined(SCENARIO_ALL) + test_get_info, + test_reg_read, + test_reg_write, + test_sync, + test_cap_move, + test_cap_delete, + test_cap_revoke, + test_cap_derive, + test_cap_derive_random, + test_pmp, + test_monitor, + test_socket +#elif defined(SCENARIO_CAP_OPS) + test_cap_delete, + test_cap_revoke, + test_cap_derive, + test_cap_derive_random, +#elif defined(SCENARIO_PMP) + test_pmp, test_monitor, test_socket +#elif defined(SCENARIO_MONITOR) + test_monitor, +#elif defined(SCENARIO_SOCKET) + test_socket +#endif +}; +// clang-format: enable + +int main(void) +{ + refresh_caps(true); + while (1) { + if (random() % 2) + flush_data_cache(); + else + random_data_access(64); + testers[random() % ARRAY_SIZE(testers)](); + } +} diff --git a/benchmark/wcrt/app2.ld b/benchmark/wcrt/app2.ld new file mode 100644 index 00000000..15430bf0 --- /dev/null +++ b/benchmark/wcrt/app2.ld @@ -0,0 +1,5 @@ +MEMORY { + RAM (rwx) : ORIGIN = 0x80040000, LENGTH = 0x20000 +} + +__stack_size = 1024; diff --git a/benchmark/wcrt/app2/main.c b/benchmark/wcrt/app2/main.c new file mode 100644 index 00000000..e83fcf42 --- /dev/null +++ b/benchmark/wcrt/app2/main.c @@ -0,0 +1,13 @@ +#include "altc/altio.h" +#include "s3k/s3k.h" + +#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) + +int main(void) +{ + s3k_msg_t msg; + do { + msg.cap_idx = 10; + s3k_sock_sendrecv(3, &msg); + } while (1); +} diff --git a/benchmark/wcrt/build.mk b/benchmark/wcrt/build.mk new file mode 100644 index 00000000..db917693 --- /dev/null +++ b/benchmark/wcrt/build.mk @@ -0,0 +1,68 @@ +.POSIX: + +BUILD ?=build +PROGRAM ?=a + +include ${ROOT}/tools.mk +include ${ROOT}/common/plat/${PLATFORM}.mk + +C_SRCS:=${wildcard ${PROGRAM}/*.c} +S_SRCS:=${wildcard ${PROGRAM}/*.S} +OBJS :=${patsubst %.c,${BUILD}/%.o,${C_SRCS}} \ + ${patsubst %.S,${BUILD}/%.o,${S_SRCS}} \ + ${STARTFILES}/start.o +DEPS :=${OBJS:.o=.d} + +CFLAGS:=-march=${ARCH} -mabi=${ABI} -mcmodel=${CMODEL} \ + -DPLATFORM_${PLATFORM} \ + -nostdlib \ + -Os -g3 -flto \ + -I${COMMON_INC} -include ${S3K_CONF_H} + +LDFLAGS:=-march=${ARCH} -mabi=${ABI} -mcmodel=${CMODEL} \ + -nostdlib \ + -flto \ + -T${PROGRAM}.ld -Tdefault.ld \ + -Wl,--no-warn-rwx-segments \ + -L${COMMON_LIB} -ls3k -laltc -lplat \ + +ELF:=${BUILD}/${PROGRAM}.elf +BIN:=${ELF:.elf=.bin} +HEX:=${ELF:.elf=.hex} +DA :=${ELF:.elf=.da} + +all: ${ELF} ${BIN} ${HEX} ${DA} + +clean: + rm -f ${ELF} ${OBJS} ${DEPS} + +${BUILD}/${PROGRAM}/%.o: ${PROGRAM}/%.S + @mkdir -p ${@D} + @${CC} -o $@ $< ${CFLAGS} ${INC} -MMD -c + @printf "CC\t$@\n" + +${BUILD}/${PROGRAM}/%.o: ${PROGRAM}/%.c + @mkdir -p ${@D} + @${CC} -o $@ $< ${CFLAGS} ${INC} -MMD -c + @printf "CC\t$@\n" + +%.elf: ${OBJS} + @mkdir -p ${@D} + @${CC} -o $@ ${OBJS} ${LDFLAGS} ${INC} + @printf "CC\t$@\n" + +%.bin: %.elf + @${OBJCOPY} -O binary $< $@ + @printf "OBJCOPY\t$@\n" + +%.hex: %.elf + @${OBJCOPY} -O ihex $< $@ + @printf "OBJCOPY\t$@\n" + +%.da: %.elf + @${OBJDUMP} -D $< > $@ + @printf "OBJDUMP\t$@\n" + +.PHONY: all clean + +-include ${DEPS} diff --git a/benchmark/wcrt/default.ld b/benchmark/wcrt/default.ld new file mode 100644 index 00000000..fe968757 --- /dev/null +++ b/benchmark/wcrt/default.ld @@ -0,0 +1,34 @@ +/* See LICENSE file for copyright and license details. */ +OUTPUT_ARCH(riscv) +ENTRY(_start) + +__global_pointer$ = MIN(_sdata + 0x800, MAX(_data + 0x800, _end - 0x800)); + +SECTIONS { + .text : { + *( .init ) + *( .text .text.* ) + } > RAM + + .data : { + _data = . ; + *( .data ) + *( .data.* ) + _sdata = . ; + *( .sdata ) + *( .sdata.* ) + } > RAM + + .bss : { + _bss = .; + _sbss = .; + *(.sbss .sbss.*) + *(.bss .bss.*) + _end = .; + } > RAM + + .stack ORIGIN(RAM) + LENGTH(RAM) - __stack_size : ALIGN(8) { + . += __stack_size; + __stack_pointer = .; + } +} diff --git a/benchmark/wcrt/s3k_conf.h b/benchmark/wcrt/s3k_conf.h new file mode 100644 index 00000000..4757bf58 --- /dev/null +++ b/benchmark/wcrt/s3k_conf.h @@ -0,0 +1,35 @@ +#pragma once + +#include "plat/config.h" + +// Number of user processes +#define S3K_PROC_CNT 6 + +// Number of capabilities per process. +#define S3K_CAP_CNT 32 + +// Number of IPC channels. +#define S3K_CHAN_CNT 16 + +// Number of slots per period +#define S3K_SLOT_CNT 32ull + +// Length of slots in ticks. +#define S3K_SLOT_LEN (S3K_RTC_HZ / S3K_SLOT_CNT / 100) + +// Scheduler time +#define S3K_SCHED_TIME 8 +//#define NPREMPT + +// If debugging, comment +#define NDEBUG +#define INSTRUMENT_WCRT +#define VERBOSITY 2 + +#define MEASUREMENTS 100000 + +//#define SCENARIO_CAP_OPS +//#define SCENARIO_PMP +//#define SCENARIO_MONITOR +//#define SCENARIO_SOCKET +#define SCENARIO_ALL