再读内核存储管理(6):高速缓存的应用
来源:互联网 发布:南京逍遥游网络怎么样 编辑:程序博客网 时间:2024/05/22 06:17
快乐虾
http://blog.csdn.net/lights_joy/
lights@hb165.com
本文适用于
ADI bf561 DSP
uclinux-2008r1-rc8 (移植到vdsp5)
Visual DSP++ 5.0
欢迎转载,但请保留作者信息
1.1 高速缓存的应用
内核经常需要请求和释放单个页面。为了提升系统性能,每个内存管理区zone定义了一个“每CPU”页面高速缓存。所有高速缓存包含一些预先分配的页,它们被用于满足本地CPU发出的单一内存请求。
实际上,这里为每个内存管理区和每个CPU提供了两个高速缓存:一个热高速缓存,它存放的页框中所包含的内容很可能就在CPU硬件高速缓存中;还有一个冷高速缓存。
内核使用两个位标来监视热高速缓存和冷高速缓存的大小:如果页个数低于下界low,内核通过buddy系统分配batch个单一页面来补充对应的高速缓存;否则,如果页框个数高过上界high,内核从高速缓存中释放batch个页框到buddy系统中。
1.1.1 页面回收
当buddy算法回收一个页时,它会首先试图将其放在热高速缓存中,其实现如下:
fastcall void __free_pages(struct page *page, unsigned int order)
{
if (put_page_testzero(page)) {
if (order == 0)
free_hot_page(page);
else
__free_pages_ok(page, order);
}
}
void fastcall free_hot_page(struct page *page)
{
free_hot_cold_page(page, 0);
}
跟踪free_hot_cold_page函数:
/*
* Free a 0-order page
*/
static void fastcall free_hot_cold_page(struct page *page, int cold)
{
struct zone *zone = page_zone(page); // 返回ZONE_DMA这个区域
struct per_cpu_pages *pcp;
unsigned long flags;
if (PageAnon(page))
page->mapping = NULL;
if (free_pages_check(page))
return;
if (!PageHighMem(page)) // 总为FALSE
debug_check_no_locks_freed(page_address(page), PAGE_SIZE);
arch_free_page(page, 0); // 空语句
kernel_map_pages(page, 1, 0); // 空语句
pcp = &zone_pcp(zone, get_cpu())->pcp[cold];
local_irq_save(flags);
__count_vm_event(PGFREE); // 空语句
list_add(&page->lru, &pcp->list);
pcp->count++;
if (pcp->count >= pcp->high) {
free_pages_bulk(zone, pcp->batch, &pcp->list, 0);
pcp->count -= pcp->batch;
}
local_irq_restore(flags);
put_cpu();
}
从这个函数可以看出,如果pcp中的页数较少的时候,它将直接把回收的页面放在高速缓存中(热高速缓存或者冷高速缓存),即上述函数中的list_add调用。在这里pcp实际指向DMA_ZONE中的pcp。当高速缓存的页面较多时,它将切换出部分最后进入缓存的页,将这些页链接到可用的页面链表中(使用BUDDY算法)。
1.1.2 换页策略
内核中当高速缓存的页面较多时,会将部分页面切换到可用内存的链表中,这个操作由free_pages_bulk函数完成:
/*
* Frees a list of pages.
* Assumes all pages on list are in same zone, and of same order.
* count is the number of pages to free.
*
* If the zone was previously in an "all pages pinned" state then look to
* see if this freeing clears that state.
*
* And clear the zone's pages_scanned counter, to hold off the "all pages are
* pinned" detection logic.
*/
static void free_pages_bulk(struct zone *zone, int count,
struct list_head *list, int order)
{
spin_lock(&zone->lock);
zone->all_unreclaimable = 0;
zone->pages_scanned = 0;
while (count--) {
struct page *page;
VM_BUG_ON(list_empty(list));
page = list_entry(list->prev, struct page, lru);
/* have to delete it as __free_one_page list manipulates */
list_del(&page->lru);
__free_one_page(page, zone, order);
}
spin_unlock(&zone->lock);
}
因为在页面回收时是将要回收的页面插入到双链表的表头,而从上述函数中可以看出,在将页面切换出高速缓存的时候,也是从链表头按顺序进行的,因此整个切换策略就是后进先出,即最后进入高速缓存的先切换出去。
- 再读内核存储管理(6):高速缓存的应用
- 再读内核存储管理(1):相关的全局变量
- 再读内核存储管理(2):相关的数据结构
- 再读内核存储管理(8):片内SRAM的使用
- 再读内核存储管理(5):buddy算法
- 再读内核存储管理(7):icache支持
- 再读内核存储管理(4):存储区域管理
- 再读高速缓存
- 再读内核存储管理(3):bootmem分配策略
- 再读内核存储管理(3):bootmem分配策略[ZZ]
- 再读uclinux-2008r1(bf561)内核存储区域管理(1):相关数据结构
- 再读uclinux-2008r1(bf561)内核存储区域管理(2):可用页表初始化
- 再读uclinux-2008r1(bf561)内核存储区域管理(3):zone初始化
- 再读uclinux-2008r1(bf561)内核存储区域管理(4):zonelist初始化
- 再读uclinux-2008r1(bf561)内核存储区域管理(5):page初始化
- 【存储管理】内核缓冲区的管理概述
- 【存储管理】内核缓冲区的管理
- 再读《Linux内核设计与实现》之时间管理
- 有感于《游戏脚本高级编程》的劣质翻译
- 写在之前...
- Mysql忘记密码后的终级办法
- 98 XP 2000下查找进程 vc
- How to Install Win32 Assemblies for Side-by-Side Sharing (e.g. WinSxS)
- 再读内核存储管理(6):高速缓存的应用
- 只运行一个实例
- 如何写批处理文件自动将数据导入oracle数据库
- 再读内核存储管理(7):icache支持
- 数据库 xml treeview 的操作
- .ini配置文件的存取
- 言葉
- 夜的眼泪
- Isolated Applications