In some distant arcade, a clock tower calls out six times and then stops. The young man slumps at his desk. He has come to the office at dawn, after another upheaval. His hair is uncombed and his trousers are too big. In his hand he holds twenty crumpled pages, his new theory of time ...
Alan Lightman—Einstein's Dreams, Prologue
Linux's real-time scheduling classes are for processes that require a great deal of control over how they execute, including their timing behavior. The real-time scheduling classes can be used to define programs that execute in very specific ways, including preempting other programs and even the operating system kernel.
In this studio, you will:
Please complete the required exercises below, as well as the optional enrichment exercise if you wish to complete it.
As you work through these exercises, please record your answers, and when finished please email your results to email@example.com with the phrase Real-Time Scheduler in the subject line.
Make sure that the name of each person who worked on these exercises is listed in the first answer, and make sure you number each of your responses so it is easy to match your responses with each exercise.
Copy your CPU-bound workload program from the previous studio into a new file, and modify the new program so that rather than looping forever, it increments a loop index from zero to five hundred million (500,000,000). This will provide a CPU bound task that's guaranteed to finish.
NOTE: Modern compilers are smart enough to optimize your loop away.
Make sure to compile without any optimizations when you build your executable
file for this exercise. With compiled with no optimization (e.g., simply running
gcc -o big_loop big_loop.c), on the 900 MHz Raspberry Pi 3,
the instructor's program runs for about four seconds. When compiled with
runs for about a half second. For any higher optimization level (e.g.,
-O2 or above) the program returns immediately. Compile your new program on your Raspberry Pi,
and then use the
time command to verify that your program runs for around four
As the answer to this exercise, please show the output from running your new program
(compiled without any optimizations) within the
trace-cmdcommand to record sched_switch events during an execution of your program. Recall that the syntax for this looks like "
sudo trace-cmd record -e sched_switch ./big_loop 3". Make a copy of the
trace.dattrace file that command generated (in the directory where you ran it), so you can inspect it later - the next time we run
trace-cmdit will overwrite the current local
Then use Kernelshark to inspect the trace, and zoom in on specific portions of the trace (e.g., on the CPU core where you pinned the program) to examine how your program executes. As the answer to this exercise, please name three processes that interefered with the execution of your program on that core, and explain briefly how you know they did that based on the trace you examined.
man sched_get_priority_maxto see documentation for the data structure and functions needed for this exercise.
Modify your workload program so that it takes a second command line
argument (in addition to the first argument, which specifies on which core
the program should run) that gives the real-time priority with which it
should run (valid values for that argument are in the range from the value returned
Also modify your program so that it uses the
structure and the
sched_setscheduler() function to run under the SCHED_RR
scheduling class with the real-time priority that was passed in the
second command line argument.
Be sure your program checks that valid command line parameters were passed
(in particular, that the passed priority is in the range from the value returned by
sched_get_priority_min(SCHED_RR) to value returned by
sched_get_priority_max(SCHED_RR) inclusive), and also
checks the return value from calling the
and that it prints out an appropriate error message (and returns a negative value)
in the event of failure.
Compile your program (without optimization) and run it both as root (using
sudo) and not as root with different priority values ranging from
1 to 99. Find the largest number for which
succeeds when run as root, and the largest number for which
sched_setscheduler() succeeds when run not as root, and report
those values as the answer to this exercise.
trace-cmdwith a real-time priority of 1, to generate a new trace, and inspect the resulting trace in Kernelshark. As the answer to this exercise please say whether any processes preempted your program (and if so which ones), and whether there are any meaningful differences in how these interruptions appear in this trace (
kernelshark trace.dat), versus in your original (non-real-time) trace (
Filtermenu and select
list CPUs. As the answer to this exercise please say how many
sched_switchevents were recorded on that CPU core, and compare that number to the number of
sched_switchevents were recorded on each of the other CPU cores.
ps -e -o cmd,rtprioto get a list of all processes on the system and their real-time priorities. A dash in the priority column means that this process does not have a real-time priority.
As the answer to this exercise please (1) say what range of real-time priorities you see being used, (2) name two processes that have real-time priorities, and (3) speculate why they may need to be run with real-time priority.
sched_switchevents occur on your program's processor, (2) whether your program is ever preempted, and if so (3) when and where is it preempted?
Make a copy of your real-time workload program, and modify it so that
it takes a third argument, which will be the number of real-time tasks to
create (only accept values ranging from 1 to 10). Using this number, insert
appropriate calls to the
fork() function. It is
fork() is called AFTER you have set the
program's real-time priority, but BEFORE you start executing the program's
Compile and test your modified program, and when you are confident that it is working correctly, trace the execution of the program running three concurrent real-time workloads, and inspect the trace in Kernelshark. Recalling that you can set marker A with a left mouse click, and set marker B with shift + left mouse click, use markers to measure the length of a round-robin time-slice.
As the answer to this exercise (1) report the length of the round-robin time-slice you saw, and (2) briefly describe the pattern of execution of the three processes that you saw in that trace.
SCHED_FIFO, under which tasks are allowed to run to completion or until they give up the processor with
sched_yield(). Repeat the previous exercises that used the
SCHED_FIFOinstead, and as the answer to this exercise please describe what differences you saw in the scheduling behavior with
SCHED_FIFO, versus what you saw with