当前位置: 首页 > wzjs >正文

律师做网站费用信息流广告代理商排名

律师做网站费用,信息流广告代理商排名,清华科技园的网站谁做的,纳森网络做网站多少钱文章目录 零、写在前面一、Eliminate allocation from sbrk()1.1 说明1.2 实现 二、Lazy allocation2.1 说明2.2 实现 三、Lazytests and Usertests3.1 说明3.2 实现3.2.1 lazytests3.2.2 usertests 零、写在前面 可以阅读下4.6页面错误异常 像应用程序申请内存,内…

文章目录

    • 零、写在前面
    • 一、Eliminate allocation from sbrk()
      • 1.1 说明
      • 1.2 实现
    • 二、Lazy allocation
      • 2.1 说明
      • 2.2 实现
    • 三、Lazytests and Usertests
      • 3.1 说明
      • 3.2 实现
        • 3.2.1 lazytests
        • 3.2.2 usertests


零、写在前面

可以阅读下4.6页面错误异常

像应用程序申请内存,内核分配和映射这些内存其实是很耗费时间的。比如,一个 GB 的内存包含 262,144 个 4096 字节的页;即便每次分配的开销很小,这么多次操作累积起来仍然非常耗时。

此外,一些程序会分配比实际使用更多的内存(例如,为了实现稀疏数组),或者会提前分配内存但迟迟不使用。为加快 sbrk() 的执行速度,现代内核采用了一种称为懒惰分配的技术:sbrk() 不再立即分配物理内存,而是仅记录下哪些用户地址被分配了,并在用户页表中将这些地址标记为无效

当进程首次尝试访问这些**“懒惰分配”**的页面时,CPU 会触发一次缺页异常(page fault)。内核在处理该异常时,会分配一页物理内存、将其清零,并将其映射到进程的地址空间中。

总的来说,懒惰分配是一种常见的降低均摊成本的操作

在本实验中,你将为 xv6 添加这个懒惰分配的功能。

记得先切换分支到lazy

一、Eliminate allocation from sbrk()

1.1 说明

你的第一个任务是sbrk(n) 系统调用的实现中删除物理页面分配。该系统调用对应的函数是 sysproc.c 文件中的 sys_sbrk()

sbrk(n) 系统调用的作用是将当前进程的内存大小增加 n 字节,并返回新分配区域的起始地址(即原来的内存大小)。你需要修改 sbrk(n) 的实现,使其仅仅将进程的大小(myproc()->sz)增加 n 字节并返回旧的大小

注意:不应该在这里分配物理内存,因此需要删除对 growproc() 的调用。但你仍然需要更新进程的大小字段。

试着猜一猜:这个修改会导致什么问题?会有什么地方出错?

进行上述修改后,启动 xv6,并在 shell 中输入 echo hi。你应该会看到类似下面的输出:

init: starting sh
$ echo hi
usertrap(): unexpected scause 0x000000000000000f pid=3sepc=0x0000000000001258 stval=0x0000000000004008
va=0x0000000000004000 pte=0x0000000000000000
panic: uvmunmap: not mapped

其中,usertrap(): ... 是来自 trap.c 中用户异常处理函数(user trap handler)的信息;它捕获到了一个它不知道如何处理的异常。你需要弄清楚为什么会发生这个缺页异常(page fault)

信息中的 stval=0x0000000000004008 表示导致缺页异常的虚拟地址是 0x4008

1.2 实现

我们先来看看初始的sys_sbrk

uint64 sys_sbrk(void) {int addr;int n;if(argint(0, &n) < 0)return -1;addr = myproc()->sz;if(growproc(n) < 0)return -1;return addr;
}
  • 从寄存器a0拿出n
  • growproc(n) 来分配n byte 的物理内存
  • 返回addr

修改后:

  • 删除分配物理内存的逻辑
  • 如果n 大于0,我们增加sz
  • 否则,我们dealloc 掉n个字节
