He then told them many remarkable stories, sometimes half as if speaking to himself, sometimes looking at them suddenly with a bright blue eye under his deep brows. Often his voice would turn to song, and he would get out of his chair and dance about. He told them tales of bees and flowers, the ways of trees, and the strange creatures of the Forest, about the evil things and good things, things friendly and things unfriendly, cruel things and kind things, and secrets hidden under brambles.
As they listened, they began to understand the lives of the Forest, apart from themselves, indeed to feel themselves as the strangers where all other things were at home.
—The Fellowship of the Ring, Book I, Chapter 7
An important aspect of system development is to verify the correct operation of the system. Real-world systems usually must conform to some performance requirement beyond simply being free of bugs or producing the correct output. For example, for high-performance systems it might be important to know computational throughput, for interactive systems it might be important to provide quick response to a user, and safety-critical systems might need to make some guarantee about their ability to handle problematic events within a bounded timeframe. In such situations, the system must be able to monitor itself and take actions as necessary to ensure the correct operation of the system. In this assignment we will explore one such way to perform this monitoring task.
In this lab, you will:
Please complete the required exercises below, as well as any optional enrichment exercises that you wish to complete.
As you work through these exercises, please record your answers, and when finished email your results to firstname.lastname@example.org with the phrase Monitoring Framework 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.
include/linux/kthread.h, and is very similar to the POSIX threading interface. You must specify a function that is executed by the thread when it is created, may optionally specify a pointer to a data struct, and should specify thread name. This thread name is the human-readable identifier (e.g. that shows up in
Have your kernel thread print a system message so that you know it ran. It will automatically destroy itself once it returns from the specified function.
kthread_stop()will be very useful here.
However, your thread should not occupy the processor indefinitely.
Kernel code may call the function
invokes the system scheduler and effectively yields the processor to any other
processes that might be waiting to run. When your kernel thread is eventually
re-scheduled, it will resume executing after the call to
Have your thread print a message every time it is activated by the system scheduler. Copy and paste the tail of the system log. Is there any issue with the way your thread is running?
schedule()merely allows other processes to run, it doesn't cause our thread to run sensibly. If the thread loops through a call to
schedule(), it will run constantly. Instead, we want some way to allow our thread to sleep while it is not needed, and then wake up and perform work when it is needed.
Putting a thread to sleep in the kernel is somewhat different from
user-space. Really, what we want to do is prevent the scheduler from selecting
our thread to run. We can do so by changing the state of the thread
TASK_INTERRUPTIBLE. You can
do this by calling
set_current_state(TASK_INTERRUPTIBLE) from the
thread function. This will remove the current task (i.e. our kernel thread)
from the scheduler runqueue. The thread will continue executing after the
call to this function, but once it is scheduled off of the processor, it will
not be re-scheduled until its state is changed back to
Have your thread change its state to TASK_INTERRUPTIBLE and verify that it sleeps.
hrtimersframework to schedule a wakeup call for itself one second into the future.
You can read about
hrtimers API here (however, the function signatures
there are slightly out of date, so be sure to cross reference these with
your actual kernel). You can wake up a kthread using the function
dmesg. However, the system log is also accessible through the file
/var/log/syslog. This makes it possible to view real-time updates to the system log with the command "
tail -f /var/log/syslog".
Hypothetically your thread should wake up and execute every second. However,
fluctuations in the actual timing of execution are called variations.
dmesg command gives timestamps with six significant digits
(i.e. microseconds resolution). Use this to estimate the timing variation
of your kernel thread.
To explain, the
current variable is a macro to the
task_struct of the
currently executing process. If we were executing inside a system call, this
would point to the task that initiated the system call. However, since we're
executing in a kernel thread, and kernel threads are effectively treated like
any other process in the system, this points to the
that describes the kernel thread we have made. The data fields
nivcsw stand for Number of Voluntary
Context SWitches and Number of InVoluntary Context SWitches,
respectively, and record the occurences of these two events.
log_nsecthat modify how frequently your threads will execute (see chapter 17 of our text for a refresher on kernel module parameters). Provide reasonable default values in the event that your module is loaded without arguments.
[ksoftirq/2]only executes on core 2, while
[migrate/1]only runs on core 1.
Make a copy of your existing module and modify it so that you create
four kernel threads, one pinned to each core in the system. There exists
a function in
linux/kthread.h that binds kernel threads
to designated processors, and the header files
linux/smp.h provide necessary functions for working with
smp_processor_id()) within a relatively short time of one another.
When you are satisfied that your kernel threads are behaving properly,
take a system trace with
trace-cmd. You can perform system
tracing in free-running mode by simply omitting a program name. I.e., the
trace-cmd record -e sched_switch will trace the
system until you interrupt it with CTRL-C. Take at least ten seconds of trace.
Graphically verify your system's behavior with Kernelshark. Take a
screenshot and name it
trace.png. You can take a screenshot
of the whole screen by hitting the
Print Screen button on your
keyboard, or you can install a graphical screenshot utility with
sudo apt-get install gnome-screenshot (which will then show up
Accessories in the system menu).
trace-cmd reportgenerates this text, and you can search for relevant log entries with
grep. For example, the command
trace-cmd report | grep log_thread/3would return all log entries related to the process
log_thread/3. Use this technique to compute the actual running time over five wakeups of a single logging thread, and identify the minimum and maximum values.
In addition to the exercises above, please turn in:
printkand module parameters) is somewhat artificial. We will explore this later in the semester, but effective utilities would provide a facility for file-like I/O through the Virtual File System. This allows for reading and writing to RAM-backed files (i.e. files that never exist on disk anywhere). This is the common way to pass data to and from the kernel. For example, the
/procfilesystem contains a lot of data about the currently running system, and all of these files are virtual files that are maintained by the kernel.
task_struct). Try printing out various data fields to see how they change over time. (Note, some fields, such as
stimeare not updated for the
currentpointer since we are executing in kernel thread context. However, you could look up how to get a
task_structpointer to a userspace process to see these data fields in action.)
trace-cmdlog file. You can pull out a lot of valuable information with simple regular expressions.