 Good morning. What happens at this time of year? Looks like about half the class is here. What's that? There's an exam? Huh. Well, I wonder if that's true. Everybody, so welcome back to class. One of these days, you should just play music all hour. That would be interesting. I don't want to turn the music off today, but to talk about swapping. OK, so today we're going. At some point, the music must end, and the fun operating system concepts must begin. So today we're going to talk about swapping. We're going to talk about how, so on Friday at the end of class, we hinted that we can make memory look bigger by moving intelligently, moving pages of content back and forth between memory and a portion of the disk that we use for this purpose that is sometimes called a swap file. And the process of doing this is called swapping. So today we're going to look through a little bit more of the mechanics of swapping in terms of exactly what the operating system needs to do in order to move a page out. And that'll be a good review of some of our virtual addressing and sort of MMU concepts. And then we'll talk a little bit about the difference between different types of page faults. We'll introduce a pretty common architecture for interaction between the MMU and the kernel, which are called Harbor Managed TLBs. And they're common because the x86 uses this. And your MIPS system does not, but many, many other commercial systems do. And so it's just a little bit of a different relationship between the MMU and the operating system. We'll talk about how that works. And then we'll talk a little bit about procrastination, how procrastination might be an interesting and useful technique for the operating system to use in certain cases when dealing with process requests for memory. So at this point, hopefully, you guys are at least in the thick of, if not wrapping up, assignment to. That's where I would want to be. On Friday, we're going to turn on the assignment 3 auto grading for people who are ready to move on to that point. And at that point, there's just one deadline left and everything will work. I mean, I don't want to terrify people, but these assignments are hard. And at least at this point, you want to feel engaged in assignment 2. Like you have some idea of what you're trying to do. You know, when I took this class, assignment 2, we had two weeks to do. Assignment 3, we also had two weeks to do. And assignment 3 was a lot harder. Back in the old days, we walked uphill to school both ways. Assignment 3 was really difficult. So I mean, they're doable in a couple of weeks, but you really have to put yourself into them at that point. So time, the clock is ticking. All right, so on Friday, we talked about, essentially, when the kernel is interrupted by the memory management unit and needs to load a page translation, what are some data structures that it uses for that purpose. Any questions about that before we go on? Just a little bit of review. Good morning, Vook. Good morning, Paul. So what's the purpose of keeping this state? What do we need to be able to keep up to date? Let's try Kevin. Yeah, the TLB or the MMU, right? So that's the point. And particularly, we talk about maintaining that cache of address translations in the TLB that the MMU uses to make virtual to physical address translation fast, right? So what do we need to be able to do? This is a fairly particular or a couple specific things that the kernel needs to be able to do in order to keep this cache current Spencer. Yeah, so we need to be able to store information. The kernel needs to have information stored about every virtual address and used by any process, right? Or about every virtual page. And then what else do we need to be able to do, Bart? Yeah, so when we're on the page fault or TLB fault handling path, we want to be able to look up that information quickly, because we've already stalled so that the MMU can load the translation. We don't want to make things even slower than they already are, right? So what information do we actually need to keep about each page? Nick, give me one. OK, permissions is one. Sumit? What's that? OK, the location, right? The location could be what or what, Tim? Could be in memory or on disk, right? And so I need to have some. I need to be able to find the page contents, right? Anything else? Sean, Amit? Yeah, OK, so I need to know what the process ID is, right? This came up in Piazza too, but this actually isn't necessarily something I'm going to store with the page table entry, right? Because the process ID is going to be used. So how do I use the process ID in the process of locating information about a virtual address, right? I can also keep some statistics about how many times the page has been used. Andrew, how does the process ID come into play here? It's not actually stored in the PTE, but how is it used by the kernel? Right, so I need to be able to store separate virtual address translations for different processes, but how do I use the process ID? So there's an MMU. The MMU says, hey, I don't know how to translate this address. You're the kernel, you start running. Robert, so you know what process is running, and then what is per process here that I'm going to use as part of this? So there are PTEs associated with the process, but there's no process ID in the PTE necessarily. So how do I know that the PTE is for a particular process? Damn. How do I find the PTEs in the first place? Well, but we talked about this data structure that I had, right? That was called, Alyssa? Anybody want to help her out? Wembley. I have a page table, right? The page table is how I translate a virtual address to a PTE, which stores information about that virtual address that I need in order to help the MMU complete the translation. What? So again, I'm going to go back to my question. Where does the process ID come in here? Sugar. Rune. Well, I know. OK, so I know what process is running, right? So that's important to remember, right? I know what process is running because I scheduled it, right? I scheduled the process on the core, so I know it's running on that core. How do I use that process information in the process of translating a virtual address? I have to, right? Because the virtual address is a reprocessed, but how do I use it, Sean? See, I'm saying that is not true. There is no PID in each page table, right? This is really important. Every process has a separate page table. So when I translate a virtual address, I'm going to use this page table data structure, but that page table data structure is different for each process. So if I translated a virtual address using multiple page tables, I would get different answers, right? And maybe some of them would be the same if those pages are actually being actively shared by processes, but the point is that this is where the process ID comes into play, right? I use the process ID to find a page table data structure that is specific to that process. That data structure allows me to find a PTE that PTE has the data, the rest of the data I need in order to figure out what to do at that point. Does this make sense to everybody? Because this came up in the outside, I just want to make sure it's addressed, Nick. Yeah, I mean, usually what I do is I have some process data structure or a thread data structure. For example, on OS 161, a thread data structure already exists, and I use that thread data structure to find the page table, right? And actually, you can look in your kernel right now and see how this is done, right? And for assignment three, you will do this because your kernel right now is actually capable of translating virtual to physical addresses. If it didn't, none of the user programs you guys are working out for assignment two would work, right? The problem is that it uses a very, very dumb virtual memory manager, which you guys will have to replace in assignment three. It doesn't do anything smart, but it still has to work. And basically, the requirements for how we stored this information were we wanted to make it as compact as possible, right? Because the number of page table entries grows as the total number of virtual pages allocated by any process on the system, right? Any process on the system allocates a virtual page. I need a page table for it, so I can have lots of these. We've been talking about page table entries, so I don't think this will surprise anybody. And then we also just talked about page tables, right? So the page table is this data structure that is used to quickly map a virtual page number to a page table entry. It's called a page table. And these are per process data structures, right? And why are they per process? Swatha, this is listening to and processing the last three minutes of class questions. Why does every process have a separate page table? Sarah, virtual addresses are inherently per process, right? There is a virtual address has no meaning without associating it with the process, right? All right, so we talked about three different ways to set up our page tables. I'll just briefly review this. So we had this flat page table data structure, which is essentially one big array for the entire address space. We had linked list page tables, where I created a new entry for every PTE. And then I had a multi-level page table, which was a tree-like data structure, where I split up the virtual page number and used different parts of the virtual page number as indexes into different parts of the table. So flat page tables, speed, big O notation. Okay, O1, yeah, there's a constant lookup, right? It's just a, you know, I just convert the virtual page number directly into an index into an array, right? What about the size? John, very big, yeah, kind of O huge, right? Actually O address space size divided by number of pages, right? But O bad, right? Like O, not, not gonna implement it. Okay, so what about the linked list page tables? Speed. Sean, where N is what? Yeah, so ON for N virtual pages, right? I mean, it's a flat data structure. I just have to search the whole thing and it's basically ON. And then what about size? Paul, ON as well, right? One, you know, link in my list for every page. All right, what about my multi-level page tables? Tom? Yeah, O constant, right? It depends on the depth, but I have to do some number of traversals, right? But it's a constant for a given page, for a given multi-number of levels, right? It scales with the number of levels and then what about the size? Yeah, but it can vary and I really should have a more convincing explanation of this, but it's much, much smaller than a flat array while preserving the same quality, right? Because I'm only gonna have second-level page table. I'm only gonna have second-level tables for parts of the address space that aren't in use, right? Every page table needs a top level, but I only have the second levels that I need, right? So this grows quite slowly and it's a nice fit for address-based abstraction because it's sparse, right? We have these sparse address spaces. All right, any questions about this stuff before we venture forward, right? So this is how the kernel translates virtual pages into information about a page, okay? So as we talked about a little bit in the class, so we, you know, reclaiming memory requires that we store the content somewhere else, right? While we reclaim that page to give to another processor to do something else with, right? The place we put it is on disk, right? Typically these swap files are kind of transitory, right? They're not stored across reboots, right? Disk is just, the reason we use the disk is not because it's persistent. The reason we use the disk is what? Damn. It's big, right? It's huge. I have lots of it, right? I usually have a much, much bigger disk. Maybe one or two orders of magnitude, bigger disk. Then I have RAM. So I have a lot of space there that I can use. So we call this process of moving data back and forth from the disk to make, to allow us to reclaim memory swapping, right? And remember we talked about this goal, right? When we do swapping well, we can make your computer feel like it has the amount of memory, an amount of memory that's equal to the amount of memory it actually has plus the size of the swap file, potentially, right? Certainly bigger, right? We make it feel like it has more memory. If we do it poorly, right? We can make your system feel like all of the memory is as slow as your disk, right? And in the past, people have submitted assignment three submissions that had this property, right? They worked, actually. I remember David Holland once spent three days testing a submission because one of the tests that we run ended up taking like 12 hours to complete on this particular system. I think that system was using one page or maybe two or something, right? It was very broken, but it did complete. And it got credit when it finished, right? We don't do that here. We kill things after an hour or so. So don't write anything that's that slow for assignment three, because you will not get credit. I'm not that patient. All right, so, okay, so what do we need to do, right? We have this great idea. We said, okay, we're gonna copy a page out to disk, right? I copy page out to disk and suddenly I had this 4K of RAM that I didn't have before. And I can use it for something else and I can make memory look bigger than it actually is. But let's say a page is in memory and it's in use by a process. What are the steps we have to take to swap a page out of memory and onto disk? He wants to throw something out. A good review of kind of all of the different parts of this boot. Yeah, so I have to preserve the contents, right? This is probably one of the most important parts, right? I have to preserve the contents. If I don't preserve the contents, then the process is going to be confused when it was using something that looked like memory and it just kind of like walked away from it for a little while and came back and suddenly the contents were different, right? That violates the interface and the guarantees that we're making to processes about how virtual memory is going to look, right? So if I'm gonna copy the contents, which is one of the things I'm going to do, what do I have to do, AJ? What else do I have to do? This page is currently, let's say the page is in the MMU, there's a translation that's mapped for it and a process at some point was using it, Vroom. Yeah, I need to stop the process from using it, right? The problem is, if you think about it, right, I'm going to copy the contents, right? I have to have some idea of what the contents were at a point in time, right? You can think about it as a checkpoint where I say, this is how the page looked. If I allow the process to continue to use the page while I'm copying the contents, what will happen is that there will be some parts of the changes that it made to the page that will never get to disk, right? And many of you guys will probably do this by accident when you guys have planned assignment three, right? And you'll get these weird errors with some of the tests we run because they'll be in the middle of writing some data to a page and you'll be swapping it out, but you'll have forgot to remove the entry from the TOB. And so the contents that land on disk are some weird mixture of what was on the page when you started copying it and some of the changes that the process made to the page while you were in the process of copying, right? So I need to stop the process of using the page so I have a, like the page state is frozen, right? The page is not going to change at that point, right? So the first thing I'm going to do is remove the translation. The second thing I'm going to do is copy the contents of the page to disk. What's the last thing I need to do? Well, this is swapping out, right? All I'm thinking about is bye-bye page. You're going to disk, right? But what's the last thing I have to do here? What am I missing? Sean. Well, remember at this point, these, what I'm doing is I'm moving this page onto disk, right? So there is a separate process which we'll cover in a second for getting back, right? Which we will talk about, right? But we're just talking about the first part. What we call this is I'm evicting this page from memory, right? Yeah, actually. Okay, so that's actually true. That's not what I'm after here. So before I reuse the page, I want to clear the contents. Why is that, actually? That's a good question. Let me ask. Before I give this page to another process, I am going to clear the contents, meaning that I am going to fill this page with zeros. Why would I do that? Sir, well, even if I didn't have that problem, right? So what am I doing? I'm swapping this page out because I'm going to take this page and give it to another process, right? So there's some contents on the page, right? That the process was doing something. It had some information on the page, right? I'm copying the page out to disk. Before I give that page away to another process, I'm going to fill it with zeros. The reason I'm going to do that is, I don't know, yeah, yeah, and is private to the previous process, right? So imagine I have, I don't know, like Firefox and you just entered your password for a website or your credit card number or something, right? And that Firefox had that stored in memory for some reason, then use that page for a while. Now I swap that page out and I give it over to bad evil process and bad evil process looks around on the page and says, hey, look at this. This is a 16-digit number that starts with one of the common credit card prefixes. Yeah, there you go, right? So yeah, this is a security hole, right? So we need to make sure that when we recycle pages, we zero the contents out, right? But there's a third thing I'm thinking about here, right? What's this last piece of bookkeeping that I need to do? Summon. Okay, where do I store it? Some data structure. Where data structure would that be? Right, where is that bit value? Oh, page table entry, right? So I have to update the page table entry, right? Remember, I'm going, the virtual address, has the virtual address for this page changed? No, right? The process is going to use the same virtual address next time it wants to use this page. What's changed is the status of this page. It's no longer in memory, right? So the next time the process tries to use it, I'm going to use the page table entry to find information about this virtual address for this process, and I'm going to find page table entry and that page table entry had better. Tell me where that page is, yeah, correct. Yeah, exactly, yeah, exactly, right? So what I've done, well there's a good question, right? So the virtual address is the same, right? If the contents aren't in memory, I cannot load this virtual address into the MMU, right? The MMU doesn't have any idea about how to map stuff to disk, right? The MMU maps virtual addresses to physical addresses, right? So at this point, there is no valid translation that I can load into the MMU for this page, right? But I do need to know where did I put the contents, right? And so, like I said before, usually the page table entries have some bit packing that they do that allow them to hold either a physical page number, if the page is in memory, or a disk block or disk identifier, some sort of swap, something that allows me to find it in the swap file, right? And then I also need to have some state. So next time the process tries to use this address, I need to figure out where did I put it, right? We'll go through that in a sec, right? But let me show off one of my cool diagrams. All right, so here's the situation I have, right? I've got a particular code page for this process. I have a valid mapping for it in the TLB. The TLB points to place and physical memory. And my page table entry here also has this physical memory location, right? So now I want to swap the page out, right? So the first thing I need to do is I need to get, and this is a lot of times, really the first thing, right? I need to get the page out of the TLB, right? We'll talk in a little, we'll talk maybe Wednesday about why this might not be a good page to evict, right? When I'm choosing pages to move to disk, right? A page that has a valid mapping in the MMU might not be the best choice. Why is that? Somebody I haven't heard from for a little while. Zoo. Oh, he's not listening to me or I have the wrong name. Z. Yeah, why would, what was I asking? Oh yeah, why would this be a bad page, right? It has a valid mapping in the MMU. If I was thinking about all the different pages in memory that I could potentially move to disk to create space, why might I want to avoid ones that have a valid mapping in the MMU? So it means I have one more update to do, but what else does it mean about this page, Jen? If there's a translation loaded for it in the MMU, what happened to it recently? Sam? It's being used, right? Remember, the TLB is small. It's a cache. It's a cache of translations in use by the running process. So if there's an entry in the TLB for a page, what it means is that the kernel loaded that entry fairly recently, which means that an address on that page was accessed, right? And now you're saying, this is a great page to move to disk, right? False, okay, but let's just go through this example because this is like the worst possible case, right? In the best case, there's no entry in the TLB for the page and then you're in good shape because you don't have to remove it, right? Think about it, there's thousands of other pages out here in physical memory that potentially do not have an address mapped in the TLB right now, right? Those would potentially be better pages to evict, right? And for your assignment three implementation, sometimes you might just decide to avoid evicting these pages altogether, right? If the page is in a TLB, you might say, I'm just not going to ever try to swap it out. Nick, you got a question? Yeah, so this is a good question. So the question is, when I switch between processes during, what do we call that? Context switch. So when I perform a context switch, in general, the entries in my TLB are per process, right? Because they're mapping virtual addresses, which are per process, right? Some TLBs have an additional bit or set of bits here that you can use as a process identifier, right? In fact, your TLB on the MIPS architecture you guys are programming has a process identifier, right? A lot of times, you know, there's problems using these process identifiers. For example, the PIDs that you guys give out for assignment two might be like 32 bits, right? Whereas the process identifier that the TLB knows about might only be five bits or something, right? So there might be issues mapping. It might not just be able to, it would be great if you could just load the PID in along with the virtual to physical translation, right? But that's not exactly how it works, right? Anyway, so let's pretend the TLB doesn't know anything about processes. It just maps virtual to physical addresses. So when I do a context switch, are the addresses that are, as let's say I'm switching in a new process, right? Are the addresses in the TLB useful anymore? No, because they're for the old process, right? So I have a couple of choices. One is I can just clear it, right? Just invalidate all the entries. And so what will happen, I believe you had your hand up for this one. I was gonna say, isn't the TLB used by the MMU and the MMU's cleared on the context switch? No, no, no, but there is a question about how to do this, right? And you guys, when you guys write assignment three, you guys will have a question about how to do this yourself, right? So one solution is I could save the translations that were loaded and reload them next time, right? If I don't, what happens? Let's say I just invalidate all the entries in the TLB. What will happen, what will I see quite a few of after every context switch? Harish. During the context switch, I clear the TLB. I start a new process running and what's gonna happen immediately? Well, not from disk, right? But I'm gonna see a bunch of TLB faults, right? Like because there's no, the MMU has no idea how to map anything. So as soon as that process starts running, every, the first couple of instructions are all gonna start faulting, right? And then I'll load some entries in the TLB and hopefully after I've warmed up my cache a little bit, I'll be okay, right? But yeah, so if I clear the entries, but as Nick points out, you could also save the entries. You could save them as part of the context, which in a very similar way that you save all the other registers that are in use by that process. And then when you restart the process, you could reload those entries into the TLB. You guys can experiment with this on assignment three. See which way you like better. All right, so I've made this potentially ill guided decision to remove an entry that has a valid mapping. So the first thing I have to do is get this mapping out of the TLB. Okay, now it's gone, right? Once it's gone, can this process use this virtual address anymore? What's that? It can. It can? Right, yeah, okay. So yeah, right, in the worst, right. So in the worst possible case, this is another reason why it's usually a bad idea to take, to swap out pages that have valid TLB entries, right? So let's say you're like, hey, I'm gonna swap out a page for this process, right? And I invalidate this, right? Because, so now I clear it from the TLB, right? Now the next thing I'm going to have to do here, I'll come back to that comment and suck, is start writing the contents out to disk, okay? How long does this take? A long time, right? A long, long time, right? Yeah, this is great, right? I'm really glad that I did that in three parts. Because it's, so the whole time, so here's the interesting thing too, right? I start up this disk operation, and the process that is in the process that's actually swapping a page out at that point is going to sleep, right? Because this IO is in progress. The worst thing that can happen then, right, is that this process starts running again and falls on this address, right? So now I've got this terribly, I've got the situation where the page is being written out to disk, which takes forever, right? Meanwhile, there's another process trying to use the address again. So I can't, if you get caught in the middle here, you kind of have to decide what to do, right? The safest thing is usually just to let it finish, right? And then immediately swap the page back in, right? And like we'll talk about on Wednesday, that's like the worst possible case. Like this is, if you wanted a way to make your system slow, this is a great way, right? This is the way that makes your system seem as if all of the memory is as slow as disk, right? As if in the middle of swapping, you know, what you were hoping when you swap the page out is it would stay on disk for a long time before it got used again. And here, you didn't even get it to disk before it got used again. So this is terrible, right? Okay, but at some point, let's assume that this process is not using this address for whatever reason. I got lucky, the disk write completes, okay? Now my contents on disk are equivalent to the contents in memory. And now before I can repurpose this page, right? I need to make sure that I update my page table entry to point to the new contents on disk, right? So now the next time I fault and I find this page table entry, I know where the contents are. Does this make sense? Okay, let's go on. So we think about the parts of this operation, right? So removing the translation from the TOB. How slower fast would you expect that to be? Fast, right? It's like one instruction, maybe, right? Just invalidating entry from the TOB. Copying the contents of the page to disk. Slow, right? This is really slow, potentially. Update the page table entry. Again, I mean, this is like, I might have to grab a lock and just fiddle with some bits, right? So this is fast as well, right? When you guys start working on assignment three and the thing that makes this hard from a synchronization perspective is this, right? So a lot of people, when they do assignment three, find that they do the first part of the assignment, which is page translation, everything works fine, right? And then they start to try to get it to swap and they run it to all these synchronization problems, right? And the reason is that while this IO is happening, there's all sorts of things about the world that can change, right? And if your synchronization isn't very good, right? Then this copy can really cause things to go wrong, right? Any questions? Sean? So remember, that translation is not done by hardware. That's only done by the kernel, right? So all the kernel needs to do is have some way of using the contents of the PTE to find where the contents of the page are, right? So for example, one way to do this is to set up a swap file, right? As a big array that's indexed by a, that's in 4K blocks, right? Because you're only ever gonna write a 4K page in there, right? And then in the PTE, when it's on disk, you store the index into the swap file, right? Does that make sense? So you set up the swap file as kind of a big array on disk, right? And you just, you find an empty slot, you copy the page contents there, and then you store the slot number in the page table. Again, so that's, yeah, it's not really, we'll talk about disk addressing, right? But it doesn't really have to be an address on disk, right? It doesn't have to be an address that disk understands. It just has to be something that the kernel understands and the kernel can use to find an on disk, right? It's a good question. Any other questions? All right, so frequently, so right, so again, when we're swapping out a page, right? When we're on this path, it's usually because the process that's swapping out the page, itself needs more memory, right? So for example, if I'm running as a process and I take a TLB fault, I'm in the kernel, I found the contents that that virtual address points to, but my page is on disk, right? So I need to move my page in, which we're gonna talk about in just a second, but I also need to find space for it. I mean, I need to swap somebody else's page out, right? So if you think about it, now I'm forcing a process to wait for two different IOs, right? The first IO is the one I need to get my stuff in from disk. The second IO is the one that I need to get somebody else's contents out, right? So that I can use that page, okay? And it would be great if at least one part of this operation were faster, right? So the question is, is there a way to prepare the system, right, to optimize the swap out process? So what was the slow part of swapping out a page, right? Updating states fast, what's slow, right? Copying the page to disk, okay? So there's a way to optimize this that we sometimes call page cleaning, right? And the way page cleaning works is the following. So first of all, every page, if I'm going to do this, I need to kind of have a dedicated page place in the swap file for each page, right? This is the easiest way to do it. And this is something you guys can do when you write your own virtual memory system is every time you allocate a virtual page for a process, right then you find a place for it in the swap file, so you kind of do those things together, right? So now every page, every virtual page has a home on disk, right? And now what happens is when the system is idle, you know, nothing's going on, the operating system is kind of like hanging out, looking for stuff to do. What I do is that I take pages from memory and I write their contents back to disk, right? We call this process cleaning the page, right? And the reason why is because once I've written the contents to disk, if I end up having to swap that page out and if no changes have been made to the page contents, I don't have to write it out again, right? So what I, and I call pages with matching content on the swap disk clean. So if I have a page in memory and I know that the contents in the swap file are already the same, right? Then I call that page clean. And when I'm looking for a page to evict or to swap out, clean pages are nice, right? Because with a clean page, again, I don't have to do that slow IO to copy the contents out, right? All I can do is just throw the page out, right? I know the contents on the swap disk are there when I need them. So all I have to do is, you know, update the page table entry and fill the page with zeros and I can hand it off to another process, right? And tracking this, right, is something that the operating system also needs to do, right? So if I don't do a good job of tracking whether pages are clean or dirty, right? Then a process has made some changes to its page. I think the contents on disk are the same. I throw away the changes it made and the next time it uses that address, it gets some old version of the page that's not what it wanted, right? All right, so now let's talk about, after that brief digression, let's talk about how to swap out a page, right? So this is what we had to do, sorry, to swap out, oh, sorry, I was gonna point out here, a synchronization problem with my own slides. So now the idea here is that when I'm on the swap out path, I only have to copy the contents of page of the page if the page is dirty, right? And so let's say I'm looking for a page to evict, what else might I look for, right? We've talked about maybe I wanna avoid pages that are actively mapped in the MMU because that's a sign that they might be in use. What else can I, what else might I look for when I'm looking for a page to swap out? Tell, what's that? Thor, what kind of page would I like? What's a good page to swap out, Sarah? A clean page, right? It sounds good, right? Avoid those dirty pages. You don't wanna get messed up with those guys. No, a clean page, right? Because if the page is clean and I know it's clean, then I can avoid that copy out, right? And then this becomes much, much, much faster, right? So when I'm looking for a page, my page replacement algorithm might say, hey, if there's clean pages available, I should use those, right? And I will only swap out a dirty page if I don't have any clean pages around, right? All right, so we have to, so swapping in, right? So now we talked about this process of swapping out, right? So I stopped the process from using the page, I copied the contents to disk, I updated the PT, I'm in good shape, right? When I, I have to swap in a page when it's used again, right? So remember, all of this is being done behind a virtual memory interface that's a memory interface, right? So the process has no idea that I've moved its contents to disk, right? And it never can have an idea, right? If the process checked the timing of its instructions, it probably could tell, right? Because loads and stores to pages that are on disk are much slower, right? Because I have to get the contents in, right? But the next time the process uses this virtual address, I need to restore it to memory and make it look like memory, right? So what do I need to do to do this, right? The page contents are on disk, the page table entry has been updated, it's not mapped in the MMU. Now the process does a load from that page. What do I need to do? Lovely. Yeah, so broadly speaking, that's what I have to do, right? But let's break it down into smaller pieces. So the first thing is I have to stop the instruction, right? And also I have to know that it's doing this. So how do I know, right? How does the kernel even find out that the process is trying to use a page that it swapped out? Well, listen. Yeah, and the MMU will cause an exception because there's no valid translation for this page, right? There cannot be because there's no physical page of memory that holds its contents, right? So I have to stop the instruction, right? Or the instruction will cause an exception. Sorry, the instruction will always cause an exception, right? Then now what do I need to do? So now I'm in the kernel, this process has done this, now I'm trying to make things right. What's the next thing I need to do? Yeah, correct. Yeah, so I need to allocate a page in memory. I need to find space, right? If I've got spare memory laying around for some reason, maybe a process exited or some of its allocations or something then this can be easy, but this might mean I have to swap another page out, right? You know, I need to find a slot for this in memory. This has to look like memory again, right? Next thing is I need to locate the page, right? And I need to keep the page stable entry up to date so I can do this, what now? Now I know where the page is going, where it's coming from, what's the next thing to do? Nick, yeah, copy it in, right? Now I have the contents in memory, what are the last couple of things I need to do, Paul? Yeah, so I need to update the page table entry, right? Because the page table entry always has to reflect where this page is, right? Now the page is in memory, instead of on disk, page table entry gets updated, two more things. Yeah, who still doesn't know where the page is? Who needs to know? AJ, the TLB or the MMU, right? I need to load this so now I know, I always knew the virtual address, now I know the physical address, right? So I tell the MMU where it is, and then what's the last thing I do? Maybe this isn't obvious, but I just restart the instruction, right? Now this instruction can complete because now the virtual address that's supposed to be memory looks like memory again, is memory, right? All right, so another diagram. So here's my starting point, process does a load, I see, uh-oh, now I'm in the kernel, I find that I notice that the page is on disk, I have to allocate a spot forward in physical memory, I have to copy my contents in, I update the PTE, I reload the address in the TLB, and now that instruction can complete. All right, any questions about this? Swap out, swap in. Does the kernel always do this check when the MMU has an address that needs translated? Like before the kernel gives the MMU a new address. Okay, so this is a good question, what do people think? Can, so can I give the MMU a translation if the page is not in memory? Andrew, no, I mean the MMU will only, does that answer your question? It was a new translate, because you know when a process tries to use a virtual address and access the MMU, and then the MMU has to do it. Right. It's for the kernel to translate the address, but if that process already had a page I would swap it out to this. Right? And it wants to get it back. I think you're in the process of answering your own question. Which is good. Yeah, so I mean it's the same thing, right? So the kernel will use the page table to find the page table entry, the page table entry will either say, and there's a couple of other cases here, but the two we've talked about are either the pages in memory, in which case I load the translation into the TLB, or the page is not in memory, in which case I need to go get it, put it in memory and then load the translation. So those are kind of my two cases, right? If the page is in memory, all I need to do is load the translation, right? If the page is not in memory, I have this other step, which is I need to get it into memory, right? But I can't restart the instruction until the contents that the process is using are in memory, right? All right. So next time we're gonna talk about algorithms for figuring out which are the right pages to swap in and swap out. I have a few more minutes, okay, good. So there's a couple of last things to point out, right? So we distinguish now between two types of virtual memory-related fault, okay? And this is a great segue from one of these questions, right? So a TLB fault happens when the any required virtual to physical address translation is not in the TLB, right? A page fault, on the other hand, consists of cases where essentially the contents of the virtual page are not in memory, right? There's cases where that virtual page, the contents may not have been initialized, but there's other cases where it might be at disk, right? If you think about it, page faults are a subset of TLB faults. Every page fault is preceded by a TLB fault, right? Because if the contents of the virtual page aren't in memory, then there's no valid translation that can exist, right? So there's no way that there's a valid translation in the MMU. On the other hand, not every TLB fault is followed by a page fault, because if the contents of the page are in memory, then all I do is load the translation I've done, right? Let me actually come back to this, talk about, yeah. So the reason this is significant is on some architectures, right? Not the one you guys are programming this semester, but on, again, fairly significantly the x86 architecture, the MMU actually searches the page tables for a translation itself, right? So this is kind of, you know, messing around in my page tables, right? So the idea here is that the kernel and the hardware have to agree on the structure of the page tables. If there is a TLB fault, the MMU will actually, again, look in those page tables itself, right? Interpreting the contents in an agreed upon way, right? If it finds a valid translation, it'll load it into its TLB without the kernel ever knowing, right? So on hardware-managed TLB architectures, TLB faults are not seen by the kernel, right? They don't generate an exception, right? If the MMU can figure it out itself using the data structures that the kernel has set up and has to maintain along lines that are agreed on, and this is hardware, right? Hardware is a very inflexible person who's very good at doing one thing, right? So hardware knows, like hardware, I mean, you think hardware and software agree on the page table structure, but that's not really true, right? Hardware tells the operating system, here's the kind of page table I know how to understand, right? And then it's the kernel's job to set up page tables in that way, otherwise hardware gets confused and crashes and, you know, like, you don't teach hardware anything. Hardware doesn't learn, right? Hardware just is the way it is and software has to work around it. All my hardware friends are gonna love that. So the nice thing, so what's the pro about this architecture, right? If you think about pros and cons with the software-managed TLB, right? Correct. Yeah, so translation, TLB faults are faster, right? Because the hardware can, without interrupting the kernel, without causing the context, which without requiring that, you know, I cross the user kernel boundary and the kernel do all this work, the hardware can just very quickly look things up in the page tables and if I only have a TLB fault and the page is somewhere in memory, I say, great, I load the translation, I'm done, right? So it reduces the number of virtual memory related faults, right, which is nice. What's a con, potentially? We kill. What does this require? I mean, what is the kernel loss? Yeah, that answer is correct. You just have to fill in the... Well, remember, the MMU will still get my attention in certain cases, right? So for example, if the page, if there's no valid entry, then it causes a page fault, right? And then the kernel will run, right? So the MMU is not gonna like page stuff in for disk, doesn't know how to do that, right? All it does how to do is find translations of the translations in memory, right? So one con here is that the operating system has to set up the page tables in a very specific way so the hardware can understand it. You don't, we talked all about these different ways of setting up page tables and you could think about all these fun data structures to try with the hardware managed TLB, it just doesn't matter, right? Because the hardware tells you how to do it and you just say, yes, sir. It also reduces a little bit of visibility, right? Because with the hardware managed TLB, the TLB faults are handled by the hardware and so the kernel never sees, right? So the kernel is running along and all it sees are page faults. So I get a little bit less information about, the kernel gets a little bit less information about what pages are being used, right? And again, don't worry, you guys get to manage the TLB yourself, right? I don't think that's a good question. No, the kernel still has to be able to do that, right? Because when I swap pages back and forth to disk, I still need to, I still need to be able to do that. The idea is the kernel still controls the contents of the page table entries, right? Hardware just knows how to find them, right? So essentially you can think of it, hardware takes the virtual address, it uses it, it finds the page tables, right? So usually there's a register that the kernel has to set that points to the page tables, right? So the hardware has to be able to find the page tables, the hardware has to know how to find the right page table entry. But then if that page table entry isn't marked valid, then a page fault is generated, right? So there's a way for the operating system to make the hardware ask for help, right? So again, the operating system controls the content of the page table entries. The hardware just knows how to find, right? And if it happens to be in memory, then hardware can load the TOB itself without having to ask them, right? All right, let me see what time it is. I think I'm out of time. Yeah, let me just do this quickly, you guys, since we're packing up. So, right, so we did this. So one last thing I wanna just mention here is a very common technique and a nice example of how operating systems use procrastination, right? So you guys may have been thinking, you know, when a process starts running, you know, it tells the kernel, here's this big, so for example, when a process starts running, it tells the kernel, I want this big piece of code, I'm Microsoft Word, right? I have this huge chunk of code, all of these libraries, like, this is how I want my address space loaded, right? Here's this huge executable file somewhere and here's all this stuff, and like, here's, it's like this huge address space full of, you know, stuff, right, to use a nice word. So when it starts running, does the kernel load all that stuff right away? How many people think yes? How many people think when I give the kernel a big executable and it runs, the kernel takes all the code from that executable file and copies it all into the address space right away. So what do I do, right? So first of all, why not, right? I mean, the process told me, hey, I've got all this code, that's code that the processes, you know, can use, right? Those are really important, you know, submenus and sub-submenus and, you know, weird hidden features that nobody ever finds and like stuff like that. So why wouldn't I load it all at start time? Yeah, so there's big parts of the code, for example, that are never used, right? And on Wednesday, I'll come back to this and we'll finish this story. The question is, how does the kernel handle this and what's the right approach? All right, see you guys on Wednesday.