 All right. Good afternoon. Welcome back. Oh, that's not on. That would be a thing. There we go. All right. So lab four grades are back. So there's no feedback on it. So I'll upload to your repository the actual breakdown of the marks. I've already posted what TA is graded what part. So lab four stuff, I'll upload when I get back on the train after this lecture. So lab five going ish. Going okay. I added more test cases to lab five. You guys are oddly quiet. I don't know if it means you haven't started yet, which isn't good. Yeah. Yeah. Yeah, because you're meant to read it a little bit. Because the lab you're only writing like a hundred lines of code if that. So yeah, mostly it's reading. I can add a bit just ask questions if you have more. I think I answered the same thing. It's like, you don't need that many functions to actually do this lab. So you can ask, but yeah, you can ask. I'll add more context to it. But yeah, part of it was reading it, but I can add more context if you want. Okay. All right, well, I'll do that after. So yeah. All right. So today, page replacement. So the fun stuff. So we've kind of explored disk, we've explored memory, we've explored CPUs and know that each of them kind of have its own cache. What we've been talking about so far, fastest speed memory on your computer are the registers which are on the CPU. They're going to be the fastest things, but there's always this capacity, speed, trade off. And also the speed trade off is typically also a price trade off. So you have a few registers are really, really fast, but there's not very many of them. Maybe there's only 64, 32, even maybe even 16 on some systems. Then below that, there is RAM actually on your CPU die itself that caches, it acts as a cache for the memory. And typically this will be a bit bigger. It'll be like in the megabyte size. Some of the big ones now have like 128 megabyte L three cache or whatever. So that's as quick as you can get on your CPU, but capacity is bigger, but it's going to be slower. And there's different levels of cache. Each are smaller and less capacity than the other ones. So below that is memory. So that's RAM, your random access memory, all of your volatile memory that gets wiped whenever you reboot your computer. That's pretty fast. The capacity is pretty good. And it's not that expensive. And that's typically in the gig or gigabyte ranges. So like 64 gigabytes of memory is not typically uncommon now. And then below that, there's your NVMe. So that's starting to get into the disk drives. That's what we talked about a few lectures ago. So the fastest version of that is called NVMe. So that's non volatile memory. So it uses some principles of memory. But whenever you power down your machine and power it back up, all your files are still there. So that's the non volatile part of it. Then below that are SSDs or solid state disks, which are going to be higher capacity and cheaper, but also a lot slower. And then below that, there's hard disk drives, which many of you have never seen before. Those are the mechanical drives that go around. Sometimes people call them spinning rust because they like making fun of them. And then below this, you'll see tape drives. I guarantee none of you have ever seen tape drives. Wait, how many of you have ever saw like a VHS tape? We got a few VHSs. Oh, we got excited VHS. Is that like nostalgic now? Okay, cool. So the tape technology, like it writes stuff directly on a tape. Well, that actually applies to computers too. And they can actually store, if you go super crazy with it, tapes can store terabytes and terabytes of information. And they are dirt cheap, but they are also dirt slow. But that is something like Google and IBM and all those companies that store massive amounts of archival data that will never be written again, or that they will use very, very infrequently are actually written to tape drives, kind of like a VHS tape. But they are like, they will actually store like terabytes of information. But they're really, really slow. Because if you actually, you can look at YouTube and see them some of these videos. So there's actual physical tapes. And if you want to retrieve information, you get to see the machine go physically grab a tape, put it in the machine, and then read it really, really slow. So that's actually used, but no one in their same mind is going to use it. Yep. Yeah. So flop floppy drives are like magnetic, but the capacity is really, really bad. The flop floppy drives are like 1.4 megabytes. So no one's ever going to really use those. And the like actual floppy disks that actually flop, I forget how big those are, but those are even before my time. But yeah, they're just old, old, but it's the same principle. It's like magnetic disk storage kind of. Okay, so part of this diagram for all the memory, if you are properly using the memory hierarchies, you want to create this fun little illusion where each level pretends to be as fast as the speed above it, but have the capacity of the layer below it. So if you're using the disk, like non volatile memory, like a really fast SSD drive, ideally you want it to be as fast as memory, but also have store or also have its own capacity. And maybe even a higher capacity if there's even a slower disk on the drive that or slower disk on the machine that is bigger. So we can use this today. We'll be talking about kind of bridging this gap between persistent storage and actual and your actual physical RAM or actual memory on the machine. So when you're using your machine, you're using your processes, you might notice that even if you look at the actual RAM used by a process, the total amount of RAM used by every single process on your machine can actually exceed the amount of physical RAM on your machine, even though it's all in use. So how it does this is it will go ahead and cache any memory that's not in use and throw it on the disk drive. So if you need it, it can go grab it from the disk drive. If you don't, it just stays there and it can swap in and out whenever it wants. So you might notice this whenever your computer is running slow or has anyone ever seen a file on Windows called the page file or the swap file or something like that. So if some of you go browsing around, where is it see windows or something like that or maybe it's in the root drive, I forget, there's a gigantic file that's like eight gigabytes or something like that that says page sys or something like that. That's basically a cache for your RAM that if you actually run out of physical memory, it will start offloading some of that storage to that file, which would be on disk. So the idea behind that is you only keep pages in memory that are actually referenced and then you put others on disk and sometimes you have the nice property like we saw before. If your disk block sizes are the same as your page sizes, well, you can just throw them on there kind of willy nilly. And whenever you need to access that information again, you can read it back from disk and put it back into memory whenever you need it. So today we will be talking about page replacement algorithms, which is just picking which memory to swap to disk, one you need to access something that is not currently in memory. So there's four main algorithms we'll go over today. There's optimal, which is just replace the page that won't be used for the longest. And this is completely impractical because this is looking into the future. And it's mostly just for evaluating your page algorithm knowing what the benchmark is for the best you can do. And then there's another strategy which might be intriguing and easy to implement. There's random page replacement where you just randomly throw to page disk and swap it out. Then there's also our good old first in, first out, which would replace the oldest page first. We've been using first in, first out. It seems to be like the default for every single problem we have to do in operating systems. And then the last one we'll look into today is least recently used. So the idea behind that is we replace the page that hasn't been used in the longest time because the process is probably done with that for now and it's accessing other pages. So for all of this we're going to assume that it's like a silly assumption but we'll assume that our physical memory can only hold four pages at a time. And whenever we access memory we want it to be, or whenever we access a page we want it to be in memory. But initially all the pages are already on disk just so we have something to do. And we'll use this for every lecture or every example in this lecture. So our goal for page replacement is whenever you swap in a page you want to swap in a page that will be used continually and our goal is to reduce the number of page faults because each page fault is terribly slow because it actually has to read it physically from disk which as we know is a lot slower than actual memory. So that's our criteria is basically the number of page faults. Yep. Yeah so in this case so we can generate page faults a few ways so page faults can just be that it's not mapped or you can use page faults for other things so like lab five you're using page faults for copy on write. For this we're going to use page faults to actually read in information from disk. So you can use page faults for a variety of different purposes and this is just another one of kind of fooling the system to thinking it has more memory accessible than it actually has. So again we're assuming our physical memory only holds four pages and then we'll just I'll just tell you the accesses in terms of what page it accesses. So in this example we're accessing page one two three four then one two five one two three four five. So at the top of all these I'll put whatever page we're accessing so in this case we're accessing page one and within the box at the bottom is what is currently in physical memory and whenever I color a page red in physical memory that means we read it from disk and we put it into physical memory. So if our first access into page one initially there'd be nothing in memory because that is our assumption. So I would have to read it from disk and read that page into memory so it is now red indicating a page fault and I read it from the disk into memory. All right same page have to say that joke. All right so now if I access page two also not in memory so I have to bring it to disk or sorry I have to bring it yeah I have to read it from disk into memory so I would read page two and I can hold four pages in memory so I don't have to kick anything out so I would just have page one and two in memory now. Similarly for page three same thing I read it from disk put it into memory and now it is in memory I can hold four pages so I'm still good. Now I access page four same idea it's not in memory yet I read it from disk now it's in memory and now my memory is full because it is at capacity because I can only hold four pages so now if I try and access page one I don't have to read anything from disk because I already have it in memory so now there's nothing red there's no pages in red because it's already in memory I don't have to do anything you could also think of this as a cache hit if you want or whatever you want. So same thing is going to happen for page two it's already in memory no problem there don't have to do anything so the interesting thing happens at when we access page five so when we access page five we need to bring it into memory but in this case since it's full we have to kick something out so now our problem is we have to kick out either one two three or four and which one would we like to kick out so votes for kicking out one but we like one votes for kicking out two votes for kicking out three some of us don't like three votes for kicking out four most of us don't like four more enthusiastic for four so this one says we're trying to do the optimal thing so let's do a hypothetical and do what no one wanted so if we kick out page one now so we replace page one with page five in memory then whenever we do the next access of page one well we just kicked it out so we have to reload it again so that's a big waste of time so if we're doing the optimal thing we will kick out whatever page is not whatever page is not going to be used for the longest time so you can start at five and then go up to argue about it until you have one page remaining so between page one two three and four well the next page access is one so I'm not going to kick it out then after that access page two so I'm not going to kick it out then after that access page three so I'm not going to kick it out and then at this point I only have one page remaining so I would kick out page four so I now replace page four with page five yep yeah so I removed four so I still have to swap it out because it's not in memory but I just have to pick something to kick out right so if I picked if I picked one to kick out you know in the next access it wouldn't be in and I'd have to load it back again right yeah you have to load back four eventually in this case but it also might be the case that I never access four again or something else it could be way longer than this but this is like a very it's hard to get like big picture examples from this because I have to fit it on a slide and explain it so now because we replaced page four with page five well we essentially looked at the future so our next three accesses are all going to already be in memory so we're all good we access page one already there don't have to load it from disk page two same idea page three same idea and now we get to page four so now when we are loading in page four well we're stuck we actually have to load it in to memory now and we need to kick out a page so we can kick out one two three or five and in this case there is a bunch of correct answers it's just if I look ahead my next access is to five so I don't want to replace page five because I would just have to reload it again anyways which would be slow but I don't use one two or three anytime in the future so I can pick any one of those in this case to kick out in this case I'll just kick out one so I would replace page one with page four and then I'm good next access is page five it's already in the cache yep or memory yeah so we'll see in other examples with the same sequence so it's optimal in the sense that we're reducing the number of page faults because we're delaying it as long as possible so for this case we didn't have to reload anything for like three accesses in a row well if we pick the wrong thing we would have to reload it immediately right yeah yeah here we're trying to just minimize the number of page faults and if we look into the future that's the lowest number of page faults we can get for that sequence there's another question no yeah yeah so the question is how do we know which one so in this case we have the sequence and we can look at it so this is just to evaluate them because we're looking in the future so yeah so in this case we already know the entire sequence so this is mostly if we're analyzing these types of algorithms well you would record the number of page accesses and then analyze it after the fact and you can compare it to the optimal so so here our goal of this is just to count the number of page faults in this case makes it really easy you just count the number of red numbers so for this sequence with this algorithm there are six page faults so we can remember that because we'll we'll very shortly make very poor decisions so poor decision let's use FIFO because we always use FIFO as like a first first try thing so same accesses same problem except this time we're not doing optimal we're doing first in first out which will not look at the future so you'll probably find it make a bunch of very poor and borderline silly decisions so the only thing we can't avoid is the four accesses at the beginning because there's nothing in memory so the first four are going to look the same where we have to bring them into memory from disk so everyone okay with doing that so I can just skip it for the rest of the other ones okay so the next access going to follow the same suit as optimal we're accessing page one already already in memory no problem already there our next access page two already in memory no problem already there now here is our decision so now we can't look into the future you have to look into the past so we'd want to access page five it is not in memory we have to kick something out so we have to kick out one two three or four so between one two three or four what did we add first so one anyone so one was the first access so that's the first thing we added in memory and you can pretty much look backwards and see that oh yeah we added one to memory first so that's the first one we got to kick out so if we're doing FIFO I added one first so it's the first one out so we replace one with page five which you can see is going to add be a bit of a problem so we just kicked out page one replaced it with page five and now our next access is page one crap I just kicked it out so I have to reload it again from the disc so now I have to pick do I kick out page five page two page three or page four well yeah in this case I would have to pick out page two because that is the with all the ones remaining that's the oldest one and it also kind of looks like a diagonal line when you look at it with the red numbers like this so that's an easy way to do it really really fast so I had to kick out number two so now in memory I have five one three and four and then I do my next access my next access is the page two the one I just kicked out oh geez this sucks so I have to pick one to replace now I replace page three because it's the oldest one all right great doing a great job here now I access page three when I just kicked out again so I have to do this again and the oldest one now is page four so I kick it out oh okay my next access is to page four wow I'm doing a real good job here you can see how this is kind of a crappy approach so between what is remaining in memory now one or five one two and three five is now the oldest so I kick it out so I replace five with four and now I have four one two three in memory and now I finally access page five which again I have to bring back in and now my oldest is one so this would be my final final access where I brought bring it in so now if I count the number page faults here or count the number of red which there is an access which there is a lot of how many page faults do I have now I'll pretend I heard 10 yeah I see 10 mouth so now I have 10 page faults so you can so this decision was clearly the bad one so optimal was six and now if I did FIFO I did 10 so it was way way worse for this memory trace so any questions about that yep so the question is why don't we replace individual bytes instead of pages so if we replace individual bytes instead of pages first your hard disk does not like accessing bytes it only accesses blocks at a time and two it's the same reason why we do it for a memory subsystem because things are really really slow so if we can bring in a page at a time it's way faster yep good question though okay so let's do something fun so this was FIFO we have four or we had four pages we could hold in memory so let's do this again same sequence same everything except now I have less memory so I only have three pages I can hold in memory so if I can only hold three pages in memory my memory is smaller that kind of makes me suspect that I should have more page faults because I have less room to store things sorry so if I have less memory it makes sense that I have more page faults right because I have less room to store stuff everyone agree with that or the other way if I have more memory I should have less page faults yep okay yeah so what you might expect by looking at this is okay well let's go the other way so if I have more pages I will have less page faults so if I started here where I had four well if I can hold five pages in memory I'll just have the five page faults when I initially load them in and then that's it because I can fit everything so if I have five pages I'll have five page faults if I have four pages in memory I have ten page faults you might expect that trend to continue where if I have three pages or less physical memory I'll have more page faults because it won't fit but let's just make it smaller now so we'll do the same FIFO thing but instead of this time instead of having four pages we can only hold three pages in memory so our first three accesses are going to be the same because we need to load it into memory from disk so now this will kind of give us the intuition behind it that this is bad because whenever we access page four well that generates a page fault and we have to kick something out which should be worse than before because we didn't even have to kick something out whenever we uh whenever we access page four because we had room for it so if we access page four we have to kick out one two or three in this case it's FIFO again so we're going to kick out page one so we kick out page one load in four and this is what our access looks like and now it's looking real bad for this because our next access is to page one which we just kicked out so we're going to have to load it back into memory and we're going to have to kick out the oldest one which would be page two which looks real bad so now we have five page faults in a row we're not doing too good so our next access is to page two which again we just kicked out of memory we are doing very very crappy here so we have to kick out whatever the oldest one is in this case it's page three so we would replace page three which page two okay so things still aren't looking good so our next access is to page five we have to bring it into memory we have to kick out the oldest one which if we're doing that waterfall thing is now page four so we kick out page four replace it with five so everyone on the same track right now we're all good okay so this is where our luck changes a little bit so now our next access is to page one thankfully it's already in memory so that is a hit and not a page fault so that's good next access is to page two all three in memory we're all good next one is to page three page three we have to load in from disk into memory and replace the oldest one in this case the oldest one is page one again so we replace page one with page three so now in memory we have five three and two now we're going to access page four when we access page four we replace two because that is now the oldest one so now in memory we'll have five three and four and then our last access is to page five which thankfully is already there so now we have this so how many page faults is that nine which is less than before so we have less memory and less page faults which seems a bit weird so if you took that to its extreme if you want to speed up your computer and make page faults less common just get a smaller hard drive right it's everyone's solution to everything so that might imply that this isn't used so this thing actually has yeah yeah so yeah so the question is is that always the case and the answer is someone has gone far in the depth for that problem so there's a name for this so it's called belladay's anomaly and it actually formalizes it more and it says in general more page frames cause more page faults and this is a problem with all of the FIFO algorithms it doesn't exist in at least recently used or lru that we'll see much later or stack based ones so in fact for that question they actually wrote a paper about it some mathematical people wrote a paper that's in greek that i can't read but they figured it out in like 2010 that it's actually unbounded so given any sequence or any combination of it you can come up with a sequence that gets an arbitrary number of page faults so that's fun if you really like math you can go read that paper if you want have any questions about that paper don't ask me because yeah i did engineering not math so for all other algorithms your intuition is correct where if you increase the number of page frames or increase the amount of memory you have it will decrease the number of page faults which is more what you actually expect so this is just for FIFO algorithms which is kind of a fun thing all right so last one for the day we'll do least recently used is that a question yep yeah so if you go with the extreme cases you can come up with different ones but this is like yeah for the non-trivial cases they can come up with anyone okay but for us we don't really care because we're not going to use FIFO because it's garbage so the first one we actually will use which we'll see is kind of impractical but we can actually argue about it is least recently used so it doesn't look into the future it just looks at the usage pattern in the past to kind of predict the future so again same accesses same everything as before we'll go back to four pages and do the same tie or sorry and do the same accesses so our first four going to look exactly the same where we have to bring it into memory from disk then again our next two accesses are going to be the same so one and two are already in memory so we don't have to replace anything so we're all good so our first question comes in now is now if we are replacing or if we need to read in page five again we need to replace page one two three or four so least recently used is as the name implies you go backwards in time and whatever has been used or whatever is least recently used or whatever hasn't been used in the longest is the one you kick out so if we start at page five and look backwards well right before five we use page two so we're not going to kick out page two so it's safe then we look at page then it accesses page one if we go backwards so we're not going to kick out page one so it's safe and then if we look back another one it used four so we're not going to kick out four so it's safe so there's only one page remaining in memory and that's poor old three so three it hasn't been used in the longest so it's out of here so we would replace five with three so any question about that fairly ish straightforward okay so now we actually made a good decision this time for a change so our next access is to page one and this is typically how memory accesses actually happen on your machine if you use a page typically you're running a program something like that you'll access you know the next thing in the array which will typically be on the same page or you'll execute the next instruction which will probably also be on the same page so this is more like memory access patterns you'll actually see on your machine so access page one we're all good it's already there so we don't have to replace anything then we access page two again already there don't have to kick anything out now when we access page three oh shucks now we have to kick something out again so again we look backwards in times to see what has been used least recently so if we go backwards we can't kick out two because it was used right before too safe we also can't kick out one because it was just used so one safe and we also can't kick out five because it was used right before that so five safe so by process of elimination four is the one we kick out which will prove to be a bad decision but hey we made it so we kick out four and we replace it with three and now we access page four which unfortunately we just kicked out so it will do the same thing so we'll look backwards we have to kick out page one two three or five so we'll go backwards so we're not kicking out page three we're not kicking out page two we're not kicking out page one we're kicking out page five which again unlucky decision so we kick out page five with page four and we end up with this in memory now we access page five and we have to do the same thing we have to kick out one of them so again we'd go backwards we're not kicking out four we're not kicking out three we're not kicking out two so we're kicking out one so we replace one with five and this would be our final answer so if we count the number of page faults here well one two three four five six seven eight so now we have eight page faults so it was better than FIFO wasn't as good as optimal but it was clearly an improvement over FIFO so any questions about that yep oh yeah so the question is if it's done sequentially when would we have a tie so you would have a tie only in the case of like multiple cores or multiple processors that might actually try and access the same thing at the same time so for these questions they're all sequential if we assume one core so there won't be a tie but that's mostly there for like for practical mirrors if it looks like a tie you just used FIFO to break it okay so this kind least recently used kind of sucks practically so it actually works fairly well it's just whenever you go to implement it it is a pain so if you want to implement this in hardware well you have to search all the pages so you have to search all the pages in memory and actually do the traversal which is like order n which really really sucks so you could implement it and that would you keep a counter for each page that essentially says oh when was I last accessed and then if you have to replace a page well you could save that clock you know you save the time on each page and then you search them all to find whatever the oldest one is and then you kick out the oldest one but that involves saving a clock for every page which is going to take some space and scanning through every page which is going to be really really really really slow so you could do it in software we could be like oh yeah well link lists are one they're constant time that's great so let's just create a doubly linked list of pages and then for each page reference well I would just move it to the front of the list and that way I maintain that the order of my link list is the order of accesses so if you just have an access to it then it goes to the front of the list so if you do that well then your link list is actually ordered by access time without having to store it explicitly because you're just moving it up now for replacement that's really really simple you could just look at the back of the list and say I'm removing that page but the problem with this is that the constant the constant really really really really matters because that constant of adding that page to the front of the list happens for every single memory access on your machine so every single byte you would have to do essentially six pointer updates for everything every memory operation you use on your machine so it would slow down your computer by like a factor of a lot by like several hundred probably on each reference so it's not going to be practical whatsoever and there's also it's even worse if you assume multiple processors because you would have one queue and then say eight processors trying to all manage that queue at one time and as we know from lab four that's a data race so all the processors would have to contend with updating that list so it even be worse than that constant time thing so this would just be absolutely abysmal and you just couldn't do it so what we settled for is an approximate least recently used and we think that is okay because least recently used is kind of an approximation of the optimal algorithm if you think about it it's just using the past to predict the future instead of actually knowing the future so there's a lot of different tweaks you can do to implement more efficiently so next lecture we will look at the clock algorithm but there's also a bunch of different one there's least frequently used which is a little bit different where it counts the number of usages there's like using two hardware queues there's adaptive cash there's all types of what different algorithms with different tradeoffs and we will just see one particular one that's a bit more easy to understand in the next lecture all right so any questions next lecture will be a fun one because I animated a little clock it's lots of fun so goal of today we use page replacement algorithms to reduce the number of page faults because we're now taking advantage of disk being bigger and trying to fool our operating system into using more memory than it physically has so we saw four algorithms we saw optimal which is good for comparison but not realistic random we didn't do an example of it because as the name implies it's random but if you actually analyze how well random works well it actually works surprisingly well it beats FIFO quite handedly because in practicality it avoids the worst case if you just randomly make a decision you can't really make a bad one or you're least likely to make the worst decision possible which FIFO tends to do so it actually kind of works in practice FIFO we saw kind of easy to implement but it has that anomaly where we give it more RAM and we have more page faults which kind of sucks and then lastly we saw at least recently used which gets close to optimal but it's expensive to implement but it's the first one we saw that's actually practical so with that just remember fooling for you we're on this