 I'm covering for Jeff again today and it looks like I probably am going to be in here on Friday enjoying everyone smiling faces on this. So again I answered to Carl what I'd like to do is pick up with the beginning of virtual memory and if I could have one conversation it would be great. Donka, actually that's an ample of time multiplexing. In other words one person at a time in the room. Anyway what we're going to be talking about is kind of a quick recap of scheduling with the caveat that I am very rusty with the swirly staircase thing of a bob. But then go on from that we're going to be talking about the introduction to virtual memory and kind of talk about some of the justifications for why we have this whole virtual memory apparatus. In other words why can't we simply get away with not having it and let's talk about some of the problems that result from that. And kind of leave the class with an introduction to some of the goals that Jeff's going to be talking about in subsequent classes as to how we can have an efficient and well effective virtual memory system on that. As you probably know this is going to be if you will the in part of the last part of the projects in the class. This is assignment three is essentially to write a memory manager from the ground up. It's a big project but I can also tell you it's a fun project. So once you get through assignment two and one sense the assignment gets bigger but it's also more rewarding on that sense. So you can kind of get a sense for well how if you will memory gets shared multiplex and you're actually the one that are going to be designing the policies and enforcement procedures for the user processes when they're out there and they decide to misbehave on that. So problems with direct physical allocation well actually before we get to this kind of oh yes announcements dot text I think this is where last year Jeff talked a little bit about pacing for assignment number two. Again assignment number two checkpoint two point two the rest of it is going to be due next Friday that is creeping up on that in terms of pacing I would suggest for most people you should be just about done with fork and working on wait if you have not done so already. I assume people are done with the file sis calls if you're not you really are behind the eight ball on that. As far as the process this calls a kind of a good pacing is fork for about maybe three four days or so it's a big one then wait. Maybe a couple days at sec the about maybe three four days or so wait. I'm trying to get paid all of them maybe about two minutes and you know that's the one where you want some again affirmation and you know you want some positive reinforcement you know you can knock out wait. I'm trying to get paid right away and then I'd allow a few days at the end for things like going over cleanup inevitable bugs you're going to need to make sure that everything ties in with your file system on that. And again one of the reasons I am trying to push this is obviously next week is probably going to be high time for midterms projects in other classes and whatnot. So again the sooner you can get this done the better it is with that midterm coming up the week after spring break on that we do look to hopefully have some review sessions for coming up for you people on that. Followed by the first checkpoint for assignment number three one week after that the first checkpoint for assignment number three is a relatively small one. But again just you don't want to kind of let it flop off of your scheduling calendar on that. So questions about kind of the pacing the assignments what have you. We're seeing a lot of the same faces in office hours which is good and bad that's what office hours are for use them. Okay so for those of you who are strangers don't be strange the sooner you can unstrange yourself the better it's going to be for everyone concerned on this. All right scheduling goals here what is the purpose of goals again to recapitulate on this. Well we want something that works on here so in other words when we want to meet deadlines we don't want to starve things out. So just because there is one thing that's a priority we don't want to make sure that the things that are not priorities eventually just fall off the face of the earth. That said we also want to make sure that things that are priorities get prioritized ahead or things that are less so on this. Okay resource allocation this is a general trend again in this class. You want to make sure that things are not if you will twiddling your silicon thumbs on this. So we want to use the scheduling policies to ensure that the CPU is booked as much as possible. The disk drive is booked as much as possible that we're responsive to the user. Obviously these are conflicting goals but that's one of the aims of the scheduler is to try to sort out these conflicting goals. And of course the last thing here performance on this and I know Jeff is big about talking about the fact that performance itself takes a hit. In other words if we have a scheduler that's trying to implement let's say a nice QT algorithm but it itself takes so long to figure out that QT algorithm it's not very good on that. So we want to make sure that a scheduler makes smart decisions but it doesn't unduly impact the performance of the system on that. Okay oh and obviously the big one one of the biggest things is don't keep people waiting. You can keep silicon waiting over people. Okay now in terms of types of schedulers that are out there there's a whole bunch of them and you kind of get the feeling after a while that it's a case of trying to build a better mouse trap on that. We start off with the simple ones in other words let's just pick something at random. Okay we could certainly do that or another one probably looked at this has anyone looked at I know some of you have but have you looked at the scheduling algorithm in OS 161. Yeah I mean what does it do it says in effect grab the next one off of the queue. Okay and just kind of keep cycling it through essentially schedule does squat nothing on this. Simple it works it's perhaps not very efficient under heavy loads or special circumstances but it at least well it's simple and again on a didactic operating system that's perhaps exactly what the doctor ordered. But let's see if we can't do a little bit better than simply if you will I know nothing let's maybe can we throw maybe a few IQ points at maybe making a better selection about which thread to schedule and in what order on this. So know it all is if we are omniscient we have our swamis had on and we know exactly what is coming up in the future well then in that case we can presumably make a lot better decisions. In other words if I know for sure that thread X is about to block we know I might as well schedule that because remember of one of these if you will OS imperatives something that is going to block on let's say it needs I owe from the disk. Let's get that blocking process started fast for two reasons number one is the blocking itself we started and immediately blocks we can now use the CPU for something else. But the other thing to is the sooner we get the blocking process to get the disk drive circuitry spinning and doing its wizardry the better on that too so if we know that a process is about to block let's start that blocking process ASAP on that. Similarly if we know a particular process it has to run some computations in order to produce let's say a pretty graph or let's say a picture of an angry bird dying on a screen for the purpose of the user. We want to probably run that quickly too because that's something that will in some way impact a user experience. So again the more we know about the future the smarter scheduling decisions we can make the user will be happy etc on this. That's great again assuming that we have our swamis hat on and we have a perfect view of the future on this. Now in practice here what are some of the decisions that's going on here how long is it going to be using the CPU with a block or yield or how long will it wait on here. Again these are all factors that need to be considered with me on this so far. So okay now the problem is can we predict the future. Well we're not swamis but maybe we can at the very least instead of knowing the future for sure make good guesses about the future on this. And this is where let's say just talking about using the past to predict the future kind of you here if you follow like financial investing. Okay past performance is not entirely indicative of future results on that whenever some stockbroker is trying to sell you some financial investing scheme. Well the thing is it's not completely predictive otherwise you know what we would already know what the stock market is going to do next year. And essentially decisions would already have been made but at least past performance does give us some indication as to what's going on we're going to do the same thing here. In other words if a thread blocked a lot in the past there's a good chance that it might block a lot in the future etc on this. So what we're trying to say here is a dumb schedule that knows nothing is easy to implement but let's be a little bit smarter than that. Okay the more we know about the future then the better scheduling decisions we can make. Now unfortunately we don't know the future but we can take guesses about the future and that is we're talking about using the past to predict the future. And let's look at a couple examples of this here multi-level feedback queue again that's essentially a thing where we have well a bunch of queues here. And remember we're going to reward if you will threads that block a lot by kind of keeping them on the high priority queues and vice versa on that. Those that let's say churn through lots of numerical computations we're going to kind of bottom them down in terms of priority on that. And then oh actually the other one is did Jeff called it like the BF scheduler on this and he talked to you guys about that. Okay okay the swirly staircase and then the DNS that is okay all that yes okay which I think that's the next slide on that. Again another attempt at if you will using if you will smart decisions to come up with what's coming up. Now couple people here just in terms of line scheduling by the way this is the sort of thing that you will probably want to know for it like multiple choice questions on the test here. But like Ingo Molnar do you remember the if you will line scheduling wizard and this con is is it I forget is it Austrian or Australian. Okay okay yeah but the the doctor who spent half his life trying to reinvent the mouse trap on here. So rotating staircase which I will not attempt to explain except only superficially on here. We have an example of let's say all these different levels of priority here and Jeff is an example I'm sorry asking is an example. Let's say that we have let's say something that is all the way down at the second to lowest priority schedule and we've got three threads on zero three and seven. Well essentially what's the worst case scenario well you can take the time quanta for each of those three ahead just multiply it out and we get our answer of 15 milliseconds on this. Something like this might show up in maybe one of the short answers where he might ask you let's say to do a little bit of computations or something like that. So questions about going once going twice sold. Okay and I can assure you if Jeff could be here today he would he really does love virtual memory it is a cool topic I will agree with that. So he will at least be in here on Wednesday to kind of reintroduce the next step in the process here. So let's talk a little bit about space versus time multiplexing again you probably encountered this if you took 341 it's very closely analog if you will ally with the concept of if you will spatial versus temporal parallelism. But in essence here time multiplexing again this is the thing about we have this is the classic CPU thing where we have one CPU being chased by a whole bunch of threads and we need to kind of divvy that CPUs up among threads according to what according to time on this. So it's kind of like again what right now I'm speaking but if one of you has a question I have to shut up so that you can communicate. So in essence only one person can be on deck at any one time because if you don't what happens is you get what you can't hear what's going on. Let's actually go back to that analog in just a minute here. OK so CPU scheduling room scheduling again because there was I believe it's distributed in here before and now there's 421 in here today and then who knows what's going to be in here after this. I don't know our history what have you. But the upshot is that we are dividing things up according to time over time here. And this is what we talk about when we're talking about concurrency if you will that multiple things happen over a block of time as distinguished from. If you will space multiplexing this could actually involve things multiple things happening simultaneously. But in order to do that we have to divide it into smaller pieces on this. And again an example of that is CPU scheduling on multi core systems because what's going on here is let's say that I have four CPUs. Well I can kind of multiplex things spatially by running four things simultaneously at an instantaneous point in time. However those four things only get a quarter of the resources on that. An analog to that is again right now I'm speaking to the entire room. If one of you wants to ask a question I have to yield the floor for the entire room. But let's say we could divide this up into let's say several subgroups. And let's say you people do a sub discussion you people do a sub discussion on this. So now we have several sub discussions that are going on simultaneously but at the cost of what you don't get the entire floor to yourself. You only get part of the room with me on the distinction here between temporal versus spatial multiplexing here. So okay other examples here memory management. Now I should say we're talking about low and high granularity here. We're simply talking about like with CPU scheduling the quanta typically are very very teeny tiny in terms of CPUs. As opposed to when we're talking about memory we're talking about if you will much bigger chunks here. Now when I'm talking about memory management in terms of spatial multiplexing a crude way to think about it is your computer has who knows let's say four gigabytes of RAM. And let's say that you're running a whole bunch of processes. Well we know in terms of the CPU okay the CPU let's say let's just say for simplicity sake you have a 15 year old computer that has only one core. Well that CPU can only run one thing at a time hence again time multiplexing. In terms of memory how about that four gigabytes are we talking about giving all four gigabytes to one thread. And then all four gigabytes to another thread and then all four gigabytes to yet another thread. No of course not because you probably pulled up like process manager or whatever it is in Mac. And you can see how much memory is allocated to each thing of a bob. So in other words we multiplex memory in terms of space you get this chunk you get this chunk you get this chunk. And I should say I'm being a little bit sloppy when I say chunk because in terms of like the underlying physical memory it's very often chunk. But again this is what Jeff is going to be talking about in terms of virtualization. It very often appears that it's not chunked that's kind of some of the magic on that. But for now if you think about it in terms of practice like in terms of the underlying physical memory this is actually a very good way of thinking about it. Because let's say Internet Explorer might be let's say given let's say this area of I don't know the first 10 megabytes then who knows mosaic might be given the next 20 megabytes. And then who knows Netscape Navigator might be given the next 30 megabytes because we're trying to play with really old and obsolete web browsers. Questions, comments, complaints, spatial versus temporal multiplexing. Alright memory allocation here. This is kind of from a programmatic viewpoint here. Let's say that my program is running and I need a bunch of memory here. Now actually what goes on let me start at the bottom here and go back or actually start with number two and work back up. You probably know that let's say I need a clutch of memory for I let's say I wanted to clear an array or something like that. I'm going to call the malloc function and malloc is strictly speaking a user level function. It's implemented in library. I don't remember me talking two weeks ago but crudely speaking there are three levels in a computer. There are user level applications. There's library code and then there's kernel. Okay the top two if you will applications and library those are both user level. Alright even though we often think of let's say only the application is being user but the library code is also run in user mode or unprivileged mode. And then the bottom one is if you will the kernel itself. Well malloc is a function that if you will exist in user land and essentially what it does is if I say I need 100 bytes it says here you go. Here's 100 bytes and by the way what else does it say what does it return it returns a. I'm sorry. Yes starting because I need to know where that is right and if you're thinking about this there's this voodoo magic going on in the background. How does it know where to get that address. Well that's actually one of the nice things about how malloc works and this is what Jeff is alluding to here. I know at a lot of universities it's a project of like a software level systems course right malloc. And it's your job to kind of come up with cool algorithms to if you will divide up memory efficiently avoid things like fragmentation and what not. Okay but where does malloc get its memory back to the top one here. I say I want 10 bytes or I want 100 bytes or whatever else malloc is very flexible in that. But if you look underneath the hood and you already have an example in front of you in terms of OS 161 take a look at K malloc. And you don't have to look at all the gory details your eyes will glaze over and your head will drop off if you look over it for more than five minutes. Okay but eventually K malloc will make a call to a sub-subroutine if you will which what does it in user get K SEGs. I forget the what is that oh get get P pages I'm to get okay well what's the one above that. It's okay well anyway I forget okay anyway the upshot is that there is a function that K malloc calls to get memories in slabs if you will. Or in the case of OS 161 it gets it in terms of 4k chunks on that. So and that's something that at the if you will user level okay malloc actually calls down to the operating system. And it uses typically the syscall either S break or M map on that you're going to be implementing S break as part of assignment number three. But even within the kernel you can see there's a kernel analog to S break call again well it eventually boils down to get P pages on this. And that's actually what you're going to be doing as implementing as part of assignment three point one. So but the upshot is how do we actually go about getting memory here. A user level program asked for an essentially a flexible number of bytes from something like malloc and malloc in turn calls down to the operating system. And the operating system makes more voodoo happen but in terms of typically larger chunks that are fixed in size on this. In other words all the operating system call cares about is the principle. Here you go here's a chunk I don't want to be bothered with the details of how you use that. I'm concerned with things with security and enforcement and whatnot. You at the higher levels can fiddle around with if you will 10 bytes 15 bytes or whatever your magic number happens to be. Now remember I promised at the beginning of class that one of the main motivations of this class is why do we have memory managers in the first place. In other words why you know if you think about it assignment three it's going to be a pain to implement. I do promise you will learn a lot and you will actually learn to love it in the end if you're warped like me and a few other people on this. But the thing is that it's it's a pain to implement so why do we go through this. Is it because we're masochists. I guess that's one explanation. But maybe there are some other explanations here. Maybe there's a problem with not doing that. So let's take a look at what might happen without if you will a memory manager on here. In other words let's talk about if you will direct physical memory multiplexing on this. So let's just divide memory in between processes on this. So in other words we've got this huge blotch of memory here. And let's say that I have one process and it's using one piece of memory and I assign another process to another piece of memory and you get the idea here. Very simple on this. And indeed that does work. So in other words we don't need a memory manager. Well it works again as long as there's some caveats that we're going to get into in just a sec here. Problems with this here. Okay we used up this amount and this amount and we're kind of getting to close to the end here. Which already highlights one of our problems. If we're dealing with memory in terms of if you will the direct physical memory. Oh let me digress for just a moment. Physical. What do we mean by physical? You're going to hear the terms physical versus virtual bounced around a lot for essentially the rest of the semester here. So a quickie version is that when we're talking about physical memory we're talking about the stuff in if you will the RAM chips. Okay the SD RAM chips in the dynap. In other words the things you know when you pop a like one of those memory stick thingamabobs into or out of your computer or hot swap it if you will. Okay so that is what we mean by physical memory. And when we're talking about a physical address we're talking about the number that appears on the address bus the memory chips. Okay the address is the memory chips perceive it. Contrast that with virtual memory. Okay roughly put virtual memory is the stuff as it appears if you will to the program or the CPU that's executing the instructions on this. And I'm being hazy because essentially that's one of the features slash bugs of virtual memory. Where is this stuff? It could be in if you will real memory chips but sometimes it could exist elsewhere and sometimes it might not exist at all. So again that's what we mean by virtual memory is something that as it appears to the CPU and a virtual address is the number as it appears on if you will the address bus to the CPU. So again physical address is the address as it appears to a memory chip as opposed to a virtual address that is the address as it appears to the CPU. So in other words if I say store the string foobar and let's say virtual address 1000 all right well it's going to take that virtual address go to the memory management thingamabob and it's going to produce a physical address that might be 2000 and that's where it stores in the actual underlying chips. So clear on this so we're going to be using again these terms about physical versus virtual. So when we're talking about dividing physical memory we're talking about the addresses actually as they appear on the memory chip. So again I've got these three processes in here and I should say oh one other thing when I'm talking about processes and you know what in this case it's probably better to think about it as processes. So we're kind of running out of memory here because well we've used up everything that we already have here which kind of leads us to one of our problems here and that is that if we do run out of memory we now have to do what? We have to kind of in some way maybe stop a program remove it what have you on that. Now if you know on a real operating system what goes on you talk about configuring windows with its actual swap space or linux or what have you. So we know that there's something else that's going on here but the problem is that requires a memory manager. So if we don't have that memory manager if we kind of run out of physical memory we're beginning to have problems on this. So the other thing to you is what happens if they request memory that they do not use. This happens by the way a lot. Well we can try to minimize this because with a memory manager if we run out of memory again this goes back to this diagram right here there's a couple things that we can do. We can on a real system maybe take one of these processes or part of it and shove it out to the disk drive and as far as the computer I'm sorry the program is concerned it doesn't know what hit it. The other thing that one can do is let's say this process request this amount of memory here rather than giving all that memory to it in the RAM chips we're going to say you know what you're allowed to access that amount of memory. With me on this you're allowed to access it but we're not going to allocate it unless and until you actually use it. And that's a neat little trick to kind of try to reduce memory footprint on this too. So again this is some of the advantages that we can do with a memory manager but if we have physical memory multiplexing you know what if a process says give me memory I got to give you memory right away and so we've got some problems here. So far so good. Alright another problem here. Okay we've got our process here and let's say here that let's just say okay let's say this process here goes away here and we want to expand if you will this process here. Okay so see this first process let's say it died or we killed it or what have you anyway it died a miserable death and this other process over here wants some more memory we can now kind of give it that other chunk of memory. That's great what's the problem with this now not contiguous right now we smart programmers can get around this and yes it does work okay you certainly need to sometimes deal with this right but it's a pain. So to the extent possible can we avoid this here okay it complicates process memory layout on this. So to the extent that we can avoid this contiguous get this kind of whatever it is okay we want to avoid that. Alright fragmentation and then take a look at it basically remember fragmentation it's a problem with your disk drive it's a problem with memory it makes things a pain it makes things harder to program it makes things less efficient on this. Alright process memory layout now earlier I had asked remember if we malloc something malloc very nicely returns a pointer to where it is in memory here that's kind of taken care of us of us by the library code here. Well let's actually dig a wee bit deeper here and where do they know where their code and data is located. So let's say that we have a program here and we've got a little bit of an array here and we've got let's say okay where is if you will the code for the executable food on this. Well roughly put this is all decided for us at compile time because if we think about it okay when we're running this program presumably it's already been translated into machine executables on this. So the compiler at some point in the past had to make some decisions about which piece of executable code which piece of data is at what point in memory on this. So that's a decision that's been made for us so presumably we're just going to punt this whole problem to the compiler on this and indeed the compiler can certainly make some smart decisions. You can see okay locate this piece of code here or this piece of memory and if you dig in especially into the assembly code in OS 161 you know the .s files you will see a bunch of declarations hey put this here hey put that there sometimes you need to do that like for example the interrupt handler for OS 161 has to go at a very specific location that is expected by the MIPS hardware. It's just a convention of the fact that we have a MIPS machine. So sometimes we have to tell the compiler that sometimes the compiler can figure it out on its own here. But you know what in issue essence it's something that we really want to make as simple as possible. Let's actually see why we're talking about fragmentation and let's talk about a couple flavors here. First off internal fragmentation okay we're talking about inside existing allocations here. Do you remember back where we were right here? So let's say that we have this right here this allocation here okay well this process asked for and got this huge block of blue memory here. We're kind of assuming that it's using it well let's kind of unassume it at this point and let's just now kind of dig in and say that let's say this process has used maybe this amount of memory and this amount of memory but we've got this big wad in between that is not being used. That's an example of if you will internal fragmentation. There's unused memory but it's within if you will kind of a particular allocation. External fragmentation that would be an example if let's say in this example here right here okay. This well actually in this case it's a poor example because that's the only unallocated segment. But let's just say that where is it? Ah right here okay. Here is an example of external fragmentation. We've got this blue thing here and we've got an unused segment here and we've got an unused chunk over there. Alright and so when another program goes to request if you will the sum total that program has to get if you will two discontinuous pieces on this. So in other words this is if you will unallocated areas that are outside if you will particular allocations. So everyone clear on internal versus external fragmentation. The upshot is that it's fragmented. We don't like it. Alright good example of that okay. Let's say that my program really does need a big contiguous big wad of memory on this. That array might not fit into if you will the largest current free piece of memory even though the total free memory might be much greater than that. This is one of the problems that if you will caused by fragmentation. Alright more problems with this. So again once again limited to the amount of physical memory. We can't push it out to disk. We also can't play tricks like not allocate it until it's actually used on this. We also have problems with if you will contiguousness the fact that yes we can get around it but it is sometimes a pain and it makes programming things like handling huge arrays very difficult on this. And just in terms of fragmentation efficiency the fact that we have to remember if you will manage discontinuous segments it's going to be a pain. So one other thing is until now we talked about things that can be handled if you will as long as programs play nicely and the programmers know in advance kind of what's going on here. Now we're getting into the policing issue here. And we're not going to talk a lot about this today but you want to kind of put this in the back of your brains here. Remember what's one of the main reasons that we need an operating system here and why do we need these levels of protection here? It's to enforce things here. In other words I've got these allocations. Again let's go back to something like here. Let's say that the blue process here is getting a little bit greedy and just decides to munge on the red process. What's preventing it from doing that? Absence some sort of enforcement mechanism essentially absolutely nothing. And this greediness could be caused by either maliciousness or it could be caused by if you will just poor programming a bug if you will. So we're going to have to do something in terms of if you will enforcing things. One way, okay, Jeff has put this on the board here. How about this one for you? A process wants to access a memory location to let's say a store, I don't know, access an integer. But before it does that it checks with the operating system. Can I access memory location 1, 2, 3, 4, 5, 6? Yes, okay. Can I access memory location 1, 2, 3, 4, 5, 7? Yes, okay. 1, 2, 3, 4, 5, 8. Yes. This sounds like a really bad plan. Okay. Extremely inefficient on this. Later on when Jeff talks about virtualization, this is actually some of the problems with traditional virtualization. You'll get into this because sometimes you do have to do byte by byte translation and that's one of the reasons why traditional virtualization can be slow as molasses on this. In general, we don't want to do this. We're going to have to have some sort of better enforcement mechanism. And again, more on that later on here. All right. Now next thing here, we're talking about reclaiming unused memory. And by that, let me, well, we'll talk more about this in a minute here. But by reclaiming, what we're talking about is essentially we've got a bunch of memory that we would just rather use for better things. It's just not being used right now. Well, again, remember back to the diagram showing the processes here. Like if let's say I decide that there is part of a memory, let's say again, where was it again? Ah, there it is. Let's say that the middle part of this blue part we really don't need here so we want to give it back and be nice about it. Well, that's great, but what is that going to do? It's going to lead to yet more fragmentation on this. So again, what we're trying to say here is there's got to be a better mouse trap than the clutch of, if you will, direct physical addressing here. So let's say what do we want here? This is kind of our wish list. This is what we want our memory manager to achieve. So up until now we've been talking about the problems with the model of direct physical access. Now we're going to switch gears and we're going to talk about what might be a better model here. We want a model that first off, if a process needs memory, the operating system should be able to grant memory. Okay? Either statically or dynamically. Okay? Number two, enforce it. Okay? Which is what are the enforcement mechanisms for the operating system, making sure that remember the blue process, if you will, doesn't eat up the red process or vice versa on that. All right? Reclaim and revoke. Let me actually go down to revoke and go up. Grant means, okay, a process, if you will, says I need memory. Revoke means the kernel is saying, you know what, you're done, or in essence we're just going to get rid of a block of memory. Distinguish this from reclaiming. What we're talking about here is, in other words, let's say that you have a process that you haven't used for a while and it's just eating up a lot of space in the RAM chips here. And right now the user needs to go to another website or what have it. In other words, there's a need for memory right here and now here. And we don't want to nuke the other process because we might need it later on. So what the kernel wants to do, we want a method of, if you will, reclaiming that memory, that is the stuff in the RAM chips and use it for something else that's more pressing, but not trashing the underlying data. So clear on the distinction between if you're revoking and reclaiming. Revoking is, let's say when a program is done, either it exits or it has to be killed, as opposed to reclaiming, means you know what, the program isn't necessarily done, we just really need to use this space on the physical RAM chips for something more pressing right now. All right, let's compare this page here to how we might, if you will, multiplex out ACPU. Grant, again, this is when we're scheduling a thread here. Enforcement, the mechanism there, we already talked about that. Remember, I can count on there being a timer interrupt, so I know I'm going to get control. This is the essence of preemptive multitasking. There is no way that a bad process can grab more CPU time, regardless of whether or not it wants to on this. Okay, and revoke, well, the issue about that is when, let's say a thread, let's say, is just done with its time slice and we go on to the next one. Reclaim, there is really no analog to that in terms of CPU multiplexing on this. Questions, comments? Oh, again, with me on this, granting, enforcing, reclaiming, revoking memory. By the way, what do we mean by reclaiming? When I say more on this in just a sec, because this is going to be part of assignment three. If I need to reclaim memory, again, I don't want to trash it. What am I probably going to do with the data that I'd say the other process is using? Exactly, yeah. This is exactly French for swapping, or in some way it's going to be pushed down to some other type of backing store as distinguished from revoking. All right. Oh, one other thing I should say, let me actually not so much digress, but backgress for just a moment. Remember I was saying that there is time multiplexing and there is spatial multiplexing and how are we multiplexing memory? We're dividing it up into smaller chunks here. Exam question, how might we or when did we do time multiplexing of memory? We know it's not a very good idea, but think back earlier. When did we do time multiplexing of memory? Maybe I'm dating myself. I barely remember this. Big honking computers. Do you remember batch jobs, batch scheduling? In essence, that is, if you will, time multiplexing of memory. In other words, one job runs, it gets the entire blooming computer to itself and then it prints out the syntax error. Then you run the next job and it prints out the syntax error for that, etc. But in other words, it gets all of the systems resources at once. As distinguished from currently, we are, if you will, not giving any one program the entire access to memory on this. So I just thought I'd digress on this. All right. Just spaces. Memory management extraction here. Now, in other words, this is our ideal world. This is how we want things to appear to the user on this. So remember by plentiful what we're talking about is if we have, let's say, 4 gigabytes of memory, we want it to appear to the user that user has 4 gigabytes of memory. As a matter of fact, we want Internet Explorer to have 4 gigabytes of memory. We want, who knows, your favorite torrent application to have 4 gigabytes of memory. We want, who knows, Spotify. All of them have 4 gigabytes of memory on this. Now, how are we going to do this with smoke and mirrors? Well, essentially, that's what a virtual memory manager does here. Contiguous. Why do we want it to be contiguous here? Remember we were talking earlier in terms of the problems with this contiguous memory. We can get around it. You're smart programmers, but you know what? We'd rather not. It's a pain. We want it that we can, if you will, allow user-level programmers to make the assumption that the memory that you get as a user is contiguous, it's going to make things a lot easier. Plus the other thing, too, is if you think about it, I've glossed over something earlier. Remember when we said that we load in, let's say, who knows, Firefox at one area and then some other program, remember the red and blue processes on that? I said, well, how do we know where that is? There has to make some decisions on this. Well, we're assuming that the compiler knows where this program is loaded into memory. In other words, we're assuming that the compiler knows that, let's say, the red process gets loaded into low memory and the blue process gets loaded into middle memory on this. That might not be the case. Or if it is the case, we're kind of straight-jacketing ourselves going forward on this. So in other words, if we can allow the user to make the assumption that you know what, you always, if you will, get to start things, if you will, you've got at the same place and if you will, in a big block of memory, it's going to make life a lot easier for you on that. Now, one thing here, you're thinking, hey, wait a minute, what about these things called dynamic libraries? It's a corner case. I'm not going to get into that right now, just suffice to say that sometimes you can't get around the fact that you need to relocate things on here, but again, to the extent possible, to the extent that we can avoid dynamic relocation, it's going to make things go a lot easier. You've probably all heard about dill hell and windows or if you just like the whole problem with dynalinks. This is part of the issue here, that we're moving things around in memory. We want to avoid that if at all possible. So plentiful, contiguous, uniform. In other words, it always looks the same. And private. This is the other thing too, because think about it. I said that you guys as application programmers get to make the assumption that, let's say, your executable segment always begins at, who knows, memory address 10 million or whatever it is. Well, that's great. So I as, again, Internet Explorer, get to run things at 10 million on here. Or you at Safari also gets to run, what's the problem here? You've got all these user processes and all of their executable, a.k.a. text segments, begin at the same address here. Problem? Well, actually not. That's, again, part of the magic of virtual memory. In other words, within each process, they all get essentially clones of the address space. Think about it, you're writing fork right now. And remember, part of it is you need to duplicate the address space on this. Well, now we have a parent and a child. And remember, we're talking about they're running essentially clones of the same program here, but they're different processes, if you will. How is that possible? Well, they both have what appears to each process, both the parent and the child, the same program running in the same apparent address. Key word here is apparent. And Jeff's going to be getting into the details later on. It appears to the program that it appears at the same location and memory, but actually it is not in the same physical location in the memory. And that's where the virtual memory manager does its translation behind the back. And that's why something like fork works. It appears to the user that, if you will, things have been cloned. Well, again, the matrix has been cloned. But underneath that, if you will, there is some magic going on. So that's also why, if you think about it like, if you will, the kernel stacks are not cloned when you're writing fork. So that's kind of some of the, if you will, behind the guts what's going on. Make sense on this? Okay. So goals here, what are we looking at here? We want something that is, essentially it appears like we get access to all of memory and we get access, well, to all of memory, and it's continuous. And it's the same type. It's the same location, in other words. And also, again, kind of, if you will, uniform and private are duels of each other. The fact that it's private means, if you will, I can get away with having, okay, them all start, let's say, their code segments at the same address because they're private to each process. And vice versa. If it's uniform, it'd better be private. Okay. I can't have one without the other. So I hit two birds with one stone. Make sense? Yes, no. I see heads bobbing. Okay. Couple thumbs up. All right. So here we go here. Classic example. Okay. I've got the address space, the whole 6432 bits here. And I've got the code segment. Oh. Code is sometimes called text for whatever reason you will hear that referred to in this class. The text segment is the code segment. Text is not ASCII. It's like the executable code. So don't ask me. Don't blame me. Anyway. So we've got a code segment. We've got a heat segment. And we've got, let's say, we've got three stacks because, if you will, let's say we have three threads running in this process here. And take a look at this. We have a very, very happy process. I get the entire four gigabytes. And it's the entire shmaha. And I get the same thing every time here. Really the only fly in the ointment here is sometimes where I have to load in my dynamic libraries. But again, we're just going to modulo that for this class. Questions? Okay. Layout here. Okay. Take a look at this here. I always get to put my code and static variables. And again, I should say this. The specific numbers here are kind of arbitrary. The point is that the expectation remains the same here. So again, here we go. Whoops. Okay. Code. Again, more about this later on. The heap grows up. The stack grows down here, et cetera, here. But the point is that we always have these same expectations. Like in the case of OS 161, you probably have noticed that the stack starts at 7ffff and grows down. In the case of the executable, it's 400,000 for the text segment and grows up. Now, in terms of where do we get these numbers? In other words, where do I pull, let's say, 400,000 or whatever else it is? This is something that we've glossed over. And again, in the case of OS 161, remember you're given the stuff that loads in the init process. But if you want to know some of the details, look into what's going in in, like, run program and load elf here. It's kind of spelled out by, if you will, the UNIX ELF convention and some parameters that are on the file that's loaded in from disk here. But in essence, what we have here is it's numbers that are specified. Put me in 400,000. Put me at 7ff and loading down or whatever else it is. Now, take a look at this. Why not load the code at zero here? In the abstract, there really is no reason. In other words, I could very well say, you know, let's begin our text segment at location zero and go right up. Again, this is, if you will, assuming a way that there isn't some hardware problem, like some chips, let's say, they have their interrupt vectors down at location zero. But aside from that, if you will, corner case here, there's nothing in the abstract that says I can't put it at zero here. There is a practical convention and a practical reason of why we might not want to do this here. And that is, if you will, good old null pointers. Because if you think about it, we've all done it null pointer exception. Or if you are on Timberlake segmentation fault here. Because you have a pointer, you forgot to initialize it. It's defaulted to zero here. And when you try to dereference the pointer, you are trying to access memory location zilch. So we're deliberately going to say that location zero is not allowed to a process. Why? Because we want to generate an error. Because it is ironically a common programming mistake on this. If we didn't generate an error, the user would get, in essence, a false positive and the user would be getting garbage data back or worse yet, munging on existing good data on this. So we're actually going to say, you know what, we're going to leave the area at location zero and maybe a little bit above that as empty, and by empty we mean, if you will, not allowed, it's not part of the user's address space. And again, when you get into assignment 3.2, writing page tables, you'll see exactly how this works. Oh, what fun it is for you people to be the ones to generate the segmentation fault and kill off the bad process. You're on the other side of the equation, rather than seeing it. So Jeff is going to be running garbage programs at you and it's your job to catch the seg fault and kill it because that's actually what the test will be expecting on this. Okay, ah, core dumped segmentation fault. Questions? All righty. Thanks for coming people. More on virtual memory next time. Again, checkpoint for assignment 2. Try to be finishing up for like now.