Browse Source

replaced home written allocator with well known design

master
Artyom Beilis 8 years ago
parent
commit
2033d558b7
4 changed files with 393 additions and 665 deletions
  1. +322
    -0
      private/buddy_allocator.h
  2. +1
    -0
      private/hash_map.h
  3. +12
    -656
      private/shmem_allocator.h
  4. +58
    -9
      tests/allocator_test.cpp

+ 322
- 0
private/buddy_allocator.h View File

@@ -0,0 +1,322 @@
///////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2008-2012 Artyom Beilis (Tonkikh) <artyomtnk@yahoo.com>
//
// See accompanying file COPYING.TXT file for licensing details.
//
///////////////////////////////////////////////////////////////////////////////
#ifndef CPPCMS_PRIVATE_BUDDY_ALLOCATOR_H
#define CPPCMS_PRIVATE_BUDDY_ALLOCATOR_H

#include <stddef.h>
#include <assert.h>
#include <memory.h>

#ifdef DEBUG_ALLOCATOR
#include <stdio.h>
#define LOG(...) do { printf("%5d:",__LINE__); printf( __VA_ARGS__ ); printf("\n"); } while(0)
#else
#define LOG(...) do {} while(0)
#endif

#ifdef TEST_ALLOCATOR
#include <map>
#include <utility>
#endif
namespace cppcms {
namespace impl {
class buddy_allocator {
struct page;
public:
static const int alignment_bits = (sizeof(void*) > 4 ? 4 : 3);
static const size_t alignment = (1 << alignment_bits); // 8 or 16 at 32 and 64 bit platform

buddy_allocator(size_t memory_size)
{
assert(sizeof(*this) <= memory_size);
assert(sizeof(page) <= alignment * 2);
assert(sizeof(*this) % alignment == 0);
memory_size_ = memory_size - sizeof(*this);
max_bit_size_ = -1;
memset(free_list_,0,sizeof(free_list_));
LOG("Usable memory %zd",memory_size_);
char *pos = memory();
size_t reminder = memory_size_;
for(;;) {
int bits = containts_bits(reminder);
if(bits < alignment_bits + 1)
break;
size_t page_size = size_t(1) << bits;
page *p=reinterpret_cast<page *>(pos);
reminder -= page_size;
LOG("Added chunk of size %zd (%d) at pos %zx reminder %zd",page_size,bits,pos - memory(),reminder);
pos+= page_size;
p->bits = bits;
p->prev = 0;
p->next = 0;
free_list_[bits] = p;
if(max_bit_size_ == -1)
max_bit_size_ = bits;
}
}


void *malloc(size_t required_size)
{
size_t n = ((required_size+alignment-1)/alignment + 1)*alignment;
int bits = get_bits(n);

LOG("Allocating chunk of size %zd (%d) for request of %zd",n,bits,required_size);
page *p = page_alloc(bits);
LOG("Got %zx",(p?(char*)(p) - memory():0));
if(!p)
return 0;
void *r = reinterpret_cast<char *>(p) + alignment;
return r;
}

void free(void *ptr)
{
if(!ptr)
return;
page *p = reinterpret_cast<page *>(static_cast<char *>(ptr) - alignment);
assert(p->bits & page_in_use);
LOG("Freeing page %zx with bits %d",(char *)(p) - memory() , p->bits - page_in_use);
free_page(p);
}

size_t total_free_memory()
{
size_t total = 0;
for(unsigned i=0;i<sizeof(void*)*8;i++) {
total += total_free_at(i);
}
return total;
}
size_t max_free_chunk()
{
for(int bits=sizeof(void*)*8-1;bits>0;bits--) {
if(free_list_[bits])
return total_free_at(bits);
}
return 0;
}
size_t total_free_at(int bits)
{
size_t count=0;
for(page *p=free_list_[bits];p;p=p->next)
count++;
return count * ((size_t(1) << bits) - alignment);
}

#ifdef TEST_ALLOCATOR
void test_free() {
char *p=memory();
for(int i=max_bit_size_;i>=0;i--) {
if(free_list_[i]) {
TEST((char*)free_list_[i]==p);
TEST(free_list_[i]->bits == i);
p += 1ul << free_list_[i]->bits;
}
}
TEST(p<= memory() + memory_size_);
TEST(memory() + memory_size_ - p < int(alignment * 2));
}
void test_and_get_free_pages(std::map<page *,bool> *all_pages=0)
{
for(int i=0;i<int(sizeof(void*)*8);i++) {
if(i+1 < alignment_bits)
TEST(free_list_[i]==0);
if(i>max_bit_size_)
TEST(free_list_[i]==0);

for(page *p=free_list_[i];p;p=p->next) {
// check bit marks
TEST(p->bits == i);
// check linked list
if(p==free_list_[i])
TEST(p->prev == 0);
else
TEST(p->prev->next == p);
if(p->next != 0)
TEST(p->next->prev == p);
if(all_pages) {
TEST(all_pages->find(p) == all_pages->end());
all_pages->insert(std::make_pair(p,true));
}
page *buddy = get_buddy(p);
if(buddy) {
TEST((buddy->bits & page_in_use) || (buddy->bits < p->bits));
TEST((buddy->bits & 0xFF) <= p->bits);
if(all_pages && (buddy->bits & page_in_use))
TEST(all_pages->find(buddy) == all_pages->end());
}
}
}
}
void test_consistent(void * const *allocated,size_t allocated_size)
{
std::map<page *,bool> all_pages;
test_and_get_free_pages(&all_pages);
for(size_t i=0;i<allocated_size;i++) {
if(allocated[i]==0)
continue;
page *p=reinterpret_cast<page *>(static_cast<char *>(allocated[i]) - alignment);
TEST(p->bits & page_in_use);
TEST(all_pages.find(p)==all_pages.end());
all_pages[p]=false;
}
size_t pos = 0;
for(std::map<page *,bool>::const_iterator pg=all_pages.begin();pg!=all_pages.end();++pg) {
page *p=pg->first;
bool is_free = pg->second;
TEST(is_free == !(p->bits & page_in_use));
size_t page_pos = reinterpret_cast<char *>(pg->first) - memory();
TEST(pos == page_pos);
size_t page_size = size_t(1) << (pg->first->bits & 0xFF);
pos+= page_size;
TEST(pos <= memory_size_);
}
TEST(memory_size_ - pos < size_t(alignment * 2));
}
void test_consistent()
{
test_and_get_free_pages(0);
}
#endif

private:

static const int page_in_use = 0x100;

struct page {
int bits;
page *next;
page *prev;
};

static int containts_bits(size_t n)
{
for(int i=sizeof(n)*8-2;i>0;i--) {
size_t upper = size_t(1) << (i + 1);
size_t lower = upper / 2;
if(lower <= n && n< upper)
return i;
}
return -1;
}
static int get_bits(size_t n)
{
int i;
for(i=0;i<int(sizeof(n) * 8);i++) {
if( (1ull << i) >= n)
break;
}
return i;
}


page *page_alloc(int bit_size)
{
LOG("Allocating page %d bits",bit_size);
if(bit_size > max_bit_size_) {
LOG("Too big size requested %d > %d",bit_size,max_bit_size_);
return 0;
}

page *result = 0;
if(free_list_[bit_size]==0) {
LOG("No page for bits %d, splitting",bit_size);
page *to_split = page_alloc(bit_size + 1);
if(!to_split)
return 0;

page *unused = reinterpret_cast<page *>(reinterpret_cast<char *>(to_split) + (size_t(1)<<bit_size));

unused->prev = 0;
unused->next = 0;
unused->bits = bit_size;

free_list_[bit_size] = unused;

result = to_split;
LOG("Got %zx; %zx is spare",(char*)to_split - memory(),(char*)unused - memory());
}
else {
result = free_list_[bit_size];
free_list_[bit_size]=result->next;
if(free_list_[bit_size])
free_list_[bit_size]->prev = 0;
LOG("Using free page %zx, disconnecting",(char*)result - memory());
}

result->next = 0;
result->prev = 0;
result->bits = bit_size + page_in_use;
LOG("Result is %zx",(char*)result - memory());
return result;
}
page *get_buddy(page *p)
{
size_t p_ptr = reinterpret_cast<char *>(p) - memory();
size_t p_len = size_t(1) << p->bits;
size_t b_ptr = p_len ^ p_ptr;
if(b_ptr + p_len > memory_size_)
return 0;
return reinterpret_cast<page *>(b_ptr + memory());
}
void free_page(page *p)
{
assert(p->bits & page_in_use);
for(;;) {
p->bits -= page_in_use;
int bits = p->bits;
LOG("Freing page with bits %d at %zx",bits,(char*)(p) - memory());
page *buddy = get_buddy(p);
if(buddy != 0 && buddy->bits == bits) {
page *bnext = buddy->next;
page *bprev = buddy->prev;
if(bnext)
bnext->prev = bprev;
if(bprev)
bprev->next = bnext;
if(bprev==0) {
free_list_[bits]=bnext;
}
if(buddy < p)
p=buddy;
LOG("Found free buddy merging to %zx with bits %d freeing it as well",(char*)(p)-memory(),bits+1);
p->bits = (bits+1) + page_in_use;
continue; // tail recursion
}
else {
LOG("No buddy avalible - adding to free list");
p->next = free_list_[bits];
p->prev = 0;
if(p->next)
p->next->prev = p;
free_list_[bits] = p;
return;
}
}
}
char *memory()
{
return reinterpret_cast<char *>(this) + sizeof(*this);
}
private:
// DATA

page *free_list_[sizeof(void*)*8]; // 16 always
size_t memory_size_;
int max_bit_size_; // at least sizeof(size_t)
size_t padding_for_alignment_[2];
};
} // impl
} // cppcms

