Merge branch 'perfcounters/urgent' into perfcounters/core
authorIngo Molnar <mingo@elte.hu>
Sat, 15 Aug 2009 10:06:12 +0000 (12:06 +0200)
committerIngo Molnar <mingo@elte.hu>
Sat, 15 Aug 2009 10:06:12 +0000 (12:06 +0200)
Conflicts:
kernel/perf_counter.c

Merge reason: update to latest upstream (-rc6) and resolve
              the conflict with urgent fixes.

Signed-off-by: Ingo Molnar <mingo@elte.hu>
21 files changed:
arch/x86/include/asm/perf_counter.h
arch/x86/kernel/cpu/perf_counter.c
tools/perf/Documentation/perf-report.txt
tools/perf/Makefile
tools/perf/builtin-annotate.c
tools/perf/builtin-record.c
tools/perf/builtin-report.c
tools/perf/builtin-stat.c
tools/perf/builtin-top.c
tools/perf/builtin.h
tools/perf/perf.h
tools/perf/util/callchain.h
tools/perf/util/debug.c [new file with mode: 0644]
tools/perf/util/debug.h [new file with mode: 0644]
tools/perf/util/event.h [new file with mode: 0644]
tools/perf/util/map.c [new file with mode: 0644]
tools/perf/util/symbol.c
tools/perf/util/symbol.h
tools/perf/util/util.h
tools/perf/util/values.c [new file with mode: 0644]
tools/perf/util/values.h [new file with mode: 0644]

