buddy找伙伴块算法(linux 3.10.102)

背景

本文描述内核找伙伴块的算法,根据给定order及page_idx(buddy块中第一个page的index),找到伙伴块的page_idx。如果需要查阅buddy的原理知识,请参考其他资料。

算法分析

内核找伙伴块的代码如下:

mm/page_alloc.c

/*

 * Locate the struct page for both the matching buddy in our

 * pair (buddy1) and the combined O(n+1) page they form (page).

 *

 * 1) Any buddy B1 will have an order O twin B2 which satisfies

 * the following equation:

 *     B2 = B1 ^ (1 << O)

 * For example, if the starting buddy (buddy2) is #8 its order

 * 1 buddy is #10:

 *     B2 = 8 ^ (1 << 1) = 8 ^ 2 = 10

 *

 * 2) Any buddy B will have an order O+1 parent P which

 * satisfies the following equation:

 *     P = B & ~(1 << O)

 *

 * Assumption: *_mem_map is contiguous at least up to MAX_ORDER

 */

static inline unsigned long

__find_buddy_index(unsigned long page_idx, unsigned int order)

{

         return page_idx ^ (1 << order);

}

参数 page_idex为需要释放的2^{order}个pages中的第一个page在mem_map数组中的下标。

order为1时(下图中连续灰白颜色的个4个page,灰白部分互为buddy):

page [0] [1]与page [2] [3]互为伙伴块;page [4] [5]与page [6] [7]互为伙伴块;以此类推。第一个伙伴块中第一个页框index为2*2^{order}的倍数。

buddy算法关注伙伴块中的第一个page,所以我们可以这样说,以0和2代表的block为伙伴块,以4和6为代表的block互为伙伴块。从规律上看,给定一个block中第一个page的index,它的伙伴块中的第一个page的索引buddy_index只有两种可能:

  1. buddy_index = page index + 2^{order},即向上加2^{order}个page
  2. buddy_index = page index - 2^{order},即向下减2^{order}个page

还可以推出另一个规律,见下图(同一个颜色表示伙伴块):

page index

0

2

4

6

8

10

12

14

二进制

0000

0010

0100

0110

1000

1010

1100

1110

从二进制可以看出,互为伙伴块的各块中first page index区别在于第order位不同,该位为0表示伙伴块中的第一个块,为1表示伙伴块中的第二个块。根据上面的计算公式,该位为0的块中第一个page index加2^{order}个page、该位为1的块中第一个page index减2^{order}个page,就能找到对应的伙伴块。从数学上说加2^{order}即是把第order位置1,减2^{order}即是把order位置0,相当于:把块中的第一个page的index的第order位取反即得到对应伙伴块中第一个page的index(从上图中直接分析二进制也可以总结出这个规律)。

也就是说,为了求page_idx(伙伴块中第一个page的index)的伙伴块,需要先求出page_idx第order本来的值,然后取反就得到page_idx的伙伴块,但比较浪费时间。可以在此基础上推导出更快的方法,按照上面分析,

page_idx第order位

伙伴块page_idx第order位

0

1

1

0

从上表可以看出,第一列的bit值与1异或,就可以得到第二列的值。内核代码就是采用了异或的方法,即文章开头的函数:

static inline unsigned long

__find_buddy_index(unsigned long page_idx, unsigned int order)

{

    return page_idx ^ (1 << order);

}

 

posted @ 2018-08-21 20:50  geshifei  阅读(8)  评论(0编辑  收藏  举报  来源