Implementing resize of heap blocks.

- adding mem_heap_try_resize_block routine that tries to resize
   block using free space that is located right after the resized block;
 - placing long-term blocks from start of heap space and short-term - from end
   of the space to increase probability of success of resizing just allocated
   long-term block;
 - adding mem_heap_try_resize_block invocation to 'test_heap' unit test.
This commit is contained in:
Ruben Ayrapetyan 2014-11-11 15:25:19 +03:00
parent 4875762cfc
commit bd60d1874b
3 changed files with 164 additions and 7 deletions

View File

@ -415,7 +415,7 @@ mem_heap_alloc_block (size_t size_in_bytes, /**< size of region to all
mem_check_heap ();
if (alloc_term == MEM_HEAP_ALLOC_SHORT_TERM)
if (alloc_term == MEM_HEAP_ALLOC_LONG_TERM)
{
block_p = mem_heap.first_block_p;
direction = MEM_DIRECTION_NEXT;
@ -473,7 +473,7 @@ mem_heap_alloc_block (size_t size_in_bytes, /**< size of region to all
mem_init_block_header (new_free_block_first_chunk_p,
0,
MEM_BLOCK_FREE,
block_p /* there we will place new allocated block */,
block_p,
next_block_p);
mem_block_header_t *new_free_block_p = (mem_block_header_t*) new_free_block_first_chunk_p;
@ -521,6 +521,143 @@ mem_heap_alloc_block (size_t size_in_bytes, /**< size of region to all
return data_space_p;
} /* mem_heap_alloc_block */
/**
* Try to resize memory region.
*
* @return true - if resize is successful,
* false - if there is not enough memory in front of the block.
*/
bool
mem_heap_try_resize_block (uint8_t *ptr, /**< pointer to beginning of data space of the block to resize */
size_t size_in_bytes) /**< new block size */
{
/* checking that ptr points to the heap */
JERRY_ASSERT(ptr >= mem_heap.heap_start
&& ptr <= mem_heap.heap_start + mem_heap.heap_size);
mem_check_heap ();
mem_block_header_t *block_p = (mem_block_header_t*) ptr - 1;
VALGRIND_DEFINED_STRUCT(block_p);
JERRY_ASSERT(block_p->magic_num == MEM_MAGIC_NUM_OF_ALLOCATED_BLOCK);
/* For heap statistics unit we show what is going on as though
* the block is freed and then new block (the same or resized)
* is allocated */
mem_heap_stat_free_block (block_p);
size_t current_block_may_expand_up_to = mem_get_block_data_space_size (block_p);
bool is_resized = false;
if (current_block_may_expand_up_to >= size_in_bytes)
{
is_resized = true;
}
else
{
size_t need_additional_bytes = size_in_bytes - current_block_may_expand_up_to;
mem_block_header_t *next_block_p = mem_get_next_block_by_direction (block_p, MEM_DIRECTION_NEXT);
if (next_block_p != NULL)
{
VALGRIND_DEFINED_STRUCT (next_block_p);
if (next_block_p->magic_num == MEM_MAGIC_NUM_OF_FREE_BLOCK)
{
size_t next_block_data_space_size = mem_get_block_data_space_size (next_block_p);
if (next_block_data_space_size >= need_additional_bytes)
{
/* next block is free and contains enough space */
is_resized = true;
size_t new_block_chunks_count = mem_get_block_chunks_count_from_data_size (size_in_bytes);
size_t current_block_chunks_count = mem_get_block_chunks_count (block_p);
size_t next_block_chunks_count = mem_get_block_chunks_count (next_block_p);
JERRY_ASSERT (new_block_chunks_count <= current_block_chunks_count + next_block_chunks_count);
size_t diff_in_chunks = (size_t) ((current_block_chunks_count +
next_block_chunks_count) - new_block_chunks_count);
mem_block_header_t *block_after_next_p = mem_get_next_block_by_direction (next_block_p,
MEM_DIRECTION_NEXT);
mem_block_header_t *new_next_of_current_block_p;
mem_block_header_t *new_prev_of_block_after_next_p;
if (diff_in_chunks > 0)
{
mem_block_header_t *new_free_block_p = (mem_block_header_t*) ((uint8_t*) block_p +
new_block_chunks_count * MEM_HEAP_CHUNK_SIZE);
mem_init_block_header ((uint8_t*) new_free_block_p,
0,
MEM_BLOCK_FREE,
block_p,
block_after_next_p);
new_prev_of_block_after_next_p = new_free_block_p;
new_next_of_current_block_p = new_free_block_p;
}
else
{
new_prev_of_block_after_next_p = block_p;
new_next_of_current_block_p = block_after_next_p;
}
block_p->neighbours[ MEM_DIRECTION_NEXT ] = mem_get_block_neighbour_field (block_p,
new_next_of_current_block_p);
if (block_after_next_p != NULL)
{
VALGRIND_DEFINED_STRUCT (block_after_next_p);
mem_heap_offset_t offset = mem_get_block_neighbour_field (new_prev_of_block_after_next_p,
block_after_next_p);
block_after_next_p->neighbours[ MEM_DIRECTION_PREV ] = offset;
VALGRIND_NOACCESS_STRUCT (block_after_next_p);
}
else
{
mem_heap.last_block_p = new_prev_of_block_after_next_p;
}
}
}
else
{
JERRY_ASSERT (next_block_p->magic_num == MEM_MAGIC_NUM_OF_ALLOCATED_BLOCK);
}
VALGRIND_NOACCESS_STRUCT (next_block_p);
}
}
if (is_resized)
{
JERRY_ASSERT ((mem_heap_offset_t) size_in_bytes == size_in_bytes);
if (size_in_bytes >= block_p->allocated_bytes)
{
VALGRIND_UNDEFINED_SPACE (ptr + block_p->allocated_bytes, size_in_bytes - block_p->allocated_bytes);
}
block_p->allocated_bytes = (mem_heap_offset_t) size_in_bytes;
}
mem_heap_stat_alloc_block (block_p);
VALGRIND_NOACCESS_STRUCT(block_p);
mem_check_heap ();
return is_resized;
} /* mem_heap_try_resize_block */
/**
* Free the memory block.
*/

View File

@ -42,6 +42,7 @@ typedef enum
extern void mem_heap_init (uint8_t *heap_start, size_t heap_size);
extern void mem_heap_finalize (void);
extern uint8_t* mem_heap_alloc_block (size_t size_in_bytes, mem_heap_alloc_term_t alloc_term);
extern bool mem_heap_try_resize_block (uint8_t *ptr, size_t size_in_bytes);
extern void mem_heap_free_block (uint8_t *ptr);
extern size_t mem_heap_recommend_allocation_size (size_t minimum_allocation_size);
extern void mem_heap_print (bool dump_block_headers, bool dump_block_data, bool dump_stats);

View File

@ -22,17 +22,17 @@ extern long int time (long int *__timer);
extern int printf (__const char *__restrict __format, ...);
extern void *memset (void *__s, int __c, size_t __n);
// Heap size is 8K
const size_t test_heap_size = 8 * 1024;
// Heap size is 32K
const size_t test_heap_size = 32 * 1024;
// Iterations count
const uint32_t test_iters = 1024 * 1024;
const uint32_t test_iters = 64 * 1024;
// Subiterations count
const uint32_t test_sub_iters = 3;
const uint32_t test_sub_iters = 32;
// Threshold size of block to allocate
const uint32_t test_threshold_block_size = 2048;
const uint32_t test_threshold_block_size = 8192;
int
main( int __unused argc,
@ -69,6 +69,25 @@ main( int __unused argc,
// mem_heap_print( true);
for ( uint32_t j = 0; j < subiters; j++ )
{
if ( ptrs[j] != NULL && (rand () % 2) == 0 )
{
for( size_t k = 0; k < sizes[j]; k++ )
{
JERRY_ASSERT( ptrs[j][k] == 0 );
}
size_t new_size = (unsigned int) rand() % ( test_threshold_block_size );
if (mem_heap_try_resize_block (ptrs[j], new_size))
{
sizes[j] = new_size;
memset (ptrs[j], 0, sizes[j]);
}
}
}
for ( uint32_t j = 0; j < subiters; j++ )
{
if ( ptrs[j] != NULL )