Change 'mem' namspace to 'jmem'
The 'mem_' prefix is too general, so it might clash with symbols in other libraries. Renamed the directory, file, funtion and type names. Related issue: #1052 JerryScript-DCO-1.0-Signed-off-by: László Langó llango.u-szeged@partner.samsung.com
This commit is contained in:
@@ -0,0 +1,33 @@
|
||||
/* Copyright 2014-2016 Samsung Electronics Co., Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef JMEM_ALLOCATOR_INTERNAL_H
|
||||
#define JMEM_ALLOCATOR_INTERNAL_H
|
||||
|
||||
#ifndef JMEM_ALLOCATOR_INTERNAL
|
||||
# error "The header is for internal routines of memory allocator component. Please, don't use the routines directly."
|
||||
#endif /* !JMEM_ALLOCATOR_INTERNAL */
|
||||
|
||||
/** \addtogroup mem Memory allocation
|
||||
* @{
|
||||
*/
|
||||
|
||||
extern void jmem_run_try_to_give_memory_back_callbacks (jmem_try_give_memory_back_severity_t);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#endif /* !JMEM_ALLOCATOR_INTERNAL_H */
|
||||
@@ -0,0 +1,149 @@
|
||||
/* Copyright 2014-2016 Samsung Electronics Co., Ltd.
|
||||
* Copyright 2016 University of Szeged.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Allocator implementation
|
||||
*/
|
||||
|
||||
#include "jrt.h"
|
||||
#include "jrt-libc-includes.h"
|
||||
#include "jmem-allocator.h"
|
||||
#include "jmem-heap.h"
|
||||
#include "jmem-poolman.h"
|
||||
|
||||
#define JMEM_ALLOCATOR_INTERNAL
|
||||
#include "jmem-allocator-internal.h"
|
||||
|
||||
/**
|
||||
* The 'try to give memory back' callback
|
||||
*/
|
||||
static jmem_try_give_memory_back_callback_t jmem_try_give_memory_back_callback = NULL;
|
||||
|
||||
/**
|
||||
* Initialize memory allocators.
|
||||
*/
|
||||
void
|
||||
jmem_init (void)
|
||||
{
|
||||
jmem_heap_init ();
|
||||
jmem_pools_init ();
|
||||
} /* jmem_init */
|
||||
|
||||
/**
|
||||
* Finalize memory allocators.
|
||||
*/
|
||||
void
|
||||
jmem_finalize (bool is_show_mem_stats) /**< show heap memory stats
|
||||
before finalization? */
|
||||
{
|
||||
jmem_pools_finalize ();
|
||||
|
||||
#ifdef JMEM_STATS
|
||||
if (is_show_mem_stats)
|
||||
{
|
||||
jmem_stats_print ();
|
||||
}
|
||||
#else /* !JMEM_STATS */
|
||||
(void) is_show_mem_stats;
|
||||
#endif /* JMEM_STATS */
|
||||
|
||||
jmem_heap_finalize ();
|
||||
} /* jmem_finalize */
|
||||
|
||||
/**
|
||||
* Compress pointer
|
||||
*
|
||||
* @return packed pointer
|
||||
*/
|
||||
uintptr_t
|
||||
jmem_compress_pointer (const void *pointer_p) /**< pointer to compress */
|
||||
{
|
||||
JERRY_ASSERT (jmem_is_heap_pointer (pointer_p));
|
||||
|
||||
return jmem_heap_compress_pointer (pointer_p);
|
||||
} /* jmem_compress_pointer */
|
||||
|
||||
/**
|
||||
* Decompress pointer
|
||||
*
|
||||
* @return unpacked pointer
|
||||
*/
|
||||
void *
|
||||
jmem_decompress_pointer (uintptr_t compressed_pointer) /**< pointer to decompress */
|
||||
{
|
||||
return jmem_heap_decompress_pointer (compressed_pointer);
|
||||
} /* jmem_decompress_pointer */
|
||||
|
||||
/**
|
||||
* Register specified 'try to give memory back' callback routine
|
||||
*/
|
||||
void
|
||||
jmem_register_a_try_give_memory_back_callback (jmem_try_give_memory_back_callback_t callback) /**< callback routine */
|
||||
{
|
||||
/* Currently only one callback is supported */
|
||||
JERRY_ASSERT (jmem_try_give_memory_back_callback == NULL);
|
||||
|
||||
jmem_try_give_memory_back_callback = callback;
|
||||
} /* jmem_register_a_try_give_memory_back_callback */
|
||||
|
||||
/**
|
||||
* Unregister specified 'try to give memory back' callback routine
|
||||
*/
|
||||
void
|
||||
jmem_unregister_a_try_give_memory_back_callback (jmem_try_give_memory_back_callback_t callback) /**< callback routine */
|
||||
{
|
||||
/* Currently only one callback is supported */
|
||||
JERRY_ASSERT (jmem_try_give_memory_back_callback == callback);
|
||||
|
||||
jmem_try_give_memory_back_callback = NULL;
|
||||
} /* jmem_unregister_a_try_give_memory_back_callback */
|
||||
|
||||
/**
|
||||
* Run 'try to give memory back' callbacks with specified severity
|
||||
*/
|
||||
void
|
||||
jmem_run_try_to_give_memory_back_callbacks (jmem_try_give_memory_back_severity_t severity) /**< severity of
|
||||
the request */
|
||||
{
|
||||
if (jmem_try_give_memory_back_callback != NULL)
|
||||
{
|
||||
jmem_try_give_memory_back_callback (severity);
|
||||
}
|
||||
|
||||
jmem_pools_collect_empty ();
|
||||
} /* jmem_run_try_to_give_memory_back_callbacks */
|
||||
|
||||
#ifdef JMEM_STATS
|
||||
/**
|
||||
* Reset peak values in memory usage statistics
|
||||
*/
|
||||
void
|
||||
jmem_stats_reset_peak (void)
|
||||
{
|
||||
jmem_heap_stats_reset_peak ();
|
||||
jmem_pools_stats_reset_peak ();
|
||||
} /* jmem_stats_reset_peak */
|
||||
|
||||
/**
|
||||
* Print memory usage statistics
|
||||
*/
|
||||
void
|
||||
jmem_stats_print (void)
|
||||
{
|
||||
jmem_heap_stats_print ();
|
||||
jmem_pools_stats_print ();
|
||||
} /* jmem_stats_print */
|
||||
#endif /* JMEM_STATS */
|
||||
@@ -0,0 +1,132 @@
|
||||
/* Copyright 2014-2016 Samsung Electronics Co., Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Allocator interface
|
||||
*/
|
||||
#ifndef JMEM_ALLOCATOR_H
|
||||
#define JMEM_ALLOCATOR_H
|
||||
|
||||
#include "jrt.h"
|
||||
#include "jmem-config.h"
|
||||
#include "jmem-heap.h"
|
||||
#include "jmem-poolman.h"
|
||||
|
||||
/** \addtogroup mem Memory allocation
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* Compressed pointer
|
||||
*/
|
||||
typedef uint16_t jmem_cpointer_t;
|
||||
|
||||
/**
|
||||
* Representation of NULL value for compressed pointers
|
||||
*/
|
||||
#define JMEM_CP_NULL ((jmem_cpointer_t) 0)
|
||||
|
||||
/**
|
||||
* Required alignment for allocated units/blocks
|
||||
*/
|
||||
#define JMEM_ALIGNMENT (1u << JMEM_ALIGNMENT_LOG)
|
||||
|
||||
/**
|
||||
* Width of compressed memory pointer
|
||||
*/
|
||||
#define JMEM_CP_WIDTH (JMEM_HEAP_OFFSET_LOG - JMEM_ALIGNMENT_LOG)
|
||||
|
||||
/**
|
||||
* Compressed pointer value mask
|
||||
*/
|
||||
#define JMEM_CP_MASK ((1ull << JMEM_CP_WIDTH) - 1)
|
||||
|
||||
/**
|
||||
* Severity of a 'try give memory back' request
|
||||
*
|
||||
* The request are posted sequentially beginning from
|
||||
* low to high until enough memory is freed.
|
||||
*
|
||||
* If not enough memory is freed upon a high request
|
||||
* then the engine is shut down with ERR_OUT_OF_MEMORY.
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
JMEM_TRY_GIVE_MEMORY_BACK_SEVERITY_LOW, /* 'low' severity */
|
||||
JMEM_TRY_GIVE_MEMORY_BACK_SEVERITY_HIGH, /* 'high' severity */
|
||||
} jmem_try_give_memory_back_severity_t;
|
||||
|
||||
/**
|
||||
* A 'try give memory back' callback routine type.
|
||||
*/
|
||||
typedef void (*jmem_try_give_memory_back_callback_t) (jmem_try_give_memory_back_severity_t);
|
||||
|
||||
/**
|
||||
* Get value of pointer from specified non-null compressed pointer value
|
||||
*/
|
||||
#define JMEM_CP_GET_NON_NULL_POINTER(type, cp_value) \
|
||||
((type *) (jmem_decompress_pointer (cp_value)))
|
||||
|
||||
/**
|
||||
* Get value of pointer from specified compressed pointer value
|
||||
*/
|
||||
#define JMEM_CP_GET_POINTER(type, cp_value) \
|
||||
(((unlikely ((cp_value) == JMEM_CP_NULL)) ? NULL : JMEM_CP_GET_NON_NULL_POINTER (type, cp_value)))
|
||||
|
||||
/**
|
||||
* Set value of non-null compressed pointer so that it will correspond
|
||||
* to specified non_compressed_pointer
|
||||
*/
|
||||
#define JMEM_CP_SET_NON_NULL_POINTER(cp_value, non_compressed_pointer) \
|
||||
(cp_value) = (jmem_compress_pointer (non_compressed_pointer) & JMEM_CP_MASK)
|
||||
|
||||
/**
|
||||
* Set value of compressed pointer so that it will correspond
|
||||
* to specified non_compressed_pointer
|
||||
*/
|
||||
#define JMEM_CP_SET_POINTER(cp_value, non_compressed_pointer) \
|
||||
do \
|
||||
{ \
|
||||
void *ptr_value = (void *) non_compressed_pointer; \
|
||||
\
|
||||
if (unlikely ((ptr_value) == NULL)) \
|
||||
{ \
|
||||
(cp_value) = JMEM_CP_NULL; \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
JMEM_CP_SET_NON_NULL_POINTER (cp_value, ptr_value); \
|
||||
} \
|
||||
} while (false);
|
||||
|
||||
extern void jmem_init (void);
|
||||
extern void jmem_finalize (bool);
|
||||
|
||||
extern uintptr_t jmem_compress_pointer (const void *);
|
||||
extern void *jmem_decompress_pointer (uintptr_t);
|
||||
|
||||
extern void jmem_register_a_try_give_memory_back_callback (jmem_try_give_memory_back_callback_t);
|
||||
extern void jmem_unregister_a_try_give_memory_back_callback (jmem_try_give_memory_back_callback_t);
|
||||
|
||||
#ifdef JMEM_STATS
|
||||
extern void jmem_stats_reset_peak (void);
|
||||
extern void jmem_stats_print (void);
|
||||
#endif /* JMEM_STATS */
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#endif /* !JMEM_ALLOCATOR_H */
|
||||
@@ -0,0 +1,41 @@
|
||||
/* Copyright 2014-2016 Samsung Electronics Co., Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef JMEM_CONFIG_H
|
||||
#define JMEM_CONFIG_H
|
||||
|
||||
#include "config.h"
|
||||
|
||||
/**
|
||||
* Log2 of maximum possible offset in the heap
|
||||
*/
|
||||
#define JMEM_HEAP_OFFSET_LOG (CONFIG_MEM_HEAP_OFFSET_LOG)
|
||||
|
||||
/**
|
||||
* Size of heap
|
||||
*/
|
||||
#define JMEM_HEAP_SIZE ((size_t) (CONFIG_MEM_HEAP_AREA_SIZE))
|
||||
|
||||
/**
|
||||
* Size of pool chunk
|
||||
*/
|
||||
#define JMEM_POOL_CHUNK_SIZE ((size_t) (CONFIG_MEM_POOL_CHUNK_SIZE))
|
||||
|
||||
/**
|
||||
* Logarithm of required alignment for allocated units/blocks
|
||||
*/
|
||||
#define JMEM_ALIGNMENT_LOG 3
|
||||
|
||||
#endif /* !JMEM_CONFIG_H */
|
||||
@@ -0,0 +1,775 @@
|
||||
/* Copyright 2014-2016 Samsung Electronics Co., Ltd.
|
||||
* Copyright 2016 University of Szeged.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Heap implementation
|
||||
*/
|
||||
|
||||
#include "jrt.h"
|
||||
#include "jrt-bit-fields.h"
|
||||
#include "jrt-libc-includes.h"
|
||||
#include "jmem-allocator.h"
|
||||
#include "jmem-config.h"
|
||||
#include "jmem-heap.h"
|
||||
|
||||
#define JMEM_ALLOCATOR_INTERNAL
|
||||
#include "jmem-allocator-internal.h"
|
||||
|
||||
/** \addtogroup mem Memory allocation
|
||||
* @{
|
||||
*
|
||||
* \addtogroup heap Heap
|
||||
* @{
|
||||
*/
|
||||
|
||||
/*
|
||||
* Valgrind-related options and headers
|
||||
*/
|
||||
#ifdef JERRY_VALGRIND
|
||||
# include "memcheck.h"
|
||||
|
||||
# define VALGRIND_NOACCESS_SPACE(p, s) VALGRIND_MAKE_MEM_NOACCESS((p), (s))
|
||||
# define VALGRIND_UNDEFINED_SPACE(p, s) VALGRIND_MAKE_MEM_UNDEFINED((p), (s))
|
||||
# define VALGRIND_DEFINED_SPACE(p, s) VALGRIND_MAKE_MEM_DEFINED((p), (s))
|
||||
|
||||
#else /* !JERRY_VALGRIND */
|
||||
# define VALGRIND_NOACCESS_SPACE(p, s)
|
||||
# define VALGRIND_UNDEFINED_SPACE(p, s)
|
||||
# define VALGRIND_DEFINED_SPACE(p, s)
|
||||
#endif /* JERRY_VALGRIND */
|
||||
|
||||
#ifdef JERRY_VALGRIND_FREYA
|
||||
# include "memcheck.h"
|
||||
|
||||
/**
|
||||
* Tells whether a pool manager allocator request is in progress.
|
||||
*/
|
||||
static bool valgrind_freya_mempool_request = false;
|
||||
|
||||
/**
|
||||
* Called by pool manager before a heap allocation or free.
|
||||
*/
|
||||
void jmem_heap_valgrind_freya_mempool_request (void)
|
||||
{
|
||||
valgrind_freya_mempool_request = true;
|
||||
} /* jmem_heap_valgrind_freya_mempool_request */
|
||||
|
||||
# define VALGRIND_FREYA_CHECK_MEMPOOL_REQUEST \
|
||||
bool mempool_request = valgrind_freya_mempool_request; \
|
||||
valgrind_freya_mempool_request = false
|
||||
|
||||
# define VALGRIND_FREYA_MALLOCLIKE_SPACE(p, s) \
|
||||
if (!mempool_request) \
|
||||
{ \
|
||||
VALGRIND_MALLOCLIKE_BLOCK((p), (s), 0, 0); \
|
||||
}
|
||||
|
||||
# define VALGRIND_FREYA_FREELIKE_SPACE(p) \
|
||||
if (!mempool_request) \
|
||||
{ \
|
||||
VALGRIND_FREELIKE_BLOCK((p), 0); \
|
||||
}
|
||||
|
||||
#else /* !JERRY_VALGRIND_FREYA */
|
||||
# define VALGRIND_FREYA_CHECK_MEMPOOL_REQUEST
|
||||
# define VALGRIND_FREYA_MALLOCLIKE_SPACE(p, s)
|
||||
# define VALGRIND_FREYA_FREELIKE_SPACE(p)
|
||||
#endif /* JERRY_VALGRIND_FREYA */
|
||||
|
||||
/* Calculate heap area size, leaving space for a pointer to the free list */
|
||||
#define JMEM_HEAP_AREA_SIZE (JMEM_HEAP_SIZE - JMEM_ALIGNMENT)
|
||||
#define JMEM_HEAP_END_OF_LIST ((jmem_heap_free_t *const) ~((uint32_t) 0x0))
|
||||
|
||||
/**
|
||||
* Free region node
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
uint32_t next_offset; /**< Offset of next region in list */
|
||||
uint32_t size; /**< Size of region */
|
||||
} jmem_heap_free_t;
|
||||
|
||||
#if UINTPTR_MAX > UINT32_MAX
|
||||
#define JMEM_HEAP_GET_OFFSET_FROM_ADDR(p) ((uint32_t) ((uint8_t *) (p) - (uint8_t *) jmem_heap.area))
|
||||
#define JMEM_HEAP_GET_ADDR_FROM_OFFSET(u) ((jmem_heap_free_t *) &jmem_heap.area[u])
|
||||
#else /* UINTPTR_MAX <= UINT32_MAX */
|
||||
/* In this case we simply store the pointer, since it fits anyway. */
|
||||
#define JMEM_HEAP_GET_OFFSET_FROM_ADDR(p) ((uint32_t) (p))
|
||||
#define JMEM_HEAP_GET_ADDR_FROM_OFFSET(u) ((jmem_heap_free_t *)(u))
|
||||
#endif /* UINTPTR_MAX > UINT32_MAX */
|
||||
|
||||
/**
|
||||
* Get end of region
|
||||
*/
|
||||
static inline jmem_heap_free_t * __attr_always_inline___ __attr_pure___
|
||||
jmem_heap_get_region_end (jmem_heap_free_t *curr_p) /**< current region */
|
||||
{
|
||||
return (jmem_heap_free_t *)((uint8_t *) curr_p + curr_p->size);
|
||||
} /* jmem_heap_get_region_end */
|
||||
|
||||
/**
|
||||
* Heap structure
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
/** First node in free region list */
|
||||
jmem_heap_free_t first;
|
||||
|
||||
/**
|
||||
* Heap area
|
||||
*/
|
||||
uint8_t area[JMEM_HEAP_AREA_SIZE] __attribute__ ((aligned (JMEM_ALIGNMENT)));
|
||||
} jmem_heap_t;
|
||||
|
||||
/**
|
||||
* Heap
|
||||
*/
|
||||
#ifndef JERRY_HEAP_SECTION_ATTR
|
||||
jmem_heap_t jmem_heap;
|
||||
#else /* JERRY_HEAP_SECTION_ATTR */
|
||||
jmem_heap_t jmem_heap __attribute__ ((section (JERRY_HEAP_SECTION_ATTR)));
|
||||
#endif /* !JERRY_HEAP_SECTION_ATTR */
|
||||
|
||||
/**
|
||||
* Check size of heap is corresponding to configuration
|
||||
*/
|
||||
JERRY_STATIC_ASSERT (sizeof (jmem_heap) <= JMEM_HEAP_SIZE,
|
||||
size_of_mem_heap_must_be_less_than_or_equal_to_MEM_HEAP_SIZE);
|
||||
|
||||
/**
|
||||
* Size of allocated regions
|
||||
*/
|
||||
size_t jmem_heap_allocated_size;
|
||||
|
||||
/**
|
||||
* Current limit of heap usage, that is upon being reached, causes call of "try give memory back" callbacks
|
||||
*/
|
||||
size_t jmem_heap_limit;
|
||||
|
||||
/* This is used to speed up deallocation. */
|
||||
jmem_heap_free_t *jmem_heap_list_skip_p;
|
||||
|
||||
#ifdef JMEM_STATS
|
||||
/**
|
||||
* Heap's memory usage statistics
|
||||
*/
|
||||
static jmem_heap_stats_t jmem_heap_stats;
|
||||
|
||||
static void jmem_heap_stat_init (void);
|
||||
static void jmem_heap_stat_alloc (size_t num);
|
||||
static void jmem_heap_stat_free (size_t num);
|
||||
static void jmem_heap_stat_skip ();
|
||||
static void jmem_heap_stat_nonskip ();
|
||||
static void jmem_heap_stat_alloc_iter ();
|
||||
static void jmem_heap_stat_free_iter ();
|
||||
|
||||
# define JMEM_HEAP_STAT_INIT() jmem_heap_stat_init ()
|
||||
# define JMEM_HEAP_STAT_ALLOC(v1) jmem_heap_stat_alloc (v1)
|
||||
# define JMEM_HEAP_STAT_FREE(v1) jmem_heap_stat_free (v1)
|
||||
# define JMEM_HEAP_STAT_SKIP() jmem_heap_stat_skip ()
|
||||
# define JMEM_HEAP_STAT_NONSKIP() jmem_heap_stat_nonskip ()
|
||||
# define JMEM_HEAP_STAT_ALLOC_ITER() jmem_heap_stat_alloc_iter ()
|
||||
# define JMEM_HEAP_STAT_FREE_ITER() jmem_heap_stat_free_iter ()
|
||||
#else /* !JMEM_STATS */
|
||||
# define JMEM_HEAP_STAT_INIT()
|
||||
# define JMEM_HEAP_STAT_ALLOC(v1)
|
||||
# define JMEM_HEAP_STAT_FREE(v1)
|
||||
# define JMEM_HEAP_STAT_SKIP()
|
||||
# define JMEM_HEAP_STAT_NONSKIP()
|
||||
# define JMEM_HEAP_STAT_ALLOC_ITER()
|
||||
# define JMEM_HEAP_STAT_FREE_ITER()
|
||||
#endif /* JMEM_STATS */
|
||||
|
||||
/**
|
||||
* Startup initialization of heap
|
||||
*/
|
||||
void
|
||||
jmem_heap_init (void)
|
||||
{
|
||||
JERRY_STATIC_ASSERT ((uintptr_t) jmem_heap.area % JMEM_ALIGNMENT == 0,
|
||||
jmem_heap_area_must_be_multiple_of_MEM_ALIGNMENT);
|
||||
|
||||
JERRY_STATIC_ASSERT ((1u << JMEM_HEAP_OFFSET_LOG) >= JMEM_HEAP_SIZE,
|
||||
two_pow_mem_heap_offset_should_not_be_less_than_mem_heap_size);
|
||||
|
||||
jmem_heap_allocated_size = 0;
|
||||
jmem_heap_limit = CONFIG_MEM_HEAP_DESIRED_LIMIT;
|
||||
jmem_heap.first.size = 0;
|
||||
jmem_heap_free_t *const region_p = (jmem_heap_free_t *) jmem_heap.area;
|
||||
jmem_heap.first.next_offset = JMEM_HEAP_GET_OFFSET_FROM_ADDR (region_p);
|
||||
region_p->size = sizeof (jmem_heap.area);
|
||||
region_p->next_offset = JMEM_HEAP_GET_OFFSET_FROM_ADDR (JMEM_HEAP_END_OF_LIST);
|
||||
|
||||
jmem_heap_list_skip_p = &jmem_heap.first;
|
||||
|
||||
VALGRIND_NOACCESS_SPACE (jmem_heap.area, JMEM_HEAP_AREA_SIZE);
|
||||
|
||||
JMEM_HEAP_STAT_INIT ();
|
||||
} /* jmem_heap_init */
|
||||
|
||||
/**
|
||||
* Finalize heap
|
||||
*/
|
||||
void jmem_heap_finalize (void)
|
||||
{
|
||||
JERRY_ASSERT (jmem_heap_allocated_size == 0);
|
||||
VALGRIND_NOACCESS_SPACE (&jmem_heap, sizeof (jmem_heap));
|
||||
} /* jmem_heap_finalize */
|
||||
|
||||
/**
|
||||
* Allocation of memory region.
|
||||
*
|
||||
* See also:
|
||||
* jmem_heap_alloc_block
|
||||
*
|
||||
* @return pointer to allocated memory block - if allocation is successful,
|
||||
* NULL - if there is not enough memory.
|
||||
*/
|
||||
static __attribute__((hot))
|
||||
void *jmem_heap_alloc_block_internal (const size_t size)
|
||||
{
|
||||
// Align size
|
||||
const size_t required_size = ((size + JMEM_ALIGNMENT - 1) / JMEM_ALIGNMENT) * JMEM_ALIGNMENT;
|
||||
jmem_heap_free_t *data_space_p = NULL;
|
||||
|
||||
VALGRIND_DEFINED_SPACE (&jmem_heap.first, sizeof (jmem_heap_free_t));
|
||||
|
||||
// Fast path for 8 byte chunks, first region is guaranteed to be sufficient
|
||||
if (required_size == JMEM_ALIGNMENT
|
||||
&& likely (jmem_heap.first.next_offset != JMEM_HEAP_GET_OFFSET_FROM_ADDR (JMEM_HEAP_END_OF_LIST)))
|
||||
{
|
||||
data_space_p = JMEM_HEAP_GET_ADDR_FROM_OFFSET (jmem_heap.first.next_offset);
|
||||
JERRY_ASSERT (jmem_is_heap_pointer (data_space_p));
|
||||
|
||||
VALGRIND_DEFINED_SPACE (data_space_p, sizeof (jmem_heap_free_t));
|
||||
jmem_heap_allocated_size += JMEM_ALIGNMENT;
|
||||
JMEM_HEAP_STAT_ALLOC_ITER ();
|
||||
|
||||
if (data_space_p->size == JMEM_ALIGNMENT)
|
||||
{
|
||||
jmem_heap.first.next_offset = data_space_p->next_offset;
|
||||
}
|
||||
else
|
||||
{
|
||||
JERRY_ASSERT (data_space_p->size > JMEM_ALIGNMENT);
|
||||
jmem_heap_free_t *const remaining_p = JMEM_HEAP_GET_ADDR_FROM_OFFSET (jmem_heap.first.next_offset) + 1;
|
||||
|
||||
VALGRIND_DEFINED_SPACE (remaining_p, sizeof (jmem_heap_free_t));
|
||||
remaining_p->size = data_space_p->size - JMEM_ALIGNMENT;
|
||||
remaining_p->next_offset = data_space_p->next_offset;
|
||||
VALGRIND_NOACCESS_SPACE (remaining_p, sizeof (jmem_heap_free_t));
|
||||
|
||||
jmem_heap.first.next_offset = JMEM_HEAP_GET_OFFSET_FROM_ADDR (remaining_p);
|
||||
}
|
||||
|
||||
VALGRIND_UNDEFINED_SPACE (data_space_p, sizeof (jmem_heap_free_t));
|
||||
|
||||
if (unlikely (data_space_p == jmem_heap_list_skip_p))
|
||||
{
|
||||
jmem_heap_list_skip_p = JMEM_HEAP_GET_ADDR_FROM_OFFSET (jmem_heap.first.next_offset);
|
||||
}
|
||||
}
|
||||
// Slow path for larger regions
|
||||
else
|
||||
{
|
||||
jmem_heap_free_t *current_p = JMEM_HEAP_GET_ADDR_FROM_OFFSET (jmem_heap.first.next_offset);
|
||||
jmem_heap_free_t *prev_p = &jmem_heap.first;
|
||||
while (current_p != JMEM_HEAP_END_OF_LIST)
|
||||
{
|
||||
JERRY_ASSERT (jmem_is_heap_pointer (current_p));
|
||||
VALGRIND_DEFINED_SPACE (current_p, sizeof (jmem_heap_free_t));
|
||||
JMEM_HEAP_STAT_ALLOC_ITER ();
|
||||
|
||||
const uint32_t next_offset = current_p->next_offset;
|
||||
JERRY_ASSERT (jmem_is_heap_pointer (JMEM_HEAP_GET_ADDR_FROM_OFFSET (next_offset))
|
||||
|| next_offset == JMEM_HEAP_GET_OFFSET_FROM_ADDR (JMEM_HEAP_END_OF_LIST));
|
||||
|
||||
if (current_p->size >= required_size)
|
||||
{
|
||||
// Region is sufficiently big, store address
|
||||
data_space_p = current_p;
|
||||
jmem_heap_allocated_size += required_size;
|
||||
|
||||
// Region was larger than necessary
|
||||
if (current_p->size > required_size)
|
||||
{
|
||||
// Get address of remaining space
|
||||
jmem_heap_free_t *const remaining_p = (jmem_heap_free_t *) ((uint8_t *) current_p + required_size);
|
||||
|
||||
// Update metadata
|
||||
VALGRIND_DEFINED_SPACE (remaining_p, sizeof (jmem_heap_free_t));
|
||||
remaining_p->size = current_p->size - (uint32_t) required_size;
|
||||
remaining_p->next_offset = next_offset;
|
||||
VALGRIND_NOACCESS_SPACE (remaining_p, sizeof (jmem_heap_free_t));
|
||||
|
||||
// Update list
|
||||
VALGRIND_DEFINED_SPACE (prev_p, sizeof (jmem_heap_free_t));
|
||||
prev_p->next_offset = JMEM_HEAP_GET_OFFSET_FROM_ADDR (remaining_p);
|
||||
VALGRIND_NOACCESS_SPACE (prev_p, sizeof (jmem_heap_free_t));
|
||||
}
|
||||
// Block is an exact fit
|
||||
else
|
||||
{
|
||||
// Remove the region from the list
|
||||
VALGRIND_DEFINED_SPACE (prev_p, sizeof (jmem_heap_free_t));
|
||||
prev_p->next_offset = next_offset;
|
||||
VALGRIND_NOACCESS_SPACE (prev_p, sizeof (jmem_heap_free_t));
|
||||
}
|
||||
|
||||
jmem_heap_list_skip_p = prev_p;
|
||||
|
||||
// Found enough space
|
||||
break;
|
||||
}
|
||||
|
||||
VALGRIND_NOACCESS_SPACE (current_p, sizeof (jmem_heap_free_t));
|
||||
// Next in list
|
||||
prev_p = current_p;
|
||||
current_p = JMEM_HEAP_GET_ADDR_FROM_OFFSET (next_offset);
|
||||
}
|
||||
}
|
||||
|
||||
while (jmem_heap_allocated_size >= jmem_heap_limit)
|
||||
{
|
||||
jmem_heap_limit += CONFIG_MEM_HEAP_DESIRED_LIMIT;
|
||||
}
|
||||
|
||||
VALGRIND_NOACCESS_SPACE (&jmem_heap.first, sizeof (jmem_heap_free_t));
|
||||
|
||||
if (unlikely (!data_space_p))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
JERRY_ASSERT ((uintptr_t) data_space_p % JMEM_ALIGNMENT == 0);
|
||||
VALGRIND_UNDEFINED_SPACE (data_space_p, size);
|
||||
JMEM_HEAP_STAT_ALLOC (size);
|
||||
|
||||
return (void *) data_space_p;
|
||||
} /* jmem_heap_finalize */
|
||||
|
||||
/**
|
||||
* Allocation of memory block, running 'try to give memory back' callbacks, if there is not enough memory.
|
||||
*
|
||||
* Note:
|
||||
* if after running the callbacks, there is still not enough memory, engine is terminated with ERR_OUT_OF_MEMORY.
|
||||
*
|
||||
* @return pointer to allocated memory block
|
||||
*/
|
||||
void * __attribute__((hot))
|
||||
jmem_heap_alloc_block (const size_t size)
|
||||
{
|
||||
if (unlikely (size == 0))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
VALGRIND_FREYA_CHECK_MEMPOOL_REQUEST;
|
||||
|
||||
#ifdef JMEM_GC_BEFORE_EACH_ALLOC
|
||||
jmem_run_try_to_give_memory_back_callbacks (JMEM_TRY_GIVE_MEMORY_BACK_SEVERITY_HIGH);
|
||||
#endif /* JMEM_GC_BEFORE_EACH_ALLOC */
|
||||
|
||||
if (jmem_heap_allocated_size + size >= jmem_heap_limit)
|
||||
{
|
||||
jmem_run_try_to_give_memory_back_callbacks (JMEM_TRY_GIVE_MEMORY_BACK_SEVERITY_LOW);
|
||||
}
|
||||
|
||||
void *data_space_p = jmem_heap_alloc_block_internal (size);
|
||||
|
||||
if (likely (data_space_p != NULL))
|
||||
{
|
||||
VALGRIND_FREYA_MALLOCLIKE_SPACE (data_space_p, size);
|
||||
return data_space_p;
|
||||
}
|
||||
|
||||
for (jmem_try_give_memory_back_severity_t severity = JMEM_TRY_GIVE_MEMORY_BACK_SEVERITY_LOW;
|
||||
severity <= JMEM_TRY_GIVE_MEMORY_BACK_SEVERITY_HIGH;
|
||||
severity = (jmem_try_give_memory_back_severity_t) (severity + 1))
|
||||
{
|
||||
jmem_run_try_to_give_memory_back_callbacks (severity);
|
||||
|
||||
data_space_p = jmem_heap_alloc_block_internal (size);
|
||||
|
||||
if (likely (data_space_p != NULL))
|
||||
{
|
||||
VALGRIND_FREYA_MALLOCLIKE_SPACE (data_space_p, size);
|
||||
return data_space_p;
|
||||
}
|
||||
}
|
||||
|
||||
JERRY_ASSERT (data_space_p == NULL);
|
||||
|
||||
jerry_fatal (ERR_OUT_OF_MEMORY);
|
||||
} /* jmem_heap_alloc_block */
|
||||
|
||||
/**
|
||||
* Allocate block and store block size.
|
||||
*
|
||||
* Note: block will only be aligned to 4 bytes.
|
||||
*/
|
||||
inline void * __attr_always_inline___
|
||||
jmem_heap_alloc_block_store_size (size_t size) /**< required size */
|
||||
{
|
||||
if (unlikely (size == 0))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size += sizeof (jmem_heap_free_t);
|
||||
|
||||
jmem_heap_free_t *const data_space_p = (jmem_heap_free_t *) jmem_heap_alloc_block (size);
|
||||
data_space_p->size = (uint32_t) size;
|
||||
return (void *) (data_space_p + 1);
|
||||
} /* jmem_heap_alloc_block_store_size */
|
||||
|
||||
/**
|
||||
* Free the memory block.
|
||||
*/
|
||||
void __attribute__((hot))
|
||||
jmem_heap_free_block (void *ptr, /**< pointer to beginning of data space of the block */
|
||||
const size_t size) /**< size of allocated region */
|
||||
{
|
||||
VALGRIND_FREYA_CHECK_MEMPOOL_REQUEST;
|
||||
|
||||
/* checking that ptr points to the heap */
|
||||
JERRY_ASSERT (jmem_is_heap_pointer (ptr));
|
||||
JERRY_ASSERT (size > 0);
|
||||
JERRY_ASSERT (jmem_heap_limit >= jmem_heap_allocated_size);
|
||||
|
||||
VALGRIND_FREYA_FREELIKE_SPACE (ptr);
|
||||
VALGRIND_NOACCESS_SPACE (ptr, size);
|
||||
JMEM_HEAP_STAT_FREE_ITER ();
|
||||
|
||||
jmem_heap_free_t *block_p = (jmem_heap_free_t *) ptr;
|
||||
jmem_heap_free_t *prev_p;
|
||||
jmem_heap_free_t *next_p;
|
||||
|
||||
VALGRIND_DEFINED_SPACE (&jmem_heap.first, sizeof (jmem_heap_free_t));
|
||||
|
||||
if (block_p > jmem_heap_list_skip_p)
|
||||
{
|
||||
prev_p = jmem_heap_list_skip_p;
|
||||
JMEM_HEAP_STAT_SKIP ();
|
||||
}
|
||||
else
|
||||
{
|
||||
prev_p = &jmem_heap.first;
|
||||
JMEM_HEAP_STAT_NONSKIP ();
|
||||
}
|
||||
|
||||
JERRY_ASSERT (jmem_is_heap_pointer (block_p));
|
||||
const uint32_t block_offset = JMEM_HEAP_GET_OFFSET_FROM_ADDR (block_p);
|
||||
|
||||
VALGRIND_DEFINED_SPACE (prev_p, sizeof (jmem_heap_free_t));
|
||||
// Find position of region in the list
|
||||
while (prev_p->next_offset < block_offset)
|
||||
{
|
||||
jmem_heap_free_t *const next_p = JMEM_HEAP_GET_ADDR_FROM_OFFSET (prev_p->next_offset);
|
||||
JERRY_ASSERT (jmem_is_heap_pointer (next_p));
|
||||
|
||||
VALGRIND_DEFINED_SPACE (next_p, sizeof (jmem_heap_free_t));
|
||||
VALGRIND_NOACCESS_SPACE (prev_p, sizeof (jmem_heap_free_t));
|
||||
prev_p = next_p;
|
||||
|
||||
JMEM_HEAP_STAT_FREE_ITER ();
|
||||
}
|
||||
|
||||
next_p = JMEM_HEAP_GET_ADDR_FROM_OFFSET (prev_p->next_offset);
|
||||
VALGRIND_DEFINED_SPACE (next_p, sizeof (jmem_heap_free_t));
|
||||
|
||||
/* Realign size */
|
||||
const size_t aligned_size = (size + JMEM_ALIGNMENT - 1) / JMEM_ALIGNMENT * JMEM_ALIGNMENT;
|
||||
|
||||
VALGRIND_DEFINED_SPACE (block_p, sizeof (jmem_heap_free_t));
|
||||
VALGRIND_DEFINED_SPACE (prev_p, sizeof (jmem_heap_free_t));
|
||||
// Update prev
|
||||
if (jmem_heap_get_region_end (prev_p) == block_p)
|
||||
{
|
||||
// Can be merged
|
||||
prev_p->size += (uint32_t) aligned_size;
|
||||
VALGRIND_NOACCESS_SPACE (block_p, sizeof (jmem_heap_free_t));
|
||||
block_p = prev_p;
|
||||
}
|
||||
else
|
||||
{
|
||||
block_p->size = (uint32_t) aligned_size;
|
||||
prev_p->next_offset = block_offset;
|
||||
}
|
||||
|
||||
VALGRIND_DEFINED_SPACE (next_p, sizeof (jmem_heap_free_t));
|
||||
// Update next
|
||||
if (jmem_heap_get_region_end (block_p) == next_p)
|
||||
{
|
||||
if (unlikely (next_p == jmem_heap_list_skip_p))
|
||||
{
|
||||
jmem_heap_list_skip_p = block_p;
|
||||
}
|
||||
|
||||
// Can be merged
|
||||
block_p->size += next_p->size;
|
||||
block_p->next_offset = next_p->next_offset;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
block_p->next_offset = JMEM_HEAP_GET_OFFSET_FROM_ADDR (next_p);
|
||||
}
|
||||
|
||||
jmem_heap_list_skip_p = prev_p;
|
||||
|
||||
VALGRIND_NOACCESS_SPACE (prev_p, sizeof (jmem_heap_free_t));
|
||||
VALGRIND_NOACCESS_SPACE (block_p, size);
|
||||
VALGRIND_NOACCESS_SPACE (next_p, sizeof (jmem_heap_free_t));
|
||||
|
||||
JERRY_ASSERT (jmem_heap_allocated_size > 0);
|
||||
jmem_heap_allocated_size -= aligned_size;
|
||||
|
||||
while (jmem_heap_allocated_size + CONFIG_MEM_HEAP_DESIRED_LIMIT <= jmem_heap_limit)
|
||||
{
|
||||
jmem_heap_limit -= CONFIG_MEM_HEAP_DESIRED_LIMIT;
|
||||
}
|
||||
|
||||
VALGRIND_NOACCESS_SPACE (&jmem_heap.first, sizeof (jmem_heap_free_t));
|
||||
JERRY_ASSERT (jmem_heap_limit >= jmem_heap_allocated_size);
|
||||
JMEM_HEAP_STAT_FREE (size);
|
||||
} /* jmem_heap_free_block */
|
||||
|
||||
/**
|
||||
* Free block with stored size
|
||||
*/
|
||||
inline void __attr_always_inline___
|
||||
jmem_heap_free_block_size_stored (void *ptr) /**< pointer to the memory block */
|
||||
{
|
||||
jmem_heap_free_t *const original_p = ((jmem_heap_free_t *) ptr) - 1;
|
||||
JERRY_ASSERT (original_p + 1 == ptr);
|
||||
jmem_heap_free_block (original_p, original_p->size);
|
||||
} /* jmem_heap_free_block_size_stored */
|
||||
|
||||
/**
|
||||
* Compress pointer
|
||||
*
|
||||
* @return packed heap pointer
|
||||
*/
|
||||
uintptr_t __attr_pure___ __attribute__((hot))
|
||||
jmem_heap_compress_pointer (const void *pointer_p) /**< pointer to compress */
|
||||
{
|
||||
JERRY_ASSERT (pointer_p != NULL);
|
||||
JERRY_ASSERT (jmem_is_heap_pointer (pointer_p));
|
||||
|
||||
uintptr_t int_ptr = (uintptr_t) pointer_p;
|
||||
const uintptr_t heap_start = (uintptr_t) &jmem_heap;
|
||||
|
||||
JERRY_ASSERT (int_ptr % JMEM_ALIGNMENT == 0);
|
||||
|
||||
int_ptr -= heap_start;
|
||||
int_ptr >>= JMEM_ALIGNMENT_LOG;
|
||||
|
||||
JERRY_ASSERT ((int_ptr & ~((1u << JMEM_HEAP_OFFSET_LOG) - 1)) == 0);
|
||||
|
||||
JERRY_ASSERT (int_ptr != JMEM_CP_NULL);
|
||||
|
||||
return int_ptr;
|
||||
} /* jmem_heap_compress_pointer */
|
||||
|
||||
/**
|
||||
* Decompress pointer
|
||||
*
|
||||
* @return unpacked heap pointer
|
||||
*/
|
||||
void * __attr_pure___ __attribute__((hot))
|
||||
jmem_heap_decompress_pointer (uintptr_t compressed_pointer) /**< pointer to decompress */
|
||||
{
|
||||
JERRY_ASSERT (compressed_pointer != JMEM_CP_NULL);
|
||||
|
||||
uintptr_t int_ptr = compressed_pointer;
|
||||
const uintptr_t heap_start = (uintptr_t) &jmem_heap;
|
||||
|
||||
int_ptr <<= JMEM_ALIGNMENT_LOG;
|
||||
int_ptr += heap_start;
|
||||
|
||||
JERRY_ASSERT (jmem_is_heap_pointer ((void *) int_ptr));
|
||||
return (void *) int_ptr;
|
||||
} /* jmem_heap_decompress_pointer */
|
||||
|
||||
#ifndef JERRY_NDEBUG
|
||||
/**
|
||||
* Check whether the pointer points to the heap
|
||||
*
|
||||
* Note:
|
||||
* the routine should be used only for assertion checks
|
||||
*
|
||||
* @return true - if pointer points to the heap,
|
||||
* false - otherwise
|
||||
*/
|
||||
bool
|
||||
jmem_is_heap_pointer (const void *pointer) /**< pointer */
|
||||
{
|
||||
return ((uint8_t *) pointer >= jmem_heap.area
|
||||
&& (uint8_t *) pointer <= ((uint8_t *) jmem_heap.area + JMEM_HEAP_AREA_SIZE));
|
||||
} /* jmem_is_heap_pointer */
|
||||
#endif /* !JERRY_NDEBUG */
|
||||
|
||||
#ifdef JMEM_STATS
|
||||
/**
|
||||
* Get heap memory usage statistics
|
||||
*/
|
||||
void
|
||||
jmem_heap_get_stats (jmem_heap_stats_t *out_heap_stats_p) /**< [out] heap stats */
|
||||
{
|
||||
JERRY_ASSERT (out_heap_stats_p != NULL);
|
||||
|
||||
*out_heap_stats_p = jmem_heap_stats;
|
||||
} /* jmem_heap_get_stats */
|
||||
|
||||
/**
|
||||
* Reset peak values in memory usage statistics
|
||||
*/
|
||||
void
|
||||
jmem_heap_stats_reset_peak (void)
|
||||
{
|
||||
jmem_heap_stats.peak_allocated_bytes = jmem_heap_stats.allocated_bytes;
|
||||
jmem_heap_stats.peak_waste_bytes = jmem_heap_stats.waste_bytes;
|
||||
} /* jmem_heap_stats_reset_peak */
|
||||
|
||||
/**
|
||||
* Print heap memory usage statistics
|
||||
*/
|
||||
void
|
||||
jmem_heap_stats_print (void)
|
||||
{
|
||||
printf ("Heap stats:\n"
|
||||
" Heap size = %zu bytes\n"
|
||||
" Allocated = %zu bytes\n"
|
||||
" Waste = %zu bytes\n"
|
||||
" Peak allocated = %zu bytes\n"
|
||||
" Peak waste = %zu bytes\n"
|
||||
" Skip-ahead ratio = %zu.%04zu\n"
|
||||
" Average alloc iteration = %zu.%04zu\n"
|
||||
" Average free iteration = %zu.%04zu\n"
|
||||
"\n",
|
||||
jmem_heap_stats.size,
|
||||
jmem_heap_stats.allocated_bytes,
|
||||
jmem_heap_stats.waste_bytes,
|
||||
jmem_heap_stats.peak_allocated_bytes,
|
||||
jmem_heap_stats.peak_waste_bytes,
|
||||
jmem_heap_stats.skip_count / jmem_heap_stats.nonskip_count,
|
||||
jmem_heap_stats.skip_count % jmem_heap_stats.nonskip_count * 10000 / jmem_heap_stats.nonskip_count,
|
||||
jmem_heap_stats.alloc_iter_count / jmem_heap_stats.alloc_count,
|
||||
jmem_heap_stats.alloc_iter_count % jmem_heap_stats.alloc_count * 10000 / jmem_heap_stats.alloc_count,
|
||||
jmem_heap_stats.free_iter_count / jmem_heap_stats.free_count,
|
||||
jmem_heap_stats.free_iter_count % jmem_heap_stats.free_count * 10000 / jmem_heap_stats.free_count);
|
||||
} /* jmem_heap_stats_print */
|
||||
|
||||
/**
|
||||
* Initalize heap memory usage statistics account structure
|
||||
*/
|
||||
static void
|
||||
jmem_heap_stat_init ()
|
||||
{
|
||||
memset (&jmem_heap_stats, 0, sizeof (jmem_heap_stats));
|
||||
|
||||
jmem_heap_stats.size = JMEM_HEAP_AREA_SIZE;
|
||||
} /* jmem_heap_stat_init */
|
||||
|
||||
/**
|
||||
* Account allocation
|
||||
*/
|
||||
static void
|
||||
jmem_heap_stat_alloc (size_t size) /**< Size of allocated block */
|
||||
{
|
||||
const size_t aligned_size = (size + JMEM_ALIGNMENT - 1) / JMEM_ALIGNMENT * JMEM_ALIGNMENT;
|
||||
const size_t waste_bytes = aligned_size - size;
|
||||
|
||||
jmem_heap_stats.allocated_bytes += aligned_size;
|
||||
jmem_heap_stats.waste_bytes += waste_bytes;
|
||||
jmem_heap_stats.alloc_count++;
|
||||
|
||||
|
||||
if (jmem_heap_stats.allocated_bytes > jmem_heap_stats.peak_allocated_bytes)
|
||||
{
|
||||
jmem_heap_stats.peak_allocated_bytes = jmem_heap_stats.allocated_bytes;
|
||||
}
|
||||
if (jmem_heap_stats.allocated_bytes > jmem_heap_stats.global_peak_allocated_bytes)
|
||||
{
|
||||
jmem_heap_stats.global_peak_allocated_bytes = jmem_heap_stats.allocated_bytes;
|
||||
}
|
||||
|
||||
if (jmem_heap_stats.waste_bytes > jmem_heap_stats.peak_waste_bytes)
|
||||
{
|
||||
jmem_heap_stats.peak_waste_bytes = jmem_heap_stats.waste_bytes;
|
||||
}
|
||||
if (jmem_heap_stats.waste_bytes > jmem_heap_stats.global_peak_waste_bytes)
|
||||
{
|
||||
jmem_heap_stats.global_peak_waste_bytes = jmem_heap_stats.waste_bytes;
|
||||
}
|
||||
} /* jmem_heap_stat_alloc */
|
||||
|
||||
/**
|
||||
* Account freeing
|
||||
*/
|
||||
static void
|
||||
jmem_heap_stat_free (size_t size) /**< Size of freed block */
|
||||
{
|
||||
const size_t aligned_size = (size + JMEM_ALIGNMENT - 1) / JMEM_ALIGNMENT * JMEM_ALIGNMENT;
|
||||
const size_t waste_bytes = aligned_size - size;
|
||||
|
||||
jmem_heap_stats.free_count++;
|
||||
jmem_heap_stats.allocated_bytes -= aligned_size;
|
||||
jmem_heap_stats.waste_bytes -= waste_bytes;
|
||||
} /* jmem_heap_stat_free */
|
||||
|
||||
/**
|
||||
* Counts number of skip-aheads during insertion of free block
|
||||
*/
|
||||
static void
|
||||
jmem_heap_stat_skip ()
|
||||
{
|
||||
jmem_heap_stats.skip_count++;
|
||||
} /* jmem_heap_stat_skip */
|
||||
|
||||
/**
|
||||
* Counts number of times we could not skip ahead during free block insertion
|
||||
*/
|
||||
static void
|
||||
jmem_heap_stat_nonskip ()
|
||||
{
|
||||
jmem_heap_stats.nonskip_count++;
|
||||
} /* jmem_heap_stat_nonskip */
|
||||
|
||||
/**
|
||||
* Count number of iterations required for allocations
|
||||
*/
|
||||
static void
|
||||
jmem_heap_stat_alloc_iter ()
|
||||
{
|
||||
jmem_heap_stats.alloc_iter_count++;
|
||||
} /* jmem_heap_stat_alloc_iter */
|
||||
|
||||
/**
|
||||
* Counts number of iterations required for inserting free blocks
|
||||
*/
|
||||
static void
|
||||
jmem_heap_stat_free_iter ()
|
||||
{
|
||||
jmem_heap_stats.free_iter_count++;
|
||||
} /* jmem_heap_stat_free_iter */
|
||||
#endif /* JMEM_STATS */
|
||||
|
||||
/**
|
||||
* @}
|
||||
* @}
|
||||
*/
|
||||
@@ -0,0 +1,125 @@
|
||||
/* Copyright 2014-2016 Samsung Electronics Co., Ltd.
|
||||
* Copyright 2016 University of Szeged.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Heap allocator interface
|
||||
*/
|
||||
#ifndef JMEM_HEAP_H
|
||||
#define JMEM_HEAP_H
|
||||
|
||||
#include "jrt.h"
|
||||
|
||||
/** \addtogroup mem Memory allocation
|
||||
* @{
|
||||
*
|
||||
* \addtogroup heap Heap
|
||||
* @{
|
||||
*/
|
||||
|
||||
extern void jmem_heap_init (void);
|
||||
extern void jmem_heap_finalize (void);
|
||||
extern void *jmem_heap_alloc_block (const size_t);
|
||||
extern void jmem_heap_free_block (void *, const size_t);
|
||||
extern void *jmem_heap_alloc_block_store_size (size_t);
|
||||
extern void jmem_heap_free_block_size_stored (void *);
|
||||
extern uintptr_t jmem_heap_compress_pointer (const void *);
|
||||
extern void *jmem_heap_decompress_pointer (uintptr_t);
|
||||
extern bool jmem_is_heap_pointer (const void *);
|
||||
|
||||
#ifdef JMEM_STATS
|
||||
/**
|
||||
* Heap memory usage statistics
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
size_t size; /**< size */
|
||||
|
||||
size_t allocated_bytes; /**< currently allocated bytes */
|
||||
size_t peak_allocated_bytes; /**< peak allocated bytes */
|
||||
size_t global_peak_allocated_bytes; /**< non-resettable peak allocated bytes */
|
||||
|
||||
size_t waste_bytes; /**< bytes waste due to blocks filled partially
|
||||
and due to block headers */
|
||||
size_t peak_waste_bytes; /**< peak bytes waste */
|
||||
size_t global_peak_waste_bytes; /**< non-resettable peak bytes waste */
|
||||
|
||||
size_t skip_count;
|
||||
size_t nonskip_count;
|
||||
|
||||
size_t alloc_count;
|
||||
size_t alloc_iter_count;
|
||||
|
||||
size_t free_count;
|
||||
size_t free_iter_count;
|
||||
} jmem_heap_stats_t;
|
||||
|
||||
extern void jmem_heap_get_stats (jmem_heap_stats_t *);
|
||||
extern void jmem_heap_stats_reset_peak (void);
|
||||
extern void jmem_heap_stats_print (void);
|
||||
#endif /* JMEM_STATS */
|
||||
|
||||
#ifdef JERRY_VALGRIND_FREYA
|
||||
|
||||
#ifdef JERRY_VALGRIND
|
||||
#error Valgrind and valgrind-freya modes are not compatible.
|
||||
#endif /* JERRY_VALGRIND */
|
||||
|
||||
extern void jmem_heap_valgrind_freya_mempool_request (void);
|
||||
|
||||
#define JMEM_HEAP_VALGRIND_FREYA_MEMPOOL_REQUEST() jmem_heap_valgrind_freya_mempool_request ()
|
||||
|
||||
#else /* !JERRY_VALGRIND_FREYA */
|
||||
|
||||
#define JMEM_HEAP_VALGRIND_FREYA_MEMPOOL_REQUEST()
|
||||
|
||||
#endif /* JERRY_VALGRIND_FREYA */
|
||||
|
||||
/**
|
||||
* Define a local array variable and allocate memory for the array on the heap.
|
||||
*
|
||||
* If requested number of elements is zero, assign NULL to the variable.
|
||||
*
|
||||
* Warning:
|
||||
* if there is not enough memory on the heap, shutdown engine with ERR_OUT_OF_MEMORY.
|
||||
*/
|
||||
#define JMEM_DEFINE_LOCAL_ARRAY(var_name, number, type) \
|
||||
{ \
|
||||
size_t var_name ## ___size = (size_t) (number) * sizeof (type); \
|
||||
type *var_name = (type *) (jmem_heap_alloc_block (var_name ## ___size));
|
||||
|
||||
/**
|
||||
* Free the previously defined local array variable, freeing corresponding block on the heap,
|
||||
* if it was allocated (i.e. if the array's size was non-zero).
|
||||
*/
|
||||
#define JMEM_FINALIZE_LOCAL_ARRAY(var_name) \
|
||||
if (var_name != NULL) \
|
||||
{ \
|
||||
JERRY_ASSERT (var_name ## ___size != 0); \
|
||||
\
|
||||
jmem_heap_free_block (var_name, var_name ## ___size); \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
JERRY_ASSERT (var_name ## ___size == 0); \
|
||||
} \
|
||||
}
|
||||
|
||||
/**
|
||||
* @}
|
||||
* @}
|
||||
*/
|
||||
|
||||
#endif /* !JMEM_HEAP_H */
|
||||
@@ -0,0 +1,312 @@
|
||||
/* Copyright 2014-2016 Samsung Electronics Co., Ltd.
|
||||
* Copyright 2016 University of Szeged.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Memory pool manager implementation
|
||||
*/
|
||||
|
||||
#include "jrt.h"
|
||||
#include "jrt-libc-includes.h"
|
||||
#include "jmem-allocator.h"
|
||||
#include "jmem-heap.h"
|
||||
#include "jmem-poolman.h"
|
||||
|
||||
#define JMEM_ALLOCATOR_INTERNAL
|
||||
#include "jmem-allocator-internal.h"
|
||||
|
||||
/** \addtogroup mem Memory allocation
|
||||
* @{
|
||||
*
|
||||
* \addtogroup poolman Memory pool manager
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* Node for free chunk list
|
||||
*/
|
||||
typedef struct jmem_pools_chunk
|
||||
{
|
||||
struct jmem_pools_chunk *next_p; /**< pointer to next pool chunk */
|
||||
} jmem_pools_chunk_t;
|
||||
|
||||
/**
|
||||
* List of free pool chunks
|
||||
*/
|
||||
jmem_pools_chunk_t *jmem_free_chunk_p;
|
||||
|
||||
#ifdef JMEM_STATS
|
||||
|
||||
/**
|
||||
* Pools' memory usage statistics
|
||||
*/
|
||||
jmem_pools_stats_t jmem_pools_stats;
|
||||
|
||||
static void jmem_pools_stat_init (void);
|
||||
static void jmem_pools_stat_free_pool (void);
|
||||
static void jmem_pools_stat_new_alloc (void);
|
||||
static void jmem_pools_stat_reuse (void);
|
||||
static void jmem_pools_stat_dealloc (void);
|
||||
|
||||
# define JMEM_POOLS_STAT_INIT() jmem_pools_stat_init ()
|
||||
# define JMEM_POOLS_STAT_FREE_POOL() jmem_pools_stat_free_pool ()
|
||||
# define JMEM_POOLS_STAT_NEW_ALLOC() jmem_pools_stat_new_alloc ()
|
||||
# define JMEM_POOLS_STAT_REUSE() jmem_pools_stat_reuse ()
|
||||
# define JMEM_POOLS_STAT_DEALLOC() jmem_pools_stat_dealloc ()
|
||||
#else /* !JMEM_STATS */
|
||||
# define JMEM_POOLS_STAT_INIT()
|
||||
# define JMEM_POOLS_STAT_FREE_POOL()
|
||||
# define JMEM_POOLS_STAT_NEW_ALLOC()
|
||||
# define JMEM_POOLS_STAT_REUSE()
|
||||
# define JMEM_POOLS_STAT_DEALLOC()
|
||||
#endif /* JMEM_STATS */
|
||||
|
||||
/*
|
||||
* Valgrind-related options and headers
|
||||
*/
|
||||
#ifdef JERRY_VALGRIND
|
||||
# include "memcheck.h"
|
||||
|
||||
# define VALGRIND_NOACCESS_SPACE(p, s) VALGRIND_MAKE_MEM_NOACCESS((p), (s))
|
||||
# define VALGRIND_UNDEFINED_SPACE(p, s) VALGRIND_MAKE_MEM_UNDEFINED((p), (s))
|
||||
# define VALGRIND_DEFINED_SPACE(p, s) VALGRIND_MAKE_MEM_DEFINED((p), (s))
|
||||
#else /* !JERRY_VALGRIND */
|
||||
# define VALGRIND_NOACCESS_SPACE(p, s)
|
||||
# define VALGRIND_UNDEFINED_SPACE(p, s)
|
||||
# define VALGRIND_DEFINED_SPACE(p, s)
|
||||
#endif /* JERRY_VALGRIND */
|
||||
|
||||
#ifdef JERRY_VALGRIND_FREYA
|
||||
# include "memcheck.h"
|
||||
|
||||
# define VALGRIND_FREYA_MALLOCLIKE_SPACE(p, s) VALGRIND_MALLOCLIKE_BLOCK((p), (s), 0, 0)
|
||||
# define VALGRIND_FREYA_FREELIKE_SPACE(p) VALGRIND_FREELIKE_BLOCK((p), 0)
|
||||
#else /* !JERRY_VALGRIND_FREYA */
|
||||
# define VALGRIND_FREYA_MALLOCLIKE_SPACE(p, s)
|
||||
# define VALGRIND_FREYA_FREELIKE_SPACE(p)
|
||||
#endif /* JERRY_VALGRIND_FREYA */
|
||||
|
||||
/**
|
||||
* Initialize pool manager
|
||||
*/
|
||||
void
|
||||
jmem_pools_init (void)
|
||||
{
|
||||
JERRY_STATIC_ASSERT (sizeof (jmem_pools_chunk_t) <= JMEM_POOL_CHUNK_SIZE,
|
||||
size_of_mem_pools_chunk_t_must_be_less_than_or_equal_to_MEM_POOL_CHUNK_SIZE);
|
||||
|
||||
jmem_free_chunk_p = NULL;
|
||||
|
||||
JMEM_POOLS_STAT_INIT ();
|
||||
} /* jmem_pools_init */
|
||||
|
||||
/**
|
||||
* Finalize pool manager
|
||||
*/
|
||||
void
|
||||
jmem_pools_finalize (void)
|
||||
{
|
||||
jmem_pools_collect_empty ();
|
||||
|
||||
JERRY_ASSERT (jmem_free_chunk_p == NULL);
|
||||
} /* jmem_pools_finalize */
|
||||
|
||||
/**
|
||||
* Allocate a chunk of specified size
|
||||
*
|
||||
* @return pointer to allocated chunk, if allocation was successful,
|
||||
* or NULL - if not enough memory.
|
||||
*/
|
||||
inline void * __attribute__((hot)) __attr_always_inline___
|
||||
jmem_pools_alloc (void)
|
||||
{
|
||||
#ifdef JMEM_GC_BEFORE_EACH_ALLOC
|
||||
jmem_run_try_to_give_memory_back_callbacks (JMEM_TRY_GIVE_MEMORY_BACK_SEVERITY_HIGH);
|
||||
#endif /* JMEM_GC_BEFORE_EACH_ALLOC */
|
||||
|
||||
if (jmem_free_chunk_p != NULL)
|
||||
{
|
||||
const jmem_pools_chunk_t *const chunk_p = jmem_free_chunk_p;
|
||||
|
||||
JMEM_POOLS_STAT_REUSE ();
|
||||
|
||||
VALGRIND_DEFINED_SPACE (chunk_p, JMEM_POOL_CHUNK_SIZE);
|
||||
|
||||
jmem_free_chunk_p = chunk_p->next_p;
|
||||
|
||||
VALGRIND_UNDEFINED_SPACE (chunk_p, JMEM_POOL_CHUNK_SIZE);
|
||||
|
||||
return (void *) chunk_p;
|
||||
}
|
||||
else
|
||||
{
|
||||
JMEM_POOLS_STAT_NEW_ALLOC ();
|
||||
return (void *) jmem_heap_alloc_block (JMEM_POOL_CHUNK_SIZE);
|
||||
}
|
||||
} /* jmem_pools_alloc */
|
||||
|
||||
/**
|
||||
* Free the chunk
|
||||
*/
|
||||
void __attribute__((hot))
|
||||
jmem_pools_free (void *chunk_p) /**< pointer to the chunk */
|
||||
{
|
||||
jmem_pools_chunk_t *const chunk_to_free_p = (jmem_pools_chunk_t *) chunk_p;
|
||||
|
||||
VALGRIND_DEFINED_SPACE (chunk_to_free_p, JMEM_POOL_CHUNK_SIZE);
|
||||
|
||||
chunk_to_free_p->next_p = jmem_free_chunk_p;
|
||||
jmem_free_chunk_p = chunk_to_free_p;
|
||||
|
||||
VALGRIND_NOACCESS_SPACE (chunk_to_free_p, JMEM_POOL_CHUNK_SIZE);
|
||||
|
||||
JMEM_POOLS_STAT_FREE_POOL ();
|
||||
} /* jmem_pools_free */
|
||||
|
||||
/**
|
||||
* Collect empty pool chunks
|
||||
*/
|
||||
void
|
||||
jmem_pools_collect_empty ()
|
||||
{
|
||||
while (jmem_free_chunk_p)
|
||||
{
|
||||
VALGRIND_DEFINED_SPACE (jmem_free_chunk_p, sizeof (jmem_pools_chunk_t));
|
||||
jmem_pools_chunk_t *const next_p = jmem_free_chunk_p->next_p;
|
||||
VALGRIND_NOACCESS_SPACE (jmem_free_chunk_p, sizeof (jmem_pools_chunk_t));
|
||||
|
||||
jmem_heap_free_block (jmem_free_chunk_p, JMEM_POOL_CHUNK_SIZE);
|
||||
JMEM_POOLS_STAT_DEALLOC ();
|
||||
jmem_free_chunk_p = next_p;
|
||||
}
|
||||
} /* jmem_pools_collect_empty */
|
||||
|
||||
#ifdef JMEM_STATS
|
||||
/**
|
||||
* Get pools memory usage statistics
|
||||
*/
|
||||
void
|
||||
jmem_pools_get_stats (jmem_pools_stats_t *out_pools_stats_p) /**< [out] pools' stats */
|
||||
{
|
||||
JERRY_ASSERT (out_pools_stats_p != NULL);
|
||||
|
||||
*out_pools_stats_p = jmem_pools_stats;
|
||||
} /* jmem_pools_get_stats */
|
||||
|
||||
/**
|
||||
* Reset peak values in memory usage statistics
|
||||
*/
|
||||
void
|
||||
jmem_pools_stats_reset_peak (void)
|
||||
{
|
||||
jmem_pools_stats.peak_pools_count = jmem_pools_stats.pools_count;
|
||||
} /* jmem_pools_stats_reset_peak */
|
||||
|
||||
/**
|
||||
* Print pools memory usage statistics
|
||||
*/
|
||||
void
|
||||
jmem_pools_stats_print (void)
|
||||
{
|
||||
printf ("Pools stats:\n"
|
||||
" Chunk size: %zu\n"
|
||||
" Pool chunks: %zu\n"
|
||||
" Peak pool chunks: %zu\n"
|
||||
" Free chunks: %zu\n"
|
||||
" Pool reuse ratio: %zu.%04zu\n",
|
||||
JMEM_POOL_CHUNK_SIZE,
|
||||
jmem_pools_stats.pools_count,
|
||||
jmem_pools_stats.peak_pools_count,
|
||||
jmem_pools_stats.free_chunks,
|
||||
jmem_pools_stats.reused_count / jmem_pools_stats.new_alloc_count,
|
||||
jmem_pools_stats.reused_count % jmem_pools_stats.new_alloc_count * 10000 / jmem_pools_stats.new_alloc_count);
|
||||
} /* jmem_pools_stats_print */
|
||||
|
||||
/**
|
||||
* Initalize pools' memory usage statistics account structure
|
||||
*/
|
||||
static void
|
||||
jmem_pools_stat_init (void)
|
||||
{
|
||||
memset (&jmem_pools_stats, 0, sizeof (jmem_pools_stats));
|
||||
} /* jmem_pools_stat_init */
|
||||
|
||||
/**
|
||||
* Account for allocation of new pool chunk
|
||||
*/
|
||||
static void
|
||||
jmem_pools_stat_new_alloc (void)
|
||||
{
|
||||
jmem_pools_stats.pools_count++;
|
||||
jmem_pools_stats.new_alloc_count++;
|
||||
|
||||
if (jmem_pools_stats.pools_count > jmem_pools_stats.peak_pools_count)
|
||||
{
|
||||
jmem_pools_stats.peak_pools_count = jmem_pools_stats.pools_count;
|
||||
}
|
||||
if (jmem_pools_stats.pools_count > jmem_pools_stats.global_peak_pools_count)
|
||||
{
|
||||
jmem_pools_stats.global_peak_pools_count = jmem_pools_stats.pools_count;
|
||||
}
|
||||
} /* jmem_pools_stat_new_alloc */
|
||||
|
||||
|
||||
/**
|
||||
* Account for reuse of pool chunk
|
||||
*/
|
||||
static void
|
||||
jmem_pools_stat_reuse (void)
|
||||
{
|
||||
jmem_pools_stats.pools_count++;
|
||||
jmem_pools_stats.free_chunks--;
|
||||
jmem_pools_stats.reused_count++;
|
||||
|
||||
if (jmem_pools_stats.pools_count > jmem_pools_stats.peak_pools_count)
|
||||
{
|
||||
jmem_pools_stats.peak_pools_count = jmem_pools_stats.pools_count;
|
||||
}
|
||||
if (jmem_pools_stats.pools_count > jmem_pools_stats.global_peak_pools_count)
|
||||
{
|
||||
jmem_pools_stats.global_peak_pools_count = jmem_pools_stats.pools_count;
|
||||
}
|
||||
} /* jmem_pools_stat_reuse */
|
||||
|
||||
|
||||
/**
|
||||
* Account for freeing a chunk
|
||||
*/
|
||||
static void
|
||||
jmem_pools_stat_free_pool (void)
|
||||
{
|
||||
JERRY_ASSERT (jmem_pools_stats.pools_count > 0);
|
||||
|
||||
jmem_pools_stats.pools_count--;
|
||||
jmem_pools_stats.free_chunks++;
|
||||
} /* jmem_pools_stat_free_pool */
|
||||
|
||||
/**
|
||||
* Account for freeing a chunk
|
||||
*/
|
||||
static void
|
||||
jmem_pools_stat_dealloc (void)
|
||||
{
|
||||
jmem_pools_stats.free_chunks--;
|
||||
} /* jmem_pools_stat_dealloc */
|
||||
#endif /* JMEM_STATS */
|
||||
|
||||
/**
|
||||
* @}
|
||||
* @}
|
||||
*/
|
||||
@@ -0,0 +1,73 @@
|
||||
/* Copyright 2014-2016 Samsung Electronics Co., Ltd.
|
||||
* Copyright 2016 University of Szeged.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Pool manager interface
|
||||
*/
|
||||
#ifndef JMEM_POOLMAN_H
|
||||
#define JMEM_POOLMAN_H
|
||||
|
||||
#include "jrt.h"
|
||||
|
||||
/** \addtogroup mem Memory allocation
|
||||
* @{
|
||||
*
|
||||
* \addtogroup poolman Memory pool manager
|
||||
* @{
|
||||
*/
|
||||
|
||||
extern void jmem_pools_init (void);
|
||||
extern void jmem_pools_finalize (void);
|
||||
extern void *jmem_pools_alloc (void);
|
||||
extern void jmem_pools_free (void *);
|
||||
extern void jmem_pools_collect_empty (void);
|
||||
|
||||
#ifdef JMEM_STATS
|
||||
/**
|
||||
* Pools' memory usage statistics
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
/** pools' count */
|
||||
size_t pools_count;
|
||||
|
||||
/** peak pools' count */
|
||||
size_t peak_pools_count;
|
||||
|
||||
/** non-resettable peak pools' count */
|
||||
size_t global_peak_pools_count;
|
||||
|
||||
/** free chunks count */
|
||||
size_t free_chunks;
|
||||
|
||||
/* Number of newly allocated pool chunks */
|
||||
size_t new_alloc_count;
|
||||
|
||||
/* Number of reused pool chunks */
|
||||
size_t reused_count;
|
||||
} jmem_pools_stats_t;
|
||||
|
||||
extern void jmem_pools_get_stats (jmem_pools_stats_t *);
|
||||
extern void jmem_pools_stats_reset_peak (void);
|
||||
extern void jmem_pools_stats_print (void);
|
||||
#endif /* JMEM_STATS */
|
||||
|
||||
/**
|
||||
* @}
|
||||
* @}
|
||||
*/
|
||||
|
||||
#endif /* !JMEM_POOLMAN_H */
|
||||
Reference in New Issue
Block a user