linux/kernel/rcutree_trace.c
<<
>>
Prefs
   1/*
   2 * Read-Copy Update tracing for classic implementation
   3 *
   4 * This program is free software; you can redistribute it and/or modify
   5 * it under the terms of the GNU General Public License as published by
   6 * the Free Software Foundation; either version 2 of the License, or
   7 * (at your option) any later version.
   8 *
   9 * This program is distributed in the hope that it will be useful,
  10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12 * GNU General Public License for more details.
  13 *
  14 * You should have received a copy of the GNU General Public License
  15 * along with this program; if not, write to the Free Software
  16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  17 *
  18 * Copyright IBM Corporation, 2008
  19 *
  20 * Papers:  http://www.rdrop.com/users/paulmck/RCU
  21 *
  22 * For detailed explanation of Read-Copy Update mechanism see -
  23 *              Documentation/RCU
  24 *
  25 */
  26#include <linux/types.h>
  27#include <linux/kernel.h>
  28#include <linux/init.h>
  29#include <linux/spinlock.h>
  30#include <linux/smp.h>
  31#include <linux/rcupdate.h>
  32#include <linux/interrupt.h>
  33#include <linux/sched.h>
  34#include <asm/atomic.h>
  35#include <linux/bitops.h>
  36#include <linux/module.h>
  37#include <linux/completion.h>
  38#include <linux/moduleparam.h>
  39#include <linux/percpu.h>
  40#include <linux/notifier.h>
  41#include <linux/cpu.h>
  42#include <linux/mutex.h>
  43#include <linux/debugfs.h>
  44#include <linux/seq_file.h>
  45
  46#define RCU_TREE_NONCORE
  47#include "rcutree.h"
  48
  49static void print_one_rcu_data(struct seq_file *m, struct rcu_data *rdp)
  50{
  51        if (!rdp->beenonline)
  52                return;
  53        seq_printf(m, "%3d%cc=%lu g=%lu pq=%d pqc=%lu qp=%d",
  54                   rdp->cpu,
  55                   cpu_is_offline(rdp->cpu) ? '!' : ' ',
  56                   rdp->completed, rdp->gpnum,
  57                   rdp->passed_quiesc, rdp->passed_quiesc_completed,
  58                   rdp->qs_pending);
  59#ifdef CONFIG_NO_HZ
  60        seq_printf(m, " dt=%d/%d dn=%d df=%lu",
  61                   rdp->dynticks->dynticks,
  62                   rdp->dynticks->dynticks_nesting,
  63                   rdp->dynticks->dynticks_nmi,
  64                   rdp->dynticks_fqs);
  65#endif /* #ifdef CONFIG_NO_HZ */
  66        seq_printf(m, " of=%lu ri=%lu", rdp->offline_fqs, rdp->resched_ipi);
  67        seq_printf(m, " ql=%ld b=%ld", rdp->qlen, rdp->blimit);
  68        seq_printf(m, " ci=%lu co=%lu ca=%lu\n",
  69                   rdp->n_cbs_invoked, rdp->n_cbs_orphaned, rdp->n_cbs_adopted);
  70}
  71
  72#define PRINT_RCU_DATA(name, func, m) \
  73        do { \
  74                int _p_r_d_i; \
  75                \
  76                for_each_possible_cpu(_p_r_d_i) \
  77                        func(m, &per_cpu(name, _p_r_d_i)); \
  78        } while (0)
  79
  80static int show_rcudata(struct seq_file *m, void *unused)
  81{
  82#ifdef CONFIG_TREE_PREEMPT_RCU
  83        seq_puts(m, "rcu_preempt:\n");
  84        PRINT_RCU_DATA(rcu_preempt_data, print_one_rcu_data, m);
  85#endif /* #ifdef CONFIG_TREE_PREEMPT_RCU */
  86        seq_puts(m, "rcu_sched:\n");
  87        PRINT_RCU_DATA(rcu_sched_data, print_one_rcu_data, m);
  88        seq_puts(m, "rcu_bh:\n");
  89        PRINT_RCU_DATA(rcu_bh_data, print_one_rcu_data, m);
  90        return 0;
  91}
  92
  93static int rcudata_open(struct inode *inode, struct file *file)
  94{
  95        return single_open(file, show_rcudata, NULL);
  96}
  97
  98static const struct file_operations rcudata_fops = {
  99        .owner = THIS_MODULE,
 100        .open = rcudata_open,
 101        .read = seq_read,
 102        .llseek = seq_lseek,
 103        .release = single_release,
 104};
 105
 106static void print_one_rcu_data_csv(struct seq_file *m, struct rcu_data *rdp)
 107{
 108        if (!rdp->beenonline)
 109                return;
 110        seq_printf(m, "%d,%s,%lu,%lu,%d,%lu,%d",
 111                   rdp->cpu,
 112                   cpu_is_offline(rdp->cpu) ? "\"N\"" : "\"Y\"",
 113                   rdp->completed, rdp->gpnum,
 114                   rdp->passed_quiesc, rdp->passed_quiesc_completed,
 115                   rdp->qs_pending);
 116#ifdef CONFIG_NO_HZ
 117        seq_printf(m, ",%d,%d,%d,%lu",
 118                   rdp->dynticks->dynticks,
 119                   rdp->dynticks->dynticks_nesting,
 120                   rdp->dynticks->dynticks_nmi,
 121                   rdp->dynticks_fqs);
 122#endif /* #ifdef CONFIG_NO_HZ */
 123        seq_printf(m, ",%lu,%lu", rdp->offline_fqs, rdp->resched_ipi);
 124        seq_printf(m, ",%ld,%ld", rdp->qlen, rdp->blimit);
 125        seq_printf(m, ",%lu,%lu,%lu\n",
 126                   rdp->n_cbs_invoked, rdp->n_cbs_orphaned, rdp->n_cbs_adopted);
 127}
 128
 129static int show_rcudata_csv(struct seq_file *m, void *unused)
 130{
 131        seq_puts(m, "\"CPU\",\"Online?\",\"c\",\"g\",\"pq\",\"pqc\",\"pq\",");
 132#ifdef CONFIG_NO_HZ
 133        seq_puts(m, "\"dt\",\"dt nesting\",\"dn\",\"df\",");
 134#endif /* #ifdef CONFIG_NO_HZ */
 135        seq_puts(m, "\"of\",\"ri\",\"ql\",\"b\",\"ci\",\"co\",\"ca\"\n");
 136#ifdef CONFIG_TREE_PREEMPT_RCU
 137        seq_puts(m, "\"rcu_preempt:\"\n");
 138        PRINT_RCU_DATA(rcu_preempt_data, print_one_rcu_data_csv, m);
 139#endif /* #ifdef CONFIG_TREE_PREEMPT_RCU */
 140        seq_puts(m, "\"rcu_sched:\"\n");
 141        PRINT_RCU_DATA(rcu_sched_data, print_one_rcu_data_csv, m);
 142        seq_puts(m, "\"rcu_bh:\"\n");
 143        PRINT_RCU_DATA(rcu_bh_data, print_one_rcu_data_csv, m);
 144        return 0;
 145}
 146
 147static int rcudata_csv_open(struct inode *inode, struct file *file)
 148{
 149        return single_open(file, show_rcudata_csv, NULL);
 150}
 151
 152static const struct file_operations rcudata_csv_fops = {
 153        .owner = THIS_MODULE,
 154        .open = rcudata_csv_open,
 155        .read = seq_read,
 156        .llseek = seq_lseek,
 157        .release = single_release,
 158};
 159
 160static void print_one_rcu_state(struct seq_file *m, struct rcu_state *rsp)
 161{
 162        unsigned long gpnum;
 163        int level = 0;
 164        int phase;
 165        struct rcu_node *rnp;
 166
 167        gpnum = rsp->gpnum;
 168        seq_printf(m, "c=%lu g=%lu s=%d jfq=%ld j=%x "
 169                      "nfqs=%lu/nfqsng=%lu(%lu) fqlh=%lu\n",
 170                   rsp->completed, gpnum, rsp->signaled,
 171                   (long)(rsp->jiffies_force_qs - jiffies),
 172                   (int)(jiffies & 0xffff),
 173                   rsp->n_force_qs, rsp->n_force_qs_ngp,
 174                   rsp->n_force_qs - rsp->n_force_qs_ngp,
 175                   rsp->n_force_qs_lh);
 176        for (rnp = &rsp->node[0]; rnp - &rsp->node[0] < NUM_RCU_NODES; rnp++) {
 177                if (rnp->level != level) {
 178                        seq_puts(m, "\n");
 179                        level = rnp->level;
 180                }
 181                phase = gpnum & 0x1;
 182                seq_printf(m, "%lx/%lx %c%c>%c%c %d:%d ^%d    ",
 183                           rnp->qsmask, rnp->qsmaskinit,
 184                           "T."[list_empty(&rnp->blocked_tasks[phase])],
 185                           "E."[list_empty(&rnp->blocked_tasks[phase + 2])],
 186                           "T."[list_empty(&rnp->blocked_tasks[!phase])],
 187                           "E."[list_empty(&rnp->blocked_tasks[!phase + 2])],
 188                           rnp->grplo, rnp->grphi, rnp->grpnum);
 189        }
 190        seq_puts(m, "\n");
 191}
 192
 193static int show_rcuhier(struct seq_file *m, void *unused)
 194{
 195#ifdef CONFIG_TREE_PREEMPT_RCU
 196        seq_puts(m, "rcu_preempt:\n");
 197        print_one_rcu_state(m, &rcu_preempt_state);
 198#endif /* #ifdef CONFIG_TREE_PREEMPT_RCU */
 199        seq_puts(m, "rcu_sched:\n");
 200        print_one_rcu_state(m, &rcu_sched_state);
 201        seq_puts(m, "rcu_bh:\n");
 202        print_one_rcu_state(m, &rcu_bh_state);
 203        return 0;
 204}
 205
 206static int rcuhier_open(struct inode *inode, struct file *file)
 207{
 208        return single_open(file, show_rcuhier, NULL);
 209}
 210
 211static const struct file_operations rcuhier_fops = {
 212        .owner = THIS_MODULE,
 213        .open = rcuhier_open,
 214        .read = seq_read,
 215        .llseek = seq_lseek,
 216        .release = single_release,
 217};
 218
 219static int show_rcugp(struct seq_file *m, void *unused)
 220{
 221#ifdef CONFIG_TREE_PREEMPT_RCU
 222        seq_printf(m, "rcu_preempt: completed=%ld  gpnum=%lu\n",
 223                   rcu_preempt_state.completed, rcu_preempt_state.gpnum);
 224#endif /* #ifdef CONFIG_TREE_PREEMPT_RCU */
 225        seq_printf(m, "rcu_sched: completed=%ld  gpnum=%lu\n",
 226                   rcu_sched_state.completed, rcu_sched_state.gpnum);
 227        seq_printf(m, "rcu_bh: completed=%ld  gpnum=%lu\n",
 228                   rcu_bh_state.completed, rcu_bh_state.gpnum);
 229        return 0;
 230}
 231
 232static int rcugp_open(struct inode *inode, struct file *file)
 233{
 234        return single_open(file, show_rcugp, NULL);
 235}
 236
 237static const struct file_operations rcugp_fops = {
 238        .owner = THIS_MODULE,
 239        .open = rcugp_open,
 240        .read = seq_read,
 241        .llseek = seq_lseek,
 242        .release = single_release,
 243};
 244
 245static void print_one_rcu_pending(struct seq_file *m, struct rcu_data *rdp)
 246{
 247        seq_printf(m, "%3d%cnp=%ld "
 248                   "qsp=%ld rpq=%ld cbr=%ld cng=%ld "
 249                   "gpc=%ld gps=%ld nf=%ld nn=%ld\n",
 250                   rdp->cpu,
 251                   cpu_is_offline(rdp->cpu) ? '!' : ' ',
 252                   rdp->n_rcu_pending,
 253                   rdp->n_rp_qs_pending,
 254                   rdp->n_rp_report_qs,
 255                   rdp->n_rp_cb_ready,
 256                   rdp->n_rp_cpu_needs_gp,
 257                   rdp->n_rp_gp_completed,
 258                   rdp->n_rp_gp_started,
 259                   rdp->n_rp_need_fqs,
 260                   rdp->n_rp_need_nothing);
 261}
 262
 263static void print_rcu_pendings(struct seq_file *m, struct rcu_state *rsp)
 264{
 265        int cpu;
 266        struct rcu_data *rdp;
 267
 268        for_each_possible_cpu(cpu) {
 269                rdp = per_cpu_ptr(rsp->rda, cpu);
 270                if (rdp->beenonline)
 271                        print_one_rcu_pending(m, rdp);
 272        }
 273}
 274
 275static int show_rcu_pending(struct seq_file *m, void *unused)
 276{
 277#ifdef CONFIG_TREE_PREEMPT_RCU
 278        seq_puts(m, "rcu_preempt:\n");
 279        print_rcu_pendings(m, &rcu_preempt_state);
 280#endif /* #ifdef CONFIG_TREE_PREEMPT_RCU */
 281        seq_puts(m, "rcu_sched:\n");
 282        print_rcu_pendings(m, &rcu_sched_state);
 283        seq_puts(m, "rcu_bh:\n");
 284        print_rcu_pendings(m, &rcu_bh_state);
 285        return 0;
 286}
 287
 288static int rcu_pending_open(struct inode *inode, struct file *file)
 289{
 290        return single_open(file, show_rcu_pending, NULL);
 291}
 292
 293static const struct file_operations rcu_pending_fops = {
 294        .owner = THIS_MODULE,
 295        .open = rcu_pending_open,
 296        .read = seq_read,
 297        .llseek = seq_lseek,
 298        .release = single_release,
 299};
 300
 301static struct dentry *rcudir;
 302
 303static int __init rcutree_trace_init(void)
 304{
 305        struct dentry *retval;
 306
 307        rcudir = debugfs_create_dir("rcu", NULL);
 308        if (!rcudir)
 309                goto free_out;
 310
 311        retval = debugfs_create_file("rcudata", 0444, rcudir,
 312                                                NULL, &rcudata_fops);
 313        if (!retval)
 314                goto free_out;
 315
 316        retval = debugfs_create_file("rcudata.csv", 0444, rcudir,
 317                                                NULL, &rcudata_csv_fops);
 318        if (!retval)
 319                goto free_out;
 320
 321        retval = debugfs_create_file("rcugp", 0444, rcudir, NULL, &rcugp_fops);
 322        if (!retval)
 323                goto free_out;
 324
 325        retval = debugfs_create_file("rcuhier", 0444, rcudir,
 326                                                NULL, &rcuhier_fops);
 327        if (!retval)
 328                goto free_out;
 329
 330        retval = debugfs_create_file("rcu_pending", 0444, rcudir,
 331                                                NULL, &rcu_pending_fops);
 332        if (!retval)
 333                goto free_out;
 334        return 0;
 335free_out:
 336        debugfs_remove_recursive(rcudir);
 337        return 1;
 338}
 339
 340static void __exit rcutree_trace_cleanup(void)
 341{
 342        debugfs_remove_recursive(rcudir);
 343}
 344
 345
 346module_init(rcutree_trace_init);
 347module_exit(rcutree_trace_cleanup);
 348
 349MODULE_AUTHOR("Paul E. McKenney");
 350MODULE_DESCRIPTION("Read-Copy Update tracing for hierarchical implementation");
 351MODULE_LICENSE("GPL");
 352