 Hi. Welcome back. So today, we are going to begin the process of wrapping up our unit on threads and multiplexing and abstracting the CPU. So at this point, we've talked about how we're going to do this. We've talked about some of the mechanisms and the abstractions that are required in order to allow the OS to manage the processor. And now we're going to talk about spend a couple of lectures talking about policies for how to do that. So that will be, essentially, take us through this week. And Friday is one of my favorite lectures of the semester, because I get to swear in class for a reason. I get to turn off that filter briefly, which is usually pretty effective. So today, we'll finish up talking about thread-state transitions, and then we'll talk about schedule. So what are the goals of scheduling? What is the OS trying to accomplish? And some of your expectations as computer users, as far as interactive scheduling. And then we'll start off talking about scheduling by discussing some really simple sort of dumb scheduling algorithms that really aren't super useful, except A, they might be things to implement for assignment two, because they're pretty easy. And B, they're also useful comparison points when we discuss other schedules. OK. So let's see, I don't think there's much to announce. Assignment two is in. Please keep working on assignment two. It's due in two and a half weeks. All right, any questions? Of course, logistics stuff. I am, it's possible that we'll make some changes to the office hours scheduled this week. I'm going to try to give the TAs some time to work through the grading backlog. I know that we have quite a few questions left to grade, but we're working on it. And we'll try to get through it by the end of this week. That was my goal, was to get totally caught up. So hopefully by the end of this week, we will have your assignment two design docs graded as well as everything else. All right, cool. OK, so let's finish up by talking about thread states. This is something that we sort of skimmed over at the end. So when we talk about scheduling, we want to talk, we're going to use some terminology to describe the state that a thread is in. And so one state a thread can be in, that probably the simplest one is running. That means it's been scheduled on a CPU core, and it's currently executing instructions on that core. A thread can also be in the ready state. So when the thread is ready, it means that there's nothing blocking it from making forward progress. It can make forward progress. It's just that it's actually not currently running on a CPU. So normally this is because the operating system scheduler has made a decision that at this point in time it's better to devote the CPU resources to something else. So we use these three pieces of terminology sort of interchangeably. We've heard of threads as waiting, blocked, or sleepy. What this means is the thread can't make forward progress. It's waiting for something to happen. So it made some sort of, made a system call or it's blocked waiting for a memory page to be brought in or something like this where it literally cannot execute the next instruction. There's some side effect from the previous instruction that needs to happen before the thread can move on. Okay, so these are our primary thread states. And now that you guys have done assignment one, you're probably a little more familiar with how at least OS 161 has data structures to maintain threads in one of these three states. In the last state normally we talked about the thread waiting for something to happen. So that's being on a wake queue or a sleep queue. There's some event or some key that the thread is waiting on that is gonna signal that the event that it's waiting for has happened and it can continue, right? Okay, so thread state transitions. Let's talk about how these happen. So when would a thread go from the running state to the ready state? When does this happen? Or what event does this correspond to? Yeah, okay, so remember interrupts are always required to move threads between these states, right? I have to have an interrupt to have a context switch. But if the thread goes from being running to being ready, it's still ready to run, but it's not running. What has happened? Yeah. So time interrupts take place, the kernel ran, and what did the kernel decide to do? Yeah. Yeah, so this, I'm having a hard time talking today. This is referred to as the thread being descheduled, right, the thread was running. It did not block, it didn't do anything to cause it to go to sleep. There was no reason that it was stopped. It could have continued executing instructions, but the kernel decided, nah, we've had enough time, right? No, I just want to, I think there's a little bit of confusion, I just want to make this distinction. So when we talk about this, we're normally talking about thread states not in and out of the kernel. So the fact that the kernel woke up and processed a timer interrupt and decided to do this, we think about transitions between two user threads, right? But it's a good thing to keep in mind that the kernel always has to run in order for this stuff to happen, right? That's the only way that a thread moves between thread states is that the kernel wakes up and does some work, right? Okay, what about from the running to the waiting state? What could cause this to happen? Yeah. Yeah, so it made a system call, right? So the syscall instruction can frequently cause this to happen, right? It means that I'm waiting for the syscall to complete, right? What else could trigger this? Yeah. Okay, so inside the kernel, yeah, absolutely. So the kernel might call yield, right? As part of implementing a lock, right? And you could certainly have the equivalent in user states, right? So it's waiting for something to happen. So that's a good point. This could be something in user space, if it's in the user thread library or something in kernel space. It could have also hit an exception. It might have used a memory address that the kernel has some work to do before it's allowed to use, things like this, right? But a good example of this is a blocking system call, right? What about waiting to ready? How does this happen? What's that? Yeah. Okay, so has this thread been scheduled? If it was scheduled, what state would it be in? The running state. It hasn't been scheduled. It's just now ready to run again. What does that indicate? Yeah. Yeah, whatever it was waiting for happened. So whatever my thread was blocked on, whether it was for some data to come back from the disk or whether it was for a network packet to arrive or whatever, that thing happened. And now the thread can continue, okay? Now the thread has not been scheduled yet. In a lot of cases, and I think this is true in your kernel as well, threads don't usually move directly from the waiting state to the running state, right? They get put on the ready state first and the scheduler gets to make a decision now about who gets to run, right? So when the scheduler runs, the scheduler's always choosing between the threads that are ready, right? Threads that are waiting can't be run. Threads that are running are already running, right? So I'm looking at the ready queue and I'm trying to figure out should any of these threads be moved onto a CPU core in place of one of the threads that's already run, right? Okay, ready to running. Now what is this? This is the answer from last time. Yeah, so this is a thread that's scheduled, right? Okay, running to terminated. How does this happen? Yeah, I call it exit, right? That's the way threads go away, right? Call it exit or I hit some sort of fatal exception that caused the kernel to implement exit on my behalf, right? I've done something that I can't proceed forward and so the thread stops, right? Yeah, so from the kernel's perspective, exit, it just means the thread is not going to continue to run on the CPU core. That could happen for a couple of reasons. One reason it could happen is the thread actually called exit, right? So I'm done. I don't have any more work to do, whatever, right? The application shutting down, who knows? The other thing that could happen is there could be some sort of exception that took place, right? I could have tried to do something dumb, like use a privilege instruction. Some cases that might actually terminate the entire process as well, just for fun, but yeah, so, but normally threads exit because they're finished, right? They don't have any more work to do and sometimes the applications in the process are shutting down, but not always, right? You know, you might, you know, if you imagine Firefox having a thread per tab, which I'm not sure is actually how it's done, but if you close the tab, then that thread's no longer needed, yeah. Yeah, okay, so the question is what state, let's say I'm the thread that's running and a time runner up takes place and the kernel starts to run. What state is that thread in? We don't know, right? You can almost say it's still running, right? Because the kernel has to make a decision about what to do at that point, right? In some cases, on a lot of time run-ups, the kernel may say, you know what? I'm fine, you know? Like there's nothing to do here. The thread hasn't run long enough yet. There's no new threads that have woken up that need to be scheduled. I'm just gonna leave things as they are. So it's possible that I can have a sort of a null transition where the thread is running. The kernel runs, maybe even the scheduler runs, right? But nothing changes. The thread that was running keeps running and eventually a context switch back out into that thread and off it goes. Does that make sense? Oh yeah, okay. So now we're to this mysterious distinction between kernel threads and user threads, right? And this is something that was sort of covered in one of the lectures that I was out of town for. So my disembodied 2014 self tried to explain this to you, but maybe my actual 2015 self will be better at it. So this is an interesting question, right? So the question is when a thread is running in a user space and a time interrupt takes place, clearly the kernel starts to run, right? We know that. We know that the CPU jumps to a particular point. I saved some state and there is some thread that's now running, okay? There's two ways to think about this. The first way to think about it is that the user thread that was running has now transitioned into the kernel, right? So that same thread is now running kernel code, okay? It's not a terrible way to think about it. In some ways it's kind of equivalent to making a function call, right? I'm in function foo, I call function bar, bar is running, foo is still around, right? Foo is waiting for bar to return so foo can go on its way, right? Clearly the calling semantics are very different, right? I mean, most of the time function calls will divide up the registers between the caller and the callee. In this case, the kernel sort of clears all the registers or almost all of them so it can use them while it's running. Okay, so that's one way to think about it and that's not a terrible way to think about it, okay? The only place that falls down is the fact that the kernel frequently also has its own threads that do not correspond to a user process, right? Those threads are doing things that are very similar to what a user process would be doing. They're doing stuff in the background, right? They may be going through and writing out dirty pages to disk. They may be involved in managing devices. So there are usually a pool of kernel threads that do not correspond to a user program, right? So there's no equivalent user thread. Those kernel threads never go, they never transition into user space or come back, right? They purely exist to do kernel work, right? But it's not a terrible analogy to think of the thread that made a system call or was interrupted as now having transitioned into the kernel, right? So you could think of that thread as being inside. Does that answer your question? Yeah, it's kind of a mysterious thing, right? If you don't like thinking about it that way, you can think of the fact that the kernel starts to run and this thread is in this indeterminate state until the kernel decides what to do, right? It's a great question. Any other questions about that? Very nice question. Meta questions. All right. Yeah, so okay, we've got this. Okay, so now let's talk about scheduling, right? So we'll do some of the what, where, why, when, how of scheduling, who is not all that interesting. So you guys are probably to the point now where you can guess what the answer to this is, but what is thread scheduling? What is it, you know, if I asked this question on an exam, what would you write down? Yeah. Yeah, so you can imagine that there's some work that the system is trying to do, right? You've used the computer in a system way, a particular way, right, a deterministic way. That results in the threads on your computer having access to the CPU at certain times and not having access to the CPU at certain times. Some of that is the result of doing things like making blocking system calls, right? So when I do that, I can't keep running. So I know that there's another thread that has to run. But in other times, there are multiple threads that are ready to run, more threads that are ready to run than I have available cores. And then choosing in what order those threads are gonna run for how long, that's thread scheduling. Okay, so it's the, I think I have a definition. And you can think of it in an iterative fashion, right? Scheduling is repeatedly choosing the next thread to run on the CPU, right? Or potentially more accurately, it's repeatedly a timer interrupts making a decision of, first of all, whether or not I need to switch threads and if so, which thread should get to run, okay? And this could be happening on multiple CPU cores simultaneously, right? But you can think of it as just really happening on one core, right? Although there's some fun, there's some fun messy sort of gooey design stuff that you get to do when you start thinking about multi-core scheduling, okay? Okay, so why does the OS have to do this? Why is there this continuous ongoing process? And again, we'll talk on Friday about a relatively recent attempt to modernize the Linux schedule. The Linux scheduler has been rewritten in the last five years, okay? But this is not over, this is not a solved problem, but why do we keep working on this? Yeah, so I mean, first of all, I have to, right? When I have more, if the number of cores that I have is always greater than the number of threads that are ready to run, then there really isn't much of a scheduling task to perform, okay? Now, you can get into these weird situations where small groups of cores share higher level caches and so it might be advantageous to put certain threads on certain cores so they can be closer to other threads, but who cares? Don't worry about that stuff, right? In general, it's easy, right? If I have more cores than I have threads ready to run, I'm done, right? Everyone gets to run, everybody's happy, right? But the other reason we do this, of course, is because it's our job, right? You're the kernel. This is a resource that you need to multiplex, and so your job is to try to make the best use of it. Now, one of the reasons scheduling is so interesting is because the best means a lot of different things to a lot of different applications, okay? And one of the things that's gonna drive our discussion on Friday is this idea that there's this tension within the OS community between the needs of scheduling for server class systems and the needs of scheduling for interactive systems, right? Like the ones that most people use. And that sort of that tension sort of drives some of the development that we'll look at on Friday. Little bit of review, when does the kernel have the opportunity to make scheduling decisions? When does the scheduler have the chance to run? What's that? Timer interrupts, right? Or when I, okay, sorry, I was preempted by my own slides. So if a thread voluntarily calls yield, clearly I have a chance to run, okay? This doesn't happen that often. Most of the time, what happens is the timer interrupts, right? So we're not even on the slide. Writing is sort of missing, I'll have to fix this. So here are some opportunities, right? You know these, right? This is when the kernel gets control, right? The kernel gets control when I voluntarily give up the CPU. The kernel gets control when I ask the kernel to do something because now the kernel is running. The kernel gets control when a thread exits because now there's available core. And because exit is itself a system call, that the kernel has to handle. And finally, number four, right? So number four, we implement using timer interrupts, okay? And number four, the inclusion of number four on this list is what makes a particular scheduling policy preemptive as opposed to cooperative. If all I had was the top three, I'd have cooperative thread scheduling. I'm relying on threads to voluntarily give up the CPU. Once I have number four implemented through timer interrupts, I am capable of wrenching the CPU out of their clenched little fists, right? And forcibly giving it away to somebody else who needs, right? Yeah, what's that? Why would a thread yield? Ooh, good question. Why would a thread yield? Yeah, what's that? Yeah, so I will accept that answer. Threads yield because they want to cooperate with each other, right? That's the only reason to call it yield. Threads yield because the person who programmed the application has decided that this would be a good point to see if anything else needs to be done, right? So in general, you can think of yield as just a programming tool, okay? It's not necessarily a great one, but the threads call yield because the person who wrote the program has decided this would be a good place to see if somebody else has work to do, right? That's a good question. Oh, look at that. I should have looked at the slides. There we go, there's the answer to your question. You guys have the slides now online. You shouldn't ask questions that are answered on the next slide. You guys are trying to mess with me now. I knew this was gonna happen. I'm not putting the slides up before class anymore. Leads to stuff like this. Yeah, so there we go. That's what I just said, right? And yeah, yield is an inherently cooperative permit. Yeah, could a thread decide which thread wants to run after it? I'm assuming if you implemented your own sort of user space threading library, then sure, right? If you're trying to tell the kernel what to do, I don't think so, right? That would probably not be a, not necessarily be something that you wouldn't be able to do, I suspect that there's some OS design out there that has explored this feature, but I think the kernel would only take that as a hint. It would never take that as a command, right? Because I'm the kernel. I don't take orders from applications, right? I'm in charge. I told them what to do, not the other way around. Okay, so how do I, so the final question is sort of how do I schedule threads? Any ideas? Anybody have great new algorithms? Yeah, so there's two separate questions here, right? So we know the mechanism, right? We know how to do this. This is just, take this, you know, context switching threads off the CPU. Scheduling is now a policy issue. And this is a nice example of a nice split that we look at as a design principle in this class, which is building systems that cleanly separate policy from mechanism, right? So now at this point, we have the mechanisms that we need to implement scheduling, so now we can have fun talking about the policies without worrying about whether or not we can get these things to work. We know that we can implement any scheduling policy that we want, right? Because we have the mechanisms that are required, okay? And yeah, we switched between threads, but before in a context switch, we probably need to maintain some state in the kernel about which threads are ready to run, which threads cannot be run because they're waiting for something to happen, and of course, which threads are running and which corridors are scheduled, right? And that's what we're gonna talk about this week, is this decision of how to choose what to run, okay? But let's just do a fun exercise looking at policy first mechanism, because this is an important distinction for you guys to understand as software developers, okay? So, for each one of these, tell me policy or mechanism, deciding what thread to run, is that a policy or a mechanism? Oh, a policy. A policy, all right, good. How about a context switch? Mechanism, okay? Maintaining these queues that are used by the schedule and algorithm. Mechanism, right? There's no policy embedded in the queue. The queue is set up to support the policy, right? It's set up by the policy, it doesn't dictate the policy, right? What if I try to give preference to interactive work? That's a policy, right? I'm trying to get a certain thing to happen. Using timer interrupts to stop running threads? Mechanism, right? Choosing a thread to run at random, that's an example of a policy. Okay, good. So, scheduling is a fun thing to talk about because thread scheduling, and this is something that you guys want, you can certainly experiment with your own system. And this might be a fun thing to try, right? You guys might enjoy, for example, fiddling with the scheduling quantum on OS 161, see how that affects performance of various things, particularly your ability to interact with the system. But scheduling is really pretty important, okay? When you have a system that's scheduled well, so there's, and I forgot about one of the most important reasons for this, right? Which is that getting access to any resource on the machine requires running, right? There's no way for a thread to use anything on the system if it can't execute instructions, right? So, essentially, every other part of the system is sort of mediated through the CPU, right? For example, the network connection may be totally and utterly unused, okay? Nobody's using the network. But if I have an application that wants to use the network, it cannot get access to it unless it gets a chance to run. So if it's sitting there descheduled, it will never get a chance to use the network even if that resource is totally, totally underutilized, right? I have to give it a chance to run so it can tell me what else it wants to do, right? So, essentially, any other resource that the system, you know, obviously things like memory, I have to actually be running to use other system resources I need to be running so I can issue the instructions necessary to tell the kernel what to do. And when you have a good thread schedule, it can really make a modestly powered system seem to perform really well, right? Depending on your definition to perform it. And this is something that we'll come back to because it's a tricky question, right? If you're a user and you have, you know, a good thread schedule or, you know, the system feels very responsive, right? It feels like you can interact with it. It feels like it's, you know, responding to what you want to do, your typing and things are appearing and there's, you know, it's a, what you guys would consider to be a usable system. If you have a bad thread schedule or you can have a really powerful machine down there, but to you it's gonna feel terrible, right? It's gonna feel, and I'm sure this has happened to you, right? I mean you guys, and this isn't always caused by scheduling but I'm sure you guys have experiences where you've been using your brand new super powerful, you know, four core machine and it's like you're typing into a Firefox text box and it's laggy and you're thinking like, why? You know, how on earth is this happening? I've got 32 gigabytes of memory. How can that not render a text box to the point where, you know, so, and again, this is usually not caused by scheduling, it's caused by other problems but that's the type of behavior you can see when you have bad schedule. All right, so in order for us to really appreciate scheduling and what scheduling is trying to do, I wanna talk about some of the expectations that we have of our machines, right? What do we expect our computers to be able to do? And I've broken this down into a couple of different categories, right? So the first one is for spawn, which you can sort of map to click. The second one is continue and this is sort of an active process of watching something that we expect to unfold smoothly. The third one is finish, right? Complete, get something done, right? Over a long time frame. So let me talk about each one of these in detail, right? So to some degree responsiveness really boils down to your computer being able to do whatever it is you thought it was supposed to do within a reasonable period of time. So this can be a variety of different things, right? And the important thing to keep in mind is that it's not necessarily that the computer finished what you wanted it to do, but it did something that indicated to you that it understood and it's in the process of doing, right? So what's some examples from, like using a shell? You guys are now using a shell on a regular basis. So it's an example of responsiveness from a shell. What's the simplest one? Yeah, what's that? Oh, that's terrible, yeah. Okay, so blinking cursor, yeah, yeah. You guys haven't disabled that yet? I thought I'd disabled that in your VM for you just to save you all that terrible. You can find these great web pages. It's like blinking cursors, like the Chinese water torture of computers, right? I don't know, I turned that off on all my machines because I find it really annoying. But yeah, I mean, the blinking cursor is at least some sort of signal that the machine is there ready to respond. It's claiming it's ready. It's like, I'm so ready that I'm blinking, right? You know, I have all this extra cycles. I'm gonna use them to blink the cursor, right? But they're waiting for you as soon as you type something. Now you have machines that stop blinking the cursor after a few minutes. So I think it's even weirder, right? Because if you were blinking, now you're not blinking. What do you want me to think? You're totally frozen, right? Like, what just happened? It's very odd. Anyway, sorry, you just got my blinking thing going. Okay, so another example. What's the simplest example? What's that? Too big, message. Break it down, message, smaller piece of a message. Yeah. What's that? No, shell. Your shell is a progress bar? Wow, it's fancy. Yeah. How about when you type a character, right? Shouldn't that character appear on the screen? That's not magic, guys, right? There's actually code that runs to get that to happen, right? You may not realize that, but there's actually like some piece of computer code inside your computer that's like, oh, this key code from the computer and now I'm gonna draw, I'm gonna grab the font file or whatever. I mean, clearly it's a little simpler than that, right? But anyway, like that actually takes, there's some cycles involved in just rendering a character. But if your character took like a second to render, would that, I mean, how many people have ever tried to use a machine over like a really slow SSH link or really slow terminal link, right? I mean, it's mind-bogglingly hard, right? Because you're typing and it's kind of like, oh, you know, and you realize you mis-typed something, you try to backspace, but you can't figure out how many backspaces you did pretty soon, like it's a mess, right? So yeah, just drawing the character, right? What else? So sometimes your shell will like run a command that will take a little while, like let's say you're doing a get push or something like that. How do you know that's actually taking place? You type the command, you hit enter, then what happens? Okay? Yeah, I might output something which is nice, but what if the command doesn't output anything? Do you know that it's running? Can you tell? Can you tell that Bash has started to respond to your command? How do you know? Can you tell the difference between typing a command and forgetting to hit return and typing a command and hitting return and the shell is starting to run it? Yeah, like pushes up the thing a little bit, right? I mean, that's your sign that Bash has received your command and is in the process of doing your bidding, right? If the cursor's over there at the right, then you didn't finish, right? So there are all these little subtle signs that we really rely on as computer users to tell us what to do, and that's really important because our computers are fundamentally really responsive objects, right? Like we expect to interact with them. That's what makes them different from television, at least someone, right? So yeah, so, and you know, you can think of lots of different examples, right? And good tools that you guys use are really good about telling you that something's happened, right? Giving you little hints and indications that something is taking place, right? That it's responding to you, you know, again, imagine if your web browser, you hit return and it just froze entirely, right? And then at some later point, flomp, the whole webpage displayed, right? No progress bars, no spinner, nothing, just flomp, right? But you'd have no idea, like is the webpage down? Is my internet connection up? You know, like we rely on these little things to let us know that something's happened, right? Okay, so the other expectation we have that I think is pretty important now that computers have sort of started to converge with television, sadly, is continuity, right? We expect things to keep happening. And a lot of these continuous tasks that we expect to keep happening don't occupy the computer fully, right? They don't require your computer's full attention all the time, right? So what's an example of something like this? When do you guys feel like you're watching your computer? You're watching the lecture videos online, right? So continuity involves this active waiting, right? Well, you're not really waiting for anything to take place, but there's a process that's going on that you're aware of proceeding at a reasonable pace, right? And you know, so here's blinking cursor, right? There it is. I knew this was in the slide somewhere, right? I don't know what you're waiting for when you watch the blinking cursor, right? But again, if you were sitting there watching the cursor and it was like, blank, blank, blank, blank, blank, blank, blank, blank. He'd be like, what is going on with my computer, right? Like you'd fire up top and try to figure out what was going on. So the blinking cursor to work really relies on like, you know, being rhythmic. If it's not rhythmic, it's weird, right? Someone should design that just to mess with people, you know? Like a weird blinking cursor. Time is going by at different weights, you know? It's kind of confusing. But this is the big thing, right? Playing music or movies is a lot of what we do with our computers today. And this really relies on this heavily, right? If you, if you, you know, again, writing plain music is not a really, really high CPU load task for your computers these days, a lot of the sound cards have built-in MP3 and decoders. So there's really not even much to do. But the CPU does have to periodically keep sending the sound card data. If it forgets to do that for a long enough period of time, you notice, right? Because the sound stops, right? Same thing with video. And you know, all the web animation stuff that you block, right? The final thing that I think some of us are, and this is probably of all the things that we're aware of. I mean, I think responsiveness, we're like really innately aware of, although we don't really realize it. Continuity we're really actively aware of because we realize that's a lot of what we spend our time doing on the internet, sadly. But completion is one of these weird things. I'm not sure most of us really are even aware of it. So your computer is periodically doing long-term tasks that start and complete in the background. Your computer relies on them to complete in order to work properly, but you don't really have any ideas as going on. You're just not aware of it. You'd be aware of it if it stopped happening, but you're not aware of it when it's going on. To some degree, you're passively waiting, but I would argue sometimes, again, you're not even really conscious of the stuff happening. And these are normally not user-initiated. So who can come up with an example of this kind of background task? There's some canonical ones, yeah. Disk defragmentation, so that's normally, well okay, so if that's going on constantly, maybe there's some systems now that are constantly defragmenting the disk just little by little in the background, then yeah, that would fall into that category, yeah. Virus scanning, sadly terrible buggy virus scanners you guys run that are, those you're probably aware of because it's using like 50% of the CPU all the time, yeah. Yeah, so to update checking, right? I mean, you'd probably get a little weirded out if Firefox had gone like two weeks and hadn't updated to like major version 4,022, right? So yeah, backup is another one, file indexing. Most of you guys now use tools like Spotlight or whatever Microsoft replaced the dog with. You guys use these tools to find things on your computer. Those indexes aren't built by magic, right? They happen in the background, you're not aware of it going on, but if it stopped, if it stopped happening, if it stopped completing, you'd be sad because there'd be files on your computer that the little dog would never find, right? And it would be sad too because it was always really disappointing when it didn't find it, what's sad. So a lot of applications combine these in sort of continuous ways as well. So this is not, you know, trying to produce an application taxonomy here is really not the right way to go. We need to think of all of these things as happening, right? So a music player, you click to start the track, right? You expect it to indicate, hey, I'm playing a new track. Obviously it's playing the track and then it's probably updating album artwork in the background or indexing your files or making predictions about what you want to hear next. It's a variety of different things that are happening as well, right? Same thing with the web browser, right? So, you know, again, most applications merge all these three things together, okay? So you can probably start to see that these expectations, all three of them leave to sort of different scheduling goals, right? On some level, scheduling is about trying to optimally allocate resources, okay? But you can keep saying that over and over again without what, while refusing to define what you mean by optimal, right? And you're not really saying much because clearly that's a good idea, but what's good about it, right? So, but let's go through the different requirements, right? So if I'm trying to optimize for responsiveness, that involves being ready sort of at any moment to just stop everything and do something quickly, right? Because the user clicked, right? Quick, right? Race to the site of the click and deal with it, right? That's one type of expectation you guys have and that's one way that's the direction that scheduling algorithms get pulled, okay? Responsiveness, so responsiveness and continuity both involve deadlines, right? Now, keep in mind, sorry, not responsiveness and continuity, oh, okay, sorry, that's true. Responsiveness and continuity, responsiveness and deadlines are unpredictable, right? You set them. As soon as you click on that button, there's a little timer that's running in your head, right? You don't know it's there. Sometimes if you're really quiet, you can hear it. Anyway, so that little timer is going and that's the timer at which you have decided that this computer is not fast enough for you anymore, right? Because it hasn't painted the screen, okay? So as soon as you click on something that's going, but the OS has no idea that that was about to happen. It's like, oh my gosh, right? Panic, there's an emergency, you know, there's a little timer running, okay? Now, keep in mind, that timer is like really long to the OS, like millennia go by, right? Wars are fought, you know, dictators come and go and your little timer's still going and the OS has plenty of time to get this done, okay? But still, like that happens. And then you also have these continuity things. So continuity are predictable deadlines. The OS knows once you start playing that music file, I need to deliver audio to the sound card on this schedule, right? Every, you know, this number of ticks, the sound card needs to get some more data or there's a buffer in the sound card I have to monitor and I know I have to write data to it at a particular rate. So I might even have some slack in that schedule or maybe I fill up the buffer at the beginning, a little drain a little bit if I need to do some other things. But I know, you know, as long as this music clip continues to play, as long as this video continues to play, I need to do a particular task at a regular interval repeatedly, okay? And I can't say, oh, well, I'm gonna put a hundred of those tasks off for later because you perceive that as the music stopping or skipping or the video going down to a lower resolution or whatever. Now, if that wasn't hard enough, balancing, you know, the sudden interactive deadlines with the responsiveness, the continuity-oriented deadlines, now I've got this throughput thing, right? Where I'm trying to run these background tasks, a lot of times those background tasks need a lot of system resources and I want them to complete in a timely fashion. And this starts to be about resource allocation and making as much of the machine useful to these tasks as possible. How many people have ever walked up to their machine and for a minute, it's sort of a little bit groggy, right? Has anyone ever caught the machine in that state or it's like you mouse over and for a minute, it's kind of like, you know, you kind of, like, you're like, oh, it's waking up, right? It's not waking up, right? It was asleep the whole time. It was, sorry, it was awake the whole time. It was doing something else. You caught it in the act, right? It was like, I was just rearranging the whole disk. I thought you were gonna be out at lunch for longer. I thought I had enough time to finish this, right? But suddenly you come back and you start poking buttons and I've got to, like, stop all that stuff and start responding to you, right? So that's a symptom of the conflict between these types. Okay? Overall though, particularly on interactive systems, deadlines are king because you guys notice deadlines. Remember, you're not even that aware of a lot of the background work that your computer is doing. But you guys notice when the computer is not responsive, you notice when the video stalls. So these things tend to start to drive how scheduling algorithms work on human-facing systems. Okay, so when we talk about scheduling, just keep that big distinction in the back of your mind. There's two types of computers as far as scheduling is concerned. Computers that people look at and other, okay? And when we're talking about other, we don't have to worry about some of this stuff because there's no little timer going in anyone's mind. Nobody's waiting for something to happen, okay? So yeah, I mean, you hear people say my computer feels slow, right? It feels slow because it's laggy and weird and windows aren't dragging the way they're supposed to and stuff like that. It's not slow because the search index creation took longer than expected, right? No one has ever noticed how long that takes, right? It doesn't matter, right? What they notice is that the interactive stuff starts to slow down, right? And people also don't tend to notice resource allocation. That's the thing, right? I mean, how many people have any idea how much RAM your computer is using, right? How many people know how much RAM your computer even has? All right, well, at least we're good there, right? But you guys don't know how much of that RAM is in use. And no clue, right? You know, and nobody complains about this. And well, maybe they should actually. Maybe you have too much RAM. Maybe you blew a lot of money on RAM that you didn't need to spend, right? But who cares, right? You think, hey, I've got a lot of RAM. It's the OS's job to make use of it. And you typically don't notice if the OS is making good use of it as long as this other stuff takes place, right? If I could make your system as responsive using half as much memory, you'd never tell the difference, okay? And the real reason for this is that human time is expensive, okay? That is the, you know, we have made, over decades and decades, we have made computers faster and faster and faster and way more powerful. And it's super exciting to be able to program these things because they're so cool. They're like these incredible machines. Nobody in the history of mankind would have ever dreamed of being able to use a machine like the ones that you guys could use today. It's just mind boggling, okay? At the same time, sadly, you guys aren't getting any smarter, right? I'm just, I'm sorry to say it, right? Like we've built better tools, but we as human beings are really way lagging behind, right? It's like Moore's Law and us, right? Like flat line down there. And so our time is really important. Our time is really valuable because we don't scale the way computers do. So when the computer wastes our time, we think, hey, none of that, right? That's not okay. If the computer has to spend a little longer doing its index or whatever, who cares, right? That's the computer's problem. It's not like, it doesn't have a dog to pet or whatever and a cat to feed and stuff like that. It's just gonna sit there all day. So again, I mean, when you have poor throughput, that's usually just computer cycles that could waste, right? I mean, to some degree, you're also displaying the planet because you're consuming extra energy, but whatever. That's like a second order concern at this point. All right. So I think we're almost out of time today. Oh, I've got four more minutes, cool. Okay, so let's talk a little bit about scheduling goals and then we'll fire up next, we'll fire up on Wednesday, we're talking about some simple schedules, okay? So the first thing you think about with schedulers is how does it meet deadlines? How well does it meet deadlines? How is it, is there any, and some schedulers keep in mind, some of the simple ones we're gonna talk about on Wednesday, they don't even care. They don't think about deadlines at all. They're totally oblivious to whether or not a particular task has eyeballs waiting for it or not. On the other hand, there's been a lot of work in the mainline OS community in figuring out how to determine what types of tasks have eyeballs waiting for it, distinguishing between interactive tasks and non-interactive tasks. One of the things that we're gonna talk about on Friday is one of the innovations in some of the new interactive scheduling algorithms that Linux incorporated about five years ago was that they got rid of all this really terrible logic in the old scheduler for doing interactivity detection. So the old schedule had these like magic potions that it used to try to figure out if a thread was interactive or not. And the new scheduler was like, no way. This is too complicated and it has a simpler and potentially better way of doing it. So that was one of the improvements that's still going on again after 2000 in Linux schedule. And the second thing is how completely does it put system resources to use, right? And this is because the computer on some level is expensive. Again, it's time is not as valuable as yours, but the faster it runs, the more you can do, particularly when you're really good at programming it and getting it to do things that you wanna do that are cool. So these two things, and we just talked about why deadlines win, but these two things are really attention with each other when we talk about scheduling, right? And that's important to understand. Just a quick little aside to finish the day, right? So on human facing systems, so if you missed deadlines, it's like, okay, the progress bar looked a little laggy for a minute there, not a big deal. On real time systems, missing deadlines could potentially just be totally catastrophic. And so there's a whole separate category of systems, including hardware support and algorithms for what's called real time scheduling. And real time scheduling is really concerned with meeting deadlines, right? Particularly with meeting hard deadlines. For example, if I have to, if I'm a robot, right? And the guy told me, you know, advance 10 meters. And I got to 10 meters and I was starting to run my defragmentation task and that took a little while and the stop motor task got delayed and pretty soon it's like, you know. So on any sort of, or I was the robot who was reaching out to shake your hand and I started the grip task and I just, it ran a little longer than I thought and it's like, you know, this is why. Thank God there are still these problems to solve before the robots totally take over, right? Because clearly they can't take over before they can shake our hands. So yeah, this is, so, and if you look, there's a whole bunch of fun techniques. We're not gonna cover them in this class because it's not a class on embedded systems, but it's good to know they're out. Okay. Any questions on this? We will start on Wednesday. Well, I'll take this question while people are getting up. Yeah. What's that? Thread migration. Thread migration. So thread migration is usually moving threads from one, it's forward to another.