Compare commits
2 commits
bde7511577
...
9223d06dbb
| Author | SHA1 | Date | |
|---|---|---|---|
| 9223d06dbb | |||
| f0d62111f3 |
5 changed files with 505 additions and 0 deletions
6
Makefile
6
Makefile
|
|
@ -75,6 +75,12 @@ build/tests/test_mem_range: tests/test_mem_range.c $(TEST_MEM_RANGE_DEPS) build/
|
||||||
@"$(CC)" $(CFLAGS) -c -o $@.o $< $(CPPFLAGS)
|
@"$(CC)" $(CFLAGS) -c -o $@.o $< $(CPPFLAGS)
|
||||||
@"$(CC)" -o $@ $@.o $(TEST_MEM_RANGE_DEPS)
|
@"$(CC)" -o $@ $@.o $(TEST_MEM_RANGE_DEPS)
|
||||||
|
|
||||||
|
TEST_TLSF_DEPS=build/src/test.o build/src/tlsf.o
|
||||||
|
build/tests/test_tlsf: tests/test_tlsf.c $(TEST_TLSF_DEPS) build/tests
|
||||||
|
@printf "CC %s\n" $@
|
||||||
|
@"$(CC)" $(CFLAGS) -c -o $@.o $< $(CPPFLAGS)
|
||||||
|
@"$(CC)" -o $@ $@.o $(TEST_TLSF_DEPS)
|
||||||
|
|
||||||
build/tests:
|
build/tests:
|
||||||
mkdir -p $@
|
mkdir -p $@
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,5 +14,6 @@
|
||||||
__attribute__ ((noreturn))
|
__attribute__ ((noreturn))
|
||||||
void test_fail(const char *file, unsigned int line, const char *msg);
|
void test_fail(const char *file, unsigned int line, const char *msg);
|
||||||
void test_success(const char *file, unsigned int line, const char *msg);
|
void test_success(const char *file, unsigned int line, const char *msg);
|
||||||
|
void printf(const char *restrict fmt, ...);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
44
include/tlsf.h
Normal file
44
include/tlsf.h
Normal file
|
|
@ -0,0 +1,44 @@
|
||||||
|
#ifndef KARLOS_TLSF_H
|
||||||
|
#define KARLOS_TLSF_H
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
struct tlsf_pool {
|
||||||
|
// the total pool size, including space reserved for allocator structs.
|
||||||
|
size_t pool_size;
|
||||||
|
size_t sli_shift;
|
||||||
|
|
||||||
|
uint64_t bitmap;
|
||||||
|
struct tlsf_free_lv2 *free[];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct tlsf_free_lv2 {
|
||||||
|
uint64_t bitmap;
|
||||||
|
struct tlsf_block_hdr *free[];
|
||||||
|
};
|
||||||
|
|
||||||
|
// #define TLSF_BLOCK_HDR_CANARY 0xb10c5555aaaab10c
|
||||||
|
|
||||||
|
struct tlsf_block_hdr {
|
||||||
|
// uint64_t canary;
|
||||||
|
uint64_t info;
|
||||||
|
struct tlsf_block_hdr *prev_phys_block;
|
||||||
|
struct tlsf_block_hdr *next_free;
|
||||||
|
struct tlsf_block_hdr *prev_free;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// TODO may inline this later, but leave it here now (also for testing)
|
||||||
|
void tlsf_mapping(size_t sz, size_t sli_shift, size_t *first, size_t *second);
|
||||||
|
size_t tlsf_num_lv1_buckets(size_t pool_size);
|
||||||
|
void tlsf_mapping_next(size_t sz, size_t sli_shift, size_t *first, size_t *second);
|
||||||
|
bool tlsf_find_free_list(struct tlsf_pool *pool, size_t sz, size_t *first_out, size_t *second_out);
|
||||||
|
void tlsf_mapping_range(size_t first, size_t second, size_t sli_shift, size_t *begin, size_t *end);
|
||||||
|
|
||||||
|
struct tlsf_pool *tlsf_init(void *mem, size_t pool_size, size_t sli_shift);
|
||||||
|
void *tlsf_malloc(struct tlsf_pool *pool, size_t size);
|
||||||
|
void tlsf_free(struct tlsf_pool *pool, void *addr);
|
||||||
|
|
||||||
|
#endif
|
||||||
216
src/tlsf.c
Normal file
216
src/tlsf.c
Normal file
|
|
@ -0,0 +1,216 @@
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "std.h"
|
||||||
|
#include "tlsf.h"
|
||||||
|
|
||||||
|
// Highest bit set (0-indexed).
|
||||||
|
// - 4 (100) has highest bit 2.
|
||||||
|
// - 10 (1010) has highest bit 3.
|
||||||
|
// The following holds: (1 << HIGHEST_BIT_SET(sz)) <= sz
|
||||||
|
// Don't use for `sz == 0`.
|
||||||
|
#define HIGHEST_BIT_SET(sz) (63 - __builtin_clzl(sz))
|
||||||
|
|
||||||
|
// Calculate the mapping.
|
||||||
|
// `first` is highest bit set.
|
||||||
|
// `second` are the `sli_shift` bits below the highest bit set (padded with 0 to the right if necessary).
|
||||||
|
void tlsf_mapping(size_t sz, size_t sli_shift, size_t *first, size_t *second) {
|
||||||
|
ASSERT(sz > 0);
|
||||||
|
size_t hb = HIGHEST_BIT_SET(sz);
|
||||||
|
size_t mask = (1ull << sli_shift) - 1;
|
||||||
|
*first = hb;
|
||||||
|
if (hb >= sli_shift) {
|
||||||
|
*second = (sz >> (hb - sli_shift)) & mask;
|
||||||
|
} else {
|
||||||
|
*second = (sz << (sli_shift - hb)) & mask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// index `i` in the level 1 lists is for [1 << (i+4), 1<<(i+5)]
|
||||||
|
// we don't need lists for elements < 16 because we round up anyways.
|
||||||
|
#define LV1_LIST_OFFSET 4
|
||||||
|
|
||||||
|
size_t tlsf_num_lv1_buckets(size_t pool_size) {
|
||||||
|
return HIGHEST_BIT_SET(pool_size) - LV1_LIST_OFFSET + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define IS_ALIGNED_16(sz) (((uint64_t)(sz) & (uint64_t)15) == 0)
|
||||||
|
#define ROUND_UP(n, shift) ((((uint64_t)n) + ((1ull << shift) - 1)) & ~(uint64_t)((1ull << shift) - 1))
|
||||||
|
|
||||||
|
// must be char pointer.
|
||||||
|
#define PTR_ADVANCE(ptr, base_struct, num_pointers) do { \
|
||||||
|
(ptr) += sizeof(base_struct) + num_pointers*sizeof(void *); \
|
||||||
|
(ptr) = (char *) ROUND_UP(ptr, 4); \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
#define INFO_PACK(size, is_last_physical, is_free) \
|
||||||
|
(((uint64_t)(size) & ~3ull) | ((uint64_t)(is_last_physical) << 1) | ((uint64_t)(is_free)))
|
||||||
|
#define INFO_UNPACK_SIZE(info) ((info) & ~3ull)
|
||||||
|
#define INFO_UNPACK_IS_LAST_PHYSICAL(info) (((info) >> 1) & 0x1)
|
||||||
|
#define INFO_UNPACK_IS_FREE(info) ((info) & 0x1)
|
||||||
|
|
||||||
|
// Effective block size is the size that can actually be used by an allocation.
|
||||||
|
// subtract size of "used" header.
|
||||||
|
#define EFFECTIVE_BLOCK_SIZE(sz) ((sz) - (sizeof(struct tlsf_block_hdr) - 2*sizeof(struct tlsf_block_hdr *)))
|
||||||
|
|
||||||
|
struct tlsf_pool *tlsf_init(void *mem, size_t pool_size, size_t sli_shift) {
|
||||||
|
ASSERT(mem != NULL);
|
||||||
|
ASSERT(IS_ALIGNED_16(mem));
|
||||||
|
ASSERT(pool_size >= 4096); // TODO is this enough? Better estimate?
|
||||||
|
ASSERT(IS_ALIGNED_16(pool_size));
|
||||||
|
ASSERT(sli_shift <= 6);
|
||||||
|
|
||||||
|
struct tlsf_pool *lv1 = mem;
|
||||||
|
lv1->pool_size = pool_size;
|
||||||
|
lv1->sli_shift = sli_shift;
|
||||||
|
lv1->bitmap = 0;
|
||||||
|
size_t num_lv1_buckets = tlsf_num_lv1_buckets(pool_size);
|
||||||
|
char *currp = (char *) mem;
|
||||||
|
PTR_ADVANCE(currp, struct tlsf_pool, num_lv1_buckets);
|
||||||
|
for (size_t lv1_idx = 0; lv1_idx < num_lv1_buckets; lv1_idx++) {
|
||||||
|
// allocate second level
|
||||||
|
struct tlsf_free_lv2 *lv2 = (struct tlsf_free_lv2 *)currp;
|
||||||
|
lv1->free[lv1_idx] = lv2;
|
||||||
|
lv2->bitmap = 0;
|
||||||
|
memset(&lv2->free[0], 0, (1 << sli_shift) * sizeof(void *));
|
||||||
|
PTR_ADVANCE(currp, struct tlsf_free_lv2, (1 << sli_shift));
|
||||||
|
}
|
||||||
|
|
||||||
|
// free this one remaining block
|
||||||
|
struct tlsf_block_hdr *free_block = (struct tlsf_block_hdr *) currp;
|
||||||
|
size_t remaining = EFFECTIVE_BLOCK_SIZE((intptr_t)mem + pool_size - (intptr_t)currp);
|
||||||
|
ASSERT(remaining >= 16);
|
||||||
|
size_t first, second;
|
||||||
|
tlsf_mapping(remaining, sli_shift, &first, &second);
|
||||||
|
lv1->bitmap |= (1ull << (first - LV1_LIST_OFFSET));
|
||||||
|
struct tlsf_free_lv2 *lv2 = lv1->free[first - LV1_LIST_OFFSET];
|
||||||
|
lv2->bitmap |= (1ull << second);
|
||||||
|
lv2->free[second] = free_block;
|
||||||
|
free_block->info = INFO_PACK(remaining, true, true);
|
||||||
|
free_block->prev_phys_block = NULL;
|
||||||
|
free_block->next_free = free_block;
|
||||||
|
free_block->prev_free = free_block;
|
||||||
|
|
||||||
|
return lv1;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct tlsf_free_lv2 *access_in_lv1(struct tlsf_pool *pool, size_t first) {
|
||||||
|
ASSERT(first >= LV1_LIST_OFFSET);
|
||||||
|
return pool->free[first - LV1_LIST_OFFSET];
|
||||||
|
}
|
||||||
|
|
||||||
|
// find smallest non-empty free list starting at index `first` (inclusive).
|
||||||
|
// This will be the smallest non-empty list including items >= `1 << first`.
|
||||||
|
struct tlsf_free_lv2 *find_in_lv1(struct tlsf_pool *pool, size_t first) {
|
||||||
|
ASSERT(first >= LV1_LIST_OFFSET);
|
||||||
|
uint64_t search = pool->bitmap >> (first - LV1_LIST_OFFSET);
|
||||||
|
if (search == 0) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
size_t move_up = __builtin_ffsl(search) - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define IS_POWER_OF_2(n) (__builtin_popcountl(n) == 1)
|
||||||
|
|
||||||
|
// returns if this `sz` is at the beginning (smallest size) of a bucket
|
||||||
|
bool tlsf_starts_range(size_t sz, size_t sli_shift) {
|
||||||
|
size_t hb = HIGHEST_BIT_SET(sz);
|
||||||
|
if (hb <= sli_shift) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
size_t mask = (1ull << (hb - sli_shift)) - 1;
|
||||||
|
return (sz & mask) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// returns the range that is described by first and second values, for testing
|
||||||
|
void tlsf_mapping_range(size_t first, size_t second, size_t sli_shift, size_t *begin, size_t *nelem) {
|
||||||
|
// TODO
|
||||||
|
size_t b = (1 << first);
|
||||||
|
if (first >= sli_shift) {
|
||||||
|
b |= second << (first - sli_shift);
|
||||||
|
} else {
|
||||||
|
b |= second >> (sli_shift - first);
|
||||||
|
}
|
||||||
|
*begin = b;
|
||||||
|
*nelem = (first > sli_shift) ? (1 << (first - sli_shift)) : 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// sets `first` and `second` so that they point to a range where all elements are >= sz
|
||||||
|
void tlsf_mapping_next(size_t sz, size_t sli_shift, size_t *first, size_t *second) {
|
||||||
|
tlsf_mapping(sz, sli_shift, first, second);
|
||||||
|
if (!tlsf_starts_range(sz, sli_shift)) {
|
||||||
|
if (*second + 1 < (1ull << sli_shift)) {
|
||||||
|
(*second)++;
|
||||||
|
} else {
|
||||||
|
(*first)++;
|
||||||
|
*second = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#define LV1_BITMAP_GET(pool, first) (((pool)->bitmap >> (first - LV1_LIST_OFFSET)) & 1)
|
||||||
|
|
||||||
|
|
||||||
|
// modifies first
|
||||||
|
bool tlsf_lv1_bitmap_find(uint64_t bitmap, size_t *first) {
|
||||||
|
ASSERT(first != NULL && *first >= LV1_LIST_OFFSET);
|
||||||
|
bitmap >>= *first - LV1_LIST_OFFSET;
|
||||||
|
if (bitmap == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
*first = __builtin_ctzl(bitmap) + *first;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool tlsf_lv2_bitmap_find(uint64_t bitmap, size_t *second) {
|
||||||
|
ASSERT(second != NULL);
|
||||||
|
bitmap >>= *second;
|
||||||
|
if (bitmap == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
*second = __builtin_ctzl(bitmap) + *second;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *tlsf_malloc(struct tlsf_pool *pool, size_t sz) {
|
||||||
|
if (sz < 16) {
|
||||||
|
sz = 16;
|
||||||
|
}
|
||||||
|
size_t first, second;
|
||||||
|
tlsf_mapping_next(sz, pool->sli_shift, &first, &second);
|
||||||
|
size_t old_first = first;
|
||||||
|
if (!tlsf_lv1_bitmap_find(pool->bitmap, &first)) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct tlsf_free_lv2 *lv2 = pool->free[first - LV1_LIST_OFFSET];
|
||||||
|
if (old_first < first) {
|
||||||
|
second = 0;
|
||||||
|
}
|
||||||
|
if (!tlsf_lv2_bitmap_find(lv2->bitmap, &second)) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
struct tlsf_block_hdr *hdr = lv2->free[second];
|
||||||
|
ASSERT(hdr != NULL);
|
||||||
|
ASSERT(INFO_UNPACK_SIZE(hdr->info) >= sz);
|
||||||
|
ASSERT(INFO_UNPACK_IS_FREE(hdr->info));
|
||||||
|
if (hdr->next_free == hdr) {
|
||||||
|
// list is now empty
|
||||||
|
lv2->free[second] = NULL;
|
||||||
|
lv2->bitmap &= ~(1ull << second);
|
||||||
|
} else {
|
||||||
|
lv2->free[second] = hdr->next_free;
|
||||||
|
// remove self from list
|
||||||
|
hdr->next_free->prev_free = hdr->prev_free;
|
||||||
|
hdr->prev_free->next_free = hdr->next_free;
|
||||||
|
}
|
||||||
|
hdr->info &= ~1ull; // clear 'free' bit
|
||||||
|
return &hdr->next_free; // this is the data that's not present in an occupied block
|
||||||
|
}
|
||||||
|
|
||||||
|
void tlsf_free(struct tlsf_pool *pool, void *addr) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
// - circular linked list, is this correct?
|
||||||
|
// - what is T used for?
|
||||||
238
tests/test_tlsf.c
Normal file
238
tests/test_tlsf.c
Normal file
|
|
@ -0,0 +1,238 @@
|
||||||
|
#include "tlsf.h"
|
||||||
|
#include "test.h"
|
||||||
|
|
||||||
|
void test_mapping(void) {
|
||||||
|
static size_t mapping_test[63][2] = {
|
||||||
|
{ 0, 0 },
|
||||||
|
|
||||||
|
{ 1, 0 },
|
||||||
|
{ 1, 8 },
|
||||||
|
|
||||||
|
{ 2, 0 },
|
||||||
|
{ 2, 4 },
|
||||||
|
{ 2, 8 },
|
||||||
|
{ 2, 12 },
|
||||||
|
|
||||||
|
{ 3, 0 },
|
||||||
|
{ 3, 2 },
|
||||||
|
{ 3, 4 },
|
||||||
|
{ 3, 6 },
|
||||||
|
{ 3, 8 },
|
||||||
|
{ 3, 10 },
|
||||||
|
{ 3, 12 },
|
||||||
|
{ 3, 14 },
|
||||||
|
|
||||||
|
{ 4, 0 },
|
||||||
|
{ 4, 1 },
|
||||||
|
{ 4, 2 },
|
||||||
|
{ 4, 3 },
|
||||||
|
{ 4, 4 },
|
||||||
|
{ 4, 5 },
|
||||||
|
{ 4, 6 },
|
||||||
|
{ 4, 7 },
|
||||||
|
{ 4, 8 },
|
||||||
|
{ 4, 9 },
|
||||||
|
{ 4, 10 },
|
||||||
|
{ 4, 11 },
|
||||||
|
{ 4, 12 },
|
||||||
|
{ 4, 13 },
|
||||||
|
{ 4, 14 },
|
||||||
|
{ 4, 15 },
|
||||||
|
|
||||||
|
{ 5, 0 },
|
||||||
|
{ 5, 0 },
|
||||||
|
{ 5, 1 },
|
||||||
|
{ 5, 1 },
|
||||||
|
{ 5, 2 },
|
||||||
|
{ 5, 2 },
|
||||||
|
{ 5, 3 },
|
||||||
|
{ 5, 3 },
|
||||||
|
{ 5, 4 },
|
||||||
|
{ 5, 4 },
|
||||||
|
{ 5, 5 },
|
||||||
|
{ 5, 5 },
|
||||||
|
{ 5, 6 },
|
||||||
|
{ 5, 6 },
|
||||||
|
{ 5, 7 },
|
||||||
|
{ 5, 7 },
|
||||||
|
{ 5, 8 },
|
||||||
|
{ 5, 8 },
|
||||||
|
{ 5, 9 },
|
||||||
|
{ 5, 9 },
|
||||||
|
{ 5, 10 },
|
||||||
|
{ 5, 10 },
|
||||||
|
{ 5, 11 },
|
||||||
|
{ 5, 11 },
|
||||||
|
{ 5, 12 },
|
||||||
|
{ 5, 12 },
|
||||||
|
{ 5, 13 },
|
||||||
|
{ 5, 13 },
|
||||||
|
{ 5, 14 },
|
||||||
|
{ 5, 14 },
|
||||||
|
{ 5, 15 },
|
||||||
|
{ 5, 15 }
|
||||||
|
};
|
||||||
|
size_t first, second;
|
||||||
|
for (size_t i = 0; i < 63; i++) {
|
||||||
|
tlsf_mapping(i + 1, 4, &first, &second);
|
||||||
|
TEST_ASSERT(first == mapping_test[i][0] && second == mapping_test[i][1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_bucket_size(void) {
|
||||||
|
for (size_t i = 16; i < 32; i++) {
|
||||||
|
TEST_ASSERT(tlsf_num_lv1_buckets(i) == 1);
|
||||||
|
}
|
||||||
|
TEST_ASSERT(tlsf_num_lv1_buckets(32) == 2);
|
||||||
|
TEST_ASSERT(tlsf_num_lv1_buckets(63) == 2);
|
||||||
|
TEST_ASSERT(tlsf_num_lv1_buckets(64) == 3); // 2^6, 2^5, 2^4
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_access(struct tlsf_pool *pool) {
|
||||||
|
pool->bitmap = 1ull << 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_mapping_range(void) {
|
||||||
|
size_t begin, nelem;
|
||||||
|
tlsf_mapping_range(1, 0, 4, &begin, &nelem);
|
||||||
|
TEST_ASSERT(begin == 2 && nelem == 1);
|
||||||
|
tlsf_mapping_range(1, 8, 4, &begin, &nelem);
|
||||||
|
TEST_ASSERT(begin == 3 && nelem == 1);
|
||||||
|
tlsf_mapping_range(2, 0, 4, &begin, &nelem);
|
||||||
|
TEST_ASSERT(begin == 4 && nelem == 1);
|
||||||
|
tlsf_mapping_range(2, 4, 4, &begin, &nelem);
|
||||||
|
TEST_ASSERT(begin == 5 && nelem == 1);
|
||||||
|
tlsf_mapping_range(2, 8, 4, &begin, &nelem);
|
||||||
|
TEST_ASSERT(begin == 6 && nelem == 1);
|
||||||
|
tlsf_mapping_range(2, 12, 4, &begin, &nelem);
|
||||||
|
TEST_ASSERT(begin == 7 && nelem == 1);
|
||||||
|
tlsf_mapping_range(3, 0, 4, &begin, &nelem);
|
||||||
|
TEST_ASSERT(begin == 8 && nelem == 1);
|
||||||
|
tlsf_mapping_range(3, 2, 4, &begin, &nelem);
|
||||||
|
TEST_ASSERT(begin == 9 && nelem == 1);
|
||||||
|
tlsf_mapping_range(3, 4, 4, &begin, &nelem);
|
||||||
|
TEST_ASSERT(begin == 10 && nelem == 1);
|
||||||
|
tlsf_mapping_range(3, 6, 4, &begin, &nelem);
|
||||||
|
TEST_ASSERT(begin == 11 && nelem == 1);
|
||||||
|
tlsf_mapping_range(3, 8, 4, &begin, &nelem);
|
||||||
|
TEST_ASSERT(begin == 12 && nelem == 1);
|
||||||
|
tlsf_mapping_range(3, 10, 4, &begin, &nelem);
|
||||||
|
TEST_ASSERT(begin == 13 && nelem == 1);
|
||||||
|
tlsf_mapping_range(3, 12, 4, &begin, &nelem);
|
||||||
|
TEST_ASSERT(begin == 14 && nelem == 1);
|
||||||
|
tlsf_mapping_range(3, 14, 4, &begin, &nelem);
|
||||||
|
TEST_ASSERT(begin == 15 && nelem == 1);
|
||||||
|
tlsf_mapping_range(4, 0, 4, &begin, &nelem);
|
||||||
|
TEST_ASSERT(begin == 16 && nelem == 1);
|
||||||
|
tlsf_mapping_range(4, 1, 4, &begin, &nelem);
|
||||||
|
TEST_ASSERT(begin == 17 && nelem == 1);
|
||||||
|
tlsf_mapping_range(4, 2, 4, &begin, &nelem);
|
||||||
|
TEST_ASSERT(begin == 18 && nelem == 1);
|
||||||
|
// ...
|
||||||
|
tlsf_mapping_range(4, 15, 4, &begin, &nelem);
|
||||||
|
TEST_ASSERT(begin == 31 && nelem == 1);
|
||||||
|
tlsf_mapping_range(5, 0, 4, &begin, &nelem);
|
||||||
|
TEST_ASSERT(begin == 32 && nelem == 2);
|
||||||
|
tlsf_mapping_range(5, 1, 4, &begin, &nelem);
|
||||||
|
TEST_ASSERT(begin == 34 && nelem == 2);
|
||||||
|
tlsf_mapping_range(6, 0, 4, &begin, &nelem);
|
||||||
|
TEST_ASSERT(begin == 64 && nelem == 4);
|
||||||
|
tlsf_mapping_range(6, 1, 4, &begin, &nelem);
|
||||||
|
TEST_ASSERT(begin == 68 && nelem == 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_mapping_next(void) {
|
||||||
|
size_t first, second;
|
||||||
|
size_t begin, nelem;
|
||||||
|
// try for each size
|
||||||
|
for (size_t sz = 1; sz < 256; sz++) {
|
||||||
|
tlsf_mapping_next(sz, 4, &first, &second);
|
||||||
|
tlsf_mapping_range(first, second, 4, &begin, &nelem);
|
||||||
|
TEST_ASSERT(sz <= begin);
|
||||||
|
|
||||||
|
// now, test that we actually got the smallest range
|
||||||
|
if (second > 0) {
|
||||||
|
second--;
|
||||||
|
} else if (first > 1) {
|
||||||
|
first--;
|
||||||
|
} else {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
tlsf_mapping_range(first, second, 4, &begin, &nelem);
|
||||||
|
TEST_ASSERT(sz > begin);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool tlsf_starts_range(size_t, size_t);
|
||||||
|
void test_starts_range() {
|
||||||
|
for (size_t i = 1; i < 32; i++) {
|
||||||
|
TEST_ASSERT(tlsf_starts_range(i, 4));
|
||||||
|
}
|
||||||
|
for (size_t i = 32; i < 64; i++) {
|
||||||
|
TEST_ASSERT(tlsf_starts_range(i, 4) == (i%2 == 0));
|
||||||
|
}
|
||||||
|
for (size_t i = 64; i < 128; i++) {
|
||||||
|
TEST_ASSERT(tlsf_starts_range(i, 4) == (i%4 == 0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool tlsf_lv1_bitmap_find(uint64_t, size_t *);
|
||||||
|
void test_lv1_bitmap_find() {
|
||||||
|
size_t first;
|
||||||
|
|
||||||
|
first = 4;
|
||||||
|
TEST_ASSERT(!tlsf_lv1_bitmap_find(0x00, &first));
|
||||||
|
first = 4;
|
||||||
|
TEST_ASSERT(tlsf_lv1_bitmap_find(0x01, &first) && first == 4);
|
||||||
|
first = 4;
|
||||||
|
TEST_ASSERT(tlsf_lv1_bitmap_find(0x02, &first) && first == 5);
|
||||||
|
first = 4;
|
||||||
|
TEST_ASSERT(tlsf_lv1_bitmap_find(0x03, &first) && first == 4);
|
||||||
|
first = 4;
|
||||||
|
TEST_ASSERT(tlsf_lv1_bitmap_find(0x04, &first) && first == 6);
|
||||||
|
first = 4;
|
||||||
|
TEST_ASSERT(tlsf_lv1_bitmap_find(0x05, &first) && first == 4);
|
||||||
|
|
||||||
|
first = 5;
|
||||||
|
TEST_ASSERT(!tlsf_lv1_bitmap_find(0x00, &first));
|
||||||
|
first = 5;
|
||||||
|
TEST_ASSERT(!tlsf_lv1_bitmap_find(0x01, &first));
|
||||||
|
first = 5;
|
||||||
|
TEST_ASSERT(tlsf_lv1_bitmap_find(0x02, &first) && first == 5);
|
||||||
|
first = 5;
|
||||||
|
TEST_ASSERT(tlsf_lv1_bitmap_find(0x03, &first) && first == 5);
|
||||||
|
first = 5;
|
||||||
|
TEST_ASSERT(tlsf_lv1_bitmap_find(0x04, &first) && first == 6);
|
||||||
|
first = 5;
|
||||||
|
TEST_ASSERT(tlsf_lv1_bitmap_find(0x05, &first) && first == 6);
|
||||||
|
first = 5;
|
||||||
|
TEST_ASSERT(tlsf_lv1_bitmap_find(0x06, &first) && first == 5);
|
||||||
|
first = 5;
|
||||||
|
TEST_ASSERT(tlsf_lv1_bitmap_find(0x07, &first) && first == 5);
|
||||||
|
first = 5;
|
||||||
|
TEST_ASSERT(tlsf_lv1_bitmap_find(0x08, &first) && first == 7);
|
||||||
|
first = 5;
|
||||||
|
TEST_ASSERT(tlsf_lv1_bitmap_find(0x09, &first) && first == 7);
|
||||||
|
first = 5;
|
||||||
|
TEST_ASSERT(tlsf_lv1_bitmap_find(0x0a, &first) && first == 5);
|
||||||
|
first = 5;
|
||||||
|
TEST_ASSERT(tlsf_lv1_bitmap_find(0x0b, &first) && first == 5);
|
||||||
|
first = 5;
|
||||||
|
TEST_ASSERT(tlsf_lv1_bitmap_find(0x0c, &first) && first == 6);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define POOL_SIZE 4096
|
||||||
|
char mem[POOL_SIZE] __attribute__ ((aligned (16)));
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
test_mapping();
|
||||||
|
TEST_ASSERT(1 == 1);
|
||||||
|
test_bucket_size();
|
||||||
|
TEST_ASSERT(2 == 2);
|
||||||
|
test_starts_range();
|
||||||
|
test_mapping_range();
|
||||||
|
test_mapping_next();
|
||||||
|
test_lv1_bitmap_find();
|
||||||
|
for (int i = 0; i < POOL_SIZE; i++) ((char*)mem)[i] = 0x55;
|
||||||
|
tlsf_init(mem, POOL_SIZE, 4);
|
||||||
|
}
|
||||||
Loading…
Add table
Reference in a new issue