#endif

+ 1
- 0
private/hash_map.h View File

@@ -11,6 +11,7 @@
#include <new>
#include <functional>
#include <vector>
#include <utility>
#include <assert.h>

#include <cppcms/cstdint.h>


+ 12
- 656
private/shmem_allocator.h View File

@@ -16,6 +16,7 @@

#include "basic_allocator.h"
#include "posix_util.h"
#include "buddy_allocator.h"
#include <cppcms/cppcms_error.h>

#include <string>
@@ -24,649 +25,7 @@

namespace cppcms {
namespace impl {
namespace details {

class memory_manager {
public:
memory_manager(size_t n,int bits=12)
{
init(n,bits);
}

void *malloc(size_t n)
{
return slab_alloc(n);
}

void free(void *p)
{
slab_free(p);
}

size_t get_free_memory()
{
size_t max_block = 0;
size_t last_free = 0;
for(size_t i=0;i<map_size;i++) {
if(map[i]==0) {
last_free ++;
if(last_free > max_block)
max_block = last_free;
}
else {
last_free=0;
}
}
return max_block * super_page_size;
}

#ifdef TEST_ALLOCATOR
void test_free()
{
ptest_free();
}
#endif
private:

class segment;

char *memory_start;
size_t map_size;
int page_bits;
size_t page_size;
size_t super_page_size;
int slab_bits;
static const int align_bits = 4;
static const size_t align = 1 << align_bits;
static const int min_bits = align_bits + 1;

segment *all[sizeof(void *)*8][2];
unsigned long long map[1];

static size_t align_addr(size_t pos)
{
return ((pos + (align-1)) >> align_bits) << align_bits;
}

static void *align_addr(void *p)
{
size_t pos = reinterpret_cast<size_t>(p);
pos = align_addr(pos);
return reinterpret_cast<void*>(pos);
}
void init(size_t n,int pb=12)
{
page_bits = pb;
page_size = 1 << page_bits; // 4096
super_page_size = page_size * 64;
slab_bits = page_bits - min_bits;

map_size = (n - align_addr(sizeof(*this))) / (super_page_size + 8);

// sizeof this contains 1 more value for map
memory_start = (char *)(this) + align_addr(sizeof(*this) + map_size * 8);

if(n < align_addr(sizeof(*this)) || map_size == 0) {
throw cppcms::cppcms_error("The provided memory region is too small, increase cache.memory");
}
assert((char *)&map[map_size] <= memory_start);
assert(align_addr(memory_start) == memory_start);
assert(memory_start + super_page_size * map_size <= (char*)(this) + n);
memset(map,0,map_size * 8);
}
class segment {
public:
segment(int bits,int pos)
{
memset(this,0,sizeof(*this));
page_size_in_bits_ = bits;
segment_offset_ = pos;
}
int bits() const
{
return page_size_in_bits_;
}
int segment_size() const
{
return 1 << page_size_in_bits_;
}
int segment_count(size_t page_size) const
{
return page_size / segment_size();
}

int inc()
{
return ++at(0)->segment_count_;
}
int dec()
{
return --at(0)->segment_count_;
}
int count()
{
return at(0)->segment_count_;
}
void count(int n)
{
at(0)->segment_count_ = n;
}

void push(segment *lst[2],char *memory_start)
{
prev(0,memory_start);
if(lst[0]==0) {
next(0,memory_start);
lst[0] = this;
lst[1] = this;
return;
}
next(lst[0],memory_start);
lst[0]->prev(this,memory_start);
lst[0] = this;
}

void erase(segment *lst[2],char *memory_start)
{
if(lst[0]==this)
lst[0]=next(memory_start);
if(lst[1]==this)
lst[1]=prev(memory_start);
if(next_not_null_) {
next(memory_start)->prev(prev(memory_start),memory_start);
}
if(prev_not_null_) {
prev(memory_start)->next(next(memory_start),memory_start);
}
}

segment *at(int pos)
{
int offset = pos - segment_offset_;
void *newp = ((char *)(this)) + offset * segment_size();
return static_cast<segment *>(newp);
}

segment *next(char *memory_start) const
{
if(!next_not_null_)
return 0;
unsigned long long p=next_msb_;
p<<=32;
p+=next_lsb_;
return (segment *)(memory_start + p);
}
segment *prev(char *memory_start) const
{
if(!prev_not_null_)
return 0;
unsigned long long p=prev_msb_;
p<<=32;
p+=prev_lsb_;
return reinterpret_cast<segment *>(memory_start + p);
}
void next(segment *p,char *memory_start)
{
if(p==0) {
next_not_null_ = 0;
return;
}
unsigned long long off = reinterpret_cast<char *>(p) - memory_start;
next_msb_ = off >> 32;
next_lsb_ = off & 0xFFFFFFFFu;
next_not_null_ = 1;
}
void prev(segment *p,char *memory_start)
{
if(p==0) {
prev_not_null_ = 0;
return;
}
unsigned long long off = reinterpret_cast<char *>(p) - memory_start;
prev_msb_ = off >> 32;
prev_lsb_ = off & 0xFFFFFFFFu;
prev_not_null_ = 1;
}
private:
uint8_t page_size_in_bits_;
uint8_t segment_count_;
uint8_t segment_offset_;
uint8_t next_not_null_ : 1;
uint8_t prev_not_null_ : 1;
uint8_t reserved_ : 6;

uint32_t next_lsb_; // 0 - 5
uint32_t prev_lsb_; // 0 - 5
uint16_t next_msb_;
uint16_t prev_msb_;
};
struct page {
page(size_t p)
{
memset(this,0,sizeof(*this));
pages = p;
}
uint8_t zero; // always zero
size_t pages;
};

#ifdef TEST_ALLOCATOR
public:
void print_stats()
{
std::cout << "Slab" << std::endl;
unsigned long long total_free = 0;
for(int i=0;i<slab_bits;i++) {
int count = 0;
for(segment *p=all[i][0];p;p=p->next(memory_start))
count++;
std::cout << std::setw(8) << count << ' ' << std::setw(8) << (1ul<<(min_bits + i)) << std::endl;
total_free += (1ul<<(min_bits + i)) * count ;
}
int free_super_pages = 0;
int free_pages = 0;
int max_block = 0;
int last_free = 0;
std::cout << std::setw(16) << "Free Slab" << std::setw(16) << total_free << std::endl;
for(size_t i=0;i<map_size;i++) {
if(map[i]==0) {
free_super_pages++;
last_free ++;
if(last_free > max_block)
max_block = last_free;
}
else {
last_free=0;
}
unsigned long long v=map[i];
for(int i=0;i<64;i++) {
if((v & 1) == 0) {
free_pages++;
total_free += page_size;
}
v>>=1;
}
}
std::cout << std::setw(16) << "Pages" << std::setw(16) << free_pages * page_size << std::endl;
std::cout << std::setw(16) << "Super Pages" << std::setw(16) << free_super_pages * (64 * page_size) << std::endl;
std::cout << std::setw(16) << "Max Free" << std::setw(16) << (64 * page_size * max_block) << std::endl;
std::cout << std::setw(16) << "Total Free" << std::setw(16) << total_free << std::endl;
std::cout << std::setw(16) << "Inital" << std::setw(16) << super_page_size * map_size << std::endl;
}
private:
#endif

int get_optimal_size_and_bits(size_t &n)
{
n = (((n + (align - 1)) >> (align_bits)) + 1) << align_bits;
if(n >= super_page_size) {
n=(n + super_page_size - 1) / super_page_size * super_page_size;
return -1;
}
else {
int i = get_bits(n);
n = size_t(1) << i;
if( n>= page_size)
return -1;
return i;
/*
for(i=0;i<int(sizeof(n) * 8);i++) {
if( (1ull << i) >= n)
break;
}
n = 1ull << i;
if(n >= page_size)
return -1;
return i;*/
}
}

static void *make_offset(void *p)
{
return static_cast<char *>(p) + align;
}

static void *remove_offset(void *p)
{
return static_cast<char *>(p) - align;
}

void *slab_alloc(size_t n)
{
int bits = get_optimal_size_and_bits(n);
if(bits == -1) {
void *p=page_alloc(n / page_size);
if(!p)
return 0;
new(p) page(n/page_size);
return make_offset(p);
}

segment **lst = all[bits - min_bits];

if(lst[0]) {
segment *p = lst[0];
p->erase(lst,memory_start);
p->dec();
return make_offset(p);
}
else {
void *p=page_alloc(1);
if(!p)
return 0;
segment *s = new(p) segment(bits,0);
int count = s->segment_count(page_size);
s->count(count-1);
for(int i=1;i<count;i++) {
new(s->at(i)) segment(bits,i);
s->at(i)->push(lst,memory_start);
}
return make_offset(p);
}
}

void slab_free(void *p)
{
if(!p)
return;
p=remove_offset(p);
if(*static_cast<uint8_t *>(p)==0) {
page *pg= static_cast<page *>(p);
page_free(pg,pg->pages);
return;
}
segment *s = static_cast<segment *>(p);
segment **lst = all[s->bits() - min_bits];
s->push(lst,memory_start);
s=s->at(0);
if(s->inc() == s->segment_count(page_size)) {
int sc = s->segment_count(page_size);
for(int i=0;i<sc;i++) {
s->at(i)->erase(lst,memory_start);
}
page_free(s,1);
}
}

#ifdef TEST_ALLOCATOR
void ptest_free()
{
for(int i=0;i<slab_bits;i++) {
assert(all[i][0]==0);
assert(all[i][1]==0);
}
for(size_t i = 0 ;i<map_size;i++) {
assert(map[i]==0);
}
}
#endif

static int m2(unsigned long long v)
{
static unsigned long long const m1 = 0xAAAAAAAAAAAAAAAAULL;
static unsigned long long const m2 = 0x5555555555555555ULL;

unsigned long long first_bit_set = v & m1;
unsigned long long second_bit_set = v & m2;
unsigned long long first_or_second_set = first_bit_set | (second_bit_set << 1);
return first_or_second_set !=0xAAAAAAAAAAAAAAAAULL;
}

static int m4(unsigned long long v)
{

//(1 or 2) ( 3 or 4 )
// x 0 x 0
// x
static unsigned long long const m1 = 0xAAAAAAAAAAAAAAAAull;
static unsigned long long const m2 = 0x5555555555555555ull;

unsigned long long b1 = m1 & v;
unsigned long long b2 = m2 & v;
unsigned long long b3 = b1 | (b2 << 1);

static unsigned long long const m3 = 0x8888888888888888ull;
static unsigned long long const m4 = 0x2222222222222222ull;

unsigned long long b4 = b3 & m3;
unsigned long long b5 = b3 & m4;

return (b4 | (b5 << 2))!=m3;

}

static int m8(unsigned long long v)
{
static unsigned long long const m1 = 0xAAAAAAAAAAAAAAAAull;
static unsigned long long const m2 = 0x5555555555555555ull;

unsigned long long b1 = m1 & v;
unsigned long long b2 = m2 & v;
unsigned long long b3 = b1 | (b2 << 1);

static unsigned long long const m3 = 0x8888888888888888ull;
static unsigned long long const m4 = 0x2222222222222222ull;

unsigned long long b4 = b3 & m3;
unsigned long long b5 = b3 & m4;
unsigned long long b6 = (b4 | (b5 << 2));
static unsigned long long const m5 = 0x8080808080808080ull;
static unsigned long long const m6 = 0x0808080808080808ull;
unsigned long long b7 = b6 & m5;
unsigned long long b8 = b6 & m6;

return (b7 | (b8 << 4))!=m5;
}

static int m16(unsigned long long v)
{
static unsigned long long m1 = 0xFFFFull << 0;
static unsigned long long m2 = 0xFFFFull << 16;
static unsigned long long m3 = 0xFFFFull << 32;
static unsigned long long m4 = 0xFFFFull << 48;
return (v & m1)==0 || (v & m2)==0 || (v & m3)==0 || (v & m4)==0;
}

static int m32(unsigned long long v)
{
static unsigned long long m1 = 0xFFFFFFFFull << 0;
static unsigned long long m2 = m1 << 32;
return (v & m1)==0 || (v & m2)==0;
}

/*

static int get_bits_old(size_t n)
{
int i;
for(i=0;i<int(sizeof(n) * 8);i++) {
if( (1ull << i) >= n)
break;
}
return i;
}
*/
static int get_bits(size_t n)
{
int xh=sizeof(n)*8,xl=0,x;
while(xh>xl+1) {
x = (xh + xl)/2;
if( (1ull<<x) >= n)
xh = x;
else
xl = x;
}
if((1ull << xl)>=n)
return xl;
else
return xh;
}


static int find_free_bits(unsigned long long u,int n)
{
int p=0;
while(u & ((1ull << n)-1)) {
u>>=n;
p+=n;
}
return p;
}

void *page_alloc(size_t pages)
{
int bit = get_bits(pages);
size_t i=0;
switch(bit) {
case 0:
for(i=0;i<map_size;i++) {
if(map[i]!=~0ull)
break;
}
break;
case 1:
for(i=0;i<map_size;i++) {
if(m2(map[i]))
break;
}
break;
case 2:
for(i=0;i<map_size;i++) {
if(m4(map[i]))
break;
}
break;
case 3:
for(i=0;i<map_size;i++) {
if(m8(map[i]))
break;
}
break;
case 4:
for(i=0;i<map_size;i++) {
if(m16(map[i]))
break;
}
break;
case 5:
for(i=0;i<map_size;i++) {
if(m32(map[i]))
break;
}
break;
}
switch(bit) {
case 0:
case 1:
case 2:
case 3:
case 4:
case 5:
{
if(i >= map_size)
return 0;
int bits_needed = 1 << bit;
int pos = find_free_bits(map[i],bits_needed);
unsigned long long bmask = (1ull << bits_needed)-1;
map[i] |= (bmask << pos);
return memory_start + page_size * (64 * i + pos);
}
default:
{
size_t n = pages / 64;
bool found = false;
if(n==1) {
for(i=0;i<map_size;i++) {
if(map[i]==0) {
found=true;
break;
}
}
}
else {
size_t n1=n-1;
for(i=0;!found && i+n1<map_size;) {
unsigned long long p2=map[i+n1];
if(p2!=0) {
i+=n;
continue;
}
unsigned long long p1=map[i];
if(p1!=0) {
size_t k = n / 2;
while(k>0 && map[i+k]==0) {
k/=2;
}
i+=k+1;
continue;
}
found = true;
for(size_t j=1;j<n-1;j++) {
if(map[i+j]) {
i+=j+1;
found = false;
break;
}
}
}
}
if(!found)
return 0;
for(size_t j=0;j<n;j++) {
#ifdef CHECK
assert(map[i+j]==0);
#endif
map[i+j]=~0ull;
}
return memory_start + super_page_size * i;
}
}
}

void page_free(void *p,size_t n)
{
int bit = get_bits(n);
size_t i = (static_cast<char*>(p) - memory_start) / super_page_size;
if(bit<=5) {
{
int pos = (static_cast<char *>(p) - memory_start) % (super_page_size) / page_size;
int bits_needed = 1 << bit;
unsigned long long bmask = (1ull << bits_needed)-1;
map[i] &= ~(bmask << pos);
}
}
else {
n /= 64;
while(n>0) {
map[i]=0;
n--;
i++;
}
}
}



}; // memory_manager

} // details
class shmem_control : public booster::noncopyable{
public:
shmem_control(size_t size) :
@@ -674,10 +33,13 @@ public:
region_(mmap_anonymous(size)),
memory_(0)
{
memory_ = new (region_) details::memory_manager(size_);
if(size < sizeof(*memory_))
throw cppcms_error("shared memory size is too small");
memory_ = new (region_) cppcms::impl::buddy_allocator(size_);
}
~shmem_control()
{
memory_->~buddy_allocator();
::munmap(region_,size_);
}
inline size_t size()
@@ -687,9 +49,14 @@ public:
inline size_t available()
{
mutex::guard g(lock_);
return memory_->get_free_memory();
return memory_->total_free_memory();

}
inline size_t max_available()
{
mutex::guard g(lock_);
return memory_->max_free_chunk();
}
inline void *malloc(size_t s)
{
mutex::guard g(lock_);
@@ -701,21 +68,11 @@ public:
return memory_->free(p);
}

#ifdef TEST_ALLOCATOR
void test_free()
{
memory_->test_free();
}
void print_stats()
{
memory_->print_stats();
}
#endif
private:
mutex lock_;
size_t size_;
void *region_;
details::memory_manager *memory_;
cppcms::impl::buddy_allocator *memory_;
};

template<typename T,shmem_control *&mm>
@@ -754,7 +111,6 @@ public :
};



} //
} //