uint64 sys_sbrk(void) {int addr;int n;if(argint(0, &n) < 0)return -1;struct proc* p = myproc();addr = p->sz;//  if(growproc(n) < 0)//    return -1;// allocif (n > 0){(p->sz) += n;} else {// shrinkuint sz = p->sz;p->sz = uvmdealloc(p->pagetable, sz, sz + n);}return addr;
}

我们启动xv6来测试下:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

和预期一致,我们接着做后面的作业。

二、Lazy allocation

2.1 说明

修改 trap.c 中的代码,使其能在用户空间发生缺页异常时,为发生异常的地址映射一页新分配的物理内存,然后返回用户空间,让进程继续执行。你应当在打印 "usertrap(): ..." 的那条 printf 语句之前加入你的处理代码。此外,你还需要根据需要修改 xv6 内核中的其他代码,使 echo hi 能够正常运行。

官网的一些提示:

  • 你可以在 usertrap() 中通过检查 r_scause() 是否为 1315 来判断是否是页面异常(page fault):
    • 13 表示加载时的页面异常(load page fault)
    • 15 表示存储时的页面异常(store page fault)
  • r_stval() 返回 RISC-V 的 stval 寄存器的值,它表示触发异常的虚拟地址
  • 你可以参考 vm.c 中的 uvmalloc() 函数的代码,这是 sbrk() 通过 growproc() 最终调用的函数。你会用到以下两个函数:
    • kalloc():用于分配一页物理内存。
    • mappages():用于将虚拟地址映射到物理页。
  • 使用 PGROUNDDOWN(va) 宏将发生异常的虚拟地址向下对齐到页边界。
  • uvmunmap() 默认会触发 panic;你需要修改它的行为,使其在取消映射时不会因为某些页未映射就 panic
  • 如果内核崩溃了,你可以查找 kernel/kernel.asm 中的 sepc 来定位异常发生的位置。
  • 使用你在页表实验(pgtbl lab)中写的 vmprint 函数来打印页表内容,辅助调试。
  • 如果你遇到 incomplete type proc 的错误,记得先 #include "spinlock.h",再 #include "proc.h"

如果一切顺利,你的懒惰分配(lazy allocation)代码应该能使 echo hi 正常工作。在执行过程中,系统应该至少会发生一次页面异常(触发懒惰分配),也可能会触发两次。

2.2 实现

  • 按照官网提示,在trap.c 中的usertrap 的 printf else分支前添加处理代码
  • 如果 是 13(load page fault)或 15(store page fault)我们就调用 uvmalloc() 函数分配物理内存,并映射用户页表。
// ...
} else if((which_dev = devintr()) != 0){// ok
} else if(r_scause() == 13 || r_scause() == 15) {uint64 va = r_stval();if (uvmalloc(p->pagetable, PGROUNDDOWN(va), PGROUNDDOWN(va) + PGSIZE) == 0)p->killed = 1;
}
else {printf("usertrap(): unexpected scause %p pid=%d\n", r_scause(), p->pid);printf("            sepc=%p stval=%p\n", r_sepc(), r_stval());p->killed = 1;
}

值得注意的是,因为我们是利用缺页异常实现延迟分配,所以 uvmunmap 中的无法根据虚拟地址找到实际物理页面的情况需要取消panic,改为continue,否则就会触发panic:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

然后我们运行一下:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

三、Lazytests and Usertests

3.1 说明

我们为你提供了一个名为 lazytests 的 xv6 用户程序,它会测试一些特定情况,这些情况可能会对你的懒惰内存分配器造成压力。请修改你的内核代码,使 lazytestsusertests 中的所有测试都能通过。

