From 3528f88fc36df6964c0efed784ae223cfe93544e Mon Sep 17 00:00:00 2001 From: Kimplul Date: Sat, 6 Jul 2024 22:08:50 +0300 Subject: add RAM usage counting + Slightly more overhead but will help track down possible memory leaks in the future. Could also add in a flag for turning off/on but I don't think the difference in performance is that significant. --- arch/riscv64/conf/init | Bin 3688 -> 4008 bytes arch/riscv64/conf/init.c | 30 +++++++++++++++++++ arch/riscv64/conf/initrd | Bin 4096 -> 4608 bytes include/kmi/pmem.h | 3 ++ include/kmi/syscalls.h | 29 +++++++++++++++++++ src/pmem.c | 73 ++++++++++++++++++++++++++++++++++++++++------- src/uapi/conf.c | 22 ++++++++------ 7 files changed, 138 insertions(+), 19 deletions(-) diff --git a/arch/riscv64/conf/init b/arch/riscv64/conf/init index e1a5de7..567ff43 100755 Binary files a/arch/riscv64/conf/init and b/arch/riscv64/conf/init differ diff --git a/arch/riscv64/conf/init.c b/arch/riscv64/conf/init.c index 7029dbd..6b1ce46 100644 --- a/arch/riscv64/conf/init.c +++ b/arch/riscv64/conf/init.c @@ -220,6 +220,28 @@ static void *sys_req_mem(size_t count) return (void *)r.ar0; } +static size_t get_ram_usage() +{ + struct sys_ret r = ecall2(SYS_CONF_GET, CONF_RAM_USAGE); + if (r.s) { + print_value("getting RAM usage failed with error ", r.s); + return 0; + } + + return r.ar0; +} + +static size_t get_ram_size() +{ + struct sys_ret r = ecall2(SYS_CONF_GET, CONF_RAM_SIZE); + if (r.s) { + print_value("getting RAM size failed with error ", r.s); + return 0; + } + + return r.ar0; +} + static void sys_free_mem(void *p) { struct sys_ret r = ecall2(SYS_FREE_MEM, (long)p); @@ -336,12 +358,20 @@ void _start() print_value("IPC requests per second", n); puts("Doing memory allocations...\n"); + + size_t ram = get_ram_usage(); + size_t size = get_ram_size(); + print_value("Memory usage before allocations: ", ram); + print_value("Memory size in total: ", size); for (i = 0; i < 1000000; ++i) { char *p = sys_req_mem(10); *p = 'c'; sys_free_mem(p); } + ram = get_ram_usage(); + print_value("Memory usage after allocations: ", ram); + puts("Checking shared memory\n"); struct sys_ret r = sys_ipc_req(1, 1, 0, 0, 0); rw_buf = (char *)r.ar1; diff --git a/arch/riscv64/conf/initrd b/arch/riscv64/conf/initrd index 6c101bc..e331c21 100644 Binary files a/arch/riscv64/conf/initrd and b/arch/riscv64/conf/initrd differ diff --git a/include/kmi/pmem.h b/include/kmi/pmem.h index 966f269..0c7a4a2 100644 --- a/include/kmi/pmem.h +++ b/include/kmi/pmem.h @@ -39,6 +39,9 @@ void mark_used(enum mm_order order, pm_t addr); */ pm_t alloc_page(enum mm_order order); +/** @return How many bytes of memory are currently in use. */ +size_t query_used(); + /** * Populate physical RAM usage map. * In theory we could easily implement NUMA nodes by just using different orders diff --git a/include/kmi/syscalls.h b/include/kmi/syscalls.h index 0801f50..a94cdf1 100644 --- a/include/kmi/syscalls.h +++ b/include/kmi/syscalls.h @@ -204,6 +204,35 @@ enum notify_flag { */ typedef long sys_arg_t; +/** IDs for configuration parameters. */ +enum conf_param { + /** + * How large a regular thread stack is. + * \c R/W + */ + CONF_THREAD_STACK, + + /** + * How large an RPC stack element is. R/W. Note that this is not how + * large the RPC stack is in total, as that is hardcoded by the + * architecture, but how much of that stack one RPC call can take. + * \c R/W + */ + CONF_RPC_STACK, + + /** + * Current RAM usage. + * \c R + */ + CONF_RAM_USAGE, + + /** + * Total RAM size. + * \c R. + */ + CONF_RAM_SIZE, +}; + /** * Return structure of syscall. * \note Field names are generic, and can be used for whatever, diff --git a/src/pmem.c b/src/pmem.c index 91aff5a..cf70c3f 100644 --- a/src/pmem.c +++ b/src/pmem.c @@ -208,11 +208,21 @@ static void __get_bit(struct mm_bucket *bucket, pm_t a, size_t *s, size_t *b) *b = p % bucket->bits; } -void free_page(enum mm_order order, pm_t addr) +/** Counter for how many bytes are currently in use. */ +static size_t used = 0; + +/** + * Non-usage counting worker for \ref free_page(). + * + * @param order Order of page to free. + * @param addr Address of page to free. + * @return \ref true if usage count should be updated, \ref false otherwise. + */ +static bool __free_page(enum mm_order order, pm_t addr) { struct mm_bucket *bucket = pmap->buckets[order]; if (!bucket) - return; + return false; size_t set = 0, bit = 0; __get_bit(bucket, addr, &set, &bit); @@ -227,11 +237,25 @@ void free_page(enum mm_order order, pm_t addr) __detach_set(bucket, bmap); if (bmap->size == order_width(order + 1)) - free_page(order + 1, __page_addr(bucket, set, bit)); + __free_page(order + 1, __page_addr(bucket, set, bit)); } + + return true; } -pm_t alloc_page(enum mm_order order) +void free_page(enum mm_order order, pm_t addr) +{ + if (__free_page(order, addr)) + used -= order_size(order); +} + +/** + * Non-usage counting worker for \ref alloc_page(). + * + * @param order Order of page to allocate. + * @return Address of allocated page, NULL of no page available. + */ +static pm_t __alloc_page(enum mm_order order) { struct mm_bucket *bucket = pmap->buckets[order]; if (!bucket) @@ -239,7 +263,7 @@ pm_t alloc_page(enum mm_order order) struct mm_bmap *bmap = bucket->head; if (!bmap) { - pm_t a = alloc_page(order + 1); + pm_t a = __alloc_page(order + 1); if (!a) return 0; @@ -250,7 +274,7 @@ pm_t alloc_page(enum mm_order order) bmap->used = 0; bitmap_clear_all(bmap->bits, bmap->size); __attach_set(bucket, bmap); - return alloc_page(order); + return __alloc_page(order); } bmap->used++; @@ -265,11 +289,27 @@ pm_t alloc_page(enum mm_order order) return __page_addr(bucket, set, bit); } -void mark_used(enum mm_order order, pm_t addr) +pm_t alloc_page(enum mm_order order) +{ + pm_t page = __alloc_page(order); + if (page) + used += order_size(order); + + return page; +} + +/** + * Non-usage counting worker for \ref __mark_used(). + * + * @param order Order of page to mark used. + * @param addr Address of page to mark used. + * @return \ref true if usage count should be updated, \ref false otherwise. + */ +static bool __mark_used(enum mm_order order, pm_t addr) { struct mm_bucket *bucket = pmap->buckets[order]; if (!bucket) - return; + return false; size_t set = 0, bit = 0; __get_bit(bucket, addr, &set, &bit); @@ -278,7 +318,7 @@ void mark_used(enum mm_order order, pm_t addr) if (bmap->used == 0) { bitmap_clear_all(bmap->bits, bmap->size); __attach_set(bucket, bmap); - mark_used(order + 1, addr); + __mark_used(order + 1, addr); } /* a page already in use can just be left alone. This MIGHT hide some @@ -286,13 +326,26 @@ void mark_used(enum mm_order order, pm_t addr) * initialization, but that scenario should probably be handled outside * of this function anyway. */ if (bitmap_is_set(bmap->bits, bit)) - return; + return false; bmap->used++; bitmap_set(bmap->bits, bit); if (bmap->used == bmap->size) __detach_set(bucket, bmap); + + return true; +} + +void mark_used(enum mm_order order, pm_t addr) +{ + if (__mark_used(order, addr)) + used += order_size(order); +} + +size_t query_used() +{ + return used; } /** diff --git a/src/uapi/conf.c b/src/uapi/conf.c index 685d294..be9abfc 100644 --- a/src/uapi/conf.c +++ b/src/uapi/conf.c @@ -21,12 +21,6 @@ size_t __thread_stack_size = SZ_2M; size_t __rpc_stack_size = SZ_512K; -/** IDs for configuration parameters. */ -/** @todo should probably be moved somewhere so it can be shared with userspace */ -enum conf_param { - CONF_THREAD_STACK = 0, - CONF_RPC_STACK, -}; /** * Configuration parameter read syscall handler. @@ -39,9 +33,8 @@ enum conf_param { */ SYSCALL_DEFINE1(conf_get)(struct tcb *t, sys_arg_t param) { - if (!has_cap(t->caps, CAP_CONF)) - return_args1(t, ERR_PERM); - + /* anyone can read any current parameter, I don't think they should be + * hidden. */ long val = 0; switch (param) { case CONF_THREAD_STACK: @@ -52,6 +45,14 @@ SYSCALL_DEFINE1(conf_get)(struct tcb *t, sys_arg_t param) val = __rpc_stack_size; break; + case CONF_RAM_USAGE: + val = query_used(); + break; + + case CONF_RAM_SIZE: + val = get_ram_size(); + break; + default: return_args1(t, ERR_NF); } @@ -87,6 +88,9 @@ SYSCALL_DEFINE2(conf_set)(struct tcb *t, sys_arg_t param, sys_arg_t val) __rpc_stack_size = size; break; + + default: + return_args1(t, ERR_INVAL); } return_args1(t, OK); -- cgit v1.3