pktgen: convert to use ktime_t
The kernel ktime_t is a nice generic infrastructure for mananging high resolution times, as is done in pktgen. Signed-off-by: Stephen Hemminger <shemminger@vyatta.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
5c9d191c16
commit
fd29cf7262
@ -246,16 +246,14 @@ struct pktgen_dev {
|
|||||||
int max_pkt_size; /* = ETH_ZLEN; */
|
int max_pkt_size; /* = ETH_ZLEN; */
|
||||||
int pkt_overhead; /* overhead for MPLS, VLANs, IPSEC etc */
|
int pkt_overhead; /* overhead for MPLS, VLANs, IPSEC etc */
|
||||||
int nfrags;
|
int nfrags;
|
||||||
__u32 delay_us; /* Default delay */
|
u64 delay; /* nano-seconds */
|
||||||
__u32 delay_ns;
|
|
||||||
__u64 count; /* Default No packets to send */
|
__u64 count; /* Default No packets to send */
|
||||||
__u64 sofar; /* How many pkts we've sent so far */
|
__u64 sofar; /* How many pkts we've sent so far */
|
||||||
__u64 tx_bytes; /* How many bytes we've transmitted */
|
__u64 tx_bytes; /* How many bytes we've transmitted */
|
||||||
__u64 errors; /* Errors when trying to transmit, pkts will be re-sent */
|
__u64 errors; /* Errors when trying to transmit, pkts will be re-sent */
|
||||||
|
|
||||||
/* runtime counters relating to clone_skb */
|
/* runtime counters relating to clone_skb */
|
||||||
__u64 next_tx_us; /* timestamp of when to tx next */
|
|
||||||
__u32 next_tx_ns;
|
|
||||||
|
|
||||||
__u64 allocated_skbs;
|
__u64 allocated_skbs;
|
||||||
__u32 clone_count;
|
__u32 clone_count;
|
||||||
@ -263,9 +261,11 @@ struct pktgen_dev {
|
|||||||
* Or a failed transmit of some sort? This will keep
|
* Or a failed transmit of some sort? This will keep
|
||||||
* sequence numbers in order, for example.
|
* sequence numbers in order, for example.
|
||||||
*/
|
*/
|
||||||
__u64 started_at; /* micro-seconds */
|
ktime_t next_tx;
|
||||||
__u64 stopped_at; /* micro-seconds */
|
ktime_t started_at;
|
||||||
__u64 idle_acc; /* micro-seconds */
|
ktime_t stopped_at;
|
||||||
|
u64 idle_acc; /* nano-seconds */
|
||||||
|
|
||||||
__u32 seq_num;
|
__u32 seq_num;
|
||||||
|
|
||||||
int clone_skb; /* Use multiple SKBs during packet gen. If this number
|
int clone_skb; /* Use multiple SKBs during packet gen. If this number
|
||||||
@ -397,23 +397,20 @@ struct pktgen_thread {
|
|||||||
#define REMOVE 1
|
#define REMOVE 1
|
||||||
#define FIND 0
|
#define FIND 0
|
||||||
|
|
||||||
/** Convert to micro-seconds */
|
static inline ktime_t ktime_now(void)
|
||||||
static inline __u64 tv_to_us(const struct timeval *tv)
|
|
||||||
{
|
{
|
||||||
__u64 us = tv->tv_usec;
|
struct timespec ts;
|
||||||
us += (__u64) tv->tv_sec * (__u64) 1000000;
|
ktime_get_ts(&ts);
|
||||||
return us;
|
|
||||||
|
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;
|
return cmp1.tv64 < cmp2.tv64;
|
||||||
do_gettimeofday(&tv);
|
|
||||||
return tv_to_us(&tv);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* old include end */
|
|
||||||
|
|
||||||
static const char version[] __initconst = VERSION;
|
static const char version[] __initconst = VERSION;
|
||||||
|
|
||||||
static int pktgen_remove_device(struct pktgen_thread *t, struct pktgen_dev *i);
|
static int pktgen_remove_device(struct pktgen_thread *t, struct pktgen_dev *i);
|
||||||
@ -510,9 +507,8 @@ static const struct file_operations pktgen_fops = {
|
|||||||
static int pktgen_if_show(struct seq_file *seq, void *v)
|
static int pktgen_if_show(struct seq_file *seq, void *v)
|
||||||
{
|
{
|
||||||
const struct pktgen_dev *pkt_dev = seq->private;
|
const struct pktgen_dev *pkt_dev = seq->private;
|
||||||
__u64 sa;
|
ktime_t stopped;
|
||||||
__u64 stopped;
|
u64 idle;
|
||||||
__u64 now = getCurUs();
|
|
||||||
|
|
||||||
seq_printf(seq,
|
seq_printf(seq,
|
||||||
"Params: count %llu min_pkt_size: %u max_pkt_size: %u\n",
|
"Params: count %llu min_pkt_size: %u max_pkt_size: %u\n",
|
||||||
@ -520,9 +516,8 @@ static int pktgen_if_show(struct seq_file *seq, void *v)
|
|||||||
pkt_dev->max_pkt_size);
|
pkt_dev->max_pkt_size);
|
||||||
|
|
||||||
seq_printf(seq,
|
seq_printf(seq,
|
||||||
" frags: %d delay: %u clone_skb: %d ifname: %s\n",
|
" frags: %d delay: %llu clone_skb: %d ifname: %s\n",
|
||||||
pkt_dev->nfrags,
|
pkt_dev->nfrags, (unsigned long long) pkt_dev->delay,
|
||||||
1000 * pkt_dev->delay_us + pkt_dev->delay_ns,
|
|
||||||
pkt_dev->clone_skb, pkt_dev->odev->name);
|
pkt_dev->clone_skb, pkt_dev->odev->name);
|
||||||
|
|
||||||
seq_printf(seq, " flows: %u flowlen: %u\n", pkt_dev->cflows,
|
seq_printf(seq, " flows: %u flowlen: %u\n", pkt_dev->cflows,
|
||||||
@ -654,17 +649,21 @@ static int pktgen_if_show(struct seq_file *seq, void *v)
|
|||||||
|
|
||||||
seq_puts(seq, "\n");
|
seq_puts(seq, "\n");
|
||||||
|
|
||||||
sa = pkt_dev->started_at;
|
/* not really stopped, more like last-running-at */
|
||||||
stopped = pkt_dev->stopped_at;
|
stopped = pkt_dev->running ? ktime_now() : pkt_dev->stopped_at;
|
||||||
if (pkt_dev->running)
|
idle = pkt_dev->idle_acc;
|
||||||
stopped = now; /* not really stopped, more like last-running-at */
|
do_div(idle, NSEC_PER_USEC);
|
||||||
|
|
||||||
seq_printf(seq,
|
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->sofar,
|
||||||
(unsigned long long)pkt_dev->errors, (unsigned long long)sa,
|
(unsigned long long)pkt_dev->errors);
|
||||||
(unsigned long long)stopped,
|
|
||||||
(unsigned long long)pkt_dev->idle_acc);
|
seq_printf(seq,
|
||||||
|
" started: %lluus stopped: %lluus idle: %lluus\n",
|
||||||
|
(unsigned long long) ktime_to_us(pkt_dev->started_at),
|
||||||
|
(unsigned long long) ktime_to_us(stopped),
|
||||||
|
(unsigned long long) idle);
|
||||||
|
|
||||||
seq_printf(seq,
|
seq_printf(seq,
|
||||||
" seq_num: %d cur_dst_mac_offset: %d cur_src_mac_offset: %d\n",
|
" seq_num: %d cur_dst_mac_offset: %d cur_src_mac_offset: %d\n",
|
||||||
@ -950,15 +949,13 @@ static ssize_t pktgen_if_write(struct file *file,
|
|||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
i += len;
|
i += len;
|
||||||
if (value == 0x7FFFFFFF) {
|
if (value == 0x7FFFFFFF)
|
||||||
pkt_dev->delay_us = 0x7FFFFFFF;
|
pkt_dev->delay = ULLONG_MAX;
|
||||||
pkt_dev->delay_ns = 0;
|
else
|
||||||
} else {
|
pkt_dev->delay = (u64)value * NSEC_PER_USEC;
|
||||||
pkt_dev->delay_us = value / 1000;
|
|
||||||
pkt_dev->delay_ns = value % 1000;
|
sprintf(pg_result, "OK: delay=%llu",
|
||||||
}
|
(unsigned long long) pkt_dev->delay);
|
||||||
sprintf(pg_result, "OK: delay=%u",
|
|
||||||
1000 * pkt_dev->delay_us + pkt_dev->delay_ns);
|
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
if (!strcmp(name, "udp_src_min")) {
|
if (!strcmp(name, "udp_src_min")) {
|
||||||
@ -2089,27 +2086,33 @@ static void pktgen_setup_inject(struct pktgen_dev *pkt_dev)
|
|||||||
pkt_dev->nflows = 0;
|
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;
|
return ktime_to_ns(ktime_sub(a, b));
|
||||||
__u64 now;
|
}
|
||||||
|
|
||||||
start = now = getCurUs();
|
static void spin(struct pktgen_dev *pkt_dev, ktime_t spin_until)
|
||||||
while (now < spin_until_us) {
|
{
|
||||||
|
ktime_t start, now;
|
||||||
|
s64 dt;
|
||||||
|
|
||||||
|
start = now = ktime_now();
|
||||||
|
|
||||||
|
while ((dt = delta_ns(spin_until, now)) > 0) {
|
||||||
/* TODO: optimize sleeping behavior */
|
/* TODO: optimize sleeping behavior */
|
||||||
if (spin_until_us - now > jiffies_to_usecs(1) + 1)
|
if (dt > TICK_NSEC)
|
||||||
schedule_timeout_interruptible(1);
|
schedule_timeout_interruptible(1);
|
||||||
else if (spin_until_us - now > 100) {
|
else if (dt > 100*NSEC_PER_USEC) {
|
||||||
if (!pkt_dev->running)
|
if (!pkt_dev->running)
|
||||||
return;
|
return;
|
||||||
if (need_resched())
|
if (need_resched())
|
||||||
schedule();
|
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)
|
static inline void set_pkt_overhead(struct pktgen_dev *pkt_dev)
|
||||||
@ -3070,9 +3073,9 @@ static void pktgen_run(struct pktgen_thread *t)
|
|||||||
pktgen_clear_counters(pkt_dev);
|
pktgen_clear_counters(pkt_dev);
|
||||||
pkt_dev->running = 1; /* Cranke yeself! */
|
pkt_dev->running = 1; /* Cranke yeself! */
|
||||||
pkt_dev->skb = NULL;
|
pkt_dev->skb = NULL;
|
||||||
pkt_dev->started_at = getCurUs();
|
pkt_dev->started_at =
|
||||||
pkt_dev->next_tx_us = getCurUs(); /* Transmit immediately */
|
pkt_dev->next_tx = ktime_now();
|
||||||
pkt_dev->next_tx_ns = 0;
|
|
||||||
set_pkt_overhead(pkt_dev);
|
set_pkt_overhead(pkt_dev);
|
||||||
|
|
||||||
strcpy(pkt_dev->result, "Starting");
|
strcpy(pkt_dev->result, "Starting");
|
||||||
@ -3188,28 +3191,21 @@ static void pktgen_reset_all_threads(void)
|
|||||||
|
|
||||||
static void show_results(struct pktgen_dev *pkt_dev, int nr_frags)
|
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;
|
char *p = pkt_dev->result;
|
||||||
|
ktime_t elapsed = ktime_sub(pkt_dev->stopped_at,
|
||||||
|
pkt_dev->started_at);
|
||||||
|
ktime_t idle = ns_to_ktime(pkt_dev->idle_acc);
|
||||||
|
|
||||||
total_us = pkt_dev->stopped_at - pkt_dev->started_at;
|
p += sprintf(p, "OK: %llu(c%llu+d%llu) nsec, %llu (%dbyte,%dfrags)\n",
|
||||||
|
(unsigned long long)ktime_to_us(elapsed),
|
||||||
idle = pkt_dev->idle_acc;
|
(unsigned long long)ktime_to_us(ktime_sub(elapsed, idle)),
|
||||||
|
(unsigned long long)ktime_to_us(idle),
|
||||||
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,
|
|
||||||
(unsigned long long)pkt_dev->sofar,
|
(unsigned long long)pkt_dev->sofar,
|
||||||
pkt_dev->cur_pkt_size, nr_frags);
|
pkt_dev->cur_pkt_size, nr_frags);
|
||||||
|
|
||||||
pps = pkt_dev->sofar * USEC_PER_SEC;
|
pps = div64_u64(pkt_dev->sofar * NSEC_PER_SEC,
|
||||||
|
ktime_to_ns(elapsed));
|
||||||
while ((total_us >> 32) != 0) {
|
|
||||||
pps >>= 1;
|
|
||||||
total_us >>= 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
do_div(pps, total_us);
|
|
||||||
|
|
||||||
bps = pps * 8 * pkt_dev->cur_pkt_size;
|
bps = pps * 8 * pkt_dev->cur_pkt_size;
|
||||||
|
|
||||||
@ -3235,7 +3231,7 @@ static int pktgen_stop_device(struct pktgen_dev *pkt_dev)
|
|||||||
|
|
||||||
kfree_skb(pkt_dev->skb);
|
kfree_skb(pkt_dev->skb);
|
||||||
pkt_dev->skb = NULL;
|
pkt_dev->skb = NULL;
|
||||||
pkt_dev->stopped_at = getCurUs();
|
pkt_dev->stopped_at = ktime_now();
|
||||||
pkt_dev->running = 0;
|
pkt_dev->running = 0;
|
||||||
|
|
||||||
show_results(pkt_dev, nr_frags);
|
show_results(pkt_dev, nr_frags);
|
||||||
@ -3254,7 +3250,7 @@ static struct pktgen_dev *next_to_run(struct pktgen_thread *t)
|
|||||||
continue;
|
continue;
|
||||||
if (best == NULL)
|
if (best == NULL)
|
||||||
best = pkt_dev;
|
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;
|
best = pkt_dev;
|
||||||
}
|
}
|
||||||
if_unlock(t);
|
if_unlock(t);
|
||||||
@ -3343,16 +3339,17 @@ static void pktgen_rem_thread(struct pktgen_thread *t)
|
|||||||
|
|
||||||
static void idle(struct pktgen_dev *pkt_dev)
|
static void idle(struct pktgen_dev *pkt_dev)
|
||||||
{
|
{
|
||||||
u64 idle_start = getCurUs();
|
ktime_t idle_start = ktime_now();
|
||||||
|
|
||||||
if (need_resched())
|
if (need_resched())
|
||||||
schedule();
|
schedule();
|
||||||
else
|
else
|
||||||
cpu_relax();
|
cpu_relax();
|
||||||
|
|
||||||
pkt_dev->idle_acc += getCurUs() - idle_start;
|
pkt_dev->idle_acc += ktime_to_ns(ktime_sub(ktime_now(), idle_start));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void pktgen_xmit(struct pktgen_dev *pkt_dev)
|
static void pktgen_xmit(struct pktgen_dev *pkt_dev)
|
||||||
{
|
{
|
||||||
struct net_device *odev = pkt_dev->odev;
|
struct net_device *odev = pkt_dev->odev;
|
||||||
@ -3362,19 +3359,15 @@ static void pktgen_xmit(struct pktgen_dev *pkt_dev)
|
|||||||
u16 queue_map;
|
u16 queue_map;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (pkt_dev->delay_us || pkt_dev->delay_ns) {
|
if (pkt_dev->delay) {
|
||||||
u64 now;
|
if (ktime_lt(ktime_now(), pkt_dev->next_tx))
|
||||||
|
spin(pkt_dev, pkt_dev->next_tx);
|
||||||
now = getCurUs();
|
|
||||||
if (now < pkt_dev->next_tx_us)
|
|
||||||
spin(pkt_dev, pkt_dev->next_tx_us);
|
|
||||||
|
|
||||||
/* This is max DELAY, this has special meaning of
|
/* This is max DELAY, this has special meaning of
|
||||||
* "never transmit"
|
* "never transmit"
|
||||||
*/
|
*/
|
||||||
if (pkt_dev->delay_us == 0x7FFFFFFF) {
|
if (pkt_dev->delay == ULLONG_MAX) {
|
||||||
pkt_dev->next_tx_us = getCurUs() + pkt_dev->delay_us;
|
pkt_dev->next_tx = ktime_add_ns(ktime_now(), ULONG_MAX);
|
||||||
pkt_dev->next_tx_ns = pkt_dev->delay_ns;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3450,32 +3443,24 @@ static void pktgen_xmit(struct pktgen_dev *pkt_dev)
|
|||||||
pkt_dev->last_ok = 0;
|
pkt_dev->last_ok = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pkt_dev->delay_us || pkt_dev->delay_ns) {
|
if (pkt_dev->delay)
|
||||||
pkt_dev->next_tx_us = getCurUs();
|
pkt_dev->next_tx = ktime_add_ns(ktime_now(),
|
||||||
pkt_dev->next_tx_ns = 0;
|
pkt_dev->delay);
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
__netif_tx_unlock_bh(txq);
|
__netif_tx_unlock_bh(txq);
|
||||||
|
|
||||||
/* If pkt_dev->count is zero, then run forever */
|
/* If pkt_dev->count is zero, then run forever */
|
||||||
if ((pkt_dev->count != 0) && (pkt_dev->sofar >= pkt_dev->count)) {
|
if ((pkt_dev->count != 0) && (pkt_dev->sofar >= pkt_dev->count)) {
|
||||||
if (atomic_read(&(pkt_dev->skb->users)) != 1) {
|
if (atomic_read(&(pkt_dev->skb->users)) != 1) {
|
||||||
u64 idle_start = getCurUs();
|
ktime_t idle_start = ktime_now();
|
||||||
while (atomic_read(&(pkt_dev->skb->users)) != 1) {
|
while (atomic_read(&(pkt_dev->skb->users)) != 1) {
|
||||||
if (signal_pending(current)) {
|
if (signal_pending(current)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
schedule();
|
schedule();
|
||||||
}
|
}
|
||||||
pkt_dev->idle_acc += getCurUs() - idle_start;
|
pkt_dev->idle_acc += ktime_to_ns(ktime_sub(ktime_now(),
|
||||||
|
idle_start));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Done with this */
|
/* Done with this */
|
||||||
@ -3634,8 +3619,7 @@ static int pktgen_add_device(struct pktgen_thread *t, const char *ifname)
|
|||||||
pkt_dev->max_pkt_size = ETH_ZLEN;
|
pkt_dev->max_pkt_size = ETH_ZLEN;
|
||||||
pkt_dev->nfrags = 0;
|
pkt_dev->nfrags = 0;
|
||||||
pkt_dev->clone_skb = pg_clone_skb_d;
|
pkt_dev->clone_skb = pg_clone_skb_d;
|
||||||
pkt_dev->delay_us = pg_delay_d / 1000;
|
pkt_dev->delay = pg_delay_d;
|
||||||
pkt_dev->delay_ns = pg_delay_d % 1000;
|
|
||||||
pkt_dev->count = pg_count_d;
|
pkt_dev->count = pg_count_d;
|
||||||
pkt_dev->sofar = 0;
|
pkt_dev->sofar = 0;
|
||||||
pkt_dev->udp_src_min = 9; /* sink port */
|
pkt_dev->udp_src_min = 9; /* sink port */
|
||||||
|
Loading…
Reference in New Issue
Block a user