]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - arch/x86/xen/multicalls.c
xen: add debugfs support
[linux-2.6-omap-h63xx.git] / arch / x86 / xen / multicalls.c
index 9efd1c6c9776c5f9e8973026dd03b111c6e9e585..8ea8a0d0b0deeff69a438a5ad4fc0552d250d68f 100644 (file)
  */
 #include <linux/percpu.h>
 #include <linux/hardirq.h>
+#include <linux/debugfs.h>
 
 #include <asm/xen/hypercall.h>
 
 #include "multicalls.h"
+#include "debugfs.h"
+
+#define MC_BATCH       32
 
 #define MC_DEBUG       1
 
-#define MC_BATCH       32
 #define MC_ARGS                (MC_BATCH * 16)
 
+
 struct mc_buffer {
        struct multicall_entry entries[MC_BATCH];
 #if MC_DEBUG
@@ -47,6 +51,76 @@ struct mc_buffer {
 static DEFINE_PER_CPU(struct mc_buffer, mc_buffer);
 DEFINE_PER_CPU(unsigned long, xen_mc_irq_flags);
 
+/* flush reasons 0- slots, 1- args, 2- callbacks */
+enum flush_reasons
+{
+       FL_SLOTS,
+       FL_ARGS,
+       FL_CALLBACKS,
+
+       FL_N_REASONS
+};
+
+#ifdef CONFIG_XEN_DEBUG_FS
+#define NHYPERCALLS    40              /* not really */
+
+static struct {
+       unsigned histo[MC_BATCH+1];
+
+       unsigned issued;
+       unsigned arg_total;
+       unsigned hypercalls;
+       unsigned histo_hypercalls[NHYPERCALLS];
+
+       unsigned flush[FL_N_REASONS];
+} mc_stats;
+
+static u8 zero_stats;
+
+static inline void check_zero(void)
+{
+       if (unlikely(zero_stats)) {
+               memset(&mc_stats, 0, sizeof(mc_stats));
+               zero_stats = 0;
+       }
+}
+
+static void mc_add_stats(const struct mc_buffer *mc)
+{
+       int i;
+
+       check_zero();
+
+       mc_stats.issued++;
+       mc_stats.hypercalls += mc->mcidx;
+       mc_stats.arg_total += mc->argidx;
+
+       mc_stats.histo[mc->mcidx]++;
+       for(i = 0; i < mc->mcidx; i++) {
+               unsigned op = mc->entries[i].op;
+               if (op < NHYPERCALLS)
+                       mc_stats.histo_hypercalls[op]++;
+       }
+}
+
+static void mc_stats_flush(enum flush_reasons idx)
+{
+       check_zero();
+
+       mc_stats.flush[idx]++;
+}
+
+#else  /* !CONFIG_XEN_DEBUG_FS */
+
+static inline void mc_add_stats(const struct mc_buffer *mc)
+{
+}
+
+static inline void mc_stats_flush(enum flush_reasons idx)
+{
+}
+#endif /* CONFIG_XEN_DEBUG_FS */
+
 void xen_mc_flush(void)
 {
        struct mc_buffer *b = &__get_cpu_var(mc_buffer);
@@ -60,6 +134,8 @@ void xen_mc_flush(void)
           something in the middle */
        local_irq_save(flags);
 
+       mc_add_stats(b);
+
        if (b->mcidx) {
 #if MC_DEBUG
                memcpy(b->debug, b->entries,
@@ -115,6 +191,7 @@ struct multicall_space __xen_mc_entry(size_t args)
 
        if (b->mcidx == MC_BATCH ||
            (argidx + args) > MC_ARGS) {
+               mc_stats_flush(b->mcidx == MC_BATCH ? FL_SLOTS : FL_ARGS);
                xen_mc_flush();
                argidx = roundup(b->argidx, sizeof(u64));
        }
@@ -158,10 +235,44 @@ void xen_mc_callback(void (*fn)(void *), void *data)
        struct mc_buffer *b = &__get_cpu_var(mc_buffer);
        struct callback *cb;
 
-       if (b->cbidx == MC_BATCH)
+       if (b->cbidx == MC_BATCH) {
+               mc_stats_flush(FL_CALLBACKS);
                xen_mc_flush();
+       }
 
        cb = &b->callbacks[b->cbidx++];
        cb->fn = fn;
        cb->data = data;
 }
+
+#ifdef CONFIG_XEN_DEBUG_FS
+
+static struct dentry *d_mc_debug;
+
+static int __init xen_mc_debugfs(void)
+{
+       struct dentry *d_xen = xen_init_debugfs();
+
+       if (d_xen == NULL)
+               return -ENOMEM;
+
+       d_mc_debug = debugfs_create_dir("multicalls", d_xen);
+
+       debugfs_create_u8("zero_stats", 0644, d_mc_debug, &zero_stats);
+
+       debugfs_create_u32("batches", 0444, d_mc_debug, &mc_stats.issued);
+       debugfs_create_u32("hypercalls", 0444, d_mc_debug, &mc_stats.hypercalls);
+       debugfs_create_u32("arg_total", 0444, d_mc_debug, &mc_stats.arg_total);
+
+       xen_debugfs_create_u32_array("batch_histo", 0444, d_mc_debug,
+                                    mc_stats.histo, MC_BATCH);
+       xen_debugfs_create_u32_array("hypercall_histo", 0444, d_mc_debug,
+                                    mc_stats.histo_hypercalls, NHYPERCALLS);
+       xen_debugfs_create_u32_array("flush_reasons", 0444, d_mc_debug,
+                                    mc_stats.flush, FL_N_REASONS);
+
+       return 0;
+}
+fs_initcall(xen_mc_debugfs);
+
+#endif /* CONFIG_XEN_DEBUG_FS */