 All right, good afternoon. Welcome, so happy Halloween, this one as a Halloween treat. The lecture will not probably take the full time and we'll be able to go ahead and either commiserate or work on lab four or you can study for your other midterms because apparently that's the thing. So, lab four is released after your midterms. If you wanna feel good about yourself for reading week, just do lab four, it shouldn't take that long, hopefully. If you understood the lab four primer, you're like halfway there. So, all the tests are there, it should be hopefully not too bad to implement. As long as you're careful about your file descriptors, you won't have any real hard to diagnose bugs. But today, this will be a quick one and we will talk about page replacement. So, on your machine, you have this trade-off between capacity of memory and speed. At the very top, the fastest thing is your CPU, which has a set number of very fast registers where all the operations happen, but there's not that many of them, but they're very, very fast. And below that, you have your CPU caches, your L1, your L2, your L3, somewhere in the range of like, the newer processors have up to like 32 megabytes of cache. It's really, it's much faster than RAM, but it's still slower than actual registers. So, below that, you have some more capacity, but it's a bit slower. And then below that is memory, which is pretty fast. We have like, you know, 32 gigs is not too uncommon, it's relatively fast. Then below that, we have NVMe storage for non-volatile memory. So that's like your newer M.2 SSDs and all that stuff. So they're in the range of, you know, terabytes are pretty affordable and it is much, much faster than old spinning disks, but still it's going to be more expensive than RAM, or less expensive than RAM, but have lower capacity. Then beyond that is like your flash memory SSDs, like your two and a half inch drives. They're terabytes, not that uncommon either, and they're going to be much, much cheaper, but they're going to also be slower. Then below that, you have spinning magnetic disks, which, you know, 12 terabytes is not uncommon to buy and it's fairly cheap. And that's going to be fairly slow. And then below that is tape drives, which I'm sure no one has ever seen before, but they are used for like archival storage, like Google data centers and things like that. They are exceedingly cheap and can hold like, you know, like 50 terabytes, I think is not uncommon, but likely you will never ever see that because you don't need to store that much data. They're really, really slow, but they're super cheap. So we have this whole hierarchy and you want to kind of hide it away from the user and give them an illusion that everything has the speed of the layer above it while the capacity of the layer below it. So you have the best of both worlds. So I have large, fast capacity and it is our job to kind of hide that to users and make it as easy as possible to actually use. So normally the memory used by all the processes on your machine can't exceed the amount of physical memory, but they may not be all in use at one particular time. So you can take advantage of having fast disks and any access storage or any access memory. You can put some unused memory onto the disk and get it later and then swap things into main memory and kind of create an illusion that you have lots of memory so we can actually use like visual studio code and all your browser tabs with only like eight gigs of RAM as long as you have your disk as the backup there. So that's what we'll be talking about today is how to actually which pages you would swap to disk and into memory. So ideally you only keep the pages that are in use in memory so they're already there and you can use them and then anything that's not used you put to disk and then hopefully that's used very infrequently so you would swap that back into memory whenever you need it and hopefully that doesn't happen that often. So you just swap pages back into memory as they're needed. So these page algorithms there are several of them and again it is just swapping things from disk to memory and memory are the pages that are actually in use. So the first algorithm is the optimal algorithm. So this is to replace the page that won't be used in the longest time. So I swap out the page I know is not going to be used in the longest and the intuition behind that is all the remaining pages are going to be used more frequently and so whenever those get access they're already still in memory so they would already be there you don't have to do any swapping and everything is good. Another strategy might be just random which is just replace a random page. So whenever I need to swap memories full I need to swap something out I just pick a random page and throw it out. Yeah from memory yeah. Yeah so if you have eight gigs of RAM and all your processes are using like 10 gigs two gigs of that could be pages that it throws onto the hard drive and then it would swap them back in as they're needed. Okay the third algorithm would be first in first out so we swap the oldest page first nice and simple first in first out is kind of your go to for scheduling and page replacement it's the simplest thing to do. Then so optimal also requires looking into the future so I'm looking into the page that won't be used in the longest. Obviously you can't actually do that on your machine because you won't know what page isn't going to be the longest because you cannot perfectly predict the future so it's not really practical. So a more practical version of that is least recently used so it's kind of an approximation so I replace the page that hasn't been used in the longest and the idea behind that is well whatever I most recently used I'm likely to use it again so I should just keep it in memory and swap out anything that hasn't been used in the long time because likely I'm pretty much done with that or I just access it very infrequently. So this is going to be the running example we use the whole lecture and this is how we evaluate page replacement algorithms. So it's going to be a slightly convoluted and silly example where we only assume our physical memory can hold four pages because I don't want to write like 10,000 numbers. So memory can only hold four pages and then there's going to be five pages we access we just give them a number so we access pages one to five and we access them in this order and we're going to assume all the pages are initially on disk so we have to swap them into memory so these are our access one, two, three, four, one, two, five, one, two, three, four, five. So this is going to be a running example for all of our lectures or sorry all of our examples in this lecture and to evaluate page faults it's a bit easier than scheduling because we only care about the number of page faults because then it's slow to swap things in from disk so we just want to minimize the number of page faults. So that makes sense to everyone. Okay, so let's go through those accesses and see what happens in the optimal case. We were where we replace the page that isn't going to be used in the longest time. So again, physical memory can only hold four pages so inside of those boxes are going to be four up to four numbers that's the pages that are currently in memory and then above the boxes is going to be the current page we're accessing and then if the number's in red that means we swapped in that page in that slot. So when we first access page one we're going to assume they're all on disk so we have to bring it into memory so we swap page one into memory so now in memory in our box we have one and it's in red. So when we access page two it is also not in memory so this is going to get fairly boring so it's not in memory we bring it into memory there's still additional slots so now we have page one and two into memory and we swap page two in at that access. Then page three, same thing. We have another slot, we bring in page three. Page four, same deal. We bring in page four, now our memory's full. So now after page four we're accessing page one. It's already in memory so we don't have to swap anything. It's all good, we have essentially a cache hit so it's in memory, we access it, we continue on with our lives. Now we have an access to page two, same thing. It's in memory, so it's all good. We access page two and then we don't have to do anything. So now the interesting thing happens when we access page five. So it's not in memory and now we have to pick a page to swap out. So remember for optimal we're going to swap out the page that is used the furthest in the future. So if I want, and that's the goal is to reduce the number of page faults. So should I swap out page one? No, because it's going to be accessed next so page one safe. So I shouldn't touch page one then after that I access page two so I shouldn't touch that. Then after that I access page three so I shouldn't touch that. So now I only have one option left. I have to get rid of page four. So I swap out page four with page five. So on my access to page five I swap out page four so I put page five in red and it replaces page four. So now in memory we have pages one, two, three and five. So after that, well, we're going to get a bunch of hits because we were smart about this. So now we access page one. That's a hit. It's already in memory. So we're good. Access page two already in memory. That's a hit. That's good. Then we access page three. It's a hit. It's already in memory. So we're all good. Now we have page five. So we have to swap in page five. So we have to swap out either page one, two, three or five. So which one should I swap out? One, two or three. So I basically, the next access is page five. So as long as I don't touch page five, it's fine. Generally we don't like page one so screw page one. So we replace page one with page four and now this is what's in memory is four, two, three, five. And we swapped it in. So when we access page five as long as we didn't swap it out and again the previous one we could have swapped either page two or page three as well. So page five would be a hit. So now we just count the number of page faults which is essentially the number of red number. So how many page faults are there in this case? Six. So we're done. So in the optimal case, there's gonna be six page faults. So whatever we evaluate any other algorithms since this is the optimal, it should be either six or higher because if it was, that'd be a contradiction and then optimal wouldn't be optimal. So remember six page faults here. So let's do the same thing with first in, first out. So first in, first out, the beginning four accesses are gonna be all the same. Actually the beginning six accesses are gonna be all the same. So one, page fault have to bring it into memory. Two, page fault have to bring it into memory. Three, same thing. Four, same thing. And then I'm going to access page one. So if I access page one, it's a hit. It's already in memory. Then I access page two. It's a hit. It's already in memory. Now we get to page five. So page five is in memory. So we have to bring it in. So we have to kick out something. What do I kick out? Number one. So first in, first out. First thing I put in was page one. So it's the first thing out. So I replace page one with page five. So page five is in red. And now in memory it's five, two, three, four. Okay, well, that was silly. So next access, I access page one, which I just removed. So now I have to swap back in page one. And what do I pick to swap in for page, so page two. Page two is now the first one in. So page two gets swapped out. So now memory looks like five, one, three, four. Ugh, shucks. So now I access page two. And that's a miss as well. So now I have to swap out something else. So what should I swap out? Three. So I swap out page three because now it is the oldest. So you can look backwards too, so you can see the nice diagonal lines of red. So first in, first out, you'll know you're doing it right. If you see the diagonal lines of red or circles or whatever you choose to put in for your swap. So now when I access page two, I replaced it, I replaced page three. And now memory has five, one, two, four. Now I access page three. Ah, crap, I just swapped that out too. So now what am I replacing? Four. So now four is the oldest. So now I replaced page four. Now in memory it's five, one, two, three. Now I'm accessing page four. Oh no, I just swapped out page four. So now I swap out page five because now it is the oldest. So now in memory I have four, one, two, three. Now I access page five. Again, I just swapped it out, so I made some poor decisions in life. So now I have to swap out the next oldest one, which is going to be, what's it now? One again. So now I swap out one. And now in memory I have four, five, two, three. So how many page faults do I have here? Ten. A lot worse than optimal. Optimal was only six. So that kind of sucked. So you might be thinking here's a brain teaser. So if I have less physical memory, so if I only had like three, if memory could only hold three pages, that should make this problem even worse, right? Because I have less physical memory, so I should probably have more page faults. That makes sense? Because the reverse is definitely true. If I had five pages in memory, I could fit everything and I would just have the five page faults and then everything fits. So I would only ever have my five page faults. So let's test that theory. So let's do FIFO again, but this time we can only hold three pages in memory. So we have less memory, so we expect more page faults. So let's go through it again. Now this will get slightly more interesting. So for the first access, again, now our boxes are smaller because we can only hold three pages. So first access, swap it in. Page one is in. Two, swap it in. Three, swap it in. Now in memory, we have one, two, three. And now we access page four. So what am I kicking out for page four? One. Okay, I kick out page one. All good. Clearly made a poor decision again because I just swapped out page one and now I'm accessing it again. So when I access page one, what am I swapping out? Two. So crap, I did it again. So now in memory is four, three, one, and now I'm accessing page two. So if I access page two, I have to replace something. When am I replacing? Three. So we got that nice diagonal line going on. So I replaced page three. Now I access page five. So what should I replace with page five? Four. So now in memory is five, one, two. So finally now I get a bit of a break. So when we access page one, it's there. Good. Then we're going to access page two. It's already there too. So we're good. Now we access page three. Oops. Now we access page three. We have to kick out something while we're kicking out. Page one. So page one gets replaced with three. So now in memory we have five, three, and two. Okay, so now we're accessing page four. It's not in memory so we have to swap out something. What are we swapping out? Two. Two is now the oldest, or the first in. So it is first out. So now we have five, three, and four. Then finally with our last access we have five, which is a hit. How many page faults do we have now? Huh, weird, huh? Didn't we say that we should have more page faults with less memory? Yeah, that's kind of weird. So we had 10 page faults before with four physical memory holding four pages and now we have three and we only have nine, which is better, which is kind of weird. So this weirdness has a name. It's Abilities Anomaly. And it says for first in, first out algorithms that more page frames actually cause more faults in kind of a fun paradox. And this is only a problem with the FIFO algorithms. It doesn't exist for at least recently used. And it is one of the very many reasons why you wouldn't use first in, first out. Cause the more memory you have, the worse it gets. Yeah, so just as, can you just use one, which is the best? No, because that would be terrible. So there's this fun paper because it involves a lot of math. So if you're really interested, you can read that. Or if you wanna like have something to read before you go to sleep to put you in a coma, you can read that. Basically the paper, if you read it says that most of the time you would expect that to be true where you've less memory and you have more page faults. But this says with those algorithms, you can carefully construct a sequence to get any arbitrary page fault ratio you want. So it depends on the accesses. In normal accesses, it would typically be better to have more memory. But because FIFO and the way it works with this, you can just, if you carefully craft it, you can get just some arbitrary page fault ratio. Yep, yeah, some cases you can craft cases to get whatever miss ratio you want. Yes, for, and for least recently used, more, the more memory you have, the better the less page faults you have. Everything follows, it's only for FIFO where you can carefully craft stuff. Yeah, it doesn't have this. So yeah, for any of the other algorithms, not FIFO, if you increase the number of page frames or the amount of memory you have, you'll have fewer page faults. Yep, yes, yeah, yeah. When I say page frames, it's like kind of redundant because frames typically means physical memory. But page is like a set size. Generally people just say page when they just say anything is size of a page, which is at four kilobytes. Okay, so let's do one of the other examples. So least recently used, in this case, you would use FIFO to break a tie. In this case, it's like a unit processor system, so there'd be no way to have a tie. But if you had multiple processors and you actually implemented this, there could be scenarios where you would actually have a tie so you might use something like FIFO to break the tie. But in this scenarios, we'll never have a tie because we're just arguing essentially about one CPU. So, again, go back, our physical memory can hold four pages again, same page accesses. The first six are gonna be really boring yet again, so one, have to swap it in, two, swap it in, three, swap it in, four, swap it in, and now we access one, it's there, so it's a hit. Access page two, it's there, it's a hit. Finally comes the time where we can think, so now we access page five, so what should I replace with page five? Three, yeah, so if I look back, so least recently used, I'm going to look back in history and then figure out what I have used most recently, so I just used page two, so page two is safe, I can't get rid of that, I shouldn't get rid of page one either, and then pass that, I shouldn't get rid of page four. So, if I can't get rid of one, two, or four, the only one left is three, and that's the least recently used, so I would replace page three with page five. So, I swap in page five for page three, and now in memory I have one, two, five, and four. So now I'm going to access page one, so it's already there, that's good, we didn't kick out page one like FIFO did, so it's already there, it's a hit, access page two, it is also a hit, it's already there. Then we go to access page three, so it's not in memory, so what should we kick out? I see a four, we agree for four, so between one, two, five, and four, while I wouldn't kick out two, I wouldn't kick out one, I wouldn't kick out five, so last one standing is four, so I replace page four with three. So now in memory I have one, two, five, three. Then I made a poor decision because now I'm going to try and access page four, so now I have to kick something else out, why am I going to replace for page four, five, right? So, I'm not going to kick out page three, I'm not going to kick out page two, I'm not going to kick out page one, so last page standing is five, so it is gone, which was a poor decision, so I replaced five with four, so then next access, I am accessing page five, so I have to swap out something, why am I swapping out one? Yeah, so I wouldn't swap out four, I wouldn't swap out three, I wouldn't swap out two, so last page standing is one, so I'd swap out one with five, now I would count how many page faults I have, how many page faults do I have? Eight, so I was better than FIFO, I wasn't quite as good as the optimal, but hey, I was better than FIFO. All right, any questions about that? Nice and straightforward, finally, right? So, when you actually go to implement, how least recently used, it's actually pretty bad, so we could think of an implementation where for each page we have a counter that says, what's the time it was last accessed, and then every time you access any page in memory, you would have to update that timestamp, because that's when it was used last recently, and then if you need to replace a page, well, you need to scan through all of memory and then find the page that has been used in the one with the oldest clock, which is going to be really, really slow. If every memory access you actually had to write a number and access your system clock, that would be really, really bad, so that would essentially at least double the amount of memory operations you have to do, which is terrible, and when you replace scanning through all of memory every single time, it's going to be just really, really, really slow. So, we might be a bit more clever if we try and implement it using Qs and software, so you could try and be a bit better and create doubly linked list of pages, and then for a reference, well, you just move it to the front of the list, and then whenever you need to replace it, instead of scanning through all the pages, you can make it a lot better by just taking the page at the back of the list, because that would by definition be the oldest one, but now it still requires like six pointer updates for every page reference, which you might be like, oh, it's 01, so it's all good, but six memory accesses essentially means you're slowing down your computer by six times, so if every reference you did six pointer updates, that would be atrocious, and because they're all pointer updates too, you could imagine if you had a processor with multiple cores and they all use memory, there would be some contention because you would have to put a mutex around that link list and then you have every core fighting for the mutex and you essentially make it serial, and it would just be a complete disaster. So, implementing this is not going to work. So, when you implement this, which is what we'll see in the next lecture, you essentially take some liberties and implement an approximate lease recently used, since lease recently used is like an approximation of the optimal case anyways, it's okay, we're all engineers, approximation is the name of the game, so it's all good, it's heuristically, it's about the same and we can implement it more efficiently. So, there's lots of different tweaks, you could do it used to implement more efficiently, it's kind of like scheduling in a way that there is also no one size all fit solution, it depends on the scenario and kind of the workload that you have. Next lecture, we'll be looking at something called the clock algorithm, which will take longer than we have left in the lecture, so we can just end early because we have midterms, so we can do that, or we can all work on lab four, we could, if we all, we could probably finish lab four if you wanted to, it's not that big, I finished lab four on the train in like 20 minutes, so you should be able to as well, so don't worry about it. So don't feel bad, that was a re-implementation because I did it before, so on the train, I just ran out of internet, so instead of waiting for air and end, I just did it better, so. But I've done it before, so you will probably take more than 20 minutes, but it's not gonna be that much harder than the like lab four primer. Just be really careful about your file descriptors and you won't have any terrible errors. So we'll be looking at the clock algorithm, there's lots of different flavors, there's like least frequently used, which is slightly better than least recently used because you just keep track of the number of accesses instead of the time. There's something called 2Q, there's adaptive replacement cache that we won't get into, but like scheduling, there's a ton of options that you can use. So the goal of page replacement algorithm is to reduce the number of page faults whenever you do these types of questions, it will always ask, hey, here's all the accesses, how many page faults are there given this algorithm? So you should know these algorithms. So we saw Optimal, which was replace the page that's used the furthest in the future and it is Optimal, it's good for comparison sake, but it's not going to be realistic to implement because we are not fortune tellers. Realistically, you will not know what happens in the future. Then there's Random, which actually works surprisingly well, it actually works better than FIFO because it avoids the worst case and you would think that wouldn't be the case, but just actually just doing random stuff is actually pretty good in this case. There's FIFO, it's easy to implement, but has that weird paradox that anomaly we saw where we had fewer page frames and we saw fewer page faults, which was kind of weird. Then we saw LRU, which gets close to Optimal, but it's expensive to implement. Yep, yeah, everything would take too long. There's some implementation, we'll see one next lecture, but yeah, it's fairly expensive or awful. All right, any other questions for today? Oh, and lab, no, quiz to the grading, apparently it should be done on Wednesday. No, I didn't finish my sentence. All right, yeah. Like, yeah, it's like, like, I don't know. So, Corkus, one of the questions the answer was wrong in the bank and so it doesn't, if you update it, it doesn't regrade it. So, the quiz summary just shows like zero for everything. So, well, which is good, because it was wrong, so if it's zero, then it's at least greater than zero. So, I have no idea what it is, but hopefully it's not too bad. All right, any other questions? Other than that, free time, so just remember, I'm pulling for you. We're all in this together.