#define method 2
#if method == 0x00
#include<stdio.h>
#include<math.h>
/*
* struct array_cache
*
* Per cpu structures
* Purpose:
* - LIFO ordering, to hand out cache-warm objects from _alloc
* - reduce the number of linked list operations
* - reduce spinlock operations
*
* The limit is stored in the per-cpu structure to reduce the data cache
* footprint.
*
*/
/**
* 空闲对象的本地高速缓存描述符(注意:是描述符而不是本地高速缓存本身,本地高速缓存在描述符后面)
*/
struct array_cache {
/**
* 指向本地高速缓存中可使用对象的指针的个数。
* 它同时也作为高速缓存中第一个空槽的下标。
*/
unsigned int avail;
/**
* 本地高速缓存的大小,也就是本地高速缓存中指针的最大个数
*/
unsigned int limit;
/**
* 本地高速缓存重新填充或者腾空时使用的块大小
*/
unsigned int batchcount;
/**
* 如果最近被使用过,则置为1
*/
unsigned int touched;
};
/* bootstrap: The caches do not work without cpuarrays anymore,
* but the cpuarrays are allocated from the generic caches...
*/
#define BOOT_CPUCACHE_ENTRIES
1
struct arraycache_init {
struct array_cache cache;
void * entries[BOOT_CPUCACHE_ENTRIES];
};
static struct arraycache_init initarray_cache =
{ { 0, BOOT_CPUCACHE_ENTRIES, 1, 0},{(void *) 0x11} };
static struct arraycache_init initarray_generic =
{ { 0, BOOT_CPUCACHE_ENTRIES, 1, 0} };
int main()
{
printf("sizeof(struct array_cache) = %d.\r\n", sizeof(struct array_cache) );
printf("sizeof(initarray_generic) = %d.\r\n", sizeof(initarray_generic) );
return 0;
}
#elif method == 0x01
#include <stdlib.h>
#include <assert.h>
#include <stdio.h>
#include <string.h>
static int fixsize( int size );
struct buddy2 {
unsigned size;
unsigned longest[1];
};
#define LEFT_LEAF(index) ((index) * 2 + 1)
#define RIGHT_LEAF(index) ((index) * 2 + 2)
#define PARENT(index) ( ((index) + 1) / 2 - 1)
#define IS_POWER_OF_2(x) (!((x)&((x)-1)))
#define MAX(a, b) ((a) > (b) ? (a) : (b))
#define ALLOC malloc
#define FREE free
//#define IS_POWER_OF_2(x) ((x) != 0 && (((x) & ((x) - 1)) == 0))
struct buddy2* buddy2_new( int size ) {
struct buddy2* self;
unsigned node_size;
int i;
if (size < 1 || !IS_POWER_OF_2(size))
return NULL;
self = (struct buddy2*)ALLOC( 2 * size * sizeof(unsigned));
self->size = size;
node_size = size * 2;
for (i = 0; i < 2 * size - 1; ++i) {
if (IS_POWER_OF_2(i+1))
node_size /= 2;
self->longest[i] = node_size;
}
return self;
}
int buddy2_alloc(struct buddy2* self, int size) {
unsigned index = 0;
unsigned node_size;
unsigned offset = 0;
if (self==NULL)
return -1;
if (size <= 0)
size = 1;
else if (!IS_POWER_OF_2(size))
size = fixsize(size);
if (self->longest[index] < size)
return -1;
for(node_size = self->size; node_size != size; node_size /= 2 ) {
if (self->longest[LEFT_LEAF(index)] >= size)
index = LEFT_LEAF(index);
else
index = RIGHT_LEAF(index);
}
self->longest[index] = 0;
offset = (index + 1) * node_size - self->size;
while (index) {
index = PARENT(index);
self->longest[index] =
MAX(self->longest[LEFT_LEAF(index)], self->longest[RIGHT_LEAF(index)]);
}
return offset;
}
void buddy2_free(struct buddy2* self, int offset) {
unsigned node_size, index = 0;
unsigned left_longest, right_longest;
//assert(self && offset >= 0 && offset < size);
node_size = 1;
index = offset + self->size - 1;
for (; self->longest[index] ; index = PARENT(index)) {
node_size *= 2;
if (index == 0)
return;
}
self->longest[index] = node_size;
while (index) {
index = PARENT(index);
node_size *= 2;
left_longest = self->longest[LEFT_LEAF(index)];
right_longest = self->longest[RIGHT_LEAF(index)];
if (left_longest + right_longest == node_size)
self->longest[index] = node_size;
else
self->longest[index] = MAX(left_longest, right_longest);
}
}
#ifndef __BUDDY2_H__
#define __BUDDY2_H__
#include <stdlib.h>
struct buddy2;
struct buddy2* buddy2_new( int size );
void buddy2_destroy( struct buddy2* self );
int buddy2_alloc(struct buddy2* self, int size);
void buddy2_free(struct buddy2* self, int offset);
int buddy2_size(struct buddy2* self, int offset);
void buddy2_dump(struct buddy2* self);
#endif//__BUDDY2_H__
static int fixsize( int size )
{
size |= size >> 1;
size |= size >> 2;
size |= size >> 4;
size |= size >> 8;
size |= size >> 16;
return size+1;
}
void buddy2_destroy( struct buddy2* self) {
FREE(self);
}
int buddy2_size(struct buddy2* self, int offset) {
unsigned node_size, index = 0;
assert(self && offset >= 0 && offset < self->size);
node_size = 1;
for (index = offset + self->size - 1; self->longest[index] ; index = PARENT(index))
node_size *= 2;
return node_size;
}
void buddy2_dump(struct buddy2* self) {
char canvas[65];
int i,j;
unsigned node_size, offset;
if (self == NULL) {
printf("buddy2_dump: (struct buddy2*)self == NULL");
return;
}
if (self->size > 64) {
printf("buddy2_dump: (struct buddy2*)self is too big to dump");
return;
}
memset(canvas,'_', sizeof(canvas));
node_size = self->size * 2;
for (i = 0; i < 2 * self->size - 1; ++i) {
if ( IS_POWER_OF_2(i+1) )
node_size /= 2;
if ( self->longest[i] == 0 ) {
if (i >= self->size - 1) {
canvas[i - self->size + 1] = '*';
}
else if (self->longest[LEFT_LEAF(i)] && self->longest[RIGHT_LEAF(i)]) {
offset = (i+1) * node_size - self->size;
for (j = offset; j < offset + node_size; ++j)
canvas[j] = '*';
}
}
}
canvas[self->size] = '\0';
puts(canvas);
}
//#include "buddy2.h"
#include <stdio.h>
int main() {
char cmd[80];
int arg;
struct buddy2* buddy = buddy2_new(32);
buddy2_dump(buddy);
for (;;) {
scanf("%s %d", cmd, &arg);
if (strcmp(cmd, "alloc") == 0) {
printf("allocated@%d\n", buddy2_alloc(buddy, arg));
buddy2_dump(buddy);
} else if (strcmp(cmd, "free") == 0) {
buddy2_free(buddy, arg);
buddy2_dump(buddy);
} else if (strcmp(cmd, "size") == 0) {
printf("size: %d\n", buddy2_size(buddy, arg));
buddy2_dump(buddy);
} else
buddy2_dump(buddy);
}
}
////////////////////////////////////////////////////////////////
#elif method == 0x02
//start from here
#ifndef BUDDY_MEMORY_ALLOCATION_H
#define BUDDY_MEMORY_ALLOCATION_H
struct buddy;
struct buddy * buddy_new(int level);
void buddy_delete(struct buddy *);
int buddy_alloc(struct buddy *, int size);
void buddy_free(struct buddy *, int offset);
int buddy_size(struct buddy *, int offset);
void buddy_dump(struct buddy *);
#endif
//#include "buddy.h"
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <assert.h>
#include <string.h>
#define NODE_UNUSED 0
#define NODE_USED 1
#define NODE_SPLIT 2
#define NODE_FULL 3
struct buddy {
int level;
uint8_t tree[1];
};
struct buddy * buddy_new( int level )
{
int size = 1 << level;
//printf( "level = %d.\r\n", level );
//printf( "size = %d.\r\n", size );
//printf( "sizeof(struct buddy) = %d.\r\n", sizeof(struct buddy) );
//printf( "sizeof(uint8_t) = %d.\r\n", sizeof(uint8_t) );
struct buddy *self = malloc(sizeof(struct buddy) + sizeof(uint8_t) * (size * 2 - 2));
//printf( "(sizeof(struct buddy) + sizeof(uint8_t) * (size * 2 - 2)) = %d.\r\n", (sizeof(struct buddy) + sizeof(uint8_t) * (size * 2 - 2)) );
//printf( "self = 0x%x.\r\n", self );
self->level = level;
//printf( "self->level = 0x%x.\r\n", self->level );
//printf( "&self->level = 0x%x.\r\n", &self->level );
//printf( "&self->tree = 0x%x.\r\n", &self->tree );
//printf( "self->tree = 0x%x.\r\n", self->tree );
memset( self->tree, NODE_UNUSED, size*2-1 );
return self;
}
void buddy_delete( struct buddy * self )
{
free(self);
}
//inline
static int is_pow_of_2( uint32_t x )
{
return !(x & (x-1));
}
//看一个数是否是2的power,2的n次幂
//即0 1 2 4 8 16 32 64 ...
//inline
static uint32_t next_pow_of_2( uint32_t x )
{
if( is_pow_of_2(x) ){
return x;
}
x |= x>>1;
x |= x>>2;
x |= x>>4;
x |= x>>8;
x |= x>>16;
return x+1;
}
//static inline int _index_offset(int index, int level, int max_level)
//为运行效率计,用inline,为调试方便计,去除inline
static int _index_offset( int index, int level, int max_level )
{
unsigned int ret;
//printf( "index = %d.\r\n", index );
//printf( "level = %d.\r\n", level );
//printf( "max_level = %d.\r\n", max_level );
ret = ((index + 1) - (1 << level)) << (max_level - level);
//printf( "ret = %d.\r\n", ret );
return ret;
}
//标记父母函数
static void _mark_parent( struct buddy * self, int index )
{
for( ; ; ){
//printf( "index = %d.\r\n", index );
int buddy = index - 1 + (index & 1) * 2;
//printf( "buddy = %d.\r\n", buddy );
//找出自己的兄弟
if( buddy > 0 && (self->tree[buddy] == NODE_USED || self->tree[buddy] == NODE_FULL) ){
//不是根节点 并且 兄弟节点使用了或者兄弟节点满了
//那么就要标记父亲节点
index = (index + 1) / 2 - 1;
//找到父亲节点的索引号
self->tree[index] = NODE_FULL;
//父亲节点置为满
}else{
//否则,还没满,不用管,维持原状就好了
return;
}
}
}
int buddy_alloc( struct buddy * self, int s )
{
int size, length, index, level;
if( s == 0 ){
size = 1;
}else{
size = (int)next_pow_of_2(s);
}
length = 1 << self->level;
if( size > length ){
return -1;
}
index = 0;
level = 0;
//printf( "size = %d.\r\n", size );
//printf( "length = %d.\r\n", length );
while( index >= 0 ){
if( size == length ){
//printf( "index.2 = %d.\r\n", index );
//printf( "self.2 = 0x%x.\r\n", self );
if( self->tree[index] == NODE_UNUSED ){
self->tree[index] = NODE_USED;
_mark_parent(self, index);
return _index_offset(index, level, self->level);
}
}else{
//size < length
switch( self->tree[index] )
{
case NODE_USED:
case NODE_FULL:
//已经使用或者已经满了
break;
case NODE_UNUSED:
//split first
//第一步 裂开 前提是父节点没有被使用 才可以裂开
self->tree[index] = NODE_SPLIT;
//父节点置为裂开状态 (2)
self->tree[index*2+1] = NODE_UNUSED;
//左孩子置为未使用状态 (0)
self->tree[index*2+2] = NODE_UNUSED;
//右孩子置为未使用状态 (0)
//printf( "index.0 = %d.\r\n", index );
//printf( "self = 0x%x.\r\n", self );
//printf( "self->tree[index] = %d.\r\n", self->tree[index] );
//printf( "&self->tree[index] = 0x%x.\r\n", &self->tree[index] );
//printf( "self->tree[index] = %d.\r\n", self->tree[index*2+1] );
//printf( "self->tree[index] = %d.\r\n", self->tree[index*2+2] );
//注意没有break
default:
index = index * 2 + 1;
//索引指向左孩子
length /= 2;
//长度缩小一半
level++;
//搜索层级加1 即指向下一层
//printf( "index.1 = %d.\r\n", index );
//printf( "length = %d.\r\n", length );
//printf( "level = %d.\r\n", level );
continue;
//注意没有break
}
}
//printf( "index.2 = %d.\r\n", index );
if( index & 1 ){
++index;
continue;
}
for( ; ; ){
printf( "index.2 = %d.\r\n", index );
level--;
length *= 2;
index = (index+1)/2 -1;
//父亲
//左边树搜索完没找到 那么就到右子树去搜索
if( index < 0 ){
return -1;
}
if( index & 1 ){
//父亲是左孩子,指向父亲的兄弟,即右孩子
++index;
break;
}
}
}
return -1;
}
static void _combine( struct buddy *self, int index )
{
for( ; ; ){
int buddy = index - 1 + (index & 1) * 2;
if( buddy < 0 || self->tree[buddy] != NODE_UNUSED ){
self->tree[index] = NODE_UNUSED;
while( ((index = (index + 1) / 2 - 1) >= 0) && self->tree[index] == NODE_FULL ){
self->tree[index] = NODE_SPLIT;
}
return;
}
index = (index + 1) / 2 - 1;
}
}
void buddy_free( struct buddy *self, int offset )
{
assert( offset < (1<< self->level));
int left = 0;
int length = 1 << self->level;
int index = 0;
for( ; ; ){
switch( self->tree[index] )
{
case NODE_USED:
assert(offset == left);
_combine(self, index);
return;
case NODE_UNUSED:
assert(0);
return;
default:
length /= 2;
if( offset < left+length ){
index = index * 2 + 1;
}else{
left += length;
index = index * 2 + 2;
}
break;
}
}
}
//计算buddy的大小
int buddy_size( struct buddy * self, int offset )
{
assert( offset < (1<< self->level) );
int left = 0;
int length = 1 << self->level;
int index = 0;
for( ; ; ){
switch( self->tree[index] )
{
case NODE_USED:
assert(offset == left);
return length;
//相当于break
case NODE_UNUSED:
assert(0);
return length;
default:
length /= 2;
if( offset < left+length ){
index = index * 2 + 1;
}else{
left += length;
index = index * 2 + 2;
}
break;
}
}
}
//具有递归调用
static void _dump(struct buddy * self, int index , int level)
{
switch( self->tree[index] )
{
case NODE_UNUSED:
//节点未使用
printf("(%d:%d)", _index_offset(index, level, self->level) , 1 << (self->level - level));
break;
case NODE_USED:
//节点已使用
printf("[%d:%d]", _index_offset(index, level, self->level) , 1 << (self->level - level));
break;
case NODE_FULL:
//节点已满
printf("{");
_dump(self, index * 2 + 1 , level+1);
//左孩子
_dump(self, index * 2 + 2 , level+1);
//右孩子
printf("}");
break;
default:
//节点裂开 分叉 生了一对双胞胎左右儿子
printf("(");
_dump(self, index * 2 + 1 , level+1);
//左孩子
_dump(self, index * 2 + 2 , level+1);
//右孩子
printf(")");
break;
}
}
void buddy_dump(struct buddy * self)
{
_dump(self, 0 , 0);
printf("\n");
}
static int test_alloc( struct buddy *b, int sz )
{
printf("\r\nstart alloc.\r\n");
int r = buddy_alloc(b, sz);
printf("alloc %d (sz= %d).\r\n\r\n",r,sz);
buddy_dump(b);
return r;
}
static void test_free( struct buddy *b, int addr )
{
printf( "free %d.\r\n", addr );
buddy_free( b, addr );
buddy_dump(b);
}
static void test_size(struct buddy *b, int addr)
{
int s = buddy_size(b,addr);
printf( "size addr = %d, (sz = %d).\r\n", addr, s );
}
//buddy 伙伴算法的简单实现
//只要看明白了这个c程序,就可以明白linux下的伙伴算法
void dump_array( unsigned char *p, int cnt )
{
int i = 0x00;
//printf( "p = %x.\r\n", p );
//printf( "cnt = %d.\r\n", cnt );
for( ; cnt; cnt-- ){
if( p[i] ){
printf( "p[%d] = 0x%x.\r\n", i, p[i] );
}
i++;
}
}
int main( void )
{
struct buddy * b;
int m1, m2, m3, m4, m5, m6;
b = buddy_new(3);
buddy_dump(b);
//dump_array( &b->tree[0], 32 );
m1 = test_alloc(b,2);
test_size(b,m1);
dump_array( &b->tree[0], 16 );
m2 = test_alloc(b,1);
test_size(b,m2);
dump_array( &b->tree[0], 16 );
m3 = test_alloc(b,2);
test_size(b,m3);
dump_array( &b->tree[0], 16 );
m4 = test_alloc(b,1);
test_size(b,m4);
dump_array( &b->tree[0], 16 );
m5 = test_alloc(b,2);
test_size(b,m5);
dump_array( &b->tree[0], 16 );
#if 0
m2 = test_alloc(b,9);
test_size(b,m2);
m3 = test_alloc(b,3);
test_size(b,m3);
m4 = test_alloc(b,7);
test_free(b,m3);
test_free(b,m1);
test_free(b,m4);
test_free(b,m2);
m5 = test_alloc(b,32);
test_free(b,m5);
m6 = test_alloc(b,0);
test_free(b,m6);
buddy_delete(b);
#endif
return 0;
}
#endif
#if 0
## Buddy Memory Allocation
A simple buddy memory allocation library .
See test.c for detail use.
## Question ?
* Send me an email : http://www.codingnow.com/2000/gmail.gif
* My Blog : http://blog.codingnow.com
* http://blog.codingnow.com/2011/12/buddy_memory_allocation.html (in Chinese)
.Phony : all clean
all : test
test : test.c buddy.c
gcc -g -Wall -o $@ $^
clean :
rm -f test test.exe
#endif