jerryscript/jerry-core/jmem/jmem-poolman.c
2016-06-13 05:35:53 -07:00

313 lines
8.0 KiB
C

/* 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_free_unused_memory_callbacks (JMEM_FREE_UNUSED_MEMORY_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 */
/**
* @}
* @}
*/