云题海 - 专业文章范例文档资料分享平台

当前位置:首页 > 清华大学操作系统lab2及slub实现实验报告

清华大学操作系统lab2及slub实现实验报告

  • 62 次阅读
  • 3 次下载
  • 2025/6/17 21:53:27

pde_t *pdep = &pgdir[PDX(la)];

if (!(*pdep & PTE_P)) { //如果不存在 struct Page *page;

if (!create || (page = alloc_page()) == NULL) { //判断是否建立 return NULL; } //设置参数,初始化 set_page_ref(page, 1);

uintptr_t pa = page2pa(page); memset(KADDR(pa), 0, PGSIZE);

*pdep = pa | PTE_U | PTE_W | PTE_P; }

return &((pte_t *)KADDR(PDE_ADDR(*pdep)))[PTX(la)]; //返回入口

练习3:释放某虚拟地址所在的页并取消对应的二级页表项的映射

if (*ptep & PTE_P) { //判断是否存在

struct Page *page = pte2page(*ptep);

if (page_ref_dec(page) == 0) { //判断是否需要释放 free_page(page); }

*ptep = 0; //初始化二级页表项 tlb_invalidate(pgdir, la); //更新tlb }

Challenge:

引入slub的原因:

Slab管理器过于复杂,管理结构消耗内存过大,尤其是在多处理器、多节点的情况下,另外slab管理器对Cache数没有限制,对内存对象的大小也没有限制,容易产生Cache泛滥的现象,因此引入了Slub,它尽管理部分满的Slab,忽略完全满的和完全空闲的slab,减少了管理队列;它仅建立几个通用Cache,并尽力避免建立专用Cache,大大缩减了Cache的数量。

对象分配过程:

(1) 如果处理器的热对象缓存不空,则直接从热对象缓存中分配内存对象,

即将freelist所指的对象分配出去,而后让freelist指向队列中下一个空闲对象。

static __always_inline void *slab_alloc(struct kmem_cache *s, gfp_t gfpflags, int node, void *addr){ void **object;

struct kmem_cache_cpu *c; unsigned long flags; local_irq_save(flags);

//获取本处理器的 kmem_cache_cpu 数据结构

c = get_cpu_slab(s, smp_processor_id());

if (unlikely(!c->freelist || !node_match(c, node)))

//假如当前活动 slab 没有空闲对象,或本处理器所 //在节点与指定节点不一致,则调用 __slab_alloc 函数

object = __slab_alloc(s, gfpflags, node, addr, c); else { //获得第一个空闲对象的指针,然后更新指针使其

//指向下一个空闲对象

object = c->freelist; c->freelist = object[c->offset]; stat(c, ALLOC_FASTPATH); }

local_irq_restore(flags); //是否需要将对象清0

if (unlikely((gfpflags & __GFP_ZERO) && object)) memset(object, 0, c->objsize);

return object; }

参数说明:

1) s:cache指针。

2) gfpflags:分配标志。

3) node:NUMA,从指定内存节点分配 4) addr:初始调用函数地址

每个内核对象缓冲区都是由 kmem_cache 类型的数据结构来描述的:

(2) 如果处理器的热对象缓存为空但它的当前Slab不空,则将当前Slab的第

一个空闲对象分配出去,将其空余的对象转移到处理器的热对象缓存中。转移后当前slab变成完全满的。

(3) 如果处理器的当前Slab为空但节点的partial队列不空,则从中选择一个

Slab,将它的第一个空闲对象分配出去,将其余的空闲对象全部转移到处理器的热对象缓存中。转移之后,新的Slab变成处理器当前的slab,其page结构从partial队列中摘下,page结构中的freelist被清空,inuse被设定为完全满。

(4) 如果节点的partial队列也为空,则创建一个新的Slab,将它的第一个空

闲对象分配出去,将其余空闲对象转移到处理器的热对象缓存中,使之成为当前slab。新的slab是从伙伴内存管理器中申请的一块物理内存页块。这些内存对象被串成一个链表,起始页page结构中的freelist指向表头。

在 SLUB 中,没有单独的 Empty slab 队列。每个 NUMA 节点使用 kmem_cache_node 结构维护一个处于 Partial 状态的 slab 队列。

static void *__slab_alloc(struct kmem_cache *s, gfp_t gfpflags, int node,unsigned long addr, struct kmem_cache_cpu *c)

