Merge branch 'perf-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git...
authorLinus Torvalds <torvalds@linux-foundation.org>
Mon, 13 Oct 2014 13:58:15 +0000 (15:58 +0200)
committerLinus Torvalds <torvalds@linux-foundation.org>
Mon, 13 Oct 2014 13:58:15 +0000 (15:58 +0200)
Pull perf updates from Ingo Molnar:
 "Kernel side updates:

   - Fix and enhance poll support (Jiri Olsa)

   - Re-enable inheritance optimization (Jiri Olsa)

   - Enhance Intel memory events support (Stephane Eranian)

   - Refactor the Intel uncore driver to be more maintainable (Zheng
     Yan)

   - Enhance and fix Intel CPU and uncore PMU drivers (Peter Zijlstra,
     Andi Kleen)

   - [ plus various smaller fixes/cleanups ]

  User visible tooling updates:

   - Add +field argument support for --field option, so that one can add
     fields to the default list of fields to show, ie now one can just
     do:

         perf report --fields +pid

     And the pid will appear in addition to the default fields (Jiri
     Olsa)

   - Add +field argument support for --sort option (Jiri Olsa)

   - Honour -w in the report tools (report, top), allowing to specify
     the widths for the histogram entries columns (Namhyung Kim)

   - Properly show submicrosecond times in 'perf kvm stat' (Christian
     Borntraeger)

   - Add beautifier for mremap flags param in 'trace' (Alex Snast)

   - perf script: Allow callchains if any event samples them

   - Don't truncate Intel style addresses in 'annotate' (Alex Converse)

   - Allow profiling when kptr_restrict == 1 for non root users, kernel
     samples will just remain unresolved (Andi Kleen)

   - Allow configuring default options for callchains in config file
     (Namhyung Kim)

   - Support operations for shared futexes.  (Davidlohr Bueso)

   - "perf kvm stat report" improvements by Alexander Yarygin:
       -  Save pid string in opts.target.pid
       -  Enable the target.system_wide flag
       -  Unify the title bar output

   - [ plus lots of other fixes and small improvements.  ]

  Tooling infrastructure changes:

   - Refactor unit and scale function parameters for PMU parsing
     routines (Matt Fleming)

   - Improve DSO long names lookup with rbtree, resulting in great
     speedup for workloads with lots of DSOs (Waiman Long)

   - We were not handling POLLHUP notifications for event file
     descriptors

     Fix it by filtering entries in the events file descriptor array
     after poll() returns, refcounting mmaps so that when the last fd
     pointing to a perf mmap goes away we do the unmap (Arnaldo Carvalho
     de Melo)

   - Intel PT prep work, from Adrian Hunter, including:
       - Let a user specify a PMU event without any config terms
       - Add perf-with-kcore script
       - Let default config be defined for a PMU
       - Add perf_pmu__scan_file()
       - Add a 'perf test' for tracking with sched_switch
       - Add 'flush' callback to scripting API

   - Use ring buffer consume method to look like other tools (Arnaldo
     Carvalho de Melo)

   - hists browser (used in top and report) refactorings, getting rid of
     unused variables and reducing source code size by handling similar
     cases in a fewer functions (Namhyung Kim).

   - Replace thread unsafe strerror() with strerror_r() accross the
     whole tools/perf/ tree (Masami Hiramatsu)

   - Rename ordered_samples to ordered_events and allow setting a queue
     size for ordering events (Jiri Olsa)

   - [ plus lots of fixes, cleanups and other improvements ]"

* 'perf-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (198 commits)
  perf/x86: Tone down kernel messages when the PMU check fails in a virtual environment
  perf/x86/intel/uncore: Fix minor race in box set up
  perf record: Fix error message for --filter option not coming after tracepoint
  perf tools: Fix build breakage on arm64 targets
  perf symbols: Improve DSO long names lookup speed with rbtree
  perf symbols: Encapsulate dsos list head into struct dsos
  perf bench futex: Sanitize -q option in requeue
  perf bench futex: Support operations for shared futexes
  perf trace: Fix mmap return address truncation to 32-bit
  perf tools: Refactor unit and scale function parameters
  perf tools: Fix line number in the config file error message
  perf tools: Convert {record,top}.call-graph option to call-graph.record-mode
  perf tools: Introduce perf_callchain_config()
  perf callchain: Move some parser functions to callchain.c
  perf tools: Move callchain config from record_opts to callchain_param
  perf hists browser: Fix callchain print bug on TUI
  perf tools: Use ACCESS_ONCE() instead of volatile cast
  perf tools: Modify error code for when perf_session__new() fails
  perf tools: Fix perf record as non root with kptr_restrict == 1
  perf stat: Fix --per-core on multi socket systems
  ...

134 files changed:
arch/x86/include/asm/perf_event.h
arch/x86/kernel/cpu/Makefile
arch/x86/kernel/cpu/perf_event.c
arch/x86/kernel/cpu/perf_event.h
arch/x86/kernel/cpu/perf_event_intel.c
arch/x86/kernel/cpu/perf_event_intel_ds.c
arch/x86/kernel/cpu/perf_event_intel_lbr.c
arch/x86/kernel/cpu/perf_event_intel_uncore.c
arch/x86/kernel/cpu/perf_event_intel_uncore.h
arch/x86/kernel/cpu/perf_event_intel_uncore_nhmex.c [new file with mode: 0644]
arch/x86/kernel/cpu/perf_event_intel_uncore_snb.c [new file with mode: 0644]
arch/x86/kernel/cpu/perf_event_intel_uncore_snbep.c [new file with mode: 0644]
include/linux/jump_label.h
include/linux/pci_ids.h
include/linux/perf_event.h
kernel/events/callchain.c
kernel/events/core.c
tools/lib/api/Makefile
tools/lib/api/fd/array.c [new file with mode: 0644]
tools/lib/api/fd/array.h [new file with mode: 0644]
tools/perf/.gitignore
tools/perf/Documentation/perf-probe.txt
tools/perf/Documentation/perf-report.txt
tools/perf/Documentation/perf-top.txt
tools/perf/Makefile.perf
tools/perf/arch/arm/tests/dwarf-unwind.c
tools/perf/arch/arm/util/unwind-libunwind.c
tools/perf/arch/arm64/include/perf_regs.h
tools/perf/arch/arm64/util/unwind-libunwind.c
tools/perf/arch/common.c
tools/perf/arch/powerpc/Makefile
tools/perf/arch/powerpc/util/skip-callchain-idx.c
tools/perf/bench/futex-hash.c
tools/perf/bench/futex-requeue.c
tools/perf/bench/futex-wake.c
tools/perf/bench/sched-messaging.c
tools/perf/builtin-annotate.c
tools/perf/builtin-buildid-cache.c
tools/perf/builtin-diff.c
tools/perf/builtin-evlist.c
tools/perf/builtin-help.c
tools/perf/builtin-inject.c
tools/perf/builtin-kmem.c
tools/perf/builtin-kvm.c
tools/perf/builtin-lock.c
tools/perf/builtin-mem.c
tools/perf/builtin-probe.c
tools/perf/builtin-record.c
tools/perf/builtin-report.c
tools/perf/builtin-sched.c
tools/perf/builtin-script.c
tools/perf/builtin-stat.c
tools/perf/builtin-timechart.c
tools/perf/builtin-top.c
tools/perf/builtin-trace.c
tools/perf/config/Makefile
tools/perf/config/feature-checks/Makefile
tools/perf/config/utilities.mak
tools/perf/perf-with-kcore.sh [new file with mode: 0644]
tools/perf/perf.c
tools/perf/perf.h
tools/perf/tests/builtin-test.c
tools/perf/tests/fdarray.c [new file with mode: 0644]
tools/perf/tests/mmap-basic.c
tools/perf/tests/open-syscall-all-cpus.c
tools/perf/tests/open-syscall-tp-fields.c
tools/perf/tests/open-syscall.c
tools/perf/tests/perf-record.c
tools/perf/tests/pmu.c
tools/perf/tests/rdpmc.c
tools/perf/tests/sw-clock.c
tools/perf/tests/switch-tracking.c [new file with mode: 0644]
tools/perf/tests/task-exit.c
tools/perf/tests/tests.h
tools/perf/ui/browsers/hists.c
tools/perf/ui/gtk/hists.c
tools/perf/ui/hist.c
tools/perf/ui/stdio/hist.c
tools/perf/util/annotate.c
tools/perf/util/cache.h
tools/perf/util/callchain.c
tools/perf/util/callchain.h
tools/perf/util/cloexec.c
tools/perf/util/color.c
tools/perf/util/color.h
tools/perf/util/comm.c
tools/perf/util/comm.h
tools/perf/util/config.c
tools/perf/util/data.c
tools/perf/util/debug.c
tools/perf/util/debug.h
tools/perf/util/dso.c
tools/perf/util/dso.h
tools/perf/util/event.c
tools/perf/util/event.h
tools/perf/util/evlist.c
tools/perf/util/evlist.h
tools/perf/util/evsel.c
tools/perf/util/evsel.h
tools/perf/util/header.c
tools/perf/util/hist.c
tools/perf/util/hist.h
tools/perf/util/kvm-stat.h
tools/perf/util/machine.c
tools/perf/util/machine.h
tools/perf/util/map.c
tools/perf/util/ordered-events.c [new file with mode: 0644]
tools/perf/util/ordered-events.h [new file with mode: 0644]
tools/perf/util/parse-events.c
tools/perf/util/parse-events.y
tools/perf/util/pmu.c
tools/perf/util/pmu.h
tools/perf/util/probe-event.c
tools/perf/util/probe-event.h
tools/perf/util/probe-finder.c
tools/perf/util/python.c
tools/perf/util/record.c
tools/perf/util/run-command.c
tools/perf/util/scripting-engines/trace-event-perl.c
tools/perf/util/scripting-engines/trace-event-python.c
tools/perf/util/session.c
tools/perf/util/session.h
tools/perf/util/sort.c
tools/perf/util/sort.h
tools/perf/util/symbol-elf.c
tools/perf/util/symbol.c
tools/perf/util/symbol.h
tools/perf/util/thread.c
tools/perf/util/thread.h
tools/perf/util/tool.h
tools/perf/util/trace-event-scripting.c
tools/perf/util/trace-event.h
tools/perf/util/util.c
tools/perf/util/util.h

index 8249df45d2f2b52dcecd46411db73408bf1ab392..8dfc9fd094a3b3fea4912da838d2114766017295 100644 (file)
         ARCH_PERFMON_EVENTSEL_EDGE  |  \
         ARCH_PERFMON_EVENTSEL_INV   |  \
         ARCH_PERFMON_EVENTSEL_CMASK)
+#define X86_ALL_EVENT_FLAGS                    \
+       (ARCH_PERFMON_EVENTSEL_EDGE |           \
+        ARCH_PERFMON_EVENTSEL_INV |            \
+        ARCH_PERFMON_EVENTSEL_CMASK |          \
+        ARCH_PERFMON_EVENTSEL_ANY |            \
+        ARCH_PERFMON_EVENTSEL_PIN_CONTROL |    \
+        HSW_IN_TX |                            \
+        HSW_IN_TX_CHECKPOINTED)
 #define AMD64_RAW_EVENT_MASK           \
        (X86_RAW_EVENT_MASK          |  \
         AMD64_EVENTSEL_EVENT)
index 77dcab277710763cc0e6cc7ceb9a3fb8ef0b8c57..01d5453b5502c235759712b751da809123b565cc 100644 (file)
@@ -39,7 +39,9 @@ obj-$(CONFIG_CPU_SUP_AMD)             += perf_event_amd_iommu.o
 endif
 obj-$(CONFIG_CPU_SUP_INTEL)            += perf_event_p6.o perf_event_knc.o perf_event_p4.o
 obj-$(CONFIG_CPU_SUP_INTEL)            += perf_event_intel_lbr.o perf_event_intel_ds.o perf_event_intel.o
-obj-$(CONFIG_CPU_SUP_INTEL)            += perf_event_intel_uncore.o perf_event_intel_rapl.o
+obj-$(CONFIG_CPU_SUP_INTEL)            += perf_event_intel_uncore.o perf_event_intel_uncore_snb.o
+obj-$(CONFIG_CPU_SUP_INTEL)            += perf_event_intel_uncore_snbep.o perf_event_intel_uncore_nhmex.o
+obj-$(CONFIG_CPU_SUP_INTEL)            += perf_event_intel_rapl.o
 endif
 
 
index 2879ecdaac430c62710db3c90b326e6e25f60acf..16c73022306ebcde1c92a208cfa460dea0fc47f0 100644 (file)
@@ -243,7 +243,8 @@ static bool check_hw_exists(void)
 
 msr_fail:
        printk(KERN_CONT "Broken PMU hardware detected, using software events only.\n");
-       printk(KERN_ERR "Failed to access perfctr msr (MSR %x is %Lx)\n", reg, val_new);
+       printk(boot_cpu_has(X86_FEATURE_HYPERVISOR) ? KERN_INFO : KERN_ERR
+              "Failed to access perfctr msr (MSR %x is %Lx)\n", reg, val_new);
 
        return false;
 }
@@ -387,7 +388,7 @@ int x86_pmu_hw_config(struct perf_event *event)
                        precise++;
 
                        /* Support for IP fixup */
-                       if (x86_pmu.lbr_nr)
+                       if (x86_pmu.lbr_nr || x86_pmu.intel_cap.pebs_format >= 2)
                                precise++;
                }
 
@@ -443,6 +444,12 @@ int x86_pmu_hw_config(struct perf_event *event)
        if (event->attr.type == PERF_TYPE_RAW)
                event->hw.config |= event->attr.config & X86_RAW_EVENT_MASK;
 
+       if (event->attr.sample_period && x86_pmu.limit_period) {
+               if (x86_pmu.limit_period(event, event->attr.sample_period) >
+                               event->attr.sample_period)
+                       return -EINVAL;
+       }
+
        return x86_setup_perfctr(event);
 }
 
@@ -980,6 +987,9 @@ int x86_perf_event_set_period(struct perf_event *event)
        if (left > x86_pmu.max_period)
                left = x86_pmu.max_period;
 
+       if (x86_pmu.limit_period)
+               left = x86_pmu.limit_period(event, left);
+
        per_cpu(pmc_prev_left[idx], smp_processor_id()) = left;
 
        /*
index 8ade93111e0379fd79e0b421d29256b6c9b1b206..d98a34d435d7b5260154bcf4463bbcb24ad073fb 100644 (file)
@@ -67,8 +67,10 @@ struct event_constraint {
  */
 #define PERF_X86_EVENT_PEBS_LDLAT      0x1 /* ld+ldlat data address sampling */
 #define PERF_X86_EVENT_PEBS_ST         0x2 /* st data address sampling */
-#define PERF_X86_EVENT_PEBS_ST_HSW     0x4 /* haswell style st data sampling */
+#define PERF_X86_EVENT_PEBS_ST_HSW     0x4 /* haswell style datala, store */
 #define PERF_X86_EVENT_COMMITTED       0x8 /* event passed commit_txn */
+#define PERF_X86_EVENT_PEBS_LD_HSW     0x10 /* haswell style datala, load */
+#define PERF_X86_EVENT_PEBS_NA_HSW     0x20 /* haswell style datala, unknown */
 
 struct amd_nb {
        int nb_id;  /* NorthBridge id */
@@ -252,18 +254,52 @@ struct cpu_hw_events {
        EVENT_CONSTRAINT(c, n, INTEL_ARCH_EVENT_MASK)
 
 #define INTEL_PLD_CONSTRAINT(c, n)     \
-       __EVENT_CONSTRAINT(c, n, INTEL_ARCH_EVENT_MASK, \
+       __EVENT_CONSTRAINT(c, n, INTEL_ARCH_EVENT_MASK|X86_ALL_EVENT_FLAGS, \
                           HWEIGHT(n), 0, PERF_X86_EVENT_PEBS_LDLAT)
 
 #define INTEL_PST_CONSTRAINT(c, n)     \
-       __EVENT_CONSTRAINT(c, n, INTEL_ARCH_EVENT_MASK, \
+       __EVENT_CONSTRAINT(c, n, INTEL_ARCH_EVENT_MASK|X86_ALL_EVENT_FLAGS, \
                          HWEIGHT(n), 0, PERF_X86_EVENT_PEBS_ST)
 
-/* DataLA version of store sampling without extra enable bit. */
-#define INTEL_PST_HSW_CONSTRAINT(c, n) \
-       __EVENT_CONSTRAINT(c, n, INTEL_ARCH_EVENT_MASK, \
+/* Event constraint, but match on all event flags too. */
+#define INTEL_FLAGS_EVENT_CONSTRAINT(c, n) \
+       EVENT_CONSTRAINT(c, n, INTEL_ARCH_EVENT_MASK|X86_ALL_EVENT_FLAGS)
+
+/* Check only flags, but allow all event/umask */
+#define INTEL_ALL_EVENT_CONSTRAINT(code, n)    \
+       EVENT_CONSTRAINT(code, n, X86_ALL_EVENT_FLAGS)
+
+/* Check flags and event code, and set the HSW store flag */
+#define INTEL_FLAGS_EVENT_CONSTRAINT_DATALA_ST(code, n) \
+       __EVENT_CONSTRAINT(code, n,                     \
+                         ARCH_PERFMON_EVENTSEL_EVENT|X86_ALL_EVENT_FLAGS, \
+                         HWEIGHT(n), 0, PERF_X86_EVENT_PEBS_ST_HSW)
+
+/* Check flags and event code, and set the HSW load flag */
+#define INTEL_FLAGS_EVENT_CONSTRAINT_DATALA_LD(code, n) \
+       __EVENT_CONSTRAINT(code, n,                     \
+                         ARCH_PERFMON_EVENTSEL_EVENT|X86_ALL_EVENT_FLAGS, \
+                         HWEIGHT(n), 0, PERF_X86_EVENT_PEBS_LD_HSW)
+
+/* Check flags and event code/umask, and set the HSW store flag */
+#define INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_ST(code, n) \
+       __EVENT_CONSTRAINT(code, n,                     \
+                         INTEL_ARCH_EVENT_MASK|X86_ALL_EVENT_FLAGS, \
                          HWEIGHT(n), 0, PERF_X86_EVENT_PEBS_ST_HSW)
 
+/* Check flags and event code/umask, and set the HSW load flag */
+#define INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_LD(code, n) \
+       __EVENT_CONSTRAINT(code, n,                     \
+                         INTEL_ARCH_EVENT_MASK|X86_ALL_EVENT_FLAGS, \
+                         HWEIGHT(n), 0, PERF_X86_EVENT_PEBS_LD_HSW)
+
+/* Check flags and event code/umask, and set the HSW N/A flag */
+#define INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_NA(code, n) \
+       __EVENT_CONSTRAINT(code, n,                     \
+                         INTEL_ARCH_EVENT_MASK|INTEL_ARCH_EVENT_MASK, \
+                         HWEIGHT(n), 0, PERF_X86_EVENT_PEBS_NA_HSW)
+
+
 /*
  * We define the end marker as having a weight of -1
  * to enable blacklisting of events using a counter bitmask
@@ -409,6 +445,7 @@ struct x86_pmu {
        struct x86_pmu_quirk *quirks;
        int             perfctr_second_write;
        bool            late_ack;
+       unsigned        (*limit_period)(struct perf_event *event, unsigned l);
 
        /*
         * sysfs attrs
index 2502d0d9d246a1fe63c57070176b2bcc04cad3bb..3851def5057c3dd1b2a7b08acc6641dc918a395a 100644 (file)
@@ -220,6 +220,15 @@ static struct event_constraint intel_hsw_event_constraints[] = {
        EVENT_CONSTRAINT_END
 };
 
+static struct event_constraint intel_bdw_event_constraints[] = {
+       FIXED_EVENT_CONSTRAINT(0x00c0, 0),      /* INST_RETIRED.ANY */
+       FIXED_EVENT_CONSTRAINT(0x003c, 1),      /* CPU_CLK_UNHALTED.CORE */
+       FIXED_EVENT_CONSTRAINT(0x0300, 2),      /* CPU_CLK_UNHALTED.REF */
+       INTEL_UEVENT_CONSTRAINT(0x148, 0x4),    /* L1D_PEND_MISS.PENDING */
+       INTEL_EVENT_CONSTRAINT(0xa3, 0x4),      /* CYCLE_ACTIVITY.* */
+       EVENT_CONSTRAINT_END
+};
+
 static u64 intel_pmu_event_map(int hw_event)
 {
        return intel_perfmon_event_map[hw_event];
@@ -415,6 +424,126 @@ static __initconst const u64 snb_hw_cache_event_ids
 
 };
 
+static __initconst const u64 hsw_hw_cache_event_ids
+                               [PERF_COUNT_HW_CACHE_MAX]
+                               [PERF_COUNT_HW_CACHE_OP_MAX]
+                               [PERF_COUNT_HW_CACHE_RESULT_MAX] =
+{
+ [ C(L1D ) ] = {
+       [ C(OP_READ) ] = {
+               [ C(RESULT_ACCESS) ] = 0x81d0,  /* MEM_UOPS_RETIRED.ALL_LOADS */
+               [ C(RESULT_MISS)   ] = 0x151,   /* L1D.REPLACEMENT */
+       },
+       [ C(OP_WRITE) ] = {
+               [ C(RESULT_ACCESS) ] = 0x82d0,  /* MEM_UOPS_RETIRED.ALL_STORES */
+               [ C(RESULT_MISS)   ] = 0x0,
+       },
+       [ C(OP_PREFETCH) ] = {
+               [ C(RESULT_ACCESS) ] = 0x0,
+               [ C(RESULT_MISS)   ] = 0x0,
+       },
+ },
+ [ C(L1I ) ] = {
+       [ C(OP_READ) ] = {
+               [ C(RESULT_ACCESS) ] = 0x0,
+               [ C(RESULT_MISS)   ] = 0x280,   /* ICACHE.MISSES */
+       },
+       [ C(OP_WRITE) ] = {
+               [ C(RESULT_ACCESS) ] = -1,
+               [ C(RESULT_MISS)   ] = -1,
+       },
+       [ C(OP_PREFETCH) ] = {
+               [ C(RESULT_ACCESS) ] = 0x0,
+               [ C(RESULT_MISS)   ] = 0x0,
+       },
+ },
+ [ C(LL  ) ] = {
+       [ C(OP_READ) ] = {
+               /* OFFCORE_RESPONSE:ALL_DATA_RD|ALL_CODE_RD */
+               [ C(RESULT_ACCESS) ] = 0x1b7,
+               /* OFFCORE_RESPONSE:ALL_DATA_RD|ALL_CODE_RD|SUPPLIER_NONE|
+                   L3_MISS|ANY_SNOOP */
+               [ C(RESULT_MISS)   ] = 0x1b7,
+       },
+       [ C(OP_WRITE) ] = {
+               [ C(RESULT_ACCESS) ] = 0x1b7,   /* OFFCORE_RESPONSE:ALL_RFO */
+               /* OFFCORE_RESPONSE:ALL_RFO|SUPPLIER_NONE|L3_MISS|ANY_SNOOP */
+               [ C(RESULT_MISS)   ] = 0x1b7,
+       },
+       [ C(OP_PREFETCH) ] = {
+               [ C(RESULT_ACCESS) ] = 0x0,
+               [ C(RESULT_MISS)   ] = 0x0,
+       },
+ },
+ [ C(DTLB) ] = {
+       [ C(OP_READ) ] = {
+               [ C(RESULT_ACCESS) ] = 0x81d0,  /* MEM_UOPS_RETIRED.ALL_LOADS */
+               [ C(RESULT_MISS)   ] = 0x108,   /* DTLB_LOAD_MISSES.MISS_CAUSES_A_WALK */
+       },
+       [ C(OP_WRITE) ] = {
+               [ C(RESULT_ACCESS) ] = 0x82d0,  /* MEM_UOPS_RETIRED.ALL_STORES */
+               [ C(RESULT_MISS)   ] = 0x149,   /* DTLB_STORE_MISSES.MISS_CAUSES_A_WALK */
+       },
+       [ C(OP_PREFETCH) ] = {
+               [ C(RESULT_ACCESS) ] = 0x0,
+               [ C(RESULT_MISS)   ] = 0x0,
+       },
+ },
+ [ C(ITLB) ] = {
+       [ C(OP_READ) ] = {
+               [ C(RESULT_ACCESS) ] = 0x6085,  /* ITLB_MISSES.STLB_HIT */
+               [ C(RESULT_MISS)   ] = 0x185,   /* ITLB_MISSES.MISS_CAUSES_A_WALK */
+       },
+       [ C(OP_WRITE) ] = {
+               [ C(RESULT_ACCESS) ] = -1,
+               [ C(RESULT_MISS)   ] = -1,
+       },
+       [ C(OP_PREFETCH) ] = {
+               [ C(RESULT_ACCESS) ] = -1,
+               [ C(RESULT_MISS)   ] = -1,
+       },
+ },
+ [ C(BPU ) ] = {
+       [ C(OP_READ) ] = {
+               [ C(RESULT_ACCESS) ] = 0xc4,    /* BR_INST_RETIRED.ALL_BRANCHES */
+               [ C(RESULT_MISS)   ] = 0xc5,    /* BR_MISP_RETIRED.ALL_BRANCHES */
+       },
+       [ C(OP_WRITE) ] = {
+               [ C(RESULT_ACCESS) ] = -1,
+               [ C(RESULT_MISS)   ] = -1,
+       },
+       [ C(OP_PREFETCH) ] = {
+               [ C(RESULT_ACCESS) ] = -1,
+               [ C(RESULT_MISS)   ] = -1,
+       },
+ },
+};
+
+static __initconst const u64 hsw_hw_cache_extra_regs
+                               [PERF_COUNT_HW_CACHE_MAX]
+                               [PERF_COUNT_HW_CACHE_OP_MAX]
+                               [PERF_COUNT_HW_CACHE_RESULT_MAX] =
+{
+ [ C(LL  ) ] = {
+       [ C(OP_READ) ] = {
+               /* OFFCORE_RESPONSE:ALL_DATA_RD|ALL_CODE_RD */
+               [ C(RESULT_ACCESS) ] = 0x2d5,
+               /* OFFCORE_RESPONSE:ALL_DATA_RD|ALL_CODE_RD|SUPPLIER_NONE|
+                   L3_MISS|ANY_SNOOP */
+               [ C(RESULT_MISS)   ] = 0x3fbc0202d5ull,
+       },
+       [ C(OP_WRITE) ] = {
+               [ C(RESULT_ACCESS) ] = 0x122,   /* OFFCORE_RESPONSE:ALL_RFO */
+               /* OFFCORE_RESPONSE:ALL_RFO|SUPPLIER_NONE|L3_MISS|ANY_SNOOP */
+               [ C(RESULT_MISS)   ] = 0x3fbc020122ull,
+       },
+       [ C(OP_PREFETCH) ] = {
+               [ C(RESULT_ACCESS) ] = 0x0,
+               [ C(RESULT_MISS)   ] = 0x0,
+       },
+ },
+};
+
 static __initconst const u64 westmere_hw_cache_event_ids
                                [PERF_COUNT_HW_CACHE_MAX]
                                [PERF_COUNT_HW_CACHE_OP_MAX]
@@ -1905,6 +2034,24 @@ hsw_get_event_constraints(struct cpu_hw_events *cpuc, struct perf_event *event)
        return c;
 }
 
+/*
+ * Broadwell:
+ * The INST_RETIRED.ALL period always needs to have lowest
+ * 6bits cleared (BDM57). It shall not use a period smaller
+ * than 100 (BDM11). We combine the two to enforce
+ * a min-period of 128.
+ */
+static unsigned bdw_limit_period(struct perf_event *event, unsigned left)
+{
+       if ((event->hw.config & INTEL_ARCH_EVENT_MASK) ==
+                       X86_CONFIG(.event=0xc0, .umask=0x01)) {
+               if (left < 128)
+                       left = 128;
+               left &= ~0x3fu;
+       }
+       return left;
+}
+
 PMU_FORMAT_ATTR(event, "config:0-7"    );
 PMU_FORMAT_ATTR(umask, "config:8-15"   );
 PMU_FORMAT_ATTR(edge,  "config:18"     );
@@ -2367,15 +2514,15 @@ __init int intel_pmu_init(void)
         * Install the hw-cache-events table:
         */
        switch (boot_cpu_data.x86_model) {
-       case 14: /* 65 nm core solo/duo, "Yonah" */
+       case 14: /* 65nm Core "Yonah" */
                pr_cont("Core events, ");
                break;
 
-       case 15: /* original 65 nm celeron/pentium/core2/xeon, "Merom"/"Conroe" */
+       case 15: /* 65nm Core2 "Merom"          */
                x86_add_quirk(intel_clovertown_quirk);
-       case 22: /* single-core 65 nm celeron/core2solo "Merom-L"/"Conroe-L" */
-       case 23: /* current 45 nm celeron/core2/xeon "Penryn"/"Wolfdale" */
-       case 29: /* six-core 45 nm xeon "Dunnington" */
+       case 22: /* 65nm Core2 "Merom-L"        */
+       case 23: /* 45nm Core2 "Penryn"         */
+       case 29: /* 45nm Core2 "Dunnington (MP) */
                memcpy(hw_cache_event_ids, core2_hw_cache_event_ids,
                       sizeof(hw_cache_event_ids));
 
@@ -2386,9 +2533,9 @@ __init int intel_pmu_init(void)
                pr_cont("Core2 events, ");
                break;
 
-       case 26: /* 45 nm nehalem, "Bloomfield" */
-       case 30: /* 45 nm nehalem, "Lynnfield" */
-       case 46: /* 45 nm nehalem-ex, "Beckton" */
+       case 30: /* 45nm Nehalem    */
+       case 26: /* 45nm Nehalem-EP */
+       case 46: /* 45nm Nehalem-EX */
                memcpy(hw_cache_event_ids, nehalem_hw_cache_event_ids,
                       sizeof(hw_cache_event_ids));
                memcpy(hw_cache_extra_regs, nehalem_hw_cache_extra_regs,
@@ -2415,11 +2562,11 @@ __init int intel_pmu_init(void)
                pr_cont("Nehalem events, ");
                break;
 
-       case 28: /* Atom */
-       case 38: /* Lincroft */
-       case 39: /* Penwell */
-       case 53: /* Cloverview */
-       case 54: /* Cedarview */
+       case 28: /* 45nm Atom "Pineview"   */
+       case 38: /* 45nm Atom "Lincroft"   */
+       case 39: /* 32nm Atom "Penwell"    */
+       case 53: /* 32nm Atom "Cloverview" */
+       case 54: /* 32nm Atom "Cedarview"  */
                memcpy(hw_cache_event_ids, atom_hw_cache_event_ids,
                       sizeof(hw_cache_event_ids));
 
@@ -2430,8 +2577,8 @@ __init int intel_pmu_init(void)
                pr_cont("Atom events, ");
                break;
 
-       case 55: /* Atom 22nm "Silvermont" */
-       case 77: /* Avoton "Silvermont" */
+       case 55: /* 22nm Atom "Silvermont"                */
+       case 77: /* 22nm Atom "Silvermont Avoton/Rangely" */
                memcpy(hw_cache_event_ids, slm_hw_cache_event_ids,
                        sizeof(hw_cache_event_ids));
                memcpy(hw_cache_extra_regs, slm_hw_cache_extra_regs,
@@ -2446,9 +2593,9 @@ __init int intel_pmu_init(void)
                pr_cont("Silvermont events, ");
                break;
 
-       case 37: /* 32 nm nehalem, "Clarkdale" */
-       case 44: /* 32 nm nehalem, "Gulftown" */
-       case 47: /* 32 nm Xeon E7 */
+       case 37: /* 32nm Westmere    */
+       case 44: /* 32nm Westmere-EP */
+       case 47: /* 32nm Westmere-EX */
                memcpy(hw_cache_event_ids, westmere_hw_cache_event_ids,
                       sizeof(hw_cache_event_ids));
                memcpy(hw_cache_extra_regs, nehalem_hw_cache_extra_regs,
@@ -2474,8 +2621,8 @@ __init int intel_pmu_init(void)
                pr_cont("Westmere events, ");
                break;
 
-       case 42: /* SandyBridge */
-       case 45: /* SandyBridge, "Romely-EP" */
+       case 42: /* 32nm SandyBridge         */
+       case 45: /* 32nm SandyBridge-E/EN/EP */
                x86_add_quirk(intel_sandybridge_quirk);
                memcpy(hw_cache_event_ids, snb_hw_cache_event_ids,
                       sizeof(hw_cache_event_ids));
@@ -2506,8 +2653,9 @@ __init int intel_pmu_init(void)
 
                pr_cont("SandyBridge events, ");
                break;
-       case 58: /* IvyBridge */
-       case 62: /* IvyBridge EP */
+
+       case 58: /* 22nm IvyBridge       */
+       case 62: /* 22nm IvyBridge-EP/EX */
                memcpy(hw_cache_event_ids, snb_hw_cache_event_ids,
                       sizeof(hw_cache_event_ids));
                /* dTLB-load-misses on IVB is different than SNB */
@@ -2539,20 +2687,19 @@ __init int intel_pmu_init(void)
                break;
 
 
-       case 60: /* Haswell Client */
-       case 70:
-       case 71:
-       case 63:
-       case 69:
+       case 60: /* 22nm Haswell Core */
+       case 63: /* 22nm Haswell Server */
+       case 69: /* 22nm Haswell ULT */
+       case 70: /* 22nm Haswell + GT3e (Intel Iris Pro graphics) */
                x86_pmu.late_ack = true;
-               memcpy(hw_cache_event_ids, snb_hw_cache_event_ids, sizeof(hw_cache_event_ids));
-               memcpy(hw_cache_extra_regs, snb_hw_cache_extra_regs, sizeof(hw_cache_extra_regs));
+               memcpy(hw_cache_event_ids, hsw_hw_cache_event_ids, sizeof(hw_cache_event_ids));
+               memcpy(hw_cache_extra_regs, hsw_hw_cache_extra_regs, sizeof(hw_cache_extra_regs));
 
                intel_pmu_lbr_init_snb();
 
                x86_pmu.event_constraints = intel_hsw_event_constraints;
                x86_pmu.pebs_constraints = intel_hsw_pebs_event_constraints;
-               x86_pmu.extra_regs = intel_snb_extra_regs;
+               x86_pmu.extra_regs = intel_snbep_extra_regs;
                x86_pmu.pebs_aliases = intel_pebs_aliases_snb;
                /* all extra regs are per-cpu when HT is on */
                x86_pmu.er_flags |= ERF_HAS_RSP_1;
@@ -2565,6 +2712,28 @@ __init int intel_pmu_init(void)
                pr_cont("Haswell events, ");
                break;
 
+       case 61: /* 14nm Broadwell Core-M */
+               x86_pmu.late_ack = true;
+               memcpy(hw_cache_event_ids, hsw_hw_cache_event_ids, sizeof(hw_cache_event_ids));
+               memcpy(hw_cache_extra_regs, hsw_hw_cache_extra_regs, sizeof(hw_cache_extra_regs));
+
+               intel_pmu_lbr_init_snb();
+
+               x86_pmu.event_constraints = intel_bdw_event_constraints;
+               x86_pmu.pebs_constraints = intel_hsw_pebs_event_constraints;
+               x86_pmu.extra_regs = intel_snbep_extra_regs;
+               x86_pmu.pebs_aliases = intel_pebs_aliases_snb;
+               /* all extra regs are per-cpu when HT is on */
+               x86_pmu.er_flags |= ERF_HAS_RSP_1;
+               x86_pmu.er_flags |= ERF_NO_HT_SHARING;
+
+               x86_pmu.hw_config = hsw_hw_config;
+               x86_pmu.get_event_constraints = hsw_get_event_constraints;
+               x86_pmu.cpu_events = hsw_events_attrs;
+               x86_pmu.limit_period = bdw_limit_period;
+               pr_cont("Broadwell events, ");
+               break;
+
        default:
                switch (x86_pmu.version) {
                case 1:
index 696ade311ded7d01103323d159cff621b46d4a89..b1553d05a5cb6adee590a2733913e1c774192025 100644 (file)
@@ -108,14 +108,16 @@ static u64 precise_store_data(u64 status)
        return val;
 }
 
-static u64 precise_store_data_hsw(struct perf_event *event, u64 status)
+static u64 precise_datala_hsw(struct perf_event *event, u64 status)
 {
        union perf_mem_data_src dse;
-       u64 cfg = event->hw.config & INTEL_ARCH_EVENT_MASK;
 
-       dse.val = 0;
-       dse.mem_op = PERF_MEM_OP_STORE;
-       dse.mem_lvl = PERF_MEM_LVL_NA;
+       dse.val = PERF_MEM_NA;
+
+       if (event->hw.flags & PERF_X86_EVENT_PEBS_ST_HSW)
+               dse.mem_op = PERF_MEM_OP_STORE;
+       else if (event->hw.flags & PERF_X86_EVENT_PEBS_LD_HSW)
+               dse.mem_op = PERF_MEM_OP_LOAD;
 
        /*
         * L1 info only valid for following events:
@@ -125,15 +127,12 @@ static u64 precise_store_data_hsw(struct perf_event *event, u64 status)
         * MEM_UOPS_RETIRED.SPLIT_STORES
         * MEM_UOPS_RETIRED.ALL_STORES
         */
-       if (cfg != 0x12d0 && cfg != 0x22d0 && cfg != 0x42d0 && cfg != 0x82d0)
-               return dse.mem_lvl;
-
-       if (status & 1)
-               dse.mem_lvl = PERF_MEM_LVL_L1 | PERF_MEM_LVL_HIT;
-       else
-               dse.mem_lvl = PERF_MEM_LVL_L1 | PERF_MEM_LVL_MISS;
-
-       /* Nothing else supported. Sorry. */
+       if (event->hw.flags & PERF_X86_EVENT_PEBS_ST_HSW) {
+               if (status & 1)
+                       dse.mem_lvl = PERF_MEM_LVL_L1 | PERF_MEM_LVL_HIT;
+               else
+                       dse.mem_lvl = PERF_MEM_LVL_L1 | PERF_MEM_LVL_MISS;
+       }
        return dse.val;
 }
 
@@ -569,28 +568,10 @@ struct event_constraint intel_atom_pebs_event_constraints[] = {
 };
 
 struct event_constraint intel_slm_pebs_event_constraints[] = {
-       INTEL_UEVENT_CONSTRAINT(0x0103, 0x1), /* REHABQ.LD_BLOCK_ST_FORWARD_PS */
-       INTEL_UEVENT_CONSTRAINT(0x0803, 0x1), /* REHABQ.LD_SPLITS_PS */
-       INTEL_UEVENT_CONSTRAINT(0x0204, 0x1), /* MEM_UOPS_RETIRED.L2_HIT_LOADS_PS */
-       INTEL_UEVENT_CONSTRAINT(0x0404, 0x1), /* MEM_UOPS_RETIRED.L2_MISS_LOADS_PS */
-       INTEL_UEVENT_CONSTRAINT(0x0804, 0x1), /* MEM_UOPS_RETIRED.DTLB_MISS_LOADS_PS */
-       INTEL_UEVENT_CONSTRAINT(0x2004, 0x1), /* MEM_UOPS_RETIRED.HITM_PS */
-       INTEL_UEVENT_CONSTRAINT(0x00c0, 0x1), /* INST_RETIRED.ANY_PS */
-       INTEL_UEVENT_CONSTRAINT(0x00c4, 0x1), /* BR_INST_RETIRED.ALL_BRANCHES_PS */
-       INTEL_UEVENT_CONSTRAINT(0x7ec4, 0x1), /* BR_INST_RETIRED.JCC_PS */
-       INTEL_UEVENT_CONSTRAINT(0xbfc4, 0x1), /* BR_INST_RETIRED.FAR_BRANCH_PS */
-       INTEL_UEVENT_CONSTRAINT(0xebc4, 0x1), /* BR_INST_RETIRED.NON_RETURN_IND_PS */
-       INTEL_UEVENT_CONSTRAINT(0xf7c4, 0x1), /* BR_INST_RETIRED.RETURN_PS */
-       INTEL_UEVENT_CONSTRAINT(0xf9c4, 0x1), /* BR_INST_RETIRED.CALL_PS */
-       INTEL_UEVENT_CONSTRAINT(0xfbc4, 0x1), /* BR_INST_RETIRED.IND_CALL_PS */
-       INTEL_UEVENT_CONSTRAINT(0xfdc4, 0x1), /* BR_INST_RETIRED.REL_CALL_PS */
-       INTEL_UEVENT_CONSTRAINT(0xfec4, 0x1), /* BR_INST_RETIRED.TAKEN_JCC_PS */
-       INTEL_UEVENT_CONSTRAINT(0x00c5, 0x1), /* BR_INST_MISP_RETIRED.ALL_BRANCHES_PS */
-       INTEL_UEVENT_CONSTRAINT(0x7ec5, 0x1), /* BR_INST_MISP_RETIRED.JCC_PS */
-       INTEL_UEVENT_CONSTRAINT(0xebc5, 0x1), /* BR_INST_MISP_RETIRED.NON_RETURN_IND_PS */
-       INTEL_UEVENT_CONSTRAINT(0xf7c5, 0x1), /* BR_INST_MISP_RETIRED.RETURN_PS */
-       INTEL_UEVENT_CONSTRAINT(0xfbc5, 0x1), /* BR_INST_MISP_RETIRED.IND_CALL_PS */
-       INTEL_UEVENT_CONSTRAINT(0xfec5, 0x1), /* BR_INST_MISP_RETIRED.TAKEN_JCC_PS */
+       /* UOPS_RETIRED.ALL, inv=1, cmask=16 (cycles:p). */
+       INTEL_FLAGS_EVENT_CONSTRAINT(0x108001c2, 0xf),
+       /* Allow all events as PEBS with no flags */
+       INTEL_ALL_EVENT_CONSTRAINT(0, 0x1),
        EVENT_CONSTRAINT_END
 };
 
@@ -626,68 +607,44 @@ struct event_constraint intel_westmere_pebs_event_constraints[] = {
 
 struct event_constraint intel_snb_pebs_event_constraints[] = {
        INTEL_UEVENT_CONSTRAINT(0x01c0, 0x2), /* INST_RETIRED.PRECDIST */
-       INTEL_UEVENT_CONSTRAINT(0x01c2, 0xf), /* UOPS_RETIRED.ALL */
-       INTEL_UEVENT_CONSTRAINT(0x02c2, 0xf), /* UOPS_RETIRED.RETIRE_SLOTS */
-       INTEL_EVENT_CONSTRAINT(0xc4, 0xf),    /* BR_INST_RETIRED.* */
-       INTEL_EVENT_CONSTRAINT(0xc5, 0xf),    /* BR_MISP_RETIRED.* */
        INTEL_PLD_CONSTRAINT(0x01cd, 0x8),    /* MEM_TRANS_RETIRED.LAT_ABOVE_THR */
        INTEL_PST_CONSTRAINT(0x02cd, 0x8),    /* MEM_TRANS_RETIRED.PRECISE_STORES */
-       INTEL_EVENT_CONSTRAINT(0xd0, 0xf),    /* MEM_UOP_RETIRED.* */
-       INTEL_EVENT_CONSTRAINT(0xd1, 0xf),    /* MEM_LOAD_UOPS_RETIRED.* */
-       INTEL_EVENT_CONSTRAINT(0xd2, 0xf),    /* MEM_LOAD_UOPS_LLC_HIT_RETIRED.* */
-       INTEL_EVENT_CONSTRAINT(0xd3, 0xf),    /* MEM_LOAD_UOPS_LLC_MISS_RETIRED.* */
-       INTEL_UEVENT_CONSTRAINT(0x02d4, 0xf), /* MEM_LOAD_UOPS_MISC_RETIRED.LLC_MISS */
+       /* UOPS_RETIRED.ALL, inv=1, cmask=16 (cycles:p). */
+       INTEL_FLAGS_EVENT_CONSTRAINT(0x108001c2, 0xf),
+       /* Allow all events as PEBS with no flags */
+       INTEL_ALL_EVENT_CONSTRAINT(0, 0xf),
        EVENT_CONSTRAINT_END
 };
 
 struct event_constraint intel_ivb_pebs_event_constraints[] = {
         INTEL_UEVENT_CONSTRAINT(0x01c0, 0x2), /* INST_RETIRED.PRECDIST */
-        INTEL_UEVENT_CONSTRAINT(0x01c2, 0xf), /* UOPS_RETIRED.ALL */
-        INTEL_UEVENT_CONSTRAINT(0x02c2, 0xf), /* UOPS_RETIRED.RETIRE_SLOTS */
-        INTEL_EVENT_CONSTRAINT(0xc4, 0xf),    /* BR_INST_RETIRED.* */
-        INTEL_EVENT_CONSTRAINT(0xc5, 0xf),    /* BR_MISP_RETIRED.* */
         INTEL_PLD_CONSTRAINT(0x01cd, 0x8),    /* MEM_TRANS_RETIRED.LAT_ABOVE_THR */
        INTEL_PST_CONSTRAINT(0x02cd, 0x8),    /* MEM_TRANS_RETIRED.PRECISE_STORES */
-        INTEL_EVENT_CONSTRAINT(0xd0, 0xf),    /* MEM_UOP_RETIRED.* */
-        INTEL_EVENT_CONSTRAINT(0xd1, 0xf),    /* MEM_LOAD_UOPS_RETIRED.* */
-        INTEL_EVENT_CONSTRAINT(0xd2, 0xf),    /* MEM_LOAD_UOPS_LLC_HIT_RETIRED.* */
-        INTEL_EVENT_CONSTRAINT(0xd3, 0xf),    /* MEM_LOAD_UOPS_LLC_MISS_RETIRED.* */
+       /* UOPS_RETIRED.ALL, inv=1, cmask=16 (cycles:p). */
+       INTEL_FLAGS_EVENT_CONSTRAINT(0x108001c2, 0xf),
+       /* Allow all events as PEBS with no flags */
+       INTEL_ALL_EVENT_CONSTRAINT(0, 0xf),
         EVENT_CONSTRAINT_END
 };
 
 struct event_constraint intel_hsw_pebs_event_constraints[] = {
        INTEL_UEVENT_CONSTRAINT(0x01c0, 0x2), /* INST_RETIRED.PRECDIST */
-       INTEL_PST_HSW_CONSTRAINT(0x01c2, 0xf), /* UOPS_RETIRED.ALL */
-       INTEL_UEVENT_CONSTRAINT(0x02c2, 0xf), /* UOPS_RETIRED.RETIRE_SLOTS */
-       INTEL_EVENT_CONSTRAINT(0xc4, 0xf),    /* BR_INST_RETIRED.* */
-       INTEL_UEVENT_CONSTRAINT(0x01c5, 0xf), /* BR_MISP_RETIRED.CONDITIONAL */
-       INTEL_UEVENT_CONSTRAINT(0x04c5, 0xf), /* BR_MISP_RETIRED.ALL_BRANCHES */
-       INTEL_UEVENT_CONSTRAINT(0x20c5, 0xf), /* BR_MISP_RETIRED.NEAR_TAKEN */
-       INTEL_PLD_CONSTRAINT(0x01cd, 0x8),    /* MEM_TRANS_RETIRED.* */
-       /* MEM_UOPS_RETIRED.STLB_MISS_LOADS */
-       INTEL_UEVENT_CONSTRAINT(0x11d0, 0xf),
-       /* MEM_UOPS_RETIRED.STLB_MISS_STORES */
-       INTEL_UEVENT_CONSTRAINT(0x12d0, 0xf),
-       INTEL_UEVENT_CONSTRAINT(0x21d0, 0xf), /* MEM_UOPS_RETIRED.LOCK_LOADS */
-       INTEL_UEVENT_CONSTRAINT(0x41d0, 0xf), /* MEM_UOPS_RETIRED.SPLIT_LOADS */
-       /* MEM_UOPS_RETIRED.SPLIT_STORES */
-       INTEL_UEVENT_CONSTRAINT(0x42d0, 0xf),
-       INTEL_UEVENT_CONSTRAINT(0x81d0, 0xf), /* MEM_UOPS_RETIRED.ALL_LOADS */
-       INTEL_PST_HSW_CONSTRAINT(0x82d0, 0xf), /* MEM_UOPS_RETIRED.ALL_STORES */
-       INTEL_UEVENT_CONSTRAINT(0x01d1, 0xf), /* MEM_LOAD_UOPS_RETIRED.L1_HIT */
-       INTEL_UEVENT_CONSTRAINT(0x02d1, 0xf), /* MEM_LOAD_UOPS_RETIRED.L2_HIT */
-       INTEL_UEVENT_CONSTRAINT(0x04d1, 0xf), /* MEM_LOAD_UOPS_RETIRED.L3_HIT */
-       /* MEM_LOAD_UOPS_RETIRED.HIT_LFB */
-       INTEL_UEVENT_CONSTRAINT(0x40d1, 0xf),
-       /* MEM_LOAD_UOPS_LLC_HIT_RETIRED.XSNP_MISS */
-       INTEL_UEVENT_CONSTRAINT(0x01d2, 0xf),
-       /* MEM_LOAD_UOPS_LLC_HIT_RETIRED.XSNP_HIT */
-       INTEL_UEVENT_CONSTRAINT(0x02d2, 0xf),
-       /* MEM_LOAD_UOPS_LLC_MISS_RETIRED.LOCAL_DRAM */
-       INTEL_UEVENT_CONSTRAINT(0x01d3, 0xf),
-       INTEL_UEVENT_CONSTRAINT(0x04c8, 0xf), /* HLE_RETIRED.Abort */
-       INTEL_UEVENT_CONSTRAINT(0x04c9, 0xf), /* RTM_RETIRED.Abort */
-
+       INTEL_PLD_CONSTRAINT(0x01cd, 0xf),    /* MEM_TRANS_RETIRED.* */
+       /* UOPS_RETIRED.ALL, inv=1, cmask=16 (cycles:p). */
+       INTEL_FLAGS_EVENT_CONSTRAINT(0x108001c2, 0xf),
+       INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_NA(0x01c2, 0xf), /* UOPS_RETIRED.ALL */
+       INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_LD(0x11d0, 0xf), /* MEM_UOPS_RETIRED.STLB_MISS_LOADS */
+       INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_LD(0x21d0, 0xf), /* MEM_UOPS_RETIRED.LOCK_LOADS */
+       INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_LD(0x41d0, 0xf), /* MEM_UOPS_RETIRED.SPLIT_LOADS */
+       INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_LD(0x81d0, 0xf), /* MEM_UOPS_RETIRED.ALL_LOADS */
+       INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_ST(0x12d0, 0xf), /* MEM_UOPS_RETIRED.STLB_MISS_STORES */
+       INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_ST(0x42d0, 0xf), /* MEM_UOPS_RETIRED.SPLIT_STORES */
+       INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_ST(0x82d0, 0xf), /* MEM_UOPS_RETIRED.ALL_STORES */
+       INTEL_FLAGS_EVENT_CONSTRAINT_DATALA_LD(0xd1, 0xf),    /* MEM_LOAD_UOPS_RETIRED.* */
+       INTEL_FLAGS_EVENT_CONSTRAINT_DATALA_LD(0xd2, 0xf),    /* MEM_LOAD_UOPS_L3_HIT_RETIRED.* */
+       INTEL_FLAGS_EVENT_CONSTRAINT_DATALA_LD(0xd3, 0xf),    /* MEM_LOAD_UOPS_L3_MISS_RETIRED.* */
+       /* Allow all events as PEBS with no flags */
+       INTEL_ALL_EVENT_CONSTRAINT(0, 0xf),
        EVENT_CONSTRAINT_END
 };
 
@@ -864,6 +821,10 @@ static inline u64 intel_hsw_transaction(struct pebs_record_hsw *pebs)
 static void __intel_pmu_pebs_event(struct perf_event *event,
                                   struct pt_regs *iregs, void *__pebs)
 {
+#define PERF_X86_EVENT_PEBS_HSW_PREC \
+               (PERF_X86_EVENT_PEBS_ST_HSW | \
+                PERF_X86_EVENT_PEBS_LD_HSW | \
+                PERF_X86_EVENT_PEBS_NA_HSW)
        /*
         * We cast to the biggest pebs_record but are careful not to
         * unconditionally access the 'extra' entries.
@@ -873,42 +834,40 @@ static void __intel_pmu_pebs_event(struct perf_event *event,
        struct perf_sample_data data;
        struct pt_regs regs;
        u64 sample_type;
-       int fll, fst;
+       int fll, fst, dsrc;
+       int fl = event->hw.flags;
 
        if (!intel_pmu_save_and_restart(event))
                return;
 
-       fll = event->hw.flags & PERF_X86_EVENT_PEBS_LDLAT;
-       fst = event->hw.flags & (PERF_X86_EVENT_PEBS_ST |
-                                PERF_X86_EVENT_PEBS_ST_HSW);
+       sample_type = event->attr.sample_type;
+       dsrc = sample_type & PERF_SAMPLE_DATA_SRC;
+
+       fll = fl & PERF_X86_EVENT_PEBS_LDLAT;
+       fst = fl & (PERF_X86_EVENT_PEBS_ST | PERF_X86_EVENT_PEBS_HSW_PREC);
 
        perf_sample_data_init(&data, 0, event->hw.last_period);
 
        data.period = event->hw.last_period;
-       sample_type = event->attr.sample_type;
 
        /*
-        * if PEBS-LL or PreciseStore
+        * Use latency for weight (only avail with PEBS-LL)
         */
-       if (fll || fst) {
-               /*
-                * Use latency for weight (only avail with PEBS-LL)
-                */
-               if (fll && (sample_type & PERF_SAMPLE_WEIGHT))
-                       data.weight = pebs->lat;
-
-               /*
-                * data.data_src encodes the data source
-                */
-               if (sample_type & PERF_SAMPLE_DATA_SRC) {
-                       if (fll)
-                               data.data_src.val = load_latency_data(pebs->dse);
-                       else if (event->hw.flags & PERF_X86_EVENT_PEBS_ST_HSW)
-                               data.data_src.val =
-                                       precise_store_data_hsw(event, pebs->dse);
-                       else
-                               data.data_src.val = precise_store_data(pebs->dse);
-               }
+       if (fll && (sample_type & PERF_SAMPLE_WEIGHT))
+               data.weight = pebs->lat;
+
+       /*
+        * data.data_src encodes the data source
+        */
+       if (dsrc) {
+               u64 val = PERF_MEM_NA;
+               if (fll)
+                       val = load_latency_data(pebs->dse);
+               else if (fst && (fl & PERF_X86_EVENT_PEBS_HSW_PREC))
+                       val = precise_datala_hsw(event, pebs->dse);
+               else if (fst)
+                       val = precise_store_data(pebs->dse);
+               data.data_src.val = val;
        }
 
        /*
@@ -935,16 +894,16 @@ static void __intel_pmu_pebs_event(struct perf_event *event,
        else
                regs.flags &= ~PERF_EFLAGS_EXACT;
 
-       if ((event->attr.sample_type & PERF_SAMPLE_ADDR) &&
+       if ((sample_type & PERF_SAMPLE_ADDR) &&
            x86_pmu.intel_cap.pebs_format >= 1)
                data.addr = pebs->dla;
 
        if (x86_pmu.intel_cap.pebs_format >= 2) {
                /* Only set the TSX weight when no memory weight. */
-               if ((event->attr.sample_type & PERF_SAMPLE_WEIGHT) && !fll)
+               if ((sample_type & PERF_SAMPLE_WEIGHT) && !fll)
                        data.weight = intel_hsw_weight(pebs);
 
-               if (event->attr.sample_type & PERF_SAMPLE_TRANSACTION)
+               if (sample_type & PERF_SAMPLE_TRANSACTION)
                        data.txn = intel_hsw_transaction(pebs);
        }
 
@@ -1055,7 +1014,7 @@ static void intel_pmu_drain_pebs_nhm(struct pt_regs *iregs)
  * BTS, PEBS probe and setup
  */
 
-void intel_ds_init(void)
+void __init intel_ds_init(void)
 {
        /*
         * No support for 32bit formats
index 9dd2459a4c738d99bb4a75ebf51062bcbf6b21de..4af10617de3389040f28a24dac6875ce933e359a 100644 (file)
@@ -697,7 +697,7 @@ static const int snb_lbr_sel_map[PERF_SAMPLE_BRANCH_MAX] = {
 };
 
 /* core */
-void intel_pmu_lbr_init_core(void)
+void __init intel_pmu_lbr_init_core(void)
 {
        x86_pmu.lbr_nr     = 4;
        x86_pmu.lbr_tos    = MSR_LBR_TOS;
@@ -712,7 +712,7 @@ void intel_pmu_lbr_init_core(void)
 }
 
 /* nehalem/westmere */
-void intel_pmu_lbr_init_nhm(void)
+void __init intel_pmu_lbr_init_nhm(void)
 {
        x86_pmu.lbr_nr     = 16;
        x86_pmu.lbr_tos    = MSR_LBR_TOS;
@@ -733,7 +733,7 @@ void intel_pmu_lbr_init_nhm(void)
 }
 
 /* sandy bridge */
-void intel_pmu_lbr_init_snb(void)
+void __init intel_pmu_lbr_init_snb(void)
 {
        x86_pmu.lbr_nr   = 16;
        x86_pmu.lbr_tos  = MSR_LBR_TOS;
@@ -753,7 +753,7 @@ void intel_pmu_lbr_init_snb(void)
 }
 
 /* atom */
-void intel_pmu_lbr_init_atom(void)
+void __init intel_pmu_lbr_init_atom(void)
 {
        /*
         * only models starting at stepping 10 seems
index 0939f86f543d04ceb9a4bcb81f0a60775e078ee3..9762dbd9f3f7d7a4e11f040aa19b21e31fe62667 100644 (file)
 #include "perf_event_intel_uncore.h"
 
 static struct intel_uncore_type *empty_uncore[] = { NULL, };
-static struct intel_uncore_type **msr_uncores = empty_uncore;
-static struct intel_uncore_type **pci_uncores = empty_uncore;
-/* pci bus to socket mapping */
-static int pcibus_to_physid[256] = { [0 ... 255] = -1, };
-
-static struct pci_dev *extra_pci_dev[UNCORE_SOCKET_MAX][UNCORE_EXTRA_PCI_DEV_MAX];
-
-static DEFINE_RAW_SPINLOCK(uncore_box_lock);
-
-/* mask of cpus that collect uncore events */
-static cpumask_t uncore_cpu_mask;
-
-/* constraint for the fixed counter */
-static struct event_constraint constraint_fixed =
-       EVENT_CONSTRAINT(~0ULL, 1 << UNCORE_PMC_IDX_FIXED, ~0ULL);
-static struct event_constraint constraint_empty =
-       EVENT_CONSTRAINT(0, 0, 0);
-
-#define __BITS_VALUE(x, i, n)  ((typeof(x))(((x) >> ((i) * (n))) & \
-                               ((1ULL << (n)) - 1)))
-
-DEFINE_UNCORE_FORMAT_ATTR(event, event, "config:0-7");
-DEFINE_UNCORE_FORMAT_ATTR(event_ext, event, "config:0-7,21");
-DEFINE_UNCORE_FORMAT_ATTR(umask, umask, "config:8-15");
-DEFINE_UNCORE_FORMAT_ATTR(edge, edge, "config:18");
-DEFINE_UNCORE_FORMAT_ATTR(tid_en, tid_en, "config:19");
-DEFINE_UNCORE_FORMAT_ATTR(inv, inv, "config:23");
-DEFINE_UNCORE_FORMAT_ATTR(cmask5, cmask, "config:24-28");
-DEFINE_UNCORE_FORMAT_ATTR(cmask8, cmask, "config:24-31");
-DEFINE_UNCORE_FORMAT_ATTR(thresh8, thresh, "config:24-31");
-DEFINE_UNCORE_FORMAT_ATTR(thresh5, thresh, "config:24-28");
-DEFINE_UNCORE_FORMAT_ATTR(occ_sel, occ_sel, "config:14-15");
-DEFINE_UNCORE_FORMAT_ATTR(occ_invert, occ_invert, "config:30");
-DEFINE_UNCORE_FORMAT_ATTR(occ_edge, occ_edge, "config:14-51");
-DEFINE_UNCORE_FORMAT_ATTR(filter_tid, filter_tid, "config1:0-4");
-DEFINE_UNCORE_FORMAT_ATTR(filter_link, filter_link, "config1:5-8");
-DEFINE_UNCORE_FORMAT_ATTR(filter_nid, filter_nid, "config1:10-17");
-DEFINE_UNCORE_FORMAT_ATTR(filter_nid2, filter_nid, "config1:32-47");
-DEFINE_UNCORE_FORMAT_ATTR(filter_state, filter_state, "config1:18-22");
-DEFINE_UNCORE_FORMAT_ATTR(filter_state2, filter_state, "config1:17-22");
-DEFINE_UNCORE_FORMAT_ATTR(filter_opc, filter_opc, "config1:23-31");
-DEFINE_UNCORE_FORMAT_ATTR(filter_opc2, filter_opc, "config1:52-60");
-DEFINE_UNCORE_FORMAT_ATTR(filter_band0, filter_band0, "config1:0-7");
-DEFINE_UNCORE_FORMAT_ATTR(filter_band1, filter_band1, "config1:8-15");
-DEFINE_UNCORE_FORMAT_ATTR(filter_band2, filter_band2, "config1:16-23");
-DEFINE_UNCORE_FORMAT_ATTR(filter_band3, filter_band3, "config1:24-31");
-DEFINE_UNCORE_FORMAT_ATTR(match_rds, match_rds, "config1:48-51");
-DEFINE_UNCORE_FORMAT_ATTR(match_rnid30, match_rnid30, "config1:32-35");
-DEFINE_UNCORE_FORMAT_ATTR(match_rnid4, match_rnid4, "config1:31");
-DEFINE_UNCORE_FORMAT_ATTR(match_dnid, match_dnid, "config1:13-17");
-DEFINE_UNCORE_FORMAT_ATTR(match_mc, match_mc, "config1:9-12");
-DEFINE_UNCORE_FORMAT_ATTR(match_opc, match_opc, "config1:5-8");
-DEFINE_UNCORE_FORMAT_ATTR(match_vnw, match_vnw, "config1:3-4");
-DEFINE_UNCORE_FORMAT_ATTR(match0, match0, "config1:0-31");
-DEFINE_UNCORE_FORMAT_ATTR(match1, match1, "config1:32-63");
-DEFINE_UNCORE_FORMAT_ATTR(mask_rds, mask_rds, "config2:48-51");
-DEFINE_UNCORE_FORMAT_ATTR(mask_rnid30, mask_rnid30, "config2:32-35");
-DEFINE_UNCORE_FORMAT_ATTR(mask_rnid4, mask_rnid4, "config2:31");
-DEFINE_UNCORE_FORMAT_ATTR(mask_dnid, mask_dnid, "config2:13-17");
-DEFINE_UNCORE_FORMAT_ATTR(mask_mc, mask_mc, "config2:9-12");
-DEFINE_UNCORE_FORMAT_ATTR(mask_opc, mask_opc, "config2:5-8");
-DEFINE_UNCORE_FORMAT_ATTR(mask_vnw, mask_vnw, "config2:3-4");
-DEFINE_UNCORE_FORMAT_ATTR(mask0, mask0, "config2:0-31");
-DEFINE_UNCORE_FORMAT_ATTR(mask1, mask1, "config2:32-63");
-
-static void uncore_pmu_start_hrtimer(struct intel_uncore_box *box);
-static void uncore_pmu_cancel_hrtimer(struct intel_uncore_box *box);
-static void uncore_perf_event_update(struct intel_uncore_box *box, struct perf_event *event);
-static void uncore_pmu_event_read(struct perf_event *event);
-
-static struct intel_uncore_pmu *uncore_event_to_pmu(struct perf_event *event)
-{
-       return container_of(event->pmu, struct intel_uncore_pmu, pmu);
-}
-
-static struct intel_uncore_box *
-uncore_pmu_to_box(struct intel_uncore_pmu *pmu, int cpu)
-{
-       struct intel_uncore_box *box;
-
-       box = *per_cpu_ptr(pmu->box, cpu);
-       if (box)
-               return box;
-
-       raw_spin_lock(&uncore_box_lock);
-       list_for_each_entry(box, &pmu->box_list, list) {
-               if (box->phys_id == topology_physical_package_id(cpu)) {
-                       atomic_inc(&box->refcnt);
-                       *per_cpu_ptr(pmu->box, cpu) = box;
-                       break;
-               }
-       }
-       raw_spin_unlock(&uncore_box_lock);
-
-       return *per_cpu_ptr(pmu->box, cpu);
-}
-
-static struct intel_uncore_box *uncore_event_to_box(struct perf_event *event)
-{
-       /*
-        * perf core schedules event on the basis of cpu, uncore events are
-        * collected by one of the cpus inside a physical package.
-        */
-       return uncore_pmu_to_box(uncore_event_to_pmu(event), smp_processor_id());
-}
-
-static u64 uncore_msr_read_counter(struct intel_uncore_box *box, struct perf_event *event)
-{
-       u64 count;
-
-       rdmsrl(event->hw.event_base, count);
-
-       return count;
-}
-
-/*
- * generic get constraint function for shared match/mask registers.
- */
-static struct event_constraint *
-uncore_get_constraint(struct intel_uncore_box *box, struct perf_event *event)
-{
-       struct intel_uncore_extra_reg *er;
-       struct hw_perf_event_extra *reg1 = &event->hw.extra_reg;
-       struct hw_perf_event_extra *reg2 = &event->hw.branch_reg;
-       unsigned long flags;
-       bool ok = false;
-
-       /*
-        * reg->alloc can be set due to existing state, so for fake box we
-        * need to ignore this, otherwise we might fail to allocate proper
-        * fake state for this extra reg constraint.
-        */
-       if (reg1->idx == EXTRA_REG_NONE ||
-           (!uncore_box_is_fake(box) && reg1->alloc))
-               return NULL;
-
-       er = &box->shared_regs[reg1->idx];
-       raw_spin_lock_irqsave(&er->lock, flags);
-       if (!atomic_read(&er->ref) ||
-           (er->config1 == reg1->config && er->config2 == reg2->config)) {
-               atomic_inc(&er->ref);
-               er->config1 = reg1->config;
-               er->config2 = reg2->config;
-               ok = true;
-       }
-       raw_spin_unlock_irqrestore(&er->lock, flags);
-
-       if (ok) {
-               if (!uncore_box_is_fake(box))
-                       reg1->alloc = 1;
-               return NULL;
-       }
-
-       return &constraint_empty;
-}
-
-static void uncore_put_constraint(struct intel_uncore_box *box, struct perf_event *event)
-{
-       struct intel_uncore_extra_reg *er;
-       struct hw_perf_event_extra *reg1 = &event->hw.extra_reg;
-
-       /*
-        * Only put constraint if extra reg was actually allocated. Also
-        * takes care of event which do not use an extra shared reg.
-        *
-        * Also, if this is a fake box we shouldn't touch any event state
-        * (reg->alloc) and we don't care about leaving inconsistent box
-        * state either since it will be thrown out.
-        */
-       if (uncore_box_is_fake(box) || !reg1->alloc)
-               return;
-
-       er = &box->shared_regs[reg1->idx];
-       atomic_dec(&er->ref);
-       reg1->alloc = 0;
-}
-
-static u64 uncore_shared_reg_config(struct intel_uncore_box *box, int idx)
-{
-       struct intel_uncore_extra_reg *er;
-       unsigned long flags;
-       u64 config;
-
-       er = &box->shared_regs[idx];
-
-       raw_spin_lock_irqsave(&er->lock, flags);
-       config = er->config;
-       raw_spin_unlock_irqrestore(&er->lock, flags);
-
-       return config;
-}
-
-/* Sandy Bridge-EP uncore support */
-static struct intel_uncore_type snbep_uncore_cbox;
-static struct intel_uncore_type snbep_uncore_pcu;
-
-static void snbep_uncore_pci_disable_box(struct intel_uncore_box *box)
-{
-       struct pci_dev *pdev = box->pci_dev;
-       int box_ctl = uncore_pci_box_ctl(box);
-       u32 config = 0;
-
-       if (!pci_read_config_dword(pdev, box_ctl, &config)) {
-               config |= SNBEP_PMON_BOX_CTL_FRZ;
-               pci_write_config_dword(pdev, box_ctl, config);
-       }
-}
-
-static void snbep_uncore_pci_enable_box(struct intel_uncore_box *box)
-{
-       struct pci_dev *pdev = box->pci_dev;
-       int box_ctl = uncore_pci_box_ctl(box);
-       u32 config = 0;
-
-       if (!pci_read_config_dword(pdev, box_ctl, &config)) {
-               config &= ~SNBEP_PMON_BOX_CTL_FRZ;
-               pci_write_config_dword(pdev, box_ctl, config);
-       }
-}
-
-static void snbep_uncore_pci_enable_event(struct intel_uncore_box *box, struct perf_event *event)
-{
-       struct pci_dev *pdev = box->pci_dev;
-       struct hw_perf_event *hwc = &event->hw;
-
-       pci_write_config_dword(pdev, hwc->config_base, hwc->config | SNBEP_PMON_CTL_EN);
-}
-
-static void snbep_uncore_pci_disable_event(struct intel_uncore_box *box, struct perf_event *event)
-{
-       struct pci_dev *pdev = box->pci_dev;
-       struct hw_perf_event *hwc = &event->hw;
-
-       pci_write_config_dword(pdev, hwc->config_base, hwc->config);
-}
-
-static u64 snbep_uncore_pci_read_counter(struct intel_uncore_box *box, struct perf_event *event)
-{
-       struct pci_dev *pdev = box->pci_dev;
-       struct hw_perf_event *hwc = &event->hw;
-       u64 count = 0;
-
-       pci_read_config_dword(pdev, hwc->event_base, (u32 *)&count);
-       pci_read_config_dword(pdev, hwc->event_base + 4, (u32 *)&count + 1);
-
-       return count;
-}
-
-static void snbep_uncore_pci_init_box(struct intel_uncore_box *box)
-{
-       struct pci_dev *pdev = box->pci_dev;
-
-       pci_write_config_dword(pdev, SNBEP_PCI_PMON_BOX_CTL, SNBEP_PMON_BOX_CTL_INT);
-}
-
-static void snbep_uncore_msr_disable_box(struct intel_uncore_box *box)
-{
-       u64 config;
-       unsigned msr;
-
-       msr = uncore_msr_box_ctl(box);
-       if (msr) {
-               rdmsrl(msr, config);
-               config |= SNBEP_PMON_BOX_CTL_FRZ;
-               wrmsrl(msr, config);
-       }
-}
-
-static void snbep_uncore_msr_enable_box(struct intel_uncore_box *box)
-{
-       u64 config;
-       unsigned msr;
-
-       msr = uncore_msr_box_ctl(box);
-       if (msr) {
-               rdmsrl(msr, config);
-               config &= ~SNBEP_PMON_BOX_CTL_FRZ;
-               wrmsrl(msr, config);
-       }
-}
-
-static void snbep_uncore_msr_enable_event(struct intel_uncore_box *box, struct perf_event *event)
-{
-       struct hw_perf_event *hwc = &event->hw;
-       struct hw_perf_event_extra *reg1 = &hwc->extra_reg;
-
-       if (reg1->idx != EXTRA_REG_NONE)
-               wrmsrl(reg1->reg, uncore_shared_reg_config(box, 0));
-
-       wrmsrl(hwc->config_base, hwc->config | SNBEP_PMON_CTL_EN);
-}
-
-static void snbep_uncore_msr_disable_event(struct intel_uncore_box *box,
-                                       struct perf_event *event)
-{
-       struct hw_perf_event *hwc = &event->hw;
-
-       wrmsrl(hwc->config_base, hwc->config);
-}
-
-static void snbep_uncore_msr_init_box(struct intel_uncore_box *box)
-{
-       unsigned msr = uncore_msr_box_ctl(box);
-
-       if (msr)
-               wrmsrl(msr, SNBEP_PMON_BOX_CTL_INT);
-}
-
-static struct attribute *snbep_uncore_formats_attr[] = {
-       &format_attr_event.attr,
-       &format_attr_umask.attr,
-       &format_attr_edge.attr,
-       &format_attr_inv.attr,
-       &format_attr_thresh8.attr,
-       NULL,
-};
-
-static struct attribute *snbep_uncore_ubox_formats_attr[] = {
-       &format_attr_event.attr,
-       &format_attr_umask.attr,
-       &format_attr_edge.attr,
-       &format_attr_inv.attr,
-       &format_attr_thresh5.attr,
-       NULL,
-};
-
-static struct attribute *snbep_uncore_cbox_formats_attr[] = {
-       &format_attr_event.attr,
-       &format_attr_umask.attr,
-       &format_attr_edge.attr,
-       &format_attr_tid_en.attr,
-       &format_attr_inv.attr,
-       &format_attr_thresh8.attr,
-       &format_attr_filter_tid.attr,
-       &format_attr_filter_nid.attr,
-       &format_attr_filter_state.attr,
-       &format_attr_filter_opc.attr,
-       NULL,
-};
-
-static struct attribute *snbep_uncore_pcu_formats_attr[] = {
-       &format_attr_event_ext.attr,
-       &format_attr_occ_sel.attr,
-       &format_attr_edge.attr,
-       &format_attr_inv.attr,
-       &format_attr_thresh5.attr,
-       &format_attr_occ_invert.attr,
-       &format_attr_occ_edge.attr,
-       &format_attr_filter_band0.attr,
-       &format_attr_filter_band1.attr,
-       &format_attr_filter_band2.attr,
-       &format_attr_filter_band3.attr,
-       NULL,
-};
-
-static struct attribute *snbep_uncore_qpi_formats_attr[] = {
-       &format_attr_event_ext.attr,
-       &format_attr_umask.attr,
-       &format_attr_edge.attr,
-       &format_attr_inv.attr,
-       &format_attr_thresh8.attr,
-       &format_attr_match_rds.attr,
-       &format_attr_match_rnid30.attr,
-       &format_attr_match_rnid4.attr,
-       &format_attr_match_dnid.attr,
-       &format_attr_match_mc.attr,
-       &format_attr_match_opc.attr,
-       &format_attr_match_vnw.attr,
-       &format_attr_match0.attr,
-       &format_attr_match1.attr,
-       &format_attr_mask_rds.attr,
-       &format_attr_mask_rnid30.attr,
-       &format_attr_mask_rnid4.attr,
-       &format_attr_mask_dnid.attr,
-       &format_attr_mask_mc.attr,
-       &format_attr_mask_opc.attr,
-       &format_attr_mask_vnw.attr,
-       &format_attr_mask0.attr,
-       &format_attr_mask1.attr,
-       NULL,
-};
-
-static struct uncore_event_desc snbep_uncore_imc_events[] = {
-       INTEL_UNCORE_EVENT_DESC(clockticks,      "event=0xff,umask=0x00"),
-       INTEL_UNCORE_EVENT_DESC(cas_count_read,  "event=0x04,umask=0x03"),
-       INTEL_UNCORE_EVENT_DESC(cas_count_write, "event=0x04,umask=0x0c"),
-       { /* end: all zeroes */ },
-};
-
-static struct uncore_event_desc snbep_uncore_qpi_events[] = {
-       INTEL_UNCORE_EVENT_DESC(clockticks,       "event=0x14"),
-       INTEL_UNCORE_EVENT_DESC(txl_flits_active, "event=0x00,umask=0x06"),
-       INTEL_UNCORE_EVENT_DESC(drs_data,         "event=0x102,umask=0x08"),
-       INTEL_UNCORE_EVENT_DESC(ncb_data,         "event=0x103,umask=0x04"),
-       { /* end: all zeroes */ },
-};
-
-static struct attribute_group snbep_uncore_format_group = {
-       .name = "format",
-       .attrs = snbep_uncore_formats_attr,
-};
-
-static struct attribute_group snbep_uncore_ubox_format_group = {
-       .name = "format",
-       .attrs = snbep_uncore_ubox_formats_attr,
-};
-
-static struct attribute_group snbep_uncore_cbox_format_group = {
-       .name = "format",
-       .attrs = snbep_uncore_cbox_formats_attr,
-};
-
-static struct attribute_group snbep_uncore_pcu_format_group = {
-       .name = "format",
-       .attrs = snbep_uncore_pcu_formats_attr,
-};
-
-static struct attribute_group snbep_uncore_qpi_format_group = {
-       .name = "format",
-       .attrs = snbep_uncore_qpi_formats_attr,
-};
-
-#define SNBEP_UNCORE_MSR_OPS_COMMON_INIT()                     \
-       .init_box       = snbep_uncore_msr_init_box,            \
-       .disable_box    = snbep_uncore_msr_disable_box,         \
-       .enable_box     = snbep_uncore_msr_enable_box,          \
-       .disable_event  = snbep_uncore_msr_disable_event,       \
-       .enable_event   = snbep_uncore_msr_enable_event,        \
-       .read_counter   = uncore_msr_read_counter
-
-static struct intel_uncore_ops snbep_uncore_msr_ops = {
-       SNBEP_UNCORE_MSR_OPS_COMMON_INIT(),
-};
-
-#define SNBEP_UNCORE_PCI_OPS_COMMON_INIT()                     \
-       .init_box       = snbep_uncore_pci_init_box,            \
-       .disable_box    = snbep_uncore_pci_disable_box,         \
-       .enable_box     = snbep_uncore_pci_enable_box,          \
-       .disable_event  = snbep_uncore_pci_disable_event,       \
-       .read_counter   = snbep_uncore_pci_read_counter
-
-static struct intel_uncore_ops snbep_uncore_pci_ops = {
-       SNBEP_UNCORE_PCI_OPS_COMMON_INIT(),
-       .enable_event   = snbep_uncore_pci_enable_event,        \
-};
-
-static struct event_constraint snbep_uncore_cbox_constraints[] = {
-       UNCORE_EVENT_CONSTRAINT(0x01, 0x1),
-       UNCORE_EVENT_CONSTRAINT(0x02, 0x3),
-       UNCORE_EVENT_CONSTRAINT(0x04, 0x3),
-       UNCORE_EVENT_CONSTRAINT(0x05, 0x3),
-       UNCORE_EVENT_CONSTRAINT(0x07, 0x3),
-       UNCORE_EVENT_CONSTRAINT(0x09, 0x3),
-       UNCORE_EVENT_CONSTRAINT(0x11, 0x1),
-       UNCORE_EVENT_CONSTRAINT(0x12, 0x3),
-       UNCORE_EVENT_CONSTRAINT(0x13, 0x3),
-       UNCORE_EVENT_CONSTRAINT(0x1b, 0xc),
-       UNCORE_EVENT_CONSTRAINT(0x1c, 0xc),
-       UNCORE_EVENT_CONSTRAINT(0x1d, 0xc),
-       UNCORE_EVENT_CONSTRAINT(0x1e, 0xc),
-       EVENT_CONSTRAINT_OVERLAP(0x1f, 0xe, 0xff),
-       UNCORE_EVENT_CONSTRAINT(0x21, 0x3),
-       UNCORE_EVENT_CONSTRAINT(0x23, 0x3),
-       UNCORE_EVENT_CONSTRAINT(0x31, 0x3),
-       UNCORE_EVENT_CONSTRAINT(0x32, 0x3),
-       UNCORE_EVENT_CONSTRAINT(0x33, 0x3),
-       UNCORE_EVENT_CONSTRAINT(0x34, 0x3),
-       UNCORE_EVENT_CONSTRAINT(0x35, 0x3),
-       UNCORE_EVENT_CONSTRAINT(0x36, 0x1),
-       UNCORE_EVENT_CONSTRAINT(0x37, 0x3),
-       UNCORE_EVENT_CONSTRAINT(0x38, 0x3),
-       UNCORE_EVENT_CONSTRAINT(0x39, 0x3),
-       UNCORE_EVENT_CONSTRAINT(0x3b, 0x1),
-       EVENT_CONSTRAINT_END
-};
-
-static struct event_constraint snbep_uncore_r2pcie_constraints[] = {
-       UNCORE_EVENT_CONSTRAINT(0x10, 0x3),
-       UNCORE_EVENT_CONSTRAINT(0x11, 0x3),
-       UNCORE_EVENT_CONSTRAINT(0x12, 0x1),
-       UNCORE_EVENT_CONSTRAINT(0x23, 0x3),
-       UNCORE_EVENT_CONSTRAINT(0x24, 0x3),
-       UNCORE_EVENT_CONSTRAINT(0x25, 0x3),
-       UNCORE_EVENT_CONSTRAINT(0x26, 0x3),
-       UNCORE_EVENT_CONSTRAINT(0x32, 0x3),
-       UNCORE_EVENT_CONSTRAINT(0x33, 0x3),
-       UNCORE_EVENT_CONSTRAINT(0x34, 0x3),
-       EVENT_CONSTRAINT_END
-};
-
-static struct event_constraint snbep_uncore_r3qpi_constraints[] = {
-       UNCORE_EVENT_CONSTRAINT(0x10, 0x3),
-       UNCORE_EVENT_CONSTRAINT(0x11, 0x3),
-       UNCORE_EVENT_CONSTRAINT(0x12, 0x3),
-       UNCORE_EVENT_CONSTRAINT(0x13, 0x1),
-       UNCORE_EVENT_CONSTRAINT(0x20, 0x3),
-       UNCORE_EVENT_CONSTRAINT(0x21, 0x3),
-       UNCORE_EVENT_CONSTRAINT(0x22, 0x3),
-       UNCORE_EVENT_CONSTRAINT(0x23, 0x3),
-       UNCORE_EVENT_CONSTRAINT(0x24, 0x3),
-       UNCORE_EVENT_CONSTRAINT(0x25, 0x3),
-       UNCORE_EVENT_CONSTRAINT(0x26, 0x3),
-       UNCORE_EVENT_CONSTRAINT(0x28, 0x3),
-       UNCORE_EVENT_CONSTRAINT(0x29, 0x3),
-       UNCORE_EVENT_CONSTRAINT(0x2a, 0x3),
-       UNCORE_EVENT_CONSTRAINT(0x2b, 0x3),
-       UNCORE_EVENT_CONSTRAINT(0x2c, 0x3),
-       UNCORE_EVENT_CONSTRAINT(0x2d, 0x3),
-       UNCORE_EVENT_CONSTRAINT(0x2e, 0x3),
-       UNCORE_EVENT_CONSTRAINT(0x2f, 0x3),
-       UNCORE_EVENT_CONSTRAINT(0x30, 0x3),
-       UNCORE_EVENT_CONSTRAINT(0x31, 0x3),
-       UNCORE_EVENT_CONSTRAINT(0x32, 0x3),
-       UNCORE_EVENT_CONSTRAINT(0x33, 0x3),
-       UNCORE_EVENT_CONSTRAINT(0x34, 0x3),
-       UNCORE_EVENT_CONSTRAINT(0x36, 0x3),
-       UNCORE_EVENT_CONSTRAINT(0x37, 0x3),
-       UNCORE_EVENT_CONSTRAINT(0x38, 0x3),
-       UNCORE_EVENT_CONSTRAINT(0x39, 0x3),
-       EVENT_CONSTRAINT_END
-};
-
-static struct intel_uncore_type snbep_uncore_ubox = {
-       .name           = "ubox",
-       .num_counters   = 2,
-       .num_boxes      = 1,
-       .perf_ctr_bits  = 44,
-       .fixed_ctr_bits = 48,
-       .perf_ctr       = SNBEP_U_MSR_PMON_CTR0,
-       .event_ctl      = SNBEP_U_MSR_PMON_CTL0,
-       .event_mask     = SNBEP_U_MSR_PMON_RAW_EVENT_MASK,
-       .fixed_ctr      = SNBEP_U_MSR_PMON_UCLK_FIXED_CTR,
-       .fixed_ctl      = SNBEP_U_MSR_PMON_UCLK_FIXED_CTL,
-       .ops            = &snbep_uncore_msr_ops,
-       .format_group   = &snbep_uncore_ubox_format_group,
-};
-
-static struct extra_reg snbep_uncore_cbox_extra_regs[] = {
-       SNBEP_CBO_EVENT_EXTRA_REG(SNBEP_CBO_PMON_CTL_TID_EN,
-                                 SNBEP_CBO_PMON_CTL_TID_EN, 0x1),
-       SNBEP_CBO_EVENT_EXTRA_REG(0x0334, 0xffff, 0x4),
-       SNBEP_CBO_EVENT_EXTRA_REG(0x4334, 0xffff, 0x6),
-       SNBEP_CBO_EVENT_EXTRA_REG(0x0534, 0xffff, 0x4),
-       SNBEP_CBO_EVENT_EXTRA_REG(0x4534, 0xffff, 0x6),
-       SNBEP_CBO_EVENT_EXTRA_REG(0x0934, 0xffff, 0x4),
-       SNBEP_CBO_EVENT_EXTRA_REG(0x4934, 0xffff, 0x6),
-       SNBEP_CBO_EVENT_EXTRA_REG(0x4134, 0xffff, 0x6),
-       SNBEP_CBO_EVENT_EXTRA_REG(0x0135, 0xffff, 0x8),
-       SNBEP_CBO_EVENT_EXTRA_REG(0x0335, 0xffff, 0x8),
-       SNBEP_CBO_EVENT_EXTRA_REG(0x4135, 0xffff, 0xa),
-       SNBEP_CBO_EVENT_EXTRA_REG(0x4335, 0xffff, 0xa),
-       SNBEP_CBO_EVENT_EXTRA_REG(0x4435, 0xffff, 0x2),
-       SNBEP_CBO_EVENT_EXTRA_REG(0x4835, 0xffff, 0x2),
-       SNBEP_CBO_EVENT_EXTRA_REG(0x4a35, 0xffff, 0x2),
-       SNBEP_CBO_EVENT_EXTRA_REG(0x5035, 0xffff, 0x2),
-       SNBEP_CBO_EVENT_EXTRA_REG(0x0136, 0xffff, 0x8),
-       SNBEP_CBO_EVENT_EXTRA_REG(0x0336, 0xffff, 0x8),
-       SNBEP_CBO_EVENT_EXTRA_REG(0x4136, 0xffff, 0xa),
-       SNBEP_CBO_EVENT_EXTRA_REG(0x4336, 0xffff, 0xa),
-       SNBEP_CBO_EVENT_EXTRA_REG(0x4436, 0xffff, 0x2),
-       SNBEP_CBO_EVENT_EXTRA_REG(0x4836, 0xffff, 0x2),
-       SNBEP_CBO_EVENT_EXTRA_REG(0x4a36, 0xffff, 0x2),
-       SNBEP_CBO_EVENT_EXTRA_REG(0x4037, 0x40ff, 0x2),
-       EVENT_EXTRA_END
-};
-
-static void snbep_cbox_put_constraint(struct intel_uncore_box *box, struct perf_event *event)
-{
-       struct hw_perf_event_extra *reg1 = &event->hw.extra_reg;
-       struct intel_uncore_extra_reg *er = &box->shared_regs[0];
-       int i;
-
-       if (uncore_box_is_fake(box))
-               return;
-
-       for (i = 0; i < 5; i++) {
-               if (reg1->alloc & (0x1 << i))
-                       atomic_sub(1 << (i * 6), &er->ref);
-       }
-       reg1->alloc = 0;
-}
-
-static struct event_constraint *
-__snbep_cbox_get_constraint(struct intel_uncore_box *box, struct perf_event *event,
-                           u64 (*cbox_filter_mask)(int fields))
-{
-       struct hw_perf_event_extra *reg1 = &event->hw.extra_reg;
-       struct intel_uncore_extra_reg *er = &box->shared_regs[0];
-       int i, alloc = 0;
-       unsigned long flags;
-       u64 mask;
-
-       if (reg1->idx == EXTRA_REG_NONE)
-               return NULL;
-
-       raw_spin_lock_irqsave(&er->lock, flags);
-       for (i = 0; i < 5; i++) {
-               if (!(reg1->idx & (0x1 << i)))
-                       continue;
-               if (!uncore_box_is_fake(box) && (reg1->alloc & (0x1 << i)))
-                       continue;
-
-               mask = cbox_filter_mask(0x1 << i);
-               if (!__BITS_VALUE(atomic_read(&er->ref), i, 6) ||
-                   !((reg1->config ^ er->config) & mask)) {
-                       atomic_add(1 << (i * 6), &er->ref);
-                       er->config &= ~mask;
-                       er->config |= reg1->config & mask;
-                       alloc |= (0x1 << i);
-               } else {
-                       break;
-               }
-       }
-       raw_spin_unlock_irqrestore(&er->lock, flags);
-       if (i < 5)
-               goto fail;
-
-       if (!uncore_box_is_fake(box))
-               reg1->alloc |= alloc;
-
-       return NULL;
-fail:
-       for (; i >= 0; i--) {
-               if (alloc & (0x1 << i))
-                       atomic_sub(1 << (i * 6), &er->ref);
-       }
-       return &constraint_empty;
-}
-
-static u64 snbep_cbox_filter_mask(int fields)
-{
-       u64 mask = 0;
-
-       if (fields & 0x1)
-               mask |= SNBEP_CB0_MSR_PMON_BOX_FILTER_TID;
-       if (fields & 0x2)
-               mask |= SNBEP_CB0_MSR_PMON_BOX_FILTER_NID;
-       if (fields & 0x4)
-               mask |= SNBEP_CB0_MSR_PMON_BOX_FILTER_STATE;
-       if (fields & 0x8)
-               mask |= SNBEP_CB0_MSR_PMON_BOX_FILTER_OPC;
-
-       return mask;
-}
-
-static struct event_constraint *
-snbep_cbox_get_constraint(struct intel_uncore_box *box, struct perf_event *event)
-{
-       return __snbep_cbox_get_constraint(box, event, snbep_cbox_filter_mask);
-}
-
-static int snbep_cbox_hw_config(struct intel_uncore_box *box, struct perf_event *event)
-{
-       struct hw_perf_event_extra *reg1 = &event->hw.extra_reg;
-       struct extra_reg *er;
-       int idx = 0;
-
-       for (er = snbep_uncore_cbox_extra_regs; er->msr; er++) {
-               if (er->event != (event->hw.config & er->config_mask))
-                       continue;
-               idx |= er->idx;
-       }
-
-       if (idx) {
-               reg1->reg = SNBEP_C0_MSR_PMON_BOX_FILTER +
-                       SNBEP_CBO_MSR_OFFSET * box->pmu->pmu_idx;
-               reg1->config = event->attr.config1 & snbep_cbox_filter_mask(idx);
-               reg1->idx = idx;
-       }
-       return 0;
-}
-
-static struct intel_uncore_ops snbep_uncore_cbox_ops = {
-       SNBEP_UNCORE_MSR_OPS_COMMON_INIT(),
-       .hw_config              = snbep_cbox_hw_config,
-       .get_constraint         = snbep_cbox_get_constraint,
-       .put_constraint         = snbep_cbox_put_constraint,
-};
-
-static struct intel_uncore_type snbep_uncore_cbox = {
-       .name                   = "cbox",
-       .num_counters           = 4,
-       .num_boxes              = 8,
-       .perf_ctr_bits          = 44,
-       .event_ctl              = SNBEP_C0_MSR_PMON_CTL0,
-       .perf_ctr               = SNBEP_C0_MSR_PMON_CTR0,
-       .event_mask             = SNBEP_CBO_MSR_PMON_RAW_EVENT_MASK,
-       .box_ctl                = SNBEP_C0_MSR_PMON_BOX_CTL,
-       .msr_offset             = SNBEP_CBO_MSR_OFFSET,
-       .num_shared_regs        = 1,
-       .constraints            = snbep_uncore_cbox_constraints,
-       .ops                    = &snbep_uncore_cbox_ops,
-       .format_group           = &snbep_uncore_cbox_format_group,
-};
-
-static u64 snbep_pcu_alter_er(struct perf_event *event, int new_idx, bool modify)
-{
-       struct hw_perf_event *hwc = &event->hw;
-       struct hw_perf_event_extra *reg1 = &hwc->extra_reg;
-       u64 config = reg1->config;
-
-       if (new_idx > reg1->idx)
-               config <<= 8 * (new_idx - reg1->idx);
-       else
-               config >>= 8 * (reg1->idx - new_idx);
-
-       if (modify) {
-               hwc->config += new_idx - reg1->idx;
-               reg1->config = config;
-               reg1->idx = new_idx;
-       }
-       return config;
-}
-
-static struct event_constraint *
-snbep_pcu_get_constraint(struct intel_uncore_box *box, struct perf_event *event)
-{
-       struct hw_perf_event_extra *reg1 = &event->hw.extra_reg;
-       struct intel_uncore_extra_reg *er = &box->shared_regs[0];
-       unsigned long flags;
-       int idx = reg1->idx;
-       u64 mask, config1 = reg1->config;
-       bool ok = false;
-
-       if (reg1->idx == EXTRA_REG_NONE ||
-           (!uncore_box_is_fake(box) && reg1->alloc))
-               return NULL;
-again:
-       mask = 0xffULL << (idx * 8);
-       raw_spin_lock_irqsave(&er->lock, flags);
-       if (!__BITS_VALUE(atomic_read(&er->ref), idx, 8) ||
-           !((config1 ^ er->config) & mask)) {
-               atomic_add(1 << (idx * 8), &er->ref);
-               er->config &= ~mask;
-               er->config |= config1 & mask;
-               ok = true;
-       }
-       raw_spin_unlock_irqrestore(&er->lock, flags);
-
-       if (!ok) {
-               idx = (idx + 1) % 4;
-               if (idx != reg1->idx) {
-                       config1 = snbep_pcu_alter_er(event, idx, false);
-                       goto again;
-               }
-               return &constraint_empty;
-       }
-
-       if (!uncore_box_is_fake(box)) {
-               if (idx != reg1->idx)
-                       snbep_pcu_alter_er(event, idx, true);
-               reg1->alloc = 1;
-       }
-       return NULL;
-}
-
-static void snbep_pcu_put_constraint(struct intel_uncore_box *box, struct perf_event *event)
-{
-       struct hw_perf_event_extra *reg1 = &event->hw.extra_reg;
-       struct intel_uncore_extra_reg *er = &box->shared_regs[0];
-
-       if (uncore_box_is_fake(box) || !reg1->alloc)
-               return;
-
-       atomic_sub(1 << (reg1->idx * 8), &er->ref);
-       reg1->alloc = 0;
-}
-
-static int snbep_pcu_hw_config(struct intel_uncore_box *box, struct perf_event *event)
-{
-       struct hw_perf_event *hwc = &event->hw;
-       struct hw_perf_event_extra *reg1 = &hwc->extra_reg;
-       int ev_sel = hwc->config & SNBEP_PMON_CTL_EV_SEL_MASK;
-
-       if (ev_sel >= 0xb && ev_sel <= 0xe) {
-               reg1->reg = SNBEP_PCU_MSR_PMON_BOX_FILTER;
-               reg1->idx = ev_sel - 0xb;
-               reg1->config = event->attr.config1 & (0xff << reg1->idx);
-       }
-       return 0;
-}
-
-static struct intel_uncore_ops snbep_uncore_pcu_ops = {
-       SNBEP_UNCORE_MSR_OPS_COMMON_INIT(),
-       .hw_config              = snbep_pcu_hw_config,
-       .get_constraint         = snbep_pcu_get_constraint,
-       .put_constraint         = snbep_pcu_put_constraint,
-};
-
-static struct intel_uncore_type snbep_uncore_pcu = {
-       .name                   = "pcu",
-       .num_counters           = 4,
-       .num_boxes              = 1,
-       .perf_ctr_bits          = 48,
-       .perf_ctr               = SNBEP_PCU_MSR_PMON_CTR0,
-       .event_ctl              = SNBEP_PCU_MSR_PMON_CTL0,
-       .event_mask             = SNBEP_PCU_MSR_PMON_RAW_EVENT_MASK,
-       .box_ctl                = SNBEP_PCU_MSR_PMON_BOX_CTL,
-       .num_shared_regs        = 1,
-       .ops                    = &snbep_uncore_pcu_ops,
-       .format_group           = &snbep_uncore_pcu_format_group,
-};
-
-static struct intel_uncore_type *snbep_msr_uncores[] = {
-       &snbep_uncore_ubox,
-       &snbep_uncore_cbox,
-       &snbep_uncore_pcu,
-       NULL,
-};
-
-enum {
-       SNBEP_PCI_QPI_PORT0_FILTER,
-       SNBEP_PCI_QPI_PORT1_FILTER,
-};
-
-static int snbep_qpi_hw_config(struct intel_uncore_box *box, struct perf_event *event)
-{
-       struct hw_perf_event *hwc = &event->hw;
-       struct hw_perf_event_extra *reg1 = &hwc->extra_reg;
-       struct hw_perf_event_extra *reg2 = &hwc->branch_reg;
-
-       if ((hwc->config & SNBEP_PMON_CTL_EV_SEL_MASK) == 0x38) {
-               reg1->idx = 0;
-               reg1->reg = SNBEP_Q_Py_PCI_PMON_PKT_MATCH0;
-               reg1->config = event->attr.config1;
-               reg2->reg = SNBEP_Q_Py_PCI_PMON_PKT_MASK0;
-               reg2->config = event->attr.config2;
-       }
-       return 0;
-}
-
-static void snbep_qpi_enable_event(struct intel_uncore_box *box, struct perf_event *event)
-{
-       struct pci_dev *pdev = box->pci_dev;
-       struct hw_perf_event *hwc = &event->hw;
-       struct hw_perf_event_extra *reg1 = &hwc->extra_reg;
-       struct hw_perf_event_extra *reg2 = &hwc->branch_reg;
-
-       if (reg1->idx != EXTRA_REG_NONE) {
-               int idx = box->pmu->pmu_idx + SNBEP_PCI_QPI_PORT0_FILTER;
-               struct pci_dev *filter_pdev = extra_pci_dev[box->phys_id][idx];
-               WARN_ON_ONCE(!filter_pdev);
-               if (filter_pdev) {
-                       pci_write_config_dword(filter_pdev, reg1->reg,
-                                               (u32)reg1->config);
-                       pci_write_config_dword(filter_pdev, reg1->reg + 4,
-                                               (u32)(reg1->config >> 32));
-                       pci_write_config_dword(filter_pdev, reg2->reg,
-                                               (u32)reg2->config);
-                       pci_write_config_dword(filter_pdev, reg2->reg + 4,
-                                               (u32)(reg2->config >> 32));
-               }
-       }
-
-       pci_write_config_dword(pdev, hwc->config_base, hwc->config | SNBEP_PMON_CTL_EN);
-}
-
-static struct intel_uncore_ops snbep_uncore_qpi_ops = {
-       SNBEP_UNCORE_PCI_OPS_COMMON_INIT(),
-       .enable_event           = snbep_qpi_enable_event,
-       .hw_config              = snbep_qpi_hw_config,
-       .get_constraint         = uncore_get_constraint,
-       .put_constraint         = uncore_put_constraint,
-};
-
-#define SNBEP_UNCORE_PCI_COMMON_INIT()                         \
-       .perf_ctr       = SNBEP_PCI_PMON_CTR0,                  \
-       .event_ctl      = SNBEP_PCI_PMON_CTL0,                  \
-       .event_mask     = SNBEP_PMON_RAW_EVENT_MASK,            \
-       .box_ctl        = SNBEP_PCI_PMON_BOX_CTL,               \
-       .ops            = &snbep_uncore_pci_ops,                \
-       .format_group   = &snbep_uncore_format_group
-
-static struct intel_uncore_type snbep_uncore_ha = {
-       .name           = "ha",
-       .num_counters   = 4,
-       .num_boxes      = 1,
-       .perf_ctr_bits  = 48,
-       SNBEP_UNCORE_PCI_COMMON_INIT(),
-};
-
-static struct intel_uncore_type snbep_uncore_imc = {
-       .name           = "imc",
-       .num_counters   = 4,
-       .num_boxes      = 4,
-       .perf_ctr_bits  = 48,
-       .fixed_ctr_bits = 48,
-       .fixed_ctr      = SNBEP_MC_CHy_PCI_PMON_FIXED_CTR,
-       .fixed_ctl      = SNBEP_MC_CHy_PCI_PMON_FIXED_CTL,
-       .event_descs    = snbep_uncore_imc_events,
-       SNBEP_UNCORE_PCI_COMMON_INIT(),
-};
-
-static struct intel_uncore_type snbep_uncore_qpi = {
-       .name                   = "qpi",
-       .num_counters           = 4,
-       .num_boxes              = 2,
-       .perf_ctr_bits          = 48,
-       .perf_ctr               = SNBEP_PCI_PMON_CTR0,
-       .event_ctl              = SNBEP_PCI_PMON_CTL0,
-       .event_mask             = SNBEP_QPI_PCI_PMON_RAW_EVENT_MASK,
-       .box_ctl                = SNBEP_PCI_PMON_BOX_CTL,
-       .num_shared_regs        = 1,
-       .ops                    = &snbep_uncore_qpi_ops,
-       .event_descs            = snbep_uncore_qpi_events,
-       .format_group           = &snbep_uncore_qpi_format_group,
-};
-
-
-static struct intel_uncore_type snbep_uncore_r2pcie = {
-       .name           = "r2pcie",
-       .num_counters   = 4,
-       .num_boxes      = 1,
-       .perf_ctr_bits  = 44,
-       .constraints    = snbep_uncore_r2pcie_constraints,
-       SNBEP_UNCORE_PCI_COMMON_INIT(),
-};
-
-static struct intel_uncore_type snbep_uncore_r3qpi = {
-       .name           = "r3qpi",
-       .num_counters   = 3,
-       .num_boxes      = 2,
-       .perf_ctr_bits  = 44,
-       .constraints    = snbep_uncore_r3qpi_constraints,
-       SNBEP_UNCORE_PCI_COMMON_INIT(),
-};
-
-enum {
-       SNBEP_PCI_UNCORE_HA,
-       SNBEP_PCI_UNCORE_IMC,
-       SNBEP_PCI_UNCORE_QPI,
-       SNBEP_PCI_UNCORE_R2PCIE,
-       SNBEP_PCI_UNCORE_R3QPI,
-};
-
-static struct intel_uncore_type *snbep_pci_uncores[] = {
-       [SNBEP_PCI_UNCORE_HA]           = &snbep_uncore_ha,
-       [SNBEP_PCI_UNCORE_IMC]          = &snbep_uncore_imc,
-       [SNBEP_PCI_UNCORE_QPI]          = &snbep_uncore_qpi,
-       [SNBEP_PCI_UNCORE_R2PCIE]       = &snbep_uncore_r2pcie,
-       [SNBEP_PCI_UNCORE_R3QPI]        = &snbep_uncore_r3qpi,
-       NULL,
-};
-
-static const struct pci_device_id snbep_uncore_pci_ids[] = {
-       { /* Home Agent */
-               PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_HA),
-               .driver_data = UNCORE_PCI_DEV_DATA(SNBEP_PCI_UNCORE_HA, 0),
-       },
-       { /* MC Channel 0 */
-               PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_IMC0),
-               .driver_data = UNCORE_PCI_DEV_DATA(SNBEP_PCI_UNCORE_IMC, 0),
-       },
-       { /* MC Channel 1 */
-               PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_IMC1),
-               .driver_data = UNCORE_PCI_DEV_DATA(SNBEP_PCI_UNCORE_IMC, 1),
-       },
-       { /* MC Channel 2 */
-               PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_IMC2),
-               .driver_data = UNCORE_PCI_DEV_DATA(SNBEP_PCI_UNCORE_IMC, 2),
-       },
-       { /* MC Channel 3 */
-               PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_IMC3),
-               .driver_data = UNCORE_PCI_DEV_DATA(SNBEP_PCI_UNCORE_IMC, 3),
-       },
-       { /* QPI Port 0 */
-               PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_QPI0),
-               .driver_data = UNCORE_PCI_DEV_DATA(SNBEP_PCI_UNCORE_QPI, 0),
-       },
-       { /* QPI Port 1 */
-               PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_QPI1),
-               .driver_data = UNCORE_PCI_DEV_DATA(SNBEP_PCI_UNCORE_QPI, 1),
-       },
-       { /* R2PCIe */
-               PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_R2PCIE),
-               .driver_data = UNCORE_PCI_DEV_DATA(SNBEP_PCI_UNCORE_R2PCIE, 0),
-       },
-       { /* R3QPI Link 0 */
-               PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_R3QPI0),
-               .driver_data = UNCORE_PCI_DEV_DATA(SNBEP_PCI_UNCORE_R3QPI, 0),
-       },
-       { /* R3QPI Link 1 */
-               PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_R3QPI1),
-               .driver_data = UNCORE_PCI_DEV_DATA(SNBEP_PCI_UNCORE_R3QPI, 1),
-       },
-       { /* QPI Port 0 filter  */
-               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x3c86),
-               .driver_data = UNCORE_PCI_DEV_DATA(UNCORE_EXTRA_PCI_DEV,
-                                                  SNBEP_PCI_QPI_PORT0_FILTER),
-       },
-       { /* QPI Port 0 filter  */
-               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x3c96),
-               .driver_data = UNCORE_PCI_DEV_DATA(UNCORE_EXTRA_PCI_DEV,
-                                                  SNBEP_PCI_QPI_PORT1_FILTER),
-       },
-       { /* end: all zeroes */ }
-};
-
-static struct pci_driver snbep_uncore_pci_driver = {
-       .name           = "snbep_uncore",
-       .id_table       = snbep_uncore_pci_ids,
-};
-
-/*
- * build pci bus to socket mapping
- */
-static int snbep_pci2phy_map_init(int devid)
-{
-       struct pci_dev *ubox_dev = NULL;
-       int i, bus, nodeid;
-       int err = 0;
-       u32 config = 0;
-
-       while (1) {
-               /* find the UBOX device */
-               ubox_dev = pci_get_device(PCI_VENDOR_ID_INTEL, devid, ubox_dev);
-               if (!ubox_dev)
-                       break;
-               bus = ubox_dev->bus->number;
-               /* get the Node ID of the local register */
-               err = pci_read_config_dword(ubox_dev, 0x40, &config);
-               if (err)
-                       break;
-               nodeid = config;
-               /* get the Node ID mapping */
-               err = pci_read_config_dword(ubox_dev, 0x54, &config);
-               if (err)
-                       break;
-               /*
-                * every three bits in the Node ID mapping register maps
-                * to a particular node.
-                */
-               for (i = 0; i < 8; i++) {
-                       if (nodeid == ((config >> (3 * i)) & 0x7)) {
-                               pcibus_to_physid[bus] = i;
-                               break;
-                       }
-               }
-       }
-
-       if (!err) {
-               /*
-                * For PCI bus with no UBOX device, find the next bus
-                * that has UBOX device and use its mapping.
-                */
-               i = -1;
-               for (bus = 255; bus >= 0; bus--) {
-                       if (pcibus_to_physid[bus] >= 0)
-                               i = pcibus_to_physid[bus];
-                       else
-                               pcibus_to_physid[bus] = i;
-               }
-       }
-
-       if (ubox_dev)
-               pci_dev_put(ubox_dev);
-
-       return err ? pcibios_err_to_errno(err) : 0;
-}
-/* end of Sandy Bridge-EP uncore support */
-
-/* IvyTown uncore support */
-static void ivt_uncore_msr_init_box(struct intel_uncore_box *box)
-{
-       unsigned msr = uncore_msr_box_ctl(box);
-       if (msr)
-               wrmsrl(msr, IVT_PMON_BOX_CTL_INT);
-}
-
-static void ivt_uncore_pci_init_box(struct intel_uncore_box *box)
-{
-       struct pci_dev *pdev = box->pci_dev;
-
-       pci_write_config_dword(pdev, SNBEP_PCI_PMON_BOX_CTL, IVT_PMON_BOX_CTL_INT);
-}
-
-#define IVT_UNCORE_MSR_OPS_COMMON_INIT()                       \
-       .init_box       = ivt_uncore_msr_init_box,              \
-       .disable_box    = snbep_uncore_msr_disable_box,         \
-       .enable_box     = snbep_uncore_msr_enable_box,          \
-       .disable_event  = snbep_uncore_msr_disable_event,       \
-       .enable_event   = snbep_uncore_msr_enable_event,        \
-       .read_counter   = uncore_msr_read_counter
-
-static struct intel_uncore_ops ivt_uncore_msr_ops = {
-       IVT_UNCORE_MSR_OPS_COMMON_INIT(),
-};
-
-static struct intel_uncore_ops ivt_uncore_pci_ops = {
-       .init_box       = ivt_uncore_pci_init_box,
-       .disable_box    = snbep_uncore_pci_disable_box,
-       .enable_box     = snbep_uncore_pci_enable_box,
-       .disable_event  = snbep_uncore_pci_disable_event,
-       .enable_event   = snbep_uncore_pci_enable_event,
-       .read_counter   = snbep_uncore_pci_read_counter,
-};
-
-#define IVT_UNCORE_PCI_COMMON_INIT()                           \
-       .perf_ctr       = SNBEP_PCI_PMON_CTR0,                  \
-       .event_ctl      = SNBEP_PCI_PMON_CTL0,                  \
-       .event_mask     = IVT_PMON_RAW_EVENT_MASK,              \
-       .box_ctl        = SNBEP_PCI_PMON_BOX_CTL,               \
-       .ops            = &ivt_uncore_pci_ops,                  \
-       .format_group   = &ivt_uncore_format_group
-
-static struct attribute *ivt_uncore_formats_attr[] = {
-       &format_attr_event.attr,
-       &format_attr_umask.attr,
-       &format_attr_edge.attr,
-       &format_attr_inv.attr,
-       &format_attr_thresh8.attr,
-       NULL,
-};
-
-static struct attribute *ivt_uncore_ubox_formats_attr[] = {
-       &format_attr_event.attr,
-       &format_attr_umask.attr,
-       &format_attr_edge.attr,
-       &format_attr_inv.attr,
-       &format_attr_thresh5.attr,
-       NULL,
-};
-
-static struct attribute *ivt_uncore_cbox_formats_attr[] = {
-       &format_attr_event.attr,
-       &format_attr_umask.attr,
-       &format_attr_edge.attr,
-       &format_attr_tid_en.attr,
-       &format_attr_thresh8.attr,
-       &format_attr_filter_tid.attr,
-       &format_attr_filter_link.attr,
-       &format_attr_filter_state2.attr,
-       &format_attr_filter_nid2.attr,
-       &format_attr_filter_opc2.attr,
-       NULL,
-};
-
-static struct attribute *ivt_uncore_pcu_formats_attr[] = {
-       &format_attr_event_ext.attr,
-       &format_attr_occ_sel.attr,
-       &format_attr_edge.attr,
-       &format_attr_thresh5.attr,
-       &format_attr_occ_invert.attr,
-       &format_attr_occ_edge.attr,
-       &format_attr_filter_band0.attr,
-       &format_attr_filter_band1.attr,
-       &format_attr_filter_band2.attr,
-       &format_attr_filter_band3.attr,
-       NULL,
-};
-
-static struct attribute *ivt_uncore_qpi_formats_attr[] = {
-       &format_attr_event_ext.attr,
-       &format_attr_umask.attr,
-       &format_attr_edge.attr,
-       &format_attr_thresh8.attr,
-       &format_attr_match_rds.attr,
-       &format_attr_match_rnid30.attr,
-       &format_attr_match_rnid4.attr,
-       &format_attr_match_dnid.attr,
-       &format_attr_match_mc.attr,
-       &format_attr_match_opc.attr,
-       &format_attr_match_vnw.attr,
-       &format_attr_match0.attr,
-       &format_attr_match1.attr,
-       &format_attr_mask_rds.attr,
-       &format_attr_mask_rnid30.attr,
-       &format_attr_mask_rnid4.attr,
-       &format_attr_mask_dnid.attr,
-       &format_attr_mask_mc.attr,
-       &format_attr_mask_opc.attr,
-       &format_attr_mask_vnw.attr,
-       &format_attr_mask0.attr,
-       &format_attr_mask1.attr,
-       NULL,
-};
-
-static struct attribute_group ivt_uncore_format_group = {
-       .name = "format",
-       .attrs = ivt_uncore_formats_attr,
-};
-
-static struct attribute_group ivt_uncore_ubox_format_group = {
-       .name = "format",
-       .attrs = ivt_uncore_ubox_formats_attr,
-};
-
-static struct attribute_group ivt_uncore_cbox_format_group = {
-       .name = "format",
-       .attrs = ivt_uncore_cbox_formats_attr,
-};
-
-static struct attribute_group ivt_uncore_pcu_format_group = {
-       .name = "format",
-       .attrs = ivt_uncore_pcu_formats_attr,
-};
-
-static struct attribute_group ivt_uncore_qpi_format_group = {
-       .name = "format",
-       .attrs = ivt_uncore_qpi_formats_attr,
-};
-
-static struct intel_uncore_type ivt_uncore_ubox = {
-       .name           = "ubox",
-       .num_counters   = 2,
-       .num_boxes      = 1,
-       .perf_ctr_bits  = 44,
-       .fixed_ctr_bits = 48,
-       .perf_ctr       = SNBEP_U_MSR_PMON_CTR0,
-       .event_ctl      = SNBEP_U_MSR_PMON_CTL0,
-       .event_mask     = IVT_U_MSR_PMON_RAW_EVENT_MASK,
-       .fixed_ctr      = SNBEP_U_MSR_PMON_UCLK_FIXED_CTR,
-       .fixed_ctl      = SNBEP_U_MSR_PMON_UCLK_FIXED_CTL,
-       .ops            = &ivt_uncore_msr_ops,
-       .format_group   = &ivt_uncore_ubox_format_group,
-};
-
-static struct extra_reg ivt_uncore_cbox_extra_regs[] = {
-       SNBEP_CBO_EVENT_EXTRA_REG(SNBEP_CBO_PMON_CTL_TID_EN,
-                                 SNBEP_CBO_PMON_CTL_TID_EN, 0x1),
-       SNBEP_CBO_EVENT_EXTRA_REG(0x1031, 0x10ff, 0x2),
-
-       SNBEP_CBO_EVENT_EXTRA_REG(0x1134, 0xffff, 0x4),
-       SNBEP_CBO_EVENT_EXTRA_REG(0x4134, 0xffff, 0xc),
-       SNBEP_CBO_EVENT_EXTRA_REG(0x5134, 0xffff, 0xc),
-       SNBEP_CBO_EVENT_EXTRA_REG(0x0334, 0xffff, 0x4),
-       SNBEP_CBO_EVENT_EXTRA_REG(0x4334, 0xffff, 0xc),
-       SNBEP_CBO_EVENT_EXTRA_REG(0x0534, 0xffff, 0x4),
-       SNBEP_CBO_EVENT_EXTRA_REG(0x4534, 0xffff, 0xc),
-       SNBEP_CBO_EVENT_EXTRA_REG(0x0934, 0xffff, 0x4),
-       SNBEP_CBO_EVENT_EXTRA_REG(0x4934, 0xffff, 0xc),
-       SNBEP_CBO_EVENT_EXTRA_REG(0x0135, 0xffff, 0x10),
-       SNBEP_CBO_EVENT_EXTRA_REG(0x0335, 0xffff, 0x10),
-       SNBEP_CBO_EVENT_EXTRA_REG(0x2135, 0xffff, 0x10),
-       SNBEP_CBO_EVENT_EXTRA_REG(0x2335, 0xffff, 0x10),
-       SNBEP_CBO_EVENT_EXTRA_REG(0x4135, 0xffff, 0x18),
-       SNBEP_CBO_EVENT_EXTRA_REG(0x4335, 0xffff, 0x18),
-       SNBEP_CBO_EVENT_EXTRA_REG(0x4435, 0xffff, 0x8),
-       SNBEP_CBO_EVENT_EXTRA_REG(0x4835, 0xffff, 0x8),
-       SNBEP_CBO_EVENT_EXTRA_REG(0x4a35, 0xffff, 0x8),
-       SNBEP_CBO_EVENT_EXTRA_REG(0x5035, 0xffff, 0x8),
-       SNBEP_CBO_EVENT_EXTRA_REG(0x8135, 0xffff, 0x10),
-       SNBEP_CBO_EVENT_EXTRA_REG(0x8335, 0xffff, 0x10),
-       SNBEP_CBO_EVENT_EXTRA_REG(0x0136, 0xffff, 0x10),
-       SNBEP_CBO_EVENT_EXTRA_REG(0x0336, 0xffff, 0x10),
-       SNBEP_CBO_EVENT_EXTRA_REG(0x2136, 0xffff, 0x10),
-       SNBEP_CBO_EVENT_EXTRA_REG(0x2336, 0xffff, 0x10),
-       SNBEP_CBO_EVENT_EXTRA_REG(0x4136, 0xffff, 0x18),
-       SNBEP_CBO_EVENT_EXTRA_REG(0x4336, 0xffff, 0x18),
-       SNBEP_CBO_EVENT_EXTRA_REG(0x4436, 0xffff, 0x8),
-       SNBEP_CBO_EVENT_EXTRA_REG(0x4836, 0xffff, 0x8),
-       SNBEP_CBO_EVENT_EXTRA_REG(0x4a36, 0xffff, 0x8),
-       SNBEP_CBO_EVENT_EXTRA_REG(0x5036, 0xffff, 0x8),
-       SNBEP_CBO_EVENT_EXTRA_REG(0x8136, 0xffff, 0x10),
-       SNBEP_CBO_EVENT_EXTRA_REG(0x8336, 0xffff, 0x10),
-       SNBEP_CBO_EVENT_EXTRA_REG(0x4037, 0x40ff, 0x8),
-       EVENT_EXTRA_END
-};
-
-static u64 ivt_cbox_filter_mask(int fields)
-{
-       u64 mask = 0;
-
-       if (fields & 0x1)
-               mask |= IVT_CB0_MSR_PMON_BOX_FILTER_TID;
-       if (fields & 0x2)
-               mask |= IVT_CB0_MSR_PMON_BOX_FILTER_LINK;
-       if (fields & 0x4)
-               mask |= IVT_CB0_MSR_PMON_BOX_FILTER_STATE;
-       if (fields & 0x8)
-               mask |= IVT_CB0_MSR_PMON_BOX_FILTER_NID;
-       if (fields & 0x10)
-               mask |= IVT_CB0_MSR_PMON_BOX_FILTER_OPC;
-
-       return mask;
-}
-
-static struct event_constraint *
-ivt_cbox_get_constraint(struct intel_uncore_box *box, struct perf_event *event)
-{
-       return __snbep_cbox_get_constraint(box, event, ivt_cbox_filter_mask);
-}
-
-static int ivt_cbox_hw_config(struct intel_uncore_box *box, struct perf_event *event)
-{
-       struct hw_perf_event_extra *reg1 = &event->hw.extra_reg;
-       struct extra_reg *er;
-       int idx = 0;
-
-       for (er = ivt_uncore_cbox_extra_regs; er->msr; er++) {
-               if (er->event != (event->hw.config & er->config_mask))
-                       continue;
-               idx |= er->idx;
-       }
-
-       if (idx) {
-               reg1->reg = SNBEP_C0_MSR_PMON_BOX_FILTER +
-                       SNBEP_CBO_MSR_OFFSET * box->pmu->pmu_idx;
-               reg1->config = event->attr.config1 & ivt_cbox_filter_mask(idx);
-               reg1->idx = idx;
-       }
-       return 0;
-}
-
-static void ivt_cbox_enable_event(struct intel_uncore_box *box, struct perf_event *event)
-{
-       struct hw_perf_event *hwc = &event->hw;
-       struct hw_perf_event_extra *reg1 = &hwc->extra_reg;
-
-       if (reg1->idx != EXTRA_REG_NONE) {
-               u64 filter = uncore_shared_reg_config(box, 0);
-               wrmsrl(reg1->reg, filter & 0xffffffff);
-               wrmsrl(reg1->reg + 6, filter >> 32);
-       }
-
-       wrmsrl(hwc->config_base, hwc->config | SNBEP_PMON_CTL_EN);
-}
-
-static struct intel_uncore_ops ivt_uncore_cbox_ops = {
-       .init_box               = ivt_uncore_msr_init_box,
-       .disable_box            = snbep_uncore_msr_disable_box,
-       .enable_box             = snbep_uncore_msr_enable_box,
-       .disable_event          = snbep_uncore_msr_disable_event,
-       .enable_event           = ivt_cbox_enable_event,
-       .read_counter           = uncore_msr_read_counter,
-       .hw_config              = ivt_cbox_hw_config,
-       .get_constraint         = ivt_cbox_get_constraint,
-       .put_constraint         = snbep_cbox_put_constraint,
-};
-
-static struct intel_uncore_type ivt_uncore_cbox = {
-       .name                   = "cbox",
-       .num_counters           = 4,
-       .num_boxes              = 15,
-       .perf_ctr_bits          = 44,
-       .event_ctl              = SNBEP_C0_MSR_PMON_CTL0,
-       .perf_ctr               = SNBEP_C0_MSR_PMON_CTR0,
-       .event_mask             = IVT_CBO_MSR_PMON_RAW_EVENT_MASK,
-       .box_ctl                = SNBEP_C0_MSR_PMON_BOX_CTL,
-       .msr_offset             = SNBEP_CBO_MSR_OFFSET,
-       .num_shared_regs        = 1,
-       .constraints            = snbep_uncore_cbox_constraints,
-       .ops                    = &ivt_uncore_cbox_ops,
-       .format_group           = &ivt_uncore_cbox_format_group,
-};
-
-static struct intel_uncore_ops ivt_uncore_pcu_ops = {
-       IVT_UNCORE_MSR_OPS_COMMON_INIT(),
-       .hw_config              = snbep_pcu_hw_config,
-       .get_constraint         = snbep_pcu_get_constraint,
-       .put_constraint         = snbep_pcu_put_constraint,
-};
-
-static struct intel_uncore_type ivt_uncore_pcu = {
-       .name                   = "pcu",
-       .num_counters           = 4,
-       .num_boxes              = 1,
-       .perf_ctr_bits          = 48,
-       .perf_ctr               = SNBEP_PCU_MSR_PMON_CTR0,
-       .event_ctl              = SNBEP_PCU_MSR_PMON_CTL0,
-       .event_mask             = IVT_PCU_MSR_PMON_RAW_EVENT_MASK,
-       .box_ctl                = SNBEP_PCU_MSR_PMON_BOX_CTL,
-       .num_shared_regs        = 1,
-       .ops                    = &ivt_uncore_pcu_ops,
-       .format_group           = &ivt_uncore_pcu_format_group,
-};
-
-static struct intel_uncore_type *ivt_msr_uncores[] = {
-       &ivt_uncore_ubox,
-       &ivt_uncore_cbox,
-       &ivt_uncore_pcu,
-       NULL,
-};
-
-static struct intel_uncore_type ivt_uncore_ha = {
-       .name           = "ha",
-       .num_counters   = 4,
-       .num_boxes      = 2,
-       .perf_ctr_bits  = 48,
-       IVT_UNCORE_PCI_COMMON_INIT(),
-};
-
-static struct intel_uncore_type ivt_uncore_imc = {
-       .name           = "imc",
-       .num_counters   = 4,
-       .num_boxes      = 8,
-       .perf_ctr_bits  = 48,
-       .fixed_ctr_bits = 48,
-       .fixed_ctr      = SNBEP_MC_CHy_PCI_PMON_FIXED_CTR,
-       .fixed_ctl      = SNBEP_MC_CHy_PCI_PMON_FIXED_CTL,
-       IVT_UNCORE_PCI_COMMON_INIT(),
-};
-
-/* registers in IRP boxes are not properly aligned */
-static unsigned ivt_uncore_irp_ctls[] = {0xd8, 0xdc, 0xe0, 0xe4};
-static unsigned ivt_uncore_irp_ctrs[] = {0xa0, 0xb0, 0xb8, 0xc0};
-
-static void ivt_uncore_irp_enable_event(struct intel_uncore_box *box, struct perf_event *event)
-{
-       struct pci_dev *pdev = box->pci_dev;
-       struct hw_perf_event *hwc = &event->hw;
-
-       pci_write_config_dword(pdev, ivt_uncore_irp_ctls[hwc->idx],
-                              hwc->config | SNBEP_PMON_CTL_EN);
-}
-
-static void ivt_uncore_irp_disable_event(struct intel_uncore_box *box, struct perf_event *event)
-{
-       struct pci_dev *pdev = box->pci_dev;
-       struct hw_perf_event *hwc = &event->hw;
-
-       pci_write_config_dword(pdev, ivt_uncore_irp_ctls[hwc->idx], hwc->config);
-}
-
-static u64 ivt_uncore_irp_read_counter(struct intel_uncore_box *box, struct perf_event *event)
-{
-       struct pci_dev *pdev = box->pci_dev;
-       struct hw_perf_event *hwc = &event->hw;
-       u64 count = 0;
-
-       pci_read_config_dword(pdev, ivt_uncore_irp_ctrs[hwc->idx], (u32 *)&count);
-       pci_read_config_dword(pdev, ivt_uncore_irp_ctrs[hwc->idx] + 4, (u32 *)&count + 1);
-
-       return count;
-}
-
-static struct intel_uncore_ops ivt_uncore_irp_ops = {
-       .init_box       = ivt_uncore_pci_init_box,
-       .disable_box    = snbep_uncore_pci_disable_box,
-       .enable_box     = snbep_uncore_pci_enable_box,
-       .disable_event  = ivt_uncore_irp_disable_event,
-       .enable_event   = ivt_uncore_irp_enable_event,
-       .read_counter   = ivt_uncore_irp_read_counter,
-};
-
-static struct intel_uncore_type ivt_uncore_irp = {
-       .name                   = "irp",
-       .num_counters           = 4,
-       .num_boxes              = 1,
-       .perf_ctr_bits          = 48,
-       .event_mask             = IVT_PMON_RAW_EVENT_MASK,
-       .box_ctl                = SNBEP_PCI_PMON_BOX_CTL,
-       .ops                    = &ivt_uncore_irp_ops,
-       .format_group           = &ivt_uncore_format_group,
-};
-
-static struct intel_uncore_ops ivt_uncore_qpi_ops = {
-       .init_box       = ivt_uncore_pci_init_box,
-       .disable_box    = snbep_uncore_pci_disable_box,
-       .enable_box     = snbep_uncore_pci_enable_box,
-       .disable_event  = snbep_uncore_pci_disable_event,
-       .enable_event   = snbep_qpi_enable_event,
-       .read_counter   = snbep_uncore_pci_read_counter,
-       .hw_config      = snbep_qpi_hw_config,
-       .get_constraint = uncore_get_constraint,
-       .put_constraint = uncore_put_constraint,
-};
-
-static struct intel_uncore_type ivt_uncore_qpi = {
-       .name                   = "qpi",
-       .num_counters           = 4,
-       .num_boxes              = 3,
-       .perf_ctr_bits          = 48,
-       .perf_ctr               = SNBEP_PCI_PMON_CTR0,
-       .event_ctl              = SNBEP_PCI_PMON_CTL0,
-       .event_mask             = IVT_QPI_PCI_PMON_RAW_EVENT_MASK,
-       .box_ctl                = SNBEP_PCI_PMON_BOX_CTL,
-       .num_shared_regs        = 1,
-       .ops                    = &ivt_uncore_qpi_ops,
-       .format_group           = &ivt_uncore_qpi_format_group,
-};
-
-static struct intel_uncore_type ivt_uncore_r2pcie = {
-       .name           = "r2pcie",
-       .num_counters   = 4,
-       .num_boxes      = 1,
-       .perf_ctr_bits  = 44,
-       .constraints    = snbep_uncore_r2pcie_constraints,
-       IVT_UNCORE_PCI_COMMON_INIT(),
-};
-
-static struct intel_uncore_type ivt_uncore_r3qpi = {
-       .name           = "r3qpi",
-       .num_counters   = 3,
-       .num_boxes      = 2,
-       .perf_ctr_bits  = 44,
-       .constraints    = snbep_uncore_r3qpi_constraints,
-       IVT_UNCORE_PCI_COMMON_INIT(),
-};
-
-enum {
-       IVT_PCI_UNCORE_HA,
-       IVT_PCI_UNCORE_IMC,
-       IVT_PCI_UNCORE_IRP,
-       IVT_PCI_UNCORE_QPI,
-       IVT_PCI_UNCORE_R2PCIE,
-       IVT_PCI_UNCORE_R3QPI,
-};
-
-static struct intel_uncore_type *ivt_pci_uncores[] = {
-       [IVT_PCI_UNCORE_HA]     = &ivt_uncore_ha,
-       [IVT_PCI_UNCORE_IMC]    = &ivt_uncore_imc,
-       [IVT_PCI_UNCORE_IRP]    = &ivt_uncore_irp,
-       [IVT_PCI_UNCORE_QPI]    = &ivt_uncore_qpi,
-       [IVT_PCI_UNCORE_R2PCIE] = &ivt_uncore_r2pcie,
-       [IVT_PCI_UNCORE_R3QPI]  = &ivt_uncore_r3qpi,
-       NULL,
-};
-
-static const struct pci_device_id ivt_uncore_pci_ids[] = {
-       { /* Home Agent 0 */
-               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe30),
-               .driver_data = UNCORE_PCI_DEV_DATA(IVT_PCI_UNCORE_HA, 0),
-       },
-       { /* Home Agent 1 */
-               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe38),
-               .driver_data = UNCORE_PCI_DEV_DATA(IVT_PCI_UNCORE_HA, 1),
-       },
-       { /* MC0 Channel 0 */
-               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xeb4),
-               .driver_data = UNCORE_PCI_DEV_DATA(IVT_PCI_UNCORE_IMC, 0),
-       },
-       { /* MC0 Channel 1 */
-               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xeb5),
-               .driver_data = UNCORE_PCI_DEV_DATA(IVT_PCI_UNCORE_IMC, 1),
-       },
-       { /* MC0 Channel 3 */
-               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xeb0),
-               .driver_data = UNCORE_PCI_DEV_DATA(IVT_PCI_UNCORE_IMC, 2),
-       },
-       { /* MC0 Channel 4 */
-               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xeb1),
-               .driver_data = UNCORE_PCI_DEV_DATA(IVT_PCI_UNCORE_IMC, 3),
-       },
-       { /* MC1 Channel 0 */
-               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xef4),
-               .driver_data = UNCORE_PCI_DEV_DATA(IVT_PCI_UNCORE_IMC, 4),
-       },
-       { /* MC1 Channel 1 */
-               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xef5),
-               .driver_data = UNCORE_PCI_DEV_DATA(IVT_PCI_UNCORE_IMC, 5),
-       },
-       { /* MC1 Channel 3 */
-               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xef0),
-               .driver_data = UNCORE_PCI_DEV_DATA(IVT_PCI_UNCORE_IMC, 6),
-       },
-       { /* MC1 Channel 4 */
-               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xef1),
-               .driver_data = UNCORE_PCI_DEV_DATA(IVT_PCI_UNCORE_IMC, 7),
-       },
-       { /* IRP */
-               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe39),
-               .driver_data = UNCORE_PCI_DEV_DATA(IVT_PCI_UNCORE_IRP, 0),
-       },
-       { /* QPI0 Port 0 */
-               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe32),
-               .driver_data = UNCORE_PCI_DEV_DATA(IVT_PCI_UNCORE_QPI, 0),
-       },
-       { /* QPI0 Port 1 */
-               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe33),
-               .driver_data = UNCORE_PCI_DEV_DATA(IVT_PCI_UNCORE_QPI, 1),
-       },
-       { /* QPI1 Port 2 */
-               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe3a),
-               .driver_data = UNCORE_PCI_DEV_DATA(IVT_PCI_UNCORE_QPI, 2),
-       },
-       { /* R2PCIe */
-               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe34),
-               .driver_data = UNCORE_PCI_DEV_DATA(IVT_PCI_UNCORE_R2PCIE, 0),
-       },
-       { /* R3QPI0 Link 0 */
-               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe36),
-               .driver_data = UNCORE_PCI_DEV_DATA(IVT_PCI_UNCORE_R3QPI, 0),
-       },
-       { /* R3QPI0 Link 1 */
-               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe37),
-               .driver_data = UNCORE_PCI_DEV_DATA(IVT_PCI_UNCORE_R3QPI, 1),
-       },
-       { /* R3QPI1 Link 2 */
-               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe3e),
-               .driver_data = UNCORE_PCI_DEV_DATA(IVT_PCI_UNCORE_R3QPI, 2),
-       },
-       { /* QPI Port 0 filter  */
-               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe86),
-               .driver_data = UNCORE_PCI_DEV_DATA(UNCORE_EXTRA_PCI_DEV,
-                                                  SNBEP_PCI_QPI_PORT0_FILTER),
-       },
-       { /* QPI Port 0 filter  */
-               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe96),
-               .driver_data = UNCORE_PCI_DEV_DATA(UNCORE_EXTRA_PCI_DEV,
-                                                  SNBEP_PCI_QPI_PORT1_FILTER),
-       },
-       { /* end: all zeroes */ }
-};
-
-static struct pci_driver ivt_uncore_pci_driver = {
-       .name           = "ivt_uncore",
-       .id_table       = ivt_uncore_pci_ids,
-};
-/* end of IvyTown uncore support */
-
-/* Sandy Bridge uncore support */
-static void snb_uncore_msr_enable_event(struct intel_uncore_box *box, struct perf_event *event)
-{
-       struct hw_perf_event *hwc = &event->hw;
-
-       if (hwc->idx < UNCORE_PMC_IDX_FIXED)
-               wrmsrl(hwc->config_base, hwc->config | SNB_UNC_CTL_EN);
-       else
-               wrmsrl(hwc->config_base, SNB_UNC_CTL_EN);
-}
-
-static void snb_uncore_msr_disable_event(struct intel_uncore_box *box, struct perf_event *event)
-{
-       wrmsrl(event->hw.config_base, 0);
-}
-
-static void snb_uncore_msr_init_box(struct intel_uncore_box *box)
-{
-       if (box->pmu->pmu_idx == 0) {
-               wrmsrl(SNB_UNC_PERF_GLOBAL_CTL,
-                       SNB_UNC_GLOBAL_CTL_EN | SNB_UNC_GLOBAL_CTL_CORE_ALL);
-       }
-}
-
-static struct uncore_event_desc snb_uncore_events[] = {
-       INTEL_UNCORE_EVENT_DESC(clockticks, "event=0xff,umask=0x00"),
-       { /* end: all zeroes */ },
-};
-
-static struct attribute *snb_uncore_formats_attr[] = {
-       &format_attr_event.attr,
-       &format_attr_umask.attr,
-       &format_attr_edge.attr,
-       &format_attr_inv.attr,
-       &format_attr_cmask5.attr,
-       NULL,
-};
-
-static struct attribute_group snb_uncore_format_group = {
-       .name           = "format",
-       .attrs          = snb_uncore_formats_attr,
-};
-
-static struct intel_uncore_ops snb_uncore_msr_ops = {
-       .init_box       = snb_uncore_msr_init_box,
-       .disable_event  = snb_uncore_msr_disable_event,
-       .enable_event   = snb_uncore_msr_enable_event,
-       .read_counter   = uncore_msr_read_counter,
-};
-
-static struct event_constraint snb_uncore_cbox_constraints[] = {
-       UNCORE_EVENT_CONSTRAINT(0x80, 0x1),
-       UNCORE_EVENT_CONSTRAINT(0x83, 0x1),
-       EVENT_CONSTRAINT_END
-};
-
-static struct intel_uncore_type snb_uncore_cbox = {
-       .name           = "cbox",
-       .num_counters   = 2,
-       .num_boxes      = 4,
-       .perf_ctr_bits  = 44,
-       .fixed_ctr_bits = 48,
-       .perf_ctr       = SNB_UNC_CBO_0_PER_CTR0,
-       .event_ctl      = SNB_UNC_CBO_0_PERFEVTSEL0,
-       .fixed_ctr      = SNB_UNC_FIXED_CTR,
-       .fixed_ctl      = SNB_UNC_FIXED_CTR_CTRL,
-       .single_fixed   = 1,
-       .event_mask     = SNB_UNC_RAW_EVENT_MASK,
-       .msr_offset     = SNB_UNC_CBO_MSR_OFFSET,
-       .constraints    = snb_uncore_cbox_constraints,
-       .ops            = &snb_uncore_msr_ops,
-       .format_group   = &snb_uncore_format_group,
-       .event_descs    = snb_uncore_events,
-};
-
-static struct intel_uncore_type *snb_msr_uncores[] = {
-       &snb_uncore_cbox,
-       NULL,
-};
-
-enum {
-       SNB_PCI_UNCORE_IMC,
-};
-
-static struct uncore_event_desc snb_uncore_imc_events[] = {
-       INTEL_UNCORE_EVENT_DESC(data_reads,  "event=0x01"),
-       INTEL_UNCORE_EVENT_DESC(data_reads.scale, "6.103515625e-5"),
-       INTEL_UNCORE_EVENT_DESC(data_reads.unit, "MiB"),
-
-       INTEL_UNCORE_EVENT_DESC(data_writes, "event=0x02"),
-       INTEL_UNCORE_EVENT_DESC(data_writes.scale, "6.103515625e-5"),
-       INTEL_UNCORE_EVENT_DESC(data_writes.unit, "MiB"),
-
-       { /* end: all zeroes */ },
-};
-
-#define SNB_UNCORE_PCI_IMC_EVENT_MASK          0xff
-#define SNB_UNCORE_PCI_IMC_BAR_OFFSET          0x48
-
-/* page size multiple covering all config regs */
-#define SNB_UNCORE_PCI_IMC_MAP_SIZE            0x6000
-
-#define SNB_UNCORE_PCI_IMC_DATA_READS          0x1
-#define SNB_UNCORE_PCI_IMC_DATA_READS_BASE     0x5050
-#define SNB_UNCORE_PCI_IMC_DATA_WRITES         0x2
-#define SNB_UNCORE_PCI_IMC_DATA_WRITES_BASE    0x5054
-#define SNB_UNCORE_PCI_IMC_CTR_BASE            SNB_UNCORE_PCI_IMC_DATA_READS_BASE
-
-static struct attribute *snb_uncore_imc_formats_attr[] = {
-       &format_attr_event.attr,
-       NULL,
-};
-
-static struct attribute_group snb_uncore_imc_format_group = {
-       .name = "format",
-       .attrs = snb_uncore_imc_formats_attr,
-};
-
-static void snb_uncore_imc_init_box(struct intel_uncore_box *box)
-{
-       struct pci_dev *pdev = box->pci_dev;
-       int where = SNB_UNCORE_PCI_IMC_BAR_OFFSET;
-       resource_size_t addr;
-       u32 pci_dword;
-
-       pci_read_config_dword(pdev, where, &pci_dword);
-       addr = pci_dword;
-
-#ifdef CONFIG_PHYS_ADDR_T_64BIT
-       pci_read_config_dword(pdev, where + 4, &pci_dword);
-       addr |= ((resource_size_t)pci_dword << 32);
-#endif
-
-       addr &= ~(PAGE_SIZE - 1);
-
-       box->io_addr = ioremap(addr, SNB_UNCORE_PCI_IMC_MAP_SIZE);
-       box->hrtimer_duration = UNCORE_SNB_IMC_HRTIMER_INTERVAL;
-}
-
-static void snb_uncore_imc_enable_box(struct intel_uncore_box *box)
-{}
-
-static void snb_uncore_imc_disable_box(struct intel_uncore_box *box)
-{}
-
-static void snb_uncore_imc_enable_event(struct intel_uncore_box *box, struct perf_event *event)
-{}
-
-static void snb_uncore_imc_disable_event(struct intel_uncore_box *box, struct perf_event *event)
-{}
-
-static u64 snb_uncore_imc_read_counter(struct intel_uncore_box *box, struct perf_event *event)
-{
-       struct hw_perf_event *hwc = &event->hw;
-
-       return (u64)*(unsigned int *)(box->io_addr + hwc->event_base);
-}
-
-/*
- * custom event_init() function because we define our own fixed, free
- * running counters, so we do not want to conflict with generic uncore
- * logic. Also simplifies processing
- */
-static int snb_uncore_imc_event_init(struct perf_event *event)
-{
-       struct intel_uncore_pmu *pmu;
-       struct intel_uncore_box *box;
-       struct hw_perf_event *hwc = &event->hw;
-       u64 cfg = event->attr.config & SNB_UNCORE_PCI_IMC_EVENT_MASK;
-       int idx, base;
-
-       if (event->attr.type != event->pmu->type)
-               return -ENOENT;
-
-       pmu = uncore_event_to_pmu(event);
-       /* no device found for this pmu */
-       if (pmu->func_id < 0)
-               return -ENOENT;
-
-       /* Sampling not supported yet */
-       if (hwc->sample_period)
-               return -EINVAL;
-
-       /* unsupported modes and filters */
-       if (event->attr.exclude_user   ||
-           event->attr.exclude_kernel ||
-           event->attr.exclude_hv     ||
-           event->attr.exclude_idle   ||
-           event->attr.exclude_host   ||
-           event->attr.exclude_guest  ||
-           event->attr.sample_period) /* no sampling */
-               return -EINVAL;
-
-       /*
-        * Place all uncore events for a particular physical package
-        * onto a single cpu
-        */
-       if (event->cpu < 0)
-               return -EINVAL;
-
-       /* check only supported bits are set */
-       if (event->attr.config & ~SNB_UNCORE_PCI_IMC_EVENT_MASK)
-               return -EINVAL;
-
-       box = uncore_pmu_to_box(pmu, event->cpu);
-       if (!box || box->cpu < 0)
-               return -EINVAL;
-
-       event->cpu = box->cpu;
-
-       event->hw.idx = -1;
-       event->hw.last_tag = ~0ULL;
-       event->hw.extra_reg.idx = EXTRA_REG_NONE;
-       event->hw.branch_reg.idx = EXTRA_REG_NONE;
-       /*
-        * check event is known (whitelist, determines counter)
-        */
-       switch (cfg) {
-       case SNB_UNCORE_PCI_IMC_DATA_READS:
-               base = SNB_UNCORE_PCI_IMC_DATA_READS_BASE;
-               idx = UNCORE_PMC_IDX_FIXED;
-               break;
-       case SNB_UNCORE_PCI_IMC_DATA_WRITES:
-               base = SNB_UNCORE_PCI_IMC_DATA_WRITES_BASE;
-               idx = UNCORE_PMC_IDX_FIXED + 1;
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       /* must be done before validate_group */
-       event->hw.event_base = base;
-       event->hw.config = cfg;
-       event->hw.idx = idx;
-
-       /* no group validation needed, we have free running counters */
-
-       return 0;
-}
-
-static int snb_uncore_imc_hw_config(struct intel_uncore_box *box, struct perf_event *event)
-{
-       return 0;
-}
-
-static void snb_uncore_imc_event_start(struct perf_event *event, int flags)
-{
-       struct intel_uncore_box *box = uncore_event_to_box(event);
-       u64 count;
-
-       if (WARN_ON_ONCE(!(event->hw.state & PERF_HES_STOPPED)))
-               return;
-
-       event->hw.state = 0;
-       box->n_active++;
-
-       list_add_tail(&event->active_entry, &box->active_list);
-
-       count = snb_uncore_imc_read_counter(box, event);
-       local64_set(&event->hw.prev_count, count);
-
-       if (box->n_active == 1)
-               uncore_pmu_start_hrtimer(box);
-}
-
-static void snb_uncore_imc_event_stop(struct perf_event *event, int flags)
-{
-       struct intel_uncore_box *box = uncore_event_to_box(event);
-       struct hw_perf_event *hwc = &event->hw;
-
-       if (!(hwc->state & PERF_HES_STOPPED)) {
-               box->n_active--;
-
-               WARN_ON_ONCE(hwc->state & PERF_HES_STOPPED);
-               hwc->state |= PERF_HES_STOPPED;
-
-               list_del(&event->active_entry);
-
-               if (box->n_active == 0)
-                       uncore_pmu_cancel_hrtimer(box);
-       }
-
-       if ((flags & PERF_EF_UPDATE) && !(hwc->state & PERF_HES_UPTODATE)) {
-               /*
-                * Drain the remaining delta count out of a event
-                * that we are disabling:
-                */
-               uncore_perf_event_update(box, event);
-               hwc->state |= PERF_HES_UPTODATE;
-       }
-}
-
-static int snb_uncore_imc_event_add(struct perf_event *event, int flags)
-{
-       struct intel_uncore_box *box = uncore_event_to_box(event);
-       struct hw_perf_event *hwc = &event->hw;
-
-       if (!box)
-               return -ENODEV;
-
-       hwc->state = PERF_HES_UPTODATE | PERF_HES_STOPPED;
-       if (!(flags & PERF_EF_START))
-               hwc->state |= PERF_HES_ARCH;
-
-       snb_uncore_imc_event_start(event, 0);
-
-       box->n_events++;
-
-       return 0;
-}
-
-static void snb_uncore_imc_event_del(struct perf_event *event, int flags)
-{
-       struct intel_uncore_box *box = uncore_event_to_box(event);
-       int i;
-
-       snb_uncore_imc_event_stop(event, PERF_EF_UPDATE);
-
-       for (i = 0; i < box->n_events; i++) {
-               if (event == box->event_list[i]) {
-                       --box->n_events;
-                       break;
-               }
-       }
-}
-
-static int snb_pci2phy_map_init(int devid)
-{
-       struct pci_dev *dev = NULL;
-       int bus;
-
-       dev = pci_get_device(PCI_VENDOR_ID_INTEL, devid, dev);
-       if (!dev)
-               return -ENOTTY;
-
-       bus = dev->bus->number;
-
-       pcibus_to_physid[bus] = 0;
-
-       pci_dev_put(dev);
-
-       return 0;
-}
-
-static struct pmu snb_uncore_imc_pmu = {
-       .task_ctx_nr    = perf_invalid_context,
-       .event_init     = snb_uncore_imc_event_init,
-       .add            = snb_uncore_imc_event_add,
-       .del            = snb_uncore_imc_event_del,
-       .start          = snb_uncore_imc_event_start,
-       .stop           = snb_uncore_imc_event_stop,
-       .read           = uncore_pmu_event_read,
-};
-
-static struct intel_uncore_ops snb_uncore_imc_ops = {
-       .init_box       = snb_uncore_imc_init_box,
-       .enable_box     = snb_uncore_imc_enable_box,
-       .disable_box    = snb_uncore_imc_disable_box,
-       .disable_event  = snb_uncore_imc_disable_event,
-       .enable_event   = snb_uncore_imc_enable_event,
-       .hw_config      = snb_uncore_imc_hw_config,
-       .read_counter   = snb_uncore_imc_read_counter,
-};
-
-static struct intel_uncore_type snb_uncore_imc = {
-       .name           = "imc",
-       .num_counters   = 2,
-       .num_boxes      = 1,
-       .fixed_ctr_bits = 32,
-       .fixed_ctr      = SNB_UNCORE_PCI_IMC_CTR_BASE,
-       .event_descs    = snb_uncore_imc_events,
-       .format_group   = &snb_uncore_imc_format_group,
-       .perf_ctr       = SNB_UNCORE_PCI_IMC_DATA_READS_BASE,
-       .event_mask     = SNB_UNCORE_PCI_IMC_EVENT_MASK,
-       .ops            = &snb_uncore_imc_ops,
-       .pmu            = &snb_uncore_imc_pmu,
-};
-
-static struct intel_uncore_type *snb_pci_uncores[] = {
-       [SNB_PCI_UNCORE_IMC]    = &snb_uncore_imc,
-       NULL,
-};
-
-static const struct pci_device_id snb_uncore_pci_ids[] = {
-       { /* IMC */
-               PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SNB_IMC),
-               .driver_data = UNCORE_PCI_DEV_DATA(SNB_PCI_UNCORE_IMC, 0),
-       },
-       { /* end: all zeroes */ },
-};
-
-static const struct pci_device_id ivb_uncore_pci_ids[] = {
-       { /* IMC */
-               PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IVB_IMC),
-               .driver_data = UNCORE_PCI_DEV_DATA(SNB_PCI_UNCORE_IMC, 0),
-       },
-       { /* end: all zeroes */ },
-};
-
-static const struct pci_device_id hsw_uncore_pci_ids[] = {
-       { /* IMC */
-               PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_HSW_IMC),
-               .driver_data = UNCORE_PCI_DEV_DATA(SNB_PCI_UNCORE_IMC, 0),
-       },
-       { /* end: all zeroes */ },
-};
-
-static struct pci_driver snb_uncore_pci_driver = {
-       .name           = "snb_uncore",
-       .id_table       = snb_uncore_pci_ids,
-};
-
-static struct pci_driver ivb_uncore_pci_driver = {
-       .name           = "ivb_uncore",
-       .id_table       = ivb_uncore_pci_ids,
-};
-
-static struct pci_driver hsw_uncore_pci_driver = {
-       .name           = "hsw_uncore",
-       .id_table       = hsw_uncore_pci_ids,
-};
-
-/* end of Sandy Bridge uncore support */
-
-/* Nehalem uncore support */
-static void nhm_uncore_msr_disable_box(struct intel_uncore_box *box)
-{
-       wrmsrl(NHM_UNC_PERF_GLOBAL_CTL, 0);
-}
-
-static void nhm_uncore_msr_enable_box(struct intel_uncore_box *box)
-{
-       wrmsrl(NHM_UNC_PERF_GLOBAL_CTL, NHM_UNC_GLOBAL_CTL_EN_PC_ALL | NHM_UNC_GLOBAL_CTL_EN_FC);
-}
-
-static void nhm_uncore_msr_enable_event(struct intel_uncore_box *box, struct perf_event *event)
-{
-       struct hw_perf_event *hwc = &event->hw;
-
-       if (hwc->idx < UNCORE_PMC_IDX_FIXED)
-               wrmsrl(hwc->config_base, hwc->config | SNB_UNC_CTL_EN);
-       else
-               wrmsrl(hwc->config_base, NHM_UNC_FIXED_CTR_CTL_EN);
-}
-
-static struct attribute *nhm_uncore_formats_attr[] = {
-       &format_attr_event.attr,
-       &format_attr_umask.attr,
-       &format_attr_edge.attr,
-       &format_attr_inv.attr,
-       &format_attr_cmask8.attr,
-       NULL,
-};
-
-static struct attribute_group nhm_uncore_format_group = {
-       .name = "format",
-       .attrs = nhm_uncore_formats_attr,
-};
-
-static struct uncore_event_desc nhm_uncore_events[] = {
-       INTEL_UNCORE_EVENT_DESC(clockticks,                "event=0xff,umask=0x00"),
-       INTEL_UNCORE_EVENT_DESC(qmc_writes_full_any,       "event=0x2f,umask=0x0f"),
-       INTEL_UNCORE_EVENT_DESC(qmc_normal_reads_any,      "event=0x2c,umask=0x0f"),
-       INTEL_UNCORE_EVENT_DESC(qhl_request_ioh_reads,     "event=0x20,umask=0x01"),
-       INTEL_UNCORE_EVENT_DESC(qhl_request_ioh_writes,    "event=0x20,umask=0x02"),
-       INTEL_UNCORE_EVENT_DESC(qhl_request_remote_reads,  "event=0x20,umask=0x04"),
-       INTEL_UNCORE_EVENT_DESC(qhl_request_remote_writes, "event=0x20,umask=0x08"),
-       INTEL_UNCORE_EVENT_DESC(qhl_request_local_reads,   "event=0x20,umask=0x10"),
-       INTEL_UNCORE_EVENT_DESC(qhl_request_local_writes,  "event=0x20,umask=0x20"),
-       { /* end: all zeroes */ },
-};
-
-static struct intel_uncore_ops nhm_uncore_msr_ops = {
-       .disable_box    = nhm_uncore_msr_disable_box,
-       .enable_box     = nhm_uncore_msr_enable_box,
-       .disable_event  = snb_uncore_msr_disable_event,
-       .enable_event   = nhm_uncore_msr_enable_event,
-       .read_counter   = uncore_msr_read_counter,
-};
-
-static struct intel_uncore_type nhm_uncore = {
-       .name           = "",
-       .num_counters   = 8,
-       .num_boxes      = 1,
-       .perf_ctr_bits  = 48,
-       .fixed_ctr_bits = 48,
-       .event_ctl      = NHM_UNC_PERFEVTSEL0,
-       .perf_ctr       = NHM_UNC_UNCORE_PMC0,
-       .fixed_ctr      = NHM_UNC_FIXED_CTR,
-       .fixed_ctl      = NHM_UNC_FIXED_CTR_CTRL,
-       .event_mask     = NHM_UNC_RAW_EVENT_MASK,
-       .event_descs    = nhm_uncore_events,
-       .ops            = &nhm_uncore_msr_ops,
-       .format_group   = &nhm_uncore_format_group,
-};
-
-static struct intel_uncore_type *nhm_msr_uncores[] = {
-       &nhm_uncore,
-       NULL,
-};
-/* end of Nehalem uncore support */
-
-/* Nehalem-EX uncore support */
-DEFINE_UNCORE_FORMAT_ATTR(event5, event, "config:1-5");
-DEFINE_UNCORE_FORMAT_ATTR(counter, counter, "config:6-7");
-DEFINE_UNCORE_FORMAT_ATTR(match, match, "config1:0-63");
-DEFINE_UNCORE_FORMAT_ATTR(mask, mask, "config2:0-63");
-
-static void nhmex_uncore_msr_init_box(struct intel_uncore_box *box)
-{
-       wrmsrl(NHMEX_U_MSR_PMON_GLOBAL_CTL, NHMEX_U_PMON_GLOBAL_EN_ALL);
-}
-
-static void nhmex_uncore_msr_disable_box(struct intel_uncore_box *box)
-{
-       unsigned msr = uncore_msr_box_ctl(box);
-       u64 config;
-
-       if (msr) {
-               rdmsrl(msr, config);
-               config &= ~((1ULL << uncore_num_counters(box)) - 1);
-               /* WBox has a fixed counter */
-               if (uncore_msr_fixed_ctl(box))
-                       config &= ~NHMEX_W_PMON_GLOBAL_FIXED_EN;
-               wrmsrl(msr, config);
-       }
-}
-
-static void nhmex_uncore_msr_enable_box(struct intel_uncore_box *box)
-{
-       unsigned msr = uncore_msr_box_ctl(box);
-       u64 config;
-
-       if (msr) {
-               rdmsrl(msr, config);
-               config |= (1ULL << uncore_num_counters(box)) - 1;
-               /* WBox has a fixed counter */
-               if (uncore_msr_fixed_ctl(box))
-                       config |= NHMEX_W_PMON_GLOBAL_FIXED_EN;
-               wrmsrl(msr, config);
-       }
-}
-
-static void nhmex_uncore_msr_disable_event(struct intel_uncore_box *box, struct perf_event *event)
-{
-       wrmsrl(event->hw.config_base, 0);
-}
-
-static void nhmex_uncore_msr_enable_event(struct intel_uncore_box *box, struct perf_event *event)
-{
-       struct hw_perf_event *hwc = &event->hw;
-
-       if (hwc->idx >= UNCORE_PMC_IDX_FIXED)
-               wrmsrl(hwc->config_base, NHMEX_PMON_CTL_EN_BIT0);
-       else if (box->pmu->type->event_mask & NHMEX_PMON_CTL_EN_BIT0)
-               wrmsrl(hwc->config_base, hwc->config | NHMEX_PMON_CTL_EN_BIT22);
-       else
-               wrmsrl(hwc->config_base, hwc->config | NHMEX_PMON_CTL_EN_BIT0);
-}
-
-#define NHMEX_UNCORE_OPS_COMMON_INIT()                         \
-       .init_box       = nhmex_uncore_msr_init_box,            \
-       .disable_box    = nhmex_uncore_msr_disable_box,         \
-       .enable_box     = nhmex_uncore_msr_enable_box,          \
-       .disable_event  = nhmex_uncore_msr_disable_event,       \
-       .read_counter   = uncore_msr_read_counter
-
-static struct intel_uncore_ops nhmex_uncore_ops = {
-       NHMEX_UNCORE_OPS_COMMON_INIT(),
-       .enable_event   = nhmex_uncore_msr_enable_event,
-};
-
-static struct attribute *nhmex_uncore_ubox_formats_attr[] = {
-       &format_attr_event.attr,
-       &format_attr_edge.attr,
-       NULL,
-};
-
-static struct attribute_group nhmex_uncore_ubox_format_group = {
-       .name           = "format",
-       .attrs          = nhmex_uncore_ubox_formats_attr,
-};
-
-static struct intel_uncore_type nhmex_uncore_ubox = {
-       .name           = "ubox",
-       .num_counters   = 1,
-       .num_boxes      = 1,
-       .perf_ctr_bits  = 48,
-       .event_ctl      = NHMEX_U_MSR_PMON_EV_SEL,
-       .perf_ctr       = NHMEX_U_MSR_PMON_CTR,
-       .event_mask     = NHMEX_U_PMON_RAW_EVENT_MASK,
-       .box_ctl        = NHMEX_U_MSR_PMON_GLOBAL_CTL,
-       .ops            = &nhmex_uncore_ops,
-       .format_group   = &nhmex_uncore_ubox_format_group
-};
-
-static struct attribute *nhmex_uncore_cbox_formats_attr[] = {
-       &format_attr_event.attr,
-       &format_attr_umask.attr,
-       &format_attr_edge.attr,
-       &format_attr_inv.attr,
-       &format_attr_thresh8.attr,
-       NULL,
-};
-
-static struct attribute_group nhmex_uncore_cbox_format_group = {
-       .name = "format",
-       .attrs = nhmex_uncore_cbox_formats_attr,
-};
-
-/* msr offset for each instance of cbox */
-static unsigned nhmex_cbox_msr_offsets[] = {
-       0x0, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, 0x240, 0x2c0,
-};
-
-static struct intel_uncore_type nhmex_uncore_cbox = {
-       .name                   = "cbox",
-       .num_counters           = 6,
-       .num_boxes              = 10,
-       .perf_ctr_bits          = 48,
-       .event_ctl              = NHMEX_C0_MSR_PMON_EV_SEL0,
-       .perf_ctr               = NHMEX_C0_MSR_PMON_CTR0,
-       .event_mask             = NHMEX_PMON_RAW_EVENT_MASK,
-       .box_ctl                = NHMEX_C0_MSR_PMON_GLOBAL_CTL,
-       .msr_offsets            = nhmex_cbox_msr_offsets,
-       .pair_ctr_ctl           = 1,
-       .ops                    = &nhmex_uncore_ops,
-       .format_group           = &nhmex_uncore_cbox_format_group
-};
-
-static struct uncore_event_desc nhmex_uncore_wbox_events[] = {
-       INTEL_UNCORE_EVENT_DESC(clockticks, "event=0xff,umask=0"),
-       { /* end: all zeroes */ },
-};
-
-static struct intel_uncore_type nhmex_uncore_wbox = {
-       .name                   = "wbox",
-       .num_counters           = 4,
-       .num_boxes              = 1,
-       .perf_ctr_bits          = 48,
-       .event_ctl              = NHMEX_W_MSR_PMON_CNT0,
-       .perf_ctr               = NHMEX_W_MSR_PMON_EVT_SEL0,
-       .fixed_ctr              = NHMEX_W_MSR_PMON_FIXED_CTR,
-       .fixed_ctl              = NHMEX_W_MSR_PMON_FIXED_CTL,
-       .event_mask             = NHMEX_PMON_RAW_EVENT_MASK,
-       .box_ctl                = NHMEX_W_MSR_GLOBAL_CTL,
-       .pair_ctr_ctl           = 1,
-       .event_descs            = nhmex_uncore_wbox_events,
-       .ops                    = &nhmex_uncore_ops,
-       .format_group           = &nhmex_uncore_cbox_format_group
-};
-
-static int nhmex_bbox_hw_config(struct intel_uncore_box *box, struct perf_event *event)
-{
-       struct hw_perf_event *hwc = &event->hw;
-       struct hw_perf_event_extra *reg1 = &hwc->extra_reg;
-       struct hw_perf_event_extra *reg2 = &hwc->branch_reg;
-       int ctr, ev_sel;
-
-       ctr = (hwc->config & NHMEX_B_PMON_CTR_MASK) >>
-               NHMEX_B_PMON_CTR_SHIFT;
-       ev_sel = (hwc->config & NHMEX_B_PMON_CTL_EV_SEL_MASK) >>
-                 NHMEX_B_PMON_CTL_EV_SEL_SHIFT;
-
-       /* events that do not use the match/mask registers */
-       if ((ctr == 0 && ev_sel > 0x3) || (ctr == 1 && ev_sel > 0x6) ||
-           (ctr == 2 && ev_sel != 0x4) || ctr == 3)
-               return 0;
-
-       if (box->pmu->pmu_idx == 0)
-               reg1->reg = NHMEX_B0_MSR_MATCH;
-       else
-               reg1->reg = NHMEX_B1_MSR_MATCH;
-       reg1->idx = 0;
-       reg1->config = event->attr.config1;
-       reg2->config = event->attr.config2;
-       return 0;
-}
-
-static void nhmex_bbox_msr_enable_event(struct intel_uncore_box *box, struct perf_event *event)
-{
-       struct hw_perf_event *hwc = &event->hw;
-       struct hw_perf_event_extra *reg1 = &hwc->extra_reg;
-       struct hw_perf_event_extra *reg2 = &hwc->branch_reg;
-
-       if (reg1->idx != EXTRA_REG_NONE) {
-               wrmsrl(reg1->reg, reg1->config);
-               wrmsrl(reg1->reg + 1, reg2->config);
-       }
-       wrmsrl(hwc->config_base, NHMEX_PMON_CTL_EN_BIT0 |
-               (hwc->config & NHMEX_B_PMON_CTL_EV_SEL_MASK));
-}
-
-/*
- * The Bbox has 4 counters, but each counter monitors different events.
- * Use bits 6-7 in the event config to select counter.
- */
-static struct event_constraint nhmex_uncore_bbox_constraints[] = {
-       EVENT_CONSTRAINT(0 , 1, 0xc0),
-       EVENT_CONSTRAINT(0x40, 2, 0xc0),
-       EVENT_CONSTRAINT(0x80, 4, 0xc0),
-       EVENT_CONSTRAINT(0xc0, 8, 0xc0),
-       EVENT_CONSTRAINT_END,
-};
-
-static struct attribute *nhmex_uncore_bbox_formats_attr[] = {
-       &format_attr_event5.attr,
-       &format_attr_counter.attr,
-       &format_attr_match.attr,
-       &format_attr_mask.attr,
-       NULL,
-};
-
-static struct attribute_group nhmex_uncore_bbox_format_group = {
-       .name = "format",
-       .attrs = nhmex_uncore_bbox_formats_attr,
-};
-
-static struct intel_uncore_ops nhmex_uncore_bbox_ops = {
-       NHMEX_UNCORE_OPS_COMMON_INIT(),
-       .enable_event           = nhmex_bbox_msr_enable_event,
-       .hw_config              = nhmex_bbox_hw_config,
-       .get_constraint         = uncore_get_constraint,
-       .put_constraint         = uncore_put_constraint,
-};
-
-static struct intel_uncore_type nhmex_uncore_bbox = {
-       .name                   = "bbox",
-       .num_counters           = 4,
-       .num_boxes              = 2,
-       .perf_ctr_bits          = 48,
-       .event_ctl              = NHMEX_B0_MSR_PMON_CTL0,
-       .perf_ctr               = NHMEX_B0_MSR_PMON_CTR0,
-       .event_mask             = NHMEX_B_PMON_RAW_EVENT_MASK,
-       .box_ctl                = NHMEX_B0_MSR_PMON_GLOBAL_CTL,
-       .msr_offset             = NHMEX_B_MSR_OFFSET,
-       .pair_ctr_ctl           = 1,
-       .num_shared_regs        = 1,
-       .constraints            = nhmex_uncore_bbox_constraints,
-       .ops                    = &nhmex_uncore_bbox_ops,
-       .format_group           = &nhmex_uncore_bbox_format_group
-};
-
-static int nhmex_sbox_hw_config(struct intel_uncore_box *box, struct perf_event *event)
-{
-       struct hw_perf_event *hwc = &event->hw;
-       struct hw_perf_event_extra *reg1 = &hwc->extra_reg;
-       struct hw_perf_event_extra *reg2 = &hwc->branch_reg;
-
-       /* only TO_R_PROG_EV event uses the match/mask register */
-       if ((hwc->config & NHMEX_PMON_CTL_EV_SEL_MASK) !=
-           NHMEX_S_EVENT_TO_R_PROG_EV)
-               return 0;
-
-       if (box->pmu->pmu_idx == 0)
-               reg1->reg = NHMEX_S0_MSR_MM_CFG;
-       else
-               reg1->reg = NHMEX_S1_MSR_MM_CFG;
-       reg1->idx = 0;
-       reg1->config = event->attr.config1;
-       reg2->config = event->attr.config2;
-       return 0;
-}
-
-static void nhmex_sbox_msr_enable_event(struct intel_uncore_box *box, struct perf_event *event)
-{
-       struct hw_perf_event *hwc = &event->hw;
-       struct hw_perf_event_extra *reg1 = &hwc->extra_reg;
-       struct hw_perf_event_extra *reg2 = &hwc->branch_reg;
-
-       if (reg1->idx != EXTRA_REG_NONE) {
-               wrmsrl(reg1->reg, 0);
-               wrmsrl(reg1->reg + 1, reg1->config);
-               wrmsrl(reg1->reg + 2, reg2->config);
-               wrmsrl(reg1->reg, NHMEX_S_PMON_MM_CFG_EN);
-       }
-       wrmsrl(hwc->config_base, hwc->config | NHMEX_PMON_CTL_EN_BIT22);
-}
-
-static struct attribute *nhmex_uncore_sbox_formats_attr[] = {
-       &format_attr_event.attr,
-       &format_attr_umask.attr,
-       &format_attr_edge.attr,
-       &format_attr_inv.attr,
-       &format_attr_thresh8.attr,
-       &format_attr_match.attr,
-       &format_attr_mask.attr,
-       NULL,
-};
-
-static struct attribute_group nhmex_uncore_sbox_format_group = {
-       .name                   = "format",
-       .attrs                  = nhmex_uncore_sbox_formats_attr,
-};
-
-static struct intel_uncore_ops nhmex_uncore_sbox_ops = {
-       NHMEX_UNCORE_OPS_COMMON_INIT(),
-       .enable_event           = nhmex_sbox_msr_enable_event,
-       .hw_config              = nhmex_sbox_hw_config,
-       .get_constraint         = uncore_get_constraint,
-       .put_constraint         = uncore_put_constraint,
-};
-
-static struct intel_uncore_type nhmex_uncore_sbox = {
-       .name                   = "sbox",
-       .num_counters           = 4,
-       .num_boxes              = 2,
-       .perf_ctr_bits          = 48,
-       .event_ctl              = NHMEX_S0_MSR_PMON_CTL0,
-       .perf_ctr               = NHMEX_S0_MSR_PMON_CTR0,
-       .event_mask             = NHMEX_PMON_RAW_EVENT_MASK,
-       .box_ctl                = NHMEX_S0_MSR_PMON_GLOBAL_CTL,
-       .msr_offset             = NHMEX_S_MSR_OFFSET,
-       .pair_ctr_ctl           = 1,
-       .num_shared_regs        = 1,
-       .ops                    = &nhmex_uncore_sbox_ops,
-       .format_group           = &nhmex_uncore_sbox_format_group
-};
-
-enum {
-       EXTRA_REG_NHMEX_M_FILTER,
-       EXTRA_REG_NHMEX_M_DSP,
-       EXTRA_REG_NHMEX_M_ISS,
-       EXTRA_REG_NHMEX_M_MAP,
-       EXTRA_REG_NHMEX_M_MSC_THR,
-       EXTRA_REG_NHMEX_M_PGT,
-       EXTRA_REG_NHMEX_M_PLD,
-       EXTRA_REG_NHMEX_M_ZDP_CTL_FVC,
-};
-
-static struct extra_reg nhmex_uncore_mbox_extra_regs[] = {
-       MBOX_INC_SEL_EXTAR_REG(0x0, DSP),
-       MBOX_INC_SEL_EXTAR_REG(0x4, MSC_THR),
-       MBOX_INC_SEL_EXTAR_REG(0x5, MSC_THR),
-       MBOX_INC_SEL_EXTAR_REG(0x9, ISS),
-       /* event 0xa uses two extra registers */
-       MBOX_INC_SEL_EXTAR_REG(0xa, ISS),
-       MBOX_INC_SEL_EXTAR_REG(0xa, PLD),
-       MBOX_INC_SEL_EXTAR_REG(0xb, PLD),
-       /* events 0xd ~ 0x10 use the same extra register */
-       MBOX_INC_SEL_EXTAR_REG(0xd, ZDP_CTL_FVC),
-       MBOX_INC_SEL_EXTAR_REG(0xe, ZDP_CTL_FVC),
-       MBOX_INC_SEL_EXTAR_REG(0xf, ZDP_CTL_FVC),
-       MBOX_INC_SEL_EXTAR_REG(0x10, ZDP_CTL_FVC),
-       MBOX_INC_SEL_EXTAR_REG(0x16, PGT),
-       MBOX_SET_FLAG_SEL_EXTRA_REG(0x0, DSP),
-       MBOX_SET_FLAG_SEL_EXTRA_REG(0x1, ISS),
-       MBOX_SET_FLAG_SEL_EXTRA_REG(0x5, PGT),
-       MBOX_SET_FLAG_SEL_EXTRA_REG(0x6, MAP),
-       EVENT_EXTRA_END
-};
-
-/* Nehalem-EX or Westmere-EX ? */
-static bool uncore_nhmex;
-
-static bool nhmex_mbox_get_shared_reg(struct intel_uncore_box *box, int idx, u64 config)
-{
-       struct intel_uncore_extra_reg *er;
-       unsigned long flags;
-       bool ret = false;
-       u64 mask;
-
-       if (idx < EXTRA_REG_NHMEX_M_ZDP_CTL_FVC) {
-               er = &box->shared_regs[idx];
-               raw_spin_lock_irqsave(&er->lock, flags);
-               if (!atomic_read(&er->ref) || er->config == config) {
-                       atomic_inc(&er->ref);
-                       er->config = config;
-                       ret = true;
-               }
-               raw_spin_unlock_irqrestore(&er->lock, flags);
-
-               return ret;
-       }
-       /*
-        * The ZDP_CTL_FVC MSR has 4 fields which are used to control
-        * events 0xd ~ 0x10. Besides these 4 fields, there are additional
-        * fields which are shared.
-        */
-       idx -= EXTRA_REG_NHMEX_M_ZDP_CTL_FVC;
-       if (WARN_ON_ONCE(idx >= 4))
-               return false;
+struct intel_uncore_type **uncore_msr_uncores = empty_uncore;
+struct intel_uncore_type **uncore_pci_uncores = empty_uncore;
 
-       /* mask of the shared fields */
-       if (uncore_nhmex)
-               mask = NHMEX_M_PMON_ZDP_CTL_FVC_MASK;
-       else
-               mask = WSMEX_M_PMON_ZDP_CTL_FVC_MASK;
-       er = &box->shared_regs[EXTRA_REG_NHMEX_M_ZDP_CTL_FVC];
-
-       raw_spin_lock_irqsave(&er->lock, flags);
-       /* add mask of the non-shared field if it's in use */
-       if (__BITS_VALUE(atomic_read(&er->ref), idx, 8)) {
-               if (uncore_nhmex)
-                       mask |= NHMEX_M_PMON_ZDP_CTL_FVC_EVENT_MASK(idx);
-               else
-                       mask |= WSMEX_M_PMON_ZDP_CTL_FVC_EVENT_MASK(idx);
-       }
+static bool pcidrv_registered;
+struct pci_driver *uncore_pci_driver;
+/* pci bus to socket mapping */
+int uncore_pcibus_to_physid[256] = { [0 ... 255] = -1, };
+struct pci_dev *uncore_extra_pci_dev[UNCORE_SOCKET_MAX][UNCORE_EXTRA_PCI_DEV_MAX];
 
-       if (!atomic_read(&er->ref) || !((er->config ^ config) & mask)) {
-               atomic_add(1 << (idx * 8), &er->ref);
-               if (uncore_nhmex)
-                       mask = NHMEX_M_PMON_ZDP_CTL_FVC_MASK |
-                               NHMEX_M_PMON_ZDP_CTL_FVC_EVENT_MASK(idx);
-               else
-                       mask = WSMEX_M_PMON_ZDP_CTL_FVC_MASK |
-                               WSMEX_M_PMON_ZDP_CTL_FVC_EVENT_MASK(idx);
-               er->config &= ~mask;
-               er->config |= (config & mask);
-               ret = true;
-       }
-       raw_spin_unlock_irqrestore(&er->lock, flags);
+static DEFINE_RAW_SPINLOCK(uncore_box_lock);
+/* mask of cpus that collect uncore events */
+static cpumask_t uncore_cpu_mask;
 
-       return ret;
-}
+/* constraint for the fixed counter */
+static struct event_constraint uncore_constraint_fixed =
+       EVENT_CONSTRAINT(~0ULL, 1 << UNCORE_PMC_IDX_FIXED, ~0ULL);
+struct event_constraint uncore_constraint_empty =
+       EVENT_CONSTRAINT(0, 0, 0);
 
-static void nhmex_mbox_put_shared_reg(struct intel_uncore_box *box, int idx)
+ssize_t uncore_event_show(struct kobject *kobj,
+                         struct kobj_attribute *attr, char *buf)
 {
-       struct intel_uncore_extra_reg *er;
-
-       if (idx < EXTRA_REG_NHMEX_M_ZDP_CTL_FVC) {
-               er = &box->shared_regs[idx];
-               atomic_dec(&er->ref);
-               return;
-       }
-
-       idx -= EXTRA_REG_NHMEX_M_ZDP_CTL_FVC;
-       er = &box->shared_regs[EXTRA_REG_NHMEX_M_ZDP_CTL_FVC];
-       atomic_sub(1 << (idx * 8), &er->ref);
+       struct uncore_event_desc *event =
+               container_of(attr, struct uncore_event_desc, attr);
+       return sprintf(buf, "%s", event->config);
 }
 
-static u64 nhmex_mbox_alter_er(struct perf_event *event, int new_idx, bool modify)
+struct intel_uncore_pmu *uncore_event_to_pmu(struct perf_event *event)
 {
-       struct hw_perf_event *hwc = &event->hw;
-       struct hw_perf_event_extra *reg1 = &hwc->extra_reg;
-       u64 idx, orig_idx = __BITS_VALUE(reg1->idx, 0, 8);
-       u64 config = reg1->config;
-
-       /* get the non-shared control bits and shift them */
-       idx = orig_idx - EXTRA_REG_NHMEX_M_ZDP_CTL_FVC;
-       if (uncore_nhmex)
-               config &= NHMEX_M_PMON_ZDP_CTL_FVC_EVENT_MASK(idx);
-       else
-               config &= WSMEX_M_PMON_ZDP_CTL_FVC_EVENT_MASK(idx);
-       if (new_idx > orig_idx) {
-               idx = new_idx - orig_idx;
-               config <<= 3 * idx;
-       } else {
-               idx = orig_idx - new_idx;
-               config >>= 3 * idx;
-       }
-
-       /* add the shared control bits back */
-       if (uncore_nhmex)
-               config |= NHMEX_M_PMON_ZDP_CTL_FVC_MASK & reg1->config;
-       else
-               config |= WSMEX_M_PMON_ZDP_CTL_FVC_MASK & reg1->config;
-       config |= NHMEX_M_PMON_ZDP_CTL_FVC_MASK & reg1->config;
-       if (modify) {
-               /* adjust the main event selector */
-               if (new_idx > orig_idx)
-                       hwc->config += idx << NHMEX_M_PMON_CTL_INC_SEL_SHIFT;
-               else
-                       hwc->config -= idx << NHMEX_M_PMON_CTL_INC_SEL_SHIFT;
-               reg1->config = config;
-               reg1->idx = ~0xff | new_idx;
-       }
-       return config;
+       return container_of(event->pmu, struct intel_uncore_pmu, pmu);
 }
 
-static struct event_constraint *
-nhmex_mbox_get_constraint(struct intel_uncore_box *box, struct perf_event *event)
+struct intel_uncore_box *uncore_pmu_to_box(struct intel_uncore_pmu *pmu, int cpu)
 {
-       struct hw_perf_event_extra *reg1 = &event->hw.extra_reg;
-       struct hw_perf_event_extra *reg2 = &event->hw.branch_reg;
-       int i, idx[2], alloc = 0;
-       u64 config1 = reg1->config;
-
-       idx[0] = __BITS_VALUE(reg1->idx, 0, 8);
-       idx[1] = __BITS_VALUE(reg1->idx, 1, 8);
-again:
-       for (i = 0; i < 2; i++) {
-               if (!uncore_box_is_fake(box) && (reg1->alloc & (0x1 << i)))
-                       idx[i] = 0xff;
-
-               if (idx[i] == 0xff)
-                       continue;
-
-               if (!nhmex_mbox_get_shared_reg(box, idx[i],
-                               __BITS_VALUE(config1, i, 32)))
-                       goto fail;
-               alloc |= (0x1 << i);
-       }
+       struct intel_uncore_box *box;
 
-       /* for the match/mask registers */
-       if (reg2->idx != EXTRA_REG_NONE &&
-           (uncore_box_is_fake(box) || !reg2->alloc) &&
-           !nhmex_mbox_get_shared_reg(box, reg2->idx, reg2->config))
-               goto fail;
+       box = *per_cpu_ptr(pmu->box, cpu);
+       if (box)
+               return box;
 
-       /*
-        * If it's a fake box -- as per validate_{group,event}() we
-        * shouldn't touch event state and we can avoid doing so
-        * since both will only call get_event_constraints() once
-        * on each event, this avoids the need for reg->alloc.
-        */
-       if (!uncore_box_is_fake(box)) {
-               if (idx[0] != 0xff && idx[0] != __BITS_VALUE(reg1->idx, 0, 8))
-                       nhmex_mbox_alter_er(event, idx[0], true);
-               reg1->alloc |= alloc;
-               if (reg2->idx != EXTRA_REG_NONE)
-                       reg2->alloc = 1;
-       }
-       return NULL;
-fail:
-       if (idx[0] != 0xff && !(alloc & 0x1) &&
-           idx[0] >= EXTRA_REG_NHMEX_M_ZDP_CTL_FVC) {
-               /*
-                * events 0xd ~ 0x10 are functional identical, but are
-                * controlled by different fields in the ZDP_CTL_FVC
-                * register. If we failed to take one field, try the
-                * rest 3 choices.
-                */
-               BUG_ON(__BITS_VALUE(reg1->idx, 1, 8) != 0xff);
-               idx[0] -= EXTRA_REG_NHMEX_M_ZDP_CTL_FVC;
-               idx[0] = (idx[0] + 1) % 4;
-               idx[0] += EXTRA_REG_NHMEX_M_ZDP_CTL_FVC;
-               if (idx[0] != __BITS_VALUE(reg1->idx, 0, 8)) {
-                       config1 = nhmex_mbox_alter_er(event, idx[0], false);
-                       goto again;
+       raw_spin_lock(&uncore_box_lock);
+       /* Recheck in lock to handle races. */
+       if (*per_cpu_ptr(pmu->box, cpu))
+               goto out;
+       list_for_each_entry(box, &pmu->box_list, list) {
+               if (box->phys_id == topology_physical_package_id(cpu)) {
+                       atomic_inc(&box->refcnt);
+                       *per_cpu_ptr(pmu->box, cpu) = box;
+                       break;
                }
        }
+out:
+       raw_spin_unlock(&uncore_box_lock);
 
-       if (alloc & 0x1)
-               nhmex_mbox_put_shared_reg(box, idx[0]);
-       if (alloc & 0x2)
-               nhmex_mbox_put_shared_reg(box, idx[1]);
-       return &constraint_empty;
-}
-
-static void nhmex_mbox_put_constraint(struct intel_uncore_box *box, struct perf_event *event)
-{
-       struct hw_perf_event_extra *reg1 = &event->hw.extra_reg;
-       struct hw_perf_event_extra *reg2 = &event->hw.branch_reg;
-
-       if (uncore_box_is_fake(box))
-               return;
-
-       if (reg1->alloc & 0x1)
-               nhmex_mbox_put_shared_reg(box, __BITS_VALUE(reg1->idx, 0, 8));
-       if (reg1->alloc & 0x2)
-               nhmex_mbox_put_shared_reg(box, __BITS_VALUE(reg1->idx, 1, 8));
-       reg1->alloc = 0;
-
-       if (reg2->alloc) {
-               nhmex_mbox_put_shared_reg(box, reg2->idx);
-               reg2->alloc = 0;
-       }
-}
-
-static int nhmex_mbox_extra_reg_idx(struct extra_reg *er)
-{
-       if (er->idx < EXTRA_REG_NHMEX_M_ZDP_CTL_FVC)
-               return er->idx;
-       return er->idx + (er->event >> NHMEX_M_PMON_CTL_INC_SEL_SHIFT) - 0xd;
+       return *per_cpu_ptr(pmu->box, cpu);
 }
 
-static int nhmex_mbox_hw_config(struct intel_uncore_box *box, struct perf_event *event)
+struct intel_uncore_box *uncore_event_to_box(struct perf_event *event)
 {
-       struct intel_uncore_type *type = box->pmu->type;
-       struct hw_perf_event_extra *reg1 = &event->hw.extra_reg;
-       struct hw_perf_event_extra *reg2 = &event->hw.branch_reg;
-       struct extra_reg *er;
-       unsigned msr;
-       int reg_idx = 0;
-       /*
-        * The mbox events may require 2 extra MSRs at the most. But only
-        * the lower 32 bits in these MSRs are significant, so we can use
-        * config1 to pass two MSRs' config.
-        */
-       for (er = nhmex_uncore_mbox_extra_regs; er->msr; er++) {
-               if (er->event != (event->hw.config & er->config_mask))
-                       continue;
-               if (event->attr.config1 & ~er->valid_mask)
-                       return -EINVAL;
-
-               msr = er->msr + type->msr_offset * box->pmu->pmu_idx;
-               if (WARN_ON_ONCE(msr >= 0xffff || er->idx >= 0xff))
-                       return -EINVAL;
-
-               /* always use the 32~63 bits to pass the PLD config */
-               if (er->idx == EXTRA_REG_NHMEX_M_PLD)
-                       reg_idx = 1;
-               else if (WARN_ON_ONCE(reg_idx > 0))
-                       return -EINVAL;
-
-               reg1->idx &= ~(0xff << (reg_idx * 8));
-               reg1->reg &= ~(0xffff << (reg_idx * 16));
-               reg1->idx |= nhmex_mbox_extra_reg_idx(er) << (reg_idx * 8);
-               reg1->reg |= msr << (reg_idx * 16);
-               reg1->config = event->attr.config1;
-               reg_idx++;
-       }
        /*
-        * The mbox only provides ability to perform address matching
-        * for the PLD events.
+        * perf core schedules event on the basis of cpu, uncore events are
+        * collected by one of the cpus inside a physical package.
         */
-       if (reg_idx == 2) {
-               reg2->idx = EXTRA_REG_NHMEX_M_FILTER;
-               if (event->attr.config2 & NHMEX_M_PMON_MM_CFG_EN)
-                       reg2->config = event->attr.config2;
-               else
-                       reg2->config = ~0ULL;
-               if (box->pmu->pmu_idx == 0)
-                       reg2->reg = NHMEX_M0_MSR_PMU_MM_CFG;
-               else
-                       reg2->reg = NHMEX_M1_MSR_PMU_MM_CFG;
-       }
-       return 0;
-}
-
-static u64 nhmex_mbox_shared_reg_config(struct intel_uncore_box *box, int idx)
-{
-       struct intel_uncore_extra_reg *er;
-       unsigned long flags;
-       u64 config;
-
-       if (idx < EXTRA_REG_NHMEX_M_ZDP_CTL_FVC)
-               return box->shared_regs[idx].config;
-
-       er = &box->shared_regs[EXTRA_REG_NHMEX_M_ZDP_CTL_FVC];
-       raw_spin_lock_irqsave(&er->lock, flags);
-       config = er->config;
-       raw_spin_unlock_irqrestore(&er->lock, flags);
-       return config;
-}
-
-static void nhmex_mbox_msr_enable_event(struct intel_uncore_box *box, struct perf_event *event)
-{
-       struct hw_perf_event *hwc = &event->hw;
-       struct hw_perf_event_extra *reg1 = &hwc->extra_reg;
-       struct hw_perf_event_extra *reg2 = &hwc->branch_reg;
-       int idx;
-
-       idx = __BITS_VALUE(reg1->idx, 0, 8);
-       if (idx != 0xff)
-               wrmsrl(__BITS_VALUE(reg1->reg, 0, 16),
-                       nhmex_mbox_shared_reg_config(box, idx));
-       idx = __BITS_VALUE(reg1->idx, 1, 8);
-       if (idx != 0xff)
-               wrmsrl(__BITS_VALUE(reg1->reg, 1, 16),
-                       nhmex_mbox_shared_reg_config(box, idx));
-
-       if (reg2->idx != EXTRA_REG_NONE) {
-               wrmsrl(reg2->reg, 0);
-               if (reg2->config != ~0ULL) {
-                       wrmsrl(reg2->reg + 1,
-                               reg2->config & NHMEX_M_PMON_ADDR_MATCH_MASK);
-                       wrmsrl(reg2->reg + 2, NHMEX_M_PMON_ADDR_MASK_MASK &
-                               (reg2->config >> NHMEX_M_PMON_ADDR_MASK_SHIFT));
-                       wrmsrl(reg2->reg, NHMEX_M_PMON_MM_CFG_EN);
-               }
-       }
-
-       wrmsrl(hwc->config_base, hwc->config | NHMEX_PMON_CTL_EN_BIT0);
+       return uncore_pmu_to_box(uncore_event_to_pmu(event), smp_processor_id());
 }
 
-DEFINE_UNCORE_FORMAT_ATTR(count_mode,          count_mode,     "config:2-3");
-DEFINE_UNCORE_FORMAT_ATTR(storage_mode,                storage_mode,   "config:4-5");
-DEFINE_UNCORE_FORMAT_ATTR(wrap_mode,           wrap_mode,      "config:6");
-DEFINE_UNCORE_FORMAT_ATTR(flag_mode,           flag_mode,      "config:7");
-DEFINE_UNCORE_FORMAT_ATTR(inc_sel,             inc_sel,        "config:9-13");
-DEFINE_UNCORE_FORMAT_ATTR(set_flag_sel,                set_flag_sel,   "config:19-21");
-DEFINE_UNCORE_FORMAT_ATTR(filter_cfg_en,       filter_cfg_en,  "config2:63");
-DEFINE_UNCORE_FORMAT_ATTR(filter_match,                filter_match,   "config2:0-33");
-DEFINE_UNCORE_FORMAT_ATTR(filter_mask,         filter_mask,    "config2:34-61");
-DEFINE_UNCORE_FORMAT_ATTR(dsp,                 dsp,            "config1:0-31");
-DEFINE_UNCORE_FORMAT_ATTR(thr,                 thr,            "config1:0-31");
-DEFINE_UNCORE_FORMAT_ATTR(fvc,                 fvc,            "config1:0-31");
-DEFINE_UNCORE_FORMAT_ATTR(pgt,                 pgt,            "config1:0-31");
-DEFINE_UNCORE_FORMAT_ATTR(map,                 map,            "config1:0-31");
-DEFINE_UNCORE_FORMAT_ATTR(iss,                 iss,            "config1:0-31");
-DEFINE_UNCORE_FORMAT_ATTR(pld,                 pld,            "config1:32-63");
-
-static struct attribute *nhmex_uncore_mbox_formats_attr[] = {
-       &format_attr_count_mode.attr,
-       &format_attr_storage_mode.attr,
-       &format_attr_wrap_mode.attr,
-       &format_attr_flag_mode.attr,
-       &format_attr_inc_sel.attr,
-       &format_attr_set_flag_sel.attr,
-       &format_attr_filter_cfg_en.attr,
-       &format_attr_filter_match.attr,
-       &format_attr_filter_mask.attr,
-       &format_attr_dsp.attr,
-       &format_attr_thr.attr,
-       &format_attr_fvc.attr,
-       &format_attr_pgt.attr,
-       &format_attr_map.attr,
-       &format_attr_iss.attr,
-       &format_attr_pld.attr,
-       NULL,
-};
-
-static struct attribute_group nhmex_uncore_mbox_format_group = {
-       .name           = "format",
-       .attrs          = nhmex_uncore_mbox_formats_attr,
-};
-
-static struct uncore_event_desc nhmex_uncore_mbox_events[] = {
-       INTEL_UNCORE_EVENT_DESC(bbox_cmds_read, "inc_sel=0xd,fvc=0x2800"),
-       INTEL_UNCORE_EVENT_DESC(bbox_cmds_write, "inc_sel=0xd,fvc=0x2820"),
-       { /* end: all zeroes */ },
-};
-
-static struct uncore_event_desc wsmex_uncore_mbox_events[] = {
-       INTEL_UNCORE_EVENT_DESC(bbox_cmds_read, "inc_sel=0xd,fvc=0x5000"),
-       INTEL_UNCORE_EVENT_DESC(bbox_cmds_write, "inc_sel=0xd,fvc=0x5040"),
-       { /* end: all zeroes */ },
-};
-
-static struct intel_uncore_ops nhmex_uncore_mbox_ops = {
-       NHMEX_UNCORE_OPS_COMMON_INIT(),
-       .enable_event   = nhmex_mbox_msr_enable_event,
-       .hw_config      = nhmex_mbox_hw_config,
-       .get_constraint = nhmex_mbox_get_constraint,
-       .put_constraint = nhmex_mbox_put_constraint,
-};
-
-static struct intel_uncore_type nhmex_uncore_mbox = {
-       .name                   = "mbox",
-       .num_counters           = 6,
-       .num_boxes              = 2,
-       .perf_ctr_bits          = 48,
-       .event_ctl              = NHMEX_M0_MSR_PMU_CTL0,
-       .perf_ctr               = NHMEX_M0_MSR_PMU_CNT0,
-       .event_mask             = NHMEX_M_PMON_RAW_EVENT_MASK,
-       .box_ctl                = NHMEX_M0_MSR_GLOBAL_CTL,
-       .msr_offset             = NHMEX_M_MSR_OFFSET,
-       .pair_ctr_ctl           = 1,
-       .num_shared_regs        = 8,
-       .event_descs            = nhmex_uncore_mbox_events,
-       .ops                    = &nhmex_uncore_mbox_ops,
-       .format_group           = &nhmex_uncore_mbox_format_group,
-};
-
-static void nhmex_rbox_alter_er(struct intel_uncore_box *box, struct perf_event *event)
+u64 uncore_msr_read_counter(struct intel_uncore_box *box, struct perf_event *event)
 {
-       struct hw_perf_event *hwc = &event->hw;
-       struct hw_perf_event_extra *reg1 = &hwc->extra_reg;
+       u64 count;
 
-       /* adjust the main event selector and extra register index */
-       if (reg1->idx % 2) {
-               reg1->idx--;
-               hwc->config -= 1 << NHMEX_R_PMON_CTL_EV_SEL_SHIFT;
-       } else {
-               reg1->idx++;
-               hwc->config += 1 << NHMEX_R_PMON_CTL_EV_SEL_SHIFT;
-       }
+       rdmsrl(event->hw.event_base, count);
 
-       /* adjust extra register config */
-       switch (reg1->idx % 6) {
-       case 2:
-               /* shift the 8~15 bits to the 0~7 bits */
-               reg1->config >>= 8;
-               break;
-       case 3:
-               /* shift the 0~7 bits to the 8~15 bits */
-               reg1->config <<= 8;
-               break;
-       };
+       return count;
 }
 
 /*
- * Each rbox has 4 event set which monitor PQI port 0~3 or 4~7.
- * An event set consists of 6 events, the 3rd and 4th events in
- * an event set use the same extra register. So an event set uses
- * 5 extra registers.
+ * generic get constraint function for shared match/mask registers.
  */
-static struct event_constraint *
-nhmex_rbox_get_constraint(struct intel_uncore_box *box, struct perf_event *event)
+struct event_constraint *
+uncore_get_constraint(struct intel_uncore_box *box, struct perf_event *event)
 {
-       struct hw_perf_event *hwc = &event->hw;
-       struct hw_perf_event_extra *reg1 = &hwc->extra_reg;
-       struct hw_perf_event_extra *reg2 = &hwc->branch_reg;
        struct intel_uncore_extra_reg *er;
+       struct hw_perf_event_extra *reg1 = &event->hw.extra_reg;
+       struct hw_perf_event_extra *reg2 = &event->hw.branch_reg;
        unsigned long flags;
-       int idx, er_idx;
-       u64 config1;
        bool ok = false;
 
-       if (!uncore_box_is_fake(box) && reg1->alloc)
+       /*
+        * reg->alloc can be set due to existing state, so for fake box we
+        * need to ignore this, otherwise we might fail to allocate proper
+        * fake state for this extra reg constraint.
+        */
+       if (reg1->idx == EXTRA_REG_NONE ||
+           (!uncore_box_is_fake(box) && reg1->alloc))
                return NULL;
 
-       idx = reg1->idx % 6;
-       config1 = reg1->config;
-again:
-       er_idx = idx;
-       /* the 3rd and 4th events use the same extra register */
-       if (er_idx > 2)
-               er_idx--;
-       er_idx += (reg1->idx / 6) * 5;
-
-       er = &box->shared_regs[er_idx];
+       er = &box->shared_regs[reg1->idx];
        raw_spin_lock_irqsave(&er->lock, flags);
-       if (idx < 2) {
-               if (!atomic_read(&er->ref) || er->config == reg1->config) {
-                       atomic_inc(&er->ref);
-                       er->config = reg1->config;
-                       ok = true;
-               }
-       } else if (idx == 2 || idx == 3) {
-               /*
-                * these two events use different fields in a extra register,
-                * the 0~7 bits and the 8~15 bits respectively.
-                */
-               u64 mask = 0xff << ((idx - 2) * 8);
-               if (!__BITS_VALUE(atomic_read(&er->ref), idx - 2, 8) ||
-                               !((er->config ^ config1) & mask)) {
-                       atomic_add(1 << ((idx - 2) * 8), &er->ref);
-                       er->config &= ~mask;
-                       er->config |= config1 & mask;
-                       ok = true;
-               }
-       } else {
-               if (!atomic_read(&er->ref) ||
-                               (er->config == (hwc->config >> 32) &&
-                                er->config1 == reg1->config &&
-                                er->config2 == reg2->config)) {
-                       atomic_inc(&er->ref);
-                       er->config = (hwc->config >> 32);
-                       er->config1 = reg1->config;
-                       er->config2 = reg2->config;
-                       ok = true;
-               }
+       if (!atomic_read(&er->ref) ||
+           (er->config1 == reg1->config && er->config2 == reg2->config)) {
+               atomic_inc(&er->ref);
+               er->config1 = reg1->config;
+               er->config2 = reg2->config;
+               ok = true;
        }
        raw_spin_unlock_irqrestore(&er->lock, flags);
 
-       if (!ok) {
-               /*
-                * The Rbox events are always in pairs. The paired
-                * events are functional identical, but use different
-                * extra registers. If we failed to take an extra
-                * register, try the alternative.
-                */
-               idx ^= 1;
-               if (idx != reg1->idx % 6) {
-                       if (idx == 2)
-                               config1 >>= 8;
-                       else if (idx == 3)
-                               config1 <<= 8;
-                       goto again;
-               }
-       } else {
-               if (!uncore_box_is_fake(box)) {
-                       if (idx != reg1->idx % 6)
-                               nhmex_rbox_alter_er(box, event);
+       if (ok) {
+               if (!uncore_box_is_fake(box))
                        reg1->alloc = 1;
-               }
                return NULL;
        }
-       return &constraint_empty;
+
+       return &uncore_constraint_empty;
 }
 
-static void nhmex_rbox_put_constraint(struct intel_uncore_box *box, struct perf_event *event)
+void uncore_put_constraint(struct intel_uncore_box *box, struct perf_event *event)
 {
        struct intel_uncore_extra_reg *er;
        struct hw_perf_event_extra *reg1 = &event->hw.extra_reg;
-       int idx, er_idx;
 
+       /*
+        * Only put constraint if extra reg was actually allocated. Also
+        * takes care of event which do not use an extra shared reg.
+        *
+        * Also, if this is a fake box we shouldn't touch any event state
+        * (reg->alloc) and we don't care about leaving inconsistent box
+        * state either since it will be thrown out.
+        */
        if (uncore_box_is_fake(box) || !reg1->alloc)
                return;
 
-       idx = reg1->idx % 6;
-       er_idx = idx;
-       if (er_idx > 2)
-               er_idx--;
-       er_idx += (reg1->idx / 6) * 5;
-
-       er = &box->shared_regs[er_idx];
-       if (idx == 2 || idx == 3)
-               atomic_sub(1 << ((idx - 2) * 8), &er->ref);
-       else
-               atomic_dec(&er->ref);
-
+       er = &box->shared_regs[reg1->idx];
+       atomic_dec(&er->ref);
        reg1->alloc = 0;
 }
 
-static int nhmex_rbox_hw_config(struct intel_uncore_box *box, struct perf_event *event)
-{
-       struct hw_perf_event *hwc = &event->hw;
-       struct hw_perf_event_extra *reg1 = &event->hw.extra_reg;
-       struct hw_perf_event_extra *reg2 = &event->hw.branch_reg;
-       int idx;
-
-       idx = (event->hw.config & NHMEX_R_PMON_CTL_EV_SEL_MASK) >>
-               NHMEX_R_PMON_CTL_EV_SEL_SHIFT;
-       if (idx >= 0x18)
-               return -EINVAL;
-
-       reg1->idx = idx;
-       reg1->config = event->attr.config1;
-
-       switch (idx % 6) {
-       case 4:
-       case 5:
-               hwc->config |= event->attr.config & (~0ULL << 32);
-               reg2->config = event->attr.config2;
-               break;
-       };
-       return 0;
-}
-
-static void nhmex_rbox_msr_enable_event(struct intel_uncore_box *box, struct perf_event *event)
+u64 uncore_shared_reg_config(struct intel_uncore_box *box, int idx)
 {
-       struct hw_perf_event *hwc = &event->hw;
-       struct hw_perf_event_extra *reg1 = &hwc->extra_reg;
-       struct hw_perf_event_extra *reg2 = &hwc->branch_reg;
-       int idx, port;
+       struct intel_uncore_extra_reg *er;
+       unsigned long flags;
+       u64 config;
 
-       idx = reg1->idx;
-       port = idx / 6 + box->pmu->pmu_idx * 4;
+       er = &box->shared_regs[idx];
 
-       switch (idx % 6) {
-       case 0:
-               wrmsrl(NHMEX_R_MSR_PORTN_IPERF_CFG0(port), reg1->config);
-               break;
-       case 1:
-               wrmsrl(NHMEX_R_MSR_PORTN_IPERF_CFG1(port), reg1->config);
-               break;
-       case 2:
-       case 3:
-               wrmsrl(NHMEX_R_MSR_PORTN_QLX_CFG(port),
-                       uncore_shared_reg_config(box, 2 + (idx / 6) * 5));
-               break;
-       case 4:
-               wrmsrl(NHMEX_R_MSR_PORTN_XBR_SET1_MM_CFG(port),
-                       hwc->config >> 32);
-               wrmsrl(NHMEX_R_MSR_PORTN_XBR_SET1_MATCH(port), reg1->config);
-               wrmsrl(NHMEX_R_MSR_PORTN_XBR_SET1_MASK(port), reg2->config);
-               break;
-       case 5:
-               wrmsrl(NHMEX_R_MSR_PORTN_XBR_SET2_MM_CFG(port),
-                       hwc->config >> 32);
-               wrmsrl(NHMEX_R_MSR_PORTN_XBR_SET2_MATCH(port), reg1->config);
-               wrmsrl(NHMEX_R_MSR_PORTN_XBR_SET2_MASK(port), reg2->config);
-               break;
-       };
+       raw_spin_lock_irqsave(&er->lock, flags);
+       config = er->config;
+       raw_spin_unlock_irqrestore(&er->lock, flags);
 
-       wrmsrl(hwc->config_base, NHMEX_PMON_CTL_EN_BIT0 |
-               (hwc->config & NHMEX_R_PMON_CTL_EV_SEL_MASK));
+       return config;
 }
 
-DEFINE_UNCORE_FORMAT_ATTR(xbr_mm_cfg, xbr_mm_cfg, "config:32-63");
-DEFINE_UNCORE_FORMAT_ATTR(xbr_match, xbr_match, "config1:0-63");
-DEFINE_UNCORE_FORMAT_ATTR(xbr_mask, xbr_mask, "config2:0-63");
-DEFINE_UNCORE_FORMAT_ATTR(qlx_cfg, qlx_cfg, "config1:0-15");
-DEFINE_UNCORE_FORMAT_ATTR(iperf_cfg, iperf_cfg, "config1:0-31");
-
-static struct attribute *nhmex_uncore_rbox_formats_attr[] = {
-       &format_attr_event5.attr,
-       &format_attr_xbr_mm_cfg.attr,
-       &format_attr_xbr_match.attr,
-       &format_attr_xbr_mask.attr,
-       &format_attr_qlx_cfg.attr,
-       &format_attr_iperf_cfg.attr,
-       NULL,
-};
-
-static struct attribute_group nhmex_uncore_rbox_format_group = {
-       .name = "format",
-       .attrs = nhmex_uncore_rbox_formats_attr,
-};
-
-static struct uncore_event_desc nhmex_uncore_rbox_events[] = {
-       INTEL_UNCORE_EVENT_DESC(qpi0_flit_send,         "event=0x0,iperf_cfg=0x80000000"),
-       INTEL_UNCORE_EVENT_DESC(qpi1_filt_send,         "event=0x6,iperf_cfg=0x80000000"),
-       INTEL_UNCORE_EVENT_DESC(qpi0_idle_filt,         "event=0x0,iperf_cfg=0x40000000"),
-       INTEL_UNCORE_EVENT_DESC(qpi1_idle_filt,         "event=0x6,iperf_cfg=0x40000000"),
-       INTEL_UNCORE_EVENT_DESC(qpi0_date_response,     "event=0x0,iperf_cfg=0xc4"),
-       INTEL_UNCORE_EVENT_DESC(qpi1_date_response,     "event=0x6,iperf_cfg=0xc4"),
-       { /* end: all zeroes */ },
-};
-
-static struct intel_uncore_ops nhmex_uncore_rbox_ops = {
-       NHMEX_UNCORE_OPS_COMMON_INIT(),
-       .enable_event           = nhmex_rbox_msr_enable_event,
-       .hw_config              = nhmex_rbox_hw_config,
-       .get_constraint         = nhmex_rbox_get_constraint,
-       .put_constraint         = nhmex_rbox_put_constraint,
-};
-
-static struct intel_uncore_type nhmex_uncore_rbox = {
-       .name                   = "rbox",
-       .num_counters           = 8,
-       .num_boxes              = 2,
-       .perf_ctr_bits          = 48,
-       .event_ctl              = NHMEX_R_MSR_PMON_CTL0,
-       .perf_ctr               = NHMEX_R_MSR_PMON_CNT0,
-       .event_mask             = NHMEX_R_PMON_RAW_EVENT_MASK,
-       .box_ctl                = NHMEX_R_MSR_GLOBAL_CTL,
-       .msr_offset             = NHMEX_R_MSR_OFFSET,
-       .pair_ctr_ctl           = 1,
-       .num_shared_regs        = 20,
-       .event_descs            = nhmex_uncore_rbox_events,
-       .ops                    = &nhmex_uncore_rbox_ops,
-       .format_group           = &nhmex_uncore_rbox_format_group
-};
-
-static struct intel_uncore_type *nhmex_msr_uncores[] = {
-       &nhmex_uncore_ubox,
-       &nhmex_uncore_cbox,
-       &nhmex_uncore_bbox,
-       &nhmex_uncore_sbox,
-       &nhmex_uncore_mbox,
-       &nhmex_uncore_rbox,
-       &nhmex_uncore_wbox,
-       NULL,
-};
-/* end of Nehalem-EX uncore support */
-
 static void uncore_assign_hw_event(struct intel_uncore_box *box, struct perf_event *event, int idx)
 {
        struct hw_perf_event *hwc = &event->hw;
@@ -3140,7 +170,7 @@ static void uncore_assign_hw_event(struct intel_uncore_box *box, struct perf_eve
        hwc->event_base  = uncore_perf_ctr(box, hwc->idx);
 }
 
-static void uncore_perf_event_update(struct intel_uncore_box *box, struct perf_event *event)
+void uncore_perf_event_update(struct intel_uncore_box *box, struct perf_event *event)
 {
        u64 prev_count, new_count, delta;
        int shift;
@@ -3201,14 +231,14 @@ static enum hrtimer_restart uncore_pmu_hrtimer(struct hrtimer *hrtimer)
        return HRTIMER_RESTART;
 }
 
-static void uncore_pmu_start_hrtimer(struct intel_uncore_box *box)
+void uncore_pmu_start_hrtimer(struct intel_uncore_box *box)
 {
        __hrtimer_start_range_ns(&box->hrtimer,
                        ns_to_ktime(box->hrtimer_duration), 0,
                        HRTIMER_MODE_REL_PINNED, 0);
 }
 
-static void uncore_pmu_cancel_hrtimer(struct intel_uncore_box *box)
+void uncore_pmu_cancel_hrtimer(struct intel_uncore_box *box)
 {
        hrtimer_cancel(&box->hrtimer);
 }
@@ -3291,7 +321,7 @@ uncore_get_event_constraint(struct intel_uncore_box *box, struct perf_event *eve
        }
 
        if (event->attr.config == UNCORE_FIXED_EVENT)
-               return &constraint_fixed;
+               return &uncore_constraint_fixed;
 
        if (type->constraints) {
                for_each_event_constraint(c, type->constraints) {
@@ -3496,7 +526,7 @@ static void uncore_pmu_event_del(struct perf_event *event, int flags)
        event->hw.last_tag = ~0ULL;
 }
 
-static void uncore_pmu_event_read(struct perf_event *event)
+void uncore_pmu_event_read(struct perf_event *event)
 {
        struct intel_uncore_box *box = uncore_event_to_box(event);
        uncore_perf_event_update(box, event);
@@ -3635,7 +665,7 @@ static struct attribute_group uncore_pmu_attr_group = {
        .attrs = uncore_pmu_attrs,
 };
 
-static int __init uncore_pmu_register(struct intel_uncore_pmu *pmu)
+static int uncore_pmu_register(struct intel_uncore_pmu *pmu)
 {
        int ret;
 
@@ -3758,9 +788,6 @@ fail:
        return ret;
 }
 
-static struct pci_driver *uncore_pci_driver;
-static bool pcidrv_registered;
-
 /*
  * add a pci uncore device
  */
@@ -3770,18 +797,20 @@ static int uncore_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id
        struct intel_uncore_box *box;
        struct intel_uncore_type *type;
        int phys_id;
+       bool first_box = false;
 
-       phys_id = pcibus_to_physid[pdev->bus->number];
+       phys_id = uncore_pcibus_to_physid[pdev->bus->number];
        if (phys_id < 0)
                return -ENODEV;
 
        if (UNCORE_PCI_DEV_TYPE(id->driver_data) == UNCORE_EXTRA_PCI_DEV) {
-               extra_pci_dev[phys_id][UNCORE_PCI_DEV_IDX(id->driver_data)] = pdev;
+               int idx = UNCORE_PCI_DEV_IDX(id->driver_data);
+               uncore_extra_pci_dev[phys_id][idx] = pdev;
                pci_set_drvdata(pdev, NULL);
                return 0;
        }
 
-       type = pci_uncores[UNCORE_PCI_DEV_TYPE(id->driver_data)];
+       type = uncore_pci_uncores[UNCORE_PCI_DEV_TYPE(id->driver_data)];
        box = uncore_alloc_box(type, NUMA_NO_NODE);
        if (!box)
                return -ENOMEM;
@@ -3803,9 +832,13 @@ static int uncore_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id
        pci_set_drvdata(pdev, box);
 
        raw_spin_lock(&uncore_box_lock);
+       if (list_empty(&pmu->box_list))
+               first_box = true;
        list_add_tail(&box->list, &pmu->box_list);
        raw_spin_unlock(&uncore_box_lock);
 
+       if (first_box)
+               uncore_pmu_register(pmu);
        return 0;
 }
 
@@ -3813,13 +846,14 @@ static void uncore_pci_remove(struct pci_dev *pdev)
 {
        struct intel_uncore_box *box = pci_get_drvdata(pdev);
        struct intel_uncore_pmu *pmu;
-       int i, cpu, phys_id = pcibus_to_physid[pdev->bus->number];
+       int i, cpu, phys_id = uncore_pcibus_to_physid[pdev->bus->number];
+       bool last_box = false;
 
        box = pci_get_drvdata(pdev);
        if (!box) {
                for (i = 0; i < UNCORE_EXTRA_PCI_DEV_MAX; i++) {
-                       if (extra_pci_dev[phys_id][i] == pdev) {
-                               extra_pci_dev[phys_id][i] = NULL;
+                       if (uncore_extra_pci_dev[phys_id][i] == pdev) {
+                               uncore_extra_pci_dev[phys_id][i] = NULL;
                                break;
                        }
                }
@@ -3835,6 +869,8 @@ static void uncore_pci_remove(struct pci_dev *pdev)
 
        raw_spin_lock(&uncore_box_lock);
        list_del(&box->list);
+       if (list_empty(&pmu->box_list))
+               last_box = true;
        raw_spin_unlock(&uncore_box_lock);
 
        for_each_possible_cpu(cpu) {
@@ -3846,6 +882,9 @@ static void uncore_pci_remove(struct pci_dev *pdev)
 
        WARN_ON_ONCE(atomic_read(&box->refcnt) != 1);
        kfree(box);
+
+       if (last_box)
+               perf_pmu_unregister(&pmu->pmu);
 }
 
 static int __init uncore_pci_init(void)
@@ -3854,46 +893,32 @@ static int __init uncore_pci_init(void)
 
        switch (boot_cpu_data.x86_model) {
        case 45: /* Sandy Bridge-EP */
-               ret = snbep_pci2phy_map_init(0x3ce0);
-               if (ret)
-                       return ret;
-               pci_uncores = snbep_pci_uncores;
-               uncore_pci_driver = &snbep_uncore_pci_driver;
+               ret = snbep_uncore_pci_init();
                break;
-       case 62: /* IvyTown */
-               ret = snbep_pci2phy_map_init(0x0e1e);
-               if (ret)
-                       return ret;
-               pci_uncores = ivt_pci_uncores;
-               uncore_pci_driver = &ivt_uncore_pci_driver;
+       case 62: /* Ivy Bridge-EP */
+               ret = ivbep_uncore_pci_init();
+               break;
+       case 63: /* Haswell-EP */
+               ret = hswep_uncore_pci_init();
                break;
        case 42: /* Sandy Bridge */
-               ret = snb_pci2phy_map_init(PCI_DEVICE_ID_INTEL_SNB_IMC);
-               if (ret)
-                       return ret;
-               pci_uncores = snb_pci_uncores;
-               uncore_pci_driver = &snb_uncore_pci_driver;
+               ret = snb_uncore_pci_init();
                break;
        case 58: /* Ivy Bridge */
-               ret = snb_pci2phy_map_init(PCI_DEVICE_ID_INTEL_IVB_IMC);
-               if (ret)
-                       return ret;
-               pci_uncores = snb_pci_uncores;
-               uncore_pci_driver = &ivb_uncore_pci_driver;
+               ret = ivb_uncore_pci_init();
                break;
        case 60: /* Haswell */
        case 69: /* Haswell Celeron */
-               ret = snb_pci2phy_map_init(PCI_DEVICE_ID_INTEL_HSW_IMC);
-               if (ret)
-                       return ret;
-               pci_uncores = snb_pci_uncores;
-               uncore_pci_driver = &hsw_uncore_pci_driver;
+               ret = hsw_uncore_pci_init();
                break;
        default:
                return 0;
        }
 
-       ret = uncore_types_init(pci_uncores);
+       if (ret)
+               return ret;
+
+       ret = uncore_types_init(uncore_pci_uncores);
        if (ret)
                return ret;
 
@@ -3904,7 +929,7 @@ static int __init uncore_pci_init(void)
        if (ret == 0)
                pcidrv_registered = true;
        else
-               uncore_types_exit(pci_uncores);
+               uncore_types_exit(uncore_pci_uncores);
 
        return ret;
 }
@@ -3914,7 +939,7 @@ static void __init uncore_pci_exit(void)
        if (pcidrv_registered) {
                pcidrv_registered = false;
                pci_unregister_driver(uncore_pci_driver);
-               uncore_types_exit(pci_uncores);
+               uncore_types_exit(uncore_pci_uncores);
        }
 }
 
@@ -3940,8 +965,8 @@ static void uncore_cpu_dying(int cpu)
        struct intel_uncore_box *box;
        int i, j;
 
-       for (i = 0; msr_uncores[i]; i++) {
-               type = msr_uncores[i];
+       for (i = 0; uncore_msr_uncores[i]; i++) {
+               type = uncore_msr_uncores[i];
                for (j = 0; j < type->num_boxes; j++) {
                        pmu = &type->pmus[j];
                        box = *per_cpu_ptr(pmu->box, cpu);
@@ -3961,8 +986,8 @@ static int uncore_cpu_starting(int cpu)
 
        phys_id = topology_physical_package_id(cpu);
 
-       for (i = 0; msr_uncores[i]; i++) {
-               type = msr_uncores[i];
+       for (i = 0; uncore_msr_uncores[i]; i++) {
+               type = uncore_msr_uncores[i];
                for (j = 0; j < type->num_boxes; j++) {
                        pmu = &type->pmus[j];
                        box = *per_cpu_ptr(pmu->box, cpu);
@@ -4002,8 +1027,8 @@ static int uncore_cpu_prepare(int cpu, int phys_id)
        struct intel_uncore_box *box;
        int i, j;
 
-       for (i = 0; msr_uncores[i]; i++) {
-               type = msr_uncores[i];
+       for (i = 0; uncore_msr_uncores[i]; i++) {
+               type = uncore_msr_uncores[i];
                for (j = 0; j < type->num_boxes; j++) {
                        pmu = &type->pmus[j];
                        if (pmu->func_id < 0)
@@ -4083,8 +1108,8 @@ static void uncore_event_exit_cpu(int cpu)
        if (target >= 0)
                cpumask_set_cpu(target, &uncore_cpu_mask);
 
-       uncore_change_context(msr_uncores, cpu, target);
-       uncore_change_context(pci_uncores, cpu, target);
+       uncore_change_context(uncore_msr_uncores, cpu, target);
+       uncore_change_context(uncore_pci_uncores, cpu, target);
 }
 
 static void uncore_event_init_cpu(int cpu)
@@ -4099,8 +1124,8 @@ static void uncore_event_init_cpu(int cpu)
 
        cpumask_set_cpu(cpu, &uncore_cpu_mask);
 
-       uncore_change_context(msr_uncores, -1, cpu);
-       uncore_change_context(pci_uncores, -1, cpu);
+       uncore_change_context(uncore_msr_uncores, -1, cpu);
+       uncore_change_context(uncore_pci_uncores, -1, cpu);
 }
 
 static int uncore_cpu_notifier(struct notifier_block *self,
@@ -4160,47 +1185,37 @@ static void __init uncore_cpu_setup(void *dummy)
 
 static int __init uncore_cpu_init(void)
 {
-       int ret, max_cores;
+       int ret;
 
-       max_cores = boot_cpu_data.x86_max_cores;
        switch (boot_cpu_data.x86_model) {
        case 26: /* Nehalem */
        case 30:
        case 37: /* Westmere */
        case 44:
-               msr_uncores = nhm_msr_uncores;
+               nhm_uncore_cpu_init();
                break;
        case 42: /* Sandy Bridge */
        case 58: /* Ivy Bridge */
-               if (snb_uncore_cbox.num_boxes > max_cores)
-                       snb_uncore_cbox.num_boxes = max_cores;
-               msr_uncores = snb_msr_uncores;
+               snb_uncore_cpu_init();
                break;
        case 45: /* Sandy Bridge-EP */
-               if (snbep_uncore_cbox.num_boxes > max_cores)
-                       snbep_uncore_cbox.num_boxes = max_cores;
-               msr_uncores = snbep_msr_uncores;
+               snbep_uncore_cpu_init();
                break;
        case 46: /* Nehalem-EX */
-               uncore_nhmex = true;
        case 47: /* Westmere-EX aka. Xeon E7 */
-               if (!uncore_nhmex)
-                       nhmex_uncore_mbox.event_descs = wsmex_uncore_mbox_events;
-               if (nhmex_uncore_cbox.num_boxes > max_cores)
-                       nhmex_uncore_cbox.num_boxes = max_cores;
-               msr_uncores = nhmex_msr_uncores;
+               nhmex_uncore_cpu_init();
                break;
-       case 62: /* IvyTown */
-               if (ivt_uncore_cbox.num_boxes > max_cores)
-                       ivt_uncore_cbox.num_boxes = max_cores;
-               msr_uncores = ivt_msr_uncores;
+       case 62: /* Ivy Bridge-EP */
+               ivbep_uncore_cpu_init();
+               break;
+       case 63: /* Haswell-EP */
+               hswep_uncore_cpu_init();
                break;
-
        default:
                return 0;
        }
 
-       ret = uncore_types_init(msr_uncores);
+       ret = uncore_types_init(uncore_msr_uncores);
        if (ret)
                return ret;
 
@@ -4213,16 +1228,8 @@ static int __init uncore_pmus_register(void)
        struct intel_uncore_type *type;
        int i, j;
 
-       for (i = 0; msr_uncores[i]; i++) {
-               type = msr_uncores[i];
-               for (j = 0; j < type->num_boxes; j++) {
-                       pmu = &type->pmus[j];
-                       uncore_pmu_register(pmu);
-               }
-       }
-
-       for (i = 0; pci_uncores[i]; i++) {
-               type = pci_uncores[i];
+       for (i = 0; uncore_msr_uncores[i]; i++) {
+               type = uncore_msr_uncores[i];
                for (j = 0; j < type->num_boxes; j++) {
                        pmu = &type->pmus[j];
                        uncore_pmu_register(pmu);
index 90236f0c94a90679506973efe6e56c51bfb9bb2f..18eb78bbdd1003a5f7d1d8b302b608405214741f 100644 (file)
 
 #define UNCORE_EVENT_CONSTRAINT(c, n) EVENT_CONSTRAINT(c, n, 0xff)
 
-/* SNB event control */
-#define SNB_UNC_CTL_EV_SEL_MASK                        0x000000ff
-#define SNB_UNC_CTL_UMASK_MASK                 0x0000ff00
-#define SNB_UNC_CTL_EDGE_DET                   (1 << 18)
-#define SNB_UNC_CTL_EN                         (1 << 22)
-#define SNB_UNC_CTL_INVERT                     (1 << 23)
-#define SNB_UNC_CTL_CMASK_MASK                 0x1f000000
-#define NHM_UNC_CTL_CMASK_MASK                 0xff000000
-#define NHM_UNC_FIXED_CTR_CTL_EN               (1 << 0)
-
-#define SNB_UNC_RAW_EVENT_MASK                 (SNB_UNC_CTL_EV_SEL_MASK | \
-                                                SNB_UNC_CTL_UMASK_MASK | \
-                                                SNB_UNC_CTL_EDGE_DET | \
-                                                SNB_UNC_CTL_INVERT | \
-                                                SNB_UNC_CTL_CMASK_MASK)
-
-#define NHM_UNC_RAW_EVENT_MASK                 (SNB_UNC_CTL_EV_SEL_MASK | \
-                                                SNB_UNC_CTL_UMASK_MASK | \
-                                                SNB_UNC_CTL_EDGE_DET | \
-                                                SNB_UNC_CTL_INVERT | \
-                                                NHM_UNC_CTL_CMASK_MASK)
-
-/* SNB global control register */
-#define SNB_UNC_PERF_GLOBAL_CTL                 0x391
-#define SNB_UNC_FIXED_CTR_CTRL                  0x394
-#define SNB_UNC_FIXED_CTR                       0x395
-
-/* SNB uncore global control */
-#define SNB_UNC_GLOBAL_CTL_CORE_ALL             ((1 << 4) - 1)
-#define SNB_UNC_GLOBAL_CTL_EN                   (1 << 29)
-
-/* SNB Cbo register */
-#define SNB_UNC_CBO_0_PERFEVTSEL0               0x700
-#define SNB_UNC_CBO_0_PER_CTR0                  0x706
-#define SNB_UNC_CBO_MSR_OFFSET                  0x10
-
-/* NHM global control register */
-#define NHM_UNC_PERF_GLOBAL_CTL                 0x391
-#define NHM_UNC_FIXED_CTR                       0x394
-#define NHM_UNC_FIXED_CTR_CTRL                  0x395
-
-/* NHM uncore global control */
-#define NHM_UNC_GLOBAL_CTL_EN_PC_ALL            ((1ULL << 8) - 1)
-#define NHM_UNC_GLOBAL_CTL_EN_FC                (1ULL << 32)
-
-/* NHM uncore register */
-#define NHM_UNC_PERFEVTSEL0                     0x3c0
-#define NHM_UNC_UNCORE_PMC0                     0x3b0
-
-/* SNB-EP Box level control */
-#define SNBEP_PMON_BOX_CTL_RST_CTRL    (1 << 0)
-#define SNBEP_PMON_BOX_CTL_RST_CTRS    (1 << 1)
-#define SNBEP_PMON_BOX_CTL_FRZ         (1 << 8)
-#define SNBEP_PMON_BOX_CTL_FRZ_EN      (1 << 16)
-#define SNBEP_PMON_BOX_CTL_INT         (SNBEP_PMON_BOX_CTL_RST_CTRL | \
-                                        SNBEP_PMON_BOX_CTL_RST_CTRS | \
-                                        SNBEP_PMON_BOX_CTL_FRZ_EN)
-/* SNB-EP event control */
-#define SNBEP_PMON_CTL_EV_SEL_MASK     0x000000ff
-#define SNBEP_PMON_CTL_UMASK_MASK      0x0000ff00
-#define SNBEP_PMON_CTL_RST             (1 << 17)
-#define SNBEP_PMON_CTL_EDGE_DET                (1 << 18)
-#define SNBEP_PMON_CTL_EV_SEL_EXT      (1 << 21)
-#define SNBEP_PMON_CTL_EN              (1 << 22)
-#define SNBEP_PMON_CTL_INVERT          (1 << 23)
-#define SNBEP_PMON_CTL_TRESH_MASK      0xff000000
-#define SNBEP_PMON_RAW_EVENT_MASK      (SNBEP_PMON_CTL_EV_SEL_MASK | \
-                                        SNBEP_PMON_CTL_UMASK_MASK | \
-                                        SNBEP_PMON_CTL_EDGE_DET | \
-                                        SNBEP_PMON_CTL_INVERT | \
-                                        SNBEP_PMON_CTL_TRESH_MASK)
-
-/* SNB-EP Ubox event control */
-#define SNBEP_U_MSR_PMON_CTL_TRESH_MASK                0x1f000000
-#define SNBEP_U_MSR_PMON_RAW_EVENT_MASK                \
-                               (SNBEP_PMON_CTL_EV_SEL_MASK | \
-                                SNBEP_PMON_CTL_UMASK_MASK | \
-                                SNBEP_PMON_CTL_EDGE_DET | \
-                                SNBEP_PMON_CTL_INVERT | \
-                                SNBEP_U_MSR_PMON_CTL_TRESH_MASK)
-
-#define SNBEP_CBO_PMON_CTL_TID_EN              (1 << 19)
-#define SNBEP_CBO_MSR_PMON_RAW_EVENT_MASK      (SNBEP_PMON_RAW_EVENT_MASK | \
-                                                SNBEP_CBO_PMON_CTL_TID_EN)
-
-/* SNB-EP PCU event control */
-#define SNBEP_PCU_MSR_PMON_CTL_OCC_SEL_MASK    0x0000c000
-#define SNBEP_PCU_MSR_PMON_CTL_TRESH_MASK      0x1f000000
-#define SNBEP_PCU_MSR_PMON_CTL_OCC_INVERT      (1 << 30)
-#define SNBEP_PCU_MSR_PMON_CTL_OCC_EDGE_DET    (1 << 31)
-#define SNBEP_PCU_MSR_PMON_RAW_EVENT_MASK      \
-                               (SNBEP_PMON_CTL_EV_SEL_MASK | \
-                                SNBEP_PCU_MSR_PMON_CTL_OCC_SEL_MASK | \
-                                SNBEP_PMON_CTL_EDGE_DET | \
-                                SNBEP_PMON_CTL_EV_SEL_EXT | \
-                                SNBEP_PMON_CTL_INVERT | \
-                                SNBEP_PCU_MSR_PMON_CTL_TRESH_MASK | \
-                                SNBEP_PCU_MSR_PMON_CTL_OCC_INVERT | \
-                                SNBEP_PCU_MSR_PMON_CTL_OCC_EDGE_DET)
-
-#define SNBEP_QPI_PCI_PMON_RAW_EVENT_MASK      \
-                               (SNBEP_PMON_RAW_EVENT_MASK | \
-                                SNBEP_PMON_CTL_EV_SEL_EXT)
-
-/* SNB-EP pci control register */
-#define SNBEP_PCI_PMON_BOX_CTL                 0xf4
-#define SNBEP_PCI_PMON_CTL0                    0xd8
-/* SNB-EP pci counter register */
-#define SNBEP_PCI_PMON_CTR0                    0xa0
-
-/* SNB-EP home agent register */
-#define SNBEP_HA_PCI_PMON_BOX_ADDRMATCH0       0x40
-#define SNBEP_HA_PCI_PMON_BOX_ADDRMATCH1       0x44
-#define SNBEP_HA_PCI_PMON_BOX_OPCODEMATCH      0x48
-/* SNB-EP memory controller register */
-#define SNBEP_MC_CHy_PCI_PMON_FIXED_CTL                0xf0
-#define SNBEP_MC_CHy_PCI_PMON_FIXED_CTR                0xd0
-/* SNB-EP QPI register */
-#define SNBEP_Q_Py_PCI_PMON_PKT_MATCH0         0x228
-#define SNBEP_Q_Py_PCI_PMON_PKT_MATCH1         0x22c
-#define SNBEP_Q_Py_PCI_PMON_PKT_MASK0          0x238
-#define SNBEP_Q_Py_PCI_PMON_PKT_MASK1          0x23c
-
-/* SNB-EP Ubox register */
-#define SNBEP_U_MSR_PMON_CTR0                  0xc16
-#define SNBEP_U_MSR_PMON_CTL0                  0xc10
-
-#define SNBEP_U_MSR_PMON_UCLK_FIXED_CTL                0xc08
-#define SNBEP_U_MSR_PMON_UCLK_FIXED_CTR                0xc09
-
-/* SNB-EP Cbo register */
-#define SNBEP_C0_MSR_PMON_CTR0                 0xd16
-#define SNBEP_C0_MSR_PMON_CTL0                 0xd10
-#define SNBEP_C0_MSR_PMON_BOX_CTL              0xd04
-#define SNBEP_C0_MSR_PMON_BOX_FILTER           0xd14
-#define SNBEP_CBO_MSR_OFFSET                   0x20
-
-#define SNBEP_CB0_MSR_PMON_BOX_FILTER_TID      0x1f
-#define SNBEP_CB0_MSR_PMON_BOX_FILTER_NID      0x3fc00
-#define SNBEP_CB0_MSR_PMON_BOX_FILTER_STATE    0x7c0000
-#define SNBEP_CB0_MSR_PMON_BOX_FILTER_OPC      0xff800000
-
-#define SNBEP_CBO_EVENT_EXTRA_REG(e, m, i) {   \
-       .event = (e),                           \
-       .msr = SNBEP_C0_MSR_PMON_BOX_FILTER,    \
-       .config_mask = (m),                     \
-       .idx = (i)                              \
-}
-
-/* SNB-EP PCU register */
-#define SNBEP_PCU_MSR_PMON_CTR0                        0xc36
-#define SNBEP_PCU_MSR_PMON_CTL0                        0xc30
-#define SNBEP_PCU_MSR_PMON_BOX_CTL             0xc24
-#define SNBEP_PCU_MSR_PMON_BOX_FILTER          0xc34
-#define SNBEP_PCU_MSR_PMON_BOX_FILTER_MASK     0xffffffff
-#define SNBEP_PCU_MSR_CORE_C3_CTR              0x3fc
-#define SNBEP_PCU_MSR_CORE_C6_CTR              0x3fd
-
-/* IVT event control */
-#define IVT_PMON_BOX_CTL_INT           (SNBEP_PMON_BOX_CTL_RST_CTRL | \
-                                        SNBEP_PMON_BOX_CTL_RST_CTRS)
-#define IVT_PMON_RAW_EVENT_MASK                (SNBEP_PMON_CTL_EV_SEL_MASK | \
-                                        SNBEP_PMON_CTL_UMASK_MASK | \
-                                        SNBEP_PMON_CTL_EDGE_DET | \
-                                        SNBEP_PMON_CTL_TRESH_MASK)
-/* IVT Ubox */
-#define IVT_U_MSR_PMON_GLOBAL_CTL              0xc00
-#define IVT_U_PMON_GLOBAL_FRZ_ALL              (1 << 31)
-#define IVT_U_PMON_GLOBAL_UNFRZ_ALL            (1 << 29)
-
-#define IVT_U_MSR_PMON_RAW_EVENT_MASK  \
-                               (SNBEP_PMON_CTL_EV_SEL_MASK | \
-                                SNBEP_PMON_CTL_UMASK_MASK | \
-                                SNBEP_PMON_CTL_EDGE_DET | \
-                                SNBEP_U_MSR_PMON_CTL_TRESH_MASK)
-/* IVT Cbo */
-#define IVT_CBO_MSR_PMON_RAW_EVENT_MASK                (IVT_PMON_RAW_EVENT_MASK | \
-                                                SNBEP_CBO_PMON_CTL_TID_EN)
-
-#define IVT_CB0_MSR_PMON_BOX_FILTER_TID                (0x1fULL << 0)
-#define IVT_CB0_MSR_PMON_BOX_FILTER_LINK       (0xfULL << 5)
-#define IVT_CB0_MSR_PMON_BOX_FILTER_STATE      (0x3fULL << 17)
-#define IVT_CB0_MSR_PMON_BOX_FILTER_NID                (0xffffULL << 32)
-#define IVT_CB0_MSR_PMON_BOX_FILTER_OPC                (0x1ffULL << 52)
-#define IVT_CB0_MSR_PMON_BOX_FILTER_C6         (0x1ULL << 61)
-#define IVT_CB0_MSR_PMON_BOX_FILTER_NC         (0x1ULL << 62)
-#define IVT_CB0_MSR_PMON_BOX_FILTER_IOSC       (0x1ULL << 63)
-
-/* IVT home agent */
-#define IVT_HA_PCI_PMON_CTL_Q_OCC_RST          (1 << 16)
-#define IVT_HA_PCI_PMON_RAW_EVENT_MASK         \
-                               (IVT_PMON_RAW_EVENT_MASK | \
-                                IVT_HA_PCI_PMON_CTL_Q_OCC_RST)
-/* IVT PCU */
-#define IVT_PCU_MSR_PMON_RAW_EVENT_MASK        \
-                               (SNBEP_PMON_CTL_EV_SEL_MASK | \
-                                SNBEP_PMON_CTL_EV_SEL_EXT | \
-                                SNBEP_PCU_MSR_PMON_CTL_OCC_SEL_MASK | \
-                                SNBEP_PMON_CTL_EDGE_DET | \
-                                SNBEP_PCU_MSR_PMON_CTL_TRESH_MASK | \
-                                SNBEP_PCU_MSR_PMON_CTL_OCC_INVERT | \
-                                SNBEP_PCU_MSR_PMON_CTL_OCC_EDGE_DET)
-/* IVT QPI */
-#define IVT_QPI_PCI_PMON_RAW_EVENT_MASK        \
-                               (IVT_PMON_RAW_EVENT_MASK | \
-                                SNBEP_PMON_CTL_EV_SEL_EXT)
-
-/* NHM-EX event control */
-#define NHMEX_PMON_CTL_EV_SEL_MASK     0x000000ff
-#define NHMEX_PMON_CTL_UMASK_MASK      0x0000ff00
-#define NHMEX_PMON_CTL_EN_BIT0         (1 << 0)
-#define NHMEX_PMON_CTL_EDGE_DET                (1 << 18)
-#define NHMEX_PMON_CTL_PMI_EN          (1 << 20)
-#define NHMEX_PMON_CTL_EN_BIT22                (1 << 22)
-#define NHMEX_PMON_CTL_INVERT          (1 << 23)
-#define NHMEX_PMON_CTL_TRESH_MASK      0xff000000
-#define NHMEX_PMON_RAW_EVENT_MASK      (NHMEX_PMON_CTL_EV_SEL_MASK | \
-                                        NHMEX_PMON_CTL_UMASK_MASK | \
-                                        NHMEX_PMON_CTL_EDGE_DET | \
-                                        NHMEX_PMON_CTL_INVERT | \
-                                        NHMEX_PMON_CTL_TRESH_MASK)
-
-/* NHM-EX Ubox */
-#define NHMEX_U_MSR_PMON_GLOBAL_CTL            0xc00
-#define NHMEX_U_MSR_PMON_CTR                   0xc11
-#define NHMEX_U_MSR_PMON_EV_SEL                        0xc10
-
-#define NHMEX_U_PMON_GLOBAL_EN                 (1 << 0)
-#define NHMEX_U_PMON_GLOBAL_PMI_CORE_SEL       0x0000001e
-#define NHMEX_U_PMON_GLOBAL_EN_ALL             (1 << 28)
-#define NHMEX_U_PMON_GLOBAL_RST_ALL            (1 << 29)
-#define NHMEX_U_PMON_GLOBAL_FRZ_ALL            (1 << 31)
-
-#define NHMEX_U_PMON_RAW_EVENT_MASK            \
-               (NHMEX_PMON_CTL_EV_SEL_MASK |   \
-                NHMEX_PMON_CTL_EDGE_DET)
-
-/* NHM-EX Cbox */
-#define NHMEX_C0_MSR_PMON_GLOBAL_CTL           0xd00
-#define NHMEX_C0_MSR_PMON_CTR0                 0xd11
-#define NHMEX_C0_MSR_PMON_EV_SEL0              0xd10
-#define NHMEX_C_MSR_OFFSET                     0x20
-
-/* NHM-EX Bbox */
-#define NHMEX_B0_MSR_PMON_GLOBAL_CTL           0xc20
-#define NHMEX_B0_MSR_PMON_CTR0                 0xc31
-#define NHMEX_B0_MSR_PMON_CTL0                 0xc30
-#define NHMEX_B_MSR_OFFSET                     0x40
-#define NHMEX_B0_MSR_MATCH                     0xe45
-#define NHMEX_B0_MSR_MASK                      0xe46
-#define NHMEX_B1_MSR_MATCH                     0xe4d
-#define NHMEX_B1_MSR_MASK                      0xe4e
-
-#define NHMEX_B_PMON_CTL_EN                    (1 << 0)
-#define NHMEX_B_PMON_CTL_EV_SEL_SHIFT          1
-#define NHMEX_B_PMON_CTL_EV_SEL_MASK           \
-               (0x1f << NHMEX_B_PMON_CTL_EV_SEL_SHIFT)
-#define NHMEX_B_PMON_CTR_SHIFT         6
-#define NHMEX_B_PMON_CTR_MASK          \
-               (0x3 << NHMEX_B_PMON_CTR_SHIFT)
-#define NHMEX_B_PMON_RAW_EVENT_MASK            \
-               (NHMEX_B_PMON_CTL_EV_SEL_MASK | \
-                NHMEX_B_PMON_CTR_MASK)
-
-/* NHM-EX Sbox */
-#define NHMEX_S0_MSR_PMON_GLOBAL_CTL           0xc40
-#define NHMEX_S0_MSR_PMON_CTR0                 0xc51
-#define NHMEX_S0_MSR_PMON_CTL0                 0xc50
-#define NHMEX_S_MSR_OFFSET                     0x80
-#define NHMEX_S0_MSR_MM_CFG                    0xe48
-#define NHMEX_S0_MSR_MATCH                     0xe49
-#define NHMEX_S0_MSR_MASK                      0xe4a
-#define NHMEX_S1_MSR_MM_CFG                    0xe58
-#define NHMEX_S1_MSR_MATCH                     0xe59
-#define NHMEX_S1_MSR_MASK                      0xe5a
-
-#define NHMEX_S_PMON_MM_CFG_EN                 (0x1ULL << 63)
-#define NHMEX_S_EVENT_TO_R_PROG_EV             0
-
-/* NHM-EX Mbox */
-#define NHMEX_M0_MSR_GLOBAL_CTL                        0xca0
-#define NHMEX_M0_MSR_PMU_DSP                   0xca5
-#define NHMEX_M0_MSR_PMU_ISS                   0xca6
-#define NHMEX_M0_MSR_PMU_MAP                   0xca7
-#define NHMEX_M0_MSR_PMU_MSC_THR               0xca8
-#define NHMEX_M0_MSR_PMU_PGT                   0xca9
-#define NHMEX_M0_MSR_PMU_PLD                   0xcaa
-#define NHMEX_M0_MSR_PMU_ZDP_CTL_FVC           0xcab
-#define NHMEX_M0_MSR_PMU_CTL0                  0xcb0
-#define NHMEX_M0_MSR_PMU_CNT0                  0xcb1
-#define NHMEX_M_MSR_OFFSET                     0x40
-#define NHMEX_M0_MSR_PMU_MM_CFG                        0xe54
-#define NHMEX_M1_MSR_PMU_MM_CFG                        0xe5c
-
-#define NHMEX_M_PMON_MM_CFG_EN                 (1ULL << 63)
-#define NHMEX_M_PMON_ADDR_MATCH_MASK           0x3ffffffffULL
-#define NHMEX_M_PMON_ADDR_MASK_MASK            0x7ffffffULL
-#define NHMEX_M_PMON_ADDR_MASK_SHIFT           34
-
-#define NHMEX_M_PMON_CTL_EN                    (1 << 0)
-#define NHMEX_M_PMON_CTL_PMI_EN                        (1 << 1)
-#define NHMEX_M_PMON_CTL_COUNT_MODE_SHIFT      2
-#define NHMEX_M_PMON_CTL_COUNT_MODE_MASK       \
-       (0x3 << NHMEX_M_PMON_CTL_COUNT_MODE_SHIFT)
-#define NHMEX_M_PMON_CTL_STORAGE_MODE_SHIFT    4
-#define NHMEX_M_PMON_CTL_STORAGE_MODE_MASK     \
-       (0x3 << NHMEX_M_PMON_CTL_STORAGE_MODE_SHIFT)
-#define NHMEX_M_PMON_CTL_WRAP_MODE             (1 << 6)
-#define NHMEX_M_PMON_CTL_FLAG_MODE             (1 << 7)
-#define NHMEX_M_PMON_CTL_INC_SEL_SHIFT         9
-#define NHMEX_M_PMON_CTL_INC_SEL_MASK          \
-       (0x1f << NHMEX_M_PMON_CTL_INC_SEL_SHIFT)
-#define NHMEX_M_PMON_CTL_SET_FLAG_SEL_SHIFT    19
-#define NHMEX_M_PMON_CTL_SET_FLAG_SEL_MASK     \
-       (0x7 << NHMEX_M_PMON_CTL_SET_FLAG_SEL_SHIFT)
-#define NHMEX_M_PMON_RAW_EVENT_MASK                    \
-               (NHMEX_M_PMON_CTL_COUNT_MODE_MASK |     \
-                NHMEX_M_PMON_CTL_STORAGE_MODE_MASK |   \
-                NHMEX_M_PMON_CTL_WRAP_MODE |           \
-                NHMEX_M_PMON_CTL_FLAG_MODE |           \
-                NHMEX_M_PMON_CTL_INC_SEL_MASK |        \
-                NHMEX_M_PMON_CTL_SET_FLAG_SEL_MASK)
-
-#define NHMEX_M_PMON_ZDP_CTL_FVC_MASK          (((1 << 11) - 1) | (1 << 23))
-#define NHMEX_M_PMON_ZDP_CTL_FVC_EVENT_MASK(n) (0x7ULL << (11 + 3 * (n)))
-
-#define WSMEX_M_PMON_ZDP_CTL_FVC_MASK          (((1 << 12) - 1) | (1 << 24))
-#define WSMEX_M_PMON_ZDP_CTL_FVC_EVENT_MASK(n) (0x7ULL << (12 + 3 * (n)))
-
-/*
- * use the 9~13 bits to select event If the 7th bit is not set,
- * otherwise use the 19~21 bits to select event.
- */
-#define MBOX_INC_SEL(x) ((x) << NHMEX_M_PMON_CTL_INC_SEL_SHIFT)
-#define MBOX_SET_FLAG_SEL(x) (((x) << NHMEX_M_PMON_CTL_SET_FLAG_SEL_SHIFT) | \
-                               NHMEX_M_PMON_CTL_FLAG_MODE)
-#define MBOX_INC_SEL_MASK (NHMEX_M_PMON_CTL_INC_SEL_MASK | \
-                          NHMEX_M_PMON_CTL_FLAG_MODE)
-#define MBOX_SET_FLAG_SEL_MASK (NHMEX_M_PMON_CTL_SET_FLAG_SEL_MASK | \
-                               NHMEX_M_PMON_CTL_FLAG_MODE)
-#define MBOX_INC_SEL_EXTAR_REG(c, r) \
-               EVENT_EXTRA_REG(MBOX_INC_SEL(c), NHMEX_M0_MSR_PMU_##r, \
-                               MBOX_INC_SEL_MASK, (u64)-1, NHMEX_M_##r)
-#define MBOX_SET_FLAG_SEL_EXTRA_REG(c, r) \
-               EVENT_EXTRA_REG(MBOX_SET_FLAG_SEL(c), NHMEX_M0_MSR_PMU_##r, \
-                               MBOX_SET_FLAG_SEL_MASK, \
-                               (u64)-1, NHMEX_M_##r)
-
-/* NHM-EX Rbox */
-#define NHMEX_R_MSR_GLOBAL_CTL                 0xe00
-#define NHMEX_R_MSR_PMON_CTL0                  0xe10
-#define NHMEX_R_MSR_PMON_CNT0                  0xe11
-#define NHMEX_R_MSR_OFFSET                     0x20
-
-#define NHMEX_R_MSR_PORTN_QLX_CFG(n)           \
-               ((n) < 4 ? (0xe0c + (n)) : (0xe2c + (n) - 4))
-#define NHMEX_R_MSR_PORTN_IPERF_CFG0(n)                (0xe04 + (n))
-#define NHMEX_R_MSR_PORTN_IPERF_CFG1(n)                (0xe24 + (n))
-#define NHMEX_R_MSR_PORTN_XBR_OFFSET(n)                \
-               (((n) < 4 ? 0 : 0x10) + (n) * 4)
-#define NHMEX_R_MSR_PORTN_XBR_SET1_MM_CFG(n)   \
-               (0xe60 + NHMEX_R_MSR_PORTN_XBR_OFFSET(n))
-#define NHMEX_R_MSR_PORTN_XBR_SET1_MATCH(n)    \
-               (NHMEX_R_MSR_PORTN_XBR_SET1_MM_CFG(n) + 1)
-#define NHMEX_R_MSR_PORTN_XBR_SET1_MASK(n)     \
-               (NHMEX_R_MSR_PORTN_XBR_SET1_MM_CFG(n) + 2)
-#define NHMEX_R_MSR_PORTN_XBR_SET2_MM_CFG(n)   \
-               (0xe70 + NHMEX_R_MSR_PORTN_XBR_OFFSET(n))
-#define NHMEX_R_MSR_PORTN_XBR_SET2_MATCH(n)    \
-               (NHMEX_R_MSR_PORTN_XBR_SET2_MM_CFG(n) + 1)
-#define NHMEX_R_MSR_PORTN_XBR_SET2_MASK(n)     \
-               (NHMEX_R_MSR_PORTN_XBR_SET2_MM_CFG(n) + 2)
-
-#define NHMEX_R_PMON_CTL_EN                    (1 << 0)
-#define NHMEX_R_PMON_CTL_EV_SEL_SHIFT          1
-#define NHMEX_R_PMON_CTL_EV_SEL_MASK           \
-               (0x1f << NHMEX_R_PMON_CTL_EV_SEL_SHIFT)
-#define NHMEX_R_PMON_CTL_PMI_EN                        (1 << 6)
-#define NHMEX_R_PMON_RAW_EVENT_MASK            NHMEX_R_PMON_CTL_EV_SEL_MASK
-
-/* NHM-EX Wbox */
-#define NHMEX_W_MSR_GLOBAL_CTL                 0xc80
-#define NHMEX_W_MSR_PMON_CNT0                  0xc90
-#define NHMEX_W_MSR_PMON_EVT_SEL0              0xc91
-#define NHMEX_W_MSR_PMON_FIXED_CTR             0x394
-#define NHMEX_W_MSR_PMON_FIXED_CTL             0x395
-
-#define NHMEX_W_PMON_GLOBAL_FIXED_EN           (1ULL << 31)
-
 struct intel_uncore_ops;
 struct intel_uncore_pmu;
 struct intel_uncore_box;
@@ -505,6 +116,9 @@ struct uncore_event_desc {
        const char *config;
 };
 
+ssize_t uncore_event_show(struct kobject *kobj,
+                         struct kobj_attribute *attr, char *buf);
+
 #define INTEL_UNCORE_EVENT_DESC(_name, _config)                        \
 {                                                              \
        .attr   = __ATTR(_name, 0444, uncore_event_show, NULL), \
@@ -522,15 +136,6 @@ static ssize_t __uncore_##_var##_show(struct kobject *kobj,                \
 static struct kobj_attribute format_attr_##_var =                      \
        __ATTR(_name, 0444, __uncore_##_var##_show, NULL)
 
-
-static ssize_t uncore_event_show(struct kobject *kobj,
-                               struct kobj_attribute *attr, char *buf)
-{
-       struct uncore_event_desc *event =
-               container_of(attr, struct uncore_event_desc, attr);
-       return sprintf(buf, "%s", event->config);
-}
-
 static inline unsigned uncore_pci_box_ctl(struct intel_uncore_box *box)
 {
        return box->pmu->type->box_ctl;
@@ -694,3 +299,41 @@ static inline bool uncore_box_is_fake(struct intel_uncore_box *box)
 {
        return (box->phys_id < 0);
 }
+
+struct intel_uncore_pmu *uncore_event_to_pmu(struct perf_event *event);
+struct intel_uncore_box *uncore_pmu_to_box(struct intel_uncore_pmu *pmu, int cpu);
+struct intel_uncore_box *uncore_event_to_box(struct perf_event *event);
+u64 uncore_msr_read_counter(struct intel_uncore_box *box, struct perf_event *event);
+void uncore_pmu_start_hrtimer(struct intel_uncore_box *box);
+void uncore_pmu_cancel_hrtimer(struct intel_uncore_box *box);
+void uncore_pmu_event_read(struct perf_event *event);
+void uncore_perf_event_update(struct intel_uncore_box *box, struct perf_event *event);
+struct event_constraint *
+uncore_get_constraint(struct intel_uncore_box *box, struct perf_event *event);
+void uncore_put_constraint(struct intel_uncore_box *box, struct perf_event *event);
+u64 uncore_shared_reg_config(struct intel_uncore_box *box, int idx);
+
+extern struct intel_uncore_type **uncore_msr_uncores;
+extern struct intel_uncore_type **uncore_pci_uncores;
+extern struct pci_driver *uncore_pci_driver;
+extern int uncore_pcibus_to_physid[256];
+extern struct pci_dev *uncore_extra_pci_dev[UNCORE_SOCKET_MAX][UNCORE_EXTRA_PCI_DEV_MAX];
+extern struct event_constraint uncore_constraint_empty;
+
+/* perf_event_intel_uncore_snb.c */
+int snb_uncore_pci_init(void);
+int ivb_uncore_pci_init(void);
+int hsw_uncore_pci_init(void);
+void snb_uncore_cpu_init(void);
+void nhm_uncore_cpu_init(void);
+
+/* perf_event_intel_uncore_snbep.c */
+int snbep_uncore_pci_init(void);
+void snbep_uncore_cpu_init(void);
+int ivbep_uncore_pci_init(void);
+void ivbep_uncore_cpu_init(void);
+int hswep_uncore_pci_init(void);
+void hswep_uncore_cpu_init(void);
+
+/* perf_event_intel_uncore_nhmex.c */
+void nhmex_uncore_cpu_init(void);
diff --git a/arch/x86/kernel/cpu/perf_event_intel_uncore_nhmex.c b/arch/x86/kernel/cpu/perf_event_intel_uncore_nhmex.c
new file mode 100644 (file)
index 0000000..2749965
--- /dev/null
@@ -0,0 +1,1221 @@
+/* Nehalem-EX/Westmere-EX uncore support */
+#include "perf_event_intel_uncore.h"
+
+/* NHM-EX event control */
+#define NHMEX_PMON_CTL_EV_SEL_MASK     0x000000ff
+#define NHMEX_PMON_CTL_UMASK_MASK      0x0000ff00
+#define NHMEX_PMON_CTL_EN_BIT0         (1 << 0)
+#define NHMEX_PMON_CTL_EDGE_DET                (1 << 18)
+#define NHMEX_PMON_CTL_PMI_EN          (1 << 20)
+#define NHMEX_PMON_CTL_EN_BIT22                (1 << 22)
+#define NHMEX_PMON_CTL_INVERT          (1 << 23)
+#define NHMEX_PMON_CTL_TRESH_MASK      0xff000000
+#define NHMEX_PMON_RAW_EVENT_MASK      (NHMEX_PMON_CTL_EV_SEL_MASK | \
+                                        NHMEX_PMON_CTL_UMASK_MASK | \
+                                        NHMEX_PMON_CTL_EDGE_DET | \
+                                        NHMEX_PMON_CTL_INVERT | \
+                                        NHMEX_PMON_CTL_TRESH_MASK)
+
+/* NHM-EX Ubox */
+#define NHMEX_U_MSR_PMON_GLOBAL_CTL            0xc00
+#define NHMEX_U_MSR_PMON_CTR                   0xc11
+#define NHMEX_U_MSR_PMON_EV_SEL                        0xc10
+
+#define NHMEX_U_PMON_GLOBAL_EN                 (1 << 0)
+#define NHMEX_U_PMON_GLOBAL_PMI_CORE_SEL       0x0000001e
+#define NHMEX_U_PMON_GLOBAL_EN_ALL             (1 << 28)
+#define NHMEX_U_PMON_GLOBAL_RST_ALL            (1 << 29)
+#define NHMEX_U_PMON_GLOBAL_FRZ_ALL            (1 << 31)
+
+#define NHMEX_U_PMON_RAW_EVENT_MASK            \
+               (NHMEX_PMON_CTL_EV_SEL_MASK |   \
+                NHMEX_PMON_CTL_EDGE_DET)
+
+/* NHM-EX Cbox */
+#define NHMEX_C0_MSR_PMON_GLOBAL_CTL           0xd00
+#define NHMEX_C0_MSR_PMON_CTR0                 0xd11
+#define NHMEX_C0_MSR_PMON_EV_SEL0              0xd10
+#define NHMEX_C_MSR_OFFSET                     0x20
+
+/* NHM-EX Bbox */
+#define NHMEX_B0_MSR_PMON_GLOBAL_CTL           0xc20
+#define NHMEX_B0_MSR_PMON_CTR0                 0xc31
+#define NHMEX_B0_MSR_PMON_CTL0                 0xc30
+#define NHMEX_B_MSR_OFFSET                     0x40
+#define NHMEX_B0_MSR_MATCH                     0xe45
+#define NHMEX_B0_MSR_MASK                      0xe46
+#define NHMEX_B1_MSR_MATCH                     0xe4d
+#define NHMEX_B1_MSR_MASK                      0xe4e
+
+#define NHMEX_B_PMON_CTL_EN                    (1 << 0)
+#define NHMEX_B_PMON_CTL_EV_SEL_SHIFT          1
+#define NHMEX_B_PMON_CTL_EV_SEL_MASK           \
+               (0x1f << NHMEX_B_PMON_CTL_EV_SEL_SHIFT)
+#define NHMEX_B_PMON_CTR_SHIFT         6
+#define NHMEX_B_PMON_CTR_MASK          \
+               (0x3 << NHMEX_B_PMON_CTR_SHIFT)
+#define NHMEX_B_PMON_RAW_EVENT_MASK            \
+               (NHMEX_B_PMON_CTL_EV_SEL_MASK | \
+                NHMEX_B_PMON_CTR_MASK)
+
+/* NHM-EX Sbox */
+#define NHMEX_S0_MSR_PMON_GLOBAL_CTL           0xc40
+#define NHMEX_S0_MSR_PMON_CTR0                 0xc51
+#define NHMEX_S0_MSR_PMON_CTL0                 0xc50
+#define NHMEX_S_MSR_OFFSET                     0x80
+#define NHMEX_S0_MSR_MM_CFG                    0xe48
+#define NHMEX_S0_MSR_MATCH                     0xe49
+#define NHMEX_S0_MSR_MASK                      0xe4a
+#define NHMEX_S1_MSR_MM_CFG                    0xe58
+#define NHMEX_S1_MSR_MATCH                     0xe59
+#define NHMEX_S1_MSR_MASK                      0xe5a
+
+#define NHMEX_S_PMON_MM_CFG_EN                 (0x1ULL << 63)
+#define NHMEX_S_EVENT_TO_R_PROG_EV             0
+
+/* NHM-EX Mbox */
+#define NHMEX_M0_MSR_GLOBAL_CTL                        0xca0
+#define NHMEX_M0_MSR_PMU_DSP                   0xca5
+#define NHMEX_M0_MSR_PMU_ISS                   0xca6
+#define NHMEX_M0_MSR_PMU_MAP                   0xca7
+#define NHMEX_M0_MSR_PMU_MSC_THR               0xca8
+#define NHMEX_M0_MSR_PMU_PGT                   0xca9
+#define NHMEX_M0_MSR_PMU_PLD                   0xcaa
+#define NHMEX_M0_MSR_PMU_ZDP_CTL_FVC           0xcab
+#define NHMEX_M0_MSR_PMU_CTL0                  0xcb0
+#define NHMEX_M0_MSR_PMU_CNT0                  0xcb1
+#define NHMEX_M_MSR_OFFSET                     0x40
+#define NHMEX_M0_MSR_PMU_MM_CFG                        0xe54
+#define NHMEX_M1_MSR_PMU_MM_CFG                        0xe5c
+
+#define NHMEX_M_PMON_MM_CFG_EN                 (1ULL << 63)
+#define NHMEX_M_PMON_ADDR_MATCH_MASK           0x3ffffffffULL
+#define NHMEX_M_PMON_ADDR_MASK_MASK            0x7ffffffULL
+#define NHMEX_M_PMON_ADDR_MASK_SHIFT           34
+
+#define NHMEX_M_PMON_CTL_EN                    (1 << 0)
+#define NHMEX_M_PMON_CTL_PMI_EN                        (1 << 1)
+#define NHMEX_M_PMON_CTL_COUNT_MODE_SHIFT      2
+#define NHMEX_M_PMON_CTL_COUNT_MODE_MASK       \
+       (0x3 << NHMEX_M_PMON_CTL_COUNT_MODE_SHIFT)
+#define NHMEX_M_PMON_CTL_STORAGE_MODE_SHIFT    4
+#define NHMEX_M_PMON_CTL_STORAGE_MODE_MASK     \
+       (0x3 << NHMEX_M_PMON_CTL_STORAGE_MODE_SHIFT)
+#define NHMEX_M_PMON_CTL_WRAP_MODE             (1 << 6)
+#define NHMEX_M_PMON_CTL_FLAG_MODE             (1 << 7)
+#define NHMEX_M_PMON_CTL_INC_SEL_SHIFT         9
+#define NHMEX_M_PMON_CTL_INC_SEL_MASK          \
+       (0x1f << NHMEX_M_PMON_CTL_INC_SEL_SHIFT)
+#define NHMEX_M_PMON_CTL_SET_FLAG_SEL_SHIFT    19
+#define NHMEX_M_PMON_CTL_SET_FLAG_SEL_MASK     \
+       (0x7 << NHMEX_M_PMON_CTL_SET_FLAG_SEL_SHIFT)
+#define NHMEX_M_PMON_RAW_EVENT_MASK                    \
+               (NHMEX_M_PMON_CTL_COUNT_MODE_MASK |     \
+                NHMEX_M_PMON_CTL_STORAGE_MODE_MASK |   \
+                NHMEX_M_PMON_CTL_WRAP_MODE |           \
+                NHMEX_M_PMON_CTL_FLAG_MODE |           \
+                NHMEX_M_PMON_CTL_INC_SEL_MASK |        \
+                NHMEX_M_PMON_CTL_SET_FLAG_SEL_MASK)
+
+#define NHMEX_M_PMON_ZDP_CTL_FVC_MASK          (((1 << 11) - 1) | (1 << 23))
+#define NHMEX_M_PMON_ZDP_CTL_FVC_EVENT_MASK(n) (0x7ULL << (11 + 3 * (n)))
+
+#define WSMEX_M_PMON_ZDP_CTL_FVC_MASK          (((1 << 12) - 1) | (1 << 24))
+#define WSMEX_M_PMON_ZDP_CTL_FVC_EVENT_MASK(n) (0x7ULL << (12 + 3 * (n)))
+
+/*
+ * use the 9~13 bits to select event If the 7th bit is not set,
+ * otherwise use the 19~21 bits to select event.
+ */
+#define MBOX_INC_SEL(x) ((x) << NHMEX_M_PMON_CTL_INC_SEL_SHIFT)
+#define MBOX_SET_FLAG_SEL(x) (((x) << NHMEX_M_PMON_CTL_SET_FLAG_SEL_SHIFT) | \
+                               NHMEX_M_PMON_CTL_FLAG_MODE)
+#define MBOX_INC_SEL_MASK (NHMEX_M_PMON_CTL_INC_SEL_MASK | \
+                          NHMEX_M_PMON_CTL_FLAG_MODE)
+#define MBOX_SET_FLAG_SEL_MASK (NHMEX_M_PMON_CTL_SET_FLAG_SEL_MASK | \
+                               NHMEX_M_PMON_CTL_FLAG_MODE)
+#define MBOX_INC_SEL_EXTAR_REG(c, r) \
+               EVENT_EXTRA_REG(MBOX_INC_SEL(c), NHMEX_M0_MSR_PMU_##r, \
+                               MBOX_INC_SEL_MASK, (u64)-1, NHMEX_M_##r)
+#define MBOX_SET_FLAG_SEL_EXTRA_REG(c, r) \
+               EVENT_EXTRA_REG(MBOX_SET_FLAG_SEL(c), NHMEX_M0_MSR_PMU_##r, \
+                               MBOX_SET_FLAG_SEL_MASK, \
+                               (u64)-1, NHMEX_M_##r)
+
+/* NHM-EX Rbox */
+#define NHMEX_R_MSR_GLOBAL_CTL                 0xe00
+#define NHMEX_R_MSR_PMON_CTL0                  0xe10
+#define NHMEX_R_MSR_PMON_CNT0                  0xe11
+#define NHMEX_R_MSR_OFFSET                     0x20
+
+#define NHMEX_R_MSR_PORTN_QLX_CFG(n)           \
+               ((n) < 4 ? (0xe0c + (n)) : (0xe2c + (n) - 4))
+#define NHMEX_R_MSR_PORTN_IPERF_CFG0(n)                (0xe04 + (n))
+#define NHMEX_R_MSR_PORTN_IPERF_CFG1(n)                (0xe24 + (n))
+#define NHMEX_R_MSR_PORTN_XBR_OFFSET(n)                \
+               (((n) < 4 ? 0 : 0x10) + (n) * 4)
+#define NHMEX_R_MSR_PORTN_XBR_SET1_MM_CFG(n)   \
+               (0xe60 + NHMEX_R_MSR_PORTN_XBR_OFFSET(n))
+#define NHMEX_R_MSR_PORTN_XBR_SET1_MATCH(n)    \
+               (NHMEX_R_MSR_PORTN_XBR_SET1_MM_CFG(n) + 1)
+#define NHMEX_R_MSR_PORTN_XBR_SET1_MASK(n)     \
+               (NHMEX_R_MSR_PORTN_XBR_SET1_MM_CFG(n) + 2)
+#define NHMEX_R_MSR_PORTN_XBR_SET2_MM_CFG(n)   \
+               (0xe70 + NHMEX_R_MSR_PORTN_XBR_OFFSET(n))
+#define NHMEX_R_MSR_PORTN_XBR_SET2_MATCH(n)    \
+               (NHMEX_R_MSR_PORTN_XBR_SET2_MM_CFG(n) + 1)
+#define NHMEX_R_MSR_PORTN_XBR_SET2_MASK(n)     \
+               (NHMEX_R_MSR_PORTN_XBR_SET2_MM_CFG(n) + 2)
+
+#define NHMEX_R_PMON_CTL_EN                    (1 << 0)
+#define NHMEX_R_PMON_CTL_EV_SEL_SHIFT          1
+#define NHMEX_R_PMON_CTL_EV_SEL_MASK           \
+               (0x1f << NHMEX_R_PMON_CTL_EV_SEL_SHIFT)
+#define NHMEX_R_PMON_CTL_PMI_EN                        (1 << 6)
+#define NHMEX_R_PMON_RAW_EVENT_MASK            NHMEX_R_PMON_CTL_EV_SEL_MASK
+
+/* NHM-EX Wbox */
+#define NHMEX_W_MSR_GLOBAL_CTL                 0xc80
+#define NHMEX_W_MSR_PMON_CNT0                  0xc90
+#define NHMEX_W_MSR_PMON_EVT_SEL0              0xc91
+#define NHMEX_W_MSR_PMON_FIXED_CTR             0x394
+#define NHMEX_W_MSR_PMON_FIXED_CTL             0x395
+
+#define NHMEX_W_PMON_GLOBAL_FIXED_EN           (1ULL << 31)
+
+#define __BITS_VALUE(x, i, n)  ((typeof(x))(((x) >> ((i) * (n))) & \
+                               ((1ULL << (n)) - 1)))
+
+DEFINE_UNCORE_FORMAT_ATTR(event, event, "config:0-7");
+DEFINE_UNCORE_FORMAT_ATTR(event5, event, "config:1-5");
+DEFINE_UNCORE_FORMAT_ATTR(umask, umask, "config:8-15");
+DEFINE_UNCORE_FORMAT_ATTR(edge, edge, "config:18");
+DEFINE_UNCORE_FORMAT_ATTR(inv, inv, "config:23");
+DEFINE_UNCORE_FORMAT_ATTR(thresh8, thresh, "config:24-31");
+DEFINE_UNCORE_FORMAT_ATTR(counter, counter, "config:6-7");
+DEFINE_UNCORE_FORMAT_ATTR(match, match, "config1:0-63");
+DEFINE_UNCORE_FORMAT_ATTR(mask, mask, "config2:0-63");
+
+static void nhmex_uncore_msr_init_box(struct intel_uncore_box *box)
+{
+       wrmsrl(NHMEX_U_MSR_PMON_GLOBAL_CTL, NHMEX_U_PMON_GLOBAL_EN_ALL);
+}
+
+static void nhmex_uncore_msr_disable_box(struct intel_uncore_box *box)
+{
+       unsigned msr = uncore_msr_box_ctl(box);
+       u64 config;
+
+       if (msr) {
+               rdmsrl(msr, config);
+               config &= ~((1ULL << uncore_num_counters(box)) - 1);
+               /* WBox has a fixed counter */
+               if (uncore_msr_fixed_ctl(box))
+                       config &= ~NHMEX_W_PMON_GLOBAL_FIXED_EN;
+               wrmsrl(msr, config);
+       }
+}
+
+static void nhmex_uncore_msr_enable_box(struct intel_uncore_box *box)
+{
+       unsigned msr = uncore_msr_box_ctl(box);
+       u64 config;
+
+       if (msr) {
+               rdmsrl(msr, config);
+               config |= (1ULL << uncore_num_counters(box)) - 1;
+               /* WBox has a fixed counter */
+               if (uncore_msr_fixed_ctl(box))
+                       config |= NHMEX_W_PMON_GLOBAL_FIXED_EN;
+               wrmsrl(msr, config);
+       }
+}
+
+static void nhmex_uncore_msr_disable_event(struct intel_uncore_box *box, struct perf_event *event)
+{
+       wrmsrl(event->hw.config_base, 0);
+}
+
+static void nhmex_uncore_msr_enable_event(struct intel_uncore_box *box, struct perf_event *event)
+{
+       struct hw_perf_event *hwc = &event->hw;
+
+       if (hwc->idx >= UNCORE_PMC_IDX_FIXED)
+               wrmsrl(hwc->config_base, NHMEX_PMON_CTL_EN_BIT0);
+       else if (box->pmu->type->event_mask & NHMEX_PMON_CTL_EN_BIT0)
+               wrmsrl(hwc->config_base, hwc->config | NHMEX_PMON_CTL_EN_BIT22);
+       else
+               wrmsrl(hwc->config_base, hwc->config | NHMEX_PMON_CTL_EN_BIT0);
+}
+
+#define NHMEX_UNCORE_OPS_COMMON_INIT()                         \
+       .init_box       = nhmex_uncore_msr_init_box,            \
+       .disable_box    = nhmex_uncore_msr_disable_box,         \
+       .enable_box     = nhmex_uncore_msr_enable_box,          \
+       .disable_event  = nhmex_uncore_msr_disable_event,       \
+       .read_counter   = uncore_msr_read_counter
+
+static struct intel_uncore_ops nhmex_uncore_ops = {
+       NHMEX_UNCORE_OPS_COMMON_INIT(),
+       .enable_event   = nhmex_uncore_msr_enable_event,
+};
+
+static struct attribute *nhmex_uncore_ubox_formats_attr[] = {
+       &format_attr_event.attr,
+       &format_attr_edge.attr,
+       NULL,
+};
+
+static struct attribute_group nhmex_uncore_ubox_format_group = {
+       .name           = "format",
+       .attrs          = nhmex_uncore_ubox_formats_attr,
+};
+
+static struct intel_uncore_type nhmex_uncore_ubox = {
+       .name           = "ubox",
+       .num_counters   = 1,
+       .num_boxes      = 1,
+       .perf_ctr_bits  = 48,
+       .event_ctl      = NHMEX_U_MSR_PMON_EV_SEL,
+       .perf_ctr       = NHMEX_U_MSR_PMON_CTR,
+       .event_mask     = NHMEX_U_PMON_RAW_EVENT_MASK,
+       .box_ctl        = NHMEX_U_MSR_PMON_GLOBAL_CTL,
+       .ops            = &nhmex_uncore_ops,
+       .format_group   = &nhmex_uncore_ubox_format_group
+};
+
+static struct attribute *nhmex_uncore_cbox_formats_attr[] = {
+       &format_attr_event.attr,
+       &format_attr_umask.attr,
+       &format_attr_edge.attr,
+       &format_attr_inv.attr,
+       &format_attr_thresh8.attr,
+       NULL,
+};
+
+static struct attribute_group nhmex_uncore_cbox_format_group = {
+       .name = "format",
+       .attrs = nhmex_uncore_cbox_formats_attr,
+};
+
+/* msr offset for each instance of cbox */
+static unsigned nhmex_cbox_msr_offsets[] = {
+       0x0, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, 0x240, 0x2c0,
+};
+
+static struct intel_uncore_type nhmex_uncore_cbox = {
+       .name                   = "cbox",
+       .num_counters           = 6,
+       .num_boxes              = 10,
+       .perf_ctr_bits          = 48,
+       .event_ctl              = NHMEX_C0_MSR_PMON_EV_SEL0,
+       .perf_ctr               = NHMEX_C0_MSR_PMON_CTR0,
+       .event_mask             = NHMEX_PMON_RAW_EVENT_MASK,
+       .box_ctl                = NHMEX_C0_MSR_PMON_GLOBAL_CTL,
+       .msr_offsets            = nhmex_cbox_msr_offsets,
+       .pair_ctr_ctl           = 1,
+       .ops                    = &nhmex_uncore_ops,
+       .format_group           = &nhmex_uncore_cbox_format_group
+};
+
+static struct uncore_event_desc nhmex_uncore_wbox_events[] = {
+       INTEL_UNCORE_EVENT_DESC(clockticks, "event=0xff,umask=0"),
+       { /* end: all zeroes */ },
+};
+
+static struct intel_uncore_type nhmex_uncore_wbox = {
+       .name                   = "wbox",
+       .num_counters           = 4,
+       .num_boxes              = 1,
+       .perf_ctr_bits          = 48,
+       .event_ctl              = NHMEX_W_MSR_PMON_CNT0,
+       .perf_ctr               = NHMEX_W_MSR_PMON_EVT_SEL0,
+       .fixed_ctr              = NHMEX_W_MSR_PMON_FIXED_CTR,
+       .fixed_ctl              = NHMEX_W_MSR_PMON_FIXED_CTL,
+       .event_mask             = NHMEX_PMON_RAW_EVENT_MASK,
+       .box_ctl                = NHMEX_W_MSR_GLOBAL_CTL,
+       .pair_ctr_ctl           = 1,
+       .event_descs            = nhmex_uncore_wbox_events,
+       .ops                    = &nhmex_uncore_ops,
+       .format_group           = &nhmex_uncore_cbox_format_group
+};
+
+static int nhmex_bbox_hw_config(struct intel_uncore_box *box, struct perf_event *event)
+{
+       struct hw_perf_event *hwc = &event->hw;
+       struct hw_perf_event_extra *reg1 = &hwc->extra_reg;
+       struct hw_perf_event_extra *reg2 = &hwc->branch_reg;
+       int ctr, ev_sel;
+
+       ctr = (hwc->config & NHMEX_B_PMON_CTR_MASK) >>
+               NHMEX_B_PMON_CTR_SHIFT;
+       ev_sel = (hwc->config & NHMEX_B_PMON_CTL_EV_SEL_MASK) >>
+                 NHMEX_B_PMON_CTL_EV_SEL_SHIFT;
+
+       /* events that do not use the match/mask registers */
+       if ((ctr == 0 && ev_sel > 0x3) || (ctr == 1 && ev_sel > 0x6) ||
+           (ctr == 2 && ev_sel != 0x4) || ctr == 3)
+               return 0;
+
+       if (box->pmu->pmu_idx == 0)
+               reg1->reg = NHMEX_B0_MSR_MATCH;
+       else
+               reg1->reg = NHMEX_B1_MSR_MATCH;
+       reg1->idx = 0;
+       reg1->config = event->attr.config1;
+       reg2->config = event->attr.config2;
+       return 0;
+}
+
+static void nhmex_bbox_msr_enable_event(struct intel_uncore_box *box, struct perf_event *event)
+{
+       struct hw_perf_event *hwc = &event->hw;
+       struct hw_perf_event_extra *reg1 = &hwc->extra_reg;
+       struct hw_perf_event_extra *reg2 = &hwc->branch_reg;
+
+       if (reg1->idx != EXTRA_REG_NONE) {
+               wrmsrl(reg1->reg, reg1->config);
+               wrmsrl(reg1->reg + 1, reg2->config);
+       }
+       wrmsrl(hwc->config_base, NHMEX_PMON_CTL_EN_BIT0 |
+               (hwc->config & NHMEX_B_PMON_CTL_EV_SEL_MASK));
+}
+
+/*
+ * The Bbox has 4 counters, but each counter monitors different events.
+ * Use bits 6-7 in the event config to select counter.
+ */
+static struct event_constraint nhmex_uncore_bbox_constraints[] = {
+       EVENT_CONSTRAINT(0 , 1, 0xc0),
+       EVENT_CONSTRAINT(0x40, 2, 0xc0),
+       EVENT_CONSTRAINT(0x80, 4, 0xc0),
+       EVENT_CONSTRAINT(0xc0, 8, 0xc0),
+       EVENT_CONSTRAINT_END,
+};
+
+static struct attribute *nhmex_uncore_bbox_formats_attr[] = {
+       &format_attr_event5.attr,
+       &format_attr_counter.attr,
+       &format_attr_match.attr,
+       &format_attr_mask.attr,
+       NULL,
+};
+
+static struct attribute_group nhmex_uncore_bbox_format_group = {
+       .name = "format",
+       .attrs = nhmex_uncore_bbox_formats_attr,
+};
+
+static struct intel_uncore_ops nhmex_uncore_bbox_ops = {
+       NHMEX_UNCORE_OPS_COMMON_INIT(),
+       .enable_event           = nhmex_bbox_msr_enable_event,
+       .hw_config              = nhmex_bbox_hw_config,
+       .get_constraint         = uncore_get_constraint,
+       .put_constraint         = uncore_put_constraint,
+};
+
+static struct intel_uncore_type nhmex_uncore_bbox = {
+       .name                   = "bbox",
+       .num_counters           = 4,
+       .num_boxes              = 2,
+       .perf_ctr_bits          = 48,
+       .event_ctl              = NHMEX_B0_MSR_PMON_CTL0,
+       .perf_ctr               = NHMEX_B0_MSR_PMON_CTR0,
+       .event_mask             = NHMEX_B_PMON_RAW_EVENT_MASK,
+       .box_ctl                = NHMEX_B0_MSR_PMON_GLOBAL_CTL,
+       .msr_offset             = NHMEX_B_MSR_OFFSET,
+       .pair_ctr_ctl           = 1,
+       .num_shared_regs        = 1,
+       .constraints            = nhmex_uncore_bbox_constraints,
+       .ops                    = &nhmex_uncore_bbox_ops,
+       .format_group           = &nhmex_uncore_bbox_format_group
+};
+
+static int nhmex_sbox_hw_config(struct intel_uncore_box *box, struct perf_event *event)
+{
+       struct hw_perf_event *hwc = &event->hw;
+       struct hw_perf_event_extra *reg1 = &hwc->extra_reg;
+       struct hw_perf_event_extra *reg2 = &hwc->branch_reg;
+
+       /* only TO_R_PROG_EV event uses the match/mask register */
+       if ((hwc->config & NHMEX_PMON_CTL_EV_SEL_MASK) !=
+           NHMEX_S_EVENT_TO_R_PROG_EV)
+               return 0;
+
+       if (box->pmu->pmu_idx == 0)
+               reg1->reg = NHMEX_S0_MSR_MM_CFG;
+       else
+               reg1->reg = NHMEX_S1_MSR_MM_CFG;
+       reg1->idx = 0;
+       reg1->config = event->attr.config1;
+       reg2->config = event->attr.config2;
+       return 0;
+}
+
+static void nhmex_sbox_msr_enable_event(struct intel_uncore_box *box, struct perf_event *event)
+{
+       struct hw_perf_event *hwc = &event->hw;
+       struct hw_perf_event_extra *reg1 = &hwc->extra_reg;
+       struct hw_perf_event_extra *reg2 = &hwc->branch_reg;
+
+       if (reg1->idx != EXTRA_REG_NONE) {
+               wrmsrl(reg1->reg, 0);
+               wrmsrl(reg1->reg + 1, reg1->config);
+               wrmsrl(reg1->reg + 2, reg2->config);
+               wrmsrl(reg1->reg, NHMEX_S_PMON_MM_CFG_EN);
+       }
+       wrmsrl(hwc->config_base, hwc->config | NHMEX_PMON_CTL_EN_BIT22);
+}
+
+static struct attribute *nhmex_uncore_sbox_formats_attr[] = {
+       &format_attr_event.attr,
+       &format_attr_umask.attr,
+       &format_attr_edge.attr,
+       &format_attr_inv.attr,
+       &format_attr_thresh8.attr,
+       &format_attr_match.attr,
+       &format_attr_mask.attr,
+       NULL,
+};
+
+static struct attribute_group nhmex_uncore_sbox_format_group = {
+       .name                   = "format",
+       .attrs                  = nhmex_uncore_sbox_formats_attr,
+};
+
+static struct intel_uncore_ops nhmex_uncore_sbox_ops = {
+       NHMEX_UNCORE_OPS_COMMON_INIT(),
+       .enable_event           = nhmex_sbox_msr_enable_event,
+       .hw_config              = nhmex_sbox_hw_config,
+       .get_constraint         = uncore_get_constraint,
+       .put_constraint         = uncore_put_constraint,
+};
+
+static struct intel_uncore_type nhmex_uncore_sbox = {
+       .name                   = "sbox",
+       .num_counters           = 4,
+       .num_boxes              = 2,
+       .perf_ctr_bits          = 48,
+       .event_ctl              = NHMEX_S0_MSR_PMON_CTL0,
+       .perf_ctr               = NHMEX_S0_MSR_PMON_CTR0,
+       .event_mask             = NHMEX_PMON_RAW_EVENT_MASK,
+       .box_ctl                = NHMEX_S0_MSR_PMON_GLOBAL_CTL,
+       .msr_offset             = NHMEX_S_MSR_OFFSET,
+       .pair_ctr_ctl           = 1,
+       .num_shared_regs        = 1,
+       .ops                    = &nhmex_uncore_sbox_ops,
+       .format_group           = &nhmex_uncore_sbox_format_group
+};
+
+enum {
+       EXTRA_REG_NHMEX_M_FILTER,
+       EXTRA_REG_NHMEX_M_DSP,
+       EXTRA_REG_NHMEX_M_ISS,
+       EXTRA_REG_NHMEX_M_MAP,
+       EXTRA_REG_NHMEX_M_MSC_THR,
+       EXTRA_REG_NHMEX_M_PGT,
+       EXTRA_REG_NHMEX_M_PLD,
+       EXTRA_REG_NHMEX_M_ZDP_CTL_FVC,
+};
+
+static struct extra_reg nhmex_uncore_mbox_extra_regs[] = {
+       MBOX_INC_SEL_EXTAR_REG(0x0, DSP),
+       MBOX_INC_SEL_EXTAR_REG(0x4, MSC_THR),
+       MBOX_INC_SEL_EXTAR_REG(0x5, MSC_THR),
+       MBOX_INC_SEL_EXTAR_REG(0x9, ISS),
+       /* event 0xa uses two extra registers */
+       MBOX_INC_SEL_EXTAR_REG(0xa, ISS),
+       MBOX_INC_SEL_EXTAR_REG(0xa, PLD),
+       MBOX_INC_SEL_EXTAR_REG(0xb, PLD),
+       /* events 0xd ~ 0x10 use the same extra register */
+       MBOX_INC_SEL_EXTAR_REG(0xd, ZDP_CTL_FVC),
+       MBOX_INC_SEL_EXTAR_REG(0xe, ZDP_CTL_FVC),
+       MBOX_INC_SEL_EXTAR_REG(0xf, ZDP_CTL_FVC),
+       MBOX_INC_SEL_EXTAR_REG(0x10, ZDP_CTL_FVC),
+       MBOX_INC_SEL_EXTAR_REG(0x16, PGT),
+       MBOX_SET_FLAG_SEL_EXTRA_REG(0x0, DSP),
+       MBOX_SET_FLAG_SEL_EXTRA_REG(0x1, ISS),
+       MBOX_SET_FLAG_SEL_EXTRA_REG(0x5, PGT),
+       MBOX_SET_FLAG_SEL_EXTRA_REG(0x6, MAP),
+       EVENT_EXTRA_END
+};
+
+/* Nehalem-EX or Westmere-EX ? */
+static bool uncore_nhmex;
+
+static bool nhmex_mbox_get_shared_reg(struct intel_uncore_box *box, int idx, u64 config)
+{
+       struct intel_uncore_extra_reg *er;
+       unsigned long flags;
+       bool ret = false;
+       u64 mask;
+
+       if (idx < EXTRA_REG_NHMEX_M_ZDP_CTL_FVC) {
+               er = &box->shared_regs[idx];
+               raw_spin_lock_irqsave(&er->lock, flags);
+               if (!atomic_read(&er->ref) || er->config == config) {
+                       atomic_inc(&er->ref);
+                       er->config = config;
+                       ret = true;
+               }
+               raw_spin_unlock_irqrestore(&er->lock, flags);
+
+               return ret;
+       }
+       /*
+        * The ZDP_CTL_FVC MSR has 4 fields which are used to control
+        * events 0xd ~ 0x10. Besides these 4 fields, there are additional
+        * fields which are shared.
+        */
+       idx -= EXTRA_REG_NHMEX_M_ZDP_CTL_FVC;
+       if (WARN_ON_ONCE(idx >= 4))
+               return false;
+
+       /* mask of the shared fields */
+       if (uncore_nhmex)
+               mask = NHMEX_M_PMON_ZDP_CTL_FVC_MASK;
+       else
+               mask = WSMEX_M_PMON_ZDP_CTL_FVC_MASK;
+       er = &box->shared_regs[EXTRA_REG_NHMEX_M_ZDP_CTL_FVC];
+
+       raw_spin_lock_irqsave(&er->lock, flags);
+       /* add mask of the non-shared field if it's in use */
+       if (__BITS_VALUE(atomic_read(&er->ref), idx, 8)) {
+               if (uncore_nhmex)
+                       mask |= NHMEX_M_PMON_ZDP_CTL_FVC_EVENT_MASK(idx);
+               else
+                       mask |= WSMEX_M_PMON_ZDP_CTL_FVC_EVENT_MASK(idx);
+       }
+
+       if (!atomic_read(&er->ref) || !((er->config ^ config) & mask)) {
+               atomic_add(1 << (idx * 8), &er->ref);
+               if (uncore_nhmex)
+                       mask = NHMEX_M_PMON_ZDP_CTL_FVC_MASK |
+                               NHMEX_M_PMON_ZDP_CTL_FVC_EVENT_MASK(idx);
+               else
+                       mask = WSMEX_M_PMON_ZDP_CTL_FVC_MASK |
+                               WSMEX_M_PMON_ZDP_CTL_FVC_EVENT_MASK(idx);
+               er->config &= ~mask;
+               er->config |= (config & mask);
+               ret = true;
+       }
+       raw_spin_unlock_irqrestore(&er->lock, flags);
+
+       return ret;
+}
+
+static void nhmex_mbox_put_shared_reg(struct intel_uncore_box *box, int idx)
+{
+       struct intel_uncore_extra_reg *er;
+
+       if (idx < EXTRA_REG_NHMEX_M_ZDP_CTL_FVC) {
+               er = &box->shared_regs[idx];
+               atomic_dec(&er->ref);
+               return;
+       }
+
+       idx -= EXTRA_REG_NHMEX_M_ZDP_CTL_FVC;
+       er = &box->shared_regs[EXTRA_REG_NHMEX_M_ZDP_CTL_FVC];
+       atomic_sub(1 << (idx * 8), &er->ref);
+}
+
+static u64 nhmex_mbox_alter_er(struct perf_event *event, int new_idx, bool modify)
+{
+       struct hw_perf_event *hwc = &event->hw;
+       struct hw_perf_event_extra *reg1 = &hwc->extra_reg;
+       u64 idx, orig_idx = __BITS_VALUE(reg1->idx, 0, 8);
+       u64 config = reg1->config;
+
+       /* get the non-shared control bits and shift them */
+       idx = orig_idx - EXTRA_REG_NHMEX_M_ZDP_CTL_FVC;
+       if (uncore_nhmex)
+               config &= NHMEX_M_PMON_ZDP_CTL_FVC_EVENT_MASK(idx);
+       else
+               config &= WSMEX_M_PMON_ZDP_CTL_FVC_EVENT_MASK(idx);
+       if (new_idx > orig_idx) {
+               idx = new_idx - orig_idx;
+               config <<= 3 * idx;
+       } else {
+               idx = orig_idx - new_idx;
+               config >>= 3 * idx;
+       }
+
+       /* add the shared control bits back */
+       if (uncore_nhmex)
+               config |= NHMEX_M_PMON_ZDP_CTL_FVC_MASK & reg1->config;
+       else
+               config |= WSMEX_M_PMON_ZDP_CTL_FVC_MASK & reg1->config;
+       config |= NHMEX_M_PMON_ZDP_CTL_FVC_MASK & reg1->config;
+       if (modify) {
+               /* adjust the main event selector */
+               if (new_idx > orig_idx)
+                       hwc->config += idx << NHMEX_M_PMON_CTL_INC_SEL_SHIFT;
+               else
+                       hwc->config -= idx << NHMEX_M_PMON_CTL_INC_SEL_SHIFT;
+               reg1->config = config;
+               reg1->idx = ~0xff | new_idx;
+       }
+       return config;
+}
+
+static struct event_constraint *
+nhmex_mbox_get_constraint(struct intel_uncore_box *box, struct perf_event *event)
+{
+       struct hw_perf_event_extra *reg1 = &event->hw.extra_reg;
+       struct hw_perf_event_extra *reg2 = &event->hw.branch_reg;
+       int i, idx[2], alloc = 0;
+       u64 config1 = reg1->config;
+
+       idx[0] = __BITS_VALUE(reg1->idx, 0, 8);
+       idx[1] = __BITS_VALUE(reg1->idx, 1, 8);
+again:
+       for (i = 0; i < 2; i++) {
+               if (!uncore_box_is_fake(box) && (reg1->alloc & (0x1 << i)))
+                       idx[i] = 0xff;
+
+               if (idx[i] == 0xff)
+                       continue;
+
+               if (!nhmex_mbox_get_shared_reg(box, idx[i],
+                               __BITS_VALUE(config1, i, 32)))
+                       goto fail;
+               alloc |= (0x1 << i);
+       }
+
+       /* for the match/mask registers */
+       if (reg2->idx != EXTRA_REG_NONE &&
+           (uncore_box_is_fake(box) || !reg2->alloc) &&
+           !nhmex_mbox_get_shared_reg(box, reg2->idx, reg2->config))
+               goto fail;
+
+       /*
+        * If it's a fake box -- as per validate_{group,event}() we
+        * shouldn't touch event state and we can avoid doing so
+        * since both will only call get_event_constraints() once
+        * on each event, this avoids the need for reg->alloc.
+        */
+       if (!uncore_box_is_fake(box)) {
+               if (idx[0] != 0xff && idx[0] != __BITS_VALUE(reg1->idx, 0, 8))
+                       nhmex_mbox_alter_er(event, idx[0], true);
+               reg1->alloc |= alloc;
+               if (reg2->idx != EXTRA_REG_NONE)
+                       reg2->alloc = 1;
+       }
+       return NULL;
+fail:
+       if (idx[0] != 0xff && !(alloc & 0x1) &&
+           idx[0] >= EXTRA_REG_NHMEX_M_ZDP_CTL_FVC) {
+               /*
+                * events 0xd ~ 0x10 are functional identical, but are
+                * controlled by different fields in the ZDP_CTL_FVC
+                * register. If we failed to take one field, try the
+                * rest 3 choices.
+                */
+               BUG_ON(__BITS_VALUE(reg1->idx, 1, 8) != 0xff);
+               idx[0] -= EXTRA_REG_NHMEX_M_ZDP_CTL_FVC;
+               idx[0] = (idx[0] + 1) % 4;
+               idx[0] += EXTRA_REG_NHMEX_M_ZDP_CTL_FVC;
+               if (idx[0] != __BITS_VALUE(reg1->idx, 0, 8)) {
+                       config1 = nhmex_mbox_alter_er(event, idx[0], false);
+                       goto again;
+               }
+       }
+
+       if (alloc & 0x1)
+               nhmex_mbox_put_shared_reg(box, idx[0]);
+       if (alloc & 0x2)
+               nhmex_mbox_put_shared_reg(box, idx[1]);
+       return &uncore_constraint_empty;
+}
+
+static void nhmex_mbox_put_constraint(struct intel_uncore_box *box, struct perf_event *event)
+{
+       struct hw_perf_event_extra *reg1 = &event->hw.extra_reg;
+       struct hw_perf_event_extra *reg2 = &event->hw.branch_reg;
+
+       if (uncore_box_is_fake(box))
+               return;
+
+       if (reg1->alloc & 0x1)
+               nhmex_mbox_put_shared_reg(box, __BITS_VALUE(reg1->idx, 0, 8));
+       if (reg1->alloc & 0x2)
+               nhmex_mbox_put_shared_reg(box, __BITS_VALUE(reg1->idx, 1, 8));
+       reg1->alloc = 0;
+
+       if (reg2->alloc) {
+               nhmex_mbox_put_shared_reg(box, reg2->idx);
+               reg2->alloc = 0;
+       }
+}
+
+static int nhmex_mbox_extra_reg_idx(struct extra_reg *er)
+{
+       if (er->idx < EXTRA_REG_NHMEX_M_ZDP_CTL_FVC)
+               return er->idx;
+       return er->idx + (er->event >> NHMEX_M_PMON_CTL_INC_SEL_SHIFT) - 0xd;
+}
+
+static int nhmex_mbox_hw_config(struct intel_uncore_box *box, struct perf_event *event)
+{
+       struct intel_uncore_type *type = box->pmu->type;
+       struct hw_perf_event_extra *reg1 = &event->hw.extra_reg;
+       struct hw_perf_event_extra *reg2 = &event->hw.branch_reg;
+       struct extra_reg *er;
+       unsigned msr;
+       int reg_idx = 0;
+       /*
+        * The mbox events may require 2 extra MSRs at the most. But only
+        * the lower 32 bits in these MSRs are significant, so we can use
+        * config1 to pass two MSRs' config.
+        */
+       for (er = nhmex_uncore_mbox_extra_regs; er->msr; er++) {
+               if (er->event != (event->hw.config & er->config_mask))
+                       continue;
+               if (event->attr.config1 & ~er->valid_mask)
+                       return -EINVAL;
+
+               msr = er->msr + type->msr_offset * box->pmu->pmu_idx;
+               if (WARN_ON_ONCE(msr >= 0xffff || er->idx >= 0xff))
+                       return -EINVAL;
+
+               /* always use the 32~63 bits to pass the PLD config */
+               if (er->idx == EXTRA_REG_NHMEX_M_PLD)
+                       reg_idx = 1;
+               else if (WARN_ON_ONCE(reg_idx > 0))
+                       return -EINVAL;
+
+               reg1->idx &= ~(0xff << (reg_idx * 8));
+               reg1->reg &= ~(0xffff << (reg_idx * 16));
+               reg1->idx |= nhmex_mbox_extra_reg_idx(er) << (reg_idx * 8);
+               reg1->reg |= msr << (reg_idx * 16);
+               reg1->config = event->attr.config1;
+               reg_idx++;
+       }
+       /*
+        * The mbox only provides ability to perform address matching
+        * for the PLD events.
+        */
+       if (reg_idx == 2) {
+               reg2->idx = EXTRA_REG_NHMEX_M_FILTER;
+               if (event->attr.config2 & NHMEX_M_PMON_MM_CFG_EN)
+                       reg2->config = event->attr.config2;
+               else
+                       reg2->config = ~0ULL;
+               if (box->pmu->pmu_idx == 0)
+                       reg2->reg = NHMEX_M0_MSR_PMU_MM_CFG;
+               else
+                       reg2->reg = NHMEX_M1_MSR_PMU_MM_CFG;
+       }
+       return 0;
+}
+
+static u64 nhmex_mbox_shared_reg_config(struct intel_uncore_box *box, int idx)
+{
+       struct intel_uncore_extra_reg *er;
+       unsigned long flags;
+       u64 config;
+
+       if (idx < EXTRA_REG_NHMEX_M_ZDP_CTL_FVC)
+               return box->shared_regs[idx].config;
+
+       er = &box->shared_regs[EXTRA_REG_NHMEX_M_ZDP_CTL_FVC];
+       raw_spin_lock_irqsave(&er->lock, flags);
+       config = er->config;
+       raw_spin_unlock_irqrestore(&er->lock, flags);
+       return config;
+}
+
+static void nhmex_mbox_msr_enable_event(struct intel_uncore_box *box, struct perf_event *event)
+{
+       struct hw_perf_event *hwc = &event->hw;
+       struct hw_perf_event_extra *reg1 = &hwc->extra_reg;
+       struct hw_perf_event_extra *reg2 = &hwc->branch_reg;
+       int idx;
+
+       idx = __BITS_VALUE(reg1->idx, 0, 8);
+       if (idx != 0xff)
+               wrmsrl(__BITS_VALUE(reg1->reg, 0, 16),
+                       nhmex_mbox_shared_reg_config(box, idx));
+       idx = __BITS_VALUE(reg1->idx, 1, 8);
+       if (idx != 0xff)
+               wrmsrl(__BITS_VALUE(reg1->reg, 1, 16),
+                       nhmex_mbox_shared_reg_config(box, idx));
+
+       if (reg2->idx != EXTRA_REG_NONE) {
+               wrmsrl(reg2->reg, 0);
+               if (reg2->config != ~0ULL) {
+                       wrmsrl(reg2->reg + 1,
+                               reg2->config & NHMEX_M_PMON_ADDR_MATCH_MASK);
+                       wrmsrl(reg2->reg + 2, NHMEX_M_PMON_ADDR_MASK_MASK &
+                               (reg2->config >> NHMEX_M_PMON_ADDR_MASK_SHIFT));
+                       wrmsrl(reg2->reg, NHMEX_M_PMON_MM_CFG_EN);
+               }
+       }
+
+       wrmsrl(hwc->config_base, hwc->config | NHMEX_PMON_CTL_EN_BIT0);
+}
+
+DEFINE_UNCORE_FORMAT_ATTR(count_mode,          count_mode,     "config:2-3");
+DEFINE_UNCORE_FORMAT_ATTR(storage_mode,                storage_mode,   "config:4-5");
+DEFINE_UNCORE_FORMAT_ATTR(wrap_mode,           wrap_mode,      "config:6");
+DEFINE_UNCORE_FORMAT_ATTR(flag_mode,           flag_mode,      "config:7");
+DEFINE_UNCORE_FORMAT_ATTR(inc_sel,             inc_sel,        "config:9-13");
+DEFINE_UNCORE_FORMAT_ATTR(set_flag_sel,                set_flag_sel,   "config:19-21");
+DEFINE_UNCORE_FORMAT_ATTR(filter_cfg_en,       filter_cfg_en,  "config2:63");
+DEFINE_UNCORE_FORMAT_ATTR(filter_match,                filter_match,   "config2:0-33");
+DEFINE_UNCORE_FORMAT_ATTR(filter_mask,         filter_mask,    "config2:34-61");
+DEFINE_UNCORE_FORMAT_ATTR(dsp,                 dsp,            "config1:0-31");
+DEFINE_UNCORE_FORMAT_ATTR(thr,                 thr,            "config1:0-31");
+DEFINE_UNCORE_FORMAT_ATTR(fvc,                 fvc,            "config1:0-31");
+DEFINE_UNCORE_FORMAT_ATTR(pgt,                 pgt,            "config1:0-31");
+DEFINE_UNCORE_FORMAT_ATTR(map,                 map,            "config1:0-31");
+DEFINE_UNCORE_FORMAT_ATTR(iss,                 iss,            "config1:0-31");
+DEFINE_UNCORE_FORMAT_ATTR(pld,                 pld,            "config1:32-63");
+
+static struct attribute *nhmex_uncore_mbox_formats_attr[] = {
+       &format_attr_count_mode.attr,
+       &format_attr_storage_mode.attr,
+       &format_attr_wrap_mode.attr,
+       &format_attr_flag_mode.attr,
+       &format_attr_inc_sel.attr,
+       &format_attr_set_flag_sel.attr,
+       &format_attr_filter_cfg_en.attr,
+       &format_attr_filter_match.attr,
+       &format_attr_filter_mask.attr,
+       &format_attr_dsp.attr,
+       &format_attr_thr.attr,
+       &format_attr_fvc.attr,
+       &format_attr_pgt.attr,
+       &format_attr_map.attr,
+       &format_attr_iss.attr,
+       &format_attr_pld.attr,
+       NULL,
+};
+
+static struct attribute_group nhmex_uncore_mbox_format_group = {
+       .name           = "format",
+       .attrs          = nhmex_uncore_mbox_formats_attr,
+};
+
+static struct uncore_event_desc nhmex_uncore_mbox_events[] = {
+       INTEL_UNCORE_EVENT_DESC(bbox_cmds_read, "inc_sel=0xd,fvc=0x2800"),
+       INTEL_UNCORE_EVENT_DESC(bbox_cmds_write, "inc_sel=0xd,fvc=0x2820"),
+       { /* end: all zeroes */ },
+};
+
+static struct uncore_event_desc wsmex_uncore_mbox_events[] = {
+       INTEL_UNCORE_EVENT_DESC(bbox_cmds_read, "inc_sel=0xd,fvc=0x5000"),
+       INTEL_UNCORE_EVENT_DESC(bbox_cmds_write, "inc_sel=0xd,fvc=0x5040"),
+       { /* end: all zeroes */ },
+};
+
+static struct intel_uncore_ops nhmex_uncore_mbox_ops = {
+       NHMEX_UNCORE_OPS_COMMON_INIT(),
+       .enable_event   = nhmex_mbox_msr_enable_event,
+       .hw_config      = nhmex_mbox_hw_config,
+       .get_constraint = nhmex_mbox_get_constraint,
+       .put_constraint = nhmex_mbox_put_constraint,
+};
+
+static struct intel_uncore_type nhmex_uncore_mbox = {
+       .name                   = "mbox",
+       .num_counters           = 6,
+       .num_boxes              = 2,
+       .perf_ctr_bits          = 48,
+       .event_ctl              = NHMEX_M0_MSR_PMU_CTL0,
+       .perf_ctr               = NHMEX_M0_MSR_PMU_CNT0,
+       .event_mask             = NHMEX_M_PMON_RAW_EVENT_MASK,
+       .box_ctl                = NHMEX_M0_MSR_GLOBAL_CTL,
+       .msr_offset             = NHMEX_M_MSR_OFFSET,
+       .pair_ctr_ctl           = 1,
+       .num_shared_regs        = 8,
+       .event_descs            = nhmex_uncore_mbox_events,
+       .ops                    = &nhmex_uncore_mbox_ops,
+       .format_group           = &nhmex_uncore_mbox_format_group,
+};
+
+static void nhmex_rbox_alter_er(struct intel_uncore_box *box, struct perf_event *event)
+{
+       struct hw_perf_event *hwc = &event->hw;
+       struct hw_perf_event_extra *reg1 = &hwc->extra_reg;
+
+       /* adjust the main event selector and extra register index */
+       if (reg1->idx % 2) {
+               reg1->idx--;
+               hwc->config -= 1 << NHMEX_R_PMON_CTL_EV_SEL_SHIFT;
+       } else {
+               reg1->idx++;
+               hwc->config += 1 << NHMEX_R_PMON_CTL_EV_SEL_SHIFT;
+       }
+
+       /* adjust extra register config */
+       switch (reg1->idx % 6) {
+       case 2:
+               /* shift the 8~15 bits to the 0~7 bits */
+               reg1->config >>= 8;
+               break;
+       case 3:
+               /* shift the 0~7 bits to the 8~15 bits */
+               reg1->config <<= 8;
+               break;
+       }
+}
+
+/*
+ * Each rbox has 4 event set which monitor PQI port 0~3 or 4~7.
+ * An event set consists of 6 events, the 3rd and 4th events in
+ * an event set use the same extra register. So an event set uses
+ * 5 extra registers.
+ */
+static struct event_constraint *
+nhmex_rbox_get_constraint(struct intel_uncore_box *box, struct perf_event *event)
+{
+       struct hw_perf_event *hwc = &event->hw;
+       struct hw_perf_event_extra *reg1 = &hwc->extra_reg;
+       struct hw_perf_event_extra *reg2 = &hwc->branch_reg;
+       struct intel_uncore_extra_reg *er;
+       unsigned long flags;
+       int idx, er_idx;
+       u64 config1;
+       bool ok = false;
+
+       if (!uncore_box_is_fake(box) && reg1->alloc)
+               return NULL;
+
+       idx = reg1->idx % 6;
+       config1 = reg1->config;
+again:
+       er_idx = idx;
+       /* the 3rd and 4th events use the same extra register */
+       if (er_idx > 2)
+               er_idx--;
+       er_idx += (reg1->idx / 6) * 5;
+
+       er = &box->shared_regs[er_idx];
+       raw_spin_lock_irqsave(&er->lock, flags);
+       if (idx < 2) {
+               if (!atomic_read(&er->ref) || er->config == reg1->config) {
+                       atomic_inc(&er->ref);
+                       er->config = reg1->config;
+                       ok = true;
+               }
+       } else if (idx == 2 || idx == 3) {
+               /*
+                * these two events use different fields in a extra register,
+                * the 0~7 bits and the 8~15 bits respectively.
+                */
+               u64 mask = 0xff << ((idx - 2) * 8);
+               if (!__BITS_VALUE(atomic_read(&er->ref), idx - 2, 8) ||
+                               !((er->config ^ config1) & mask)) {
+                       atomic_add(1 << ((idx - 2) * 8), &er->ref);
+                       er->config &= ~mask;
+                       er->config |= config1 & mask;
+                       ok = true;
+               }
+       } else {
+               if (!atomic_read(&er->ref) ||
+                               (er->config == (hwc->config >> 32) &&
+                                er->config1 == reg1->config &&
+                                er->config2 == reg2->config)) {
+                       atomic_inc(&er->ref);
+                       er->config = (hwc->config >> 32);
+                       er->config1 = reg1->config;
+                       er->config2 = reg2->config;
+                       ok = true;
+               }
+       }
+       raw_spin_unlock_irqrestore(&er->lock, flags);
+
+       if (!ok) {
+               /*
+                * The Rbox events are always in pairs. The paired
+                * events are functional identical, but use different
+                * extra registers. If we failed to take an extra
+                * register, try the alternative.
+                */
+               idx ^= 1;
+               if (idx != reg1->idx % 6) {
+                       if (idx == 2)
+                               config1 >>= 8;
+                       else if (idx == 3)
+                               config1 <<= 8;
+                       goto again;
+               }
+       } else {
+               if (!uncore_box_is_fake(box)) {
+                       if (idx != reg1->idx % 6)
+                               nhmex_rbox_alter_er(box, event);
+                       reg1->alloc = 1;
+               }
+               return NULL;
+       }
+       return &uncore_constraint_empty;
+}
+
+static void nhmex_rbox_put_constraint(struct intel_uncore_box *box, struct perf_event *event)
+{
+       struct intel_uncore_extra_reg *er;
+       struct hw_perf_event_extra *reg1 = &event->hw.extra_reg;
+       int idx, er_idx;
+
+       if (uncore_box_is_fake(box) || !reg1->alloc)
+               return;
+
+       idx = reg1->idx % 6;
+       er_idx = idx;
+       if (er_idx > 2)
+               er_idx--;
+       er_idx += (reg1->idx / 6) * 5;
+
+       er = &box->shared_regs[er_idx];
+       if (idx == 2 || idx == 3)
+               atomic_sub(1 << ((idx - 2) * 8), &er->ref);
+       else
+               atomic_dec(&er->ref);
+
+       reg1->alloc = 0;
+}
+
+static int nhmex_rbox_hw_config(struct intel_uncore_box *box, struct perf_event *event)
+{
+       struct hw_perf_event *hwc = &event->hw;
+       struct hw_perf_event_extra *reg1 = &event->hw.extra_reg;
+       struct hw_perf_event_extra *reg2 = &event->hw.branch_reg;
+       int idx;
+
+       idx = (event->hw.config & NHMEX_R_PMON_CTL_EV_SEL_MASK) >>
+               NHMEX_R_PMON_CTL_EV_SEL_SHIFT;
+       if (idx >= 0x18)
+               return -EINVAL;
+
+       reg1->idx = idx;
+       reg1->config = event->attr.config1;
+
+       switch (idx % 6) {
+       case 4:
+       case 5:
+               hwc->config |= event->attr.config & (~0ULL << 32);
+               reg2->config = event->attr.config2;
+               break;
+       }
+       return 0;
+}
+
+static void nhmex_rbox_msr_enable_event(struct intel_uncore_box *box, struct perf_event *event)
+{
+       struct hw_perf_event *hwc = &event->hw;
+       struct hw_perf_event_extra *reg1 = &hwc->extra_reg;
+       struct hw_perf_event_extra *reg2 = &hwc->branch_reg;
+       int idx, port;
+
+       idx = reg1->idx;
+       port = idx / 6 + box->pmu->pmu_idx * 4;
+
+       switch (idx % 6) {
+       case 0:
+               wrmsrl(NHMEX_R_MSR_PORTN_IPERF_CFG0(port), reg1->config);
+               break;
+       case 1:
+               wrmsrl(NHMEX_R_MSR_PORTN_IPERF_CFG1(port), reg1->config);
+               break;
+       case 2:
+       case 3:
+               wrmsrl(NHMEX_R_MSR_PORTN_QLX_CFG(port),
+                       uncore_shared_reg_config(box, 2 + (idx / 6) * 5));
+               break;
+       case 4:
+               wrmsrl(NHMEX_R_MSR_PORTN_XBR_SET1_MM_CFG(port),
+                       hwc->config >> 32);
+               wrmsrl(NHMEX_R_MSR_PORTN_XBR_SET1_MATCH(port), reg1->config);
+               wrmsrl(NHMEX_R_MSR_PORTN_XBR_SET1_MASK(port), reg2->config);
+               break;
+       case 5:
+               wrmsrl(NHMEX_R_MSR_PORTN_XBR_SET2_MM_CFG(port),
+                       hwc->config >> 32);
+               wrmsrl(NHMEX_R_MSR_PORTN_XBR_SET2_MATCH(port), reg1->config);
+               wrmsrl(NHMEX_R_MSR_PORTN_XBR_SET2_MASK(port), reg2->config);
+               break;
+       }
+
+       wrmsrl(hwc->config_base, NHMEX_PMON_CTL_EN_BIT0 |
+               (hwc->config & NHMEX_R_PMON_CTL_EV_SEL_MASK));
+}
+
+DEFINE_UNCORE_FORMAT_ATTR(xbr_mm_cfg, xbr_mm_cfg, "config:32-63");
+DEFINE_UNCORE_FORMAT_ATTR(xbr_match, xbr_match, "config1:0-63");
+DEFINE_UNCORE_FORMAT_ATTR(xbr_mask, xbr_mask, "config2:0-63");
+DEFINE_UNCORE_FORMAT_ATTR(qlx_cfg, qlx_cfg, "config1:0-15");
+DEFINE_UNCORE_FORMAT_ATTR(iperf_cfg, iperf_cfg, "config1:0-31");
+
+static struct attribute *nhmex_uncore_rbox_formats_attr[] = {
+       &format_attr_event5.attr,
+       &format_attr_xbr_mm_cfg.attr,
+       &format_attr_xbr_match.attr,
+       &format_attr_xbr_mask.attr,
+       &format_attr_qlx_cfg.attr,
+       &format_attr_iperf_cfg.attr,
+       NULL,
+};
+
+static struct attribute_group nhmex_uncore_rbox_format_group = {
+       .name = "format",
+       .attrs = nhmex_uncore_rbox_formats_attr,
+};
+
+static struct uncore_event_desc nhmex_uncore_rbox_events[] = {
+       INTEL_UNCORE_EVENT_DESC(qpi0_flit_send,         "event=0x0,iperf_cfg=0x80000000"),
+       INTEL_UNCORE_EVENT_DESC(qpi1_filt_send,         "event=0x6,iperf_cfg=0x80000000"),
+       INTEL_UNCORE_EVENT_DESC(qpi0_idle_filt,         "event=0x0,iperf_cfg=0x40000000"),
+       INTEL_UNCORE_EVENT_DESC(qpi1_idle_filt,         "event=0x6,iperf_cfg=0x40000000"),
+       INTEL_UNCORE_EVENT_DESC(qpi0_date_response,     "event=0x0,iperf_cfg=0xc4"),
+       INTEL_UNCORE_EVENT_DESC(qpi1_date_response,     "event=0x6,iperf_cfg=0xc4"),
+       { /* end: all zeroes */ },
+};
+
+static struct intel_uncore_ops nhmex_uncore_rbox_ops = {
+       NHMEX_UNCORE_OPS_COMMON_INIT(),
+       .enable_event           = nhmex_rbox_msr_enable_event,
+       .hw_config              = nhmex_rbox_hw_config,
+       .get_constraint         = nhmex_rbox_get_constraint,
+       .put_constraint         = nhmex_rbox_put_constraint,
+};
+
+static struct intel_uncore_type nhmex_uncore_rbox = {
+       .name                   = "rbox",
+       .num_counters           = 8,
+       .num_boxes              = 2,
+       .perf_ctr_bits          = 48,
+       .event_ctl              = NHMEX_R_MSR_PMON_CTL0,
+       .perf_ctr               = NHMEX_R_MSR_PMON_CNT0,
+       .event_mask             = NHMEX_R_PMON_RAW_EVENT_MASK,
+       .box_ctl                = NHMEX_R_MSR_GLOBAL_CTL,
+       .msr_offset             = NHMEX_R_MSR_OFFSET,
+       .pair_ctr_ctl           = 1,
+       .num_shared_regs        = 20,
+       .event_descs            = nhmex_uncore_rbox_events,
+       .ops                    = &nhmex_uncore_rbox_ops,
+       .format_group           = &nhmex_uncore_rbox_format_group
+};
+
+static struct intel_uncore_type *nhmex_msr_uncores[] = {
+       &nhmex_uncore_ubox,
+       &nhmex_uncore_cbox,
+       &nhmex_uncore_bbox,
+       &nhmex_uncore_sbox,
+       &nhmex_uncore_mbox,
+       &nhmex_uncore_rbox,
+       &nhmex_uncore_wbox,
+       NULL,
+};
+
+void nhmex_uncore_cpu_init(void)
+{
+       if (boot_cpu_data.x86_model == 46)
+               uncore_nhmex = true;
+       else
+               nhmex_uncore_mbox.event_descs = wsmex_uncore_mbox_events;
+       if (nhmex_uncore_cbox.num_boxes > boot_cpu_data.x86_max_cores)
+               nhmex_uncore_cbox.num_boxes = boot_cpu_data.x86_max_cores;
+       uncore_msr_uncores = nhmex_msr_uncores;
+}
+/* end of Nehalem-EX uncore support */
diff --git a/arch/x86/kernel/cpu/perf_event_intel_uncore_snb.c b/arch/x86/kernel/cpu/perf_event_intel_uncore_snb.c
new file mode 100644 (file)
index 0000000..3001015
--- /dev/null
@@ -0,0 +1,636 @@
+/* Nehalem/SandBridge/Haswell uncore support */
+#include "perf_event_intel_uncore.h"
+
+/* SNB event control */
+#define SNB_UNC_CTL_EV_SEL_MASK                        0x000000ff
+#define SNB_UNC_CTL_UMASK_MASK                 0x0000ff00
+#define SNB_UNC_CTL_EDGE_DET                   (1 << 18)
+#define SNB_UNC_CTL_EN                         (1 << 22)
+#define SNB_UNC_CTL_INVERT                     (1 << 23)
+#define SNB_UNC_CTL_CMASK_MASK                 0x1f000000
+#define NHM_UNC_CTL_CMASK_MASK                 0xff000000
+#define NHM_UNC_FIXED_CTR_CTL_EN               (1 << 0)
+
+#define SNB_UNC_RAW_EVENT_MASK                 (SNB_UNC_CTL_EV_SEL_MASK | \
+                                                SNB_UNC_CTL_UMASK_MASK | \
+                                                SNB_UNC_CTL_EDGE_DET | \
+                                                SNB_UNC_CTL_INVERT | \
+                                                SNB_UNC_CTL_CMASK_MASK)
+
+#define NHM_UNC_RAW_EVENT_MASK                 (SNB_UNC_CTL_EV_SEL_MASK | \
+                                                SNB_UNC_CTL_UMASK_MASK | \
+                                                SNB_UNC_CTL_EDGE_DET | \
+                                                SNB_UNC_CTL_INVERT | \
+                                                NHM_UNC_CTL_CMASK_MASK)
+
+/* SNB global control register */
+#define SNB_UNC_PERF_GLOBAL_CTL                 0x391
+#define SNB_UNC_FIXED_CTR_CTRL                  0x394
+#define SNB_UNC_FIXED_CTR                       0x395
+
+/* SNB uncore global control */
+#define SNB_UNC_GLOBAL_CTL_CORE_ALL             ((1 << 4) - 1)
+#define SNB_UNC_GLOBAL_CTL_EN                   (1 << 29)
+
+/* SNB Cbo register */
+#define SNB_UNC_CBO_0_PERFEVTSEL0               0x700
+#define SNB_UNC_CBO_0_PER_CTR0                  0x706
+#define SNB_UNC_CBO_MSR_OFFSET                  0x10
+
+/* NHM global control register */
+#define NHM_UNC_PERF_GLOBAL_CTL                 0x391
+#define NHM_UNC_FIXED_CTR                       0x394
+#define NHM_UNC_FIXED_CTR_CTRL                  0x395
+
+/* NHM uncore global control */
+#define NHM_UNC_GLOBAL_CTL_EN_PC_ALL            ((1ULL << 8) - 1)
+#define NHM_UNC_GLOBAL_CTL_EN_FC                (1ULL << 32)
+
+/* NHM uncore register */
+#define NHM_UNC_PERFEVTSEL0                     0x3c0
+#define NHM_UNC_UNCORE_PMC0                     0x3b0
+
+DEFINE_UNCORE_FORMAT_ATTR(event, event, "config:0-7");
+DEFINE_UNCORE_FORMAT_ATTR(umask, umask, "config:8-15");
+DEFINE_UNCORE_FORMAT_ATTR(edge, edge, "config:18");
+DEFINE_UNCORE_FORMAT_ATTR(inv, inv, "config:23");
+DEFINE_UNCORE_FORMAT_ATTR(cmask5, cmask, "config:24-28");
+DEFINE_UNCORE_FORMAT_ATTR(cmask8, cmask, "config:24-31");
+
+/* Sandy Bridge uncore support */
+static void snb_uncore_msr_enable_event(struct intel_uncore_box *box, struct perf_event *event)
+{
+       struct hw_perf_event *hwc = &event->hw;
+
+       if (hwc->idx < UNCORE_PMC_IDX_FIXED)
+               wrmsrl(hwc->config_base, hwc->config | SNB_UNC_CTL_EN);
+       else
+               wrmsrl(hwc->config_base, SNB_UNC_CTL_EN);
+}
+
+static void snb_uncore_msr_disable_event(struct intel_uncore_box *box, struct perf_event *event)
+{
+       wrmsrl(event->hw.config_base, 0);
+}
+
+static void snb_uncore_msr_init_box(struct intel_uncore_box *box)
+{
+       if (box->pmu->pmu_idx == 0) {
+               wrmsrl(SNB_UNC_PERF_GLOBAL_CTL,
+                       SNB_UNC_GLOBAL_CTL_EN | SNB_UNC_GLOBAL_CTL_CORE_ALL);
+       }
+}
+
+static struct uncore_event_desc snb_uncore_events[] = {
+       INTEL_UNCORE_EVENT_DESC(clockticks, "event=0xff,umask=0x00"),
+       { /* end: all zeroes */ },
+};
+
+static struct attribute *snb_uncore_formats_attr[] = {
+       &format_attr_event.attr,
+       &format_attr_umask.attr,
+       &format_attr_edge.attr,
+       &format_attr_inv.attr,
+       &format_attr_cmask5.attr,
+       NULL,
+};
+
+static struct attribute_group snb_uncore_format_group = {
+       .name           = "format",
+       .attrs          = snb_uncore_formats_attr,
+};
+
+static struct intel_uncore_ops snb_uncore_msr_ops = {
+       .init_box       = snb_uncore_msr_init_box,
+       .disable_event  = snb_uncore_msr_disable_event,
+       .enable_event   = snb_uncore_msr_enable_event,
+       .read_counter   = uncore_msr_read_counter,
+};
+
+static struct event_constraint snb_uncore_cbox_constraints[] = {
+       UNCORE_EVENT_CONSTRAINT(0x80, 0x1),
+       UNCORE_EVENT_CONSTRAINT(0x83, 0x1),
+       EVENT_CONSTRAINT_END
+};
+
+static struct intel_uncore_type snb_uncore_cbox = {
+       .name           = "cbox",
+       .num_counters   = 2,
+       .num_boxes      = 4,
+       .perf_ctr_bits  = 44,
+       .fixed_ctr_bits = 48,
+       .perf_ctr       = SNB_UNC_CBO_0_PER_CTR0,
+       .event_ctl      = SNB_UNC_CBO_0_PERFEVTSEL0,
+       .fixed_ctr      = SNB_UNC_FIXED_CTR,
+       .fixed_ctl      = SNB_UNC_FIXED_CTR_CTRL,
+       .single_fixed   = 1,
+       .event_mask     = SNB_UNC_RAW_EVENT_MASK,
+       .msr_offset     = SNB_UNC_CBO_MSR_OFFSET,
+       .constraints    = snb_uncore_cbox_constraints,
+       .ops            = &snb_uncore_msr_ops,
+       .format_group   = &snb_uncore_format_group,
+       .event_descs    = snb_uncore_events,
+};
+
+static struct intel_uncore_type *snb_msr_uncores[] = {
+       &snb_uncore_cbox,
+       NULL,
+};
+
+void snb_uncore_cpu_init(void)
+{
+       uncore_msr_uncores = snb_msr_uncores;
+       if (snb_uncore_cbox.num_boxes > boot_cpu_data.x86_max_cores)
+               snb_uncore_cbox.num_boxes = boot_cpu_data.x86_max_cores;
+}
+
+enum {
+       SNB_PCI_UNCORE_IMC,
+};
+
+static struct uncore_event_desc snb_uncore_imc_events[] = {
+       INTEL_UNCORE_EVENT_DESC(data_reads,  "event=0x01"),
+       INTEL_UNCORE_EVENT_DESC(data_reads.scale, "6.103515625e-5"),
+       INTEL_UNCORE_EVENT_DESC(data_reads.unit, "MiB"),
+
+       INTEL_UNCORE_EVENT_DESC(data_writes, "event=0x02"),
+       INTEL_UNCORE_EVENT_DESC(data_writes.scale, "6.103515625e-5"),
+       INTEL_UNCORE_EVENT_DESC(data_writes.unit, "MiB"),
+
+       { /* end: all zeroes */ },
+};
+
+#define SNB_UNCORE_PCI_IMC_EVENT_MASK          0xff
+#define SNB_UNCORE_PCI_IMC_BAR_OFFSET          0x48
+
+/* page size multiple covering all config regs */
+#define SNB_UNCORE_PCI_IMC_MAP_SIZE            0x6000
+
+#define SNB_UNCORE_PCI_IMC_DATA_READS          0x1
+#define SNB_UNCORE_PCI_IMC_DATA_READS_BASE     0x5050
+#define SNB_UNCORE_PCI_IMC_DATA_WRITES         0x2
+#define SNB_UNCORE_PCI_IMC_DATA_WRITES_BASE    0x5054
+#define SNB_UNCORE_PCI_IMC_CTR_BASE            SNB_UNCORE_PCI_IMC_DATA_READS_BASE
+
+static struct attribute *snb_uncore_imc_formats_attr[] = {
+       &format_attr_event.attr,
+       NULL,
+};
+
+static struct attribute_group snb_uncore_imc_format_group = {
+       .name = "format",
+       .attrs = snb_uncore_imc_formats_attr,
+};
+
+static void snb_uncore_imc_init_box(struct intel_uncore_box *box)
+{
+       struct pci_dev *pdev = box->pci_dev;
+       int where = SNB_UNCORE_PCI_IMC_BAR_OFFSET;
+       resource_size_t addr;
+       u32 pci_dword;
+
+       pci_read_config_dword(pdev, where, &pci_dword);
+       addr = pci_dword;
+
+#ifdef CONFIG_PHYS_ADDR_T_64BIT
+       pci_read_config_dword(pdev, where + 4, &pci_dword);
+       addr |= ((resource_size_t)pci_dword << 32);
+#endif
+
+       addr &= ~(PAGE_SIZE - 1);
+
+       box->io_addr = ioremap(addr, SNB_UNCORE_PCI_IMC_MAP_SIZE);
+       box->hrtimer_duration = UNCORE_SNB_IMC_HRTIMER_INTERVAL;
+}
+
+static void snb_uncore_imc_enable_box(struct intel_uncore_box *box)
+{}
+
+static void snb_uncore_imc_disable_box(struct intel_uncore_box *box)
+{}
+
+static void snb_uncore_imc_enable_event(struct intel_uncore_box *box, struct perf_event *event)
+{}
+
+static void snb_uncore_imc_disable_event(struct intel_uncore_box *box, struct perf_event *event)
+{}
+
+static u64 snb_uncore_imc_read_counter(struct intel_uncore_box *box, struct perf_event *event)
+{
+       struct hw_perf_event *hwc = &event->hw;
+
+       return (u64)*(unsigned int *)(box->io_addr + hwc->event_base);
+}
+
+/*
+ * custom event_init() function because we define our own fixed, free
+ * running counters, so we do not want to conflict with generic uncore
+ * logic. Also simplifies processing
+ */
+static int snb_uncore_imc_event_init(struct perf_event *event)
+{
+       struct intel_uncore_pmu *pmu;
+       struct intel_uncore_box *box;
+       struct hw_perf_event *hwc = &event->hw;
+       u64 cfg = event->attr.config & SNB_UNCORE_PCI_IMC_EVENT_MASK;
+       int idx, base;
+
+       if (event->attr.type != event->pmu->type)
+               return -ENOENT;
+
+       pmu = uncore_event_to_pmu(event);
+       /* no device found for this pmu */
+       if (pmu->func_id < 0)
+               return -ENOENT;
+
+       /* Sampling not supported yet */
+       if (hwc->sample_period)
+               return -EINVAL;
+
+       /* unsupported modes and filters */
+       if (event->attr.exclude_user   ||
+           event->attr.exclude_kernel ||
+           event->attr.exclude_hv     ||
+           event->attr.exclude_idle   ||
+           event->attr.exclude_host   ||
+           event->attr.exclude_guest  ||
+           event->attr.sample_period) /* no sampling */
+               return -EINVAL;
+
+       /*
+        * Place all uncore events for a particular physical package
+        * onto a single cpu
+        */
+       if (event->cpu < 0)
+               return -EINVAL;
+
+       /* check only supported bits are set */
+       if (event->attr.config & ~SNB_UNCORE_PCI_IMC_EVENT_MASK)
+               return -EINVAL;
+
+       box = uncore_pmu_to_box(pmu, event->cpu);
+       if (!box || box->cpu < 0)
+               return -EINVAL;
+
+       event->cpu = box->cpu;
+
+       event->hw.idx = -1;
+       event->hw.last_tag = ~0ULL;
+       event->hw.extra_reg.idx = EXTRA_REG_NONE;
+       event->hw.branch_reg.idx = EXTRA_REG_NONE;
+       /*
+        * check event is known (whitelist, determines counter)
+        */
+       switch (cfg) {
+       case SNB_UNCORE_PCI_IMC_DATA_READS:
+               base = SNB_UNCORE_PCI_IMC_DATA_READS_BASE;
+               idx = UNCORE_PMC_IDX_FIXED;
+               break;
+       case SNB_UNCORE_PCI_IMC_DATA_WRITES:
+               base = SNB_UNCORE_PCI_IMC_DATA_WRITES_BASE;
+               idx = UNCORE_PMC_IDX_FIXED + 1;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /* must be done before validate_group */
+       event->hw.event_base = base;
+       event->hw.config = cfg;
+       event->hw.idx = idx;
+
+       /* no group validation needed, we have free running counters */
+
+       return 0;
+}
+
+static int snb_uncore_imc_hw_config(struct intel_uncore_box *box, struct perf_event *event)
+{
+       return 0;
+}
+
+static void snb_uncore_imc_event_start(struct perf_event *event, int flags)
+{
+       struct intel_uncore_box *box = uncore_event_to_box(event);
+       u64 count;
+
+       if (WARN_ON_ONCE(!(event->hw.state & PERF_HES_STOPPED)))
+               return;
+
+       event->hw.state = 0;
+       box->n_active++;
+
+       list_add_tail(&event->active_entry, &box->active_list);
+
+       count = snb_uncore_imc_read_counter(box, event);
+       local64_set(&event->hw.prev_count, count);
+
+       if (box->n_active == 1)
+               uncore_pmu_start_hrtimer(box);
+}
+
+static void snb_uncore_imc_event_stop(struct perf_event *event, int flags)
+{
+       struct intel_uncore_box *box = uncore_event_to_box(event);
+       struct hw_perf_event *hwc = &event->hw;
+
+       if (!(hwc->state & PERF_HES_STOPPED)) {
+               box->n_active--;
+
+               WARN_ON_ONCE(hwc->state & PERF_HES_STOPPED);
+               hwc->state |= PERF_HES_STOPPED;
+
+               list_del(&event->active_entry);
+
+               if (box->n_active == 0)
+                       uncore_pmu_cancel_hrtimer(box);
+       }
+
+       if ((flags & PERF_EF_UPDATE) && !(hwc->state & PERF_HES_UPTODATE)) {
+               /*
+                * Drain the remaining delta count out of a event
+                * that we are disabling:
+                */
+               uncore_perf_event_update(box, event);
+               hwc->state |= PERF_HES_UPTODATE;
+       }
+}
+
+static int snb_uncore_imc_event_add(struct perf_event *event, int flags)
+{
+       struct intel_uncore_box *box = uncore_event_to_box(event);
+       struct hw_perf_event *hwc = &event->hw;
+
+       if (!box)
+               return -ENODEV;
+
+       hwc->state = PERF_HES_UPTODATE | PERF_HES_STOPPED;
+       if (!(flags & PERF_EF_START))
+               hwc->state |= PERF_HES_ARCH;
+
+       snb_uncore_imc_event_start(event, 0);
+
+       box->n_events++;
+
+       return 0;
+}
+
+static void snb_uncore_imc_event_del(struct perf_event *event, int flags)
+{
+       struct intel_uncore_box *box = uncore_event_to_box(event);
+       int i;
+
+       snb_uncore_imc_event_stop(event, PERF_EF_UPDATE);
+
+       for (i = 0; i < box->n_events; i++) {
+               if (event == box->event_list[i]) {
+                       --box->n_events;
+                       break;
+               }
+       }
+}
+
+static int snb_pci2phy_map_init(int devid)
+{
+       struct pci_dev *dev = NULL;
+       int bus;
+
+       dev = pci_get_device(PCI_VENDOR_ID_INTEL, devid, dev);
+       if (!dev)
+               return -ENOTTY;
+
+       bus = dev->bus->number;
+
+       uncore_pcibus_to_physid[bus] = 0;
+
+       pci_dev_put(dev);
+
+       return 0;
+}
+
+static struct pmu snb_uncore_imc_pmu = {
+       .task_ctx_nr    = perf_invalid_context,
+       .event_init     = snb_uncore_imc_event_init,
+       .add            = snb_uncore_imc_event_add,
+       .del            = snb_uncore_imc_event_del,
+       .start          = snb_uncore_imc_event_start,
+       .stop           = snb_uncore_imc_event_stop,
+       .read           = uncore_pmu_event_read,
+};
+
+static struct intel_uncore_ops snb_uncore_imc_ops = {
+       .init_box       = snb_uncore_imc_init_box,
+       .enable_box     = snb_uncore_imc_enable_box,
+       .disable_box    = snb_uncore_imc_disable_box,
+       .disable_event  = snb_uncore_imc_disable_event,
+       .enable_event   = snb_uncore_imc_enable_event,
+       .hw_config      = snb_uncore_imc_hw_config,
+       .read_counter   = snb_uncore_imc_read_counter,
+};
+
+static struct intel_uncore_type snb_uncore_imc = {
+       .name           = "imc",
+       .num_counters   = 2,
+       .num_boxes      = 1,
+       .fixed_ctr_bits = 32,
+       .fixed_ctr      = SNB_UNCORE_PCI_IMC_CTR_BASE,
+       .event_descs    = snb_uncore_imc_events,
+       .format_group   = &snb_uncore_imc_format_group,
+       .perf_ctr       = SNB_UNCORE_PCI_IMC_DATA_READS_BASE,
+       .event_mask     = SNB_UNCORE_PCI_IMC_EVENT_MASK,
+       .ops            = &snb_uncore_imc_ops,
+       .pmu            = &snb_uncore_imc_pmu,
+};
+
+static struct intel_uncore_type *snb_pci_uncores[] = {
+       [SNB_PCI_UNCORE_IMC]    = &snb_uncore_imc,
+       NULL,
+};
+
+static const struct pci_device_id snb_uncore_pci_ids[] = {
+       { /* IMC */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SNB_IMC),
+               .driver_data = UNCORE_PCI_DEV_DATA(SNB_PCI_UNCORE_IMC, 0),
+       },
+       { /* end: all zeroes */ },
+};
+
+static const struct pci_device_id ivb_uncore_pci_ids[] = {
+       { /* IMC */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IVB_IMC),
+               .driver_data = UNCORE_PCI_DEV_DATA(SNB_PCI_UNCORE_IMC, 0),
+       },
+       { /* IMC */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IVB_E3_IMC),
+               .driver_data = UNCORE_PCI_DEV_DATA(SNB_PCI_UNCORE_IMC, 0),
+       },
+       { /* end: all zeroes */ },
+};
+
+static const struct pci_device_id hsw_uncore_pci_ids[] = {
+       { /* IMC */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_HSW_IMC),
+               .driver_data = UNCORE_PCI_DEV_DATA(SNB_PCI_UNCORE_IMC, 0),
+       },
+       { /* end: all zeroes */ },
+};
+
+static struct pci_driver snb_uncore_pci_driver = {
+       .name           = "snb_uncore",
+       .id_table       = snb_uncore_pci_ids,
+};
+
+static struct pci_driver ivb_uncore_pci_driver = {
+       .name           = "ivb_uncore",
+       .id_table       = ivb_uncore_pci_ids,
+};
+
+static struct pci_driver hsw_uncore_pci_driver = {
+       .name           = "hsw_uncore",
+       .id_table       = hsw_uncore_pci_ids,
+};
+
+struct imc_uncore_pci_dev {
+       __u32 pci_id;
+       struct pci_driver *driver;
+};
+#define IMC_DEV(a, d) \
+       { .pci_id = PCI_DEVICE_ID_INTEL_##a, .driver = (d) }
+
+static const struct imc_uncore_pci_dev desktop_imc_pci_ids[] = {
+       IMC_DEV(SNB_IMC, &snb_uncore_pci_driver),
+       IMC_DEV(IVB_IMC, &ivb_uncore_pci_driver),    /* 3rd Gen Core processor */
+       IMC_DEV(IVB_E3_IMC, &ivb_uncore_pci_driver), /* Xeon E3-1200 v2/3rd Gen Core processor */
+       IMC_DEV(HSW_IMC, &hsw_uncore_pci_driver),    /* 4th Gen Core Processor */
+       {  /* end marker */ }
+};
+
+
+#define for_each_imc_pci_id(x, t) \
+       for (x = (t); (x)->pci_id; x++)
+
+static struct pci_driver *imc_uncore_find_dev(void)
+{
+       const struct imc_uncore_pci_dev *p;
+       int ret;
+
+       for_each_imc_pci_id(p, desktop_imc_pci_ids) {
+               ret = snb_pci2phy_map_init(p->pci_id);
+               if (ret == 0)
+                       return p->driver;
+       }
+       return NULL;
+}
+
+static int imc_uncore_pci_init(void)
+{
+       struct pci_driver *imc_drv = imc_uncore_find_dev();
+
+       if (!imc_drv)
+               return -ENODEV;
+
+       uncore_pci_uncores = snb_pci_uncores;
+       uncore_pci_driver = imc_drv;
+
+       return 0;
+}
+
+int snb_uncore_pci_init(void)
+{
+       return imc_uncore_pci_init();
+}
+
+int ivb_uncore_pci_init(void)
+{
+       return imc_uncore_pci_init();
+}
+int hsw_uncore_pci_init(void)
+{
+       return imc_uncore_pci_init();
+}
+
+/* end of Sandy Bridge uncore support */
+
+/* Nehalem uncore support */
+static void nhm_uncore_msr_disable_box(struct intel_uncore_box *box)
+{
+       wrmsrl(NHM_UNC_PERF_GLOBAL_CTL, 0);
+}
+
+static void nhm_uncore_msr_enable_box(struct intel_uncore_box *box)
+{
+       wrmsrl(NHM_UNC_PERF_GLOBAL_CTL, NHM_UNC_GLOBAL_CTL_EN_PC_ALL | NHM_UNC_GLOBAL_CTL_EN_FC);
+}
+
+static void nhm_uncore_msr_enable_event(struct intel_uncore_box *box, struct perf_event *event)
+{
+       struct hw_perf_event *hwc = &event->hw;
+
+       if (hwc->idx < UNCORE_PMC_IDX_FIXED)
+               wrmsrl(hwc->config_base, hwc->config | SNB_UNC_CTL_EN);
+       else
+               wrmsrl(hwc->config_base, NHM_UNC_FIXED_CTR_CTL_EN);
+}
+
+static struct attribute *nhm_uncore_formats_attr[] = {
+       &format_attr_event.attr,
+       &format_attr_umask.attr,
+       &format_attr_edge.attr,
+       &format_attr_inv.attr,
+       &format_attr_cmask8.attr,
+       NULL,
+};
+
+static struct attribute_group nhm_uncore_format_group = {
+       .name = "format",
+       .attrs = nhm_uncore_formats_attr,
+};
+
+static struct uncore_event_desc nhm_uncore_events[] = {
+       INTEL_UNCORE_EVENT_DESC(clockticks,                "event=0xff,umask=0x00"),
+       INTEL_UNCORE_EVENT_DESC(qmc_writes_full_any,       "event=0x2f,umask=0x0f"),
+       INTEL_UNCORE_EVENT_DESC(qmc_normal_reads_any,      "event=0x2c,umask=0x0f"),
+       INTEL_UNCORE_EVENT_DESC(qhl_request_ioh_reads,     "event=0x20,umask=0x01"),
+       INTEL_UNCORE_EVENT_DESC(qhl_request_ioh_writes,    "event=0x20,umask=0x02"),
+       INTEL_UNCORE_EVENT_DESC(qhl_request_remote_reads,  "event=0x20,umask=0x04"),
+       INTEL_UNCORE_EVENT_DESC(qhl_request_remote_writes, "event=0x20,umask=0x08"),
+       INTEL_UNCORE_EVENT_DESC(qhl_request_local_reads,   "event=0x20,umask=0x10"),
+       INTEL_UNCORE_EVENT_DESC(qhl_request_local_writes,  "event=0x20,umask=0x20"),
+       { /* end: all zeroes */ },
+};
+
+static struct intel_uncore_ops nhm_uncore_msr_ops = {
+       .disable_box    = nhm_uncore_msr_disable_box,
+       .enable_box     = nhm_uncore_msr_enable_box,
+       .disable_event  = snb_uncore_msr_disable_event,
+       .enable_event   = nhm_uncore_msr_enable_event,
+       .read_counter   = uncore_msr_read_counter,
+};
+
+static struct intel_uncore_type nhm_uncore = {
+       .name           = "",
+       .num_counters   = 8,
+       .num_boxes      = 1,
+       .perf_ctr_bits  = 48,
+       .fixed_ctr_bits = 48,
+       .event_ctl      = NHM_UNC_PERFEVTSEL0,
+       .perf_ctr       = NHM_UNC_UNCORE_PMC0,
+       .fixed_ctr      = NHM_UNC_FIXED_CTR,
+       .fixed_ctl      = NHM_UNC_FIXED_CTR_CTRL,
+       .event_mask     = NHM_UNC_RAW_EVENT_MASK,
+       .event_descs    = nhm_uncore_events,
+       .ops            = &nhm_uncore_msr_ops,
+       .format_group   = &nhm_uncore_format_group,
+};
+
+static struct intel_uncore_type *nhm_msr_uncores[] = {
+       &nhm_uncore,
+       NULL,
+};
+
+void nhm_uncore_cpu_init(void)
+{
+       uncore_msr_uncores = nhm_msr_uncores;
+}
+
+/* end of Nehalem uncore support */
diff --git a/arch/x86/kernel/cpu/perf_event_intel_uncore_snbep.c b/arch/x86/kernel/cpu/perf_event_intel_uncore_snbep.c
new file mode 100644 (file)
index 0000000..adf138e
--- /dev/null
@@ -0,0 +1,2258 @@
+/* SandyBridge-EP/IvyTown uncore support */
+#include "perf_event_intel_uncore.h"
+
+
+/* SNB-EP Box level control */
+#define SNBEP_PMON_BOX_CTL_RST_CTRL    (1 << 0)
+#define SNBEP_PMON_BOX_CTL_RST_CTRS    (1 << 1)
+#define SNBEP_PMON_BOX_CTL_FRZ         (1 << 8)
+#define SNBEP_PMON_BOX_CTL_FRZ_EN      (1 << 16)
+#define SNBEP_PMON_BOX_CTL_INT         (SNBEP_PMON_BOX_CTL_RST_CTRL | \
+                                        SNBEP_PMON_BOX_CTL_RST_CTRS | \
+                                        SNBEP_PMON_BOX_CTL_FRZ_EN)
+/* SNB-EP event control */
+#define SNBEP_PMON_CTL_EV_SEL_MASK     0x000000ff
+#define SNBEP_PMON_CTL_UMASK_MASK      0x0000ff00
+#define SNBEP_PMON_CTL_RST             (1 << 17)
+#define SNBEP_PMON_CTL_EDGE_DET                (1 << 18)
+#define SNBEP_PMON_CTL_EV_SEL_EXT      (1 << 21)
+#define SNBEP_PMON_CTL_EN              (1 << 22)
+#define SNBEP_PMON_CTL_INVERT          (1 << 23)
+#define SNBEP_PMON_CTL_TRESH_MASK      0xff000000
+#define SNBEP_PMON_RAW_EVENT_MASK      (SNBEP_PMON_CTL_EV_SEL_MASK | \
+                                        SNBEP_PMON_CTL_UMASK_MASK | \
+                                        SNBEP_PMON_CTL_EDGE_DET | \
+                                        SNBEP_PMON_CTL_INVERT | \
+                                        SNBEP_PMON_CTL_TRESH_MASK)
+
+/* SNB-EP Ubox event control */
+#define SNBEP_U_MSR_PMON_CTL_TRESH_MASK                0x1f000000
+#define SNBEP_U_MSR_PMON_RAW_EVENT_MASK                \
+                               (SNBEP_PMON_CTL_EV_SEL_MASK | \
+                                SNBEP_PMON_CTL_UMASK_MASK | \
+                                SNBEP_PMON_CTL_EDGE_DET | \
+                                SNBEP_PMON_CTL_INVERT | \
+                                SNBEP_U_MSR_PMON_CTL_TRESH_MASK)
+
+#define SNBEP_CBO_PMON_CTL_TID_EN              (1 << 19)
+#define SNBEP_CBO_MSR_PMON_RAW_EVENT_MASK      (SNBEP_PMON_RAW_EVENT_MASK | \
+                                                SNBEP_CBO_PMON_CTL_TID_EN)
+
+/* SNB-EP PCU event control */
+#define SNBEP_PCU_MSR_PMON_CTL_OCC_SEL_MASK    0x0000c000
+#define SNBEP_PCU_MSR_PMON_CTL_TRESH_MASK      0x1f000000
+#define SNBEP_PCU_MSR_PMON_CTL_OCC_INVERT      (1 << 30)
+#define SNBEP_PCU_MSR_PMON_CTL_OCC_EDGE_DET    (1 << 31)
+#define SNBEP_PCU_MSR_PMON_RAW_EVENT_MASK      \
+                               (SNBEP_PMON_CTL_EV_SEL_MASK | \
+                                SNBEP_PCU_MSR_PMON_CTL_OCC_SEL_MASK | \
+                                SNBEP_PMON_CTL_EDGE_DET | \
+                                SNBEP_PMON_CTL_EV_SEL_EXT | \
+                                SNBEP_PMON_CTL_INVERT | \
+                                SNBEP_PCU_MSR_PMON_CTL_TRESH_MASK | \
+                                SNBEP_PCU_MSR_PMON_CTL_OCC_INVERT | \
+                                SNBEP_PCU_MSR_PMON_CTL_OCC_EDGE_DET)
+
+#define SNBEP_QPI_PCI_PMON_RAW_EVENT_MASK      \
+                               (SNBEP_PMON_RAW_EVENT_MASK | \
+                                SNBEP_PMON_CTL_EV_SEL_EXT)
+
+/* SNB-EP pci control register */
+#define SNBEP_PCI_PMON_BOX_CTL                 0xf4
+#define SNBEP_PCI_PMON_CTL0                    0xd8
+/* SNB-EP pci counter register */
+#define SNBEP_PCI_PMON_CTR0                    0xa0
+
+/* SNB-EP home agent register */
+#define SNBEP_HA_PCI_PMON_BOX_ADDRMATCH0       0x40
+#define SNBEP_HA_PCI_PMON_BOX_ADDRMATCH1       0x44
+#define SNBEP_HA_PCI_PMON_BOX_OPCODEMATCH      0x48
+/* SNB-EP memory controller register */
+#define SNBEP_MC_CHy_PCI_PMON_FIXED_CTL                0xf0
+#define SNBEP_MC_CHy_PCI_PMON_FIXED_CTR                0xd0
+/* SNB-EP QPI register */
+#define SNBEP_Q_Py_PCI_PMON_PKT_MATCH0         0x228
+#define SNBEP_Q_Py_PCI_PMON_PKT_MATCH1         0x22c
+#define SNBEP_Q_Py_PCI_PMON_PKT_MASK0          0x238
+#define SNBEP_Q_Py_PCI_PMON_PKT_MASK1          0x23c
+
+/* SNB-EP Ubox register */
+#define SNBEP_U_MSR_PMON_CTR0                  0xc16
+#define SNBEP_U_MSR_PMON_CTL0                  0xc10
+
+#define SNBEP_U_MSR_PMON_UCLK_FIXED_CTL                0xc08
+#define SNBEP_U_MSR_PMON_UCLK_FIXED_CTR                0xc09
+
+/* SNB-EP Cbo register */
+#define SNBEP_C0_MSR_PMON_CTR0                 0xd16
+#define SNBEP_C0_MSR_PMON_CTL0                 0xd10
+#define SNBEP_C0_MSR_PMON_BOX_CTL              0xd04
+#define SNBEP_C0_MSR_PMON_BOX_FILTER           0xd14
+#define SNBEP_CBO_MSR_OFFSET                   0x20
+
+#define SNBEP_CB0_MSR_PMON_BOX_FILTER_TID      0x1f
+#define SNBEP_CB0_MSR_PMON_BOX_FILTER_NID      0x3fc00
+#define SNBEP_CB0_MSR_PMON_BOX_FILTER_STATE    0x7c0000
+#define SNBEP_CB0_MSR_PMON_BOX_FILTER_OPC      0xff800000
+
+#define SNBEP_CBO_EVENT_EXTRA_REG(e, m, i) {   \
+       .event = (e),                           \
+       .msr = SNBEP_C0_MSR_PMON_BOX_FILTER,    \
+       .config_mask = (m),                     \
+       .idx = (i)                              \
+}
+
+/* SNB-EP PCU register */
+#define SNBEP_PCU_MSR_PMON_CTR0                        0xc36
+#define SNBEP_PCU_MSR_PMON_CTL0                        0xc30
+#define SNBEP_PCU_MSR_PMON_BOX_CTL             0xc24
+#define SNBEP_PCU_MSR_PMON_BOX_FILTER          0xc34
+#define SNBEP_PCU_MSR_PMON_BOX_FILTER_MASK     0xffffffff
+#define SNBEP_PCU_MSR_CORE_C3_CTR              0x3fc
+#define SNBEP_PCU_MSR_CORE_C6_CTR              0x3fd
+
+/* IVBEP event control */
+#define IVBEP_PMON_BOX_CTL_INT         (SNBEP_PMON_BOX_CTL_RST_CTRL | \
+                                        SNBEP_PMON_BOX_CTL_RST_CTRS)
+#define IVBEP_PMON_RAW_EVENT_MASK              (SNBEP_PMON_CTL_EV_SEL_MASK | \
+                                        SNBEP_PMON_CTL_UMASK_MASK | \
+                                        SNBEP_PMON_CTL_EDGE_DET | \
+                                        SNBEP_PMON_CTL_TRESH_MASK)
+/* IVBEP Ubox */
+#define IVBEP_U_MSR_PMON_GLOBAL_CTL            0xc00
+#define IVBEP_U_PMON_GLOBAL_FRZ_ALL            (1 << 31)
+#define IVBEP_U_PMON_GLOBAL_UNFRZ_ALL          (1 << 29)
+
+#define IVBEP_U_MSR_PMON_RAW_EVENT_MASK        \
+                               (SNBEP_PMON_CTL_EV_SEL_MASK | \
+                                SNBEP_PMON_CTL_UMASK_MASK | \
+                                SNBEP_PMON_CTL_EDGE_DET | \
+                                SNBEP_U_MSR_PMON_CTL_TRESH_MASK)
+/* IVBEP Cbo */
+#define IVBEP_CBO_MSR_PMON_RAW_EVENT_MASK              (IVBEP_PMON_RAW_EVENT_MASK | \
+                                                SNBEP_CBO_PMON_CTL_TID_EN)
+
+#define IVBEP_CB0_MSR_PMON_BOX_FILTER_TID              (0x1fULL << 0)
+#define IVBEP_CB0_MSR_PMON_BOX_FILTER_LINK     (0xfULL << 5)
+#define IVBEP_CB0_MSR_PMON_BOX_FILTER_STATE    (0x3fULL << 17)
+#define IVBEP_CB0_MSR_PMON_BOX_FILTER_NID              (0xffffULL << 32)
+#define IVBEP_CB0_MSR_PMON_BOX_FILTER_OPC              (0x1ffULL << 52)
+#define IVBEP_CB0_MSR_PMON_BOX_FILTER_C6               (0x1ULL << 61)
+#define IVBEP_CB0_MSR_PMON_BOX_FILTER_NC               (0x1ULL << 62)
+#define IVBEP_CB0_MSR_PMON_BOX_FILTER_ISOC     (0x1ULL << 63)
+
+/* IVBEP home agent */
+#define IVBEP_HA_PCI_PMON_CTL_Q_OCC_RST                (1 << 16)
+#define IVBEP_HA_PCI_PMON_RAW_EVENT_MASK               \
+                               (IVBEP_PMON_RAW_EVENT_MASK | \
+                                IVBEP_HA_PCI_PMON_CTL_Q_OCC_RST)
+/* IVBEP PCU */
+#define IVBEP_PCU_MSR_PMON_RAW_EVENT_MASK      \
+                               (SNBEP_PMON_CTL_EV_SEL_MASK | \
+                                SNBEP_PMON_CTL_EV_SEL_EXT | \
+                                SNBEP_PCU_MSR_PMON_CTL_OCC_SEL_MASK | \
+                                SNBEP_PMON_CTL_EDGE_DET | \
+                                SNBEP_PCU_MSR_PMON_CTL_TRESH_MASK | \
+                                SNBEP_PCU_MSR_PMON_CTL_OCC_INVERT | \
+                                SNBEP_PCU_MSR_PMON_CTL_OCC_EDGE_DET)
+/* IVBEP QPI */
+#define IVBEP_QPI_PCI_PMON_RAW_EVENT_MASK      \
+                               (IVBEP_PMON_RAW_EVENT_MASK | \
+                                SNBEP_PMON_CTL_EV_SEL_EXT)
+
+#define __BITS_VALUE(x, i, n)  ((typeof(x))(((x) >> ((i) * (n))) & \
+                               ((1ULL << (n)) - 1)))
+
+/* Haswell-EP Ubox */
+#define HSWEP_U_MSR_PMON_CTR0                  0x705
+#define HSWEP_U_MSR_PMON_CTL0                  0x709
+#define HSWEP_U_MSR_PMON_FILTER                        0x707
+
+#define HSWEP_U_MSR_PMON_UCLK_FIXED_CTL                0x703
+#define HSWEP_U_MSR_PMON_UCLK_FIXED_CTR                0x704
+
+#define HSWEP_U_MSR_PMON_BOX_FILTER_TID                (0x1 << 0)
+#define HSWEP_U_MSR_PMON_BOX_FILTER_CID                (0x1fULL << 1)
+#define HSWEP_U_MSR_PMON_BOX_FILTER_MASK \
+                                       (HSWEP_U_MSR_PMON_BOX_FILTER_TID | \
+                                        HSWEP_U_MSR_PMON_BOX_FILTER_CID)
+
+/* Haswell-EP CBo */
+#define HSWEP_C0_MSR_PMON_CTR0                 0xe08
+#define HSWEP_C0_MSR_PMON_CTL0                 0xe01
+#define HSWEP_C0_MSR_PMON_BOX_CTL                      0xe00
+#define HSWEP_C0_MSR_PMON_BOX_FILTER0          0xe05
+#define HSWEP_CBO_MSR_OFFSET                   0x10
+
+
+#define HSWEP_CB0_MSR_PMON_BOX_FILTER_TID              (0x3fULL << 0)
+#define HSWEP_CB0_MSR_PMON_BOX_FILTER_LINK     (0xfULL << 6)
+#define HSWEP_CB0_MSR_PMON_BOX_FILTER_STATE    (0x7fULL << 17)
+#define HSWEP_CB0_MSR_PMON_BOX_FILTER_NID              (0xffffULL << 32)
+#define HSWEP_CB0_MSR_PMON_BOX_FILTER_OPC              (0x1ffULL << 52)
+#define HSWEP_CB0_MSR_PMON_BOX_FILTER_C6               (0x1ULL << 61)
+#define HSWEP_CB0_MSR_PMON_BOX_FILTER_NC               (0x1ULL << 62)
+#define HSWEP_CB0_MSR_PMON_BOX_FILTER_ISOC     (0x1ULL << 63)
+
+
+/* Haswell-EP Sbox */
+#define HSWEP_S0_MSR_PMON_CTR0                 0x726
+#define HSWEP_S0_MSR_PMON_CTL0                 0x721
+#define HSWEP_S0_MSR_PMON_BOX_CTL                      0x720
+#define HSWEP_SBOX_MSR_OFFSET                  0xa
+#define HSWEP_S_MSR_PMON_RAW_EVENT_MASK                (SNBEP_PMON_RAW_EVENT_MASK | \
+                                                SNBEP_CBO_PMON_CTL_TID_EN)
+
+/* Haswell-EP PCU */
+#define HSWEP_PCU_MSR_PMON_CTR0                        0x717
+#define HSWEP_PCU_MSR_PMON_CTL0                        0x711
+#define HSWEP_PCU_MSR_PMON_BOX_CTL             0x710
+#define HSWEP_PCU_MSR_PMON_BOX_FILTER          0x715
+
+
+DEFINE_UNCORE_FORMAT_ATTR(event, event, "config:0-7");
+DEFINE_UNCORE_FORMAT_ATTR(event_ext, event, "config:0-7,21");
+DEFINE_UNCORE_FORMAT_ATTR(umask, umask, "config:8-15");
+DEFINE_UNCORE_FORMAT_ATTR(edge, edge, "config:18");
+DEFINE_UNCORE_FORMAT_ATTR(tid_en, tid_en, "config:19");
+DEFINE_UNCORE_FORMAT_ATTR(inv, inv, "config:23");
+DEFINE_UNCORE_FORMAT_ATTR(thresh8, thresh, "config:24-31");
+DEFINE_UNCORE_FORMAT_ATTR(thresh5, thresh, "config:24-28");
+DEFINE_UNCORE_FORMAT_ATTR(occ_sel, occ_sel, "config:14-15");
+DEFINE_UNCORE_FORMAT_ATTR(occ_invert, occ_invert, "config:30");
+DEFINE_UNCORE_FORMAT_ATTR(occ_edge, occ_edge, "config:14-51");
+DEFINE_UNCORE_FORMAT_ATTR(filter_tid, filter_tid, "config1:0-4");
+DEFINE_UNCORE_FORMAT_ATTR(filter_tid2, filter_tid, "config1:0");
+DEFINE_UNCORE_FORMAT_ATTR(filter_tid3, filter_tid, "config1:0-5");
+DEFINE_UNCORE_FORMAT_ATTR(filter_cid, filter_cid, "config1:5");
+DEFINE_UNCORE_FORMAT_ATTR(filter_link, filter_link, "config1:5-8");
+DEFINE_UNCORE_FORMAT_ATTR(filter_link2, filter_link, "config1:6-8");
+DEFINE_UNCORE_FORMAT_ATTR(filter_nid, filter_nid, "config1:10-17");
+DEFINE_UNCORE_FORMAT_ATTR(filter_nid2, filter_nid, "config1:32-47");
+DEFINE_UNCORE_FORMAT_ATTR(filter_state, filter_state, "config1:18-22");
+DEFINE_UNCORE_FORMAT_ATTR(filter_state2, filter_state, "config1:17-22");
+DEFINE_UNCORE_FORMAT_ATTR(filter_state3, filter_state, "config1:17-23");
+DEFINE_UNCORE_FORMAT_ATTR(filter_opc, filter_opc, "config1:23-31");
+DEFINE_UNCORE_FORMAT_ATTR(filter_opc2, filter_opc, "config1:52-60");
+DEFINE_UNCORE_FORMAT_ATTR(filter_nc, filter_nc, "config1:62");
+DEFINE_UNCORE_FORMAT_ATTR(filter_c6, filter_c6, "config1:61");
+DEFINE_UNCORE_FORMAT_ATTR(filter_isoc, filter_isoc, "config1:63");
+DEFINE_UNCORE_FORMAT_ATTR(filter_band0, filter_band0, "config1:0-7");
+DEFINE_UNCORE_FORMAT_ATTR(filter_band1, filter_band1, "config1:8-15");
+DEFINE_UNCORE_FORMAT_ATTR(filter_band2, filter_band2, "config1:16-23");
+DEFINE_UNCORE_FORMAT_ATTR(filter_band3, filter_band3, "config1:24-31");
+DEFINE_UNCORE_FORMAT_ATTR(match_rds, match_rds, "config1:48-51");
+DEFINE_UNCORE_FORMAT_ATTR(match_rnid30, match_rnid30, "config1:32-35");
+DEFINE_UNCORE_FORMAT_ATTR(match_rnid4, match_rnid4, "config1:31");
+DEFINE_UNCORE_FORMAT_ATTR(match_dnid, match_dnid, "config1:13-17");
+DEFINE_UNCORE_FORMAT_ATTR(match_mc, match_mc, "config1:9-12");
+DEFINE_UNCORE_FORMAT_ATTR(match_opc, match_opc, "config1:5-8");
+DEFINE_UNCORE_FORMAT_ATTR(match_vnw, match_vnw, "config1:3-4");
+DEFINE_UNCORE_FORMAT_ATTR(match0, match0, "config1:0-31");
+DEFINE_UNCORE_FORMAT_ATTR(match1, match1, "config1:32-63");
+DEFINE_UNCORE_FORMAT_ATTR(mask_rds, mask_rds, "config2:48-51");
+DEFINE_UNCORE_FORMAT_ATTR(mask_rnid30, mask_rnid30, "config2:32-35");
+DEFINE_UNCORE_FORMAT_ATTR(mask_rnid4, mask_rnid4, "config2:31");
+DEFINE_UNCORE_FORMAT_ATTR(mask_dnid, mask_dnid, "config2:13-17");
+DEFINE_UNCORE_FORMAT_ATTR(mask_mc, mask_mc, "config2:9-12");
+DEFINE_UNCORE_FORMAT_ATTR(mask_opc, mask_opc, "config2:5-8");
+DEFINE_UNCORE_FORMAT_ATTR(mask_vnw, mask_vnw, "config2:3-4");
+DEFINE_UNCORE_FORMAT_ATTR(mask0, mask0, "config2:0-31");
+DEFINE_UNCORE_FORMAT_ATTR(mask1, mask1, "config2:32-63");
+
+static void snbep_uncore_pci_disable_box(struct intel_uncore_box *box)
+{
+       struct pci_dev *pdev = box->pci_dev;
+       int box_ctl = uncore_pci_box_ctl(box);
+       u32 config = 0;
+
+       if (!pci_read_config_dword(pdev, box_ctl, &config)) {
+               config |= SNBEP_PMON_BOX_CTL_FRZ;
+               pci_write_config_dword(pdev, box_ctl, config);
+       }
+}
+
+static void snbep_uncore_pci_enable_box(struct intel_uncore_box *box)
+{
+       struct pci_dev *pdev = box->pci_dev;
+       int box_ctl = uncore_pci_box_ctl(box);
+       u32 config = 0;
+
+       if (!pci_read_config_dword(pdev, box_ctl, &config)) {
+               config &= ~SNBEP_PMON_BOX_CTL_FRZ;
+               pci_write_config_dword(pdev, box_ctl, config);
+       }
+}
+
+static void snbep_uncore_pci_enable_event(struct intel_uncore_box *box, struct perf_event *event)
+{
+       struct pci_dev *pdev = box->pci_dev;
+       struct hw_perf_event *hwc = &event->hw;
+
+       pci_write_config_dword(pdev, hwc->config_base, hwc->config | SNBEP_PMON_CTL_EN);
+}
+
+static void snbep_uncore_pci_disable_event(struct intel_uncore_box *box, struct perf_event *event)
+{
+       struct pci_dev *pdev = box->pci_dev;
+       struct hw_perf_event *hwc = &event->hw;
+
+       pci_write_config_dword(pdev, hwc->config_base, hwc->config);
+}
+
+static u64 snbep_uncore_pci_read_counter(struct intel_uncore_box *box, struct perf_event *event)
+{
+       struct pci_dev *pdev = box->pci_dev;
+       struct hw_perf_event *hwc = &event->hw;
+       u64 count = 0;
+
+       pci_read_config_dword(pdev, hwc->event_base, (u32 *)&count);
+       pci_read_config_dword(pdev, hwc->event_base + 4, (u32 *)&count + 1);
+
+       return count;
+}
+
+static void snbep_uncore_pci_init_box(struct intel_uncore_box *box)
+{
+       struct pci_dev *pdev = box->pci_dev;
+
+       pci_write_config_dword(pdev, SNBEP_PCI_PMON_BOX_CTL, SNBEP_PMON_BOX_CTL_INT);
+}
+
+static void snbep_uncore_msr_disable_box(struct intel_uncore_box *box)
+{
+       u64 config;
+       unsigned msr;
+
+       msr = uncore_msr_box_ctl(box);
+       if (msr) {
+               rdmsrl(msr, config);
+               config |= SNBEP_PMON_BOX_CTL_FRZ;
+               wrmsrl(msr, config);
+       }
+}
+
+static void snbep_uncore_msr_enable_box(struct intel_uncore_box *box)
+{
+       u64 config;
+       unsigned msr;
+
+       msr = uncore_msr_box_ctl(box);
+       if (msr) {
+               rdmsrl(msr, config);
+               config &= ~SNBEP_PMON_BOX_CTL_FRZ;
+               wrmsrl(msr, config);
+       }
+}
+
+static void snbep_uncore_msr_enable_event(struct intel_uncore_box *box, struct perf_event *event)
+{
+       struct hw_perf_event *hwc = &event->hw;
+       struct hw_perf_event_extra *reg1 = &hwc->extra_reg;
+
+       if (reg1->idx != EXTRA_REG_NONE)
+               wrmsrl(reg1->reg, uncore_shared_reg_config(box, 0));
+
+       wrmsrl(hwc->config_base, hwc->config | SNBEP_PMON_CTL_EN);
+}
+
+static void snbep_uncore_msr_disable_event(struct intel_uncore_box *box,
+                                       struct perf_event *event)
+{
+       struct hw_perf_event *hwc = &event->hw;
+
+       wrmsrl(hwc->config_base, hwc->config);
+}
+
+static void snbep_uncore_msr_init_box(struct intel_uncore_box *box)
+{
+       unsigned msr = uncore_msr_box_ctl(box);
+
+       if (msr)
+               wrmsrl(msr, SNBEP_PMON_BOX_CTL_INT);
+}
+
+static struct attribute *snbep_uncore_formats_attr[] = {
+       &format_attr_event.attr,
+       &format_attr_umask.attr,
+       &format_attr_edge.attr,
+       &format_attr_inv.attr,
+       &format_attr_thresh8.attr,
+       NULL,
+};
+
+static struct attribute *snbep_uncore_ubox_formats_attr[] = {
+       &format_attr_event.attr,
+       &format_attr_umask.attr,
+       &format_attr_edge.attr,
+       &format_attr_inv.attr,
+       &format_attr_thresh5.attr,
+       NULL,
+};
+
+static struct attribute *snbep_uncore_cbox_formats_attr[] = {
+       &format_attr_event.attr,
+       &format_attr_umask.attr,
+       &format_attr_edge.attr,
+       &format_attr_tid_en.attr,
+       &format_attr_inv.attr,
+       &format_attr_thresh8.attr,
+       &format_attr_filter_tid.attr,
+       &format_attr_filter_nid.attr,
+       &format_attr_filter_state.attr,
+       &format_attr_filter_opc.attr,
+       NULL,
+};
+
+static struct attribute *snbep_uncore_pcu_formats_attr[] = {
+       &format_attr_event_ext.attr,
+       &format_attr_occ_sel.attr,
+       &format_attr_edge.attr,
+       &format_attr_inv.attr,
+       &format_attr_thresh5.attr,
+       &format_attr_occ_invert.attr,
+       &format_attr_occ_edge.attr,
+       &format_attr_filter_band0.attr,
+       &format_attr_filter_band1.attr,
+       &format_attr_filter_band2.attr,
+       &format_attr_filter_band3.attr,
+       NULL,
+};
+
+static struct attribute *snbep_uncore_qpi_formats_attr[] = {
+       &format_attr_event_ext.attr,
+       &format_attr_umask.attr,
+       &format_attr_edge.attr,
+       &format_attr_inv.attr,
+       &format_attr_thresh8.attr,
+       &format_attr_match_rds.attr,
+       &format_attr_match_rnid30.attr,
+       &format_attr_match_rnid4.attr,
+       &format_attr_match_dnid.attr,
+       &format_attr_match_mc.attr,
+       &format_attr_match_opc.attr,
+       &format_attr_match_vnw.attr,
+       &format_attr_match0.attr,
+       &format_attr_match1.attr,
+       &format_attr_mask_rds.attr,
+       &format_attr_mask_rnid30.attr,
+       &format_attr_mask_rnid4.attr,
+       &format_attr_mask_dnid.attr,
+       &format_attr_mask_mc.attr,
+       &format_attr_mask_opc.attr,
+       &format_attr_mask_vnw.attr,
+       &format_attr_mask0.attr,
+       &format_attr_mask1.attr,
+       NULL,
+};
+
+static struct uncore_event_desc snbep_uncore_imc_events[] = {
+       INTEL_UNCORE_EVENT_DESC(clockticks,      "event=0xff,umask=0x00"),
+       INTEL_UNCORE_EVENT_DESC(cas_count_read,  "event=0x04,umask=0x03"),
+       INTEL_UNCORE_EVENT_DESC(cas_count_write, "event=0x04,umask=0x0c"),
+       { /* end: all zeroes */ },
+};
+
+static struct uncore_event_desc snbep_uncore_qpi_events[] = {
+       INTEL_UNCORE_EVENT_DESC(clockticks,       "event=0x14"),
+       INTEL_UNCORE_EVENT_DESC(txl_flits_active, "event=0x00,umask=0x06"),
+       INTEL_UNCORE_EVENT_DESC(drs_data,         "event=0x102,umask=0x08"),
+       INTEL_UNCORE_EVENT_DESC(ncb_data,         "event=0x103,umask=0x04"),
+       { /* end: all zeroes */ },
+};
+
+static struct attribute_group snbep_uncore_format_group = {
+       .name = "format",
+       .attrs = snbep_uncore_formats_attr,
+};
+
+static struct attribute_group snbep_uncore_ubox_format_group = {
+       .name = "format",
+       .attrs = snbep_uncore_ubox_formats_attr,
+};
+
+static struct attribute_group snbep_uncore_cbox_format_group = {
+       .name = "format",
+       .attrs = snbep_uncore_cbox_formats_attr,
+};
+
+static struct attribute_group snbep_uncore_pcu_format_group = {
+       .name = "format",
+       .attrs = snbep_uncore_pcu_formats_attr,
+};
+
+static struct attribute_group snbep_uncore_qpi_format_group = {
+       .name = "format",
+       .attrs = snbep_uncore_qpi_formats_attr,
+};
+
+#define SNBEP_UNCORE_MSR_OPS_COMMON_INIT()                     \
+       .init_box       = snbep_uncore_msr_init_box,            \
+       .disable_box    = snbep_uncore_msr_disable_box,         \
+       .enable_box     = snbep_uncore_msr_enable_box,          \
+       .disable_event  = snbep_uncore_msr_disable_event,       \
+       .enable_event   = snbep_uncore_msr_enable_event,        \
+       .read_counter   = uncore_msr_read_counter
+
+static struct intel_uncore_ops snbep_uncore_msr_ops = {
+       SNBEP_UNCORE_MSR_OPS_COMMON_INIT(),
+};
+
+#define SNBEP_UNCORE_PCI_OPS_COMMON_INIT()                     \
+       .init_box       = snbep_uncore_pci_init_box,            \
+       .disable_box    = snbep_uncore_pci_disable_box,         \
+       .enable_box     = snbep_uncore_pci_enable_box,          \
+       .disable_event  = snbep_uncore_pci_disable_event,       \
+       .read_counter   = snbep_uncore_pci_read_counter
+
+static struct intel_uncore_ops snbep_uncore_pci_ops = {
+       SNBEP_UNCORE_PCI_OPS_COMMON_INIT(),
+       .enable_event   = snbep_uncore_pci_enable_event,        \
+};
+
+static struct event_constraint snbep_uncore_cbox_constraints[] = {
+       UNCORE_EVENT_CONSTRAINT(0x01, 0x1),
+       UNCORE_EVENT_CONSTRAINT(0x02, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x04, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x05, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x07, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x09, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x11, 0x1),
+       UNCORE_EVENT_CONSTRAINT(0x12, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x13, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x1b, 0xc),
+       UNCORE_EVENT_CONSTRAINT(0x1c, 0xc),
+       UNCORE_EVENT_CONSTRAINT(0x1d, 0xc),
+       UNCORE_EVENT_CONSTRAINT(0x1e, 0xc),
+       EVENT_CONSTRAINT_OVERLAP(0x1f, 0xe, 0xff),
+       UNCORE_EVENT_CONSTRAINT(0x21, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x23, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x31, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x32, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x33, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x34, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x35, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x36, 0x1),
+       UNCORE_EVENT_CONSTRAINT(0x37, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x38, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x39, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x3b, 0x1),
+       EVENT_CONSTRAINT_END
+};
+
+static struct event_constraint snbep_uncore_r2pcie_constraints[] = {
+       UNCORE_EVENT_CONSTRAINT(0x10, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x11, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x12, 0x1),
+       UNCORE_EVENT_CONSTRAINT(0x23, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x24, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x25, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x26, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x32, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x33, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x34, 0x3),
+       EVENT_CONSTRAINT_END
+};
+
+static struct event_constraint snbep_uncore_r3qpi_constraints[] = {
+       UNCORE_EVENT_CONSTRAINT(0x10, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x11, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x12, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x13, 0x1),
+       UNCORE_EVENT_CONSTRAINT(0x20, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x21, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x22, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x23, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x24, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x25, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x26, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x28, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x29, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x2a, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x2b, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x2c, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x2d, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x2e, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x2f, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x30, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x31, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x32, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x33, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x34, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x36, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x37, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x38, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x39, 0x3),
+       EVENT_CONSTRAINT_END
+};
+
+static struct intel_uncore_type snbep_uncore_ubox = {
+       .name           = "ubox",
+       .num_counters   = 2,
+       .num_boxes      = 1,
+       .perf_ctr_bits  = 44,
+       .fixed_ctr_bits = 48,
+       .perf_ctr       = SNBEP_U_MSR_PMON_CTR0,
+       .event_ctl      = SNBEP_U_MSR_PMON_CTL0,
+       .event_mask     = SNBEP_U_MSR_PMON_RAW_EVENT_MASK,
+       .fixed_ctr      = SNBEP_U_MSR_PMON_UCLK_FIXED_CTR,
+       .fixed_ctl      = SNBEP_U_MSR_PMON_UCLK_FIXED_CTL,
+       .ops            = &snbep_uncore_msr_ops,
+       .format_group   = &snbep_uncore_ubox_format_group,
+};
+
+static struct extra_reg snbep_uncore_cbox_extra_regs[] = {
+       SNBEP_CBO_EVENT_EXTRA_REG(SNBEP_CBO_PMON_CTL_TID_EN,
+                                 SNBEP_CBO_PMON_CTL_TID_EN, 0x1),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x0334, 0xffff, 0x4),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x4334, 0xffff, 0x6),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x0534, 0xffff, 0x4),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x4534, 0xffff, 0x6),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x0934, 0xffff, 0x4),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x4934, 0xffff, 0x6),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x4134, 0xffff, 0x6),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x0135, 0xffff, 0x8),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x0335, 0xffff, 0x8),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x4135, 0xffff, 0xa),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x4335, 0xffff, 0xa),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x4435, 0xffff, 0x2),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x4835, 0xffff, 0x2),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x4a35, 0xffff, 0x2),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x5035, 0xffff, 0x2),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x0136, 0xffff, 0x8),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x0336, 0xffff, 0x8),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x4136, 0xffff, 0xa),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x4336, 0xffff, 0xa),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x4436, 0xffff, 0x2),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x4836, 0xffff, 0x2),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x4a36, 0xffff, 0x2),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x4037, 0x40ff, 0x2),
+       EVENT_EXTRA_END
+};
+
+static void snbep_cbox_put_constraint(struct intel_uncore_box *box, struct perf_event *event)
+{
+       struct hw_perf_event_extra *reg1 = &event->hw.extra_reg;
+       struct intel_uncore_extra_reg *er = &box->shared_regs[0];
+       int i;
+
+       if (uncore_box_is_fake(box))
+               return;
+
+       for (i = 0; i < 5; i++) {
+               if (reg1->alloc & (0x1 << i))
+                       atomic_sub(1 << (i * 6), &er->ref);
+       }
+       reg1->alloc = 0;
+}
+
+static struct event_constraint *
+__snbep_cbox_get_constraint(struct intel_uncore_box *box, struct perf_event *event,
+                           u64 (*cbox_filter_mask)(int fields))
+{
+       struct hw_perf_event_extra *reg1 = &event->hw.extra_reg;
+       struct intel_uncore_extra_reg *er = &box->shared_regs[0];
+       int i, alloc = 0;
+       unsigned long flags;
+       u64 mask;
+
+       if (reg1->idx == EXTRA_REG_NONE)
+               return NULL;
+
+       raw_spin_lock_irqsave(&er->lock, flags);
+       for (i = 0; i < 5; i++) {
+               if (!(reg1->idx & (0x1 << i)))
+                       continue;
+               if (!uncore_box_is_fake(box) && (reg1->alloc & (0x1 << i)))
+                       continue;
+
+               mask = cbox_filter_mask(0x1 << i);
+               if (!__BITS_VALUE(atomic_read(&er->ref), i, 6) ||
+                   !((reg1->config ^ er->config) & mask)) {
+                       atomic_add(1 << (i * 6), &er->ref);
+                       er->config &= ~mask;
+                       er->config |= reg1->config & mask;
+                       alloc |= (0x1 << i);
+               } else {
+                       break;
+               }
+       }
+       raw_spin_unlock_irqrestore(&er->lock, flags);
+       if (i < 5)
+               goto fail;
+
+       if (!uncore_box_is_fake(box))
+               reg1->alloc |= alloc;
+
+       return NULL;
+fail:
+       for (; i >= 0; i--) {
+               if (alloc & (0x1 << i))
+                       atomic_sub(1 << (i * 6), &er->ref);
+       }
+       return &uncore_constraint_empty;
+}
+
+static u64 snbep_cbox_filter_mask(int fields)
+{
+       u64 mask = 0;
+
+       if (fields & 0x1)
+               mask |= SNBEP_CB0_MSR_PMON_BOX_FILTER_TID;
+       if (fields & 0x2)
+               mask |= SNBEP_CB0_MSR_PMON_BOX_FILTER_NID;
+       if (fields & 0x4)
+               mask |= SNBEP_CB0_MSR_PMON_BOX_FILTER_STATE;
+       if (fields & 0x8)
+               mask |= SNBEP_CB0_MSR_PMON_BOX_FILTER_OPC;
+
+       return mask;
+}
+
+static struct event_constraint *
+snbep_cbox_get_constraint(struct intel_uncore_box *box, struct perf_event *event)
+{
+       return __snbep_cbox_get_constraint(box, event, snbep_cbox_filter_mask);
+}
+
+static int snbep_cbox_hw_config(struct intel_uncore_box *box, struct perf_event *event)
+{
+       struct hw_perf_event_extra *reg1 = &event->hw.extra_reg;
+       struct extra_reg *er;
+       int idx = 0;
+
+       for (er = snbep_uncore_cbox_extra_regs; er->msr; er++) {
+               if (er->event != (event->hw.config & er->config_mask))
+                       continue;
+               idx |= er->idx;
+       }
+
+       if (idx) {
+               reg1->reg = SNBEP_C0_MSR_PMON_BOX_FILTER +
+                       SNBEP_CBO_MSR_OFFSET * box->pmu->pmu_idx;
+               reg1->config = event->attr.config1 & snbep_cbox_filter_mask(idx);
+               reg1->idx = idx;
+       }
+       return 0;
+}
+
+static struct intel_uncore_ops snbep_uncore_cbox_ops = {
+       SNBEP_UNCORE_MSR_OPS_COMMON_INIT(),
+       .hw_config              = snbep_cbox_hw_config,
+       .get_constraint         = snbep_cbox_get_constraint,
+       .put_constraint         = snbep_cbox_put_constraint,
+};
+
+static struct intel_uncore_type snbep_uncore_cbox = {
+       .name                   = "cbox",
+       .num_counters           = 4,
+       .num_boxes              = 8,
+       .perf_ctr_bits          = 44,
+       .event_ctl              = SNBEP_C0_MSR_PMON_CTL0,
+       .perf_ctr               = SNBEP_C0_MSR_PMON_CTR0,
+       .event_mask             = SNBEP_CBO_MSR_PMON_RAW_EVENT_MASK,
+       .box_ctl                = SNBEP_C0_MSR_PMON_BOX_CTL,
+       .msr_offset             = SNBEP_CBO_MSR_OFFSET,
+       .num_shared_regs        = 1,
+       .constraints            = snbep_uncore_cbox_constraints,
+       .ops                    = &snbep_uncore_cbox_ops,
+       .format_group           = &snbep_uncore_cbox_format_group,
+};
+
+static u64 snbep_pcu_alter_er(struct perf_event *event, int new_idx, bool modify)
+{
+       struct hw_perf_event *hwc = &event->hw;
+       struct hw_perf_event_extra *reg1 = &hwc->extra_reg;
+       u64 config = reg1->config;
+
+       if (new_idx > reg1->idx)
+               config <<= 8 * (new_idx - reg1->idx);
+       else
+               config >>= 8 * (reg1->idx - new_idx);
+
+       if (modify) {
+               hwc->config += new_idx - reg1->idx;
+               reg1->config = config;
+               reg1->idx = new_idx;
+       }
+       return config;
+}
+
+static struct event_constraint *
+snbep_pcu_get_constraint(struct intel_uncore_box *box, struct perf_event *event)
+{
+       struct hw_perf_event_extra *reg1 = &event->hw.extra_reg;
+       struct intel_uncore_extra_reg *er = &box->shared_regs[0];
+       unsigned long flags;
+       int idx = reg1->idx;
+       u64 mask, config1 = reg1->config;
+       bool ok = false;
+
+       if (reg1->idx == EXTRA_REG_NONE ||
+           (!uncore_box_is_fake(box) && reg1->alloc))
+               return NULL;
+again:
+       mask = 0xffULL << (idx * 8);
+       raw_spin_lock_irqsave(&er->lock, flags);
+       if (!__BITS_VALUE(atomic_read(&er->ref), idx, 8) ||
+           !((config1 ^ er->config) & mask)) {
+               atomic_add(1 << (idx * 8), &er->ref);
+               er->config &= ~mask;
+               er->config |= config1 & mask;
+               ok = true;
+       }
+       raw_spin_unlock_irqrestore(&er->lock, flags);
+
+       if (!ok) {
+               idx = (idx + 1) % 4;
+               if (idx != reg1->idx) {
+                       config1 = snbep_pcu_alter_er(event, idx, false);
+                       goto again;
+               }
+               return &uncore_constraint_empty;
+       }
+
+       if (!uncore_box_is_fake(box)) {
+               if (idx != reg1->idx)
+                       snbep_pcu_alter_er(event, idx, true);
+               reg1->alloc = 1;
+       }
+       return NULL;
+}
+
+static void snbep_pcu_put_constraint(struct intel_uncore_box *box, struct perf_event *event)
+{
+       struct hw_perf_event_extra *reg1 = &event->hw.extra_reg;
+       struct intel_uncore_extra_reg *er = &box->shared_regs[0];
+
+       if (uncore_box_is_fake(box) || !reg1->alloc)
+               return;
+
+       atomic_sub(1 << (reg1->idx * 8), &er->ref);
+       reg1->alloc = 0;
+}
+
+static int snbep_pcu_hw_config(struct intel_uncore_box *box, struct perf_event *event)
+{
+       struct hw_perf_event *hwc = &event->hw;
+       struct hw_perf_event_extra *reg1 = &hwc->extra_reg;
+       int ev_sel = hwc->config & SNBEP_PMON_CTL_EV_SEL_MASK;
+
+       if (ev_sel >= 0xb && ev_sel <= 0xe) {
+               reg1->reg = SNBEP_PCU_MSR_PMON_BOX_FILTER;
+               reg1->idx = ev_sel - 0xb;
+               reg1->config = event->attr.config1 & (0xff << (reg1->idx * 8));
+       }
+       return 0;
+}
+
+static struct intel_uncore_ops snbep_uncore_pcu_ops = {
+       SNBEP_UNCORE_MSR_OPS_COMMON_INIT(),
+       .hw_config              = snbep_pcu_hw_config,
+       .get_constraint         = snbep_pcu_get_constraint,
+       .put_constraint         = snbep_pcu_put_constraint,
+};
+
+static struct intel_uncore_type snbep_uncore_pcu = {
+       .name                   = "pcu",
+       .num_counters           = 4,
+       .num_boxes              = 1,
+       .perf_ctr_bits          = 48,
+       .perf_ctr               = SNBEP_PCU_MSR_PMON_CTR0,
+       .event_ctl              = SNBEP_PCU_MSR_PMON_CTL0,
+       .event_mask             = SNBEP_PCU_MSR_PMON_RAW_EVENT_MASK,
+       .box_ctl                = SNBEP_PCU_MSR_PMON_BOX_CTL,
+       .num_shared_regs        = 1,
+       .ops                    = &snbep_uncore_pcu_ops,
+       .format_group           = &snbep_uncore_pcu_format_group,
+};
+
+static struct intel_uncore_type *snbep_msr_uncores[] = {
+       &snbep_uncore_ubox,
+       &snbep_uncore_cbox,
+       &snbep_uncore_pcu,
+       NULL,
+};
+
+void snbep_uncore_cpu_init(void)
+{
+       if (snbep_uncore_cbox.num_boxes > boot_cpu_data.x86_max_cores)
+               snbep_uncore_cbox.num_boxes = boot_cpu_data.x86_max_cores;
+       uncore_msr_uncores = snbep_msr_uncores;
+}
+
+enum {
+       SNBEP_PCI_QPI_PORT0_FILTER,
+       SNBEP_PCI_QPI_PORT1_FILTER,
+};
+
+static int snbep_qpi_hw_config(struct intel_uncore_box *box, struct perf_event *event)
+{
+       struct hw_perf_event *hwc = &event->hw;
+       struct hw_perf_event_extra *reg1 = &hwc->extra_reg;
+       struct hw_perf_event_extra *reg2 = &hwc->branch_reg;
+
+       if ((hwc->config & SNBEP_PMON_CTL_EV_SEL_MASK) == 0x38) {
+               reg1->idx = 0;
+               reg1->reg = SNBEP_Q_Py_PCI_PMON_PKT_MATCH0;
+               reg1->config = event->attr.config1;
+               reg2->reg = SNBEP_Q_Py_PCI_PMON_PKT_MASK0;
+               reg2->config = event->attr.config2;
+       }
+       return 0;
+}
+
+static void snbep_qpi_enable_event(struct intel_uncore_box *box, struct perf_event *event)
+{
+       struct pci_dev *pdev = box->pci_dev;
+       struct hw_perf_event *hwc = &event->hw;
+       struct hw_perf_event_extra *reg1 = &hwc->extra_reg;
+       struct hw_perf_event_extra *reg2 = &hwc->branch_reg;
+
+       if (reg1->idx != EXTRA_REG_NONE) {
+               int idx = box->pmu->pmu_idx + SNBEP_PCI_QPI_PORT0_FILTER;
+               struct pci_dev *filter_pdev = uncore_extra_pci_dev[box->phys_id][idx];
+               if (filter_pdev) {
+                       pci_write_config_dword(filter_pdev, reg1->reg,
+                                               (u32)reg1->config);
+                       pci_write_config_dword(filter_pdev, reg1->reg + 4,
+                                               (u32)(reg1->config >> 32));
+                       pci_write_config_dword(filter_pdev, reg2->reg,
+                                               (u32)reg2->config);
+                       pci_write_config_dword(filter_pdev, reg2->reg + 4,
+                                               (u32)(reg2->config >> 32));
+               }
+       }
+
+       pci_write_config_dword(pdev, hwc->config_base, hwc->config | SNBEP_PMON_CTL_EN);
+}
+
+static struct intel_uncore_ops snbep_uncore_qpi_ops = {
+       SNBEP_UNCORE_PCI_OPS_COMMON_INIT(),
+       .enable_event           = snbep_qpi_enable_event,
+       .hw_config              = snbep_qpi_hw_config,
+       .get_constraint         = uncore_get_constraint,
+       .put_constraint         = uncore_put_constraint,
+};
+
+#define SNBEP_UNCORE_PCI_COMMON_INIT()                         \
+       .perf_ctr       = SNBEP_PCI_PMON_CTR0,                  \
+       .event_ctl      = SNBEP_PCI_PMON_CTL0,                  \
+       .event_mask     = SNBEP_PMON_RAW_EVENT_MASK,            \
+       .box_ctl        = SNBEP_PCI_PMON_BOX_CTL,               \
+       .ops            = &snbep_uncore_pci_ops,                \
+       .format_group   = &snbep_uncore_format_group
+
+static struct intel_uncore_type snbep_uncore_ha = {
+       .name           = "ha",
+       .num_counters   = 4,
+       .num_boxes      = 1,
+       .perf_ctr_bits  = 48,
+       SNBEP_UNCORE_PCI_COMMON_INIT(),
+};
+
+static struct intel_uncore_type snbep_uncore_imc = {
+       .name           = "imc",
+       .num_counters   = 4,
+       .num_boxes      = 4,
+       .perf_ctr_bits  = 48,
+       .fixed_ctr_bits = 48,
+       .fixed_ctr      = SNBEP_MC_CHy_PCI_PMON_FIXED_CTR,
+       .fixed_ctl      = SNBEP_MC_CHy_PCI_PMON_FIXED_CTL,
+       .event_descs    = snbep_uncore_imc_events,
+       SNBEP_UNCORE_PCI_COMMON_INIT(),
+};
+
+static struct intel_uncore_type snbep_uncore_qpi = {
+       .name                   = "qpi",
+       .num_counters           = 4,
+       .num_boxes              = 2,
+       .perf_ctr_bits          = 48,
+       .perf_ctr               = SNBEP_PCI_PMON_CTR0,
+       .event_ctl              = SNBEP_PCI_PMON_CTL0,
+       .event_mask             = SNBEP_QPI_PCI_PMON_RAW_EVENT_MASK,
+       .box_ctl                = SNBEP_PCI_PMON_BOX_CTL,
+       .num_shared_regs        = 1,
+       .ops                    = &snbep_uncore_qpi_ops,
+       .event_descs            = snbep_uncore_qpi_events,
+       .format_group           = &snbep_uncore_qpi_format_group,
+};
+
+
+static struct intel_uncore_type snbep_uncore_r2pcie = {
+       .name           = "r2pcie",
+       .num_counters   = 4,
+       .num_boxes      = 1,
+       .perf_ctr_bits  = 44,
+       .constraints    = snbep_uncore_r2pcie_constraints,
+       SNBEP_UNCORE_PCI_COMMON_INIT(),
+};
+
+static struct intel_uncore_type snbep_uncore_r3qpi = {
+       .name           = "r3qpi",
+       .num_counters   = 3,
+       .num_boxes      = 2,
+       .perf_ctr_bits  = 44,
+       .constraints    = snbep_uncore_r3qpi_constraints,
+       SNBEP_UNCORE_PCI_COMMON_INIT(),
+};
+
+enum {
+       SNBEP_PCI_UNCORE_HA,
+       SNBEP_PCI_UNCORE_IMC,
+       SNBEP_PCI_UNCORE_QPI,
+       SNBEP_PCI_UNCORE_R2PCIE,
+       SNBEP_PCI_UNCORE_R3QPI,
+};
+
+static struct intel_uncore_type *snbep_pci_uncores[] = {
+       [SNBEP_PCI_UNCORE_HA]           = &snbep_uncore_ha,
+       [SNBEP_PCI_UNCORE_IMC]          = &snbep_uncore_imc,
+       [SNBEP_PCI_UNCORE_QPI]          = &snbep_uncore_qpi,
+       [SNBEP_PCI_UNCORE_R2PCIE]       = &snbep_uncore_r2pcie,
+       [SNBEP_PCI_UNCORE_R3QPI]        = &snbep_uncore_r3qpi,
+       NULL,
+};
+
+static const struct pci_device_id snbep_uncore_pci_ids[] = {
+       { /* Home Agent */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_HA),
+               .driver_data = UNCORE_PCI_DEV_DATA(SNBEP_PCI_UNCORE_HA, 0),
+       },
+       { /* MC Channel 0 */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_IMC0),
+               .driver_data = UNCORE_PCI_DEV_DATA(SNBEP_PCI_UNCORE_IMC, 0),
+       },
+       { /* MC Channel 1 */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_IMC1),
+               .driver_data = UNCORE_PCI_DEV_DATA(SNBEP_PCI_UNCORE_IMC, 1),
+       },
+       { /* MC Channel 2 */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_IMC2),
+               .driver_data = UNCORE_PCI_DEV_DATA(SNBEP_PCI_UNCORE_IMC, 2),
+       },
+       { /* MC Channel 3 */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_IMC3),
+               .driver_data = UNCORE_PCI_DEV_DATA(SNBEP_PCI_UNCORE_IMC, 3),
+       },
+       { /* QPI Port 0 */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_QPI0),
+               .driver_data = UNCORE_PCI_DEV_DATA(SNBEP_PCI_UNCORE_QPI, 0),
+       },
+       { /* QPI Port 1 */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_QPI1),
+               .driver_data = UNCORE_PCI_DEV_DATA(SNBEP_PCI_UNCORE_QPI, 1),
+       },
+       { /* R2PCIe */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_R2PCIE),
+               .driver_data = UNCORE_PCI_DEV_DATA(SNBEP_PCI_UNCORE_R2PCIE, 0),
+       },
+       { /* R3QPI Link 0 */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_R3QPI0),
+               .driver_data = UNCORE_PCI_DEV_DATA(SNBEP_PCI_UNCORE_R3QPI, 0),
+       },
+       { /* R3QPI Link 1 */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_R3QPI1),
+               .driver_data = UNCORE_PCI_DEV_DATA(SNBEP_PCI_UNCORE_R3QPI, 1),
+       },
+       { /* QPI Port 0 filter  */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x3c86),
+               .driver_data = UNCORE_PCI_DEV_DATA(UNCORE_EXTRA_PCI_DEV,
+                                                  SNBEP_PCI_QPI_PORT0_FILTER),
+       },
+       { /* QPI Port 0 filter  */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x3c96),
+               .driver_data = UNCORE_PCI_DEV_DATA(UNCORE_EXTRA_PCI_DEV,
+                                                  SNBEP_PCI_QPI_PORT1_FILTER),
+       },
+       { /* end: all zeroes */ }
+};
+
+static struct pci_driver snbep_uncore_pci_driver = {
+       .name           = "snbep_uncore",
+       .id_table       = snbep_uncore_pci_ids,
+};
+
+/*
+ * build pci bus to socket mapping
+ */
+static int snbep_pci2phy_map_init(int devid)
+{
+       struct pci_dev *ubox_dev = NULL;
+       int i, bus, nodeid;
+       int err = 0;
+       u32 config = 0;
+
+       while (1) {
+               /* find the UBOX device */
+               ubox_dev = pci_get_device(PCI_VENDOR_ID_INTEL, devid, ubox_dev);
+               if (!ubox_dev)
+                       break;
+               bus = ubox_dev->bus->number;
+               /* get the Node ID of the local register */
+               err = pci_read_config_dword(ubox_dev, 0x40, &config);
+               if (err)
+                       break;
+               nodeid = config;
+               /* get the Node ID mapping */
+               err = pci_read_config_dword(ubox_dev, 0x54, &config);
+               if (err)
+                       break;
+               /*
+                * every three bits in the Node ID mapping register maps
+                * to a particular node.
+                */
+               for (i = 0; i < 8; i++) {
+                       if (nodeid == ((config >> (3 * i)) & 0x7)) {
+                               uncore_pcibus_to_physid[bus] = i;
+                               break;
+                       }
+               }
+       }
+
+       if (!err) {
+               /*
+                * For PCI bus with no UBOX device, find the next bus
+                * that has UBOX device and use its mapping.
+                */
+               i = -1;
+               for (bus = 255; bus >= 0; bus--) {
+                       if (uncore_pcibus_to_physid[bus] >= 0)
+                               i = uncore_pcibus_to_physid[bus];
+                       else
+                               uncore_pcibus_to_physid[bus] = i;
+               }
+       }
+
+       if (ubox_dev)
+               pci_dev_put(ubox_dev);
+
+       return err ? pcibios_err_to_errno(err) : 0;
+}
+
+int snbep_uncore_pci_init(void)
+{
+       int ret = snbep_pci2phy_map_init(0x3ce0);
+       if (ret)
+               return ret;
+       uncore_pci_uncores = snbep_pci_uncores;
+       uncore_pci_driver = &snbep_uncore_pci_driver;
+       return 0;
+}
+/* end of Sandy Bridge-EP uncore support */
+
+/* IvyTown uncore support */
+static void ivbep_uncore_msr_init_box(struct intel_uncore_box *box)
+{
+       unsigned msr = uncore_msr_box_ctl(box);
+       if (msr)
+               wrmsrl(msr, IVBEP_PMON_BOX_CTL_INT);
+}
+
+static void ivbep_uncore_pci_init_box(struct intel_uncore_box *box)
+{
+       struct pci_dev *pdev = box->pci_dev;
+
+       pci_write_config_dword(pdev, SNBEP_PCI_PMON_BOX_CTL, IVBEP_PMON_BOX_CTL_INT);
+}
+
+#define IVBEP_UNCORE_MSR_OPS_COMMON_INIT()                     \
+       .init_box       = ivbep_uncore_msr_init_box,            \
+       .disable_box    = snbep_uncore_msr_disable_box,         \
+       .enable_box     = snbep_uncore_msr_enable_box,          \
+       .disable_event  = snbep_uncore_msr_disable_event,       \
+       .enable_event   = snbep_uncore_msr_enable_event,        \
+       .read_counter   = uncore_msr_read_counter
+
+static struct intel_uncore_ops ivbep_uncore_msr_ops = {
+       IVBEP_UNCORE_MSR_OPS_COMMON_INIT(),
+};
+
+static struct intel_uncore_ops ivbep_uncore_pci_ops = {
+       .init_box       = ivbep_uncore_pci_init_box,
+       .disable_box    = snbep_uncore_pci_disable_box,
+       .enable_box     = snbep_uncore_pci_enable_box,
+       .disable_event  = snbep_uncore_pci_disable_event,
+       .enable_event   = snbep_uncore_pci_enable_event,
+       .read_counter   = snbep_uncore_pci_read_counter,
+};
+
+#define IVBEP_UNCORE_PCI_COMMON_INIT()                         \
+       .perf_ctr       = SNBEP_PCI_PMON_CTR0,                  \
+       .event_ctl      = SNBEP_PCI_PMON_CTL0,                  \
+       .event_mask     = IVBEP_PMON_RAW_EVENT_MASK,            \
+       .box_ctl        = SNBEP_PCI_PMON_BOX_CTL,               \
+       .ops            = &ivbep_uncore_pci_ops,                        \
+       .format_group   = &ivbep_uncore_format_group
+
+static struct attribute *ivbep_uncore_formats_attr[] = {
+       &format_attr_event.attr,
+       &format_attr_umask.attr,
+       &format_attr_edge.attr,
+       &format_attr_inv.attr,
+       &format_attr_thresh8.attr,
+       NULL,
+};
+
+static struct attribute *ivbep_uncore_ubox_formats_attr[] = {
+       &format_attr_event.attr,
+       &format_attr_umask.attr,
+       &format_attr_edge.attr,
+       &format_attr_inv.attr,
+       &format_attr_thresh5.attr,
+       NULL,
+};
+
+static struct attribute *ivbep_uncore_cbox_formats_attr[] = {
+       &format_attr_event.attr,
+       &format_attr_umask.attr,
+       &format_attr_edge.attr,
+       &format_attr_tid_en.attr,
+       &format_attr_thresh8.attr,
+       &format_attr_filter_tid.attr,
+       &format_attr_filter_link.attr,
+       &format_attr_filter_state2.attr,
+       &format_attr_filter_nid2.attr,
+       &format_attr_filter_opc2.attr,
+       &format_attr_filter_nc.attr,
+       &format_attr_filter_c6.attr,
+       &format_attr_filter_isoc.attr,
+       NULL,
+};
+
+static struct attribute *ivbep_uncore_pcu_formats_attr[] = {
+       &format_attr_event_ext.attr,
+       &format_attr_occ_sel.attr,
+       &format_attr_edge.attr,
+       &format_attr_thresh5.attr,
+       &format_attr_occ_invert.attr,
+       &format_attr_occ_edge.attr,
+       &format_attr_filter_band0.attr,
+       &format_attr_filter_band1.attr,
+       &format_attr_filter_band2.attr,
+       &format_attr_filter_band3.attr,
+       NULL,
+};
+
+static struct attribute *ivbep_uncore_qpi_formats_attr[] = {
+       &format_attr_event_ext.attr,
+       &format_attr_umask.attr,
+       &format_attr_edge.attr,
+       &format_attr_thresh8.attr,
+       &format_attr_match_rds.attr,
+       &format_attr_match_rnid30.attr,
+       &format_attr_match_rnid4.attr,
+       &format_attr_match_dnid.attr,
+       &format_attr_match_mc.attr,
+       &format_attr_match_opc.attr,
+       &format_attr_match_vnw.attr,
+       &format_attr_match0.attr,
+       &format_attr_match1.attr,
+       &format_attr_mask_rds.attr,
+       &format_attr_mask_rnid30.attr,
+       &format_attr_mask_rnid4.attr,
+       &format_attr_mask_dnid.attr,
+       &format_attr_mask_mc.attr,
+       &format_attr_mask_opc.attr,
+       &format_attr_mask_vnw.attr,
+       &format_attr_mask0.attr,
+       &format_attr_mask1.attr,
+       NULL,
+};
+
+static struct attribute_group ivbep_uncore_format_group = {
+       .name = "format",
+       .attrs = ivbep_uncore_formats_attr,
+};
+
+static struct attribute_group ivbep_uncore_ubox_format_group = {
+       .name = "format",
+       .attrs = ivbep_uncore_ubox_formats_attr,
+};
+
+static struct attribute_group ivbep_uncore_cbox_format_group = {
+       .name = "format",
+       .attrs = ivbep_uncore_cbox_formats_attr,
+};
+
+static struct attribute_group ivbep_uncore_pcu_format_group = {
+       .name = "format",
+       .attrs = ivbep_uncore_pcu_formats_attr,
+};
+
+static struct attribute_group ivbep_uncore_qpi_format_group = {
+       .name = "format",
+       .attrs = ivbep_uncore_qpi_formats_attr,
+};
+
+static struct intel_uncore_type ivbep_uncore_ubox = {
+       .name           = "ubox",
+       .num_counters   = 2,
+       .num_boxes      = 1,
+       .perf_ctr_bits  = 44,
+       .fixed_ctr_bits = 48,
+       .perf_ctr       = SNBEP_U_MSR_PMON_CTR0,
+       .event_ctl      = SNBEP_U_MSR_PMON_CTL0,
+       .event_mask     = IVBEP_U_MSR_PMON_RAW_EVENT_MASK,
+       .fixed_ctr      = SNBEP_U_MSR_PMON_UCLK_FIXED_CTR,
+       .fixed_ctl      = SNBEP_U_MSR_PMON_UCLK_FIXED_CTL,
+       .ops            = &ivbep_uncore_msr_ops,
+       .format_group   = &ivbep_uncore_ubox_format_group,
+};
+
+static struct extra_reg ivbep_uncore_cbox_extra_regs[] = {
+       SNBEP_CBO_EVENT_EXTRA_REG(SNBEP_CBO_PMON_CTL_TID_EN,
+                                 SNBEP_CBO_PMON_CTL_TID_EN, 0x1),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x1031, 0x10ff, 0x2),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x1134, 0xffff, 0x4),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x4134, 0xffff, 0xc),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x5134, 0xffff, 0xc),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x0334, 0xffff, 0x4),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x4334, 0xffff, 0xc),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x0534, 0xffff, 0x4),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x4534, 0xffff, 0xc),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x0934, 0xffff, 0x4),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x4934, 0xffff, 0xc),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x0135, 0xffff, 0x10),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x0335, 0xffff, 0x10),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x2135, 0xffff, 0x10),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x2335, 0xffff, 0x10),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x4135, 0xffff, 0x18),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x4335, 0xffff, 0x18),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x4435, 0xffff, 0x8),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x4835, 0xffff, 0x8),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x4a35, 0xffff, 0x8),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x5035, 0xffff, 0x8),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x8135, 0xffff, 0x10),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x8335, 0xffff, 0x10),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x0136, 0xffff, 0x10),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x0336, 0xffff, 0x10),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x2136, 0xffff, 0x10),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x2336, 0xffff, 0x10),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x4136, 0xffff, 0x18),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x4336, 0xffff, 0x18),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x4436, 0xffff, 0x8),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x4836, 0xffff, 0x8),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x4a36, 0xffff, 0x8),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x5036, 0xffff, 0x8),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x8136, 0xffff, 0x10),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x8336, 0xffff, 0x10),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x4037, 0x40ff, 0x8),
+       EVENT_EXTRA_END
+};
+
+static u64 ivbep_cbox_filter_mask(int fields)
+{
+       u64 mask = 0;
+
+       if (fields & 0x1)
+               mask |= IVBEP_CB0_MSR_PMON_BOX_FILTER_TID;
+       if (fields & 0x2)
+               mask |= IVBEP_CB0_MSR_PMON_BOX_FILTER_LINK;
+       if (fields & 0x4)
+               mask |= IVBEP_CB0_MSR_PMON_BOX_FILTER_STATE;
+       if (fields & 0x8)
+               mask |= IVBEP_CB0_MSR_PMON_BOX_FILTER_NID;
+       if (fields & 0x10) {
+               mask |= IVBEP_CB0_MSR_PMON_BOX_FILTER_OPC;
+               mask |= IVBEP_CB0_MSR_PMON_BOX_FILTER_NC;
+               mask |= IVBEP_CB0_MSR_PMON_BOX_FILTER_C6;
+               mask |= IVBEP_CB0_MSR_PMON_BOX_FILTER_ISOC;
+       }
+
+       return mask;
+}
+
+static struct event_constraint *
+ivbep_cbox_get_constraint(struct intel_uncore_box *box, struct perf_event *event)
+{
+       return __snbep_cbox_get_constraint(box, event, ivbep_cbox_filter_mask);
+}
+
+static int ivbep_cbox_hw_config(struct intel_uncore_box *box, struct perf_event *event)
+{
+       struct hw_perf_event_extra *reg1 = &event->hw.extra_reg;
+       struct extra_reg *er;
+       int idx = 0;
+
+       for (er = ivbep_uncore_cbox_extra_regs; er->msr; er++) {
+               if (er->event != (event->hw.config & er->config_mask))
+                       continue;
+               idx |= er->idx;
+       }
+
+       if (idx) {
+               reg1->reg = SNBEP_C0_MSR_PMON_BOX_FILTER +
+                       SNBEP_CBO_MSR_OFFSET * box->pmu->pmu_idx;
+               reg1->config = event->attr.config1 & ivbep_cbox_filter_mask(idx);
+               reg1->idx = idx;
+       }
+       return 0;
+}
+
+static void ivbep_cbox_enable_event(struct intel_uncore_box *box, struct perf_event *event)
+{
+       struct hw_perf_event *hwc = &event->hw;
+       struct hw_perf_event_extra *reg1 = &hwc->extra_reg;
+
+       if (reg1->idx != EXTRA_REG_NONE) {
+               u64 filter = uncore_shared_reg_config(box, 0);
+               wrmsrl(reg1->reg, filter & 0xffffffff);
+               wrmsrl(reg1->reg + 6, filter >> 32);
+       }
+
+       wrmsrl(hwc->config_base, hwc->config | SNBEP_PMON_CTL_EN);
+}
+
+static struct intel_uncore_ops ivbep_uncore_cbox_ops = {
+       .init_box               = ivbep_uncore_msr_init_box,
+       .disable_box            = snbep_uncore_msr_disable_box,
+       .enable_box             = snbep_uncore_msr_enable_box,
+       .disable_event          = snbep_uncore_msr_disable_event,
+       .enable_event           = ivbep_cbox_enable_event,
+       .read_counter           = uncore_msr_read_counter,
+       .hw_config              = ivbep_cbox_hw_config,
+       .get_constraint         = ivbep_cbox_get_constraint,
+       .put_constraint         = snbep_cbox_put_constraint,
+};
+
+static struct intel_uncore_type ivbep_uncore_cbox = {
+       .name                   = "cbox",
+       .num_counters           = 4,
+       .num_boxes              = 15,
+       .perf_ctr_bits          = 44,
+       .event_ctl              = SNBEP_C0_MSR_PMON_CTL0,
+       .perf_ctr               = SNBEP_C0_MSR_PMON_CTR0,
+       .event_mask             = IVBEP_CBO_MSR_PMON_RAW_EVENT_MASK,
+       .box_ctl                = SNBEP_C0_MSR_PMON_BOX_CTL,
+       .msr_offset             = SNBEP_CBO_MSR_OFFSET,
+       .num_shared_regs        = 1,
+       .constraints            = snbep_uncore_cbox_constraints,
+       .ops                    = &ivbep_uncore_cbox_ops,
+       .format_group           = &ivbep_uncore_cbox_format_group,
+};
+
+static struct intel_uncore_ops ivbep_uncore_pcu_ops = {
+       IVBEP_UNCORE_MSR_OPS_COMMON_INIT(),
+       .hw_config              = snbep_pcu_hw_config,
+       .get_constraint         = snbep_pcu_get_constraint,
+       .put_constraint         = snbep_pcu_put_constraint,
+};
+
+static struct intel_uncore_type ivbep_uncore_pcu = {
+       .name                   = "pcu",
+       .num_counters           = 4,
+       .num_boxes              = 1,
+       .perf_ctr_bits          = 48,
+       .perf_ctr               = SNBEP_PCU_MSR_PMON_CTR0,
+       .event_ctl              = SNBEP_PCU_MSR_PMON_CTL0,
+       .event_mask             = IVBEP_PCU_MSR_PMON_RAW_EVENT_MASK,
+       .box_ctl                = SNBEP_PCU_MSR_PMON_BOX_CTL,
+       .num_shared_regs        = 1,
+       .ops                    = &ivbep_uncore_pcu_ops,
+       .format_group           = &ivbep_uncore_pcu_format_group,
+};
+
+static struct intel_uncore_type *ivbep_msr_uncores[] = {
+       &ivbep_uncore_ubox,
+       &ivbep_uncore_cbox,
+       &ivbep_uncore_pcu,
+       NULL,
+};
+
+void ivbep_uncore_cpu_init(void)
+{
+       if (ivbep_uncore_cbox.num_boxes > boot_cpu_data.x86_max_cores)
+               ivbep_uncore_cbox.num_boxes = boot_cpu_data.x86_max_cores;
+       uncore_msr_uncores = ivbep_msr_uncores;
+}
+
+static struct intel_uncore_type ivbep_uncore_ha = {
+       .name           = "ha",
+       .num_counters   = 4,
+       .num_boxes      = 2,
+       .perf_ctr_bits  = 48,
+       IVBEP_UNCORE_PCI_COMMON_INIT(),
+};
+
+static struct intel_uncore_type ivbep_uncore_imc = {
+       .name           = "imc",
+       .num_counters   = 4,
+       .num_boxes      = 8,
+       .perf_ctr_bits  = 48,
+       .fixed_ctr_bits = 48,
+       .fixed_ctr      = SNBEP_MC_CHy_PCI_PMON_FIXED_CTR,
+       .fixed_ctl      = SNBEP_MC_CHy_PCI_PMON_FIXED_CTL,
+       .event_descs    = snbep_uncore_imc_events,
+       IVBEP_UNCORE_PCI_COMMON_INIT(),
+};
+
+/* registers in IRP boxes are not properly aligned */
+static unsigned ivbep_uncore_irp_ctls[] = {0xd8, 0xdc, 0xe0, 0xe4};
+static unsigned ivbep_uncore_irp_ctrs[] = {0xa0, 0xb0, 0xb8, 0xc0};
+
+static void ivbep_uncore_irp_enable_event(struct intel_uncore_box *box, struct perf_event *event)
+{
+       struct pci_dev *pdev = box->pci_dev;
+       struct hw_perf_event *hwc = &event->hw;
+
+       pci_write_config_dword(pdev, ivbep_uncore_irp_ctls[hwc->idx],
+                              hwc->config | SNBEP_PMON_CTL_EN);
+}
+
+static void ivbep_uncore_irp_disable_event(struct intel_uncore_box *box, struct perf_event *event)
+{
+       struct pci_dev *pdev = box->pci_dev;
+       struct hw_perf_event *hwc = &event->hw;
+
+       pci_write_config_dword(pdev, ivbep_uncore_irp_ctls[hwc->idx], hwc->config);
+}
+
+static u64 ivbep_uncore_irp_read_counter(struct intel_uncore_box *box, struct perf_event *event)
+{
+       struct pci_dev *pdev = box->pci_dev;
+       struct hw_perf_event *hwc = &event->hw;
+       u64 count = 0;
+
+       pci_read_config_dword(pdev, ivbep_uncore_irp_ctrs[hwc->idx], (u32 *)&count);
+       pci_read_config_dword(pdev, ivbep_uncore_irp_ctrs[hwc->idx] + 4, (u32 *)&count + 1);
+
+       return count;
+}
+
+static struct intel_uncore_ops ivbep_uncore_irp_ops = {
+       .init_box       = ivbep_uncore_pci_init_box,
+       .disable_box    = snbep_uncore_pci_disable_box,
+       .enable_box     = snbep_uncore_pci_enable_box,
+       .disable_event  = ivbep_uncore_irp_disable_event,
+       .enable_event   = ivbep_uncore_irp_enable_event,
+       .read_counter   = ivbep_uncore_irp_read_counter,
+};
+
+static struct intel_uncore_type ivbep_uncore_irp = {
+       .name                   = "irp",
+       .num_counters           = 4,
+       .num_boxes              = 1,
+       .perf_ctr_bits          = 48,
+       .event_mask             = IVBEP_PMON_RAW_EVENT_MASK,
+       .box_ctl                = SNBEP_PCI_PMON_BOX_CTL,
+       .ops                    = &ivbep_uncore_irp_ops,
+       .format_group           = &ivbep_uncore_format_group,
+};
+
+static struct intel_uncore_ops ivbep_uncore_qpi_ops = {
+       .init_box       = ivbep_uncore_pci_init_box,
+       .disable_box    = snbep_uncore_pci_disable_box,
+       .enable_box     = snbep_uncore_pci_enable_box,
+       .disable_event  = snbep_uncore_pci_disable_event,
+       .enable_event   = snbep_qpi_enable_event,
+       .read_counter   = snbep_uncore_pci_read_counter,
+       .hw_config      = snbep_qpi_hw_config,
+       .get_constraint = uncore_get_constraint,
+       .put_constraint = uncore_put_constraint,
+};
+
+static struct intel_uncore_type ivbep_uncore_qpi = {
+       .name                   = "qpi",
+       .num_counters           = 4,
+       .num_boxes              = 3,
+       .perf_ctr_bits          = 48,
+       .perf_ctr               = SNBEP_PCI_PMON_CTR0,
+       .event_ctl              = SNBEP_PCI_PMON_CTL0,
+       .event_mask             = IVBEP_QPI_PCI_PMON_RAW_EVENT_MASK,
+       .box_ctl                = SNBEP_PCI_PMON_BOX_CTL,
+       .num_shared_regs        = 1,
+       .ops                    = &ivbep_uncore_qpi_ops,
+       .format_group           = &ivbep_uncore_qpi_format_group,
+};
+
+static struct intel_uncore_type ivbep_uncore_r2pcie = {
+       .name           = "r2pcie",
+       .num_counters   = 4,
+       .num_boxes      = 1,
+       .perf_ctr_bits  = 44,
+       .constraints    = snbep_uncore_r2pcie_constraints,
+       IVBEP_UNCORE_PCI_COMMON_INIT(),
+};
+
+static struct intel_uncore_type ivbep_uncore_r3qpi = {
+       .name           = "r3qpi",
+       .num_counters   = 3,
+       .num_boxes      = 2,
+       .perf_ctr_bits  = 44,
+       .constraints    = snbep_uncore_r3qpi_constraints,
+       IVBEP_UNCORE_PCI_COMMON_INIT(),
+};
+
+enum {
+       IVBEP_PCI_UNCORE_HA,
+       IVBEP_PCI_UNCORE_IMC,
+       IVBEP_PCI_UNCORE_IRP,
+       IVBEP_PCI_UNCORE_QPI,
+       IVBEP_PCI_UNCORE_R2PCIE,
+       IVBEP_PCI_UNCORE_R3QPI,
+};
+
+static struct intel_uncore_type *ivbep_pci_uncores[] = {
+       [IVBEP_PCI_UNCORE_HA]   = &ivbep_uncore_ha,
+       [IVBEP_PCI_UNCORE_IMC]  = &ivbep_uncore_imc,
+       [IVBEP_PCI_UNCORE_IRP]  = &ivbep_uncore_irp,
+       [IVBEP_PCI_UNCORE_QPI]  = &ivbep_uncore_qpi,
+       [IVBEP_PCI_UNCORE_R2PCIE]       = &ivbep_uncore_r2pcie,
+       [IVBEP_PCI_UNCORE_R3QPI]        = &ivbep_uncore_r3qpi,
+       NULL,
+};
+
+static const struct pci_device_id ivbep_uncore_pci_ids[] = {
+       { /* Home Agent 0 */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe30),
+               .driver_data = UNCORE_PCI_DEV_DATA(IVBEP_PCI_UNCORE_HA, 0),
+       },
+       { /* Home Agent 1 */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe38),
+               .driver_data = UNCORE_PCI_DEV_DATA(IVBEP_PCI_UNCORE_HA, 1),
+       },
+       { /* MC0 Channel 0 */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xeb4),
+               .driver_data = UNCORE_PCI_DEV_DATA(IVBEP_PCI_UNCORE_IMC, 0),
+       },
+       { /* MC0 Channel 1 */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xeb5),
+               .driver_data = UNCORE_PCI_DEV_DATA(IVBEP_PCI_UNCORE_IMC, 1),
+       },
+       { /* MC0 Channel 3 */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xeb0),
+               .driver_data = UNCORE_PCI_DEV_DATA(IVBEP_PCI_UNCORE_IMC, 2),
+       },
+       { /* MC0 Channel 4 */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xeb1),
+               .driver_data = UNCORE_PCI_DEV_DATA(IVBEP_PCI_UNCORE_IMC, 3),
+       },
+       { /* MC1 Channel 0 */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xef4),
+               .driver_data = UNCORE_PCI_DEV_DATA(IVBEP_PCI_UNCORE_IMC, 4),
+       },
+       { /* MC1 Channel 1 */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xef5),
+               .driver_data = UNCORE_PCI_DEV_DATA(IVBEP_PCI_UNCORE_IMC, 5),
+       },
+       { /* MC1 Channel 3 */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xef0),
+               .driver_data = UNCORE_PCI_DEV_DATA(IVBEP_PCI_UNCORE_IMC, 6),
+       },
+       { /* MC1 Channel 4 */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xef1),
+               .driver_data = UNCORE_PCI_DEV_DATA(IVBEP_PCI_UNCORE_IMC, 7),
+       },
+       { /* IRP */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe39),
+               .driver_data = UNCORE_PCI_DEV_DATA(IVBEP_PCI_UNCORE_IRP, 0),
+       },
+       { /* QPI0 Port 0 */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe32),
+               .driver_data = UNCORE_PCI_DEV_DATA(IVBEP_PCI_UNCORE_QPI, 0),
+       },
+       { /* QPI0 Port 1 */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe33),
+               .driver_data = UNCORE_PCI_DEV_DATA(IVBEP_PCI_UNCORE_QPI, 1),
+       },
+       { /* QPI1 Port 2 */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe3a),
+               .driver_data = UNCORE_PCI_DEV_DATA(IVBEP_PCI_UNCORE_QPI, 2),
+       },
+       { /* R2PCIe */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe34),
+               .driver_data = UNCORE_PCI_DEV_DATA(IVBEP_PCI_UNCORE_R2PCIE, 0),
+       },
+       { /* R3QPI0 Link 0 */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe36),
+               .driver_data = UNCORE_PCI_DEV_DATA(IVBEP_PCI_UNCORE_R3QPI, 0),
+       },
+       { /* R3QPI0 Link 1 */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe37),
+               .driver_data = UNCORE_PCI_DEV_DATA(IVBEP_PCI_UNCORE_R3QPI, 1),
+       },
+       { /* R3QPI1 Link 2 */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe3e),
+               .driver_data = UNCORE_PCI_DEV_DATA(IVBEP_PCI_UNCORE_R3QPI, 2),
+       },
+       { /* QPI Port 0 filter  */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe86),
+               .driver_data = UNCORE_PCI_DEV_DATA(UNCORE_EXTRA_PCI_DEV,
+                                                  SNBEP_PCI_QPI_PORT0_FILTER),
+       },
+       { /* QPI Port 0 filter  */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe96),
+               .driver_data = UNCORE_PCI_DEV_DATA(UNCORE_EXTRA_PCI_DEV,
+                                                  SNBEP_PCI_QPI_PORT1_FILTER),
+       },
+       { /* end: all zeroes */ }
+};
+
+static struct pci_driver ivbep_uncore_pci_driver = {
+       .name           = "ivbep_uncore",
+       .id_table       = ivbep_uncore_pci_ids,
+};
+
+int ivbep_uncore_pci_init(void)
+{
+       int ret = snbep_pci2phy_map_init(0x0e1e);
+       if (ret)
+               return ret;
+       uncore_pci_uncores = ivbep_pci_uncores;
+       uncore_pci_driver = &ivbep_uncore_pci_driver;
+       return 0;
+}
+/* end of IvyTown uncore support */
+
+/* Haswell-EP uncore support */
+static struct attribute *hswep_uncore_ubox_formats_attr[] = {
+       &format_attr_event.attr,
+       &format_attr_umask.attr,
+       &format_attr_edge.attr,
+       &format_attr_inv.attr,
+       &format_attr_thresh5.attr,
+       &format_attr_filter_tid2.attr,
+       &format_attr_filter_cid.attr,
+       NULL,
+};
+
+static struct attribute_group hswep_uncore_ubox_format_group = {
+       .name = "format",
+       .attrs = hswep_uncore_ubox_formats_attr,
+};
+
+static int hswep_ubox_hw_config(struct intel_uncore_box *box, struct perf_event *event)
+{
+       struct hw_perf_event_extra *reg1 = &event->hw.extra_reg;
+       reg1->reg = HSWEP_U_MSR_PMON_FILTER;
+       reg1->config = event->attr.config1 & HSWEP_U_MSR_PMON_BOX_FILTER_MASK;
+       reg1->idx = 0;
+       return 0;
+}
+
+static struct intel_uncore_ops hswep_uncore_ubox_ops = {
+       SNBEP_UNCORE_MSR_OPS_COMMON_INIT(),
+       .hw_config              = hswep_ubox_hw_config,
+       .get_constraint         = uncore_get_constraint,
+       .put_constraint         = uncore_put_constraint,
+};
+
+static struct intel_uncore_type hswep_uncore_ubox = {
+       .name                   = "ubox",
+       .num_counters           = 2,
+       .num_boxes              = 1,
+       .perf_ctr_bits          = 44,
+       .fixed_ctr_bits         = 48,
+       .perf_ctr               = HSWEP_U_MSR_PMON_CTR0,
+       .event_ctl              = HSWEP_U_MSR_PMON_CTL0,
+       .event_mask             = SNBEP_U_MSR_PMON_RAW_EVENT_MASK,
+       .fixed_ctr              = HSWEP_U_MSR_PMON_UCLK_FIXED_CTR,
+       .fixed_ctl              = HSWEP_U_MSR_PMON_UCLK_FIXED_CTL,
+       .num_shared_regs        = 1,
+       .ops                    = &hswep_uncore_ubox_ops,
+       .format_group           = &hswep_uncore_ubox_format_group,
+};
+
+static struct attribute *hswep_uncore_cbox_formats_attr[] = {
+       &format_attr_event.attr,
+       &format_attr_umask.attr,
+       &format_attr_edge.attr,
+       &format_attr_tid_en.attr,
+       &format_attr_thresh8.attr,
+       &format_attr_filter_tid3.attr,
+       &format_attr_filter_link2.attr,
+       &format_attr_filter_state3.attr,
+       &format_attr_filter_nid2.attr,
+       &format_attr_filter_opc2.attr,
+       &format_attr_filter_nc.attr,
+       &format_attr_filter_c6.attr,
+       &format_attr_filter_isoc.attr,
+       NULL,
+};
+
+static struct attribute_group hswep_uncore_cbox_format_group = {
+       .name = "format",
+       .attrs = hswep_uncore_cbox_formats_attr,
+};
+
+static struct event_constraint hswep_uncore_cbox_constraints[] = {
+       UNCORE_EVENT_CONSTRAINT(0x01, 0x1),
+       UNCORE_EVENT_CONSTRAINT(0x09, 0x1),
+       UNCORE_EVENT_CONSTRAINT(0x11, 0x1),
+       UNCORE_EVENT_CONSTRAINT(0x36, 0x1),
+       UNCORE_EVENT_CONSTRAINT(0x38, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x3b, 0x1),
+       UNCORE_EVENT_CONSTRAINT(0x3e, 0x1),
+       EVENT_CONSTRAINT_END
+};
+
+static struct extra_reg hswep_uncore_cbox_extra_regs[] = {
+       SNBEP_CBO_EVENT_EXTRA_REG(SNBEP_CBO_PMON_CTL_TID_EN,
+                                 SNBEP_CBO_PMON_CTL_TID_EN, 0x1),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x0334, 0xffff, 0x4),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x0534, 0xffff, 0x4),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x0934, 0xffff, 0x4),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x1134, 0xffff, 0x4),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x2134, 0xffff, 0x4),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x4134, 0xffff, 0x4),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x4037, 0x40ff, 0x8),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x4028, 0x40ff, 0x8),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x4032, 0x40ff, 0x8),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x4029, 0x40ff, 0x8),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x4033, 0x40ff, 0x8),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x402A, 0x40ff, 0x8),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x0135, 0xffff, 0x12),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x0335, 0xffff, 0x10),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x4135, 0xffff, 0x18),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x4435, 0xffff, 0x8),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x4835, 0xffff, 0x8),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x5035, 0xffff, 0x8),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x4335, 0xffff, 0x18),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x4a35, 0xffff, 0x8),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x2335, 0xffff, 0x10),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x8335, 0xffff, 0x10),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x2135, 0xffff, 0x10),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x8135, 0xffff, 0x10),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x0136, 0xffff, 0x10),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x0336, 0xffff, 0x10),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x4136, 0xffff, 0x18),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x4436, 0xffff, 0x8),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x4836, 0xffff, 0x8),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x4336, 0xffff, 0x18),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x4a36, 0xffff, 0x8),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x2336, 0xffff, 0x10),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x8336, 0xffff, 0x10),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x2136, 0xffff, 0x10),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x8136, 0xffff, 0x10),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x5036, 0xffff, 0x8),
+       EVENT_EXTRA_END
+};
+
+static u64 hswep_cbox_filter_mask(int fields)
+{
+       u64 mask = 0;
+       if (fields & 0x1)
+               mask |= HSWEP_CB0_MSR_PMON_BOX_FILTER_TID;
+       if (fields & 0x2)
+               mask |= HSWEP_CB0_MSR_PMON_BOX_FILTER_LINK;
+       if (fields & 0x4)
+               mask |= HSWEP_CB0_MSR_PMON_BOX_FILTER_STATE;
+       if (fields & 0x8)
+               mask |= HSWEP_CB0_MSR_PMON_BOX_FILTER_NID;
+       if (fields & 0x10) {
+               mask |= HSWEP_CB0_MSR_PMON_BOX_FILTER_OPC;
+               mask |= HSWEP_CB0_MSR_PMON_BOX_FILTER_NC;
+               mask |= HSWEP_CB0_MSR_PMON_BOX_FILTER_C6;
+               mask |= HSWEP_CB0_MSR_PMON_BOX_FILTER_ISOC;
+       }
+       return mask;
+}
+
+static struct event_constraint *
+hswep_cbox_get_constraint(struct intel_uncore_box *box, struct perf_event *event)
+{
+       return __snbep_cbox_get_constraint(box, event, hswep_cbox_filter_mask);
+}
+
+static int hswep_cbox_hw_config(struct intel_uncore_box *box, struct perf_event *event)
+{
+       struct hw_perf_event_extra *reg1 = &event->hw.extra_reg;
+       struct extra_reg *er;
+       int idx = 0;
+
+       for (er = hswep_uncore_cbox_extra_regs; er->msr; er++) {
+               if (er->event != (event->hw.config & er->config_mask))
+                       continue;
+               idx |= er->idx;
+       }
+
+       if (idx) {
+               reg1->reg = HSWEP_C0_MSR_PMON_BOX_FILTER0 +
+                           HSWEP_CBO_MSR_OFFSET * box->pmu->pmu_idx;
+               reg1->config = event->attr.config1 & hswep_cbox_filter_mask(idx);
+               reg1->idx = idx;
+       }
+       return 0;
+}
+
+static void hswep_cbox_enable_event(struct intel_uncore_box *box,
+                                 struct perf_event *event)
+{
+       struct hw_perf_event *hwc = &event->hw;
+       struct hw_perf_event_extra *reg1 = &hwc->extra_reg;
+
+       if (reg1->idx != EXTRA_REG_NONE) {
+               u64 filter = uncore_shared_reg_config(box, 0);
+               wrmsrl(reg1->reg, filter & 0xffffffff);
+               wrmsrl(reg1->reg + 1, filter >> 32);
+       }
+
+       wrmsrl(hwc->config_base, hwc->config | SNBEP_PMON_CTL_EN);
+}
+
+static struct intel_uncore_ops hswep_uncore_cbox_ops = {
+       .init_box               = snbep_uncore_msr_init_box,
+       .disable_box            = snbep_uncore_msr_disable_box,
+       .enable_box             = snbep_uncore_msr_enable_box,
+       .disable_event          = snbep_uncore_msr_disable_event,
+       .enable_event           = hswep_cbox_enable_event,
+       .read_counter           = uncore_msr_read_counter,
+       .hw_config              = hswep_cbox_hw_config,
+       .get_constraint         = hswep_cbox_get_constraint,
+       .put_constraint         = snbep_cbox_put_constraint,
+};
+
+static struct intel_uncore_type hswep_uncore_cbox = {
+       .name                   = "cbox",
+       .num_counters           = 4,
+       .num_boxes              = 18,
+       .perf_ctr_bits          = 44,
+       .event_ctl              = HSWEP_C0_MSR_PMON_CTL0,
+       .perf_ctr               = HSWEP_C0_MSR_PMON_CTR0,
+       .event_mask             = SNBEP_CBO_MSR_PMON_RAW_EVENT_MASK,
+       .box_ctl                = HSWEP_C0_MSR_PMON_BOX_CTL,
+       .msr_offset             = HSWEP_CBO_MSR_OFFSET,
+       .num_shared_regs        = 1,
+       .constraints            = hswep_uncore_cbox_constraints,
+       .ops                    = &hswep_uncore_cbox_ops,
+       .format_group           = &hswep_uncore_cbox_format_group,
+};
+
+static struct attribute *hswep_uncore_sbox_formats_attr[] = {
+       &format_attr_event.attr,
+       &format_attr_umask.attr,
+       &format_attr_edge.attr,
+       &format_attr_tid_en.attr,
+       &format_attr_inv.attr,
+       &format_attr_thresh8.attr,
+       NULL,
+};
+
+static struct attribute_group hswep_uncore_sbox_format_group = {
+       .name = "format",
+       .attrs = hswep_uncore_sbox_formats_attr,
+};
+
+static struct intel_uncore_type hswep_uncore_sbox = {
+       .name                   = "sbox",
+       .num_counters           = 4,
+       .num_boxes              = 4,
+       .perf_ctr_bits          = 44,
+       .event_ctl              = HSWEP_S0_MSR_PMON_CTL0,
+       .perf_ctr               = HSWEP_S0_MSR_PMON_CTR0,
+       .event_mask             = HSWEP_S_MSR_PMON_RAW_EVENT_MASK,
+       .box_ctl                = HSWEP_S0_MSR_PMON_BOX_CTL,
+       .msr_offset             = HSWEP_SBOX_MSR_OFFSET,
+       .ops                    = &snbep_uncore_msr_ops,
+       .format_group           = &hswep_uncore_sbox_format_group,
+};
+
+static int hswep_pcu_hw_config(struct intel_uncore_box *box, struct perf_event *event)
+{
+       struct hw_perf_event *hwc = &event->hw;
+       struct hw_perf_event_extra *reg1 = &hwc->extra_reg;
+       int ev_sel = hwc->config & SNBEP_PMON_CTL_EV_SEL_MASK;
+
+       if (ev_sel >= 0xb && ev_sel <= 0xe) {
+               reg1->reg = HSWEP_PCU_MSR_PMON_BOX_FILTER;
+               reg1->idx = ev_sel - 0xb;
+               reg1->config = event->attr.config1 & (0xff << reg1->idx);
+       }
+       return 0;
+}
+
+static struct intel_uncore_ops hswep_uncore_pcu_ops = {
+       SNBEP_UNCORE_MSR_OPS_COMMON_INIT(),
+       .hw_config              = hswep_pcu_hw_config,
+       .get_constraint         = snbep_pcu_get_constraint,
+       .put_constraint         = snbep_pcu_put_constraint,
+};
+
+static struct intel_uncore_type hswep_uncore_pcu = {
+       .name                   = "pcu",
+       .num_counters           = 4,
+       .num_boxes              = 1,
+       .perf_ctr_bits          = 48,
+       .perf_ctr               = HSWEP_PCU_MSR_PMON_CTR0,
+       .event_ctl              = HSWEP_PCU_MSR_PMON_CTL0,
+       .event_mask             = SNBEP_PCU_MSR_PMON_RAW_EVENT_MASK,
+       .box_ctl                = HSWEP_PCU_MSR_PMON_BOX_CTL,
+       .num_shared_regs        = 1,
+       .ops                    = &hswep_uncore_pcu_ops,
+       .format_group           = &snbep_uncore_pcu_format_group,
+};
+
+static struct intel_uncore_type *hswep_msr_uncores[] = {
+       &hswep_uncore_ubox,
+       &hswep_uncore_cbox,
+       &hswep_uncore_sbox,
+       &hswep_uncore_pcu,
+       NULL,
+};
+
+void hswep_uncore_cpu_init(void)
+{
+       if (hswep_uncore_cbox.num_boxes > boot_cpu_data.x86_max_cores)
+               hswep_uncore_cbox.num_boxes = boot_cpu_data.x86_max_cores;
+       uncore_msr_uncores = hswep_msr_uncores;
+}
+
+static struct intel_uncore_type hswep_uncore_ha = {
+       .name           = "ha",
+       .num_counters   = 5,
+       .num_boxes      = 2,
+       .perf_ctr_bits  = 48,
+       SNBEP_UNCORE_PCI_COMMON_INIT(),
+};
+
+static struct uncore_event_desc hswep_uncore_imc_events[] = {
+       INTEL_UNCORE_EVENT_DESC(clockticks,      "event=0x00,umask=0x00"),
+       INTEL_UNCORE_EVENT_DESC(cas_count_read,  "event=0x04,umask=0x03"),
+       INTEL_UNCORE_EVENT_DESC(cas_count_write, "event=0x04,umask=0x0c"),
+       { /* end: all zeroes */ },
+};
+
+static struct intel_uncore_type hswep_uncore_imc = {
+       .name           = "imc",
+       .num_counters   = 5,
+       .num_boxes      = 8,
+       .perf_ctr_bits  = 48,
+       .fixed_ctr_bits = 48,
+       .fixed_ctr      = SNBEP_MC_CHy_PCI_PMON_FIXED_CTR,
+       .fixed_ctl      = SNBEP_MC_CHy_PCI_PMON_FIXED_CTL,
+       .event_descs    = hswep_uncore_imc_events,
+       SNBEP_UNCORE_PCI_COMMON_INIT(),
+};
+
+static struct intel_uncore_ops hswep_uncore_irp_ops = {
+       .init_box       = snbep_uncore_pci_init_box,
+       .disable_box    = snbep_uncore_pci_disable_box,
+       .enable_box     = snbep_uncore_pci_enable_box,
+       .disable_event  = ivbep_uncore_irp_disable_event,
+       .enable_event   = ivbep_uncore_irp_enable_event,
+       .read_counter   = ivbep_uncore_irp_read_counter,
+};
+
+static struct intel_uncore_type hswep_uncore_irp = {
+       .name                   = "irp",
+       .num_counters           = 4,
+       .num_boxes              = 1,
+       .perf_ctr_bits          = 48,
+       .event_mask             = SNBEP_PMON_RAW_EVENT_MASK,
+       .box_ctl                = SNBEP_PCI_PMON_BOX_CTL,
+       .ops                    = &hswep_uncore_irp_ops,
+       .format_group           = &snbep_uncore_format_group,
+};
+
+static struct intel_uncore_type hswep_uncore_qpi = {
+       .name                   = "qpi",
+       .num_counters           = 5,
+       .num_boxes              = 3,
+       .perf_ctr_bits          = 48,
+       .perf_ctr               = SNBEP_PCI_PMON_CTR0,
+       .event_ctl              = SNBEP_PCI_PMON_CTL0,
+       .event_mask             = SNBEP_QPI_PCI_PMON_RAW_EVENT_MASK,
+       .box_ctl                = SNBEP_PCI_PMON_BOX_CTL,
+       .num_shared_regs        = 1,
+       .ops                    = &snbep_uncore_qpi_ops,
+       .format_group           = &snbep_uncore_qpi_format_group,
+};
+
+static struct event_constraint hswep_uncore_r2pcie_constraints[] = {
+       UNCORE_EVENT_CONSTRAINT(0x10, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x11, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x13, 0x1),
+       UNCORE_EVENT_CONSTRAINT(0x23, 0x1),
+       UNCORE_EVENT_CONSTRAINT(0x24, 0x1),
+       UNCORE_EVENT_CONSTRAINT(0x25, 0x1),
+       UNCORE_EVENT_CONSTRAINT(0x26, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x27, 0x1),
+       UNCORE_EVENT_CONSTRAINT(0x28, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x29, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x2a, 0x1),
+       UNCORE_EVENT_CONSTRAINT(0x2b, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x2c, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x2d, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x32, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x33, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x34, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x35, 0x3),
+       EVENT_CONSTRAINT_END
+};
+
+static struct intel_uncore_type hswep_uncore_r2pcie = {
+       .name           = "r2pcie",
+       .num_counters   = 4,
+       .num_boxes      = 1,
+       .perf_ctr_bits  = 48,
+       .constraints    = hswep_uncore_r2pcie_constraints,
+       SNBEP_UNCORE_PCI_COMMON_INIT(),
+};
+
+static struct event_constraint hswep_uncore_r3qpi_constraints[] = {
+       UNCORE_EVENT_CONSTRAINT(0x01, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x07, 0x7),
+       UNCORE_EVENT_CONSTRAINT(0x08, 0x7),
+       UNCORE_EVENT_CONSTRAINT(0x09, 0x7),
+       UNCORE_EVENT_CONSTRAINT(0x0a, 0x7),
+       UNCORE_EVENT_CONSTRAINT(0x0e, 0x7),
+       UNCORE_EVENT_CONSTRAINT(0x10, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x11, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x12, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x13, 0x1),
+       UNCORE_EVENT_CONSTRAINT(0x14, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x15, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x1f, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x20, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x21, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x22, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x23, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x25, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x26, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x28, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x29, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x2c, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x2d, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x2e, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x2f, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x31, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x32, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x33, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x34, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x36, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x37, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x38, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x39, 0x3),
+       EVENT_CONSTRAINT_END
+};
+
+static struct intel_uncore_type hswep_uncore_r3qpi = {
+       .name           = "r3qpi",
+       .num_counters   = 4,
+       .num_boxes      = 3,
+       .perf_ctr_bits  = 44,
+       .constraints    = hswep_uncore_r3qpi_constraints,
+       SNBEP_UNCORE_PCI_COMMON_INIT(),
+};
+
+enum {
+       HSWEP_PCI_UNCORE_HA,
+       HSWEP_PCI_UNCORE_IMC,
+       HSWEP_PCI_UNCORE_IRP,
+       HSWEP_PCI_UNCORE_QPI,
+       HSWEP_PCI_UNCORE_R2PCIE,
+       HSWEP_PCI_UNCORE_R3QPI,
+};
+
+static struct intel_uncore_type *hswep_pci_uncores[] = {
+       [HSWEP_PCI_UNCORE_HA]   = &hswep_uncore_ha,
+       [HSWEP_PCI_UNCORE_IMC]  = &hswep_uncore_imc,
+       [HSWEP_PCI_UNCORE_IRP]  = &hswep_uncore_irp,
+       [HSWEP_PCI_UNCORE_QPI]  = &hswep_uncore_qpi,
+       [HSWEP_PCI_UNCORE_R2PCIE]       = &hswep_uncore_r2pcie,
+       [HSWEP_PCI_UNCORE_R3QPI]        = &hswep_uncore_r3qpi,
+       NULL,
+};
+
+static DEFINE_PCI_DEVICE_TABLE(hswep_uncore_pci_ids) = {
+       { /* Home Agent 0 */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x2f30),
+               .driver_data = UNCORE_PCI_DEV_DATA(HSWEP_PCI_UNCORE_HA, 0),
+       },
+       { /* Home Agent 1 */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x2f38),
+               .driver_data = UNCORE_PCI_DEV_DATA(HSWEP_PCI_UNCORE_HA, 1),
+       },
+       { /* MC0 Channel 0 */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x2fb0),
+               .driver_data = UNCORE_PCI_DEV_DATA(HSWEP_PCI_UNCORE_IMC, 0),
+       },
+       { /* MC0 Channel 1 */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x2fb1),
+               .driver_data = UNCORE_PCI_DEV_DATA(HSWEP_PCI_UNCORE_IMC, 1),
+       },
+       { /* MC0 Channel 2 */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x2fb4),
+               .driver_data = UNCORE_PCI_DEV_DATA(HSWEP_PCI_UNCORE_IMC, 2),
+       },
+       { /* MC0 Channel 3 */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x2fb5),
+               .driver_data = UNCORE_PCI_DEV_DATA(HSWEP_PCI_UNCORE_IMC, 3),
+       },
+       { /* MC1 Channel 0 */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x2fd0),
+               .driver_data = UNCORE_PCI_DEV_DATA(HSWEP_PCI_UNCORE_IMC, 4),
+       },
+       { /* MC1 Channel 1 */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x2fd1),
+               .driver_data = UNCORE_PCI_DEV_DATA(HSWEP_PCI_UNCORE_IMC, 5),
+       },
+       { /* MC1 Channel 2 */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x2fd4),
+               .driver_data = UNCORE_PCI_DEV_DATA(HSWEP_PCI_UNCORE_IMC, 6),
+       },
+       { /* MC1 Channel 3 */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x2fd5),
+               .driver_data = UNCORE_PCI_DEV_DATA(HSWEP_PCI_UNCORE_IMC, 7),
+       },
+       { /* IRP */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x2f39),
+               .driver_data = UNCORE_PCI_DEV_DATA(HSWEP_PCI_UNCORE_IRP, 0),
+       },
+       { /* QPI0 Port 0 */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x2f32),
+               .driver_data = UNCORE_PCI_DEV_DATA(HSWEP_PCI_UNCORE_QPI, 0),
+       },
+       { /* QPI0 Port 1 */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x2f33),
+               .driver_data = UNCORE_PCI_DEV_DATA(HSWEP_PCI_UNCORE_QPI, 1),
+       },
+       { /* QPI1 Port 2 */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x2f3a),
+               .driver_data = UNCORE_PCI_DEV_DATA(HSWEP_PCI_UNCORE_QPI, 2),
+       },
+       { /* R2PCIe */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x2f34),
+               .driver_data = UNCORE_PCI_DEV_DATA(HSWEP_PCI_UNCORE_R2PCIE, 0),
+       },
+       { /* R3QPI0 Link 0 */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x2f36),
+               .driver_data = UNCORE_PCI_DEV_DATA(HSWEP_PCI_UNCORE_R3QPI, 0),
+       },
+       { /* R3QPI0 Link 1 */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x2f37),
+               .driver_data = UNCORE_PCI_DEV_DATA(HSWEP_PCI_UNCORE_R3QPI, 1),
+       },
+       { /* R3QPI1 Link 2 */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x2f3e),
+               .driver_data = UNCORE_PCI_DEV_DATA(HSWEP_PCI_UNCORE_R3QPI, 2),
+       },
+       { /* QPI Port 0 filter  */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x2f86),
+               .driver_data = UNCORE_PCI_DEV_DATA(UNCORE_EXTRA_PCI_DEV,
+                                                  SNBEP_PCI_QPI_PORT0_FILTER),
+       },
+       { /* QPI Port 1 filter  */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x2f96),
+               .driver_data = UNCORE_PCI_DEV_DATA(UNCORE_EXTRA_PCI_DEV,
+                                                  SNBEP_PCI_QPI_PORT1_FILTER),
+       },
+       { /* end: all zeroes */ }
+};
+
+static struct pci_driver hswep_uncore_pci_driver = {
+       .name           = "hswep_uncore",
+       .id_table       = hswep_uncore_pci_ids,
+};
+
+int hswep_uncore_pci_init(void)
+{
+       int ret = snbep_pci2phy_map_init(0x2f1e);
+       if (ret)
+               return ret;
+       uncore_pci_uncores = hswep_pci_uncores;
+       uncore_pci_driver = &hswep_uncore_pci_driver;
+       return 0;
+}
+/* end of Haswell-EP uncore support */
index 784304b222b3e6707332f6b4c46015605ea519ad..98f923b6a0eaa78ee8b4ffdf57c87f146e3c03d6 100644 (file)
@@ -8,28 +8,28 @@
  * Copyright (C) 2011-2012 Peter Zijlstra <pzijlstr@redhat.com>
  *
  * Jump labels provide an interface to generate dynamic branches using
- * self-modifying code. Assuming toolchain and architecture support the result
- * of a "if (static_key_false(&key))" statement is a unconditional branch (which
+ * self-modifying code. Assuming toolchain and architecture support, the result
+ * of a "if (static_key_false(&key))" statement is an unconditional branch (which
  * defaults to false - and the true block is placed out of line).
  *
  * However at runtime we can change the branch target using
  * static_key_slow_{inc,dec}(). These function as a 'reference' count on the key
- * object and for as long as there are references all branches referring to
+ * object, and for as long as there are references all branches referring to
  * that particular key will point to the (out of line) true block.
  *
- * Since this relies on modifying code the static_key_slow_{inc,dec}() functions
+ * Since this relies on modifying code, the static_key_slow_{inc,dec}() functions
  * must be considered absolute slow paths (machine wide synchronization etc.).
- * OTOH, since the affected branches are unconditional their runtime overhead
+ * OTOH, since the affected branches are unconditional, their runtime overhead
  * will be absolutely minimal, esp. in the default (off) case where the total
  * effect is a single NOP of appropriate size. The on case will patch in a jump
  * to the out-of-line block.
  *
- * When the control is directly exposed to userspace it is prudent to delay the
+ * When the control is directly exposed to userspace, it is prudent to delay the
  * decrement to avoid high frequency code modifications which can (and do)
  * cause significant performance degradation. Struct static_key_deferred and
  * static_key_slow_dec_deferred() provide for this.
  *
- * Lacking toolchain and or architecture support, it falls back to a simple
+ * Lacking toolchain and or architecture support, jump labels fall back to a simple
  * conditional branch.
  *
  * struct static_key my_key = STATIC_KEY_INIT_TRUE;
@@ -43,8 +43,7 @@
  *
  * Not initializing the key (static data is initialized to 0s anyway) is the
  * same as using STATIC_KEY_INIT_FALSE.
- *
-*/
+ */
 
 #include <linux/types.h>
 #include <linux/compiler.h>
index 2338e68398cb5d70fb7aa4d04e86119e2d6da609..0aa51b45159736988851e61d2d3c2e6cfa70b87b 100644 (file)
 #define PCI_DEVICE_ID_INTEL_EESSC      0x0008
 #define PCI_DEVICE_ID_INTEL_SNB_IMC    0x0100
 #define PCI_DEVICE_ID_INTEL_IVB_IMC    0x0154
+#define PCI_DEVICE_ID_INTEL_IVB_E3_IMC 0x0150
 #define PCI_DEVICE_ID_INTEL_HSW_IMC    0x0c00
 #define PCI_DEVICE_ID_INTEL_PXHD_0     0x0320
 #define PCI_DEVICE_ID_INTEL_PXHD_1     0x0321
index 707617a8c0f6c647b8f3c9d210b833638c20eb02..893a0d07986f526b1402ef19238f6e2dccd70973 100644 (file)
@@ -52,6 +52,7 @@ struct perf_guest_info_callbacks {
 #include <linux/atomic.h>
 #include <linux/sysfs.h>
 #include <linux/perf_regs.h>
+#include <linux/workqueue.h>
 #include <asm/local.h>
 
 struct perf_callchain_entry {
@@ -268,6 +269,7 @@ struct pmu {
  * enum perf_event_active_state - the states of a event
  */
 enum perf_event_active_state {
+       PERF_EVENT_STATE_EXIT           = -3,
        PERF_EVENT_STATE_ERROR          = -2,
        PERF_EVENT_STATE_OFF            = -1,
        PERF_EVENT_STATE_INACTIVE       =  0,
@@ -507,6 +509,9 @@ struct perf_event_context {
        int                             nr_cgroups;      /* cgroup evts */
        int                             nr_branch_stack; /* branch_stack evt */
        struct rcu_head                 rcu_head;
+
+       struct delayed_work             orphans_remove;
+       bool                            orphans_remove_sched;
 };
 
 /*
@@ -604,6 +609,13 @@ struct perf_sample_data {
        u64                             txn;
 };
 
+/* default value for data source */
+#define PERF_MEM_NA (PERF_MEM_S(OP, NA)   |\
+                   PERF_MEM_S(LVL, NA)   |\
+                   PERF_MEM_S(SNOOP, NA) |\
+                   PERF_MEM_S(LOCK, NA)  |\
+                   PERF_MEM_S(TLB, NA))
+
 static inline void perf_sample_data_init(struct perf_sample_data *data,
                                         u64 addr, u64 period)
 {
@@ -616,7 +628,7 @@ static inline void perf_sample_data_init(struct perf_sample_data *data,
        data->regs_user.regs = NULL;
        data->stack_user_size = 0;
        data->weight = 0;
-       data->data_src.val = 0;
+       data->data_src.val = PERF_MEM_NA;
        data->txn = 0;
 }
 
index 97b67df8fbfed0fe7d3cdbcec0ed213b5df80e6b..f2a88de87a49b590207a0fc966b54060fd103f49 100644 (file)
@@ -52,7 +52,7 @@ static void release_callchain_buffers(void)
        struct callchain_cpus_entries *entries;
 
        entries = callchain_cpus_entries;
-       rcu_assign_pointer(callchain_cpus_entries, NULL);
+       RCU_INIT_POINTER(callchain_cpus_entries, NULL);
        call_rcu(&entries->rcu_head, release_callchain_buffers_rcu);
 }
 
index b1c663593f5c9f082cb3dd997f94978a723b7599..385f11d941059f94a0f7bc988855f68998a1f7aa 100644 (file)
@@ -47,6 +47,8 @@
 
 #include <asm/irq_regs.h>
 
+static struct workqueue_struct *perf_wq;
+
 struct remote_function_call {
        struct task_struct      *p;
        int                     (*func)(void *info);
@@ -120,6 +122,13 @@ static int cpu_function_call(int cpu, int (*func) (void *info), void *info)
        return data.ret;
 }
 
+#define EVENT_OWNER_KERNEL ((void *) -1)
+
+static bool is_kernel_event(struct perf_event *event)
+{
+       return event->owner == EVENT_OWNER_KERNEL;
+}
+
 #define PERF_FLAG_ALL (PERF_FLAG_FD_NO_GROUP |\
                       PERF_FLAG_FD_OUTPUT  |\
                       PERF_FLAG_PID_CGROUP |\
@@ -1370,6 +1379,45 @@ out:
                perf_event__header_size(tmp);
 }
 
+/*
+ * User event without the task.
+ */
+static bool is_orphaned_event(struct perf_event *event)
+{
+       return event && !is_kernel_event(event) && !event->owner;
+}
+
+/*
+ * Event has a parent but parent's task finished and it's
+ * alive only because of children holding refference.
+ */
+static bool is_orphaned_child(struct perf_event *event)
+{
+       return is_orphaned_event(event->parent);
+}
+
+static void orphans_remove_work(struct work_struct *work);
+
+static void schedule_orphans_remove(struct perf_event_context *ctx)
+{
+       if (!ctx->task || ctx->orphans_remove_sched || !perf_wq)
+               return;
+
+       if (queue_delayed_work(perf_wq, &ctx->orphans_remove, 1)) {
+               get_ctx(ctx);
+               ctx->orphans_remove_sched = true;
+       }
+}
+
+static int __init perf_workqueue_init(void)
+{
+       perf_wq = create_singlethread_workqueue("perf");
+       WARN(!perf_wq, "failed to create perf workqueue\n");
+       return perf_wq ? 0 : -1;
+}
+
+core_initcall(perf_workqueue_init);
+
 static inline int
 event_filter_match(struct perf_event *event)
 {
@@ -1419,6 +1467,9 @@ event_sched_out(struct perf_event *event,
        if (event->attr.exclusive || !cpuctx->active_oncpu)
                cpuctx->exclusive = 0;
 
+       if (is_orphaned_child(event))
+               schedule_orphans_remove(ctx);
+
        perf_pmu_enable(event->pmu);
 }
 
@@ -1726,6 +1777,9 @@ event_sched_in(struct perf_event *event,
        if (event->attr.exclusive)
                cpuctx->exclusive = 1;
 
+       if (is_orphaned_child(event))
+               schedule_orphans_remove(ctx);
+
 out:
        perf_pmu_enable(event->pmu);
 
@@ -2326,7 +2380,7 @@ static void perf_event_context_sched_out(struct task_struct *task, int ctxn,
        next_parent = rcu_dereference(next_ctx->parent_ctx);
 
        /* If neither context have a parent context; they cannot be clones. */
-       if (!parent || !next_parent)
+       if (!parent && !next_parent)
                goto unlock;
 
        if (next_parent == ctx || next_ctx == parent || next_parent == parent) {
@@ -3073,6 +3127,7 @@ static void __perf_event_init_context(struct perf_event_context *ctx)
        INIT_LIST_HEAD(&ctx->flexible_groups);
        INIT_LIST_HEAD(&ctx->event_list);
        atomic_set(&ctx->refcount, 1);
+       INIT_DELAYED_WORK(&ctx->orphans_remove, orphans_remove_work);
 }
 
 static struct perf_event_context *
@@ -3318,16 +3373,12 @@ static void free_event(struct perf_event *event)
 }
 
 /*
- * Called when the last reference to the file is gone.
+ * Remove user event from the owner task.
  */
-static void put_event(struct perf_event *event)
+static void perf_remove_from_owner(struct perf_event *event)
 {
-       struct perf_event_context *ctx = event->ctx;
        struct task_struct *owner;
 
-       if (!atomic_long_dec_and_test(&event->refcount))
-               return;
-
        rcu_read_lock();
        owner = ACCESS_ONCE(event->owner);
        /*
@@ -3360,6 +3411,20 @@ static void put_event(struct perf_event *event)
                mutex_unlock(&owner->perf_event_mutex);
                put_task_struct(owner);
        }
+}
+
+/*
+ * Called when the last reference to the file is gone.
+ */
+static void put_event(struct perf_event *event)
+{
+       struct perf_event_context *ctx = event->ctx;
+
+       if (!atomic_long_dec_and_test(&event->refcount))
+               return;
+
+       if (!is_kernel_event(event))
+               perf_remove_from_owner(event);
 
        WARN_ON_ONCE(ctx->parent_ctx);
        /*
@@ -3394,6 +3459,42 @@ static int perf_release(struct inode *inode, struct file *file)
        return 0;
 }
 
+/*
+ * Remove all orphanes events from the context.
+ */
+static void orphans_remove_work(struct work_struct *work)
+{
+       struct perf_event_context *ctx;
+       struct perf_event *event, *tmp;
+
+       ctx = container_of(work, struct perf_event_context,
+                          orphans_remove.work);
+
+       mutex_lock(&ctx->mutex);
+       list_for_each_entry_safe(event, tmp, &ctx->event_list, event_entry) {
+               struct perf_event *parent_event = event->parent;
+
+               if (!is_orphaned_child(event))
+                       continue;
+
+               perf_remove_from_context(event, true);
+
+               mutex_lock(&parent_event->child_mutex);
+               list_del_init(&event->child_list);
+               mutex_unlock(&parent_event->child_mutex);
+
+               free_event(event);
+               put_event(parent_event);
+       }
+
+       raw_spin_lock_irq(&ctx->lock);
+       ctx->orphans_remove_sched = false;
+       raw_spin_unlock_irq(&ctx->lock);
+       mutex_unlock(&ctx->mutex);
+
+       put_ctx(ctx);
+}
+
 u64 perf_event_read_value(struct perf_event *event, u64 *enabled, u64 *running)
 {
        struct perf_event *child;
@@ -3491,6 +3592,19 @@ static int perf_event_read_one(struct perf_event *event,
        return n * sizeof(u64);
 }
 
+static bool is_event_hup(struct perf_event *event)
+{
+       bool no_children;
+
+       if (event->state != PERF_EVENT_STATE_EXIT)
+               return false;
+
+       mutex_lock(&event->child_mutex);
+       no_children = list_empty(&event->child_list);
+       mutex_unlock(&event->child_mutex);
+       return no_children;
+}
+
 /*
  * Read the performance event - simple non blocking version for now
  */
@@ -3532,7 +3646,12 @@ static unsigned int perf_poll(struct file *file, poll_table *wait)
 {
        struct perf_event *event = file->private_data;
        struct ring_buffer *rb;
-       unsigned int events = POLL_HUP;
+       unsigned int events = POLLHUP;
+
+       poll_wait(file, &event->waitq, wait);
+
+       if (is_event_hup(event))
+               return events;
 
        /*
         * Pin the event->rb by taking event->mmap_mutex; otherwise
@@ -3543,9 +3662,6 @@ static unsigned int perf_poll(struct file *file, poll_table *wait)
        if (rb)
                events = atomic_xchg(&rb->poll, 0);
        mutex_unlock(&event->mmap_mutex);
-
-       poll_wait(file, &event->waitq, wait);
-
        return events;
 }
 
@@ -5809,7 +5925,7 @@ static void swevent_hlist_release(struct swevent_htable *swhash)
        if (!hlist)
                return;
 
-       rcu_assign_pointer(swhash->swevent_hlist, NULL);
+       RCU_INIT_POINTER(swhash->swevent_hlist, NULL);
        kfree_rcu(hlist, rcu_head);
 }
 
@@ -7392,6 +7508,9 @@ perf_event_create_kernel_counter(struct perf_event_attr *attr, int cpu,
                goto err;
        }
 
+       /* Mark owner so we could distinguish it from user events. */
+       event->owner = EVENT_OWNER_KERNEL;
+
        account_event(event);
 
        ctx = find_get_context(event->pmu, task, cpu);
@@ -7478,6 +7597,12 @@ static void sync_child_event(struct perf_event *child_event,
        list_del_init(&child_event->child_list);
        mutex_unlock(&parent_event->child_mutex);
 
+       /*
+        * Make sure user/parent get notified, that we just
+        * lost one event.
+        */
+       perf_event_wakeup(parent_event);
+
        /*
         * Release the parent event, if this was the last
         * reference to it.
@@ -7512,6 +7637,9 @@ __perf_event_exit_task(struct perf_event *child_event,
        if (child_event->parent) {
                sync_child_event(child_event, child);
                free_event(child_event);
+       } else {
+               child_event->state = PERF_EVENT_STATE_EXIT;
+               perf_event_wakeup(child_event);
        }
 }
 
@@ -7695,6 +7823,7 @@ inherit_event(struct perf_event *parent_event,
              struct perf_event *group_leader,
              struct perf_event_context *child_ctx)
 {
+       enum perf_event_active_state parent_state = parent_event->state;
        struct perf_event *child_event;
        unsigned long flags;
 
@@ -7715,7 +7844,8 @@ inherit_event(struct perf_event *parent_event,
        if (IS_ERR(child_event))
                return child_event;
 
-       if (!atomic_long_inc_not_zero(&parent_event->refcount)) {
+       if (is_orphaned_event(parent_event) ||
+           !atomic_long_inc_not_zero(&parent_event->refcount)) {
                free_event(child_event);
                return NULL;
        }
@@ -7727,7 +7857,7 @@ inherit_event(struct perf_event *parent_event,
         * not its attr.disabled bit.  We hold the parent's mutex,
         * so we won't race with perf_event_{en, dis}able_family.
         */
-       if (parent_event->state >= PERF_EVENT_STATE_INACTIVE)
+       if (parent_state >= PERF_EVENT_STATE_INACTIVE)
                child_event->state = PERF_EVENT_STATE_INACTIVE;
        else
                child_event->state = PERF_EVENT_STATE_OFF;
index ce00f7ee6455248d92dba7016b2770c824e897f9..36c08b1f4afbc9379007c3b49e79fb5f87a3f1c9 100644 (file)
@@ -10,9 +10,14 @@ LIB_OBJS=
 
 LIB_H += fs/debugfs.h
 LIB_H += fs/fs.h
+# See comment below about piggybacking...
+LIB_H += fd/array.h
 
 LIB_OBJS += $(OUTPUT)fs/debugfs.o
 LIB_OBJS += $(OUTPUT)fs/fs.o
+# XXX piggybacking here, need to introduce libapikfd, or rename this
+# to plain libapik.a and make it have it all api goodies
+LIB_OBJS += $(OUTPUT)fd/array.o
 
 LIBFILE = libapikfs.a
 
@@ -29,7 +34,7 @@ $(LIBFILE): $(LIB_OBJS)
 $(LIB_OBJS): $(LIB_H)
 
 libapi_dirs:
-       $(QUIET_MKDIR)mkdir -p $(OUTPUT)fs/
+       $(QUIET_MKDIR)mkdir -p $(OUTPUT)fd $(OUTPUT)fs
 
 $(OUTPUT)%.o: %.c libapi_dirs
        $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $<
diff --git a/tools/lib/api/fd/array.c b/tools/lib/api/fd/array.c
new file mode 100644 (file)
index 0000000..0e636c4
--- /dev/null
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2014, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com>
+ *
+ * Released under the GPL v2. (and only v2, not any later version)
+ */
+#include "array.h"
+#include <errno.h>
+#include <fcntl.h>
+#include <poll.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+void fdarray__init(struct fdarray *fda, int nr_autogrow)
+{
+       fda->entries     = NULL;
+       fda->priv        = NULL;
+       fda->nr          = fda->nr_alloc = 0;
+       fda->nr_autogrow = nr_autogrow;
+}
+
+int fdarray__grow(struct fdarray *fda, int nr)
+{
+       void *priv;
+       int nr_alloc = fda->nr_alloc + nr;
+       size_t psize = sizeof(fda->priv[0]) * nr_alloc;
+       size_t size  = sizeof(struct pollfd) * nr_alloc;
+       struct pollfd *entries = realloc(fda->entries, size);
+
+       if (entries == NULL)
+               return -ENOMEM;
+
+       priv = realloc(fda->priv, psize);
+       if (priv == NULL) {
+               free(entries);
+               return -ENOMEM;
+       }
+
+       fda->nr_alloc = nr_alloc;
+       fda->entries  = entries;
+       fda->priv     = priv;
+       return 0;
+}
+
+struct fdarray *fdarray__new(int nr_alloc, int nr_autogrow)
+{
+       struct fdarray *fda = calloc(1, sizeof(*fda));
+
+       if (fda != NULL) {
+               if (fdarray__grow(fda, nr_alloc)) {
+                       free(fda);
+                       fda = NULL;
+               } else {
+                       fda->nr_autogrow = nr_autogrow;
+               }
+       }
+
+       return fda;
+}
+
+void fdarray__exit(struct fdarray *fda)
+{
+       free(fda->entries);
+       free(fda->priv);
+       fdarray__init(fda, 0);
+}
+
+void fdarray__delete(struct fdarray *fda)
+{
+       fdarray__exit(fda);
+       free(fda);
+}
+
+int fdarray__add(struct fdarray *fda, int fd, short revents)
+{
+       int pos = fda->nr;
+
+       if (fda->nr == fda->nr_alloc &&
+           fdarray__grow(fda, fda->nr_autogrow) < 0)
+               return -ENOMEM;
+
+       fda->entries[fda->nr].fd     = fd;
+       fda->entries[fda->nr].events = revents;
+       fda->nr++;
+       return pos;
+}
+
+int fdarray__filter(struct fdarray *fda, short revents,
+                   void (*entry_destructor)(struct fdarray *fda, int fd))
+{
+       int fd, nr = 0;
+
+       if (fda->nr == 0)
+               return 0;
+
+       for (fd = 0; fd < fda->nr; ++fd) {
+               if (fda->entries[fd].revents & revents) {
+                       if (entry_destructor)
+                               entry_destructor(fda, fd);
+
+                       continue;
+               }
+
+               if (fd != nr) {
+                       fda->entries[nr] = fda->entries[fd];
+                       fda->priv[nr]    = fda->priv[fd];
+               }
+
+               ++nr;
+       }
+
+       return fda->nr = nr;
+}
+
+int fdarray__poll(struct fdarray *fda, int timeout)
+{
+       return poll(fda->entries, fda->nr, timeout);
+}
+
+int fdarray__fprintf(struct fdarray *fda, FILE *fp)
+{
+       int fd, printed = fprintf(fp, "%d [ ", fda->nr);
+
+       for (fd = 0; fd < fda->nr; ++fd)
+               printed += fprintf(fp, "%s%d", fd ? ", " : "", fda->entries[fd].fd);
+
+       return printed + fprintf(fp, " ]");
+}
diff --git a/tools/lib/api/fd/array.h b/tools/lib/api/fd/array.h
new file mode 100644 (file)
index 0000000..45db018
--- /dev/null
@@ -0,0 +1,46 @@
+#ifndef __API_FD_ARRAY__
+#define __API_FD_ARRAY__
+
+#include <stdio.h>
+
+struct pollfd;
+
+/**
+ * struct fdarray: Array of file descriptors
+ *
+ * @priv: Per array entry priv area, users should access just its contents,
+ *       not set it to anything, as it is kept in synch with @entries, being
+ *       realloc'ed, * for instance, in fdarray__{grow,filter}.
+ *
+ *       I.e. using 'fda->priv[N].idx = * value' where N < fda->nr is ok,
+ *       but doing 'fda->priv = malloc(M)' is not allowed.
+ */
+struct fdarray {
+       int            nr;
+       int            nr_alloc;
+       int            nr_autogrow;
+       struct pollfd *entries;
+       union {
+               int    idx;
+       } *priv;
+};
+
+void fdarray__init(struct fdarray *fda, int nr_autogrow);
+void fdarray__exit(struct fdarray *fda);
+
+struct fdarray *fdarray__new(int nr_alloc, int nr_autogrow);
+void fdarray__delete(struct fdarray *fda);
+
+int fdarray__add(struct fdarray *fda, int fd, short revents);
+int fdarray__poll(struct fdarray *fda, int timeout);
+int fdarray__filter(struct fdarray *fda, short revents,
+                   void (*entry_destructor)(struct fdarray *fda, int fd));
+int fdarray__grow(struct fdarray *fda, int extra);
+int fdarray__fprintf(struct fdarray *fda, FILE *fp);
+
+static inline int fdarray__available_entries(struct fdarray *fda)
+{
+       return fda->nr_alloc - fda->nr;
+}
+
+#endif /* __API_FD_ARRAY__ */
index 782d86e961b9fb79195407e7634bceae9d55f279..717221e98450a37ffb0eb726e0ffd2773af300ff 100644 (file)
@@ -15,6 +15,7 @@ perf.data
 perf.data.old
 output.svg
 perf-archive
+perf-with-kcore
 tags
 TAGS
 cscope*
index 1513935c399b67c6e2158b9041af548edf3e610c..aaa869be3dc1d48ac5573163d752d08b9152a295 100644 (file)
@@ -104,6 +104,9 @@ OPTIONS
        Specify path to the executable or shared library file for user
        space tracing. Can also be used with --funcs option.
 
+--demangle-kernel::
+       Demangle kernel symbols.
+
 In absence of -m/-x options, perf probe checks if the first argument after
 the options is an absolute path name. If its an absolute path, perf probe
 uses it as a target module/target user space binary to probe.
index d2b59af62bc0ad6ddff918f2aee04a67fbf5541f..0927bf4e6c2a6c78b30cc185bf0c4637b2c5082e 100644 (file)
@@ -147,7 +147,7 @@ OPTIONS
 -w::
 --column-widths=<width[,width...]>::
        Force each column width to the provided list, for large terminal
-       readability.
+       readability.  0 means no limit (default behavior).
 
 -t::
 --field-separator=::
@@ -276,6 +276,9 @@ OPTIONS
        Demangle symbol names to human readable form. It's enabled by default,
        disable with --no-demangle.
 
+--demangle-kernel::
+       Demangle kernel symbol names to human readable form (for C++ kernels).
+
 --mem-mode::
        Use the data addresses of samples in addition to instruction addresses
        to build the histograms.  To generate meaningful output, the perf.data
index 180ae02137a519acf1b3d779a92eb651db6b4aff..3265b10705188027ab30256f7475d218d78f6fbb 100644 (file)
@@ -98,6 +98,9 @@ Default is to monitor all CPUS.
 --hide_user_symbols::
         Hide user symbols.
 
+--demangle-kernel::
+        Demangle kernel symbols.
+
 -D::
 --dump-symtab::
         Dump the symbol table used for profiling.
@@ -193,6 +196,12 @@ Default is to monitor all CPUS.
        sum of shown entries will be always 100%. "absolute" means it retains
        the original value before and after the filter is applied.
 
+-w::
+--column-widths=<width[,width...]>::
+       Force each column width to the provided list, for large terminal
+       readability.  0 means no limit (default behavior).
+
+
 INTERACTIVE PROMPTING KEYS
 --------------------------
 
index 2240974b7745874f3e2e39c3ee9f98d18c8c7912..262916f4a37758447ec0ece4aa17a956c332dd84 100644 (file)
@@ -126,6 +126,7 @@ PYRF_OBJS =
 SCRIPT_SH =
 
 SCRIPT_SH += perf-archive.sh
+SCRIPT_SH += perf-with-kcore.sh
 
 grep-libs = $(filter -l%,$(1))
 strip-libs = $(filter-out -l%,$(1))
@@ -263,6 +264,7 @@ LIB_H += util/xyarray.h
 LIB_H += util/header.h
 LIB_H += util/help.h
 LIB_H += util/session.h
+LIB_H += util/ordered-events.h
 LIB_H += util/strbuf.h
 LIB_H += util/strlist.h
 LIB_H += util/strfilter.h
@@ -347,6 +349,7 @@ LIB_OBJS += $(OUTPUT)util/machine.o
 LIB_OBJS += $(OUTPUT)util/map.o
 LIB_OBJS += $(OUTPUT)util/pstack.o
 LIB_OBJS += $(OUTPUT)util/session.o
+LIB_OBJS += $(OUTPUT)util/ordered-events.o
 LIB_OBJS += $(OUTPUT)util/comm.o
 LIB_OBJS += $(OUTPUT)util/thread.o
 LIB_OBJS += $(OUTPUT)util/thread_map.o
@@ -399,6 +402,7 @@ LIB_OBJS += $(OUTPUT)tests/perf-record.o
 LIB_OBJS += $(OUTPUT)tests/rdpmc.o
 LIB_OBJS += $(OUTPUT)tests/evsel-roundtrip-name.o
 LIB_OBJS += $(OUTPUT)tests/evsel-tp-sched.o
+LIB_OBJS += $(OUTPUT)tests/fdarray.o
 LIB_OBJS += $(OUTPUT)tests/pmu.o
 LIB_OBJS += $(OUTPUT)tests/hists_common.o
 LIB_OBJS += $(OUTPUT)tests/hists_link.o
@@ -423,6 +427,7 @@ endif
 endif
 LIB_OBJS += $(OUTPUT)tests/mmap-thread-lookup.o
 LIB_OBJS += $(OUTPUT)tests/thread-mg-share.o
+LIB_OBJS += $(OUTPUT)tests/switch-tracking.o
 
 BUILTIN_OBJS += $(OUTPUT)builtin-annotate.o
 BUILTIN_OBJS += $(OUTPUT)builtin-bench.o
@@ -765,7 +770,7 @@ $(LIBTRACEEVENT)-clean:
 install-traceevent-plugins: $(LIBTRACEEVENT)
        $(QUIET_SUBDIR0)$(TRACE_EVENT_DIR) $(LIBTRACEEVENT_FLAGS) install_plugins
 
-LIBAPIKFS_SOURCES = $(wildcard $(LIB_PATH)fs/*.[ch])
+LIBAPIKFS_SOURCES = $(wildcard $(LIB_PATH)fs/*.[ch] $(LIB_PATH)fd/*.[ch])
 
 # if subdir is set, we've been called from above so target has been built
 # already
@@ -875,6 +880,8 @@ install-bin: all install-gtk
                $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)'
        $(call QUIET_INSTALL, perf-archive) \
                $(INSTALL) $(OUTPUT)perf-archive -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)'
+       $(call QUIET_INSTALL, perf-with-kcore) \
+               $(INSTALL) $(OUTPUT)perf-with-kcore -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)'
 ifndef NO_LIBPERL
        $(call QUIET_INSTALL, perl-scripts) \
                $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/Perf-Trace-Util/lib/Perf/Trace'; \
@@ -920,7 +927,7 @@ config-clean:
        @$(MAKE) -C config/feature-checks clean >/dev/null
 
 clean: $(LIBTRACEEVENT)-clean $(LIBAPIKFS)-clean config-clean
-       $(call QUIET_CLEAN, core-objs)  $(RM) $(LIB_OBJS) $(BUILTIN_OBJS) $(LIB_FILE) $(OUTPUT)perf-archive $(OUTPUT)perf.o $(LANG_BINDINGS) $(GTK_OBJS)
+       $(call QUIET_CLEAN, core-objs)  $(RM) $(LIB_OBJS) $(BUILTIN_OBJS) $(LIB_FILE) $(OUTPUT)perf-archive $(OUTPUT)perf-with-kcore $(OUTPUT)perf.o $(LANG_BINDINGS) $(GTK_OBJS)
        $(call QUIET_CLEAN, core-progs) $(RM) $(ALL_PROGRAMS) perf
        $(call QUIET_CLEAN, core-gen)   $(RM)  *.spec *.pyc *.pyo */*.pyc */*.pyo $(OUTPUT)common-cmds.h TAGS tags cscope* $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)PERF-CFLAGS $(OUTPUT)PERF-FEATURES $(OUTPUT)util/*-bison* $(OUTPUT)util/*-flex*
        $(QUIET_SUBDIR0)Documentation $(QUIET_SUBDIR1) clean
index 9f870d27cb39575b04763c050a5184025301653d..62eff847f91c4edc4754fb08a110f7b88b9c0411 100644 (file)
@@ -3,6 +3,7 @@
 #include "thread.h"
 #include "map.h"
 #include "event.h"
+#include "debug.h"
 #include "tests/tests.h"
 
 #define STACK_SIZE 8192
index 729ed69a66649cad6cecea5693c191cc91fc4e16..62c397ed3d97868bb979d32815f066dd6e1cb2b5 100644 (file)
@@ -3,6 +3,7 @@
 #include <libunwind.h>
 #include "perf_regs.h"
 #include "../../util/unwind.h"
+#include "../../util/debug.h"
 
 int libunwind__arch_reg_id(int regnum)
 {
index e9441b9e2a302a686e0db2cb03f0f30690f5c2ff..1d3f39c3aa564fd2e85a950fddcb4bba18f5e8db 100644 (file)
@@ -6,6 +6,8 @@
 #include <asm/perf_regs.h>
 
 #define PERF_REGS_MASK ((1ULL << PERF_REG_ARM64_MAX) - 1)
+#define PERF_REGS_MAX  PERF_REG_ARM64_MAX
+
 #define PERF_REG_IP    PERF_REG_ARM64_PC
 #define PERF_REG_SP    PERF_REG_ARM64_SP
 
index 436ee43859dc6d9929128e61ff3eb9f4088b59f5..a87afa91a99ebf31df4839872606b99d7137c486 100644 (file)
@@ -3,6 +3,7 @@
 #include <libunwind.h>
 #include "perf_regs.h"
 #include "../../util/unwind.h"
+#include "../../util/debug.h"
 
 int libunwind__arch_reg_id(int regnum)
 {
index 42faf369211c853f21f87cd037df5e9f4683b4f7..49776f190abfab295920534840aa1df479a4c094 100644 (file)
@@ -12,6 +12,11 @@ const char *const arm_triplets[] = {
        NULL
 };
 
+const char *const arm64_triplets[] = {
+       "aarch64-linux-android-",
+       NULL
+};
+
 const char *const powerpc_triplets[] = {
        "powerpc-unknown-linux-gnu-",
        "powerpc64-unknown-linux-gnu-",
@@ -105,6 +110,8 @@ static const char *normalize_arch(char *arch)
                return "x86";
        if (!strcmp(arch, "sun4u") || !strncmp(arch, "sparc", 5))
                return "sparc";
+       if (!strcmp(arch, "aarch64") || !strcmp(arch, "arm64"))
+               return "arm64";
        if (!strncmp(arch, "arm", 3) || !strcmp(arch, "sa110"))
                return "arm";
        if (!strncmp(arch, "s390", 4))
@@ -159,6 +166,8 @@ static int perf_session_env__lookup_binutils_path(struct perf_session_env *env,
 
        if (!strcmp(arch, "arm"))
                path_list = arm_triplets;
+       else if (!strcmp(arch, "arm64"))
+               path_list = arm64_triplets;
        else if (!strcmp(arch, "powerpc"))
                path_list = powerpc_triplets;
        else if (!strcmp(arch, "sh"))
index b92219b1900d7b8ca03be6d10d3b439bc1752931..6f7782bea5dd848c9e31985fb159b0eea11ca9ba 100644 (file)
@@ -1,6 +1,6 @@
 ifndef NO_DWARF
 PERF_HAVE_DWARF_REGS := 1
 LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/dwarf-regs.o
+LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/skip-callchain-idx.o
 endif
 LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/header.o
-LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/skip-callchain-idx.o
index a7c23a4b377802be92b1aafb9b46e91c27e453d2..d73ef8bb08c76a63c8846d4bdf49114c0558908a 100644 (file)
@@ -15,6 +15,7 @@
 
 #include "util/thread.h"
 #include "util/callchain.h"
+#include "util/debug.h"
 
 /*
  * When saving the callchain on Power, the kernel conservatively saves
index a84206e9c4aa09b97bb2dddc5c00a598234abd2c..fc9bebd2cca0575734f84f9947bf29f7f991c6ab 100644 (file)
@@ -26,6 +26,7 @@ static unsigned int nsecs    = 10;
 /* amount of futexes per thread */
 static unsigned int nfutexes = 1024;
 static bool fshared = false, done = false, silent = false;
+static int futex_flag = 0;
 
 struct timeval start, end, runtime;
 static pthread_mutex_t thread_lock;
@@ -75,8 +76,7 @@ static void *workerfn(void *arg)
                         * such as internal waitqueue handling, thus enlarging
                         * the critical region protected by hb->lock.
                         */
-                       ret = futex_wait(&w->futex[i], 1234, NULL,
-                                        fshared ? 0 : FUTEX_PRIVATE_FLAG);
+                       ret = futex_wait(&w->futex[i], 1234, NULL, futex_flag);
                        if (!silent &&
                            (!ret || errno != EAGAIN || errno != EWOULDBLOCK))
                                warn("Non-expected futex return call");
@@ -135,6 +135,9 @@ int bench_futex_hash(int argc, const char **argv,
        if (!worker)
                goto errmem;
 
+       if (!fshared)
+               futex_flag = FUTEX_PRIVATE_FLAG;
+
        printf("Run summary [PID %d]: %d threads, each operating on %d [%s] futexes for %d secs.\n\n",
               getpid(), nthreads, nfutexes, fshared ? "shared":"private", nsecs);
 
index 732403bfd31a9391e50719c182577047a8eb508b..bedff6b5b3cf3a61b38b172a97504cafebfd519f 100644 (file)
@@ -30,16 +30,18 @@ static u_int32_t futex1 = 0, futex2 = 0;
 static unsigned int nrequeue = 1;
 
 static pthread_t *worker;
-static bool done = 0, silent = 0;
+static bool done = false, silent = false, fshared = false;
 static pthread_mutex_t thread_lock;
 static pthread_cond_t thread_parent, thread_worker;
 static struct stats requeuetime_stats, requeued_stats;
 static unsigned int ncpus, threads_starting, nthreads = 0;
+static int futex_flag = 0;
 
 static const struct option options[] = {
        OPT_UINTEGER('t', "threads",  &nthreads, "Specify amount of threads"),
        OPT_UINTEGER('q', "nrequeue", &nrequeue, "Specify amount of threads to requeue at once"),
        OPT_BOOLEAN( 's', "silent",   &silent,   "Silent mode: do not display data/details"),
+       OPT_BOOLEAN( 'S', "shared",   &fshared,  "Use shared futexes instead of private ones"),
        OPT_END()
 };
 
@@ -70,7 +72,7 @@ static void *workerfn(void *arg __maybe_unused)
        pthread_cond_wait(&thread_worker, &thread_lock);
        pthread_mutex_unlock(&thread_lock);
 
-       futex_wait(&futex1, 0, NULL, FUTEX_PRIVATE_FLAG);
+       futex_wait(&futex1, 0, NULL, futex_flag);
        return NULL;
 }
 
@@ -127,9 +129,12 @@ int bench_futex_requeue(int argc, const char **argv,
        if (!worker)
                err(EXIT_FAILURE, "calloc");
 
-       printf("Run summary [PID %d]: Requeuing %d threads (from %p to %p), "
-              "%d at a time.\n\n",
-              getpid(), nthreads, &futex1, &futex2, nrequeue);
+       if (!fshared)
+               futex_flag = FUTEX_PRIVATE_FLAG;
+
+       printf("Run summary [PID %d]: Requeuing %d threads (from [%s] %p to %p), "
+              "%d at a time.\n\n",  getpid(), nthreads,
+              fshared ? "shared":"private", &futex1, &futex2, nrequeue);
 
        init_stats(&requeued_stats);
        init_stats(&requeuetime_stats);
@@ -156,16 +161,20 @@ int bench_futex_requeue(int argc, const char **argv,
 
                /* Ok, all threads are patiently blocked, start requeueing */
                gettimeofday(&start, NULL);
-               for (nrequeued = 0; nrequeued < nthreads; nrequeued += nrequeue)
+               for (nrequeued = 0; nrequeued < nthreads; nrequeued += nrequeue) {
                        /*
                         * Do not wakeup any tasks blocked on futex1, allowing
                         * us to really measure futex_wait functionality.
                         */
-                       futex_cmp_requeue(&futex1, 0, &futex2, 0, nrequeue,
-                                         FUTEX_PRIVATE_FLAG);
+                       futex_cmp_requeue(&futex1, 0, &futex2, 0,
+                                         nrequeue, futex_flag);
+               }
                gettimeofday(&end, NULL);
                timersub(&end, &start, &runtime);
 
+               if (nrequeued > nthreads)
+                       nrequeued = nthreads;
+
                update_stats(&requeued_stats, nrequeued);
                update_stats(&requeuetime_stats, runtime.tv_usec);
 
@@ -175,7 +184,7 @@ int bench_futex_requeue(int argc, const char **argv,
                }
 
                /* everybody should be blocked on futex2, wake'em up */
-               nrequeued = futex_wake(&futex2, nthreads, FUTEX_PRIVATE_FLAG);
+               nrequeued = futex_wake(&futex2, nthreads, futex_flag);
                if (nthreads != nrequeued)
                        warnx("couldn't wakeup all tasks (%d/%d)", nrequeued, nthreads);
 
@@ -184,7 +193,6 @@ int bench_futex_requeue(int argc, const char **argv,
                        if (ret)
                                err(EXIT_FAILURE, "pthread_join");
                }
-
        }
 
        /* cleanup & report results */
index 50022cbce87e2e124168de5259675dbea300b3b3..929f762be47e9735058f5c57bd394c4f09360c45 100644 (file)
@@ -31,16 +31,18 @@ static u_int32_t futex1 = 0;
 static unsigned int nwakes = 1;
 
 pthread_t *worker;
-static bool done = false, silent = false;
+static bool done = false, silent = false, fshared = false;
 static pthread_mutex_t thread_lock;
 static pthread_cond_t thread_parent, thread_worker;
 static struct stats waketime_stats, wakeup_stats;
 static unsigned int ncpus, threads_starting, nthreads = 0;
+static int futex_flag = 0;
 
 static const struct option options[] = {
        OPT_UINTEGER('t', "threads", &nthreads, "Specify amount of threads"),
        OPT_UINTEGER('w', "nwakes",  &nwakes,   "Specify amount of threads to wake at once"),
        OPT_BOOLEAN( 's', "silent",  &silent,   "Silent mode: do not display data/details"),
+       OPT_BOOLEAN( 'S', "shared",  &fshared,  "Use shared futexes instead of private ones"),
        OPT_END()
 };
 
@@ -58,7 +60,7 @@ static void *workerfn(void *arg __maybe_unused)
        pthread_cond_wait(&thread_worker, &thread_lock);
        pthread_mutex_unlock(&thread_lock);
 
-       futex_wait(&futex1, 0, NULL, FUTEX_PRIVATE_FLAG);
+       futex_wait(&futex1, 0, NULL, futex_flag);
        return NULL;
 }
 
@@ -130,9 +132,12 @@ int bench_futex_wake(int argc, const char **argv,
        if (!worker)
                err(EXIT_FAILURE, "calloc");
 
-       printf("Run summary [PID %d]: blocking on %d threads (at futex %p), "
+       if (!fshared)
+               futex_flag = FUTEX_PRIVATE_FLAG;
+
+       printf("Run summary [PID %d]: blocking on %d threads (at [%s] futex %p), "
               "waking up %d at a time.\n\n",
-              getpid(), nthreads, &futex1, nwakes);
+              getpid(), nthreads, fshared ? "shared":"private",  &futex1, nwakes);
 
        init_stats(&wakeup_stats);
        init_stats(&waketime_stats);
@@ -160,7 +165,7 @@ int bench_futex_wake(int argc, const char **argv,
                /* Ok, all threads are patiently blocked, start waking folks up */
                gettimeofday(&start, NULL);
                while (nwoken != nthreads)
-                       nwoken += futex_wake(&futex1, nwakes, FUTEX_PRIVATE_FLAG);
+                       nwoken += futex_wake(&futex1, nwakes, futex_flag);
                gettimeofday(&end, NULL);
                timersub(&end, &start, &runtime);
 
index 52a56599a543a1ddf9ec7653550e47571f64265e..d7f281c2828d97e35bb1f007f2f792666e89b78b 100644 (file)
@@ -26,7 +26,7 @@
 #include <sys/socket.h>
 #include <sys/wait.h>
 #include <sys/time.h>
-#include <sys/poll.h>
+#include <poll.h>
 #include <limits.h>
 #include <err.h>
 
index 1ec429fef2be9354d79400efe074e707229bef2f..be59394184252c88861edb353bd2be7be469f6c1 100644 (file)
@@ -36,7 +36,8 @@
 
 struct perf_annotate {
        struct perf_tool tool;
-       bool       force, use_tui, use_stdio, use_gtk;
+       struct perf_session *session;
+       bool       use_tui, use_stdio, use_gtk;
        bool       full_paths;
        bool       print_line;
        bool       skip_missing;
@@ -188,18 +189,9 @@ find_next:
 static int __cmd_annotate(struct perf_annotate *ann)
 {
        int ret;
-       struct perf_session *session;
+       struct perf_session *session = ann->session;
        struct perf_evsel *pos;
        u64 total_nr_samples;
-       struct perf_data_file file = {
-               .path  = input_name,
-               .mode  = PERF_DATA_MODE_READ,
-               .force = ann->force,
-       };
-
-       session = perf_session__new(&file, false, &ann->tool);
-       if (session == NULL)
-               return -ENOMEM;
 
        machines__set_symbol_filter(&session->machines, symbol__annotate_init);
 
@@ -207,22 +199,22 @@ static int __cmd_annotate(struct perf_annotate *ann)
                ret = perf_session__cpu_bitmap(session, ann->cpu_list,
                                               ann->cpu_bitmap);
                if (ret)
-                       goto out_delete;
+                       goto out;
        }
 
        if (!objdump_path) {
                ret = perf_session_env__lookup_objdump(&session->header.env);
                if (ret)
-                       goto out_delete;
+                       goto out;
        }
 
        ret = perf_session__process_events(session, &ann->tool);
        if (ret)
-               goto out_delete;
+               goto out;
 
        if (dump_trace) {
                perf_session__fprintf_nr_events(session, stdout);
-               goto out_delete;
+               goto out;
        }
 
        if (verbose > 3)
@@ -250,8 +242,8 @@ static int __cmd_annotate(struct perf_annotate *ann)
        }
 
        if (total_nr_samples == 0) {
-               ui__error("The %s file has no samples!\n", file.path);
-               goto out_delete;
+               ui__error("The %s file has no samples!\n", session->file->path);
+               goto out;
        }
 
        if (use_browser == 2) {
@@ -261,24 +253,12 @@ static int __cmd_annotate(struct perf_annotate *ann)
                                         "perf_gtk__show_annotations");
                if (show_annotations == NULL) {
                        ui__error("GTK browser not found!\n");
-                       goto out_delete;
+                       goto out;
                }
                show_annotations();
        }
 
-out_delete:
-       /*
-        * Speed up the exit process, for large files this can
-        * take quite a while.
-        *
-        * XXX Enable this when using valgrind or if we ever
-        * librarize this command.
-        *
-        * Also experiment with obstacks to see how much speed
-        * up we'll get here.
-        *
-        * perf_session__delete(session);
-        */
+out:
        return ret;
 }
 
@@ -297,10 +277,14 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __maybe_unused)
                        .comm   = perf_event__process_comm,
                        .exit   = perf_event__process_exit,
                        .fork   = perf_event__process_fork,
-                       .ordered_samples = true,
+                       .ordered_events = true,
                        .ordering_requires_timestamps = true,
                },
        };
+       struct perf_data_file file = {
+               .path  = input_name,
+               .mode  = PERF_DATA_MODE_READ,
+       };
        const struct option options[] = {
        OPT_STRING('i', "input", &input_name, "file",
                    "input file name"),
@@ -308,7 +292,7 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __maybe_unused)
                   "only consider symbols in these dsos"),
        OPT_STRING('s', "symbol", &annotate.sym_hist_filter, "symbol",
                    "symbol to annotate"),
-       OPT_BOOLEAN('f', "force", &annotate.force, "don't complain, do it"),
+       OPT_BOOLEAN('f', "force", &file.force, "don't complain, do it"),
        OPT_INCR('v', "verbose", &verbose,
                    "be more verbose (show symbol address, etc)"),
        OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
@@ -341,6 +325,7 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __maybe_unused)
                    "Show event group information together"),
        OPT_END()
        };
+       int ret;
 
        argc = parse_options(argc, argv, options, annotate_usage, 0);
 
@@ -353,11 +338,16 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __maybe_unused)
 
        setup_browser(true);
 
+       annotate.session = perf_session__new(&file, false, &annotate.tool);
+       if (annotate.session == NULL)
+               return -1;
+
        symbol_conf.priv_size = sizeof(struct annotation);
        symbol_conf.try_vmlinux_path = true;
 
-       if (symbol__init() < 0)
-               return -1;
+       ret = symbol__init(&annotate.session->header.env);
+       if (ret < 0)
+               goto out_delete;
 
        if (setup_sorting() < 0)
                usage_with_options(annotate_usage, options);
@@ -373,5 +363,20 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __maybe_unused)
                annotate.sym_hist_filter = argv[0];
        }
 
-       return __cmd_annotate(&annotate);
+       ret = __cmd_annotate(&annotate);
+
+out_delete:
+       /*
+        * Speed up the exit process, for large files this can
+        * take quite a while.
+        *
+        * XXX Enable this when using valgrind or if we ever
+        * librarize this command.
+        *
+        * Also experiment with obstacks to see how much speed
+        * up we'll get here.
+        *
+        * perf_session__delete(session);
+        */
+       return ret;
 }
index 2a2c78f8087663852292d1220e51a41694ce0f3c..70385756da63f12bcfafe362bc55b1f157e8feae 100644 (file)
@@ -246,20 +246,9 @@ static bool dso__missing_buildid_cache(struct dso *dso, int parm __maybe_unused)
        return true;
 }
 
-static int build_id_cache__fprintf_missing(const char *filename, bool force, FILE *fp)
+static int build_id_cache__fprintf_missing(struct perf_session *session, FILE *fp)
 {
-       struct perf_data_file file = {
-               .path  = filename,
-               .mode  = PERF_DATA_MODE_READ,
-               .force = force,
-       };
-       struct perf_session *session = perf_session__new(&file, false, NULL);
-       if (session == NULL)
-               return -1;
-
        perf_session__fprintf_dsos_buildid(session, fp, dso__missing_buildid_cache, 0);
-       perf_session__delete(session);
-
        return 0;
 }
 
@@ -302,6 +291,12 @@ int cmd_buildid_cache(int argc, const char **argv,
                   *missing_filename = NULL,
                   *update_name_list_str = NULL,
                   *kcore_filename;
+       char sbuf[STRERR_BUFSIZE];
+
+       struct perf_data_file file = {
+               .mode  = PERF_DATA_MODE_READ,
+       };
+       struct perf_session *session = NULL;
 
        const struct option buildid_cache_options[] = {
        OPT_STRING('a', "add", &add_name_list_str,
@@ -326,8 +321,17 @@ int cmd_buildid_cache(int argc, const char **argv,
        argc = parse_options(argc, argv, buildid_cache_options,
                             buildid_cache_usage, 0);
 
-       if (symbol__init() < 0)
-               return -1;
+       if (missing_filename) {
+               file.path = missing_filename;
+               file.force = force;
+
+               session = perf_session__new(&file, false, NULL);
+               if (session == NULL)
+                       return -1;
+       }
+
+       if (symbol__init(session ? &session->header.env : NULL) < 0)
+               goto out;
 
        setup_pager();
 
@@ -344,7 +348,7 @@ int cmd_buildid_cache(int argc, const char **argv,
                                                continue;
                                        }
                                        pr_warning("Couldn't add %s: %s\n",
-                                                  pos->s, strerror(errno));
+                                                  pos->s, strerror_r(errno, sbuf, sizeof(sbuf)));
                                }
 
                        strlist__delete(list);
@@ -362,7 +366,7 @@ int cmd_buildid_cache(int argc, const char **argv,
                                                continue;
                                        }
                                        pr_warning("Couldn't remove %s: %s\n",
-                                                  pos->s, strerror(errno));
+                                                  pos->s, strerror_r(errno, sbuf, sizeof(sbuf)));
                                }
 
                        strlist__delete(list);
@@ -370,7 +374,7 @@ int cmd_buildid_cache(int argc, const char **argv,
        }
 
        if (missing_filename)
-               ret = build_id_cache__fprintf_missing(missing_filename, force, stdout);
+               ret = build_id_cache__fprintf_missing(session, stdout);
 
        if (update_name_list_str) {
                list = strlist__new(true, update_name_list_str);
@@ -383,7 +387,7 @@ int cmd_buildid_cache(int argc, const char **argv,
                                                continue;
                                        }
                                        pr_warning("Couldn't update %s: %s\n",
-                                                  pos->s, strerror(errno));
+                                                  pos->s, strerror_r(errno, sbuf, sizeof(sbuf)));
                                }
 
                        strlist__delete(list);
@@ -394,5 +398,9 @@ int cmd_buildid_cache(int argc, const char **argv,
            build_id_cache__add_kcore(kcore_filename, debugdir, force))
                pr_warning("Couldn't add %s\n", kcore_filename);
 
+out:
+       if (session)
+               perf_session__delete(session);
+
        return ret;
 }
index 9a5a035cb4262afcf1e74986276df8763f1036b9..a3ce19f7aebdd6f63e440b88ab9d168338ed509f 100644 (file)
@@ -360,7 +360,7 @@ static struct perf_tool tool = {
        .exit   = perf_event__process_exit,
        .fork   = perf_event__process_fork,
        .lost   = perf_event__process_lost,
-       .ordered_samples = true,
+       .ordered_events = true,
        .ordering_requires_timestamps = true,
 };
 
@@ -683,7 +683,7 @@ static int __cmd_diff(void)
                d->session = perf_session__new(&d->file, false, &tool);
                if (!d->session) {
                        pr_err("Failed to open %s\n", d->file.path);
-                       ret = -ENOMEM;
+                       ret = -1;
                        goto out_delete;
                }
 
@@ -1143,7 +1143,7 @@ int cmd_diff(int argc, const char **argv, const char *prefix __maybe_unused)
 
        argc = parse_options(argc, argv, options, diff_usage, 0);
 
-       if (symbol__init() < 0)
+       if (symbol__init(NULL) < 0)
                return -1;
 
        if (data_init(argc, argv) < 0)
index 66e12f55c052869e32864ad52e19dda226d918c3..0f93f859b782ba1701b1457cb3f90c9d1ecf5995 100644 (file)
@@ -28,7 +28,7 @@ static int __cmd_evlist(const char *file_name, struct perf_attr_details *details
 
        session = perf_session__new(&file, 0, NULL);
        if (session == NULL)
-               return -ENOMEM;
+               return -1;
 
        evlist__for_each(session->evlist, pos)
                perf_evsel__fprintf(pos, details, stdout);
index 0384d930480b47b29adbb86d93ae7c48e15f3741..25d20628212ed4691ad8ca3cc3c432e5dbffcd13 100644 (file)
@@ -103,6 +103,8 @@ static int check_emacsclient_version(void)
 
 static void exec_woman_emacs(const char *path, const char *page)
 {
+       char sbuf[STRERR_BUFSIZE];
+
        if (!check_emacsclient_version()) {
                /* This works only with emacsclient version >= 22. */
                struct strbuf man_page = STRBUF_INIT;
@@ -111,16 +113,19 @@ static void exec_woman_emacs(const char *path, const char *page)
                        path = "emacsclient";
                strbuf_addf(&man_page, "(woman \"%s\")", page);
                execlp(path, "emacsclient", "-e", man_page.buf, NULL);
-               warning("failed to exec '%s': %s", path, strerror(errno));
+               warning("failed to exec '%s': %s", path,
+                       strerror_r(errno, sbuf, sizeof(sbuf)));
        }
 }
 
 static void exec_man_konqueror(const char *path, const char *page)
 {
        const char *display = getenv("DISPLAY");
+
        if (display && *display) {
                struct strbuf man_page = STRBUF_INIT;
                const char *filename = "kfmclient";
+               char sbuf[STRERR_BUFSIZE];
 
                /* It's simpler to launch konqueror using kfmclient. */
                if (path) {
@@ -139,24 +144,31 @@ static void exec_man_konqueror(const char *path, const char *page)
                        path = "kfmclient";
                strbuf_addf(&man_page, "man:%s(1)", page);
                execlp(path, filename, "newTab", man_page.buf, NULL);
-               warning("failed to exec '%s': %s", path, strerror(errno));
+               warning("failed to exec '%s': %s", path,
+                       strerror_r(errno, sbuf, sizeof(sbuf)));
        }
 }
 
 static void exec_man_man(const char *path, const char *page)
 {
+       char sbuf[STRERR_BUFSIZE];
+
        if (!path)
                path = "man";
        execlp(path, "man", page, NULL);
-       warning("failed to exec '%s': %s", path, strerror(errno));
+       warning("failed to exec '%s': %s", path,
+               strerror_r(errno, sbuf, sizeof(sbuf)));
 }
 
 static void exec_man_cmd(const char *cmd, const char *page)
 {
        struct strbuf shell_cmd = STRBUF_INIT;
+       char sbuf[STRERR_BUFSIZE];
+
        strbuf_addf(&shell_cmd, "%s %s", cmd, page);
        execl("/bin/sh", "sh", "-c", shell_cmd.buf, NULL);
-       warning("failed to exec '%s': %s", cmd, strerror(errno));
+       warning("failed to exec '%s': %s", cmd,
+               strerror_r(errno, sbuf, sizeof(sbuf)));
 }
 
 static void add_man_viewer(const char *name)
index 9a02807387d6c25b9c41236f9404a88da5580a3f..de99ca1bb94268d01c1baebb5757490c367ec912 100644 (file)
@@ -23,6 +23,7 @@
 
 struct perf_inject {
        struct perf_tool        tool;
+       struct perf_session     *session;
        bool                    build_ids;
        bool                    sched_stat;
        const char              *input_name;
@@ -340,12 +341,8 @@ static int perf_evsel__check_stype(struct perf_evsel *evsel,
 
 static int __cmd_inject(struct perf_inject *inject)
 {
-       struct perf_session *session;
        int ret = -EINVAL;
-       struct perf_data_file file = {
-               .path = inject->input_name,
-               .mode = PERF_DATA_MODE_READ,
-       };
+       struct perf_session *session = inject->session;
        struct perf_data_file *file_out = &inject->output;
 
        signal(SIGINT, sig_handler);
@@ -357,16 +354,12 @@ static int __cmd_inject(struct perf_inject *inject)
                inject->tool.tracing_data = perf_event__repipe_tracing_data;
        }
 
-       session = perf_session__new(&file, true, &inject->tool);
-       if (session == NULL)
-               return -ENOMEM;
-
        if (inject->build_ids) {
                inject->tool.sample = perf_event__inject_buildid;
        } else if (inject->sched_stat) {
                struct perf_evsel *evsel;
 
-               inject->tool.ordered_samples = true;
+               inject->tool.ordered_events = true;
 
                evlist__for_each(session->evlist, evsel) {
                        const char *name = perf_evsel__name(evsel);
@@ -396,8 +389,6 @@ static int __cmd_inject(struct perf_inject *inject)
                perf_session__write_header(session, session->evlist, file_out->fd, true);
        }
 
-       perf_session__delete(session);
-
        return ret;
 }
 
@@ -427,6 +418,11 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused)
                        .mode = PERF_DATA_MODE_WRITE,
                },
        };
+       struct perf_data_file file = {
+               .mode = PERF_DATA_MODE_READ,
+       };
+       int ret;
+
        const struct option options[] = {
                OPT_BOOLEAN('b', "build-ids", &inject.build_ids,
                            "Inject build-ids into the output stream"),
@@ -461,8 +457,17 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused)
                return -1;
        }
 
-       if (symbol__init() < 0)
+       file.path = inject.input_name;
+       inject.session = perf_session__new(&file, true, &inject.tool);
+       if (inject.session == NULL)
+               return -1;
+
+       if (symbol__init(&inject.session->header.env) < 0)
                return -1;
 
-       return __cmd_inject(&inject);
+       ret = __cmd_inject(&inject);
+
+       perf_session__delete(inject.session);
+
+       return ret;
 }
index bef3376bfaf3a6e093a227fddb15e6cbf7ffbd7f..f295141025bcfecdb01c913b94cc3b1ed533d2b4 100644 (file)
@@ -256,7 +256,9 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused,
 static struct perf_tool perf_kmem = {
        .sample          = process_sample_event,
        .comm            = perf_event__process_comm,
-       .ordered_samples = true,
+       .mmap            = perf_event__process_mmap,
+       .mmap2           = perf_event__process_mmap2,
+       .ordered_events  = true,
 };
 
 static double fragmentation(unsigned long n_req, unsigned long n_alloc)
@@ -403,10 +405,9 @@ static void sort_result(void)
        __sort_result(&root_caller_stat, &root_caller_sorted, &caller_sort);
 }
 
-static int __cmd_kmem(void)
+static int __cmd_kmem(struct perf_session *session)
 {
        int err = -EINVAL;
-       struct perf_session *session;
        const struct perf_evsel_str_handler kmem_tracepoints[] = {
                { "kmem:kmalloc",               perf_evsel__process_alloc_event, },
                { "kmem:kmem_cache_alloc",      perf_evsel__process_alloc_event, },
@@ -415,34 +416,22 @@ static int __cmd_kmem(void)
                { "kmem:kfree",                 perf_evsel__process_free_event, },
                { "kmem:kmem_cache_free",       perf_evsel__process_free_event, },
        };
-       struct perf_data_file file = {
-               .path = input_name,
-               .mode = PERF_DATA_MODE_READ,
-       };
-
-       session = perf_session__new(&file, false, &perf_kmem);
-       if (session == NULL)
-               return -ENOMEM;
-
-       if (perf_session__create_kernel_maps(session) < 0)
-               goto out_delete;
 
        if (!perf_session__has_traces(session, "kmem record"))
-               goto out_delete;
+               goto out;
 
        if (perf_session__set_tracepoints_handlers(session, kmem_tracepoints)) {
                pr_err("Initializing perf session tracepoint handlers failed\n");
-               return -1;
+               goto out;
        }
 
        setup_pager();
        err = perf_session__process_events(session, &perf_kmem);
        if (err != 0)
-               goto out_delete;
+               goto out;
        sort_result();
        print_result(session);
-out_delete:
-       perf_session__delete(session);
+out:
        return err;
 }
 
@@ -689,29 +678,46 @@ int cmd_kmem(int argc, const char **argv, const char *prefix __maybe_unused)
                NULL,
                NULL
        };
+       struct perf_session *session;
+       struct perf_data_file file = {
+               .path = input_name,
+               .mode = PERF_DATA_MODE_READ,
+       };
+       int ret = -1;
+
        argc = parse_options_subcommand(argc, argv, kmem_options,
                                        kmem_subcommands, kmem_usage, 0);
 
        if (!argc)
                usage_with_options(kmem_usage, kmem_options);
 
-       symbol__init();
-
        if (!strncmp(argv[0], "rec", 3)) {
+               symbol__init(NULL);
                return __cmd_record(argc, argv);
-       } else if (!strcmp(argv[0], "stat")) {
+       }
+
+       session = perf_session__new(&file, false, &perf_kmem);
+       if (session == NULL)
+               return -1;
+
+       symbol__init(&session->header.env);
+
+       if (!strcmp(argv[0], "stat")) {
                if (cpu__setup_cpunode_map())
-                       return -1;
+                       goto out_delete;
 
                if (list_empty(&caller_sort))
                        setup_sorting(&caller_sort, default_sort_order);
                if (list_empty(&alloc_sort))
                        setup_sorting(&alloc_sort, default_sort_order);
 
-               return __cmd_kmem();
+               ret = __cmd_kmem(session);
        } else
                usage_with_options(kmem_usage, kmem_options);
 
-       return 0;
+out_delete:
+       perf_session__delete(session);
+
+       return ret;
 }
 
index 43367eb005100ae939b8c6d372e5d6d0e6649e34..d8bf2271f4ea7e298811c7aa4759ed7ffda84dbd 100644 (file)
@@ -543,14 +543,12 @@ static void print_vcpu_info(struct perf_kvm_stat *kvm)
 
        pr_info("Analyze events for ");
 
-       if (kvm->live) {
-               if (kvm->opts.target.system_wide)
-                       pr_info("all VMs, ");
-               else if (kvm->opts.target.pid)
-                       pr_info("pid(s) %s, ", kvm->opts.target.pid);
-               else
-                       pr_info("dazed and confused on what is monitored, ");
-       }
+       if (kvm->opts.target.system_wide)
+               pr_info("all VMs, ");
+       else if (kvm->opts.target.pid)
+               pr_info("pid(s) %s, ", kvm->opts.target.pid);
+       else
+               pr_info("dazed and confused on what is monitored, ");
 
        if (vcpu == -1)
                pr_info("all VCPUs:\n\n");
@@ -592,8 +590,8 @@ static void print_result(struct perf_kvm_stat *kvm)
        pr_info("%9s ", "Samples%");
 
        pr_info("%9s ", "Time%");
-       pr_info("%10s ", "Min Time");
-       pr_info("%10s ", "Max Time");
+       pr_info("%11s ", "Min Time");
+       pr_info("%11s ", "Max Time");
        pr_info("%16s ", "Avg time");
        pr_info("\n\n");
 
@@ -610,8 +608,8 @@ static void print_result(struct perf_kvm_stat *kvm)
                pr_info("%10llu ", (unsigned long long)ecount);
                pr_info("%8.2f%% ", (double)ecount / kvm->total_count * 100);
                pr_info("%8.2f%% ", (double)etime / kvm->total_time * 100);
-               pr_info("%8" PRIu64 "us ", min / 1000);
-               pr_info("%8" PRIu64 "us ", max / 1000);
+               pr_info("%9.2fus ", (double)min / 1e3);
+               pr_info("%9.2fus ", (double)max / 1e3);
                pr_info("%9.2fus ( +-%7.2f%% )", (double)etime / ecount/1e3,
                        kvm_event_rel_stddev(vcpu, event));
                pr_info("\n");
@@ -732,7 +730,7 @@ static s64 perf_kvm__mmap_read_idx(struct perf_kvm_stat *kvm, int idx,
                        return -1;
                }
 
-               err = perf_session_queue_event(kvm->session, event, &sample, 0);
+               err = perf_session_queue_event(kvm->session, event, &kvm->tool, &sample, 0);
                /*
                 * FIXME: Here we can't consume the event, as perf_session_queue_event will
                 *        point to it, and it'll get possibly overwritten by the kernel.
@@ -785,7 +783,7 @@ static int perf_kvm__mmap_read(struct perf_kvm_stat *kvm)
 
        /* flush queue after each round in which we processed events */
        if (ntotal) {
-               kvm->session->ordered_samples.next_flush = flush_time;
+               kvm->session->ordered_events.next_flush = flush_time;
                err = kvm->tool.finished_round(&kvm->tool, NULL, kvm->session);
                if (err) {
                        if (kvm->lost_events)
@@ -885,15 +883,11 @@ static int fd_set_nonblock(int fd)
        return 0;
 }
 
-static
-int perf_kvm__handle_stdin(struct termios *tc_now, struct termios *tc_save)
+static int perf_kvm__handle_stdin(void)
 {
        int c;
 
-       tcsetattr(0, TCSANOW, tc_now);
        c = getc(stdin);
-       tcsetattr(0, TCSAFLUSH, tc_save);
-
        if (c == 'q')
                return 1;
 
@@ -904,7 +898,7 @@ static int kvm_events_live_report(struct perf_kvm_stat *kvm)
 {
        struct pollfd *pollfds = NULL;
        int nr_fds, nr_stdin, ret, err = -EINVAL;
-       struct termios tc, save;
+       struct termios save;
 
        /* live flag must be set first */
        kvm->live = true;
@@ -919,26 +913,14 @@ static int kvm_events_live_report(struct perf_kvm_stat *kvm)
                goto out;
        }
 
+       set_term_quiet_input(&save);
        init_kvm_event_record(kvm);
 
-       tcgetattr(0, &save);
-       tc = save;
-       tc.c_lflag &= ~(ICANON | ECHO);
-       tc.c_cc[VMIN] = 0;
-       tc.c_cc[VTIME] = 0;
-
        signal(SIGINT, sig_handler);
        signal(SIGTERM, sig_handler);
 
-       /* copy pollfds -- need to add timerfd and stdin */
-       nr_fds = kvm->evlist->nr_fds;
-       pollfds = zalloc(sizeof(struct pollfd) * (nr_fds + 2));
-       if (!pollfds) {
-               err = -ENOMEM;
-               goto out;
-       }
-       memcpy(pollfds, kvm->evlist->pollfd,
-               sizeof(struct pollfd) * kvm->evlist->nr_fds);
+       /* use pollfds -- need to add timerfd and stdin */
+       nr_fds = kvm->evlist->pollfd.nr;
 
        /* add timer fd */
        if (perf_kvm__timerfd_create(kvm) < 0) {
@@ -946,17 +928,21 @@ static int kvm_events_live_report(struct perf_kvm_stat *kvm)
                goto out;
        }
 
-       pollfds[nr_fds].fd = kvm->timerfd;
-       pollfds[nr_fds].events = POLLIN;
+       if (perf_evlist__add_pollfd(kvm->evlist, kvm->timerfd))
+               goto out;
+
        nr_fds++;
 
-       pollfds[nr_fds].fd = fileno(stdin);
-       pollfds[nr_fds].events = POLLIN;
+       if (perf_evlist__add_pollfd(kvm->evlist, fileno(stdin)))
+               goto out;
+
        nr_stdin = nr_fds;
        nr_fds++;
        if (fd_set_nonblock(fileno(stdin)) != 0)
                goto out;
 
+       pollfds  = kvm->evlist->pollfd.entries;
+
        /* everything is good - enable the events and process */
        perf_evlist__enable(kvm->evlist);
 
@@ -972,7 +958,7 @@ static int kvm_events_live_report(struct perf_kvm_stat *kvm)
                        goto out;
 
                if (pollfds[nr_stdin].revents & POLLIN)
-                       done = perf_kvm__handle_stdin(&tc, &save);
+                       done = perf_kvm__handle_stdin();
 
                if (!rc && !done)
                        err = poll(pollfds, nr_fds, 100);
@@ -989,7 +975,7 @@ out:
        if (kvm->timerfd >= 0)
                close(kvm->timerfd);
 
-       free(pollfds);
+       tcsetattr(0, TCSAFLUSH, &save);
        return err;
 }
 
@@ -998,6 +984,7 @@ static int kvm_live_open_events(struct perf_kvm_stat *kvm)
        int err, rc = -1;
        struct perf_evsel *pos;
        struct perf_evlist *evlist = kvm->evlist;
+       char sbuf[STRERR_BUFSIZE];
 
        perf_evlist__config(evlist, &kvm->opts);
 
@@ -1034,12 +1021,14 @@ static int kvm_live_open_events(struct perf_kvm_stat *kvm)
 
        err = perf_evlist__open(evlist);
        if (err < 0) {
-               printf("Couldn't create the events: %s\n", strerror(errno));
+               printf("Couldn't create the events: %s\n",
+                      strerror_r(errno, sbuf, sizeof(sbuf)));
                goto out;
        }
 
        if (perf_evlist__mmap(evlist, kvm->opts.mmap_pages, false) < 0) {
-               ui__error("Failed to mmap the events: %s\n", strerror(errno));
+               ui__error("Failed to mmap the events: %s\n",
+                         strerror_r(errno, sbuf, sizeof(sbuf)));
                perf_evlist__close(evlist);
                goto out;
        }
@@ -1058,7 +1047,7 @@ static int read_events(struct perf_kvm_stat *kvm)
        struct perf_tool eops = {
                .sample                 = process_sample_event,
                .comm                   = perf_event__process_comm,
-               .ordered_samples        = true,
+               .ordered_events         = true,
        };
        struct perf_data_file file = {
                .path = kvm->file_name,
@@ -1069,9 +1058,11 @@ static int read_events(struct perf_kvm_stat *kvm)
        kvm->session = perf_session__new(&file, false, &kvm->tool);
        if (!kvm->session) {
                pr_err("Initializing perf session failed\n");
-               return -EINVAL;
+               return -1;
        }
 
+       symbol__init(&kvm->session->header.env);
+
        if (!perf_session__has_traces(kvm->session, "kvm record"))
                return -EINVAL;
 
@@ -1088,8 +1079,8 @@ static int read_events(struct perf_kvm_stat *kvm)
 
 static int parse_target_str(struct perf_kvm_stat *kvm)
 {
-       if (kvm->pid_str) {
-               kvm->pid_list = intlist__new(kvm->pid_str);
+       if (kvm->opts.target.pid) {
+               kvm->pid_list = intlist__new(kvm->opts.target.pid);
                if (kvm->pid_list == NULL) {
                        pr_err("Error parsing process id string\n");
                        return -EINVAL;
@@ -1191,7 +1182,7 @@ kvm_events_report(struct perf_kvm_stat *kvm, int argc, const char **argv)
                OPT_STRING('k', "key", &kvm->sort_key, "sort-key",
                            "key for sorting: sample(sort by samples number)"
                            " time (sort by avg time)"),
-               OPT_STRING('p', "pid", &kvm->pid_str, "pid",
+               OPT_STRING('p', "pid", &kvm->opts.target.pid, "pid",
                           "analyze events only for given process id(s)"),
                OPT_END()
        };
@@ -1201,8 +1192,6 @@ kvm_events_report(struct perf_kvm_stat *kvm, int argc, const char **argv)
                NULL
        };
 
-       symbol__init();
-
        if (argc) {
                argc = parse_options(argc, argv,
                                     kvm_events_report_options,
@@ -1212,6 +1201,9 @@ kvm_events_report(struct perf_kvm_stat *kvm, int argc, const char **argv)
                                           kvm_events_report_options);
        }
 
+       if (!kvm->opts.target.pid)
+               kvm->opts.target.system_wide = true;
+
        return kvm_events_report_vcpu(kvm);
 }
 
@@ -1311,7 +1303,7 @@ static int kvm_events_live(struct perf_kvm_stat *kvm,
        kvm->tool.exit   = perf_event__process_exit;
        kvm->tool.fork   = perf_event__process_fork;
        kvm->tool.lost   = process_lost_event;
-       kvm->tool.ordered_samples = true;
+       kvm->tool.ordered_events = true;
        perf_tool__fill_defaults(&kvm->tool);
 
        /* set defaults */
@@ -1322,7 +1314,7 @@ static int kvm_events_live(struct perf_kvm_stat *kvm,
        kvm->opts.target.uid_str = NULL;
        kvm->opts.target.uid = UINT_MAX;
 
-       symbol__init();
+       symbol__init(NULL);
        disable_buildid_cache();
 
        use_browser = 0;
@@ -1369,7 +1361,7 @@ static int kvm_events_live(struct perf_kvm_stat *kvm,
         */
        kvm->session = perf_session__new(&file, false, &kvm->tool);
        if (kvm->session == NULL) {
-               err = -ENOMEM;
+               err = -1;
                goto out;
        }
        kvm->session->evlist = kvm->evlist;
index 6148afc995c68a0bd11b61826a741185a69e4294..e7ec71589da6dbcc06f5a8367466f953cac99c4c 100644 (file)
@@ -852,7 +852,7 @@ static int __cmd_report(bool display_info)
        struct perf_tool eops = {
                .sample          = process_sample_event,
                .comm            = perf_event__process_comm,
-               .ordered_samples = true,
+               .ordered_events  = true,
        };
        struct perf_data_file file = {
                .path = input_name,
@@ -862,9 +862,11 @@ static int __cmd_report(bool display_info)
        session = perf_session__new(&file, false, &eops);
        if (!session) {
                pr_err("Initializing perf session failed\n");
-               return -ENOMEM;
+               return -1;
        }
 
+       symbol__init(&session->header.env);
+
        if (!perf_session__has_traces(session, "lock record"))
                goto out_delete;
 
@@ -974,7 +976,6 @@ int cmd_lock(int argc, const char **argv, const char *prefix __maybe_unused)
        unsigned int i;
        int rc = 0;
 
-       symbol__init();
        for (i = 0; i < LOCKHASH_SIZE; i++)
                INIT_LIST_HEAD(lockhash_table + i);
 
index 4a1a6c94a5ebcb5b7a08bef5034f22419ce07c77..24db6ffe2957450d17a6a6465441317b81f7f49e 100644 (file)
@@ -124,7 +124,7 @@ static int report_raw_events(struct perf_mem *mem)
                                                         &mem->tool);
 
        if (session == NULL)
-               return -ENOMEM;
+               return -1;
 
        if (mem->cpu_list) {
                ret = perf_session__cpu_bitmap(session, mem->cpu_list,
@@ -133,7 +133,7 @@ static int report_raw_events(struct perf_mem *mem)
                        goto out_delete;
        }
 
-       if (symbol__init() < 0)
+       if (symbol__init(&session->header.env) < 0)
                return -1;
 
        printf("# PID, TID, IP, ADDR, LOCAL WEIGHT, DSRC, SYMBOL\n");
@@ -194,7 +194,7 @@ int cmd_mem(int argc, const char **argv, const char *prefix __maybe_unused)
                        .lost           = perf_event__process_lost,
                        .fork           = perf_event__process_fork,
                        .build_id       = perf_event__process_build_id,
-                       .ordered_samples = true,
+                       .ordered_events = true,
                },
                .input_name              = "perf.data",
        };
index c63fa29250753b09d7468a1f5142a3f540e48249..04412b4770a2230ec83296cb179eb397ebb42e94 100644 (file)
@@ -290,8 +290,11 @@ static void cleanup_params(void)
 
 static void pr_err_with_code(const char *msg, int err)
 {
+       char sbuf[STRERR_BUFSIZE];
+
        pr_err("%s", msg);
-       pr_debug(" Reason: %s (Code: %d)", strerror(-err), err);
+       pr_debug(" Reason: %s (Code: %d)",
+                strerror_r(-err, sbuf, sizeof(sbuf)), err);
        pr_err("\n");
 }
 
@@ -373,6 +376,8 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
                        "target executable name or path", opt_set_target),
        OPT_BOOLEAN(0, "demangle", &symbol_conf.demangle,
                    "Disable symbol demangling"),
+       OPT_BOOLEAN(0, "demangle-kernel", &symbol_conf.demangle_kernel,
+                   "Enable kernel symbol demangling"),
        OPT_END()
        };
        int ret;
@@ -467,7 +472,8 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
                        usage_with_options(probe_usage, options);
                }
 
-               ret = show_line_range(&params.line_range, params.target);
+               ret = show_line_range(&params.line_range, params.target,
+                                     params.uprobes);
                if (ret < 0)
                        pr_err_with_code("  Error: Failed to show lines.", ret);
                return ret;
index 4869050e7194c18311da81f165f6f8e5cb5882ea..44c6f3d55ce76066ca8911d31f196a1fe128f36a 100644 (file)
@@ -65,8 +65,9 @@ static int process_synthesized_event(struct perf_tool *tool,
        return record__write(rec, event, event->header.size);
 }
 
-static int record__mmap_read(struct record *rec, struct perf_mmap *md)
+static int record__mmap_read(struct record *rec, int idx)
 {
+       struct perf_mmap *md = &rec->evlist->mmap[idx];
        unsigned int head = perf_mmap__read_head(md);
        unsigned int old = md->prev;
        unsigned char *data = md->base + page_size;
@@ -102,8 +103,7 @@ static int record__mmap_read(struct record *rec, struct perf_mmap *md)
        }
 
        md->prev = old;
-       perf_mmap__write_tail(md, old);
-
+       perf_evlist__mmap_consume(rec->evlist, idx);
 out:
        return rc;
 }
@@ -161,7 +161,7 @@ try_again:
 
        if (perf_evlist__apply_filters(evlist)) {
                error("failed to set filter with %d (%s)\n", errno,
-                       strerror(errno));
+                       strerror_r(errno, msg, sizeof(msg)));
                rc = -1;
                goto out;
        }
@@ -175,7 +175,8 @@ try_again:
                               "(current value: %u)\n", opts->mmap_pages);
                        rc = -errno;
                } else {
-                       pr_err("failed to mmap with %d (%s)\n", errno, strerror(errno));
+                       pr_err("failed to mmap with %d (%s)\n", errno,
+                               strerror_r(errno, msg, sizeof(msg)));
                        rc = -errno;
                }
                goto out;
@@ -244,7 +245,7 @@ static int record__mmap_read_all(struct record *rec)
 
        for (i = 0; i < rec->evlist->nr_mmaps; i++) {
                if (rec->evlist->mmap[i].base) {
-                       if (record__mmap_read(rec, &rec->evlist->mmap[i]) != 0) {
+                       if (record__mmap_read(rec, i) != 0) {
                                rc = -1;
                                goto out;
                        }
@@ -307,7 +308,7 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
        struct record_opts *opts = &rec->opts;
        struct perf_data_file *file = &rec->file;
        struct perf_session *session;
-       bool disabled = false;
+       bool disabled = false, draining = false;
 
        rec->progname = argv[0];
 
@@ -456,9 +457,9 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
                }
 
                if (hits == rec->samples) {
-                       if (done)
+                       if (done || draining)
                                break;
-                       err = poll(rec->evlist->pollfd, rec->evlist->nr_fds, -1);
+                       err = perf_evlist__poll(rec->evlist, -1);
                        /*
                         * Propagate error, only if there's any. Ignore positive
                         * number of returned events and interrupt error.
@@ -466,6 +467,9 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
                        if (err > 0 || (err < 0 && errno == EINTR))
                                err = 0;
                        waking++;
+
+                       if (perf_evlist__filter_pollfd(rec->evlist, POLLERR | POLLHUP) == 0)
+                               draining = true;
                }
 
                /*
@@ -480,7 +484,7 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
        }
 
        if (forks && workload_exec_errno) {
-               char msg[512];
+               char msg[STRERR_BUFSIZE];
                const char *emsg = strerror_r(workload_exec_errno, msg, sizeof(msg));
                pr_err("Workload failed: %s\n", emsg);
                err = -1;
@@ -620,145 +624,56 @@ error:
        return ret;
 }
 
-#ifdef HAVE_DWARF_UNWIND_SUPPORT
-static int get_stack_size(char *str, unsigned long *_size)
-{
-       char *endptr;
-       unsigned long size;
-       unsigned long max_size = round_down(USHRT_MAX, sizeof(u64));
-
-       size = strtoul(str, &endptr, 0);
-
-       do {
-               if (*endptr)
-                       break;
-
-               size = round_up(size, sizeof(u64));
-               if (!size || size > max_size)
-                       break;
-
-               *_size = size;
-               return 0;
-
-       } while (0);
-
-       pr_err("callchain: Incorrect stack dump size (max %ld): %s\n",
-              max_size, str);
-       return -1;
-}
-#endif /* HAVE_DWARF_UNWIND_SUPPORT */
-
-int record_parse_callchain(const char *arg, struct record_opts *opts)
-{
-       char *tok, *name, *saveptr = NULL;
-       char *buf;
-       int ret = -1;
-
-       /* We need buffer that we know we can write to. */
-       buf = malloc(strlen(arg) + 1);
-       if (!buf)
-               return -ENOMEM;
-
-       strcpy(buf, arg);
-
-       tok = strtok_r((char *)buf, ",", &saveptr);
-       name = tok ? : (char *)buf;
-
-       do {
-               /* Framepointer style */
-               if (!strncmp(name, "fp", sizeof("fp"))) {
-                       if (!strtok_r(NULL, ",", &saveptr)) {
-                               opts->call_graph = CALLCHAIN_FP;
-                               ret = 0;
-                       } else
-                               pr_err("callchain: No more arguments "
-                                      "needed for -g fp\n");
-                       break;
-
-#ifdef HAVE_DWARF_UNWIND_SUPPORT
-               /* Dwarf style */
-               } else if (!strncmp(name, "dwarf", sizeof("dwarf"))) {
-                       const unsigned long default_stack_dump_size = 8192;
-
-                       ret = 0;
-                       opts->call_graph = CALLCHAIN_DWARF;
-                       opts->stack_dump_size = default_stack_dump_size;
-
-                       tok = strtok_r(NULL, ",", &saveptr);
-                       if (tok) {
-                               unsigned long size = 0;
-
-                               ret = get_stack_size(tok, &size);
-                               opts->stack_dump_size = size;
-                       }
-#endif /* HAVE_DWARF_UNWIND_SUPPORT */
-               } else {
-                       pr_err("callchain: Unknown --call-graph option "
-                              "value: %s\n", arg);
-                       break;
-               }
-
-       } while (0);
-
-       free(buf);
-       return ret;
-}
-
-static void callchain_debug(struct record_opts *opts)
+static void callchain_debug(void)
 {
        static const char *str[CALLCHAIN_MAX] = { "NONE", "FP", "DWARF" };
 
-       pr_debug("callchain: type %s\n", str[opts->call_graph]);
+       pr_debug("callchain: type %s\n", str[callchain_param.record_mode]);
 
-       if (opts->call_graph == CALLCHAIN_DWARF)
+       if (callchain_param.record_mode == CALLCHAIN_DWARF)
                pr_debug("callchain: stack dump size %d\n",
-                        opts->stack_dump_size);
+                        callchain_param.dump_size);
 }
 
-int record_parse_callchain_opt(const struct option *opt,
+int record_parse_callchain_opt(const struct option *opt __maybe_unused,
                               const char *arg,
                               int unset)
 {
-       struct record_opts *opts = opt->value;
        int ret;
 
-       opts->call_graph_enabled = !unset;
+       callchain_param.enabled = !unset;
 
        /* --no-call-graph */
        if (unset) {
-               opts->call_graph = CALLCHAIN_NONE;
+               callchain_param.record_mode = CALLCHAIN_NONE;
                pr_debug("callchain: disabled\n");
                return 0;
        }
 
-       ret = record_parse_callchain(arg, opts);
+       ret = parse_callchain_record_opt(arg);
        if (!ret)
-               callchain_debug(opts);
+               callchain_debug();
 
        return ret;
 }
 
-int record_callchain_opt(const struct option *opt,
+int record_callchain_opt(const struct option *opt __maybe_unused,
                         const char *arg __maybe_unused,
                         int unset __maybe_unused)
 {
-       struct record_opts *opts = opt->value;
+       callchain_param.enabled = true;
 
-       opts->call_graph_enabled = !unset;
+       if (callchain_param.record_mode == CALLCHAIN_NONE)
+               callchain_param.record_mode = CALLCHAIN_FP;
 
-       if (opts->call_graph == CALLCHAIN_NONE)
-               opts->call_graph = CALLCHAIN_FP;
-
-       callchain_debug(opts);
+       callchain_debug();
        return 0;
 }
 
 static int perf_record_config(const char *var, const char *value, void *cb)
 {
-       struct record *rec = cb;
-
        if (!strcmp(var, "record.call-graph"))
-               return record_parse_callchain(value, &rec->opts);
+               var = "call-graph.record-mode"; /* fall-through */
 
        return perf_default_config(var, value, cb);
 }
@@ -781,6 +696,7 @@ static const char * const record_usage[] = {
  */
 static struct record record = {
        .opts = {
+               .sample_time         = true,
                .mmap_pages          = UINT_MAX,
                .user_freq           = UINT_MAX,
                .user_interval       = ULLONG_MAX,
@@ -907,7 +823,7 @@ int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused)
                usage_with_options(record_usage, record_options);
        }
 
-       symbol__init();
+       symbol__init(NULL);
 
        if (symbol_conf.kptr_restrict)
                pr_warning(
index 21d830bafff32aaa4b38ec0eb2e63ec66dfc00f8..ac145fae0521c3c9779a90c097228ff39074d5a6 100644 (file)
@@ -58,17 +58,19 @@ struct report {
        const char              *symbol_filter_str;
        float                   min_percent;
        u64                     nr_entries;
+       u64                     queue_size;
        DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS);
 };
 
 static int report__config(const char *var, const char *value, void *cb)
 {
+       struct report *rep = cb;
+
        if (!strcmp(var, "report.group")) {
                symbol_conf.event_group = perf_config_bool(var, value);
                return 0;
        }
        if (!strcmp(var, "report.percent-limit")) {
-               struct report *rep = cb;
                rep->min_percent = strtof(value, NULL);
                return 0;
        }
@@ -76,6 +78,10 @@ static int report__config(const char *var, const char *value, void *cb)
                symbol_conf.cumulate_callchain = perf_config_bool(var, value);
                return 0;
        }
+       if (!strcmp(var, "report.queue-size")) {
+               rep->queue_size = perf_config_u64(var, value);
+               return 0;
+       }
 
        return perf_default_config(var, value, cb);
 }
@@ -578,7 +584,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
                        .attr            = perf_event__process_attr,
                        .tracing_data    = perf_event__process_tracing_data,
                        .build_id        = perf_event__process_build_id,
-                       .ordered_samples = true,
+                       .ordered_events  = true,
                        .ordering_requires_timestamps = true,
                },
                .max_stack               = PERF_MAX_STACK_DEPTH,
@@ -674,6 +680,8 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
                   "objdump binary to use for disassembly and annotations"),
        OPT_BOOLEAN(0, "demangle", &symbol_conf.demangle,
                    "Disable symbol demangling"),
+       OPT_BOOLEAN(0, "demangle-kernel", &symbol_conf.demangle_kernel,
+                   "Enable kernel symbol demangling"),
        OPT_BOOLEAN(0, "mem-mode", &report.mem_mode, "mem access profile"),
        OPT_CALLBACK(0, "percent-limit", &report, "percent",
                     "Don't show entries under that percent", parse_percent_limit),
@@ -712,14 +720,19 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
 repeat:
        session = perf_session__new(&file, false, &report.tool);
        if (session == NULL)
-               return -ENOMEM;
+               return -1;
+
+       if (report.queue_size) {
+               ordered_events__set_alloc_size(&session->ordered_events,
+                                              report.queue_size);
+       }
 
        report.session = session;
 
        has_br_stack = perf_header__has_feat(&session->header,
                                             HEADER_BRANCH_STACK);
 
-       if (branch_mode == -1 && has_br_stack) {
+       if ((branch_mode == -1 && has_br_stack) || branch_mode == 1) {
                sort__mode = SORT_MODE__BRANCH;
                symbol_conf.cumulate_callchain = false;
        }
@@ -787,7 +800,7 @@ repeat:
                }
        }
 
-       if (symbol__init() < 0)
+       if (symbol__init(&session->header.env) < 0)
                goto error;
 
        if (argc) {
index f83c08c0dd87caaa97a8c0b3958320b65a2ed2ef..9c9287fbf8e98d4b480a668d34d756b2c11ed9f3 100644 (file)
@@ -428,6 +428,7 @@ static u64 get_cpu_usage_nsec_parent(void)
 static int self_open_counters(void)
 {
        struct perf_event_attr attr;
+       char sbuf[STRERR_BUFSIZE];
        int fd;
 
        memset(&attr, 0, sizeof(attr));
@@ -440,7 +441,8 @@ static int self_open_counters(void)
 
        if (fd < 0)
                pr_err("Error: sys_perf_event_open() syscall returned "
-                      "with %d (%s)\n", fd, strerror(errno));
+                      "with %d (%s)\n", fd,
+                      strerror_r(errno, sbuf, sizeof(sbuf)));
        return fd;
 }
 
@@ -1462,6 +1464,8 @@ static int perf_sched__read_events(struct perf_sched *sched,
                return -1;
        }
 
+       symbol__init(&session->header.env);
+
        if (perf_session__set_tracepoints_handlers(session, handlers))
                goto out_delete;
 
@@ -1662,7 +1666,7 @@ int cmd_sched(int argc, const char **argv, const char *prefix __maybe_unused)
                        .comm            = perf_event__process_comm,
                        .lost            = perf_event__process_lost,
                        .fork            = perf_sched__process_fork_event,
-                       .ordered_samples = true,
+                       .ordered_events = true,
                },
                .cmp_pid              = LIST_HEAD_INIT(sched.cmp_pid),
                .sort_list            = LIST_HEAD_INIT(sched.sort_list),
@@ -1747,7 +1751,6 @@ int cmd_sched(int argc, const char **argv, const char *prefix __maybe_unused)
        if (!strcmp(argv[0], "script"))
                return cmd_script(argc, argv, prefix);
 
-       symbol__init();
        if (!strncmp(argv[0], "rec", 3)) {
                return __cmd_record(argc, argv);
        } else if (!strncmp(argv[0], "lat", 3)) {
index f57035b89c15d11a5178cd3468cf5bd9b03405c1..b9b9e58a6c399d4c4c2e8dc3162598acf2b1cd62 100644 (file)
@@ -184,10 +184,6 @@ static int perf_evsel__check_attr(struct perf_evsel *evsel,
                if (perf_evsel__check_stype(evsel, PERF_SAMPLE_IP, "IP",
                                            PERF_OUTPUT_IP))
                        return -EINVAL;
-
-               if (!no_callchain &&
-                   !(attr->sample_type & PERF_SAMPLE_CALLCHAIN))
-                       symbol_conf.use_callchain = false;
        }
 
        if (PRINT_FIELD(ADDR) &&
@@ -290,6 +286,19 @@ static int perf_session__check_output_opt(struct perf_session *session)
                set_print_ip_opts(&evsel->attr);
        }
 
+       if (!no_callchain) {
+               bool use_callchain = false;
+
+               evlist__for_each(session->evlist, evsel) {
+                       if (evsel->attr.sample_type & PERF_SAMPLE_CALLCHAIN) {
+                               use_callchain = true;
+                               break;
+                       }
+               }
+               if (!use_callchain)
+                       symbol_conf.use_callchain = false;
+       }
+
        /*
         * set default for tracepoints to print symbols only
         * if callchains are present
@@ -476,6 +485,11 @@ static int default_start_script(const char *script __maybe_unused,
        return 0;
 }
 
+static int default_flush_script(void)
+{
+       return 0;
+}
+
 static int default_stop_script(void)
 {
        return 0;
@@ -489,6 +503,7 @@ static int default_generate_script(struct pevent *pevent __maybe_unused,
 
 static struct scripting_ops default_scripting_ops = {
        .start_script           = default_start_script,
+       .flush_script           = default_flush_script,
        .stop_script            = default_stop_script,
        .process_event          = process_event,
        .generate_script        = default_generate_script,
@@ -504,6 +519,11 @@ static void setup_scripting(void)
        scripting_ops = &default_scripting_ops;
 }
 
+static int flush_scripting(void)
+{
+       return scripting_ops->flush_script();
+}
+
 static int cleanup_scripting(void)
 {
        pr_debug("\nperf script stopped\n");
@@ -1471,12 +1491,13 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
        bool show_full_info = false;
        bool header = false;
        bool header_only = false;
+       bool script_started = false;
        char *rec_script_path = NULL;
        char *rep_script_path = NULL;
        struct perf_session *session;
        char *script_path = NULL;
        const char **__argv;
-       int i, j, err;
+       int i, j, err = 0;
        struct perf_script script = {
                .tool = {
                        .sample          = process_sample_event,
@@ -1488,7 +1509,7 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
                        .attr            = process_attr,
                        .tracing_data    = perf_event__process_tracing_data,
                        .build_id        = perf_event__process_build_id,
-                       .ordered_samples = true,
+                       .ordered_events  = true,
                        .ordering_requires_timestamps = true,
                },
        };
@@ -1718,26 +1739,28 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
                exit(-1);
        }
 
-       if (symbol__init() < 0)
-               return -1;
        if (!script_name)
                setup_pager();
 
        session = perf_session__new(&file, false, &script.tool);
        if (session == NULL)
-               return -ENOMEM;
+               return -1;
 
        if (header || header_only) {
                perf_session__fprintf_info(session, stdout, show_full_info);
                if (header_only)
-                       return 0;
+                       goto out_delete;
        }
 
+       if (symbol__init(&session->header.env) < 0)
+               goto out_delete;
+
        script.session = session;
 
        if (cpu_list) {
-               if (perf_session__cpu_bitmap(session, cpu_list, cpu_bitmap))
-                       return -1;
+               err = perf_session__cpu_bitmap(session, cpu_list, cpu_bitmap);
+               if (err < 0)
+                       goto out_delete;
        }
 
        if (!no_callchain)
@@ -1752,53 +1775,62 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
                if (output_set_by_user()) {
                        fprintf(stderr,
                                "custom fields not supported for generated scripts");
-                       return -1;
+                       err = -EINVAL;
+                       goto out_delete;
                }
 
                input = open(file.path, O_RDONLY);      /* input_name */
                if (input < 0) {
+                       err = -errno;
                        perror("failed to open file");
-                       return -1;
+                       goto out_delete;
                }
 
                err = fstat(input, &perf_stat);
                if (err < 0) {
                        perror("failed to stat file");
-                       return -1;
+                       goto out_delete;
                }
 
                if (!perf_stat.st_size) {
                        fprintf(stderr, "zero-sized file, nothing to do!\n");
-                       return 0;
+                       goto out_delete;
                }
 
                scripting_ops = script_spec__lookup(generate_script_lang);
                if (!scripting_ops) {
                        fprintf(stderr, "invalid language specifier");
-                       return -1;
+                       err = -ENOENT;
+                       goto out_delete;
                }
 
                err = scripting_ops->generate_script(session->tevent.pevent,
                                                     "perf-script");
-               goto out;
+               goto out_delete;
        }
 
        if (script_name) {
                err = scripting_ops->start_script(script_name, argc, argv);
                if (err)
-                       goto out;
+                       goto out_delete;
                pr_debug("perf script started with script %s\n\n", script_name);
+               script_started = true;
        }
 
 
        err = perf_session__check_output_opt(session);
        if (err < 0)
-               goto out;
+               goto out_delete;
 
        err = __cmd_script(&script);
 
+       flush_scripting();
+
+out_delete:
        perf_session__delete(session);
-       cleanup_scripting();
+
+       if (script_started)
+               cleanup_scripting();
 out:
        return err;
 }
index 3e80aa10cfd8d717c37850a23abade2321f134a4..b22c62f80078771d9167a2311a6e504cdd3a5690 100644 (file)
@@ -593,7 +593,7 @@ static int __run_perf_stat(int argc, const char **argv)
 
        if (perf_evlist__apply_filters(evsel_list)) {
                error("failed to set filter with %d (%s)\n", errno,
-                       strerror(errno));
+                       strerror_r(errno, msg, sizeof(msg)));
                return -1;
        }
 
@@ -732,7 +732,7 @@ static void aggr_printout(struct perf_evsel *evsel, int id, int nr)
        }
 }
 
-static void nsec_printout(int cpu, int nr, struct perf_evsel *evsel, double avg)
+static void nsec_printout(int id, int nr, struct perf_evsel *evsel, double avg)
 {
        double msecs = avg / 1e6;
        const char *fmt_v, *fmt_n;
@@ -741,7 +741,7 @@ static void nsec_printout(int cpu, int nr, struct perf_evsel *evsel, double avg)
        fmt_v = csv_output ? "%.6f%s" : "%18.6f%s";
        fmt_n = csv_output ? "%s" : "%-25s";
 
-       aggr_printout(evsel, cpu, nr);
+       aggr_printout(evsel, id, nr);
 
        scnprintf(name, sizeof(name), "%s%s",
                  perf_evsel__name(evsel), csv_output ? "" : " (msec)");
@@ -947,11 +947,12 @@ static void print_ll_cache_misses(int cpu,
        fprintf(output, " of all LL-cache hits   ");
 }
 
-static void abs_printout(int cpu, int nr, struct perf_evsel *evsel, double avg)
+static void abs_printout(int id, int nr, struct perf_evsel *evsel, double avg)
 {
        double total, ratio = 0.0, total2;
        double sc =  evsel->scale;
        const char *fmt;
+       int cpu = cpu_map__id_to_cpu(id);
 
        if (csv_output) {
                fmt = sc != 1.0 ?  "%.2f%s" : "%.0f%s";
@@ -962,7 +963,7 @@ static void abs_printout(int cpu, int nr, struct perf_evsel *evsel, double avg)
                        fmt = sc != 1.0 ? "%18.2f%s" : "%18.0f%s";
        }
 
-       aggr_printout(evsel, cpu, nr);
+       aggr_printout(evsel, id, nr);
 
        if (aggr_mode == AGGR_GLOBAL)
                cpu = 0;
index 2f1a5220c090f4fd8461b743f85b88b0b812214b..35b425b6293f759b5119d8fb6a07d2ab2303d6f7 100644 (file)
@@ -1605,7 +1605,9 @@ static int __cmd_timechart(struct timechart *tchart, const char *output_name)
        int ret = -EINVAL;
 
        if (session == NULL)
-               return -ENOMEM;
+               return -1;
+
+       symbol__init(&session->header.env);
 
        (void)perf_header__process_sections(&session->header,
                                            perf_data_file__fd(session->file),
@@ -1920,7 +1922,7 @@ int cmd_timechart(int argc, const char **argv,
                        .fork            = process_fork_event,
                        .exit            = process_exit_event,
                        .sample          = process_sample_event,
-                       .ordered_samples = true,
+                       .ordered_events  = true,
                },
                .proc_num = 15,
                .min_time = 1000000,
@@ -1982,8 +1984,6 @@ int cmd_timechart(int argc, const char **argv,
                return -1;
        }
 
-       symbol__init();
-
        if (argc && !strncmp(argv[0], "rec", 3)) {
                argc = parse_options(argc, argv, record_options, record_usage,
                                     PARSE_OPT_STOP_AT_NON_OPTION);
index 377971dc89a3b26ffcd25b9eb3e8c0c01338ea24..fc3d55f832ac0c55d316fe17aa20170f7096dfe9 100644 (file)
@@ -59,7 +59,7 @@
 
 #include <sys/syscall.h>
 #include <sys/ioctl.h>
-#include <sys/poll.h>
+#include <poll.h>
 #include <sys/prctl.h>
 #include <sys/wait.h>
 #include <sys/uio.h>
@@ -276,11 +276,17 @@ static void perf_top__print_sym_table(struct perf_top *top)
                return;
        }
 
+       if (top->zero) {
+               hists__delete_entries(&top->sym_evsel->hists);
+       } else {
+               hists__decay_entries(&top->sym_evsel->hists,
+                                    top->hide_user_symbols,
+                                    top->hide_kernel_symbols);
+       }
+
        hists__collapse_resort(&top->sym_evsel->hists, NULL);
        hists__output_resort(&top->sym_evsel->hists);
-       hists__decay_entries(&top->sym_evsel->hists,
-                            top->hide_user_symbols,
-                            top->hide_kernel_symbols);
+
        hists__output_recalc_col_len(&top->sym_evsel->hists,
                                     top->print_entries - printed);
        putchar('\n');
@@ -427,18 +433,13 @@ static bool perf_top__handle_keypress(struct perf_top *top, int c)
 
        if (!perf_top__key_mapped(top, c)) {
                struct pollfd stdin_poll = { .fd = 0, .events = POLLIN };
-               struct termios tc, save;
+               struct termios save;
 
                perf_top__print_mapped_keys(top);
                fprintf(stdout, "\nEnter selection, or unmapped key to continue: ");
                fflush(stdout);
 
-               tcgetattr(0, &save);
-               tc = save;
-               tc.c_lflag &= ~(ICANON | ECHO);
-               tc.c_cc[VMIN] = 0;
-               tc.c_cc[VTIME] = 0;
-               tcsetattr(0, TCSANOW, &tc);
+               set_term_quiet_input(&save);
 
                poll(&stdin_poll, 1, -1);
                c = getc(stdin);
@@ -542,11 +543,16 @@ static void perf_top__sort_new_samples(void *arg)
        if (t->evlist->selected != NULL)
                t->sym_evsel = t->evlist->selected;
 
+       if (t->zero) {
+               hists__delete_entries(&t->sym_evsel->hists);
+       } else {
+               hists__decay_entries(&t->sym_evsel->hists,
+                                    t->hide_user_symbols,
+                                    t->hide_kernel_symbols);
+       }
+
        hists__collapse_resort(&t->sym_evsel->hists, NULL);
        hists__output_resort(&t->sym_evsel->hists);
-       hists__decay_entries(&t->sym_evsel->hists,
-                            t->hide_user_symbols,
-                            t->hide_kernel_symbols);
 }
 
 static void *display_thread_tui(void *arg)
@@ -577,23 +583,32 @@ static void *display_thread_tui(void *arg)
        return NULL;
 }
 
+static void display_sig(int sig __maybe_unused)
+{
+       done = 1;
+}
+
+static void display_setup_sig(void)
+{
+       signal(SIGSEGV, display_sig);
+       signal(SIGFPE,  display_sig);
+       signal(SIGINT,  display_sig);
+       signal(SIGQUIT, display_sig);
+       signal(SIGTERM, display_sig);
+}
+
 static void *display_thread(void *arg)
 {
        struct pollfd stdin_poll = { .fd = 0, .events = POLLIN };
-       struct termios tc, save;
+       struct termios save;
        struct perf_top *top = arg;
        int delay_msecs, c;
 
-       tcgetattr(0, &save);
-       tc = save;
-       tc.c_lflag &= ~(ICANON | ECHO);
-       tc.c_cc[VMIN] = 0;
-       tc.c_cc[VTIME] = 0;
-
+       display_setup_sig();
        pthread__unblock_sigwinch();
 repeat:
        delay_msecs = top->delay_secs * 1000;
-       tcsetattr(0, TCSANOW, &tc);
+       set_term_quiet_input(&save);
        /* trash return*/
        getc(stdin);
 
@@ -620,13 +635,16 @@ repeat:
                }
        }
 
+       tcsetattr(0, TCSAFLUSH, &save);
        return NULL;
 }
 
-static int symbol_filter(struct map *map __maybe_unused, struct symbol *sym)
+static int symbol_filter(struct map *map, struct symbol *sym)
 {
        const char *name = sym->name;
 
+       if (!map->dso->kernel)
+               return 0;
        /*
         * ppc64 uses function descriptors and appends a '.' to the
         * start of every instruction address. Remove it.
@@ -876,7 +894,7 @@ try_again:
 
        if (perf_evlist__mmap(evlist, opts->mmap_pages, false) < 0) {
                ui__error("Failed to mmap with %d (%s)\n",
-                           errno, strerror(errno));
+                           errno, strerror_r(errno, msg, sizeof(msg)));
                goto out_err;
        }
 
@@ -911,7 +929,7 @@ static int __cmd_top(struct perf_top *top)
 
        top->session = perf_session__new(NULL, false, NULL);
        if (top->session == NULL)
-               return -ENOMEM;
+               return -1;
 
        machines__set_symbol_filter(&top->session->machines, symbol_filter);
 
@@ -946,7 +964,7 @@ static int __cmd_top(struct perf_top *top)
                 perf_evlist__enable(top->evlist);
 
        /* Wait for a minimal set of events before starting the snapshot */
-       poll(top->evlist->pollfd, top->evlist->nr_fds, 100);
+       perf_evlist__poll(top->evlist, 100);
 
        perf_top__mmap_read(top);
 
@@ -963,7 +981,7 @@ static int __cmd_top(struct perf_top *top)
                param.sched_priority = top->realtime_prio;
                if (sched_setscheduler(0, SCHED_FIFO, &param)) {
                        ui__error("Could not set realtime priority.\n");
-                       goto out_delete;
+                       goto out_join;
                }
        }
 
@@ -973,10 +991,12 @@ static int __cmd_top(struct perf_top *top)
                perf_top__mmap_read(top);
 
                if (hits == top->samples)
-                       ret = poll(top->evlist->pollfd, top->evlist->nr_fds, 100);
+                       ret = perf_evlist__poll(top->evlist, 100);
        }
 
        ret = 0;
+out_join:
+       pthread_join(thread, NULL);
 out_delete:
        perf_session__delete(top->session);
        top->session = NULL;
@@ -1000,10 +1020,8 @@ parse_callchain_opt(const struct option *opt, const char *arg, int unset)
 
 static int perf_top_config(const char *var, const char *value, void *cb)
 {
-       struct perf_top *top = cb;
-
        if (!strcmp(var, "top.call-graph"))
-               return record_parse_callchain(value, &top->record_opts);
+               var = "call-graph.record-mode"; /* fall-through */
        if (!strcmp(var, "top.children")) {
                symbol_conf.cumulate_callchain = perf_config_bool(var, value);
                return 0;
@@ -1122,6 +1140,8 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
                    "Interleave source code with assembly code (default)"),
        OPT_BOOLEAN(0, "asm-raw", &symbol_conf.annotate_asm_raw,
                    "Display raw encoding of assembly instructions (default)"),
+       OPT_BOOLEAN(0, "demangle-kernel", &symbol_conf.demangle_kernel,
+                   "Enable kernel symbol demangling"),
        OPT_STRING(0, "objdump", &objdump_path, "path",
                    "objdump binary to use for disassembly and annotations"),
        OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style",
@@ -1131,6 +1151,9 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
                     "Don't show entries under that percent", parse_percent_limit),
        OPT_CALLBACK(0, "percentage", NULL, "relative|absolute",
                     "How to display percentage of filtered entries", parse_filter_percentage),
+       OPT_STRING('w', "column-widths", &symbol_conf.col_width_list_str,
+                  "width[,width...]",
+                  "don't try to adjust column width, use these fixed values"),
        OPT_END()
        };
        const char * const top_usage[] = {
@@ -1217,7 +1240,7 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
        symbol_conf.priv_size = sizeof(struct annotation);
 
        symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL);
-       if (symbol__init() < 0)
+       if (symbol__init(NULL) < 0)
                return -1;
 
        sort__setup_elide(stdout);
index a6c375224f4613c27ab72d02799f8632d6db505f..09bcf2393910af792911a622f1ce613d31895af6 100644 (file)
@@ -402,6 +402,31 @@ static size_t syscall_arg__scnprintf_mmap_flags(char *bf, size_t size,
 
 #define SCA_MMAP_FLAGS syscall_arg__scnprintf_mmap_flags
 
+static size_t syscall_arg__scnprintf_mremap_flags(char *bf, size_t size,
+                                                 struct syscall_arg *arg)
+{
+       int printed = 0, flags = arg->val;
+
+#define P_MREMAP_FLAG(n) \
+       if (flags & MREMAP_##n) { \
+               printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
+               flags &= ~MREMAP_##n; \
+       }
+
+       P_MREMAP_FLAG(MAYMOVE);
+#ifdef MREMAP_FIXED
+       P_MREMAP_FLAG(FIXED);
+#endif
+#undef P_MREMAP_FLAG
+
+       if (flags)
+               printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
+
+       return printed;
+}
+
+#define SCA_MREMAP_FLAGS syscall_arg__scnprintf_mremap_flags
+
 static size_t syscall_arg__scnprintf_madvise_behavior(char *bf, size_t size,
                                                      struct syscall_arg *arg)
 {
@@ -1004,6 +1029,7 @@ static struct syscall_fmt {
                             [2] = SCA_MMAP_PROT, /* prot */ }, },
        { .name     = "mremap",     .hexret = true,
          .arg_scnprintf = { [0] = SCA_HEX, /* addr */
+                            [3] = SCA_MREMAP_FLAGS, /* flags */
                             [4] = SCA_HEX, /* new_addr */ }, },
        { .name     = "munlock",    .errmsg = true,
          .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
@@ -1385,7 +1411,7 @@ static int trace__tool_process(struct perf_tool *tool,
 
 static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
 {
-       int err = symbol__init();
+       int err = symbol__init(NULL);
 
        if (err)
                return err;
@@ -1669,7 +1695,7 @@ static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
                           union perf_event *event __maybe_unused,
                           struct perf_sample *sample)
 {
-       int ret;
+       long ret;
        u64 duration = 0;
        struct thread *thread;
        int id = perf_evsel__sc_tp_uint(evsel, id, sample);
@@ -1722,9 +1748,9 @@ static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
 
        if (sc->fmt == NULL) {
 signed_print:
-               fprintf(trace->output, ") = %d", ret);
+               fprintf(trace->output, ") = %ld", ret);
        } else if (ret < 0 && sc->fmt->errmsg) {
-               char bf[256];
+               char bf[STRERR_BUFSIZE];
                const char *emsg = strerror_r(-ret, bf, sizeof(bf)),
                           *e = audit_errno_to_name(-ret);
 
@@ -1732,7 +1758,7 @@ signed_print:
        } else if (ret == 0 && sc->fmt->timeout)
                fprintf(trace->output, ") = 0 Timeout");
        else if (sc->fmt->hexret)
-               fprintf(trace->output, ") = %#x", ret);
+               fprintf(trace->output, ") = %#lx", ret);
        else
                goto signed_print;
 
@@ -2018,6 +2044,8 @@ static int trace__run(struct trace *trace, int argc, const char **argv)
        int err = -1, i;
        unsigned long before;
        const bool forks = argc > 0;
+       bool draining = false;
+       char sbuf[STRERR_BUFSIZE];
 
        trace->live = true;
 
@@ -2079,7 +2107,8 @@ static int trace__run(struct trace *trace, int argc, const char **argv)
 
        err = perf_evlist__mmap(evlist, trace->opts.mmap_pages, false);
        if (err < 0) {
-               fprintf(trace->output, "Couldn't mmap the events: %s\n", strerror(errno));
+               fprintf(trace->output, "Couldn't mmap the events: %s\n",
+                       strerror_r(errno, sbuf, sizeof(sbuf)));
                goto out_delete_evlist;
        }
 
@@ -2143,8 +2172,12 @@ next_event:
        if (trace->nr_events == before) {
                int timeout = done ? 100 : -1;
 
-               if (poll(evlist->pollfd, evlist->nr_fds, timeout) > 0)
+               if (!draining && perf_evlist__poll(evlist, timeout) > 0) {
+                       if (perf_evlist__filter_pollfd(evlist, POLLERR | POLLHUP) == 0)
+                               draining = true;
+
                        goto again;
+               }
        } else {
                goto again;
        }
@@ -2209,18 +2242,18 @@ static int trace__replay(struct trace *trace)
        trace->tool.tracing_data = perf_event__process_tracing_data;
        trace->tool.build_id      = perf_event__process_build_id;
 
-       trace->tool.ordered_samples = true;
+       trace->tool.ordered_events = true;
        trace->tool.ordering_requires_timestamps = true;
 
        /* add tid to output */
        trace->multiple_threads = true;
 
-       if (symbol__init() < 0)
-               return -1;
-
        session = perf_session__new(&file, false, &trace->tool);
        if (session == NULL)
-               return -ENOMEM;
+               return -1;
+
+       if (symbol__init(&session->header.env) < 0)
+               goto out;
 
        trace->host = &session->machines.host;
 
index 1f67aa02d240b0ba5c3ae53a55f0ecc03fbfb76a..58f609198c6dcce0c7af6082d62c7254c29e5179 100644 (file)
@@ -48,10 +48,6 @@ ifneq ($(ARCH),$(filter $(ARCH),x86 arm))
   NO_LIBDW_DWARF_UNWIND := 1
 endif
 
-ifeq ($(ARCH),powerpc)
-  CFLAGS += -DHAVE_SKIP_CALLCHAIN_IDX
-endif
-
 ifeq ($(LIBUNWIND_LIBS),)
   NO_LIBUNWIND := 1
 else
@@ -120,6 +116,29 @@ ifdef PARSER_DEBUG
   CFLAGS             += -DPARSER_DEBUG
 endif
 
+ifndef NO_LIBPYTHON
+  # Try different combinations to accommodate systems that only have
+  # python[2][-config] in weird combinations but always preferring
+  # python2 and python2-config as per pep-0394. If we catch a
+  # python[-config] in version 3, the version check will kill it.
+  PYTHON2 := $(if $(call get-executable,python2),python2,python)
+  override PYTHON := $(call get-executable-or-default,PYTHON,$(PYTHON2))
+  PYTHON2_CONFIG := \
+    $(if $(call get-executable,$(PYTHON)-config),$(PYTHON)-config,python-config)
+  override PYTHON_CONFIG := \
+    $(call get-executable-or-default,PYTHON_CONFIG,$(PYTHON2_CONFIG))
+
+  PYTHON_CONFIG_SQ := $(call shell-sq,$(PYTHON_CONFIG))
+
+  PYTHON_EMBED_LDOPTS := $(shell $(PYTHON_CONFIG_SQ) --ldflags 2>/dev/null)
+  PYTHON_EMBED_CCOPTS := $(shell $(PYTHON_CONFIG_SQ) --cflags 2>/dev/null)
+
+  FEATURE_CHECK_CFLAGS-libpython := $(PYTHON_EMBED_CCOPTS)
+  FEATURE_CHECK_LDFLAGS-libpython := $(PYTHON_EMBED_LDOPTS)
+  FEATURE_CHECK_CFLAGS-libpython-version := $(PYTHON_EMBED_CCOPTS)
+  FEATURE_CHECK_LDFLAGS-libpython-version := $(PYTHON_EMBED_LDOPTS)
+endif
+
 CFLAGS += -fno-omit-frame-pointer
 CFLAGS += -ggdb3
 CFLAGS += -funwind-tables
@@ -355,6 +374,12 @@ ifndef NO_LIBELF
   endif # NO_DWARF
 endif # NO_LIBELF
 
+ifeq ($(ARCH),powerpc)
+  ifndef NO_DWARF
+    CFLAGS += -DHAVE_SKIP_CALLCHAIN_IDX
+  endif
+endif
+
 ifndef NO_LIBUNWIND
   ifneq ($(feature-libunwind), 1)
     msg := $(warning No libunwind found. Please install libunwind-dev[el] >= 1.1 and/or set LIBUNWIND_DIR);
@@ -482,21 +507,14 @@ define disable-python_code
   NO_LIBPYTHON := 1
 endef
 
-override PYTHON := \
-  $(call get-executable-or-default,PYTHON,python)
-
-ifndef PYTHON
-  $(call disable-python,python interpreter)
+ifdef NO_LIBPYTHON
+  $(call disable-python)
 else
 
-  PYTHON_WORD := $(call shell-wordify,$(PYTHON))
-
-  ifdef NO_LIBPYTHON
-    $(call disable-python)
+  ifndef PYTHON
+    $(call disable-python,python interpreter)
   else
-
-    override PYTHON_CONFIG := \
-      $(call get-executable-or-default,PYTHON_CONFIG,$(PYTHON)-config)
+    PYTHON_WORD := $(call shell-wordify,$(PYTHON))
 
     ifndef PYTHON_CONFIG
       $(call disable-python,python-config tool)
@@ -635,11 +653,13 @@ else
 sysconfdir = $(prefix)/etc
 ETC_PERFCONFIG = etc/perfconfig
 endif
+ifndef lib
 ifeq ($(IS_X86_64),1)
 lib = lib64
 else
 lib = lib
 endif
+endif # lib
 libdir = $(prefix)/$(lib)
 
 # Shell quote (do not use $(call) to accommodate ancient setups);
index 6088f8d8a434a2860031b464caa4dac1ad691fad..72ab2984718e341e0a18f2e4ad0953cc3359a4c6 100644 (file)
@@ -101,25 +101,11 @@ FLAGS_PERL_EMBED=$(PERL_EMBED_CCOPTS) $(PERL_EMBED_LDOPTS)
 test-libperl.bin:
        $(BUILD) $(FLAGS_PERL_EMBED)
 
-override PYTHON := python
-override PYTHON_CONFIG := python-config
-
-escape-for-shell-sq =  $(subst ','\'',$(1))
-shell-sq = '$(escape-for-shell-sq)'
-
-PYTHON_CONFIG_SQ = $(call shell-sq,$(PYTHON_CONFIG))
-
-PYTHON_EMBED_LDOPTS = $(shell $(PYTHON_CONFIG_SQ) --ldflags 2>/dev/null)
-PYTHON_EMBED_LDFLAGS = $(call strip-libs,$(PYTHON_EMBED_LDOPTS))
-PYTHON_EMBED_LIBADD = $(call grep-libs,$(PYTHON_EMBED_LDOPTS))
-PYTHON_EMBED_CCOPTS = $(shell $(PYTHON_CONFIG_SQ) --cflags 2>/dev/null)
-FLAGS_PYTHON_EMBED = $(PYTHON_EMBED_CCOPTS) $(PYTHON_EMBED_LDOPTS)
-
 test-libpython.bin:
-       $(BUILD) $(FLAGS_PYTHON_EMBED)
+       $(BUILD)
 
 test-libpython-version.bin:
-       $(BUILD) $(FLAGS_PYTHON_EMBED)
+       $(BUILD)
 
 test-libbfd.bin:
        $(BUILD) -DPACKAGE='"perf"' -lbfd -lz -liberty -ldl
index 4d985e0f03f584f666fb74b86efd095a064ebaae..7076a62d0ff72c094ca0bb2e1eae7308aaaf948f 100644 (file)
@@ -132,7 +132,7 @@ endef
 #
 # Usage: bool-value = $(call is-absolute,path)
 #
-is-absolute = $(shell echo $(shell-sq) | grep ^/ -q && echo y)
+is-absolute = $(shell echo $(shell-sq) | grep -q ^/ && echo y)
 
 # lookup
 #
diff --git a/tools/perf/perf-with-kcore.sh b/tools/perf/perf-with-kcore.sh
new file mode 100644 (file)
index 0000000..c7ff90a
--- /dev/null
@@ -0,0 +1,259 @@
+#!/bin/bash
+# perf-with-kcore: use perf with a copy of kcore
+# Copyright (c) 2014, Intel Corporation.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms and conditions of the GNU General Public License,
+# version 2, as published by the Free Software Foundation.
+#
+# This program is distributed in the hope it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+# more details.
+
+set -e
+
+usage()
+{
+        echo "Usage: perf-with-kcore <perf sub-command> <perf.data directory> [<sub-command options> [ -- <workload>]]" >&2
+        echo "       <perf sub-command> can be record, script, report or inject" >&2
+        echo "   or: perf-with-kcore fix_buildid_cache_permissions" >&2
+        exit 1
+}
+
+find_perf()
+{
+       if [ -n "$PERF" ] ; then
+               return
+       fi
+       PERF=`which perf || true`
+       if [ -z "$PERF" ] ; then
+               echo "Failed to find perf" >&2
+               exit 1
+       fi
+       if [ ! -x "$PERF" ] ; then
+               echo "Failed to find perf" >&2
+               exit 1
+       fi
+       echo "Using $PERF"
+       "$PERF" version
+}
+
+copy_kcore()
+{
+       echo "Copying kcore"
+
+       if [ $EUID -eq 0 ] ; then
+               SUDO=""
+       else
+               SUDO="sudo"
+       fi
+
+       rm -f perf.data.junk
+       ("$PERF" record -o perf.data.junk $PERF_OPTIONS -- sleep 60) >/dev/null 2>/dev/null &
+       PERF_PID=$!
+
+       # Need to make sure that perf has started
+       sleep 1
+
+       KCORE=$(($SUDO "$PERF" buildid-cache -v -f -k /proc/kcore >/dev/null) 2>&1)
+       case "$KCORE" in
+       "kcore added to build-id cache directory "*)
+               KCORE_DIR=${KCORE#"kcore added to build-id cache directory "}
+       ;;
+       *)
+               kill $PERF_PID
+               wait >/dev/null 2>/dev/null || true
+               rm perf.data.junk
+               echo "$KCORE"
+               echo "Failed to find kcore" >&2
+               exit 1
+       ;;
+       esac
+
+       kill $PERF_PID
+       wait >/dev/null 2>/dev/null || true
+       rm perf.data.junk
+
+       $SUDO cp -a "$KCORE_DIR" "$(pwd)/$PERF_DATA_DIR"
+       $SUDO rm -f "$KCORE_DIR/kcore"
+       $SUDO rm -f "$KCORE_DIR/kallsyms"
+       $SUDO rm -f "$KCORE_DIR/modules"
+       $SUDO rmdir "$KCORE_DIR"
+
+       KCORE_DIR_BASENAME=$(basename "$KCORE_DIR")
+       KCORE_DIR="$(pwd)/$PERF_DATA_DIR/$KCORE_DIR_BASENAME"
+
+       $SUDO chown $UID "$KCORE_DIR"
+       $SUDO chown $UID "$KCORE_DIR/kcore"
+       $SUDO chown $UID "$KCORE_DIR/kallsyms"
+       $SUDO chown $UID "$KCORE_DIR/modules"
+
+       $SUDO chgrp $GROUPS "$KCORE_DIR"
+       $SUDO chgrp $GROUPS "$KCORE_DIR/kcore"
+       $SUDO chgrp $GROUPS "$KCORE_DIR/kallsyms"
+       $SUDO chgrp $GROUPS "$KCORE_DIR/modules"
+
+       ln -s "$KCORE_DIR_BASENAME" "$PERF_DATA_DIR/kcore_dir"
+}
+
+fix_buildid_cache_permissions()
+{
+       if [ $EUID -ne 0 ] ; then
+               echo "This script must be run as root via sudo " >&2
+               exit 1
+       fi
+
+       if [ -z "$SUDO_USER" ] ; then
+               echo "This script must be run via sudo" >&2
+               exit 1
+       fi
+
+       USER_HOME=$(bash <<< "echo ~$SUDO_USER")
+
+       if [ "$HOME" != "$USER_HOME" ] ; then
+               echo "Fix unnecessary because root has a home: $HOME" >&2
+               exit 1
+       fi
+
+       echo "Fixing buildid cache permissions"
+
+       find "$USER_HOME/.debug" -xdev -type d          ! -user "$SUDO_USER" -ls -exec chown    "$SUDO_USER" \{\} \;
+       find "$USER_HOME/.debug" -xdev -type f -links 1 ! -user "$SUDO_USER" -ls -exec chown    "$SUDO_USER" \{\} \;
+       find "$USER_HOME/.debug" -xdev -type l          ! -user "$SUDO_USER" -ls -exec chown -h "$SUDO_USER" \{\} \;
+
+       if [ -n "$SUDO_GID" ] ; then
+               find "$USER_HOME/.debug" -xdev -type d          ! -group "$SUDO_GID" -ls -exec chgrp    "$SUDO_GID" \{\} \;
+               find "$USER_HOME/.debug" -xdev -type f -links 1 ! -group "$SUDO_GID" -ls -exec chgrp    "$SUDO_GID" \{\} \;
+               find "$USER_HOME/.debug" -xdev -type l          ! -group "$SUDO_GID" -ls -exec chgrp -h "$SUDO_GID" \{\} \;
+       fi
+
+       echo "Done"
+}
+
+check_buildid_cache_permissions()
+{
+       if [ $EUID -eq 0 ] ; then
+               return
+       fi
+
+       PERMISSIONS_OK+=$(find "$HOME/.debug" -xdev -type d          ! -user "$USER" -print -quit)
+       PERMISSIONS_OK+=$(find "$HOME/.debug" -xdev -type f -links 1 ! -user "$USER" -print -quit)
+       PERMISSIONS_OK+=$(find "$HOME/.debug" -xdev -type l          ! -user "$USER" -print -quit)
+
+       PERMISSIONS_OK+=$(find "$HOME/.debug" -xdev -type d          ! -group "$GROUPS" -print -quit)
+       PERMISSIONS_OK+=$(find "$HOME/.debug" -xdev -type f -links 1 ! -group "$GROUPS" -print -quit)
+       PERMISSIONS_OK+=$(find "$HOME/.debug" -xdev -type l          ! -group "$GROUPS" -print -quit)
+
+       if [ -n "$PERMISSIONS_OK" ] ; then
+               echo "*** WARNING *** buildid cache permissions may need fixing" >&2
+       fi
+}
+
+record()
+{
+       echo "Recording"
+
+       if [ $EUID -ne 0 ] ; then
+
+               if [ "$(cat /proc/sys/kernel/kptr_restrict)" -ne 0 ] ; then
+                       echo "*** WARNING *** /proc/sys/kernel/kptr_restrict prevents access to kernel addresses" >&2
+               fi
+
+               if echo "$PERF_OPTIONS" | grep -q ' -a \|^-a \| -a$\|^-a$\| --all-cpus \|^--all-cpus \| --all-cpus$\|^--all-cpus$' ; then
+                       echo "*** WARNING *** system-wide tracing without root access will not be able to read all necessary information from /proc" >&2
+               fi
+
+               if echo "$PERF_OPTIONS" | grep -q 'intel_pt\|intel_bts\| -I\|^-I' ; then
+                       if [ "$(cat /proc/sys/kernel/perf_event_paranoid)" -gt -1 ] ; then
+                               echo "*** WARNING *** /proc/sys/kernel/perf_event_paranoid restricts buffer size and tracepoint (sched_switch) use" >&2
+                       fi
+
+                       if echo "$PERF_OPTIONS" | grep -q ' --per-thread \|^--per-thread \| --per-thread$\|^--per-thread$' ; then
+                               true
+                       elif echo "$PERF_OPTIONS" | grep -q ' -t \|^-t \| -t$\|^-t$' ; then
+                               true
+                       elif [ ! -r /sys/kernel/debug -o ! -x /sys/kernel/debug ] ; then
+                               echo "*** WARNING *** /sys/kernel/debug permissions prevent tracepoint (sched_switch) use" >&2
+                       fi
+               fi
+       fi
+
+       if [ -z "$1" ] ; then
+               echo "Workload is required for recording" >&2
+               usage
+       fi
+
+       if [ -e "$PERF_DATA_DIR" ] ; then
+               echo "'$PERF_DATA_DIR' exists" >&2
+               exit 1
+       fi
+
+       find_perf
+
+       mkdir "$PERF_DATA_DIR"
+
+       echo "$PERF record -o $PERF_DATA_DIR/perf.data $PERF_OPTIONS -- $*"
+       "$PERF" record -o "$PERF_DATA_DIR/perf.data" $PERF_OPTIONS -- $* || true
+
+       if rmdir "$PERF_DATA_DIR" > /dev/null 2>/dev/null ; then
+               exit 1
+       fi
+
+       copy_kcore
+
+       echo "Done"
+}
+
+subcommand()
+{
+       find_perf
+       check_buildid_cache_permissions
+       echo "$PERF $PERF_SUB_COMMAND -i $PERF_DATA_DIR/perf.data --kallsyms=$PERF_DATA_DIR/kcore_dir/kallsyms $*"
+       "$PERF" $PERF_SUB_COMMAND -i "$PERF_DATA_DIR/perf.data" "--kallsyms=$PERF_DATA_DIR/kcore_dir/kallsyms" $*
+}
+
+if [ "$1" = "fix_buildid_cache_permissions" ] ; then
+       fix_buildid_cache_permissions
+       exit 0
+fi
+
+PERF_SUB_COMMAND=$1
+PERF_DATA_DIR=$2
+shift || true
+shift || true
+
+if [ -z "$PERF_SUB_COMMAND" ] ; then
+       usage
+fi
+
+if [ -z "$PERF_DATA_DIR" ] ; then
+       usage
+fi
+
+case "$PERF_SUB_COMMAND" in
+"record")
+       while [ "$1" != "--" ] ; do
+               PERF_OPTIONS+="$1 "
+               shift || break
+       done
+       if [ "$1" != "--" ] ; then
+               echo "Options and workload are required for recording" >&2
+               usage
+       fi
+       shift
+       record $*
+;;
+"script")
+       subcommand $*
+;;
+"report")
+       subcommand $*
+;;
+"inject")
+       subcommand $*
+;;
+*)
+       usage
+;;
+esac
index 2282d41879a2b2ef0c1927f91856c21948e68f30..452a8474d29d8cedbed3e47f46a4ebc728663907 100644 (file)
@@ -313,6 +313,7 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv)
        int status;
        struct stat st;
        const char *prefix;
+       char sbuf[STRERR_BUFSIZE];
 
        prefix = NULL;
        if (p->option & RUN_SETUP)
@@ -343,7 +344,8 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv)
        status = 1;
        /* Check for ENOSPC and EIO errors.. */
        if (fflush(stdout)) {
-               fprintf(stderr, "write failure on standard output: %s", strerror(errno));
+               fprintf(stderr, "write failure on standard output: %s",
+                       strerror_r(errno, sbuf, sizeof(sbuf)));
                goto out;
        }
        if (ferror(stdout)) {
@@ -351,7 +353,8 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv)
                goto out;
        }
        if (fclose(stdout)) {
-               fprintf(stderr, "close failed on standard output: %s", strerror(errno));
+               fprintf(stderr, "close failed on standard output: %s",
+                       strerror_r(errno, sbuf, sizeof(sbuf)));
                goto out;
        }
        status = 0;
@@ -466,6 +469,7 @@ void pthread__unblock_sigwinch(void)
 int main(int argc, const char **argv)
 {
        const char *cmd;
+       char sbuf[STRERR_BUFSIZE];
 
        /* The page_size is placed in util object. */
        page_size = sysconf(_SC_PAGE_SIZE);
@@ -561,7 +565,7 @@ int main(int argc, const char **argv)
        }
 
        fprintf(stderr, "Failed to run command '%s': %s\n",
-               cmd, strerror(errno));
+               cmd, strerror_r(errno, sbuf, sizeof(sbuf)));
 out:
        return 1;
 }
index 510c65f72858fb09fcdad8a5c21ba7bb732747d6..220d44e44c1b1d4fdfafcbe546690d2534108d7f 100644 (file)
@@ -41,8 +41,6 @@ void pthread__unblock_sigwinch(void);
 
 struct record_opts {
        struct target target;
-       int          call_graph;
-       bool         call_graph_enabled;
        bool         group;
        bool         inherit_stat;
        bool         no_buffering;
@@ -60,7 +58,6 @@ struct record_opts {
        u64          branch_stack;
        u64          default_interval;
        u64          user_interval;
-       u16          stack_dump_size;
        bool         sample_transaction;
        unsigned     initial_delay;
 };
index 6f8b01bc60330c71722e4d22a7d40b83c32fac25..ac655b0700e7648335cc15c45a560c80f35ae27c 100644 (file)
@@ -153,6 +153,18 @@ static struct test {
                .desc = "Test cumulation of child hist entries",
                .func = test__hists_cumulate,
        },
+       {
+               .desc = "Test tracking with sched_switch",
+               .func = test__switch_tracking,
+       },
+       {
+               .desc = "Filter fds with revents mask in a fdarray",
+               .func = test__fdarray__filter,
+       },
+       {
+               .desc = "Add fd to a fdarray, making it autogrow",
+               .func = test__fdarray__add,
+       },
        {
                .func = NULL,
        },
@@ -185,9 +197,11 @@ static bool perf_test__matches(int curr, int argc, const char *argv[])
 static int run_test(struct test *test)
 {
        int status, err = -1, child = fork();
+       char sbuf[STRERR_BUFSIZE];
 
        if (child < 0) {
-               pr_err("failed to fork test: %s\n", strerror(errno));
+               pr_err("failed to fork test: %s\n",
+                       strerror_r(errno, sbuf, sizeof(sbuf)));
                return -1;
        }
 
@@ -297,7 +311,7 @@ int cmd_test(int argc, const char **argv, const char *prefix __maybe_unused)
        symbol_conf.sort_by_name = true;
        symbol_conf.try_vmlinux_path = true;
 
-       if (symbol__init() < 0)
+       if (symbol__init(NULL) < 0)
                return -1;
 
        if (skip != NULL)
diff --git a/tools/perf/tests/fdarray.c b/tools/perf/tests/fdarray.c
new file mode 100644 (file)
index 0000000..d24b837
--- /dev/null
@@ -0,0 +1,174 @@
+#include <api/fd/array.h>
+#include "util/debug.h"
+#include "tests/tests.h"
+
+static void fdarray__init_revents(struct fdarray *fda, short revents)
+{
+       int fd;
+
+       fda->nr = fda->nr_alloc;
+
+       for (fd = 0; fd < fda->nr; ++fd) {
+               fda->entries[fd].fd      = fda->nr - fd;
+               fda->entries[fd].revents = revents;
+       }
+}
+
+static int fdarray__fprintf_prefix(struct fdarray *fda, const char *prefix, FILE *fp)
+{
+       int printed = 0;
+
+       if (!verbose)
+               return 0;
+
+       printed += fprintf(fp, "\n%s: ", prefix);
+       return printed + fdarray__fprintf(fda, fp);
+}
+
+int test__fdarray__filter(void)
+{
+       int nr_fds, expected_fd[2], fd, err = TEST_FAIL;
+       struct fdarray *fda = fdarray__new(5, 5);
+
+       if (fda == NULL) {
+               pr_debug("\nfdarray__new() failed!");
+               goto out;
+       }
+
+       fdarray__init_revents(fda, POLLIN);
+       nr_fds = fdarray__filter(fda, POLLHUP, NULL);
+       if (nr_fds != fda->nr_alloc) {
+               pr_debug("\nfdarray__filter()=%d != %d shouldn't have filtered anything",
+                        nr_fds, fda->nr_alloc);
+               goto out_delete;
+       }
+
+       fdarray__init_revents(fda, POLLHUP);
+       nr_fds = fdarray__filter(fda, POLLHUP, NULL);
+       if (nr_fds != 0) {
+               pr_debug("\nfdarray__filter()=%d != %d, should have filtered all fds",
+                        nr_fds, fda->nr_alloc);
+               goto out_delete;
+       }
+
+       fdarray__init_revents(fda, POLLHUP);
+       fda->entries[2].revents = POLLIN;
+       expected_fd[0] = fda->entries[2].fd;
+
+       pr_debug("\nfiltering all but fda->entries[2]:");
+       fdarray__fprintf_prefix(fda, "before", stderr);
+       nr_fds = fdarray__filter(fda, POLLHUP, NULL);
+       fdarray__fprintf_prefix(fda, " after", stderr);
+       if (nr_fds != 1) {
+               pr_debug("\nfdarray__filter()=%d != 1, should have left just one event", nr_fds);
+               goto out_delete;
+       }
+
+       if (fda->entries[0].fd != expected_fd[0]) {
+               pr_debug("\nfda->entries[0].fd=%d != %d\n",
+                        fda->entries[0].fd, expected_fd[0]);
+               goto out_delete;
+       }
+
+       fdarray__init_revents(fda, POLLHUP);
+       fda->entries[0].revents = POLLIN;
+       expected_fd[0] = fda->entries[0].fd;
+       fda->entries[3].revents = POLLIN;
+       expected_fd[1] = fda->entries[3].fd;
+
+       pr_debug("\nfiltering all but (fda->entries[0], fda->entries[3]):");
+       fdarray__fprintf_prefix(fda, "before", stderr);
+       nr_fds = fdarray__filter(fda, POLLHUP, NULL);
+       fdarray__fprintf_prefix(fda, " after", stderr);
+       if (nr_fds != 2) {
+               pr_debug("\nfdarray__filter()=%d != 2, should have left just two events",
+                        nr_fds);
+               goto out_delete;
+       }
+
+       for (fd = 0; fd < 2; ++fd) {
+               if (fda->entries[fd].fd != expected_fd[fd]) {
+                       pr_debug("\nfda->entries[%d].fd=%d != %d\n", fd,
+                                fda->entries[fd].fd, expected_fd[fd]);
+                       goto out_delete;
+               }
+       }
+
+       pr_debug("\n");
+
+       err = 0;
+out_delete:
+       fdarray__delete(fda);
+out:
+       return err;
+}
+
+int test__fdarray__add(void)
+{
+       int err = TEST_FAIL;
+       struct fdarray *fda = fdarray__new(2, 2);
+
+       if (fda == NULL) {
+               pr_debug("\nfdarray__new() failed!");
+               goto out;
+       }
+
+#define FDA_CHECK(_idx, _fd, _revents)                                    \
+       if (fda->entries[_idx].fd != _fd) {                                \
+               pr_debug("\n%d: fda->entries[%d](%d) != %d!",              \
+                        __LINE__, _idx, fda->entries[1].fd, _fd);         \
+               goto out_delete;                                           \
+       }                                                                  \
+       if (fda->entries[_idx].events != (_revents)) {                     \
+               pr_debug("\n%d: fda->entries[%d].revents(%d) != %d!",      \
+                        __LINE__, _idx, fda->entries[_idx].fd, _revents); \
+               goto out_delete;                                           \
+       }
+
+#define FDA_ADD(_idx, _fd, _revents, _nr)                                 \
+       if (fdarray__add(fda, _fd, _revents) < 0) {                        \
+               pr_debug("\n%d: fdarray__add(fda, %d, %d) failed!",        \
+                        __LINE__,_fd, _revents);                          \
+               goto out_delete;                                           \
+       }                                                                  \
+       if (fda->nr != _nr) {                                              \
+               pr_debug("\n%d: fdarray__add(fda, %d, %d)=%d != %d",       \
+                        __LINE__,_fd, _revents, fda->nr, _nr);            \
+               goto out_delete;                                           \
+       }                                                                  \
+       FDA_CHECK(_idx, _fd, _revents)
+
+       FDA_ADD(0, 1, POLLIN, 1);
+       FDA_ADD(1, 2, POLLERR, 2);
+
+       fdarray__fprintf_prefix(fda, "before growing array", stderr);
+
+       FDA_ADD(2, 35, POLLHUP, 3);
+
+       if (fda->entries == NULL) {
+               pr_debug("\nfdarray__add(fda, 35, POLLHUP) should have allocated fda->pollfd!");
+               goto out_delete;
+       }
+
+       fdarray__fprintf_prefix(fda, "after 3rd add", stderr);
+
+       FDA_ADD(3, 88, POLLIN | POLLOUT, 4);
+
+       fdarray__fprintf_prefix(fda, "after 4th add", stderr);
+
+       FDA_CHECK(0, 1, POLLIN);
+       FDA_CHECK(1, 2, POLLERR);
+       FDA_CHECK(2, 35, POLLHUP);
+       FDA_CHECK(3, 88, POLLIN | POLLOUT);
+
+#undef FDA_ADD
+#undef FDA_CHECK
+
+       pr_debug("\n");
+
+       err = 0;
+out_delete:
+       fdarray__delete(fda);
+out:
+       return err;
+}
index 142263492f6fe9234c8f4ba3141568e36f1bd38d..9b9622a33932dadf2e98bd249850c62f16ac66e5 100644 (file)
@@ -31,6 +31,7 @@ int test__basic_mmap(void)
        unsigned int nr_events[nsyscalls],
                     expected_nr_events[nsyscalls], i, j;
        struct perf_evsel *evsels[nsyscalls], *evsel;
+       char sbuf[STRERR_BUFSIZE];
 
        threads = thread_map__new(-1, getpid(), UINT_MAX);
        if (threads == NULL) {
@@ -49,7 +50,7 @@ int test__basic_mmap(void)
        sched_setaffinity(0, sizeof(cpu_set), &cpu_set);
        if (sched_setaffinity(0, sizeof(cpu_set), &cpu_set) < 0) {
                pr_debug("sched_setaffinity() failed on CPU %d: %s ",
-                        cpus->map[0], strerror(errno));
+                        cpus->map[0], strerror_r(errno, sbuf, sizeof(sbuf)));
                goto out_free_cpus;
        }
 
@@ -79,7 +80,7 @@ int test__basic_mmap(void)
                if (perf_evsel__open(evsels[i], cpus, threads) < 0) {
                        pr_debug("failed to open counter: %s, "
                                 "tweak /proc/sys/kernel/perf_event_paranoid?\n",
-                                strerror(errno));
+                                strerror_r(errno, sbuf, sizeof(sbuf)));
                        goto out_delete_evlist;
                }
 
@@ -89,7 +90,7 @@ int test__basic_mmap(void)
 
        if (perf_evlist__mmap(evlist, 128, true) < 0) {
                pr_debug("failed to mmap events: %d (%s)\n", errno,
-                        strerror(errno));
+                        strerror_r(errno, sbuf, sizeof(sbuf)));
                goto out_delete_evlist;
        }
 
index 5fecdbd2f5f772c09cb26d58cf9a1cb057cfa6a3..8fa82d1700c725f13519ef24ca4a8fbe8b235ea3 100644 (file)
@@ -12,6 +12,7 @@ int test__open_syscall_event_on_all_cpus(void)
        unsigned int nr_open_calls = 111, i;
        cpu_set_t cpu_set;
        struct thread_map *threads = thread_map__new(-1, getpid(), UINT_MAX);
+       char sbuf[STRERR_BUFSIZE];
 
        if (threads == NULL) {
                pr_debug("thread_map__new\n");
@@ -35,7 +36,7 @@ int test__open_syscall_event_on_all_cpus(void)
        if (perf_evsel__open(evsel, cpus, threads) < 0) {
                pr_debug("failed to open counter: %s, "
                         "tweak /proc/sys/kernel/perf_event_paranoid?\n",
-                        strerror(errno));
+                        strerror_r(errno, sbuf, sizeof(sbuf)));
                goto out_evsel_delete;
        }
 
@@ -56,7 +57,7 @@ int test__open_syscall_event_on_all_cpus(void)
                if (sched_setaffinity(0, sizeof(cpu_set), &cpu_set) < 0) {
                        pr_debug("sched_setaffinity() failed on CPU %d: %s ",
                                 cpus->map[cpu],
-                                strerror(errno));
+                                strerror_r(errno, sbuf, sizeof(sbuf)));
                        goto out_close_fd;
                }
                for (i = 0; i < ncalls; ++i) {
index 0785b64ffd6cd8b49009d89bdd935475e957f32a..127dcae0b76033cf457a4a4ff572da6771594e6f 100644 (file)
@@ -22,6 +22,7 @@ int test__syscall_open_tp_fields(void)
        struct perf_evlist *evlist = perf_evlist__new();
        struct perf_evsel *evsel;
        int err = -1, i, nr_events = 0, nr_polls = 0;
+       char sbuf[STRERR_BUFSIZE];
 
        if (evlist == NULL) {
                pr_debug("%s: perf_evlist__new\n", __func__);
@@ -48,13 +49,15 @@ int test__syscall_open_tp_fields(void)
 
        err = perf_evlist__open(evlist);
        if (err < 0) {
-               pr_debug("perf_evlist__open: %s\n", strerror(errno));
+               pr_debug("perf_evlist__open: %s\n",
+                        strerror_r(errno, sbuf, sizeof(sbuf)));
                goto out_delete_evlist;
        }
 
        err = perf_evlist__mmap(evlist, UINT_MAX, false);
        if (err < 0) {
-               pr_debug("perf_evlist__mmap: %s\n", strerror(errno));
+               pr_debug("perf_evlist__mmap: %s\n",
+                        strerror_r(errno, sbuf, sizeof(sbuf)));
                goto out_delete_evlist;
        }
 
@@ -102,7 +105,7 @@ int test__syscall_open_tp_fields(void)
                }
 
                if (nr_events == before)
-                       poll(evlist->pollfd, evlist->nr_fds, 10);
+                       perf_evlist__poll(evlist, 10);
 
                if (++nr_polls > 5) {
                        pr_debug("%s: no events!\n", __func__);
index c1dc7d25f38c6170847c74188ec5bac6d08e06f0..a33b2daae40f5239daa299a9a5335de26b39b420 100644 (file)
@@ -9,6 +9,7 @@ int test__open_syscall_event(void)
        struct perf_evsel *evsel;
        unsigned int nr_open_calls = 111, i;
        struct thread_map *threads = thread_map__new(-1, getpid(), UINT_MAX);
+       char sbuf[STRERR_BUFSIZE];
 
        if (threads == NULL) {
                pr_debug("thread_map__new\n");
@@ -24,7 +25,7 @@ int test__open_syscall_event(void)
        if (perf_evsel__open_per_thread(evsel, threads) < 0) {
                pr_debug("failed to open counter: %s, "
                         "tweak /proc/sys/kernel/perf_event_paranoid?\n",
-                        strerror(errno));
+                        strerror_r(errno, sbuf, sizeof(sbuf)));
                goto out_evsel_delete;
        }
 
index aca1a83dd13a946e8f47456725c3b725cfb4b25c..7a228a2a070bb2280d69320116b2985b5be05b21 100644 (file)
@@ -59,6 +59,7 @@ int test__PERF_RECORD(void)
        int err = -1, errs = 0, i, wakeups = 0;
        u32 cpu;
        int total_events = 0, nr_events[PERF_RECORD_MAX] = { 0, };
+       char sbuf[STRERR_BUFSIZE];
 
        if (evlist == NULL || argv == NULL) {
                pr_debug("Not enough memory to create evlist\n");
@@ -100,7 +101,8 @@ int test__PERF_RECORD(void)
 
        err = sched__get_first_possible_cpu(evlist->workload.pid, &cpu_mask);
        if (err < 0) {
-               pr_debug("sched__get_first_possible_cpu: %s\n", strerror(errno));
+               pr_debug("sched__get_first_possible_cpu: %s\n",
+                        strerror_r(errno, sbuf, sizeof(sbuf)));
                goto out_delete_evlist;
        }
 
@@ -110,7 +112,8 @@ int test__PERF_RECORD(void)
         * So that we can check perf_sample.cpu on all the samples.
         */
        if (sched_setaffinity(evlist->workload.pid, cpu_mask_size, &cpu_mask) < 0) {
-               pr_debug("sched_setaffinity: %s\n", strerror(errno));
+               pr_debug("sched_setaffinity: %s\n",
+                        strerror_r(errno, sbuf, sizeof(sbuf)));
                goto out_delete_evlist;
        }
 
@@ -120,7 +123,8 @@ int test__PERF_RECORD(void)
         */
        err = perf_evlist__open(evlist);
        if (err < 0) {
-               pr_debug("perf_evlist__open: %s\n", strerror(errno));
+               pr_debug("perf_evlist__open: %s\n",
+                        strerror_r(errno, sbuf, sizeof(sbuf)));
                goto out_delete_evlist;
        }
 
@@ -131,7 +135,8 @@ int test__PERF_RECORD(void)
         */
        err = perf_evlist__mmap(evlist, opts.mmap_pages, false);
        if (err < 0) {
-               pr_debug("perf_evlist__mmap: %s\n", strerror(errno));
+               pr_debug("perf_evlist__mmap: %s\n",
+                        strerror_r(errno, sbuf, sizeof(sbuf)));
                goto out_delete_evlist;
        }
 
@@ -263,7 +268,7 @@ int test__PERF_RECORD(void)
                 * perf_event_attr.wakeup_events, just PERF_EVENT_SAMPLE does.
                 */
                if (total_events == before && false)
-                       poll(evlist->pollfd, evlist->nr_fds, -1);
+                       perf_evlist__poll(evlist, -1);
 
                sleep(1);
                if (++wakeups > 5) {
index 12b322fa34753b9d463762276dc7ec4e9b0c909a..eeb68bb1972d44e41bafa5fc10809700e4afc630 100644 (file)
@@ -152,7 +152,7 @@ int test__pmu(void)
                if (ret)
                        break;
 
-               ret = perf_pmu__config_terms(&formats, &attr, terms);
+               ret = perf_pmu__config_terms(&formats, &attr, terms, false);
                if (ret)
                        break;
 
index c04d1f268576568f8a5b32c77e95796f40d8b723..d31f2c4d9f6491c62893f00cfbf46cdeff12ec90 100644 (file)
@@ -100,6 +100,7 @@ static int __test__rdpmc(void)
        };
        u64 delta_sum = 0;
         struct sigaction sa;
+       char sbuf[STRERR_BUFSIZE];
 
        sigfillset(&sa.sa_mask);
        sa.sa_sigaction = segfault_handler;
@@ -109,14 +110,15 @@ static int __test__rdpmc(void)
                                 perf_event_open_cloexec_flag());
        if (fd < 0) {
                pr_err("Error: sys_perf_event_open() syscall returned "
-                      "with %d (%s)\n", fd, strerror(errno));
+                      "with %d (%s)\n", fd,
+                      strerror_r(errno, sbuf, sizeof(sbuf)));
                return -1;
        }
 
        addr = mmap(NULL, page_size, PROT_READ, MAP_SHARED, fd, 0);
        if (addr == (void *)(-1)) {
                pr_err("Error: mmap() syscall returned with (%s)\n",
-                      strerror(errno));
+                      strerror_r(errno, sbuf, sizeof(sbuf)));
                goto out_close;
        }
 
index 983d6b8562a89f06f30f0aebd32e8b522f6b35fe..1aa21c90731b3eca400d91c2fec5d2b55a127f03 100644 (file)
@@ -22,6 +22,7 @@ static int __test__sw_clock_freq(enum perf_sw_ids clock_id)
        volatile int tmp = 0;
        u64 total_periods = 0;
        int nr_samples = 0;
+       char sbuf[STRERR_BUFSIZE];
        union perf_event *event;
        struct perf_evsel *evsel;
        struct perf_evlist *evlist;
@@ -62,14 +63,15 @@ static int __test__sw_clock_freq(enum perf_sw_ids clock_id)
 
                err = -errno;
                pr_debug("Couldn't open evlist: %s\nHint: check %s, using %" PRIu64 " in this test.\n",
-                        strerror(errno), knob, (u64)attr.sample_freq);
+                        strerror_r(errno, sbuf, sizeof(sbuf)),
+                        knob, (u64)attr.sample_freq);
                goto out_delete_evlist;
        }
 
        err = perf_evlist__mmap(evlist, 128, true);
        if (err < 0) {
                pr_debug("failed to mmap event: %d (%s)\n", errno,
-                        strerror(errno));
+                        strerror_r(errno, sbuf, sizeof(sbuf)));
                goto out_delete_evlist;
        }
 
diff --git a/tools/perf/tests/switch-tracking.c b/tools/perf/tests/switch-tracking.c
new file mode 100644 (file)
index 0000000..cc68648
--- /dev/null
@@ -0,0 +1,572 @@
+#include <sys/time.h>
+#include <sys/prctl.h>
+#include <time.h>
+#include <stdlib.h>
+
+#include "parse-events.h"
+#include "evlist.h"
+#include "evsel.h"
+#include "thread_map.h"
+#include "cpumap.h"
+#include "tests.h"
+
+static int spin_sleep(void)
+{
+       struct timeval start, now, diff, maxtime;
+       struct timespec ts;
+       int err, i;
+
+       maxtime.tv_sec = 0;
+       maxtime.tv_usec = 50000;
+
+       err = gettimeofday(&start, NULL);
+       if (err)
+               return err;
+
+       /* Spin for 50ms */
+       while (1) {
+               for (i = 0; i < 1000; i++)
+                       barrier();
+
+               err = gettimeofday(&now, NULL);
+               if (err)
+                       return err;
+
+               timersub(&now, &start, &diff);
+               if (timercmp(&diff, &maxtime, > /* For checkpatch */))
+                       break;
+       }
+
+       ts.tv_nsec = 50 * 1000 * 1000;
+       ts.tv_sec = 0;
+
+       /* Sleep for 50ms */
+       err = nanosleep(&ts, NULL);
+       if (err == EINTR)
+               err = 0;
+
+       return err;
+}
+
+struct switch_tracking {
+       struct perf_evsel *switch_evsel;
+       struct perf_evsel *cycles_evsel;
+       pid_t *tids;
+       int nr_tids;
+       int comm_seen[4];
+       int cycles_before_comm_1;
+       int cycles_between_comm_2_and_comm_3;
+       int cycles_after_comm_4;
+};
+
+static int check_comm(struct switch_tracking *switch_tracking,
+                     union perf_event *event, const char *comm, int nr)
+{
+       if (event->header.type == PERF_RECORD_COMM &&
+           (pid_t)event->comm.pid == getpid() &&
+           (pid_t)event->comm.tid == getpid() &&
+           strcmp(event->comm.comm, comm) == 0) {
+               if (switch_tracking->comm_seen[nr]) {
+                       pr_debug("Duplicate comm event\n");
+                       return -1;
+               }
+               switch_tracking->comm_seen[nr] = 1;
+               pr_debug3("comm event: %s nr: %d\n", event->comm.comm, nr);
+               return 1;
+       }
+       return 0;
+}
+
+static int check_cpu(struct switch_tracking *switch_tracking, int cpu)
+{
+       int i, nr = cpu + 1;
+
+       if (cpu < 0)
+               return -1;
+
+       if (!switch_tracking->tids) {
+               switch_tracking->tids = calloc(nr, sizeof(pid_t));
+               if (!switch_tracking->tids)
+                       return -1;
+               for (i = 0; i < nr; i++)
+                       switch_tracking->tids[i] = -1;
+               switch_tracking->nr_tids = nr;
+               return 0;
+       }
+
+       if (cpu >= switch_tracking->nr_tids) {
+               void *addr;
+
+               addr = realloc(switch_tracking->tids, nr * sizeof(pid_t));
+               if (!addr)
+                       return -1;
+               switch_tracking->tids = addr;
+               for (i = switch_tracking->nr_tids; i < nr; i++)
+                       switch_tracking->tids[i] = -1;
+               switch_tracking->nr_tids = nr;
+               return 0;
+       }
+
+       return 0;
+}
+
+static int process_sample_event(struct perf_evlist *evlist,
+                               union perf_event *event,
+                               struct switch_tracking *switch_tracking)
+{
+       struct perf_sample sample;
+       struct perf_evsel *evsel;
+       pid_t next_tid, prev_tid;
+       int cpu, err;
+
+       if (perf_evlist__parse_sample(evlist, event, &sample)) {
+               pr_debug("perf_evlist__parse_sample failed\n");
+               return -1;
+       }
+
+       evsel = perf_evlist__id2evsel(evlist, sample.id);
+       if (evsel == switch_tracking->switch_evsel) {
+               next_tid = perf_evsel__intval(evsel, &sample, "next_pid");
+               prev_tid = perf_evsel__intval(evsel, &sample, "prev_pid");
+               cpu = sample.cpu;
+               pr_debug3("sched_switch: cpu: %d prev_tid %d next_tid %d\n",
+                         cpu, prev_tid, next_tid);
+               err = check_cpu(switch_tracking, cpu);
+               if (err)
+                       return err;
+               /*
+                * Check for no missing sched_switch events i.e. that the
+                * evsel->system_wide flag has worked.
+                */
+               if (switch_tracking->tids[cpu] != -1 &&
+                   switch_tracking->tids[cpu] != prev_tid) {
+                       pr_debug("Missing sched_switch events\n");
+                       return -1;
+               }
+               switch_tracking->tids[cpu] = next_tid;
+       }
+
+       if (evsel == switch_tracking->cycles_evsel) {
+               pr_debug3("cycles event\n");
+               if (!switch_tracking->comm_seen[0])
+                       switch_tracking->cycles_before_comm_1 = 1;
+               if (switch_tracking->comm_seen[1] &&
+                   !switch_tracking->comm_seen[2])
+                       switch_tracking->cycles_between_comm_2_and_comm_3 = 1;
+               if (switch_tracking->comm_seen[3])
+                       switch_tracking->cycles_after_comm_4 = 1;
+       }
+
+       return 0;
+}
+
+static int process_event(struct perf_evlist *evlist, union perf_event *event,
+                        struct switch_tracking *switch_tracking)
+{
+       if (event->header.type == PERF_RECORD_SAMPLE)
+               return process_sample_event(evlist, event, switch_tracking);
+
+       if (event->header.type == PERF_RECORD_COMM) {
+               int err, done = 0;
+
+               err = check_comm(switch_tracking, event, "Test COMM 1", 0);
+               if (err < 0)
+                       return -1;
+               done += err;
+               err = check_comm(switch_tracking, event, "Test COMM 2", 1);
+               if (err < 0)
+                       return -1;
+               done += err;
+               err = check_comm(switch_tracking, event, "Test COMM 3", 2);
+               if (err < 0)
+                       return -1;
+               done += err;
+               err = check_comm(switch_tracking, event, "Test COMM 4", 3);
+               if (err < 0)
+                       return -1;
+               done += err;
+               if (done != 1) {
+                       pr_debug("Unexpected comm event\n");
+                       return -1;
+               }
+       }
+
+       return 0;
+}
+
+struct event_node {
+       struct list_head list;
+       union perf_event *event;
+       u64 event_time;
+};
+
+static int add_event(struct perf_evlist *evlist, struct list_head *events,
+                    union perf_event *event)
+{
+       struct perf_sample sample;
+       struct event_node *node;
+
+       node = malloc(sizeof(struct event_node));
+       if (!node) {
+               pr_debug("malloc failed\n");
+               return -1;
+       }
+       node->event = event;
+       list_add(&node->list, events);
+
+       if (perf_evlist__parse_sample(evlist, event, &sample)) {
+               pr_debug("perf_evlist__parse_sample failed\n");
+               return -1;
+       }
+
+       if (!sample.time) {
+               pr_debug("event with no time\n");
+               return -1;
+       }
+
+       node->event_time = sample.time;
+
+       return 0;
+}
+
+static void free_event_nodes(struct list_head *events)
+{
+       struct event_node *node;
+
+       while (!list_empty(events)) {
+               node = list_entry(events->next, struct event_node, list);
+               list_del(&node->list);
+               free(node);
+       }
+}
+
+static int compar(const void *a, const void *b)
+{
+       const struct event_node *nodea = a;
+       const struct event_node *nodeb = b;
+       s64 cmp = nodea->event_time - nodeb->event_time;
+
+       return cmp;
+}
+
+static int process_events(struct perf_evlist *evlist,
+                         struct switch_tracking *switch_tracking)
+{
+       union perf_event *event;
+       unsigned pos, cnt = 0;
+       LIST_HEAD(events);
+       struct event_node *events_array, *node;
+       int i, ret;
+
+       for (i = 0; i < evlist->nr_mmaps; i++) {
+               while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
+                       cnt += 1;
+                       ret = add_event(evlist, &events, event);
+                       perf_evlist__mmap_consume(evlist, i);
+                       if (ret < 0)
+                               goto out_free_nodes;
+               }
+       }
+
+       events_array = calloc(cnt, sizeof(struct event_node));
+       if (!events_array) {
+               pr_debug("calloc failed\n");
+               ret = -1;
+               goto out_free_nodes;
+       }
+
+       pos = 0;
+       list_for_each_entry(node, &events, list)
+               events_array[pos++] = *node;
+
+       qsort(events_array, cnt, sizeof(struct event_node), compar);
+
+       for (pos = 0; pos < cnt; pos++) {
+               ret = process_event(evlist, events_array[pos].event,
+                                   switch_tracking);
+               if (ret < 0)
+                       goto out_free;
+       }
+
+       ret = 0;
+out_free:
+       pr_debug("%u events recorded\n", cnt);
+       free(events_array);
+out_free_nodes:
+       free_event_nodes(&events);
+       return ret;
+}
+
+/**
+ * test__switch_tracking - test using sched_switch and tracking events.
+ *
+ * This function implements a test that checks that sched_switch events and
+ * tracking events can be recorded for a workload (current process) using the
+ * evsel->system_wide and evsel->tracking flags (respectively) with other events
+ * sometimes enabled or disabled.
+ */
+int test__switch_tracking(void)
+{
+       const char *sched_switch = "sched:sched_switch";
+       struct switch_tracking switch_tracking = { .tids = NULL, };
+       struct record_opts opts = {
+               .mmap_pages          = UINT_MAX,
+               .user_freq           = UINT_MAX,
+               .user_interval       = ULLONG_MAX,
+               .freq                = 4000,
+               .target              = {
+                       .uses_mmap   = true,
+               },
+       };
+       struct thread_map *threads = NULL;
+       struct cpu_map *cpus = NULL;
+       struct perf_evlist *evlist = NULL;
+       struct perf_evsel *evsel, *cpu_clocks_evsel, *cycles_evsel;
+       struct perf_evsel *switch_evsel, *tracking_evsel;
+       const char *comm;
+       int err = -1;
+
+       threads = thread_map__new(-1, getpid(), UINT_MAX);
+       if (!threads) {
+               pr_debug("thread_map__new failed!\n");
+               goto out_err;
+       }
+
+       cpus = cpu_map__new(NULL);
+       if (!cpus) {
+               pr_debug("cpu_map__new failed!\n");
+               goto out_err;
+       }
+
+       evlist = perf_evlist__new();
+       if (!evlist) {
+               pr_debug("perf_evlist__new failed!\n");
+               goto out_err;
+       }
+
+       perf_evlist__set_maps(evlist, cpus, threads);
+
+       /* First event */
+       err = parse_events(evlist, "cpu-clock:u");
+       if (err) {
+               pr_debug("Failed to parse event dummy:u\n");
+               goto out_err;
+       }
+
+       cpu_clocks_evsel = perf_evlist__last(evlist);
+
+       /* Second event */
+       err = parse_events(evlist, "cycles:u");
+       if (err) {
+               pr_debug("Failed to parse event cycles:u\n");
+               goto out_err;
+       }
+
+       cycles_evsel = perf_evlist__last(evlist);
+
+       /* Third event */
+       if (!perf_evlist__can_select_event(evlist, sched_switch)) {
+               fprintf(stderr, " (no sched_switch)");
+               err = 0;
+               goto out;
+       }
+
+       err = parse_events(evlist, sched_switch);
+       if (err) {
+               pr_debug("Failed to parse event %s\n", sched_switch);
+               goto out_err;
+       }
+
+       switch_evsel = perf_evlist__last(evlist);
+
+       perf_evsel__set_sample_bit(switch_evsel, CPU);
+       perf_evsel__set_sample_bit(switch_evsel, TIME);
+
+       switch_evsel->system_wide = true;
+       switch_evsel->no_aux_samples = true;
+       switch_evsel->immediate = true;
+
+       /* Test moving an event to the front */
+       if (cycles_evsel == perf_evlist__first(evlist)) {
+               pr_debug("cycles event already at front");
+               goto out_err;
+       }
+       perf_evlist__to_front(evlist, cycles_evsel);
+       if (cycles_evsel != perf_evlist__first(evlist)) {
+               pr_debug("Failed to move cycles event to front");
+               goto out_err;
+       }
+
+       perf_evsel__set_sample_bit(cycles_evsel, CPU);
+       perf_evsel__set_sample_bit(cycles_evsel, TIME);
+
+       /* Fourth event */
+       err = parse_events(evlist, "dummy:u");
+       if (err) {
+               pr_debug("Failed to parse event dummy:u\n");
+               goto out_err;
+       }
+
+       tracking_evsel = perf_evlist__last(evlist);
+
+       perf_evlist__set_tracking_event(evlist, tracking_evsel);
+
+       tracking_evsel->attr.freq = 0;
+       tracking_evsel->attr.sample_period = 1;
+
+       perf_evsel__set_sample_bit(tracking_evsel, TIME);
+
+       /* Config events */
+       perf_evlist__config(evlist, &opts);
+
+       /* Check moved event is still at the front */
+       if (cycles_evsel != perf_evlist__first(evlist)) {
+               pr_debug("Front event no longer at front");
+               goto out_err;
+       }
+
+       /* Check tracking event is tracking */
+       if (!tracking_evsel->attr.mmap || !tracking_evsel->attr.comm) {
+               pr_debug("Tracking event not tracking\n");
+               goto out_err;
+       }
+
+       /* Check non-tracking events are not tracking */
+       evlist__for_each(evlist, evsel) {
+               if (evsel != tracking_evsel) {
+                       if (evsel->attr.mmap || evsel->attr.comm) {
+                               pr_debug("Non-tracking event is tracking\n");
+                               goto out_err;
+                       }
+               }
+       }
+
+       if (perf_evlist__open(evlist) < 0) {
+               fprintf(stderr, " (not supported)");
+               err = 0;
+               goto out;
+       }
+
+       err = perf_evlist__mmap(evlist, UINT_MAX, false);
+       if (err) {
+               pr_debug("perf_evlist__mmap failed!\n");
+               goto out_err;
+       }
+
+       perf_evlist__enable(evlist);
+
+       err = perf_evlist__disable_event(evlist, cpu_clocks_evsel);
+       if (err) {
+               pr_debug("perf_evlist__disable_event failed!\n");
+               goto out_err;
+       }
+
+       err = spin_sleep();
+       if (err) {
+               pr_debug("spin_sleep failed!\n");
+               goto out_err;
+       }
+
+       comm = "Test COMM 1";
+       err = prctl(PR_SET_NAME, (unsigned long)comm, 0, 0, 0);
+       if (err) {
+               pr_debug("PR_SET_NAME failed!\n");
+               goto out_err;
+       }
+
+       err = perf_evlist__disable_event(evlist, cycles_evsel);
+       if (err) {
+               pr_debug("perf_evlist__disable_event failed!\n");
+               goto out_err;
+       }
+
+       comm = "Test COMM 2";
+       err = prctl(PR_SET_NAME, (unsigned long)comm, 0, 0, 0);
+       if (err) {
+               pr_debug("PR_SET_NAME failed!\n");
+               goto out_err;
+       }
+
+       err = spin_sleep();
+       if (err) {
+               pr_debug("spin_sleep failed!\n");
+               goto out_err;
+       }
+
+       comm = "Test COMM 3";
+       err = prctl(PR_SET_NAME, (unsigned long)comm, 0, 0, 0);
+       if (err) {
+               pr_debug("PR_SET_NAME failed!\n");
+               goto out_err;
+       }
+
+       err = perf_evlist__enable_event(evlist, cycles_evsel);
+       if (err) {
+               pr_debug("perf_evlist__disable_event failed!\n");
+               goto out_err;
+       }
+
+       comm = "Test COMM 4";
+       err = prctl(PR_SET_NAME, (unsigned long)comm, 0, 0, 0);
+       if (err) {
+               pr_debug("PR_SET_NAME failed!\n");
+               goto out_err;
+       }
+
+       err = spin_sleep();
+       if (err) {
+               pr_debug("spin_sleep failed!\n");
+               goto out_err;
+       }
+
+       perf_evlist__disable(evlist);
+
+       switch_tracking.switch_evsel = switch_evsel;
+       switch_tracking.cycles_evsel = cycles_evsel;
+
+       err = process_events(evlist, &switch_tracking);
+
+       zfree(&switch_tracking.tids);
+
+       if (err)
+               goto out_err;
+
+       /* Check all 4 comm events were seen i.e. that evsel->tracking works */
+       if (!switch_tracking.comm_seen[0] || !switch_tracking.comm_seen[1] ||
+           !switch_tracking.comm_seen[2] || !switch_tracking.comm_seen[3]) {
+               pr_debug("Missing comm events\n");
+               goto out_err;
+       }
+
+       /* Check cycles event got enabled */
+       if (!switch_tracking.cycles_before_comm_1) {
+               pr_debug("Missing cycles events\n");
+               goto out_err;
+       }
+
+       /* Check cycles event got disabled */
+       if (switch_tracking.cycles_between_comm_2_and_comm_3) {
+               pr_debug("cycles events even though event was disabled\n");
+               goto out_err;
+       }
+
+       /* Check cycles event got enabled again */
+       if (!switch_tracking.cycles_after_comm_4) {
+               pr_debug("Missing cycles events\n");
+               goto out_err;
+       }
+out:
+       if (evlist) {
+               perf_evlist__disable(evlist);
+               perf_evlist__delete(evlist);
+       } else {
+               cpu_map__delete(cpus);
+               thread_map__delete(threads);
+       }
+
+       return err;
+
+out_err:
+       err = -1;
+       goto out;
+}
index 5ff3db318f12ae5971d3916fc49599e14fd51075..3a8fedef83bc086e5328dea03dcf6107d3ff1e39 100644 (file)
@@ -42,6 +42,7 @@ int test__task_exit(void)
                .uses_mmap      = true,
        };
        const char *argv[] = { "true", NULL };
+       char sbuf[STRERR_BUFSIZE];
 
        signal(SIGCHLD, sig_handler);
 
@@ -82,13 +83,14 @@ int test__task_exit(void)
 
        err = perf_evlist__open(evlist);
        if (err < 0) {
-               pr_debug("Couldn't open the evlist: %s\n", strerror(-err));
+               pr_debug("Couldn't open the evlist: %s\n",
+                        strerror_r(-err, sbuf, sizeof(sbuf)));
                goto out_delete_evlist;
        }
 
        if (perf_evlist__mmap(evlist, 128, true) < 0) {
                pr_debug("failed to mmap events: %d (%s)\n", errno,
-                        strerror(errno));
+                        strerror_r(errno, sbuf, sizeof(sbuf)));
                goto out_delete_evlist;
        }
 
@@ -103,7 +105,7 @@ retry:
        }
 
        if (!exited || !nr_exit) {
-               poll(evlist->pollfd, evlist->nr_fds, -1);
+               perf_evlist__poll(evlist, -1);
                goto retry;
        }
 
index ed64790a395f16093748e2c199b9369665a3c316..00e776a87a9c76e3821953fcd203c1df59189e25 100644 (file)
@@ -48,6 +48,9 @@ int test__mmap_thread_lookup(void);
 int test__thread_mg_share(void);
 int test__hists_output(void);
 int test__hists_cumulate(void);
+int test__switch_tracking(void);
+int test__fdarray__filter(void);
+int test__fdarray__add(void);
 
 #if defined(__x86_64__) || defined(__i386__) || defined(__arm__)
 #ifdef HAVE_DWARF_UNWIND_SUPPORT
index a94b11fc5e00263bd1adf50a456925fbc895d5aa..8f60a970404f8e82ed009fc2847945590581fde6 100644 (file)
@@ -10,6 +10,7 @@
 #include "../../util/pstack.h"
 #include "../../util/sort.h"
 #include "../../util/util.h"
+#include "../../util/top.h"
 #include "../../arch/common.h"
 
 #include "../browser.h"
@@ -228,8 +229,10 @@ static void callchain_node__init_have_children(struct callchain_node *node)
 {
        struct callchain_list *chain;
 
-       list_for_each_entry(chain, &node->val, list)
+       if (!list_empty(&node->val)) {
+               chain = list_entry(node->val.prev, struct callchain_list, list);
                chain->ms.has_children = !RB_EMPTY_ROOT(&node->rb_root);
+       }
 
        callchain_node__init_have_children_rb_tree(node);
 }
@@ -474,26 +477,87 @@ static char *callchain_list__sym_name(struct callchain_list *cl,
        return bf;
 }
 
+struct callchain_print_arg {
+       /* for hists browser */
+       off_t   row_offset;
+       bool    is_current_entry;
+
+       /* for file dump */
+       FILE    *fp;
+       int     printed;
+};
+
+typedef void (*print_callchain_entry_fn)(struct hist_browser *browser,
+                                        struct callchain_list *chain,
+                                        const char *str, int offset,
+                                        unsigned short row,
+                                        struct callchain_print_arg *arg);
+
+static void hist_browser__show_callchain_entry(struct hist_browser *browser,
+                                              struct callchain_list *chain,
+                                              const char *str, int offset,
+                                              unsigned short row,
+                                              struct callchain_print_arg *arg)
+{
+       int color, width;
+       char folded_sign = callchain_list__folded(chain);
+
+       color = HE_COLORSET_NORMAL;
+       width = browser->b.width - (offset + 2);
+       if (ui_browser__is_current_entry(&browser->b, row)) {
+               browser->selection = &chain->ms;
+               color = HE_COLORSET_SELECTED;
+               arg->is_current_entry = true;
+       }
+
+       ui_browser__set_color(&browser->b, color);
+       hist_browser__gotorc(browser, row, 0);
+       slsmg_write_nstring(" ", offset);
+       slsmg_printf("%c ", folded_sign);
+       slsmg_write_nstring(str, width);
+}
+
+static void hist_browser__fprintf_callchain_entry(struct hist_browser *b __maybe_unused,
+                                                 struct callchain_list *chain,
+                                                 const char *str, int offset,
+                                                 unsigned short row __maybe_unused,
+                                                 struct callchain_print_arg *arg)
+{
+       char folded_sign = callchain_list__folded(chain);
+
+       arg->printed += fprintf(arg->fp, "%*s%c %s\n", offset, " ",
+                               folded_sign, str);
+}
+
+typedef bool (*check_output_full_fn)(struct hist_browser *browser,
+                                    unsigned short row);
+
+static bool hist_browser__check_output_full(struct hist_browser *browser,
+                                           unsigned short row)
+{
+       return browser->b.rows == row;
+}
+
+static bool hist_browser__check_dump_full(struct hist_browser *browser __maybe_unused,
+                                         unsigned short row __maybe_unused)
+{
+       return false;
+}
+
 #define LEVEL_OFFSET_STEP 3
 
-static int hist_browser__show_callchain_node_rb_tree(struct hist_browser *browser,
-                                                    struct callchain_node *chain_node,
-                                                    u64 total, int level,
-                                                    unsigned short row,
-                                                    off_t *row_offset,
-                                                    bool *is_current_entry)
+static int hist_browser__show_callchain(struct hist_browser *browser,
+                                       struct rb_root *root, int level,
+                                       unsigned short row, u64 total,
+                                       print_callchain_entry_fn print,
+                                       struct callchain_print_arg *arg,
+                                       check_output_full_fn is_output_full)
 {
        struct rb_node *node;
-       int first_row = row, width, offset = level * LEVEL_OFFSET_STEP;
-       u64 new_total, remaining;
+       int first_row = row, offset = level * LEVEL_OFFSET_STEP;
+       u64 new_total;
 
-       if (callchain_param.mode == CHAIN_GRAPH_REL)
-               new_total = chain_node->children_hit;
-       else
-               new_total = total;
-
-       remaining = new_total;
-       node = rb_first(&chain_node->rb_root);
+       node = rb_first(root);
        while (node) {
                struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
                struct rb_node *next = rb_next(node);
@@ -503,30 +567,28 @@ static int hist_browser__show_callchain_node_rb_tree(struct hist_browser *browse
                int first = true;
                int extra_offset = 0;
 
-               remaining -= cumul;
-
                list_for_each_entry(chain, &child->val, list) {
                        char bf[1024], *alloc_str;
                        const char *str;
-                       int color;
                        bool was_first = first;
 
                        if (first)
                                first = false;
-                       else
+                       else if (level > 1)
                                extra_offset = LEVEL_OFFSET_STEP;
 
                        folded_sign = callchain_list__folded(chain);
-                       if (*row_offset != 0) {
-                               --*row_offset;
+                       if (arg->row_offset != 0) {
+                               arg->row_offset--;
                                goto do_next;
                        }
 
                        alloc_str = NULL;
                        str = callchain_list__sym_name(chain, bf, sizeof(bf),
                                                       browser->show_dso);
-                       if (was_first) {
-                               double percent = cumul * 100.0 / new_total;
+
+                       if (was_first && level > 1) {
+                               double percent = cumul * 100.0 / total;
 
                                if (asprintf(&alloc_str, "%2.2f%% %s", percent, str) < 0)
                                        str = "Not enough memory!";
@@ -534,22 +596,11 @@ static int hist_browser__show_callchain_node_rb_tree(struct hist_browser *browse
                                        str = alloc_str;
                        }
 
-                       color = HE_COLORSET_NORMAL;
-                       width = browser->b.width - (offset + extra_offset + 2);
-                       if (ui_browser__is_current_entry(&browser->b, row)) {
-                               browser->selection = &chain->ms;
-                               color = HE_COLORSET_SELECTED;
-                               *is_current_entry = true;
-                       }
+                       print(browser, chain, str, offset + extra_offset, row, arg);
 
-                       ui_browser__set_color(&browser->b, color);
-                       hist_browser__gotorc(browser, row, 0);
-                       slsmg_write_nstring(" ", offset + extra_offset);
-                       slsmg_printf("%c ", folded_sign);
-                       slsmg_write_nstring(str, width);
                        free(alloc_str);
 
-                       if (++row == browser->b.rows)
+                       if (is_output_full(browser, ++row))
                                goto out;
 do_next:
                        if (folded_sign == '+')
@@ -558,89 +609,21 @@ do_next:
 
                if (folded_sign == '-') {
                        const int new_level = level + (extra_offset ? 2 : 1);
-                       row += hist_browser__show_callchain_node_rb_tree(browser, child, new_total,
-                                                                        new_level, row, row_offset,
-                                                                        is_current_entry);
-               }
-               if (row == browser->b.rows)
-                       goto out;
-               node = next;
-       }
-out:
-       return row - first_row;
-}
-
-static int hist_browser__show_callchain_node(struct hist_browser *browser,
-                                            struct callchain_node *node,
-                                            int level, unsigned short row,
-                                            off_t *row_offset,
-                                            bool *is_current_entry)
-{
-       struct callchain_list *chain;
-       int first_row = row,
-            offset = level * LEVEL_OFFSET_STEP,
-            width = browser->b.width - offset;
-       char folded_sign = ' ';
 
-       list_for_each_entry(chain, &node->val, list) {
-               char bf[1024], *s;
-               int color;
-
-               folded_sign = callchain_list__folded(chain);
-
-               if (*row_offset != 0) {
-                       --*row_offset;
-                       continue;
-               }
+                       if (callchain_param.mode == CHAIN_GRAPH_REL)
+                               new_total = child->children_hit;
+                       else
+                               new_total = total;
 
-               color = HE_COLORSET_NORMAL;
-               if (ui_browser__is_current_entry(&browser->b, row)) {
-                       browser->selection = &chain->ms;
-                       color = HE_COLORSET_SELECTED;
-                       *is_current_entry = true;
+                       row += hist_browser__show_callchain(browser, &child->rb_root,
+                                                           new_level, row, new_total,
+                                                           print, arg, is_output_full);
                }
-
-               s = callchain_list__sym_name(chain, bf, sizeof(bf),
-                                            browser->show_dso);
-               hist_browser__gotorc(browser, row, 0);
-               ui_browser__set_color(&browser->b, color);
-               slsmg_write_nstring(" ", offset);
-               slsmg_printf("%c ", folded_sign);
-               slsmg_write_nstring(s, width - 2);
-
-               if (++row == browser->b.rows)
-                       goto out;
-       }
-
-       if (folded_sign == '-')
-               row += hist_browser__show_callchain_node_rb_tree(browser, node,
-                                                                browser->hists->stats.total_period,
-                                                                level + 1, row,
-                                                                row_offset,
-                                                                is_current_entry);
-out:
-       return row - first_row;
-}
-
-static int hist_browser__show_callchain(struct hist_browser *browser,
-                                       struct rb_root *chain,
-                                       int level, unsigned short row,
-                                       off_t *row_offset,
-                                       bool *is_current_entry)
-{
-       struct rb_node *nd;
-       int first_row = row;
-
-       for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
-               struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
-
-               row += hist_browser__show_callchain_node(browser, node, level,
-                                                        row, row_offset,
-                                                        is_current_entry);
-               if (row == browser->b.rows)
+               if (is_output_full(browser, row))
                        break;
+               node = next;
        }
-
+out:
        return row - first_row;
 }
 
@@ -653,17 +636,18 @@ struct hpp_arg {
 static int __hpp__slsmg_color_printf(struct perf_hpp *hpp, const char *fmt, ...)
 {
        struct hpp_arg *arg = hpp->ptr;
-       int ret;
+       int ret, len;
        va_list args;
        double percent;
 
        va_start(args, fmt);
+       len = va_arg(args, int);
        percent = va_arg(args, double);
        va_end(args);
 
        ui_browser__set_percent_color(arg->b, percent, arg->current_entry);
 
-       ret = scnprintf(hpp->buf, hpp->size, fmt, percent);
+       ret = scnprintf(hpp->buf, hpp->size, fmt, len, percent);
        slsmg_printf("%s", hpp->buf);
 
        advance_hpp(hpp, ret);
@@ -677,12 +661,12 @@ static u64 __hpp_get_##_field(struct hist_entry *he)                      \
 }                                                                      \
                                                                        \
 static int                                                             \
-hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt __maybe_unused,\
+hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt,              \
                                struct perf_hpp *hpp,                   \
                                struct hist_entry *he)                  \
 {                                                                      \
-       return __hpp__fmt(hpp, he, __hpp_get_##_field, " %6.2f%%",      \
-                         __hpp__slsmg_color_printf, true);             \
+       return hpp__fmt(fmt, hpp, he, __hpp_get_##_field, " %*.2f%%",   \
+                       __hpp__slsmg_color_printf, true);               \
 }
 
 #define __HPP_COLOR_ACC_PERCENT_FN(_type, _field)                      \
@@ -692,18 +676,20 @@ static u64 __hpp_get_acc_##_field(struct hist_entry *he)          \
 }                                                                      \
                                                                        \
 static int                                                             \
-hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt __maybe_unused,\
+hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt,              \
                                struct perf_hpp *hpp,                   \
                                struct hist_entry *he)                  \
 {                                                                      \
        if (!symbol_conf.cumulate_callchain) {                          \
-               int ret = scnprintf(hpp->buf, hpp->size, "%8s", "N/A"); \
+               int len = fmt->user_len ?: fmt->len;                    \
+               int ret = scnprintf(hpp->buf, hpp->size,                \
+                                   "%*s", len, "N/A");                 \
                slsmg_printf("%s", hpp->buf);                           \
                                                                        \
                return ret;                                             \
        }                                                               \
-       return __hpp__fmt(hpp, he, __hpp_get_acc_##_field, " %6.2f%%",  \
-                         __hpp__slsmg_color_printf, true);             \
+       return hpp__fmt(fmt, hpp, he, __hpp_get_acc_##_field,           \
+                       " %*.2f%%", __hpp__slsmg_color_printf, true);   \
 }
 
 __HPP_COLOR_PERCENT_FN(overhead, period)
@@ -812,10 +798,18 @@ static int hist_browser__show_entry(struct hist_browser *browser,
                --row_offset;
 
        if (folded_sign == '-' && row != browser->b.rows) {
-               printed += hist_browser__show_callchain(browser, &entry->sorted_chain,
-                                                       1, row, &row_offset,
-                                                       &current_entry);
-               if (current_entry)
+               u64 total = hists__total_period(entry->hists);
+               struct callchain_print_arg arg = {
+                       .row_offset = row_offset,
+                       .is_current_entry = current_entry,
+               };
+
+               printed += hist_browser__show_callchain(browser,
+                                       &entry->sorted_chain, 1, row, total,
+                                       hist_browser__show_callchain_entry, &arg,
+                                       hist_browser__check_output_full);
+
+               if (arg.is_current_entry)
                        browser->he_selection = entry;
        }
 
@@ -847,9 +841,6 @@ static int hists__scnprintf_headers(char *buf, size_t size, struct hists *hists)
                if (perf_hpp__should_skip(fmt))
                        continue;
 
-               /* We need to add the length of the columns header. */
-               perf_hpp__reset_width(fmt, hists);
-
                ret = fmt->header(fmt, &dummy_hpp, hists_to_evsel(hists));
                if (advance_hpp_check(&dummy_hpp, ret))
                        break;
@@ -1074,113 +1065,21 @@ do_offset:
        }
 }
 
-static int hist_browser__fprintf_callchain_node_rb_tree(struct hist_browser *browser,
-                                                       struct callchain_node *chain_node,
-                                                       u64 total, int level,
-                                                       FILE *fp)
-{
-       struct rb_node *node;
-       int offset = level * LEVEL_OFFSET_STEP;
-       u64 new_total, remaining;
-       int printed = 0;
-
-       if (callchain_param.mode == CHAIN_GRAPH_REL)
-               new_total = chain_node->children_hit;
-       else
-               new_total = total;
-
-       remaining = new_total;
-       node = rb_first(&chain_node->rb_root);
-       while (node) {
-               struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
-               struct rb_node *next = rb_next(node);
-               u64 cumul = callchain_cumul_hits(child);
-               struct callchain_list *chain;
-               char folded_sign = ' ';
-               int first = true;
-               int extra_offset = 0;
-
-               remaining -= cumul;
-
-               list_for_each_entry(chain, &child->val, list) {
-                       char bf[1024], *alloc_str;
-                       const char *str;
-                       bool was_first = first;
-
-                       if (first)
-                               first = false;
-                       else
-                               extra_offset = LEVEL_OFFSET_STEP;
-
-                       folded_sign = callchain_list__folded(chain);
-
-                       alloc_str = NULL;
-                       str = callchain_list__sym_name(chain, bf, sizeof(bf),
-                                                      browser->show_dso);
-                       if (was_first) {
-                               double percent = cumul * 100.0 / new_total;
-
-                               if (asprintf(&alloc_str, "%2.2f%% %s", percent, str) < 0)
-                                       str = "Not enough memory!";
-                               else
-                                       str = alloc_str;
-                       }
-
-                       printed += fprintf(fp, "%*s%c %s\n", offset + extra_offset, " ", folded_sign, str);
-                       free(alloc_str);
-                       if (folded_sign == '+')
-                               break;
-               }
-
-               if (folded_sign == '-') {
-                       const int new_level = level + (extra_offset ? 2 : 1);
-                       printed += hist_browser__fprintf_callchain_node_rb_tree(browser, child, new_total,
-                                                                               new_level, fp);
-               }
-
-               node = next;
-       }
-
-       return printed;
-}
-
-static int hist_browser__fprintf_callchain_node(struct hist_browser *browser,
-                                               struct callchain_node *node,
-                                               int level, FILE *fp)
-{
-       struct callchain_list *chain;
-       int offset = level * LEVEL_OFFSET_STEP;
-       char folded_sign = ' ';
-       int printed = 0;
-
-       list_for_each_entry(chain, &node->val, list) {
-               char bf[1024], *s;
-
-               folded_sign = callchain_list__folded(chain);
-               s = callchain_list__sym_name(chain, bf, sizeof(bf), browser->show_dso);
-               printed += fprintf(fp, "%*s%c %s\n", offset, " ", folded_sign, s);
-       }
-
-       if (folded_sign == '-')
-               printed += hist_browser__fprintf_callchain_node_rb_tree(browser, node,
-                                                                       browser->hists->stats.total_period,
-                                                                       level + 1,  fp);
-       return printed;
-}
-
 static int hist_browser__fprintf_callchain(struct hist_browser *browser,
-                                          struct rb_root *chain, int level, FILE *fp)
+                                          struct hist_entry *he, FILE *fp)
 {
-       struct rb_node *nd;
-       int printed = 0;
+       u64 total = hists__total_period(he->hists);
+       struct callchain_print_arg arg  = {
+               .fp = fp,
+       };
 
-       for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
-               struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
+       if (symbol_conf.cumulate_callchain)
+               total = he->stat_acc->period;
 
-               printed += hist_browser__fprintf_callchain_node(browser, node, level, fp);
-       }
-
-       return printed;
+       hist_browser__show_callchain(browser, &he->sorted_chain, 1, 0, total,
+                                    hist_browser__fprintf_callchain_entry, &arg,
+                                    hist_browser__check_dump_full);
+       return arg.printed;
 }
 
 static int hist_browser__fprintf_entry(struct hist_browser *browser,
@@ -1219,7 +1118,7 @@ static int hist_browser__fprintf_entry(struct hist_browser *browser,
        printed += fprintf(fp, "%s\n", rtrim(s));
 
        if (folded_sign == '-')
-               printed += hist_browser__fprintf_callchain(browser, &he->sorted_chain, 1, fp);
+               printed += hist_browser__fprintf_callchain(browser, he, fp);
 
        return printed;
 }
@@ -1498,6 +1397,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
        char buf[64];
        char script_opt[64];
        int delay_secs = hbt ? hbt->refresh : 0;
+       struct perf_hpp_fmt *fmt;
 
 #define HIST_BROWSER_HELP_COMMON                                       \
        "h/?/F1        Show this window\n"                              \
@@ -1529,6 +1429,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
        "P             Print histograms to perf.hist.N\n"
        "t             Zoom into current Thread\n"
        "V             Verbose (DSO names in callchains, etc)\n"
+       "z             Toggle zeroing of samples\n"
        "/             Filter symbol by name";
 
        if (browser == NULL)
@@ -1547,6 +1448,12 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
 
        memset(options, 0, sizeof(options));
 
+       perf_hpp__for_each_format(fmt)
+               perf_hpp__reset_width(fmt, hists);
+
+       if (symbol_conf.col_width_list_str)
+               perf_hpp__set_user_width(symbol_conf.col_width_list_str);
+
        while (1) {
                const struct thread *thread = NULL;
                const struct dso *dso = NULL;
@@ -1623,6 +1530,13 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
                case 'F':
                        symbol_conf.filter_relative ^= 1;
                        continue;
+               case 'z':
+                       if (!is_report_browser(hbt)) {
+                               struct perf_top *top = hbt->arg;
+
+                               top->zero = !top->zero;
+                       }
+                       continue;
                case K_F1:
                case 'h':
                case '?':
index 6ca60e482cdc2594382466bbaecdde12462dfbec..f3fa4258b256b9d3a8c4fb9f570172d96cca47f8 100644 (file)
@@ -11,6 +11,7 @@
 static int __percent_color_snprintf(struct perf_hpp *hpp, const char *fmt, ...)
 {
        int ret = 0;
+       int len;
        va_list args;
        double percent;
        const char *markup;
@@ -18,6 +19,7 @@ static int __percent_color_snprintf(struct perf_hpp *hpp, const char *fmt, ...)
        size_t size = hpp->size;
 
        va_start(args, fmt);
+       len = va_arg(args, int);
        percent = va_arg(args, double);
        va_end(args);
 
@@ -25,7 +27,7 @@ static int __percent_color_snprintf(struct perf_hpp *hpp, const char *fmt, ...)
        if (markup)
                ret += scnprintf(buf, size, markup);
 
-       ret += scnprintf(buf + ret, size - ret, fmt, percent);
+       ret += scnprintf(buf + ret, size - ret, fmt, len, percent);
 
        if (markup)
                ret += scnprintf(buf + ret, size - ret, "</span>");
@@ -39,12 +41,12 @@ static u64 he_get_##_field(struct hist_entry *he)                           \
        return he->stat._field;                                                 \
 }                                                                              \
                                                                                \
-static int perf_gtk__hpp_color_##_type(struct perf_hpp_fmt *fmt __maybe_unused,        \
+static int perf_gtk__hpp_color_##_type(struct perf_hpp_fmt *fmt,               \
                                       struct perf_hpp *hpp,                    \
                                       struct hist_entry *he)                   \
 {                                                                              \
-       return __hpp__fmt(hpp, he, he_get_##_field, " %6.2f%%",                 \
-                         __percent_color_snprintf, true);                      \
+       return hpp__fmt(fmt, hpp, he, he_get_##_field, " %*.2f%%",              \
+                       __percent_color_snprintf, true);                        \
 }
 
 #define __HPP_COLOR_ACC_PERCENT_FN(_type, _field)                              \
@@ -57,8 +59,8 @@ static int perf_gtk__hpp_color_##_type(struct perf_hpp_fmt *fmt __maybe_unused,
                                       struct perf_hpp *hpp,                    \
                                       struct hist_entry *he)                   \
 {                                                                              \
-       return __hpp__fmt_acc(hpp, he, he_get_acc_##_field, " %6.2f%%",         \
-                             __percent_color_snprintf, true);                  \
+       return hpp__fmt_acc(fmt, hpp, he, he_get_acc_##_field, " %*.2f%%",      \
+                           __percent_color_snprintf, true);                    \
 }
 
 __HPP_COLOR_PERCENT_FN(overhead, period)
@@ -205,10 +207,8 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,
                if (perf_hpp__is_sort_entry(fmt))
                        sym_col = col_idx;
 
-               fmt->header(fmt, &hpp, hists_to_evsel(hists));
-
                gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
-                                                           -1, ltrim(s),
+                                                           -1, fmt->name,
                                                            renderer, "markup",
                                                            col_idx++, NULL);
        }
index 498adb23c02ef9992f82c840aca5aa31220af9bf..2af18376b0772ea5094e1f6277afa343533a484c 100644 (file)
@@ -15,9 +15,9 @@
        __ret;                                                  \
 })
 
-int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he,
-              hpp_field_fn get_field, const char *fmt,
-              hpp_snprint_fn print_fn, bool fmt_percent)
+static int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he,
+                     hpp_field_fn get_field, const char *fmt, int len,
+                     hpp_snprint_fn print_fn, bool fmt_percent)
 {
        int ret;
        struct hists *hists = he->hists;
@@ -32,9 +32,9 @@ int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he,
                if (total)
                        percent = 100.0 * get_field(he) / total;
 
-               ret = hpp__call_print_fn(hpp, print_fn, fmt, percent);
+               ret = hpp__call_print_fn(hpp, print_fn, fmt, len, percent);
        } else
-               ret = hpp__call_print_fn(hpp, print_fn, fmt, get_field(he));
+               ret = hpp__call_print_fn(hpp, print_fn, fmt, len, get_field(he));
 
        if (perf_evsel__is_group_event(evsel)) {
                int prev_idx, idx_delta;
@@ -60,19 +60,19 @@ int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he,
                                 */
                                if (fmt_percent) {
                                        ret += hpp__call_print_fn(hpp, print_fn,
-                                                                 fmt, 0.0);
+                                                                 fmt, len, 0.0);
                                } else {
                                        ret += hpp__call_print_fn(hpp, print_fn,
-                                                                 fmt, 0ULL);
+                                                                 fmt, len, 0ULL);
                                }
                        }
 
                        if (fmt_percent) {
-                               ret += hpp__call_print_fn(hpp, print_fn, fmt,
+                               ret += hpp__call_print_fn(hpp, print_fn, fmt, len,
                                                          100.0 * period / total);
                        } else {
                                ret += hpp__call_print_fn(hpp, print_fn, fmt,
-                                                         period);
+                                                         len, period);
                        }
 
                        prev_idx = perf_evsel__group_idx(evsel);
@@ -86,10 +86,10 @@ int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he,
                         */
                        if (fmt_percent) {
                                ret += hpp__call_print_fn(hpp, print_fn,
-                                                         fmt, 0.0);
+                                                         fmt, len, 0.0);
                        } else {
                                ret += hpp__call_print_fn(hpp, print_fn,
-                                                         fmt, 0ULL);
+                                                         fmt, len, 0ULL);
                        }
                }
        }
@@ -104,16 +104,35 @@ int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he,
        return ret;
 }
 
-int __hpp__fmt_acc(struct perf_hpp *hpp, struct hist_entry *he,
-                  hpp_field_fn get_field, const char *fmt,
-                  hpp_snprint_fn print_fn, bool fmt_percent)
+int hpp__fmt(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
+            struct hist_entry *he, hpp_field_fn get_field,
+            const char *fmtstr, hpp_snprint_fn print_fn, bool fmt_percent)
+{
+       int len = fmt->user_len ?: fmt->len;
+
+       if (symbol_conf.field_sep) {
+               return __hpp__fmt(hpp, he, get_field, fmtstr, 1,
+                                 print_fn, fmt_percent);
+       }
+
+       if (fmt_percent)
+               len -= 2; /* 2 for a space and a % sign */
+       else
+               len -= 1;
+
+       return  __hpp__fmt(hpp, he, get_field, fmtstr, len, print_fn, fmt_percent);
+}
+
+int hpp__fmt_acc(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
+                struct hist_entry *he, hpp_field_fn get_field,
+                const char *fmtstr, hpp_snprint_fn print_fn, bool fmt_percent)
 {
        if (!symbol_conf.cumulate_callchain) {
-               return snprintf(hpp->buf, hpp->size, "%*s",
-                               fmt_percent ? 8 : 12, "N/A");
+               int len = fmt->user_len ?: fmt->len;
+               return snprintf(hpp->buf, hpp->size, " %*s", len - 1, "N/A");
        }
 
-       return __hpp__fmt(hpp, he, get_field, fmt, print_fn, fmt_percent);
+       return hpp__fmt(fmt, hpp, he, get_field, fmtstr, print_fn, fmt_percent);
 }
 
 static int field_cmp(u64 field_a, u64 field_b)
@@ -190,30 +209,26 @@ static int __hpp__sort_acc(struct hist_entry *a, struct hist_entry *b,
        return ret;
 }
 
-#define __HPP_HEADER_FN(_type, _str, _min_width, _unit_width)          \
-static int hpp__header_##_type(struct perf_hpp_fmt *fmt __maybe_unused,        \
-                              struct perf_hpp *hpp,                    \
-                              struct perf_evsel *evsel)                \
-{                                                                      \
-       int len = _min_width;                                           \
-                                                                       \
-       if (symbol_conf.event_group)                                    \
-               len = max(len, evsel->nr_members * _unit_width);        \
-                                                                       \
-       return scnprintf(hpp->buf, hpp->size, "%*s", len, _str);        \
-}
-
-#define __HPP_WIDTH_FN(_type, _min_width, _unit_width)                         \
-static int hpp__width_##_type(struct perf_hpp_fmt *fmt __maybe_unused, \
-                             struct perf_hpp *hpp __maybe_unused,      \
-                             struct perf_evsel *evsel)                 \
-{                                                                      \
-       int len = _min_width;                                           \
-                                                                       \
-       if (symbol_conf.event_group)                                    \
-               len = max(len, evsel->nr_members * _unit_width);        \
-                                                                       \
-       return len;                                                     \
+static int hpp__width_fn(struct perf_hpp_fmt *fmt,
+                        struct perf_hpp *hpp __maybe_unused,
+                        struct perf_evsel *evsel)
+{
+       int len = fmt->user_len ?: fmt->len;
+
+       if (symbol_conf.event_group)
+               len = max(len, evsel->nr_members * fmt->len);
+
+       if (len < (int)strlen(fmt->name))
+               len = strlen(fmt->name);
+
+       return len;
+}
+
+static int hpp__header_fn(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
+                         struct perf_evsel *evsel)
+{
+       int len = hpp__width_fn(fmt, hpp, evsel);
+       return scnprintf(hpp->buf, hpp->size, "%*s", len, fmt->name);
 }
 
 static int hpp_color_scnprintf(struct perf_hpp *hpp, const char *fmt, ...)
@@ -221,11 +236,12 @@ static int hpp_color_scnprintf(struct perf_hpp *hpp, const char *fmt, ...)
        va_list args;
        ssize_t ssize = hpp->size;
        double percent;
-       int ret;
+       int ret, len;
 
        va_start(args, fmt);
+       len = va_arg(args, int);
        percent = va_arg(args, double);
-       ret = value_color_snprintf(hpp->buf, hpp->size, fmt, percent);
+       ret = percent_color_len_snprintf(hpp->buf, hpp->size, fmt, len, percent);
        va_end(args);
 
        return (ret >= ssize) ? (ssize - 1) : ret;
@@ -250,20 +266,19 @@ static u64 he_get_##_field(struct hist_entry *he)                         \
        return he->stat._field;                                                 \
 }                                                                              \
                                                                                \
-static int hpp__color_##_type(struct perf_hpp_fmt *fmt __maybe_unused,         \
+static int hpp__color_##_type(struct perf_hpp_fmt *fmt,                                \
                              struct perf_hpp *hpp, struct hist_entry *he)      \
 {                                                                              \
-       return __hpp__fmt(hpp, he, he_get_##_field, " %6.2f%%",                 \
-                         hpp_color_scnprintf, true);                           \
+       return hpp__fmt(fmt, hpp, he, he_get_##_field, " %*.2f%%",              \
+                       hpp_color_scnprintf, true);                             \
 }
 
 #define __HPP_ENTRY_PERCENT_FN(_type, _field)                                  \
-static int hpp__entry_##_type(struct perf_hpp_fmt *_fmt __maybe_unused,                \
+static int hpp__entry_##_type(struct perf_hpp_fmt *fmt,                                \
                              struct perf_hpp *hpp, struct hist_entry *he)      \
 {                                                                              \
-       const char *fmt = symbol_conf.field_sep ? " %.2f" : " %6.2f%%";         \
-       return __hpp__fmt(hpp, he, he_get_##_field, fmt,                        \
-                         hpp_entry_scnprintf, true);                           \
+       return hpp__fmt(fmt, hpp, he, he_get_##_field, " %*.2f%%",              \
+                       hpp_entry_scnprintf, true);                             \
 }
 
 #define __HPP_SORT_FN(_type, _field)                                           \
@@ -278,20 +293,19 @@ static u64 he_get_acc_##_field(struct hist_entry *he)                             \
        return he->stat_acc->_field;                                            \
 }                                                                              \
                                                                                \
-static int hpp__color_##_type(struct perf_hpp_fmt *fmt __maybe_unused,         \
+static int hpp__color_##_type(struct perf_hpp_fmt *fmt,                                \
                              struct perf_hpp *hpp, struct hist_entry *he)      \
 {                                                                              \
-       return __hpp__fmt_acc(hpp, he, he_get_acc_##_field, " %6.2f%%",         \
-                             hpp_color_scnprintf, true);                       \
+       return hpp__fmt_acc(fmt, hpp, he, he_get_acc_##_field, " %*.2f%%",      \
+                           hpp_color_scnprintf, true);                         \
 }
 
 #define __HPP_ENTRY_ACC_PERCENT_FN(_type, _field)                              \
-static int hpp__entry_##_type(struct perf_hpp_fmt *_fmt __maybe_unused,                \
+static int hpp__entry_##_type(struct perf_hpp_fmt *fmt,                                \
                              struct perf_hpp *hpp, struct hist_entry *he)      \
 {                                                                              \
-       const char *fmt = symbol_conf.field_sep ? " %.2f" : " %6.2f%%";         \
-       return __hpp__fmt_acc(hpp, he, he_get_acc_##_field, fmt,                \
-                             hpp_entry_scnprintf, true);                       \
+       return hpp__fmt_acc(fmt, hpp, he, he_get_acc_##_field, " %*.2f%%",      \
+                           hpp_entry_scnprintf, true);                         \
 }
 
 #define __HPP_SORT_ACC_FN(_type, _field)                                       \
@@ -306,12 +320,11 @@ static u64 he_get_raw_##_field(struct hist_entry *he)                             \
        return he->stat._field;                                                 \
 }                                                                              \
                                                                                \
-static int hpp__entry_##_type(struct perf_hpp_fmt *_fmt __maybe_unused,                \
+static int hpp__entry_##_type(struct perf_hpp_fmt *fmt,                                \
                              struct perf_hpp *hpp, struct hist_entry *he)      \
 {                                                                              \
-       const char *fmt = symbol_conf.field_sep ? " %"PRIu64 : " %11"PRIu64;    \
-       return __hpp__fmt(hpp, he, he_get_raw_##_field, fmt,                    \
-                         hpp_entry_scnprintf, false);                          \
+       return hpp__fmt(fmt, hpp, he, he_get_raw_##_field, " %*"PRIu64,         \
+                       hpp_entry_scnprintf, false);                            \
 }
 
 #define __HPP_SORT_RAW_FN(_type, _field)                                       \
@@ -321,37 +334,29 @@ static int64_t hpp__sort_##_type(struct hist_entry *a, struct hist_entry *b)      \
 }
 
 
-#define HPP_PERCENT_FNS(_type, _str, _field, _min_width, _unit_width)  \
-__HPP_HEADER_FN(_type, _str, _min_width, _unit_width)                  \
-__HPP_WIDTH_FN(_type, _min_width, _unit_width)                         \
+#define HPP_PERCENT_FNS(_type, _field)                                 \
 __HPP_COLOR_PERCENT_FN(_type, _field)                                  \
 __HPP_ENTRY_PERCENT_FN(_type, _field)                                  \
 __HPP_SORT_FN(_type, _field)
 
-#define HPP_PERCENT_ACC_FNS(_type, _str, _field, _min_width, _unit_width)\
-__HPP_HEADER_FN(_type, _str, _min_width, _unit_width)                  \
-__HPP_WIDTH_FN(_type, _min_width, _unit_width)                         \
+#define HPP_PERCENT_ACC_FNS(_type, _field)                             \
 __HPP_COLOR_ACC_PERCENT_FN(_type, _field)                              \
 __HPP_ENTRY_ACC_PERCENT_FN(_type, _field)                              \
 __HPP_SORT_ACC_FN(_type, _field)
 
-#define HPP_RAW_FNS(_type, _str, _field, _min_width, _unit_width)      \
-__HPP_HEADER_FN(_type, _str, _min_width, _unit_width)                  \
-__HPP_WIDTH_FN(_type, _min_width, _unit_width)                         \
+#define HPP_RAW_FNS(_type, _field)                                     \
 __HPP_ENTRY_RAW_FN(_type, _field)                                      \
 __HPP_SORT_RAW_FN(_type, _field)
 
-__HPP_HEADER_FN(overhead_self, "Self", 8, 8)
-
-HPP_PERCENT_FNS(overhead, "Overhead", period, 8, 8)
-HPP_PERCENT_FNS(overhead_sys, "sys", period_sys, 8, 8)
-HPP_PERCENT_FNS(overhead_us, "usr", period_us, 8, 8)
-HPP_PERCENT_FNS(overhead_guest_sys, "guest sys", period_guest_sys, 9, 8)
-HPP_PERCENT_FNS(overhead_guest_us, "guest usr", period_guest_us, 9, 8)
-HPP_PERCENT_ACC_FNS(overhead_acc, "Children", period, 8, 8)
+HPP_PERCENT_FNS(overhead, period)
+HPP_PERCENT_FNS(overhead_sys, period_sys)
+HPP_PERCENT_FNS(overhead_us, period_us)
+HPP_PERCENT_FNS(overhead_guest_sys, period_guest_sys)
+HPP_PERCENT_FNS(overhead_guest_us, period_guest_us)
+HPP_PERCENT_ACC_FNS(overhead_acc, period)
 
-HPP_RAW_FNS(samples, "Samples", nr_events, 12, 12)
-HPP_RAW_FNS(period, "Period", period, 12, 12)
+HPP_RAW_FNS(samples, nr_events)
+HPP_RAW_FNS(period, period)
 
 static int64_t hpp__nop_cmp(struct hist_entry *a __maybe_unused,
                            struct hist_entry *b __maybe_unused)
@@ -359,47 +364,50 @@ static int64_t hpp__nop_cmp(struct hist_entry *a __maybe_unused,
        return 0;
 }
 
-#define HPP__COLOR_PRINT_FNS(_name)                    \
+#define HPP__COLOR_PRINT_FNS(_name, _fn)               \
        {                                               \
-               .header = hpp__header_ ## _name,        \
-               .width  = hpp__width_ ## _name,         \
-               .color  = hpp__color_ ## _name,         \
-               .entry  = hpp__entry_ ## _name,         \
+               .name   = _name,                        \
+               .header = hpp__header_fn,               \
+               .width  = hpp__width_fn,                \
+               .color  = hpp__color_ ## _fn,           \
+               .entry  = hpp__entry_ ## _fn,           \
                .cmp    = hpp__nop_cmp,                 \
                .collapse = hpp__nop_cmp,               \
-               .sort   = hpp__sort_ ## _name,          \
+               .sort   = hpp__sort_ ## _fn,            \
        }
 
-#define HPP__COLOR_ACC_PRINT_FNS(_name)                        \
+#define HPP__COLOR_ACC_PRINT_FNS(_name, _fn)           \
        {                                               \
-               .header = hpp__header_ ## _name,        \
-               .width  = hpp__width_ ## _name,         \
-               .color  = hpp__color_ ## _name,         \
-               .entry  = hpp__entry_ ## _name,         \
+               .name   = _name,                        \
+               .header = hpp__header_fn,               \
+               .width  = hpp__width_fn,                \
+               .color  = hpp__color_ ## _fn,           \
+               .entry  = hpp__entry_ ## _fn,           \
                .cmp    = hpp__nop_cmp,                 \
                .collapse = hpp__nop_cmp,               \
-               .sort   = hpp__sort_ ## _name,          \
+               .sort   = hpp__sort_ ## _fn,            \
        }
 
-#define HPP__PRINT_FNS(_name)                          \
+#define HPP__PRINT_FNS(_name, _fn)                     \
        {                                               \
-               .header = hpp__header_ ## _name,        \
-               .width  = hpp__width_ ## _name,         \
-               .entry  = hpp__entry_ ## _name,         \
+               .name   = _name,                        \
+               .header = hpp__header_fn,               \
+               .width  = hpp__width_fn,                \
+               .entry  = hpp__entry_ ## _fn,           \
                .cmp    = hpp__nop_cmp,                 \
                .collapse = hpp__nop_cmp,               \
-               .sort   = hpp__sort_ ## _name,          \
+               .sort   = hpp__sort_ ## _fn,            \
        }
 
 struct perf_hpp_fmt perf_hpp__format[] = {
-       HPP__COLOR_PRINT_FNS(overhead),
-       HPP__COLOR_PRINT_FNS(overhead_sys),
-       HPP__COLOR_PRINT_FNS(overhead_us),
-       HPP__COLOR_PRINT_FNS(overhead_guest_sys),
-       HPP__COLOR_PRINT_FNS(overhead_guest_us),
-       HPP__COLOR_ACC_PRINT_FNS(overhead_acc),
-       HPP__PRINT_FNS(samples),
-       HPP__PRINT_FNS(period)
+       HPP__COLOR_PRINT_FNS("Overhead", overhead),
+       HPP__COLOR_PRINT_FNS("sys", overhead_sys),
+       HPP__COLOR_PRINT_FNS("usr", overhead_us),
+       HPP__COLOR_PRINT_FNS("guest sys", overhead_guest_sys),
+       HPP__COLOR_PRINT_FNS("guest usr", overhead_guest_us),
+       HPP__COLOR_ACC_PRINT_FNS("Children", overhead_acc),
+       HPP__PRINT_FNS("Samples", samples),
+       HPP__PRINT_FNS("Period", period)
 };
 
 LIST_HEAD(perf_hpp__list);
@@ -444,14 +452,12 @@ void perf_hpp__init(void)
        /*
         * If user specified field order, no need to setup default fields.
         */
-       if (field_order)
+       if (is_strict_order(field_order))
                return;
 
        if (symbol_conf.cumulate_callchain) {
                perf_hpp__column_enable(PERF_HPP__OVERHEAD_ACC);
-
-               perf_hpp__format[PERF_HPP__OVERHEAD].header =
-                                               hpp__header_overhead_self;
+               perf_hpp__format[PERF_HPP__OVERHEAD].name = "Self";
        }
 
        perf_hpp__column_enable(PERF_HPP__OVERHEAD);
@@ -513,11 +519,11 @@ void perf_hpp__column_disable(unsigned col)
 
 void perf_hpp__cancel_cumulate(void)
 {
-       if (field_order)
+       if (is_strict_order(field_order))
                return;
 
        perf_hpp__column_disable(PERF_HPP__OVERHEAD_ACC);
-       perf_hpp__format[PERF_HPP__OVERHEAD].header = hpp__header_overhead;
+       perf_hpp__format[PERF_HPP__OVERHEAD].name = "Overhead";
 }
 
 void perf_hpp__setup_output_field(void)
@@ -622,3 +628,59 @@ unsigned int hists__sort_list_width(struct hists *hists)
 
        return ret;
 }
+
+void perf_hpp__reset_width(struct perf_hpp_fmt *fmt, struct hists *hists)
+{
+       int idx;
+
+       if (perf_hpp__is_sort_entry(fmt))
+               return perf_hpp__reset_sort_width(fmt, hists);
+
+       for (idx = 0; idx < PERF_HPP__MAX_INDEX; idx++) {
+               if (fmt == &perf_hpp__format[idx])
+                       break;
+       }
+
+       if (idx == PERF_HPP__MAX_INDEX)
+               return;
+
+       switch (idx) {
+       case PERF_HPP__OVERHEAD:
+       case PERF_HPP__OVERHEAD_SYS:
+       case PERF_HPP__OVERHEAD_US:
+       case PERF_HPP__OVERHEAD_ACC:
+               fmt->len = 8;
+               break;
+
+       case PERF_HPP__OVERHEAD_GUEST_SYS:
+       case PERF_HPP__OVERHEAD_GUEST_US:
+               fmt->len = 9;
+               break;
+
+       case PERF_HPP__SAMPLES:
+       case PERF_HPP__PERIOD:
+               fmt->len = 12;
+               break;
+
+       default:
+               break;
+       }
+}
+
+void perf_hpp__set_user_width(const char *width_list_str)
+{
+       struct perf_hpp_fmt *fmt;
+       const char *ptr = width_list_str;
+
+       perf_hpp__for_each_format(fmt) {
+               char *p;
+
+               int len = strtol(ptr, &p, 10);
+               fmt->user_len = len;
+
+               if (*p == ',')
+                       ptr = p + 1;
+               else
+                       break;
+       }
+}
index 40af0acb4fe95da232e441ebcb69e0c5f1b601a1..15b451acbde61081eaf22aba07a5da3752a9e205 100644 (file)
@@ -395,10 +395,12 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,
 
        init_rem_hits();
 
-
        perf_hpp__for_each_format(fmt)
                perf_hpp__reset_width(fmt, hists);
 
+       if (symbol_conf.col_width_list_str)
+               perf_hpp__set_user_width(symbol_conf.col_width_list_str);
+
        if (!show_header)
                goto print_entries;
 
index 809b4c50beaed3e3a57845919b3a034fe7ab8c9e..36437527dbb347301c7d44f6322f72b4568a0d2a 100644 (file)
@@ -232,9 +232,16 @@ static int mov__parse(struct ins_operands *ops)
                return -1;
 
        target = ++s;
+       comment = strchr(s, '#');
 
-       while (s[0] != '\0' && !isspace(s[0]))
-               ++s;
+       if (comment != NULL)
+               s = comment - 1;
+       else
+               s = strchr(s, '\0') - 1;
+
+       while (s > target && isspace(s[0]))
+               --s;
+       s++;
        prev = *s;
        *s = '\0';
 
@@ -244,7 +251,6 @@ static int mov__parse(struct ins_operands *ops)
        if (ops->target.raw == NULL)
                goto out_free_source;
 
-       comment = strchr(s, '#');
        if (comment == NULL)
                return 0;
 
@@ -899,10 +905,8 @@ int symbol__annotate(struct symbol *sym, struct map *map, size_t privsize)
        struct kcore_extract kce;
        bool delete_extract = false;
 
-       if (filename) {
-               snprintf(symfs_filename, sizeof(symfs_filename), "%s%s",
-                        symbol_conf.symfs, filename);
-       }
+       if (filename)
+               symbol__join_symfs(symfs_filename, filename);
 
        if (filename == NULL) {
                if (dso->has_build_id) {
@@ -922,8 +926,7 @@ fallback:
                 * DSO is the same as when 'perf record' ran.
                 */
                filename = (char *)dso->long_name;
-               snprintf(symfs_filename, sizeof(symfs_filename), "%s%s",
-                        symbol_conf.symfs, filename);
+               symbol__join_symfs(symfs_filename, filename);
                free_filename = false;
        }
 
index 7b176dd02e1ae94e6f5479b78ae4c2e84bb7836c..5cf9e1b5989de40cb677b1bd744d684cd3bfc871 100644 (file)
@@ -22,6 +22,7 @@ typedef int (*config_fn_t)(const char *, const char *, void *);
 extern int perf_default_config(const char *, const char *, void *);
 extern int perf_config(config_fn_t fn, void *);
 extern int perf_config_int(const char *, const char *);
+extern u64 perf_config_u64(const char *, const char *);
 extern int perf_config_bool(const char *, const char *);
 extern int config_error_nonbool(const char *);
 extern const char *perf_config_dirname(const char *, const char *);
index 437ee09727e6053bc4eb6169008f04c02b8a654f..c84d3f8dcb7594602c4664c4926eaf050d26247e 100644 (file)
 
 __thread struct callchain_cursor callchain_cursor;
 
-int
-parse_callchain_report_opt(const char *arg)
+#ifdef HAVE_DWARF_UNWIND_SUPPORT
+static int get_stack_size(const char *str, unsigned long *_size)
 {
-       char *tok, *tok2;
        char *endptr;
+       unsigned long size;
+       unsigned long max_size = round_down(USHRT_MAX, sizeof(u64));
 
-       symbol_conf.use_callchain = true;
+       size = strtoul(str, &endptr, 0);
 
-       if (!arg)
+       do {
+               if (*endptr)
+                       break;
+
+               size = round_up(size, sizeof(u64));
+               if (!size || size > max_size)
+                       break;
+
+               *_size = size;
                return 0;
 
-       tok = strtok((char *)arg, ",");
-       if (!tok)
-               return -1;
+       } while (0);
 
-       /* get the output mode */
-       if (!strncmp(tok, "graph", strlen(arg))) {
-               callchain_param.mode = CHAIN_GRAPH_ABS;
+       pr_err("callchain: Incorrect stack dump size (max %ld): %s\n",
+              max_size, str);
+       return -1;
+}
+#endif /* HAVE_DWARF_UNWIND_SUPPORT */
 
-       } else if (!strncmp(tok, "flat", strlen(arg))) {
-               callchain_param.mode = CHAIN_FLAT;
-       } else if (!strncmp(tok, "fractal", strlen(arg))) {
-               callchain_param.mode = CHAIN_GRAPH_REL;
-       } else if (!strncmp(tok, "none", strlen(arg))) {
-               callchain_param.mode = CHAIN_NONE;
-               symbol_conf.use_callchain = false;
-               return 0;
-       } else {
-               return -1;
-       }
+int parse_callchain_record_opt(const char *arg)
+{
+       char *tok, *name, *saveptr = NULL;
+       char *buf;
+       int ret = -1;
+
+       /* We need buffer that we know we can write to. */
+       buf = malloc(strlen(arg) + 1);
+       if (!buf)
+               return -ENOMEM;
+
+       strcpy(buf, arg);
+
+       tok = strtok_r((char *)buf, ",", &saveptr);
+       name = tok ? : (char *)buf;
+
+       do {
+               /* Framepointer style */
+               if (!strncmp(name, "fp", sizeof("fp"))) {
+                       if (!strtok_r(NULL, ",", &saveptr)) {
+                               callchain_param.record_mode = CALLCHAIN_FP;
+                               ret = 0;
+                       } else
+                               pr_err("callchain: No more arguments "
+                                      "needed for -g fp\n");
+                       break;
 
-       /* get the min percentage */
-       tok = strtok(NULL, ",");
-       if (!tok)
-               goto setup;
+#ifdef HAVE_DWARF_UNWIND_SUPPORT
+               /* Dwarf style */
+               } else if (!strncmp(name, "dwarf", sizeof("dwarf"))) {
+                       const unsigned long default_stack_dump_size = 8192;
 
-       callchain_param.min_percent = strtod(tok, &endptr);
-       if (tok == endptr)
-               return -1;
+                       ret = 0;
+                       callchain_param.record_mode = CALLCHAIN_DWARF;
+                       callchain_param.dump_size = default_stack_dump_size;
 
-       /* get the print limit */
-       tok2 = strtok(NULL, ",");
-       if (!tok2)
-               goto setup;
+                       tok = strtok_r(NULL, ",", &saveptr);
+                       if (tok) {
+                               unsigned long size = 0;
 
-       if (tok2[0] != 'c') {
-               callchain_param.print_limit = strtoul(tok2, &endptr, 0);
-               tok2 = strtok(NULL, ",");
-               if (!tok2)
-                       goto setup;
+                               ret = get_stack_size(tok, &size);
+                               callchain_param.dump_size = size;
+                       }
+#endif /* HAVE_DWARF_UNWIND_SUPPORT */
+               } else {
+                       pr_err("callchain: Unknown --call-graph option "
+                              "value: %s\n", arg);
+                       break;
+               }
+
+       } while (0);
+
+       free(buf);
+       return ret;
+}
+
+static int parse_callchain_mode(const char *value)
+{
+       if (!strncmp(value, "graph", strlen(value))) {
+               callchain_param.mode = CHAIN_GRAPH_ABS;
+               return 0;
+       }
+       if (!strncmp(value, "flat", strlen(value))) {
+               callchain_param.mode = CHAIN_FLAT;
+               return 0;
        }
+       if (!strncmp(value, "fractal", strlen(value))) {
+               callchain_param.mode = CHAIN_GRAPH_REL;
+               return 0;
+       }
+       return -1;
+}
 
-       /* get the call chain order */
-       if (!strncmp(tok2, "caller", strlen("caller")))
+static int parse_callchain_order(const char *value)
+{
+       if (!strncmp(value, "caller", strlen(value))) {
                callchain_param.order = ORDER_CALLER;
-       else if (!strncmp(tok2, "callee", strlen("callee")))
+               return 0;
+       }
+       if (!strncmp(value, "callee", strlen(value))) {
                callchain_param.order = ORDER_CALLEE;
-       else
-               return -1;
+               return 0;
+       }
+       return -1;
+}
 
-       /* Get the sort key */
-       tok2 = strtok(NULL, ",");
-       if (!tok2)
-               goto setup;
-       if (!strncmp(tok2, "function", strlen("function")))
+static int parse_callchain_sort_key(const char *value)
+{
+       if (!strncmp(value, "function", strlen(value))) {
                callchain_param.key = CCKEY_FUNCTION;
-       else if (!strncmp(tok2, "address", strlen("address")))
+               return 0;
+       }
+       if (!strncmp(value, "address", strlen(value))) {
                callchain_param.key = CCKEY_ADDRESS;
-       else
-               return -1;
-setup:
+               return 0;
+       }
+       return -1;
+}
+
+int
+parse_callchain_report_opt(const char *arg)
+{
+       char *tok;
+       char *endptr;
+       bool minpcnt_set = false;
+
+       symbol_conf.use_callchain = true;
+
+       if (!arg)
+               return 0;
+
+       while ((tok = strtok((char *)arg, ",")) != NULL) {
+               if (!strncmp(tok, "none", strlen(tok))) {
+                       callchain_param.mode = CHAIN_NONE;
+                       symbol_conf.use_callchain = false;
+                       return 0;
+               }
+
+               if (!parse_callchain_mode(tok) ||
+                   !parse_callchain_order(tok) ||
+                   !parse_callchain_sort_key(tok)) {
+                       /* parsing ok - move on to the next */
+               } else if (!minpcnt_set) {
+                       /* try to get the min percent */
+                       callchain_param.min_percent = strtod(tok, &endptr);
+                       if (tok == endptr)
+                               return -1;
+                       minpcnt_set = true;
+               } else {
+                       /* try print limit at last */
+                       callchain_param.print_limit = strtoul(tok, &endptr, 0);
+                       if (tok == endptr)
+                               return -1;
+               }
+
+               arg = NULL;
+       }
+
        if (callchain_register_param(&callchain_param) < 0) {
                pr_err("Can't register callchain params\n");
                return -1;
@@ -103,6 +198,47 @@ setup:
        return 0;
 }
 
+int perf_callchain_config(const char *var, const char *value)
+{
+       char *endptr;
+
+       if (prefixcmp(var, "call-graph."))
+               return 0;
+       var += sizeof("call-graph.") - 1;
+
+       if (!strcmp(var, "record-mode"))
+               return parse_callchain_record_opt(value);
+#ifdef HAVE_DWARF_UNWIND_SUPPORT
+       if (!strcmp(var, "dump-size")) {
+               unsigned long size = 0;
+               int ret;
+
+               ret = get_stack_size(value, &size);
+               callchain_param.dump_size = size;
+
+               return ret;
+       }
+#endif
+       if (!strcmp(var, "print-type"))
+               return parse_callchain_mode(value);
+       if (!strcmp(var, "order"))
+               return parse_callchain_order(value);
+       if (!strcmp(var, "sort-key"))
+               return parse_callchain_sort_key(value);
+       if (!strcmp(var, "threshold")) {
+               callchain_param.min_percent = strtod(value, &endptr);
+               if (value == endptr)
+                       return -1;
+       }
+       if (!strcmp(var, "print-limit")) {
+               callchain_param.print_limit = strtod(value, &endptr);
+               if (value == endptr)
+                       return -1;
+       }
+
+       return 0;
+}
+
 static void
 rb_insert_callchain(struct rb_root *root, struct callchain_node *chain,
                    enum chain_mode mode)
index da43619d61733ab2e0d273690200797c92089519..2a1f5a46543a1cd3ecfb0b78c622921c9ee5a564 100644 (file)
@@ -54,6 +54,9 @@ enum chain_key {
 };
 
 struct callchain_param {
+       bool                    enabled;
+       enum perf_call_graph_mode record_mode;
+       u32                     dump_size;
        enum chain_mode         mode;
        u32                     print_limit;
        double                  min_percent;
@@ -154,7 +157,6 @@ static inline void callchain_cursor_advance(struct callchain_cursor *cursor)
 struct option;
 struct hist_entry;
 
-int record_parse_callchain(const char *arg, struct record_opts *opts);
 int record_parse_callchain_opt(const struct option *opt, const char *arg, int unset);
 int record_callchain_opt(const struct option *opt, const char *arg, int unset);
 
@@ -166,7 +168,9 @@ int fill_callchain_info(struct addr_location *al, struct callchain_cursor_node *
                        bool hide_unresolved);
 
 extern const char record_callchain_help[];
+int parse_callchain_record_opt(const char *arg);
 int parse_callchain_report_opt(const char *arg);
+int perf_callchain_config(const char *var, const char *value);
 
 static inline void callchain_cursor_snapshot(struct callchain_cursor *dest,
                                             struct callchain_cursor *src)
index c5d05ec172206d6d86dd1bdc14edfa29a2d7bd0f..47b78b3f03257385023629696dda95e57d2b5ab7 100644 (file)
@@ -1,7 +1,9 @@
+#include <sched.h>
 #include "util.h"
 #include "../perf.h"
 #include "cloexec.h"
 #include "asm/bug.h"
+#include "debug.h"
 
 static unsigned long flag = PERF_FLAG_FD_CLOEXEC;
 
@@ -9,15 +11,30 @@ static int perf_flag_probe(void)
 {
        /* use 'safest' configuration as used in perf_evsel__fallback() */
        struct perf_event_attr attr = {
-               .type = PERF_COUNT_SW_CPU_CLOCK,
+               .type = PERF_TYPE_SOFTWARE,
                .config = PERF_COUNT_SW_CPU_CLOCK,
+               .exclude_kernel = 1,
        };
        int fd;
        int err;
+       int cpu;
+       pid_t pid = -1;
+       char sbuf[STRERR_BUFSIZE];
 
-       /* check cloexec flag */
-       fd = sys_perf_event_open(&attr, 0, -1, -1,
-                                PERF_FLAG_FD_CLOEXEC);
+       cpu = sched_getcpu();
+       if (cpu < 0)
+               cpu = 0;
+
+       while (1) {
+               /* check cloexec flag */
+               fd = sys_perf_event_open(&attr, pid, cpu, -1,
+                                        PERF_FLAG_FD_CLOEXEC);
+               if (fd < 0 && pid == -1 && errno == EACCES) {
+                       pid = 0;
+                       continue;
+               }
+               break;
+       }
        err = errno;
 
        if (fd >= 0) {
@@ -25,17 +42,17 @@ static int perf_flag_probe(void)
                return 1;
        }
 
-       WARN_ONCE(err != EINVAL,
+       WARN_ONCE(err != EINVAL && err != EBUSY,
                  "perf_event_open(..., PERF_FLAG_FD_CLOEXEC) failed with unexpected error %d (%s)\n",
-                 err, strerror(err));
+                 err, strerror_r(err, sbuf, sizeof(sbuf)));
 
        /* not supported, confirm error related to PERF_FLAG_FD_CLOEXEC */
-       fd = sys_perf_event_open(&attr, 0, -1, -1, 0);
+       fd = sys_perf_event_open(&attr, pid, cpu, -1, 0);
        err = errno;
 
-       if (WARN_ONCE(fd < 0,
+       if (WARN_ONCE(fd < 0 && err != EBUSY,
                      "perf_event_open(..., 0) failed unexpectedly with error %d (%s)\n",
-                     err, strerror(err)))
+                     err, strerror_r(err, sbuf, sizeof(sbuf))))
                return -1;
 
        close(fd);
index 87b8672eb4134cab6d29b3a2accda19093edb9aa..f4654183d391a4051a970719229d47b2a9027108 100644 (file)
@@ -335,3 +335,19 @@ int percent_color_snprintf(char *bf, size_t size, const char *fmt, ...)
        va_end(args);
        return value_color_snprintf(bf, size, fmt, percent);
 }
+
+int percent_color_len_snprintf(char *bf, size_t size, const char *fmt, ...)
+{
+       va_list args;
+       int len;
+       double percent;
+       const char *color;
+
+       va_start(args, fmt);
+       len = va_arg(args, int);
+       percent = va_arg(args, double);
+       va_end(args);
+
+       color = get_percent_color(percent);
+       return color_snprintf(bf, size, color, fmt, len, percent);
+}
index 7ff30a62a132296a6f82de9fea62629defa8e658..0a594b8a0c26ab2e0753221ea0ae03e2b63e640e 100644 (file)
@@ -41,6 +41,7 @@ int color_fprintf_ln(FILE *fp, const char *color, const char *fmt, ...);
 int color_fwrite_lines(FILE *fp, const char *color, size_t count, const char *buf);
 int value_color_snprintf(char *bf, size_t size, const char *fmt, double value);
 int percent_color_snprintf(char *bf, size_t size, const char *fmt, ...);
+int percent_color_len_snprintf(char *bf, size_t size, const char *fmt, ...);
 int percent_color_fprintf(FILE *fp, const char *fmt, double percent);
 const char *get_percent_color(double percent);
 
index f9e777629e21cd1780fad2dc891f4c24d637787e..b2bb59df65e10c10cfe6dd1aacb495d4804a6a4f 100644 (file)
@@ -74,7 +74,7 @@ static struct comm_str *comm_str__findnew(const char *str, struct rb_root *root)
        return new;
 }
 
-struct comm *comm__new(const char *str, u64 timestamp)
+struct comm *comm__new(const char *str, u64 timestamp, bool exec)
 {
        struct comm *comm = zalloc(sizeof(*comm));
 
@@ -82,6 +82,7 @@ struct comm *comm__new(const char *str, u64 timestamp)
                return NULL;
 
        comm->start = timestamp;
+       comm->exec = exec;
 
        comm->comm_str = comm_str__findnew(str, &comm_str_root);
        if (!comm->comm_str) {
@@ -94,7 +95,7 @@ struct comm *comm__new(const char *str, u64 timestamp)
        return comm;
 }
 
-int comm__override(struct comm *comm, const char *str, u64 timestamp)
+int comm__override(struct comm *comm, const char *str, u64 timestamp, bool exec)
 {
        struct comm_str *new, *old = comm->comm_str;
 
@@ -106,6 +107,8 @@ int comm__override(struct comm *comm, const char *str, u64 timestamp)
        comm_str__put(old);
        comm->comm_str = new;
        comm->start = timestamp;
+       if (exec)
+               comm->exec = true;
 
        return 0;
 }
index fac5bd51befc4c4a2b6aafe5cd21220829334673..51c10ab257f8b2b079d120075cc7effb45bd73e3 100644 (file)
@@ -11,11 +11,13 @@ struct comm {
        struct comm_str *comm_str;
        u64 start;
        struct list_head list;
+       bool exec;
 };
 
 void comm__free(struct comm *comm);
-struct comm *comm__new(const char *str, u64 timestamp);
+struct comm *comm__new(const char *str, u64 timestamp, bool exec);
 const char *comm__str(const struct comm *comm);
-int comm__override(struct comm *comm, const char *str, u64 timestamp);
+int comm__override(struct comm *comm, const char *str, u64 timestamp,
+                  bool exec);
 
 #endif  /* __PERF_COMM_H */
index 1e5e2e5af6b1d05b18b1f6b92b88c4e62e85f33c..57ff826f150bfe4db2f89814a1e2a77be54aebfa 100644 (file)
@@ -222,7 +222,8 @@ static int perf_parse_file(config_fn_t fn, void *data)
        const unsigned char *bomptr = utf8_bom;
 
        for (;;) {
-               int c = get_next_char();
+               int line, c = get_next_char();
+
                if (bomptr && *bomptr) {
                        /* We are at the file beginning; skip UTF8-encoded BOM
                         * if present. Sane editors won't put this in on their
@@ -261,8 +262,16 @@ static int perf_parse_file(config_fn_t fn, void *data)
                if (!isalpha(c))
                        break;
                var[baselen] = tolower(c);
-               if (get_value(fn, data, var, baselen+1) < 0)
+
+               /*
+                * The get_value function might or might not reach the '\n',
+                * so saving the current line number for error reporting.
+                */
+               line = config_linenr;
+               if (get_value(fn, data, var, baselen+1) < 0) {
+                       config_linenr = line;
                        break;
+               }
        }
        die("bad config file line %d in %s", config_linenr, config_file_name);
 }
@@ -286,6 +295,21 @@ static int parse_unit_factor(const char *end, unsigned long *val)
        return 0;
 }
 
+static int perf_parse_llong(const char *value, long long *ret)
+{
+       if (value && *value) {
+               char *end;
+               long long val = strtoll(value, &end, 0);
+               unsigned long factor = 1;
+
+               if (!parse_unit_factor(end, &factor))
+                       return 0;
+               *ret = val * factor;
+               return 1;
+       }
+       return 0;
+}
+
 static int perf_parse_long(const char *value, long *ret)
 {
        if (value && *value) {
@@ -307,6 +331,15 @@ static void die_bad_config(const char *name)
        die("bad config value for '%s'", name);
 }
 
+u64 perf_config_u64(const char *name, const char *value)
+{
+       long long ret = 0;
+
+       if (!perf_parse_llong(value, &ret))
+               die_bad_config(name);
+       return (u64) ret;
+}
+
 int perf_config_int(const char *name, const char *value)
 {
        long ret = 0;
@@ -372,6 +405,9 @@ int perf_default_config(const char *var, const char *value,
        if (!prefixcmp(var, "ui."))
                return perf_ui_config(var, value);
 
+       if (!prefixcmp(var, "call-graph."))
+               return perf_callchain_config(var, value);
+
        /* Add other config variables here. */
        return 0;
 }
index 29d720cf5844763f300611b85e503cc1e6013bf8..1921942fc2e035cb2ddec0ba94b066e02a8f5bc9 100644 (file)
@@ -50,12 +50,14 @@ static int open_file_read(struct perf_data_file *file)
 {
        struct stat st;
        int fd;
+       char sbuf[STRERR_BUFSIZE];
 
        fd = open(file->path, O_RDONLY);
        if (fd < 0) {
                int err = errno;
 
-               pr_err("failed to open %s: %s", file->path, strerror(err));
+               pr_err("failed to open %s: %s", file->path,
+                       strerror_r(err, sbuf, sizeof(sbuf)));
                if (err == ENOENT && !strcmp(file->path, "perf.data"))
                        pr_err("  (try 'perf record' first)");
                pr_err("\n");
@@ -88,6 +90,7 @@ static int open_file_read(struct perf_data_file *file)
 static int open_file_write(struct perf_data_file *file)
 {
        int fd;
+       char sbuf[STRERR_BUFSIZE];
 
        if (check_backup(file))
                return -1;
@@ -95,7 +98,8 @@ static int open_file_write(struct perf_data_file *file)
        fd = open(file->path, O_CREAT|O_RDWR|O_TRUNC, S_IRUSR|S_IWUSR);
 
        if (fd < 0)
-               pr_err("failed to open %s : %s\n", file->path, strerror(errno));
+               pr_err("failed to open %s : %s\n", file->path,
+                       strerror_r(errno, sbuf, sizeof(sbuf)));
 
        return fd;
 }
index 71d419362634768f32d22862da4a44952e02edd4..ba357f3226c69533c5d79497e3d2fb2207656514 100644 (file)
 #include "util.h"
 #include "target.h"
 
+#define NSECS_PER_SEC  1000000000ULL
+#define NSECS_PER_USEC 1000ULL
+
 int verbose;
 bool dump_trace = false, quiet = false;
+int debug_ordered_events;
 
 static int _eprintf(int level, int var, const char *fmt, va_list args)
 {
@@ -42,6 +46,35 @@ int eprintf(int level, int var, const char *fmt, ...)
        return ret;
 }
 
+static int __eprintf_time(u64 t, const char *fmt, va_list args)
+{
+       int ret = 0;
+       u64 secs, usecs, nsecs = t;
+
+       secs   = nsecs / NSECS_PER_SEC;
+       nsecs -= secs  * NSECS_PER_SEC;
+       usecs  = nsecs / NSECS_PER_USEC;
+
+       ret = fprintf(stderr, "[%13" PRIu64 ".%06" PRIu64 "] ",
+                     secs, usecs);
+       ret += vfprintf(stderr, fmt, args);
+       return ret;
+}
+
+int eprintf_time(int level, int var, u64 t, const char *fmt, ...)
+{
+       int ret = 0;
+       va_list args;
+
+       if (var >= level) {
+               va_start(args, fmt);
+               ret = __eprintf_time(t, fmt, args);
+               va_end(args);
+       }
+
+       return ret;
+}
+
 /*
  * Overloading libtraceevent standard info print
  * function, display with -v in perf.
@@ -110,7 +143,8 @@ static struct debug_variable {
        const char *name;
        int *ptr;
 } debug_variables[] = {
-       { .name = "verbose", .ptr = &verbose },
+       { .name = "verbose",            .ptr = &verbose },
+       { .name = "ordered-events",     .ptr = &debug_ordered_events},
        { .name = NULL, }
 };
 
index 89fb6b0f7ab221d746163b5bb842ce6bf5416fad..be264d6f3b304933988f73fa3790e132bf6d4e2d 100644 (file)
@@ -3,6 +3,7 @@
 #define __PERF_DEBUG_H
 
 #include <stdbool.h>
+#include <string.h>
 #include "event.h"
 #include "../ui/helpline.h"
 #include "../ui/progress.h"
@@ -10,6 +11,7 @@
 
 extern int verbose;
 extern bool quiet, dump_trace;
+extern int debug_ordered_events;
 
 #ifndef pr_fmt
 #define pr_fmt(fmt) fmt
@@ -29,6 +31,14 @@ extern bool quiet, dump_trace;
 #define pr_debug3(fmt, ...) pr_debugN(3, pr_fmt(fmt), ##__VA_ARGS__)
 #define pr_debug4(fmt, ...) pr_debugN(4, pr_fmt(fmt), ##__VA_ARGS__)
 
+#define pr_time_N(n, var, t, fmt, ...) \
+       eprintf_time(n, var, t, fmt, ##__VA_ARGS__)
+
+#define pr_oe_time(t, fmt, ...)  pr_time_N(1, debug_ordered_events, t, pr_fmt(fmt), ##__VA_ARGS__)
+#define pr_oe_time2(t, fmt, ...) pr_time_N(2, debug_ordered_events, t, pr_fmt(fmt), ##__VA_ARGS__)
+
+#define STRERR_BUFSIZE 128     /* For the buffer size of strerror_r */
+
 int dump_printf(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
 void trace_event(union perf_event *event);
 
@@ -38,6 +48,7 @@ int ui__warning(const char *format, ...) __attribute__((format(printf, 1, 2)));
 void pr_stat(const char *fmt, ...);
 
 int eprintf(int level, int var, const char *fmt, ...) __attribute__((format(printf, 3, 4)));
+int eprintf_time(int level, int var, u64 t, const char *fmt, ...) __attribute__((format(printf, 4, 5)));
 
 int perf_debug_option(const char *str);
 
index 90d02c661dd4b5087e4f00759c08cab5290abb9a..0247acfdfaca807a1378631f19d6d38ddef67cf3 100644 (file)
@@ -37,6 +37,7 @@ int dso__read_binary_type_filename(const struct dso *dso,
 {
        char build_id_hex[BUILD_ID_SIZE * 2 + 1];
        int ret = 0;
+       size_t len;
 
        switch (type) {
        case DSO_BINARY_TYPE__DEBUGLINK: {
@@ -60,26 +61,25 @@ int dso__read_binary_type_filename(const struct dso *dso,
                break;
 
        case DSO_BINARY_TYPE__FEDORA_DEBUGINFO:
-               snprintf(filename, size, "%s/usr/lib/debug%s.debug",
-                        symbol_conf.symfs, dso->long_name);
+               len = __symbol__join_symfs(filename, size, "/usr/lib/debug");
+               snprintf(filename + len, size - len, "%s.debug", dso->long_name);
                break;
 
        case DSO_BINARY_TYPE__UBUNTU_DEBUGINFO:
-               snprintf(filename, size, "%s/usr/lib/debug%s",
-                        symbol_conf.symfs, dso->long_name);
+               len = __symbol__join_symfs(filename, size, "/usr/lib/debug");
+               snprintf(filename + len, size - len, "%s", dso->long_name);
                break;
 
        case DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO:
        {
                const char *last_slash;
-               size_t len;
                size_t dir_size;
 
                last_slash = dso->long_name + dso->long_name_len;
                while (last_slash != dso->long_name && *last_slash != '/')
                        last_slash--;
 
-               len = scnprintf(filename, size, "%s", symbol_conf.symfs);
+               len = __symbol__join_symfs(filename, size, "");
                dir_size = last_slash - dso->long_name + 2;
                if (dir_size > (size - len)) {
                        ret = -1;
@@ -100,26 +100,24 @@ int dso__read_binary_type_filename(const struct dso *dso,
                build_id__sprintf(dso->build_id,
                                  sizeof(dso->build_id),
                                  build_id_hex);
-               snprintf(filename, size,
-                        "%s/usr/lib/debug/.build-id/%.2s/%s.debug",
-                        symbol_conf.symfs, build_id_hex, build_id_hex + 2);
+               len = __symbol__join_symfs(filename, size, "/usr/lib/debug/.build-id/");
+               snprintf(filename + len, size - len, "%.2s/%s.debug",
+                        build_id_hex, build_id_hex + 2);
                break;
 
        case DSO_BINARY_TYPE__VMLINUX:
        case DSO_BINARY_TYPE__GUEST_VMLINUX:
        case DSO_BINARY_TYPE__SYSTEM_PATH_DSO:
-               snprintf(filename, size, "%s%s",
-                        symbol_conf.symfs, dso->long_name);
+               __symbol__join_symfs(filename, size, dso->long_name);
                break;
 
        case DSO_BINARY_TYPE__GUEST_KMODULE:
-               snprintf(filename, size, "%s%s%s", symbol_conf.symfs,
-                        root_dir, dso->long_name);
+               path__join3(filename, size, symbol_conf.symfs,
+                           root_dir, dso->long_name);
                break;
 
        case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE:
-               snprintf(filename, size, "%s%s", symbol_conf.symfs,
-                        dso->long_name);
+               __symbol__join_symfs(filename, size, dso->long_name);
                break;
 
        case DSO_BINARY_TYPE__KCORE:
@@ -164,13 +162,15 @@ static void close_first_dso(void);
 static int do_open(char *name)
 {
        int fd;
+       char sbuf[STRERR_BUFSIZE];
 
        do {
                fd = open(name, O_RDONLY);
                if (fd >= 0)
                        return fd;
 
-               pr_debug("dso open failed, mmap: %s\n", strerror(errno));
+               pr_debug("dso open failed, mmap: %s\n",
+                        strerror_r(errno, sbuf, sizeof(sbuf)));
                if (!dso__data_open_cnt || errno != EMFILE)
                        break;
 
@@ -532,10 +532,12 @@ static ssize_t cached_read(struct dso *dso, u64 offset, u8 *data, ssize_t size)
 static int data_file_size(struct dso *dso)
 {
        struct stat st;
+       char sbuf[STRERR_BUFSIZE];
 
        if (!dso->data.file_size) {
                if (fstat(dso->data.fd, &st)) {
-                       pr_err("dso mmap failed, fstat: %s\n", strerror(errno));
+                       pr_err("dso mmap failed, fstat: %s\n",
+                               strerror_r(errno, sbuf, sizeof(sbuf)));
                        return -1;
                }
                dso->data.file_size = st.st_size;
@@ -651,6 +653,65 @@ struct dso *dso__kernel_findnew(struct machine *machine, const char *name,
        return dso;
 }
 
+/*
+ * Find a matching entry and/or link current entry to RB tree.
+ * Either one of the dso or name parameter must be non-NULL or the
+ * function will not work.
+ */
+static struct dso *dso__findlink_by_longname(struct rb_root *root,
+                                            struct dso *dso, const char *name)
+{
+       struct rb_node **p = &root->rb_node;
+       struct rb_node  *parent = NULL;
+
+       if (!name)
+               name = dso->long_name;
+       /*
+        * Find node with the matching name
+        */
+       while (*p) {
+               struct dso *this = rb_entry(*p, struct dso, rb_node);
+               int rc = strcmp(name, this->long_name);
+
+               parent = *p;
+               if (rc == 0) {
+                       /*
+                        * In case the new DSO is a duplicate of an existing
+                        * one, print an one-time warning & put the new entry
+                        * at the end of the list of duplicates.
+                        */
+                       if (!dso || (dso == this))
+                               return this;    /* Find matching dso */
+                       /*
+                        * The core kernel DSOs may have duplicated long name.
+                        * In this case, the short name should be different.
+                        * Comparing the short names to differentiate the DSOs.
+                        */
+                       rc = strcmp(dso->short_name, this->short_name);
+                       if (rc == 0) {
+                               pr_err("Duplicated dso name: %s\n", name);
+                               return NULL;
+                       }
+               }
+               if (rc < 0)
+                       p = &parent->rb_left;
+               else
+                       p = &parent->rb_right;
+       }
+       if (dso) {
+               /* Add new node and rebalance tree */
+               rb_link_node(&dso->rb_node, parent, p);
+               rb_insert_color(&dso->rb_node, root);
+       }
+       return NULL;
+}
+
+static inline struct dso *
+dso__find_by_longname(const struct rb_root *root, const char *name)
+{
+       return dso__findlink_by_longname((struct rb_root *)root, NULL, name);
+}
+
 void dso__set_long_name(struct dso *dso, const char *name, bool name_allocated)
 {
        if (name == NULL)
@@ -753,6 +814,7 @@ struct dso *dso__new(const char *name)
                dso->a2l_fails = 1;
                dso->kernel = DSO_TYPE_USER;
                dso->needs_swap = DSO_SWAP__UNSET;
+               RB_CLEAR_NODE(&dso->rb_node);
                INIT_LIST_HEAD(&dso->node);
                INIT_LIST_HEAD(&dso->data.open_entry);
        }
@@ -763,6 +825,10 @@ struct dso *dso__new(const char *name)
 void dso__delete(struct dso *dso)
 {
        int i;
+
+       if (!RB_EMPTY_NODE(&dso->rb_node))
+               pr_err("DSO %s is still in rbtree when being deleted!\n",
+                      dso->long_name);
        for (i = 0; i < MAP__NR_TYPES; ++i)
                symbols__delete(&dso->symbols[i]);
 
@@ -849,35 +915,34 @@ bool __dsos__read_build_ids(struct list_head *head, bool with_hits)
        return have_build_id;
 }
 
-void dsos__add(struct list_head *head, struct dso *dso)
+void dsos__add(struct dsos *dsos, struct dso *dso)
 {
-       list_add_tail(&dso->node, head);
+       list_add_tail(&dso->node, &dsos->head);
+       dso__findlink_by_longname(&dsos->root, dso, NULL);
 }
 
-struct dso *dsos__find(const struct list_head *head, const char *name, bool cmp_short)
+struct dso *dsos__find(const struct dsos *dsos, const char *name,
+                      bool cmp_short)
 {
        struct dso *pos;
 
        if (cmp_short) {
-               list_for_each_entry(pos, head, node)
+               list_for_each_entry(pos, &dsos->head, node)
                        if (strcmp(pos->short_name, name) == 0)
                                return pos;
                return NULL;
        }
-       list_for_each_entry(pos, head, node)
-               if (strcmp(pos->long_name, name) == 0)
-                       return pos;
-       return NULL;
+       return dso__find_by_longname(&dsos->root, name);
 }
 
-struct dso *__dsos__findnew(struct list_head *head, const char *name)
+struct dso *__dsos__findnew(struct dsos *dsos, const char *name)
 {
-       struct dso *dso = dsos__find(head, name, false);
+       struct dso *dso = dsos__find(dsos, name, false);
 
        if (!dso) {
                dso = dso__new(name);
                if (dso != NULL) {
-                       dsos__add(head, dso);
+                       dsos__add(dsos, dso);
                        dso__set_basename(dso);
                }
        }
index 5e463c0964d442b23a44c67377ec016925f68363..acb651acc7fdf1e6ee74dde78cf85ee98da6a1bf 100644 (file)
@@ -90,8 +90,18 @@ struct dso_cache {
        char data[0];
 };
 
+/*
+ * DSOs are put into both a list for fast iteration and rbtree for fast
+ * long name lookup.
+ */
+struct dsos {
+       struct list_head head;
+       struct rb_root   root;  /* rbtree root sorted by long name */
+};
+
 struct dso {
        struct list_head node;
+       struct rb_node   rb_node;       /* rbtree node sorted by long name */
        struct rb_root   symbols[MAP__NR_TYPES];
        struct rb_root   symbol_names[MAP__NR_TYPES];
        void             *a2l;
@@ -224,10 +234,10 @@ struct map *dso__new_map(const char *name);
 struct dso *dso__kernel_findnew(struct machine *machine, const char *name,
                                const char *short_name, int dso_type);
 
-void dsos__add(struct list_head *head, struct dso *dso);
-struct dso *dsos__find(const struct list_head *head, const char *name,
+void dsos__add(struct dsos *dsos, struct dso *dso);
+struct dso *dsos__find(const struct dsos *dsos, const char *name,
                       bool cmp_short);
-struct dso *__dsos__findnew(struct list_head *head, const char *name);
+struct dso *__dsos__findnew(struct dsos *dsos, const char *name);
 bool __dsos__read_build_ids(struct list_head *head, bool with_hits);
 
 size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp,
index 1398c83d896dffb170d5ca107bdb98e0d9630aaa..4af6b279e34a94881da3e838ff41f407aeb0cbfc 100644 (file)
@@ -558,13 +558,17 @@ int perf_event__synthesize_kernel_mmap(struct perf_tool *tool,
        struct map *map;
        struct kmap *kmap;
        int err;
+       union perf_event *event;
+
+       if (machine->vmlinux_maps[0] == NULL)
+               return -1;
+
        /*
         * We should get this from /sys/kernel/sections/.text, but till that is
         * available use this, and after it is use this as a fallback for older
         * kernels.
         */
-       union perf_event *event = zalloc((sizeof(event->mmap) +
-                                         machine->id_hdr_size));
+       event = zalloc((sizeof(event->mmap) + machine->id_hdr_size));
        if (event == NULL) {
                pr_debug("Not enough memory synthesizing mmap event "
                         "for kernel modules\n");
@@ -784,9 +788,9 @@ try_again:
                 * "[vdso]" dso, but for now lets use the old trick of looking
                 * in the whole kernel symbol list.
                 */
-               if ((long long)al->addr < 0 &&
-                   cpumode == PERF_RECORD_MISC_USER &&
-                   machine && mg != &machine->kmaps) {
+               if (cpumode == PERF_RECORD_MISC_USER && machine &&
+                   mg != &machine->kmaps &&
+                   machine__kernel_ip(machine, al->addr)) {
                        mg = &machine->kmaps;
                        load_map = true;
                        goto try_again;
index 94d6976180daa5959090fae2fed308b45b14af27..7eb7107731eca8a47db95d590a091b176e70d8f7 100644 (file)
@@ -156,6 +156,8 @@ struct perf_sample {
        u32 cpu;
        u32 raw_size;
        u64 data_src;
+       u32 flags;
+       u16 insn_len;
        void *raw_data;
        struct ip_callchain *callchain;
        struct branch_stack *branch_stack;
index 814e954c1318ed04ed1bcf9666927f6a4c64e426..3cebc9a8d52e232e9dafe13dd2b8cf2b0dcd613d 100644 (file)
@@ -25,6 +25,9 @@
 #include <linux/bitops.h>
 #include <linux/hash.h>
 
+static void perf_evlist__mmap_put(struct perf_evlist *evlist, int idx);
+static void __perf_evlist__munmap(struct perf_evlist *evlist, int idx);
+
 #define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y))
 #define SID(e, x, y) xyarray__entry(e->sample_id, x, y)
 
@@ -37,6 +40,7 @@ void perf_evlist__init(struct perf_evlist *evlist, struct cpu_map *cpus,
                INIT_HLIST_HEAD(&evlist->heads[i]);
        INIT_LIST_HEAD(&evlist->entries);
        perf_evlist__set_maps(evlist, cpus, threads);
+       fdarray__init(&evlist->pollfd, 64);
        evlist->workload.pid = -1;
 }
 
@@ -102,7 +106,7 @@ static void perf_evlist__purge(struct perf_evlist *evlist)
 void perf_evlist__exit(struct perf_evlist *evlist)
 {
        zfree(&evlist->mmap);
-       zfree(&evlist->pollfd);
+       fdarray__exit(&evlist->pollfd);
 }
 
 void perf_evlist__delete(struct perf_evlist *evlist)
@@ -122,6 +126,7 @@ void perf_evlist__add(struct perf_evlist *evlist, struct perf_evsel *entry)
 {
        list_add_tail(&entry->node, &evlist->entries);
        entry->idx = evlist->nr_entries;
+       entry->tracking = !entry->idx;
 
        if (!evlist->nr_entries++)
                perf_evlist__set_id_pos(evlist);
@@ -265,17 +270,27 @@ int perf_evlist__add_newtp(struct perf_evlist *evlist,
        return 0;
 }
 
+static int perf_evlist__nr_threads(struct perf_evlist *evlist,
+                                  struct perf_evsel *evsel)
+{
+       if (evsel->system_wide)
+               return 1;
+       else
+               return thread_map__nr(evlist->threads);
+}
+
 void perf_evlist__disable(struct perf_evlist *evlist)
 {
        int cpu, thread;
        struct perf_evsel *pos;
        int nr_cpus = cpu_map__nr(evlist->cpus);
-       int nr_threads = thread_map__nr(evlist->threads);
+       int nr_threads;
 
        for (cpu = 0; cpu < nr_cpus; cpu++) {
                evlist__for_each(evlist, pos) {
                        if (!perf_evsel__is_group_leader(pos) || !pos->fd)
                                continue;
+                       nr_threads = perf_evlist__nr_threads(evlist, pos);
                        for (thread = 0; thread < nr_threads; thread++)
                                ioctl(FD(pos, cpu, thread),
                                      PERF_EVENT_IOC_DISABLE, 0);
@@ -288,12 +303,13 @@ void perf_evlist__enable(struct perf_evlist *evlist)
        int cpu, thread;
        struct perf_evsel *pos;
        int nr_cpus = cpu_map__nr(evlist->cpus);
-       int nr_threads = thread_map__nr(evlist->threads);
+       int nr_threads;
 
        for (cpu = 0; cpu < nr_cpus; cpu++) {
                evlist__for_each(evlist, pos) {
                        if (!perf_evsel__is_group_leader(pos) || !pos->fd)
                                continue;
+                       nr_threads = perf_evlist__nr_threads(evlist, pos);
                        for (thread = 0; thread < nr_threads; thread++)
                                ioctl(FD(pos, cpu, thread),
                                      PERF_EVENT_IOC_ENABLE, 0);
@@ -305,12 +321,14 @@ int perf_evlist__disable_event(struct perf_evlist *evlist,
                               struct perf_evsel *evsel)
 {
        int cpu, thread, err;
+       int nr_cpus = cpu_map__nr(evlist->cpus);
+       int nr_threads = perf_evlist__nr_threads(evlist, evsel);
 
        if (!evsel->fd)
                return 0;
 
-       for (cpu = 0; cpu < evlist->cpus->nr; cpu++) {
-               for (thread = 0; thread < evlist->threads->nr; thread++) {
+       for (cpu = 0; cpu < nr_cpus; cpu++) {
+               for (thread = 0; thread < nr_threads; thread++) {
                        err = ioctl(FD(evsel, cpu, thread),
                                    PERF_EVENT_IOC_DISABLE, 0);
                        if (err)
@@ -324,12 +342,14 @@ int perf_evlist__enable_event(struct perf_evlist *evlist,
                              struct perf_evsel *evsel)
 {
        int cpu, thread, err;
+       int nr_cpus = cpu_map__nr(evlist->cpus);
+       int nr_threads = perf_evlist__nr_threads(evlist, evsel);
 
        if (!evsel->fd)
                return -EINVAL;
 
-       for (cpu = 0; cpu < evlist->cpus->nr; cpu++) {
-               for (thread = 0; thread < evlist->threads->nr; thread++) {
+       for (cpu = 0; cpu < nr_cpus; cpu++) {
+               for (thread = 0; thread < nr_threads; thread++) {
                        err = ioctl(FD(evsel, cpu, thread),
                                    PERF_EVENT_IOC_ENABLE, 0);
                        if (err)
@@ -339,21 +359,111 @@ int perf_evlist__enable_event(struct perf_evlist *evlist,
        return 0;
 }
 
-static int perf_evlist__alloc_pollfd(struct perf_evlist *evlist)
+static int perf_evlist__enable_event_cpu(struct perf_evlist *evlist,
+                                        struct perf_evsel *evsel, int cpu)
+{
+       int thread, err;
+       int nr_threads = perf_evlist__nr_threads(evlist, evsel);
+
+       if (!evsel->fd)
+               return -EINVAL;
+
+       for (thread = 0; thread < nr_threads; thread++) {
+               err = ioctl(FD(evsel, cpu, thread),
+                           PERF_EVENT_IOC_ENABLE, 0);
+               if (err)
+                       return err;
+       }
+       return 0;
+}
+
+static int perf_evlist__enable_event_thread(struct perf_evlist *evlist,
+                                           struct perf_evsel *evsel,
+                                           int thread)
+{
+       int cpu, err;
+       int nr_cpus = cpu_map__nr(evlist->cpus);
+
+       if (!evsel->fd)
+               return -EINVAL;
+
+       for (cpu = 0; cpu < nr_cpus; cpu++) {
+               err = ioctl(FD(evsel, cpu, thread), PERF_EVENT_IOC_ENABLE, 0);
+               if (err)
+                       return err;
+       }
+       return 0;
+}
+
+int perf_evlist__enable_event_idx(struct perf_evlist *evlist,
+                                 struct perf_evsel *evsel, int idx)
+{
+       bool per_cpu_mmaps = !cpu_map__empty(evlist->cpus);
+
+       if (per_cpu_mmaps)
+               return perf_evlist__enable_event_cpu(evlist, evsel, idx);
+       else
+               return perf_evlist__enable_event_thread(evlist, evsel, idx);
+}
+
+int perf_evlist__alloc_pollfd(struct perf_evlist *evlist)
 {
        int nr_cpus = cpu_map__nr(evlist->cpus);
        int nr_threads = thread_map__nr(evlist->threads);
-       int nfds = nr_cpus * nr_threads * evlist->nr_entries;
-       evlist->pollfd = malloc(sizeof(struct pollfd) * nfds);
-       return evlist->pollfd != NULL ? 0 : -ENOMEM;
+       int nfds = 0;
+       struct perf_evsel *evsel;
+
+       list_for_each_entry(evsel, &evlist->entries, node) {
+               if (evsel->system_wide)
+                       nfds += nr_cpus;
+               else
+                       nfds += nr_cpus * nr_threads;
+       }
+
+       if (fdarray__available_entries(&evlist->pollfd) < nfds &&
+           fdarray__grow(&evlist->pollfd, nfds) < 0)
+               return -ENOMEM;
+
+       return 0;
+}
+
+static int __perf_evlist__add_pollfd(struct perf_evlist *evlist, int fd, int idx)
+{
+       int pos = fdarray__add(&evlist->pollfd, fd, POLLIN | POLLERR | POLLHUP);
+       /*
+        * Save the idx so that when we filter out fds POLLHUP'ed we can
+        * close the associated evlist->mmap[] entry.
+        */
+       if (pos >= 0) {
+               evlist->pollfd.priv[pos].idx = idx;
+
+               fcntl(fd, F_SETFL, O_NONBLOCK);
+       }
+
+       return pos;
+}
+
+int perf_evlist__add_pollfd(struct perf_evlist *evlist, int fd)
+{
+       return __perf_evlist__add_pollfd(evlist, fd, -1);
+}
+
+static void perf_evlist__munmap_filtered(struct fdarray *fda, int fd)
+{
+       struct perf_evlist *evlist = container_of(fda, struct perf_evlist, pollfd);
+
+       perf_evlist__mmap_put(evlist, fda->priv[fd].idx);
+}
+
+int perf_evlist__filter_pollfd(struct perf_evlist *evlist, short revents_and_mask)
+{
+       return fdarray__filter(&evlist->pollfd, revents_and_mask,
+                              perf_evlist__munmap_filtered);
 }
 
-void perf_evlist__add_pollfd(struct perf_evlist *evlist, int fd)
+int perf_evlist__poll(struct perf_evlist *evlist, int timeout)
 {
-       fcntl(fd, F_SETFL, O_NONBLOCK);
-       evlist->pollfd[evlist->nr_fds].fd = fd;
-       evlist->pollfd[evlist->nr_fds].events = POLLIN;
-       evlist->nr_fds++;
+       return fdarray__poll(&evlist->pollfd, timeout);
 }
 
 static void perf_evlist__id_hash(struct perf_evlist *evlist,
@@ -566,14 +676,36 @@ union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx)
        return event;
 }
 
+static bool perf_mmap__empty(struct perf_mmap *md)
+{
+       return perf_mmap__read_head(md) != md->prev;
+}
+
+static void perf_evlist__mmap_get(struct perf_evlist *evlist, int idx)
+{
+       ++evlist->mmap[idx].refcnt;
+}
+
+static void perf_evlist__mmap_put(struct perf_evlist *evlist, int idx)
+{
+       BUG_ON(evlist->mmap[idx].refcnt == 0);
+
+       if (--evlist->mmap[idx].refcnt == 0)
+               __perf_evlist__munmap(evlist, idx);
+}
+
 void perf_evlist__mmap_consume(struct perf_evlist *evlist, int idx)
 {
+       struct perf_mmap *md = &evlist->mmap[idx];
+
        if (!evlist->overwrite) {
-               struct perf_mmap *md = &evlist->mmap[idx];
                unsigned int old = md->prev;
 
                perf_mmap__write_tail(md, old);
        }
+
+       if (md->refcnt == 1 && perf_mmap__empty(md))
+               perf_evlist__mmap_put(evlist, idx);
 }
 
 static void __perf_evlist__munmap(struct perf_evlist *evlist, int idx)
@@ -581,6 +713,7 @@ static void __perf_evlist__munmap(struct perf_evlist *evlist, int idx)
        if (evlist->mmap[idx].base != NULL) {
                munmap(evlist->mmap[idx].base, evlist->mmap_len);
                evlist->mmap[idx].base = NULL;
+               evlist->mmap[idx].refcnt = 0;
        }
 }
 
@@ -614,6 +747,20 @@ struct mmap_params {
 static int __perf_evlist__mmap(struct perf_evlist *evlist, int idx,
                               struct mmap_params *mp, int fd)
 {
+       /*
+        * The last one will be done at perf_evlist__mmap_consume(), so that we
+        * make sure we don't prevent tools from consuming every last event in
+        * the ring buffer.
+        *
+        * I.e. we can get the POLLHUP meaning that the fd doesn't exist
+        * anymore, but the last events for it are still in the ring buffer,
+        * waiting to be consumed.
+        *
+        * Tools can chose to ignore this at their own discretion, but the
+        * evlist layer can't just drop it when filtering events in
+        * perf_evlist__filter_pollfd().
+        */
+       evlist->mmap[idx].refcnt = 2;
        evlist->mmap[idx].prev = 0;
        evlist->mmap[idx].mask = mp->mask;
        evlist->mmap[idx].base = mmap(NULL, evlist->mmap_len, mp->prot,
@@ -625,7 +772,6 @@ static int __perf_evlist__mmap(struct perf_evlist *evlist, int idx,
                return -1;
        }
 
-       perf_evlist__add_pollfd(evlist, fd);
        return 0;
 }
 
@@ -636,7 +782,12 @@ static int perf_evlist__mmap_per_evsel(struct perf_evlist *evlist, int idx,
        struct perf_evsel *evsel;
 
        evlist__for_each(evlist, evsel) {
-               int fd = FD(evsel, cpu, thread);
+               int fd;
+
+               if (evsel->system_wide && thread)
+                       continue;
+
+               fd = FD(evsel, cpu, thread);
 
                if (*output == -1) {
                        *output = fd;
@@ -645,6 +796,13 @@ static int perf_evlist__mmap_per_evsel(struct perf_evlist *evlist, int idx,
                } else {
                        if (ioctl(fd, PERF_EVENT_IOC_SET_OUTPUT, *output) != 0)
                                return -1;
+
+                       perf_evlist__mmap_get(evlist, idx);
+               }
+
+               if (__perf_evlist__add_pollfd(evlist, fd, idx) < 0) {
+                       perf_evlist__mmap_put(evlist, idx);
+                       return -1;
                }
 
                if ((evsel->attr.read_format & PERF_FORMAT_ID) &&
@@ -804,7 +962,7 @@ int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages,
        if (evlist->mmap == NULL && perf_evlist__alloc_mmap(evlist) < 0)
                return -ENOMEM;
 
-       if (evlist->pollfd == NULL && perf_evlist__alloc_pollfd(evlist) < 0)
+       if (evlist->pollfd.entries == NULL && perf_evlist__alloc_pollfd(evlist) < 0)
                return -ENOMEM;
 
        evlist->overwrite = overwrite;
@@ -1061,6 +1219,8 @@ int perf_evlist__prepare_workload(struct perf_evlist *evlist, struct target *tar
        }
 
        if (!evlist->workload.pid) {
+               int ret;
+
                if (pipe_output)
                        dup2(2, 1);
 
@@ -1078,8 +1238,22 @@ int perf_evlist__prepare_workload(struct perf_evlist *evlist, struct target *tar
                /*
                 * Wait until the parent tells us to go.
                 */
-               if (read(go_pipe[0], &bf, 1) == -1)
-                       perror("unable to read pipe");
+               ret = read(go_pipe[0], &bf, 1);
+               /*
+                * The parent will ask for the execvp() to be performed by
+                * writing exactly one byte, in workload.cork_fd, usually via
+                * perf_evlist__start_workload().
+                *
+                * For cancelling the workload without actuallin running it,
+                * the parent will just close workload.cork_fd, without writing
+                * anything, i.e. read will return zero and we just exit()
+                * here.
+                */
+               if (ret != 1) {
+                       if (ret == -1)
+                               perror("unable to read pipe");
+                       exit(ret);
+               }
 
                execvp(argv[0], (char **)argv);
 
@@ -1202,7 +1376,7 @@ int perf_evlist__strerror_open(struct perf_evlist *evlist __maybe_unused,
                               int err, char *buf, size_t size)
 {
        int printed, value;
-       char sbuf[128], *emsg = strerror_r(err, sbuf, sizeof(sbuf));
+       char sbuf[STRERR_BUFSIZE], *emsg = strerror_r(err, sbuf, sizeof(sbuf));
 
        switch (err) {
        case EACCES:
@@ -1250,3 +1424,19 @@ void perf_evlist__to_front(struct perf_evlist *evlist,
 
        list_splice(&move, &evlist->entries);
 }
+
+void perf_evlist__set_tracking_event(struct perf_evlist *evlist,
+                                    struct perf_evsel *tracking_evsel)
+{
+       struct perf_evsel *evsel;
+
+       if (tracking_evsel->tracking)
+               return;
+
+       evlist__for_each(evlist, evsel) {
+               if (evsel != tracking_evsel)
+                       evsel->tracking = false;
+       }
+
+       tracking_evsel->tracking = true;
+}
index f5173cd63693cc7944b500a65a0b407567512143..bd312b01e8766e97dd50f8661f3e4213f8513fde 100644 (file)
@@ -2,6 +2,7 @@
 #define __PERF_EVLIST_H 1
 
 #include <linux/list.h>
+#include <api/fd/array.h>
 #include <stdio.h>
 #include "../perf.h"
 #include "event.h"
@@ -17,9 +18,15 @@ struct record_opts;
 #define PERF_EVLIST__HLIST_BITS 8
 #define PERF_EVLIST__HLIST_SIZE (1 << PERF_EVLIST__HLIST_BITS)
 
+/**
+ * struct perf_mmap - perf's ring buffer mmap details
+ *
+ * @refcnt - e.g. code using PERF_EVENT_IOC_SET_OUTPUT to share this
+ */
 struct perf_mmap {
        void             *base;
        int              mask;
+       int              refcnt;
        unsigned int     prev;
        char             event_copy[PERF_SAMPLE_MAX_SIZE];
 };
@@ -29,7 +36,6 @@ struct perf_evlist {
        struct hlist_head heads[PERF_EVLIST__HLIST_SIZE];
        int              nr_entries;
        int              nr_groups;
-       int              nr_fds;
        int              nr_mmaps;
        size_t           mmap_len;
        int              id_pos;
@@ -40,8 +46,8 @@ struct perf_evlist {
                pid_t   pid;
        } workload;
        bool             overwrite;
+       struct fdarray   pollfd;
        struct perf_mmap *mmap;
-       struct pollfd    *pollfd;
        struct thread_map *threads;
        struct cpu_map    *cpus;
        struct perf_evsel *selected;
@@ -82,7 +88,11 @@ perf_evlist__find_tracepoint_by_name(struct perf_evlist *evlist,
 void perf_evlist__id_add(struct perf_evlist *evlist, struct perf_evsel *evsel,
                         int cpu, int thread, u64 id);
 
-void perf_evlist__add_pollfd(struct perf_evlist *evlist, int fd);
+int perf_evlist__add_pollfd(struct perf_evlist *evlist, int fd);
+int perf_evlist__alloc_pollfd(struct perf_evlist *evlist);
+int perf_evlist__filter_pollfd(struct perf_evlist *evlist, short revents_and_mask);
+
+int perf_evlist__poll(struct perf_evlist *evlist, int timeout);
 
 struct perf_evsel *perf_evlist__id2evsel(struct perf_evlist *evlist, u64 id);
 
@@ -122,6 +132,8 @@ int perf_evlist__disable_event(struct perf_evlist *evlist,
                               struct perf_evsel *evsel);
 int perf_evlist__enable_event(struct perf_evlist *evlist,
                              struct perf_evsel *evsel);
+int perf_evlist__enable_event_idx(struct perf_evlist *evlist,
+                                 struct perf_evsel *evsel, int idx);
 
 void perf_evlist__set_selected(struct perf_evlist *evlist,
                               struct perf_evsel *evsel);
@@ -262,4 +274,7 @@ void perf_evlist__to_front(struct perf_evlist *evlist,
 #define evlist__for_each_safe(evlist, tmp, evsel) \
        __evlist__for_each_safe(&(evlist)->entries, tmp, evsel)
 
+void perf_evlist__set_tracking_event(struct perf_evlist *evlist,
+                                    struct perf_evsel *tracking_evsel);
+
 #endif /* __PERF_EVLIST_H */
index 21a373ebea226a8208c3ccf2aaee9ad92ad4156d..e0868a901c4ac07a1855251b94937a4a1dd55cf4 100644 (file)
@@ -162,6 +162,7 @@ void perf_evsel__init(struct perf_evsel *evsel,
                      struct perf_event_attr *attr, int idx)
 {
        evsel->idx         = idx;
+       evsel->tracking    = !idx;
        evsel->attr        = *attr;
        evsel->leader      = evsel;
        evsel->unit        = "";
@@ -502,20 +503,19 @@ int perf_evsel__group_desc(struct perf_evsel *evsel, char *buf, size_t size)
 }
 
 static void
-perf_evsel__config_callgraph(struct perf_evsel *evsel,
-                            struct record_opts *opts)
+perf_evsel__config_callgraph(struct perf_evsel *evsel)
 {
        bool function = perf_evsel__is_function_event(evsel);
        struct perf_event_attr *attr = &evsel->attr;
 
        perf_evsel__set_sample_bit(evsel, CALLCHAIN);
 
-       if (opts->call_graph == CALLCHAIN_DWARF) {
+       if (callchain_param.record_mode == CALLCHAIN_DWARF) {
                if (!function) {
                        perf_evsel__set_sample_bit(evsel, REGS_USER);
                        perf_evsel__set_sample_bit(evsel, STACK_USER);
                        attr->sample_regs_user = PERF_REGS_MASK;
-                       attr->sample_stack_user = opts->stack_dump_size;
+                       attr->sample_stack_user = callchain_param.dump_size;
                        attr->exclude_callchain_user = 1;
                } else {
                        pr_info("Cannot use DWARF unwind for function trace event,"
@@ -561,7 +561,7 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts)
 {
        struct perf_evsel *leader = evsel->leader;
        struct perf_event_attr *attr = &evsel->attr;
-       int track = !evsel->idx; /* only the first counter needs these */
+       int track = evsel->tracking;
        bool per_cpu = opts->target.default_per_cpu && !opts->target.per_thread;
 
        attr->sample_id_all = perf_missing_features.sample_id_all ? 0 : 1;
@@ -624,8 +624,8 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts)
                attr->mmap_data = track;
        }
 
-       if (opts->call_graph_enabled && !evsel->no_aux_samples)
-               perf_evsel__config_callgraph(evsel, opts);
+       if (callchain_param.enabled && !evsel->no_aux_samples)
+               perf_evsel__config_callgraph(evsel);
 
        if (target__has_cpu(&opts->target))
                perf_evsel__set_sample_bit(evsel, CPU);
@@ -633,9 +633,12 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts)
        if (opts->period)
                perf_evsel__set_sample_bit(evsel, PERIOD);
 
-       if (!perf_missing_features.sample_id_all &&
-           (opts->sample_time || !opts->no_inherit ||
-            target__has_cpu(&opts->target) || per_cpu))
+       /*
+        * When the user explicitely disabled time don't force it here.
+        */
+       if (opts->sample_time &&
+           (!perf_missing_features.sample_id_all &&
+           (!opts->no_inherit || target__has_cpu(&opts->target) || per_cpu)))
                perf_evsel__set_sample_bit(evsel, TIME);
 
        if (opts->raw_samples && !evsel->no_aux_samples) {
@@ -692,6 +695,10 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts)
 int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads)
 {
        int cpu, thread;
+
+       if (evsel->system_wide)
+               nthreads = 1;
+
        evsel->fd = xyarray__new(ncpus, nthreads, sizeof(int));
 
        if (evsel->fd) {
@@ -710,6 +717,9 @@ static int perf_evsel__run_ioctl(struct perf_evsel *evsel, int ncpus, int nthrea
 {
        int cpu, thread;
 
+       if (evsel->system_wide)
+               nthreads = 1;
+
        for (cpu = 0; cpu < ncpus; cpu++) {
                for (thread = 0; thread < nthreads; thread++) {
                        int fd = FD(evsel, cpu, thread),
@@ -740,6 +750,9 @@ int perf_evsel__enable(struct perf_evsel *evsel, int ncpus, int nthreads)
 
 int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads)
 {
+       if (evsel->system_wide)
+               nthreads = 1;
+
        evsel->sample_id = xyarray__new(ncpus, nthreads, sizeof(struct perf_sample_id));
        if (evsel->sample_id == NULL)
                return -ENOMEM;
@@ -784,6 +797,9 @@ void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads)
 {
        int cpu, thread;
 
+       if (evsel->system_wide)
+               nthreads = 1;
+
        for (cpu = 0; cpu < ncpus; cpu++)
                for (thread = 0; thread < nthreads; ++thread) {
                        close(FD(evsel, cpu, thread));
@@ -872,6 +888,9 @@ int __perf_evsel__read(struct perf_evsel *evsel,
        int cpu, thread;
        struct perf_counts_values *aggr = &evsel->counts->aggr, count;
 
+       if (evsel->system_wide)
+               nthreads = 1;
+
        aggr->val = aggr->ena = aggr->run = 0;
 
        for (cpu = 0; cpu < ncpus; cpu++) {
@@ -994,13 +1013,18 @@ static size_t perf_event_attr__fprintf(struct perf_event_attr *attr, FILE *fp)
 static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
                              struct thread_map *threads)
 {
-       int cpu, thread;
+       int cpu, thread, nthreads;
        unsigned long flags = PERF_FLAG_FD_CLOEXEC;
        int pid = -1, err;
        enum { NO_CHANGE, SET_TO_MAX, INCREASED_MAX } set_rlimit = NO_CHANGE;
 
+       if (evsel->system_wide)
+               nthreads = 1;
+       else
+               nthreads = threads->nr;
+
        if (evsel->fd == NULL &&
-           perf_evsel__alloc_fd(evsel, cpus->nr, threads->nr) < 0)
+           perf_evsel__alloc_fd(evsel, cpus->nr, nthreads) < 0)
                return -ENOMEM;
 
        if (evsel->cgrp) {
@@ -1024,10 +1048,10 @@ retry_sample_id:
 
        for (cpu = 0; cpu < cpus->nr; cpu++) {
 
-               for (thread = 0; thread < threads->nr; thread++) {
+               for (thread = 0; thread < nthreads; thread++) {
                        int group_fd;
 
-                       if (!evsel->cgrp)
+                       if (!evsel->cgrp && !evsel->system_wide)
                                pid = threads->map[thread];
 
                        group_fd = get_group_fd(evsel, cpu, thread);
@@ -1100,7 +1124,7 @@ out_close:
                        close(FD(evsel, cpu, thread));
                        FD(evsel, cpu, thread) = -1;
                }
-               thread = threads->nr;
+               thread = nthreads;
        } while (--cpu >= 0);
        return err;
 }
@@ -2002,6 +2026,8 @@ bool perf_evsel__fallback(struct perf_evsel *evsel, int err,
 int perf_evsel__open_strerror(struct perf_evsel *evsel, struct target *target,
                              int err, char *msg, size_t size)
 {
+       char sbuf[STRERR_BUFSIZE];
+
        switch (err) {
        case EPERM:
        case EACCES:
@@ -2036,13 +2062,20 @@ int perf_evsel__open_strerror(struct perf_evsel *evsel, struct target *target,
        "No APIC? If so then you can boot the kernel with the \"lapic\" boot parameter to force-enable it.");
 #endif
                break;
+       case EBUSY:
+               if (find_process("oprofiled"))
+                       return scnprintf(msg, size,
+       "The PMU counters are busy/taken by another profiler.\n"
+       "We found oprofile daemon running, please stop it and try again.");
+               break;
        default:
                break;
        }
 
        return scnprintf(msg, size,
-       "The sys_perf_event_open() syscall returned with %d (%s) for event (%s).  \n"
+       "The sys_perf_event_open() syscall returned with %d (%s) for event (%s).\n"
        "/bin/dmesg may provide additional information.\n"
        "No CONFIG_PERF_EVENTS=y kernel support configured?\n",
-                        err, strerror(err), perf_evsel__name(evsel));
+                        err, strerror_r(err, sbuf, sizeof(sbuf)),
+                        perf_evsel__name(evsel));
 }
index d7f93ce0ebc12b33f542ec82d9d4f2d52ad9c661..7bc314be6a7bea55b81611788c57e95313041af9 100644 (file)
@@ -85,6 +85,8 @@ struct perf_evsel {
        bool                    needs_swap;
        bool                    no_aux_samples;
        bool                    immediate;
+       bool                    system_wide;
+       bool                    tracking;
        /* parse modifier helper */
        int                     exclude_GH;
        int                     nr_members;
index 158c787ce0c40e8bc673e3e73062dcaef3872c4f..ce0de00399da381accf00472f66c6064cdcee20a 100644 (file)
@@ -214,11 +214,11 @@ static int machine__hit_all_dsos(struct machine *machine)
 {
        int err;
 
-       err = __dsos__hit_all(&machine->kernel_dsos);
+       err = __dsos__hit_all(&machine->kernel_dsos.head);
        if (err)
                return err;
 
-       return __dsos__hit_all(&machine->user_dsos);
+       return __dsos__hit_all(&machine->user_dsos.head);
 }
 
 int dsos__hit_all(struct perf_session *session)
@@ -288,11 +288,12 @@ static int machine__write_buildid_table(struct machine *machine, int fd)
                umisc = PERF_RECORD_MISC_GUEST_USER;
        }
 
-       err = __dsos__write_buildid_table(&machine->kernel_dsos, machine,
+       err = __dsos__write_buildid_table(&machine->kernel_dsos.head, machine,
                                          machine->pid, kmisc, fd);
        if (err == 0)
-               err = __dsos__write_buildid_table(&machine->user_dsos, machine,
-                                                 machine->pid, umisc, fd);
+               err = __dsos__write_buildid_table(&machine->user_dsos.head,
+                                                 machine, machine->pid, umisc,
+                                                 fd);
        return err;
 }
 
@@ -455,9 +456,10 @@ static int __dsos__cache_build_ids(struct list_head *head,
 
 static int machine__cache_build_ids(struct machine *machine, const char *debugdir)
 {
-       int ret = __dsos__cache_build_ids(&machine->kernel_dsos, machine,
+       int ret = __dsos__cache_build_ids(&machine->kernel_dsos.head, machine,
                                          debugdir);
-       ret |= __dsos__cache_build_ids(&machine->user_dsos, machine, debugdir);
+       ret |= __dsos__cache_build_ids(&machine->user_dsos.head, machine,
+                                      debugdir);
        return ret;
 }
 
@@ -483,8 +485,10 @@ static int perf_session__cache_build_ids(struct perf_session *session)
 
 static bool machine__read_build_ids(struct machine *machine, bool with_hits)
 {
-       bool ret = __dsos__read_build_ids(&machine->kernel_dsos, with_hits);
-       ret |= __dsos__read_build_ids(&machine->user_dsos, with_hits);
+       bool ret;
+
+       ret  = __dsos__read_build_ids(&machine->kernel_dsos.head, with_hits);
+       ret |= __dsos__read_build_ids(&machine->user_dsos.head, with_hits);
        return ret;
 }
 
@@ -1548,7 +1552,7 @@ static int __event_process_build_id(struct build_id_event *bev,
                                    struct perf_session *session)
 {
        int err = -1;
-       struct list_head *head;
+       struct dsos *dsos;
        struct machine *machine;
        u16 misc;
        struct dso *dso;
@@ -1563,22 +1567,22 @@ static int __event_process_build_id(struct build_id_event *bev,
        switch (misc) {
        case PERF_RECORD_MISC_KERNEL:
                dso_type = DSO_TYPE_KERNEL;
-               head = &machine->kernel_dsos;
+               dsos = &machine->kernel_dsos;
                break;
        case PERF_RECORD_MISC_GUEST_KERNEL:
                dso_type = DSO_TYPE_GUEST_KERNEL;
-               head = &machine->kernel_dsos;
+               dsos = &machine->kernel_dsos;
                break;
        case PERF_RECORD_MISC_USER:
        case PERF_RECORD_MISC_GUEST_USER:
                dso_type = DSO_TYPE_USER;
-               head = &machine->user_dsos;
+               dsos = &machine->user_dsos;
                break;
        default:
                goto out;
        }
 
-       dso = __dsos__findnew(head, filename);
+       dso = __dsos__findnew(dsos, filename);
        if (dso != NULL) {
                char sbuild_id[BUILD_ID_SIZE * 2 + 1];
 
index 30df6187ee026acf0fb9f12013fbde891d3bdd70..86569fa3651d00a851e9e38da54df647cc6ba17c 100644 (file)
@@ -277,6 +277,28 @@ void hists__decay_entries(struct hists *hists, bool zap_user, bool zap_kernel)
        }
 }
 
+void hists__delete_entries(struct hists *hists)
+{
+       struct rb_node *next = rb_first(&hists->entries);
+       struct hist_entry *n;
+
+       while (next) {
+               n = rb_entry(next, struct hist_entry, rb_node);
+               next = rb_next(&n->rb_node);
+
+               rb_erase(&n->rb_node, &hists->entries);
+
+               if (sort__need_collapse)
+                       rb_erase(&n->rb_node_in, &hists->entries_collapsed);
+
+               --hists->nr_entries;
+               if (!n->filtered)
+                       --hists->nr_non_filtered_entries;
+
+               hist_entry__free(n);
+       }
+}
+
 /*
  * histogram, sorted on item, collects periods
  */
index 742f49a85725733e90f7342ca5f7728946574be8..8c9c70e18cbbc353631d5fa283118c3f08725c0d 100644 (file)
@@ -152,6 +152,7 @@ void hists__output_resort(struct hists *hists);
 void hists__collapse_resort(struct hists *hists, struct ui_progress *prog);
 
 void hists__decay_entries(struct hists *hists, bool zap_user, bool zap_kernel);
+void hists__delete_entries(struct hists *hists);
 void hists__output_recalc_col_len(struct hists *hists, int max_rows);
 
 u64 hists__total_period(struct hists *hists);
@@ -192,6 +193,7 @@ struct perf_hpp {
 };
 
 struct perf_hpp_fmt {
+       const char *name;
        int (*header)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
                      struct perf_evsel *evsel);
        int (*width)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
@@ -207,6 +209,8 @@ struct perf_hpp_fmt {
        struct list_head list;
        struct list_head sort_list;
        bool elide;
+       int len;
+       int user_len;
 };
 
 extern struct list_head perf_hpp__list;
@@ -261,17 +265,19 @@ static inline bool perf_hpp__should_skip(struct perf_hpp_fmt *format)
 }
 
 void perf_hpp__reset_width(struct perf_hpp_fmt *fmt, struct hists *hists);
+void perf_hpp__reset_sort_width(struct perf_hpp_fmt *fmt, struct hists *hists);
+void perf_hpp__set_user_width(const char *width_list_str);
 
 typedef u64 (*hpp_field_fn)(struct hist_entry *he);
 typedef int (*hpp_callback_fn)(struct perf_hpp *hpp, bool front);
 typedef int (*hpp_snprint_fn)(struct perf_hpp *hpp, const char *fmt, ...);
 
-int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he,
-              hpp_field_fn get_field, const char *fmt,
-              hpp_snprint_fn print_fn, bool fmt_percent);
-int __hpp__fmt_acc(struct perf_hpp *hpp, struct hist_entry *he,
-                  hpp_field_fn get_field, const char *fmt,
-                  hpp_snprint_fn print_fn, bool fmt_percent);
+int hpp__fmt(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
+            struct hist_entry *he, hpp_field_fn get_field,
+            const char *fmtstr, hpp_snprint_fn print_fn, bool fmt_percent);
+int hpp__fmt_acc(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
+                struct hist_entry *he, hpp_field_fn get_field,
+                const char *fmtstr, hpp_snprint_fn print_fn, bool fmt_percent);
 
 static inline void advance_hpp(struct perf_hpp *hpp, int inc)
 {
index 0b5a8cd2ee79a90fe52c5ecdae637f86f6fb025d..cf1d7913783bbcd89c1aa0e9cb9c818c590fd5ac 100644 (file)
@@ -92,7 +92,6 @@ struct perf_kvm_stat {
        u64 lost_events;
        u64 duration;
 
-       const char *pid_str;
        struct intlist *pid_list;
 
        struct rb_root result;
index 16bba9fff2c87b68ae55960568c58d1469665400..b7d477fbda0208bb7ef6b4923a0769c7273049e2 100644 (file)
@@ -17,8 +17,8 @@ int machine__init(struct machine *machine, const char *root_dir, pid_t pid)
 {
        map_groups__init(&machine->kmaps);
        RB_CLEAR_NODE(&machine->rb_node);
-       INIT_LIST_HEAD(&machine->user_dsos);
-       INIT_LIST_HEAD(&machine->kernel_dsos);
+       INIT_LIST_HEAD(&machine->user_dsos.head);
+       INIT_LIST_HEAD(&machine->kernel_dsos.head);
 
        machine->threads = RB_ROOT;
        INIT_LIST_HEAD(&machine->dead_threads);
@@ -31,6 +31,8 @@ int machine__init(struct machine *machine, const char *root_dir, pid_t pid)
 
        machine->symbol_filter = NULL;
        machine->id_hdr_size = 0;
+       machine->comm_exec = false;
+       machine->kernel_start = 0;
 
        machine->root_dir = strdup(root_dir);
        if (machine->root_dir == NULL)
@@ -70,11 +72,12 @@ out_delete:
        return NULL;
 }
 
-static void dsos__delete(struct list_head *dsos)
+static void dsos__delete(struct dsos *dsos)
 {
        struct dso *pos, *n;
 
-       list_for_each_entry_safe(pos, n, dsos, node) {
+       list_for_each_entry_safe(pos, n, &dsos->head, node) {
+               RB_CLEAR_NODE(&pos->rb_node);
                list_del(&pos->node);
                dso__delete(pos);
        }
@@ -179,6 +182,19 @@ void machines__set_symbol_filter(struct machines *machines,
        }
 }
 
+void machines__set_comm_exec(struct machines *machines, bool comm_exec)
+{
+       struct rb_node *nd;
+
+       machines->host.comm_exec = comm_exec;
+
+       for (nd = rb_first(&machines->guests); nd; nd = rb_next(nd)) {
+               struct machine *machine = rb_entry(nd, struct machine, rb_node);
+
+               machine->comm_exec = comm_exec;
+       }
+}
+
 struct machine *machines__find(struct machines *machines, pid_t pid)
 {
        struct rb_node **p = &machines->guests.rb_node;
@@ -398,17 +414,31 @@ struct thread *machine__find_thread(struct machine *machine, pid_t pid,
        return __machine__findnew_thread(machine, pid, tid, false);
 }
 
+struct comm *machine__thread_exec_comm(struct machine *machine,
+                                      struct thread *thread)
+{
+       if (machine->comm_exec)
+               return thread__exec_comm(thread);
+       else
+               return thread__comm(thread);
+}
+
 int machine__process_comm_event(struct machine *machine, union perf_event *event,
                                struct perf_sample *sample)
 {
        struct thread *thread = machine__findnew_thread(machine,
                                                        event->comm.pid,
                                                        event->comm.tid);
+       bool exec = event->header.misc & PERF_RECORD_MISC_COMM_EXEC;
+
+       if (exec)
+               machine->comm_exec = true;
 
        if (dump_trace)
                perf_event__fprintf_comm(event, stdout);
 
-       if (thread == NULL || thread__set_comm(thread, event->comm.comm, sample->time)) {
+       if (thread == NULL ||
+           __thread__set_comm(thread, event->comm.comm, sample->time, exec)) {
                dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n");
                return -1;
        }
@@ -448,23 +478,23 @@ struct map *machine__new_module(struct machine *machine, u64 start,
 size_t machines__fprintf_dsos(struct machines *machines, FILE *fp)
 {
        struct rb_node *nd;
-       size_t ret = __dsos__fprintf(&machines->host.kernel_dsos, fp) +
-                    __dsos__fprintf(&machines->host.user_dsos, fp);
+       size_t ret = __dsos__fprintf(&machines->host.kernel_dsos.head, fp) +
+                    __dsos__fprintf(&machines->host.user_dsos.head, fp);
 
        for (nd = rb_first(&machines->guests); nd; nd = rb_next(nd)) {
                struct machine *pos = rb_entry(nd, struct machine, rb_node);
-               ret += __dsos__fprintf(&pos->kernel_dsos, fp);
-               ret += __dsos__fprintf(&pos->user_dsos, fp);
+               ret += __dsos__fprintf(&pos->kernel_dsos.head, fp);
+               ret += __dsos__fprintf(&pos->user_dsos.head, fp);
        }
 
        return ret;
 }
 
-size_t machine__fprintf_dsos_buildid(struct machine *machine, FILE *fp,
+size_t machine__fprintf_dsos_buildid(struct machine *m, FILE *fp,
                                     bool (skip)(struct dso *dso, int parm), int parm)
 {
-       return __dsos__fprintf_buildid(&machine->kernel_dsos, fp, skip, parm) +
-              __dsos__fprintf_buildid(&machine->user_dsos, fp, skip, parm);
+       return __dsos__fprintf_buildid(&m->kernel_dsos.head, fp, skip, parm) +
+              __dsos__fprintf_buildid(&m->user_dsos.head, fp, skip, parm);
 }
 
 size_t machines__fprintf_dsos_buildid(struct machines *machines, FILE *fp,
@@ -565,8 +595,8 @@ const char *ref_reloc_sym_names[] = {"_text", "_stext", NULL};
  * Returns the name of the start symbol in *symbol_name. Pass in NULL as
  * symbol_name if it's not that important.
  */
-static u64 machine__get_kernel_start_addr(struct machine *machine,
-                                         const char **symbol_name)
+static u64 machine__get_running_kernel_start(struct machine *machine,
+                                            const char **symbol_name)
 {
        char filename[PATH_MAX];
        int i;
@@ -593,7 +623,7 @@ static u64 machine__get_kernel_start_addr(struct machine *machine,
 int __machine__create_kernel_maps(struct machine *machine, struct dso *kernel)
 {
        enum map_type type;
-       u64 start = machine__get_kernel_start_addr(machine, NULL);
+       u64 start = machine__get_running_kernel_start(machine, NULL);
 
        for (type = 0; type < MAP__NR_TYPES; ++type) {
                struct kmap *kmap;
@@ -912,7 +942,7 @@ int machine__create_kernel_maps(struct machine *machine)
 {
        struct dso *kernel = machine__get_kernel(machine);
        const char *name;
-       u64 addr = machine__get_kernel_start_addr(machine, &name);
+       u64 addr = machine__get_running_kernel_start(machine, &name);
        if (!addr)
                return -1;
 
@@ -965,7 +995,7 @@ static bool machine__uses_kcore(struct machine *machine)
 {
        struct dso *dso;
 
-       list_for_each_entry(dso, &machine->kernel_dsos, node) {
+       list_for_each_entry(dso, &machine->kernel_dsos.head, node) {
                if (dso__is_kcore(dso))
                        return true;
        }
@@ -1285,6 +1315,16 @@ static void ip__resolve_data(struct machine *machine, struct thread *thread,
 
        thread__find_addr_location(thread, machine, m, MAP__VARIABLE, addr,
                                   &al);
+       if (al.map == NULL) {
+               /*
+                * some shared data regions have execute bit set which puts
+                * their mapping in the MAP__FUNCTION type array.
+                * Check there as a fallback option before dropping the sample.
+                */
+               thread__find_addr_location(thread, machine, m, MAP__FUNCTION, addr,
+                                          &al);
+       }
+
        ams->addr = addr;
        ams->al_addr = al.addr;
        ams->sym = al.sym;
@@ -1531,3 +1571,25 @@ int machine__set_current_tid(struct machine *machine, int cpu, pid_t pid,
 
        return 0;
 }
+
+int machine__get_kernel_start(struct machine *machine)
+{
+       struct map *map = machine__kernel_map(machine, MAP__FUNCTION);
+       int err = 0;
+
+       /*
+        * The only addresses above 2^63 are kernel addresses of a 64-bit
+        * kernel.  Note that addresses are unsigned so that on a 32-bit system
+        * all addresses including kernel addresses are less than 2^32.  In
+        * that case (32-bit system), if the kernel mapping is unknown, all
+        * addresses will be assumed to be in user space - see
+        * machine__kernel_ip().
+        */
+       machine->kernel_start = 1ULL << 63;
+       if (map) {
+               err = map__load(map, machine->symbol_filter);
+               if (map->start)
+                       machine->kernel_start = map->start;
+       }
+       return err;
+}
index b972824e62941fea709fdfc92dcf9bf6f80871e9..2b651a7f5d0d113c59461f4badbd35c9ad870a45 100644 (file)
@@ -4,6 +4,7 @@
 #include <sys/types.h>
 #include <linux/rbtree.h>
 #include "map.h"
+#include "dso.h"
 #include "event.h"
 
 struct addr_location;
@@ -26,15 +27,17 @@ struct machine {
        struct rb_node    rb_node;
        pid_t             pid;
        u16               id_hdr_size;
+       bool              comm_exec;
        char              *root_dir;
        struct rb_root    threads;
        struct list_head  dead_threads;
        struct thread     *last_match;
        struct vdso_info  *vdso_info;
-       struct list_head  user_dsos;
-       struct list_head  kernel_dsos;
+       struct dsos       user_dsos;
+       struct dsos       kernel_dsos;
        struct map_groups kmaps;
        struct map        *vmlinux_maps[MAP__NR_TYPES];
+       u64               kernel_start;
        symbol_filter_t   symbol_filter;
        pid_t             *current_tid;
 };
@@ -45,8 +48,26 @@ struct map *machine__kernel_map(struct machine *machine, enum map_type type)
        return machine->vmlinux_maps[type];
 }
 
+int machine__get_kernel_start(struct machine *machine);
+
+static inline u64 machine__kernel_start(struct machine *machine)
+{
+       if (!machine->kernel_start)
+               machine__get_kernel_start(machine);
+       return machine->kernel_start;
+}
+
+static inline bool machine__kernel_ip(struct machine *machine, u64 ip)
+{
+       u64 kernel_start = machine__kernel_start(machine);
+
+       return ip >= kernel_start;
+}
+
 struct thread *machine__find_thread(struct machine *machine, pid_t pid,
                                    pid_t tid);
+struct comm *machine__thread_exec_comm(struct machine *machine,
+                                      struct thread *thread);
 
 int machine__process_comm_event(struct machine *machine, union perf_event *event,
                                struct perf_sample *sample);
@@ -88,6 +109,7 @@ char *machine__mmap_name(struct machine *machine, char *bf, size_t size);
 
 void machines__set_symbol_filter(struct machines *machines,
                                 symbol_filter_t symbol_filter);
+void machines__set_comm_exec(struct machines *machines, bool comm_exec);
 
 struct machine *machine__new_host(void);
 int machine__init(struct machine *machine, const char *root_dir, pid_t pid);
index 31b8905dd863db904ec945e554939a9877841bcc..b7090596ac5086a3a36fe65b46e43cadcfe5cc7a 100644 (file)
@@ -31,6 +31,7 @@ static inline int is_anon_memory(const char *filename)
 static inline int is_no_dso_memory(const char *filename)
 {
        return !strncmp(filename, "[stack", 6) ||
+              !strncmp(filename, "/SYSV",5)   ||
               !strcmp(filename, "[heap]");
 }
 
diff --git a/tools/perf/util/ordered-events.c b/tools/perf/util/ordered-events.c
new file mode 100644 (file)
index 0000000..706ce1a
--- /dev/null
@@ -0,0 +1,245 @@
+#include <linux/list.h>
+#include <linux/compiler.h>
+#include "ordered-events.h"
+#include "evlist.h"
+#include "session.h"
+#include "asm/bug.h"
+#include "debug.h"
+
+#define pr_N(n, fmt, ...) \
+       eprintf(n, debug_ordered_events, fmt, ##__VA_ARGS__)
+
+#define pr(fmt, ...) pr_N(1, pr_fmt(fmt), ##__VA_ARGS__)
+
+static void queue_event(struct ordered_events *oe, struct ordered_event *new)
+{
+       struct ordered_event *last = oe->last;
+       u64 timestamp = new->timestamp;
+       struct list_head *p;
+
+       ++oe->nr_events;
+       oe->last = new;
+
+       pr_oe_time2(timestamp, "queue_event nr_events %u\n", oe->nr_events);
+
+       if (!last) {
+               list_add(&new->list, &oe->events);
+               oe->max_timestamp = timestamp;
+               return;
+       }
+
+       /*
+        * last event might point to some random place in the list as it's
+        * the last queued event. We expect that the new event is close to
+        * this.
+        */
+       if (last->timestamp <= timestamp) {
+               while (last->timestamp <= timestamp) {
+                       p = last->list.next;
+                       if (p == &oe->events) {
+                               list_add_tail(&new->list, &oe->events);
+                               oe->max_timestamp = timestamp;
+                               return;
+                       }
+                       last = list_entry(p, struct ordered_event, list);
+               }
+               list_add_tail(&new->list, &last->list);
+       } else {
+               while (last->timestamp > timestamp) {
+                       p = last->list.prev;
+                       if (p == &oe->events) {
+                               list_add(&new->list, &oe->events);
+                               return;
+                       }
+                       last = list_entry(p, struct ordered_event, list);
+               }
+               list_add(&new->list, &last->list);
+       }
+}
+
+#define MAX_SAMPLE_BUFFER      (64 * 1024 / sizeof(struct ordered_event))
+static struct ordered_event *alloc_event(struct ordered_events *oe)
+{
+       struct list_head *cache = &oe->cache;
+       struct ordered_event *new = NULL;
+
+       if (!list_empty(cache)) {
+               new = list_entry(cache->next, struct ordered_event, list);
+               list_del(&new->list);
+       } else if (oe->buffer) {
+               new = oe->buffer + oe->buffer_idx;
+               if (++oe->buffer_idx == MAX_SAMPLE_BUFFER)
+                       oe->buffer = NULL;
+       } else if (oe->cur_alloc_size < oe->max_alloc_size) {
+               size_t size = MAX_SAMPLE_BUFFER * sizeof(*new);
+
+               oe->buffer = malloc(size);
+               if (!oe->buffer)
+                       return NULL;
+
+               pr("alloc size %" PRIu64 "B (+%zu), max %" PRIu64 "B\n",
+                  oe->cur_alloc_size, size, oe->max_alloc_size);
+
+               oe->cur_alloc_size += size;
+               list_add(&oe->buffer->list, &oe->to_free);
+
+               /* First entry is abused to maintain the to_free list. */
+               oe->buffer_idx = 2;
+               new = oe->buffer + 1;
+       } else {
+               pr("allocation limit reached %" PRIu64 "B\n", oe->max_alloc_size);
+       }
+
+       return new;
+}
+
+struct ordered_event *
+ordered_events__new(struct ordered_events *oe, u64 timestamp)
+{
+       struct ordered_event *new;
+
+       new = alloc_event(oe);
+       if (new) {
+               new->timestamp = timestamp;
+               queue_event(oe, new);
+       }
+
+       return new;
+}
+
+void ordered_events__delete(struct ordered_events *oe, struct ordered_event *event)
+{
+       list_move(&event->list, &oe->cache);
+       oe->nr_events--;
+}
+
+static int __ordered_events__flush(struct perf_session *s,
+                                  struct perf_tool *tool)
+{
+       struct ordered_events *oe = &s->ordered_events;
+       struct list_head *head = &oe->events;
+       struct ordered_event *tmp, *iter;
+       struct perf_sample sample;
+       u64 limit = oe->next_flush;
+       u64 last_ts = oe->last ? oe->last->timestamp : 0ULL;
+       bool show_progress = limit == ULLONG_MAX;
+       struct ui_progress prog;
+       int ret;
+
+       if (!tool->ordered_events || !limit)
+               return 0;
+
+       if (show_progress)
+               ui_progress__init(&prog, oe->nr_events, "Processing time ordered events...");
+
+       list_for_each_entry_safe(iter, tmp, head, list) {
+               if (session_done())
+                       return 0;
+
+               if (iter->timestamp > limit)
+                       break;
+
+               ret = perf_evlist__parse_sample(s->evlist, iter->event, &sample);
+               if (ret)
+                       pr_err("Can't parse sample, err = %d\n", ret);
+               else {
+                       ret = perf_session__deliver_event(s, iter->event, &sample, tool,
+                                                         iter->file_offset);
+                       if (ret)
+                               return ret;
+               }
+
+               ordered_events__delete(oe, iter);
+               oe->last_flush = iter->timestamp;
+
+               if (show_progress)
+                       ui_progress__update(&prog, 1);
+       }
+
+       if (list_empty(head))
+               oe->last = NULL;
+       else if (last_ts <= limit)
+               oe->last = list_entry(head->prev, struct ordered_event, list);
+
+       return 0;
+}
+
+int ordered_events__flush(struct perf_session *s, struct perf_tool *tool,
+                         enum oe_flush how)
+{
+       struct ordered_events *oe = &s->ordered_events;
+       static const char * const str[] = {
+               "NONE",
+               "FINAL",
+               "ROUND",
+               "HALF ",
+       };
+       int err;
+
+       switch (how) {
+       case OE_FLUSH__FINAL:
+               oe->next_flush = ULLONG_MAX;
+               break;
+
+       case OE_FLUSH__HALF:
+       {
+               struct ordered_event *first, *last;
+               struct list_head *head = &oe->events;
+
+               first = list_entry(head->next, struct ordered_event, list);
+               last = oe->last;
+
+               /* Warn if we are called before any event got allocated. */
+               if (WARN_ONCE(!last || list_empty(head), "empty queue"))
+                       return 0;
+
+               oe->next_flush  = first->timestamp;
+               oe->next_flush += (last->timestamp - first->timestamp) / 2;
+               break;
+       }
+
+       case OE_FLUSH__ROUND:
+       case OE_FLUSH__NONE:
+       default:
+               break;
+       };
+
+       pr_oe_time(oe->next_flush, "next_flush - ordered_events__flush PRE  %s, nr_events %u\n",
+                  str[how], oe->nr_events);
+       pr_oe_time(oe->max_timestamp, "max_timestamp\n");
+
+       err = __ordered_events__flush(s, tool);
+
+       if (!err) {
+               if (how == OE_FLUSH__ROUND)
+                       oe->next_flush = oe->max_timestamp;
+
+               oe->last_flush_type = how;
+       }
+
+       pr_oe_time(oe->next_flush, "next_flush - ordered_events__flush POST %s, nr_events %u\n",
+                  str[how], oe->nr_events);
+       pr_oe_time(oe->last_flush, "last_flush\n");
+
+       return err;
+}
+
+void ordered_events__init(struct ordered_events *oe)
+{
+       INIT_LIST_HEAD(&oe->events);
+       INIT_LIST_HEAD(&oe->cache);
+       INIT_LIST_HEAD(&oe->to_free);
+       oe->max_alloc_size = (u64) -1;
+       oe->cur_alloc_size = 0;
+}
+
+void ordered_events__free(struct ordered_events *oe)
+{
+       while (!list_empty(&oe->to_free)) {
+               struct ordered_event *event;
+
+               event = list_entry(oe->to_free.next, struct ordered_event, list);
+               list_del(&event->list);
+               free(event);
+       }
+}
diff --git a/tools/perf/util/ordered-events.h b/tools/perf/util/ordered-events.h
new file mode 100644 (file)
index 0000000..3b2f205
--- /dev/null
@@ -0,0 +1,51 @@
+#ifndef __ORDERED_EVENTS_H
+#define __ORDERED_EVENTS_H
+
+#include <linux/types.h>
+#include "tool.h"
+
+struct perf_session;
+
+struct ordered_event {
+       u64                     timestamp;
+       u64                     file_offset;
+       union perf_event        *event;
+       struct list_head        list;
+};
+
+enum oe_flush {
+       OE_FLUSH__NONE,
+       OE_FLUSH__FINAL,
+       OE_FLUSH__ROUND,
+       OE_FLUSH__HALF,
+};
+
+struct ordered_events {
+       u64                     last_flush;
+       u64                     next_flush;
+       u64                     max_timestamp;
+       u64                     max_alloc_size;
+       u64                     cur_alloc_size;
+       struct list_head        events;
+       struct list_head        cache;
+       struct list_head        to_free;
+       struct ordered_event    *buffer;
+       struct ordered_event    *last;
+       int                     buffer_idx;
+       unsigned int            nr_events;
+       enum oe_flush           last_flush_type;
+};
+
+struct ordered_event *ordered_events__new(struct ordered_events *oe, u64 timestamp);
+void ordered_events__delete(struct ordered_events *oe, struct ordered_event *event);
+int ordered_events__flush(struct perf_session *s, struct perf_tool *tool,
+                         enum oe_flush how);
+void ordered_events__init(struct ordered_events *oe);
+void ordered_events__free(struct ordered_events *oe);
+
+static inline
+void ordered_events__set_alloc_size(struct ordered_events *oe, u64 size)
+{
+       oe->max_alloc_size = size;
+}
+#endif /* __ORDERED_EVENTS_H */
index 1e15df10a88c2c1ff7b62dbfbcc05f39ffbe4cd1..d76aa30cb1fbf6bd580497efb8f33bf09caddd61 100644 (file)
@@ -10,6 +10,7 @@
 #include "symbol.h"
 #include "cache.h"
 #include "header.h"
+#include "debug.h"
 #include <api/fs/debugfs.h>
 #include "parse-events-bison.h"
 #define YY_EXTRA_TYPE int
@@ -633,18 +634,28 @@ int parse_events_add_pmu(struct list_head *list, int *idx,
                         char *name, struct list_head *head_config)
 {
        struct perf_event_attr attr;
+       struct perf_pmu_info info;
        struct perf_pmu *pmu;
        struct perf_evsel *evsel;
-       const char *unit;
-       double scale;
 
        pmu = perf_pmu__find(name);
        if (!pmu)
                return -EINVAL;
 
-       memset(&attr, 0, sizeof(attr));
+       if (pmu->default_config) {
+               memcpy(&attr, pmu->default_config,
+                      sizeof(struct perf_event_attr));
+       } else {
+               memset(&attr, 0, sizeof(attr));
+       }
+
+       if (!head_config) {
+               attr.type = pmu->type;
+               evsel = __add_event(list, idx, &attr, NULL, pmu->cpus);
+               return evsel ? 0 : -ENOMEM;
+       }
 
-       if (perf_pmu__check_alias(pmu, head_config, &unit, &scale))
+       if (perf_pmu__check_alias(pmu, head_config, &info))
                return -EINVAL;
 
        /*
@@ -659,8 +670,8 @@ int parse_events_add_pmu(struct list_head *list, int *idx,
        evsel = __add_event(list, idx, &attr, pmu_event_name(head_config),
                            pmu->cpus);
        if (evsel) {
-               evsel->unit = unit;
-               evsel->scale = scale;
+               evsel->unit = info.unit;
+               evsel->scale = info.scale;
        }
 
        return evsel ? 0 : -ENOMEM;
@@ -973,7 +984,7 @@ int parse_filter(const struct option *opt, const char *str,
 
        if (last == NULL || last->attr.type != PERF_TYPE_TRACEPOINT) {
                fprintf(stderr,
-                       "-F option should follow a -e tracepoint option\n");
+                       "--filter option should follow a -e tracepoint option\n");
                return -1;
        }
 
@@ -1006,9 +1017,11 @@ void print_tracepoint_events(const char *subsys_glob, const char *event_glob,
        struct dirent *sys_next, *evt_next, sys_dirent, evt_dirent;
        char evt_path[MAXPATHLEN];
        char dir_path[MAXPATHLEN];
+       char sbuf[STRERR_BUFSIZE];
 
        if (debugfs_valid_mountpoint(tracing_events_path)) {
-               printf("  [ Tracepoints not available: %s ]\n", strerror(errno));
+               printf("  [ Tracepoints not available: %s ]\n",
+                       strerror_r(errno, sbuf, sizeof(sbuf)));
                return;
        }
 
index 0bc87ba46bf3f77f507116df36449655a9fbaa6f..55fab6ad609a8ccdc7f36478dc350bfcb72e5e3f 100644 (file)
@@ -210,6 +210,16 @@ PE_NAME '/' event_config '/'
        parse_events__free_terms($3);
        $$ = list;
 }
+|
+PE_NAME '/' '/'
+{
+       struct parse_events_evlist *data = _data;
+       struct list_head *list;
+
+       ALLOC_LIST(list);
+       ABORT_ON(parse_events_add_pmu(list, &data->idx, $1, NULL));
+       $$ = list;
+}
 
 value_sym:
 PE_VALUE_SYM_HW
index 7a811eb61f75fc9b00205fd778c30cc417b0f887..93a41ca96b8e0c6f0f927b20209c58c676a98384 100644 (file)
@@ -2,6 +2,8 @@
 #include <sys/types.h>
 #include <unistd.h>
 #include <stdio.h>
+#include <stdbool.h>
+#include <stdarg.h>
 #include <dirent.h>
 #include <api/fs/fs.h>
 #include <locale.h>
@@ -14,8 +16,8 @@
 
 struct perf_pmu_alias {
        char *name;
-       struct list_head terms;
-       struct list_head list;
+       struct list_head terms; /* HEAD struct parse_events_term -> list */
+       struct list_head list;  /* ELEM */
        char unit[UNIT_MAX_LEN+1];
        double scale;
 };
@@ -208,6 +210,19 @@ static int perf_pmu__new_alias(struct list_head *list, char *dir, char *name, FI
        return 0;
 }
 
+static inline bool pmu_alias_info_file(char *name)
+{
+       size_t len;
+
+       len = strlen(name);
+       if (len > 5 && !strcmp(name + len - 5, ".unit"))
+               return true;
+       if (len > 6 && !strcmp(name + len - 6, ".scale"))
+               return true;
+
+       return false;
+}
+
 /*
  * Process all the sysfs attributes located under the directory
  * specified in 'dir' parameter.
@@ -216,7 +231,6 @@ static int pmu_aliases_parse(char *dir, struct list_head *head)
 {
        struct dirent *evt_ent;
        DIR *event_dir;
-       size_t len;
        int ret = 0;
 
        event_dir = opendir(dir);
@@ -232,13 +246,9 @@ static int pmu_aliases_parse(char *dir, struct list_head *head)
                        continue;
 
                /*
-                * skip .unit and .scale info files
-                * parsed in perf_pmu__new_alias()
+                * skip info files parsed in perf_pmu__new_alias()
                 */
-               len = strlen(name);
-               if (len > 5 && !strcmp(name + len - 5, ".unit"))
-                       continue;
-               if (len > 6 && !strcmp(name + len - 6, ".scale"))
+               if (pmu_alias_info_file(name))
                        continue;
 
                snprintf(path, PATH_MAX, "%s/%s", dir, name);
@@ -387,6 +397,12 @@ static struct cpu_map *pmu_cpumask(const char *name)
        return cpus;
 }
 
+struct perf_event_attr *__attribute__((weak))
+perf_pmu__get_default_config(struct perf_pmu *pmu __maybe_unused)
+{
+       return NULL;
+}
+
 static struct perf_pmu *pmu_lookup(const char *name)
 {
        struct perf_pmu *pmu;
@@ -421,6 +437,9 @@ static struct perf_pmu *pmu_lookup(const char *name)
        pmu->name = strdup(name);
        pmu->type = type;
        list_add_tail(&pmu->list, &pmus);
+
+       pmu->default_config = perf_pmu__get_default_config(pmu);
+
        return pmu;
 }
 
@@ -479,28 +498,24 @@ pmu_find_format(struct list_head *formats, char *name)
 }
 
 /*
- * Returns value based on the format definition (format parameter)
+ * Sets value based on the format definition (format parameter)
  * and unformated value (value parameter).
- *
- * TODO maybe optimize a little ;)
  */
-static __u64 pmu_format_value(unsigned long *format, __u64 value)
+static void pmu_format_value(unsigned long *format, __u64 value, __u64 *v,
+                            bool zero)
 {
        unsigned long fbit, vbit;
-       __u64 v = 0;
 
        for (fbit = 0, vbit = 0; fbit < PERF_PMU_FORMAT_BITS; fbit++) {
 
                if (!test_bit(fbit, format))
                        continue;
 
-               if (!(value & (1llu << vbit++)))
-                       continue;
-
-               v |= (1llu << fbit);
+               if (value & (1llu << vbit++))
+                       *v |= (1llu << fbit);
+               else if (zero)
+                       *v &= ~(1llu << fbit);
        }
-
-       return v;
 }
 
 /*
@@ -509,7 +524,8 @@ static __u64 pmu_format_value(unsigned long *format, __u64 value)
  */
 static int pmu_config_term(struct list_head *formats,
                           struct perf_event_attr *attr,
-                          struct parse_events_term *term)
+                          struct parse_events_term *term,
+                          bool zero)
 {
        struct perf_pmu_format *format;
        __u64 *vp;
@@ -548,18 +564,19 @@ static int pmu_config_term(struct list_head *formats,
         * non-hardcoded terms, here's the place to translate
         * them into value.
         */
-       *vp |= pmu_format_value(format->bits, term->val.num);
+       pmu_format_value(format->bits, term->val.num, vp, zero);
        return 0;
 }
 
 int perf_pmu__config_terms(struct list_head *formats,
                           struct perf_event_attr *attr,
-                          struct list_head *head_terms)
+                          struct list_head *head_terms,
+                          bool zero)
 {
        struct parse_events_term *term;
 
        list_for_each_entry(term, head_terms, list)
-               if (pmu_config_term(formats, attr, term))
+               if (pmu_config_term(formats, attr, term, zero))
                        return -EINVAL;
 
        return 0;
@@ -573,8 +590,10 @@ int perf_pmu__config_terms(struct list_head *formats,
 int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr,
                     struct list_head *head_terms)
 {
+       bool zero = !!pmu->default_config;
+
        attr->type = pmu->type;
-       return perf_pmu__config_terms(&pmu->format, attr, head_terms);
+       return perf_pmu__config_terms(&pmu->format, attr, head_terms, zero);
 }
 
 static struct perf_pmu_alias *pmu_find_alias(struct perf_pmu *pmu,
@@ -634,7 +653,7 @@ static int check_unit_scale(struct perf_pmu_alias *alias,
  * defined for the alias
  */
 int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms,
-                         const char **unit, double *scale)
+                         struct perf_pmu_info *info)
 {
        struct parse_events_term *term, *h;
        struct perf_pmu_alias *alias;
@@ -644,8 +663,8 @@ int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms,
         * Mark unit and scale as not set
         * (different from default values, see below)
         */
-       *unit   = NULL;
-       *scale  = 0.0;
+       info->unit   = NULL;
+       info->scale  = 0.0;
 
        list_for_each_entry_safe(term, h, head_terms, list) {
                alias = pmu_find_alias(pmu, term);
@@ -655,7 +674,7 @@ int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms,
                if (ret)
                        return ret;
 
-               ret = check_unit_scale(alias, unit, scale);
+               ret = check_unit_scale(alias, &info->unit, &info->scale);
                if (ret)
                        return ret;
 
@@ -668,11 +687,11 @@ int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms,
         * set defaults as for evsel
         * unit cannot left to NULL
         */
-       if (*unit == NULL)
-               *unit   = "";
+       if (info->unit == NULL)
+               info->unit   = "";
 
-       if (*scale == 0.0)
-               *scale  = 1.0;
+       if (info->scale == 0.0)
+               info->scale  = 1.0;
 
        return 0;
 }
@@ -794,3 +813,39 @@ bool pmu_have_event(const char *pname, const char *name)
        }
        return false;
 }
+
+static FILE *perf_pmu__open_file(struct perf_pmu *pmu, const char *name)
+{
+       struct stat st;
+       char path[PATH_MAX];
+       const char *sysfs;
+
+       sysfs = sysfs__mountpoint();
+       if (!sysfs)
+               return NULL;
+
+       snprintf(path, PATH_MAX,
+                "%s" EVENT_SOURCE_DEVICE_PATH "%s/%s", sysfs, pmu->name, name);
+
+       if (stat(path, &st) < 0)
+               return NULL;
+
+       return fopen(path, "r");
+}
+
+int perf_pmu__scan_file(struct perf_pmu *pmu, const char *name, const char *fmt,
+                       ...)
+{
+       va_list args;
+       FILE *file;
+       int ret = EOF;
+
+       va_start(args, fmt);
+       file = perf_pmu__open_file(pmu, name);
+       if (file) {
+               ret = vfscanf(file, fmt, args);
+               fclose(file);
+       }
+       va_end(args);
+       return ret;
+}
index c14a543ce1f3b563a6debfb0879c910003a2ac15..fe90a012c003b18c07ec15bdf3c4f1ffd13224d0 100644 (file)
@@ -13,13 +13,21 @@ enum {
 
 #define PERF_PMU_FORMAT_BITS 64
 
+struct perf_event_attr;
+
 struct perf_pmu {
        char *name;
        __u32 type;
+       struct perf_event_attr *default_config;
        struct cpu_map *cpus;
-       struct list_head format;
-       struct list_head aliases;
-       struct list_head list;
+       struct list_head format;  /* HEAD struct perf_pmu_format -> list */
+       struct list_head aliases; /* HEAD struct perf_pmu_alias -> list */
+       struct list_head list;    /* ELEM */
+};
+
+struct perf_pmu_info {
+       const char *unit;
+       double scale;
 };
 
 struct perf_pmu *perf_pmu__find(const char *name);
@@ -27,9 +35,10 @@ int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr,
                     struct list_head *head_terms);
 int perf_pmu__config_terms(struct list_head *formats,
                           struct perf_event_attr *attr,
-                          struct list_head *head_terms);
+                          struct list_head *head_terms,
+                          bool zero);
 int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms,
-                         const char **unit, double *scale);
+                         struct perf_pmu_info *info);
 struct list_head *perf_pmu__alias(struct perf_pmu *pmu,
                                  struct list_head *head_terms);
 int perf_pmu_wrap(void);
@@ -45,5 +54,11 @@ struct perf_pmu *perf_pmu__scan(struct perf_pmu *pmu);
 void print_pmu_events(const char *event_glob, bool name_only);
 bool pmu_have_event(const char *pname, const char *name);
 
+int perf_pmu__scan_file(struct perf_pmu *pmu, const char *name, const char *fmt,
+                       ...) __attribute__((format(scanf, 3, 4)));
+
 int perf_pmu__test(void);
+
+struct perf_event_attr *perf_pmu__get_default_config(struct perf_pmu *pmu);
+
 #endif /* __PMU_H */
index 9a0a1839a3772689e0dce818a5c16807edc6c10f..c150ca4343eb216c81244abb73bec70703f142ea 100644 (file)
@@ -79,7 +79,7 @@ static int init_symbol_maps(bool user_only)
        int ret;
 
        symbol_conf.sort_by_name = true;
-       ret = symbol__init();
+       ret = symbol__init(NULL);
        if (ret < 0) {
                pr_debug("Failed to init symbol map.\n");
                goto out;
@@ -184,7 +184,8 @@ static struct dso *kernel_get_module_dso(const char *module)
        const char *vmlinux_name;
 
        if (module) {
-               list_for_each_entry(dso, &host_machine->kernel_dsos, node) {
+               list_for_each_entry(dso, &host_machine->kernel_dsos.head,
+                                   node) {
                        if (strncmp(dso->short_name + 1, module,
                                    dso->short_name_len - 2) == 0)
                                goto found;
@@ -258,21 +259,33 @@ static void clear_probe_trace_events(struct probe_trace_event *tevs, int ntevs)
 #ifdef HAVE_DWARF_SUPPORT
 
 /* Open new debuginfo of given module */
-static struct debuginfo *open_debuginfo(const char *module)
+static struct debuginfo *open_debuginfo(const char *module, bool silent)
 {
        const char *path = module;
+       struct debuginfo *ret;
 
        if (!module || !strchr(module, '/')) {
                path = kernel_get_module_path(module);
                if (!path) {
-                       pr_err("Failed to find path of %s module.\n",
-                              module ?: "kernel");
+                       if (!silent)
+                               pr_err("Failed to find path of %s module.\n",
+                                      module ?: "kernel");
                        return NULL;
                }
        }
-       return debuginfo__new(path);
+       ret = debuginfo__new(path);
+       if (!ret && !silent) {
+               pr_warning("The %s file has no debug information.\n", path);
+               if (!module || !strtailcmp(path, ".ko"))
+                       pr_warning("Rebuild with CONFIG_DEBUG_INFO=y, ");
+               else
+                       pr_warning("Rebuild with -g, ");
+               pr_warning("or install an appropriate debuginfo package.\n");
+       }
+       return ret;
 }
 
+
 static int get_text_start_address(const char *exec, unsigned long *address)
 {
        Elf *elf;
@@ -333,15 +346,13 @@ static int find_perf_probe_point_from_dwarf(struct probe_trace_point *tp,
        pr_debug("try to find information at %" PRIx64 " in %s\n", addr,
                 tp->module ? : "kernel");
 
-       dinfo = open_debuginfo(tp->module);
+       dinfo = open_debuginfo(tp->module, verbose == 0);
        if (dinfo) {
                ret = debuginfo__find_probe_point(dinfo,
                                                 (unsigned long)addr, pp);
                debuginfo__delete(dinfo);
-       } else {
-               pr_debug("Failed to open debuginfo at 0x%" PRIx64 "\n", addr);
+       } else
                ret = -ENOENT;
-       }
 
        if (ret > 0) {
                pp->retprobe = tp->retprobe;
@@ -457,13 +468,11 @@ static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
        struct debuginfo *dinfo;
        int ntevs, ret = 0;
 
-       dinfo = open_debuginfo(target);
+       dinfo = open_debuginfo(target, !need_dwarf);
 
        if (!dinfo) {
-               if (need_dwarf) {
-                       pr_warning("Failed to open debuginfo file.\n");
+               if (need_dwarf)
                        return -ENOENT;
-               }
                pr_debug("Could not open debuginfo. Try to use symbols.\n");
                return 0;
        }
@@ -565,7 +574,7 @@ static int get_real_path(const char *raw_path, const char *comp_dir,
 
 static int __show_one_line(FILE *fp, int l, bool skip, bool show_num)
 {
-       char buf[LINEBUF_SIZE];
+       char buf[LINEBUF_SIZE], sbuf[STRERR_BUFSIZE];
        const char *color = show_num ? "" : PERF_COLOR_BLUE;
        const char *prefix = NULL;
 
@@ -585,7 +594,8 @@ static int __show_one_line(FILE *fp, int l, bool skip, bool show_num)
        return 1;
 error:
        if (ferror(fp)) {
-               pr_warning("File read error: %s\n", strerror(errno));
+               pr_warning("File read error: %s\n",
+                          strerror_r(errno, sbuf, sizeof(sbuf)));
                return -1;
        }
        return 0;
@@ -618,13 +628,12 @@ static int __show_line_range(struct line_range *lr, const char *module)
        FILE *fp;
        int ret;
        char *tmp;
+       char sbuf[STRERR_BUFSIZE];
 
        /* Search a line range */
-       dinfo = open_debuginfo(module);
-       if (!dinfo) {
-               pr_warning("Failed to open debuginfo file.\n");
+       dinfo = open_debuginfo(module, false);
+       if (!dinfo)
                return -ENOENT;
-       }
 
        ret = debuginfo__find_line_range(dinfo, lr);
        debuginfo__delete(dinfo);
@@ -656,7 +665,7 @@ static int __show_line_range(struct line_range *lr, const char *module)
        fp = fopen(lr->path, "r");
        if (fp == NULL) {
                pr_warning("Failed to open %s: %s\n", lr->path,
-                          strerror(errno));
+                          strerror_r(errno, sbuf, sizeof(sbuf)));
                return -errno;
        }
        /* Skip to starting line number */
@@ -689,11 +698,11 @@ end:
        return ret;
 }
 
-int show_line_range(struct line_range *lr, const char *module)
+int show_line_range(struct line_range *lr, const char *module, bool user)
 {
        int ret;
 
-       ret = init_symbol_maps(false);
+       ret = init_symbol_maps(user);
        if (ret < 0)
                return ret;
        ret = __show_line_range(lr, module);
@@ -768,13 +777,12 @@ int show_available_vars(struct perf_probe_event *pevs, int npevs,
        int i, ret = 0;
        struct debuginfo *dinfo;
 
-       ret = init_symbol_maps(false);
+       ret = init_symbol_maps(pevs->uprobes);
        if (ret < 0)
                return ret;
 
-       dinfo = open_debuginfo(module);
+       dinfo = open_debuginfo(module, false);
        if (!dinfo) {
-               pr_warning("Failed to open debuginfo file.\n");
                ret = -ENOENT;
                goto out;
        }
@@ -815,7 +823,8 @@ static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
 }
 
 int show_line_range(struct line_range *lr __maybe_unused,
-                   const char *module __maybe_unused)
+                   const char *module __maybe_unused,
+                   bool user __maybe_unused)
 {
        pr_warning("Debuginfo-analysis is not supported.\n");
        return -ENOSYS;
@@ -1405,8 +1414,7 @@ int synthesize_perf_probe_arg(struct perf_probe_arg *pa, char *buf, size_t len)
 
        return tmp - buf;
 error:
-       pr_debug("Failed to synthesize perf probe argument: %s\n",
-                strerror(-ret));
+       pr_debug("Failed to synthesize perf probe argument: %d\n", ret);
        return ret;
 }
 
@@ -1455,8 +1463,7 @@ static char *synthesize_perf_probe_point(struct perf_probe_point *pp)
 
        return buf;
 error:
-       pr_debug("Failed to synthesize perf probe point: %s\n",
-                strerror(-ret));
+       pr_debug("Failed to synthesize perf probe point: %d\n", ret);
        free(buf);
        return NULL;
 }
@@ -1780,10 +1787,11 @@ static void clear_probe_trace_event(struct probe_trace_event *tev)
        memset(tev, 0, sizeof(*tev));
 }
 
-static void print_warn_msg(const char *file, bool is_kprobe)
+static void print_open_warning(int err, bool is_kprobe)
 {
+       char sbuf[STRERR_BUFSIZE];
 
-       if (errno == ENOENT) {
+       if (err == -ENOENT) {
                const char *config;
 
                if (!is_kprobe)
@@ -1791,25 +1799,43 @@ static void print_warn_msg(const char *file, bool is_kprobe)
                else
                        config = "CONFIG_KPROBE_EVENTS";
 
-               pr_warning("%s file does not exist - please rebuild kernel"
-                               " with %s.\n", file, config);
-       } else
-               pr_warning("Failed to open %s file: %s\n", file,
-                               strerror(errno));
+               pr_warning("%cprobe_events file does not exist"
+                          " - please rebuild kernel with %s.\n",
+                          is_kprobe ? 'k' : 'u', config);
+       } else if (err == -ENOTSUP)
+               pr_warning("Debugfs is not mounted.\n");
+       else
+               pr_warning("Failed to open %cprobe_events: %s\n",
+                          is_kprobe ? 'k' : 'u',
+                          strerror_r(-err, sbuf, sizeof(sbuf)));
+}
+
+static void print_both_open_warning(int kerr, int uerr)
+{
+       /* Both kprobes and uprobes are disabled, warn it. */
+       if (kerr == -ENOTSUP && uerr == -ENOTSUP)
+               pr_warning("Debugfs is not mounted.\n");
+       else if (kerr == -ENOENT && uerr == -ENOENT)
+               pr_warning("Please rebuild kernel with CONFIG_KPROBE_EVENTS "
+                          "or/and CONFIG_UPROBE_EVENTS.\n");
+       else {
+               char sbuf[STRERR_BUFSIZE];
+               pr_warning("Failed to open kprobe events: %s.\n",
+                          strerror_r(-kerr, sbuf, sizeof(sbuf)));
+               pr_warning("Failed to open uprobe events: %s.\n",
+                          strerror_r(-uerr, sbuf, sizeof(sbuf)));
+       }
 }
 
-static int open_probe_events(const char *trace_file, bool readwrite,
-                               bool is_kprobe)
+static int open_probe_events(const char *trace_file, bool readwrite)
 {
        char buf[PATH_MAX];
        const char *__debugfs;
        int ret;
 
        __debugfs = debugfs_find_mountpoint();
-       if (__debugfs == NULL) {
-               pr_warning("Debugfs is not mounted.\n");
-               return -ENOENT;
-       }
+       if (__debugfs == NULL)
+               return -ENOTSUP;
 
        ret = e_snprintf(buf, PATH_MAX, "%s/%s", __debugfs, trace_file);
        if (ret >= 0) {
@@ -1820,19 +1846,19 @@ static int open_probe_events(const char *trace_file, bool readwrite,
                        ret = open(buf, O_RDONLY, 0);
 
                if (ret < 0)
-                       print_warn_msg(buf, is_kprobe);
+                       ret = -errno;
        }
        return ret;
 }
 
 static int open_kprobe_events(bool readwrite)
 {
-       return open_probe_events("tracing/kprobe_events", readwrite, true);
+       return open_probe_events("tracing/kprobe_events", readwrite);
 }
 
 static int open_uprobe_events(bool readwrite)
 {
-       return open_probe_events("tracing/uprobe_events", readwrite, false);
+       return open_probe_events("tracing/uprobe_events", readwrite);
 }
 
 /* Get raw string list of current kprobe_events  or uprobe_events */
@@ -1857,7 +1883,7 @@ static struct strlist *get_probe_trace_command_rawlist(int fd)
                        p[idx] = '\0';
                ret = strlist__add(sl, buf);
                if (ret < 0) {
-                       pr_debug("strlist__add failed: %s\n", strerror(-ret));
+                       pr_debug("strlist__add failed (%d)\n", ret);
                        strlist__delete(sl);
                        return NULL;
                }
@@ -1916,7 +1942,7 @@ static int __show_perf_probe_events(int fd, bool is_kprobe)
 
        rawlist = get_probe_trace_command_rawlist(fd);
        if (!rawlist)
-               return -ENOENT;
+               return -ENOMEM;
 
        strlist__for_each(ent, rawlist) {
                ret = parse_probe_trace_command(ent->s, &tev);
@@ -1940,27 +1966,34 @@ static int __show_perf_probe_events(int fd, bool is_kprobe)
 /* List up current perf-probe events */
 int show_perf_probe_events(void)
 {
-       int fd, ret;
+       int kp_fd, up_fd, ret;
 
        setup_pager();
-       fd = open_kprobe_events(false);
-
-       if (fd < 0)
-               return fd;
 
        ret = init_symbol_maps(false);
        if (ret < 0)
                return ret;
 
-       ret = __show_perf_probe_events(fd, true);
-       close(fd);
+       kp_fd = open_kprobe_events(false);
+       if (kp_fd >= 0) {
+               ret = __show_perf_probe_events(kp_fd, true);
+               close(kp_fd);
+               if (ret < 0)
+                       goto out;
+       }
 
-       fd = open_uprobe_events(false);
-       if (fd >= 0) {
-               ret = __show_perf_probe_events(fd, false);
-               close(fd);
+       up_fd = open_uprobe_events(false);
+       if (kp_fd < 0 && up_fd < 0) {
+               print_both_open_warning(kp_fd, up_fd);
+               ret = kp_fd;
+               goto out;
        }
 
+       if (up_fd >= 0) {
+               ret = __show_perf_probe_events(up_fd, false);
+               close(up_fd);
+       }
+out:
        exit_symbol_maps();
        return ret;
 }
@@ -1976,6 +2009,8 @@ static struct strlist *get_probe_trace_event_names(int fd, bool include_group)
 
        memset(&tev, 0, sizeof(tev));
        rawlist = get_probe_trace_command_rawlist(fd);
+       if (!rawlist)
+               return NULL;
        sl = strlist__new(true, NULL);
        strlist__for_each(ent, rawlist) {
                ret = parse_probe_trace_command(ent->s, &tev);
@@ -2005,6 +2040,7 @@ static int write_probe_trace_event(int fd, struct probe_trace_event *tev)
 {
        int ret = 0;
        char *buf = synthesize_probe_trace_command(tev);
+       char sbuf[STRERR_BUFSIZE];
 
        if (!buf) {
                pr_debug("Failed to synthesize probe trace event.\n");
@@ -2016,7 +2052,7 @@ static int write_probe_trace_event(int fd, struct probe_trace_event *tev)
                ret = write(fd, buf, strlen(buf));
                if (ret <= 0)
                        pr_warning("Failed to write event: %s\n",
-                                  strerror(errno));
+                                  strerror_r(errno, sbuf, sizeof(sbuf)));
        }
        free(buf);
        return ret;
@@ -2030,7 +2066,7 @@ static int get_new_event_name(char *buf, size_t len, const char *base,
        /* Try no suffix */
        ret = e_snprintf(buf, len, "%s", base);
        if (ret < 0) {
-               pr_debug("snprintf() failed: %s\n", strerror(-ret));
+               pr_debug("snprintf() failed: %d\n", ret);
                return ret;
        }
        if (!strlist__has_entry(namelist, buf))
@@ -2046,7 +2082,7 @@ static int get_new_event_name(char *buf, size_t len, const char *base,
        for (i = 1; i < MAX_EVENT_INDEX; i++) {
                ret = e_snprintf(buf, len, "%s_%d", base, i);
                if (ret < 0) {
-                       pr_debug("snprintf() failed: %s\n", strerror(-ret));
+                       pr_debug("snprintf() failed: %d\n", ret);
                        return ret;
                }
                if (!strlist__has_entry(namelist, buf))
@@ -2075,8 +2111,11 @@ static int __add_probe_trace_events(struct perf_probe_event *pev,
        else
                fd = open_kprobe_events(true);
 
-       if (fd < 0)
+       if (fd < 0) {
+               print_open_warning(fd, !pev->uprobes);
                return fd;
+       }
+
        /* Get current event names */
        namelist = get_probe_trace_event_names(fd, false);
        if (!namelist) {
@@ -2408,7 +2447,8 @@ static int __del_trace_probe_event(int fd, struct str_node *ent)
        printf("Removed event: %s\n", ent->s);
        return 0;
 error:
-       pr_warning("Failed to delete event: %s\n", strerror(-ret));
+       pr_warning("Failed to delete event: %s\n",
+                  strerror_r(-ret, buf, sizeof(buf)));
        return ret;
 }
 
@@ -2449,15 +2489,18 @@ int del_perf_probe_events(struct strlist *dellist)
 
        /* Get current event names */
        kfd = open_kprobe_events(true);
-       if (kfd < 0)
-               return kfd;
+       if (kfd >= 0)
+               namelist = get_probe_trace_event_names(kfd, true);
 
-       namelist = get_probe_trace_event_names(kfd, true);
        ufd = open_uprobe_events(true);
-
        if (ufd >= 0)
                unamelist = get_probe_trace_event_names(ufd, true);
 
+       if (kfd < 0 && ufd < 0) {
+               print_both_open_warning(kfd, ufd);
+               goto error;
+       }
+
        if (namelist == NULL && unamelist == NULL)
                goto error;
 
index 776c9347a3b64252e2f4c9b30b4710b580923b72..e01e9943139ff3b828ab8820aad9a5add4f34376 100644 (file)
@@ -128,7 +128,8 @@ extern int add_perf_probe_events(struct perf_probe_event *pevs, int npevs,
                                 bool force_add);
 extern int del_perf_probe_events(struct strlist *dellist);
 extern int show_perf_probe_events(void);
-extern int show_line_range(struct line_range *lr, const char *module);
+extern int show_line_range(struct line_range *lr, const char *module,
+                          bool user);
 extern int show_available_vars(struct perf_probe_event *pevs, int npevs,
                               int max_probe_points, const char *module,
                               struct strfilter *filter, bool externs);
index dca9145d704c948123a937ded474a97a60621aff..c7918f83b300086649f522bc5f663d9a5a88a5dc 100644 (file)
@@ -281,6 +281,7 @@ static int convert_variable_type(Dwarf_Die *vr_die,
        struct probe_trace_arg_ref **ref_ptr = &tvar->ref;
        Dwarf_Die type;
        char buf[16];
+       char sbuf[STRERR_BUFSIZE];
        int bsize, boffs, total;
        int ret;
 
@@ -367,7 +368,7 @@ formatted:
                if (ret >= 16)
                        ret = -E2BIG;
                pr_warning("Failed to convert variable type: %s\n",
-                          strerror(-ret));
+                          strerror_r(-ret, sbuf, sizeof(sbuf)));
                return ret;
        }
        tvar->type = strdup(buf);
@@ -608,14 +609,18 @@ static int convert_to_trace_point(Dwarf_Die *sp_die, Dwfl_Module *mod,
                return -EINVAL;
        }
 
-       /* Get an appropriate symbol from symtab */
-       symbol = dwfl_module_addrsym(mod, paddr, &sym, NULL);
+       symbol = dwarf_diename(sp_die);
        if (!symbol) {
-               pr_warning("Failed to find symbol at 0x%lx\n",
-                          (unsigned long)paddr);
-               return -ENOENT;
+               /* Try to get the symbol name from symtab */
+               symbol = dwfl_module_addrsym(mod, paddr, &sym, NULL);
+               if (!symbol) {
+                       pr_warning("Failed to find symbol at 0x%lx\n",
+                                  (unsigned long)paddr);
+                       return -ENOENT;
+               }
+               eaddr = sym.st_value;
        }
-       tp->offset = (unsigned long)(paddr - sym.st_value);
+       tp->offset = (unsigned long)(paddr - eaddr);
        tp->address = (unsigned long)paddr;
        tp->symbol = strdup(symbol);
        if (!tp->symbol)
@@ -779,10 +784,12 @@ static int find_lazy_match_lines(struct intlist *list,
        size_t line_len;
        ssize_t len;
        int count = 0, linenum = 1;
+       char sbuf[STRERR_BUFSIZE];
 
        fp = fopen(fname, "r");
        if (!fp) {
-               pr_warning("Failed to open %s: %s\n", fname, strerror(errno));
+               pr_warning("Failed to open %s: %s\n", fname,
+                          strerror_r(errno, sbuf, sizeof(sbuf)));
                return -errno;
        }
 
index 12aa9b0d0ba1769debff0615c0158e2f1c890c21..3dda85ca50c1d25bc81ff2457f9d624d774f754b 100644 (file)
@@ -736,7 +736,7 @@ static PyObject *pyrf_evlist__poll(struct pyrf_evlist *pevlist,
        if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|i", kwlist, &timeout))
                return NULL;
 
-       n = poll(evlist->pollfd, evlist->nr_fds, timeout);
+       n = perf_evlist__poll(evlist, timeout);
        if (n < 0) {
                PyErr_SetFromErrno(PyExc_OSError);
                return NULL;
@@ -753,9 +753,9 @@ static PyObject *pyrf_evlist__get_pollfd(struct pyrf_evlist *pevlist,
         PyObject *list = PyList_New(0);
        int i;
 
-       for (i = 0; i < evlist->nr_fds; ++i) {
+       for (i = 0; i < evlist->pollfd.nr; ++i) {
                PyObject *file;
-               FILE *fp = fdopen(evlist->pollfd[i].fd, "r");
+               FILE *fp = fdopen(evlist->pollfd.entries[i].fd, "r");
 
                if (fp == NULL)
                        goto free_list;
index fe8079edbdc11a239ee26524ac51d04b3d40f895..cf69325b985f15534fcb54303b98cfd5409d6e50 100644 (file)
@@ -14,6 +14,7 @@ static int perf_do_probe_api(setup_probe_fn_t fn, int cpu, const char *str)
        struct perf_evsel *evsel;
        unsigned long flags = perf_event_open_cloexec_flag();
        int err = -EAGAIN, fd;
+       static pid_t pid = -1;
 
        evlist = perf_evlist__new();
        if (!evlist)
@@ -24,14 +25,22 @@ static int perf_do_probe_api(setup_probe_fn_t fn, int cpu, const char *str)
 
        evsel = perf_evlist__first(evlist);
 
-       fd = sys_perf_event_open(&evsel->attr, -1, cpu, -1, flags);
-       if (fd < 0)
-               goto out_delete;
+       while (1) {
+               fd = sys_perf_event_open(&evsel->attr, pid, cpu, -1, flags);
+               if (fd < 0) {
+                       if (pid == -1 && errno == EACCES) {
+                               pid = 0;
+                               continue;
+                       }
+                       goto out_delete;
+               }
+               break;
+       }
        close(fd);
 
        fn(evsel);
 
-       fd = sys_perf_event_open(&evsel->attr, -1, cpu, -1, flags);
+       fd = sys_perf_event_open(&evsel->attr, pid, cpu, -1, flags);
        if (fd < 0) {
                if (errno == EINVAL)
                        err = -EINVAL;
@@ -47,7 +56,7 @@ out_delete:
 
 static bool perf_probe_api(setup_probe_fn_t fn)
 {
-       const char *try[] = {"cycles:u", "instructions:u", "cpu-clock", NULL};
+       const char *try[] = {"cycles:u", "instructions:u", "cpu-clock:u", NULL};
        struct cpu_map *cpus;
        int cpu, ret, i = 0;
 
@@ -106,7 +115,7 @@ void perf_evlist__config(struct perf_evlist *evlist, struct record_opts *opts)
 
        evlist__for_each(evlist, evsel) {
                perf_evsel__config(evsel, opts);
-               if (!evsel->idx && use_comm_exec)
+               if (evsel->tracking && use_comm_exec)
                        evsel->attr.comm_exec = 1;
        }
 
@@ -201,6 +210,7 @@ bool perf_evlist__can_select_event(struct perf_evlist *evlist, const char *str)
        struct perf_evsel *evsel;
        int err, fd, cpu;
        bool ret = false;
+       pid_t pid = -1;
 
        temp_evlist = perf_evlist__new();
        if (!temp_evlist)
@@ -221,12 +231,20 @@ bool perf_evlist__can_select_event(struct perf_evlist *evlist, const char *str)
                cpu = evlist->cpus->map[0];
        }
 
-       fd = sys_perf_event_open(&evsel->attr, -1, cpu, -1,
-                                perf_event_open_cloexec_flag());
-       if (fd >= 0) {
-               close(fd);
-               ret = true;
+       while (1) {
+               fd = sys_perf_event_open(&evsel->attr, pid, cpu, -1,
+                                        perf_event_open_cloexec_flag());
+               if (fd < 0) {
+                       if (pid == -1 && errno == EACCES) {
+                               pid = 0;
+                               continue;
+                       }
+                       goto out_delete;
+               }
+               break;
        }
+       close(fd);
+       ret = true;
 
 out_delete:
        perf_evlist__delete(temp_evlist);
index da8e9b285f5158d24d67d9722265187504bd95d5..34622b53e733b53b8d47415c67d408900a3e504f 100644 (file)
@@ -1,6 +1,7 @@
 #include "cache.h"
 #include "run-command.h"
 #include "exec_cmd.h"
+#include "debug.h"
 
 static inline void close_pair(int fd[2])
 {
@@ -19,6 +20,7 @@ int start_command(struct child_process *cmd)
 {
        int need_in, need_out, need_err;
        int fdin[2], fdout[2], fderr[2];
+       char sbuf[STRERR_BUFSIZE];
 
        /*
         * In case of errors we must keep the promise to close FDs
@@ -99,7 +101,7 @@ int start_command(struct child_process *cmd)
 
                if (cmd->dir && chdir(cmd->dir))
                        die("exec %s: cd to %s failed (%s)", cmd->argv[0],
-                           cmd->dir, strerror(errno));
+                           cmd->dir, strerror_r(errno, sbuf, sizeof(sbuf)));
                if (cmd->env) {
                        for (; *cmd->env; cmd->env++) {
                                if (strchr(*cmd->env, '='))
@@ -153,6 +155,8 @@ int start_command(struct child_process *cmd)
 
 static int wait_or_whine(pid_t pid)
 {
+       char sbuf[STRERR_BUFSIZE];
+
        for (;;) {
                int status, code;
                pid_t waiting = waitpid(pid, &status, 0);
@@ -160,7 +164,8 @@ static int wait_or_whine(pid_t pid)
                if (waiting < 0) {
                        if (errno == EINTR)
                                continue;
-                       error("waitpid failed (%s)", strerror(errno));
+                       error("waitpid failed (%s)",
+                             strerror_r(errno, sbuf, sizeof(sbuf)));
                        return -ERR_RUN_COMMAND_WAITPID;
                }
                if (waiting != pid)
index b2dba9c0a3a1843e91d0095e71845af45db1d5df..0a01bac4ce023e136ef15357e80360a90f35d40e 100644 (file)
@@ -432,6 +432,11 @@ error:
        return err;
 }
 
+static int perl_flush_script(void)
+{
+       return 0;
+}
+
 /*
  * Stop trace script
  */
@@ -633,6 +638,7 @@ static int perl_generate_script(struct pevent *pevent, const char *outfile)
 struct scripting_ops perl_scripting_ops = {
        .name = "Perl",
        .start_script = perl_start_script,
+       .flush_script = perl_flush_script,
        .stop_script = perl_stop_script,
        .process_event = perl_process_event,
        .generate_script = perl_generate_script,
index cbce2545da455fba34631818d5c08be7e8d26664..56ba07cce549ef5b5a79c2f2ae31e0799f245907 100644 (file)
@@ -73,6 +73,35 @@ static void pydict_set_item_string_decref(PyObject *dict, const char *key, PyObj
        Py_DECREF(val);
 }
 
+static PyObject *get_handler(const char *handler_name)
+{
+       PyObject *handler;
+
+       handler = PyDict_GetItemString(main_dict, handler_name);
+       if (handler && !PyCallable_Check(handler))
+               return NULL;
+       return handler;
+}
+
+static void call_object(PyObject *handler, PyObject *args, const char *die_msg)
+{
+       PyObject *retval;
+
+       retval = PyObject_CallObject(handler, args);
+       if (retval == NULL)
+               handler_call_die(die_msg);
+       Py_DECREF(retval);
+}
+
+static void try_call_object(const char *handler_name, PyObject *args)
+{
+       PyObject *handler;
+
+       handler = get_handler(handler_name);
+       if (handler)
+               call_object(handler, args, handler_name);
+}
+
 static void define_value(enum print_arg_type field_type,
                         const char *ev_name,
                         const char *field_name,
@@ -80,7 +109,7 @@ static void define_value(enum print_arg_type field_type,
                         const char *field_str)
 {
        const char *handler_name = "define_flag_value";
-       PyObject *handler, *t, *retval;
+       PyObject *t;
        unsigned long long value;
        unsigned n = 0;
 
@@ -98,13 +127,7 @@ static void define_value(enum print_arg_type field_type,
        PyTuple_SetItem(t, n++, PyInt_FromLong(value));
        PyTuple_SetItem(t, n++, PyString_FromString(field_str));
 
-       handler = PyDict_GetItemString(main_dict, handler_name);
-       if (handler && PyCallable_Check(handler)) {
-               retval = PyObject_CallObject(handler, t);
-               if (retval == NULL)
-                       handler_call_die(handler_name);
-               Py_DECREF(retval);
-       }
+       try_call_object(handler_name, t);
 
        Py_DECREF(t);
 }
@@ -127,7 +150,7 @@ static void define_field(enum print_arg_type field_type,
                         const char *delim)
 {
        const char *handler_name = "define_flag_field";
-       PyObject *handler, *t, *retval;
+       PyObject *t;
        unsigned n = 0;
 
        if (field_type == PRINT_SYMBOL)
@@ -145,13 +168,7 @@ static void define_field(enum print_arg_type field_type,
        if (field_type == PRINT_FLAGS)
                PyTuple_SetItem(t, n++, PyString_FromString(delim));
 
-       handler = PyDict_GetItemString(main_dict, handler_name);
-       if (handler && PyCallable_Check(handler)) {
-               retval = PyObject_CallObject(handler, t);
-               if (retval == NULL)
-                       handler_call_die(handler_name);
-               Py_DECREF(retval);
-       }
+       try_call_object(handler_name, t);
 
        Py_DECREF(t);
 }
@@ -362,7 +379,7 @@ static void python_process_tracepoint(struct perf_sample *sample,
                                      struct thread *thread,
                                      struct addr_location *al)
 {
-       PyObject *handler, *retval, *context, *t, *obj, *callchain;
+       PyObject *handler, *context, *t, *obj, *callchain;
        PyObject *dict = NULL;
        static char handler_name[256];
        struct format_field *field;
@@ -387,9 +404,7 @@ static void python_process_tracepoint(struct perf_sample *sample,
 
        sprintf(handler_name, "%s__%s", event->system, event->name);
 
-       handler = PyDict_GetItemString(main_dict, handler_name);
-       if (handler && !PyCallable_Check(handler))
-               handler = NULL;
+       handler = get_handler(handler_name);
        if (!handler) {
                dict = PyDict_New();
                if (!dict)
@@ -450,19 +465,9 @@ static void python_process_tracepoint(struct perf_sample *sample,
                Py_FatalError("error resizing Python tuple");
 
        if (handler) {
-               retval = PyObject_CallObject(handler, t);
-               if (retval == NULL)
-                       handler_call_die(handler_name);
-               Py_DECREF(retval);
+               call_object(handler, t, handler_name);
        } else {
-               handler = PyDict_GetItemString(main_dict, "trace_unhandled");
-               if (handler && PyCallable_Check(handler)) {
-
-                       retval = PyObject_CallObject(handler, t);
-                       if (retval == NULL)
-                               handler_call_die("trace_unhandled");
-                       Py_DECREF(retval);
-               }
+               try_call_object("trace_unhandled", t);
                Py_DECREF(dict);
        }
 
@@ -474,7 +479,7 @@ static void python_process_general_event(struct perf_sample *sample,
                                         struct thread *thread,
                                         struct addr_location *al)
 {
-       PyObject *handler, *retval, *t, *dict, *callchain, *dict_sample;
+       PyObject *handler, *t, *dict, *callchain, *dict_sample;
        static char handler_name[64];
        unsigned n = 0;
 
@@ -496,8 +501,8 @@ static void python_process_general_event(struct perf_sample *sample,
 
        snprintf(handler_name, sizeof(handler_name), "%s", "process_event");
 
-       handler = PyDict_GetItemString(main_dict, handler_name);
-       if (!handler || !PyCallable_Check(handler))
+       handler = get_handler(handler_name);
+       if (!handler)
                goto exit;
 
        pydict_set_item_string_decref(dict, "ev_name", PyString_FromString(perf_evsel__name(evsel)));
@@ -539,10 +544,7 @@ static void python_process_general_event(struct perf_sample *sample,
        if (_PyTuple_Resize(&t, n) == -1)
                Py_FatalError("error resizing Python tuple");
 
-       retval = PyObject_CallObject(handler, t);
-       if (retval == NULL)
-               handler_call_die(handler_name);
-       Py_DECREF(retval);
+       call_object(handler, t, handler_name);
 exit:
        Py_DECREF(dict);
        Py_DECREF(t);
@@ -566,36 +568,24 @@ static void python_process_event(union perf_event *event __maybe_unused,
 
 static int run_start_sub(void)
 {
-       PyObject *handler, *retval;
-       int err = 0;
-
        main_module = PyImport_AddModule("__main__");
        if (main_module == NULL)
                return -1;
        Py_INCREF(main_module);
 
        main_dict = PyModule_GetDict(main_module);
-       if (main_dict == NULL) {
-               err = -1;
+       if (main_dict == NULL)
                goto error;
-       }
        Py_INCREF(main_dict);
 
-       handler = PyDict_GetItemString(main_dict, "trace_begin");
-       if (handler == NULL || !PyCallable_Check(handler))
-               goto out;
+       try_call_object("trace_begin", NULL);
 
-       retval = PyObject_CallObject(handler, NULL);
-       if (retval == NULL)
-               handler_call_die("trace_begin");
+       return 0;
 
-       Py_DECREF(retval);
-       return err;
 error:
        Py_XDECREF(main_dict);
        Py_XDECREF(main_module);
-out:
-       return err;
+       return -1;
 }
 
 /*
@@ -649,28 +639,23 @@ error:
        return err;
 }
 
+static int python_flush_script(void)
+{
+       return 0;
+}
+
 /*
  * Stop trace script
  */
 static int python_stop_script(void)
 {
-       PyObject *handler, *retval;
-       int err = 0;
+       try_call_object("trace_end", NULL);
 
-       handler = PyDict_GetItemString(main_dict, "trace_end");
-       if (handler == NULL || !PyCallable_Check(handler))
-               goto out;
-
-       retval = PyObject_CallObject(handler, NULL);
-       if (retval == NULL)
-               handler_call_die("trace_end");
-       Py_DECREF(retval);
-out:
        Py_XDECREF(main_dict);
        Py_XDECREF(main_module);
        Py_Finalize();
 
-       return err;
+       return 0;
 }
 
 static int python_generate_script(struct pevent *pevent, const char *outfile)
@@ -843,6 +828,7 @@ static int python_generate_script(struct pevent *pevent, const char *outfile)
 struct scripting_ops python_scripting_ops = {
        .name = "Python",
        .start_script = python_start_script,
+       .flush_script = python_flush_script,
        .stop_script = python_stop_script,
        .process_event = python_process_event,
        .generate_script = python_generate_script,
index 88dfef70c13dbeb4ae75635e35762da5b19a974d..883406f4b381c5ebf6d49de5cb4f40f7c5bdeeae 100644 (file)
@@ -14,6 +14,7 @@
 #include "util.h"
 #include "cpumap.h"
 #include "perf_regs.h"
+#include "asm/bug.h"
 
 static int perf_session__open(struct perf_session *session)
 {
@@ -66,6 +67,25 @@ static void perf_session__destroy_kernel_maps(struct perf_session *session)
        machines__destroy_kernel_maps(&session->machines);
 }
 
+static bool perf_session__has_comm_exec(struct perf_session *session)
+{
+       struct perf_evsel *evsel;
+
+       evlist__for_each(session->evlist, evsel) {
+               if (evsel->attr.comm_exec)
+                       return true;
+       }
+
+       return false;
+}
+
+static void perf_session__set_comm_exec(struct perf_session *session)
+{
+       bool comm_exec = perf_session__has_comm_exec(session);
+
+       machines__set_comm_exec(&session->machines, comm_exec);
+}
+
 struct perf_session *perf_session__new(struct perf_data_file *file,
                                       bool repipe, struct perf_tool *tool)
 {
@@ -75,9 +95,7 @@ struct perf_session *perf_session__new(struct perf_data_file *file,
                goto out;
 
        session->repipe = repipe;
-       INIT_LIST_HEAD(&session->ordered_samples.samples);
-       INIT_LIST_HEAD(&session->ordered_samples.sample_cache);
-       INIT_LIST_HEAD(&session->ordered_samples.to_free);
+       ordered_events__init(&session->ordered_events);
        machines__init(&session->machines);
 
        if (file) {
@@ -91,6 +109,7 @@ struct perf_session *perf_session__new(struct perf_data_file *file,
                                goto out_close;
 
                        perf_session__set_id_hdr_size(session);
+                       perf_session__set_comm_exec(session);
                }
        }
 
@@ -100,13 +119,13 @@ struct perf_session *perf_session__new(struct perf_data_file *file,
                 * kernel MMAP event, in perf_event__process_mmap().
                 */
                if (perf_session__create_kernel_maps(session) < 0)
-                       goto out_delete;
+                       pr_warning("Cannot read kernel map\n");
        }
 
        if (tool && tool->ordering_requires_timestamps &&
-           tool->ordered_samples && !perf_evlist__sample_id_all(session->evlist)) {
+           tool->ordered_events && !perf_evlist__sample_id_all(session->evlist)) {
                dump_printf("WARNING: No sample_id_all support, falling back to unordered processing\n");
-               tool->ordered_samples = false;
+               tool->ordered_events = false;
        }
 
        return session;
@@ -238,7 +257,7 @@ void perf_tool__fill_defaults(struct perf_tool *tool)
        if (tool->build_id == NULL)
                tool->build_id = process_finished_round_stub;
        if (tool->finished_round == NULL) {
-               if (tool->ordered_samples)
+               if (tool->ordered_events)
                        tool->finished_round = process_finished_round;
                else
                        tool->finished_round = process_finished_round_stub;
@@ -444,87 +463,6 @@ static perf_event__swap_op perf_event__swap_ops[] = {
        [PERF_RECORD_HEADER_MAX]          = NULL,
 };
 
-struct sample_queue {
-       u64                     timestamp;
-       u64                     file_offset;
-       union perf_event        *event;
-       struct list_head        list;
-};
-
-static void perf_session_free_sample_buffers(struct perf_session *session)
-{
-       struct ordered_samples *os = &session->ordered_samples;
-
-       while (!list_empty(&os->to_free)) {
-               struct sample_queue *sq;
-
-               sq = list_entry(os->to_free.next, struct sample_queue, list);
-               list_del(&sq->list);
-               free(sq);
-       }
-}
-
-static int perf_session_deliver_event(struct perf_session *session,
-                                     union perf_event *event,
-                                     struct perf_sample *sample,
-                                     struct perf_tool *tool,
-                                     u64 file_offset);
-
-static int flush_sample_queue(struct perf_session *s,
-                      struct perf_tool *tool)
-{
-       struct ordered_samples *os = &s->ordered_samples;
-       struct list_head *head = &os->samples;
-       struct sample_queue *tmp, *iter;
-       struct perf_sample sample;
-       u64 limit = os->next_flush;
-       u64 last_ts = os->last_sample ? os->last_sample->timestamp : 0ULL;
-       bool show_progress = limit == ULLONG_MAX;
-       struct ui_progress prog;
-       int ret;
-
-       if (!tool->ordered_samples || !limit)
-               return 0;
-
-       if (show_progress)
-               ui_progress__init(&prog, os->nr_samples, "Processing time ordered events...");
-
-       list_for_each_entry_safe(iter, tmp, head, list) {
-               if (session_done())
-                       return 0;
-
-               if (iter->timestamp > limit)
-                       break;
-
-               ret = perf_evlist__parse_sample(s->evlist, iter->event, &sample);
-               if (ret)
-                       pr_err("Can't parse sample, err = %d\n", ret);
-               else {
-                       ret = perf_session_deliver_event(s, iter->event, &sample, tool,
-                                                        iter->file_offset);
-                       if (ret)
-                               return ret;
-               }
-
-               os->last_flush = iter->timestamp;
-               list_del(&iter->list);
-               list_add(&iter->list, &os->sample_cache);
-               os->nr_samples--;
-
-               if (show_progress)
-                       ui_progress__update(&prog, 1);
-       }
-
-       if (list_empty(head)) {
-               os->last_sample = NULL;
-       } else if (last_ts <= limit) {
-               os->last_sample =
-                       list_entry(head->prev, struct sample_queue, list);
-       }
-
-       return 0;
-}
-
 /*
  * When perf record finishes a pass on every buffers, it records this pseudo
  * event.
@@ -568,99 +506,43 @@ static int process_finished_round(struct perf_tool *tool,
                                  union perf_event *event __maybe_unused,
                                  struct perf_session *session)
 {
-       int ret = flush_sample_queue(session, tool);
-       if (!ret)
-               session->ordered_samples.next_flush = session->ordered_samples.max_timestamp;
-
-       return ret;
-}
-
-/* The queue is ordered by time */
-static void __queue_event(struct sample_queue *new, struct perf_session *s)
-{
-       struct ordered_samples *os = &s->ordered_samples;
-       struct sample_queue *sample = os->last_sample;
-       u64 timestamp = new->timestamp;
-       struct list_head *p;
-
-       ++os->nr_samples;
-       os->last_sample = new;
-
-       if (!sample) {
-               list_add(&new->list, &os->samples);
-               os->max_timestamp = timestamp;
-               return;
-       }
-
-       /*
-        * last_sample might point to some random place in the list as it's
-        * the last queued event. We expect that the new event is close to
-        * this.
-        */
-       if (sample->timestamp <= timestamp) {
-               while (sample->timestamp <= timestamp) {
-                       p = sample->list.next;
-                       if (p == &os->samples) {
-                               list_add_tail(&new->list, &os->samples);
-                               os->max_timestamp = timestamp;
-                               return;
-                       }
-                       sample = list_entry(p, struct sample_queue, list);
-               }
-               list_add_tail(&new->list, &sample->list);
-       } else {
-               while (sample->timestamp > timestamp) {
-                       p = sample->list.prev;
-                       if (p == &os->samples) {
-                               list_add(&new->list, &os->samples);
-                               return;
-                       }
-                       sample = list_entry(p, struct sample_queue, list);
-               }
-               list_add(&new->list, &sample->list);
-       }
+       return ordered_events__flush(session, tool, OE_FLUSH__ROUND);
 }
 
-#define MAX_SAMPLE_BUFFER      (64 * 1024 / sizeof(struct sample_queue))
-
 int perf_session_queue_event(struct perf_session *s, union perf_event *event,
-                                   struct perf_sample *sample, u64 file_offset)
+                            struct perf_tool *tool, struct perf_sample *sample,
+                            u64 file_offset)
 {
-       struct ordered_samples *os = &s->ordered_samples;
-       struct list_head *sc = &os->sample_cache;
+       struct ordered_events *oe = &s->ordered_events;
        u64 timestamp = sample->time;
-       struct sample_queue *new;
+       struct ordered_event *new;
 
        if (!timestamp || timestamp == ~0ULL)
                return -ETIME;
 
-       if (timestamp < s->ordered_samples.last_flush) {
-               printf("Warning: Timestamp below last timeslice flush\n");
-               return -EINVAL;
+       if (timestamp < oe->last_flush) {
+               WARN_ONCE(1, "Timestamp below last timeslice flush\n");
+
+               pr_oe_time(timestamp,      "out of order event");
+               pr_oe_time(oe->last_flush, "last flush, last_flush_type %d\n",
+                          oe->last_flush_type);
+
+               /* We could get out of order messages after forced flush. */
+               if (oe->last_flush_type != OE_FLUSH__HALF)
+                       return -EINVAL;
        }
 
-       if (!list_empty(sc)) {
-               new = list_entry(sc->next, struct sample_queue, list);
-               list_del(&new->list);
-       } else if (os->sample_buffer) {
-               new = os->sample_buffer + os->sample_buffer_idx;
-               if (++os->sample_buffer_idx == MAX_SAMPLE_BUFFER)
-                       os->sample_buffer = NULL;
-       } else {
-               os->sample_buffer = malloc(MAX_SAMPLE_BUFFER * sizeof(*new));
-               if (!os->sample_buffer)
-                       return -ENOMEM;
-               list_add(&os->sample_buffer->list, &os->to_free);
-               os->sample_buffer_idx = 2;
-               new = os->sample_buffer + 1;
+       new = ordered_events__new(oe, timestamp);
+       if (!new) {
+               ordered_events__flush(s, tool, OE_FLUSH__HALF);
+               new = ordered_events__new(oe, timestamp);
        }
 
-       new->timestamp = timestamp;
+       if (!new)
+               return -ENOMEM;
+
        new->file_offset = file_offset;
        new->event = event;
-
-       __queue_event(new, s);
-
        return 0;
 }
 
@@ -920,11 +802,10 @@ perf_session__deliver_sample(struct perf_session *session,
                                            &sample->read.one, machine);
 }
 
-static int perf_session_deliver_event(struct perf_session *session,
-                                     union perf_event *event,
-                                     struct perf_sample *sample,
-                                     struct perf_tool *tool,
-                                     u64 file_offset)
+int perf_session__deliver_event(struct perf_session *session,
+                               union perf_event *event,
+                               struct perf_sample *sample,
+                               struct perf_tool *tool, u64 file_offset)
 {
        struct perf_evsel *evsel;
        struct machine *machine;
@@ -1005,8 +886,10 @@ static s64 perf_session__process_user_event(struct perf_session *session,
        switch (event->header.type) {
        case PERF_RECORD_HEADER_ATTR:
                err = tool->attr(tool, event, &session->evlist);
-               if (err == 0)
+               if (err == 0) {
                        perf_session__set_id_hdr_size(session);
+                       perf_session__set_comm_exec(session);
+               }
                return err;
        case PERF_RECORD_HEADER_EVENT_TYPE:
                /*
@@ -1036,6 +919,61 @@ static void event_swap(union perf_event *event, bool sample_id_all)
                swap(event, sample_id_all);
 }
 
+int perf_session__peek_event(struct perf_session *session, off_t file_offset,
+                            void *buf, size_t buf_sz,
+                            union perf_event **event_ptr,
+                            struct perf_sample *sample)
+{
+       union perf_event *event;
+       size_t hdr_sz, rest;
+       int fd;
+
+       if (session->one_mmap && !session->header.needs_swap) {
+               event = file_offset - session->one_mmap_offset +
+                       session->one_mmap_addr;
+               goto out_parse_sample;
+       }
+
+       if (perf_data_file__is_pipe(session->file))
+               return -1;
+
+       fd = perf_data_file__fd(session->file);
+       hdr_sz = sizeof(struct perf_event_header);
+
+       if (buf_sz < hdr_sz)
+               return -1;
+
+       if (lseek(fd, file_offset, SEEK_SET) == (off_t)-1 ||
+           readn(fd, &buf, hdr_sz) != (ssize_t)hdr_sz)
+               return -1;
+
+       event = (union perf_event *)buf;
+
+       if (session->header.needs_swap)
+               perf_event_header__bswap(&event->header);
+
+       if (event->header.size < hdr_sz)
+               return -1;
+
+       rest = event->header.size - hdr_sz;
+
+       if (readn(fd, &buf, rest) != (ssize_t)rest)
+               return -1;
+
+       if (session->header.needs_swap)
+               event_swap(event, perf_evlist__sample_id_all(session->evlist));
+
+out_parse_sample:
+
+       if (sample && event->header.type < PERF_RECORD_USER_TYPE_START &&
+           perf_evlist__parse_sample(session->evlist, event, sample))
+               return -1;
+
+       *event_ptr = event;
+
+       return 0;
+}
+
 static s64 perf_session__process_event(struct perf_session *session,
                                       union perf_event *event,
                                       struct perf_tool *tool,
@@ -1062,15 +1000,15 @@ static s64 perf_session__process_event(struct perf_session *session,
        if (ret)
                return ret;
 
-       if (tool->ordered_samples) {
-               ret = perf_session_queue_event(session, event, &sample,
+       if (tool->ordered_events) {
+               ret = perf_session_queue_event(session, event, tool, &sample,
                                               file_offset);
                if (ret != -ETIME)
                        return ret;
        }
 
-       return perf_session_deliver_event(session, event, &sample, tool,
-                                         file_offset);
+       return perf_session__deliver_event(session, event, &sample, tool,
+                                          file_offset);
 }
 
 void perf_event_header__bswap(struct perf_event_header *hdr)
@@ -1222,12 +1160,11 @@ more:
                goto more;
 done:
        /* do the final flush for ordered samples */
-       session->ordered_samples.next_flush = ULLONG_MAX;
-       err = flush_sample_queue(session, tool);
+       err = ordered_events__flush(session, tool, OE_FLUSH__FINAL);
 out_err:
        free(buf);
        perf_session__warn_about_errors(session, tool);
-       perf_session_free_sample_buffers(session);
+       ordered_events__free(&session->ordered_events);
        return err;
 }
 
@@ -1368,12 +1305,11 @@ more:
 
 out:
        /* do the final flush for ordered samples */
-       session->ordered_samples.next_flush = ULLONG_MAX;
-       err = flush_sample_queue(session, tool);
+       err = ordered_events__flush(session, tool, OE_FLUSH__FINAL);
 out_err:
        ui_progress__finish();
        perf_session__warn_about_errors(session, tool);
-       perf_session_free_sample_buffers(session);
+       ordered_events__free(&session->ordered_events);
        session->one_mmap = false;
        return err;
 }
index 0321013bd9fde625f823fb2d15923cefc3eea965..ffb440462008ef55e65884d1849c22af9bb73856 100644 (file)
@@ -9,26 +9,13 @@
 #include "symbol.h"
 #include "thread.h"
 #include "data.h"
+#include "ordered-events.h"
 #include <linux/rbtree.h>
 #include <linux/perf_event.h>
 
-struct sample_queue;
 struct ip_callchain;
 struct thread;
 
-struct ordered_samples {
-       u64                     last_flush;
-       u64                     next_flush;
-       u64                     max_timestamp;
-       struct list_head        samples;
-       struct list_head        sample_cache;
-       struct list_head        to_free;
-       struct sample_queue     *sample_buffer;
-       struct sample_queue     *last_sample;
-       int                     sample_buffer_idx;
-       unsigned int            nr_samples;
-};
-
 struct perf_session {
        struct perf_header      header;
        struct machines         machines;
@@ -39,7 +26,7 @@ struct perf_session {
        bool                    one_mmap;
        void                    *one_mmap_addr;
        u64                     one_mmap_offset;
-       struct ordered_samples  ordered_samples;
+       struct ordered_events   ordered_events;
        struct perf_data_file   *file;
 };
 
@@ -58,6 +45,11 @@ void perf_session__delete(struct perf_session *session);
 
 void perf_event_header__bswap(struct perf_event_header *hdr);
 
+int perf_session__peek_event(struct perf_session *session, off_t file_offset,
+                            void *buf, size_t buf_sz,
+                            union perf_event **event_ptr,
+                            struct perf_sample *sample);
+
 int __perf_session__process_events(struct perf_session *session,
                                   u64 data_offset, u64 data_size, u64 size,
                                   struct perf_tool *tool);
@@ -65,10 +57,16 @@ int perf_session__process_events(struct perf_session *session,
                                 struct perf_tool *tool);
 
 int perf_session_queue_event(struct perf_session *s, union perf_event *event,
-                            struct perf_sample *sample, u64 file_offset);
+                            struct perf_tool *tool, struct perf_sample *sample,
+                            u64 file_offset);
 
 void perf_tool__fill_defaults(struct perf_tool *tool);
 
+int perf_session__deliver_event(struct perf_session *session,
+                               union perf_event *event,
+                               struct perf_sample *sample,
+                               struct perf_tool *tool, u64 file_offset);
+
 int perf_session__resolve_callchain(struct perf_session *session,
                                    struct perf_evsel *evsel,
                                    struct thread *thread,
@@ -128,5 +126,5 @@ int __perf_session__set_tracepoints_handlers(struct perf_session *session,
 
 extern volatile int session_done;
 
-#define session_done() (*(volatile int *)(&session_done))
+#define session_done() ACCESS_ONCE(session_done)
 #endif /* __PERF_SESSION_H */
index 14e5a039bc4546652ee9332dcc2751225ffaa4a8..289df9d1e65ae277f585f384db91eaa402f5b405 100644 (file)
@@ -70,12 +70,14 @@ static int hist_entry__thread_snprintf(struct hist_entry *he, char *bf,
                                       size_t size, unsigned int width)
 {
        const char *comm = thread__comm_str(he->thread);
-       return repsep_snprintf(bf, size, "%*s:%5d", width - 6,
-                              comm ?: "", he->thread->tid);
+
+       width = max(7U, width) - 6;
+       return repsep_snprintf(bf, size, "%5d:%-*.*s", he->thread->tid,
+                              width, width, comm ?: "");
 }
 
 struct sort_entry sort_thread = {
-       .se_header      = "Command:  Pid",
+       .se_header      = "  Pid:Command",
        .se_cmp         = sort__thread_cmp,
        .se_snprintf    = hist_entry__thread_snprintf,
        .se_width_idx   = HISTC_THREAD,
@@ -106,7 +108,7 @@ sort__comm_sort(struct hist_entry *left, struct hist_entry *right)
 static int hist_entry__comm_snprintf(struct hist_entry *he, char *bf,
                                     size_t size, unsigned int width)
 {
-       return repsep_snprintf(bf, size, "%*s", width, comm__str(he->comm));
+       return repsep_snprintf(bf, size, "%-*.*s", width, width, comm__str(he->comm));
 }
 
 struct sort_entry sort_comm = {
@@ -152,10 +154,10 @@ static int _hist_entry__dso_snprintf(struct map *map, char *bf,
        if (map && map->dso) {
                const char *dso_name = !verbose ? map->dso->short_name :
                        map->dso->long_name;
-               return repsep_snprintf(bf, size, "%-*s", width, dso_name);
+               return repsep_snprintf(bf, size, "%-*.*s", width, width, dso_name);
        }
 
-       return repsep_snprintf(bf, size, "%-*s", width, "[unknown]");
+       return repsep_snprintf(bf, size, "%-*.*s", width, width, "[unknown]");
 }
 
 static int hist_entry__dso_snprintf(struct hist_entry *he, char *bf,
@@ -257,7 +259,10 @@ static int _hist_entry__sym_snprintf(struct map *map, struct symbol *sym,
                                       width - ret, "");
        }
 
-       return ret;
+       if (ret > width)
+               bf[width] = '\0';
+
+       return width;
 }
 
 static int hist_entry__sym_snprintf(struct hist_entry *he, char *bf,
@@ -302,10 +307,9 @@ sort__srcline_cmp(struct hist_entry *left, struct hist_entry *right)
 }
 
 static int hist_entry__srcline_snprintf(struct hist_entry *he, char *bf,
-                                       size_t size,
-                                       unsigned int width __maybe_unused)
+                                       size_t size, unsigned int width)
 {
-       return repsep_snprintf(bf, size, "%s", he->srcline);
+       return repsep_snprintf(bf, size, "%*.*-s", width, width, he->srcline);
 }
 
 struct sort_entry sort_srcline = {
@@ -332,7 +336,7 @@ sort__parent_cmp(struct hist_entry *left, struct hist_entry *right)
 static int hist_entry__parent_snprintf(struct hist_entry *he, char *bf,
                                       size_t size, unsigned int width)
 {
-       return repsep_snprintf(bf, size, "%-*s", width,
+       return repsep_snprintf(bf, size, "%-*.*s", width, width,
                              he->parent ? he->parent->name : "[other]");
 }
 
@@ -354,7 +358,7 @@ sort__cpu_cmp(struct hist_entry *left, struct hist_entry *right)
 static int hist_entry__cpu_snprintf(struct hist_entry *he, char *bf,
                                    size_t size, unsigned int width)
 {
-       return repsep_snprintf(bf, size, "%*d", width, he->cpu);
+       return repsep_snprintf(bf, size, "%*.*d", width, width, he->cpu);
 }
 
 struct sort_entry sort_cpu = {
@@ -484,7 +488,7 @@ static int hist_entry__mispredict_snprintf(struct hist_entry *he, char *bf,
        else if (he->branch_info->flags.mispred)
                out = "Y";
 
-       return repsep_snprintf(bf, size, "%-*s", width, out);
+       return repsep_snprintf(bf, size, "%-*.*s", width, width, out);
 }
 
 /* --sort daddr_sym */
@@ -1194,7 +1198,7 @@ bool perf_hpp__same_sort_entry(struct perf_hpp_fmt *a, struct perf_hpp_fmt *b)
        return hse_a->se == hse_b->se;
 }
 
-void perf_hpp__reset_width(struct perf_hpp_fmt *fmt, struct hists *hists)
+void perf_hpp__reset_sort_width(struct perf_hpp_fmt *fmt, struct hists *hists)
 {
        struct hpp_sort_entry *hse;
 
@@ -1202,20 +1206,21 @@ void perf_hpp__reset_width(struct perf_hpp_fmt *fmt, struct hists *hists)
                return;
 
        hse = container_of(fmt, struct hpp_sort_entry, hpp);
-       hists__new_col_len(hists, hse->se->se_width_idx,
-                          strlen(hse->se->se_header));
+       hists__new_col_len(hists, hse->se->se_width_idx, strlen(fmt->name));
 }
 
 static int __sort__hpp_header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
                              struct perf_evsel *evsel)
 {
        struct hpp_sort_entry *hse;
-       size_t len;
+       size_t len = fmt->user_len;
 
        hse = container_of(fmt, struct hpp_sort_entry, hpp);
-       len = hists__col_len(&evsel->hists, hse->se->se_width_idx);
 
-       return scnprintf(hpp->buf, hpp->size, "%-*s", len, hse->se->se_header);
+       if (!len)
+               len = hists__col_len(&evsel->hists, hse->se->se_width_idx);
+
+       return scnprintf(hpp->buf, hpp->size, "%-*.*s", len, len, fmt->name);
 }
 
 static int __sort__hpp_width(struct perf_hpp_fmt *fmt,
@@ -1223,20 +1228,26 @@ static int __sort__hpp_width(struct perf_hpp_fmt *fmt,
                             struct perf_evsel *evsel)
 {
        struct hpp_sort_entry *hse;
+       size_t len = fmt->user_len;
 
        hse = container_of(fmt, struct hpp_sort_entry, hpp);
 
-       return hists__col_len(&evsel->hists, hse->se->se_width_idx);
+       if (!len)
+               len = hists__col_len(&evsel->hists, hse->se->se_width_idx);
+
+       return len;
 }
 
 static int __sort__hpp_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
                             struct hist_entry *he)
 {
        struct hpp_sort_entry *hse;
-       size_t len;
+       size_t len = fmt->user_len;
 
        hse = container_of(fmt, struct hpp_sort_entry, hpp);
-       len = hists__col_len(he->hists, hse->se->se_width_idx);
+
+       if (!len)
+               len = hists__col_len(he->hists, hse->se->se_width_idx);
 
        return hse->se->se_snprintf(he, hpp->buf, hpp->size, len);
 }
@@ -1253,6 +1264,7 @@ __sort_dimension__alloc_hpp(struct sort_dimension *sd)
        }
 
        hse->se = sd->entry;
+       hse->hpp.name = sd->entry->se_header;
        hse->hpp.header = __sort__hpp_header;
        hse->hpp.width = __sort__hpp_width;
        hse->hpp.entry = __sort__hpp_entry;
@@ -1265,6 +1277,8 @@ __sort_dimension__alloc_hpp(struct sort_dimension *sd)
        INIT_LIST_HEAD(&hse->hpp.list);
        INIT_LIST_HEAD(&hse->hpp.sort_list);
        hse->hpp.elide = false;
+       hse->hpp.len = 0;
+       hse->hpp.user_len = 0;
 
        return hse;
 }
@@ -1432,14 +1446,49 @@ static const char *get_default_sort_order(void)
        return default_sort_orders[sort__mode];
 }
 
+static int setup_sort_order(void)
+{
+       char *new_sort_order;
+
+       /*
+        * Append '+'-prefixed sort order to the default sort
+        * order string.
+        */
+       if (!sort_order || is_strict_order(sort_order))
+               return 0;
+
+       if (sort_order[1] == '\0') {
+               error("Invalid --sort key: `+'");
+               return -EINVAL;
+       }
+
+       /*
+        * We allocate new sort_order string, but we never free it,
+        * because it's checked over the rest of the code.
+        */
+       if (asprintf(&new_sort_order, "%s,%s",
+                    get_default_sort_order(), sort_order + 1) < 0) {
+               error("Not enough memory to set up --sort");
+               return -ENOMEM;
+       }
+
+       sort_order = new_sort_order;
+       return 0;
+}
+
 static int __setup_sorting(void)
 {
        char *tmp, *tok, *str;
-       const char *sort_keys = sort_order;
+       const char *sort_keys;
        int ret = 0;
 
+       ret = setup_sort_order();
+       if (ret)
+               return ret;
+
+       sort_keys = sort_order;
        if (sort_keys == NULL) {
-               if (field_order) {
+               if (is_strict_order(field_order)) {
                        /*
                         * If user specified field order but no sort order,
                         * we'll honor it and not add default sort orders.
@@ -1625,23 +1674,36 @@ static void reset_dimensions(void)
                memory_sort_dimensions[i].taken = 0;
 }
 
+bool is_strict_order(const char *order)
+{
+       return order && (*order != '+');
+}
+
 static int __setup_output_field(void)
 {
-       char *tmp, *tok, *str;
-       int ret = 0;
+       char *tmp, *tok, *str, *strp;
+       int ret = -EINVAL;
 
        if (field_order == NULL)
                return 0;
 
        reset_dimensions();
 
-       str = strdup(field_order);
+       strp = str = strdup(field_order);
        if (str == NULL) {
                error("Not enough memory to setup output fields");
                return -ENOMEM;
        }
 
-       for (tok = strtok_r(str, ", ", &tmp);
+       if (!is_strict_order(field_order))
+               strp++;
+
+       if (!strlen(strp)) {
+               error("Invalid --fields key: `+'");
+               goto out;
+       }
+
+       for (tok = strtok_r(strp, ", ", &tmp);
                        tok; tok = strtok_r(NULL, ", ", &tmp)) {
                ret = output_field_add(tok);
                if (ret == -EINVAL) {
@@ -1653,6 +1715,7 @@ static int __setup_output_field(void)
                }
        }
 
+out:
        free(str);
        return ret;
 }
index 041f0c9cea2b4f0f1af283ddeed3d3d5a9511e49..c03e4ff8beffe083ab19769d91a7e57d6f70d126 100644 (file)
@@ -218,4 +218,5 @@ void perf_hpp__set_elide(int idx, bool elide);
 
 int report_parse_ignore_callees_opt(const struct option *opt, const char *arg, int unset);
 
+bool is_strict_order(const char *order);
 #endif /* __PERF_SORT_H */
index d75349979e65e87cf0a4ecacc801cfb867ce323c..1e23a5bfb044a4cf39f2a0dfbbb5bf26bbad4b4b 100644 (file)
@@ -6,6 +6,7 @@
 #include <inttypes.h>
 
 #include "symbol.h"
+#include "machine.h"
 #include "vdso.h"
 #include <symbol/kallsyms.h>
 #include "debug.h"
@@ -680,6 +681,11 @@ static u64 ref_reloc(struct kmap *kmap)
        return 0;
 }
 
+static bool want_demangle(bool is_kernel_sym)
+{
+       return is_kernel_sym ? symbol_conf.demangle_kernel : symbol_conf.demangle;
+}
+
 int dso__load_sym(struct dso *dso, struct map *map,
                  struct symsrc *syms_ss, struct symsrc *runtime_ss,
                  symbol_filter_t filter, int kmodule)
@@ -712,6 +718,14 @@ int dso__load_sym(struct dso *dso, struct map *map,
                symbols__delete(&dso->symbols[map->type]);
 
        if (!syms_ss->symtab) {
+               /*
+                * If the vmlinux is stripped, fail so we will fall back
+                * to using kallsyms. The vmlinux runtime symbols aren't
+                * of much use.
+                */
+               if (dso->kernel)
+                       goto out_elf_end;
+
                syms_ss->symtab  = syms_ss->dynsym;
                syms_ss->symshdr = syms_ss->dynshdr;
        }
@@ -736,7 +750,7 @@ int dso__load_sym(struct dso *dso, struct map *map,
        if (symstrs == NULL)
                goto out_elf_end;
 
-       sec_strndx = elf_getscn(elf, ehdr.e_shstrndx);
+       sec_strndx = elf_getscn(runtime_ss->elf, runtime_ss->ehdr.e_shstrndx);
        if (sec_strndx == NULL)
                goto out_elf_end;
 
@@ -916,7 +930,11 @@ int dso__load_sym(struct dso *dso, struct map *map,
                                }
                                curr_dso->symtab_type = dso->symtab_type;
                                map_groups__insert(kmap->kmaps, curr_map);
-                               dsos__add(&dso->node, curr_dso);
+                               /*
+                                * The new DSO should go to the kernel DSOS
+                                */
+                               dsos__add(&map->groups->machine->kernel_dsos,
+                                         curr_dso);
                                dso__set_loaded(curr_dso, map->type);
                        } else
                                curr_dso = curr_map->dso;
@@ -938,9 +956,12 @@ new_symbol:
                 * DWARF DW_compile_unit has this, but we don't always have access
                 * to it...
                 */
-               if (symbol_conf.demangle) {
-                       demangled = bfd_demangle(NULL, elf_name,
-                                                DMGL_PARAMS | DMGL_ANSI);
+               if (want_demangle(dso->kernel || kmodule)) {
+                       int demangle_flags = DMGL_NO_OPTS;
+                       if (verbose)
+                               demangle_flags = DMGL_PARAMS | DMGL_ANSI;
+
+                       demangled = bfd_demangle(NULL, elf_name, demangle_flags);
                        if (demangled != NULL)
                                elf_name = demangled;
                }
index eb06746b06b291786721de6643ea9e3034ae49b7..be84f7a9838bff705d9c02b49168aede82b4291c 100644 (file)
@@ -15,6 +15,7 @@
 #include "machine.h"
 #include "symbol.h"
 #include "strlist.h"
+#include "header.h"
 
 #include <elf.h>
 #include <limits.h>
@@ -33,6 +34,7 @@ struct symbol_conf symbol_conf = {
        .try_vmlinux_path       = true,
        .annotate_src           = true,
        .demangle               = true,
+       .demangle_kernel        = false,
        .cumulate_callchain     = true,
        .show_hist_headers      = true,
        .symfs                  = "",
@@ -523,10 +525,15 @@ struct process_kallsyms_args {
        struct dso *dso;
 };
 
+/*
+ * These are symbols in the kernel image, so make sure that
+ * sym is from a kernel DSO.
+ */
 bool symbol__is_idle(struct symbol *sym)
 {
        const char * const idle_symbols[] = {
                "cpu_idle",
+               "cpu_startup_entry",
                "intel_idle",
                "default_idle",
                "native_safe_halt",
@@ -1468,8 +1475,7 @@ int dso__load_vmlinux(struct dso *dso, struct map *map,
        if (vmlinux[0] == '/')
                snprintf(symfs_vmlinux, sizeof(symfs_vmlinux), "%s", vmlinux);
        else
-               snprintf(symfs_vmlinux, sizeof(symfs_vmlinux), "%s%s",
-                        symbol_conf.symfs, vmlinux);
+               symbol__join_symfs(symfs_vmlinux, vmlinux);
 
        if (dso->kernel == DSO_TYPE_GUEST_KERNEL)
                symtab_type = DSO_BINARY_TYPE__GUEST_VMLINUX;
@@ -1745,12 +1751,13 @@ static void vmlinux_path__exit(void)
        zfree(&vmlinux_path);
 }
 
-static int vmlinux_path__init(void)
+static int vmlinux_path__init(struct perf_session_env *env)
 {
        struct utsname uts;
        char bf[PATH_MAX];
+       char *kernel_version;
 
-       vmlinux_path = malloc(sizeof(char *) * 5);
+       vmlinux_path = malloc(sizeof(char *) * 6);
        if (vmlinux_path == NULL)
                return -1;
 
@@ -1763,25 +1770,37 @@ static int vmlinux_path__init(void)
                goto out_fail;
        ++vmlinux_path__nr_entries;
 
-       /* only try running kernel version if no symfs was given */
+       /* only try kernel version if no symfs was given */
        if (symbol_conf.symfs[0] != 0)
                return 0;
 
-       if (uname(&uts) < 0)
-               return -1;
+       if (env) {
+               kernel_version = env->os_release;
+       } else {
+               if (uname(&uts) < 0)
+                       goto out_fail;
 
-       snprintf(bf, sizeof(bf), "/boot/vmlinux-%s", uts.release);
+               kernel_version = uts.release;
+       }
+
+       snprintf(bf, sizeof(bf), "/boot/vmlinux-%s", kernel_version);
        vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
        if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
                goto out_fail;
        ++vmlinux_path__nr_entries;
-       snprintf(bf, sizeof(bf), "/lib/modules/%s/build/vmlinux", uts.release);
+       snprintf(bf, sizeof(bf), "/usr/lib/debug/boot/vmlinux-%s",
+                kernel_version);
+       vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
+       if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
+               goto out_fail;
+        ++vmlinux_path__nr_entries;
+       snprintf(bf, sizeof(bf), "/lib/modules/%s/build/vmlinux", kernel_version);
        vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
        if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
                goto out_fail;
        ++vmlinux_path__nr_entries;
        snprintf(bf, sizeof(bf), "/usr/lib/debug/lib/modules/%s/vmlinux",
-                uts.release);
+                kernel_version);
        vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
        if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
                goto out_fail;
@@ -1827,7 +1846,7 @@ static bool symbol__read_kptr_restrict(void)
        return value;
 }
 
-int symbol__init(void)
+int symbol__init(struct perf_session_env *env)
 {
        const char *symfs;
 
@@ -1842,7 +1861,7 @@ int symbol__init(void)
                symbol_conf.priv_size += (sizeof(struct symbol_name_rb_node) -
                                          sizeof(struct symbol));
 
-       if (symbol_conf.try_vmlinux_path && vmlinux_path__init() < 0)
+       if (symbol_conf.try_vmlinux_path && vmlinux_path__init(env) < 0)
                return -1;
 
        if (symbol_conf.field_sep && *symbol_conf.field_sep == '.') {
index e7295e93cff9bff87ec7cce513280d5ed26ca7c2..bec4b7bd09debbe77efabbb0516d5faac5016af6 100644 (file)
@@ -13,6 +13,7 @@
 #include <libgen.h>
 #include "build-id.h"
 #include "event.h"
+#include "util.h"
 
 #ifdef HAVE_LIBELF_SUPPORT
 #include <libelf.h>
@@ -59,6 +60,7 @@ extern Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep,
 #endif
 
 #ifndef DMGL_PARAMS
+#define DMGL_NO_OPTS     0              /* For readability... */
 #define DMGL_PARAMS      (1 << 0)       /* Include function args */
 #define DMGL_ANSI        (1 << 1)       /* Include const, volatile, etc */
 #endif
@@ -118,6 +120,7 @@ struct symbol_conf {
                        annotate_src,
                        event_group,
                        demangle,
+                       demangle_kernel,
                        filter_relative,
                        show_hist_headers;
        const char      *vmlinux_name,
@@ -143,6 +146,14 @@ struct symbol_conf {
 };
 
 extern struct symbol_conf symbol_conf;
+
+static inline int __symbol__join_symfs(char *bf, size_t size, const char *path)
+{
+       return path__join(bf, size, symbol_conf.symfs, path);
+}
+
+#define symbol__join_symfs(bf, path) __symbol__join_symfs(bf, sizeof(bf), path)
+
 extern int vmlinux_path__nr_entries;
 extern char **vmlinux_path;
 
@@ -253,7 +264,8 @@ int modules__parse(const char *filename, void *arg,
 int filename__read_debuglink(const char *filename, char *debuglink,
                             size_t size);
 
-int symbol__init(void);
+struct perf_session_env;
+int symbol__init(struct perf_session_env *env);
 void symbol__exit(void);
 void symbol__elf_init(void);
 struct symbol *symbol__new(u64 start, u64 len, u8 binding, const char *name);
index 12c7a253a63ceecfa30f93d7f52f4361a5842c44..a9df7f2c6dc934210e83755155e843b72af68011 100644 (file)
@@ -42,7 +42,7 @@ struct thread *thread__new(pid_t pid, pid_t tid)
                        goto err_thread;
 
                snprintf(comm_str, 32, ":%d", tid);
-               comm = comm__new(comm_str, 0);
+               comm = comm__new(comm_str, 0, false);
                free(comm_str);
                if (!comm)
                        goto err_thread;
@@ -81,19 +81,33 @@ struct comm *thread__comm(const struct thread *thread)
        return list_first_entry(&thread->comm_list, struct comm, list);
 }
 
+struct comm *thread__exec_comm(const struct thread *thread)
+{
+       struct comm *comm, *last = NULL;
+
+       list_for_each_entry(comm, &thread->comm_list, list) {
+               if (comm->exec)
+                       return comm;
+               last = comm;
+       }
+
+       return last;
+}
+
 /* CHECKME: time should always be 0 if event aren't ordered */
-int thread__set_comm(struct thread *thread, const char *str, u64 timestamp)
+int __thread__set_comm(struct thread *thread, const char *str, u64 timestamp,
+                      bool exec)
 {
        struct comm *new, *curr = thread__comm(thread);
        int err;
 
        /* Override latest entry if it had no specific time coverage */
-       if (!curr->start) {
-               err = comm__override(curr, str, timestamp);
+       if (!curr->start && !curr->exec) {
+               err = comm__override(curr, str, timestamp, exec);
                if (err)
                        return err;
        } else {
-               new = comm__new(str, timestamp);
+               new = comm__new(str, timestamp, exec);
                if (!new)
                        return -ENOMEM;
                list_add(&new->list, &thread->comm_list);
index 716b7723cce27e03edf2d9a3d61fafc5b7fe1659..8c75fa774706352d22e2c4aa3390fb3350c89195 100644 (file)
@@ -38,9 +38,17 @@ static inline void thread__exited(struct thread *thread)
        thread->dead = true;
 }
 
-int thread__set_comm(struct thread *thread, const char *comm, u64 timestamp);
+int __thread__set_comm(struct thread *thread, const char *comm, u64 timestamp,
+                      bool exec);
+static inline int thread__set_comm(struct thread *thread, const char *comm,
+                                  u64 timestamp)
+{
+       return __thread__set_comm(thread, comm, timestamp, false);
+}
+
 int thread__comm_len(struct thread *thread);
 struct comm *thread__comm(const struct thread *thread);
+struct comm *thread__exec_comm(const struct thread *thread);
 const char *thread__comm_str(const struct thread *thread);
 void thread__insert_map(struct thread *thread, struct map *map);
 int thread__fork(struct thread *thread, struct thread *parent, u64 timestamp);
index 4385816d3d49643c981f64a310eaaef6d9838738..f11636966a0f19ee3e77b8e16f0f55e6db505827 100644 (file)
@@ -40,7 +40,7 @@ struct perf_tool {
        event_op2       tracing_data;
        event_op2       finished_round,
                        build_id;
-       bool            ordered_samples;
+       bool            ordered_events;
        bool            ordering_requires_timestamps;
 };
 
index 57aaccc1692e616ee0f257c90472272541f7d5b3..5c9bdd1591a975c2d1f7f028701504f228da70a0 100644 (file)
 
 struct scripting_context *scripting_context;
 
+static int flush_script_unsupported(void)
+{
+       return 0;
+}
+
 static int stop_script_unsupported(void)
 {
        return 0;
@@ -74,6 +79,7 @@ static int python_generate_script_unsupported(struct pevent *pevent
 struct scripting_ops python_scripting_unsupported_ops = {
        .name = "Python",
        .start_script = python_start_script_unsupported,
+       .flush_script = flush_script_unsupported,
        .stop_script = stop_script_unsupported,
        .process_event = process_event_unsupported,
        .generate_script = python_generate_script_unsupported,
@@ -137,6 +143,7 @@ static int perl_generate_script_unsupported(struct pevent *pevent
 struct scripting_ops perl_scripting_unsupported_ops = {
        .name = "Perl",
        .start_script = perl_start_script_unsupported,
+       .flush_script = flush_script_unsupported,
        .stop_script = stop_script_unsupported,
        .process_event = process_event_unsupported,
        .generate_script = perl_generate_script_unsupported,
index 7b6d68688327a75286eb3ab1a77fea15bb74ffb8..52aaa19e1eb13125dd30c4c82b6abe2d89de2735 100644 (file)
@@ -64,6 +64,7 @@ struct perf_session;
 struct scripting_ops {
        const char *name;
        int (*start_script) (const char *script, int argc, const char **argv);
+       int (*flush_script) (void);
        int (*stop_script) (void);
        void (*process_event) (union perf_event *event,
                               struct perf_sample *sample,
index e52e7461911b978838e868b92f024aa642c2bf53..24e8d871b74e51d10ccf35fd8188901acf4a94df 100644 (file)
@@ -13,6 +13,7 @@
 #include <limits.h>
 #include <byteswap.h>
 #include <linux/kernel.h>
+#include <unistd.h>
 
 /*
  * XXX We need to find a better place for these things...
@@ -282,6 +283,18 @@ void get_term_dimensions(struct winsize *ws)
        ws->ws_col = 80;
 }
 
+void set_term_quiet_input(struct termios *old)
+{
+       struct termios tc;
+
+       tcgetattr(0, old);
+       tc = *old;
+       tc.c_lflag &= ~(ICANON | ECHO);
+       tc.c_cc[VMIN] = 0;
+       tc.c_cc[VTIME] = 0;
+       tcsetattr(0, TCSANOW, &tc);
+}
+
 static void set_tracing_events_path(const char *mountpoint)
 {
        snprintf(tracing_events_path, sizeof(tracing_events_path), "%s/%s",
@@ -443,6 +456,7 @@ int filename__read_str(const char *filename, char **buf, size_t *sizep)
        size_t size = 0, alloc_size = 0;
        void *bf = NULL, *nbf;
        int fd, n, err = 0;
+       char sbuf[STRERR_BUFSIZE];
 
        fd = open(filename, O_RDONLY);
        if (fd < 0)
@@ -463,8 +477,8 @@ int filename__read_str(const char *filename, char **buf, size_t *sizep)
                n = read(fd, bf + size, alloc_size - size);
                if (n < 0) {
                        if (size) {
-                               pr_warning("read failed %d: %s\n",
-                                          errno, strerror(errno));
+                               pr_warning("read failed %d: %s\n", errno,
+                                        strerror_r(errno, sbuf, sizeof(sbuf)));
                                err = 0;
                        } else
                                err = -errno;
@@ -536,3 +550,39 @@ void mem_bswap_64(void *src, int byte_size)
                ++m;
        }
 }
+
+bool find_process(const char *name)
+{
+       size_t len = strlen(name);
+       DIR *dir;
+       struct dirent *d;
+       int ret = -1;
+
+       dir = opendir(procfs__mountpoint());
+       if (!dir)
+               return -1;
+
+       /* Walk through the directory. */
+       while (ret && (d = readdir(dir)) != NULL) {
+               char path[PATH_MAX];
+               char *data;
+               size_t size;
+
+               if ((d->d_type != DT_DIR) ||
+                    !strcmp(".", d->d_name) ||
+                    !strcmp("..", d->d_name))
+                       continue;
+
+               scnprintf(path, sizeof(path), "%s/%s/comm",
+                         procfs__mountpoint(), d->d_name);
+
+               if (filename__read_str(path, &data, &size))
+                       continue;
+
+               ret = strncmp(name, data, len);
+               free(data);
+       }
+
+       closedir(dir);
+       return ret ? false : true;
+}
index 66864364ccb482230e203b5369ee1fe004fadf78..80bfdaa0e2a45e5c7316625ad85e0b61ff9c191c 100644 (file)
@@ -39,6 +39,8 @@
 
 #define _ALL_SOURCE 1
 #define _BSD_SOURCE 1
+/* glibc 2.20 deprecates _BSD_SOURCE in favour of _DEFAULT_SOURCE */
+#define _DEFAULT_SOURCE 1
 #define HAS_BOOL
 
 #include <unistd.h>
 #include <regex.h>
 #include <utime.h>
 #include <sys/wait.h>
-#include <sys/poll.h>
+#include <poll.h>
 #include <sys/socket.h>
 #include <sys/ioctl.h>
 #include <inttypes.h>
+#include <linux/kernel.h>
 #include <linux/magic.h>
 #include <linux/types.h>
 #include <sys/ttydefaults.h>
 #include <api/fs/debugfs.h>
 #include <termios.h>
 #include <linux/bitops.h>
+#include <termios.h>
 
 extern const char *graph_line;
 extern const char *graph_dotted_line;
@@ -307,6 +311,7 @@ extern unsigned int page_size;
 extern int cacheline_size;
 
 void get_term_dimensions(struct winsize *ws);
+void set_term_quiet_input(struct termios *old);
 
 struct parse_tag {
        char tag;
@@ -317,6 +322,21 @@ unsigned long parse_tag_value(const char *str, struct parse_tag *tags);
 
 #define SRCLINE_UNKNOWN  ((char *) "??:0")
 
+static inline int path__join(char *bf, size_t size,
+                            const char *path1, const char *path2)
+{
+       return scnprintf(bf, size, "%s%s%s", path1, path1[0] ? "/" : "", path2);
+}
+
+static inline int path__join3(char *bf, size_t size,
+                             const char *path1, const char *path2,
+                             const char *path3)
+{
+       return scnprintf(bf, size, "%s%s%s%s%s",
+                        path1, path1[0] ? "/" : "",
+                        path2, path2[0] ? "/" : "", path3);
+}
+
 struct dso;
 
 char *get_srcline(struct dso *dso, unsigned long addr);
@@ -330,4 +350,5 @@ void mem_bswap_64(void *src, int byte_size);
 void mem_bswap_32(void *src, int byte_size);
 
 const char *get_filename_for_perf_kvm(void);
+bool find_process(const char *name);
 #endif /* GIT_COMPAT_UTIL_H */