首页 > 系统相关 >CS202 WeensyOS 内存分配算法

CS202 WeensyOS 内存分配算法

时间:2024-04-07 14:01:00浏览次数:14  
标签:实验室 WeensyOS 代码 内核 CS202 运行 内存

CS202:实验室4:WeensyOS

CS202:实验室4:WeensyOS介绍在这个实验室中,您将在一个(但却是真实的!)操作系统,名为WeensyOS。这将向您介绍虚拟内存,并强化我们已经介绍过的一些概念
学期WeensyOS内核在x86-64 CPU上运行。因为操作系统内核运行在“裸”硬件上,所以调试内核代码可能很难:如果一个错误导致硬件配置错误,通常的结果是整个内核(以及在其上运行的所有应用程序)。因为内核本身提供了最多基本系统服务(例如,使显示硬件显示错误消息),推断导致内核崩溃可能特别具有挑战性。在过去,开发操作系统代码的常用方法(无论是作为课程的一部分,在研究实验室还是在工业中)都是在物理CPU上启动它。的生活从那以后,内核开发人员变得更好了。您将在QEMU中运行WeensyOS。QEMU是一个基于软件的x86-64模拟器:在WeensyOS看来,它就像一个带有特定硬件配置。但是,如果您的WeensyOS代码正在进行中,则会楔入(虚拟)
硬件、QEMU本身以及在“真实”硬件上运行的整个操作系统(即QEMU正在运行)毫发无损地生存下来(“real”用引号表示,原因将在
下一段)。因此,例如,在内核崩溃之前的最后几次调试printf()仍然会被记录下来到磁盘(通过在Linux上运行的QEMU),并且“重新启动”您正在开发的内核相当于重新运行QEMU模拟器应用程序。
这里的实际软件/硬件堆栈是什么?对于使用x86-64计算机的学生来说,答案是不同的
(例如,Windows机器和旧的Mac电脑)和ARM。所有学生都在运行主机操作系统(在您的计算机)在x86-64或ARM硬件(ARM是所谓的Apple silicon的架构,即M1和M2芯片)。然后,Docker容器化环境在主机操作系统(作为过程粗略地说,代 写CS202 WeensyOS 内存分配算法该环境模拟x86或ARM CPU,并运行在模拟的CPU是UbuntuLinux,目标是x86-64或ARM。在Ubuntu上运行的是QEMU。QEMU提供了一个模拟的x86-64接口,QEMU本身是x86-64或ARM二进制文件,同样取决于在底层硬件上。最后,WeensyOS只是一个x86-64二进制文件,当然它运行在QEMU(不过,如果您有一些x86-64硬件,您可以尝试安装WeensyOS和
“裸运行”)。按照同样的步骤,现在是自上而下的:如果你有ARM CPU,那就意味着你在QEMU中运行WeensyOS内核的x86-64指令,QEMU是一种软件模拟的x86-64-CPU
ARM二进制,在Linux之上(以ARM为目标),在Docker容器化环境中运行(也包括自身ARM二进制),在macOS上,在ARM硬件CPU上运行。
请注意。和往常一样,准时出发很重要。在这种情况下,准时是指在任务到期了,因为你几乎肯定需要所有分配的时间来完成实验室。内核
开发不如开发用户级应用程序宽容;的配置中的微小偏差操作系统的硬件(如MMU)往往会使整个(模拟的)机器停止。为了以后不让自己头疼,在开始之前请完整阅读这篇实验室文章。资源。 CS202:实验室4:WeensyOS2/19
您可能想看看CSAPP3e的第9章(我们的x86-64虚拟内存讲义来自该章
借用)。这本书在Courant图书馆保留。第9.7节特别介绍了64位
x86-64 CPU的虚拟内存架构。图9.23和第9.7.1节显示并讨论了
PTE_P、PTE_W和PTE_U比特;这些是x86-64硬件的页表条目中的标志,用于播放
在这个实验室的核心作用。
你可能会发现自己在实验室里想要了解特定的组装说明。这是
Brown和CMU提供的x86-64指令的两个指南。前者更容易消化;后者是
更全面。提供的代码还使用某些汇编指令,如iret;看到这里
以供参考。
入门
您将像往常一样在Docker容器中工作。我们假设您已经按照描述设置了上游
在实验室设置中。然后在本地计算机上运行以下操作(Mac用户可以在本地计算机或
Docker容器内;Windows和CIMS用户应在容器外执行此操作):
$cd~/cs202
$git上游提取
$git合并上游/main
该实验室的文件位于lab4子目录中。
如果您在实验室3中有任何“冲突”,请先解决它们,然后再继续。运行git-push以保存您的工作
返回到您的个人存储库。
另一个抬头。考虑到这个实验室的复杂性,以及破坏的功能的可能性
内核如果您的代码有一些错误,请确保经常提交和推送您的代码!非常重要的是
您的提交有代码的工作版本,所以如果出现问题,您总是可以返回到
之前提交并取回一份工作副本!至少,对于这个实验室,你应该承诺
每一步一次(可能更频繁),因此如果需要,可以返回到最后一步。
球门
您将为WeensyOS进程实现完整且正确的内存隔离。然后您将执行
虚拟内存已满,这将提高利用率。您将实现fork()(在运行时创建新进程)
为了获得额外的积分,您将实现exit()(在运行时销毁进程)。
我们已经为您提供了许多有关此任务的支持代码;实际上,您需要编写的代码
范围有限。我们的完整解决方案(适用于所有5个阶段)由不到300行的代码组成,这些代码超出了
我们最初分发给您。您编写的所有代码都将放在kernel.c中(步骤6的一部分除外)。
测试、检查和验证
对于此任务,您的主要检查方法将是运行Weensy OS的实例,并可视化
将其与你在课业中看到的图片进行比较。
仔细研究这些图形内存图是确定您的WeensyOS代码是否
每个阶段都在正确工作。因此,您一定要确保了解如何
在开始编写代码之前,请先阅读这些映射。
CS202:实验室4:WeensyOS

3/19
我们提供一些评分脚本,在实验室结束时概述,但这些脚本不是您的主要来源
反馈在大多数情况下,它们只指示给定的步骤是通过还是失败;看看记忆
地图以了解原因。
初始状态
进入Docker环境:
$ ./cs202运行docker
cs202-user@172b6e333e91:~/cs202实验室$cd lab4/
cs202-user@172b6e333e91:~/cs202实验室/lab4$make run
这些指令的其余部分假定您处于Docker环境中。我们省略了cs202-
user@172b6e333e91:~/cs202实验室提示的一部分。
make-run应该会让您看到以下内容,其中显示了四个并行运行的进程,
每个都在p-分配器中运行程序的一个版本:
这个图像永远循环;在实际跑步中,杠会向右移动并停留在那里。如果你的
图像具有不同数量的K或者具有不同的细节。
如果条形图运行速度非常慢,请编辑p-allocater.c文件并减少ALLOC_SLOWDOWN常量。
现在停止阅读并理解p-allocater.c。
以下是如何解释内存映射显示:
WeensyOS显示物理内存和虚拟内存的当前状态。每个字符表示4 KB
内存:一页。总共有2 MB的物理内存。(问问自己:有多少页
这是吗?)
WeensyOS运行四个进程,从1到4。每个进程都是从相同的源代码(pallocator.c)编译的,但链接使用不同的内存区域。
每个进程都要求内核提供更多的堆内存,一次一页,直到空间用完为止。像
通常,每个进程的堆开始于其代码和全局数据的正上方,结束于其堆栈的正下方。
进程以不同的速率分配堆内存:与进程1相比,进程2分配
CS202:实验室4:WeensyOS

4/19
两倍的速度,进程3的速度快三倍,进程4的速度快四倍。(随机
使用了数字生成器,因此准确的速率可能会有所不同。)一排排数字显示了
快速分配进程1、2、3和4的堆空间。
这里有两个标记的记忆图,显示了字符的含义以及记忆是如何排列的。
虚拟内存显示类似。
虚拟内存显示在四个进程的地址空间之间依次循环。在
我们为您提供的WeensyOS代码的基本版本,所有四个进程的地址空间都是
同样(你的工作就是改变这一点!)。
虚拟内存显示中的空格对应于未映射的地址。如果一个过程(或
内核)试图访问这样的地址时,处理器将出现页面错误。
虚拟内存显示中地址X处显示的字符标识的所有者
相应的物理页面。
在虚拟内存显示中,如果允许应用程序进程,则字符为反向视频
访问相应的地址。最初,任何进程都可以修改所有物理内存,包括
内核。内存未正确隔离。
运行WeensyOS

fork()复制进程的所有内存是很浪费的。例如,包括p-叉的大多数过程,
永远不要更改他们的代码。那么,如果我们共享包含代码的内存呢?这对流程来说没问题
隔离,只要两个进程都不能编写代码。
CS202:实验室4:WeensyOS

15/19
步骤A:更改k-loader.c中的进程加载器以检测只读程序段,并将其映射为
应用程序只读(PTE_P|PTE_U)。程序段ph为只读iff(ph->p_flags&
ELF_PFLAG_WRITE)==0。
步骤B:从步骤5开始,您的fork()代码就不应该复制可共享的页面。但在这一步中要确保
您的代码可以准确地跟踪每个用户页面的活动引用数。具体而言,如果
pageinfo[pn].refcount>0且pageinfo[pn].owner>0,则pageinfo[pn-].refccount应等于
pn在进程页表中被映射的次数。
完成后,运行p-fork应如下所示:
暗示
在将数据添加到的memcpy和memset操作之后,将程序段标记为只读
段否则你会犯错的。
再次承诺并推动!
(额外学分)第7步:释放内存
到目前为止,没有一个测试程序释放内存或退出。内存分配非常容易,直到你
免费添加!因此,让我们通过允许应用程序退出来做到这一点。在本练习中,您将实现sys_exit()
系统调用,退出当前进程。
这个练习很有挑战性:释放内存往往会暴露出其他代码中的弱点和问题。
要测试您的工作,请使用make run,然后键入“e”。这将重新启动WeensyOS以运行p-forkeexit程序。
(最初它会崩溃,因为sys_exit()尚未实现。)p-forkeexit结合了两种类型的行为:
进程1无限期地分叉子进程。
2号及以上的子进程是内存分配器,与实验室前面的部分一样
概率在每一步,每个子进程要么退出,要么尝试派生一个新的子进程。
结果是,一旦您的代码是正确的,p-forkeexit就会永远生成疯狂的模式。例如:
CS202:实验室4:WeensyOS

16/19
你的照片看起来可能有点不同;例如,由于步骤6,您的进程应该共享一个代码
页面,将显示为颜色较深的“1”。
这是你的任务。
sys_exit()应该将进程标记为空闲,并释放其所有内存。这包括过程的代码,
数据、堆和堆栈页面,以及用于其分页结构的页面。
在p-forkeexit中,与实验室的前几部分不同,sys_fork()可以在没有足够的资源时运行
内存以创建新进程。您的代码应该能够处理这种情况。如果没有足够的可用内存
分配一个进程,fork()应该在其自身之后进行清理(即,释放分配给的任何内存
内存耗尽之前的新进程,包括作为分页一部分分配的页面
结构),然后向调用者返回-1。不应存在内存泄漏。
定期运行的check_virtual_memory函数应该有助于捕获一些错误。请随意添加
你自己的支票。
进修(额外学分)
如果你已经完成了,迫不及待地想做更多这类工作,请尝试以下操作。这些将只接收令牌
点,如果您感兴趣,可供您探索:
写入时复制页面分配!
更快的系统调用,例如使用syscall和sysexit指令!
运行分级测试
正如本实验室开始时所述,当您的WeensyOS内核运行时,QEMU显示的视觉内存映射是
确定代码行为的最佳方式。
然而,我们提供自动化测试,以帮助我们评分,并让您确认您已经完成了一个步骤。
测试不是决定性的:有些情况下,您的代码通过了测试,但最终并不正确
(在分级过程中手动检查会失分)。然而,我们没有看到相反的情况:
其中您的代码未通过测试但正确。因此,如果测试失败,几乎可以肯定您有一个bug。
CS202:实验室4:WeensyOS

17/19
最重要的是:使用make-run或make-run控制台(或make-run-gdb)运行,以可视化内存的情况
在编码和验证设计时使用。然后,切换到所述的自动测试
当你认为你已经完成了一个步骤并想再次检查时,请在下面。
共有五个测试,每个步骤一个。您可以使用shell命令运行它们中的每一个,使等级为一
直到五年级。请注意,步骤编号以文本形式书写,而不是使用数字。每一步的结果
要么全有要么全无。
在所有五个步骤的测试中,有三个不变量是您的代码必须满足的。这些不变量是:
CGA控制台必须可供所有进程访问(这一要求在上面的文本中讨论
步骤1)。
如果我们考虑进程P,则在用户空间地址处的P的页面表中不应存在虚拟页面(即
是,其地址位于内核/用户虚拟地址分割点之上),该地址由P所有,但不是
P可访问。
当我们运行测试时,我们将WeensyOS内核配置为在执行10秒后退出(1000
WeensyOS内核“滴答”)。如果代码中的一个错误导致内核在1000 WeensyOS内核之前崩溃
滴答作响,你将无法通过发生这种情况的测试。或者,如果内核进入无限循环
永远不会在1000次时到达我们的出口,虚拟机将陷入无限循环,永远不会退出,所以测试
将挂起,您需要终止挂起的内核。打开另一个终端窗口并
发出命令make-kill,这将终止您正在运行的所有QEMU进程。
这些不变量是合理的:无论内存映射显示是什么样子,一个好的解决方案
既不应崩溃也不应进入无限循环。
我们的测试是累积的:每个步骤的测试都运行之前的所有步骤的测试。如果之前的任何步骤测试失败
“当前”步骤的测试被视为失败。因此,如果您有一个回归错误——例如,
当前步骤中的代码重新引入了前一步骤中的错误——不仅当前步骤会丢分
您正在进行中,但也适用于之前的步骤。如果你需要提交并发现这种情况已经发生,不要绝望:
只需将代码恢复到回归前的最后一个好版本(使用GitHub提供的历史记录
--因此,再次确保您经常提交和推送!)。
在“分级”模式中使用gdb
make grade-X脚本向QEMU传递的选项与make run略有不同。如果你发现自己失败了
在gdb下,可以使用分级选项运行分级测试。要执行此操作,请按照上面的gdb说明进行操作,
除了上面写着make-run-gdb之外,请键入make-grade-gdb。
其他提示
内核定义了一个常数HZ,它决定了内核时钟每秒滴答的次数。不要
改变这个值——在解决实验室问题时绝对没有必要这样做,这样做可能会导致
您的代码无法通过我们的测试!
在您运行任何一个阶段的N级测试后,如果您碰巧检查/tmp/log.txt文件,您将
我们在其中生成了大量用于自动测试的输出。你可以忽略它(和它
当您在开发过程中使用make-run运行时,将不存在,因此它不会打乱您自己的调试
logprintf()在这些运行中)。
2.
CS202:实验室4:WeensyOS

18/19
屈服
移交包括三个步骤:
1.执行本检查表:
确保您的代码生成时没有编译器警告。
请确保您已使用git add添加您创建的任何文件。
填写answers.txt文件的顶部,包括您的姓名和纽约大学Id
确保你已经回答了answers.txt中的每个问题
确保您已经回答了文件中的所有代码练习。
创建一个名为slack.txt的文件,记录您用于此任务的空闲天数。这
是为了帮助我们就您使用的号码达成一致。)包括此文件,即使您没有使用
休息日。
git添加并提交slack.txt文件
2.将您的代码推送到GitHub,这样我们就有了它(从容器外部,或者,如果在Mac上,这也会起作用
从容器内):
$cd~/cs202/lab4
$make clean
$gitcommit-am“交给lab4”
$git推送原点
正在计数对象:。。。
....
[email protected]:nyu-cs202/labs-24sp-<YourGithubUsername>.git
7337116.ceed758 main->main
3.通过时间戳和识别您的推送代码,实际提交:
决定您希望我们对哪个git提交进行评分,并复制其id(您将在下一个子步骤中粘贴它)。提交id是一个40个字符的十六进制字符串。通常,您想要的提交id就是
你上次创建的。获取上次提交的提交id的最简单方法是运行命令git log-1--format=oneline。这将打印的提交id和初始行
提交消息。如果您想提交以前的提交,有多种方法可以获得提交
早期提交的id。一种方法是使用工具gitk。另一个是git-log-p,如这里所解释的,或者git显示。现在去纽约大学Brightspace;这个实验室会有一个条目。只粘贴刚提交的提交id
复制。您可以提交任意次数;我们将对提交的最后一个提交id进行评分
Brightspace。注:基本事实是您提交给Brightspace的内容和时间。因此,中不存在的提交idBrightspace意味着无论你向GitHub推送了什么,你都没有提交实验室。和为了跟踪延迟,您提交的时间是将id上传到的时间
Brightspace,而不是执行git提交的时间。这就完成了实验室。 CS202:实验室4:WeensyOS
鸣谢这个实验室由Eddie Kohler负责,Brad Karp和Nikola负责修改和一些基础设施
Gvozdiev。
1.通过使显示内容所在的RAM范围以这种方式访问控制台
被应用程序直接访问,这是对DOS时代的倒退,DOS的应用程序通常正是以这种方式生成控制台输出。DOS无法在上运行多个应用程序一次,因此不存在多个并发应用程序互相破坏显示写入的任何风险到相同的屏幕位置。我们借用这种原始的控制台设计来保持WeensyOS的简单和契约↩︎
2.在测试过程中,我们还禁用了p-allocator.c和p-fork.c中的ALLOC SLOWDOWN,这样内存分配进行得更快,以机器的速度而不是人类的视觉速度。因此1000ticks为工作负载运行和展示内核的虚拟内存系统提供了充足的时间行为。↩︎

