From Dipankar This patch makes some basic statistics for RCU available in /proc/rcu. It is a trimmed down version of the earler rcu_stats patch in -mm kernels. I removed all the RCU implementation dependent stats (mostly needed for debugging) and retained only the part that was very generic in nature - # of RCU requests and # of actual RCU updates for each CPU. This will allow us to monitor the health of the RCU subsystem and such things have been extremely useful for me to investigate problems. [dipankar@llm04 dipankar]$ cat /proc/rcu CPU : 0 RCU requests : 0 RCU updates : 0 CPU : 1 RCU requests : 0 RCU updates : 0 CPU : 2 RCU requests : 0 RCU updates : 0 CPU : 3 RCU requests : 0 RCU updates : 0 Documentation/filesystems/proc.txt | 4 +++ fs/proc/proc_misc.c | 13 ++++++++++ include/linux/rcupdate.h | 4 +++ kernel/rcupdate.c | 48 +++++++++++++++++++++++++++++++++++-- 4 files changed, 67 insertions(+), 2 deletions(-) diff -puN fs/proc/proc_misc.c~rcu-stats fs/proc/proc_misc.c --- 25/fs/proc/proc_misc.c~rcu-stats 2003-03-23 00:23:48.000000000 -0800 +++ 25-akpm/fs/proc/proc_misc.c 2003-03-23 00:23:48.000000000 -0800 @@ -244,6 +244,18 @@ static struct file_operations proc_cpuin .release = seq_release, }; +extern struct seq_operations rcu_op; +static int rcu_open(struct inode *inode, struct file *file) +{ + return seq_open(file, &rcu_op); +} +static struct file_operations proc_rcu_operations = { + .open = rcu_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + extern struct seq_operations vmstat_op; static int vmstat_open(struct inode *inode, struct file *file) { @@ -590,6 +602,7 @@ void __init proc_misc_init(void) if (entry) entry->proc_fops = &proc_kmsg_operations; create_seq_entry("cpuinfo", 0, &proc_cpuinfo_operations); + create_seq_entry("rcu", 0, &proc_rcu_operations); create_seq_entry("partitions", 0, &proc_partitions_operations); #if !defined(CONFIG_ARCH_S390) create_seq_entry("interrupts", 0, &proc_interrupts_operations); diff -puN include/linux/rcupdate.h~rcu-stats include/linux/rcupdate.h --- 25/include/linux/rcupdate.h~rcu-stats 2003-03-23 00:23:48.000000000 -0800 +++ 25-akpm/include/linux/rcupdate.h 2003-03-23 00:23:48.000000000 -0800 @@ -95,6 +95,8 @@ struct rcu_data { long batch; /* Batch # for current RCU batch */ struct list_head nxtlist; struct list_head curlist; + long nr_rcureqs; + long nr_rcupdates; }; DECLARE_PER_CPU(struct rcu_data, rcu_data); @@ -105,6 +107,8 @@ extern struct rcu_ctrlblk rcu_ctrlblk; #define RCU_batch(cpu) (per_cpu(rcu_data, (cpu)).batch) #define RCU_nxtlist(cpu) (per_cpu(rcu_data, (cpu)).nxtlist) #define RCU_curlist(cpu) (per_cpu(rcu_data, (cpu)).curlist) +#define RCU_nr_rcureqs(cpu) (per_cpu(rcu_data, (cpu)).nr_rcureqs) +#define RCU_nr_rcupdates(cpu) (per_cpu(rcu_data, (cpu)).nr_rcupdates) #define RCU_QSCTR_INVALID 0 diff -puN kernel/rcupdate.c~rcu-stats kernel/rcupdate.c --- 25/kernel/rcupdate.c~rcu-stats 2003-03-23 00:23:48.000000000 -0800 +++ 25-akpm/kernel/rcupdate.c 2003-03-23 00:23:48.000000000 -0800 @@ -41,6 +41,7 @@ #include #include #include +#include #include #include @@ -75,6 +76,7 @@ void call_rcu(struct rcu_head *head, voi local_irq_save(flags); cpu = smp_processor_id(); list_add_tail(&head->list, &RCU_nxtlist(cpu)); + RCU_nr_rcureqs(cpu)++; local_irq_restore(flags); } @@ -82,7 +84,7 @@ void call_rcu(struct rcu_head *head, voi * Invoke the completed RCU callbacks. They are expected to be in * a per-cpu list. */ -static void rcu_do_batch(struct list_head *list) +static void rcu_do_batch(int cpu, struct list_head *list) { struct list_head *entry; struct rcu_head *head; @@ -92,6 +94,7 @@ static void rcu_do_batch(struct list_hea list_del(entry); head = list_entry(entry, struct rcu_head, list); head->func(head->arg); + RCU_nr_rcupdates(cpu)++; } } @@ -187,7 +190,7 @@ static void rcu_process_callbacks(unsign } rcu_check_quiescent_state(); if (!list_empty(&list)) - rcu_do_batch(&list); + rcu_do_batch(cpu, &list); } void rcu_check_callbacks(int cpu, int user) @@ -266,3 +269,44 @@ void synchronize_kernel(void) EXPORT_SYMBOL(call_rcu); EXPORT_SYMBOL(synchronize_kernel); + +#ifdef CONFIG_PROC_FS + +static void *rcu_start(struct seq_file *m, loff_t *pos) +{ + static int cpu; + cpu = *pos; + return *pos < NR_CPUS ? &cpu : NULL; +} + +static void *rcu_next(struct seq_file *m, void *v, loff_t *pos) +{ + ++*pos; + return rcu_start(m, pos); +} + +static void rcu_stop(struct seq_file *m, void *v) +{ +} + +static int show_rcu(struct seq_file *m, void *v) +{ + int cpu = *(int *)v; + + if (!cpu_online(cpu)) + return 0; + seq_printf(m, "CPU : %d\n", cpu); + seq_printf(m, "RCU requests : %ld\n", RCU_nr_rcureqs(cpu)); + seq_printf(m, "RCU updates : %ld\n\n", RCU_nr_rcupdates(cpu)); + return 0; +} + +struct seq_operations rcu_op = { + .start = rcu_start, + .next = rcu_next, + .stop = rcu_stop, + .show = show_rcu, +}; + +#endif + diff -puN Documentation/filesystems/proc.txt~rcu-stats Documentation/filesystems/proc.txt --- 25/Documentation/filesystems/proc.txt~rcu-stats 2003-03-23 00:23:48.000000000 -0800 +++ 25-akpm/Documentation/filesystems/proc.txt 2003-03-23 00:23:48.000000000 -0800 @@ -222,6 +222,7 @@ Table 1-3: Kernel info in /proc partitions Table of partitions known to the system pci Depreciated info of PCI bus (new way -> /proc/bus/pci/, decoupled by lspci (2.4) + rcu Read-Copy Update information (2.5) rtc Real time clock scsi SCSI info (see text) slabinfo Slab pool info @@ -346,6 +347,9 @@ available. In this case, there are 0 ch ZONE_DMA, 4 chunks of 2^1*PAGE_SIZE in ZONE_DMA, 101 chunks of 2^4*PAGE_SIZE available in ZONE_NORMAL, etc... +The rcu file gives information about Read-Copy Update synchronization +primitive. It indicates the number for RCU requests and actual +updates for every CPU. 1.3 IDE devices in /proc/ide ---------------------------- _