Upload
others
View
3
Download
0
Embed Size (px)
Citation preview
Chapter 6Timing Measurements
Chapter 6Chapter 6Timing MeasurementsTiming Measurements
HsungHsung--Pin ChangPin ChangDepartment of Computer ScienceDepartment of Computer ScienceNational Chung Hsing UniversityNational Chung Hsing University
Outline• Hardware Clocks• The Linux Timekeeping Architecture• CPU’s Time Sharing• Updating the Time and Date• Updating System Statistics• Software Timers• System Calls Related to Timing
Measurement
Introductions• Countless computerized activities are
driven by timing measurements• For examples
– Screen saver program– Process switches– ……
Introductions (Cont.)• Two main kinds of timing
measurements performed by kernel– Keeping the current time and date
• For user issued system call: time(), ftime(), and gettimeofday()
• Used by the kernel itself as timestamps for files and network packets
– Maintaining timers• Mechanisms to notify the kernel or a user
program that a certain interval of time has elapsed
Hardware Clocks• On the 80x86 architecture, the kernel
interact with four kinds of clocks– Real Time Clock– Time Stamp Counter– Programmable Interval Timers– The timer of the local APICs in SMP
system
Hardware Clocks (Cont.)• The first two are for keeping track
of the current time of day• The later two are programmed by the
kernel– To issue interrupts at a fixed,
predefined frequency– Crucial for implementing the timers
used by the kernel and user programs
Real Time Clock (RTC)• RTC is independent of the CPU and all
other chips• RTC continues to tick even when the PC is
switched off since it is energized by a small battery
• RTC is capable of issuing periodic interrupts on IRQ8 at frequencies ranging between 2 Hz and 8,192 Hz– Thus, can also be programmed acting as an
alarm clock
Real Time Clock (Cont.)• Linux uses RTC only to drive the time
and date– Process can program the RTC through
/dev/rtc device file– Kernel access RTC through 0x70 and
0x71 ports– Root can set up the clock by executing
the clock system program• Act directly on these two I/O ports
Time Stamp Counter (TSC)
• All 80x86 microprocessor include a CLK input pin– Receive the clock signal of an external
oscillator• Starting from Pentium, recent 80x86
microprocessor include a 64-bit Time Stamp Counter register– A counter that increments at each clock signal
from CLK– Can be read by rdtsc instruction
Programmable Interval Timer (PIT)
• IBM-compatible PCs include a Programmable Interval Timer (PIT)– 8254 CMOS chip using the 0x40~0x43
I/O ports• Issue interrupts forever at some
fixed frequency established by kernel– Called timer interrupts
Programmable Interval Timer (Cont.)
• Linux programs the PIT to issue timer interrupts on the IRQ0 at a 100 Hz frequency– Once every 10 milliseconds– This time interval is called a tick
Programmable Interval Timer (Cont.)
• Shorter ticks result in higher resolution timers– However, require the CPU to spend a large
fraction of its time in Kernel Mode• User programs run slower
• Thus, only very powerful machine can adopt very short ticks and afford the consequent overhead– IA-64
CPU Local Timers• All current Intel CPU include a local
APIC (Advanced Programmable Interrupt Controller)– Offer the CPU local timer
• CPU local timer is a device that can issue one-shot or periodic interrupts– Similar to the PIT
CPU Local Timers• However, a few difference between CPU
local timer and PIT– The APIC’s timer counter is 32-bits, while the
PIT’s timer counter is 16-bits– The local APIC timers sends an interrupt only
to its processor, while the PIT raises a global interrupt which may be handled by any CPU in the system
– The APIC’s timer is based on the bus clock signal. Conversely, the PIT has its own internal clock oscillator
The Linux Timekeeping Architecture
• Linux must carry on several time-related activities– Update the time elapsed since system startup– Update the time and date– Determines how long the current process has
been running, and preempts it if is has exceeded the time allocated to it
– Updates resource usage statistics– Checks whether the interval of time associated
with each software timer has elapsed
The Linux Timekeeping Architecture (Cont.)
• Linux timekeeping architecture– A set of kernel DS and functions related to
the flow of time• In UP
– All time-keeping activities are triggered by interrupts raised by Programmable Interval Timer
• In MP– General activities, e.g., software timers, are
triggered by the interrupted raised by PIT– CPU-specific activities are triggered by
interrupts raised by the local APIC timers
The Linux Timekeeping Architecture (Cont.)
• Linux uses two basic timekeeping functions– One to keep the current time up to date– Another to count the number of
microseconds that have elapsed within the current second• Use the Time Stamp Counter (TSC) if
available and is more precise• Otherwise, read the 8254 Programmable
Interval Timer’s internal oscillator
Timekeeping Architecture in Uniprocessor Systems
• All time-related activities are triggered by the interrupts raised by the PIT on IRQ 0
• When a timer interrupts occurs, divide the hander into– Top half– Bottom half
PIT’s Interrupt Service Routine
• In a timer interrupt is raised, invoke the timer_interrupt() function– If CPU has a TSC register
• Execute the rdtsc instruction to obtain the value in TSC register
• Read 8254, i.e., PIT, to compute and store the delay between the interrupt occurrence and the execution of the ISR
– Used to provide correct time to time(), ftime()…
– Invoke the do_timer_interrupt()
PIT’s Interrupt Service Routine (Cont.)
• Do_timer_interrupt()– Invoke do_timer()– If timer interrupt occurred in Kernel
Mode• Invoke x86_do_profile() ; see later section
– If an adjtimex() system call is issued• Invoke set_rtc_mmss() ;see later section
PIT’s Interrupt Service Routine (Cont.)
• Do_timer(){
jiffies++update_process_time(); mark_bh(TIMER_BH);if ( TO_ACTIVE(tq_timer))
mark_bh(TQUEUE_BH);}
PIT’s Interrupt Service Routine (Cont.)
• Jiffies – A variable stores the number of elapsed
ticks since the system was started• Update_process_timer()
– Check how long the current process has been running
The IMTER_BH Bottom Half
• void timer_bh(void){
update_times();run_timer_list();
}
• Update_times()– Updates the system date, time and current
system load• Run_timer_list()
– Take care of software timers handling
CPU Time Sharing• Each process is allowed a quantum of
time of limited duration• The counter field of the process
descriptor specifies how many ticks left– Updated by update_process_times() in
PIT’s timer interrupt handler
CPU Time Sharing• update_process_times
{……; skipped, mentioned laterif (current->pid)
--current->counter;if (current->counter <= 0) {
current->counter = 0;current->need_resched = 1;
}……; skipped, mentioned later
}
Updating the Time and Date
• On boot, kernel reads the RTC and uses it to initialize the wall time– Stored in xtime variable
struct timespec xtime;struct timespec {
time_t tv_sec; # of seconds elapsed from 1.1.1970long tv_nsec; # of ms. elapsed with the last second
}
• After that, RTC is never used and kernel relies on TIMER_BH to update date and time
Updating the Time and Date (Cont.)
• update _times ;called in TIMER_BH{
write_lock_irq();ticks = jiffies – wall_jiffies;if (ticks)
wall_jiffies += ticksupdate_wall_time(tick);
}write_unlock_irq()calc_load();
}
Updating System Statistics
• The kernel must periodically collect several data used to– Check the CPU resource limit of the
running processes– Computing the average system load– Profiling the kernel code
Checking the Current Process CPU Resource Limit• In update_process_time()
– Update per_cpu_utime and per_cpu_stime field of current’s process descriptor• Store the number of ticks running in User Mode and
Kernel Mode respectively– Check whether the total CPU time (User Mode +
Kernel Mode) limit has been reached• Send SIGXCPU if > rlim[RLIMIT_CPU].rlim_cur• Send SIGKILL if > rlim[RLIMIT_CPU].rlim_max
Keeping Track of System Load
• In calu_load(), which is invoked in update_times()– Calculate average system load in the last
minute, the last 5 minute, and the last 15 minutes• Count the number of processes in the
TASK_RUNNING or TASK_UNINTERRUPTIBLE states
Profiling the Kernel Code• Kernel includes a code profiler to
identifies the hot spots of the kernel– The most frequently executed
fragments of kernel code– To enable code profiler, passing the profile parameter in the booting process
Profiling the Kernel Code (Cont.)
• in x86_do_profile() invoked in do_timer_interrupt()– Check if in Kernel Mode and if yes
• Check the eip value to determine the code segment
Software Timers• Timer
– A software facility allows functions to be invoked at some future moment
• Time-out– A moment at which the time interval
associated with a timer has elapsed
Software Timers (Cont.)• Linux considers two types of timer
– Dynamic timer• Used by kernel
– Interval timer• Used by process in User Mode
Software Timers (Cont.)• Implement a timer is quite easy
– Hold the expires field• Expires = jiffies + ticks;• Tick = timer, e.g., 5 seconds
– Then, in each timer interrupt’s BH• Check if jiffies > expires and if yes, invoke
the time-out function
Software Timers (Cont.)• Note the checking occurs in BH
– Kernel cannot ensure that the timer functions start right at their expiration times
– Not appropriate for real-time applications
Dynamic Timers• Dynamic timer may be dynamically created
and destroyed• DS: struct timer_list {
struct list_head list;unsigned long expires;unsigned long data;void (*function) (unsigned long);
}
Dynamic Timers (Cont.)• To create and activate a dynamic timer
– Create a new timer_list object• struct timer_list my_timer;
– Initialize the object• init_timer(&my_timer);
– Fill out the remaining values• my_timer.expires = jiffies + delay; • my_timer.data = 0;• my_timer.function = my_function;
– Activate the timer• add_timer(&my_timer);
Dynamic Timers (Cont.)• If you want to change the expires values
– mod_timer(&my_timer, jiffies + new_delay);• Once expiration, the kernel automatically removes
it from the list• If you need to deactivate a timer prior to its
expiration– del_timer(&my_timer); // for UP– del_timer_sync(&my_timer); // for MP
Dynamic Timers and Race Conditions
• Dynamic timers are prone to race conditions– Release a resource but a timer acts on this
resources• Sol: stop the timer before releasing the resource
– In MP, another CPU may execute a timer handler while one CPU invoke del_timer()• Use del_timer_sync() instead of del_timer()• Wait until all CPU exit from the timer handler
Dynamic Timers and Race Conditions (Cont.)
– Delete a timer, change its expires values and recreated it againg• del_timer(&my_timer);• my_timer -> expires = jiffies + new_delay;• add_timer(my_timer);• This would result in two control paths
modifies the expires values executed in different CPUs at the same time in MP
• Use mod_timer() instead
Dynamic Timer Handling• Choosing a proper DS to implement
dynamic timer is important– String all timers in a single list
• Scan operation is costly– Maintain a sorted list of timers
• Insertion and deletion operations would also be costly
Dynamic Timer Handling (Cont.)
• Kernel partitions the expires values into blocks of ticks
• The details are skipped!
An Application of Dynamic Timers
• In some cases, the kernel may suspend a process for a time interval and it executes the following code
timeout = x;set_current_state(TASK_INTERRUPTIBLE);remaining = schedule_timeour(timeout);
An Application of Dynamic Timers (Cont.)
• in schedule_timeout(){
struct timer_list timer;expire = timeout + jiffies;init_timer(&timer);timer_expires = expire;timer_data = (unsigned long) current;timer.function = process_timeout;add_timer(&timer);schedule();del_timer_sync(&timer);timeout = expire – jiffies;return (timeout < 0 ? 0 : timeout)
}
An Application of Dynamic Timers (Cont.)
• process_timeout(unsigned long data){
struct task_struct * p = (struct task_struct *) data;wake_up_process(p);
}
System Calls Related to Timing Measurements
• The time(), ftime(), and gettimeofday() System Calls
• The adjtimex() System Calls• The setitimer() and alarm() System
Calls
The time(), ftime(), and gettimeofday() System Calls
• time()– Return the number of elapsed seconds
since midnight at the start of 1.1.1970• ftime()
– Return, in a DS of type timeb, the number of elapsed seconds since midnight of 1. 1.1970 and the number of elapsed milliseconds in the last second
The time(), ftime(), and gettimeofday() System Calls
• gettimeofday()– Return, in a DS named timeval, the
number of elapsed seconds since midnight of 1. 1. 1970
• The detailed implementation is skipped!!!
The adjtimex() System Call
• adjtimex()– Receives a pointer to a timex structure– Updates kernel parameters from the
values in the timex fields– Return the same structure with current
kernel values
The setitimer() and alarm() System Calls
• User Mode processes can activate special timers called interval timers– Cause Unix signals to be sent
periodically to the process– Or activate an one-shot interval timer
The setitimer() and alarm() System Calls (Cont.)
• Accuracy applies to these timers– Guaranteed to be executed after the
requested time has elapsed– But impossible to predict exactly when
they will be delivered
The setitimer() and alarm() System Calls (Cont.)
• In setitimer() system call, the first parameters specifies– ITIMER_REAL
• The actual elapsed time; • The process receives SIGALRM signals
– ITIMER_VIRTUAL• The time spent by the process in User Mode; • The process receives SIGVTALRM signals
– ITIMER_PROF• The time spent by process in User and Kernel Mode• The process receives SIGPROF signals
The setitimer() and alarm() System Calls (Cont.)
• ITIMER_REAL– Implemented by dynamic timer– Thus, the process descriptor includes a real_timer
object• ITIMER_VIRTUAL and ITIMER_PROF
– Do not require dynamic timer since they can be updated while the process is running
– Update relative values in process descriptor in timer interrupt handler, i.e., every tick
The setitimer() and alarm() System Calls (Cont.)
• alarm() system call – Send a SIGALRM signal when a
specified time interval has elapsed– Similar to the setitimer() with
ITIMER_REAL parameter• Also use real_time dynamic timer
– Thus, alarm() and setitimer() with ITIMER_REAL parameter cannot be used at the same time