你需要处理以下几种情况:

  • 处理 sbrk() 的负数参数:即当进程释放内存时,要正确缩小进程的地址空间。
  • 如果进程在访问一个高于 sbrk() 分配范围的虚拟地址时发生缺页异常,应终止该进程
  • 正确处理 fork() 中父进程到子进程的内存拷贝,包括懒惰分配页的复制。
  • 当进程将一个来自 sbrk() 的合法地址传递给系统调用(如 readwrite),但该地址尚未实际分配物理内存时,也应正确处理并触发分配
  • 正确处理内存耗尽的情况:如果在页面异常处理函数中 kalloc() 失败,表示系统已无可用内存,应该终止当前进程。
  • 处理位于用户栈下方的非法页面上的访问异常

你的实现是合格的,如果你的内核能够通过 lazytestsusertests 的全部测试,如下所示:

$ lazytests
lazytests starting
running test lazy alloc
test lazy alloc: OK
running test lazy unmap...
usertrap(): ...
test lazy unmap: OK
running test out of memory
usertrap(): ...
test out of memory: OK
ALL TESTS PASSED$ usertests
...
ALL TESTS PASSED$

3.2 实现

先跑一下看看哪里报错,结合官网提示去调:

3.2.1 lazytests

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

~~然后它就死了。~~但是给了很多信息。

我们先看uvmcopy,原代码:

  • 这个函数会把给定的父进程页表拷贝内存到子进程页表,页表和物理内存都进行拷贝
  • 官网提示我们正确完成拷贝包括懒惰分配页的复制
// Given a parent process's page table, copy
// its memory into a child's page table.
// Copies both the page table and the
// physical memory.
// returns 0 on success, -1 on failure.
// frees any allocated pages on failure.
int uvmcopy(pagetable_t old, pagetable_t new, uint64 sz)
{pte_t *pte;uint64 pa, i;uint flags;char *mem;for(i = 0; i < sz; i += PGSIZE){if((pte = walk(old, i, 0)) == 0)panic("uvmcopy: pte should exist");if((*pte & PTE_V) == 0)panic("uvmcopy: page not present");pa = PTE2PA(*pte);flags = PTE_FLAGS(*pte);if((mem = kalloc()) == 0)goto err;memmove(mem, (char*)pa, PGSIZE);if(mappages(new, i, PGSIZE, (uint64)mem, flags) != 0){kfree(mem);goto err;}}return 0;err:uvmunmap(new, 0, i / PGSIZE, 1);return -1;
}

然后注意到 panic(“uvmcopy: page not present”);被触发显然是因为遇到了我们假分配的页面

那就很简单了,注释掉panic,改为continue即可。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

再跑一遍:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

它又死了,这次报错在 freewalk

我们查看一下源码:

  • 它会递归释放页表页
  • 所以叶子映射都必须已经释放
// Recursively free page-table pages.
// All leaf mappings must already have been removed.
void freewalk(pagetable_t pagetable)
{// there are 2^9 = 512 PTEs in a page table.for(int i = 0; i < 512; i++){pte_t pte = pagetable[i];if((pte & PTE_V) && (pte & (PTE_R|PTE_W|PTE_X)) == 0){// this PTE points to a lower-level page table.uint64 child = PTE2PA(pte);freewalk((pagetable_t)child);pagetable[i] = 0;} else if(pte & PTE_V){panic("freewalk: leaf");}}kfree((void*)pagetable);
}

钠根据该函数的描述,我们知道说明有叶子节点没有被释放。

这其实是比较奇怪的,然后看到官网这一条提示:

  • 如果进程在访问一个高于 sbrk() 分配范围的虚拟地址时发生缺页异常,应终止该进程

于是合理怀疑是因为测试点里面有对于非法地址的访问,触发缺页异常,然后让我们误以为是懒惰分配,从而分配了物理内存。

于是在最早的usertrap中的逻辑中加一个地址界限的判断:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

这次就没问题了:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

3.2.2 usertests

同样的,我们根据错误找问题:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

通过vscode找到这个sbrkarg函数是在 usertest.c 下

  • 用来测试对分配内存的读写
  • 我们报错是在write的地方报错了
