From 799ee705e8fceb6321de4345b1a772be97bc4c4b Mon Sep 17 00:00:00 2001 From: obarthel Date: Sat, 19 Nov 2016 15:49:21 +0100 Subject: [PATCH] New monitoring function for slab allocator Added __get_slab_usage() function which can be used to query the slab allocator memory usage at runtime. --- library/GNUmakefile.68k | 3 + library/amiga.lib_rev.h | 10 +-- library/amiga.lib_rev.rev | 2 +- library/c.lib_rev.h | 10 +-- library/c.lib_rev.rev | 2 +- library/changes | 9 +++ library/debug.lib_rev.h | 10 +-- library/debug.lib_rev.rev | 2 +- library/libc.gmk | 1 + library/m.lib_rev.h | 10 +-- library/m.lib_rev.rev | 2 +- library/m881.lib_rev.h | 10 +-- library/m881.lib_rev.rev | 2 +- library/net.lib_rev.h | 10 +-- library/net.lib_rev.rev | 2 +- library/smakefile | 4 ++ library/stdlib_free_unused_slabs.c | 45 +++++++------ library/stdlib_get_slab_usage.c | 104 +++++++++++++++++++++++++++++ library/stdlib_memory.h | 11 +-- library/stdlib_slab.c | 84 +++++++++++++---------- library/stdlib_slab_max_size.c | 2 +- library/unix.lib_rev.h | 10 +-- library/unix.lib_rev.rev | 2 +- 23 files changed, 241 insertions(+), 106 deletions(-) create mode 100644 library/stdlib_get_slab_usage.c diff --git a/library/GNUmakefile.68k b/library/GNUmakefile.68k index 9239b37..f1f06c0 100644 --- a/library/GNUmakefile.68k +++ b/library/GNUmakefile.68k @@ -332,6 +332,7 @@ C_LIB = \ stdlib_getmemstats.o \ stdlib_getsp.o \ stdlib_get_errno.o \ + stdlib_get_slab_usage.o \ stdlib_isresident.o \ stdlib_labs.o \ stdlib_llabs.o \ @@ -1134,6 +1135,8 @@ $(LIBC_OBJS)/stdlib_slab.o : stdlib_slab.c stdlib_memory.h $(LIBC_OBJS)/stdlib_free_unused_slabs.o : stdlib_free_unused_slabs.c stdlib_memory.h +$(LIBC_OBJS)/stdlib_get_slab_usage.o : stdlib_get_slab_usage.c stdlib_memory.h + $(LIBC_OBJS)/stdlib_realloc.o : stdlib_realloc.c stdlib_memory.h $(LIBC_OBJS)/stdlib_red_black.o : stdlib_red_black.c stdlib_memory.h diff --git a/library/amiga.lib_rev.h b/library/amiga.lib_rev.h index 31f28c3..01378d4 100644 --- a/library/amiga.lib_rev.h +++ b/library/amiga.lib_rev.h @@ -1,6 +1,6 @@ #define VERSION 1 -#define REVISION 207 -#define DATE "18.11.2016" -#define VERS "amiga.lib 1.207" -#define VSTRING "amiga.lib 1.207 (18.11.2016)\r\n" -#define VERSTAG "\0$VER: amiga.lib 1.207 (18.11.2016)" +#define REVISION 208 +#define DATE "19.11.2016" +#define VERS "amiga.lib 1.208" +#define VSTRING "amiga.lib 1.208 (19.11.2016)\r\n" +#define VERSTAG "\0$VER: amiga.lib 1.208 (19.11.2016)" diff --git a/library/amiga.lib_rev.rev b/library/amiga.lib_rev.rev index c92ba56..7d645f5 100644 --- a/library/amiga.lib_rev.rev +++ b/library/amiga.lib_rev.rev @@ -1 +1 @@ -207 +208 diff --git a/library/c.lib_rev.h b/library/c.lib_rev.h index 32abd03..3bddb28 100644 --- a/library/c.lib_rev.h +++ b/library/c.lib_rev.h @@ -1,6 +1,6 @@ #define VERSION 1 -#define REVISION 207 -#define DATE "18.11.2016" -#define VERS "c.lib 1.207" -#define VSTRING "c.lib 1.207 (18.11.2016)\r\n" -#define VERSTAG "\0$VER: c.lib 1.207 (18.11.2016)" +#define REVISION 208 +#define DATE "19.11.2016" +#define VERS "c.lib 1.208" +#define VSTRING "c.lib 1.208 (19.11.2016)\r\n" +#define VERSTAG "\0$VER: c.lib 1.208 (19.11.2016)" diff --git a/library/c.lib_rev.rev b/library/c.lib_rev.rev index c92ba56..7d645f5 100644 --- a/library/c.lib_rev.rev +++ b/library/c.lib_rev.rev @@ -1 +1 @@ -207 +208 diff --git a/library/changes b/library/changes index 0e06f71..6486cb8 100644 --- a/library/changes +++ b/library/changes @@ -1,3 +1,12 @@ +c.lib 1.208 (19.11.2016) + +- Updated with new functions and data structures for + use with the slab allocator. + +- Added __get_slab_usage() function which can be used to query + the slab allocator memory usage at runtime. + + c.lib 1.207 (18.11.2016) - Added a slab allocator which replaces the use of memory pools or the diff --git a/library/debug.lib_rev.h b/library/debug.lib_rev.h index 901ccc2..4518a3a 100644 --- a/library/debug.lib_rev.h +++ b/library/debug.lib_rev.h @@ -1,6 +1,6 @@ #define VERSION 1 -#define REVISION 207 -#define DATE "18.11.2016" -#define VERS "debug.lib 1.207" -#define VSTRING "debug.lib 1.207 (18.11.2016)\r\n" -#define VERSTAG "\0$VER: debug.lib 1.207 (18.11.2016)" +#define REVISION 208 +#define DATE "19.11.2016" +#define VERS "debug.lib 1.208" +#define VSTRING "debug.lib 1.208 (19.11.2016)\r\n" +#define VERSTAG "\0$VER: debug.lib 1.208 (19.11.2016)" diff --git a/library/debug.lib_rev.rev b/library/debug.lib_rev.rev index c92ba56..7d645f5 100644 --- a/library/debug.lib_rev.rev +++ b/library/debug.lib_rev.rev @@ -1 +1 @@ -207 +208 diff --git a/library/libc.gmk b/library/libc.gmk index 627e888..2108dc2 100644 --- a/library/libc.gmk +++ b/library/libc.gmk @@ -218,6 +218,7 @@ C_LIB := \ stdlib_getmemstats.o \ stdlib_getsp.o \ stdlib_get_errno.o \ + stdlib_get_slab_usage.o \ stdlib_isresident.o \ stdlib_labs.o \ stdlib_llabs.o \ diff --git a/library/m.lib_rev.h b/library/m.lib_rev.h index 70f709d..5eea846 100644 --- a/library/m.lib_rev.h +++ b/library/m.lib_rev.h @@ -1,6 +1,6 @@ #define VERSION 1 -#define REVISION 207 -#define DATE "18.11.2016" -#define VERS "m.lib 1.207" -#define VSTRING "m.lib 1.207 (18.11.2016)\r\n" -#define VERSTAG "\0$VER: m.lib 1.207 (18.11.2016)" +#define REVISION 208 +#define DATE "19.11.2016" +#define VERS "m.lib 1.208" +#define VSTRING "m.lib 1.208 (19.11.2016)\r\n" +#define VERSTAG "\0$VER: m.lib 1.208 (19.11.2016)" diff --git a/library/m.lib_rev.rev b/library/m.lib_rev.rev index c92ba56..7d645f5 100644 --- a/library/m.lib_rev.rev +++ b/library/m.lib_rev.rev @@ -1 +1 @@ -207 +208 diff --git a/library/m881.lib_rev.h b/library/m881.lib_rev.h index dca8355..a900c0b 100644 --- a/library/m881.lib_rev.h +++ b/library/m881.lib_rev.h @@ -1,6 +1,6 @@ #define VERSION 1 -#define REVISION 207 -#define DATE "18.11.2016" -#define VERS "m881.lib 1.207" -#define VSTRING "m881.lib 1.207 (18.11.2016)\r\n" -#define VERSTAG "\0$VER: m881.lib 1.207 (18.11.2016)" +#define REVISION 208 +#define DATE "19.11.2016" +#define VERS "m881.lib 1.208" +#define VSTRING "m881.lib 1.208 (19.11.2016)\r\n" +#define VERSTAG "\0$VER: m881.lib 1.208 (19.11.2016)" diff --git a/library/m881.lib_rev.rev b/library/m881.lib_rev.rev index c92ba56..7d645f5 100644 --- a/library/m881.lib_rev.rev +++ b/library/m881.lib_rev.rev @@ -1 +1 @@ -207 +208 diff --git a/library/net.lib_rev.h b/library/net.lib_rev.h index c1becba..168f46b 100644 --- a/library/net.lib_rev.h +++ b/library/net.lib_rev.h @@ -1,6 +1,6 @@ #define VERSION 1 -#define REVISION 207 -#define DATE "18.11.2016" -#define VERS "net.lib 1.207" -#define VSTRING "net.lib 1.207 (18.11.2016)\r\n" -#define VERSTAG "\0$VER: net.lib 1.207 (18.11.2016)" +#define REVISION 208 +#define DATE "19.11.2016" +#define VERS "net.lib 1.208" +#define VSTRING "net.lib 1.208 (19.11.2016)\r\n" +#define VERSTAG "\0$VER: net.lib 1.208 (19.11.2016)" diff --git a/library/net.lib_rev.rev b/library/net.lib_rev.rev index c92ba56..7d645f5 100644 --- a/library/net.lib_rev.rev +++ b/library/net.lib_rev.rev @@ -1 +1 @@ -207 +208 diff --git a/library/smakefile b/library/smakefile index a84b8b7..28eca28 100644 --- a/library/smakefile +++ b/library/smakefile @@ -518,6 +518,8 @@ STDLIB_OBJ = \ stdlib_getenv.o \ stdlib_getmemstats.o \ stdlib_getsp.o \ + stdlib_get_errno.o \ + stdlib_get_slab_usage.o \ stdlib_isresident.o \ stdlib_labs.o \ stdlib_ldiv.o \ @@ -801,6 +803,8 @@ stdlib_slab.o : stdlib_slab.c stdlib_memory.h stdlib_free_unused_slabs.o : stdlib_free_unused_slabs.c stdlib_memory.h +stdlib_get_slab_usage.o : stdlib_get_slab_usage.c stdlib_memory.h + stdlib_realloc.o : stdlib_realloc.c stdlib_memory.h stdlib_red_black.o : stdlib_red_black.c stdlib_memory.h diff --git a/library/stdlib_free_unused_slabs.c b/library/stdlib_free_unused_slabs.c index f10cbb4..39432ec 100644 --- a/library/stdlib_free_unused_slabs.c +++ b/library/stdlib_free_unused_slabs.c @@ -47,31 +47,34 @@ void __free_unused_slabs(void) { - struct MinNode * free_node; - struct MinNode * free_node_next; - struct SlabNode * sn; - - __memory_lock(); - - for(free_node = (struct MinNode *)__slab_data.sd_EmptySlabs.mlh_Head ; - free_node->mln_Succ != NULL ; - free_node = free_node_next) + if(__slab_data.sd_InUse) { - free_node_next = (struct MinNode *)free_node->mln_Succ; + struct MinNode * free_node; + struct MinNode * free_node_next; + struct SlabNode * sn; - /* free_node points to SlabNode.sn_EmptyLink, which - * directly follows the SlabNode.sn_MinNode. - */ - sn = (struct SlabNode *)&free_node[-1]; + __memory_lock(); - /* Unlink from list of empty slabs. */ - Remove((struct Node *)free_node); + for(free_node = (struct MinNode *)__slab_data.sd_EmptySlabs.mlh_Head ; + free_node->mln_Succ != NULL ; + free_node = free_node_next) + { + free_node_next = (struct MinNode *)free_node->mln_Succ; - /* Unlink from list of slabs of the same size. */ - Remove((struct Node *)sn); + /* free_node points to SlabNode.sn_EmptyLink, which + * directly follows the SlabNode.sn_MinNode. + */ + sn = (struct SlabNode *)&free_node[-1]; - FreeVec(sn); + /* Unlink from list of empty slabs. */ + Remove((struct Node *)free_node); + + /* Unlink from list of slabs of the same size. */ + Remove((struct Node *)sn); + + FreeVec(sn); + } + + __memory_unlock(); } - - __memory_unlock(); } diff --git a/library/stdlib_get_slab_usage.c b/library/stdlib_get_slab_usage.c new file mode 100644 index 0000000..82329a3 --- /dev/null +++ b/library/stdlib_get_slab_usage.c @@ -0,0 +1,104 @@ +/* + * :ts=4 + * + * Portable ISO 'C' (1994) runtime library for the Amiga computer + * Copyright (c) 2002-2015 by Olaf Barthel + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Neither the name of Olaf Barthel nor the names of contributors + * may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _STDLIB_HEADERS_H +#include "stdlib_headers.h" +#endif /* _STDLIB_HEADERS_H */ + +/****************************************************************************/ + +#ifndef _STDLIB_MEMORY_H +#include "stdlib_memory.h" +#endif /* _STDLIB_MEMORY_H */ + +/****************************************************************************/ + +void +__get_slab_usage(__slab_usage_callback callback) +{ + if(__slab_data.sd_InUse) + { + struct __slab_usage_information sui; + struct SlabNode * sn; + BOOL stop; + int i; + + memset(&sui,0,sizeof(sui)); + + __memory_lock(); + + sui.sui_slab_size = __slab_data.sd_MaxSlabSize; + sui.sui_num_single_allocations = __slab_data.sd_NumSingleAllocations; + sui.sui_total_single_allocation_size = __slab_data.sd_TotalSingleAllocationSize; + + for(i = 0 ; i < (int)NUM_ENTRIES(__slab_data.sd_Slabs) ; i++) + { + for(sn = (struct SlabNode *)__slab_data.sd_Slabs[i].mlh_Head ; + sn->sn_MinNode.mln_Succ != NULL ; + sn = (struct SlabNode *)sn->sn_MinNode.mln_Succ) + { + if (sn->sn_UseCount == 0) + sui.sui_num_empty_slabs++; + else if (sn->sn_Count == sn->sn_UseCount) + sui.sui_num_full_slabs++; + + sui.sui_num_slabs++; + + sui.sui_total_slab_allocation_size += sizeof(*sn) + __slab_data.sd_MaxSlabSize; + } + } + + if(sui.sui_num_slabs > 0) + { + for(i = 0, stop = FALSE ; NOT stop && i < (int)NUM_ENTRIES(__slab_data.sd_Slabs) ; i++) + { + for(sn = (struct SlabNode *)__slab_data.sd_Slabs[i].mlh_Head ; + sn->sn_MinNode.mln_Succ != NULL ; + sn = (struct SlabNode *)sn->sn_MinNode.mln_Succ) + { + sui.sui_chunk_size = sn->sn_ChunkSize; + sui.sui_num_chunks = sn->sn_Count; + sui.sui_num_chunks_used = sn->sn_UseCount; + + sui.sui_slab_index++; + + if((*callback)(&sui) != 0) + { + stop = TRUE; + break; + } + } + } + } + + __memory_unlock(); + } +} diff --git a/library/stdlib_memory.h b/library/stdlib_memory.h index b6d8eb4..8ac48d2 100644 --- a/library/stdlib_memory.h +++ b/library/stdlib_memory.h @@ -65,7 +65,6 @@ */ #define __USE_SLAB_ALLOCATOR - /****************************************************************************/ /* @@ -271,10 +270,12 @@ struct SlabData */ size_t sd_MaxSlabSize; - /* This field keeps track of how many entries there are in - * the sd_SingleAllocations list. + /* These fields kees track of how many entries there are in + * the sd_SingleAllocations list, and how much memory these + * allocations occupy. */ - ULONG sd_NumSingleAllocations; + size_t sd_NumSingleAllocations; + size_t sd_TotalSingleAllocationSize; /* If this is set to TRUE, then memory allocations will be * be managed through slabs. @@ -285,7 +286,7 @@ struct SlabData /****************************************************************************/ extern struct SlabData NOCOMMON __slab_data; -extern ULONG NOCOMMON __slab_max_size; +extern unsigned long NOCOMMON __slab_max_size; /****************************************************************************/ diff --git a/library/stdlib_slab.c b/library/stdlib_slab.c index 177aaea..5803157 100644 --- a/library/stdlib_slab.c +++ b/library/stdlib_slab.c @@ -84,6 +84,7 @@ __slab_allocate(size_t allocation_size) AddTail((struct List *)&__slab_data.sd_SingleAllocations,(struct Node *)single_allocation); __slab_data.sd_NumSingleAllocations++; + __slab_data.sd_TotalSingleAllocationSize += sizeof(*single_allocation) + allocation_size; allocation = &single_allocation[1]; @@ -118,7 +119,7 @@ __slab_allocate(size_t allocation_size) * size that still works. */ for(slab_index = 2, chunk_size = (1UL << slab_index) ; - slab_index < 31 ; + slab_index < (int)NUM_ENTRIES(__slab_data.sd_Slabs) ; slab_index++, chunk_size += chunk_size) { if(entry_size <= chunk_size) @@ -374,6 +375,10 @@ __slab_free(void * address,size_t allocation_size) __slab_data.sd_NumSingleAllocations--; + assert( __slab_data.sd_TotalSingleAllocationSize <= sizeof(*mn) + allocation_size ); + + __slab_data.sd_TotalSingleAllocationSize -= sizeof(*mn) + allocation_size; + D(("number of single allocations = %ld", __slab_data.sd_NumSingleAllocations)); } /* Otherwise the allocation should have come from a slab. */ @@ -400,7 +405,7 @@ __slab_free(void * address,size_t allocation_size) * size that still works. */ for(slab_index = 2, chunk_size = (1UL << slab_index) ; - slab_index < 31 ; + slab_index < (int)NUM_ENTRIES(__slab_data.sd_Slabs) ; slab_index++, chunk_size += chunk_size) { if(entry_size <= chunk_size) @@ -517,10 +522,12 @@ __slab_init(size_t slab_size) D(("activating slab allocator")); + memset(&__slab_data,0,sizeof(__slab_data)); + assert( size <= slab_size ); /* Start with an empty list of slabs for each chunk size. */ - for(i = 0 ; i < 31 ; i++) + for(i = 0 ; i < (int)NUM_ENTRIES(__slab_data.sd_Slabs) ; i++) NewList((struct List *)&__slab_data.sd_Slabs[i]); NewList((struct List *)&__slab_data.sd_SingleAllocations); @@ -536,48 +543,51 @@ __slab_init(size_t slab_size) void __slab_exit(void) { - struct SlabNode * sn; - struct SlabNode * sn_next; - struct MinNode * mn; - struct MinNode * mn_next; - int i; - ENTER(); - D(("freeing slabs")); - - /* Free the memory allocated for each slab. */ - for(i = 0 ; i < 31 ; i++) + if(__slab_data.sd_InUse) { - if(__slab_data.sd_Slabs[i].mlh_Head->mln_Succ != NULL) - D(("freeing slab #%ld (%lu bytes per chunk)", i, (1UL << i))); + struct SlabNode * sn; + struct SlabNode * sn_next; + struct MinNode * mn; + struct MinNode * mn_next; + int i; - for(sn = (struct SlabNode *)__slab_data.sd_Slabs[i].mlh_Head ; - sn->sn_MinNode.mln_Succ != NULL ; - sn = sn_next) + D(("freeing slabs")); + + /* Free the memory allocated for each slab. */ + for(i = 0 ; i < (int)NUM_ENTRIES(__slab_data.sd_Slabs) ; i++) { - sn_next = (struct SlabNode *)sn->sn_MinNode.mln_Succ; + if(__slab_data.sd_Slabs[i].mlh_Head->mln_Succ != NULL) + D(("freeing slab #%ld (%lu bytes per chunk)", i, (1UL << i))); - FreeVec(sn); + for(sn = (struct SlabNode *)__slab_data.sd_Slabs[i].mlh_Head ; + sn->sn_MinNode.mln_Succ != NULL ; + sn = sn_next) + { + sn_next = (struct SlabNode *)sn->sn_MinNode.mln_Succ; + + FreeVec(sn); + } } + + if(__slab_data.sd_SingleAllocations.mlh_Head->mln_Succ != NULL) + D(("freeing single allocations")); + + /* Free the memory allocated for each allocation which did not + * go into a slab. + */ + for(mn = __slab_data.sd_SingleAllocations.mlh_Head ; + mn->mln_Succ != NULL ; + mn = mn_next) + { + mn_next = mn->mln_Succ; + + FreeVec(mn); + } + + __slab_data.sd_InUse = FALSE; } - if(__slab_data.sd_SingleAllocations.mlh_Head->mln_Succ != NULL) - D(("freeing single allocations")); - - /* Free the memory allocated for each allocation which did not - * go into a slab. - */ - for(mn = __slab_data.sd_SingleAllocations.mlh_Head ; - mn->mln_Succ != NULL ; - mn = mn_next) - { - mn_next = mn->mln_Succ; - - FreeVec(mn); - } - - __slab_data.sd_InUse = FALSE; - LEAVE(); } diff --git a/library/stdlib_slab_max_size.c b/library/stdlib_slab_max_size.c index 16f01d5..8dae75d 100644 --- a/library/stdlib_slab_max_size.c +++ b/library/stdlib_slab_max_size.c @@ -35,4 +35,4 @@ /****************************************************************************/ -ULONG NOCOMMON __slab_max_size; +unsigned long __slab_max_size; diff --git a/library/unix.lib_rev.h b/library/unix.lib_rev.h index bb76990..0e8415d 100644 --- a/library/unix.lib_rev.h +++ b/library/unix.lib_rev.h @@ -1,6 +1,6 @@ #define VERSION 1 -#define REVISION 207 -#define DATE "18.11.2016" -#define VERS "unix.lib 1.207" -#define VSTRING "unix.lib 1.207 (18.11.2016)\r\n" -#define VERSTAG "\0$VER: unix.lib 1.207 (18.11.2016)" +#define REVISION 208 +#define DATE "19.11.2016" +#define VERS "unix.lib 1.208" +#define VSTRING "unix.lib 1.208 (19.11.2016)\r\n" +#define VERSTAG "\0$VER: unix.lib 1.208 (19.11.2016)" diff --git a/library/unix.lib_rev.rev b/library/unix.lib_rev.rev index c92ba56..7d645f5 100644 --- a/library/unix.lib_rev.rev +++ b/library/unix.lib_rev.rev @@ -1 +1 @@ -207 +208