标签:实验室,WeensyOS,代码,内核,CS202,运行,内存
From: https://www.cnblogs.com/gzashang/p/18118910

相关文章

  • 在使用set添加对象的时候,重写了hashcode方法后,为什么equals返回的仍是false,如何理解ha
    /**1.对象的哈希码值和内存地址值不是一回事;*2.如果自定义类不复写Object类中的equals方法,那么equals比较的就是两个对象的内存地址值。*//***下面证明了hash值和内存地址的关系*一、当没有重写hashCode()方法的时候,*S......
  • 记一次 .NET某管理局检测系统 内存暴涨分析
    一:背景1.讲故事前些天有位朋友微信找到我,说他们的WPF程序有内存泄漏的情况,让我帮忙看下怎么回事?并且dump也抓到了,网上关于程序内存泄漏,内存暴涨的文章不计其数,看样子这个dump不是很好分析,不管怎么说,上windbg说话。二:WinDbg分析1.内存真的暴涨吗在.NET调试训练营中我一直......
  • JVM—对象的创建流程与内存分配
    JVM—对象的创建流程与内存分配创建流程对象创建的流程图如下:对象的内存分配方式内存分配的方式有两种:指针碰撞(BumpthePointer)空闲列表(FreeList)分配方式说明收集器指针碰撞(BumpthePointer)内存地址是连续的(新生代)Serial和ParNew收集器空闲列表(FreeL......
  • 拿捏动态内存分配!!!
    几日不见,甚是想念今天我们来拿捏动态内存分配,很重要哦1.为什么要有动态内存分配我们已经掌握的内存开辟方式有:intval=20;//在栈空间上开辟四个字节chararr[10]={0};//在栈空间上开辟10个字节的连续空间但是上述的开辟空间的方式有两个特点:•空间开辟大小是......
  • 免杀-内存中的加解密
    3x0内存中的加解密3x0x0SystemFunction032SystemFunction032:一个系统函数,可以做到在内存中加解密,调用也很方便或者沿着这个思路我们可以找找其他在内存中加解密的方法加密代码:#include<windows.h>#include<stdio.h>typedefNTSTATUS(WINAPI*_SystemFunction033)( s......
  • 免杀-异常处理_内存波动修改
    3x1远程分段加载shellcode+windows异常处理windows异常处理机制利用原理的文章:https://forum.butian.net/share/783异常处理的个人简单理解:我们在上线cs后,cs是默认设置了60秒睡眠的,也就是心跳包机制,这10秒内我们的代码将会被sleep阻塞,60秒后执行命令再次进入睡眠;而我们的代码......
  • [转帖]JVM 内存分析工具 MAT 的深度讲解与实践——进阶篇
    https://juejin.cn/post/6911624328472133646  注:本文原创,转发需标明作者及原文链接。欢迎关注 【0广告微信公众号:Q的博客】。本系列共三篇文章, 本文是系列第2篇——进阶篇,详细讲解MAT各种工具的核心功能、用法、适用场景,并在具体实战场景下讲解帮大家学习如何针......
  • Cortex-M7 内存模型
    1前言        如图1所示, Cortex-M7最大支持4GB的内存寻址,并对内存映射(memorymap)做了初步的规定,将整个内存空间划分为了多个内存区域(region)。每个内存区域有着既定的内存类型(memorytype)和内存属性(memoryattribute),这两者决定了访存的具体行为。图1  Co......
  • Redis过期删除策略和内存淘汰机制
    过期删除策略1、惰性删除就是过期之后下一次取数据时,发现过期了,就删除它。2、定期删除定期删除一些过期的key。redis采用的时惰性删除+过期删除。问题:可能会漏掉一些key,从而导致OOM。内存淘汰机制3*2+2volatile-lru:从过期数据集中选择最近最少使用的数据淘汰。allKe......
  • 43.数据在内存中的存储
    1.整数在内存中的存储整数的2进制表⽰⽅法有三种,即原码、反码和补码三种表⽰⽅法均有符号位和数值位两部分,符号位都是⽤0表⽰“正”,⽤1表⽰“负”,⽽数值位最⾼位的⼀位是被当做符号位,剩余的都是数值位。正整数的原、反、补码都相同。负整数的三种表⽰⽅法各不相同。原......