Patchwork tcp_probe: avoid modulus operation and wrap fix

login
register
mail settings
Submitter stephen hemminger
Date Jan. 25, 2010, 5:50 a.m.
Message ID <20100124215001.78251e25@nehalam>
Download mbox | patch
Permalink /patch/43613/
State Accepted
Delegated to: David Miller
Headers show

Comments

stephen hemminger - Jan. 25, 2010, 5:50 a.m.
By rounding up the buffer size to power of 2, several expensive
modulus operations can be avoided.  This patch also solves a bug where
the gap need when ring gets full was not being accounted for.

Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>


--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
David Miller - Jan. 25, 2010, 6:41 a.m.
From: Stephen Hemminger <shemminger@vyatta.com>
Date: Sun, 24 Jan 2010 21:50:01 -0800

> @@ -75,12 +75,12 @@ static struct {
>  
>  static inline int tcp_probe_used(void)
>  {
> -	return (tcp_probe.head - tcp_probe.tail) % bufsize;
> +	return (tcp_probe.head - tcp_probe.tail) & (bufsize - 1);
>  }
>  
>  static inline int tcp_probe_avail(void)
>  {
> -	return bufsize - tcp_probe_used();
> +	return bufsize - tcp_probe_used() - 1;
>  }
>  
>  /*

Hmmm...  When the ring is full head==tail, which means
tcp_probe_used() returns 0.  Which would now make tcp_probe_avail()
return "bufsize - 0 - 1".

Is that right?
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
stephen hemminger - Jan. 25, 2010, 4:30 p.m.
On Sun, 24 Jan 2010 22:41:22 -0800 (PST)
David Miller <davem@davemloft.net> wrote:

> From: Stephen Hemminger <shemminger@vyatta.com>
> Date: Sun, 24 Jan 2010 21:50:01 -0800
> 
> > @@ -75,12 +75,12 @@ static struct {
> >  
> >  static inline int tcp_probe_used(void)
> >  {
> > -	return (tcp_probe.head - tcp_probe.tail) % bufsize;
> > +	return (tcp_probe.head - tcp_probe.tail) & (bufsize - 1);
> >  }
> >  
> >  static inline int tcp_probe_avail(void)
> >  {
> > -	return bufsize - tcp_probe_used();
> > +	return bufsize - tcp_probe_used() - 1;
> >  }
> >  
> >  /*
> 
> Hmmm...  When the ring is full head==tail, which means
> tcp_probe_used() returns 0.  Which would now make tcp_probe_avail()
> return "bufsize - 0 - 1".
> 
> Is that right?

Yes. in this ring; empty is head == tail, and full needs to
be tail == head - 1.
David Miller - Jan. 25, 2010, 11:48 p.m.
From: Stephen Hemminger <shemminger@vyatta.com>
Date: Mon, 25 Jan 2010 08:30:06 -0800

> On Sun, 24 Jan 2010 22:41:22 -0800 (PST)
> David Miller <davem@davemloft.net> wrote:
> 
>> From: Stephen Hemminger <shemminger@vyatta.com>
>> Date: Sun, 24 Jan 2010 21:50:01 -0800
>> 
>> > @@ -75,12 +75,12 @@ static struct {
>> >  
>> >  static inline int tcp_probe_used(void)
>> >  {
>> > -	return (tcp_probe.head - tcp_probe.tail) % bufsize;
>> > +	return (tcp_probe.head - tcp_probe.tail) & (bufsize - 1);
>> >  }
>> >  
>> >  static inline int tcp_probe_avail(void)
>> >  {
>> > -	return bufsize - tcp_probe_used();
>> > +	return bufsize - tcp_probe_used() - 1;
>> >  }
>> >  
>> >  /*
>> 
>> Hmmm...  When the ring is full head==tail, which means
>> tcp_probe_used() returns 0.  Which would now make tcp_probe_avail()
>> return "bufsize - 0 - 1".
>> 
>> Is that right?
> 
> Yes. in this ring; empty is head == tail, and full needs to
> be tail == head - 1.

Ok, that makes sense, thanks for explaining.

Applied, thanks Stephen.
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Patch

--- a/net/ipv4/tcp_probe.c	2010-01-24 21:43:07.069894439 -0800
+++ b/net/ipv4/tcp_probe.c	2010-01-24 21:46:15.301153066 -0800
@@ -39,9 +39,9 @@  static int port __read_mostly = 0;
 MODULE_PARM_DESC(port, "Port to match (0=all)");
 module_param(port, int, 0);
 
-static int bufsize __read_mostly = 4096;
+static unsigned int bufsize __read_mostly = 4096;
 MODULE_PARM_DESC(bufsize, "Log buffer size in packets (4096)");
-module_param(bufsize, int, 0);
+module_param(bufsize, uint, 0);
 
 static int full __read_mostly;
 MODULE_PARM_DESC(full, "Full log (1=every ack packet received,  0=only cwnd changes)");
@@ -75,12 +75,12 @@  static struct {
 
 static inline int tcp_probe_used(void)
 {
-	return (tcp_probe.head - tcp_probe.tail) % bufsize;
+	return (tcp_probe.head - tcp_probe.tail) & (bufsize - 1);
 }
 
 static inline int tcp_probe_avail(void)
 {
-	return bufsize - tcp_probe_used();
+	return bufsize - tcp_probe_used() - 1;
 }
 
 /*
@@ -116,7 +116,7 @@  static int jtcp_rcv_established(struct s
 			p->ssthresh = tcp_current_ssthresh(sk);
 			p->srtt = tp->srtt >> 3;
 
-			tcp_probe.head = (tcp_probe.head + 1) % bufsize;
+			tcp_probe.head = (tcp_probe.head + 1) & (bufsize - 1);
 		}
 		tcp_probe.lastcwnd = tp->snd_cwnd;
 		spin_unlock(&tcp_probe.lock);
@@ -149,7 +149,7 @@  static int tcpprobe_open(struct inode * 
 static int tcpprobe_sprint(char *tbuf, int n)
 {
 	const struct tcp_log *p
-		= tcp_probe.log + tcp_probe.tail % bufsize;
+		= tcp_probe.log + tcp_probe.tail;
 	struct timespec tv
 		= ktime_to_timespec(ktime_sub(p->tstamp, tcp_probe.start));
 
@@ -192,7 +192,7 @@  static ssize_t tcpprobe_read(struct file
 		width = tcpprobe_sprint(tbuf, sizeof(tbuf));
 
 		if (cnt + width < len)
-			tcp_probe.tail = (tcp_probe.tail + 1) % bufsize;
+			tcp_probe.tail = (tcp_probe.tail + 1) & (bufsize - 1);
 
 		spin_unlock_bh(&tcp_probe.lock);
 
@@ -222,9 +222,10 @@  static __init int tcpprobe_init(void)
 	init_waitqueue_head(&tcp_probe.wait);
 	spin_lock_init(&tcp_probe.lock);
 
-	if (bufsize < 0)
+	if (bufsize == 0)
 		return -EINVAL;
 
+	bufsize = roundup_pow_of_two(bufsize);
 	tcp_probe.log = kcalloc(bufsize, sizeof(struct tcp_log), GFP_KERNEL);
 	if (!tcp_probe.log)
 		goto err0;
@@ -236,7 +237,7 @@  static __init int tcpprobe_init(void)
 	if (ret)
 		goto err1;
 
-	pr_info("TCP probe registered (port=%d)\n", port);
+	pr_info("TCP probe registered (port=%d) bufsize=%u\n", port, bufsize);
 	return 0;
  err1:
 	proc_net_remove(&init_net, procname);