一个程序明白buddy算法













#define method 2






#if  method == 0x00
#include 
#include 


/*
 * 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
#include
#include
#include




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


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
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
#include
#include
#include
#include


#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









你可能感兴趣的:(一个程序明白buddy算法)