index fa64e40..e7b7c93 100644 (file)
@@ -84,6 +84,16 @@ union cpuid10_edx {
 #define MSR_ARCH_PERFMON_FIXED_CTR2                    0x30b
 #define X86_PMC_IDX_FIXED_BUS_CYCLES                   (X86_PMC_IDX_FIXED + 2)
 
+/*
+ * We model BTS tracing as another fixed-mode PMC.
+ *
+ * We choose a value in the middle of the fixed counter range, since lower
+ * values are used by actual fixed counters and higher values are used
+ * to indicate other overflow conditions in the PERF_GLOBAL_STATUS msr.
+ */
+#define X86_PMC_IDX_FIXED_BTS                          (X86_PMC_IDX_FIXED + 16)
+
+
 #ifdef CONFIG_PERF_COUNTERS
 extern void init_hw_perf_counters(void);
 extern void perf_counters_lapic_init(void);
index 900332b..396e35d 100644 (file)
@@ -6,6 +6,7 @@
  *  Copyright (C) 2009 Jaswinder Singh Rajput
  *  Copyright (C) 2009 Advanced Micro Devices, Inc., Robert Richter
  *  Copyright (C) 2008-2009 Red Hat, Inc., Peter Zijlstra <pzijlstr@redhat.com>
+ *  Copyright (C) 2009 Intel Corporation, <markus.t.metzger@intel.com>
  *
  *  For licencing details see kernel-base/COPYING
  */
@@ -20,6 +21,7 @@
 #include <linux/sched.h>
 #include <linux/uaccess.h>
 #include <linux/highmem.h>
+#include <linux/cpu.h>
 
 #include <asm/apic.h>
 #include <asm/stacktrace.h>
 
 static u64 perf_counter_mask __read_mostly;
 
+/* The maximal number of PEBS counters: */
+#define MAX_PEBS_COUNTERS      4
+
+/* The size of a BTS record in bytes: */
+#define BTS_RECORD_SIZE                24
+
+/* The size of a per-cpu BTS buffer in bytes: */
+#define BTS_BUFFER_SIZE                (BTS_RECORD_SIZE * 1024)
+
+/* The BTS overflow threshold in bytes from the end of the buffer: */
+#define BTS_OVFL_TH            (BTS_RECORD_SIZE * 64)
+
+
+/*
+ * Bits in the debugctlmsr controlling branch tracing.
+ */
+#define X86_DEBUGCTL_TR                        (1 << 6)
+#define X86_DEBUGCTL_BTS               (1 << 7)
+#define X86_DEBUGCTL_BTINT             (1 << 8)
+#define X86_DEBUGCTL_BTS_OFF_OS                (1 << 9)
+#define X86_DEBUGCTL_BTS_OFF_USR       (1 << 10)
+
+/*
+ * A debug store configuration.
+ *
+ * We only support architectures that use 64bit fields.
+ */
+struct debug_store {
+       u64     bts_buffer_base;
+       u64     bts_index;
+       u64     bts_absolute_maximum;
+       u64     bts_interrupt_threshold;
+       u64     pebs_buffer_base;
+       u64     pebs_index;
+       u64     pebs_absolute_maximum;
+       u64     pebs_interrupt_threshold;
+       u64     pebs_counter_reset[MAX_PEBS_COUNTERS];
+};
+
 struct cpu_hw_counters {
        struct perf_counter     *counters[X86_PMC_IDX_MAX];
        unsigned long           used_mask[BITS_TO_LONGS(X86_PMC_IDX_MAX)];
        unsigned long           active_mask[BITS_TO_LONGS(X86_PMC_IDX_MAX)];
        unsigned long           interrupts;
        int                     enabled;
+       struct debug_store      *ds;
 };
 
 /*
@@ -58,6 +100,8 @@ struct x86_pmu {
        int             apic;
        u64             max_period;
        u64             intel_ctrl;
+       void            (*enable_bts)(u64 config);
+       void            (*disable_bts)(void);
 };
 
 static struct x86_pmu x86_pmu __read_mostly;
@@ -577,6 +621,9 @@ x86_perf_counter_update(struct perf_counter *counter,
        u64 prev_raw_count, new_raw_count;
        s64 delta;
 
+       if (idx == X86_PMC_IDX_FIXED_BTS)
+               return 0;
+
        /*
         * Careful: an NMI might modify the previous counter value.
         *
@@ -666,10 +713,109 @@ static void release_pmc_hardware(void)
 #endif
 }
 
+static inline bool bts_available(void)
+{
+       return x86_pmu.enable_bts != NULL;
+}
+
+static inline void init_debug_store_on_cpu(int cpu)
+{
+       struct debug_store *ds = per_cpu(cpu_hw_counters, cpu).ds;
+
+       if (!ds)
+               return;
+
+       wrmsr_on_cpu(cpu, MSR_IA32_DS_AREA,
+                    (u32)((u64)(long)ds), (u32)((u64)(long)ds >> 32));
+}
+
+static inline void fini_debug_store_on_cpu(int cpu)
+{
+       if (!per_cpu(cpu_hw_counters, cpu).ds)
+               return;
+
+       wrmsr_on_cpu(cpu, MSR_IA32_DS_AREA, 0, 0);
+}
+
+static void release_bts_hardware(void)
+{
+       int cpu;
+
+       if (!bts_available())
+               return;
+
+       get_online_cpus();
+
+       for_each_online_cpu(cpu)
+               fini_debug_store_on_cpu(cpu);
+
+       for_each_possible_cpu(cpu) {
+               struct debug_store *ds = per_cpu(cpu_hw_counters, cpu).ds;
+
+               if (!ds)
+                       continue;
+
+               per_cpu(cpu_hw_counters, cpu).ds = NULL;
+
+               kfree((void *)(long)ds->bts_buffer_base);
+               kfree(ds);
+       }
+
+       put_online_cpus();
+}
+
+static int reserve_bts_hardware(void)
+{
+       int cpu, err = 0;
+
+       if (!bts_available())
+               return -EOPNOTSUPP;
+
+       get_online_cpus();
+
+       for_each_possible_cpu(cpu) {
+               struct debug_store *ds;
+               void *buffer;
+
+               err = -ENOMEM;
+               buffer = kzalloc(BTS_BUFFER_SIZE, GFP_KERNEL);
+               if (unlikely(!buffer))
+                       break;
+
+               ds = kzalloc(sizeof(*ds), GFP_KERNEL);
+               if (unlikely(!ds)) {
+                       kfree(buffer);
+                       break;
+               }
+
+               ds->bts_buffer_base = (u64)(long)buffer;
+               ds->bts_index = ds->bts_buffer_base;
+               ds->bts_absolute_maximum =
+                       ds->bts_buffer_base + BTS_BUFFER_SIZE;
+               ds->bts_interrupt_threshold =
+                       ds->bts_absolute_maximum - BTS_OVFL_TH;
+
+               per_cpu(cpu_hw_counters, cpu).ds = ds;
+               err = 0;
+       }
+
+       if (err)
+               release_bts_hardware();
+       else {
+               for_each_online_cpu(cpu)
+                       init_debug_store_on_cpu(cpu);
+       }
+
+       put_online_cpus();
+
+       return err;
+}
+
 static void hw_perf_counter_destroy(struct perf_counter *counter)
 {
        if (atomic_dec_and_mutex_lock(&active_counters, &pmc_reserve_mutex)) {
                release_pmc_hardware();
+               release_bts_hardware();
                mutex_unlock(&pmc_reserve_mutex);
        }
 }
@@ -712,6 +858,42 @@ set_ext_hw_attr(struct hw_perf_counter *hwc, struct perf_counter_attr *attr)
        return 0;
 }
 
+static void intel_pmu_enable_bts(u64 config)
+{
+       unsigned long debugctlmsr;
+
+       debugctlmsr = get_debugctlmsr();
+
+       debugctlmsr |= X86_DEBUGCTL_TR;
+       debugctlmsr |= X86_DEBUGCTL_BTS;
+       debugctlmsr |= X86_DEBUGCTL_BTINT;
+
+       if (!(config & ARCH_PERFMON_EVENTSEL_OS))
+               debugctlmsr |= X86_DEBUGCTL_BTS_OFF_OS;
+
+       if (!(config & ARCH_PERFMON_EVENTSEL_USR))
+               debugctlmsr |= X86_DEBUGCTL_BTS_OFF_USR;
+
+       update_debugctlmsr(debugctlmsr);
+}
+
+static void intel_pmu_disable_bts(void)
+{
+       struct cpu_hw_counters *cpuc = &__get_cpu_var(cpu_hw_counters);
+       unsigned long debugctlmsr;
+
+       if (!cpuc->ds)
+               return;
+
+       debugctlmsr = get_debugctlmsr();
+
+       debugctlmsr &=
+               ~(X86_DEBUGCTL_TR | X86_DEBUGCTL_BTS | X86_DEBUGCTL_BTINT |
+                 X86_DEBUGCTL_BTS_OFF_OS | X86_DEBUGCTL_BTS_OFF_USR);
+
+       update_debugctlmsr(debugctlmsr);
+}
+
 /*
  * Setup the hardware configuration for a given attr_type
  */
@@ -728,9 +910,13 @@ static int __hw_perf_counter_init(struct perf_counter *counter)
        err = 0;
        if (!atomic_inc_not_zero(&active_counters)) {
                mutex_lock(&pmc_reserve_mutex);
-               if (atomic_read(&active_counters) == 0 && !reserve_pmc_hardware())
-                       err = -EBUSY;
-               else
+               if (atomic_read(&active_counters) == 0) {
+                       if (!reserve_pmc_hardware())
+                               err = -EBUSY;
+                       else
+                               reserve_bts_hardware();
+               }
+               if (!err)
                        atomic_inc(&active_counters);
                mutex_unlock(&pmc_reserve_mutex);
        }
@@ -817,7 +1003,18 @@ static void p6_pmu_disable_all(void)
 
 static void intel_pmu_disable_all(void)
 {
+       struct cpu_hw_counters *cpuc = &__get_cpu_var(cpu_hw_counters);
+
+       if (!cpuc->enabled)
+               return;
+
+       cpuc->enabled = 0;
+       barrier();
+
        wrmsrl(MSR_CORE_PERF_GLOBAL_CTRL, 0);
+
+       if (test_bit(X86_PMC_IDX_FIXED_BTS, cpuc->active_mask))
+               intel_pmu_disable_bts();
 }
 
 static void amd_pmu_disable_all(void)
@@ -875,7 +1072,25 @@ static void p6_pmu_enable_all(void)
 
 static void intel_pmu_enable_all(void)
 {
+       struct cpu_hw_counters *cpuc = &__get_cpu_var(cpu_hw_counters);
+
+       if (cpuc->enabled)
+               return;
+
+       cpuc->enabled = 1;
+       barrier();
+
        wrmsrl(MSR_CORE_PERF_GLOBAL_CTRL, x86_pmu.intel_ctrl);
+
+       if (test_bit(X86_PMC_IDX_FIXED_BTS, cpuc->active_mask)) {
+               struct perf_counter *counter =
+                       cpuc->counters[X86_PMC_IDX_FIXED_BTS];
+
+               if (WARN_ON_ONCE(!counter))
+                       return;
+
+               intel_pmu_enable_bts(counter->hw.config);
+       }
 }
 
 static void amd_pmu_enable_all(void)
@@ -962,6 +1177,11 @@ p6_pmu_disable_counter(struct hw_perf_counter *hwc, int idx)
 static inline void
 intel_pmu_disable_counter(struct hw_perf_counter *hwc, int idx)
 {
+       if (unlikely(idx == X86_PMC_IDX_FIXED_BTS)) {
+               intel_pmu_disable_bts();
+               return;
+       }
+
        if (unlikely(hwc->config_base == MSR_ARCH_PERFMON_FIXED_CTR_CTRL)) {
                intel_pmu_disable_fixed(hwc, idx);
                return;
@@ -990,6 +1210,9 @@ x86_perf_counter_set_period(struct perf_counter *counter,
        s64 period = hwc->sample_period;
        int err, ret = 0;
 
+       if (idx == X86_PMC_IDX_FIXED_BTS)
+               return 0;
+
        /*
         * If we are way outside a reasoable range then just skip forward:
         */
@@ -1072,6 +1295,14 @@ static void p6_pmu_enable_counter(struct hw_perf_counter *hwc, int idx)
 
 static void intel_pmu_enable_counter(struct hw_perf_counter *hwc, int idx)
 {
+       if (unlikely(idx == X86_PMC_IDX_FIXED_BTS)) {
+               if (!__get_cpu_var(cpu_hw_counters).enabled)
+                       return;
+
+               intel_pmu_enable_bts(hwc->config);
+               return;
+       }
+
        if (unlikely(hwc->config_base == MSR_ARCH_PERFMON_FIXED_CTR_CTRL)) {
                intel_pmu_enable_fixed(hwc, idx);
                return;
@@ -1093,11 +1324,16 @@ fixed_mode_idx(struct perf_counter *counter, struct hw_perf_counter *hwc)
 {
        unsigned int event;
 
+       event = hwc->config & ARCH_PERFMON_EVENT_MASK;
+
+       if (unlikely((event ==
+                     x86_pmu.event_map(PERF_COUNT_HW_BRANCH_INSTRUCTIONS)) &&
+                    (hwc->sample_period == 1)))
+               return X86_PMC_IDX_FIXED_BTS;
+
        if (!x86_pmu.num_counters_fixed)
                return -1;
 
-       event = hwc->config & ARCH_PERFMON_EVENT_MASK;
-
        if (unlikely(event == x86_pmu.event_map(PERF_COUNT_HW_INSTRUCTIONS)))
                return X86_PMC_IDX_FIXED_INSTRUCTIONS;
        if (unlikely(event == x86_pmu.event_map(PERF_COUNT_HW_CPU_CYCLES)))
@@ -1118,7 +1354,25 @@ static int x86_pmu_enable(struct perf_counter *counter)
        int idx;
 
        idx = fixed_mode_idx(counter, hwc);
-       if (idx >= 0) {
+       if (idx == X86_PMC_IDX_FIXED_BTS) {
+               /*
+                * Try to use BTS for branch tracing. If that is not
+                * available, try to get a generic counter.
+                */
+               if (unlikely(!cpuc->ds))
+                       goto try_generic;
+
+               /*
+                * Try to get the fixed counter, if that is already taken
+                * then try to get a generic counter:
+                */
+               if (test_and_set_bit(idx, cpuc->used_mask))
+                       goto try_generic;
+
+               hwc->config_base        = 0;
+               hwc->counter_base       = 0;
+               hwc->idx                = idx;
+       } else if (idx >= 0) {
                /*
                 * Try to get the fixed counter, if that is already taken
                 * then try to get a generic counter:
@@ -1229,6 +1483,45 @@ void perf_counter_print_debug(void)
        local_irq_restore(flags);
 }
 
+static void intel_pmu_drain_bts_buffer(struct cpu_hw_counters *cpuc,
+                                      struct perf_sample_data *data)
+{
+       struct debug_store *ds = cpuc->ds;
+       struct bts_record {
+               u64     from;
+               u64     to;
+               u64     flags;
+       };
+       struct perf_counter *counter = cpuc->counters[X86_PMC_IDX_FIXED_BTS];
+       unsigned long orig_ip = data->regs->ip;
+       u64 at;
+
+       if (!counter)
+               return;
+
+       if (!ds)
+               return;
+
+       for (at = ds->bts_buffer_base;
+            at < ds->bts_index;
+            at += sizeof(struct bts_record)) {
+               struct bts_record *rec = (struct bts_record *)(long)at;
+
+               data->regs->ip  = rec->from;
+               data->addr      = rec->to;
+
+               perf_counter_output(counter, 1, data);
+       }
+
+       ds->bts_index = ds->bts_buffer_base;
+
+       data->regs->ip  = orig_ip;
+       data->addr      = 0;
+
+       /* There's new data available. */
+       counter->pending_kill = POLL_IN;
+}
+
 static void x86_pmu_disable(struct perf_counter *counter)
 {
        struct cpu_hw_counters *cpuc = &__get_cpu_var(cpu_hw_counters);
@@ -1253,6 +1546,15 @@ static void x86_pmu_disable(struct perf_counter *counter)
         * that we are disabling:
         */
        x86_perf_counter_update(counter, hwc, idx);
+
+       /* Drain the remaining BTS records. */
+       if (unlikely(idx == X86_PMC_IDX_FIXED_BTS)) {
+               struct perf_sample_data data;
+               struct pt_regs regs;
+
+               data.regs = &regs;
+               intel_pmu_drain_bts_buffer(cpuc, &data);
+       }
        cpuc->counters[idx] = NULL;
        clear_bit(idx, cpuc->used_mask);
 
@@ -1280,6 +1582,7 @@ static int intel_pmu_save_and_restart(struct perf_counter *counter)
 
 static void intel_pmu_reset(void)
 {
+       struct debug_store *ds = __get_cpu_var(cpu_hw_counters).ds;
        unsigned long flags;
        int idx;
 
@@ -1297,6 +1600,8 @@ static void intel_pmu_reset(void)
        for (idx = 0; idx < x86_pmu.num_counters_fixed; idx++) {
                checking_wrmsrl(MSR_ARCH_PERFMON_FIXED_CTR0 + idx, 0ull);
        }
+       if (ds)
+               ds->bts_index = ds->bts_buffer_base;
 
        local_irq_restore(flags);
 }
@@ -1362,6 +1667,7 @@ static int intel_pmu_handle_irq(struct pt_regs *regs)
        cpuc = &__get_cpu_var(cpu_hw_counters);
 
        perf_disable();
+       intel_pmu_drain_bts_buffer(cpuc, &data);
        status = intel_pmu_get_status();
        if (!status) {
                perf_enable();
@@ -1571,6 +1877,8 @@ static struct x86_pmu intel_pmu = {
         * the generic counter period:
         */
        .max_period             = (1ULL << 31) - 1,
+       .enable_bts             = intel_pmu_enable_bts,
+       .disable_bts            = intel_pmu_disable_bts,
 };
 
 static struct x86_pmu amd_pmu = {
@@ -1962,3 +2270,8 @@ struct perf_callchain_entry *perf_callchain(struct pt_regs *regs)
 
        return entry;
 }
+
+void hw_perf_counter_setup_online(int cpu)
+{
+       init_debug_store_on_cpu(cpu);
+}
index e72e931..370344a 100644 (file)
@@ -27,6 +27,9 @@ OPTIONS
 -n
 --show-nr-samples
        Show the number of samples for each symbol
+-T
+--threads
+       Show per-thread event counters
 -C::
 --comms=::
        Only consider symbols in these comms. CSV that understands
index c045b42..68218cf 100644 (file)
@@ -310,6 +310,7 @@ LIB_H += util/sigchain.h
 LIB_H += util/symbol.h
 LIB_H += util/module.h
 LIB_H += util/color.h
+LIB_H += util/values.h
 
 LIB_OBJS += util/abspath.o
 LIB_OBJS += util/alias.o
@@ -337,6 +338,9 @@ LIB_OBJS += util/color.o
 LIB_OBJS += util/pager.o
 LIB_OBJS += util/header.o
 LIB_OBJS += util/callchain.o
+LIB_OBJS += util/values.o
+LIB_OBJS += util/debug.o
+LIB_OBJS += util/map.o
 
 BUILTIN_OBJS += builtin-annotate.o
 BUILTIN_OBJS += builtin-help.o
index 1dba568..543c452 100644 (file)
@@ -26,7 +26,6 @@
 #define SHOW_HV                4
 
 static char            const *input_name = "perf.data";
-static char            *vmlinux = "vmlinux";
 
 static char            default_sort_order[] = "comm,symbol";
 static char            *sort_order = default_sort_order;
@@ -37,9 +36,6 @@ static int            show_mask = SHOW_KERNEL | SHOW_USER | SHOW_HV;
 static int             dump_trace = 0;
 #define dprintf(x...)  do { if (dump_trace) printf(x); } while (0)
 
-static int             verbose;
-
-static int             modules;
 
 static int             full_paths;
 
@@ -48,40 +44,6 @@ static int           print_line;
 static unsigned long   page_size;
 static unsigned long   mmap_window = 32;
 
-struct ip_event {
-       struct perf_event_header header;
-       u64 ip;
-       u32 pid, tid;
-};
-
-struct mmap_event {
-       struct perf_event_header header;
-       u32 pid, tid;
-       u64 start;
-       u64 len;
-       u64 pgoff;
-       char filename[PATH_MAX];
-};
-
-struct comm_event {
-       struct perf_event_header header;
-       u32 pid, tid;
-       char comm[16];
-};
-
-struct fork_event {
-       struct perf_event_header header;
-       u32 pid, ppid;
-};
-
-typedef union event_union {
-       struct perf_event_header        header;
-       struct ip_event                 ip;
-       struct mmap_event               mmap;
-       struct comm_event               comm;
-       struct fork_event               fork;
-} event_t;
-
 
 struct sym_ext {
        struct rb_node  node;
@@ -89,175 +51,6 @@ struct sym_ext {
        char            *path;
 };
 
-static LIST_HEAD(dsos);
-static struct dso *kernel_dso;
-static struct dso *vdso;
-
-
-static void dsos__add(struct dso *dso)
-{
-       list_add_tail(&dso->node, &dsos);
-}
-
-static struct dso *dsos__find(const char *name)
-{
-       struct dso *pos;
-
-       list_for_each_entry(pos, &dsos, node)
-               if (strcmp(pos->name, name) == 0)
-                       return pos;
-       return NULL;
-}
-
-static struct dso *dsos__findnew(const char *name)
-{
-       struct dso *dso = dsos__find(name);
-       int nr;
-
-       if (dso)
-               return dso;
-
-       dso = dso__new(name, 0);
-       if (!dso)
-               goto out_delete_dso;
-
-       nr = dso__load(dso, NULL, verbose);
-       if (nr < 0) {
-               if (verbose)
-                       fprintf(stderr, "Failed to open: %s\n", name);
-               goto out_delete_dso;
-       }
-       if (!nr && verbose) {
-               fprintf(stderr,
-               "No symbols found in: %s, maybe install a debug package?\n",
-                               name);
-       }
-
-       dsos__add(dso);
-
-       return dso;
-
-out_delete_dso:
-       dso__delete(dso);
-       return NULL;
-}
-
-static void dsos__fprintf(FILE *fp)
-{
-       struct dso *pos;
-
-       list_for_each_entry(pos, &dsos, node)
-               dso__fprintf(pos, fp);
-}
-
-static struct symbol *vdso__find_symbol(struct dso *dso, u64 ip)
-{
-       return dso__find_symbol(dso, ip);
-}
-
-static int load_kernel(void)
-{
-       int err;
-
-       kernel_dso = dso__new("[kernel]", 0);
-       if (!kernel_dso)
-               return -1;
-
-       err = dso__load_kernel(kernel_dso, vmlinux, NULL, verbose, modules);
-       if (err <= 0) {
-               dso__delete(kernel_dso);
-               kernel_dso = NULL;
-       } else
-               dsos__add(kernel_dso);
-
-       vdso = dso__new("[vdso]", 0);
-       if (!vdso)
-               return -1;
-
-       vdso->find_symbol = vdso__find_symbol;
-
-       dsos__add(vdso);
-
-       return err;
-}
-
-struct map {
-       struct list_head node;
-       u64      start;
-       u64      end;
-       u64      pgoff;
-       u64      (*map_ip)(struct map *, u64);
-       struct dso       *dso;
-};
-
-static u64 map__map_ip(struct map *map, u64 ip)
-{
-       return ip - map->start + map->pgoff;
-}
-
-static u64 vdso__map_ip(struct map *map __used, u64 ip)
-{
-       return ip;
-}
-
-static struct map *map__new(struct mmap_event *event)
-{
-       struct map *self = malloc(sizeof(*self));
-
-       if (self != NULL) {
-               const char *filename = event->filename;
-
-               self->start = event->start;
-               self->end   = event->start + event->len;
-               self->pgoff = event->pgoff;
-
-               self->dso = dsos__findnew(filename);
-               if (self->dso == NULL)
-                       goto out_delete;
-
-               if (self->dso == vdso)
-                       self->map_ip = vdso__map_ip;
-               else
-                       self->map_ip = map__map_ip;
-       }
-       return self;
-out_delete:
-       free(self);
-       return NULL;
-}
-
-static struct map *map__clone(struct map *self)
-{
-       struct map *map = malloc(sizeof(*self));
-
-       if (!map)
-               return NULL;
-
-       memcpy(map, self, sizeof(*self));
-
-       return map;
-}
-
-static int map__overlap(struct map *l, struct map *r)
-{
-       if (l->start > r->start) {
-               struct map *t = l;
-               l = r;
-               r = t;
-       }
-
-       if (l->end > r->start)
-               return 1;
-
-       return 0;
-}
-
-static size_t map__fprintf(struct map *self, FILE *fp)
-{
-       return fprintf(fp, " %Lx-%Lx %Lx %s\n",
-                      self->start, self->end, self->pgoff, self->dso->name);
-}
-
 
 struct thread {
        struct rb_node   rb_node;
@@ -927,7 +720,7 @@ static int
 process_mmap_event(event_t *event, unsigned long offset, unsigned long head)
 {
        struct thread *thread = threads__findnew(event->mmap.pid);
-       struct map *map = map__new(&event->mmap);
+       struct map *map = map__new(&event->mmap, NULL, 0);
 
        dprintf("%p [%p]: PERF_EVENT_MMAP %d: [%p(%p) @ %p]: %s\n",
                (void *)(offset + head),
index 89a5ddc..65b4115 100644 (file)
@@ -15,6 +15,7 @@
 #include "util/string.h"
 
 #include "util/header.h"
+#include "util/event.h"
 
 #include <unistd.h>
 #include <sched.h>
@@ -42,7 +43,6 @@ static int                    inherit                         = 1;
 static int                     force                           = 0;
 static int                     append_file                     = 0;
 static int                     call_graph                      = 0;
-static int                     verbose                         = 0;
 static int                     inherit_stat                    = 0;
 static int                     no_samples                      = 0;
 static int                     sample_address                  = 0;
@@ -62,24 +62,6 @@ static int                   file_new = 1;
 
 struct perf_header             *header;
 
-struct mmap_event {
-       struct perf_event_header        header;
-       u32                             pid;
-       u32                             tid;
-       u64                             start;
-       u64                             len;
-       u64                             pgoff;
-       char                            filename[PATH_MAX];
-};
-
-struct comm_event {
-       struct perf_event_header        header;
-       u32                             pid;
-       u32                             tid;
-       char                            comm[16];
-};
-
-
 struct mmap_data {
        int                     counter;
        void                    *base;
index b53a60f..6321951 100644 (file)
@@ -17,6 +17,7 @@
 #include "util/string.h"
 #include "util/callchain.h"
 #include "util/strlist.h"
+#include "util/values.h"
 
 #include "perf.h"
 #include "util/header.h"
@@ -29,7 +30,6 @@
 #define SHOW_HV                4
 
 static char            const *input_name = "perf.data";
-static char            *vmlinux = NULL;
 
 static char            default_sort_order[] = "comm,dso,symbol";
 static char            *sort_order = default_sort_order;
@@ -45,14 +45,15 @@ static int          dump_trace = 0;
 #define dprintf(x...)  do { if (dump_trace) printf(x); } while (0)
 #define cdprintf(x...) do { if (dump_trace) color_fprintf(stdout, color, x); } while (0)
 
-static int             verbose;
-#define eprintf(x...)  do { if (verbose) fprintf(stderr, x); } while (0)
-
-static int             modules;
-
 static int             full_paths;
 static int             show_nr_samples;
 
+static int             show_threads;
+static struct perf_read_values show_threads_values;
+
+static char            default_pretty_printing_style[] = "normal";
+static char            *pretty_printing_style = default_pretty_printing_style;
+
 static unsigned long   page_size;
 static unsigned long   mmap_window = 32;
 
@@ -66,6 +67,10 @@ static char          callchain_default_opt[] = "fractal,0.5";
 
 static int             callchain;
 
+static char            __cwd[PATH_MAX];
+static char            *cwd = __cwd;
+static int             cwdlen;
+
 static
 struct callchain_param callchain_param = {
        .mode   = CHAIN_GRAPH_REL,
@@ -74,59 +79,6 @@ struct callchain_param       callchain_param = {
 
 static u64             sample_type;
 
-struct ip_event {
-       struct perf_event_header header;
-       u64 ip;
-       u32 pid, tid;
-       unsigned char __more_data[];
-};
-
-struct mmap_event {
-       struct perf_event_header header;
-       u32 pid, tid;
-       u64 start;
-       u64 len;
-       u64 pgoff;
-       char filename[PATH_MAX];
-};
-
-struct comm_event {
-       struct perf_event_header header;
-       u32 pid, tid;
-       char comm[16];
-};
-
-struct fork_event {
-       struct perf_event_header header;
-       u32 pid, ppid;
-       u32 tid, ptid;
-};
-
-struct lost_event {
-       struct perf_event_header header;
-       u64 id;
-       u64 lost;
-};
-
-struct read_event {
-       struct perf_event_header header;
-       u32 pid,tid;
-       u64 value;
-       u64 time_enabled;
-       u64 time_running;
-       u64 id;
-};
-
-typedef union event_union {
-       struct perf_event_header        header;
-       struct ip_event                 ip;
-       struct mmap_event               mmap;
-       struct comm_event               comm;
-       struct fork_event               fork;
-       struct lost_event               lost;
-       struct read_event               read;
-} event_t;
-
 static int repsep_fprintf(FILE *fp, const char *fmt, ...)
 {
        int n;
@@ -154,215 +106,6 @@ static int repsep_fprintf(FILE *fp, const char *fmt, ...)
        return n;
 }
 
-static LIST_HEAD(dsos);
-static struct dso *kernel_dso;
-static struct dso *vdso;
-static struct dso *hypervisor_dso;
-
-static void dsos__add(struct dso *dso)
-{
-       list_add_tail(&dso->node, &dsos);
-}
-
-static struct dso *dsos__find(const char *name)
-{
-       struct dso *pos;
-
-       list_for_each_entry(pos, &dsos, node)
-               if (strcmp(pos->name, name) == 0)
-                       return pos;
-       return NULL;
-}
-
-static struct dso *dsos__findnew(const char *name)
-{
-       struct dso *dso = dsos__find(name);
-       int nr;
-
-       if (dso)
-               return dso;
-
-       dso = dso__new(name, 0);
-       if (!dso)
-               goto out_delete_dso;
-
-       nr = dso__load(dso, NULL, verbose);
-       if (nr < 0) {
-               eprintf("Failed to open: %s\n", name);
-               goto out_delete_dso;
-       }
-       if (!nr)
-               eprintf("No symbols found in: %s, maybe install a debug package?\n", name);
-
-       dsos__add(dso);
-
-       return dso;
-
-out_delete_dso:
-       dso__delete(dso);
-       return NULL;
-}
-
-static void dsos__fprintf(FILE *fp)
-{
-       struct dso *pos;
-
-       list_for_each_entry(pos, &dsos, node)
-               dso__fprintf(pos, fp);
-}
-
-static struct symbol *vdso__find_symbol(struct dso *dso, u64 ip)
-{
-       return dso__find_symbol(dso, ip);
-}
-
-static int load_kernel(void)
-{
-       int err;
-
-       kernel_dso = dso__new("[kernel]", 0);
-       if (!kernel_dso)
-               return -1;
-
-       err = dso__load_kernel(kernel_dso, vmlinux, NULL, verbose, modules);
-       if (err <= 0) {
-               dso__delete(kernel_dso);
-               kernel_dso = NULL;
-       } else
-               dsos__add(kernel_dso);
-
-       vdso = dso__new("[vdso]", 0);
-       if (!vdso)
-               return -1;
-
-       vdso->find_symbol = vdso__find_symbol;
-
-       dsos__add(vdso);
-
-       hypervisor_dso = dso__new("[hypervisor]", 0);
-       if (!hypervisor_dso)
-               return -1;
-       dsos__add(hypervisor_dso);
-
-       return err;
-}
-
-static char __cwd[PATH_MAX];
-static char *cwd = __cwd;
-static int cwdlen;
-
-static int strcommon(const char *pathname)
-{
-       int n = 0;
-
-       while (n < cwdlen && pathname[n] == cwd[n])
-               ++n;
-
-       return n;
-}
-
-struct map {
-       struct list_head node;
-       u64      start;
-       u64      end;
-       u64      pgoff;
-       u64      (*map_ip)(struct map *, u64);
-       struct dso       *dso;
-};
-
-static u64 map__map_ip(struct map *map, u64 ip)
-{
-       return ip - map->start + map->pgoff;
-}
-
-static u64 vdso__map_ip(struct map *map __used, u64 ip)
-{
-       return ip;
-}
-
-static inline int is_anon_memory(const char *filename)
-{
-       return strcmp(filename, "//anon") == 0;
-}
-
-static struct map *map__new(struct mmap_event *event)
-{
-       struct map *self = malloc(sizeof(*self));
-
-       if (self != NULL) {
-               const char *filename = event->filename;
-               char newfilename[PATH_MAX];
-               int anon;
-
-               if (cwd) {
-                       int n = strcommon(filename);
-
-                       if (n == cwdlen) {
-                               snprintf(newfilename, sizeof(newfilename),
-                                        ".%s", filename + n);
-                               filename = newfilename;
-                       }
-               }
-
-               anon = is_anon_memory(filename);
-
-               if (anon) {
-                       snprintf(newfilename, sizeof(newfilename), "/tmp/perf-%d.map", event->pid);
-                       filename = newfilename;
-               }
-
-               self->start = event->start;
-               self->end   = event->start + event->len;
-               self->pgoff = event->pgoff;
-
-               self->dso = dsos__findnew(filename);
-               if (self->dso == NULL)
-                       goto out_delete;
-
-               if (self->dso == vdso || anon)
-                       self->map_ip = vdso__map_ip;
-               else
-                       self->map_ip = map__map_ip;
-       }
-       return self;
-out_delete:
-       free(self);
-       return NULL;
-}
-
-static struct map *map__clone(struct map *self)
-{
-       struct map *map = malloc(sizeof(*self));
-
-       if (!map)
-               return NULL;
-
-       memcpy(map, self, sizeof(*self));
-
-       return map;
-}
-
-static int map__overlap(struct map *l, struct map *r)
-{
-       if (l->start > r->start) {
-               struct map *t = l;
-               l = r;
-               r = t;
-       }
-
-       if (l->end > r->start)
-               return 1;
-
-       return 0;
-}
-
-static size_t map__fprintf(struct map *self, FILE *fp)
-{
-       return fprintf(fp, " %Lx-%Lx %Lx %s\n",
-                      self->start, self->end, self->pgoff, self->dso->name);
-}
-
-
 struct thread {
        struct rb_node   rb_node;
        struct list_head maps;
@@ -1397,6 +1140,9 @@ static size_t output__fprintf(FILE *fp, u64 total_samples)
        size_t ret = 0;
        unsigned int width;
        char *col_width = col_width_list_str;
+       int raw_printing_style;
+
+       raw_printing_style = !strcmp(pretty_printing_style, "raw");
 
        init_rem_hits();
 
@@ -1473,6 +1219,10 @@ print_entries:
 
        free(rem_sq_bracket);
 
+       if (show_threads)
+               perf_read_values_display(fp, &show_threads_values,
+                                        raw_printing_style);
+
        return ret;
 }
 
@@ -1611,7 +1361,7 @@ static int
 process_mmap_event(event_t *event, unsigned long offset, unsigned long head)
 {
        struct thread *thread = threads__findnew(event->mmap.pid);
-       struct map *map = map__new(&event->mmap);
+       struct map *map = map__new(&event->mmap, cwd, cwdlen);
 
        dprintf("%p [%p]: PERF_EVENT_MMAP %d/%d: [%p(%p) @ %p]: %s\n",
                (void *)(offset + head),
@@ -1760,6 +1510,16 @@ process_read_event(event_t *event, unsigned long offset, unsigned long head)
 {
        struct perf_counter_attr *attr = perf_header__find_attr(event->read.id);
 
+       if (show_threads) {
+               char *name = attr ? __event_name(attr->type, attr->config)
+                                  : "unknown";
+               perf_read_values_add_value(&show_threads_values,
+                                          event->read.pid, event->read.tid,
+                                          event->read.id,
+                                          name,
+                                          event->read.value);
+       }
+
        dprintf("%p [%p]: PERF_EVENT_READ: %d %d %s %Lu\n",
                        (void *)(offset + head),
                        (void *)(long)(event->header.size),
@@ -1841,6 +1601,9 @@ static int __cmd_report(void)
 
        register_idle_thread();
 
+       if (show_threads)
+               perf_read_values_init(&show_threads_values);
+
        input = open(input_name, O_RDONLY);
        if (input < 0) {
                fprintf(stderr, " failed to open file: %s", input_name);
@@ -1995,6 +1758,9 @@ done:
        output__resort(total);
        output__fprintf(stdout, total);
 
+       if (show_threads)
+               perf_read_values_destroy(&show_threads_values);
+
        return rc;
 }
 
@@ -2068,6 +1834,10 @@ static const struct option options[] = {
                    "load module symbols - WARNING: use only with -k and LIVE kernel"),
        OPT_BOOLEAN('n', "show-nr-samples", &show_nr_samples,
                    "Show a column with the number of samples"),
+       OPT_BOOLEAN('T', "threads", &show_threads,
+                   "Show per-thread event counters"),
+       OPT_STRING(0, "pretty", &pretty_printing_style, "key",
+                  "pretty printing style key: normal raw"),
        OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
                   "sort by key(s): pid, comm, dso, symbol, parent"),
        OPT_BOOLEAN('P', "full-paths", &full_paths,
index b4b06c7..4b9dd4a 100644 (file)
@@ -63,7 +63,6 @@ static struct perf_counter_attr default_attrs[] = {
 #define MAX_RUN                        100
 
 static int                     system_wide                     =  0;
-static int                     verbose                         =  0;
 static unsigned int            nr_cpus                         =  0;
 static int                     run_idx                         =  0;
 
index 7de28ce..9a6dbbf 100644 (file)
@@ -68,8 +68,6 @@ static int                    group                           =  0;
 static unsigned int            page_size;
 static unsigned int            mmap_pages                      = 16;
 static int                     freq                            =  0;
-static int                     verbose                         =  0;
-static char                    *vmlinux                        =  NULL;
 
 static int                     delay_secs                      =  2;
 static int                     zero;
@@ -338,8 +336,6 @@ static void show_details(struct sym_entry *syme)
                printf("%d lines not displayed, maybe increase display entries [e]\n", more);
 }
 
-struct dso                     *kernel_dso;
-
 /*
  * Symbols will be added here in record_ip and will get out
  * after decayed.
@@ -937,26 +933,6 @@ static void mmap_read_counter(struct mmap_data *md)
        last_read = this_read;
 
        for (; old != head;) {
-               struct ip_event {
-                       struct perf_event_header header;
-                       u64 ip;
-                       u32 pid, target_pid;
-               };
-               struct mmap_event {
-                       struct perf_event_header header;
-                       u32 pid, target_pid;
-                       u64 start;
-                       u64 len;
-                       u64 pgoff;
-                       char filename[PATH_MAX];
-               };
-
-               typedef union event_union {
-                       struct perf_event_header header;
-                       struct ip_event ip;
-                       struct mmap_event mmap;
-               } event_t;
-
                event_t *event = (event_t *)&data[old & md->mask];
 
                event_t event_copy;
index 51d1682..3a63e41 100644 (file)
@@ -22,5 +22,6 @@ extern int cmd_stat(int argc, const char **argv, const char *prefix);
 extern int cmd_top(int argc, const char **argv, const char *prefix);
 extern int cmd_version(int argc, const char **argv, const char *prefix);
 extern int cmd_list(int argc, const char **argv, const char *prefix);
+extern int cmd_trace(int argc, const char **argv, const char *prefix);
 
 #endif
index e5148e2..f550921 100644 (file)
@@ -48,6 +48,7 @@
 
 #include "../../include/linux/perf_counter.h"
 #include "util/types.h"
+#include "util/debug.h"
 
 /*
  * prctl(PR_TASK_PERF_COUNTERS_DISABLE) will (cheaply) disable all
index a926ae4..43cf3ea 100644 (file)
@@ -4,6 +4,7 @@
 #include "../perf.h"
 #include <linux/list.h>
 #include <linux/rbtree.h>
+#include "util.h"
 #include "symbol.h"
 
 enum chain_mode {
diff --git a/tools/perf/util/debug.c b/tools/perf/util/debug.c
new file mode 100644 (file)
index 0000000..7cb8464
--- /dev/null
@@ -0,0 +1,22 @@
+/* For general debugging purposes */
+
+#include "../perf.h"
+#include <string.h>
+#include <stdarg.h>
+#include <stdio.h>
+
+int verbose = 0;
+
+int eprintf(const char *fmt, ...)
+{
+       va_list args;
+       int ret = 0;
+
+       if (verbose) {
+               va_start(args, fmt);
+               ret = vfprintf(stderr, fmt, args);
+               va_end(args);
+       }
+
+       return ret;
+}
diff --git a/tools/perf/util/debug.h b/tools/perf/util/debug.h
new file mode 100644 (file)
index 0000000..2ae9090
--- /dev/null
@@ -0,0 +1,5 @@
+/* For debugging general purposes */
+
+extern int verbose;
+
+int eprintf(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
new file mode 100644 (file)
index 0000000..fa7c50b
--- /dev/null
@@ -0,0 +1,90 @@
+#ifndef __PERF_EVENT_H
+#define __PERF_EVENT_H
+#include "../perf.h"
+#include "util.h"
+#include <linux/list.h>
+
+/*
+ * PERF_SAMPLE_IP | PERF_SAMPLE_TID | *
+ */
+struct ip_event {
+       struct perf_event_header header;
+       u64 ip;
+       u32 pid, tid;
+       unsigned char __more_data[];
+};
+
+struct mmap_event {
+       struct perf_event_header header;
+       u32 pid, tid;
+       u64 start;
+       u64 len;
+       u64 pgoff;
+       char filename[PATH_MAX];
+};
+
+struct comm_event {
+       struct perf_event_header header;
+       u32 pid, tid;
+       char comm[16];
+};
+
+struct fork_event {
+       struct perf_event_header header;
+       u32 pid, ppid;
+       u32 tid, ptid;
+};
+
+struct lost_event {
+       struct perf_event_header header;
+       u64 id;
+       u64 lost;
+};
+
+/*
+ * PERF_FORMAT_ENABLED | PERF_FORMAT_RUNNING | PERF_FORMAT_ID
+ */
+struct read_event {
+       struct perf_event_header header;
+       u32 pid,tid;
+       u64 value;
+       u64 time_enabled;
+       u64 time_running;
+       u64 id;
+};
+
+typedef union event_union {
+       struct perf_event_header        header;
+       struct ip_event                 ip;
+       struct mmap_event               mmap;
+       struct comm_event               comm;
+       struct fork_event               fork;
+       struct lost_event               lost;
+       struct read_event               read;
+} event_t;
+
+struct map {
+       struct list_head        node;
+       u64                     start;
+       u64                     end;
+       u64                     pgoff;
+       u64                     (*map_ip)(struct map *, u64);
+       struct dso              *dso;
+};
+
+static inline u64 map__map_ip(struct map *map, u64 ip)
+{
+       return ip - map->start + map->pgoff;
+}
+
+static inline u64 vdso__map_ip(struct map *map __used, u64 ip)
+{
+       return ip;
+}
+
+struct map *map__new(struct mmap_event *event, char *cwd, int cwdlen);
+struct map *map__clone(struct map *self);
+int map__overlap(struct map *l, struct map *r);
+size_t map__fprintf(struct map *self, FILE *fp);
+
+#endif
diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c
new file mode 100644 (file)
index 0000000..804e023
--- /dev/null
@@ -0,0 +1,97 @@
+#include "event.h"
+#include "symbol.h"
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+static inline int is_anon_memory(const char *filename)
+{
+       return strcmp(filename, "//anon") == 0;
+}
+
+static int strcommon(const char *pathname, char *cwd, int cwdlen)
+{
+       int n = 0;
+
+       while (n < cwdlen && pathname[n] == cwd[n])
+               ++n;
+
+       return n;
+}
+
+ struct map *map__new(struct mmap_event *event, char *cwd, int cwdlen)
+{
+       struct map *self = malloc(sizeof(*self));
+
+       if (self != NULL) {
+               const char *filename = event->filename;
+               char newfilename[PATH_MAX];
+               int anon;
+
+               if (cwd) {
+                       int n = strcommon(filename, cwd, cwdlen);
+
+                       if (n == cwdlen) {
+                               snprintf(newfilename, sizeof(newfilename),
+                                        ".%s", filename + n);
+                               filename = newfilename;
+                       }
+               }
+
+               anon = is_anon_memory(filename);
+
+               if (anon) {
+                       snprintf(newfilename, sizeof(newfilename), "/tmp/perf-%d.map", event->pid);
+                       filename = newfilename;
+               }
+
+               self->start = event->start;
+               self->end   = event->start + event->len;
+               self->pgoff = event->pgoff;
+
+               self->dso = dsos__findnew(filename);
+               if (self->dso == NULL)
+                       goto out_delete;
+
+               if (self->dso == vdso || anon)
+                       self->map_ip = vdso__map_ip;
+               else
+                       self->map_ip = map__map_ip;
+       }
+       return self;
+out_delete:
+       free(self);
+       return NULL;
+}
+
+struct map *map__clone(struct map *self)
+{
+       struct map *map = malloc(sizeof(*self));
+
+       if (!map)
+               return NULL;
+
+       memcpy(map, self, sizeof(*self));
+
+       return map;
+}
+
+int map__overlap(struct map *l, struct map *r)
+{
+       if (l->start > r->start) {
+               struct map *t = l;
+               l = r;
+               r = t;
+       }
+
+       if (l->end > r->start)
+               return 1;
+
+       return 0;
+}
+
+size_t map__fprintf(struct map *self, FILE *fp)
+{
+       return fprintf(fp, " %Lx-%Lx %Lx %s\n",
+                      self->start, self->end, self->pgoff, self->dso->name);
+}
index 5c0f42e..0b98623 100644 (file)
@@ -924,6 +924,103 @@ int dso__load_kernel(struct dso *self, const char *vmlinux,
        return err;
 }
 
+LIST_HEAD(dsos);
+struct dso     *kernel_dso;
+struct dso     *vdso;
+struct dso     *hypervisor_dso;
+
+char           *vmlinux = "vmlinux";
+int            modules;
+
+static void dsos__add(struct dso *dso)
+{
+       list_add_tail(&dso->node, &dsos);
+}
+
+static struct dso *dsos__find(const char *name)
+{
+       struct dso *pos;
+
+       list_for_each_entry(pos, &dsos, node)
+               if (strcmp(pos->name, name) == 0)
+                       return pos;
+       return NULL;
+}
+
+struct dso *dsos__findnew(const char *name)
+{
+       struct dso *dso = dsos__find(name);
+       int nr;
+
+       if (dso)
+               return dso;
+
+       dso = dso__new(name, 0);
+       if (!dso)
+               goto out_delete_dso;
+
+       nr = dso__load(dso, NULL, verbose);
+       if (nr < 0) {
+               eprintf("Failed to open: %s\n", name);
+               goto out_delete_dso;
+       }
+       if (!nr)
+               eprintf("No symbols found in: %s, maybe install a debug package?\n", name);
+
+       dsos__add(dso);
+
+       return dso;
+
+out_delete_dso:
+       dso__delete(dso);
+       return NULL;
+}
+
+void dsos__fprintf(FILE *fp)
+{
+       struct dso *pos;
+
+       list_for_each_entry(pos, &dsos, node)
+               dso__fprintf(pos, fp);
+}
+
+static struct symbol *vdso__find_symbol(struct dso *dso, u64 ip)
+{
+       return dso__find_symbol(dso, ip);
+}
+
+int load_kernel(void)
+{
+       int err;
+
+       kernel_dso = dso__new("[kernel]", 0);
+       if (!kernel_dso)
+               return -1;
+
+       err = dso__load_kernel(kernel_dso, vmlinux, NULL, verbose, modules);
+       if (err <= 0) {
+               dso__delete(kernel_dso);
+               kernel_dso = NULL;
+       } else
+               dsos__add(kernel_dso);
+
+       vdso = dso__new("[vdso]", 0);
+       if (!vdso)
+               return -1;
+
+       vdso->find_symbol = vdso__find_symbol;
+
+       dsos__add(vdso);
+
+       hypervisor_dso = dso__new("[hypervisor]", 0);
+       if (!hypervisor_dso)
+               return -1;
+       dsos__add(hypervisor_dso);
+
+       return err;
+}
+
+
 void symbol__init(void)
 {
        elf_version(EV_CURRENT);
index b53bf01..48b8e57 100644 (file)
@@ -6,6 +6,7 @@
 #include <linux/list.h>
 #include <linux/rbtree.h>
 #include "module.h"
+#include "event.h"
 
 #ifdef HAVE_CPLUS_DEMANGLE
 extern char *cplus_demangle(const char *, int);
@@ -72,9 +73,20 @@ int dso__load_kernel(struct dso *self, const char *vmlinux,
                     symbol_filter_t filter, int verbose, int modules);
 int dso__load_modules(struct dso *self, symbol_filter_t filter, int verbose);
 int dso__load(struct dso *self, symbol_filter_t filter, int verbose);
+struct dso *dsos__findnew(const char *name);
+void dsos__fprintf(FILE *fp);
 
 size_t dso__fprintf(struct dso *self, FILE *fp);
 char dso__symtab_origin(const struct dso *self);
 
+int load_kernel(void);
+
 void symbol__init(void);
+
+extern struct list_head dsos;
+extern struct dso *kernel_dso;
+extern struct dso *vdso;
+extern struct dso *hypervisor_dso;
+extern char *vmlinux;
+extern int   modules;
 #endif /* _PERF_SYMBOL_ */
index 68fe157..d61a6f0 100644 (file)
@@ -83,6 +83,7 @@
 #include <inttypes.h>
 #include "../../../include/linux/magic.h"
 
+
 #ifndef NO_ICONV
 #include <iconv.h>
 #endif
diff --git a/tools/perf/util/values.c b/tools/perf/util/values.c
new file mode 100644 (file)
index 0000000..614cfaf
--- /dev/null
@@ -0,0 +1,231 @@
+#include <stdlib.h>
+
+#include "util.h"
+#include "values.h"
+
+void perf_read_values_init(struct perf_read_values *values)
+{
+       values->threads_max = 16;
+       values->pid = malloc(values->threads_max * sizeof(*values->pid));
+       values->tid = malloc(values->threads_max * sizeof(*values->tid));
+       values->value = malloc(values->threads_max * sizeof(*values->value));
+       if (!values->pid || !values->tid || !values->value)
+               die("failed to allocate read_values threads arrays");
+       values->threads = 0;
+
+       values->counters_max = 16;
+       values->counterrawid = malloc(values->counters_max
+                                     * sizeof(*values->counterrawid));
+       values->countername = malloc(values->counters_max
+                                    * sizeof(*values->countername));
+       if (!values->counterrawid || !values->countername)
+               die("failed to allocate read_values counters arrays");
+       values->counters = 0;
+}
+
+void perf_read_values_destroy(struct perf_read_values *values)
+{
+       int i;
+
+       if (!values->threads_max || !values->counters_max)
+               return;
+
+       for (i = 0; i < values->threads; i++)
+               free(values->value[i]);
+       free(values->pid);
+       free(values->tid);
+       free(values->counterrawid);
+       for (i = 0; i < values->counters; i++)
+               free(values->countername[i]);
+       free(values->countername);
+}
+
+static void perf_read_values__enlarge_threads(struct perf_read_values *values)
+{
+       values->threads_max *= 2;
+       values->pid = realloc(values->pid,
+                             values->threads_max * sizeof(*values->pid));
+       values->tid = realloc(values->tid,
+                             values->threads_max * sizeof(*values->tid));
+       values->value = realloc(values->value,
+                               values->threads_max * sizeof(*values->value));
+       if (!values->pid || !values->tid || !values->value)
+               die("failed to enlarge read_values threads arrays");
+}
+
+static int perf_read_values__findnew_thread(struct perf_read_values *values,
+                                           u32 pid, u32 tid)
+{
+       int i;
+
+       for (i = 0; i < values->threads; i++)
+               if (values->pid[i] == pid && values->tid[i] == tid)
+                       return i;
+
+       if (values->threads == values->threads_max)
+               perf_read_values__enlarge_threads(values);
+
+       i = values->threads++;
+       values->pid[i] = pid;
+       values->tid[i] = tid;
+       values->value[i] = malloc(values->counters_max * sizeof(**values->value));
+       if (!values->value[i])
+               die("failed to allocate read_values counters array");
+
+       return i;
+}
+
+static void perf_read_values__enlarge_counters(struct perf_read_values *values)
+{
+       int i;
+
+       values->counters_max *= 2;
+       values->counterrawid = realloc(values->counterrawid,
+                                      values->counters_max * sizeof(*values->counterrawid));
+       values->countername = realloc(values->countername,
+                                     values->counters_max * sizeof(*values->countername));
+       if (!values->counterrawid || !values->countername)
+               die("failed to enlarge read_values counters arrays");
+
+       for (i = 0; i < values->threads; i++) {
+               values->value[i] = realloc(values->value[i],
+                                          values->counters_max * sizeof(**values->value));
+               if (!values->value[i])
+                       die("failed to enlarge read_values counters arrays");
+       }
+}
+
+static int perf_read_values__findnew_counter(struct perf_read_values *values,
+                                            u64 rawid, char *name)
+{
+       int i;
+
+       for (i = 0; i < values->counters; i++)
+               if (values->counterrawid[i] == rawid)
+                       return i;
+
+       if (values->counters == values->counters_max)
+               perf_read_values__enlarge_counters(values);
+
+       i = values->counters++;
+       values->counterrawid[i] = rawid;
+       values->countername[i] = strdup(name);
+
+       return i;
+}
+
+void perf_read_values_add_value(struct perf_read_values *values,
+                               u32 pid, u32 tid,
+                               u64 rawid, char *name, u64 value)
+{
+       int tindex, cindex;
+
+       tindex = perf_read_values__findnew_thread(values, pid, tid);
+       cindex = perf_read_values__findnew_counter(values, rawid, name);
+
+       values->value[tindex][cindex] = value;
+}
+
+static void perf_read_values__display_pretty(FILE *fp,
+                                            struct perf_read_values *values)
+{
+       int i, j;
+       int pidwidth, tidwidth;
+       int *counterwidth;
+
+       counterwidth = malloc(values->counters * sizeof(*counterwidth));
+       if (!counterwidth)
+               die("failed to allocate counterwidth array");
+       tidwidth = 3;
+       pidwidth = 3;
+       for (j = 0; j < values->counters; j++)
+               counterwidth[j] = strlen(values->countername[j]);
+       for (i = 0; i < values->threads; i++) {
+               int width;
+
+               width = snprintf(NULL, 0, "%d", values->pid[i]);
+               if (width > pidwidth)
+                       pidwidth = width;
+               width = snprintf(NULL, 0, "%d", values->tid[i]);
+               if (width > tidwidth)
+                       tidwidth = width;
+               for (j = 0; j < values->counters; j++) {
+                       width = snprintf(NULL, 0, "%Lu", values->value[i][j]);
+                       if (width > counterwidth[j])
+                               counterwidth[j] = width;
+               }
+       }
+
+       fprintf(fp, "# %*s  %*s", pidwidth, "PID", tidwidth, "TID");
+       for (j = 0; j < values->counters; j++)
+               fprintf(fp, "  %*s", counterwidth[j], values->countername[j]);
+       fprintf(fp, "\n");
+
+       for (i = 0; i < values->threads; i++) {
+               fprintf(fp, "  %*d  %*d", pidwidth, values->pid[i],
+                       tidwidth, values->tid[i]);
+               for (j = 0; j < values->counters; j++)
+                       fprintf(fp, "  %*Lu",
+                               counterwidth[j], values->value[i][j]);
+               fprintf(fp, "\n");
+       }
+}
+
+static void perf_read_values__display_raw(FILE *fp,
+                                         struct perf_read_values *values)
+{
+       int width, pidwidth, tidwidth, namewidth, rawwidth, countwidth;
+       int i, j;
+
+       tidwidth = 3; /* TID */
+       pidwidth = 3; /* PID */
+       namewidth = 4; /* "Name" */
+       rawwidth = 3; /* "Raw" */
+       countwidth = 5; /* "Count" */
+
+       for (i = 0; i < values->threads; i++) {
+               width = snprintf(NULL, 0, "%d", values->pid[i]);
+               if (width > pidwidth)
+                       pidwidth = width;
+               width = snprintf(NULL, 0, "%d", values->tid[i]);
+               if (width > tidwidth)
+                       tidwidth = width;
+       }
+       for (j = 0; j < values->counters; j++) {
+               width = strlen(values->countername[j]);
+               if (width > namewidth)
+                       namewidth = width;
+               width = snprintf(NULL, 0, "%llx", values->counterrawid[j]);
+               if (width > rawwidth)
+                       rawwidth = width;
+       }
+       for (i = 0; i < values->threads; i++) {
+               for (j = 0; j < values->counters; j++) {
+                       width = snprintf(NULL, 0, "%Lu", values->value[i][j]);
+                       if (width > countwidth)
+                               countwidth = width;
+               }
+       }
+
+       fprintf(fp, "# %*s  %*s  %*s  %*s  %*s\n",
+               pidwidth, "PID", tidwidth, "TID",
+               namewidth, "Name", rawwidth, "Raw",
+               countwidth, "Count");
+       for (i = 0; i < values->threads; i++)
+               for (j = 0; j < values->counters; j++)
+                       fprintf(fp, "  %*d  %*d  %*s  %*llx  %*Lu\n",
+                               pidwidth, values->pid[i],
+                               tidwidth, values->tid[i],
+                               namewidth, values->countername[j],
+                               rawwidth, values->counterrawid[j],
+                               countwidth, values->value[i][j]);
+}
+
+void perf_read_values_display(FILE *fp, struct perf_read_values *values,
+                             int raw)
+{
+       if (raw)
+               perf_read_values__display_raw(fp, values);
+       else
+               perf_read_values__display_pretty(fp, values);
+}
diff --git a/tools/perf/util/values.h b/tools/perf/util/values.h
new file mode 100644 (file)
index 0000000..f8960fd
--- /dev/null
@@ -0,0 +1,27 @@
+#ifndef _PERF_VALUES_H
+#define _PERF_VALUES_H
+
+#include "types.h"
+
+struct perf_read_values {
+       int threads;
+       int threads_max;
+       u32 *pid, *tid;
+       int counters;
+       int counters_max;
+       u64 *counterrawid;
+       char **countername;
+       u64 **value;
+};
+
+void perf_read_values_init(struct perf_read_values *values);
+void perf_read_values_destroy(struct perf_read_values *values);
+
+void perf_read_values_add_value(struct perf_read_values *values,
+                               u32 pid, u32 tid,
+                               u64 rawid, char *name, u64 value);
+
+void perf_read_values_display(FILE *fp, struct perf_read_values *values,
+                             int raw);
+
+#endif /* _PERF_VALUES_H */