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) - : 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