Lab 3 Buddy Allocator
Understand and improve physical memory allocator
The Problem
xv6 has only a page allocator and cannot dynamically allocate objects smaller than a page. To work around this limitation, xv6 declares objects smaller than a page statically. For example, xv6 declares an array of file structs, an array of proc structures, and so on. As a result, the number of files the system can have open is limited by the size of the statically declared file array, which has NFILE entries (see kernel/file.c and kernel/param.h).
Your Task
For this lab we have replaced the page allocator in the xv6 kernel with a buddy allocator. You will modify xv6 to use this allocator to allocate and free file structs so that xv6 can have more open file descriptors than the existing system-wide limit NFILE. Furthermore, you will implement an optimization that reduces the buddy’s use of memory.
Task 1:
Modify kernel/file.c to use the buddy allocator so that the number of file structures is limited by memory rather than NFILE.
Task 2:
The buddy allocator is space inefficient. The alloc array has a bit for each block for each size. There is a clever optimization that reduces the cost to only one bit for each pair of blocks. This single bit is B1_is_free XOR B2_is_free, for a buddy pair of blocks B1 and B2. Each time a block is allocated or freed, you flip the bit to reflect the change. For example, if B1 and B2 are allocated, the bit will be zero and if B1 is freed the bit changes to 1. If the bit is 1 and B2 is freed, then we know that B1 and B2 should be merged. Saving 1/2 bit per block matters when xv6 uses the buddy allocator for the roughly 128 Mbyte of free memory that xv6 must manage: this optimization saves about 1 MByte of memory.
Solution
Allocate file use buddy allocator
Close file should release memory
Only one bit for each pair of blocks
Add flip bit helpers
Replace bit_set
usage with flip_bit
bit_set
usage with flip_bit
Replace bit_clear
usage with flip_bit
bit_clear
usage with flip_bit
Replace bit_isset
usage with bit_alloc_get
bit_isset
usage with bit_alloc_get
Add in range check
#define in_range(a, b, x) (((x) >= (a)) && ((x) < (b)))
Change how buddy allocation initialize
Code Walk Through
During initialization, buddy allocator has a range [free_start, free_end) bd_init
callsint free = bd_initfree(p, bd_end);
to initialize free lists for each size k. bd_initfree
calls bd_initfree_pair
, which initialize the free lists for each size k. For each size k, there are only two pairs that may have a buddy that should be on free list: bd_left and bd_right.
Fix bd_initfree_pair
Calling this function, passed in the free range.
bd_initfree_pair
checks if set and in range uses new helpers. If buddy is in free range, add to free list, otherwise, add current index to free list.
Reduce the bit size
In bd_init
, change from sz = sizeof(char)* ROUNDUP(NBLK(k), 8)/8;
To: sz = sizeof(char)* ROUNDUP(NBLK(k), 16)/16; // Twins use 1 single bit!
Hence, the total size of each block is reduced in half.
Next Step?
心得
伙伴算法的初始化有多种方式, xv6的实现非常精妙。我花费了很多时间理解大师的思想,最后发现可视化是最佳理解方法了。花了很多图,最终一目了然。
Last updated