 Well, it's 403, so why don't we get started? There we go. I guess now that we can definitely get started on this. So we are on recitation x on this. And we're going to be talking about today, again, is kind of a recap of assignment 3, 2 very briefly, and then stepping ahead to look at the last part of the course coding project, which is swapping a.k.a. eviction, a.k.a. paging out to disk on this. So just by way of brief review on this. And we're going to go through these slides very quickly for people who are here or people watching by video who have questions on the wrap-up of assignment 3, 2, stop by office hours. I assume again that this is old hat. But again, in terms of data structures, because we will be talking about what you need to do to change or add to these data structures in order to get through assignment 3.3 on this. Again, for assignment 3.2, the main point is an address space, which is a representation of virtual memory for user processes on this. And again, we had things like segments which contain, if you will, the addresses that are potentially valid. And the page table, which contains a list of the currently allocated virtual pages. A lot along other stuff. More on memory segments. Talked about which ones they were in terms of the three static segments and then the heap and how you need to go about setting those up. And then we also talked a little bit about what happens in terms of faults. When you have a TLB fault and what you need to do in terms of VM fault for assignment 3.2. Obviously, this is going to need to be changed here because this last part right down here, if we have, let's say, there is a virtual page that does exist, but the data of the virtual page is not in memory. Before we return to the caller we're actually going to, at this point, have to expand VM fault to do the swapping in algorithm, which we're going to be talking about in a few minutes. So again, this is directly relevant to assignment 3.3. VM fault. Again, this is a review of the dumb VM code on this and what you needed to do. Again, this is more about what you need to implement in terms of the mechanics for assignment 3.2 with, again, the caveat that we're going to have to tweak this a little bit for assignment 3.3. Then Ali talked about last week a little bit more about the TLB in terms of what goes on with this. And I assume at this point that this is mostly implemented. You really don't need to twiddle around with populating the TLB. The only thing that you will need to be aware of for assignment 3.3 is possibly evicting out some entries. So in terms of the inner mechanics of what goes on with the 64-bit field, remember there's two 32-bit fields in each TLB translation entry. You really already have what it takes to get through the rest of the class on this. And again, TLB management routines on here. In addition to this, there is another routine, the TLB shootdown, which up until now we've been saying you don't really need to worry about, well, now you do need to start worrying about that. And we'll talk about why and how in just a sec here. So questions going once, going twice about assignment 3.2, anything about just, I guess, something of general relevance to how 3.2 ties over to 3.3, address spaces, segments, memory, page tables, all ready. So again, assignment 3.2 for this upcoming Friday, and then two more weeks to assignment 3.3. As you can imagine, assignment 3.3, you probably heard that it is a big assignment. I can confirm that. I'll also see if we can't get you started with what you need to prioritize to get the thing off the ground, and also how you can get some basic points, even if you're not able to complete, complete the assignment. There's definitely, Jeff, has it set up so that you can get swapping with one process going, and what do you need to do at a minimum to get that going? I think that's a reasonable goal for certainly everyone who's sitting here, and then gun forward from that. So let's talk about this. Eviction or swapping, depending upon your religious preference on this? What? OK. Yes, OK. We'll pay off some antatech later on. But anyway, back to this here. OK. What we're doing in terms of swapping here is using the disk to create more apparent memory. And in one sense, it is memory. It's just that where we're storing the stuff is on a hard disk rather than in, let's say, DRAM strips or what have you on this. And in terms of what's going on here, what we're trying to do is give, let's say, a particular process. Let's say the illusion that it has, who knows, 20 megabytes worth of virtual address space, even though of that virtual address space, maybe only two megabytes might currently be in memory. And the other 18 megabytes might actually be currently out on backing storage. Or alternatively, we could do something like, let's say, we have 10 processes each with one megabyte of memory allocated, even though we have only five megabytes of physical memory for the entire system. We can play games with this by using swapping on this. So again, in terms of terminology here, swapping is, roughly speaking, just moving from disk to memory or vice versa. Eviction is the thing when we're kind of rummaging through the core map and saying, you know what, I need some space pronto. I'm going to throw you out of memory and onto the disk on this, onto the street. So kind of two terms for not exactly the same thing, but certainly the same concept. How can we actually go about implementing this? This first slide here talks about what needs to be done. It's not so much how to get started. That's what we're going to be talking about at the end of today's recitation on this. But I want to kind of vanquish this very quickly and then look at each of these steps in a little bit more detail, and then we can go on from here, too. Obviously, start off with drumroll data structures, as always. Now, a lot of these data structures you have already implemented, but it's a case of adding more goo to them. Specifically, you're going to have to add additional information to physical pages. That is, the physical page frame structs that are in your core map and also to the virtual pages, a.k.a. page table entries. That's the things inside your page table. Those are already implemented, but you're going to have to add stuff to that. You're going to also need a brand new data structure, specifically the swap disk, and some way of keeping track of which swap disk blocks are actually allocated or free. You have a core map to keep track of which blocks in physical memory are allocated or free. You're going to need some way of keeping track of what's allocated or free on the swap disk. And you can, again, do this however you want. Ultimately, Jeff cares whether you passed the test or not. What we would suggest is you use some code that's already given to you. You probably have already run across it in rummaging through OS 161. If you look at bitmap.h, there's a whole bunch of nifty-needle routines that essentially allow you to create this quim-quam thingamabob data structure that essentially it's a bunch of booleans is something allocated or not. So you can very quickly have these pre-coded routines go through and figure out what's free and what's not. And we'll kind of see how we can tie that together. But this sort of thing, the swap disk and the allocation bitmap, that's new. That up until now you really have not had to worry about. Okay, so those are the data structures. We're also going to have to do some coding in terms of the routines here. Some tweaking to the fault handler, the VM fault. We already alluded to that. In other words, if there's a page fault and the data happens to be on disk, we're going to have to support that case now. And the big one is going to be here, support for page out. Up until now, I assume you probably are using something like called, let's say, GetP pages. I call that something else. It doesn't really matter, but I'm simply using GetP pages as the generic for the name that you call when you need a physical page on this. So that's what I mean by that. But up until now, you search the Quorum app and the Quorum app is full. Well, boo-hoo, you return, essentially, a big fat zero out of memory and it's tough no geese for the process. Not this time. If you go all the way through and the Quorum app is full, well, we now need to kind of, in effect, go back to a second time and see whether or not we can evict out a page and make memory to return to the caller on this. So eventually, the idea here is never to error out on the GetP pages routine on this. To answer one question, you should not have to deal with the case of the swap disk running out of spaces on this. So to the best of my knowledge, well, if you are, there's probably some bug with your code on this, but you should be given plenty of swap disk space to essentially make assignment three work on this. So the other thing too is to go along with this, you're gonna need a couple of routines to support the swap disk. I'm generically calling them block read and block write. What I mean by block is, if you will, in the way we talk about a page being a 4096 byte chunk that resides in memory, a block I'm using to refer to a 4096 block that resides on disk. Remember we were talking about, when I was covering just one lecture last Monday, in terms of disk geometry, we've got cylinders, heads, and sectors and whatnot. Well, hard disk manufacturers use the term block to refer to a bunch of sectors that are agglomerated together. And you're going to be accessing the swap disk at the level of essentially block access. So you don't have to worry about moving the disk head or anything like that. You simply say, read from this point, give me this batch of data. And as you would in any production operating system, all the nitty gritty details are taken care of you by driver routines. So again, you will however need to read, if you will, write middling level routines to read or write data from disk. And obviously you need to make sure if you're writing that you're writing to a free spot unless you really do want to nuke the underlying data on that. And then the last part, this is, okay, it's new. Up until now, you essentially have only been concerned with correctness. If any of you have taken Oliver's 562 databases course, you probably have heard that a large part of that is not just coding the routines correctly, but he's all concerned about optimizations. You have to get the data quickly enough. That's now true with this part. Jeff has some pretty stringent requirements in terms of time and memory bounds. So it's not just good enough to get the information, but you need to get under some time and memory hurdles. Well, obviously memory hurdles, that's the point of it, but you also need to do it in a fair amount of time on this. So you're gonna need to add in some optimizations. There's a bunch of them. Again, there's no right answer to which ones you need to add. Kind of sit down with your partner, talk to the core staff about which ones might be useful. As you can imagine, there's some trade-offs between implementation complexity and payoffs on this. So, but again, I just do leave that with your thoughts. So to recap again, you got some data structure changes and additions. You've got some code changes and additions. And eventually you're gonna also need to do some additional tweaking and optimization on this. So take it for you all. So general questions at this point before we dive into some of the nitty gritties on this. All righty, let's talk a little bit about the data structures on this. What can you do or what do you need to do kind of at a minimum on this? We're starting about physical page frames. And again, presumably you already do have a core map struct. I presume that you've already passed a sign at 3.1 on this. And the core map struct is an array filled with a bunch of, if you will, understruct containing the state of each physical page frame. You're gonna need to add some stuff to that. And particularly what we're gonna need to do now is if you're swapping, what you're in effect of doing is mangling with another processes state. Up until now, each process has its own address space. And if a process gets a page from your core map routines, that process can rest content that it ain't gonna be changed. Well, no moss. Because at this point, the whole point of eviction is you are going in there and kicking another poor process unknowingly in the behind and you're gonna need to have a way to track back to that process. If I want to evict, let's say page, whether physical page 10 in the core map, well, who currently owns physical page 10 on that? So I'm gonna have to keep track of that. Number one, is it the kernel? Okay, maybe the kernel itself has called, remember K-Malloc which calls down to L at K pages on that? I need to know that. Is it a user process? And if so, which user process? Because I'm gonna kind of need to notify the user process on this. So again, this is something that we're going to have to add at a minimum along with possibly some other stuff. Like if you implement, let's say, at least recently used method of eviction, you're gonna have to probably have some linked list pointers in there too. But again, you're gonna definitely have to add this. Don't worry about the size of the core map expanding on this. I have probably the equivalent of 10 integers in each of my core map entries. It really does not make the core map get that big. You will need this stuff. Now I'm not saying you shouldn't try to slim it down if you can, but this is stuff that is necessary that you need to add. In terms of the physical page stuff, we were talking about what you needed to add to the physical page entries. What you need to add to the virtual page entries is, well for one thing, where is it now? We can't assume that it is in memory anymore. It might now be on disk. And if so, where on disk? In the same way that you have a pointer to, if you will, or not to a pointer, but some variable that says what physical page it is, we could probably even use that, make it do double duty. Where is it on disk on that? So the other thing we're gonna need to do is add in synchronization. We're gonna be talking about this in just a minute because now that you, if you will, the bully process are evicting out a page of some poor victim, you are going to need to, if you will, mangle the state of that other process, these page table entries, and whether or not it's on disk or not, that's now shared data, which means think locks, think synchronizations on this. I even had a condition variable in there at one point because I needed to do some additional data passing. Again, something to keep in mind. Questions about data structures? Essentially add more goo to existing data structures. Swapping in and swapping out, all right? They're not necessarily one routine. If you are like me, you took a hydraulic ram and axle grease and shoved it all into existing code. Specifically, swapping in, you can think of this as essentially an extension of VM fault with a little bit of AS copy and swapping out with an extension of get P pages on there. But in terms of what this is, the upshot is that in terms of swapping in, we sometimes find the need to access a virtual page, but whoops, the data of that virtual page is on disk, which means we need to do a swap in. Well, when do we need to actually find ourselves in the process of accessing data that might be on disk? Well, one is VM fault and possibly also AS copy. Those are essentially the two big ones that you need to keep in mind here. So what we need to do in terms of swapping in, well, first thing here, we have to go through and we need to allocate a physical page as usual. That's what you're presumably already doing in both VM fault and AS copy, so that's already there. What's going on underneath the hood though is that this thing here triggers a call a lot of times to the next part we're gonna be talking about, swap out. So it's not that this is part of swapping in, but you need to know that the one kind of cascades down to the other on this. So we need to allocate a physical page and then the next thing we need to do is once we have the allocated physical page, all that is is the physical page. My data ain't there, okay? The data belonged to someone else. Remember, I kicked someone else out of an apartment. I need to retrieve my data from deep storage. So I have to do this call to block read and that's gonna rummage around my backing storage and retrieve the data and write it into my newly allocated process. And now that it's newly allocated, I can change the state back to in memory on this. And again, caution here, the page table entry is shared data because you know what? I am reading stuff in and changing the state of my page to in memory. By the way, why was it on disk? I didn't evict it out. Well, most of the time I didn't evict it out. Someone else probably evicted me out, which tells you what? While I'm, if you will, evicting in so to speak, there's a good chance that someone else might come around and try to evict me out. You get this tit for tat sort of thing going around here. So I'm gonna need to coordinate that. So again, this already gets into the place where we need to start coordinating what the state of each page table is. One design thing for everyone who's here and who everyone who is in video land on this. Essentially you can get interrupted at any point in this process for simplicity purposes. We like to recommend once you start doing something you let it go to completion. It's perhaps not the optimal for a production system, but like what I'm trying to say is once you begin the eviction process, let the eviction process run through to completion before you perhaps may need to undo it or what have you on this. It's going to be much harder to write subcases for undoing partial paces on this. So again, swapping in, what we wanna do here is, essentially when we allocate a physical, I'm sorry, if we find out that the state of a virtual page is on disk, we need to first allocate a physical page and then read in the data and then change it to being now in memory on this. Questions about this? Pretty straightforward. Swap out, this is the slightly more complicated of the two routines. You can see we've got a couple screens on this. And again, this is an extension to your getPages routine or whatever it is that you happen to call it on this. And essentially the getPages, the trigger for this all is you search your core map and it comes up Gooseg on this. And at this point, instead of returning an error to the user, what we wanna now do is either fall through to our eviction code or call a subroutine or however it is that you want to implement this. So essentially, this is our hook to our swapping out in the guts of assignment 3.3 on this. And the first thing we need to do, we already know that there ain't no free pages. Well, we're gonna make a free page. We're gonna do that by selecting a victim page and we're gonna use some eviction algorithm on this. And Jess already talked about this in class. And again, there are several eviction algorithms that you can use and it's not a case of one being right or wrong. What we like to suggest is perhaps start simple, implement the idea and then start getting fancy as you need it on this. There's again, a time space trade-off. You can use something simple, like let's say a round robin or random just to get it going and prove the concept. You probably will need to implement something at the very least like a clock or I would suggest really do go for a least recently used algorithm. It's not that complicated, but it does. You're now adding in another data structure, a list, yada, yada, yada on this. So again, you will need essentially a good eviction algorithm. Because remember, all the pages are used. The page you wanna pick is the page that's not used. Well, unfortunately that don't exist anymore. So we have to pick a page that we hope might not be used. Hence, perhaps maybe go to a least recently used or whatever it is. So we select our victim page here. Now, the next thing here, this is where things get a little bit complicated. We have to update the state of both the victim page and the page, I'm sorry, the victim page frame, which is in the core map and the victim page table entry on this. And we're gonna have to change some states here. Because remember, the page frame has a new owner. I'm kicking someone out. I want that page rather than the victim process, whatever that happens to be. So I have to change that. And I also have to change the state of the victim page table entry to being on disk. Because remember, I want my page table entry to say in memory, well, the victim page table entry has to go on disk. By the way, side note, I probably should have added this to the slide here. But who else does swapping out? Not just user processes, but kernel, right? Because remember, your K malloc calls alloc K pages, which calls get P pages. Most definitely you want to make sure that kernel gets its allocation request on this. So the kernel is going to swap out user processes. User processes will also swap out each other. The one thing that you don't want to get into is user processes swapping out kernel stuff. That's really bad, all right? But anyway, the upshot here is we are changing the state of both the victim page frame and the victim page table entry on this. And guess what? We need both of these to be shared data, or I'm sorry, both of these are shared data. So there is almost assuredly going to come a time when you're going to need to hold at least two locks simultaneously on this, which is going to raise a bit of a problem because remember lock acquisition, if you ever took 321, Beena talks about this, but you're going to have to make sure that you always acquire multiple locks in the same order. That can be a problem because sometimes, let's say one process is coming in and let's say wants to acquire the core map lock first, the other one wants to acquire the other one first, and you could get into a deadlock. The other thing that you need to worry about is the lock type. You may have already run into this, but essentially you don't want to go to sleep holding a spin lock. It is really, really bad for a whole bunch of reasons on this. So general design principle in multi-threaded coding, you want to acquire all your block locks first and then acquire all your spin locks after that. And again, you always want to make sure that you do them in the same order on this. So again, this is where the thing is you do want to sit down and think about it for a little bit, speak to some of the staffers who have gone through this eviction stuff already and just make sure that you're not painting yourself into a corner on this. So eviction is not a long assignment. I would say the number of lines, for as a matter of fact, I can be very specific. It's about 300 lines that I had to add to my getP pages routine. So it's not a lot, but it really is tricky in terms of making sure that you're covering all your corner spaces. You're covering all your object corner cases and that you're just not doing things like deadlocking or just doing things inefficiently on this. So one last caveat here is watch this in terms of data because I know one of the things that I and some other people had to implement is let's say I have a lock on the core map and I've selected my victim page. Okay, well now I want to notify the victim page so I need to grab that page table entry lock. Well, guess what? On the core map, I've got a block lock on the page table entry. In order to get that page table entry lock, I've got to drop the core map lock and then reacquire it later on. And in doing that, in the meantime, guess what state may have changed? So for that matter, the victim process might have exited. That's kind of a worst case scenario. You need to handle that because you don't want to simply poop out on a null pointer because in between dropping and reacquiring a lock, state has changed out from underneath you, which it may have. So again, just something food for thought on this. Last part about swapping. Again, we may need to do what we call a shoot-down. And this is another case of inter-process communication here. If I am changing the state of a virtual page of another process, the worst case scenario is, guess what? If that other process is currently running on another CPU and that victim page is currently in the TLB translation cache, I got to make sure that that is knocked out of that TLB translation cache before I actually get rid of it. Hopefully this won't happen because hopefully I'm selecting a least recently used page, but I can't guarantee it. So this is something that we need to be concerned about here on this. I need to send a message to, if you will, that victim process. Certainly I'm going to have to do it sometimes. I'm going to be able to optimize getting away from it. What I'd suggest if you're taking notes in terms of the shoot-down stuff, start simple, kiss, again, keep it simple, stupid, by always shooting down, essentially, in all cases. In other words, whenever you evict a page, you simply flush the CPU, yada, yada, yada. It's the easiest way. It's also going to be ridiculously inefficient, but at least it proves the logic, and then start adding in, all the time here. And then one last thing we talk about here is this is optional. If you are doing things like do a copy on write, or let's say a paging daemon on this, this is sometimes something that you don't have to do, and that is actually write the data out to disk. Because, again, remember, if a page is already on disk, and it hasn't been written to, it's of state clean. You don't have to rewrite it on this. That's if you are tracking dirty, clean state. If you're not doing that, you essentially do have to write it out to disk. So again, to recap, swapping out, what we need to do is we tried to get a page from the core map. It failed. So now we need to go into eviction, and we use an eviction routine to pick a victim page on this. And watch it. Okay, don't evict a kernel, or let's say a frame that's already in eviction. You don't want to deal with recursive cases. And then you need to update the state of multiple things at once, both the core map page frame and the page table entry page. And you're going to have to worry about, if you will, syncing that and making sure that, like, if your variable state has not gone out of lifetime, what have you. And then the last thing after that is we may also need to shoot down the translation entry from the victim processes CPU, and we also are going to need to write the stuff out to disk. So that, in a nutshell, is swapping out. No questions going once, going twice. Alrighty. Where do you actually get started with this assignment here? Alright. As before, data structures. So what you want to do here is, we already talked about this, start by thinking about what you need to add to your virtual and physical, if you will, page structures on this. And again, you're not going to have everything down to a T, but just at the very least sit down with your partner or what do I need to add to this potentially on this. The one thing, this is actually kind of a nice jumping off point to get started here. Design the swap disk data and allocation bitmap stuff and then eventually writing the code for that. This is something new and it's not conceptually that deep. It's mechanically kind of semi intricate on this, but this is something that, it's a good place to get started and hey, I actually now have a, I'm sorry, working swap disk on this. One thing we like to say too is, again in bitmap.h, there's a bunch of needle routines that are already written for you, so you don't have to write them yourselves, to keep track of essentially a bunch of Boolean flags and that you can use that in turn to represent blocks on a disk on this. So in other words, if Scott's test configure your kernel with let's say 32 megabytes of swap space and you have 2 megabytes of actual memory on this, what you're going to need to do is declare a bitmap of, if you will, well 32 megabytes equivalent. In other words, 32 megabytes divided by 4K pages, however many pages that is and then however many bits in the bitmap structure. And there's routines already written that will create the bitmap structure and will search the bitmap structure, in other words, get me a free bit. It'll search that and return to you or allocate a bit or deallocate a bit. So that's already done, so don't worry about the innards of that. So again, this is something, write your data structures and write the access routines on this. Ah, how about that? VM Bootstrap. Remember that bugger from CoreMap? We said that it was too late to use it. Well this is a great place that you can use it. As a matter of fact, you can't initialize your swap disk stuff and wherever it is that you initialize your CoreMap because that's way too early. You need support from other stuff here. This is where you can actually finally put VM Bootstrap to good use here. Now one note here, and this is actually going to pass here. Sometimes the device will be absent on this. Up till now you've been accessing files in vop read, vop write, vfs open, all that stuff that are essentially actual files. You probably heard that in Unix quote unquote everything is a file, including devices. You've already had one example of that. It's a file, c-o-n colon. That's a device. It's represented as a file, but it's a device. Well in the same way, the device that holds files, the disk, that device is also a file, kind of circular, but that's the way it is. And that's how you want to implement these swap disks on this. And I believe it was at LHD0 raw colon. Someone double check me on that. It's in the list of devices in the .code for OS 161, but that's how you need to actually open it up on this. So you're not writing to a file file, you're writing to a file that represents a disk that holds files. In other words, this is essentially your swap disk partition. You've probably heard about that in Linux. Well here we go. So again, this is where you can do all this initialization in vup bootstrap on this. If this device is absent, disable swapping. And the test 161 code runs, sometimes it's going to run tests with a disk and sometimes without disk. And it's going to be expecting that if you don't have a disk, that you will return out of memory. If your core map does not have if you will memory. And vice versa on this. So this is something that you'd want to, it's pretty simple, you just need like a boolean flag on there. But again, if the swap disk does not exist, so again, write your data structures and then write your swap disk access routines. You have to set it up. Again, we suggest vmbootstrap and use the bitmap.h routines and then write a couple block read block write routines on this. And here, remember you're in the kernel, you can call write down to vop read and vop write on this. Remember those functions or that one function, I forget the name of it, but it's always something that nicks people in the backside when you're writing sysread and syswrite. And it's like, you can't use that, that's only for in the kernel. Well, now you're in the kernel. Now you can use that. So this is something that will essentially initialize that data structure so that you can use it and call write down to vop read and vop write. And please yes, do do this here. I can't reach out and touch it, it's too high there. But do write a little bit of test code to make sure that your swap disk is working, that you're not clobbering data, that you can allocate and deallocate stuff before you go on. So again, getting started, if you will, write expand data structures and your swap disk routines on this. Questions on this so far, yes? How, okay, so what is the file? The question is how big is the swap disk? Well, how do we, what is the swap disk? We just got through saying this. It is a file. And how do we find out how big a file is? Bingo. Yeah, exactly. It's, you can call vop stat just like anything else. Good question. And then based upon that, what do you then do? You can then use the size of the swap disk to do what? Yeah, that bitmap thingy. So, et cetera. So, oh by the way, this is shared data so you're going to need to lock on it. Other questions? All righty. Moving right along here. Then go into the page in, the huge out routines here. And again, you need to probably expand vm fault and get ppages or equivalent on here. And we were talking earlier about where you put the code. It doesn't really matter here. But in terms of getting started, suggest just so that you don't have too many balls in the air here. Start with a simple, perhaps slower, but simple eviction algorithm. Just get things started here. And then later move on to like clock the LRU on this. And then the next thing here is after you write these expansion of the two routines, vm fault and get ppages, one other tweak you're going to need to do and that is modify AS copy and AS destroy. Why? Because, think about it here. What is the state of each virtual page? Up until now it's always been in memory on this. And presumably, AS copy and AS destroy have written them for assignment 3.2, make that assumption. So in assignment 3.3 we have to expand that assumption here because in AS copy, the source data might be in disk. You need to call that page-in routine in the same way that you do from vm fault. Similarly for destroy, if you are trashing an address space, well, if it's not in memory, you don't have to allocate the I'm sorry, deallocate the memory. You have to deallocate the space on disk. No sense in reading it in. You can kind of tweak these routines so that they play nicely on this. Oh, by the way, AS copy. We were talking about holding multiple locks earlier on this. And a note to everyone out in Video Land 2. We were talking about you have to hold the lock on the core map and a page table entry. Worst case is if you are in fork and you are calling AS copy and what does AS copy do? It's copying data from one virtual page to another virtual page here. So we need to in some way coordinate these two pages. We're getting data from one page and onto another. We may have locks on both of those two pages. And then by the way, in terms of our destination page we need to evict. So we need to grab a third page table locked, our victim page and of course our core map. So we're holding at 1.4 locks simultaneously on this. And just make sure that you're coordinating that that you're not acquiring your own lock and you don't wonder why our test just simply stall. Well, we are deadlocking. So anyway, the upshot here is make sure that AS copy and AS destroy play nicely with eviction on this. And at that point here test. Get the single process test passing on this. This is really nice here. At this point, once you get this stuff written, you probably have enough to get 40 points worth of credit here. And if you haven't looked at it already there are two tests that you can pass with single process eviction on this. In other words, you don't have to worry about multi-processes or synchronization yet. You can pass these two tests, sort and matmult. And these two tests are run directly from the kernel menu deliberately so that there is only one process in memory. It is simply testing the eviction, if you will, the swap and swap out stuff without it. And I think this is well within reach. Certainly everyone who's sitting here today on this, make sure that this actually works and submit it and get credit right there. Once you do have that submitted, now you can go on to multi-process here and at this point you need to worry about syncing. I'm not saying don't add synchronization in before, but maybe add it into the stubs and if you're having problems you can comment it out and just make sure that you get this credit. But then once you do add in synchronization for the page table and the core map on this, we already talked about type and acquisition order on this. And get this stuff working with, note this here, one CPU. What that allows you to do is ferret out the bugs that have to do with synchronization without adding in the additional complexity of shoot down. Everyone with me on this? So get stuff working with one process. Then move on to multiple processes, but one CPU once you have the bugs worked out with that, now you can add in support for multiple CPUs which means shoot down code on this. Again, we talked about this earlier the simplest approach is just simply flush out that TLB, get rid of everything. We would suggest probably you're going to need to tweak this a little bit because this is not very efficient. And then before you go again, make sure that multi-process tests are passing with multiple CPUs on this. And then after that optimizations, and at this point things become a little bit weirder because there's no right answer on this. And in terms of optimizations you definitely want some sort of a page eviction strategy. Again, I would keep in the back of my mind least recently used, speak to some of us on the staff on that. It's like all lists, lists are mechanically intricate. They're conceptually not that difficult. It's just the case of making sure that, you know, your pointers are all correct. By the way when it comes time for lists, everyone thinks well you have to malloc the nodes. Watch it! We already have a post on discourse about that. What's a great way to go into infinite recursion in OS 161 here? And you get a memory routine you malloc something because if you malloc something in your getP pages routine, what might that have to do in order to satisfy the malloc request? Right back to getP pages so you put yourself into a loop on that. So definitely there's ways around that but just make sure that you don't put yourself into an unintentional circular loop on that. One quick way I can tell you this to let one cat out of the bag, just dump the nodes right in the core map frames. Done. All right, no mallocs, no fos, no moss, no mess up. So anyway, definitely a better eviction strategy. Other things here, definitely I would suggest to look at TLB shootdown methods. You're going to have to noodle around a little bit with the code and the shootdown function. It's not rocket science but it does require a little bit of thought on that and then this is the really heavy duty stuff here. You want to get into a paging service or a take copy on write. That definitely gives a huge, huge boost to performance with of course an attendant penalty in complexity and time spent coding on this. But there's definitely a lot of stuff out there. One other thing I know I had mentioned this a couple weeks back in the last time I covered recitation and that is if you're using arrays the two level array is going to put significant memory pressure on you and this is the point where you're going to probably want to consider some sort of an optimization going to like a four level or let's say just kind of cutting out a couple of like, well anyway the upshot is two level by itself may be problematic. It's not that much extra work to get the thing working beyond that but again the two level by itself will potentially cause issues with that. So talked about again recapitulation in terms of getting started. Start off by writing your data structures on here in terms of adding additional goo to the structures for physical and virtual pages. We talked a little bit about designing the swap disk and the allocation bitmap. Use the routines that are already added to you. Then go on to the next thing. This is a nice place to start in terms of writing the actual allocation routines for the swap disk initialization and the read and write processes. Make sure that it is synced and tested. Then we talked a little bit about writing the guts of it which is page in and page out. And expand VM fault and get P pages. Start with a simple eviction strategy on this. You're going to need to tweak AS copy and AS destroy a little bit. Test that and make sure that it works with one process. Get a little bit of partial credit. Then move on and add support for multiple processes and make sure that it is passing with one CPU. Then add TLB shoot down code so that you can support multiple CPUs and you can get the rest of the points credit for the assignment here and add optimizations as needed on this. And that is all she wrote eviction 101 on this. Questions comments complaints hmm you Rick I seriously think you guys can nail I'm that that's why deliberately said that this is nice this is well within reach and you might surprise yourself like swapping is kind of like assignment 3.2 in the sense that there is going to be bugs and sometimes you can spend days but sometimes you might be able to identify them very quickly. It it really kind of depends on the luck of the draw I've already put one post on the discourse forum about this add a truck load no a train load of K asserts into your code all over the place. And think through every last corner case on this I know when I did this assignment I spent like a solid week just thinking and planning thinking and planning essentially no coding at all then about maybe a couple days of coding and essentially I only had one day of debugging I still had to do some performance after that but my point is if you put the time in up front very often it knocks down a lot of bugs after that and definitely that's what the staff is here for on this but like I say one thing that we really didn't eat well if we did have it I wasn't aware of it and that is the whole thing about the partial credit for single process swapping which that removes a lot of the nitty gritty stuff in terms of locks and weirdo deadlock and my kernel is just hanging inexplicably yada yada yada on this oh and then when you're done with that go on to assignment 4 this file system journaling it's in there I'm not joking so two minutes left okay I guess that is it thanks for coming people goodbye out there in video land