+ 58
- 9
tests/allocator_test.cpp View File

@@ -6,12 +6,16 @@
//
///////////////////////////////////////////////////////////////////////////////
#define TEST_ALLOCATOR
#include "shmem_allocator.h"
//#define DEBUG_ALLOCATOR
#include "test.h"
#include "buddy_allocator.h"
#include <stdio.h>

#include <stdlib.h>
#include <string.h>
#include <vector>
#include <iostream>
#include <iomanip>

static const size_t objects = 100;

@@ -35,20 +39,27 @@ void check_all()

int main()
{
size_t memory_size = 1024*1024*10ULL;
void *ptr = malloc(memory_size);
cppcms::impl::buddy_allocator *buddy=new(ptr) cppcms::impl::buddy_allocator(memory_size);
try{
int fail = 0;
cppcms::impl::shmem_control ct(1024*1024*10ULL);
int limit = 1000;

buddy->test_free();
for(int i=0;i<limit;i++) {
if(i*100 % limit==0)
std::cout << std::setw(5) << i*100.0 / limit << "%"<< "\b\b\b\b\b\b" << std::flush;
size_t pos = rand() % objects;
size_t size = 1 << (rand() % 22);
size_t size = (1 << (rand() % 22));
size += rand() % size;
if(memory[pos]) {
ct.free(memory[pos]);
buddy->free(memory[pos]);
memory[pos] = 0;
check_all();
}
if((memory[pos]=ct.malloc(size))==0) {
if((memory[pos]=buddy->malloc(size))==0) {
check_all();
fail++;
}
@@ -61,22 +72,60 @@ int main()
s[j] = c;
check_all();
}
buddy->test_consistent(memory,objects);
}
for(size_t i=0;i<objects;i++) {
if(memory[i]) {
ct.free(memory[i]);
buddy->free(memory[i]);
memory[i]=0;
check_all();
}
buddy->test_consistent(memory,objects);
}

buddy->test_free();
std::cout << "\n malloc fail to all " << double(fail) / limit * 100 << std::endl;
for(int dir=0;dir<=1;dir++) {
for(size_t i=1;i<memory_size;i*=2) {
std::cout << "Object size " << i << std::endl;
std::vector<void *> ptrs;
void *tmp=0;
size_t exp = memory_size / i;
while((tmp=buddy->malloc(i))!=0) {
ptrs.push_back(tmp);
if(ptrs.size() * 100 % exp==0)
buddy->test_consistent(&ptrs[0],ptrs.size());
}
if(ptrs.empty())
break;
buddy->test_consistent(&ptrs[0],ptrs.size());
if(dir == 0) {
for(size_t i=0;i<ptrs.size();i++) {
buddy->free(ptrs[i]);
ptrs[i]=0;
if(i*100 % ptrs.size() == 0)
buddy->test_consistent(&ptrs[0]+i,ptrs.size()-i);
}
}
else {
for(int i=ptrs.size()-1;i>=0;i--) {
buddy->free(ptrs[i]);
ptrs[i]=0;
if(i*100 % ptrs.size() == 0)
buddy->test_consistent(&ptrs[0],i);
}
}
buddy->test_free();
}
}

ct.test_free();
std::cout << double(fail) / limit * 100 << std::endl;
}
catch(std::exception const &e) {
std::cerr << "Fail " << e.what() << booster::trace(e) << std::endl;
std::cerr << "Fail " << e.what() << std::endl;
return 1;
}
buddy->~buddy_allocator();
free(ptr);
std::cout << "Ok\n";
}



Loading…
Cancel
Save