Skip to contentSkip to conversation

tcp_probe: avoid modulus operation and wrap fix

PATCH Applied Stephen Hemminger 2 participants 4 messages Jan 25, 2010

Subsystems (3)
lore
Share & tools
lore
#0 lore raw

PATCH 1/1 tcp_probe: avoid modulus operation and wrap fix

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.

net/ipv4/tcp_probe.c +10 -9
@@ -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);
maintainer
#1 lore raw

From: Stephen Hemminger <[email protected]>
Date: Sun, 24 Jan 2010 21:50:01 -0800

Quoted 5 lines
net/ipv4/tcp_probe.c +0 -1
@@ -75,12 +75,12 @@ static struct {
 
 static inline int tcp_probe_used(void)
 {
-	return (tcp_probe.head - tcp_probe.tail) % bufsize;

net/ipv4/tcp_probe.c static struct { · line 86

Quoted 10 lines
net/ipv4/tcp_probe.c +2 -1
+	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?

#2 lore raw
Quoted 17 lines · On Sun, 24 Jan 2010 22:41:22 -0800 (PST) David Miller <[email protected]>…

From: Stephen Hemminger <[email protected]>
Date: Sun, 24 Jan 2010 21:50:01 -0800

Quoted 14 lines
net/ipv4/tcp_probe.c +2 -2
@@ -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;
 }
 
Quoted 7 lines

Review static struct { · line 86

Quoted 1 line
(quoted diff) +0 -0
 /*

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.

maintainer Applied
#3 lore raw

From: Stephen Hemminger <[email protected]>
Date: Mon, 25 Jan 2010 08:30:06 -0800

Quoted 26 lines
Quoted 23 lines · On Sun, 24 Jan 2010 22:41:22 -0800 (PST) David Miller <[email protected]>…

From: Stephen Hemminger <[email protected]>
Date: Sun, 24 Jan 2010 21:50:01 -0800

Quoted 5 lines
net/ipv4/tcp_probe.c +0 -1
@@ -75,12 +75,12 @@ static struct {
 
 static inline int tcp_probe_used(void)
 {
-	return (tcp_probe.head - tcp_probe.tail) % bufsize;

net/ipv4/tcp_probe.c static struct { · line 86

Quoted 10 lines
net/ipv4/tcp_probe.c +2 -1
+	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".

Quoted 4 lines
Quoted 1 line

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.