1 / 22

Timers and Time Management

Timers and Time Management. Ok-Kyun Ha 2007.05.18. Contents. Kernel Notion of Time The Tick Rate: HZ Jiffies Hardware Clocks and Timers The Timer Interrupt Handler Timers Delaying Execution. Introduction. The passing of time is very important to the kernel

rronna
Download Presentation

Timers and Time Management

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Timers and Time Management Ok-Kyun Ha 2007.05.18

  2. Contents • Kernel Notion of Time • The Tick Rate: HZ • Jiffies • Hardware Clocks and Timers • The Timer Interrupt Handler • Timers • Delaying Execution

  3. Introduction • The passing of time is very important to the kernel • almost kernel functions are time driven (not event driven) • Focus (in this chapter) - system timer and timer interrupt - the system timer is a programmable piece of hardware that issues an interrupt at a fixed frequency - dynamic timers - used to schedule events that run once after specified time complete 3

  4. Kernel notion of Time • Kernel can comprehend and manage time through tick rate of system timer in hardware • When the system timer goes off, it issues an interrupt that the kernel handles via a special interrupt handler • The kernel keeps track of it simply because the kernel controls the timer interrupt • The timer interrupt is very important to the management of the operating system 4

  5. The Tick Rate: HZ • The tick rate is programmed on system boot based on a static preprocessor define, HZ • The value of HZ differs for each supported architectures • The kernel defines the value in <asm/param.h> #define HZ 1000 /* internal kernel time frequency */ • When writing kernel code, never assume that HZ has any given value 5

  6. The Tick Rate - The Ideal HZ Value • Changing its frequency has a reasonable impact on the system • Increasing the tick rate means the timer interrupt runs more frequently • Benefits - the timer interrupt has a higher resolution - all timed events have a higher resolution - the accuracy of timed events improves • Downside - implies more frequent timer interrupts - implies higher overhead - processor must spend more time executing the timer interrupt handler 6

  7. Jiffies • The global variable jiffies holds the number of ticks that have occurred since the system booted extern unsigned long volatile jiffies; /* <linux/jiffies.h> */ - on boot: jiffies = 0; - each timer interrupt: jiffies++; • convert forms of jiffies - second to jiffies: (second*HZ) - jiffies to second: (jiffies/HZ) ex) unsigned long next_tick = jiffies + _1; /* one tick from now */ unsigned long later = jiffies + 5 * HZ; /* five second from now */ 7

  8. jiffies_64 (jiffies on 64-bit machines) bit 63 31 0 jiffies on 32-bit machine Jiffies – Internal Representation of Jiffies • The jiffies variable has 32 bit in size on 32-bit architectures and 64-bit on 64-bit architectures - overflow: 49.7days (1000HZ / 32-bit) • jiffies_64 extern u64 jiffies_64; /* <jiffies.h> */ - overlays the jiffies variable over the start of the jiffies_64 variable - jiffies is the lower 32 bit of the full 64-bit jiffies_64 variable - time management code uses the entire 64 bits - prevents overflow of the full 64-bit value 8

  9. Jiffies – Jiffies Wraparound • equal to maximum and it is incremented, it wraps around to zero • macros for comparing tick counts #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)(unkown) – (long)(known) >= 0) #define time_before_eq(unknown, known) ((long)(known) – (long)(unkown) >= 0) unsigned long timeout = jiffies + HZ/2; /* timeout in 0.5s */ /* … */ if (timeout > jiffies) { /* we did not time out, good … */ } else { /* we time out, error … */ } unsigned long timeout = jiffies + HZ/2; /* timeout in 0.5s */ /* … */ if (time_after(jiffies, timeout)) { /* we did not time out, good … */ } else { /* we time out, error … */ } 9

  10. Hardware Clock and Timers • Real-Time Clock (RTC) - a nonvolatile device for storing the system time - the kernel reads the RTC and use it to initialize the wall time - stored in the ‘xtime’variable • System Timer - serves a much more important (and frequent) role in the kernel’s timekeeping - provide a mechanism for driving an interrupt at a periodic rate - primary system timer is the PIT (on x86) - the kernel programs the PIT on boot to drive the system timer interrupt at HZ frequency 10

  11. The Timer Interrupt Handler (1/3) • The architecture-dependent routine - registered as the interrupt handler for the system timer • Obtain the xtime_lock lock, which protects access to jiffies_64 and the wall time value, xtime • Acknowledge or reset the system timer as required • Periodically save the updated wall time to the real time clock • Call the architecture-independent timer routine, do_timer() • The architecture-independent routine: do_timer() • Increment the jiffies_64 count by one • Update resource usages for the currently running process (such as system and user time) • Run any dynamic timers that have expired • Execute scheduler_tick() • Update the wall time, which is stored in xtime • Calculate the load average 11

  12. The Timer Interrupt Handler (2/3) • do_timer( ) void do_timer (struct pt_regs *regs) { jiffies_64 ++; update_process_times(user_mode(regs)); update_times( ); } void update_process_times(int user_tick) { struct task_struct *p = current; int cpu = smp_processor_id(); int system = user_tick ^ 1; update_one_process(p, user_tick, system, cpu); run_local_timers(); scheduler_tick(user_tick, system); } 12

  13. The Timer Interrupt Handler (3/3) • update_times() • all this occurs every 1/HZ of a second void update_times(void) { unsigned long ticks; ticks = jiffies – wall_jiffies; if (ticks) { wall_jiffies += ticks; update_wall_time (ticks); } last_time_offset = 0; calc_load(ticks); } 13

  14. Timers • Bottom-half - used great for deferring work until later - not so much to delay work, but simply to not do the work now • Kernel Timer - can delaying a work during a specified amount of time - easy to use • perform some initial setup • specify an expiration time • specify a function to execute upon said expiration • activate the timer 14

  15. Timers – Using Timer (1/2) • represented by struct timer_list struct timer_list { struct list_head entry; /* entry in linked list of timers */ unsigned long expires; /* expiration value, in jiffies */ spinlock_t lock; /* lock protecting this timer */ 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 */ }; 15

  16. Timers – Using Timer (2/2) • Using 1. define using timer struct timer_list my_timer; 2. initialize the timer init_timer(&my_timer); 3. setting the timer funtions my_timer.expires = jiffies + delay; my_timer.data = 0; my_timer.function = my_function; 4. activate the timer add_timer(&my_timer); 16

  17. Timers – Timer Race condition • potential race conditions exist (run asynchronously) - a timer could be executed another processor in multi-processing system - a potential race condition that must be guarded against exists when deleting timers • delete timer - del_timer(&my_timer); - del_timer_sync(&my_timer); • modify timer: changes the expiration of a given timer - del_timer(my_timer); my_timer->expires = jiffies + new_delay; add_timer(my_timer); - mod_timer(&my_timer, jiffies+new_delay); 17

  18. Timers – The Timer Implementation • The Timer Implementation - the kernel executes timers in bottom-half context after the timer interrupt completes - the timer interrupt handler runs update_process_times() which calls run_local_timers() - the kernel partitions timers into five groups based on their expiration value - timers move down through the groups as their expiration time draws closer void run_local_timers(void) { raise_softirq(TIMER_SOFTIRQ); } 18

  19. Delaying Execution • kernel code (especially drivers) needs a way to delay execution for some time without using timers or bottom-half mechanism - usually to allow hardware time to complete a given task - network card driver should wait at least the two microseconds before continuing • the solutions (depending on the semantics of the delay) - Busy Looping - Small Delays - schedule_timeout() 19

  20. Delaying Execution – Busy looping • Busy looping: spin in a loop until the desired number of clock ticks pass • reschedule for current process - conditionally invokes the scheduler only if there is some more important task to run unsigned long delay = jiffies + 5 * HZ; while (time_before(jiffies, delay)) ; unsigned long delay = jiffies + 5 * HZ; while (time_before(jiffies, delay)) cond_resched(); 20

  21. Delaying Execution – Small Delays • requires very short and rather precise delays - kernel provide two functions for microsecond and millisecond delays - delays execution by busy looping for the specified number of microseconds or milliseconds • using the functions - the udelay() function should be called only for small delays - larger delays on fast machines might result in overflow - as delays over 1 millisecond for longer durations mdelay() function should be called void udelay(unsigned long usecs); /* udelay(150) */ void mdelay(unsigned long msecs); /* mdelay(150) */ 21

  22. Delaying Execution – schedule_timeout() • optimal method - task to sleep until at least the specified time has elapsed - the kernel wakes the task up and places it back on the runqueue • using the functions • sleeping on a waiting queue, with a timeout - first occur want to make desirable to wait for a specific event or wait for a specified time to elapse - call schedule_timeout() instead of schedule() after placing itself on a wait queue /* set task’state to interruptible sleep */ set_current_state(TASK_INTERRUPTIBLE); /*TASK_UNINTERRUPTIBLE */ /* take a nap and wake up in “s” seconds */ schedule_timeout(s * HZ); 22

More Related