{

void **object; struct page *new;

/* We handle __GFP_ZERO in the caller */ gfpflags &= ~__GFP_ZERO; /* 还没有local slab,从部分满slab链中提取一个slab作为local slab。Page指针保存local slab的首页 */

if (!c->page)

goto new_slab;

slab_lock(c->page);

/* local slab与指定内存节点不匹配,去激活local slab */ if (unlikely(!node_match(c, node))) goto another_slab; /* local slab重填统计 */ stat(s, ALLOC_REFILL);

/* 将local slab freelist中的空闲对象填充到cpu freelist中 */ load_freelist:

/* 检查local slab的freelist指针 */

object = c->page->freelist;

/* local slab没有空闲对象,去激活local slab */ if (unlikely(!object))

goto another_slab; if (kmem_cache_debug(s)) goto debug;

/* 将local slab freelist中的对象全部填充到cpu freelist中。这个“填充”动作实际上只是一个指针接管 */

c->freelist = get_freepointer(s, object);

/* local slab的所有空闲对象都分配给了cpu freelist(而不是一般意义上的分配给进程)*/

c->page->inuse = c->page->objects;

/* slab freelist无空闲对象了,全部分给了cpu freelist */ c->page->freelist = NULL;

/* local slab所在的内存节点 */ c->node = page_to_nid(c->page); unlock_out:

slab_unlock(c->page); stat(s, ALLOC_SLOWPATH); /* 返回空闲对象 */ return object;

another_slab:

/* 去激活旧的local slab */ deactivate_slab(s, c);

new_slab:

/* 提取一个部分满的slab。如果没有指定node,那么可能来自于本内存节点,也可能来自于其他节点。如果指定了node,那么只可能来自于本内存节点。*/

new = get_partial(s, gfpflags, node); if (new) {

/* local slab指向新的slab */ c->page = new;

stat(s, ALLOC_FROM_PARTIAL); /* 重试freelist填充流程 */ goto load_freelist; }

/* 走到这说明没有部分满的slab了,需要创建一个新slab */

gfpflags &= gfp_allowed_mask; if (gfpflags & __GFP_WAIT) local_irq_enable(); /* 创建一个新slab */

new = new_slab(s, gfpflags, node);

/*加入 gfpflags 标志置有 __GFP_WAIT,开启中断,故后续创建 slab 操作可以睡眠*/

if (gfpflags & __GFP_WAIT) local_irq_disable();

if (new) {

/* 获得local slab所在的struct kmem_cache_cpu指针 */

c = __this_cpu_ptr(s->cpu_slab); /* 更新统计 */ stat(s, ALLOC_SLAB);

/* 清除旧的local slab */ if (c->page)

flush_slab(s, c); slab_lock(new); /* 冻结新的slab,表示它已经成为某个cpu的local slab */

__SetPageSlubFrozen(new); /* 指向新的local slab */ c->page = new;

/* 重试freelist填充流程 */

goto load_freelist; }

/* 走到这,说明已经没有空闲内存,分配失败 */ if (!(gfpflags & __GFP_NOWARN) && printk_ratelimit()) slab_out_of_memory(s, gfpflags, node); return NULL; debug:

if (!alloc_debug_processing(s, c->page, object, addr)) goto another_slab;

c->page->inuse++;

c->page->freelist = get_freepointer(s, object); c->node = NUMA_NO_NODE; goto unlock_out; }

  • 收藏
  • 违规举报
  • 版权认领
下载文档10.00 元 加入VIP免费下载
推荐下载
本文作者:...

共分享92篇相关文档

文档简介:

pde_t *pdep = &pgdir[PDX(la)]; if (!(*pdep & PTE_P)) { //如果不存在 struct Page *page; if (!create || (page = alloc_page()) == NULL) { //判断是否建立 return NULL; } //设置参数,初始化 set_page_ref(page, 1); uintptr_t pa = page2pa(page); memset(KADDR(pa), 0, PGSIZE); *pdep = pa | PTE_U | PTE_W | PTE_P; }

× 游客快捷下载通道(下载后可以自由复制和排版)
单篇付费下载
限时特价:10 元/份 原价:20元
VIP包月下载
特价:29 元/月 原价:99元
低至 0.3 元/份 每月下载150
全站内容免费自由复制
VIP包月下载
特价:29 元/月 原价:99元
低至 0.3 元/份 每月下载150
全站内容免费自由复制
注:下载文档有可能“只有目录或者内容不全”等情况,请下载之前注意辨别,如果您已付费且无法下载或内容有问题,请联系我们协助你处理。
微信:fanwen365 QQ:370150219
Copyright © 云题海 All Rights Reserved. 苏ICP备16052595号-3 网站地图 客服QQ:370150219 邮箱:370150219@qq.com