2012-09-04 13:54:00 +01:00
|
|
|
/*-
|
|
|
|
* BSD LICENSE
|
2014-06-04 00:42:50 +01:00
|
|
|
*
|
2014-02-10 11:46:50 +00:00
|
|
|
* Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
|
2012-09-04 13:54:00 +01:00
|
|
|
* All rights reserved.
|
2014-06-04 00:42:50 +01:00
|
|
|
*
|
2013-09-18 12:00:00 +02:00
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions
|
2012-09-04 13:54:00 +01:00
|
|
|
* are met:
|
2014-06-04 00:42:50 +01:00
|
|
|
*
|
2013-09-18 12:00:00 +02:00
|
|
|
* * Redistributions of source code must retain the above copyright
|
2012-09-04 13:54:00 +01:00
|
|
|
* notice, this list of conditions and the following disclaimer.
|
2013-09-18 12:00:00 +02:00
|
|
|
* * Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in
|
|
|
|
* the documentation and/or other materials provided with the
|
2012-09-04 13:54:00 +01:00
|
|
|
* distribution.
|
2013-09-18 12:00:00 +02:00
|
|
|
* * Neither the name of Intel Corporation nor the names of its
|
|
|
|
* contributors may be used to endorse or promote products derived
|
2012-09-04 13:54:00 +01:00
|
|
|
* from this software without specific prior written permission.
|
2014-06-04 00:42:50 +01:00
|
|
|
*
|
2013-09-18 12:00:00 +02:00
|
|
|
* 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
|
2012-09-04 13:54:00 +01:00
|
|
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
*/
|
|
|
|
#include <stdint.h>
|
|
|
|
#include <stddef.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdarg.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <sys/queue.h>
|
|
|
|
|
|
|
|
#include <rte_memory.h>
|
|
|
|
#include <rte_memzone.h>
|
|
|
|
#include <rte_tailq.h>
|
|
|
|
#include <rte_eal.h>
|
2012-12-20 00:00:00 +01:00
|
|
|
#include <rte_eal_memconfig.h>
|
2012-09-04 13:54:00 +01:00
|
|
|
#include <rte_launch.h>
|
|
|
|
#include <rte_per_lcore.h>
|
|
|
|
#include <rte_lcore.h>
|
|
|
|
#include <rte_common.h>
|
|
|
|
#include <rte_string_fns.h>
|
|
|
|
#include <rte_spinlock.h>
|
2012-12-20 00:00:00 +01:00
|
|
|
#include <rte_memcpy.h>
|
|
|
|
#include <rte_atomic.h>
|
2012-09-04 13:54:00 +01:00
|
|
|
|
|
|
|
#include "malloc_elem.h"
|
|
|
|
#include "malloc_heap.h"
|
|
|
|
|
|
|
|
/* since the memzone size starts with a digit, it will appear unquoted in
|
|
|
|
* rte_config.h, so quote it so it can be passed to rte_str_to_size */
|
2012-12-20 00:00:00 +01:00
|
|
|
#define MALLOC_MEMZONE_SIZE RTE_STR(RTE_MALLOC_MEMZONE_SIZE)
|
2012-09-04 13:54:00 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* returns the configuration setting for the memzone size as a size_t value
|
|
|
|
*/
|
|
|
|
static inline size_t
|
|
|
|
get_malloc_memzone_size(void)
|
|
|
|
{
|
|
|
|
return rte_str_to_size(MALLOC_MEMZONE_SIZE);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* reserve an extra memory zone and make it available for use by a particular
|
|
|
|
* heap. This reserves the zone and sets a dummy malloc_elem header at the end
|
|
|
|
* to prevent overflow. The rest of the zone is added to free list as a single
|
|
|
|
* large free block
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
malloc_heap_add_memzone(struct malloc_heap *heap, size_t size, unsigned align)
|
|
|
|
{
|
|
|
|
const unsigned mz_flags = 0;
|
2013-09-18 12:00:00 +02:00
|
|
|
const size_t block_size = get_malloc_memzone_size();
|
2012-09-04 13:54:00 +01:00
|
|
|
/* ensure the data we want to allocate will fit in the memzone */
|
2013-09-18 12:00:00 +02:00
|
|
|
const size_t min_size = size + align + MALLOC_ELEM_OVERHEAD * 2;
|
|
|
|
const struct rte_memzone *mz = NULL;
|
2014-04-18 14:56:17 +02:00
|
|
|
struct rte_mem_config *mcfg = rte_eal_get_configuration()->mem_config;
|
|
|
|
unsigned numa_socket = heap - mcfg->malloc_heaps;
|
2013-09-18 12:00:00 +02:00
|
|
|
|
|
|
|
size_t mz_size = min_size;
|
|
|
|
if (mz_size < block_size)
|
|
|
|
mz_size = block_size;
|
2012-09-04 13:54:00 +01:00
|
|
|
|
|
|
|
char mz_name[RTE_MEMZONE_NAMESIZE];
|
2014-06-24 11:15:28 -07:00
|
|
|
snprintf(mz_name, sizeof(mz_name), "MALLOC_S%u_HEAP_%u",
|
2014-04-18 14:56:17 +02:00
|
|
|
numa_socket, heap->mz_count++);
|
2013-09-18 12:00:00 +02:00
|
|
|
|
|
|
|
/* try getting a block. if we fail and we don't need as big a block
|
|
|
|
* as given in the config, we can shrink our request and try again
|
|
|
|
*/
|
|
|
|
do {
|
2014-04-18 14:56:17 +02:00
|
|
|
mz = rte_memzone_reserve(mz_name, mz_size, numa_socket,
|
|
|
|
mz_flags);
|
2013-09-18 12:00:00 +02:00
|
|
|
if (mz == NULL)
|
|
|
|
mz_size /= 2;
|
|
|
|
} while (mz == NULL && mz_size > min_size);
|
2012-09-04 13:54:00 +01:00
|
|
|
if (mz == NULL)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
/* allocate the memory block headers, one at end, one at start */
|
|
|
|
struct malloc_elem *start_elem = (struct malloc_elem *)mz->addr;
|
|
|
|
struct malloc_elem *end_elem = RTE_PTR_ADD(mz->addr,
|
|
|
|
mz_size - MALLOC_ELEM_OVERHEAD);
|
2012-12-20 00:00:00 +01:00
|
|
|
end_elem = RTE_PTR_ALIGN_FLOOR(end_elem, CACHE_LINE_SIZE);
|
2012-09-04 13:54:00 +01:00
|
|
|
|
|
|
|
const unsigned elem_size = (uintptr_t)end_elem - (uintptr_t)start_elem;
|
2013-03-19 17:00:02 +01:00
|
|
|
malloc_elem_init(start_elem, heap, mz, elem_size);
|
2012-09-04 13:54:00 +01:00
|
|
|
malloc_elem_mkend(end_elem, start_elem);
|
malloc: fix linear complexity
Problems with lib rte_malloc:
1. Rte_malloc searches a heap's entire free list looking for the best
fit, resulting in linear complexity.
2. Heaps store free blocks in a singly-linked list, resulting in
linear complexity when rte_free needs to remove an adjacent block.
3. The library inserts and removes free blocks with ad hoc, in-line
code, rather than using linked-list functions or macros.
4. The library wastes potential small blocks of size 64 and 128 bytes
(plus overhead of 64 bytes) as padding when reusing free blocks or
resizing allocated blocks.
This patch addresses those problems as follows:
1. Replace single free list with a handful of free lists. Each free
list contains blocks of a specified size range, for example:
list[0]: (0 , 2^8]
list[1]: (2^8 , 2^10]
list[2]: (2^10, 2^12]
list[3]: (2^12, 2^14]
list[4]: (2^14, MAX_SIZE]
When allocating a block, start at the first list that can contain
a big enough block. Search subsequent lists, if necessary.
Terminate the search as soon as we find a block that is big enough.
2. Use doubly-linked lists, so that we can remove free blocks in
constant time.
3. Use BSD LIST macros, as defined in sys/queue.h and the QUEUE(3)
man page.
4. Change code to utilize small blocks of data size 64 and 128, when
splitting larger blocks.
Signed-off-by: Robert Sanford <rsanford2@gmail.com>
Acked-by: Pablo de Lara <pablo.de.lara.guarch@intel.com>
2014-06-23 17:17:09 -04:00
|
|
|
malloc_elem_free_list_insert(start_elem);
|
2012-09-04 13:54:00 +01:00
|
|
|
|
2012-12-20 00:00:00 +01:00
|
|
|
/* increase heap total size by size of new memzone */
|
|
|
|
heap->total_size+=mz_size - MALLOC_ELEM_OVERHEAD;
|
2012-09-04 13:54:00 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Iterates through the freelist for a heap to find a free element
|
|
|
|
* which can store data of the required size and with the requested alignment.
|
malloc: fix linear complexity
Problems with lib rte_malloc:
1. Rte_malloc searches a heap's entire free list looking for the best
fit, resulting in linear complexity.
2. Heaps store free blocks in a singly-linked list, resulting in
linear complexity when rte_free needs to remove an adjacent block.
3. The library inserts and removes free blocks with ad hoc, in-line
code, rather than using linked-list functions or macros.
4. The library wastes potential small blocks of size 64 and 128 bytes
(plus overhead of 64 bytes) as padding when reusing free blocks or
resizing allocated blocks.
This patch addresses those problems as follows:
1. Replace single free list with a handful of free lists. Each free
list contains blocks of a specified size range, for example:
list[0]: (0 , 2^8]
list[1]: (2^8 , 2^10]
list[2]: (2^10, 2^12]
list[3]: (2^12, 2^14]
list[4]: (2^14, MAX_SIZE]
When allocating a block, start at the first list that can contain
a big enough block. Search subsequent lists, if necessary.
Terminate the search as soon as we find a block that is big enough.
2. Use doubly-linked lists, so that we can remove free blocks in
constant time.
3. Use BSD LIST macros, as defined in sys/queue.h and the QUEUE(3)
man page.
4. Change code to utilize small blocks of data size 64 and 128, when
splitting larger blocks.
Signed-off-by: Robert Sanford <rsanford2@gmail.com>
Acked-by: Pablo de Lara <pablo.de.lara.guarch@intel.com>
2014-06-23 17:17:09 -04:00
|
|
|
* Returns null on failure, or pointer to element on success.
|
2012-09-04 13:54:00 +01:00
|
|
|
*/
|
|
|
|
static struct malloc_elem *
|
malloc: fix linear complexity
Problems with lib rte_malloc:
1. Rte_malloc searches a heap's entire free list looking for the best
fit, resulting in linear complexity.
2. Heaps store free blocks in a singly-linked list, resulting in
linear complexity when rte_free needs to remove an adjacent block.
3. The library inserts and removes free blocks with ad hoc, in-line
code, rather than using linked-list functions or macros.
4. The library wastes potential small blocks of size 64 and 128 bytes
(plus overhead of 64 bytes) as padding when reusing free blocks or
resizing allocated blocks.
This patch addresses those problems as follows:
1. Replace single free list with a handful of free lists. Each free
list contains blocks of a specified size range, for example:
list[0]: (0 , 2^8]
list[1]: (2^8 , 2^10]
list[2]: (2^10, 2^12]
list[3]: (2^12, 2^14]
list[4]: (2^14, MAX_SIZE]
When allocating a block, start at the first list that can contain
a big enough block. Search subsequent lists, if necessary.
Terminate the search as soon as we find a block that is big enough.
2. Use doubly-linked lists, so that we can remove free blocks in
constant time.
3. Use BSD LIST macros, as defined in sys/queue.h and the QUEUE(3)
man page.
4. Change code to utilize small blocks of data size 64 and 128, when
splitting larger blocks.
Signed-off-by: Robert Sanford <rsanford2@gmail.com>
Acked-by: Pablo de Lara <pablo.de.lara.guarch@intel.com>
2014-06-23 17:17:09 -04:00
|
|
|
find_suitable_element(struct malloc_heap *heap, size_t size, unsigned align)
|
2012-09-04 13:54:00 +01:00
|
|
|
{
|
malloc: fix linear complexity
Problems with lib rte_malloc:
1. Rte_malloc searches a heap's entire free list looking for the best
fit, resulting in linear complexity.
2. Heaps store free blocks in a singly-linked list, resulting in
linear complexity when rte_free needs to remove an adjacent block.
3. The library inserts and removes free blocks with ad hoc, in-line
code, rather than using linked-list functions or macros.
4. The library wastes potential small blocks of size 64 and 128 bytes
(plus overhead of 64 bytes) as padding when reusing free blocks or
resizing allocated blocks.
This patch addresses those problems as follows:
1. Replace single free list with a handful of free lists. Each free
list contains blocks of a specified size range, for example:
list[0]: (0 , 2^8]
list[1]: (2^8 , 2^10]
list[2]: (2^10, 2^12]
list[3]: (2^12, 2^14]
list[4]: (2^14, MAX_SIZE]
When allocating a block, start at the first list that can contain
a big enough block. Search subsequent lists, if necessary.
Terminate the search as soon as we find a block that is big enough.
2. Use doubly-linked lists, so that we can remove free blocks in
constant time.
3. Use BSD LIST macros, as defined in sys/queue.h and the QUEUE(3)
man page.
4. Change code to utilize small blocks of data size 64 and 128, when
splitting larger blocks.
Signed-off-by: Robert Sanford <rsanford2@gmail.com>
Acked-by: Pablo de Lara <pablo.de.lara.guarch@intel.com>
2014-06-23 17:17:09 -04:00
|
|
|
size_t idx;
|
|
|
|
struct malloc_elem *elem;
|
|
|
|
|
|
|
|
for (idx = malloc_elem_free_list_index(size);
|
|
|
|
idx < RTE_HEAP_NUM_FREELISTS; idx++)
|
|
|
|
{
|
|
|
|
for (elem = LIST_FIRST(&heap->free_head[idx]);
|
|
|
|
!!elem; elem = LIST_NEXT(elem, free_list))
|
|
|
|
{
|
|
|
|
if (malloc_elem_can_hold(elem, size, align))
|
|
|
|
return elem;
|
2013-06-03 00:00:00 +00:00
|
|
|
}
|
2012-09-04 13:54:00 +01:00
|
|
|
}
|
malloc: fix linear complexity
Problems with lib rte_malloc:
1. Rte_malloc searches a heap's entire free list looking for the best
fit, resulting in linear complexity.
2. Heaps store free blocks in a singly-linked list, resulting in
linear complexity when rte_free needs to remove an adjacent block.
3. The library inserts and removes free blocks with ad hoc, in-line
code, rather than using linked-list functions or macros.
4. The library wastes potential small blocks of size 64 and 128 bytes
(plus overhead of 64 bytes) as padding when reusing free blocks or
resizing allocated blocks.
This patch addresses those problems as follows:
1. Replace single free list with a handful of free lists. Each free
list contains blocks of a specified size range, for example:
list[0]: (0 , 2^8]
list[1]: (2^8 , 2^10]
list[2]: (2^10, 2^12]
list[3]: (2^12, 2^14]
list[4]: (2^14, MAX_SIZE]
When allocating a block, start at the first list that can contain
a big enough block. Search subsequent lists, if necessary.
Terminate the search as soon as we find a block that is big enough.
2. Use doubly-linked lists, so that we can remove free blocks in
constant time.
3. Use BSD LIST macros, as defined in sys/queue.h and the QUEUE(3)
man page.
4. Change code to utilize small blocks of data size 64 and 128, when
splitting larger blocks.
Signed-off-by: Robert Sanford <rsanford2@gmail.com>
Acked-by: Pablo de Lara <pablo.de.lara.guarch@intel.com>
2014-06-23 17:17:09 -04:00
|
|
|
return NULL;
|
2012-09-04 13:54:00 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Main function called by malloc to allocate a block of memory from the
|
|
|
|
* heap. It locks the free list, scans it, and adds a new memzone if the
|
|
|
|
* scan fails. Once the new memzone is added, it re-scans and should return
|
|
|
|
* the new element after releasing the lock.
|
|
|
|
*/
|
|
|
|
void *
|
|
|
|
malloc_heap_alloc(struct malloc_heap *heap,
|
|
|
|
const char *type __attribute__((unused)), size_t size, unsigned align)
|
|
|
|
{
|
|
|
|
size = CACHE_LINE_ROUNDUP(size);
|
|
|
|
align = CACHE_LINE_ROUNDUP(align);
|
|
|
|
rte_spinlock_lock(&heap->lock);
|
malloc: fix linear complexity
Problems with lib rte_malloc:
1. Rte_malloc searches a heap's entire free list looking for the best
fit, resulting in linear complexity.
2. Heaps store free blocks in a singly-linked list, resulting in
linear complexity when rte_free needs to remove an adjacent block.
3. The library inserts and removes free blocks with ad hoc, in-line
code, rather than using linked-list functions or macros.
4. The library wastes potential small blocks of size 64 and 128 bytes
(plus overhead of 64 bytes) as padding when reusing free blocks or
resizing allocated blocks.
This patch addresses those problems as follows:
1. Replace single free list with a handful of free lists. Each free
list contains blocks of a specified size range, for example:
list[0]: (0 , 2^8]
list[1]: (2^8 , 2^10]
list[2]: (2^10, 2^12]
list[3]: (2^12, 2^14]
list[4]: (2^14, MAX_SIZE]
When allocating a block, start at the first list that can contain
a big enough block. Search subsequent lists, if necessary.
Terminate the search as soon as we find a block that is big enough.
2. Use doubly-linked lists, so that we can remove free blocks in
constant time.
3. Use BSD LIST macros, as defined in sys/queue.h and the QUEUE(3)
man page.
4. Change code to utilize small blocks of data size 64 and 128, when
splitting larger blocks.
Signed-off-by: Robert Sanford <rsanford2@gmail.com>
Acked-by: Pablo de Lara <pablo.de.lara.guarch@intel.com>
2014-06-23 17:17:09 -04:00
|
|
|
struct malloc_elem *elem = find_suitable_element(heap, size, align);
|
2012-09-04 13:54:00 +01:00
|
|
|
if (elem == NULL){
|
2012-12-20 00:00:00 +01:00
|
|
|
if ((malloc_heap_add_memzone(heap, size, align)) == 0)
|
malloc: fix linear complexity
Problems with lib rte_malloc:
1. Rte_malloc searches a heap's entire free list looking for the best
fit, resulting in linear complexity.
2. Heaps store free blocks in a singly-linked list, resulting in
linear complexity when rte_free needs to remove an adjacent block.
3. The library inserts and removes free blocks with ad hoc, in-line
code, rather than using linked-list functions or macros.
4. The library wastes potential small blocks of size 64 and 128 bytes
(plus overhead of 64 bytes) as padding when reusing free blocks or
resizing allocated blocks.
This patch addresses those problems as follows:
1. Replace single free list with a handful of free lists. Each free
list contains blocks of a specified size range, for example:
list[0]: (0 , 2^8]
list[1]: (2^8 , 2^10]
list[2]: (2^10, 2^12]
list[3]: (2^12, 2^14]
list[4]: (2^14, MAX_SIZE]
When allocating a block, start at the first list that can contain
a big enough block. Search subsequent lists, if necessary.
Terminate the search as soon as we find a block that is big enough.
2. Use doubly-linked lists, so that we can remove free blocks in
constant time.
3. Use BSD LIST macros, as defined in sys/queue.h and the QUEUE(3)
man page.
4. Change code to utilize small blocks of data size 64 and 128, when
splitting larger blocks.
Signed-off-by: Robert Sanford <rsanford2@gmail.com>
Acked-by: Pablo de Lara <pablo.de.lara.guarch@intel.com>
2014-06-23 17:17:09 -04:00
|
|
|
elem = find_suitable_element(heap, size, align);
|
2012-09-04 13:54:00 +01:00
|
|
|
}
|
2012-12-20 00:00:00 +01:00
|
|
|
|
|
|
|
if (elem != NULL){
|
malloc: fix linear complexity
Problems with lib rte_malloc:
1. Rte_malloc searches a heap's entire free list looking for the best
fit, resulting in linear complexity.
2. Heaps store free blocks in a singly-linked list, resulting in
linear complexity when rte_free needs to remove an adjacent block.
3. The library inserts and removes free blocks with ad hoc, in-line
code, rather than using linked-list functions or macros.
4. The library wastes potential small blocks of size 64 and 128 bytes
(plus overhead of 64 bytes) as padding when reusing free blocks or
resizing allocated blocks.
This patch addresses those problems as follows:
1. Replace single free list with a handful of free lists. Each free
list contains blocks of a specified size range, for example:
list[0]: (0 , 2^8]
list[1]: (2^8 , 2^10]
list[2]: (2^10, 2^12]
list[3]: (2^12, 2^14]
list[4]: (2^14, MAX_SIZE]
When allocating a block, start at the first list that can contain
a big enough block. Search subsequent lists, if necessary.
Terminate the search as soon as we find a block that is big enough.
2. Use doubly-linked lists, so that we can remove free blocks in
constant time.
3. Use BSD LIST macros, as defined in sys/queue.h and the QUEUE(3)
man page.
4. Change code to utilize small blocks of data size 64 and 128, when
splitting larger blocks.
Signed-off-by: Robert Sanford <rsanford2@gmail.com>
Acked-by: Pablo de Lara <pablo.de.lara.guarch@intel.com>
2014-06-23 17:17:09 -04:00
|
|
|
elem = malloc_elem_alloc(elem, size, align);
|
2012-12-20 00:00:00 +01:00
|
|
|
/* increase heap's count of allocated elements */
|
|
|
|
heap->alloc_count++;
|
|
|
|
}
|
2012-09-04 13:54:00 +01:00
|
|
|
rte_spinlock_unlock(&heap->lock);
|
|
|
|
return elem == NULL ? NULL : (void *)(&elem[1]);
|
2012-12-20 00:00:00 +01:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Function to retrieve data for heap on given socket
|
|
|
|
*/
|
|
|
|
int
|
2013-07-12 12:12:15 +02:00
|
|
|
malloc_heap_get_stats(const struct malloc_heap *heap,
|
2012-12-20 00:00:00 +01:00
|
|
|
struct rte_malloc_socket_stats *socket_stats)
|
|
|
|
{
|
malloc: fix linear complexity
Problems with lib rte_malloc:
1. Rte_malloc searches a heap's entire free list looking for the best
fit, resulting in linear complexity.
2. Heaps store free blocks in a singly-linked list, resulting in
linear complexity when rte_free needs to remove an adjacent block.
3. The library inserts and removes free blocks with ad hoc, in-line
code, rather than using linked-list functions or macros.
4. The library wastes potential small blocks of size 64 and 128 bytes
(plus overhead of 64 bytes) as padding when reusing free blocks or
resizing allocated blocks.
This patch addresses those problems as follows:
1. Replace single free list with a handful of free lists. Each free
list contains blocks of a specified size range, for example:
list[0]: (0 , 2^8]
list[1]: (2^8 , 2^10]
list[2]: (2^10, 2^12]
list[3]: (2^12, 2^14]
list[4]: (2^14, MAX_SIZE]
When allocating a block, start at the first list that can contain
a big enough block. Search subsequent lists, if necessary.
Terminate the search as soon as we find a block that is big enough.
2. Use doubly-linked lists, so that we can remove free blocks in
constant time.
3. Use BSD LIST macros, as defined in sys/queue.h and the QUEUE(3)
man page.
4. Change code to utilize small blocks of data size 64 and 128, when
splitting larger blocks.
Signed-off-by: Robert Sanford <rsanford2@gmail.com>
Acked-by: Pablo de Lara <pablo.de.lara.guarch@intel.com>
2014-06-23 17:17:09 -04:00
|
|
|
size_t idx;
|
|
|
|
struct malloc_elem *elem;
|
2012-12-20 00:00:00 +01:00
|
|
|
|
|
|
|
/* Initialise variables for heap */
|
|
|
|
socket_stats->free_count = 0;
|
|
|
|
socket_stats->heap_freesz_bytes = 0;
|
|
|
|
socket_stats->greatest_free_size = 0;
|
|
|
|
|
|
|
|
/* Iterate through free list */
|
malloc: fix linear complexity
Problems with lib rte_malloc:
1. Rte_malloc searches a heap's entire free list looking for the best
fit, resulting in linear complexity.
2. Heaps store free blocks in a singly-linked list, resulting in
linear complexity when rte_free needs to remove an adjacent block.
3. The library inserts and removes free blocks with ad hoc, in-line
code, rather than using linked-list functions or macros.
4. The library wastes potential small blocks of size 64 and 128 bytes
(plus overhead of 64 bytes) as padding when reusing free blocks or
resizing allocated blocks.
This patch addresses those problems as follows:
1. Replace single free list with a handful of free lists. Each free
list contains blocks of a specified size range, for example:
list[0]: (0 , 2^8]
list[1]: (2^8 , 2^10]
list[2]: (2^10, 2^12]
list[3]: (2^12, 2^14]
list[4]: (2^14, MAX_SIZE]
When allocating a block, start at the first list that can contain
a big enough block. Search subsequent lists, if necessary.
Terminate the search as soon as we find a block that is big enough.
2. Use doubly-linked lists, so that we can remove free blocks in
constant time.
3. Use BSD LIST macros, as defined in sys/queue.h and the QUEUE(3)
man page.
4. Change code to utilize small blocks of data size 64 and 128, when
splitting larger blocks.
Signed-off-by: Robert Sanford <rsanford2@gmail.com>
Acked-by: Pablo de Lara <pablo.de.lara.guarch@intel.com>
2014-06-23 17:17:09 -04:00
|
|
|
for (idx = 0; idx < RTE_HEAP_NUM_FREELISTS; idx++) {
|
|
|
|
for (elem = LIST_FIRST(&heap->free_head[idx]);
|
|
|
|
!!elem; elem = LIST_NEXT(elem, free_list))
|
|
|
|
{
|
|
|
|
socket_stats->free_count++;
|
|
|
|
socket_stats->heap_freesz_bytes += elem->size;
|
|
|
|
if (elem->size > socket_stats->greatest_free_size)
|
|
|
|
socket_stats->greatest_free_size = elem->size;
|
|
|
|
}
|
2012-12-20 00:00:00 +01:00
|
|
|
}
|
|
|
|
/* Get stats on overall heap and allocated memory on this heap */
|
|
|
|
socket_stats->heap_totalsz_bytes = heap->total_size;
|
|
|
|
socket_stats->heap_allocsz_bytes = (socket_stats->heap_totalsz_bytes -
|
|
|
|
socket_stats->heap_freesz_bytes);
|
|
|
|
socket_stats->alloc_count = heap->alloc_count;
|
|
|
|
return 0;
|
2012-09-04 13:54:00 +01:00
|
|
|
}
|
2012-12-20 00:00:00 +01:00
|
|
|
|