mirror of
https://github.com/adtools/clib2.git
synced 2025-12-08 14:59:05 +00:00
Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 5617c0eacf | |||
| ac710b333e |
@ -334,6 +334,7 @@ C_LIB = \
|
|||||||
stdlib_get_errno.o \
|
stdlib_get_errno.o \
|
||||||
stdlib_get_slab_usage.o \
|
stdlib_get_slab_usage.o \
|
||||||
stdlib_get_slab_allocations.o \
|
stdlib_get_slab_allocations.o \
|
||||||
|
stdlib_get_slab_stats.o \
|
||||||
stdlib_isresident.o \
|
stdlib_isresident.o \
|
||||||
stdlib_labs.o \
|
stdlib_labs.o \
|
||||||
stdlib_llabs.o \
|
stdlib_llabs.o \
|
||||||
@ -373,6 +374,7 @@ C_LIB = \
|
|||||||
stdlib_showerror.o \
|
stdlib_showerror.o \
|
||||||
stdlib_slab.o \
|
stdlib_slab.o \
|
||||||
stdlib_slab_max_size.o \
|
stdlib_slab_max_size.o \
|
||||||
|
stdlib_slab_purge_threshold.o \
|
||||||
stdlib_srand.o \
|
stdlib_srand.o \
|
||||||
stdlib_stacksize.o \
|
stdlib_stacksize.o \
|
||||||
stdlib_stack_usage.o \
|
stdlib_stack_usage.o \
|
||||||
@ -1124,25 +1126,29 @@ $(LIBC_OBJS)/stdlib_getdefstacksize.o : stdlib_getdefstacksize.c stdlib_gcc_help
|
|||||||
|
|
||||||
$(LIBC_OBJS)/stdlib_shell_escape.o : stdlib_shell_escape.c stdlib_gcc_help.h
|
$(LIBC_OBJS)/stdlib_shell_escape.o : stdlib_shell_escape.c stdlib_gcc_help.h
|
||||||
|
|
||||||
$(LIBC_OBJS)/stdlib_alloca.o : stdlib_alloca.c stdlib_memory.h
|
$(LIBC_OBJS)/stdlib_alloca.o : stdlib_alloca.c stdlib_memory.h include/stdlib.h
|
||||||
|
|
||||||
$(LIBC_OBJS)/stdlib_calloc.o : stdlib_calloc.c stdlib_memory.h
|
$(LIBC_OBJS)/stdlib_calloc.o : stdlib_calloc.c stdlib_memory.h include/stdlib.h
|
||||||
|
|
||||||
$(LIBC_OBJS)/stdlib_free.o : stdlib_free.c stdlib_memory.h
|
$(LIBC_OBJS)/stdlib_free.o : stdlib_free.c stdlib_memory.h include/stdlib.h
|
||||||
|
|
||||||
$(LIBC_OBJS)/stdlib_malloc.o : stdlib_malloc.c stdlib_memory.h
|
$(LIBC_OBJS)/stdlib_malloc.o : stdlib_malloc.c stdlib_memory.h include/stdlib.h
|
||||||
|
|
||||||
$(LIBC_OBJS)/stdlib_slab.o : stdlib_slab.c stdlib_memory.h
|
$(LIBC_OBJS)/stdlib_slab.o : stdlib_slab.c stdlib_memory.h include/stdlib.h
|
||||||
|
|
||||||
$(LIBC_OBJS)/stdlib_free_unused_slabs.o : stdlib_free_unused_slabs.c stdlib_memory.h
|
$(LIBC_OBJS)/stdlib_slab_purge_threshold.o : stdlib_slab_purge_threshold.c stdlib_memory.h include/stdlib.h
|
||||||
|
|
||||||
$(LIBC_OBJS)/stdlib_get_slab_usage.o : stdlib_get_slab_usage.c stdlib_memory.h
|
$(LIBC_OBJS)/stdlib_get_slab_stats.o : stdlib_get_slab_stats.c stdlib_memory.h include/stdlib.h
|
||||||
|
|
||||||
$(LIBC_OBJS)/stdlib_get_slab_allocations.o : stdlib_get_slab_allocations.c stdlib_memory.h
|
$(LIBC_OBJS)/stdlib_free_unused_slabs.o : stdlib_free_unused_slabs.c stdlib_memory.h include/stdlib.h
|
||||||
|
|
||||||
$(LIBC_OBJS)/stdlib_realloc.o : stdlib_realloc.c stdlib_memory.h
|
$(LIBC_OBJS)/stdlib_get_slab_usage.o : stdlib_get_slab_usage.c stdlib_memory.h include/stdlib.h
|
||||||
|
|
||||||
$(LIBC_OBJS)/stdlib_red_black.o : stdlib_red_black.c stdlib_memory.h
|
$(LIBC_OBJS)/stdlib_get_slab_allocations.o : stdlib_get_slab_allocations.c stdlib_memory.h include/stdlib.h
|
||||||
|
|
||||||
|
$(LIBC_OBJS)/stdlib_realloc.o : stdlib_realloc.c stdlib_memory.h include/stdlib.h
|
||||||
|
|
||||||
|
$(LIBC_OBJS)/stdlib_red_black.o : stdlib_red_black.c stdlib_memory.h include/stdlib.h
|
||||||
|
|
||||||
##############################################################################
|
##############################################################################
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
#define VERSION 1
|
#define VERSION 1
|
||||||
#define REVISION 211
|
#define REVISION 212
|
||||||
#define DATE "23.11.2016"
|
#define DATE "27.11.2016"
|
||||||
#define VERS "amiga.lib 1.211"
|
#define VERS "amiga.lib 1.212"
|
||||||
#define VSTRING "amiga.lib 1.211 (23.11.2016)\r\n"
|
#define VSTRING "amiga.lib 1.212 (27.11.2016)\r\n"
|
||||||
#define VERSTAG "\0$VER: amiga.lib 1.211 (23.11.2016)"
|
#define VERSTAG "\0$VER: amiga.lib 1.212 (27.11.2016)"
|
||||||
|
|||||||
@ -1 +1 @@
|
|||||||
211
|
212
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
#define VERSION 1
|
#define VERSION 1
|
||||||
#define REVISION 211
|
#define REVISION 212
|
||||||
#define DATE "23.11.2016"
|
#define DATE "27.11.2016"
|
||||||
#define VERS "c.lib 1.211"
|
#define VERS "c.lib 1.212"
|
||||||
#define VSTRING "c.lib 1.211 (23.11.2016)\r\n"
|
#define VSTRING "c.lib 1.212 (27.11.2016)\r\n"
|
||||||
#define VERSTAG "\0$VER: c.lib 1.211 (23.11.2016)"
|
#define VERSTAG "\0$VER: c.lib 1.212 (27.11.2016)"
|
||||||
|
|||||||
@ -1 +1 @@
|
|||||||
211
|
212
|
||||||
|
|||||||
@ -1,3 +1,15 @@
|
|||||||
|
c.lib 1.212 (27.11.2016)
|
||||||
|
|
||||||
|
- Unused slabs which get recycled are no longer reinitialized from
|
||||||
|
scratch if their chunk size matches what the allocator needed.
|
||||||
|
If the chunk size matches, the list of available chunks is
|
||||||
|
left unchanged, and just the various counters are reset.
|
||||||
|
|
||||||
|
- Added __get_slab_stats() function.
|
||||||
|
|
||||||
|
- Added support for global __slab_purge_threshold tuning variable.
|
||||||
|
|
||||||
|
|
||||||
c.lib 1.211 (23.11.2016)
|
c.lib 1.211 (23.11.2016)
|
||||||
|
|
||||||
- Added more consistency checking to the slab allocator, which is
|
- Added more consistency checking to the slab allocator, which is
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
#define VERSION 1
|
#define VERSION 1
|
||||||
#define REVISION 211
|
#define REVISION 212
|
||||||
#define DATE "23.11.2016"
|
#define DATE "27.11.2016"
|
||||||
#define VERS "debug.lib 1.211"
|
#define VERS "debug.lib 1.212"
|
||||||
#define VSTRING "debug.lib 1.211 (23.11.2016)\r\n"
|
#define VSTRING "debug.lib 1.212 (27.11.2016)\r\n"
|
||||||
#define VERSTAG "\0$VER: debug.lib 1.211 (23.11.2016)"
|
#define VERSTAG "\0$VER: debug.lib 1.212 (27.11.2016)"
|
||||||
|
|||||||
@ -1 +1 @@
|
|||||||
211
|
212
|
||||||
|
|||||||
@ -173,6 +173,19 @@ extern int rand_r(unsigned int * seed);
|
|||||||
|
|
||||||
extern unsigned long __slab_max_size;
|
extern unsigned long __slab_max_size;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The slab allocator will periodically free all currently unused memory.
|
||||||
|
* You can control how much memory should be released, instead of
|
||||||
|
* releasing everything.
|
||||||
|
*
|
||||||
|
* This would make the slab allocator release only up to 512 KBytes of
|
||||||
|
* unused memory at a time:
|
||||||
|
*
|
||||||
|
* unsigned long __slab_purge_threshold = 512 * 1024;
|
||||||
|
*/
|
||||||
|
|
||||||
|
extern unsigned long __slab_purge_threshold;
|
||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -250,6 +263,11 @@ struct __slab_usage_information
|
|||||||
|
|
||||||
/* How many memory chunks in this slab are being used? */
|
/* How many memory chunks in this slab are being used? */
|
||||||
size_t sui_num_chunks_used;
|
size_t sui_num_chunks_used;
|
||||||
|
|
||||||
|
/* How many time was this slab reused without reinitializing
|
||||||
|
* it all over again from scratch?
|
||||||
|
*/
|
||||||
|
size_t sui_num_reused;
|
||||||
};
|
};
|
||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
@ -324,6 +342,31 @@ void __get_slab_allocations(__slab_allocation_callback callback);
|
|||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* You can obtain information about the memory managed by the slab allocator,
|
||||||
|
* as well as additional information about the slab allocator's performance
|
||||||
|
* in JSON format. This format can be used for more detailed analysis.
|
||||||
|
*
|
||||||
|
* You supply a function which will be called for each line of the JSON
|
||||||
|
* data produced. You can store this data in a file, or in the clipboard,
|
||||||
|
* for later use. Your function must return 0 if it wants to be called
|
||||||
|
* again, or return -1 if it wants to stop (e.g. if an error occured
|
||||||
|
* when writing the JSON data to disk). The same "user_data" pointer which
|
||||||
|
* you pass to __get_slab_stats() will be passed to your callback function.
|
||||||
|
*
|
||||||
|
* Please note that this function works within the context of the memory
|
||||||
|
* allocation system and is not safe to call from interrupt code. It may
|
||||||
|
* break a Forbid() or Disable() condition.
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef int (* __slab_status_callback)(void * user_data, const char * line, size_t line_length);
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
extern void __get_slab_stats(void * user_data, __slab_status_callback callback);
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* You can request to use the alloca() variant that actually does allocate
|
* You can request to use the alloca() variant that actually does allocate
|
||||||
* memory from the system rather than the current stack frame, which will
|
* memory from the system rather than the current stack frame, which will
|
||||||
|
|||||||
@ -220,6 +220,7 @@ C_LIB := \
|
|||||||
stdlib_get_errno.o \
|
stdlib_get_errno.o \
|
||||||
stdlib_get_slab_usage.o \
|
stdlib_get_slab_usage.o \
|
||||||
stdlib_get_slab_allocations.o \
|
stdlib_get_slab_allocations.o \
|
||||||
|
stdlib_get_slab_stats.o \
|
||||||
stdlib_isresident.o \
|
stdlib_isresident.o \
|
||||||
stdlib_labs.o \
|
stdlib_labs.o \
|
||||||
stdlib_llabs.o \
|
stdlib_llabs.o \
|
||||||
@ -260,6 +261,7 @@ C_LIB := \
|
|||||||
stdlib_showerror.o \
|
stdlib_showerror.o \
|
||||||
stdlib_slab.o \
|
stdlib_slab.o \
|
||||||
stdlib_slab_max_size.o \
|
stdlib_slab_max_size.o \
|
||||||
|
stdlib_slab_purge_threshold.o \
|
||||||
stdlib_srand.o \
|
stdlib_srand.o \
|
||||||
stdlib_stacksize.o \
|
stdlib_stacksize.o \
|
||||||
stdlib_stack_usage.o \
|
stdlib_stack_usage.o \
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
#define VERSION 1
|
#define VERSION 1
|
||||||
#define REVISION 211
|
#define REVISION 212
|
||||||
#define DATE "23.11.2016"
|
#define DATE "27.11.2016"
|
||||||
#define VERS "m.lib 1.211"
|
#define VERS "m.lib 1.212"
|
||||||
#define VSTRING "m.lib 1.211 (23.11.2016)\r\n"
|
#define VSTRING "m.lib 1.212 (27.11.2016)\r\n"
|
||||||
#define VERSTAG "\0$VER: m.lib 1.211 (23.11.2016)"
|
#define VERSTAG "\0$VER: m.lib 1.212 (27.11.2016)"
|
||||||
|
|||||||
@ -1 +1 @@
|
|||||||
211
|
212
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
#define VERSION 1
|
#define VERSION 1
|
||||||
#define REVISION 211
|
#define REVISION 212
|
||||||
#define DATE "23.11.2016"
|
#define DATE "27.11.2016"
|
||||||
#define VERS "m881.lib 1.211"
|
#define VERS "m881.lib 1.212"
|
||||||
#define VSTRING "m881.lib 1.211 (23.11.2016)\r\n"
|
#define VSTRING "m881.lib 1.212 (27.11.2016)\r\n"
|
||||||
#define VERSTAG "\0$VER: m881.lib 1.211 (23.11.2016)"
|
#define VERSTAG "\0$VER: m881.lib 1.212 (27.11.2016)"
|
||||||
|
|||||||
@ -1 +1 @@
|
|||||||
211
|
212
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
#define VERSION 1
|
#define VERSION 1
|
||||||
#define REVISION 211
|
#define REVISION 212
|
||||||
#define DATE "23.11.2016"
|
#define DATE "27.11.2016"
|
||||||
#define VERS "net.lib 1.211"
|
#define VERS "net.lib 1.212"
|
||||||
#define VSTRING "net.lib 1.211 (23.11.2016)\r\n"
|
#define VSTRING "net.lib 1.212 (27.11.2016)\r\n"
|
||||||
#define VERSTAG "\0$VER: net.lib 1.211 (23.11.2016)"
|
#define VERSTAG "\0$VER: net.lib 1.212 (27.11.2016)"
|
||||||
|
|||||||
@ -1 +1 @@
|
|||||||
211
|
212
|
||||||
|
|||||||
@ -521,6 +521,7 @@ STDLIB_OBJ = \
|
|||||||
stdlib_get_errno.o \
|
stdlib_get_errno.o \
|
||||||
stdlib_get_slab_usage.o \
|
stdlib_get_slab_usage.o \
|
||||||
stdlib_get_slab_allocations.o \
|
stdlib_get_slab_allocations.o \
|
||||||
|
stdlib_get_slab_stats.o \
|
||||||
stdlib_isresident.o \
|
stdlib_isresident.o \
|
||||||
stdlib_labs.o \
|
stdlib_labs.o \
|
||||||
stdlib_ldiv.o \
|
stdlib_ldiv.o \
|
||||||
@ -552,6 +553,7 @@ STDLIB_OBJ = \
|
|||||||
stdlib_showerror.o \
|
stdlib_showerror.o \
|
||||||
stdlib_slab.o \
|
stdlib_slab.o \
|
||||||
stdlib_slab_max_size.o \
|
stdlib_slab_max_size.o \
|
||||||
|
stdlib_slab_purge_threshold.o \
|
||||||
stdlib_srand.o \
|
stdlib_srand.o \
|
||||||
stdlib_arg.o \
|
stdlib_arg.o \
|
||||||
stdlib_stack_usage.o \
|
stdlib_stack_usage.o \
|
||||||
@ -804,6 +806,10 @@ stdlib_slab.o : stdlib_slab.c stdlib_memory.h
|
|||||||
|
|
||||||
stdlib_free_unused_slabs.o : stdlib_free_unused_slabs.c stdlib_memory.h
|
stdlib_free_unused_slabs.o : stdlib_free_unused_slabs.c stdlib_memory.h
|
||||||
|
|
||||||
|
stdlib_slab_max_size.o : stdlib_slab_max_size.c stdlib_memory.h
|
||||||
|
|
||||||
|
stdlib_slab_purge_threshold.o : stdlib_slab_purge_threshold.o stdlib_memory.h
|
||||||
|
|
||||||
stdlib_get_slab_usage.o : stdlib_get_slab_usage.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_realloc.o : stdlib_realloc.c stdlib_memory.h
|
||||||
|
|||||||
200
library/stdlib_get_slab_stats.c
Normal file
200
library/stdlib_get_slab_stats.c
Normal file
@ -0,0 +1,200 @@
|
|||||||
|
/*
|
||||||
|
* :ts=4
|
||||||
|
*
|
||||||
|
* Portable ISO 'C' (1994) runtime library for the Amiga computer
|
||||||
|
* Copyright (c) 2002-2015 by Olaf Barthel <obarthel (at) gmx.net>
|
||||||
|
* 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 */
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
struct context
|
||||||
|
{
|
||||||
|
int status;
|
||||||
|
void * user_data;
|
||||||
|
__slab_status_callback callback;
|
||||||
|
char * buffer;
|
||||||
|
size_t buffer_size;
|
||||||
|
};
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
static void print(struct context * ct, const char * format, ...)
|
||||||
|
{
|
||||||
|
if(ct->status == 0)
|
||||||
|
{
|
||||||
|
va_list args;
|
||||||
|
int len;
|
||||||
|
|
||||||
|
va_start(args,format);
|
||||||
|
len = vsnprintf(ct->buffer, ct->buffer_size, format, args);
|
||||||
|
va_end(args);
|
||||||
|
|
||||||
|
/* This shouldn't happen: the buffer ought to be large enough
|
||||||
|
* to hold every single line.
|
||||||
|
*/
|
||||||
|
if(len >= (int)ct->buffer_size)
|
||||||
|
len = strlen(ct->buffer);
|
||||||
|
|
||||||
|
ct->status = (*ct->callback)(ct->user_data, ct->buffer, len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
void
|
||||||
|
__get_slab_stats(void * user_data, __slab_status_callback callback)
|
||||||
|
{
|
||||||
|
if(__slab_data.sd_InUse)
|
||||||
|
{
|
||||||
|
static int times_checked = 1;
|
||||||
|
|
||||||
|
const struct SlabNode * sn;
|
||||||
|
size_t num_empty_slabs = 0;
|
||||||
|
size_t num_full_slabs = 0;
|
||||||
|
size_t num_slabs = 0;
|
||||||
|
size_t slab_allocation_size = 0;
|
||||||
|
size_t total_slab_allocation_size = 0;
|
||||||
|
struct context ct;
|
||||||
|
char line[1024];
|
||||||
|
char time_buffer[40];
|
||||||
|
time_t now;
|
||||||
|
struct tm when;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
memset(&ct, 0, sizeof(ct));
|
||||||
|
|
||||||
|
ct.user_data = user_data;
|
||||||
|
ct.callback = callback;
|
||||||
|
ct.buffer = line;
|
||||||
|
ct.buffer_size = sizeof(line);
|
||||||
|
|
||||||
|
__memory_lock();
|
||||||
|
|
||||||
|
now = time(NULL);
|
||||||
|
localtime_r(&now, &when);
|
||||||
|
|
||||||
|
strftime(time_buffer, sizeof(time_buffer), "%Y-%m-%dT%H:%M:%S", &when);
|
||||||
|
|
||||||
|
print(&ct,"{\n");
|
||||||
|
|
||||||
|
print(&ct,"\t\"when\": \"%s\",\n", time_buffer);
|
||||||
|
print(&ct,"\t\"times_checked\": %d,\n", times_checked++);
|
||||||
|
print(&ct,"\t\"slab_size\": %zu,\n", __slab_data.sd_StandardSlabSize);
|
||||||
|
print(&ct,"\t\"num_single_allocations\": %zu,\n", __slab_data.sd_NumSingleAllocations);
|
||||||
|
print(&ct,"\t\"total_single_allocation_size\": %zu,\n", __slab_data.sd_TotalSingleAllocationSize);
|
||||||
|
|
||||||
|
if(__slab_data.sd_SingleAllocations.mlh_Head->mln_Succ != NULL)
|
||||||
|
{
|
||||||
|
const struct SlabSingleAllocation * ssa;
|
||||||
|
|
||||||
|
print(&ct,"\t\"single_allocations\": [\n");
|
||||||
|
|
||||||
|
for(ssa = (struct SlabSingleAllocation *)__slab_data.sd_SingleAllocations.mlh_Head ;
|
||||||
|
ssa->ssa_MinNode.mln_Succ != NULL && ct.status == 0 ;
|
||||||
|
ssa = (struct SlabSingleAllocation *)ssa->ssa_MinNode.mln_Succ)
|
||||||
|
{
|
||||||
|
print(&ct,"\t\t{ \"size\": %lu, \"total_size\": %lu }%s\n",
|
||||||
|
ssa->ssa_Size - sizeof(*ssa), ssa->ssa_Size,
|
||||||
|
ssa->ssa_MinNode.mln_Succ->mln_Succ != NULL ? "," : "");
|
||||||
|
}
|
||||||
|
|
||||||
|
print(&ct,"\t],\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
print(&ct,"\t\"single_allocations\": [],\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
num_empty_slabs++;
|
||||||
|
else if (sn->sn_UseCount == sn->sn_Count)
|
||||||
|
num_full_slabs++;
|
||||||
|
|
||||||
|
num_slabs++;
|
||||||
|
|
||||||
|
slab_allocation_size += sn->sn_ChunkSize * sn->sn_UseCount;
|
||||||
|
total_slab_allocation_size += sizeof(*sn) + __slab_data.sd_StandardSlabSize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
print(&ct,"\t\"num_slabs\": %zu,\n", num_slabs);
|
||||||
|
print(&ct,"\t\"num_empty_slabs\": %zu,\n", num_empty_slabs);
|
||||||
|
print(&ct,"\t\"num_full_slabs\": %zu,\n", num_full_slabs);
|
||||||
|
print(&ct,"\t\"slab_allocation_size\": %zu,\n", slab_allocation_size);
|
||||||
|
print(&ct,"\t\"total_slab_allocation_size\": %zu,\n", total_slab_allocation_size);
|
||||||
|
|
||||||
|
if(num_slabs > 0)
|
||||||
|
{
|
||||||
|
const char * eol = "";
|
||||||
|
|
||||||
|
print(&ct,"\t\"slabs\": [\n");
|
||||||
|
|
||||||
|
for(i = 0 ; i < (int)NUM_ENTRIES(__slab_data.sd_Slabs) && ct.status == 0 ; i++)
|
||||||
|
{
|
||||||
|
for(sn = (struct SlabNode *)__slab_data.sd_Slabs[i].mlh_Head ;
|
||||||
|
sn->sn_MinNode.mln_Succ != NULL && ct.status == 0 ;
|
||||||
|
sn = (struct SlabNode *)sn->sn_MinNode.mln_Succ)
|
||||||
|
{
|
||||||
|
print(&ct,"%s\t\t{ \"size\": %lu, \"chunks\": %lu, \"chunks_in_use\": %lu, \"times_reused\": %lu }",
|
||||||
|
eol,
|
||||||
|
sn->sn_ChunkSize,
|
||||||
|
sn->sn_Count,
|
||||||
|
sn->sn_UseCount,
|
||||||
|
sn->sn_NumReused);
|
||||||
|
|
||||||
|
eol = ",\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
print(&ct,"\n\t]\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
print(&ct,"\t\"slabs\": []\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
print(&ct,"}\n");
|
||||||
|
|
||||||
|
__memory_unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -87,6 +87,7 @@ __get_slab_usage(__slab_usage_callback callback)
|
|||||||
sui.sui_chunk_size = sn->sn_ChunkSize;
|
sui.sui_chunk_size = sn->sn_ChunkSize;
|
||||||
sui.sui_num_chunks = sn->sn_Count;
|
sui.sui_num_chunks = sn->sn_Count;
|
||||||
sui.sui_num_chunks_used = sn->sn_UseCount;
|
sui.sui_num_chunks_used = sn->sn_UseCount;
|
||||||
|
sui.sui_num_reused = sn->sn_NumReused;
|
||||||
|
|
||||||
sui.sui_slab_index++;
|
sui.sui_slab_index++;
|
||||||
|
|
||||||
|
|||||||
@ -503,7 +503,7 @@ STDLIB_CONSTRUCTOR(stdlib_memory_init)
|
|||||||
#if defined(__USE_SLAB_ALLOCATOR)
|
#if defined(__USE_SLAB_ALLOCATOR)
|
||||||
{
|
{
|
||||||
/* ZZZ this is just for the purpose of testing */
|
/* ZZZ this is just for the purpose of testing */
|
||||||
#if 0
|
#if 1
|
||||||
{
|
{
|
||||||
TEXT slab_size_var[20];
|
TEXT slab_size_var[20];
|
||||||
|
|
||||||
|
|||||||
@ -235,6 +235,11 @@ struct SlabNode
|
|||||||
/* How many chunks of this slab are currently in use? */
|
/* How many chunks of this slab are currently in use? */
|
||||||
ULONG sn_UseCount;
|
ULONG sn_UseCount;
|
||||||
|
|
||||||
|
/* How many times was this slab reused instead of allocating
|
||||||
|
* it from system memory?
|
||||||
|
*/
|
||||||
|
ULONG sn_NumReused;
|
||||||
|
|
||||||
/* This contains all the chunks of memory which are available
|
/* This contains all the chunks of memory which are available
|
||||||
* for allocation.
|
* for allocation.
|
||||||
*/
|
*/
|
||||||
@ -286,7 +291,7 @@ struct SlabData
|
|||||||
*/
|
*/
|
||||||
size_t sd_StandardSlabSize;
|
size_t sd_StandardSlabSize;
|
||||||
|
|
||||||
/* These fields kees track of how many entries there are in
|
/* These fields keep track of how many entries there are in
|
||||||
* the sd_SingleAllocations list, and how much memory these
|
* the sd_SingleAllocations list, and how much memory these
|
||||||
* allocations occupy.
|
* allocations occupy.
|
||||||
*/
|
*/
|
||||||
@ -303,6 +308,7 @@ struct SlabData
|
|||||||
|
|
||||||
extern struct SlabData NOCOMMON __slab_data;
|
extern struct SlabData NOCOMMON __slab_data;
|
||||||
extern unsigned long NOCOMMON __slab_max_size;
|
extern unsigned long NOCOMMON __slab_max_size;
|
||||||
|
extern unsigned long NOCOMMON __slab_purge_threshold;
|
||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
|
|
||||||
|
|||||||
@ -31,6 +31,8 @@
|
|||||||
* POSSIBILITY OF SUCH DAMAGE.
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/*#define DEBUG*/
|
||||||
|
|
||||||
#ifndef _STDLIB_HEADERS_H
|
#ifndef _STDLIB_HEADERS_H
|
||||||
#include "stdlib_headers.h"
|
#include "stdlib_headers.h"
|
||||||
#endif /* _STDLIB_HEADERS_H */
|
#endif /* _STDLIB_HEADERS_H */
|
||||||
@ -76,6 +78,7 @@ __realloc(void *ptr,size_t size,const char * file,int line)
|
|||||||
#endif /* UNIX_PATH_SEMANTICS */
|
#endif /* UNIX_PATH_SEMANTICS */
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
size_t old_size;
|
||||||
struct MemoryNode * mn;
|
struct MemoryNode * mn;
|
||||||
BOOL reallocate;
|
BOOL reallocate;
|
||||||
|
|
||||||
@ -108,29 +111,23 @@ __realloc(void *ptr,size_t size,const char * file,int line)
|
|||||||
}
|
}
|
||||||
#endif /* __MEM_DEBUG */
|
#endif /* __MEM_DEBUG */
|
||||||
|
|
||||||
if(mn == NULL || mn->mn_NeverFree)
|
if(mn == NULL || FLAG_IS_SET(mn->mn_Size, MN_SIZE_NEVERFREE))
|
||||||
{
|
{
|
||||||
SHOWMSG("cannot free this chunk");
|
SHOWMSG("cannot free this chunk");
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
old_size = GET_MN_SIZE(mn);
|
||||||
|
|
||||||
/* Don't do anything unless the size of the allocation
|
/* Don't do anything unless the size of the allocation
|
||||||
has really changed. */
|
has really changed. */
|
||||||
#if defined(__MEM_DEBUG)
|
#if defined(__MEM_DEBUG)
|
||||||
{
|
{
|
||||||
reallocate = (mn->mn_Size != size);
|
reallocate = (old_size != size);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
{
|
{
|
||||||
size_t rounded_allocation_size;
|
if(size > old_size)
|
||||||
|
|
||||||
/* Round the total allocation size to the operating system
|
|
||||||
granularity. */
|
|
||||||
rounded_allocation_size = __get_allocation_size(size);
|
|
||||||
|
|
||||||
assert( rounded_allocation_size >= size );
|
|
||||||
|
|
||||||
if(rounded_allocation_size > mn->mn_Size)
|
|
||||||
{
|
{
|
||||||
/* Allocation size should grow. */
|
/* Allocation size should grow. */
|
||||||
reallocate = TRUE;
|
reallocate = TRUE;
|
||||||
@ -143,7 +140,7 @@ __realloc(void *ptr,size_t size,const char * file,int line)
|
|||||||
allocation. We also take into account that the
|
allocation. We also take into account that the
|
||||||
actual size of the allocation is affected by a
|
actual size of the allocation is affected by a
|
||||||
certain operating system imposed granularity. */
|
certain operating system imposed granularity. */
|
||||||
reallocate = (rounded_allocation_size < mn->mn_Size && rounded_allocation_size <= mn->mn_Size / 2);
|
reallocate = (size < old_size && size <= old_size / 2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif /* __MEM_DEBUG */
|
#endif /* __MEM_DEBUG */
|
||||||
@ -152,7 +149,7 @@ __realloc(void *ptr,size_t size,const char * file,int line)
|
|||||||
{
|
{
|
||||||
void * new_ptr;
|
void * new_ptr;
|
||||||
|
|
||||||
D(("realloc() size has changed; old=%ld, new=%ld",mn->mn_Size,size));
|
D(("realloc() size has changed; old=%ld, new=%ld",old_size,size));
|
||||||
|
|
||||||
/* We allocate the new memory chunk before we
|
/* We allocate the new memory chunk before we
|
||||||
attempt to replace the old. */
|
attempt to replace the old. */
|
||||||
@ -164,8 +161,8 @@ __realloc(void *ptr,size_t size,const char * file,int line)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Copy the contents of the old allocation to the new buffer. */
|
/* Copy the contents of the old allocation to the new buffer. */
|
||||||
if(size > mn->mn_Size)
|
if(size > old_size)
|
||||||
size = mn->mn_Size;
|
size = old_size;
|
||||||
|
|
||||||
memmove(new_ptr,ptr,size);
|
memmove(new_ptr,ptr,size);
|
||||||
|
|
||||||
@ -177,7 +174,7 @@ __realloc(void *ptr,size_t size,const char * file,int line)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
D(("size didn't actually change that much (%ld -> %ld); returning memory block as is.",mn->mn_Size,size));
|
D(("size didn't actually change that much (%ld -> %ld); returning memory block as is.",old_size,size));
|
||||||
|
|
||||||
/* No change in size. */
|
/* No change in size. */
|
||||||
result = ptr;
|
result = ptr;
|
||||||
|
|||||||
@ -125,6 +125,7 @@ __slab_allocate(size_t allocation_size)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
struct MinList * slab_list = NULL;
|
struct MinList * slab_list = NULL;
|
||||||
|
BOOL slab_reused = FALSE;
|
||||||
ULONG entry_size;
|
ULONG entry_size;
|
||||||
ULONG chunk_size;
|
ULONG chunk_size;
|
||||||
int slab_index;
|
int slab_index;
|
||||||
@ -252,11 +253,22 @@ __slab_allocate(size_t allocation_size)
|
|||||||
/* Unlink from list of empty slabs. */
|
/* Unlink from list of empty slabs. */
|
||||||
Remove((struct Node *)free_node);
|
Remove((struct Node *)free_node);
|
||||||
|
|
||||||
/* Unlink from list of slabs which keep chunks
|
/* If the chunk size of the reused slab matches
|
||||||
* of the same size. It will be added there
|
* exactly what we need then we won't have to
|
||||||
* again, at a different position.
|
* completely reinitialize it again.
|
||||||
*/
|
*/
|
||||||
Remove((struct Node *)sn);
|
if(sn->sn_ChunkSize == chunk_size)
|
||||||
|
{
|
||||||
|
slab_reused = TRUE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Unlink from list of slabs which keep chunks
|
||||||
|
* of the same size. It will be added there
|
||||||
|
* again, at a different position.
|
||||||
|
*/
|
||||||
|
Remove((struct Node *)sn);
|
||||||
|
}
|
||||||
|
|
||||||
D(("reusing a slab"));
|
D(("reusing a slab"));
|
||||||
|
|
||||||
@ -295,59 +307,75 @@ __slab_allocate(size_t allocation_size)
|
|||||||
|
|
||||||
if(new_sn != NULL)
|
if(new_sn != NULL)
|
||||||
{
|
{
|
||||||
struct MinNode * free_chunk;
|
|
||||||
ULONG num_free_chunks = 0;
|
|
||||||
BYTE * first_byte;
|
|
||||||
BYTE * last_byte;
|
|
||||||
|
|
||||||
D(("setting up slab 0x%08lx", new_sn));
|
D(("setting up slab 0x%08lx", new_sn));
|
||||||
|
|
||||||
assert( chunk_size <= __slab_data.sd_StandardSlabSize );
|
assert( chunk_size <= __slab_data.sd_StandardSlabSize );
|
||||||
|
|
||||||
memset(new_sn,0,sizeof(*new_sn));
|
/* Do we have to completely initialize this slab from scratch? */
|
||||||
|
if(NOT slab_reused)
|
||||||
NewList((struct List *)&new_sn->sn_FreeList);
|
|
||||||
|
|
||||||
/* Split up the slab memory into individual chunks
|
|
||||||
* of the same size and keep track of them
|
|
||||||
* in the free list. The memory managed by
|
|
||||||
* this slab immediately follows the
|
|
||||||
* SlabNode header.
|
|
||||||
*/
|
|
||||||
first_byte = (BYTE *)&new_sn[1];
|
|
||||||
last_byte = &first_byte[__slab_data.sd_StandardSlabSize - chunk_size];
|
|
||||||
|
|
||||||
for(free_chunk = (struct MinNode *)first_byte ;
|
|
||||||
free_chunk <= (struct MinNode *)last_byte;
|
|
||||||
free_chunk = (struct MinNode *)(((BYTE *)free_chunk) + chunk_size))
|
|
||||||
{
|
{
|
||||||
AddTail((struct List *)&new_sn->sn_FreeList, (struct Node *)free_chunk);
|
struct SlabChunk * free_chunk;
|
||||||
num_free_chunks++;
|
ULONG num_free_chunks = 0;
|
||||||
}
|
BYTE * first_byte;
|
||||||
|
BYTE * last_byte;
|
||||||
|
|
||||||
D(("slab contains %lu chunks, %lu bytes each",num_free_chunks,chunk_size));
|
memset(new_sn,0,sizeof(*new_sn));
|
||||||
|
|
||||||
|
NewList((struct List *)&new_sn->sn_FreeList);
|
||||||
|
|
||||||
|
/* This slab has room for new allocations, so make sure that
|
||||||
|
* it goes to the front of the slab list. It will be used
|
||||||
|
* by the next allocation request of this size.
|
||||||
|
*/
|
||||||
|
AddHead((struct List *)slab_list,(struct Node *)new_sn);
|
||||||
|
|
||||||
|
/* Split up the slab memory into individual chunks
|
||||||
|
* of the same size and keep track of them
|
||||||
|
* in the free list. The memory managed by
|
||||||
|
* this slab immediately follows the
|
||||||
|
* SlabNode header.
|
||||||
|
*/
|
||||||
|
first_byte = (BYTE *)&new_sn[1];
|
||||||
|
last_byte = &first_byte[__slab_data.sd_StandardSlabSize - chunk_size];
|
||||||
|
|
||||||
|
for(free_chunk = (struct SlabChunk *)first_byte ;
|
||||||
|
free_chunk <= (struct SlabChunk *)last_byte;
|
||||||
|
free_chunk = (struct SlabChunk *)(((BYTE *)free_chunk) + chunk_size))
|
||||||
|
{
|
||||||
|
AddTail((struct List *)&new_sn->sn_FreeList, (struct Node *)free_chunk);
|
||||||
|
num_free_chunks++;
|
||||||
|
}
|
||||||
|
|
||||||
|
new_sn->sn_Count = num_free_chunks;
|
||||||
|
new_sn->sn_ChunkSize = chunk_size;
|
||||||
|
|
||||||
|
D(("new slab contains %lu chunks, %lu bytes each",num_free_chunks,chunk_size));
|
||||||
|
}
|
||||||
|
/* This slab was reused and need not be reinitialized from scratch. */
|
||||||
|
else
|
||||||
|
{
|
||||||
|
new_sn->sn_NumReused++;
|
||||||
|
|
||||||
|
assert( new_sn->sn_FreeList.mlh_Head != NULL );
|
||||||
|
assert( new_sn->sn_ChunkSize == chunk_size );
|
||||||
|
assert( new_sn->sn_Count == 0 );
|
||||||
|
}
|
||||||
|
|
||||||
/* Grab the first free chunk (there has to be one). */
|
/* Grab the first free chunk (there has to be one). */
|
||||||
chunk = (struct SlabChunk *)RemHead((struct List *)&new_sn->sn_FreeList);
|
chunk = (struct SlabChunk *)RemHead((struct List *)&new_sn->sn_FreeList);
|
||||||
|
|
||||||
assert( chunk != NULL );
|
|
||||||
|
|
||||||
/* Keep track of this chunk's parent slab. */
|
/* Keep track of this chunk's parent slab. */
|
||||||
chunk->sc_Parent = new_sn;
|
chunk->sc_Parent = new_sn;
|
||||||
|
|
||||||
|
assert( chunk != NULL );
|
||||||
|
assert( chunk->sc_Parent == new_sn );
|
||||||
|
|
||||||
allocation = &chunk[1];
|
allocation = &chunk[1];
|
||||||
|
|
||||||
D(("allocation succeeded at 0x%08lx in slab 0x%08lx (slab use count = %lu)",allocation,new_sn,new_sn->sn_UseCount+1));
|
/* This slab is now in use. */
|
||||||
|
new_sn->sn_UseCount = 1;
|
||||||
|
|
||||||
/* Set up the new slab and put it where it belongs. */
|
D(("allocation succeeded at 0x%08lx in slab 0x%08lx (slab use count = %lu)",allocation,new_sn,new_sn->sn_UseCount));
|
||||||
new_sn->sn_EmptyDecay = 0;
|
|
||||||
new_sn->sn_UseCount = 1;
|
|
||||||
new_sn->sn_Count = num_free_chunks;
|
|
||||||
new_sn->sn_ChunkSize = chunk_size;
|
|
||||||
|
|
||||||
SHOWVALUE(new_sn->sn_ChunkSize);
|
|
||||||
|
|
||||||
AddHead((struct List *)slab_list,(struct Node *)new_sn);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Mark unused slabs for purging, and purge those which
|
/* Mark unused slabs for purging, and purge those which
|
||||||
@ -355,6 +383,8 @@ __slab_allocate(size_t allocation_size)
|
|||||||
*/
|
*/
|
||||||
if(purge)
|
if(purge)
|
||||||
{
|
{
|
||||||
|
size_t total_purged = 0;
|
||||||
|
|
||||||
D(("purging empty slabs"));
|
D(("purging empty slabs"));
|
||||||
|
|
||||||
for(free_node = (struct MinNode *)__slab_data.sd_EmptySlabs.mlh_Head ;
|
for(free_node = (struct MinNode *)__slab_data.sd_EmptySlabs.mlh_Head ;
|
||||||
@ -380,6 +410,15 @@ __slab_allocate(size_t allocation_size)
|
|||||||
Remove((struct Node *)sn);
|
Remove((struct Node *)sn);
|
||||||
|
|
||||||
FreeVec(sn);
|
FreeVec(sn);
|
||||||
|
|
||||||
|
total_purged += sizeof(*sn) + __slab_data.sd_StandardSlabSize;
|
||||||
|
|
||||||
|
/* Stop releasing memory if we reach the threshold. If no
|
||||||
|
* threshold has been set, we will free as much memory
|
||||||
|
* as possible.
|
||||||
|
*/
|
||||||
|
if(__slab_purge_threshold > 0 && total_purged >= __slab_purge_threshold)
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
/* Give it another chance. */
|
/* Give it another chance. */
|
||||||
else
|
else
|
||||||
@ -700,6 +739,21 @@ __slab_init(size_t slab_size)
|
|||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
|
||||||
|
static int print_json(void * ignore,const char * buffer,size_t len)
|
||||||
|
{
|
||||||
|
extern void kputs(const char * str);
|
||||||
|
|
||||||
|
kputs(buffer);
|
||||||
|
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* DEBUG */
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
void
|
void
|
||||||
__slab_exit(void)
|
__slab_exit(void)
|
||||||
{
|
{
|
||||||
@ -712,7 +766,19 @@ __slab_exit(void)
|
|||||||
struct SlabNode * sn_next;
|
struct SlabNode * sn_next;
|
||||||
struct MinNode * mn;
|
struct MinNode * mn;
|
||||||
struct MinNode * mn_next;
|
struct MinNode * mn_next;
|
||||||
int i;
|
size_t slab_count = 0, total_slab_size = 0;
|
||||||
|
size_t single_allocation_count = 0, total_single_allocation_size = 0;
|
||||||
|
int i, j;
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
{
|
||||||
|
kprintf("---BEGIN JSON DATA ---\n");
|
||||||
|
|
||||||
|
__get_slab_stats(NULL, print_json);
|
||||||
|
|
||||||
|
kprintf("---END JSON DATA ---\n\n");
|
||||||
|
}
|
||||||
|
#endif /* DEBUG */
|
||||||
|
|
||||||
D(("freeing slabs"));
|
D(("freeing slabs"));
|
||||||
|
|
||||||
@ -720,25 +786,38 @@ __slab_exit(void)
|
|||||||
for(i = 0 ; i < (int)NUM_ENTRIES(__slab_data.sd_Slabs) ; i++)
|
for(i = 0 ; i < (int)NUM_ENTRIES(__slab_data.sd_Slabs) ; i++)
|
||||||
{
|
{
|
||||||
if(__slab_data.sd_Slabs[i].mlh_Head->mln_Succ != NULL)
|
if(__slab_data.sd_Slabs[i].mlh_Head->mln_Succ != NULL)
|
||||||
D(("freeing slab #%ld (%lu bytes per chunk)", i, (1UL << i)));
|
D(("freeing slab slot #%ld (%lu bytes per chunk)", i, (1UL << i)));
|
||||||
|
|
||||||
for(sn = (struct SlabNode *)__slab_data.sd_Slabs[i].mlh_Head ;
|
for(sn = (struct SlabNode *)__slab_data.sd_Slabs[i].mlh_Head, j = 0 ;
|
||||||
sn->sn_MinNode.mln_Succ != NULL ;
|
sn->sn_MinNode.mln_Succ != NULL ;
|
||||||
sn = sn_next)
|
sn = sn_next)
|
||||||
{
|
{
|
||||||
sn_next = (struct SlabNode *)sn->sn_MinNode.mln_Succ;
|
sn_next = (struct SlabNode *)sn->sn_MinNode.mln_Succ;
|
||||||
|
|
||||||
|
D((" slab #%ld.%ld at 0x%08lx",i, ++j, sn));
|
||||||
|
D((" fragmentation = %ld%%",100 * (__slab_data.sd_StandardSlabSize - sn->sn_Count * sn->sn_ChunkSize) / __slab_data.sd_StandardSlabSize));
|
||||||
|
D((" total space used = %ld (%ld%%)",sn->sn_UseCount * sn->sn_ChunkSize, 100 * sn->sn_UseCount / sn->sn_Count));
|
||||||
|
D((" number of chunks total = %ld",sn->sn_Count));
|
||||||
|
D((" number of chunks used = %ld%s",sn->sn_UseCount,sn->sn_UseCount == 0 ? " (empty)" : (sn->sn_UseCount == sn->sn_Count) ? " (full)" : ""));
|
||||||
|
D((" how often reused = %ld",sn->sn_NumReused));
|
||||||
|
|
||||||
|
total_slab_size += sizeof(*sn) + __slab_data.sd_StandardSlabSize;
|
||||||
|
slab_count++;
|
||||||
|
|
||||||
FreeVec(sn);
|
FreeVec(sn);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(slab_count > 0)
|
||||||
|
D(("number of slabs = %ld, total slab size = %ld bytes",slab_count, total_slab_size));
|
||||||
|
|
||||||
if(__slab_data.sd_SingleAllocations.mlh_Head->mln_Succ != NULL)
|
if(__slab_data.sd_SingleAllocations.mlh_Head->mln_Succ != NULL)
|
||||||
D(("freeing single allocations"));
|
D(("freeing single allocations"));
|
||||||
|
|
||||||
/* Free the memory allocated for each allocation which did not
|
/* Free the memory allocated for each allocation which did not
|
||||||
* go into a slab.
|
* go into a slab.
|
||||||
*/
|
*/
|
||||||
for(mn = __slab_data.sd_SingleAllocations.mlh_Head ;
|
for(mn = __slab_data.sd_SingleAllocations.mlh_Head, j = 0 ;
|
||||||
mn->mln_Succ != NULL ;
|
mn->mln_Succ != NULL ;
|
||||||
mn = mn_next)
|
mn = mn_next)
|
||||||
{
|
{
|
||||||
@ -746,9 +825,17 @@ __slab_exit(void)
|
|||||||
|
|
||||||
ssa = (struct SlabSingleAllocation *)mn;
|
ssa = (struct SlabSingleAllocation *)mn;
|
||||||
|
|
||||||
|
D((" allocation #%ld at 0x%08lx, %lu bytes", ++j, ssa, ssa->ssa_Size));
|
||||||
|
|
||||||
|
total_single_allocation_size += ssa->ssa_Size;
|
||||||
|
single_allocation_count++;
|
||||||
|
|
||||||
FreeMem(ssa, ssa->ssa_Size);
|
FreeMem(ssa, ssa->ssa_Size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(single_allocation_count > 0)
|
||||||
|
D(("number of single allocations = %ld, total single allocation size = %ld", single_allocation_count, total_single_allocation_size));
|
||||||
|
|
||||||
__slab_data.sd_InUse = FALSE;
|
__slab_data.sd_InUse = FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
38
library/stdlib_slab_purge_threshold.c
Normal file
38
library/stdlib_slab_purge_threshold.c
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
/*
|
||||||
|
* :ts=4
|
||||||
|
*
|
||||||
|
* Portable ISO 'C' (1994) runtime library for the Amiga computer
|
||||||
|
* Copyright (c) 2002-2015 by Olaf Barthel <obarthel (at) gmx.net>
|
||||||
|
* 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 */
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
unsigned long __slab_purge_threshold;
|
||||||
@ -1,6 +1,6 @@
|
|||||||
#define VERSION 1
|
#define VERSION 1
|
||||||
#define REVISION 211
|
#define REVISION 212
|
||||||
#define DATE "23.11.2016"
|
#define DATE "27.11.2016"
|
||||||
#define VERS "unix.lib 1.211"
|
#define VERS "unix.lib 1.212"
|
||||||
#define VSTRING "unix.lib 1.211 (23.11.2016)\r\n"
|
#define VSTRING "unix.lib 1.212 (27.11.2016)\r\n"
|
||||||
#define VERSTAG "\0$VER: unix.lib 1.211 (23.11.2016)"
|
#define VERSTAG "\0$VER: unix.lib 1.212 (27.11.2016)"
|
||||||
|
|||||||
@ -1 +1 @@
|
|||||||
211
|
212
|
||||||
|
|||||||
@ -13,7 +13,7 @@ DELETE = delete all quiet
|
|||||||
|
|
||||||
.c.o:
|
.c.o:
|
||||||
@echo "Compiling $<"
|
@echo "Compiling $<"
|
||||||
@$(CC) -c $(CFLAGS) $<
|
$(CC) -c $(CFLAGS) $<
|
||||||
|
|
||||||
##############################################################################
|
##############################################################################
|
||||||
|
|
||||||
@ -31,7 +31,7 @@ WARNINGS = \
|
|||||||
|
|
||||||
INCLUDE = -I../library/include
|
INCLUDE = -I../library/include
|
||||||
LIB = -L../library/lib
|
LIB = -L../library/lib
|
||||||
OPTIONS = -DNDEBUG -fno-builtin -fwritable-strings -DNO_INLINE_STDARG -DIEEE_FLOATING_POINT_SUPPORT -DVERBOSE
|
OPTIONS = -DNDEBUG -fno-builtin -fwritable-strings -DNO_INLINE_STDARG -DIEEE_FLOATING_POINT_SUPPORT -DVERBOSE=1
|
||||||
#OPTIONS = -D__MEM_DEBUG -fno-builtin
|
#OPTIONS = -D__MEM_DEBUG -fno-builtin
|
||||||
#OPTIONS = -DDEBUG -D__MEM_DEBUG -DNO_INLINE_STDARG -fno-builtin
|
#OPTIONS = -DDEBUG -D__MEM_DEBUG -DNO_INLINE_STDARG -fno-builtin
|
||||||
OPTIMIZE = -O
|
OPTIMIZE = -O
|
||||||
@ -50,14 +50,14 @@ all: test fgets_test iotest sscanf_test printf_test sprintf_test \
|
|||||||
stack_size_test translate_test strtok_test uname simple \
|
stack_size_test translate_test strtok_test uname simple \
|
||||||
fstat_stdout_test simple_sprintf date_test sscanf_64 factorial \
|
fstat_stdout_test simple_sprintf date_test sscanf_64 factorial \
|
||||||
execvp_test setlocale rand fstat_test base_dir_nametest \
|
execvp_test setlocale rand fstat_test base_dir_nametest \
|
||||||
malloc-test
|
malloc-test slab-test
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
$(DELETE) #?.o #?.map test fgets_test iotest sscanf_test printf_test \
|
$(DELETE) #?.o #?.map test fgets_test iotest sscanf_test printf_test \
|
||||||
sprintf_test stack_size_test translate_test strtok_test uname \
|
sprintf_test stack_size_test translate_test strtok_test uname \
|
||||||
simple fstat_stdout_test fstat_test simple_sprintf date_test sscanf_64 \
|
simple fstat_stdout_test fstat_test simple_sprintf date_test sscanf_64 \
|
||||||
factorial execvp_test setlocale rand base_dir_nametest \
|
factorial execvp_test setlocale rand base_dir_nametest \
|
||||||
malloc-test
|
malloc-test slab-test
|
||||||
|
|
||||||
##############################################################################
|
##############################################################################
|
||||||
|
|
||||||
@ -145,9 +145,13 @@ rand : rand.o
|
|||||||
@echo "Linking $@"
|
@echo "Linking $@"
|
||||||
$(CC) $(CFLAGS) -o $@ rand.o $(LIBS) -Wl,--cref,-M,-Map=$@.map
|
$(CC) $(CFLAGS) -o $@ rand.o $(LIBS) -Wl,--cref,-M,-Map=$@.map
|
||||||
|
|
||||||
malloc-test: malloc-test.o
|
malloc-test : malloc-test.o
|
||||||
@echo "Linking $@"
|
@echo "Linking $@"
|
||||||
$(CC) $(CFLAGS) -o $@ rand.o $(LIBS) -Wl,--cref,-M,-Map=$@.map
|
$(CC) $(CFLAGS) -o $@ malloc-test.o $(LIBS) -Wl,--cref,-M,-Map=$@.map
|
||||||
|
|
||||||
|
slab-test : slab-test.o
|
||||||
|
@echo "Linking $@"
|
||||||
|
$(CC) $(CFLAGS) -o $@ slab-test.o $(LIBS) -Wl,--cref,-M,-Map=$@.map
|
||||||
|
|
||||||
##############################################################################
|
##############################################################################
|
||||||
|
|
||||||
|
|||||||
26
test_programs/slab-test.c
Normal file
26
test_programs/slab-test.c
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
unsigned long __slab_max_size = 4096;
|
||||||
|
|
||||||
|
static int print_json(void * ignore,const char * buffer,size_t len)
|
||||||
|
{
|
||||||
|
fputs(buffer, stdout);
|
||||||
|
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc,char ** argv)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
srand(1);
|
||||||
|
|
||||||
|
for(i = 0 ; i < 1000 ; i++)
|
||||||
|
malloc(1 + (rand() % 8192));
|
||||||
|
|
||||||
|
__get_slab_stats(NULL, print_json);
|
||||||
|
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user