pktgen: spin using hrtimer
Stephen Hemminger [Sat, 29 Aug 2009 06:41:29 +0000 (23:41 -0700)]
This changes how the pktgen thread spins/waits between
packets if delay is configured. It uses a high res timer to
wait for time to arrive.

Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

kernel/hrtimer.c
net/core/pktgen.c

index 49da79a..05071bf 100644 (file)
@@ -485,6 +485,7 @@ void hrtimer_init_on_stack(struct hrtimer *timer, clockid_t clock_id,
        debug_object_init_on_stack(timer, &hrtimer_debug_descr);
        __hrtimer_init(timer, clock_id, mode);
 }
+EXPORT_SYMBOL_GPL(hrtimer_init_on_stack);
 
 void destroy_hrtimer_on_stack(struct hrtimer *timer)
 {
@@ -1477,6 +1478,7 @@ void hrtimer_init_sleeper(struct hrtimer_sleeper *sl, struct task_struct *task)
        sl->timer.function = hrtimer_wakeup;
        sl->task = task;
 }
+EXPORT_SYMBOL_GPL(hrtimer_init_sleeper);
 
 static int __sched do_nanosleep(struct hrtimer_sleeper *t, enum hrtimer_mode mode)
 {
index bede00b..3045dd1 100644 (file)
 #include <linux/ioport.h>
 #include <linux/interrupt.h>
 #include <linux/capability.h>
+#include <linux/hrtimer.h>
 #include <linux/freezer.h>
 #include <linux/delay.h>
 #include <linux/timer.h>
@@ -2086,33 +2087,40 @@ static void pktgen_setup_inject(struct pktgen_dev *pkt_dev)
        pkt_dev->nflows = 0;
 }
 
-static inline s64 delta_ns(ktime_t a, ktime_t b)
-{
-       return ktime_to_ns(ktime_sub(a, b));
-}
 
 static void spin(struct pktgen_dev *pkt_dev, ktime_t spin_until)
 {
-       ktime_t start, now;
-       s64 dt;
+       ktime_t start;
+       s32 remaining;
+       struct hrtimer_sleeper t;
 
-       start = now = ktime_now();
+       hrtimer_init_on_stack(&t.timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
+       hrtimer_set_expires(&t.timer, spin_until);
+
+       remaining = ktime_to_us(hrtimer_expires_remaining(&t.timer));
+       if (remaining <= 0)
+               return;
 
-       while ((dt = delta_ns(spin_until, now)) > 0) {
-               /* TODO: optimize sleeping behavior */
-               if (dt > TICK_NSEC)
-                       schedule_timeout_interruptible(1);
-               else if (dt > 100*NSEC_PER_USEC) {
-                       if (!pkt_dev->running)
-                               return;
-                       if (need_resched())
+       start = ktime_now();
+       if (remaining < 100)
+               udelay(remaining);      /* really small just spin */
+       else {
+               /* see do_nanosleep */
+               hrtimer_init_sleeper(&t, current);
+               do {
+                       set_current_state(TASK_INTERRUPTIBLE);
+                       hrtimer_start_expires(&t.timer, HRTIMER_MODE_ABS);
+                       if (!hrtimer_active(&t.timer))
+                               t.task = NULL;
+
+                       if (likely(t.task))
                                schedule();
-               }
 
-               now = ktime_now();
+                       hrtimer_cancel(&t.timer);
+               } while (t.task && pkt_dev->running && !signal_pending(current));
+               __set_current_state(TASK_RUNNING);
        }
-
-       pkt_dev->idle_acc += ktime_to_ns(ktime_sub(now, start));
+       pkt_dev->idle_acc += ktime_to_ns(ktime_sub(ktime_now(), start));
 }
 
 static inline void set_pkt_overhead(struct pktgen_dev *pkt_dev)
@@ -3360,8 +3368,7 @@ static void pktgen_xmit(struct pktgen_dev *pkt_dev)
        int ret;
 
        if (pkt_dev->delay) {
-               if (ktime_lt(ktime_now(), pkt_dev->next_tx))
-                       spin(pkt_dev, pkt_dev->next_tx);
+               spin(pkt_dev, pkt_dev->next_tx);
 
                /* This is max DELAY, this has special meaning of
                 * "never transmit"