Measuring Time

Chapter 7

Measuring time lapses

  • Timer interrupts
  • Generated by system hardware
  • Interval programmed at boot time by kernel
  • 100 or 1000 interrupts per second for most platforms
    • See HZ macro
  • jiffies{_64,} (internal kernel counter)
    • Number of clock ticks since last boot for a given CPU
    • Has nothing to do with wall clock time

Using jiffies

  • Read only
  • Needed to calculate a future time stamp
  • time_{before,after}{,_eq}()
  • struct timeval & struct time_spec
    • Used to exchange time representations with user space programs

Processor-Specific Registers

  • Most modern CPUs have a counter register
    • Used to count clock cycles
  • Depends on platform but this register may or may not be readable
  • Handle overflows if reg is not writable
  • rdtsc on x86
    • Read (rd) time stamp counter (tsc) register
    • Different on other platforms

Knowing the Current Time

  • Drivers use jiffies to calculate time intervals across events
    • For example, to tell double-clicks from single-clicks
  • Processor specific registers for more precise measurements
  • Use do_gettimeofday to get absolute timestamp in kernel
    • Uses struct timeval to export time stamp
  • Otherwise real world time is best left for user space where the c library offers better support
    • clock_gettime(3) for example

Long Delays

Chapter 7

Long Delays: Approach #1: Busy waiting

  • A loop that monitors the jiffy counter
  • while (time_before(jiffies, j1))
    cpu_relax();
  • Call to cpu_relax invokes a way of saying you’re not doing much with the processor right now
  • If kernel not configured for preemption, loop locks processor for duration of delay
  • Avoid: what does relax even mean?? How relaxed?? (not very)
  • On x86: cpu_relax <==> no-op

Long Delays: Approach #2: Yielding the processor

  • Release the cpu when not interested in it
  • while (time_before(jiffies, j1))
    schedule();
  • The current process does nothing but release the cpu but remains in run queue
  • On realtime: schedule just re-schedules the caller!

Long Delays: Approach #3: Timeouts

  • Ask kernel to do a delay for you
  • wait_event _timeout(...);
    • Wait queue to wait for some other event but also run within a certain period of time
    • Returns after timeout
  • wait_event_interruptable_timeout(...);
    • Interruptible sleep

Short Delays

  • Drivers deal with latencies using short delays
  • ndelay, udelay, mdelay
    • Nanoseconds, microseconds and milliseconds

Kernel Timers

  • Asynchronous execution
  • Call f(x,y,z) at some point in the future
  • Used to schedule an action to happen later without blocking the current process
    • For example, polling a device by checking its state at regular intervals

Tasklets

  • Data structure that must be initialized before use.
    • struct tasklet_struct { (*func)(u long); u long data; };
  • Mostly used in interrupt management and run at interrupt time
  • Let kernel decide when to run the task
  • Run in atomic context

Workqueues

  • Similar to tasklets with a few differences
  • workqueues run in kernel process context while tasklets run in atomic context
  • Kernel code can delay execution of workqueue functions
  • Key difference is that tasklets execute quickly and in atomic mode
  • Both tasklets and workqueues run on the same processor they were submitted

The Shared Queue

  • Used occasionally to submit tasks if in driver
  • Tasks may take longer to execute since there’s sharing
  • Struct jiq_work. Actual code below:
prepare_to_wait(&jiq_wait, &wait, TASK_INTERRUPTIBLE); 
schedule_work(&jiq_work); 
schedule( ); 
finish_wait(&jiq_wait, &wait);