[prev in list] [next in list] [prev in thread] [next in thread] 

List:       linux-net
Subject:    Speeding up netstat
From:       Tachino Nobuhiro <tachino () jp ! fujitsu ! com>
Date:       2003-03-24 9:52:02
[Download RAW message or body]


Hello,

My machine is Pentium IV Xeon 2GHz x 2. When many connections (>20k) are available on
this machine, netstat is very slow and it takes almost hundred seconds. With Oprofile,
I found the read_lock()/read_unlock() in established_get_next() takes almost time.
I made the following patch which speeds up netstat almost nine times faster.
The patch reduces the usage of the lock/unlocks. The patched established_get_next()
checks whether tcp_ehash[].chain is NULL before does read_lock((tcp_ehash[].lock).
If the chain is NULL, it skips the chain. If the chain is not NULL, it locks
tcp_ehash[].lock and follows the chain.

Result is following.

2.5.65

# time netstat | wc -l
  20017

real    1m37.534s
user    0m0.670s
sys     1m36.888s

2.5.65 + patch

# time netstat | wc -l
  20017

real    0m11.020s
user    0m0.618s
sys     0m10.408s


Please comment.

----

diff -Nur linux-2.5.org/net/ipv4/tcp_ipv4.c linux-2.5/net/ipv4/tcp_ipv4.c
--- linux-2.5.org/net/ipv4/tcp_ipv4.c	Mon Mar 24 14:51:05 2003
+++ linux-2.5/net/ipv4/tcp_ipv4.c	Mon Mar 24 15:26:56 2003
@@ -2297,46 +2297,33 @@
 static void *established_get_next(struct seq_file *seq, void *cur)
 {
 	struct sock *sk = cur;
-	struct tcp_tw_bucket *tw;
 	struct tcp_iter_state* st = seq->private;
 
-	if (st->state == TCP_SEQ_STATE_TIME_WAIT) {
-		tw = cur;
-		tw = (struct tcp_tw_bucket *)tw->next;
-get_tw:
-		while (tw && !TCP_INET_FAMILY(tw->family)) {
-			++st->num;
-			tw = (struct tcp_tw_bucket *)tw->next;
-		}
-		if (tw) {
-			cur = tw;
-			goto out;
-		}
-		read_unlock(&tcp_ehash[st->bucket].lock);
-		st->state = TCP_SEQ_STATE_ESTABLISHED;
-		if (++st->bucket < tcp_ehash_size) {
+	sk = sk->next;
+redo:
+	for (;sk && !TCP_INET_FAMILY(sk->family); sk = sk->next)
+		++st->num;
+	if (sk)
+		return sk;
+
+	if (st->state != TCP_SEQ_STATE_TIME_WAIT) {
+		st->state = TCP_SEQ_STATE_TIME_WAIT;
+		sk = tcp_ehash[st->bucket + tcp_ehash_size].chain;
+		goto redo;
+	}
+	read_unlock(&tcp_ehash[st->bucket].lock);
+	st->state = TCP_SEQ_STATE_ESTABLISHED;
+
+	for (++st->bucket; st->bucket < tcp_ehash_size; ++st->bucket) {
+		if (tcp_ehash[st->bucket].chain ||
+		    tcp_ehash[st->bucket + tcp_ehash_size].chain) {
 			read_lock(&tcp_ehash[st->bucket].lock);
 			sk = tcp_ehash[st->bucket].chain;
-		} else {
-			cur = NULL;
-			goto out;
+			goto redo;
 		}
-	} else
-		sk = sk->next;
-
-	while (sk && !TCP_INET_FAMILY(sk->family)) {
-		++st->num;
-		sk = sk->next;
 	}
-	if (!sk) {
-		st->state = TCP_SEQ_STATE_TIME_WAIT;
-		tw = (struct tcp_tw_bucket *)
-				tcp_ehash[st->bucket + tcp_ehash_size].chain;
-		goto get_tw;
-	}
-	cur = sk;
-out:
-	return cur;
+
+	return NULL;
 }
 
 static void *established_get_idx(struct seq_file *seq, loff_t pos)
-
To unsubscribe from this list: send the line "unsubscribe linux-net" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic