* [PATCH 2.6] neighbour cache statistics like rt_stat
@ 2004-09-27 9:36 Harald Welte
2004-09-27 16:23 ` Harald Welte
0 siblings, 1 reply; 5+ messages in thread
From: Harald Welte @ 2004-09-27 9:36 UTC (permalink / raw)
To: netdev
[-- Attachment #1.1: Type: text/plain, Size: 1462 bytes --]
The patch below (on top of davem's recent 6-patch set and 4-patch-set up
to diff4) adds rt_stat like statistics to the neighbour cache core.
It helped a lot during debugging/testing, and I think it is generally
useful for the mainline kernel if you want to do runtime analysis of
neighbour cahce performance / problems.
Some comments/questions/ideas
1) old statistics used to be unsigned long, new ones are int. I propose
to convert all of them to int.
2) I'd also like to add gc statistics on non-forced-gc but normal
garbage collection.
3) Do we need a seperate 'miss' counter, or is the 'allocs' counter
sufficient?
4) Don't we want to put them in a /proc/net/neigh directory ?
5) Since there's now rt_stat, ct_stat, neighbour statistics, and they
all use the same clumsy format that is difficult to expand, and all
use copy+paste userspace tools: Would you accept a patch that changes
the format once again to display a template as first line, giving the
names of the individual fields? I would then work on a generic
userspace tool (too bad that the name netstat is already used) that
would work with all of those _stat files, including upcoming new
ones.
--
- Harald Welte <laforge@gnumonks.org> http://www.gnumonks.org/
============================================================================
Programming is like sex: One mistake and you have to support it your lifetime
[-- Attachment #1.2: laforge-neigh_statistics.patch --]
[-- Type: text/plain, Size: 8493 bytes --]
Add rtstat-like per-cpu statistics to the neighbour cache core.
This will add
/proc/net/arp_cache_stat for ipv4
/proc/net/ndisc_cache_stat for ipv6
/proc/net/clip_arp_cache_stat for atm/clip
/proc/net/decnet_neigh_stat for decnet
The format is similar to rt_stat, one line per cpu where each line is:
Field 1: Total number of entries in table
Field 2: Total number of hash bucket grows
Field 3: Total number of cache hits
Field 4: Total number of neigh_allocs (should equal misses)
Field 5: Total number of failed neighbour resolves
Field 6: ?
Field 7: ?
Field 8: Total number of forced garbage collector runs
Field 9: Total number of forced GC runs that missed their goal
Signed-off-by: Harald Welte <laforge@gnumonks.org>
Index: linux-2.6.9-rc2-bk9-neigh1/include/net/neighbour.h
===================================================================
--- linux-2.6.9-rc2-bk9-neigh1.orig/include/net/neighbour.h 2004-09-26 12:45:38.000000000 +0200
+++ linux-2.6.9-rc2-bk9-neigh1/include/net/neighbour.h 2004-09-26 23:31:13.000000000 +0200
@@ -7,6 +7,11 @@
* Authors:
* Pedro Roque <roque@di.fc.ul.pt>
* Alexey Kuznetsov <kuznet@ms2.inr.ac.ru>
+ *
+ * Changes:
+ *
+ * Harald Welte: <laforge@gnumonks.org>
+ * - Add neighbour cache statistics like rtstat
*/
/* The following flags & states are exported to user space,
@@ -92,10 +97,21 @@
{
unsigned long allocs;
unsigned long res_failed;
+
+ unsigned int hits; /* number of cache hits */
+
unsigned long rcv_probes_mcast;
unsigned long rcv_probes_ucast;
+
+ unsigned int hash_grows; /* total number of hash resizes */
+
+ unsigned int forced_gc_runs; /* total number of GC runs */
+ unsigned int forced_gc_goal_miss;/* total number of gc goal misses */
};
+#define NEIGH_CACHE_STAT_INC(tbl, field) \
+ (per_cpu_ptr((tbl)->stats, smp_processor_id())->field++)
+
struct neighbour
{
struct neighbour *next;
@@ -172,12 +188,15 @@
unsigned long last_rand;
struct neigh_parms *parms_list;
kmem_cache_t *kmem_cachep;
- struct neigh_statistics stats;
+ struct neigh_statistics *stats;
struct neighbour **hash_buckets;
unsigned int hash_mask;
__u32 hash_rnd;
unsigned int hash_chain_gc;
struct pneigh_entry **phash_buckets;
+#ifdef CONFIG_PROC_FS
+ struct proc_dir_entry *pde;
+#endif
};
/* flags for neigh_update() */
Index: linux-2.6.9-rc2-bk9-neigh1/net/core/neighbour.c
===================================================================
--- linux-2.6.9-rc2-bk9-neigh1.orig/net/core/neighbour.c 2004-09-26 12:37:18.000000000 +0200
+++ linux-2.6.9-rc2-bk9-neigh1/net/core/neighbour.c 2004-09-27 10:54:35.934120048 +0200
@@ -21,6 +21,7 @@
#include <linux/socket.h>
#include <linux/sched.h>
#include <linux/netdevice.h>
+#include <linux/proc_fs.h>
#ifdef CONFIG_SYSCTL
#include <linux/sysctl.h>
#endif
@@ -59,6 +60,7 @@
static int neigh_glbl_allocs;
static struct neigh_table *neigh_tables;
+static struct file_operations neigh_stat_seq_fops;
/*
Neighbour hash table buckets are protected with rwlock tbl->lock.
@@ -115,6 +117,8 @@
int shrunk = 0, num_incomplete = 0, reap_incomplete = 0;
int i;
+ NEIGH_CACHE_STAT_INC(tbl, forced_gc_runs);
+
write_lock_bh(&tbl->lock);
rescan:
for (i = 0; i <= tbl->hash_mask; i++) {
@@ -161,6 +165,7 @@
if (reap_incomplete == 0 &&
shrunk < goal &&
(shrunk + num_incomplete) >= goal) {
+ NEIGH_CACHE_STAT_INC(tbl, forced_gc_goal_miss);
reap_incomplete = 1;
goto rescan;
}
@@ -299,7 +304,8 @@
init_timer(&n->timer);
n->timer.function = neigh_timer_handler;
n->timer.data = (unsigned long)n;
- tbl->stats.allocs++;
+
+ NEIGH_CACHE_STAT_INC(tbl, allocs);
neigh_glbl_allocs++;
tbl->entries++;
n->tbl = tbl;
@@ -341,6 +347,8 @@
struct neighbour **new_hash, **old_hash;
unsigned int i, new_hash_mask, old_entries;
+ NEIGH_CACHE_STAT_INC(tbl, hash_grows);
+
BUG_ON(new_entries & (new_entries - 1));
new_hash = neigh_hash_alloc(new_entries);
if (!new_hash)
@@ -380,6 +388,7 @@
for (n = tbl->hash_buckets[hash_val]; n; n = n->next) {
if (dev == n->dev && !memcmp(n->primary_key, pkey, key_len)) {
neigh_hold(n);
+ NEIGH_CACHE_STAT_INC(tbl, hits);
break;
}
}
@@ -397,6 +406,7 @@
for (n = tbl->hash_buckets[hash_val]; n; n = n->next) {
if (!memcmp(n->primary_key, pkey, key_len)) {
neigh_hold(n);
+ NEIGH_CACHE_STAT_INC(tbl, hits);
break;
}
}
@@ -787,7 +797,7 @@
neigh->nud_state = NUD_FAILED;
notify = 1;
- neigh->tbl->stats.res_failed++;
+ NEIGH_CACHE_STAT_INC(neigh->tbl, res_failed);
NEIGH_PRINTK2("neigh %p is failed.\n", neigh);
/* It is very thin place. report_unreachable is very complicated
@@ -1336,6 +1346,30 @@
if (!tbl->kmem_cachep)
panic("cannot create neighbour cache");
+ tbl->stats = alloc_percpu(struct neigh_statistics);
+ if (!tbl->stats)
+ panic("cannot create neighbour cache statistics");
+
+#ifdef CONFIG_PROC_FS
+#define NC_STAT_SUFFIX "_stat"
+ {
+ char *proc_stat_name;
+ proc_stat_name = kmalloc(strlen(tbl->id) +
+ strlen(NC_STAT_SUFFIX) + 1, GFP_KERNEL);
+ if (!proc_stat_name)
+ panic("cannot allocate neighbour cache proc name buffer");
+ strcpy(proc_stat_name, tbl->id);
+ strcat(proc_stat_name, NC_STAT_SUFFIX);
+
+ /* FIXME: move this to seperate directory and add _stat postfix */
+ tbl->pde = create_proc_entry(proc_stat_name, 0, proc_net);
+ if (!tbl->pde)
+ panic("cannot create neighbour proc dir entry");
+ tbl->pde->proc_fops = &neigh_stat_seq_fops;
+ tbl->pde->data = tbl;
+ }
+#endif
+
tbl->hash_mask = 0x1f;
tbl->hash_buckets = neigh_hash_alloc(tbl->hash_mask + 1);
@@ -1882,6 +1916,94 @@
}
EXPORT_SYMBOL(neigh_seq_stop);
+/* statistics via seq_file */
+
+static void *neigh_stat_seq_start(struct seq_file *seq, loff_t *pos)
+{
+ struct proc_dir_entry *pde = seq->private;
+ struct neigh_table *tbl = pde->data;
+ int cpu;
+
+ for (cpu = *pos; cpu < NR_CPUS; ++cpu) {
+ if (!cpu_possible(cpu))
+ continue;
+ *pos = cpu;
+ return per_cpu_ptr(tbl->stats, cpu);
+ }
+ return NULL;
+}
+
+static void *neigh_stat_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+ struct proc_dir_entry *pde = seq->private;
+ struct neigh_table *tbl = pde->data;
+ int cpu;
+
+ for (cpu = *pos + 1; cpu < NR_CPUS; ++cpu) {
+ if (!cpu_possible(cpu))
+ continue;
+ *pos = cpu;
+ return per_cpu_ptr(tbl->stats, cpu);
+ }
+ return NULL;
+}
+
+static void neigh_stat_seq_stop(struct seq_file *seq, void *v)
+{
+
+}
+
+static int neigh_stat_seq_show(struct seq_file *seq, void *v)
+{
+ struct proc_dir_entry *pde = seq->private;
+ struct neigh_table *tbl = pde->data;
+ struct neigh_statistics *st = v;
+
+ seq_printf(seq, "%08x %08x %08x %08lx %08lx %08lx %08lx "
+ "%08x %08x\n",
+ tbl->entries,
+
+ st->hash_grows,
+ st->hits,
+ st->allocs,
+ st->res_failed,
+
+ st->rcv_probes_mcast,
+ st->rcv_probes_ucast,
+
+ st->forced_gc_runs,
+ st->forced_gc_goal_miss
+ );
+
+ return 0;
+}
+
+static struct seq_operations neigh_stat_seq_ops = {
+ .start = neigh_stat_seq_start,
+ .next = neigh_stat_seq_next,
+ .stop = neigh_stat_seq_stop,
+ .show = neigh_stat_seq_show,
+};
+
+static int neigh_stat_seq_open(struct inode *inode, struct file *file)
+{
+ int ret = seq_open(file, &neigh_stat_seq_ops);
+
+ if (!ret) {
+ struct seq_file *sf = file->private_data;
+ sf->private = PDE(inode);
+ }
+ return ret;
+};
+
+static struct file_operations neigh_stat_seq_fops = {
+ .owner = THIS_MODULE,
+ .open = neigh_stat_seq_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
+};
+
#endif /* CONFIG_PROC_FS */
#ifdef CONFIG_ARPD
Index: linux-2.6.9-rc2-bk9-neigh1/net/ipv6/ndisc.c
===================================================================
--- linux-2.6.9-rc2-bk9-neigh1.orig/net/ipv6/ndisc.c 2004-09-26 12:29:03.000000000 +0200
+++ linux-2.6.9-rc2-bk9-neigh1/net/ipv6/ndisc.c 2004-09-26 23:30:56.000000000 +0200
@@ -802,9 +802,9 @@
}
if (inc)
- nd_tbl.stats.rcv_probes_mcast++;
+ NEIGH_CACHE_STAT_INC(&nd_tbl, rcv_probes_mcast);
else
- nd_tbl.stats.rcv_probes_ucast++;
+ NEIGH_CACHE_STAT_INC(&nd_tbl, rcv_probes_ucast);
/*
* update / create cache entry
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 189 bytes --]
^ permalink raw reply [flat|nested] 5+ messages in thread* Re: [PATCH 2.6] neighbour cache statistics like rt_stat 2004-09-27 9:36 [PATCH 2.6] neighbour cache statistics like rt_stat Harald Welte @ 2004-09-27 16:23 ` Harald Welte 2004-09-27 19:21 ` David S. Miller 0 siblings, 1 reply; 5+ messages in thread From: Harald Welte @ 2004-09-27 16:23 UTC (permalink / raw) To: netdev [-- Attachment #1.1: Type: text/plain, Size: 589 bytes --] On Mon, Sep 27, 2004 at 11:36:13AM +0200, Harald Welte wrote: > The patch below (on top of davem's recent 6-patch set and 4-patch-set up > to diff4) adds rt_stat like statistics to the neighbour cache core. I've now updated the patch. Changes: - more statistics (lookups, destroy, periodic_gc_runs) - add template line to top of file -- - Harald Welte <laforge@gnumonks.org> http://www.gnumonks.org/ ============================================================================ Programming is like sex: One mistake and you have to support it your lifetime [-- Attachment #1.2: laforge-neigh_statistics.patch --] [-- Type: text/plain, Size: 10444 bytes --] Add rtstat-like per-cpu statistics to the neighbour cache core. This will add /proc/net/arp_cache_stat for ipv4 /proc/net/ndisc_cache_stat for ipv6 /proc/net/clip_arp_cache_stat for atm/clip /proc/net/decnet_neigh_stat for decnet The format is similar to rt_stat, one line per cpu where each line is: Field 0: Total number of entries in table Field 1: Total number of neighbour allocations in this tbl Field 2: Total number of neighbour destroys in this tbl Field 3: Total number of hash bucket grows Field 4: Total number of failed neighbour resolves Field 5: Total number of cache lookups Field 6: Total number of cache hits Field 7: Total number of received multicast solicitations Field 8: Total number of received unicast solicitations Field 9: Total number of periodic garbage collector runs Field 10: Total number of forced garbage collector runs Field 11: Total number of forced GC runs that missed their goal Signed-off-by: Harald Welte <laforge@gnumonks.org> Index: linux-2.6.9-rc2-bk9-neigh1/include/net/neighbour.h =================================================================== --- linux-2.6.9-rc2-bk9-neigh1.orig/include/net/neighbour.h 2004-09-26 12:45:38.000000000 +0200 +++ linux-2.6.9-rc2-bk9-neigh1/include/net/neighbour.h 2004-09-27 13:44:49.000000000 +0200 @@ -7,6 +7,11 @@ * Authors: * Pedro Roque <roque@di.fc.ul.pt> * Alexey Kuznetsov <kuznet@ms2.inr.ac.ru> + * + * Changes: + * + * Harald Welte: <laforge@gnumonks.org> + * - Add neighbour cache statistics like rtstat */ /* The following flags & states are exported to user space, @@ -90,12 +95,26 @@ struct neigh_statistics { - unsigned long allocs; - unsigned long res_failed; - unsigned long rcv_probes_mcast; - unsigned long rcv_probes_ucast; + unsigned int allocs; /* number of allocated neighs */ + unsigned int destroys; /* number of destroyed neighs */ + unsigned int hash_grows; /* number of hash resizes */ + + unsigned int res_failed; /* nomber of failed resolutions */ + + unsigned int lookups; /* number of lookups */ + unsigned int hits; /* number of hits (among lookups) */ + + unsigned int rcv_probes_mcast; /* number of received mcast ipv6 */ + unsigned int rcv_probes_ucast; /* number of received ucast ipv6 */ + + unsigned int periodic_gc_runs; /* number of periodic GC runs */ + unsigned int forced_gc_runs; /* number of forced GC runs */ + unsigned int forced_gc_goal_miss;/* number of gc goal misses */ }; +#define NEIGH_CACHE_STAT_INC(tbl, field) \ + (per_cpu_ptr((tbl)->stats, smp_processor_id())->field++) + struct neighbour { struct neighbour *next; @@ -172,12 +191,15 @@ unsigned long last_rand; struct neigh_parms *parms_list; kmem_cache_t *kmem_cachep; - struct neigh_statistics stats; + struct neigh_statistics *stats; struct neighbour **hash_buckets; unsigned int hash_mask; __u32 hash_rnd; unsigned int hash_chain_gc; struct pneigh_entry **phash_buckets; +#ifdef CONFIG_PROC_FS + struct proc_dir_entry *pde; +#endif }; /* flags for neigh_update() */ Index: linux-2.6.9-rc2-bk9-neigh1/net/core/neighbour.c =================================================================== --- linux-2.6.9-rc2-bk9-neigh1.orig/net/core/neighbour.c 2004-09-26 12:37:18.000000000 +0200 +++ linux-2.6.9-rc2-bk9-neigh1/net/core/neighbour.c 2004-09-27 17:24:41.990753504 +0200 @@ -12,6 +12,7 @@ * * Fixes: * Vitaly E. Lavrov releasing NULL neighbor in neigh_add. + * Harald Welte Add neighbour cache statistics like rtstat */ #include <linux/config.h> @@ -21,6 +22,7 @@ #include <linux/socket.h> #include <linux/sched.h> #include <linux/netdevice.h> +#include <linux/proc_fs.h> #ifdef CONFIG_SYSCTL #include <linux/sysctl.h> #endif @@ -59,6 +61,7 @@ static int neigh_glbl_allocs; static struct neigh_table *neigh_tables; +static struct file_operations neigh_stat_seq_fops; /* Neighbour hash table buckets are protected with rwlock tbl->lock. @@ -115,6 +118,8 @@ int shrunk = 0, num_incomplete = 0, reap_incomplete = 0; int i; + NEIGH_CACHE_STAT_INC(tbl, forced_gc_runs); + write_lock_bh(&tbl->lock); rescan: for (i = 0; i <= tbl->hash_mask; i++) { @@ -161,6 +166,7 @@ if (reap_incomplete == 0 && shrunk < goal && (shrunk + num_incomplete) >= goal) { + NEIGH_CACHE_STAT_INC(tbl, forced_gc_goal_miss); reap_incomplete = 1; goto rescan; } @@ -299,7 +305,8 @@ init_timer(&n->timer); n->timer.function = neigh_timer_handler; n->timer.data = (unsigned long)n; - tbl->stats.allocs++; + + NEIGH_CACHE_STAT_INC(tbl, allocs); neigh_glbl_allocs++; tbl->entries++; n->tbl = tbl; @@ -341,6 +348,8 @@ struct neighbour **new_hash, **old_hash; unsigned int i, new_hash_mask, old_entries; + NEIGH_CACHE_STAT_INC(tbl, hash_grows); + BUG_ON(new_entries & (new_entries - 1)); new_hash = neigh_hash_alloc(new_entries); if (!new_hash) @@ -375,11 +384,14 @@ struct neighbour *n; int key_len = tbl->key_len; u32 hash_val = tbl->hash(pkey, dev) & tbl->hash_mask; + + NEIGH_CACHE_STAT_INC(tbl, lookups); read_lock_bh(&tbl->lock); for (n = tbl->hash_buckets[hash_val]; n; n = n->next) { if (dev == n->dev && !memcmp(n->primary_key, pkey, key_len)) { neigh_hold(n); + NEIGH_CACHE_STAT_INC(tbl, hits); break; } } @@ -393,10 +405,13 @@ int key_len = tbl->key_len; u32 hash_val = tbl->hash(pkey, NULL) & tbl->hash_mask; + NEIGH_CACHE_STAT_INC(tbl, lookups); + read_lock_bh(&tbl->lock); for (n = tbl->hash_buckets[hash_val]; n; n = n->next) { if (!memcmp(n->primary_key, pkey, key_len)) { neigh_hold(n); + NEIGH_CACHE_STAT_INC(tbl, hits); break; } } @@ -581,6 +596,8 @@ { struct hh_cache *hh; + NEIGH_CACHE_STAT_INC(neigh->tbl, destroys); + if (!neigh->dead) { printk(KERN_WARNING "Destroying alive neighbour %p\n", neigh); @@ -656,6 +673,8 @@ struct neighbour *n, **np; unsigned long expire, now = jiffies; + NEIGH_CACHE_STAT_INC(tbl, periodic_gc_runs); + write_lock(&tbl->lock); /* @@ -787,7 +806,7 @@ neigh->nud_state = NUD_FAILED; notify = 1; - neigh->tbl->stats.res_failed++; + NEIGH_CACHE_STAT_INC(neigh->tbl, res_failed); NEIGH_PRINTK2("neigh %p is failed.\n", neigh); /* It is very thin place. report_unreachable is very complicated @@ -1336,6 +1355,29 @@ if (!tbl->kmem_cachep) panic("cannot create neighbour cache"); + tbl->stats = alloc_percpu(struct neigh_statistics); + if (!tbl->stats) + panic("cannot create neighbour cache statistics"); + +#ifdef CONFIG_PROC_FS +#define NC_STAT_SUFFIX "_stat" + { + char *proc_stat_name; + proc_stat_name = kmalloc(strlen(tbl->id) + + strlen(NC_STAT_SUFFIX) + 1, GFP_KERNEL); + if (!proc_stat_name) + panic("cannot allocate neighbour cache proc name buffer"); + strcpy(proc_stat_name, tbl->id); + strcat(proc_stat_name, NC_STAT_SUFFIX); + + tbl->pde = create_proc_entry(proc_stat_name, 0, proc_net); + if (!tbl->pde) + panic("cannot create neighbour proc dir entry"); + tbl->pde->proc_fops = &neigh_stat_seq_fops; + tbl->pde->data = tbl; + } +#endif + tbl->hash_mask = 0x1f; tbl->hash_buckets = neigh_hash_alloc(tbl->hash_mask + 1); @@ -1882,6 +1924,107 @@ } EXPORT_SYMBOL(neigh_seq_stop); +/* statistics via seq_file */ + +static void *neigh_stat_seq_start(struct seq_file *seq, loff_t *pos) +{ + struct proc_dir_entry *pde = seq->private; + struct neigh_table *tbl = pde->data; + int cpu; + + if (*pos == 0) + return SEQ_START_TOKEN; + + for (cpu = *pos-1; cpu < NR_CPUS; ++cpu) { + if (!cpu_possible(cpu)) + continue; + *pos = cpu+1; + return per_cpu_ptr(tbl->stats, cpu); + } + return NULL; +} + +static void *neigh_stat_seq_next(struct seq_file *seq, void *v, loff_t *pos) +{ + struct proc_dir_entry *pde = seq->private; + struct neigh_table *tbl = pde->data; + int cpu; + + for (cpu = *pos; cpu < NR_CPUS; ++cpu) { + if (!cpu_possible(cpu)) + continue; + *pos = cpu+1; + return per_cpu_ptr(tbl->stats, cpu); + } + return NULL; +} + +static void neigh_stat_seq_stop(struct seq_file *seq, void *v) +{ + +} + +static int neigh_stat_seq_show(struct seq_file *seq, void *v) +{ + struct proc_dir_entry *pde = seq->private; + struct neigh_table *tbl = pde->data; + struct neigh_statistics *st = v; + + if (v == SEQ_START_TOKEN) { + seq_printf(seq, "entries allocs destroys hash_grows lookups hits res_failed rcv_probes_mcast rcv_probes_ucast periodic_gc_runs forced_gc_runs forced_gc_goal_miss\n"); + return 0; + } + + seq_printf(seq, "%08x %08x %08x %08x %08x %08x %08x %08x %08x " + "%08x %08x %08x\n", + tbl->entries, + + st->allocs, + st->destroys, + st->hash_grows, + + st->lookups, + st->hits, + + st->res_failed, + + st->rcv_probes_mcast, + st->rcv_probes_ucast, + + st->periodic_gc_runs, + st->forced_gc_runs, + st->forced_gc_goal_miss + ); + + return 0; +} + +static struct seq_operations neigh_stat_seq_ops = { + .start = neigh_stat_seq_start, + .next = neigh_stat_seq_next, + .stop = neigh_stat_seq_stop, + .show = neigh_stat_seq_show, +}; + +static int neigh_stat_seq_open(struct inode *inode, struct file *file) +{ + int ret = seq_open(file, &neigh_stat_seq_ops); + + if (!ret) { + struct seq_file *sf = file->private_data; + sf->private = PDE(inode); + } + return ret; +}; + +static struct file_operations neigh_stat_seq_fops = { + .owner = THIS_MODULE, + .open = neigh_stat_seq_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + #endif /* CONFIG_PROC_FS */ #ifdef CONFIG_ARPD Index: linux-2.6.9-rc2-bk9-neigh1/net/ipv6/ndisc.c =================================================================== --- linux-2.6.9-rc2-bk9-neigh1.orig/net/ipv6/ndisc.c 2004-09-26 12:29:03.000000000 +0200 +++ linux-2.6.9-rc2-bk9-neigh1/net/ipv6/ndisc.c 2004-09-26 23:30:56.000000000 +0200 @@ -802,9 +802,9 @@ } if (inc) - nd_tbl.stats.rcv_probes_mcast++; + NEIGH_CACHE_STAT_INC(&nd_tbl, rcv_probes_mcast); else - nd_tbl.stats.rcv_probes_ucast++; + NEIGH_CACHE_STAT_INC(&nd_tbl, rcv_probes_ucast); /* * update / create cache entry [-- Attachment #2: Digital signature --] [-- Type: application/pgp-signature, Size: 189 bytes --] ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH 2.6] neighbour cache statistics like rt_stat 2004-09-27 16:23 ` Harald Welte @ 2004-09-27 19:21 ` David S. Miller 2004-09-27 22:20 ` Harald Welte 0 siblings, 1 reply; 5+ messages in thread From: David S. Miller @ 2004-09-27 19:21 UTC (permalink / raw) To: Harald Welte; +Cc: netdev On Mon, 27 Sep 2004 18:23:34 +0200 Harald Welte <laforge@gnumonks.org> wrote: > On Mon, Sep 27, 2004 at 11:36:13AM +0200, Harald Welte wrote: > > The patch below (on top of davem's recent 6-patch set and 4-patch-set up > > to diff4) adds rt_stat like statistics to the neighbour cache core. > > I've now updated the patch. > > Changes: > - more statistics (lookups, destroy, periodic_gc_runs) > - add template line to top of file I'm generally very happy with these changes, but two things: 1) Please update the patch since I replaced "diff4" with a patch simply removing the INCOMPLETE checks from neigh_forced_gc() 2) I'd recommend using unsigned long for all the statistics. Thanks. ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH 2.6] neighbour cache statistics like rt_stat 2004-09-27 19:21 ` David S. Miller @ 2004-09-27 22:20 ` Harald Welte 2004-09-28 5:17 ` David S. Miller 0 siblings, 1 reply; 5+ messages in thread From: Harald Welte @ 2004-09-27 22:20 UTC (permalink / raw) To: David S. Miller; +Cc: netdev [-- Attachment #1.1: Type: text/plain, Size: 562 bytes --] Hi Dave! On Mon, Sep 27, 2004 at 12:21:36PM -0700, David S. Miller wrote: > 1) Please update the patch since I replaced "diff4" with > a patch simply removing the INCOMPLETE checks from neigh_forced_gc() > > 2) I'd recommend using unsigned long for all the statistics. both updated in attached version. -- - Harald Welte <laforge@gnumonks.org> http://www.gnumonks.org/ ============================================================================ Programming is like sex: One mistake and you have to support it your lifetime [-- Attachment #1.2: laforge-neigh_statistics.patch --] [-- Type: text/plain, Size: 10055 bytes --] Add rtstat-like per-cpu statistics to the neighbour cache core. This will add /proc/net/arp_cache_stat for ipv4 /proc/net/ndisc_cache_stat for ipv6 /proc/net/clip_arp_cache_stat for atm/clip /proc/net/decnet_neigh_stat for decnet The format is similar to rt_stat, one line per cpu where each line is: Field 0: Total number of entries in table Field 1: Total number of neighbour allocations in this tbl Field 2: Total number of neighbour destroys in this tbl Field 3: Total number of hash bucket grows Field 4: Total number of failed neighbour resolves Field 5: Total number of cache lookups Field 6: Total number of cache hits Field 7: Total number of received multicast solicitations Field 8: Total number of received unicast solicitations Field 9: Total number of periodic garbage collector runs Field 10: Total number of forced garbage collector runs Signed-off-by: Harald Welte <laforge@gnumonks.org> Index: linux-2.6.9-rc2-bk9-neigh1/include/net/neighbour.h =================================================================== --- linux-2.6.9-rc2-bk9-neigh1.orig/include/net/neighbour.h 2004-09-26 12:45:38.000000000 +0200 +++ linux-2.6.9-rc2-bk9-neigh1/include/net/neighbour.h 2004-09-28 00:07:55.544774240 +0200 @@ -7,6 +7,11 @@ * Authors: * Pedro Roque <roque@di.fc.ul.pt> * Alexey Kuznetsov <kuznet@ms2.inr.ac.ru> + * + * Changes: + * + * Harald Welte: <laforge@gnumonks.org> + * - Add neighbour cache statistics like rtstat */ /* The following flags & states are exported to user space, @@ -90,12 +95,25 @@ struct neigh_statistics { - unsigned long allocs; - unsigned long res_failed; - unsigned long rcv_probes_mcast; - unsigned long rcv_probes_ucast; + unsigned long allocs; /* number of allocated neighs */ + unsigned long destroys; /* number of destroyed neighs */ + unsigned long hash_grows; /* number of hash resizes */ + + unsigned long res_failed; /* nomber of failed resolutions */ + + unsigned long lookups; /* number of lookups */ + unsigned long hits; /* number of hits (among lookups) */ + + unsigned long rcv_probes_mcast; /* number of received mcast ipv6 */ + unsigned long rcv_probes_ucast; /* number of received ucast ipv6 */ + + unsigned long periodic_gc_runs; /* number of periodic GC runs */ + unsigned long forced_gc_runs; /* number of forced GC runs */ }; +#define NEIGH_CACHE_STAT_INC(tbl, field) \ + (per_cpu_ptr((tbl)->stats, smp_processor_id())->field++) + struct neighbour { struct neighbour *next; @@ -172,12 +190,15 @@ unsigned long last_rand; struct neigh_parms *parms_list; kmem_cache_t *kmem_cachep; - struct neigh_statistics stats; + struct neigh_statistics *stats; struct neighbour **hash_buckets; unsigned int hash_mask; __u32 hash_rnd; unsigned int hash_chain_gc; struct pneigh_entry **phash_buckets; +#ifdef CONFIG_PROC_FS + struct proc_dir_entry *pde; +#endif }; /* flags for neigh_update() */ Index: linux-2.6.9-rc2-bk9-neigh1/net/core/neighbour.c =================================================================== --- linux-2.6.9-rc2-bk9-neigh1.orig/net/core/neighbour.c 2004-09-28 00:05:19.555488216 +0200 +++ linux-2.6.9-rc2-bk9-neigh1/net/core/neighbour.c 2004-09-28 00:15:51.372437440 +0200 @@ -12,6 +12,7 @@ * * Fixes: * Vitaly E. Lavrov releasing NULL neighbor in neigh_add. + * Harald Welte Add neighbour cache statistics like rtstat */ #include <linux/config.h> @@ -21,6 +22,7 @@ #include <linux/socket.h> #include <linux/sched.h> #include <linux/netdevice.h> +#include <linux/proc_fs.h> #ifdef CONFIG_SYSCTL #include <linux/sysctl.h> #endif @@ -59,6 +61,7 @@ static int neigh_glbl_allocs; static struct neigh_table *neigh_tables; +static struct file_operations neigh_stat_seq_fops; /* Neighbour hash table buckets are protected with rwlock tbl->lock. @@ -116,6 +119,8 @@ int shrunk = 0; int i; + NEIGH_CACHE_STAT_INC(tbl, forced_gc_runs); + write_lock_bh(&tbl->lock); for (i = 0; i <= tbl->hash_mask; i++) { struct neighbour *n, **np; @@ -273,7 +278,8 @@ init_timer(&n->timer); n->timer.function = neigh_timer_handler; n->timer.data = (unsigned long)n; - tbl->stats.allocs++; + + NEIGH_CACHE_STAT_INC(tbl, allocs); neigh_glbl_allocs++; tbl->entries++; n->tbl = tbl; @@ -315,6 +321,8 @@ struct neighbour **new_hash, **old_hash; unsigned int i, new_hash_mask, old_entries; + NEIGH_CACHE_STAT_INC(tbl, hash_grows); + BUG_ON(new_entries & (new_entries - 1)); new_hash = neigh_hash_alloc(new_entries); if (!new_hash) @@ -349,11 +357,14 @@ struct neighbour *n; int key_len = tbl->key_len; u32 hash_val = tbl->hash(pkey, dev) & tbl->hash_mask; + + NEIGH_CACHE_STAT_INC(tbl, lookups); read_lock_bh(&tbl->lock); for (n = tbl->hash_buckets[hash_val]; n; n = n->next) { if (dev == n->dev && !memcmp(n->primary_key, pkey, key_len)) { neigh_hold(n); + NEIGH_CACHE_STAT_INC(tbl, hits); break; } } @@ -367,10 +378,13 @@ int key_len = tbl->key_len; u32 hash_val = tbl->hash(pkey, NULL) & tbl->hash_mask; + NEIGH_CACHE_STAT_INC(tbl, lookups); + read_lock_bh(&tbl->lock); for (n = tbl->hash_buckets[hash_val]; n; n = n->next) { if (!memcmp(n->primary_key, pkey, key_len)) { neigh_hold(n); + NEIGH_CACHE_STAT_INC(tbl, hits); break; } } @@ -555,6 +569,8 @@ { struct hh_cache *hh; + NEIGH_CACHE_STAT_INC(neigh->tbl, destroys); + if (!neigh->dead) { printk(KERN_WARNING "Destroying alive neighbour %p\n", neigh); @@ -630,6 +646,8 @@ struct neighbour *n, **np; unsigned long expire, now = jiffies; + NEIGH_CACHE_STAT_INC(tbl, periodic_gc_runs); + write_lock(&tbl->lock); /* @@ -761,7 +779,7 @@ neigh->nud_state = NUD_FAILED; notify = 1; - neigh->tbl->stats.res_failed++; + NEIGH_CACHE_STAT_INC(neigh->tbl, res_failed); NEIGH_PRINTK2("neigh %p is failed.\n", neigh); /* It is very thin place. report_unreachable is very complicated @@ -1310,6 +1328,29 @@ if (!tbl->kmem_cachep) panic("cannot create neighbour cache"); + tbl->stats = alloc_percpu(struct neigh_statistics); + if (!tbl->stats) + panic("cannot create neighbour cache statistics"); + +#ifdef CONFIG_PROC_FS +#define NC_STAT_SUFFIX "_stat" + { + char *proc_stat_name; + proc_stat_name = kmalloc(strlen(tbl->id) + + strlen(NC_STAT_SUFFIX) + 1, GFP_KERNEL); + if (!proc_stat_name) + panic("cannot allocate neighbour cache proc name buffer"); + strcpy(proc_stat_name, tbl->id); + strcat(proc_stat_name, NC_STAT_SUFFIX); + + tbl->pde = create_proc_entry(proc_stat_name, 0, proc_net); + if (!tbl->pde) + panic("cannot create neighbour proc dir entry"); + tbl->pde->proc_fops = &neigh_stat_seq_fops; + tbl->pde->data = tbl; + } +#endif + tbl->hash_mask = 0x1f; tbl->hash_buckets = neigh_hash_alloc(tbl->hash_mask + 1); @@ -1856,6 +1897,106 @@ } EXPORT_SYMBOL(neigh_seq_stop); +/* statistics via seq_file */ + +static void *neigh_stat_seq_start(struct seq_file *seq, loff_t *pos) +{ + struct proc_dir_entry *pde = seq->private; + struct neigh_table *tbl = pde->data; + int cpu; + + if (*pos == 0) + return SEQ_START_TOKEN; + + for (cpu = *pos-1; cpu < NR_CPUS; ++cpu) { + if (!cpu_possible(cpu)) + continue; + *pos = cpu+1; + return per_cpu_ptr(tbl->stats, cpu); + } + return NULL; +} + +static void *neigh_stat_seq_next(struct seq_file *seq, void *v, loff_t *pos) +{ + struct proc_dir_entry *pde = seq->private; + struct neigh_table *tbl = pde->data; + int cpu; + + for (cpu = *pos; cpu < NR_CPUS; ++cpu) { + if (!cpu_possible(cpu)) + continue; + *pos = cpu+1; + return per_cpu_ptr(tbl->stats, cpu); + } + return NULL; +} + +static void neigh_stat_seq_stop(struct seq_file *seq, void *v) +{ + +} + +static int neigh_stat_seq_show(struct seq_file *seq, void *v) +{ + struct proc_dir_entry *pde = seq->private; + struct neigh_table *tbl = pde->data; + struct neigh_statistics *st = v; + + if (v == SEQ_START_TOKEN) { + seq_printf(seq, "entries allocs destroys hash_grows lookups hits res_failed rcv_probes_mcast rcv_probes_ucast periodic_gc_runs forced_gc_runs forced_gc_goal_miss\n"); + return 0; + } + + seq_printf(seq, "%08x %08lx %08lx %08lx %08lx %08lx %08lx " + "%08lx %08lx %08lx %08lx\n", + tbl->entries, + + st->allocs, + st->destroys, + st->hash_grows, + + st->lookups, + st->hits, + + st->res_failed, + + st->rcv_probes_mcast, + st->rcv_probes_ucast, + + st->periodic_gc_runs, + st->forced_gc_runs + ); + + return 0; +} + +static struct seq_operations neigh_stat_seq_ops = { + .start = neigh_stat_seq_start, + .next = neigh_stat_seq_next, + .stop = neigh_stat_seq_stop, + .show = neigh_stat_seq_show, +}; + +static int neigh_stat_seq_open(struct inode *inode, struct file *file) +{ + int ret = seq_open(file, &neigh_stat_seq_ops); + + if (!ret) { + struct seq_file *sf = file->private_data; + sf->private = PDE(inode); + } + return ret; +}; + +static struct file_operations neigh_stat_seq_fops = { + .owner = THIS_MODULE, + .open = neigh_stat_seq_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + #endif /* CONFIG_PROC_FS */ #ifdef CONFIG_ARPD Index: linux-2.6.9-rc2-bk9-neigh1/net/ipv6/ndisc.c =================================================================== --- linux-2.6.9-rc2-bk9-neigh1.orig/net/ipv6/ndisc.c 2004-09-26 12:29:03.000000000 +0200 +++ linux-2.6.9-rc2-bk9-neigh1/net/ipv6/ndisc.c 2004-09-28 00:05:29.917912888 +0200 @@ -802,9 +802,9 @@ } if (inc) - nd_tbl.stats.rcv_probes_mcast++; + NEIGH_CACHE_STAT_INC(&nd_tbl, rcv_probes_mcast); else - nd_tbl.stats.rcv_probes_ucast++; + NEIGH_CACHE_STAT_INC(&nd_tbl, rcv_probes_ucast); /* * update / create cache entry [-- Attachment #2: Digital signature --] [-- Type: application/pgp-signature, Size: 189 bytes --] ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH 2.6] neighbour cache statistics like rt_stat 2004-09-27 22:20 ` Harald Welte @ 2004-09-28 5:17 ` David S. Miller 0 siblings, 0 replies; 5+ messages in thread From: David S. Miller @ 2004-09-28 5:17 UTC (permalink / raw) To: Harald Welte; +Cc: netdev On Tue, 28 Sep 2004 00:20:55 +0200 Harald Welte <laforge@gnumonks.org> wrote: > On Mon, Sep 27, 2004 at 12:21:36PM -0700, David S. Miller wrote: > > > 1) Please update the patch since I replaced "diff4" with > > a patch simply removing the INCOMPLETE checks from neigh_forced_gc() > > > > 2) I'd recommend using unsigned long for all the statistics. > > both updated in attached version. Applied, thanks Harald. ^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2004-09-28 5:17 UTC | newest] Thread overview: 5+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2004-09-27 9:36 [PATCH 2.6] neighbour cache statistics like rt_stat Harald Welte 2004-09-27 16:23 ` Harald Welte 2004-09-27 19:21 ` David S. Miller 2004-09-27 22:20 ` Harald Welte 2004-09-28 5:17 ` David S. Miller
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).