This presentation is about timers in Linux based operating systems. It gives a brief idea about jiffies,system timer,real time clock,interrupts and how they are handled etc.
3. 1
KERNAL NOTION OF TIME
The kernel knows the preprogrammed tick rate, so it knows the time between any
two successive timer interrupts. This period is called a tick and is equal to 1/(tick
rate) seconds.
This is how the kernel keeps track of both wall time and system uptime.
Wall time—the actual time of day—is important to user-space applications.
The system uptime—the relative time since the system booted—is useful to both
kernel-space and user-space.
4. 1
KERNAL NOTION OF TIME
Some Functions Of Timer Interrupt
Updating the system uptime.
Updating the time of day.
On an SMP system, ensuring that the
scheduler runqueues are balanced and, if
not, balancing them.
Running any dynamic timers that have
expired.
The Tick Rate: HZ
The frequency of the system timer (the tick
rate) is programmed on system boot based
on a static preprocessor define, HZ.The value
of HZ differs for each supported architecture.
The tick rate has a frequency of HZ hertz and
a period of 1/HZ seconds. For example, by
default the x86 architecture defines HZ to be
100.
The frequency of the timer interrupt is
important. So changing its frequency has a
reasonable impact on the system.
5. 1
KERNAL NOTION OF TIME
Advantages with a Larger HZ
Kernel timers execute with finer
resolution and increased accuracy.
Measurements, such as resource
usage or the system uptime, are
recorded with a finer resolution.
Process preemption occurs more
accurately.
Disadvantages with a Larger HZ
A higher tick rate implies more frequent timer
interrupts, which implies higher overhead.
The higher the tick rate,the more time the
processor spends executing the timer
interrupt.
More frequent thrashing of the processor’s
cache and increase in power consumption.
6. 1
KERNAL NOTION OF TIME
A Tickless OS
The Linux kernel supports an option known as a tickless operation. When a
kernel is built with the CONFIG_HZ configuration option set, the system
dynamically schedules the timer interrupt in accordance with pending timers.
Instead of firing the timer interrupt every, say, 1ms, the interrupt is dynamically
scheduled and rescheduled as needed.
With a tickless system, moments of idleness are not interrupted by
unnecessary time interrupts, reducing system power consumption also
reduction in overhead.
7. 1
JIFFIES
2
The Etymology of
the Jiffy:
The origin of the term jiffy is
unknown. Phrases such as in a
jiffy are thought to originate from
18th-century England. In lay
terms, jiffy refers to an
indeterminate but brief period of
time.
In computer engineering, a jiffy
is often the time between two
successive clock cycles. In
electrical engineering, a jiffy is
the time to complete one AC
(alternating current) cycle.
1
The global variable jiffies holds the number of ticks that have occurred since the
system
booted. On boot, the kernel initializes the variable to zero, and it is incremented by
one during each timer interrupt.
There are HZ timer interrupts in a second,
There are HZ jiffies in a second.
The system uptime is therefore jiffies/HZ seconds.
The jiffies variable is declared in <linux/jiffies.h> as
extern unsigned long volatile jiffies;
The following expression converts from seconds to a unit of jiffies:
(seconds * HZ)
Likewise, this expression converts from jiffies to seconds:
(jiffies / HZ)
For example, code often needs to set a value for some time in the future, for example:
unsigned long time_stamp = jiffies;
unsigned long next_tick = jiffies + 1;
unsigned long later = jiffies + 5*HZ;
unsigned long fraction = jiffies + HZ / 10;
8. 1
JIFFIES
2
The jiffies variable has always been an unsigned long,
32 bits in size on 32-bit architectures and
64-bits on 64-bit architectures.
With a tick rate of 100, a 32-bit jiffies variable would overflow in about 497 days. With HZ
increased to 1000, however, that overflow now occurs in just 49.7 days!
If jiffies were stored in a 64-bit variable on all architectures, then for any reasonable HZ value the
jiffies variable would never overflow in anyone’s lifetime
Internal Representation of Jiffies
A second variable is also defined in : extern u64 jiffies_64;
Code that accesses jiffies simply reads the lower
32 bits of jiffies_64.
The function get_jiffies_64() can be used to read
the full 64-bit value.
9. 1
JIFFIES
2
Look at an example of a wraparound:
unsigned long timeout = jiffies + HZ/2; /*
timeout in 0.5s */
/* do some work ... */
/* then see whether we took too long */
if (timeout > jiffies) { /* we did not time out,
good ... */ }
else { /* we timed out, error ... */ }
Jiffies Wraparound
Thankfully, the kernel provides four macros
for comparing tick counts that correctly
handle wraparound in the tick count. They
are in . Listed here are simplified versions of
the macros:
define time_after(unknown, known)
((long)(known) - (long)(unknown) < 0)
#define time_before(unknown, known)
((long)(unknown) - (long)(known) < 0)
#define time_after_eq(unknown, known)
((long)(unknown) - (long)(known) >= 0)
#define time_before_eq(unknown, known)
((long)(known) - (long)(unknown) >= 0)
10. 1
JIFFIES
2
How It Actually Work
time_after(a,b) returns true if the time a is
after time b.
A special function is needed because 32-bit
architectures cannot atomically access both 32-bit
words in a 64-bit value.
The special function locks the jiffies count
via the xtime_lock lock before reading
Suppose b is 253, and five ticks later jiffies
has wrapped around to 2. We would therefore
expect
time_after(2,253) to return true. And it does
(using int8_t to denote a signed 8-bit value):
(int8_t) 253 - (int8_t) 2 == -3 - 2 == -5 < 0
You can try other values, too. This one is
trickier, for time_after(128, 127), which should be
true as well:
(int8_t) 127 - (int8_t) 128 == 127 - (-128) ==
255 == -1 (for 8-bit 2's complement) < 0
/* ... */
if (time_before(jiffies, timeout)) { /*
we did not time out, good ... */ }
else { /* we timed out, error ... */ }
So this code can be written as
11. 13
HARDWARE CLOCKS &
TIMERS
Architectures provide two hardware
devices to help with time keeping
1.Real-Time Clock –
The real-time clock (RTC) provides a
nonvolatile device for storing the system
time
On boot, the kernel reads the RTC and
uses it to initialize the wall time, which is
stored in the xtime variable
2.System Timer –
The idea behind the system time is—to
provide a mechanism for driving an
interrupt at a periodic rate
2 way to implement System Timer-
1. Electronic clock –
oscillates at a programmable frequency
2. Counter –
Set to some initial value and decrements at a
fixed rate until the counter reaches zero, an
interrupt is
triggered.
On x86,
the primary system timer is the
programmable interrupt timer (PIT)
Other include the local APIC timer and the
processor’s time stamp
counter (TSC).
12. 13
HARDWARE CLOCKS &
TIMERS
Real-Time Clock (RTC): All PCs include a clock called Real Time Clock(RTC),
which is independent of the CPU and all other
chips.
The RTC continues to keep track of time even
when the system is off by way of a small battery
typically included on the system board. On the PC
architecture, the RTC and the
CMOS are integrated, and a single battery keeps
the RTC running and the BIOS settings preserved.
On boot, the kernel reads the RTC and uses it to
initialize the wall time, which is stored in the
xtime variable.
The kernel does not typically read the value again;
however, some supported architectures, such as
x86, periodically save the current wall time back
to the RTC
13. 13
HARDWARE CLOCKS &
TIMERS
Linux uses the RTC only to derive the time
and date; however, it allows processes to
program the RTC by acting on the
/dev/rtc device file
The RTC is capable of issuing periodic
interrupts on IRQ 8 at frequencies ranging
between 2 Hz and 8,192 Hz.
It can also be programmed to activate the
IRQ 8 line when the RTC reaches a specific
value, thus working as an alarm clock.
The kernel accesses the RTC through the
0x70 and 0x71 I/O ports.
Nonetheless, the real time clock’s primary
importance is only during boot, when the
xtime variable is initialized.
The “xtime” variable
The Original Representation-
The simplest data structure is time_t , defined in the
header <time.h>
On most Unix systems—Linux included—the type is
a simple typedef to the C long type:
typedef long time_t;
#include <sys/time.h>
struct timeval
{
time_t tv_sec; /* seconds */
suseconds_t tv_usec; /* microseconds */
};
The timespec data structure is defined in
<linux/time.h> as:
struct timespec
{
time_t tv_sec; /* seconds */
long tv_nsec; /* nanoseconds */
};
Real-Time Clock (RTC):
14. 13
HARDWARE CLOCKS &
TIMERSThe “xtime” variable
The xtime variable stores the current time
and date; it is a structure of type
timespec having two fields:
tv_sec-
Stores the number of seconds that have
elapsed since midnight of January 1, 1970
(UTC)
This date is called the epoch(reference
date). Most Unix systems base their
notion of the
current wall time as relative to this epoch.
tv_nsec
Stores the number of nanoseconds that
have elapsed within the last second (its
value ranges between 0 and 999,999,999)
second.
The “xtime” variable
user programs get the current time and date
from the xtime variable.
The kernel also often refers to it, for instance,
when updating i-node timestamps.
The xtime variable is usually updated once in a
tick, that is, roughly 1000 times per The
xtime_lock seqlock avoids the race conditions
that could occur due to concurrent
accesses to the xtime variable. Remember that
xtime_lock also protects the jiffies_64
variable; in general, this seqlock is used to define
several critical regions of the timekeeping
architecture.
15. 13
HARDWARE CLOCKS &
TIMERSHow We See Time?
Some of the functions that we will cover convert between Unix time and strings, or programmatically
build a string representing a given date. To facilitate this process, the C standard provides the tm
structure for representing “broken-down” time in a more human-readable format. This structure is
also defined in <time.h> :
16. 13
HARDWARE CLOCKS &
TIMERSSystem Timer
kernel uses system timer to gauge the passing of time.
This system timer works off of an electronic time source, such as a digital clock or the frequency
of the processor.
The system timer goes off (often called hitting or popping) at a pre programmed
frequency, called the tick rate.
When the system timer goes off, it issues an interrupt that the kernel handles via a special
interrupt handler.
Because the kernel knows the pre programmed tick rate, it knows the time between any two
successive timer interrupts . This period is called a tick and is equal to 1/(tick rate) seconds.
This is how the kernel keeps track of both wall time and system uptime.
On x86, the primary system timer is the programmable interrupt timer (PIT).
The kernel programs the PIT on boot to drive the system timer interrupt (interrupt zero) at
HZ frequency.
17. 124
TIMER INTERRUPT HANDLER
The timer interrupt is broken into two pieces
interrupt handler – Architecture Depedent
tick_periodic() – Architecture independent routine
Task of Interrupt handler –
1. Obtain the xtime_lock lock, which
protects access to jiffies_64 and the wall
time value, xtime.
2. Acknowledge or reset the system timer
as required.
3. Periodically save the updated wall time
to the real time clock.
4. Call the architecture-independent timer
routine, tick_periodic().
Task of Tick Periodic()
1. Increment the jiffies_64 count by one.
2. Update resource usages, such as consumed
system and user time, for the currently
3. running process.
4. Run any dynamic timers that have expired
(discussed in the following section).
5. Execute scheduler_tick(), as discussed in
Chapter 4
6. Update the wall time, which is stored in
xtime.
7. Calculate the infamous load average.
18. 124
TIMER INTERRUPT HANDLER
The routine is simple because other functions handle most of the work:
static void tick_periodic(int cpu)
{
if (tick_do_timer_cpu == cpu) {
write_seqlock(&xtime_lock);
/* Keep track of the next tick event */
tick_next_period = ktime_add(tick_next_period, tick_period);
do_timer(1);
write_sequnlock(&xtime_lock);
}
update_process_times(user_mode(get_irq_regs()));
profile_tick(CPU_PROFILING);
}
Most of the important work is enabled in
do_timer() and
update_process_times() .
The former is responsible for actually performing the
increment to jiffies_64 :
void do_timer(unsigned long ticks)
{
jiffies_64 += ticks;
update_wall_time();
calc_global_load();
}
update_wall_time() - updates the
wall time in accordance with the
elapsed ticks, whereas
calc_global_load() -updates the
system’s load average statistics.
19. 125
TIMER
Timers are not cyclic.The timer is
destroyed after it expires
Timers are represented by struct
timer_list, which is defined in
<linux/timer.h>:
struct timer_list {
struct list_head entry; /* entry in linked list
of timers */
unsigned long expires; /* expiration value,
in jiffies */
void (*function)(unsigned long); /* the
timer handler function */
unsigned long data; /* lone argument to
the handler */
struct tvec_t_base_s *base; /* internal
timer field, do not touch */
};
Timers —
sometimes called dynamic timers or
kernel timers—are essential for
managing the flow of time in kernel
code. Kernel code often needs to delay
execution of some function
until a later time.
A timer is easy to use.
You perform some initial setup,
specify an expiration time ,Specify a
function to execute upon said
expiration, and activate the timer.
The given function runs after the timer
expires.
20. 125
TIMER
UsingTimers
4. Finally, you activate the timer:
add_timer(&my_timer);
Sometimes you might need to modify the
expiration of an already active timer
mod_timer(&my_timer, jiffies + new_delay); /*
new expiration */
If you need to deactivate a timer prior to its
expiration,use the del_timer() function:
del_timer(&my_timer);
To deactivate the timer and wait until a potentially
executing handler for the timer exits, use
del_timer_sync():
del_timer_sync(&my_timer);
1. The first step in creating a timer is defining it:
struct timer_list my_timer;
2. the timer’s internal values must be initialized
init_timer(&my_timer);
3. Now you fill out the remaining values as
required:
my_timer.expires = jiffies + delay; /* timer
expires in delay ticks */
my_timer.data = 0; /* zero is passed to the
timer handler */
my_timer.function = my_function; /*
function to run when timer expires */
21. 125
TIMER
Timer Race Conditions
Because timers run asynchronously with respect to
the currently executing code, several potential race
conditions exist.
First
never do the following as a substitute for a mere
mod_timer(), because this is unsafe on
multiprocessing machines:
del_timer(my_timer)
my_timer->expires = jiffies + new_delay;
add_timer(my_timer);
Second
Second, in almost all cases, you should use
del_timer_sync() over del_timer().
Timer Implementation
The kernel executes timers in bottom-half context, as
softirqs, after the timer interrupt
completes.
The timer interrupt handler runs update_process_times(),
which calls
run_local_timers():
void run_local_timers(void)
{
hrtimer_run_queues();
raise_softirq(TIMER_SOFTIRQ); /* raise the timer softirq */
softlockup_tick();
}
22. 126
DELAYING EXECUTION
Need for busy looping
1. When we want a delay, while using hardware
like (NIC for the first time ).
Implementation in case of first point:
unsigned long timeout = jiffies + 10; /* ten ticks */
while (time_before(jiffies, timeout)) ;
Problem in above solution :
spinning in a silly loop—because no useful work is
accomplished!!!
Second Solution (Better solution)
while (time_before(jiffies, delay))
cond_resched(); (New process is scheduled)
Busy Looping 3.When we wan't to solve critical section problem
through semaphores....
s=1;
P1 P2
---- ----
---- ----
Wait(s) Wait(s) // Busy Looping
Critial Section Critical Section
Signal(s) Signal(s)
---- ----
---- ----
Code of Wait(s) Code of Signal(s)
{ {
while(s<=0); s=s+1;
s=s-1; }
}`
23. 126
DELAYING EXECUTION
for Hz = 100 we can not provide time delay
less than 10 ms
even
for Hz= 1000 we can not provide time
delay less than 1 ms
so for smaller delay ....
kernel provides three functions for
microsecond, nanosecond, and millisecond
delays, defined in <linux/delay.h> and
<asm/delay.h>, which do not use
jiffies:
void udelay(unsigned long usecs)
void ndelay(unsigned long nsecs)
void mdelay(unsigned long msecs)
Small Delays-
BOGOMips
Its name is a contraction of bogus
(that is, fake) and MIPS (million of instructions per second).
Everyone is familiar with a boot
message similar to the following (this is on a 2.4GHz 7300-series
Intel Xeon):
Detected 2400.131 MHz processor.
Calibrating delay loop... 4799.56 BogoMIPS
This value is stored in the loops_per_jiffy variable and is readable
from
/proc/cpuinfo
BOGOMips
24. 126
DELAYING EXECUTION
This call puts your task to sleep until at least the specified time has elapsed.
When the specified time has elapsed, the kernel wakes the task up and
places it back on the runqueue.
/* set task’s state to interruptible sleep */
set_current_state(TASK_INTERRUPTIBLE);
/* take a nap and wake up in “s” seconds */
schedule_timeout(s * HZ);
Sleeping on a Wait Queue, with a Timeout -
Sometimes it is desirable to wait for a specific event or wait for a specified time to
elapse—whichever comes first.
schedule_timeout()-
26. 12
SYSTEM CALLS
A System call is the programmatic way in
which a computer program requests a
service from the kernel of the operating
system it is executed on.
System calls of timer has
#include<sys/time.h> header file.
System Call Current time of day
TIME(): get time in seconds
SETTIMEOFDAY(): set time as well as time zone
GETTIMEOFDAY(): get time as well as time zone
SLEEP(): process can sleep for s seconds.
CLOCK_SETTIME(): set the time of the specified
clock
CLOCK_GETTIME(): get the time of the specified
clock
CLOCK_GETRES(): get resolution of specified
clock
CLOCK_ADJTIME(): tune the specified clock
POSIX clocks
7
27. 125
TIMER
Clocks-based timers Timers
ALARM(): set an alarm clock for delivery of a signal
SETTIMER(): set value of an interval timer
GETTIMER(): get value of an interval timer
TIMER_CREATE(): create a POSIX pre-process timer
TIMER_DELETE(): delete a POSIX and pre-process
timer
TIMER_SETTIME(): arm/disarm POSIX and pre-
process timer
TIMER_GETTIME(): fetch state of POSIX and pre-
process timer