// test reads/writes from/to allocated memory
void sbrkarg(char *s)
{char *a;int fd, n;a = sbrk(PGSIZE);fd = open("sbrk", O_CREATE|O_WRONLY);unlink("sbrk");if(fd < 0)  {printf("%s: open sbrk failed\n", s);exit(1);}if ((n = write(fd, a, PGSIZE)) < 0) {printf("%s: write sbrk failed\n", s);exit(1);}close(fd);// test writes to allocated memorya = sbrk(PGSIZE);if(pipe((int *) a) != 0){printf("%s: pipe() failed\n", s);exit(1);} 
}

官网有着这样一条提示:

  • 当进程将一个来自 sbrk() 的合法地址传递给系统调用(如 readwrite),但该地址尚未实际分配物理内存时,也应正确处理并触发分配

那其实很好理解了,我们没有对 write 访问假分配时进行分配物理内存。

这个就需要我们去查看write 系统调用的实现,以及写逻辑。

先找到 sys_write

uint64 sys_write(void)
{struct file *f;int n;uint64 p;if(argfd(0, 0, &f) < 0 || argint(2, &n) < 0 || argaddr(1, &p) < 0)return -1;return filewrite(f, p, n);
}

发现调用了 filewrite

然后查看 filewrite 发现它又调用了 writei 来进行写逻辑

writei 又调用了either_copyin,而either_copyin又调用了copyin

最终在 copyin 中发现了对于pagetable 的访问

总而言之是这么个逻辑:

sys_write() -> filewrite() -> writei() -> either_copyin() -> copyin() -> walkaddr()

查看 walkaddr:

  • 果然有问题,如果访问到空页或者无效页,它直接返回0了(0代表未映射)
uint64 walkaddr(pagetable_t pagetable, uint64 va)
{pte_t *pte;uint64 pa;if(va >= MAXVA)return 0;pte = walk(pagetable, va, 0);if(pte == 0)return 0;if((*pte & PTE_V) == 0)return 0;if((*pte & PTE_U) == 0)return 0;pa = PTE2PA(*pte);return pa;
}

我们特判尝试物理分配即可:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

值得注意的是两个头文件的引用顺序:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

测试一下:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

http://www.dtcms.com/wzjs/73796.html

相关文章:

  • 安徽鑫华建设有限公司网站厦门小鱼网
  • 西宁网站建设开发网络查询网站
  • javaweb做商业网站太原seo排名公司
  • 网站建设项目实施方案上海百度关键词推广
  • 南通网站建设机构天津百度搜索排名优化
  • 有哪些做包装设计网站好些小网站怎么搜关键词
  • wordpress小程序配置seo实战密码第四版pdf
  • 柳州企业 商家应该如何做网站百度推广个人怎么开户
  • 专业的外贸网站建设全国各城市疫情高峰感染高峰进度
  • 网站名字如何申请网站域名流程
  • app推广注册从哪里接单做抖音seo排名软件是否合法
  • 做的网站在百度找不到了百度下载并安装最新版
  • 微信优惠群怎么做网站怎么用手机制作网站
  • 网站asp源码谷歌外贸seo
  • 网站开发答辩知识点seo优化费用
  • 建设工程质量监督网站上海站群优化
  • 人际网络网络营销是什么seo营销服务
  • 上海网站制作库榆在线磁力搜索神器
  • 网站推广策划案效果好太原网站优化
  • 做海报兼职网站深圳专业seo
  • 苏州工业园区质安监站网址买卖友链
  • 贵州网站制作品牌公司杭州推广系统
  • 网站建设属于什么工作企业网站定制
  • b2c模式的网站有哪些上海网络推广公司网站
  • 潍坊网站建设科技有限公司上海抖音seo公司
  • wordpress建站哪里好百度云搜索引擎 百度网盘
  • 鞍山市网站建设seo的含义
  • 宠物网页制作模板seo推广的常见目的有
  • 网站需求分析怎么写海门网站建设
  • 建设部166号令住建部网站现在的seo1发布页在哪里