From: Stephen Hemminger <shemminger@vyatta.com>
To: David Miller <davem@davemloft.net>,
Robert Olsson <Robert.Olsson@data.slu.se>
Cc: netdev@vger.kernel.org
Cc: Thomas Gleixner <tglx@linutronix.de>, Ingo Molnar <mingo@elte.hu>
Subject: [RFC 1/4] pktgen: convert to use ktime_t
Date: Tue, 25 Aug 2009 23:15:14 -0700 [thread overview]
Message-ID: <20090826061728.614907965@vyatta.com> (raw)
In-Reply-To: 20090826061513.755294685@vyatta.com
[-- Attachment #1: pktgen-ktime.patch --]
[-- Type: text/plain, Size: 11538 bytes --]
The kernel ktime_t is a nice generic infrastructure for mananging
high resolution times, as is done in pktgen. It also switchs from
using gettimeofday() to a monotonic clock which avoids any
NTP disturbance. In the process base resolution is increased
to nanoseconds.
Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>
--- a/net/core/pktgen.c 2009-08-25 21:36:52.469711951 -0700
+++ b/net/core/pktgen.c 2009-08-25 22:35:59.321461854 -0700
@@ -246,16 +246,14 @@ struct pktgen_dev {
int max_pkt_size; /* = ETH_ZLEN; */
int pkt_overhead; /* overhead for MPLS, VLANs, IPSEC etc */
int nfrags;
- __u32 delay_us; /* Default delay */
- __u32 delay_ns;
+ u64 delay; /* nano-seconds */
+
__u64 count; /* Default No packets to send */
__u64 sofar; /* How many pkts we've sent so far */
__u64 tx_bytes; /* How many bytes we've transmitted */
__u64 errors; /* Errors when trying to transmit, pkts will be re-sent */
/* runtime counters relating to clone_skb */
- __u64 next_tx_us; /* timestamp of when to tx next */
- __u32 next_tx_ns;
__u64 allocated_skbs;
__u32 clone_count;
@@ -263,9 +261,11 @@ struct pktgen_dev {
* Or a failed transmit of some sort? This will keep
* sequence numbers in order, for example.
*/
- __u64 started_at; /* micro-seconds */
- __u64 stopped_at; /* micro-seconds */
- __u64 idle_acc; /* micro-seconds */
+ ktime_t next_tx;
+ ktime_t started_at;
+ ktime_t stopped_at;
+ u64 idle_acc; /* nano-seconds */
+
__u32 seq_num;
int clone_skb; /* Use multiple SKBs during packet gen. If this number
@@ -397,23 +397,20 @@ struct pktgen_thread {
#define REMOVE 1
#define FIND 0
-/** Convert to micro-seconds */
-static inline __u64 tv_to_us(const struct timeval *tv)
+static inline ktime_t ktime_now(void)
{
- __u64 us = tv->tv_usec;
- us += (__u64) tv->tv_sec * (__u64) 1000000;
- return us;
+ struct timespec ts;
+ ktime_get_ts(&ts);
+
+ return timespec_to_ktime(ts);
}
-static __u64 getCurUs(void)
+/* This works even if 32 bit because of careful byte order choice */
+static inline int ktime_lt(const ktime_t cmp1, const ktime_t cmp2)
{
- struct timeval tv;
- do_gettimeofday(&tv);
- return tv_to_us(&tv);
+ return cmp1.tv64 < cmp2.tv64;
}
-/* old include end */
-
static char version[] __initdata = VERSION;
static int pktgen_remove_device(struct pktgen_thread *t, struct pktgen_dev *i);
@@ -510,9 +507,8 @@ static const struct file_operations pktg
static int pktgen_if_show(struct seq_file *seq, void *v)
{
struct pktgen_dev *pkt_dev = seq->private;
- __u64 sa;
- __u64 stopped;
- __u64 now = getCurUs();
+ ktime_t stopped;
+ struct timeval trun, idle;
seq_printf(seq,
"Params: count %llu min_pkt_size: %u max_pkt_size: %u\n",
@@ -520,9 +516,8 @@ static int pktgen_if_show(struct seq_fil
pkt_dev->max_pkt_size);
seq_printf(seq,
- " frags: %d delay: %u clone_skb: %d ifname: %s\n",
- pkt_dev->nfrags,
- 1000 * pkt_dev->delay_us + pkt_dev->delay_ns,
+ " frags: %d delay: %llu clone_skb: %d ifname: %s\n",
+ pkt_dev->nfrags, (unsigned long long) pkt_dev->delay,
pkt_dev->clone_skb, pkt_dev->odev->name);
seq_printf(seq, " flows: %u flowlen: %u\n", pkt_dev->cflows,
@@ -654,17 +649,19 @@ static int pktgen_if_show(struct seq_fil
seq_puts(seq, "\n");
- sa = pkt_dev->started_at;
- stopped = pkt_dev->stopped_at;
- if (pkt_dev->running)
- stopped = now; /* not really stopped, more like last-running-at */
+ /* not really stopped, more like last-running-at */
+ stopped = pkt_dev->running ? ktime_now() : pkt_dev->stopped_at;
+ trun = ktime_to_timeval(ktime_sub(stopped, pkt_dev->started_at));
+ idle = ns_to_timeval(pkt_dev->idle_acc);
seq_printf(seq,
- "Current:\n pkts-sofar: %llu errors: %llu\n started: %lluus stopped: %lluus idle: %lluus\n",
+ "Current:\n pkts-sofar: %llu errors: %llu\n",
(unsigned long long)pkt_dev->sofar,
- (unsigned long long)pkt_dev->errors, (unsigned long long)sa,
- (unsigned long long)stopped,
- (unsigned long long)pkt_dev->idle_acc);
+ (unsigned long long)pkt_dev->errors);
+
+ seq_printf(seq, " running: %d.%06ds idle: %d.%06ds\n",
+ (int)trun.tv_sec, (int)trun.tv_usec,
+ (int)idle.tv_sec, (int)idle.tv_usec);
seq_printf(seq,
" seq_num: %d cur_dst_mac_offset: %d cur_src_mac_offset: %d\n",
@@ -950,15 +947,13 @@ static ssize_t pktgen_if_write(struct fi
return len;
}
i += len;
- if (value == 0x7FFFFFFF) {
- pkt_dev->delay_us = 0x7FFFFFFF;
- pkt_dev->delay_ns = 0;
- } else {
- pkt_dev->delay_us = value / 1000;
- pkt_dev->delay_ns = value % 1000;
- }
- sprintf(pg_result, "OK: delay=%u",
- 1000 * pkt_dev->delay_us + pkt_dev->delay_ns);
+ if (value == 0x7FFFFFFF)
+ pkt_dev->delay = ULLONG_MAX;
+ else
+ pkt_dev->delay = (u64)value * NSEC_PER_USEC;
+
+ sprintf(pg_result, "OK: delay=%llu",
+ (unsigned long long) pkt_dev->delay);
return count;
}
if (!strcmp(name, "udp_src_min")) {
@@ -2089,27 +2084,33 @@ static void pktgen_setup_inject(struct p
pkt_dev->nflows = 0;
}
-static void spin(struct pktgen_dev *pkt_dev, __u64 spin_until_us)
+static inline s64 delta_ns(ktime_t a, ktime_t b)
{
- __u64 start;
- __u64 now;
+ return ktime_to_ns(ktime_sub(a, b));
+}
- start = now = getCurUs();
- while (now < spin_until_us) {
+static void spin(struct pktgen_dev *pkt_dev, ktime_t spin_until)
+{
+ ktime_t start, now;
+ s64 dt;
+
+ start = now = ktime_now();
+
+ while ((dt = delta_ns(spin_until, now)) > 0) {
/* TODO: optimize sleeping behavior */
- if (spin_until_us - now > jiffies_to_usecs(1) + 1)
+ if (dt > TICK_NSEC)
schedule_timeout_interruptible(1);
- else if (spin_until_us - now > 100) {
+ else if (dt > 100*NSEC_PER_USEC) {
if (!pkt_dev->running)
return;
if (need_resched())
schedule();
}
- now = getCurUs();
+ now = ktime_now();
}
- pkt_dev->idle_acc += now - start;
+ pkt_dev->idle_acc += ktime_to_ns(ktime_sub(now, start));
}
static inline void set_pkt_overhead(struct pktgen_dev *pkt_dev)
@@ -3072,9 +3073,9 @@ static void pktgen_run(struct pktgen_thr
pktgen_clear_counters(pkt_dev);
pkt_dev->running = 1; /* Cranke yeself! */
pkt_dev->skb = NULL;
- pkt_dev->started_at = getCurUs();
- pkt_dev->next_tx_us = getCurUs(); /* Transmit immediately */
- pkt_dev->next_tx_ns = 0;
+ pkt_dev->started_at =
+ pkt_dev->next_tx = ktime_now();
+
set_pkt_overhead(pkt_dev);
strcpy(pkt_dev->result, "Starting");
@@ -3193,28 +3194,21 @@ static void pktgen_reset_all_threads(voi
static void show_results(struct pktgen_dev *pkt_dev, int nr_frags)
{
- __u64 total_us, bps, mbps, pps, idle;
+ __u64 bps, mbps, pps;
char *p = pkt_dev->result;
-
- total_us = pkt_dev->stopped_at - pkt_dev->started_at;
-
- idle = pkt_dev->idle_acc;
-
- p += sprintf(p, "OK: %llu(c%llu+d%llu) usec, %llu (%dbyte,%dfrags)\n",
- (unsigned long long)total_us,
- (unsigned long long)(total_us - idle),
- (unsigned long long)idle,
+ ktime_t elapsed = ktime_sub(pkt_dev->stopped_at,
+ pkt_dev->started_at);
+ ktime_t idle = ns_to_ktime(pkt_dev->idle_acc);
+
+ p += sprintf(p, "OK: %llu(c%llu+d%llu) nsec, %llu (%dbyte,%dfrags)\n",
+ (unsigned long long)ktime_to_us(elapsed),
+ (unsigned long long)ktime_to_us(ktime_sub(elapsed, idle)),
+ (unsigned long long)ktime_to_us(idle),
(unsigned long long)pkt_dev->sofar,
pkt_dev->cur_pkt_size, nr_frags);
- pps = pkt_dev->sofar * USEC_PER_SEC;
-
- while ((total_us >> 32) != 0) {
- pps >>= 1;
- total_us >>= 1;
- }
-
- do_div(pps, total_us);
+ pps = div64_u64(pkt_dev->sofar * NSEC_PER_SEC,
+ ktime_to_ns(elapsed));
bps = pps * 8 * pkt_dev->cur_pkt_size;
@@ -3239,7 +3233,7 @@ static int pktgen_stop_device(struct pkt
return -EINVAL;
}
- pkt_dev->stopped_at = getCurUs();
+ pkt_dev->stopped_at = ktime_now();
pkt_dev->running = 0;
show_results(pkt_dev, nr_frags);
@@ -3258,7 +3252,7 @@ static struct pktgen_dev *next_to_run(st
continue;
if (best == NULL)
best = pkt_dev;
- else if (pkt_dev->next_tx_us < best->next_tx_us)
+ else if (ktime_lt(pkt_dev->next_tx, best->next_tx))
best = pkt_dev;
}
if_unlock(t);
@@ -3354,23 +3348,19 @@ static __inline__ void pktgen_xmit(struc
int (*xmit)(struct sk_buff *, struct net_device *)
= odev->netdev_ops->ndo_start_xmit;
struct netdev_queue *txq;
- __u64 idle_start = 0;
u16 queue_map;
int ret;
- if (pkt_dev->delay_us || pkt_dev->delay_ns) {
- u64 now;
-
- now = getCurUs();
- if (now < pkt_dev->next_tx_us)
- spin(pkt_dev, pkt_dev->next_tx_us);
+ if (pkt_dev->delay) {
+ if (ktime_lt(ktime_now(), pkt_dev->next_tx))
+ spin(pkt_dev, pkt_dev->next_tx);
/* This is max DELAY, this has special meaning of
* "never transmit"
*/
- if (pkt_dev->delay_us == 0x7FFFFFFF) {
- pkt_dev->next_tx_us = getCurUs() + pkt_dev->delay_us;
- pkt_dev->next_tx_ns = pkt_dev->delay_ns;
+ if (pkt_dev->delay == ULLONG_MAX) {
+ pkt_dev->next_tx = ktime_add_ns(pkt_dev->next_tx,
+ LONG_MAX);
goto out;
}
}
@@ -3386,7 +3376,7 @@ static __inline__ void pktgen_xmit(struc
if (netif_tx_queue_stopped(txq) ||
netif_tx_queue_frozen(txq) ||
need_resched()) {
- idle_start = getCurUs();
+ ktime_t idle_start = ktime_now();
if (!netif_running(odev)) {
pktgen_stop_device(pkt_dev);
@@ -3397,12 +3387,12 @@ static __inline__ void pktgen_xmit(struc
if (need_resched())
schedule();
- pkt_dev->idle_acc += getCurUs() - idle_start;
+ pkt_dev->idle_acc += ktime_to_ns(ktime_sub(ktime_now(),
+ idle_start));
if (netif_tx_queue_stopped(txq) ||
netif_tx_queue_frozen(txq)) {
- pkt_dev->next_tx_us = getCurUs(); /* TODO */
- pkt_dev->next_tx_ns = 0;
+ pkt_dev->next_tx = ktime_now();
goto out; /* Try the next interface */
}
}
@@ -3459,22 +3449,10 @@ static __inline__ void pktgen_xmit(struc
pkt_dev->last_ok = 0;
}
- pkt_dev->next_tx_us = getCurUs();
- pkt_dev->next_tx_ns = 0;
-
- pkt_dev->next_tx_us += pkt_dev->delay_us;
- pkt_dev->next_tx_ns += pkt_dev->delay_ns;
-
- if (pkt_dev->next_tx_ns > 1000) {
- pkt_dev->next_tx_us++;
- pkt_dev->next_tx_ns -= 1000;
- }
- }
-
- else { /* Retry it next time */
+ pkt_dev->next_tx = ktime_add_ns(ktime_now(), pkt_dev->delay);
+ } else { /* Retry it next time */
pkt_dev->last_ok = 0;
- pkt_dev->next_tx_us = getCurUs(); /* TODO */
- pkt_dev->next_tx_ns = 0;
+ pkt_dev->next_tx = ktime_now();
}
__netif_tx_unlock_bh(txq);
@@ -3482,14 +3460,17 @@ static __inline__ void pktgen_xmit(struc
/* If pkt_dev->count is zero, then run forever */
if ((pkt_dev->count != 0) && (pkt_dev->sofar >= pkt_dev->count)) {
if (atomic_read(&(pkt_dev->skb->users)) != 1) {
- idle_start = getCurUs();
+ ktime_t idle_start = ktime_now();
+
while (atomic_read(&(pkt_dev->skb->users)) != 1) {
if (signal_pending(current)) {
break;
}
schedule();
}
- pkt_dev->idle_acc += getCurUs() - idle_start;
+ pkt_dev->idle_acc += ktime_to_ns(ktime_sub(ktime_now(),
+ idle_start));
+
}
/* Done with this */
@@ -3651,8 +3632,7 @@ static int pktgen_add_device(struct pktg
pkt_dev->max_pkt_size = ETH_ZLEN;
pkt_dev->nfrags = 0;
pkt_dev->clone_skb = pg_clone_skb_d;
- pkt_dev->delay_us = pg_delay_d / 1000;
- pkt_dev->delay_ns = pg_delay_d % 1000;
+ pkt_dev->delay = pg_delay_d;
pkt_dev->count = pg_count_d;
pkt_dev->sofar = 0;
pkt_dev->udp_src_min = 9; /* sink port */
--
next prev parent reply other threads:[~2009-08-26 6:25 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2009-08-26 6:15 [RFC 0/4] pktgen patches Stephen Hemminger
2009-08-26 6:15 ` Stephen Hemminger [this message]
2009-08-26 6:15 ` [RFC 2/4] pktgen: spin using hrtimer Stephen Hemminger
2009-08-26 6:15 ` [RFC 3/4] pktgen: clock optimizations Stephen Hemminger
2009-08-26 6:15 ` [RFC 4/4] pktgen: minor cleanup Stephen Hemminger
2009-08-26 6:54 ` [RFC 0/4] pktgen patches Eric Dumazet
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20090826061728.614907965@vyatta.com \
--to=shemminger@vyatta.com \
--cc=Robert.Olsson@data.slu.se \
--cc=davem@davemloft.net \
--cc=netdev@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).