[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