 All right, welcome back to operating systems So today will be a nice reprieve from your brain breaking from having multiple processes running Different address spaces file descriptors all that stuff So for today has anyone ever stood in a line before a Line getting food. Yeah. All right. So if you've ever stood in a line before This lecture will be fairly straightforward. So we're just going to be talking about lines today pretty much all day So basic scheduling First we can do some boring stuff. So there's two types of resources on your machine Preemptible resources and non preemptible resources. What does that mean a preemptible resource is something that can be taken away at Any given time and shared so a CPU is an example of a preemptible resource I can stop a process from executing let another process execute for a little bit go back and forth Maybe if you have siblings, you had a preemptible resource some toy or something you could share that toy Whatever so it's shared through Scheduling so you can schedule time with that resource and then each of you can take turns or do whatever a Non preemptible resource is something that can not be taken away without some type of acknowledgement So for example this space if I'm using a gig Gigabyte for a file. I can't just say hey you can go ahead and take a hundred megabytes of it and Just give it back to me when you're done because that wouldn't make any sense. They'd use it You'd lose your information. You wouldn't get it back. It would just not really make sense Another example of this something like memory actual physical memory So you allocate and you deallocate memory. So you use it and then when you're done with it you return it So for like super high-performance computing if you ever get into that sometimes you might find out that CPUs are a non preemptible resource. So you can actually allocate the CPU to your process and then you are guaranteed to be the only one with it and You will have some nice performance characteristics with it because you know nothing else can ever take it away from you But that's not in this course in general CPUs are preemptible. You have to share So there are two things. There is a something called a dispatcher and a scheduler that works together We've already kind of talked about the dispatcher. It's just the name for the low level thing that actually does the context switching So whatever is saving state and loading state that is doing the context switching to switch between Executing two different processes. That's what the dispatcher is doing So the scheduler is the high-level policy that we will talk about today And that is responsible for deciding what processes to run and sometimes when So we can start this super simple the scheduler will run whenever a process changes state So we can first consider non preemptible processes. So a process just runs until it is done So this is like uniprogramming systems It just runs until it's done the scheduler only makes decisions whenever a process Terminates exits and then the scheduler has to pick another process to run So preemptive just so if you ever run you name dash V before or looked at it That will tell you like the date your kernel was built and like options of it one of the options that will show you is preempt So now you know what preempt means it means it's a preemptible kernel. It can interrupt processes at any given time So when we talk about scheduling there are four main metrics So the first one is minimizing waiting time and response time So you don't want to have a process waiting around too long So like it wants to execute you want to give it the CPU hopefully as quick as possible and Let it finish and let it terminate as quick as possible as well you also want to Maximize CPU utilization. So you don't want to have a CPU idle So that is especially important if you have multiple cores on your machine You don't want a core idle because it's not really doing anything The other one is throughput so throughput is just running as many processes as possible and ending them And the last one is fairness Which is kind of at odds with all the other ones So you want to try to give each process the same percentage of the CPU and essentially treat them all fairly So first algorithm not really an algorithm. It's first come first serve. So That is actually a form of scheduling. So It's just means the first process I arrive gets the CPU Processes are stored in a FIFO queue first in first out if you don't remember what that means So it's just like a normal queue if you go and get food So It maintains this queue in arrival order. So whatever arrived first is at the front of the line So throughout this yep So for now, we'll just talk about a single CPU core. You just run Single core at the time you get the whole CPU So for this we'll consider these processes. So let's consider four processes I'm super creative with names. So I named them P1 P2 P3 and P4 And then this column is the time they arrive at I'm not going to use time units I'm just going to use like just Just atomic time units, so I won't use seconds or anything like that I'll just do it in time blocks that I won't have fractions of just to make our lives easier So they all arrive at time zero and then the burst time that might sound like a weird term burst time Just means how much time will this process actually execute on a CPU for until it's terminated So process one wants to execute for seven time units process two for four process three for one process four for four So since they all arrive at time zero, I have to explicitly tell you their arrival order So here I'll assume that they arrived P1 P2 P3 P4 So if we have first come first served, this is our schedule So we just run P1 because it was at the front of the line It runs for seven time units Then whenever it's done terminating Well, whenever it's terminated then we have to pick what process to run next in this case P2 is next we'd run it for its four time units then after that P3 is next for one time unit Then P4 finishes it off for four time units, and then we're done Any questions about that schedule? Fairly straightforward. Yep So in this case, this is like the true burst time This is how long a process will take which on a real operating system. You won't know that, right? So we're just setting up a framework for dealing with this generally you You analyze Scheduling stuff after they've already completed so you know how long they run for and then you kind of do like a Postmortem and figure out, you know the average response time and all that stuff So in this case if we wanted to figure out the average waiting time Well, process one waited around for zero seconds Process two waited around for seven seconds because it also arrived at time zero Process three waited for eleven process four waited for twelve. So to calculate average waiting time No tricks twelve plus eleven plus seven plus zero divided by four So in this case, it's like seven point five. I think So there could be a slightly different order So if we assume that our order is p3 p2 p4 then p1 Now this is our schedule. So we'd pick p3 runs for one then pick p2 Which runs for four then p4 which runs for four and then p1 which runs for seven So if we did the same thing and calculated our average waiting time again It would be zero plus one plus five plus nine So if we calculated it out, it would be three point seven five or half of what it was before So you might think well first come first serve is pretty bad Because the average waiting time varies wildly between just whatever order the processes happen to come in which generally isn't Generally, we want our systems to be fairly predictable. So first come first serve It's an algorithm. It's not the greatest So If we wanted to minimize average waiting time, we could do something like shortest job first So it's a slight tweak where we always schedule the job that has the shortest first time first Again, we still don't have preemptions So the only tweak I'm going to do here is change the arrival time of the processes so that they don't all arrive at time zero so P2 arrives at time 2 p3 arrives at time 4 and P5 or p4 arrives at time 5 Then we'll just use the same example throughout the rest of the lecture just to compare them So for all that I like always like drawing the arrival time on the top So here I just draw it on the Gantt chart directly just to make things a bit easier when you have to schedule things so Our algorithm at time zero There's only p1. So it is the shortest job because it is the only job So we would schedule p1 for seven time units and then while it is executing p2 p3 and p4 would arrive so at time seven we get to decide which one to run between those three processes and The one with the shortest job is p3. It's only one time unit So we'd execute it for one then at time eight Well, there's a tie between p2 and p4 so to break the tie you can just pick whoever arrived first. Yep Yeah, so the question is hey at time p2 at time 2 it's shorter So can I just preempt it and switch to it that would be better But right now we're doing non preemptible. So we're not allowed to preempt it So so that will be our next week though. So Hold on so If we do this and then we calculate the average waiting time it just changes a little bit because some processes do not actually arrive at time zero so P1 its average waiting time is zero it arrived at zero and Waited for no time units p2. It's average. It's waiting time Well, it's came arrived at time two and it waited for one two three four five six time units until it started executing P3 while it waited for one two three time units before it started executing and then p4 waited for Seven time units because it arrived at five didn't start executing to 12 12 minus five is seven. So it's average waiting time now is four so The next tweak well first off. This isn't super practical This isn't practical it provably optimizes the average wait time if there's no preemption, but On a real system, you're not going to know the burst time of every single process Even if you did it might change from process to process you This is something you could think of you just throw a I at maybe it would be good at it but the longer the schedule take takes the worst because it's also counted as overhead so you want it to be as fast as possible and Also, there is this issue of starvation. What does that mean? Well, that means that some processes might never execute So you can't imagine if some system Constantly gets a bunch of really short processes and there's this long process Well, then all of the short processes will just run Hog the CPU and that long process would never execute So for some reason a process that never executes the term for that is it gets starved or your algorithm suffers from starvation So we can do the tweak where we add preemption so to add preemptions the shortest job first The algorithm just changes to shortest remaining time first so We also assume that our minimum execution time is one time unit, so I can only preempt on time unit boundaries So I don't have to deal with fractions and then similar to first shortest job first. This optimizes the average waiting time so Here is our schedule if we have preemptions, which was like your idea here so Time zero p1 comes in and we have no other choice, but to schedule p1 So we would schedule it for two time units and then p2 comes in at time two so at time two p1 has five time units remaining and The newly arriving p2 has four time units remaining because it hasn't executed at all So four is shorter than five. So we would schedule p2 So p2 would run for two time units then at time four p3 comes in So p2 has two time units remaining p3 only executes for a total of one so it has one remaining that shorter we'd schedule p3 So schedule p3 for one and then it's done Then p4 would come in so we have to choose between p4 p2 and p1 So p4 has four time units remaining p2 has two p1 has five So we would schedule p2 It runs for four time units, then we'd schedule p4 then p1 So if we calculate the average waiting time for this so we can use a little bit of a shortcut So if you want to do a shortcut and not count all the blocks in between here Well for process one you can just figure out when it ended so it ended at time 16 and it started at time zero So that was the total time it was available to the CPU so that total time was 16 time units So if you want to figure out the waiting time just subtract its burst time from that total time so 16 minus 7 well, that's 9 so it must have been waiting for 9 time units So process 2 waited for one time unit right here Process 3 waited for zero and then process 4 waited for two time units right here So our average waiting time in this case is 3 which is you know an improvement over what we had before Without preemptions, which was 4 So any questions about that yep? Yeah Yeah, so for this I'm assuming context switching is instant for so in general one of the things you want to report with Your scheduling is how many times does it context switch? So we'll see that with our real algorithm. So this is as far as it will get today round robin so So far we haven't handled fairness and it's a trade-off with the other metrics anyways So we do something like round robin. So that's like if you have a toy sibling You each get 30 minutes with it You have it for 30 minutes you pass it around They get 30 minutes and then if there's a third sibling they get it and then it goes back to the first person Just goes around in a circle. So that's what round robin is but we have fancier terms for it So the operating system divides execution into time slices for some reason their computer scientists So they want to use fancy turns so they'll call them quanta and the time slice will be called a quantum Why I don't know they want to be fancy and sound smart really. It's just a time slice a set amount of time So with this we maintain a FIFO queue of processes similar to first come first serve and We just give each process a time slice and if it's not done yet We preempt it at the end of its time slice and add it to the back of the queue And then we just keep on going over and over again So what are some practical considerations for determining the time slice or quantum length? So I heard one already a bit if it's too low, you'll have a lot of context switches And if the time it takes for context switch is like even comparable to the quantum length You're just gonna spend all your time context switching and it's gonna be real bad So what is the opposite problem if my time slice is absolutely gigantic? Yeah, so What if the time slice was Even longer than the process ran for Yeah, so the the time slice you don't have to use all the time slice so if you end early and Terminate well the next process the scheduler would just know that and then schedule something else to run So it wouldn't be idle for the rest of the time slice Yep, so yeah the question what how would sleeping play into this so sleeping it would just give up its time slice probably Yeah, not maximizing my throughput close So at the beginning we saw a first come first serve right and said it was really kind of crappy So if my time slice is longer than What any one process executes for what does round Robin become? Yeah, it becomes first come first serve right if my quantum length is like eight years or something like that Then well guess what it's first come first serve because the process this is going to run until it's terminated and The only thing to differentiate them is the arrival time so There's a trade-off here. You don't want the time slice to be too low. You also don't want it to be too big so This is as hard as it will get today too. Well, we'll get a little harder after this, but We're going to do the same scheduling But we're just going to say for instance that the quantum length is three time units So this might look like a bit of writing so we will go over it So here we go with the same schedule. I will Have all the arrival times written on the top and then a nice trick to do for round Robin Is to write the queue on the bottom so you keep track of your queue at all the At all the time and then you know what to schedule next so At time zero p1 arrives. It would be the only thing in the queue So it would get scheduled and here our time slice is equal to three so We p1 is the only thing to run so we would run it for three time units Unless it terminates early, but in this case its first time is seven. So it's going to still want to run after it's three time units So we would schedule it for three time units and At time two our queue would be empty and p2 would arrive So it would be the first thing in the queue and Then here whenever p1 is done. It's time slice. It still wants to execute So we would throw it to the back of the queue so at time three our queue would be p2 then p1 So if we want to figure out what to run next, it's just whatever is at the front of the queue So the next process to run is p2 So p2 would run for two time or for its three time units and During that well at time four I would have p1 at the front of the queue and then p3 arrives So it would go at the end. So my queue would look like p1 p3 and then nothing and then at time five p4 arrives So it would go to the end of the line So we would have p1 p3 then p4 so At time six here. I have to make its Process two is done with its time slice. So I have to schedule another process. What one should I run? P1 it is at the front of the queue. So I would run p1 Also p2 is still executing. So I would put it Or sorry p2 is done. So I would put it at the back of the queue So I execute p1 for three time units It still wants to execute a bit more, but it has done its time slice So it goes to the back. So my queue would be p3 p4 P2 and then p1 now p3 would It's p3's turn. It only executes for one time unit then it terminates. So it the scheduler has to reschedule something and The new process wouldn't just get the remaining time slice. It would get restarted. So p4 would go and get four time units here and Then our queue would look like p2 p1 then p4 so the reason why p4 gets a brand-new time slice and not Just continue and it kind of just uses the remaining two is Well, if you were malicious about it and you could figure out How big the time slice was well, say the time slice was 10 units and Another process just got whatever the remaining time was Well, I could time my process so that after nine time units it does something that causes a sleep and then the scheduler makes a new decision and then gives that new process a single time unit and Then it reschedules me and I get my full 10 again then I go wait for nine go to sleep It gets one I get nine nine one nine one So you could kind of game the system if the time slice just didn't restart every time so in this case P2 would run for it's one remaining time unit Then p1 then p4 and now we're done. Yep. Yeah, so you're the Yeah, so so the scheduler is done by the kernel so p3 would terminate the kernel would know about it and just start a new time slice All right So now we have our fun math questions. So first would be average waiting time So our average waiting time. Well, we can do that trick again. So This is 16 So p4 ends here P1 ends at 15 P2 ends at 14 and p3 is It's somewhere there I can count so Process one was around for 15 time units. It executed for seven of those. So it must have waited for eight Process two was around for 14 here Minus two when it arrived. So it was around for 12 And it executed for four of those based off its burst time. So it must have been waiting for eight That is a really horrible eight Then process three Well, how long did it wait for? So it came in at time four and it waited for one two three four five five time units Then process four it ended at 16 Arrived at five. So it was around for 11 time units Executed for four of those. So if I can do math 11 minus 4 hopefully it was waiting around for seven. So my average waiting time would be all this Which would be seven So the next thing to calculate is the average response time So average response is again The response time is the time that the process arrived to the time it first started executing. So For process one it arrived at time zero and started executing immediately. So its response time was zero For process two it arrived at here. Where's the highlighter? It arrived at time two and it started executing at time three. So its response time was one Process three again waited around for the same five time units that are there highlighted in green and then process four arrived at time five and Didn't start executing until Let's just count One two three four five. So it also Its response time was also five So if we divide that by four we get two point Seven five something like that So the last thing that you calculate is the number of context switches So to calculate the number of context switches You just count the number of times in the schedule that we had to change between processes So we don't count time zero and we don't count time 16 so the quickest way to do this or the most obvious way is to just Do a red line whenever we change between processes. So we change between process One and two there then we change between two and one Then one and three then three and four and four and two Then two and one then one four Then to count the number of context switches. We just count the number of red lines So how many context switches do we have there? seven so That would be What you would have to do on the exam. Yeah The numbers look horrible Why they look horrible So the other methods we introduced before aside from first come first serve you couldn't implement them Because you don't know how long a process is going to run for so Yeah, so so far. This is the first one we can run so in order to make this The hardest thing we can do today We'll do the same thing round Robin For the time slice is one So this is as hard as it gets for today and as hard as these scheduling questions get so Starts off the same thing drawing the queue at the bottom is going to save us. So Process one It arrives at time zero. It's the only thing in the queue So we would execute process one whoops Then it's time slice is one it would go to the back of the queue guess what it's still the only process So we schedule process one now we have an instance of a tie so You might be Think we could do process to process one or process one than process two So if there's a case where you're re queuing an old process and a new process is arriving at the same time You favor the newly arriving process Why well the other thing already ran and if I favor the new process I'm going to get an overall lower average response time. So Generally for these tie-breaking rules, there's generally a reason for them So the why in this case is well, I'll favor the new one because I want a lower average response time So P2 arrives So we would favor that newly arriving process and then put P1 behind it So that would be our queue at time two. So we would pick P2 to run immediately So P2 would run It would get thrown to the back of the queue then P1 would run Then same thing is going to happen. So P3 arrives. So P3 doesn't get to butt ahead of P2 because it was already at the front of the queue whenever it arrived So it doesn't get to butt ahead or anything like that so after that We would get P3 would go because it's the newly arriving process and then our re queue of process one so Then we would have scheduled process two to run Same thing is going to happen P4 arrives. So our queue would have been P3 P1 Because they were already in the queue when P4 arrived Now P2 is getting re-queued So it would be favored over the newly arriving P4. So our queue would now look like this So after this P3 would run Mercifully it only runs for one time unit So it would be done and our queue now gets shortened to P1 P4 P2 so after that Then P1 would run P4 would run and Hopefully at this point I don't have to redraw the queue because it's just going to go around the round in the order 1 4 2 1 4 2 until eventually they're done so at this point with process 2 it has run for a total of Three time units so it's thankfully almost done So we go another round of P1 P4 P2 and now P2 is Mercifully done and our queue would look like P1 P4 So now we just cycled between them P4 P P1 P4 P1 P4 and now they are mercifully all done So this is as hard as it gets. Yep. Yeah, so Right here if if we could take like fractional So like time three and a half our queue would just be P2 on our queue Right, that would be the only thing in our queue So if it's the only thing our queue When time four rolls around well We just put P3 the newly arriving one after P2 and then the re-queue of P1 at the very end Yeah Okay, so now we have to do the fun part Average waiting time Thankfully I showed you a shortcut which is much easier to do when you are writing it than if I am explaining it to you so That's 16 P4 ended 15 P1 ended To do This is 14 13 so at 12 P2 Ended So average waiting time so P1 was around from 15 to 0 So it was around for 15 time units its burst time was 7 so it waited around for 8 time units Process 2 ended at 12 Started at 2 so it was around for 10 time units minus the 4 it was executing 4 so it must have been waiting around for 6 time units Process 3 while we can just look at it up there. It arrived at time 4 started executing at time 5 So it was only waiting around for one time unit Then process 4 it ended at 16 came in at 5 so it was hanging around for 11 time units 11 minus the 4 it must have been executing 4 means it must have been waiting around for 7 So divide that by 4 processes our average waiting time is now 5.5 So which compared to before? Hey, it went down a little bit. So from 7 it went to 5.5 Next fun one is the average response So in this case P1 started executing immediately its response time was 0 P2 also started executing immediately it came in at 2 started executing at 2 so its response was 0 Process 3 while its waiting time was 1 so that was also its response time It was just waiting around for one time unit Last one is process 4 which process 4 we can see here was just whoops wrong color It was just waiting around for two time units came in at 5 waited for two time units So if we crunch the numbers here our average response time is now 0.75 which is way better than before which was 2.75 So last thing we have to get is The number of context switches which is real fun So number of context switches Same thing will use our good old red line and start counting So 0 doesn't count so and also Changing from process 1 to process 1 that is not a context switch So the scheduler would be like same process not a context switch. So Whoops, so this is our first context switch here. So our first context switch one two three four five six seven eight nine ten eleven twelve thirteen fourteen So fourteen context switches So that's as hard as it gets so lots of context switches here But we can see the trade-off of more context switches, but our response time was way better. Yep So remember we talked about context switching just being essentially a waste of time so For real systems context switches will be less than like 1% of the total time Execute Yeah, which is fairly negligible, right so So if you if you're tweaking the time slice number and then you see that hey 50% of the time is spent doing context switches Well, you're not in the 1% range So you should probably increase your time slice because you're switching way too fast So there's always going to be some type of trade-off here. Whoops. So any questions about that? Fairly straightforward something we could do in our exam get some free marks feel good about ourselves Much better than the the forking examples where I can just like throw a billion forks at you. Yeah, so this is like This is the easy part That shouldn't be too bad and then you know, you'll get a fork question and then while you're thinking about it You can do this question so Could go through do it again if you really want quantum length of 10 units Guess what that becomes first come first serve if you want to count the times again I don't suggest it, but if you want to practice it go ahead and These are the numbers you should get for when it becomes essentially first come first serve So like we said before so the round robin performance depends on the quantum length and the length of the actual processes so Generally is low response time good interactivity. It's fair low ish average waiting time when the job lengths vary But the performance depends on the quantum length. We have to set it. It's kind of difficult to set in practice Too high becomes first come first serve too low Too many context switches which is just overhead and in general it also has if you simulated the bunch It has poor average waiting time if the jobs are all fairly similar length so That's it scheduling just involves a bunch of trade-offs We saw some different algorithms if you could even call them that first come first serve Which is a valid scheduling algorithm if you just have to make a decision Then we saw a shortest job first if we want to have no preemptions and minimize waiting time And we added preemptions tweaked it a bit got shortest remaining time first then saw that that Minimize waiting time then we saw round robin which is more fair. We can implement it. Yep So the cause of so overhead is just the amount of time Wasted not doing useful work. So if you were the kernel your useful work is running applications The context switch on your system is pretty short, but if you get to pick the length you can pick wrong If you get to pick the quantum length you could pick wrong, right? So you could pick the a quantum length that's too short where the context switch time matters So you don't want to do that So yeah, any other questions? We can end early take a sigh of relief some of you have been working on lab to see you can do that. Yeah Yeah, so shortest Shortest remaining time first not going to be used because we don't know the first time of processes for one and then another reason is that starvation is an issue So we wouldn't use it and you wouldn't actually know the times ahead of time So it's like kind of an after-the-fact theoretical thing. Yeah So it just restarts a new time slice because if you knew the quantum length you could essentially game the system where say it was like Ten time units you can just wait till you're almost done your quantum length give up the CPU then some other Process just gets it for like one time unit something really short And then if it's just you another process you get it back and you get a full new time slice And then you use it almost all of it. Let them get the remainder then you use all of it I punched the microphone again. God damn it All right. Yeah, so in general for round Robin. You just always restart the time slice You just always restart the time slice. Yeah. Yeah, you don't want anyone gaming the system or doing anything weird So with that, oh, yeah, yeah, so this is assuming a single CPU core So we'll get into more advanced stuff tomorrow, but for scheduling everything's just a big trade-off So there's no right answer for scheduling. So just remember pulling for you. We're all