Merge tag 'v4.0-rc1' into perf/core, to refresh the tree
authorIngo Molnar <mingo@kernel.org>
Thu, 26 Feb 2015 11:24:50 +0000 (12:24 +0100)
committerIngo Molnar <mingo@kernel.org>
Thu, 26 Feb 2015 11:24:50 +0000 (12:24 +0100)
Signed-off-by: Ingo Molnar <mingo@kernel.org>
118 files changed:
arch/powerpc/perf/core-book3s.c
arch/x86/kernel/cpu/perf_event.c
arch/x86/kernel/cpu/perf_event.h
arch/x86/kernel/cpu/perf_event_amd_ibs.c
arch/x86/kernel/cpu/perf_event_intel.c
arch/x86/kernel/cpu/perf_event_intel_lbr.c
arch/x86/kernel/cpu/perf_event_intel_uncore_snbep.c
include/linux/perf_event.h
include/uapi/linux/perf_event.h
kernel/events/core.c
tools/build/Build.include [new file with mode: 0644]
tools/build/Documentation/Build.txt [new file with mode: 0644]
tools/build/Makefile.build [new file with mode: 0644]
tools/build/tests/ex/Build [new file with mode: 0644]
tools/build/tests/ex/Makefile [new file with mode: 0644]
tools/build/tests/ex/a.c [new file with mode: 0644]
tools/build/tests/ex/arch/Build [new file with mode: 0644]
tools/build/tests/ex/arch/e.c [new file with mode: 0644]
tools/build/tests/ex/arch/f.c [new file with mode: 0644]
tools/build/tests/ex/b.c [new file with mode: 0644]
tools/build/tests/ex/c.c [new file with mode: 0644]
tools/build/tests/ex/d.c [new file with mode: 0644]
tools/build/tests/ex/empty/Build [new file with mode: 0644]
tools/build/tests/ex/ex.c [new file with mode: 0644]
tools/build/tests/run.sh [new file with mode: 0755]
tools/lib/api/Build [new file with mode: 0644]
tools/lib/api/Makefile
tools/lib/api/fd/Build [new file with mode: 0644]
tools/lib/api/fs/Build [new file with mode: 0644]
tools/lib/api/fs/debugfs.c
tools/lib/api/fs/debugfs.h
tools/lib/api/fs/findfs.c [new file with mode: 0644]
tools/lib/api/fs/findfs.h [new file with mode: 0644]
tools/lib/api/fs/tracefs.c [new file with mode: 0644]
tools/lib/api/fs/tracefs.h [new file with mode: 0644]
tools/lib/lockdep/Build [new file with mode: 0644]
tools/lib/lockdep/Makefile
tools/lib/traceevent/Build [new file with mode: 0644]
tools/lib/traceevent/Makefile
tools/lib/traceevent/event-parse.h
tools/lib/traceevent/trace-seq.c
tools/perf/Build [new file with mode: 0644]
tools/perf/Documentation/Build.txt [new file with mode: 0644]
tools/perf/Documentation/perf-probe.txt
tools/perf/Documentation/perf-record.txt
tools/perf/MANIFEST
tools/perf/Makefile.perf
tools/perf/arch/Build [new file with mode: 0644]
tools/perf/arch/arm/Build [new file with mode: 0644]
tools/perf/arch/arm/Makefile
tools/perf/arch/arm/tests/Build [new file with mode: 0644]
tools/perf/arch/arm/util/Build [new file with mode: 0644]
tools/perf/arch/arm64/Build [new file with mode: 0644]
tools/perf/arch/arm64/Makefile
tools/perf/arch/arm64/util/Build [new file with mode: 0644]
tools/perf/arch/powerpc/Build [new file with mode: 0644]
tools/perf/arch/powerpc/Makefile
tools/perf/arch/powerpc/util/Build [new file with mode: 0644]
tools/perf/arch/s390/Build [new file with mode: 0644]
tools/perf/arch/s390/Makefile
tools/perf/arch/s390/util/Build [new file with mode: 0644]
tools/perf/arch/sh/Build [new file with mode: 0644]
tools/perf/arch/sh/Makefile
tools/perf/arch/sh/util/Build [new file with mode: 0644]
tools/perf/arch/sparc/Build [new file with mode: 0644]
tools/perf/arch/sparc/Makefile
tools/perf/arch/sparc/util/Build [new file with mode: 0644]
tools/perf/arch/x86/Build [new file with mode: 0644]
tools/perf/arch/x86/Makefile
tools/perf/arch/x86/tests/Build [new file with mode: 0644]
tools/perf/arch/x86/util/Build [new file with mode: 0644]
tools/perf/bench/Build [new file with mode: 0644]
tools/perf/builtin-buildid-cache.c
tools/perf/builtin-list.c
tools/perf/builtin-record.c
tools/perf/builtin-report.c
tools/perf/builtin-trace.c
tools/perf/config/Makefile
tools/perf/config/feature-checks/Makefile
tools/perf/scripts/Build [new file with mode: 0644]
tools/perf/scripts/perl/Perf-Trace-Util/Build [new file with mode: 0644]
tools/perf/scripts/python/Perf-Trace-Util/Build [new file with mode: 0644]
tools/perf/tests/Build [new file with mode: 0644]
tools/perf/tests/dso-data.c
tools/perf/tests/open-syscall-all-cpus.c
tools/perf/tests/open-syscall.c
tools/perf/tests/parse-events.c
tools/perf/ui/Build [new file with mode: 0644]
tools/perf/ui/browsers/Build [new file with mode: 0644]
tools/perf/ui/gtk/Build [new file with mode: 0644]
tools/perf/ui/tui/Build [new file with mode: 0644]
tools/perf/util/Build [new file with mode: 0644]
tools/perf/util/build-id.c
tools/perf/util/build-id.h
tools/perf/util/cache.h
tools/perf/util/callchain.c
tools/perf/util/callchain.h
tools/perf/util/dso.c
tools/perf/util/dwarf-aux.c
tools/perf/util/dwarf-aux.h
tools/perf/util/evlist.c
tools/perf/util/evsel.c
tools/perf/util/evsel.h
tools/perf/util/machine.c
tools/perf/util/parse-events.c
tools/perf/util/parse-events.h
tools/perf/util/parse-options.c
tools/perf/util/probe-event.c
tools/perf/util/probe-finder.c
tools/perf/util/python-ext-sources
tools/perf/util/scripting-engines/Build [new file with mode: 0644]
tools/perf/util/session.c
tools/perf/util/setup.py
tools/perf/util/symbol-elf.c
tools/perf/util/trace-event-parse.c
tools/perf/util/trace-event.h
tools/perf/util/util.c
tools/perf/util/util.h

index 7c4f669..7fd60dc 100644 (file)
@@ -124,7 +124,7 @@ static unsigned long ebb_switch_in(bool ebb, struct cpu_hw_events *cpuhw)
 
 static inline void power_pmu_bhrb_enable(struct perf_event *event) {}
 static inline void power_pmu_bhrb_disable(struct perf_event *event) {}
-static void power_pmu_flush_branch_stack(void) {}
+static void power_pmu_sched_task(struct perf_event_context *ctx, bool sched_in) {}
 static inline void power_pmu_bhrb_read(struct cpu_hw_events *cpuhw) {}
 static void pmao_restore_workaround(bool ebb) { }
 #endif /* CONFIG_PPC32 */
@@ -350,6 +350,7 @@ static void power_pmu_bhrb_enable(struct perf_event *event)
                cpuhw->bhrb_context = event->ctx;
        }
        cpuhw->bhrb_users++;
+       perf_sched_cb_inc(event->ctx->pmu);
 }
 
 static void power_pmu_bhrb_disable(struct perf_event *event)
@@ -361,6 +362,7 @@ static void power_pmu_bhrb_disable(struct perf_event *event)
 
        cpuhw->bhrb_users--;
        WARN_ON_ONCE(cpuhw->bhrb_users < 0);
+       perf_sched_cb_dec(event->ctx->pmu);
 
        if (!cpuhw->disabled && !cpuhw->bhrb_users) {
                /* BHRB cannot be turned off when other
@@ -375,9 +377,12 @@ static void power_pmu_bhrb_disable(struct perf_event *event)
 /* Called from ctxsw to prevent one process's branch entries to
  * mingle with the other process's entries during context switch.
  */
-static void power_pmu_flush_branch_stack(void)
+static void power_pmu_sched_task(struct perf_event_context *ctx, bool sched_in)
 {
-       if (ppmu->bhrb_nr)
+       if (!ppmu->bhrb_nr)
+               return;
+
+       if (sched_in)
                power_pmu_bhrb_reset();
 }
 /* Calculate the to address for a branch */
@@ -1901,7 +1906,7 @@ static struct pmu power_pmu = {
        .cancel_txn     = power_pmu_cancel_txn,
        .commit_txn     = power_pmu_commit_txn,
        .event_idx      = power_pmu_event_idx,
-       .flush_branch_stack = power_pmu_flush_branch_stack,
+       .sched_task     = power_pmu_sched_task,
 };
 
 /*
index b71a7f8..e0dab5c 100644 (file)
@@ -399,39 +399,41 @@ int x86_pmu_hw_config(struct perf_event *event)
 
                if (event->attr.precise_ip > precise)
                        return -EOPNOTSUPP;
-               /*
-                * check that PEBS LBR correction does not conflict with
-                * whatever the user is asking with attr->branch_sample_type
-                */
-               if (event->attr.precise_ip > 1 &&
-                   x86_pmu.intel_cap.pebs_format < 2) {
-                       u64 *br_type = &event->attr.branch_sample_type;
-
-                       if (has_branch_stack(event)) {
-                               if (!precise_br_compat(event))
-                                       return -EOPNOTSUPP;
-
-                               /* branch_sample_type is compatible */
-
-                       } else {
-                               /*
-                                * user did not specify  branch_sample_type
-                                *
-                                * For PEBS fixups, we capture all
-                                * the branches at the priv level of the
-                                * event.
-                                */
-                               *br_type = PERF_SAMPLE_BRANCH_ANY;
-
-                               if (!event->attr.exclude_user)
-                                       *br_type |= PERF_SAMPLE_BRANCH_USER;
-
-                               if (!event->attr.exclude_kernel)
-                                       *br_type |= PERF_SAMPLE_BRANCH_KERNEL;
-                       }
+       }
+       /*
+        * check that PEBS LBR correction does not conflict with
+        * whatever the user is asking with attr->branch_sample_type
+        */
+       if (event->attr.precise_ip > 1 && x86_pmu.intel_cap.pebs_format < 2) {
+               u64 *br_type = &event->attr.branch_sample_type;
+
+               if (has_branch_stack(event)) {
+                       if (!precise_br_compat(event))
+                               return -EOPNOTSUPP;
+
+                       /* branch_sample_type is compatible */
+
+               } else {
+                       /*
+                        * user did not specify  branch_sample_type
+                        *
+                        * For PEBS fixups, we capture all
+                        * the branches at the priv level of the
+                        * event.
+                        */
+                       *br_type = PERF_SAMPLE_BRANCH_ANY;
+
+                       if (!event->attr.exclude_user)
+                               *br_type |= PERF_SAMPLE_BRANCH_USER;
+
+                       if (!event->attr.exclude_kernel)
+                               *br_type |= PERF_SAMPLE_BRANCH_KERNEL;
                }
        }
 
+       if (event->attr.branch_sample_type & PERF_SAMPLE_BRANCH_CALL_STACK)
+               event->attach_state |= PERF_ATTACH_TASK_DATA;
+
        /*
         * Generate PMC IRQs:
         * (keep 'enabled' bit clear for now)
@@ -1914,10 +1916,10 @@ static const struct attribute_group *x86_pmu_attr_groups[] = {
        NULL,
 };
 
-static void x86_pmu_flush_branch_stack(void)
+static void x86_pmu_sched_task(struct perf_event_context *ctx, bool sched_in)
 {
-       if (x86_pmu.flush_branch_stack)
-               x86_pmu.flush_branch_stack();
+       if (x86_pmu.sched_task)
+               x86_pmu.sched_task(ctx, sched_in);
 }
 
 void perf_check_microcode(void)
@@ -1949,7 +1951,8 @@ static struct pmu pmu = {
        .commit_txn             = x86_pmu_commit_txn,
 
        .event_idx              = x86_pmu_event_idx,
-       .flush_branch_stack     = x86_pmu_flush_branch_stack,
+       .sched_task             = x86_pmu_sched_task,
+       .task_ctx_size          = sizeof(struct x86_perf_task_context),
 };
 
 void arch_perf_update_userpage(struct perf_event *event,
index df525d2..a371d27 100644 (file)
@@ -472,7 +472,8 @@ struct x86_pmu {
        void            (*cpu_dead)(int cpu);
 
        void            (*check_microcode)(void);
-       void            (*flush_branch_stack)(void);
+       void            (*sched_task)(struct perf_event_context *ctx,
+                                     bool sched_in);
 
        /*
         * Intel Arch Perfmon v2+
@@ -515,6 +516,13 @@ struct x86_pmu {
        struct perf_guest_switch_msr *(*guest_get_msrs)(int *nr);
 };
 
+struct x86_perf_task_context {
+       u64 lbr_from[MAX_LBR_ENTRIES];
+       u64 lbr_to[MAX_LBR_ENTRIES];
+       int lbr_callstack_users;
+       int lbr_stack_state;
+};
+
 #define x86_add_quirk(func_)                                           \
 do {                                                                   \
        static struct x86_pmu_quirk __quirk __initdata = {              \
@@ -546,6 +554,12 @@ static struct perf_pmu_events_attr event_attr_##v = {                      \
 
 extern struct x86_pmu x86_pmu __read_mostly;
 
+static inline bool x86_pmu_has_lbr_callstack(void)
+{
+       return  x86_pmu.lbr_sel_map &&
+               x86_pmu.lbr_sel_map[PERF_SAMPLE_BRANCH_CALL_STACK_SHIFT] > 0;
+}
+
 DECLARE_PER_CPU(struct cpu_hw_events, cpu_hw_events);
 
 int x86_perf_event_set_period(struct perf_event *event);
@@ -727,6 +741,8 @@ void intel_pmu_pebs_disable_all(void);
 
 void intel_ds_init(void);
 
+void intel_pmu_lbr_sched_task(struct perf_event_context *ctx, bool sched_in);
+
 void intel_pmu_lbr_reset(void);
 
 void intel_pmu_lbr_enable(struct perf_event *event);
@@ -747,6 +763,8 @@ void intel_pmu_lbr_init_atom(void);
 
 void intel_pmu_lbr_init_snb(void);
 
+void intel_pmu_lbr_init_hsw(void);
+
 int intel_pmu_setup_lbr_filter(struct perf_event *event);
 
 int p4_pmu_init(void);
index a61f5c6..989d3c2 100644 (file)
@@ -796,7 +796,7 @@ static int setup_ibs_ctl(int ibs_eilvt_off)
  * the IBS interrupt vector is handled by perf_ibs_cpu_notifier that
  * is using the new offset.
  */
-static int force_ibs_eilvt_setup(void)
+static void force_ibs_eilvt_setup(void)
 {
        int offset;
        int ret;
@@ -811,26 +811,24 @@ static int force_ibs_eilvt_setup(void)
 
        if (offset == APIC_EILVT_NR_MAX) {
                printk(KERN_DEBUG "No EILVT entry available\n");
-               return -EBUSY;
+               return;
        }
 
        ret = setup_ibs_ctl(offset);
        if (ret)
                goto out;
 
-       if (!ibs_eilvt_valid()) {
-               ret = -EFAULT;
+       if (!ibs_eilvt_valid())
                goto out;
-       }
 
        pr_info("IBS: LVT offset %d assigned\n", offset);
 
-       return 0;
+       return;
 out:
        preempt_disable();
        put_eilvt(offset);
        preempt_enable();
-       return ret;
+       return;
 }
 
 static void ibs_eilvt_setup(void)
index 498b6d9..9f1dd18 100644 (file)
@@ -1029,20 +1029,6 @@ static __initconst const u64 slm_hw_cache_event_ids
  },
 };
 
-static inline bool intel_pmu_needs_lbr_smpl(struct perf_event *event)
-{
-       /* user explicitly requested branch sampling */
-       if (has_branch_stack(event))
-               return true;
-
-       /* implicit branch sampling to correct PEBS skid */
-       if (x86_pmu.intel_cap.pebs_trap && event->attr.precise_ip > 1 &&
-           x86_pmu.intel_cap.pebs_format < 2)
-               return true;
-
-       return false;
-}
-
 static void intel_pmu_disable_all(void)
 {
        struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
@@ -1207,7 +1193,7 @@ static void intel_pmu_disable_event(struct perf_event *event)
         * must disable before any actual event
         * because any event may be combined with LBR
         */
-       if (intel_pmu_needs_lbr_smpl(event))
+       if (needs_branch_stack(event))
                intel_pmu_lbr_disable(event);
 
        if (unlikely(hwc->config_base == MSR_ARCH_PERFMON_FIXED_CTR_CTRL)) {
@@ -1268,7 +1254,7 @@ static void intel_pmu_enable_event(struct perf_event *event)
         * must enabled before any actual event
         * because any event may be combined with LBR
         */
-       if (intel_pmu_needs_lbr_smpl(event))
+       if (needs_branch_stack(event))
                intel_pmu_lbr_enable(event);
 
        if (event->attr.exclude_host)
@@ -1747,7 +1733,7 @@ static int intel_pmu_hw_config(struct perf_event *event)
        if (event->attr.precise_ip && x86_pmu.pebs_aliases)
                x86_pmu.pebs_aliases(event);
 
-       if (intel_pmu_needs_lbr_smpl(event)) {
+       if (needs_branch_stack(event)) {
                ret = intel_pmu_setup_lbr_filter(event);
                if (ret)
                        return ret;
@@ -2044,18 +2030,6 @@ static void intel_pmu_cpu_dying(int cpu)
        fini_debug_store_on_cpu(cpu);
 }
 
-static void intel_pmu_flush_branch_stack(void)
-{
-       /*
-        * Intel LBR does not tag entries with the
-        * PID of the current task, then we need to
-        * flush it on ctxsw
-        * For now, we simply reset it
-        */
-       if (x86_pmu.lbr_nr)
-               intel_pmu_lbr_reset();
-}
-
 PMU_FORMAT_ATTR(offcore_rsp, "config1:0-63");
 
 PMU_FORMAT_ATTR(ldlat, "config1:0-15");
@@ -2107,7 +2081,7 @@ static __initconst const struct x86_pmu intel_pmu = {
        .cpu_starting           = intel_pmu_cpu_starting,
        .cpu_dying              = intel_pmu_cpu_dying,
        .guest_get_msrs         = intel_guest_get_msrs,
-       .flush_branch_stack     = intel_pmu_flush_branch_stack,
+       .sched_task             = intel_pmu_lbr_sched_task,
 };
 
 static __init void intel_clovertown_quirk(void)
@@ -2549,7 +2523,7 @@ __init int intel_pmu_init(void)
                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));
 
-               intel_pmu_lbr_init_snb();
+               intel_pmu_lbr_init_hsw();
 
                x86_pmu.event_constraints = intel_hsw_event_constraints;
                x86_pmu.pebs_constraints = intel_hsw_pebs_event_constraints;
index 58f1a94..0473874 100644 (file)
@@ -39,6 +39,7 @@ static enum {
 #define LBR_IND_JMP_BIT                6 /* do not capture indirect jumps */
 #define LBR_REL_JMP_BIT                7 /* do not capture relative jumps */
 #define LBR_FAR_BIT            8 /* do not capture far branches */
+#define LBR_CALL_STACK_BIT     9 /* enable call stack */
 
 #define LBR_KERNEL     (1 << LBR_KERNEL_BIT)
 #define LBR_USER       (1 << LBR_USER_BIT)
@@ -49,6 +50,7 @@ static enum {
 #define LBR_REL_JMP    (1 << LBR_REL_JMP_BIT)
 #define LBR_IND_JMP    (1 << LBR_IND_JMP_BIT)
 #define LBR_FAR                (1 << LBR_FAR_BIT)
+#define LBR_CALL_STACK (1 << LBR_CALL_STACK_BIT)
 
 #define LBR_PLM (LBR_KERNEL | LBR_USER)
 
@@ -69,33 +71,31 @@ static enum {
 #define LBR_FROM_FLAG_IN_TX    (1ULL << 62)
 #define LBR_FROM_FLAG_ABORT    (1ULL << 61)
 
-#define for_each_branch_sample_type(x) \
-       for ((x) = PERF_SAMPLE_BRANCH_USER; \
-            (x) < PERF_SAMPLE_BRANCH_MAX; (x) <<= 1)
-
 /*
  * x86control flow change classification
  * x86control flow changes include branches, interrupts, traps, faults
  */
 enum {
-       X86_BR_NONE     = 0,      /* unknown */
-
-       X86_BR_USER     = 1 << 0, /* branch target is user */
-       X86_BR_KERNEL   = 1 << 1, /* branch target is kernel */
-
-       X86_BR_CALL     = 1 << 2, /* call */
-       X86_BR_RET      = 1 << 3, /* return */
-       X86_BR_SYSCALL  = 1 << 4, /* syscall */
-       X86_BR_SYSRET   = 1 << 5, /* syscall return */
-       X86_BR_INT      = 1 << 6, /* sw interrupt */
-       X86_BR_IRET     = 1 << 7, /* return from interrupt */
-       X86_BR_JCC      = 1 << 8, /* conditional */
-       X86_BR_JMP      = 1 << 9, /* jump */
-       X86_BR_IRQ      = 1 << 10,/* hw interrupt or trap or fault */
-       X86_BR_IND_CALL = 1 << 11,/* indirect calls */
-       X86_BR_ABORT    = 1 << 12,/* transaction abort */
-       X86_BR_IN_TX    = 1 << 13,/* in transaction */
-       X86_BR_NO_TX    = 1 << 14,/* not in transaction */
+       X86_BR_NONE             = 0,      /* unknown */
+
+       X86_BR_USER             = 1 << 0, /* branch target is user */
+       X86_BR_KERNEL           = 1 << 1, /* branch target is kernel */
+
+       X86_BR_CALL             = 1 << 2, /* call */
+       X86_BR_RET              = 1 << 3, /* return */
+       X86_BR_SYSCALL          = 1 << 4, /* syscall */
+       X86_BR_SYSRET           = 1 << 5, /* syscall return */
+       X86_BR_INT              = 1 << 6, /* sw interrupt */
+       X86_BR_IRET             = 1 << 7, /* return from interrupt */
+       X86_BR_JCC              = 1 << 8, /* conditional */
+       X86_BR_JMP              = 1 << 9, /* jump */
+       X86_BR_IRQ              = 1 << 10,/* hw interrupt or trap or fault */
+       X86_BR_IND_CALL         = 1 << 11,/* indirect calls */
+       X86_BR_ABORT            = 1 << 12,/* transaction abort */
+       X86_BR_IN_TX            = 1 << 13,/* in transaction */
+       X86_BR_NO_TX            = 1 << 14,/* not in transaction */
+       X86_BR_ZERO_CALL        = 1 << 15,/* zero length call */
+       X86_BR_CALL_STACK       = 1 << 16,/* call stack */
 };
 
 #define X86_BR_PLM (X86_BR_USER | X86_BR_KERNEL)
@@ -112,13 +112,15 @@ enum {
         X86_BR_JMP      |\
         X86_BR_IRQ      |\
         X86_BR_ABORT    |\
-        X86_BR_IND_CALL)
+        X86_BR_IND_CALL |\
+        X86_BR_ZERO_CALL)
 
 #define X86_BR_ALL (X86_BR_PLM | X86_BR_ANY)
 
 #define X86_BR_ANY_CALL                 \
        (X86_BR_CALL            |\
         X86_BR_IND_CALL        |\
+        X86_BR_ZERO_CALL       |\
         X86_BR_SYSCALL         |\
         X86_BR_IRQ             |\
         X86_BR_INT)
@@ -132,14 +134,23 @@ static void intel_pmu_lbr_filter(struct cpu_hw_events *cpuc);
 
 static void __intel_pmu_lbr_enable(void)
 {
-       u64 debugctl;
        struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
+       u64 debugctl, lbr_select = 0;
 
-       if (cpuc->lbr_sel)
-               wrmsrl(MSR_LBR_SELECT, cpuc->lbr_sel->config);
+       if (cpuc->lbr_sel) {
+               lbr_select = cpuc->lbr_sel->config;
+               wrmsrl(MSR_LBR_SELECT, lbr_select);
+       }
 
        rdmsrl(MSR_IA32_DEBUGCTLMSR, debugctl);
-       debugctl |= (DEBUGCTLMSR_LBR | DEBUGCTLMSR_FREEZE_LBRS_ON_PMI);
+       debugctl |= DEBUGCTLMSR_LBR;
+       /*
+        * LBR callstack does not work well with FREEZE_LBRS_ON_PMI.
+        * If FREEZE_LBRS_ON_PMI is set, PMI near call/return instructions
+        * may cause superfluous increase/decrease of LBR_TOS.
+        */
+       if (!(lbr_select & LBR_CALL_STACK))
+               debugctl |= DEBUGCTLMSR_FREEZE_LBRS_ON_PMI;
        wrmsrl(MSR_IA32_DEBUGCTLMSR, debugctl);
 }
 
@@ -181,9 +192,116 @@ void intel_pmu_lbr_reset(void)
                intel_pmu_lbr_reset_64();
 }
 
+/*
+ * TOS = most recently recorded branch
+ */
+static inline u64 intel_pmu_lbr_tos(void)
+{
+       u64 tos;
+
+       rdmsrl(x86_pmu.lbr_tos, tos);
+       return tos;
+}
+
+enum {
+       LBR_NONE,
+       LBR_VALID,
+};
+
+static void __intel_pmu_lbr_restore(struct x86_perf_task_context *task_ctx)
+{
+       int i;
+       unsigned lbr_idx, mask;
+       u64 tos;
+
+       if (task_ctx->lbr_callstack_users == 0 ||
+           task_ctx->lbr_stack_state == LBR_NONE) {
+               intel_pmu_lbr_reset();
+               return;
+       }
+
+       mask = x86_pmu.lbr_nr - 1;
+       tos = intel_pmu_lbr_tos();
+       for (i = 0; i < x86_pmu.lbr_nr; i++) {
+               lbr_idx = (tos - i) & mask;
+               wrmsrl(x86_pmu.lbr_from + lbr_idx, task_ctx->lbr_from[i]);
+               wrmsrl(x86_pmu.lbr_to + lbr_idx, task_ctx->lbr_to[i]);
+       }
+       task_ctx->lbr_stack_state = LBR_NONE;
+}
+
+static void __intel_pmu_lbr_save(struct x86_perf_task_context *task_ctx)
+{
+       int i;
+       unsigned lbr_idx, mask;
+       u64 tos;
+
+       if (task_ctx->lbr_callstack_users == 0) {
+               task_ctx->lbr_stack_state = LBR_NONE;
+               return;
+       }
+
+       mask = x86_pmu.lbr_nr - 1;
+       tos = intel_pmu_lbr_tos();
+       for (i = 0; i < x86_pmu.lbr_nr; i++) {
+               lbr_idx = (tos - i) & mask;
+               rdmsrl(x86_pmu.lbr_from + lbr_idx, task_ctx->lbr_from[i]);
+               rdmsrl(x86_pmu.lbr_to + lbr_idx, task_ctx->lbr_to[i]);
+       }
+       task_ctx->lbr_stack_state = LBR_VALID;
+}
+
+void intel_pmu_lbr_sched_task(struct perf_event_context *ctx, bool sched_in)
+{
+       struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
+       struct x86_perf_task_context *task_ctx;
+
+       if (!x86_pmu.lbr_nr)
+               return;
+
+       /*
+        * If LBR callstack feature is enabled and the stack was saved when
+        * the task was scheduled out, restore the stack. Otherwise flush
+        * the LBR stack.
+        */
+       task_ctx = ctx ? ctx->task_ctx_data : NULL;
+       if (task_ctx) {
+               if (sched_in) {
+                       __intel_pmu_lbr_restore(task_ctx);
+                       cpuc->lbr_context = ctx;
+               } else {
+                       __intel_pmu_lbr_save(task_ctx);
+               }
+               return;
+       }
+
+       /*
+        * When sampling the branck stack in system-wide, it may be
+        * necessary to flush the stack on context switch. This happens
+        * when the branch stack does not tag its entries with the pid
+        * of the current task. Otherwise it becomes impossible to
+        * associate a branch entry with a task. This ambiguity is more
+        * likely to appear when the branch stack supports priv level
+        * filtering and the user sets it to monitor only at the user
+        * level (which could be a useful measurement in system-wide
+        * mode). In that case, the risk is high of having a branch
+        * stack with branch from multiple tasks.
+        */
+       if (sched_in) {
+               intel_pmu_lbr_reset();
+               cpuc->lbr_context = ctx;
+       }
+}
+
+static inline bool branch_user_callstack(unsigned br_sel)
+{
+       return (br_sel & X86_BR_USER) && (br_sel & X86_BR_CALL_STACK);
+}
+
 void intel_pmu_lbr_enable(struct perf_event *event)
 {
        struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
+       struct x86_perf_task_context *task_ctx;
 
        if (!x86_pmu.lbr_nr)
                return;
@@ -198,18 +316,33 @@ void intel_pmu_lbr_enable(struct perf_event *event)
        }
        cpuc->br_sel = event->hw.branch_reg.reg;
 
+       if (branch_user_callstack(cpuc->br_sel) && event->ctx &&
+                                       event->ctx->task_ctx_data) {
+               task_ctx = event->ctx->task_ctx_data;
+               task_ctx->lbr_callstack_users++;
+       }
+
        cpuc->lbr_users++;
+       perf_sched_cb_inc(event->ctx->pmu);
 }
 
 void intel_pmu_lbr_disable(struct perf_event *event)
 {
        struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
+       struct x86_perf_task_context *task_ctx;
 
        if (!x86_pmu.lbr_nr)
                return;
 
+       if (branch_user_callstack(cpuc->br_sel) && event->ctx &&
+                                       event->ctx->task_ctx_data) {
+               task_ctx = event->ctx->task_ctx_data;
+               task_ctx->lbr_callstack_users--;
+       }
+
        cpuc->lbr_users--;
        WARN_ON_ONCE(cpuc->lbr_users < 0);
+       perf_sched_cb_dec(event->ctx->pmu);
 
        if (cpuc->enabled && !cpuc->lbr_users) {
                __intel_pmu_lbr_disable();
@@ -234,18 +367,6 @@ void intel_pmu_lbr_disable_all(void)
                __intel_pmu_lbr_disable();
 }
 
-/*
- * TOS = most recently recorded branch
- */
-static inline u64 intel_pmu_lbr_tos(void)
-{
-       u64 tos;
-
-       rdmsrl(x86_pmu.lbr_tos, tos);
-
-       return tos;
-}
-
 static void intel_pmu_lbr_read_32(struct cpu_hw_events *cpuc)
 {
        unsigned long mask = x86_pmu.lbr_nr - 1;
@@ -350,7 +471,7 @@ void intel_pmu_lbr_read(void)
  * - in case there is no HW filter
  * - in case the HW filter has errata or limitations
  */
-static void intel_pmu_setup_sw_lbr_filter(struct perf_event *event)
+static int intel_pmu_setup_sw_lbr_filter(struct perf_event *event)
 {
        u64 br_type = event->attr.branch_sample_type;
        int mask = 0;
@@ -387,11 +508,21 @@ static void intel_pmu_setup_sw_lbr_filter(struct perf_event *event)
        if (br_type & PERF_SAMPLE_BRANCH_COND)
                mask |= X86_BR_JCC;
 
+       if (br_type & PERF_SAMPLE_BRANCH_CALL_STACK) {
+               if (!x86_pmu_has_lbr_callstack())
+                       return -EOPNOTSUPP;
+               if (mask & ~(X86_BR_USER | X86_BR_KERNEL))
+                       return -EINVAL;
+               mask |= X86_BR_CALL | X86_BR_IND_CALL | X86_BR_RET |
+                       X86_BR_CALL_STACK;
+       }
+
        /*
         * stash actual user request into reg, it may
         * be used by fixup code for some CPU
         */
        event->hw.branch_reg.reg = mask;
+       return 0;
 }
 
 /*
@@ -403,14 +534,14 @@ static int intel_pmu_setup_hw_lbr_filter(struct perf_event *event)
 {
        struct hw_perf_event_extra *reg;
        u64 br_type = event->attr.branch_sample_type;
-       u64 mask = 0, m;
-       u64 v;
+       u64 mask = 0, v;
+       int i;
 
-       for_each_branch_sample_type(m) {
-               if (!(br_type & m))
+       for (i = 0; i < PERF_SAMPLE_BRANCH_MAX_SHIFT; i++) {
+               if (!(br_type & (1ULL << i)))
                        continue;
 
-               v = x86_pmu.lbr_sel_map[m];
+               v = x86_pmu.lbr_sel_map[i];
                if (v == LBR_NOT_SUPP)
                        return -EOPNOTSUPP;
 
@@ -420,8 +551,12 @@ static int intel_pmu_setup_hw_lbr_filter(struct perf_event *event)
        reg = &event->hw.branch_reg;
        reg->idx = EXTRA_REG_LBR;
 
-       /* LBR_SELECT operates in suppress mode so invert mask */
-       reg->config = ~mask & x86_pmu.lbr_sel_mask;
+       /*
+        * The first 9 bits (LBR_SEL_MASK) in LBR_SELECT operate
+        * in suppress mode. So LBR_SELECT should be set to
+        * (~mask & LBR_SEL_MASK) | (mask & ~LBR_SEL_MASK)
+        */
+       reg->config = mask ^ x86_pmu.lbr_sel_mask;
 
        return 0;
 }
@@ -439,7 +574,9 @@ int intel_pmu_setup_lbr_filter(struct perf_event *event)
        /*
         * setup SW LBR filter
         */
-       intel_pmu_setup_sw_lbr_filter(event);
+       ret = intel_pmu_setup_sw_lbr_filter(event);
+       if (ret)
+               return ret;
 
        /*
         * setup HW LBR filter, if any
@@ -568,6 +705,12 @@ static int branch_type(unsigned long from, unsigned long to, int abort)
                ret = X86_BR_INT;
                break;
        case 0xe8: /* call near rel */
+               insn_get_immediate(&insn);
+               if (insn.immediate1.value == 0) {
+                       /* zero length call */
+                       ret = X86_BR_ZERO_CALL;
+                       break;
+               }
        case 0x9a: /* call far absolute */
                ret = X86_BR_CALL;
                break;
@@ -678,35 +821,49 @@ intel_pmu_lbr_filter(struct cpu_hw_events *cpuc)
 /*
  * Map interface branch filters onto LBR filters
  */
-static const int nhm_lbr_sel_map[PERF_SAMPLE_BRANCH_MAX] = {
-       [PERF_SAMPLE_BRANCH_ANY]        = LBR_ANY,
-       [PERF_SAMPLE_BRANCH_USER]       = LBR_USER,
-       [PERF_SAMPLE_BRANCH_KERNEL]     = LBR_KERNEL,
-       [PERF_SAMPLE_BRANCH_HV]         = LBR_IGN,
-       [PERF_SAMPLE_BRANCH_ANY_RETURN] = LBR_RETURN | LBR_REL_JMP
-                                       | LBR_IND_JMP | LBR_FAR,
+static const int nhm_lbr_sel_map[PERF_SAMPLE_BRANCH_MAX_SHIFT] = {
+       [PERF_SAMPLE_BRANCH_ANY_SHIFT]          = LBR_ANY,
+       [PERF_SAMPLE_BRANCH_USER_SHIFT]         = LBR_USER,
+       [PERF_SAMPLE_BRANCH_KERNEL_SHIFT]       = LBR_KERNEL,
+       [PERF_SAMPLE_BRANCH_HV_SHIFT]           = LBR_IGN,
+       [PERF_SAMPLE_BRANCH_ANY_RETURN_SHIFT]   = LBR_RETURN | LBR_REL_JMP
+                                               | LBR_IND_JMP | LBR_FAR,
        /*
         * NHM/WSM erratum: must include REL_JMP+IND_JMP to get CALL branches
         */
-       [PERF_SAMPLE_BRANCH_ANY_CALL] =
+       [PERF_SAMPLE_BRANCH_ANY_CALL_SHIFT] =
         LBR_REL_CALL | LBR_IND_CALL | LBR_REL_JMP | LBR_IND_JMP | LBR_FAR,
        /*
         * NHM/WSM erratum: must include IND_JMP to capture IND_CALL
         */
-       [PERF_SAMPLE_BRANCH_IND_CALL] = LBR_IND_CALL | LBR_IND_JMP,
-       [PERF_SAMPLE_BRANCH_COND]     = LBR_JCC,
+       [PERF_SAMPLE_BRANCH_IND_CALL_SHIFT] = LBR_IND_CALL | LBR_IND_JMP,
+       [PERF_SAMPLE_BRANCH_COND_SHIFT]     = LBR_JCC,
 };
 
-static const int snb_lbr_sel_map[PERF_SAMPLE_BRANCH_MAX] = {
-       [PERF_SAMPLE_BRANCH_ANY]        = LBR_ANY,
-       [PERF_SAMPLE_BRANCH_USER]       = LBR_USER,
-       [PERF_SAMPLE_BRANCH_KERNEL]     = LBR_KERNEL,
-       [PERF_SAMPLE_BRANCH_HV]         = LBR_IGN,
-       [PERF_SAMPLE_BRANCH_ANY_RETURN] = LBR_RETURN | LBR_FAR,
-       [PERF_SAMPLE_BRANCH_ANY_CALL]   = LBR_REL_CALL | LBR_IND_CALL
-                                       | LBR_FAR,
-       [PERF_SAMPLE_BRANCH_IND_CALL]   = LBR_IND_CALL,
-       [PERF_SAMPLE_BRANCH_COND]       = LBR_JCC,
+static const int snb_lbr_sel_map[PERF_SAMPLE_BRANCH_MAX_SHIFT] = {
+       [PERF_SAMPLE_BRANCH_ANY_SHIFT]          = LBR_ANY,
+       [PERF_SAMPLE_BRANCH_USER_SHIFT]         = LBR_USER,
+       [PERF_SAMPLE_BRANCH_KERNEL_SHIFT]       = LBR_KERNEL,
+       [PERF_SAMPLE_BRANCH_HV_SHIFT]           = LBR_IGN,
+       [PERF_SAMPLE_BRANCH_ANY_RETURN_SHIFT]   = LBR_RETURN | LBR_FAR,
+       [PERF_SAMPLE_BRANCH_ANY_CALL_SHIFT]     = LBR_REL_CALL | LBR_IND_CALL
+                                               | LBR_FAR,
+       [PERF_SAMPLE_BRANCH_IND_CALL_SHIFT]     = LBR_IND_CALL,
+       [PERF_SAMPLE_BRANCH_COND_SHIFT]         = LBR_JCC,
+};
+
+static const int hsw_lbr_sel_map[PERF_SAMPLE_BRANCH_MAX_SHIFT] = {
+       [PERF_SAMPLE_BRANCH_ANY_SHIFT]          = LBR_ANY,
+       [PERF_SAMPLE_BRANCH_USER_SHIFT]         = LBR_USER,
+       [PERF_SAMPLE_BRANCH_KERNEL_SHIFT]       = LBR_KERNEL,
+       [PERF_SAMPLE_BRANCH_HV_SHIFT]           = LBR_IGN,
+       [PERF_SAMPLE_BRANCH_ANY_RETURN_SHIFT]   = LBR_RETURN | LBR_FAR,
+       [PERF_SAMPLE_BRANCH_ANY_CALL_SHIFT]     = LBR_REL_CALL | LBR_IND_CALL
+                                               | LBR_FAR,
+       [PERF_SAMPLE_BRANCH_IND_CALL_SHIFT]     = LBR_IND_CALL,
+       [PERF_SAMPLE_BRANCH_COND_SHIFT]         = LBR_JCC,
+       [PERF_SAMPLE_BRANCH_CALL_STACK_SHIFT]   = LBR_REL_CALL | LBR_IND_CALL
+                                               | LBR_RETURN | LBR_CALL_STACK,
 };
 
 /* core */
@@ -765,6 +922,20 @@ void __init intel_pmu_lbr_init_snb(void)
        pr_cont("16-deep LBR, ");
 }
 
+/* haswell */
+void intel_pmu_lbr_init_hsw(void)
+{
+       x86_pmu.lbr_nr   = 16;
+       x86_pmu.lbr_tos  = MSR_LBR_TOS;
+       x86_pmu.lbr_from = MSR_LBR_NHM_FROM;
+       x86_pmu.lbr_to   = MSR_LBR_NHM_TO;
+
+       x86_pmu.lbr_sel_mask = LBR_SEL_MASK;
+       x86_pmu.lbr_sel_map  = hsw_lbr_sel_map;
+
+       pr_cont("16-deep LBR, ");
+}
+
 /* atom */
 void __init intel_pmu_lbr_init_atom(void)
 {
index 21af614..12d9548 100644 (file)
@@ -1132,8 +1132,7 @@ static int snbep_pci2phy_map_init(int devid)
                }
        }
 
-       if (ubox_dev)
-               pci_dev_put(ubox_dev);
+       pci_dev_put(ubox_dev);
 
        return err ? pcibios_err_to_errno(err) : 0;
 }
index 2b62198..a503100 100644 (file)
@@ -262,9 +262,15 @@ struct pmu {
        int (*event_idx)                (struct perf_event *event); /*optional */
 
        /*
-        * flush branch stack on context-switches (needed in cpu-wide mode)
+        * context-switches callback
         */
-       void (*flush_branch_stack)      (void);
+       void (*sched_task)              (struct perf_event_context *ctx,
+                                       bool sched_in);
+       /*
+        * PMU specific data size
+        */
+       size_t                          task_ctx_size;
+
 };
 
 /**
@@ -300,6 +306,7 @@ struct swevent_hlist {
 #define PERF_ATTACH_CONTEXT    0x01
 #define PERF_ATTACH_GROUP      0x02
 #define PERF_ATTACH_TASK       0x04
+#define PERF_ATTACH_TASK_DATA  0x08
 
 struct perf_cgroup;
 struct ring_buffer;
@@ -504,7 +511,7 @@ struct perf_event_context {
        u64                             generation;
        int                             pin_count;
        int                             nr_cgroups;      /* cgroup evts */
-       int                             nr_branch_stack; /* branch_stack evt */
+       void                            *task_ctx_data; /* pmu specific data */
        struct rcu_head                 rcu_head;
 
        struct delayed_work             orphans_remove;
@@ -558,6 +565,8 @@ extern void perf_event_delayed_put(struct task_struct *task);
 extern void perf_event_print_debug(void);
 extern void perf_pmu_disable(struct pmu *pmu);
 extern void perf_pmu_enable(struct pmu *pmu);
+extern void perf_sched_cb_dec(struct pmu *pmu);
+extern void perf_sched_cb_inc(struct pmu *pmu);
 extern int perf_event_task_disable(void);
 extern int perf_event_task_enable(void);
 extern int perf_event_refresh(struct perf_event *event, int refresh);
@@ -800,6 +809,11 @@ static inline bool has_branch_stack(struct perf_event *event)
        return event->attr.sample_type & PERF_SAMPLE_BRANCH_STACK;
 }
 
+static inline bool needs_branch_stack(struct perf_event *event)
+{
+       return event->attr.branch_sample_type != 0;
+}
+
 extern int perf_output_begin(struct perf_output_handle *handle,
                             struct perf_event *event, unsigned int size);
 extern void perf_output_end(struct perf_output_handle *handle);
index 9b79abb..1e3cd07 100644 (file)
@@ -152,21 +152,42 @@ enum perf_event_sample_format {
  * The branch types can be combined, however BRANCH_ANY covers all types
  * of branches and therefore it supersedes all the other types.
  */
+enum perf_branch_sample_type_shift {
+       PERF_SAMPLE_BRANCH_USER_SHIFT           = 0, /* user branches */
+       PERF_SAMPLE_BRANCH_KERNEL_SHIFT         = 1, /* kernel branches */
+       PERF_SAMPLE_BRANCH_HV_SHIFT             = 2, /* hypervisor branches */
+
+       PERF_SAMPLE_BRANCH_ANY_SHIFT            = 3, /* any branch types */
+       PERF_SAMPLE_BRANCH_ANY_CALL_SHIFT       = 4, /* any call branch */
+       PERF_SAMPLE_BRANCH_ANY_RETURN_SHIFT     = 5, /* any return branch */
+       PERF_SAMPLE_BRANCH_IND_CALL_SHIFT       = 6, /* indirect calls */
+       PERF_SAMPLE_BRANCH_ABORT_TX_SHIFT       = 7, /* transaction aborts */
+       PERF_SAMPLE_BRANCH_IN_TX_SHIFT          = 8, /* in transaction */
+       PERF_SAMPLE_BRANCH_NO_TX_SHIFT          = 9, /* not in transaction */
+       PERF_SAMPLE_BRANCH_COND_SHIFT           = 10, /* conditional branches */
+
+       PERF_SAMPLE_BRANCH_CALL_STACK_SHIFT     = 11, /* call/ret stack */
+
+       PERF_SAMPLE_BRANCH_MAX_SHIFT            /* non-ABI */
+};
+
 enum perf_branch_sample_type {
-       PERF_SAMPLE_BRANCH_USER         = 1U << 0, /* user branches */
-       PERF_SAMPLE_BRANCH_KERNEL       = 1U << 1, /* kernel branches */
-       PERF_SAMPLE_BRANCH_HV           = 1U << 2, /* hypervisor branches */
-
-       PERF_SAMPLE_BRANCH_ANY          = 1U << 3, /* any branch types */
-       PERF_SAMPLE_BRANCH_ANY_CALL     = 1U << 4, /* any call branch */
-       PERF_SAMPLE_BRANCH_ANY_RETURN   = 1U << 5, /* any return branch */
-       PERF_SAMPLE_BRANCH_IND_CALL     = 1U << 6, /* indirect calls */
-       PERF_SAMPLE_BRANCH_ABORT_TX     = 1U << 7, /* transaction aborts */
-       PERF_SAMPLE_BRANCH_IN_TX        = 1U << 8, /* in transaction */
-       PERF_SAMPLE_BRANCH_NO_TX        = 1U << 9, /* not in transaction */
-       PERF_SAMPLE_BRANCH_COND         = 1U << 10, /* conditional branches */
-
-       PERF_SAMPLE_BRANCH_MAX          = 1U << 11, /* non-ABI */
+       PERF_SAMPLE_BRANCH_USER         = 1U << PERF_SAMPLE_BRANCH_USER_SHIFT,
+       PERF_SAMPLE_BRANCH_KERNEL       = 1U << PERF_SAMPLE_BRANCH_KERNEL_SHIFT,
+       PERF_SAMPLE_BRANCH_HV           = 1U << PERF_SAMPLE_BRANCH_HV_SHIFT,
+
+       PERF_SAMPLE_BRANCH_ANY          = 1U << PERF_SAMPLE_BRANCH_ANY_SHIFT,
+       PERF_SAMPLE_BRANCH_ANY_CALL     = 1U << PERF_SAMPLE_BRANCH_ANY_CALL_SHIFT,
+       PERF_SAMPLE_BRANCH_ANY_RETURN   = 1U << PERF_SAMPLE_BRANCH_ANY_RETURN_SHIFT,
+       PERF_SAMPLE_BRANCH_IND_CALL     = 1U << PERF_SAMPLE_BRANCH_IND_CALL_SHIFT,
+       PERF_SAMPLE_BRANCH_ABORT_TX     = 1U << PERF_SAMPLE_BRANCH_ABORT_TX_SHIFT,
+       PERF_SAMPLE_BRANCH_IN_TX        = 1U << PERF_SAMPLE_BRANCH_IN_TX_SHIFT,
+       PERF_SAMPLE_BRANCH_NO_TX        = 1U << PERF_SAMPLE_BRANCH_NO_TX_SHIFT,
+       PERF_SAMPLE_BRANCH_COND         = 1U << PERF_SAMPLE_BRANCH_COND_SHIFT,
+
+       PERF_SAMPLE_BRANCH_CALL_STACK   = 1U << PERF_SAMPLE_BRANCH_CALL_STACK_SHIFT,
+
+       PERF_SAMPLE_BRANCH_MAX          = 1U << PERF_SAMPLE_BRANCH_MAX_SHIFT,
 };
 
 #define PERF_SAMPLE_BRANCH_PLM_ALL \
index f04daab..af924bc 100644 (file)
@@ -153,7 +153,7 @@ enum event_type_t {
  */
 struct static_key_deferred perf_sched_events __read_mostly;
 static DEFINE_PER_CPU(atomic_t, perf_cgroup_events);
-static DEFINE_PER_CPU(atomic_t, perf_branch_stack_events);
+static DEFINE_PER_CPU(int, perf_sched_cb_usages);
 
 static atomic_t nr_mmap_events __read_mostly;
 static atomic_t nr_comm_events __read_mostly;
@@ -905,6 +905,15 @@ static void get_ctx(struct perf_event_context *ctx)
        WARN_ON(!atomic_inc_not_zero(&ctx->refcount));
 }
 
+static void free_ctx(struct rcu_head *head)
+{
+       struct perf_event_context *ctx;
+
+       ctx = container_of(head, struct perf_event_context, rcu_head);
+       kfree(ctx->task_ctx_data);
+       kfree(ctx);
+}
+
 static void put_ctx(struct perf_event_context *ctx)
 {
        if (atomic_dec_and_test(&ctx->refcount)) {
@@ -912,7 +921,7 @@ static void put_ctx(struct perf_event_context *ctx)
                        put_ctx(ctx->parent_ctx);
                if (ctx->task)
                        put_task_struct(ctx->task);
-               kfree_rcu(ctx, rcu_head);
+               call_rcu(&ctx->rcu_head, free_ctx);
        }
 }
 
@@ -1239,9 +1248,6 @@ list_add_event(struct perf_event *event, struct perf_event_context *ctx)
        if (is_cgroup_event(event))
                ctx->nr_cgroups++;
 
-       if (has_branch_stack(event))
-               ctx->nr_branch_stack++;
-
        list_add_rcu(&event->event_entry, &ctx->event_list);
        ctx->nr_events++;
        if (event->attr.inherit_stat)
@@ -1408,9 +1414,6 @@ list_del_event(struct perf_event *event, struct perf_event_context *ctx)
                        cpuctx->cgrp = NULL;
        }
 
-       if (has_branch_stack(event))
-               ctx->nr_branch_stack--;
-
        ctx->nr_events--;
        if (event->attr.inherit_stat)
                ctx->nr_stat--;
@@ -1881,6 +1884,10 @@ event_sched_in(struct perf_event *event,
 
        perf_pmu_disable(event->pmu);
 
+       event->tstamp_running += tstamp - event->tstamp_stopped;
+
+       perf_set_shadow_time(event, ctx, tstamp);
+
        if (event->pmu->add(event, PERF_EF_START)) {
                event->state = PERF_EVENT_STATE_INACTIVE;
                event->oncpu = -1;
@@ -1888,10 +1895,6 @@ event_sched_in(struct perf_event *event,
                goto out;
        }
 
-       event->tstamp_running += tstamp - event->tstamp_stopped;
-
-       perf_set_shadow_time(event, ctx, tstamp);
-
        if (!is_software_event(event))
                cpuctx->active_oncpu++;
        if (!ctx->nr_active++)
@@ -2559,6 +2562,9 @@ static void perf_event_context_sched_out(struct task_struct *task, int ctxn,
                        next->perf_event_ctxp[ctxn] = ctx;
                        ctx->task = next;
                        next_ctx->task = task;
+
+                       swap(ctx->task_ctx_data, next_ctx->task_ctx_data);
+
                        do_switch = 0;
 
                        perf_event_sync_stat(ctx, next_ctx);
@@ -2577,6 +2583,56 @@ unlock:
        }
 }
 
+void perf_sched_cb_dec(struct pmu *pmu)
+{
+       this_cpu_dec(perf_sched_cb_usages);
+}
+
+void perf_sched_cb_inc(struct pmu *pmu)
+{
+       this_cpu_inc(perf_sched_cb_usages);
+}
+
+/*
+ * This function provides the context switch callback to the lower code
+ * layer. It is invoked ONLY when the context switch callback is enabled.
+ */
+static void perf_pmu_sched_task(struct task_struct *prev,
+                               struct task_struct *next,
+                               bool sched_in)
+{
+       struct perf_cpu_context *cpuctx;
+       struct pmu *pmu;
+       unsigned long flags;
+
+       if (prev == next)
+               return;
+
+       local_irq_save(flags);
+
+       rcu_read_lock();
+
+       list_for_each_entry_rcu(pmu, &pmus, entry) {
+               if (pmu->sched_task) {
+                       cpuctx = this_cpu_ptr(pmu->pmu_cpu_context);
+
+                       perf_ctx_lock(cpuctx, cpuctx->task_ctx);
+
+                       perf_pmu_disable(pmu);
+
+                       pmu->sched_task(cpuctx->task_ctx, sched_in);
+
+                       perf_pmu_enable(pmu);
+
+                       perf_ctx_unlock(cpuctx, cpuctx->task_ctx);
+               }
+       }
+
+       rcu_read_unlock();
+
+       local_irq_restore(flags);
+}
+
 #define for_each_task_context_nr(ctxn)                                 \
        for ((ctxn) = 0; (ctxn) < perf_nr_task_contexts; (ctxn)++)
 
@@ -2596,6 +2652,9 @@ void __perf_event_task_sched_out(struct task_struct *task,
 {
        int ctxn;
 
+       if (__this_cpu_read(perf_sched_cb_usages))
+               perf_pmu_sched_task(task, next, false);
+
        for_each_task_context_nr(ctxn)
                perf_event_context_sched_out(task, ctxn, next);
 
@@ -2754,64 +2813,6 @@ static void perf_event_context_sched_in(struct perf_event_context *ctx,
        perf_ctx_unlock(cpuctx, ctx);
 }
 
-/*
- * When sampling the branck stack in system-wide, it may be necessary
- * to flush the stack on context switch. This happens when the branch
- * stack does not tag its entries with the pid of the current task.
- * Otherwise it becomes impossible to associate a branch entry with a
- * task. This ambiguity is more likely to appear when the branch stack
- * supports priv level filtering and the user sets it to monitor only
- * at the user level (which could be a useful measurement in system-wide
- * mode). In that case, the risk is high of having a branch stack with
- * branch from multiple tasks. Flushing may mean dropping the existing
- * entries or stashing them somewhere in the PMU specific code layer.
- *
- * This function provides the context switch callback to the lower code
- * layer. It is invoked ONLY when there is at least one system-wide context
- * with at least one active event using taken branch sampling.
- */
-static void perf_branch_stack_sched_in(struct task_struct *prev,
-                                      struct task_struct *task)
-{
-       struct perf_cpu_context *cpuctx;
-       struct pmu *pmu;
-       unsigned long flags;
-
-       /* no need to flush branch stack if not changing task */
-       if (prev == task)
-               return;
-
-       local_irq_save(flags);
-
-       rcu_read_lock();
-
-       list_for_each_entry_rcu(pmu, &pmus, entry) {
-               cpuctx = this_cpu_ptr(pmu->pmu_cpu_context);
-
-               /*
-                * check if the context has at least one
-                * event using PERF_SAMPLE_BRANCH_STACK
-                */
-               if (cpuctx->ctx.nr_branch_stack > 0
-                   && pmu->flush_branch_stack) {
-
-                       perf_ctx_lock(cpuctx, cpuctx->task_ctx);
-
-                       perf_pmu_disable(pmu);
-
-                       pmu->flush_branch_stack();
-
-                       perf_pmu_enable(pmu);
-
-                       perf_ctx_unlock(cpuctx, cpuctx->task_ctx);
-               }
-       }
-
-       rcu_read_unlock();
-
-       local_irq_restore(flags);
-}
-
 /*
  * Called from scheduler to add the events of the current task
  * with interrupts disabled.
@@ -2844,9 +2845,8 @@ void __perf_event_task_sched_in(struct task_struct *prev,
        if (atomic_read(this_cpu_ptr(&perf_cgroup_events)))
                perf_cgroup_sched_in(prev, task);
 
-       /* check for system-wide branch_stack events */
-       if (atomic_read(this_cpu_ptr(&perf_branch_stack_events)))
-               perf_branch_stack_sched_in(prev, task);
+       if (__this_cpu_read(perf_sched_cb_usages))
+               perf_pmu_sched_task(prev, task, true);
 }
 
 static u64 perf_calculate_period(struct perf_event *event, u64 nsec, u64 count)
@@ -3321,12 +3321,15 @@ errout:
  * Returns a matching context with refcount and pincount.
  */
 static struct perf_event_context *
-find_get_context(struct pmu *pmu, struct task_struct *task, int cpu)
+find_get_context(struct pmu *pmu, struct task_struct *task,
+               struct perf_event *event)
 {
        struct perf_event_context *ctx, *clone_ctx = NULL;
        struct perf_cpu_context *cpuctx;
+       void *task_ctx_data = NULL;
        unsigned long flags;
        int ctxn, err;
+       int cpu = event->cpu;
 
        if (!task) {
                /* Must be root to operate on a CPU event: */
@@ -3354,11 +3357,24 @@ find_get_context(struct pmu *pmu, struct task_struct *task, int cpu)
        if (ctxn < 0)
                goto errout;
 
+       if (event->attach_state & PERF_ATTACH_TASK_DATA) {
+               task_ctx_data = kzalloc(pmu->task_ctx_size, GFP_KERNEL);
+               if (!task_ctx_data) {
+                       err = -ENOMEM;
+                       goto errout;
+               }
+       }
+
 retry:
        ctx = perf_lock_task_context(task, ctxn, &flags);
        if (ctx) {
                clone_ctx = unclone_ctx(ctx);
                ++ctx->pin_count;
+
+               if (task_ctx_data && !ctx->task_ctx_data) {
+                       ctx->task_ctx_data = task_ctx_data;
+                       task_ctx_data = NULL;
+               }
                raw_spin_unlock_irqrestore(&ctx->lock, flags);
 
                if (clone_ctx)
@@ -3369,6 +3385,11 @@ retry:
                if (!ctx)
                        goto errout;
 
+               if (task_ctx_data) {
+                       ctx->task_ctx_data = task_ctx_data;
+                       task_ctx_data = NULL;
+               }
+
                err = 0;
                mutex_lock(&task->perf_event_mutex);
                /*
@@ -3395,9 +3416,11 @@ retry:
                }
        }
 
+       kfree(task_ctx_data);
        return ctx;
 
 errout:
+       kfree(task_ctx_data);
        return ERR_PTR(err);
 }
 
@@ -3423,10 +3446,6 @@ static void unaccount_event_cpu(struct perf_event *event, int cpu)
        if (event->parent)
                return;
 
-       if (has_branch_stack(event)) {
-               if (!(event->attach_state & PERF_ATTACH_TASK))
-                       atomic_dec(&per_cpu(perf_branch_stack_events, cpu));
-       }
        if (is_cgroup_event(event))
                atomic_dec(&per_cpu(perf_cgroup_events, cpu));
 }
@@ -4427,7 +4446,7 @@ static int perf_mmap(struct file *file, struct vm_area_struct *vma)
         * If we have rb pages ensure they're a power-of-two number, so we
         * can do bitmasks instead of modulo.
         */
-       if (nr_pages != 0 && !is_power_of_2(nr_pages))
+       if (!is_power_of_2(nr_pages))
                return -EINVAL;
 
        if (vma_size != PAGE_SIZE * (1 + nr_pages))
@@ -6123,6 +6142,7 @@ static int perf_swevent_add(struct perf_event *event, int flags)
        }
 
        hlist_add_head_rcu(&event->hlist_entry, head);
+       perf_event_update_userpage(event);
 
        return 0;
 }
@@ -6592,6 +6612,7 @@ static int cpu_clock_event_add(struct perf_event *event, int flags)
 {
        if (flags & PERF_EF_START)
                cpu_clock_event_start(event, flags);
+       perf_event_update_userpage(event);
 
        return 0;
 }
@@ -6666,6 +6687,7 @@ static int task_clock_event_add(struct perf_event *event, int flags)
 {
        if (flags & PERF_EF_START)
                task_clock_event_start(event, flags);
+       perf_event_update_userpage(event);
 
        return 0;
 }
@@ -7079,10 +7101,6 @@ static void account_event_cpu(struct perf_event *event, int cpu)
        if (event->parent)
                return;
 
-       if (has_branch_stack(event)) {
-               if (!(event->attach_state & PERF_ATTACH_TASK))
-                       atomic_inc(&per_cpu(perf_branch_stack_events, cpu));
-       }
        if (is_cgroup_event(event))
                atomic_inc(&per_cpu(perf_cgroup_events, cpu));
 }
@@ -7214,6 +7232,9 @@ perf_event_alloc(struct perf_event_attr *attr, int cpu,
        if (attr->inherit && (attr->read_format & PERF_FORMAT_GROUP))
                goto err_ns;
 
+       if (!has_branch_stack(event))
+               event->attr.branch_sample_type = 0;
+
        pmu = perf_init_event(event);
        if (!pmu)
                goto err_ns;
@@ -7576,7 +7597,7 @@ SYSCALL_DEFINE5(perf_event_open,
        /*
         * Get the target context (task or percpu):
         */
-       ctx = find_get_context(pmu, task, event->cpu);
+       ctx = find_get_context(pmu, task, event);
        if (IS_ERR(ctx)) {
                err = PTR_ERR(ctx);
                goto err_alloc;
@@ -7782,7 +7803,7 @@ perf_event_create_kernel_counter(struct perf_event_attr *attr, int cpu,
 
        account_event(event);
 
-       ctx = find_get_context(event->pmu, task, cpu);
+       ctx = find_get_context(event->pmu, task, event);
        if (IS_ERR(ctx)) {
                err = PTR_ERR(ctx);
                goto err_free;
diff --git a/tools/build/Build.include b/tools/build/Build.include
new file mode 100644 (file)
index 0000000..4c8daac
--- /dev/null
@@ -0,0 +1,81 @@
+###
+# build: Generic definitions
+#
+#  Lots of this code have been borrowed or heavily inspired from parts
+#  of kbuild code, which is not credited, but mostly developed by:
+#
+#  Copyright (C) Sam Ravnborg <sam@mars.ravnborg.org>, 2015
+#  Copyright (C) Linus Torvalds <torvalds@linux-foundation.org>, 2015
+#
+
+###
+# Convenient variables
+comma   := ,
+squote  := '
+
+###
+# Name of target with a '.' as filename prefix. foo/bar.o => foo/.bar.o
+dot-target = $(dir $@).$(notdir $@)
+
+###
+# filename of target with directory and extension stripped
+basetarget = $(basename $(notdir $@))
+
+###
+# The temporary file to save gcc -MD generated dependencies must not
+# contain a comma
+depfile = $(subst $(comma),_,$(dot-target).d)
+
+###
+# Check if both arguments has same arguments. Result is empty string if equal.
+arg-check = $(strip $(filter-out $(cmd_$(1)), $(cmd_$@)) \
+                    $(filter-out $(cmd_$@),   $(cmd_$(1))) )
+
+###
+# Escape single quote for use in echo statements
+escsq = $(subst $(squote),'\$(squote)',$1)
+
+# Echo command
+# Short version is used, if $(quiet) equals `quiet_', otherwise full one.
+echo-cmd = $(if $($(quiet)cmd_$(1)),\
+           echo '  $(call escsq,$($(quiet)cmd_$(1)))';)
+
+###
+# Replace >$< with >$$< to preserve $ when reloading the .cmd file
+# (needed for make)
+# Replace >#< with >\#< to avoid starting a comment in the .cmd file
+# (needed for make)
+# Replace >'< with >'\''< to be able to enclose the whole string in '...'
+# (needed for the shell)
+make-cmd = $(call escsq,$(subst \#,\\\#,$(subst $$,$$$$,$(cmd_$(1)))))
+
+###
+# Find any prerequisites that is newer than target or that does not exist.
+# PHONY targets skipped in both cases.
+any-prereq = $(filter-out $(PHONY),$?) $(filter-out $(PHONY) $(wildcard $^),$^)
+
+###
+# if_changed_dep  - execute command if any prerequisite is newer than
+#                   target, or command line has changed and update
+#                   dependencies in the cmd file
+if_changed_dep = $(if $(strip $(any-prereq) $(arg-check)),         \
+       @set -e;                                                   \
+       $(echo-cmd) $(cmd_$(1));                                   \
+       cat $(depfile) > $(dot-target).cmd;                        \
+       printf '%s\n' 'cmd_$@ := $(make-cmd)' >> $(dot-target).cmd)
+
+# if_changed      - execute command if any prerequisite is newer than
+#                   target, or command line has changed
+if_changed = $(if $(strip $(any-prereq) $(arg-check)),             \
+       @set -e;                                                   \
+       $(echo-cmd) $(cmd_$(1));                                   \
+       printf '%s\n' 'cmd_$@ := $(make-cmd)' > $(dot-target).cmd)
+
+###
+# C flags to be used in rule definitions, includes:
+# - depfile generation
+# - global $(CFLAGS)
+# - per target C flags
+# - per object C flags
+# - BUILD_STR macro to allow '-D"$(variable)"' constructs
+c_flags = -Wp,-MD,$(depfile),-MT,$@ $(CFLAGS) -D"BUILD_STR(s)=\#s" $(CFLAGS_$(basetarget).o) $(CFLAGS_$(obj))
diff --git a/tools/build/Documentation/Build.txt b/tools/build/Documentation/Build.txt
new file mode 100644 (file)
index 0000000..00ad2d6
--- /dev/null
@@ -0,0 +1,139 @@
+Build Framework
+===============
+
+The perf build framework was adopted from the kernel build system, hence the
+idea and the way how objects are built is the same.
+
+Basically the user provides set of 'Build' files that list objects and
+directories to nest for specific target to be build.
+
+Unlike the kernel we don't have a single build object 'obj-y' list that where
+we setup source objects, but we support more. This allows one 'Build' file to
+carry a sources list for multiple build objects.
+
+a) Build framework makefiles
+----------------------------
+
+The build framework consists of 2 Makefiles:
+
+  Build.include
+  Makefile.build
+
+While the 'Build.include' file contains just some generic definitions, the
+'Makefile.build' file is the makefile used from the outside. It's
+interface/usage is following:
+
+  $ make -f tools/build/Makefile srctree=$(KSRC) dir=$(DIR) obj=$(OBJECT)
+
+where:
+
+  KSRC   - is the path to kernel sources
+  DIR    - is the path to the project to be built
+  OBJECT - is the name of the build object
+
+When succefully finished the $(DIR) directory contains the final object file
+called $(OBJECT)-in.o:
+
+  $ ls $(DIR)/$(OBJECT)-in.o
+
+which includes all compiled sources described in 'Build' makefiles.
+
+a) Build makefiles
+------------------
+
+The user supplies 'Build' makefiles that contains a objects list, and connects
+the build to nested directories.
+
+Assume we have the following project structure:
+
+  ex/a.c
+    /b.c
+    /c.c
+    /d.c
+    /arch/e.c
+    /arch/f.c
+
+Out of which you build the 'ex' binary ' and the 'libex.a' library:
+
+  'ex'      - consists of 'a.o', 'b.o' and libex.a
+  'libex.a' - consists of 'c.o', 'd.o', 'e.o' and 'f.o'
+
+The build framework does not create the 'ex' and 'libex.a' binaries for you, it
+only prepares proper objects to be compiled and grouped together.
+
+To follow the above example, the user provides following 'Build' files:
+
+  ex/Build:
+    ex-y += a.o
+    ex-y += b.o
+
+    libex-y += c.o
+    libex-y += d.o
+    libex-y += arch/
+
+  ex/arch/Build:
+    libex-y += e.o
+    libex-y += f.o
+
+and runs:
+
+  $ make -f tools/build/Makefile.build dir=. obj=ex
+  $ make -f tools/build/Makefile.build dir=. obj=libex
+
+which creates the following objects:
+
+  ex/ex-in.o
+  ex/libex-in.o
+
+that contain request objects names in Build files.
+
+It's only a matter of 2 single commands to create the final binaries:
+
+  $ ar  rcs libex.a libex-in.o
+  $ gcc -o ex ex-in.o libex.a
+
+You can check the 'ex' example in 'tools/build/tests/ex' for more details.
+
+b) Rules
+--------
+
+The build framework provides standard compilation rules to handle .S and .c
+compilation.
+
+It's possible to include special rule if needed (like we do for flex or bison
+code generation).
+
+c) CFLAGS
+---------
+
+It's possible to alter the standard object C flags in the following way:
+
+  CFLAGS_perf.o += '...' - alters CFLAGS for perf.o object
+  CFLAGS_gtk += '...'    - alters CFLAGS for gtk build object
+
+This C flags changes has the scope of the Build makefile they are defined in.
+
+
+d) Dependencies
+---------------
+
+For each built object file 'a.o' the '.a.cmd' is created and holds:
+
+  - Command line used to built that object
+    (for each object)
+
+  - Dependency rules generated by 'gcc -Wp,-MD,...'
+    (for compiled object)
+
+All existing '.cmd' files are included in the Build process to follow properly
+the dependencies and trigger a rebuild when necessary.
+
+
+e) Single rules
+---------------
+
+It's possible to build single object file by choice, like:
+
+  $ make util/map.o    # objects
+  $ make util/map.i    # preprocessor
+  $ make util/map.s    # assembly
diff --git a/tools/build/Makefile.build b/tools/build/Makefile.build
new file mode 100644 (file)
index 0000000..10df572
--- /dev/null
@@ -0,0 +1,130 @@
+###
+# Main build makefile.
+#
+#  Lots of this code have been borrowed or heavily inspired from parts
+#  of kbuild code, which is not credited, but mostly developed by:
+#
+#  Copyright (C) Sam Ravnborg <sam@mars.ravnborg.org>, 2015
+#  Copyright (C) Linus Torvalds <torvalds@linux-foundation.org>, 2015
+#
+
+PHONY := __build
+__build:
+
+ifeq ($(V),1)
+  quiet =
+  Q =
+else
+  quiet=quiet_
+  Q=@
+endif
+
+build-dir := $(srctree)/tools/build
+
+# Generic definitions
+include $(build-dir)/Build.include
+
+# do not force detected configuration
+-include .config-detected
+
+# Init all relevant variables used in build files so
+# 1) they have correct type
+# 2) they do not inherit any value from the environment
+subdir-y     :=
+obj-y        :=
+subdir-y     :=
+subdir-obj-y :=
+
+# Build definitions
+build-file := $(dir)/Build
+include $(build-file)
+
+quiet_cmd_flex  = FLEX     $@
+quiet_cmd_bison = BISON    $@
+
+# Create directory unless it exists
+quiet_cmd_mkdir = MKDIR    $(dir $@)
+      cmd_mkdir = mkdir -p $(dir $@)
+     rule_mkdir = $(if $(wildcard $(dir $@)),,@$(call echo-cmd,mkdir) $(cmd_mkdir))
+
+# Compile command
+quiet_cmd_cc_o_c = CC       $@
+      cmd_cc_o_c = $(CC) $(c_flags) -c -o $@ $<
+
+quiet_cmd_cc_i_c = CPP      $@
+      cmd_cc_i_c = $(CC) $(c_flags) -E -o $@ $<
+
+quiet_cmd_cc_s_c = AS       $@
+      cmd_cc_s_c = $(CC) $(c_flags) -S -o $@ $<
+
+# Link agregate command
+# If there's nothing to link, create empty $@ object.
+quiet_cmd_ld_multi = LD       $@
+      cmd_ld_multi = $(if $(strip $(obj-y)),\
+                      $(LD) -r -o $@ $(obj-y),rm -f $@; $(AR) rcs $@)
+
+# Build rules
+$(OUTPUT)%.o: %.c FORCE
+       $(call rule_mkdir)
+       $(call if_changed_dep,cc_o_c)
+
+$(OUTPUT)%.o: %.S FORCE
+       $(call rule_mkdir)
+       $(call if_changed_dep,cc_o_c)
+
+$(OUTPUT)%.i: %.c FORCE
+       $(call rule_mkdir)
+       $(call if_changed_dep,cc_i_c)
+
+$(OUTPUT)%.i: %.S FORCE
+       $(call rule_mkdir)
+       $(call if_changed_dep,cc_i_c)
+
+$(OUTPUT)%.s: %.c FORCE
+       $(call rule_mkdir)
+       $(call if_changed_dep,cc_s_c)
+
+# Gather build data:
+#   obj-y        - list of build objects
+#   subdir-y     - list of directories to nest
+#   subdir-obj-y - list of directories objects 'dir/$(obj)-in.o'
+obj-y        := $($(obj)-y)
+subdir-y     := $(patsubst %/,%,$(filter %/, $(obj-y)))
+obj-y        := $(patsubst %/, %/$(obj)-in.o, $(obj-y))
+subdir-obj-y := $(filter %/$(obj)-in.o, $(obj-y))
+
+# '$(OUTPUT)/dir' prefix to all objects
+prefix       := $(subst ./,,$(OUTPUT)$(dir)/)
+obj-y        := $(addprefix $(prefix),$(obj-y))
+subdir-obj-y := $(addprefix $(prefix),$(subdir-obj-y))
+
+# Final '$(obj)-in.o' object
+in-target := $(prefix)$(obj)-in.o
+
+PHONY += $(subdir-y)
+
+$(subdir-y):
+       $(Q)$(MAKE) -f $(build-dir)/Makefile.build dir=$(dir)/$@ obj=$(obj)
+
+$(sort $(subdir-obj-y)): $(subdir-y) ;
+
+$(in-target): $(obj-y) FORCE
+       $(call rule_mkdir)
+       $(call if_changed,ld_multi)
+
+__build: $(in-target)
+       @:
+
+PHONY += FORCE
+FORCE:
+
+# Include all cmd files to get all the dependency rules
+# for all objects included
+targets   := $(wildcard $(sort $(obj-y) $(in-target) $(MAKECMDGOALS)))
+cmd_files := $(wildcard $(foreach f,$(targets),$(dir $(f)).$(notdir $(f)).cmd))
+
+ifneq ($(cmd_files),)
+  include $(cmd_files)
+endif
+
+.PHONY: $(PHONY)
diff --git a/tools/build/tests/ex/Build b/tools/build/tests/ex/Build
new file mode 100644 (file)
index 0000000..0e6c3e6
--- /dev/null
@@ -0,0 +1,8 @@
+ex-y += ex.o
+ex-y += a.o
+ex-y += b.o
+ex-y += empty/
+
+libex-y += c.o
+libex-y += d.o
+libex-y += arch/
diff --git a/tools/build/tests/ex/Makefile b/tools/build/tests/ex/Makefile
new file mode 100644 (file)
index 0000000..52d2476
--- /dev/null
@@ -0,0 +1,23 @@
+export srctree := ../../../..
+export CC      := gcc
+export LD      := ld
+export AR      := ar
+
+build := -f $(srctree)/tools/build/Makefile.build dir=. obj
+ex: ex-in.o libex-in.o
+       gcc -o $@ $^
+
+ex.%: FORCE
+       make -f $(srctree)/tools/build/Makefile.build dir=. $@
+
+ex-in.o: FORCE
+       make $(build)=ex
+
+libex-in.o: FORCE
+       make $(build)=libex
+
+clean:
+       find . -name '*.o' -delete -o -name '\.*.cmd' -delete -o -name '\.*.d' -delete
+       rm -f ex ex.i ex.s
+
+.PHONY: FORCE
diff --git a/tools/build/tests/ex/a.c b/tools/build/tests/ex/a.c
new file mode 100644 (file)
index 0000000..8517627
--- /dev/null
@@ -0,0 +1,5 @@
+
+int a(void)
+{
+       return 0;
+}
diff --git a/tools/build/tests/ex/arch/Build b/tools/build/tests/ex/arch/Build
new file mode 100644 (file)
index 0000000..5550618
--- /dev/null
@@ -0,0 +1,2 @@
+libex-y += e.o
+libex-y += f.o
diff --git a/tools/build/tests/ex/arch/e.c b/tools/build/tests/ex/arch/e.c
new file mode 100644 (file)
index 0000000..beaa4a1
--- /dev/null
@@ -0,0 +1,5 @@
+
+int e(void)
+{
+       return 0;
+}
diff --git a/tools/build/tests/ex/arch/f.c b/tools/build/tests/ex/arch/f.c
new file mode 100644 (file)
index 0000000..7c3e9e9
--- /dev/null
@@ -0,0 +1,5 @@
+
+int f(void)
+{
+       return 0;
+}
diff --git a/tools/build/tests/ex/b.c b/tools/build/tests/ex/b.c
new file mode 100644 (file)
index 0000000..c24ff9c
--- /dev/null
@@ -0,0 +1,5 @@
+
+int b(void)
+{
+       return 0;
+}
diff --git a/tools/build/tests/ex/c.c b/tools/build/tests/ex/c.c
new file mode 100644 (file)
index 0000000..e216d02
--- /dev/null
@@ -0,0 +1,5 @@
+
+int c(void)
+{
+       return 0;
+}
diff --git a/tools/build/tests/ex/d.c b/tools/build/tests/ex/d.c
new file mode 100644 (file)
index 0000000..80dc0f0
--- /dev/null
@@ -0,0 +1,5 @@
+
+int d(void)
+{
+       return 0;
+}
diff --git a/tools/build/tests/ex/empty/Build b/tools/build/tests/ex/empty/Build
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/tools/build/tests/ex/ex.c b/tools/build/tests/ex/ex.c
new file mode 100644 (file)
index 0000000..dc42eb2
--- /dev/null
@@ -0,0 +1,19 @@
+
+int a(void);
+int b(void);
+int c(void);
+int d(void);
+int e(void);
+int f(void);
+
+int main(void)
+{
+       a();
+       b();
+       c();
+       d();
+       e();
+       f();
+
+       return 0;
+}
diff --git a/tools/build/tests/run.sh b/tools/build/tests/run.sh
new file mode 100755 (executable)
index 0000000..5494f8e
--- /dev/null
@@ -0,0 +1,42 @@
+#!/bin/sh
+
+function test_ex {
+       make -C ex V=1 clean > ex.out 2>&1
+       make -C ex V=1 >> ex.out 2>&1
+
+       if [ ! -x ./ex/ex ]; then
+         echo FAILED
+         exit -1
+       fi
+
+       make -C ex V=1 clean > /dev/null 2>&1
+       rm -f ex.out
+}
+
+function test_ex_suffix {
+       make -C ex V=1 clean > ex.out 2>&1
+
+       # use -rR to disable make's builtin rules
+       make -rR -C ex V=1 ex.o >> ex.out 2>&1
+       make -rR -C ex V=1 ex.i >> ex.out 2>&1
+       make -rR -C ex V=1 ex.s >> ex.out 2>&1
+
+       if [ -x ./ex/ex ]; then
+         echo FAILED
+         exit -1
+       fi
+
+       if [ ! -f ./ex/ex.o -o ! -f ./ex/ex.i -o ! -f ./ex/ex.s ]; then
+         echo FAILED
+         exit -1
+       fi
+
+       make -C ex V=1 clean > /dev/null 2>&1
+       rm -f ex.out
+}
+echo -n Testing..
+
+test_ex
+test_ex_suffix
+
+echo OK
diff --git a/tools/lib/api/Build b/tools/lib/api/Build
new file mode 100644 (file)
index 0000000..3653965
--- /dev/null
@@ -0,0 +1,2 @@
+libapi-y += fd/
+libapi-y += fs/
index 36c08b1..d8fe29f 100644 (file)
@@ -1,49 +1,43 @@
 include ../../scripts/Makefile.include
 include ../../perf/config/utilities.mak                # QUIET_CLEAN
 
+ifeq ($(srctree),)
+srctree := $(patsubst %/,%,$(dir $(shell pwd)))
+srctree := $(patsubst %/,%,$(dir $(srctree)))
+srctree := $(patsubst %/,%,$(dir $(srctree)))
+#$(info Determined 'srctree' to be $(srctree))
+endif
+
 CC = $(CROSS_COMPILE)gcc
 AR = $(CROSS_COMPILE)ar
 
-# guard against environment variables
-LIB_H=
-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
+MAKEFLAGS += --no-print-directory
 
-LIBFILE = libapikfs.a
+LIBFILE = $(OUTPUT)libapi.a
 
-CFLAGS = -ggdb3 -Wall -Wextra -std=gnu99 -Werror -O6 -D_FORTIFY_SOURCE=2 $(EXTRA_WARNINGS) $(EXTRA_CFLAGS) -fPIC
-EXTLIBS = -lelf -lpthread -lrt -lm
-ALL_CFLAGS = $(CFLAGS) $(BASIC_CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64
-ALL_LDFLAGS = $(LDFLAGS)
+CFLAGS := $(EXTRA_WARNINGS) $(EXTRA_CFLAGS)
+CFLAGS += -ggdb3 -Wall -Wextra -std=gnu99 -Werror -O6 -D_FORTIFY_SOURCE=2 -fPIC
+CFLAGS += -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64
 
 RM = rm -f
 
-$(LIBFILE): $(LIB_OBJS)
-       $(QUIET_AR)$(RM) $@ && $(AR) rcs $(OUTPUT)$@ $(LIB_OBJS)
+build  := -f $(srctree)/tools/build/Makefile.build dir=. obj
+API_IN := $(OUTPUT)libapi-in.o
 
-$(LIB_OBJS): $(LIB_H)
+export srctree OUTPUT CC LD CFLAGS V
 
-libapi_dirs:
-       $(QUIET_MKDIR)mkdir -p $(OUTPUT)fd $(OUTPUT)fs
+all: $(LIBFILE)
 
-$(OUTPUT)%.o: %.c libapi_dirs
-       $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $<
-$(OUTPUT)%.s: %.c libapi_dirs
-       $(QUIET_CC)$(CC) -S $(ALL_CFLAGS) $<
-$(OUTPUT)%.o: %.S libapi_dirs
-       $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $<
+$(API_IN): FORCE
+       @$(MAKE) $(build)=libapi
+
+$(LIBFILE): $(API_IN)
+       $(QUIET_AR)$(RM) $@ && $(AR) rcs $@ $(API_IN)
 
 clean:
-       $(call QUIET_CLEAN, libapi) $(RM) $(LIB_OBJS) $(LIBFILE)
+       $(call QUIET_CLEAN, libapi) $(RM) $(LIBFILE); \
+       find $(if $(OUTPUT),$(OUTPUT),.) -name \*.o | xargs $(RM)
+
+FORCE:
 
-.PHONY: clean
+.PHONY: clean FORCE
diff --git a/tools/lib/api/fd/Build b/tools/lib/api/fd/Build
new file mode 100644 (file)
index 0000000..605d99f
--- /dev/null
@@ -0,0 +1 @@
+libapi-y += array.o
diff --git a/tools/lib/api/fs/Build b/tools/lib/api/fs/Build
new file mode 100644 (file)
index 0000000..6de5a4f
--- /dev/null
@@ -0,0 +1,4 @@
+libapi-y += fs.o
+libapi-y += debugfs.o
+libapi-y += findfs.o
+libapi-y += tracefs.o
index d2b18e8..8305b3e 100644 (file)
@@ -3,75 +3,50 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <unistd.h>
 #include <stdbool.h>
 #include <sys/vfs.h>
+#include <sys/types.h>
+#include <sys/stat.h>
 #include <sys/mount.h>
 #include <linux/kernel.h>
 
 #include "debugfs.h"
 
-char debugfs_mountpoint[PATH_MAX + 1] = "/sys/kernel/debug";
+#ifndef DEBUGFS_DEFAULT_PATH
+#define DEBUGFS_DEFAULT_PATH           "/sys/kernel/debug"
+#endif
+
+char debugfs_mountpoint[PATH_MAX + 1] = DEBUGFS_DEFAULT_PATH;
 
 static const char * const debugfs_known_mountpoints[] = {
-       "/sys/kernel/debug",
+       DEBUGFS_DEFAULT_PATH,
        "/debug",
        0,
 };
 
 static bool debugfs_found;
 
+bool debugfs_configured(void)
+{
+       return debugfs_find_mountpoint() != NULL;
+}
+
 /* find the path to the mounted debugfs */
 const char *debugfs_find_mountpoint(void)
 {
-       const char * const *ptr;
-       char type[100];
-       FILE *fp;
+       const char *ret;
 
        if (debugfs_found)
                return (const char *)debugfs_mountpoint;
 
-       ptr = debugfs_known_mountpoints;
-       while (*ptr) {
-               if (debugfs_valid_mountpoint(*ptr) == 0) {
-                       debugfs_found = true;
-                       strcpy(debugfs_mountpoint, *ptr);
-                       return debugfs_mountpoint;
-               }
-               ptr++;
-       }
-
-       /* give up and parse /proc/mounts */
-       fp = fopen("/proc/mounts", "r");
-       if (fp == NULL)
-               return NULL;
-
-       while (fscanf(fp, "%*s %" STR(PATH_MAX) "s %99s %*s %*d %*d\n",
-                     debugfs_mountpoint, type) == 2) {
-               if (strcmp(type, "debugfs") == 0)
-                       break;
-       }
-       fclose(fp);
+       ret = find_mountpoint("debugfs", (long) DEBUGFS_MAGIC,
+                             debugfs_mountpoint, PATH_MAX + 1,
+                             debugfs_known_mountpoints);
+       if (ret)
+               debugfs_found = true;
 
-       if (strcmp(type, "debugfs") != 0)
-               return NULL;
-
-       debugfs_found = true;
-
-       return debugfs_mountpoint;
-}
-
-/* verify that a mountpoint is actually a debugfs instance */
-
-int debugfs_valid_mountpoint(const char *debugfs)
-{
-       struct statfs st_fs;
-
-       if (statfs(debugfs, &st_fs) < 0)
-               return -ENOENT;
-       else if ((long)st_fs.f_type != (long)DEBUGFS_MAGIC)
-               return -ENOENT;
-
-       return 0;
+       return ret;
 }
 
 /* mount the debugfs somewhere if it's not mounted */
@@ -87,7 +62,7 @@ char *debugfs_mount(const char *mountpoint)
                mountpoint = getenv(PERF_DEBUGFS_ENVIRONMENT);
                /* if no environment variable, use default */
                if (mountpoint == NULL)
-                       mountpoint = "/sys/kernel/debug";
+                       mountpoint = DEBUGFS_DEFAULT_PATH;
        }
 
        if (mount(NULL, mountpoint, "debugfs", 0, NULL) < 0)
index 0739881..4550236 100644 (file)
@@ -1,16 +1,7 @@
 #ifndef __API_DEBUGFS_H__
 #define __API_DEBUGFS_H__
 
-#define _STR(x) #x
-#define STR(x) _STR(x)
-
-/*
- * On most systems <limits.h> would have given us this, but  not on some systems
- * (e.g. GNU/Hurd).
- */
-#ifndef PATH_MAX
-#define PATH_MAX 4096
-#endif
+#include "findfs.h"
 
 #ifndef DEBUGFS_MAGIC
 #define DEBUGFS_MAGIC          0x64626720
@@ -20,8 +11,8 @@
 #define PERF_DEBUGFS_ENVIRONMENT "PERF_DEBUGFS_DIR"
 #endif
 
+bool debugfs_configured(void);
 const char *debugfs_find_mountpoint(void);
-int debugfs_valid_mountpoint(const char *debugfs);
 char *debugfs_mount(const char *mountpoint);
 
 extern char debugfs_mountpoint[];
diff --git a/tools/lib/api/fs/findfs.c b/tools/lib/api/fs/findfs.c
new file mode 100644 (file)
index 0000000..49946cb
--- /dev/null
@@ -0,0 +1,63 @@
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdbool.h>
+#include <sys/vfs.h>
+
+#include "findfs.h"
+
+/* verify that a mountpoint is actually the type we want */
+
+int valid_mountpoint(const char *mount, long magic)
+{
+       struct statfs st_fs;
+
+       if (statfs(mount, &st_fs) < 0)
+               return -ENOENT;
+       else if ((long)st_fs.f_type != magic)
+               return -ENOENT;
+
+       return 0;
+}
+
+/* find the path to a mounted file system */
+const char *find_mountpoint(const char *fstype, long magic,
+                           char *mountpoint, int len,
+                           const char * const *known_mountpoints)
+{
+       const char * const *ptr;
+       char format[128];
+       char type[100];
+       FILE *fp;
+
+       if (known_mountpoints) {
+               ptr = known_mountpoints;
+               while (*ptr) {
+                       if (valid_mountpoint(*ptr, magic) == 0) {
+                               strncpy(mountpoint, *ptr, len - 1);
+                               mountpoint[len-1] = 0;
+                               return mountpoint;
+                       }
+                       ptr++;
+               }
+       }
+
+       /* give up and parse /proc/mounts */
+       fp = fopen("/proc/mounts", "r");
+       if (fp == NULL)
+               return NULL;
+
+       snprintf(format, 128, "%%*s %%%ds %%99s %%*s %%*d %%*d\n", len);
+
+       while (fscanf(fp, format, mountpoint, type) == 2) {
+               if (strcmp(type, fstype) == 0)
+                       break;
+       }
+       fclose(fp);
+
+       if (strcmp(type, fstype) != 0)
+               return NULL;
+
+       return mountpoint;
+}
diff --git a/tools/lib/api/fs/findfs.h b/tools/lib/api/fs/findfs.h
new file mode 100644 (file)
index 0000000..b6f5d05
--- /dev/null
@@ -0,0 +1,23 @@
+#ifndef __API_FINDFS_H__
+#define __API_FINDFS_H__
+
+#include <stdbool.h>
+
+#define _STR(x) #x
+#define STR(x) _STR(x)
+
+/*
+ * On most systems <limits.h> would have given us this, but  not on some systems
+ * (e.g. GNU/Hurd).
+ */
+#ifndef PATH_MAX
+#define PATH_MAX 4096
+#endif
+
+const char *find_mountpoint(const char *fstype, long magic,
+                           char *mountpoint, int len,
+                           const char * const *known_mountpoints);
+
+int valid_mountpoint(const char *mount, long magic);
+
+#endif /* __API_FINDFS_H__ */
diff --git a/tools/lib/api/fs/tracefs.c b/tools/lib/api/fs/tracefs.c
new file mode 100644 (file)
index 0000000..e4aa968
--- /dev/null
@@ -0,0 +1,78 @@
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdbool.h>
+#include <sys/vfs.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mount.h>
+#include <linux/kernel.h>
+
+#include "tracefs.h"
+
+#ifndef TRACEFS_DEFAULT_PATH
+#define TRACEFS_DEFAULT_PATH           "/sys/kernel/tracing"
+#endif
+
+char tracefs_mountpoint[PATH_MAX + 1] = TRACEFS_DEFAULT_PATH;
+
+static const char * const tracefs_known_mountpoints[] = {
+       TRACEFS_DEFAULT_PATH,
+       "/sys/kernel/debug/tracing",
+       "/tracing",
+       "/trace",
+       0,
+};
+
+static bool tracefs_found;
+
+bool tracefs_configured(void)
+{
+       return tracefs_find_mountpoint() != NULL;
+}
+
+/* find the path to the mounted tracefs */
+const char *tracefs_find_mountpoint(void)
+{
+       const char *ret;
+
+       if (tracefs_found)
+               return (const char *)tracefs_mountpoint;
+
+       ret = find_mountpoint("tracefs", (long) TRACEFS_MAGIC,
+                             tracefs_mountpoint, PATH_MAX + 1,
+                             tracefs_known_mountpoints);
+
+       if (ret)
+               tracefs_found = true;
+
+       return ret;
+}
+
+/* mount the tracefs somewhere if it's not mounted */
+char *tracefs_mount(const char *mountpoint)
+{
+       /* see if it's already mounted */
+       if (tracefs_find_mountpoint())
+               goto out;
+
+       /* if not mounted and no argument */
+       if (mountpoint == NULL) {
+               /* see if environment variable set */
+               mountpoint = getenv(PERF_TRACEFS_ENVIRONMENT);
+               /* if no environment variable, use default */
+               if (mountpoint == NULL)
+                       mountpoint = TRACEFS_DEFAULT_PATH;
+       }
+
+       if (mount(NULL, mountpoint, "tracefs", 0, NULL) < 0)
+               return NULL;
+
+       /* save the mountpoint */
+       tracefs_found = true;
+       strncpy(tracefs_mountpoint, mountpoint, sizeof(tracefs_mountpoint));
+out:
+       return tracefs_mountpoint;
+}
diff --git a/tools/lib/api/fs/tracefs.h b/tools/lib/api/fs/tracefs.h
new file mode 100644 (file)
index 0000000..da780ac
--- /dev/null
@@ -0,0 +1,21 @@
+#ifndef __API_TRACEFS_H__
+#define __API_TRACEFS_H__
+
+#include "findfs.h"
+
+#ifndef TRACEFS_MAGIC
+#define TRACEFS_MAGIC          0x74726163
+#endif
+
+#ifndef PERF_TRACEFS_ENVIRONMENT
+#define PERF_TRACEFS_ENVIRONMENT "PERF_TRACEFS_DIR"
+#endif
+
+bool tracefs_configured(void);
+const char *tracefs_find_mountpoint(void);
+int tracefs_valid_mountpoint(const char *debugfs);
+char *tracefs_mount(const char *mountpoint);
+
+extern char tracefs_mountpoint[];
+
+#endif /* __API_DEBUGFS_H__ */
diff --git a/tools/lib/lockdep/Build b/tools/lib/lockdep/Build
new file mode 100644 (file)
index 0000000..6f66735
--- /dev/null
@@ -0,0 +1 @@
+liblockdep-y += common.o lockdep.o preload.o rbtree.o
index 4b866c5..0c356fb 100644 (file)
@@ -35,6 +35,10 @@ bindir = $(prefix)/$(bindir_relative)
 
 export DESTDIR DESTDIR_SQ INSTALL
 
+MAKEFLAGS += --no-print-directory
+
+include ../../scripts/Makefile.include
+
 # copy a bit from Linux kbuild
 
 ifeq ("$(origin V)", "command line")
@@ -44,56 +48,21 @@ ifndef VERBOSE
   VERBOSE = 0
 endif
 
-ifeq ("$(origin O)", "command line")
-  BUILD_OUTPUT := $(O)
+ifeq ($(srctree),)
+srctree := $(patsubst %/,%,$(dir $(shell pwd)))
+srctree := $(patsubst %/,%,$(dir $(srctree)))
+srctree := $(patsubst %/,%,$(dir $(srctree)))
+#$(info Determined 'srctree' to be $(srctree))
 endif
 
-ifeq ($(BUILD_SRC),)
-ifneq ($(BUILD_OUTPUT),)
-
-define build_output
-       $(if $(VERBOSE:1=),@)$(MAKE) -C $(BUILD_OUTPUT) \
-       BUILD_SRC=$(CURDIR) -f $(CURDIR)/Makefile $1
-endef
-
-saved-output := $(BUILD_OUTPUT)
-BUILD_OUTPUT := $(shell cd $(BUILD_OUTPUT) && /bin/pwd)
-$(if $(BUILD_OUTPUT),, \
-     $(error output directory "$(saved-output)" does not exist))
-
-all: sub-make
-
-gui: force
-       $(call build_output, all_cmd)
-
-$(filter-out gui,$(MAKECMDGOALS)): sub-make
-
-sub-make: force
-       $(call build_output, $(MAKECMDGOALS))
-
-
-# Leave processing to above invocation of make
-skip-makefile := 1
-
-endif # BUILD_OUTPUT
-endif # BUILD_SRC
-
-# We process the rest of the Makefile if this is the final invocation of make
-ifeq ($(skip-makefile),)
-
-srctree                := $(realpath $(if $(BUILD_SRC),$(BUILD_SRC),$(CURDIR)))
-objtree                := $(realpath $(CURDIR))
-src            := $(srctree)
-obj            := $(objtree)
-
-export prefix libdir bindir src obj
-
 # Shell quotes
 libdir_SQ = $(subst ','\'',$(libdir))
 bindir_SQ = $(subst ','\'',$(bindir))
 
-LIB_FILE = liblockdep.a liblockdep.so.$(LIBLOCKDEP_VERSION)
+LIB_IN := $(OUTPUT)liblockdep-in.o
+
 BIN_FILE = lockdep
+LIB_FILE = $(OUTPUT)liblockdep.a $(OUTPUT)liblockdep.so.$(LIBLOCKDEP_VERSION)
 
 CONFIG_INCLUDES =
 CONFIG_LIBS    =
@@ -108,33 +77,23 @@ INCLUDES = -I. -I./uinclude -I./include -I../../include $(CONFIG_INCLUDES)
 
 # Set compile option CFLAGS if not set elsewhere
 CFLAGS ?= -g -DCONFIG_LOCKDEP -DCONFIG_STACKTRACE -DCONFIG_PROVE_LOCKING -DBITS_PER_LONG=__WORDSIZE -DLIBLOCKDEP_VERSION='"$(LIBLOCKDEP_VERSION)"' -rdynamic -O0 -g
+CFLAGS += -fPIC
 
 override CFLAGS += $(CONFIG_FLAGS) $(INCLUDES) $(PLUGIN_DIR_SQ)
 
 ifeq ($(VERBOSE),1)
   Q =
-  print_compile =
-  print_app_build =
-  print_fpic_compile =
   print_shared_lib_compile =
   print_install =
 else
   Q = @
-  print_compile =              echo '  CC                 '$(OBJ);
-  print_app_build =            echo '  BUILD              '$(OBJ);
-  print_fpic_compile =         echo '  CC FPIC            '$(OBJ);
-  print_shared_lib_compile =   echo '  BUILD SHARED LIB   '$(OBJ);
-  print_static_lib_build =     echo '  BUILD STATIC LIB   '$(OBJ);
-  print_install =              echo '  INSTALL     '$1'        to      $(DESTDIR_SQ)$2';
+  print_shared_lib_compile =   echo '  LD       '$(OBJ);
+  print_static_lib_build =     echo '  LD       '$(OBJ);
+  print_install =              echo '  INSTALL  '$1'   to      $(DESTDIR_SQ)$2';
 endif
 
-do_fpic_compile =                                      \
-       ($(print_fpic_compile)                          \
-       $(CC) -c $(CFLAGS) $(EXT) -fPIC $< -o $@)
-
-do_app_build =                                         \
-       ($(print_app_build)                             \
-       $(CC) $^ -rdynamic -o $@ $(CONFIG_LIBS) $(LIBS))
+export srctree OUTPUT CC LD CFLAGS V
+build := -f $(srctree)/tools/build/Makefile.build dir=. obj
 
 do_compile_shared_library =                    \
        ($(print_shared_lib_compile)            \
@@ -144,22 +103,6 @@ do_build_static_lib =                              \
        ($(print_static_lib_build)              \
        $(RM) $@;  $(AR) rcs $@ $^)
 
-
-define do_compile
-       $(print_compile)                                                \
-       $(CC) -c $(CFLAGS) $(EXT) $< -o $(obj)/$@;
-endef
-
-$(obj)/%.o: $(src)/%.c
-       $(Q)$(call do_compile)
-
-%.o: $(src)/%.c
-       $(Q)$(call do_compile)
-
-PEVENT_LIB_OBJS = common.o lockdep.o preload.o rbtree.o
-
-ALL_OBJS = $(PEVENT_LIB_OBJS)
-
 CMD_TARGETS = $(LIB_FILE)
 
 TARGETS = $(CMD_TARGETS)
@@ -169,42 +112,15 @@ all: all_cmd
 
 all_cmd: $(CMD_TARGETS)
 
-liblockdep.so.$(LIBLOCKDEP_VERSION): $(PEVENT_LIB_OBJS)
+$(LIB_IN): force
+       $(Q)$(MAKE) $(build)=liblockdep
+
+liblockdep.so.$(LIBLOCKDEP_VERSION): $(LIB_IN)
        $(Q)$(do_compile_shared_library)
 
-liblockdep.a: $(PEVENT_LIB_OBJS)
+liblockdep.a: $(LIB_IN)
        $(Q)$(do_build_static_lib)
 
-$(PEVENT_LIB_OBJS): %.o: $(src)/%.c
-       $(Q)$(do_fpic_compile)
-
-## make deps
-
-all_objs := $(sort $(ALL_OBJS))
-all_deps := $(all_objs:%.o=.%.d)
-
-# let .d file also depends on the source and header files
-define check_deps
-               @set -e; $(RM) $@; \
-               $(CC) -MM $(CFLAGS) $< > $@.$$$$; \
-               sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
-               $(RM) $@.$$$$
-endef
-
-$(all_deps): .%.d: $(src)/%.c
-       $(Q)$(call check_deps)
-
-$(all_objs) : %.o : .%.d
-
-dep_includes := $(wildcard $(all_deps))
-
-ifneq ($(dep_includes),)
- include $(dep_includes)
-endif
-
-### Detect environment changes
-TRACK_CFLAGS = $(subst ','\'',$(CFLAGS)):$(ARCH):$(CROSS_COMPILE)
-
 tags:  force
        $(RM) tags
        find . -name '*.[ch]' | xargs ctags --extra=+f --c-kinds=+px \
@@ -233,8 +149,6 @@ clean:
        $(RM) *.o *~ $(TARGETS) *.a *liblockdep*.so* $(VERSION_FILES) .*.d
        $(RM) tags TAGS
 
-endif # skip-makefile
-
 PHONY += force
 force:
 
diff --git a/tools/lib/traceevent/Build b/tools/lib/traceevent/Build
new file mode 100644 (file)
index 0000000..c681d05
--- /dev/null
@@ -0,0 +1,17 @@
+libtraceevent-y += event-parse.o
+libtraceevent-y += event-plugin.o
+libtraceevent-y += trace-seq.o
+libtraceevent-y += parse-filter.o
+libtraceevent-y += parse-utils.o
+libtraceevent-y += kbuffer-parse.o
+
+plugin_jbd2-y         += plugin_jbd2.o
+plugin_hrtimer-y      += plugin_hrtimer.o
+plugin_kmem-y         += plugin_kmem.o
+plugin_kvm-y          += plugin_kvm.o
+plugin_mac80211-y     += plugin_mac80211.o
+plugin_sched_switch-y += plugin_sched_switch.o
+plugin_function-y     += plugin_function.o
+plugin_xen-y          += plugin_xen.o
+plugin_scsi-y         += plugin_scsi.o
+plugin_cfg80211-y     += plugin_cfg80211.o
index 005c9cc..d410da3 100644 (file)
@@ -67,7 +67,7 @@ PLUGIN_DIR = -DPLUGIN_DIR="$(plugin_dir)"
 PLUGIN_DIR_SQ = '$(subst ','\'',$(PLUGIN_DIR))'
 endif
 
-include $(if $(BUILD_SRC),$(BUILD_SRC)/)../../scripts/Makefile.include
+include ../../scripts/Makefile.include
 
 # copy a bit from Linux kbuild
 
@@ -78,40 +78,13 @@ ifndef VERBOSE
   VERBOSE = 0
 endif
 
-ifeq ("$(origin O)", "command line")
-  BUILD_OUTPUT := $(O)
+ifeq ($(srctree),)
+srctree := $(patsubst %/,%,$(dir $(shell pwd)))
+srctree := $(patsubst %/,%,$(dir $(srctree)))
+srctree := $(patsubst %/,%,$(dir $(srctree)))
+#$(info Determined 'srctree' to be $(srctree))
 endif
 
-ifeq ($(BUILD_SRC),)
-ifneq ($(OUTPUT),)
-
-define build_output
-  $(if $(VERBOSE:1=),@)+$(MAKE) -C $(OUTPUT) \
-  BUILD_SRC=$(CURDIR)/ -f $(CURDIR)/Makefile $1
-endef
-
-all: sub-make
-
-$(MAKECMDGOALS): sub-make
-
-sub-make: force
-       $(call build_output, $(MAKECMDGOALS))
-
-
-# Leave processing to above invocation of make
-skip-makefile := 1
-
-endif # OUTPUT
-endif # BUILD_SRC
-
-# We process the rest of the Makefile if this is the final invocation of make
-ifeq ($(skip-makefile),)
-
-srctree                := $(if $(BUILD_SRC),$(BUILD_SRC),$(CURDIR))
-objtree                := $(CURDIR)
-src            := $(srctree)
-obj            := $(objtree)
-
 export prefix bindir src obj
 
 # Shell quotes
@@ -132,16 +105,19 @@ EXTRAVERSION      = $(EP_EXTRAVERSION)
 OBJ            = $@
 N              =
 
-export Q VERBOSE
-
 EVENT_PARSE_VERSION = $(EP_VERSION).$(EP_PATCHLEVEL).$(EP_EXTRAVERSION)
 
-INCLUDES = -I. -I $(srctree)/../../include $(CONFIG_INCLUDES)
+INCLUDES = -I. -I $(srctree)/tools/include $(CONFIG_INCLUDES)
 
-# Set compile option CFLAGS if not set elsewhere
-CFLAGS ?= -g -Wall
+# Set compile option CFLAGS
+ifdef EXTRA_CFLAGS
+  CFLAGS := $(EXTRA_CFLAGS)
+else
+  CFLAGS := -g -Wall
+endif
 
 # Append required CFLAGS
+override CFLAGS += -fPIC
 override CFLAGS += $(CONFIG_FLAGS) $(INCLUDES) $(PLUGIN_DIR_SQ)
 override CFLAGS += $(udis86-flags) -D_GNU_SOURCE
 
@@ -151,74 +127,58 @@ else
   Q = @
 endif
 
-do_compile_shared_library =                    \
-       ($(print_shared_lib_compile)            \
-       $(CC) --shared $^ -o $@)
-
-do_plugin_build =                              \
-       ($(print_plugin_build)                  \
-       $(CC) $(CFLAGS) -shared -nostartfiles -o $@ $<)
-
-do_build_static_lib =                          \
-       ($(print_static_lib_build)              \
-       $(RM) $@;  $(AR) rcs $@ $^)
-
-
-do_compile = $(QUIET_CC)$(CC) -c $(CFLAGS) $(EXT) $< -o $(obj)/$@;
+# Disable command line variables (CFLAGS) overide from top
+# level Makefile (perf), otherwise build Makefile will get
+# the same command line setup.
+MAKEOVERRIDES=
 
-$(obj)/%.o: $(src)/%.c
-       $(call do_compile)
+export srctree OUTPUT CC LD CFLAGS V
+build := -f $(srctree)/tools/build/Makefile.build dir=. obj
 
-%.o: $(src)/%.c
-       $(call do_compile)
+PLUGINS  = plugin_jbd2.so
+PLUGINS += plugin_hrtimer.so
+PLUGINS += plugin_kmem.so
+PLUGINS += plugin_kvm.so
+PLUGINS += plugin_mac80211.so
+PLUGINS += plugin_sched_switch.so
+PLUGINS += plugin_function.so
+PLUGINS += plugin_xen.so
+PLUGINS += plugin_scsi.so
+PLUGINS += plugin_cfg80211.so
 
-PEVENT_LIB_OBJS  = event-parse.o
-PEVENT_LIB_OBJS += event-plugin.o
-PEVENT_LIB_OBJS += trace-seq.o
-PEVENT_LIB_OBJS += parse-filter.o
-PEVENT_LIB_OBJS += parse-utils.o
-PEVENT_LIB_OBJS += kbuffer-parse.o
+PLUGINS    := $(addprefix $(OUTPUT),$(PLUGINS))
+PLUGINS_IN := $(PLUGINS:.so=-in.o)
 
-PLUGIN_OBJS  = plugin_jbd2.o
-PLUGIN_OBJS += plugin_hrtimer.o
-PLUGIN_OBJS += plugin_kmem.o
-PLUGIN_OBJS += plugin_kvm.o
-PLUGIN_OBJS += plugin_mac80211.o
-PLUGIN_OBJS += plugin_sched_switch.o
-PLUGIN_OBJS += plugin_function.o
-PLUGIN_OBJS += plugin_xen.o
-PLUGIN_OBJS += plugin_scsi.o
-PLUGIN_OBJS += plugin_cfg80211.o
-
-PLUGINS := $(PLUGIN_OBJS:.o=.so)
-
-ALL_OBJS = $(PEVENT_LIB_OBJS) $(PLUGIN_OBJS)
+TE_IN    := $(OUTPUT)libtraceevent-in.o
+LIB_FILE := $(addprefix $(OUTPUT),$(LIB_FILE))
 
 CMD_TARGETS = $(LIB_FILE) $(PLUGINS)
 
 TARGETS = $(CMD_TARGETS)
 
-
 all: all_cmd
 
 all_cmd: $(CMD_TARGETS)
 
-libtraceevent.so: $(PEVENT_LIB_OBJS)
+$(TE_IN): force
+       $(Q)$(MAKE) $(build)=libtraceevent
+
+$(OUTPUT)libtraceevent.so: $(TE_IN)
        $(QUIET_LINK)$(CC) --shared $^ -o $@
 
-libtraceevent.a: $(PEVENT_LIB_OBJS)
+$(OUTPUT)libtraceevent.a: $(TE_IN)
        $(QUIET_LINK)$(RM) $@; $(AR) rcs $@ $^
 
 plugins: $(PLUGINS)
 
-$(PEVENT_LIB_OBJS): %.o: $(src)/%.c TRACEEVENT-CFLAGS
-       $(QUIET_CC_FPIC)$(CC) -c $(CFLAGS) $(EXT) -fPIC $< -o $@
+__plugin_obj = $(notdir $@)
+  plugin_obj = $(__plugin_obj:-in.o=)
 
-$(PLUGIN_OBJS): %.o : $(src)/%.c
-       $(QUIET_CC_FPIC)$(CC) -c $(CFLAGS) -fPIC -o $@ $<
+$(PLUGINS_IN): force
+       $(Q)$(MAKE) $(build)=$(plugin_obj)
 
-$(PLUGINS): %.so: %.o
-       $(QUIET_LINK)$(CC) $(CFLAGS) -shared -nostartfiles -o $@ $<
+$(OUTPUT)%.so: $(OUTPUT)%-in.o
+       $(QUIET_LINK)$(CC) $(CFLAGS) -shared -nostartfiles -o $@ $^
 
 define make_version.h
   (echo '/* This file is automatically generated. Do not modify. */';          \
@@ -255,40 +215,6 @@ define update_dir
    fi);
 endef
 
-## make deps
-
-all_objs := $(sort $(ALL_OBJS))
-all_deps := $(all_objs:%.o=.%.d)
-
-# let .d file also depends on the source and header files
-define check_deps
-  @set -e; $(RM) $@; \
-  $(CC) -MM $(CFLAGS) $< > $@.$$$$; \
-  sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
-  $(RM) $@.$$$$
-endef
-
-$(all_deps): .%.d: $(src)/%.c
-       $(Q)$(call check_deps)
-
-$(all_objs) : %.o : .%.d
-
-dep_includes := $(wildcard $(all_deps))
-
-ifneq ($(dep_includes),)
- include $(dep_includes)
-endif
-
-### Detect environment changes
-TRACK_CFLAGS = $(subst ','\'',$(CFLAGS)):$(ARCH):$(CROSS_COMPILE)
-
-TRACEEVENT-CFLAGS: force
-       @FLAGS='$(TRACK_CFLAGS)'; \
-           if test x"$$FLAGS" != x"`cat TRACEEVENT-CFLAGS 2>/dev/null`" ; then \
-               echo 1>&2 "  FLAGS:   * new build flags or cross compiler"; \
-               echo "$$FLAGS" >TRACEEVENT-CFLAGS; \
-            fi
-
 tags:  force
        $(RM) tags
        find . -name '*.[ch]' | xargs ctags --extra=+f --c-kinds=+px \
@@ -327,14 +253,9 @@ clean:
                $(RM) *.o *~ $(TARGETS) *.a *.so $(VERSION_FILES) .*.d \
                $(RM) TRACEEVENT-CFLAGS tags TAGS
 
-endif # skip-makefile
-
 PHONY += force plugins
 force:
 
-plugins:
-       @echo > /dev/null
-
 # Declare the contents of the .PHONY variable as phony.  We keep that
 # information in a variable so we can use it in if_changed and friends.
 .PHONY: $(PHONY)
index 7a3873f..5b4efc0 100644 (file)
@@ -22,6 +22,7 @@
 
 #include <stdbool.h>
 #include <stdarg.h>
+#include <stdio.h>
 #include <regex.h>
 #include <string.h>
 
@@ -91,6 +92,7 @@ extern int trace_seq_putc(struct trace_seq *s, unsigned char c);
 
 extern void trace_seq_terminate(struct trace_seq *s);
 
+extern int trace_seq_do_fprintf(struct trace_seq *s, FILE *fp);
 extern int trace_seq_do_printf(struct trace_seq *s);
 
 
index ec3bd16..292dc9f 100644 (file)
@@ -231,19 +231,24 @@ void trace_seq_terminate(struct trace_seq *s)
        s->buffer[s->len] = 0;
 }
 
-int trace_seq_do_printf(struct trace_seq *s)
+int trace_seq_do_fprintf(struct trace_seq *s, FILE *fp)
 {
        TRACE_SEQ_CHECK(s);
 
        switch (s->state) {
        case TRACE_SEQ__GOOD:
-               return printf("%.*s", s->len, s->buffer);
+               return fprintf(fp, "%.*s", s->len, s->buffer);
        case TRACE_SEQ__BUFFER_POISONED:
-               puts("Usage of trace_seq after it was destroyed");
+               fprintf(fp, "%s\n", "Usage of trace_seq after it was destroyed");
                break;
        case TRACE_SEQ__MEM_ALLOC_FAILED:
-               puts("Can't allocate trace_seq buffer memory");
+               fprintf(fp, "%s\n", "Can't allocate trace_seq buffer memory");
                break;
        }
        return -1;
 }
+
+int trace_seq_do_printf(struct trace_seq *s)
+{
+       return trace_seq_do_fprintf(s, stdout);
+}
diff --git a/tools/perf/Build b/tools/perf/Build
new file mode 100644 (file)
index 0000000..976e038
--- /dev/null
@@ -0,0 +1,43 @@
+perf-y += builtin-bench.o
+perf-y += builtin-annotate.o
+perf-y += builtin-diff.o
+perf-y += builtin-evlist.o
+perf-y += builtin-help.o
+perf-y += builtin-sched.o
+perf-y += builtin-buildid-list.o
+perf-y += builtin-buildid-cache.o
+perf-y += builtin-list.o
+perf-y += builtin-record.o
+perf-y += builtin-report.o
+perf-y += builtin-stat.o
+perf-y += builtin-timechart.o
+perf-y += builtin-top.o
+perf-y += builtin-script.o
+perf-y += builtin-kmem.o
+perf-y += builtin-lock.o
+perf-y += builtin-kvm.o
+perf-y += builtin-inject.o
+perf-y += builtin-mem.o
+
+perf-$(CONFIG_AUDIT) += builtin-trace.o
+perf-$(CONFIG_LIBELF) += builtin-probe.o
+
+perf-y += bench/
+perf-y += tests/
+
+perf-y += perf.o
+
+paths += -DPERF_HTML_PATH="BUILD_STR($(htmldir_SQ))"
+paths += -DPERF_INFO_PATH="BUILD_STR($(infodir_SQ))"
+paths += -DPERF_MAN_PATH="BUILD_STR($(mandir_SQ))"
+
+CFLAGS_builtin-help.o      += $(paths)
+CFLAGS_builtin-timechart.o += $(paths)
+CFLAGS_perf.o              += -DPERF_HTML_PATH="BUILD_STR($(htmldir_SQ))" -include $(OUTPUT)PERF-VERSION-FILE
+
+libperf-y += util/
+libperf-y += arch/
+libperf-y += ui/
+libperf-y += scripts/
+
+gtk-y += ui/gtk/
diff --git a/tools/perf/Documentation/Build.txt b/tools/perf/Documentation/Build.txt
new file mode 100644 (file)
index 0000000..f6fc650
--- /dev/null
@@ -0,0 +1,49 @@
+
+1) perf build
+=============
+The perf build process consists of several separated building blocks,
+which are linked together to form the perf binary:
+  - libperf library (static)
+  - perf builtin commands
+  - traceevent library (static)
+  - GTK ui library
+
+Several makefiles govern the perf build:
+
+  - Makefile
+    top level Makefile working as a wrapper that calls the main
+    Makefile.perf with a -j option to do parallel builds.
+
+  - Makefile.perf
+    main makefile that triggers build of all perf objects including
+    installation and documentation processing.
+
+  - tools/build/Makefile.build
+    main makefile of the build framework
+
+  - tools/build/Build.include
+    build framework generic definitions
+
+  - Build makefiles
+    makefiles that defines build objects
+
+Please refer to tools/build/Documentation/Build.txt for more
+information about build framework.
+
+
+2) perf build
+=============
+The Makefile.perf triggers the build framework for build objects:
+   perf, libperf, gtk
+
+resulting in following objects:
+  $ ls  *-in.o
+  gtk-in.o  libperf-in.o  perf-in.o
+
+Those objects are then used in final linking:
+  libperf-gtk.so <- gtk-in.o  libperf-in.o
+  perf           <- perf-in.o libperf-in.o
+
+
+NOTE this description is omitting other libraries involved, only
+     focusing on build framework outcomes
index aaa869b..239609c 100644 (file)
@@ -47,6 +47,12 @@ OPTIONS
 -v::
 --verbose::
         Be more verbose (show parsed arguments, etc).
+       Can not use with -q.
+
+-q::
+--quiet::
+       Be quiet (do not show any messages including errors).
+       Can not use with -v.
 
 -a::
 --add=::
@@ -96,7 +102,7 @@ OPTIONS
        Dry run. With this option, --add and --del doesn't execute actual
        adding and removal operations.
 
---max-probes::
+--max-probes=NUM::
        Set the maximum number of probe points for an event. Default is 128.
 
 -x::
@@ -104,8 +110,13 @@ OPTIONS
        Specify path to the executable or shared library file for user
        space tracing. Can also be used with --funcs option.
 
+--demangle::
+       Demangle application symbols. --no-demangle is also available
+       for disabling demangling.
+
 --demangle-kernel::
-       Demangle kernel symbols.
+       Demangle kernel symbols. --no-demangle-kernel is also available
+       for disabling kernel demangling.
 
 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
@@ -137,6 +148,7 @@ Each probe argument follows below syntax.
  [NAME=]LOCALVAR|$retval|%REG|@SYMBOL[:TYPE]
 
 'NAME' specifies the name of this argument (optional). You can use the name of local variable, local data structure member (e.g. var->field, var.field2), local array with fixed index (e.g. array[1], var->array[0], var->pointer[2]), or kprobe-tracer argument format (e.g. $retval, %ax, etc). Note that the name of this argument will be set as the last member name if you specify a local data structure member (e.g. field2 for 'var->field1.field2'.)
+'$vars' special argument is also available for NAME, it is expanded to the local variables which can access at given probe point.
 'TYPE' casts the type of this argument (optional). If omitted, perf probe automatically set the type based on debuginfo. You can specify 'string' type only for the local variable or structure member which is an array of or a pointer to 'char' or 'unsigned char' type.
 
 On x86 systems %REG is always the short form of the register: for example %AX. %RAX or %EAX is not valid.
index 31e9774..1c7e50f 100644 (file)
@@ -115,13 +115,19 @@ OPTIONS
        implies -g.
 
        Allows specifying "fp" (frame pointer) or "dwarf"
-       (DWARF's CFI - Call Frame Information) as the method to collect
+       (DWARF's CFI - Call Frame Information) or "lbr"
+       (Hardware Last Branch Record facility) as the method to collect
        the information used to show the call graphs.
 
        In some systems, where binaries are build with gcc
        --fomit-frame-pointer, using the "fp" method will produce bogus
        call graphs, using "dwarf", if available (perf tools linked to
        the libunwind library) should be used instead.
+       Using the "lbr" method doesn't require any compiler options. It
+       will produce call graphs from the hardware LBR registers. The
+       main limition is that it is only available on new Intel
+       platforms, such as Haswell. It can only get user call chain. It
+       doesn't work with branch stack sampling at the same time.
 
 -q::
 --quiet::
index fbbfdc3..11ccbb2 100644 (file)
@@ -1,5 +1,6 @@
 tools/perf
 tools/scripts
+tools/build
 tools/lib/traceevent
 tools/lib/api
 tools/lib/symbol/kallsyms.c
index aa6a504..efc5158 100644 (file)
@@ -82,13 +82,29 @@ endif
 
 ifneq ($(OUTPUT),)
 #$(info Determined 'OUTPUT' to be $(OUTPUT))
+# Adding $(OUTPUT) as a directory to look for source files,
+# because use generated output files as sources dependency
+# for flex/bison parsers.
+VPATH += $(OUTPUT)
+export VPATH
 endif
 
+ifeq ($(V),1)
+  Q =
+else
+  Q = @
+endif
+
+# Do not use make's built-in rules
+# (this improves performance and avoids hard-to-debug behaviour);
+MAKEFLAGS += -r
+
 $(OUTPUT)PERF-VERSION-FILE: ../../.git/HEAD
-       @$(SHELL_PATH) util/PERF-VERSION-GEN $(OUTPUT)
-       @touch $(OUTPUT)PERF-VERSION-FILE
+       $(Q)$(SHELL_PATH) util/PERF-VERSION-GEN $(OUTPUT)
+       $(Q)touch $(OUTPUT)PERF-VERSION-FILE
 
 CC = $(CROSS_COMPILE)gcc
+LD = $(CROSS_COMPILE)ld
 AR = $(CROSS_COMPILE)ar
 PKG_CONFIG = $(CROSS_COMPILE)pkg-config
 
@@ -127,10 +143,6 @@ export prefix bindir sharedir sysconfdir DESTDIR
 SPARSE_FLAGS = -D__BIG_ENDIAN__ -D__powerpc__
 
 # Guard against environment variables
-BUILTIN_OBJS =
-LIB_H =
-LIB_OBJS =
-GTK_OBJS =
 PYRF_OBJS =
 SCRIPT_SH =
 
@@ -155,8 +167,8 @@ endif
 LIBTRACEEVENT = $(TE_PATH)libtraceevent.a
 export LIBTRACEEVENT
 
-LIBAPIKFS = $(LIB_PATH)libapikfs.a
-export LIBAPIKFS
+LIBAPI = $(LIB_PATH)libapi.a
+export LIBAPI
 
 # python extension build directories
 PYTHON_EXTBUILD     := $(OUTPUT)python_ext_build/
@@ -167,7 +179,7 @@ export PYTHON_EXTBUILD_LIB PYTHON_EXTBUILD_TMP
 python-clean := $(call QUIET_CLEAN, python) $(RM) -r $(PYTHON_EXTBUILD) $(OUTPUT)python/perf.so
 
 PYTHON_EXT_SRCS := $(shell grep -v ^\# util/python-ext-sources)
-PYTHON_EXT_DEPS := util/python-ext-sources util/setup.py $(LIBTRACEEVENT) $(LIBAPIKFS)
+PYTHON_EXT_DEPS := util/python-ext-sources util/setup.py $(LIBTRACEEVENT) $(LIBAPI)
 
 $(OUTPUT)python/perf.so: $(PYTHON_EXT_SRCS) $(PYTHON_EXT_DEPS)
        $(QUIET_GEN)CFLAGS='$(CFLAGS)' $(PYTHON_WORD) util/setup.py \
@@ -206,297 +218,9 @@ endif
 
 export PERL_PATH
 
-$(OUTPUT)util/parse-events-flex.c: util/parse-events.l $(OUTPUT)util/parse-events-bison.c
-       $(QUIET_FLEX)$(FLEX) -o $@ --header-file=$(OUTPUT)util/parse-events-flex.h $(PARSER_DEBUG_FLEX) util/parse-events.l
-
-$(OUTPUT)util/parse-events-bison.c: util/parse-events.y
-       $(QUIET_BISON)$(BISON) -v util/parse-events.y -d $(PARSER_DEBUG_BISON) -o $(OUTPUT)util/parse-events-bison.c -p parse_events_
-
-$(OUTPUT)util/pmu-flex.c: util/pmu.l $(OUTPUT)util/pmu-bison.c
-       $(QUIET_FLEX)$(FLEX) -o $@ --header-file=$(OUTPUT)util/pmu-flex.h util/pmu.l
-
-$(OUTPUT)util/pmu-bison.c: util/pmu.y
-       $(QUIET_BISON)$(BISON) -v util/pmu.y -d -o $(OUTPUT)util/pmu-bison.c -p perf_pmu_
-
-$(OUTPUT)util/parse-events.o: $(OUTPUT)util/parse-events-flex.c $(OUTPUT)util/parse-events-bison.c
-$(OUTPUT)util/pmu.o: $(OUTPUT)util/pmu-flex.c $(OUTPUT)util/pmu-bison.c
-
 LIB_FILE=$(OUTPUT)libperf.a
 
-LIB_H += ../lib/symbol/kallsyms.h
-LIB_H += ../../include/uapi/linux/perf_event.h
-LIB_H += ../../include/linux/rbtree.h
-LIB_H += ../../include/linux/list.h
-LIB_H += ../../include/uapi/linux/const.h
-LIB_H += ../include/linux/hash.h
-LIB_H += ../../include/linux/stringify.h
-LIB_H += util/include/linux/bitmap.h
-LIB_H += ../include/linux/bitops.h
-LIB_H += ../include/asm-generic/bitops/arch_hweight.h
-LIB_H += ../include/asm-generic/bitops/atomic.h
-LIB_H += ../include/asm-generic/bitops/const_hweight.h
-LIB_H += ../include/asm-generic/bitops/find.h
-LIB_H += ../include/asm-generic/bitops/fls64.h
-LIB_H += ../include/asm-generic/bitops/fls.h
-LIB_H += ../include/asm-generic/bitops/__ffs.h
-LIB_H += ../include/asm-generic/bitops/__fls.h
-LIB_H += ../include/asm-generic/bitops/hweight.h
-LIB_H += ../include/asm-generic/bitops.h
-LIB_H += ../include/linux/compiler.h
-LIB_H += ../include/linux/log2.h
-LIB_H += util/include/linux/const.h
-LIB_H += util/include/linux/ctype.h
-LIB_H += util/include/linux/kernel.h
-LIB_H += util/include/linux/list.h
-LIB_H += ../include/linux/export.h
-LIB_H += util/include/linux/poison.h
-LIB_H += util/include/linux/rbtree.h
-LIB_H += util/include/linux/rbtree_augmented.h
-LIB_H += util/include/linux/string.h
-LIB_H += ../include/linux/types.h
-LIB_H += util/include/linux/linkage.h
-LIB_H += util/include/asm/asm-offsets.h
-LIB_H += ../include/asm/bug.h
-LIB_H += util/include/asm/byteorder.h
-LIB_H += util/include/asm/swab.h
-LIB_H += util/include/asm/system.h
-LIB_H += util/include/asm/uaccess.h
-LIB_H += util/include/dwarf-regs.h
-LIB_H += util/include/asm/dwarf2.h
-LIB_H += util/include/asm/cpufeature.h
-LIB_H += util/include/asm/unistd_32.h
-LIB_H += util/include/asm/unistd_64.h
-LIB_H += perf.h
-LIB_H += util/annotate.h
-LIB_H += util/cache.h
-LIB_H += util/callchain.h
-LIB_H += util/build-id.h
-LIB_H += util/db-export.h
-LIB_H += util/debug.h
-LIB_H += util/pmu.h
-LIB_H += util/event.h
-LIB_H += util/evsel.h
-LIB_H += util/evlist.h
-LIB_H += util/exec_cmd.h
-LIB_H += util/find-vdso-map.c
-LIB_H += util/levenshtein.h
-LIB_H += util/machine.h
-LIB_H += util/map.h
-LIB_H += util/parse-options.h
-LIB_H += util/parse-events.h
-LIB_H += util/quote.h
-LIB_H += util/util.h
-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
-LIB_H += util/svghelper.h
-LIB_H += util/tool.h
-LIB_H += util/run-command.h
-LIB_H += util/sigchain.h
-LIB_H += util/dso.h
-LIB_H += util/symbol.h
-LIB_H += util/color.h
-LIB_H += util/values.h
-LIB_H += util/sort.h
-LIB_H += util/hist.h
-LIB_H += util/comm.h
-LIB_H += util/thread.h
-LIB_H += util/thread_map.h
-LIB_H += util/trace-event.h
-LIB_H += util/probe-finder.h
-LIB_H += util/dwarf-aux.h
-LIB_H += util/probe-event.h
-LIB_H += util/pstack.h
-LIB_H += util/cpumap.h
-LIB_H += util/top.h
-LIB_H += $(ARCH_INCLUDE)
-LIB_H += util/cgroup.h
-LIB_H += $(LIB_INCLUDE)traceevent/event-parse.h
-LIB_H += util/target.h
-LIB_H += util/rblist.h
-LIB_H += util/intlist.h
-LIB_H += util/perf_regs.h
-LIB_H += util/unwind.h
-LIB_H += util/vdso.h
-LIB_H += util/tsc.h
-LIB_H += ui/helpline.h
-LIB_H += ui/progress.h
-LIB_H += ui/util.h
-LIB_H += ui/ui.h
-LIB_H += util/data.h
-LIB_H += util/kvm-stat.h
-LIB_H += util/thread-stack.h
-
-LIB_OBJS += $(OUTPUT)util/abspath.o
-LIB_OBJS += $(OUTPUT)util/alias.o
-LIB_OBJS += $(OUTPUT)util/annotate.o
-LIB_OBJS += $(OUTPUT)util/build-id.o
-LIB_OBJS += $(OUTPUT)util/config.o
-LIB_OBJS += $(OUTPUT)util/ctype.o
-LIB_OBJS += $(OUTPUT)util/db-export.o
-LIB_OBJS += $(OUTPUT)util/pmu.o
-LIB_OBJS += $(OUTPUT)util/environment.o
-LIB_OBJS += $(OUTPUT)util/event.o
-LIB_OBJS += $(OUTPUT)util/evlist.o
-LIB_OBJS += $(OUTPUT)util/evsel.o
-LIB_OBJS += $(OUTPUT)util/exec_cmd.o
-LIB_OBJS += $(OUTPUT)util/find_next_bit.o
-LIB_OBJS += $(OUTPUT)util/help.o
-LIB_OBJS += $(OUTPUT)util/kallsyms.o
-LIB_OBJS += $(OUTPUT)util/levenshtein.o
-LIB_OBJS += $(OUTPUT)util/parse-options.o
-LIB_OBJS += $(OUTPUT)util/parse-events.o
-LIB_OBJS += $(OUTPUT)util/path.o
-LIB_OBJS += $(OUTPUT)util/rbtree.o
-LIB_OBJS += $(OUTPUT)util/bitmap.o
-LIB_OBJS += $(OUTPUT)util/hweight.o
-LIB_OBJS += $(OUTPUT)util/run-command.o
-LIB_OBJS += $(OUTPUT)util/quote.o
-LIB_OBJS += $(OUTPUT)util/strbuf.o
-LIB_OBJS += $(OUTPUT)util/string.o
-LIB_OBJS += $(OUTPUT)util/strlist.o
-LIB_OBJS += $(OUTPUT)util/strfilter.o
-LIB_OBJS += $(OUTPUT)util/top.o
-LIB_OBJS += $(OUTPUT)util/usage.o
-LIB_OBJS += $(OUTPUT)util/wrapper.o
-LIB_OBJS += $(OUTPUT)util/sigchain.o
-LIB_OBJS += $(OUTPUT)util/dso.o
-LIB_OBJS += $(OUTPUT)util/symbol.o
-LIB_OBJS += $(OUTPUT)util/symbol-elf.o
-LIB_OBJS += $(OUTPUT)util/color.o
-LIB_OBJS += $(OUTPUT)util/pager.o
-LIB_OBJS += $(OUTPUT)util/header.o
-LIB_OBJS += $(OUTPUT)util/callchain.o
-LIB_OBJS += $(OUTPUT)util/values.o
-LIB_OBJS += $(OUTPUT)util/debug.o
-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
-LIB_OBJS += $(OUTPUT)util/trace-event-parse.o
-LIB_OBJS += $(OUTPUT)util/parse-events-flex.o
-LIB_OBJS += $(OUTPUT)util/parse-events-bison.o
-LIB_OBJS += $(OUTPUT)util/pmu-flex.o
-LIB_OBJS += $(OUTPUT)util/pmu-bison.o
-LIB_OBJS += $(OUTPUT)util/trace-event-read.o
-LIB_OBJS += $(OUTPUT)util/trace-event-info.o
-LIB_OBJS += $(OUTPUT)util/trace-event-scripting.o
-LIB_OBJS += $(OUTPUT)util/trace-event.o
-LIB_OBJS += $(OUTPUT)util/svghelper.o
-LIB_OBJS += $(OUTPUT)util/sort.o
-LIB_OBJS += $(OUTPUT)util/hist.o
-LIB_OBJS += $(OUTPUT)util/probe-event.o
-LIB_OBJS += $(OUTPUT)util/util.o
-LIB_OBJS += $(OUTPUT)util/xyarray.o
-LIB_OBJS += $(OUTPUT)util/cpumap.o
-LIB_OBJS += $(OUTPUT)util/cgroup.o
-LIB_OBJS += $(OUTPUT)util/target.o
-LIB_OBJS += $(OUTPUT)util/rblist.o
-LIB_OBJS += $(OUTPUT)util/intlist.o
-LIB_OBJS += $(OUTPUT)util/vdso.o
-LIB_OBJS += $(OUTPUT)util/stat.o
-LIB_OBJS += $(OUTPUT)util/record.o
-LIB_OBJS += $(OUTPUT)util/srcline.o
-LIB_OBJS += $(OUTPUT)util/data.o
-LIB_OBJS += $(OUTPUT)util/tsc.o
-LIB_OBJS += $(OUTPUT)util/cloexec.o
-LIB_OBJS += $(OUTPUT)util/thread-stack.o
-
-LIB_OBJS += $(OUTPUT)ui/setup.o
-LIB_OBJS += $(OUTPUT)ui/helpline.o
-LIB_OBJS += $(OUTPUT)ui/progress.o
-LIB_OBJS += $(OUTPUT)ui/util.o
-LIB_OBJS += $(OUTPUT)ui/hist.o
-LIB_OBJS += $(OUTPUT)ui/stdio/hist.o
-
-LIB_OBJS += $(OUTPUT)arch/common.o
-
-LIB_OBJS += $(OUTPUT)tests/parse-events.o
-LIB_OBJS += $(OUTPUT)tests/dso-data.o
-LIB_OBJS += $(OUTPUT)tests/attr.o
-LIB_OBJS += $(OUTPUT)tests/vmlinux-kallsyms.o
-LIB_OBJS += $(OUTPUT)tests/open-syscall.o
-LIB_OBJS += $(OUTPUT)tests/open-syscall-all-cpus.o
-LIB_OBJS += $(OUTPUT)tests/open-syscall-tp-fields.o
-LIB_OBJS += $(OUTPUT)tests/mmap-basic.o
-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
-LIB_OBJS += $(OUTPUT)tests/hists_filter.o
-LIB_OBJS += $(OUTPUT)tests/hists_output.o
-LIB_OBJS += $(OUTPUT)tests/hists_cumulate.o
-LIB_OBJS += $(OUTPUT)tests/python-use.o
-LIB_OBJS += $(OUTPUT)tests/bp_signal.o
-LIB_OBJS += $(OUTPUT)tests/bp_signal_overflow.o
-LIB_OBJS += $(OUTPUT)tests/task-exit.o
-LIB_OBJS += $(OUTPUT)tests/sw-clock.o
-ifeq ($(ARCH),x86)
-LIB_OBJS += $(OUTPUT)tests/perf-time-to-tsc.o
-endif
-LIB_OBJS += $(OUTPUT)tests/code-reading.o
-LIB_OBJS += $(OUTPUT)tests/sample-parsing.o
-LIB_OBJS += $(OUTPUT)tests/parse-no-sample-id-all.o
-ifndef NO_DWARF_UNWIND
-ifeq ($(ARCH),$(filter $(ARCH),x86 arm))
-LIB_OBJS += $(OUTPUT)tests/dwarf-unwind.o
-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
-# Benchmark modules
-BUILTIN_OBJS += $(OUTPUT)bench/sched-messaging.o
-BUILTIN_OBJS += $(OUTPUT)bench/sched-pipe.o
-ifeq ($(ARCH), x86)
-ifeq ($(IS_64_BIT), 1)
-BUILTIN_OBJS += $(OUTPUT)bench/mem-memcpy-x86-64-asm.o
-BUILTIN_OBJS += $(OUTPUT)bench/mem-memset-x86-64-asm.o
-endif
-endif
-BUILTIN_OBJS += $(OUTPUT)bench/mem-memcpy.o
-BUILTIN_OBJS += $(OUTPUT)bench/futex-hash.o
-BUILTIN_OBJS += $(OUTPUT)bench/futex-wake.o
-BUILTIN_OBJS += $(OUTPUT)bench/futex-requeue.o
-
-BUILTIN_OBJS += $(OUTPUT)builtin-diff.o
-BUILTIN_OBJS += $(OUTPUT)builtin-evlist.o
-BUILTIN_OBJS += $(OUTPUT)builtin-help.o
-BUILTIN_OBJS += $(OUTPUT)builtin-sched.o
-BUILTIN_OBJS += $(OUTPUT)builtin-buildid-list.o
-BUILTIN_OBJS += $(OUTPUT)builtin-buildid-cache.o
-BUILTIN_OBJS += $(OUTPUT)builtin-list.o
-BUILTIN_OBJS += $(OUTPUT)builtin-record.o
-BUILTIN_OBJS += $(OUTPUT)builtin-report.o
-BUILTIN_OBJS += $(OUTPUT)builtin-stat.o
-BUILTIN_OBJS += $(OUTPUT)builtin-timechart.o
-BUILTIN_OBJS += $(OUTPUT)builtin-top.o
-BUILTIN_OBJS += $(OUTPUT)builtin-script.o
-BUILTIN_OBJS += $(OUTPUT)builtin-probe.o
-BUILTIN_OBJS += $(OUTPUT)builtin-kmem.o
-BUILTIN_OBJS += $(OUTPUT)builtin-lock.o
-BUILTIN_OBJS += $(OUTPUT)builtin-kvm.o
-BUILTIN_OBJS += $(OUTPUT)builtin-inject.o
-BUILTIN_OBJS += $(OUTPUT)tests/builtin-test.o
-BUILTIN_OBJS += $(OUTPUT)builtin-mem.o
-
-PERFLIBS = $(LIB_FILE) $(LIBAPIKFS) $(LIBTRACEEVENT)
+PERFLIBS = $(LIB_FILE) $(LIBAPI) $(LIBTRACEEVENT)
 
 # We choose to avoid "if .. else if .. else .. endif endif"
 # because maintaining the nesting to match is a pain.  If
@@ -508,67 +232,9 @@ ifneq ($(OUTPUT),)
   CFLAGS += -I$(OUTPUT)
 endif
 
-ifdef NO_LIBELF
-# Remove ELF/DWARF dependent codes
-LIB_OBJS := $(filter-out $(OUTPUT)util/symbol-elf.o,$(LIB_OBJS))
-LIB_OBJS := $(filter-out $(OUTPUT)util/dwarf-aux.o,$(LIB_OBJS))
-LIB_OBJS := $(filter-out $(OUTPUT)util/probe-event.o,$(LIB_OBJS))
-LIB_OBJS := $(filter-out $(OUTPUT)util/probe-finder.o,$(LIB_OBJS))
-
-BUILTIN_OBJS := $(filter-out $(OUTPUT)builtin-probe.o,$(BUILTIN_OBJS))
-
-# Use minimal symbol handling
-LIB_OBJS += $(OUTPUT)util/symbol-minimal.o
-
-else # NO_LIBELF
-ifndef NO_DWARF
-  LIB_OBJS += $(OUTPUT)util/probe-finder.o
-  LIB_OBJS += $(OUTPUT)util/dwarf-aux.o
-endif # NO_DWARF
-endif # NO_LIBELF
-
-ifndef NO_LIBDW_DWARF_UNWIND
-  LIB_OBJS += $(OUTPUT)util/unwind-libdw.o
-  LIB_H += util/unwind-libdw.h
-endif
-
-ifndef NO_LIBUNWIND
-  LIB_OBJS += $(OUTPUT)util/unwind-libunwind.o
-endif
-LIB_OBJS += $(OUTPUT)tests/keep-tracking.o
-
-ifndef NO_LIBAUDIT
-  BUILTIN_OBJS += $(OUTPUT)builtin-trace.o
-endif
-
-ifndef NO_SLANG
-  LIB_OBJS += $(OUTPUT)ui/browser.o
-  LIB_OBJS += $(OUTPUT)ui/browsers/annotate.o
-  LIB_OBJS += $(OUTPUT)ui/browsers/hists.o
-  LIB_OBJS += $(OUTPUT)ui/browsers/map.o
-  LIB_OBJS += $(OUTPUT)ui/browsers/scripts.o
-  LIB_OBJS += $(OUTPUT)ui/browsers/header.o
-  LIB_OBJS += $(OUTPUT)ui/tui/setup.o
-  LIB_OBJS += $(OUTPUT)ui/tui/util.o
-  LIB_OBJS += $(OUTPUT)ui/tui/helpline.o
-  LIB_OBJS += $(OUTPUT)ui/tui/progress.o
-  LIB_H += ui/tui/tui.h
-  LIB_H += ui/browser.h
-  LIB_H += ui/browsers/map.h
-  LIB_H += ui/keysyms.h
-  LIB_H += ui/libslang.h
-endif
-
 ifndef NO_GTK2
   ALL_PROGRAMS += $(OUTPUT)libperf-gtk.so
-
-  GTK_OBJS += $(OUTPUT)ui/gtk/browser.o
-  GTK_OBJS += $(OUTPUT)ui/gtk/hists.o
-  GTK_OBJS += $(OUTPUT)ui/gtk/setup.o
-  GTK_OBJS += $(OUTPUT)ui/gtk/util.o
-  GTK_OBJS += $(OUTPUT)ui/gtk/helpline.o
-  GTK_OBJS += $(OUTPUT)ui/gtk/progress.o
-  GTK_OBJS += $(OUTPUT)ui/gtk/annotate.o
+  GTK_IN := $(OUTPUT)gtk-in.o
 
 install-gtk: $(OUTPUT)libperf-gtk.so
        $(call QUIET_INSTALL, 'GTK UI') \
@@ -576,31 +242,6 @@ install-gtk: $(OUTPUT)libperf-gtk.so
                $(INSTALL) $(OUTPUT)libperf-gtk.so '$(DESTDIR_SQ)$(libdir_SQ)'
 endif
 
-ifndef NO_LIBPERL
-  LIB_OBJS += $(OUTPUT)util/scripting-engines/trace-event-perl.o
-  LIB_OBJS += $(OUTPUT)scripts/perl/Perf-Trace-Util/Context.o
-endif
-
-ifndef NO_LIBPYTHON
-  LIB_OBJS += $(OUTPUT)util/scripting-engines/trace-event-python.o
-  LIB_OBJS += $(OUTPUT)scripts/python/Perf-Trace-Util/Context.o
-endif
-
-ifeq ($(NO_PERF_REGS),0)
-  ifeq ($(ARCH),x86)
-    LIB_H += arch/x86/include/perf_regs.h
-  endif
-  LIB_OBJS += $(OUTPUT)util/perf_regs.o
-endif
-
-ifndef NO_LIBNUMA
-  BUILTIN_OBJS += $(OUTPUT)bench/numa.o
-endif
-
-ifndef NO_ZLIB
-  LIB_OBJS += $(OUTPUT)util/zlib.o
-endif
-
 ifdef ASCIIDOC8
   export ASCIIDOC8
 endif
@@ -616,39 +257,29 @@ SHELL = $(SHELL_PATH)
 all: shell_compatibility_test $(ALL_PROGRAMS) $(LANG_BINDINGS) $(OTHER_PROGRAMS)
 
 please_set_SHELL_PATH_to_a_more_modern_shell:
-       @$$(:)
+       $(Q)$$(:)
 
 shell_compatibility_test: please_set_SHELL_PATH_to_a_more_modern_shell
 
 strip: $(PROGRAMS) $(OUTPUT)perf
        $(STRIP) $(STRIP_OPTS) $(PROGRAMS) $(OUTPUT)perf
 
-$(OUTPUT)perf.o: perf.c $(OUTPUT)common-cmds.h $(OUTPUT)PERF-CFLAGS
-       $(QUIET_CC)$(CC) -include $(OUTPUT)PERF-VERSION-FILE \
-               '-DPERF_HTML_PATH="$(htmldir_SQ)"' \
-               $(CFLAGS) -c $(filter %.c,$^) -o $@
+PERF_IN := $(OUTPUT)perf-in.o
 
-$(OUTPUT)perf: $(OUTPUT)perf.o $(BUILTIN_OBJS) $(PERFLIBS)
-       $(QUIET_LINK)$(CC) $(CFLAGS) $(LDFLAGS) $(OUTPUT)perf.o \
-               $(BUILTIN_OBJS) $(LIBS) -o $@
+export srctree OUTPUT RM CC LD AR CFLAGS V BISON FLEX
+build := -f $(srctree)/tools/build/Makefile.build dir=. obj
 
-$(GTK_OBJS): $(OUTPUT)%.o: %.c $(LIB_H)
-       $(QUIET_CC)$(CC) -o $@ -c -fPIC $(CFLAGS) $(GTK_CFLAGS) $<
+$(PERF_IN): $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)common-cmds.h FORCE
+       $(Q)$(MAKE) $(build)=perf
 
-$(OUTPUT)libperf-gtk.so: $(GTK_OBJS) $(PERFLIBS)
-       $(QUIET_LINK)$(CC) -o $@ -shared $(LDFLAGS) $(filter %.o,$^) $(GTK_LIBS)
+$(OUTPUT)perf: $(PERFLIBS) $(PERF_IN)
+       $(QUIET_LINK)$(CC) $(CFLAGS) $(LDFLAGS) $(PERF_IN) $(LIBS) -o $@
 
-$(OUTPUT)builtin-help.o: builtin-help.c $(OUTPUT)common-cmds.h $(OUTPUT)PERF-CFLAGS
-       $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) \
-               '-DPERF_HTML_PATH="$(htmldir_SQ)"' \
-               '-DPERF_MAN_PATH="$(mandir_SQ)"' \
-               '-DPERF_INFO_PATH="$(infodir_SQ)"' $<
+$(GTK_IN): FORCE
+       $(Q)$(MAKE) $(build)=gtk
 
-$(OUTPUT)builtin-timechart.o: builtin-timechart.c $(OUTPUT)common-cmds.h $(OUTPUT)PERF-CFLAGS
-       $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) \
-               '-DPERF_HTML_PATH="$(htmldir_SQ)"' \
-               '-DPERF_MAN_PATH="$(mandir_SQ)"' \
-               '-DPERF_INFO_PATH="$(infodir_SQ)"' $<
+$(OUTPUT)libperf-gtk.so: $(GTK_IN) $(PERFLIBS)
+       $(QUIET_LINK)$(CC) -o $@ -shared $(LDFLAGS) $(filter %.o,$^) $(GTK_LIBS)
 
 $(OUTPUT)common-cmds.h: util/generate-cmdlist.sh command-list.txt
 
@@ -659,8 +290,7 @@ $(SCRIPTS) : % : %.sh
        $(QUIET_GEN)$(INSTALL) '$@.sh' '$(OUTPUT)$@'
 
 # These can record PERF_VERSION
-$(OUTPUT)perf.o perf.spec \
-       $(SCRIPTS) \
+perf.spec $(SCRIPTS) \
        : $(OUTPUT)PERF-VERSION-FILE
 
 .SUFFIXES:
@@ -683,90 +313,33 @@ endif
 # These two need to be here so that when O= is not used they take precedence
 # over the general rule for .o
 
-$(OUTPUT)util/%-flex.o: $(OUTPUT)util/%-flex.c $(OUTPUT)PERF-CFLAGS
-       $(QUIET_CC)$(CC) -o $@ -c -Iutil/ $(CFLAGS) -w $<
-
-$(OUTPUT)util/%-bison.o: $(OUTPUT)util/%-bison.c $(OUTPUT)PERF-CFLAGS
-       $(QUIET_CC)$(CC) -o $@ -c -Iutil/ $(CFLAGS) -DYYENABLE_NLS=0 -DYYLTYPE_IS_TRIVIAL=0 -w $<
-
-$(OUTPUT)%.o: %.c $(OUTPUT)PERF-CFLAGS
-       $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) $<
-$(OUTPUT)%.i: %.c $(OUTPUT)PERF-CFLAGS
-       $(QUIET_CC)$(CC) -o $@ -E $(CFLAGS) $<
-$(OUTPUT)%.s: %.c $(OUTPUT)PERF-CFLAGS
-       $(QUIET_CC)$(CC) -o $@ -S $(CFLAGS) $<
-$(OUTPUT)%.o: %.S
-       $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) $<
-$(OUTPUT)%.s: %.S
-       $(QUIET_CC)$(CC) -o $@ -E $(CFLAGS) $<
-
-$(OUTPUT)util/exec_cmd.o: util/exec_cmd.c $(OUTPUT)PERF-CFLAGS
-       $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) \
-               '-DPERF_EXEC_PATH="$(perfexecdir_SQ)"' \
-               '-DPREFIX="$(prefix_SQ)"' \
-               $<
-
-$(OUTPUT)tests/attr.o: tests/attr.c $(OUTPUT)PERF-CFLAGS
-       $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) \
-               '-DBINDIR="$(bindir_SQ)"' -DPYTHON='"$(PYTHON_WORD)"' \
-               $<
-
-$(OUTPUT)tests/python-use.o: tests/python-use.c $(OUTPUT)PERF-CFLAGS
-       $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) \
-               -DPYTHONPATH='"$(OUTPUT)python"' \
-               -DPYTHON='"$(PYTHON_WORD)"' \
-               $<
-
-$(OUTPUT)tests/dwarf-unwind.o: tests/dwarf-unwind.c
-       $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -fno-optimize-sibling-calls $<
-
-$(OUTPUT)util/config.o: util/config.c $(OUTPUT)PERF-CFLAGS
-       $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $<
+# get relative building directory (to $(OUTPUT))
+# and '.' if it's $(OUTPUT) itself
+__build-dir = $(subst $(OUTPUT),,$(dir $@))
+build-dir   = $(if $(__build-dir),$(__build-dir),.)
 
-$(OUTPUT)ui/setup.o: ui/setup.c $(OUTPUT)PERF-CFLAGS
-       $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -DLIBDIR='"$(libdir_SQ)"' $<
+single_dep: $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)common-cmds.h
 
-$(OUTPUT)ui/browser.o: ui/browser.c $(OUTPUT)PERF-CFLAGS
-       $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -DENABLE_SLFUTURE_CONST $<
+$(OUTPUT)%.o: %.c single_dep FORCE
+       $(Q)$(MAKE) -f $(srctree)/tools/build/Makefile.build dir=$(build-dir) $@
 
-$(OUTPUT)ui/browsers/annotate.o: ui/browsers/annotate.c $(OUTPUT)PERF-CFLAGS
-       $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -DENABLE_SLFUTURE_CONST $<
+$(OUTPUT)%.i: %.c single_dep FORCE
+       $(Q)$(MAKE) -f $(srctree)/tools/build/Makefile.build dir=$(build-dir) $@
 
-$(OUTPUT)ui/browsers/hists.o: ui/browsers/hists.c $(OUTPUT)PERF-CFLAGS
-       $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -DENABLE_SLFUTURE_CONST $<
+$(OUTPUT)%.s: %.c single_dep FORCE
+       $(Q)$(MAKE) -f $(srctree)/tools/build/Makefile.build dir=$(build-dir) $@
 
-$(OUTPUT)ui/browsers/map.o: ui/browsers/map.c $(OUTPUT)PERF-CFLAGS
-       $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -DENABLE_SLFUTURE_CONST $<
+$(OUTPUT)%-bison.o: %.c single_dep FORCE
+       $(Q)$(MAKE) -f $(srctree)/tools/build/Makefile.build dir=$(build-dir) $@
 
-$(OUTPUT)ui/browsers/scripts.o: ui/browsers/scripts.c $(OUTPUT)PERF-CFLAGS
-       $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -DENABLE_SLFUTURE_CONST $<
+$(OUTPUT)%-flex.o: %.c single_dep FORCE
+       $(Q)$(MAKE) -f $(srctree)/tools/build/Makefile.build dir=$(build-dir) $@
 
-$(OUTPUT)util/kallsyms.o: ../lib/symbol/kallsyms.c $(OUTPUT)PERF-CFLAGS
-       $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) $<
+$(OUTPUT)%.o: %.S single_dep FORCE
+       $(Q)$(MAKE) -f $(srctree)/tools/build/Makefile.build dir=$(build-dir) $@
 
-$(OUTPUT)util/rbtree.o: ../../lib/rbtree.c $(OUTPUT)PERF-CFLAGS
-       $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -Wno-unused-parameter -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $<
-
-$(OUTPUT)util/hweight.o: ../../lib/hweight.c $(OUTPUT)PERF-CFLAGS
-       $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -Wno-unused-parameter -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $<
-
-$(OUTPUT)util/find_next_bit.o: ../lib/util/find_next_bit.c $(OUTPUT)PERF-CFLAGS
-       $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -Wno-unused-parameter -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $<
-
-$(OUTPUT)util/parse-events.o: util/parse-events.c $(OUTPUT)PERF-CFLAGS
-       $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -Wno-redundant-decls $<
-
-$(OUTPUT)util/scripting-engines/trace-event-perl.o: util/scripting-engines/trace-event-perl.c $(OUTPUT)PERF-CFLAGS
-       $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) $(PERL_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-shadow -Wno-undef -Wno-switch-default $<
-
-$(OUTPUT)scripts/perl/Perf-Trace-Util/Context.o: scripts/perl/Perf-Trace-Util/Context.c $(OUTPUT)PERF-CFLAGS
-       $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) $(PERL_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-nested-externs -Wno-undef -Wno-switch-default $<
-
-$(OUTPUT)util/scripting-engines/trace-event-python.o: util/scripting-engines/trace-event-python.c $(OUTPUT)PERF-CFLAGS
-       $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) $(PYTHON_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-shadow $<
-
-$(OUTPUT)scripts/python/Perf-Trace-Util/Context.o: scripts/python/Perf-Trace-Util/Context.c $(OUTPUT)PERF-CFLAGS
-       $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) $(PYTHON_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-nested-externs $<
+$(OUTPUT)%.i: %.S single_dep FORCE
+       $(Q)$(MAKE) -f $(srctree)/tools/build/Makefile.build dir=$(build-dir) $@
 
 $(OUTPUT)perf-%: %.o $(PERFLIBS)
        $(QUIET_LINK)$(CC) $(CFLAGS) -o $@ $(LDFLAGS) $(filter %.o,$^) $(LIBS)
@@ -781,58 +354,34 @@ $(OUTPUT)perf-read-vdsox32: perf-read-vdso.c util/find-vdso-map.c
        $(QUIET_CC)$(CC) -mx32 $(filter -static,$(LDFLAGS)) -Wall -Werror -o $@ perf-read-vdso.c
 endif
 
-$(LIB_OBJS) $(BUILTIN_OBJS): $(LIB_H)
-$(patsubst perf-%,%.o,$(PROGRAMS)): $(LIB_H) $(wildcard */*.h)
-
-# we compile into subdirectories. if the target directory is not the source directory, they might not exists. So
-# we depend the various files onto their directories.
-DIRECTORY_DEPS = $(LIB_OBJS) $(BUILTIN_OBJS) $(GTK_OBJS)
-DIRECTORY_DEPS += $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)common-cmds.h
-# no need to add flex objects, because they depend on bison ones
-DIRECTORY_DEPS += $(OUTPUT)util/parse-events-bison.c
-DIRECTORY_DEPS += $(OUTPUT)util/pmu-bison.c
+$(patsubst perf-%,%.o,$(PROGRAMS)): $(wildcard */*.h)
 
-OUTPUT_DIRECTORIES := $(sort $(dir $(DIRECTORY_DEPS)))
+LIBPERF_IN := $(OUTPUT)libperf-in.o
 
-$(DIRECTORY_DEPS): | $(OUTPUT_DIRECTORIES)
-# In the second step, we make a rule to actually create these directories
-$(OUTPUT_DIRECTORIES):
-       $(QUIET_MKDIR)$(MKDIR) -p $@ 2>/dev/null
+$(LIBPERF_IN): FORCE
+       $(Q)$(MAKE) $(build)=libperf
 
-$(LIB_FILE): $(LIB_OBJS)
-       $(QUIET_AR)$(RM) $@ && $(AR) rcs $@ $(LIB_OBJS)
+$(LIB_FILE): $(LIBPERF_IN)
+       $(QUIET_AR)$(RM) $@ && $(AR) rcs $@ $(LIBPERF_IN) $(LIB_OBJS)
 
-# libtraceevent.a
-TE_SOURCES = $(wildcard $(TRACE_EVENT_DIR)*.[ch])
-
-LIBTRACEEVENT_FLAGS  = $(QUIET_SUBDIR1) O=$(OUTPUT)
-LIBTRACEEVENT_FLAGS += CFLAGS="-g -Wall $(EXTRA_CFLAGS)"
 LIBTRACEEVENT_FLAGS += plugin_dir=$(plugindir_SQ)
 
-$(LIBTRACEEVENT): $(TE_SOURCES) $(OUTPUT)PERF-CFLAGS
-       $(QUIET_SUBDIR0)$(TRACE_EVENT_DIR) $(LIBTRACEEVENT_FLAGS) libtraceevent.a plugins
+$(LIBTRACEEVENT): FORCE
+       $(Q)$(MAKE) -C $(TRACE_EVENT_DIR) $(LIBTRACEEVENT_FLAGS) O=$(OUTPUT) $(OUTPUT)libtraceevent.a plugins
 
 $(LIBTRACEEVENT)-clean:
        $(call QUIET_CLEAN, libtraceevent)
-       @$(MAKE) -C $(TRACE_EVENT_DIR) O=$(OUTPUT) clean >/dev/null
+       $(Q)$(MAKE) -C $(TRACE_EVENT_DIR) O=$(OUTPUT) clean >/dev/null
 
 install-traceevent-plugins: $(LIBTRACEEVENT)
-       $(QUIET_SUBDIR0)$(TRACE_EVENT_DIR) $(LIBTRACEEVENT_FLAGS) install_plugins
-
-LIBAPIKFS_SOURCES = $(wildcard $(LIB_PATH)fs/*.[ch] $(LIB_PATH)fd/*.[ch])
+       $(Q)$(MAKE) -C $(TRACE_EVENT_DIR) $(LIBTRACEEVENT_FLAGS) O=$(OUTPUT) install_plugins
 
-# if subdir is set, we've been called from above so target has been built
-# already
-$(LIBAPIKFS): $(LIBAPIKFS_SOURCES)
-ifeq ($(subdir),)
-       $(QUIET_SUBDIR0)$(LIB_DIR) $(QUIET_SUBDIR1) O=$(OUTPUT) libapikfs.a
-endif
+$(LIBAPI): FORCE
+       $(Q)$(MAKE) -C $(LIB_DIR) O=$(OUTPUT) $(OUTPUT)libapi.a
 
-$(LIBAPIKFS)-clean:
-ifeq ($(subdir),)
-       $(call QUIET_CLEAN, libapikfs)
-       @$(MAKE) -C $(LIB_DIR) O=$(OUTPUT) clean >/dev/null
-endif
+$(LIBAPI)-clean:
+       $(call QUIET_CLEAN, libapi)
+       $(Q)$(MAKE) -C $(LIB_DIR) O=$(OUTPUT) clean >/dev/null
 
 help:
        @echo 'Perf make targets:'
@@ -888,17 +437,6 @@ cscope:
        $(QUIET_GEN)$(RM) cscope*; \
        $(FIND) $(TAG_FOLDERS) -name '*.[hcS]' -print | xargs cscope -b $(TAG_FILES)
 
-### Detect prefix changes
-TRACK_CFLAGS = $(subst ','\'',$(CFLAGS)):\
-             $(bindir_SQ):$(perfexecdir_SQ):$(template_dir_SQ):$(prefix_SQ):$(plugindir_SQ)
-
-$(OUTPUT)PERF-CFLAGS: .FORCE-PERF-CFLAGS
-       @FLAGS='$(TRACK_CFLAGS)'; \
-           if test x"$$FLAGS" != x"`cat $(OUTPUT)PERF-CFLAGS 2>/dev/null`" ; then \
-               echo 1>&2 "  FLAGS:   * new build flags or prefix"; \
-               echo "$$FLAGS" >$(OUTPUT)PERF-CFLAGS; \
-            fi
-
 ### Testing rules
 
 # GNU make supports exporting all variables by "export" without parameters.
@@ -981,12 +519,14 @@ $(INSTALL_DOC_TARGETS):
 #
 config-clean:
        $(call QUIET_CLEAN, config)
-       @$(MAKE) -C config/feature-checks clean >/dev/null
+       $(Q)$(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-with-kcore $(OUTPUT)perf.o $(LANG_BINDINGS) $(GTK_OBJS)
+clean: $(LIBTRACEEVENT)-clean $(LIBAPI)-clean config-clean
+       $(call QUIET_CLEAN, core-objs)  $(RM) $(LIB_FILE) $(OUTPUT)perf-archive $(OUTPUT)perf-with-kcore $(LANG_BINDINGS)
+       $(Q)find . -name '*.o' -delete -o -name '\.*.cmd' -delete -o -name '\.*.d' -delete
+       $(Q)$(RM) .config-detected
        $(call QUIET_CLEAN, core-progs) $(RM) $(ALL_PROGRAMS) perf perf-read-vdso32 perf-read-vdsox32
-       $(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*
+       $(call QUIET_CLEAN, core-gen)   $(RM)  *.spec *.pyc *.pyo */*.pyc */*.pyo $(OUTPUT)common-cmds.h TAGS tags cscope* $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)PERF-FEATURES $(OUTPUT)util/*-bison* $(OUTPUT)util/*-flex*
        $(QUIET_SUBDIR0)Documentation $(QUIET_SUBDIR1) clean
        $(python-clean)
 
@@ -1000,7 +540,9 @@ else
     GIT-HEAD-PHONY =
 endif
 
+FORCE:
+
 .PHONY: all install clean config-clean strip install-gtk
 .PHONY: shell_compatibility_test please_set_SHELL_PATH_to_a_more_modern_shell
-.PHONY: $(GIT-HEAD-PHONY) TAGS tags cscope .FORCE-PERF-CFLAGS
+.PHONY: $(GIT-HEAD-PHONY) TAGS tags cscope FORCE single_dep
 
diff --git a/tools/perf/arch/Build b/tools/perf/arch/Build
new file mode 100644 (file)
index 0000000..109eb75
--- /dev/null
@@ -0,0 +1,2 @@
+libperf-y += common.o
+libperf-y += $(ARCH)/
diff --git a/tools/perf/arch/arm/Build b/tools/perf/arch/arm/Build
new file mode 100644 (file)
index 0000000..41bf61d
--- /dev/null
@@ -0,0 +1,2 @@
+libperf-y += util/
+libperf-$(CONFIG_DWARF_UNWIND) += tests/
index 09d6215..7fbca17 100644 (file)
@@ -1,14 +1,3 @@
 ifndef NO_DWARF
 PERF_HAVE_DWARF_REGS := 1
-LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/dwarf-regs.o
-endif
-ifndef NO_LIBUNWIND
-LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/unwind-libunwind.o
-endif
-ifndef NO_LIBDW_DWARF_UNWIND
-LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/unwind-libdw.o
-endif
-ifndef NO_DWARF_UNWIND
-LIB_OBJS += $(OUTPUT)arch/$(ARCH)/tests/regs_load.o
-LIB_OBJS += $(OUTPUT)arch/$(ARCH)/tests/dwarf-unwind.o
 endif
diff --git a/tools/perf/arch/arm/tests/Build b/tools/perf/arch/arm/tests/Build
new file mode 100644 (file)
index 0000000..b30eff9
--- /dev/null
@@ -0,0 +1,2 @@
+libperf-y += regs_load.o
+libperf-y += dwarf-unwind.o
diff --git a/tools/perf/arch/arm/util/Build b/tools/perf/arch/arm/util/Build
new file mode 100644 (file)
index 0000000..d22e3d0
--- /dev/null
@@ -0,0 +1,4 @@
+libperf-$(CONFIG_DWARF) += dwarf-regs.o
+
+libperf-$(CONFIG_LIBUNWIND)          += unwind-libunwind.o
+libperf-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o
diff --git a/tools/perf/arch/arm64/Build b/tools/perf/arch/arm64/Build
new file mode 100644 (file)
index 0000000..54afe4a
--- /dev/null
@@ -0,0 +1 @@
+libperf-y += util/
index 67e9b3d..7fbca17 100644 (file)
@@ -1,7 +1,3 @@
 ifndef NO_DWARF
 PERF_HAVE_DWARF_REGS := 1
-LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/dwarf-regs.o
-endif
-ifndef NO_LIBUNWIND
-LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/unwind-libunwind.o
 endif
diff --git a/tools/perf/arch/arm64/util/Build b/tools/perf/arch/arm64/util/Build
new file mode 100644 (file)
index 0000000..e58123a
--- /dev/null
@@ -0,0 +1,2 @@
+libperf-$(CONFIG_DWARF)     += dwarf-regs.o
+libperf-$(CONFIG_LIBUNWIND) += unwind-libunwind.o
diff --git a/tools/perf/arch/powerpc/Build b/tools/perf/arch/powerpc/Build
new file mode 100644 (file)
index 0000000..54afe4a
--- /dev/null
@@ -0,0 +1 @@
+libperf-y += util/
index 6f7782b..7fbca17 100644 (file)
@@ -1,6 +1,3 @@
 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
diff --git a/tools/perf/arch/powerpc/util/Build b/tools/perf/arch/powerpc/util/Build
new file mode 100644 (file)
index 0000000..0af6e9b
--- /dev/null
@@ -0,0 +1,4 @@
+libperf-y += header.o
+
+libperf-$(CONFIG_DWARF) += dwarf-regs.o
+libperf-$(CONFIG_DWARF) += skip-callchain-idx.o
diff --git a/tools/perf/arch/s390/Build b/tools/perf/arch/s390/Build
new file mode 100644 (file)
index 0000000..54afe4a
--- /dev/null
@@ -0,0 +1 @@
+libperf-y += util/
index 798ac73..21322e0 100644 (file)
@@ -1,7 +1,4 @@
 ifndef NO_DWARF
 PERF_HAVE_DWARF_REGS := 1
-LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/dwarf-regs.o
 endif
-LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/header.o
 HAVE_KVM_STAT_SUPPORT := 1
-LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/kvm-stat.o
diff --git a/tools/perf/arch/s390/util/Build b/tools/perf/arch/s390/util/Build
new file mode 100644 (file)
index 0000000..8a61372
--- /dev/null
@@ -0,0 +1,4 @@
+libperf-y += header.o
+libperf-y += kvm-stat.o
+
+libperf-$(CONFIG_DWARF) += dwarf-regs.o
diff --git a/tools/perf/arch/sh/Build b/tools/perf/arch/sh/Build
new file mode 100644 (file)
index 0000000..54afe4a
--- /dev/null
@@ -0,0 +1 @@
+libperf-y += util/
index 15130b5..7fbca17 100644 (file)
@@ -1,4 +1,3 @@
 ifndef NO_DWARF
 PERF_HAVE_DWARF_REGS := 1
-LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/dwarf-regs.o
 endif
diff --git a/tools/perf/arch/sh/util/Build b/tools/perf/arch/sh/util/Build
new file mode 100644 (file)
index 0000000..954e287
--- /dev/null
@@ -0,0 +1 @@
+libperf-$(CONFIG_DWARF) += dwarf-regs.o
diff --git a/tools/perf/arch/sparc/Build b/tools/perf/arch/sparc/Build
new file mode 100644 (file)
index 0000000..54afe4a
--- /dev/null
@@ -0,0 +1 @@
+libperf-y += util/
index 15130b5..7fbca17 100644 (file)
@@ -1,4 +1,3 @@
 ifndef NO_DWARF
 PERF_HAVE_DWARF_REGS := 1
-LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/dwarf-regs.o
 endif
diff --git a/tools/perf/arch/sparc/util/Build b/tools/perf/arch/sparc/util/Build
new file mode 100644 (file)
index 0000000..954e287
--- /dev/null
@@ -0,0 +1 @@
+libperf-$(CONFIG_DWARF) += dwarf-regs.o
diff --git a/tools/perf/arch/x86/Build b/tools/perf/arch/x86/Build
new file mode 100644 (file)
index 0000000..41bf61d
--- /dev/null
@@ -0,0 +1,2 @@
+libperf-y += util/
+libperf-$(CONFIG_DWARF_UNWIND) += tests/
index 9b21881..21322e0 100644 (file)
@@ -1,19 +1,4 @@
 ifndef NO_DWARF
 PERF_HAVE_DWARF_REGS := 1
-LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/dwarf-regs.o
 endif
-ifndef NO_LIBUNWIND
-LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/unwind-libunwind.o
-endif
-ifndef NO_LIBDW_DWARF_UNWIND
-LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/unwind-libdw.o
-endif
-ifndef NO_DWARF_UNWIND
-LIB_OBJS += $(OUTPUT)arch/$(ARCH)/tests/regs_load.o
-LIB_OBJS += $(OUTPUT)arch/$(ARCH)/tests/dwarf-unwind.o
-endif
-LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/header.o
-LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/tsc.o
-LIB_H += arch/$(ARCH)/util/tsc.h
 HAVE_KVM_STAT_SUPPORT := 1
-LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/kvm-stat.o
diff --git a/tools/perf/arch/x86/tests/Build b/tools/perf/arch/x86/tests/Build
new file mode 100644 (file)
index 0000000..b30eff9
--- /dev/null
@@ -0,0 +1,2 @@
+libperf-y += regs_load.o
+libperf-y += dwarf-unwind.o
diff --git a/tools/perf/arch/x86/util/Build b/tools/perf/arch/x86/util/Build
new file mode 100644 (file)
index 0000000..cfbccc4
--- /dev/null
@@ -0,0 +1,8 @@
+libperf-y += header.o
+libperf-y += tsc.o
+libperf-y += kvm-stat.o
+
+libperf-$(CONFIG_DWARF) += dwarf-regs.o
+
+libperf-$(CONFIG_LIBUNWIND)          += unwind-libunwind.o
+libperf-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o
diff --git a/tools/perf/bench/Build b/tools/perf/bench/Build
new file mode 100644 (file)
index 0000000..5ce9802
--- /dev/null
@@ -0,0 +1,11 @@
+perf-y += sched-messaging.o
+perf-y += sched-pipe.o
+perf-y += mem-memcpy.o
+perf-y += futex-hash.o
+perf-y += futex-wake.o
+perf-y += futex-requeue.o
+
+perf-$(CONFIG_X86_64) += mem-memcpy-x86-64-asm.o
+perf-$(CONFIG_X86_64) += mem-memset-x86-64-asm.o
+
+perf-$(CONFIG_NUMA) += numa.o
index 50e6b66..d929d95 100644 (file)
@@ -125,8 +125,7 @@ static int build_id_cache__kcore_existing(const char *from_dir, char *to_dir,
        return ret;
 }
 
-static int build_id_cache__add_kcore(const char *filename, const char *debugdir,
-                                    bool force)
+static int build_id_cache__add_kcore(const char *filename, bool force)
 {
        char dir[32], sbuildid[BUILD_ID_SIZE * 2 + 1];
        char from_dir[PATH_MAX], to_dir[PATH_MAX];
@@ -143,7 +142,7 @@ static int build_id_cache__add_kcore(const char *filename, const char *debugdir,
                return -1;
 
        scnprintf(to_dir, sizeof(to_dir), "%s/[kernel.kcore]/%s",
-                 debugdir, sbuildid);
+                 buildid_dir, sbuildid);
 
        if (!force &&
            !build_id_cache__kcore_existing(from_dir, to_dir, sizeof(to_dir))) {
@@ -155,7 +154,7 @@ static int build_id_cache__add_kcore(const char *filename, const char *debugdir,
                return -1;
 
        scnprintf(to_dir, sizeof(to_dir), "%s/[kernel.kcore]/%s/%s",
-                 debugdir, sbuildid, dir);
+                 buildid_dir, sbuildid, dir);
 
        if (mkdir_p(to_dir, 0755))
                return -1;
@@ -183,7 +182,7 @@ static int build_id_cache__add_kcore(const char *filename, const char *debugdir,
        return 0;
 }
 
-static int build_id_cache__add_file(const char *filename, const char *debugdir)
+static int build_id_cache__add_file(const char *filename)
 {
        char sbuild_id[BUILD_ID_SIZE * 2 + 1];
        u8 build_id[BUILD_ID_SIZE];
@@ -195,7 +194,7 @@ static int build_id_cache__add_file(const char *filename, const char *debugdir)
        }
 
        build_id__sprintf(build_id, sizeof(build_id), sbuild_id);
-       err = build_id_cache__add_s(sbuild_id, debugdir, filename,
+       err = build_id_cache__add_s(sbuild_id, filename,
                                    false, false);
        if (verbose)
                pr_info("Adding %s %s: %s\n", sbuild_id, filename,
@@ -203,8 +202,7 @@ static int build_id_cache__add_file(const char *filename, const char *debugdir)
        return err;
 }
 
-static int build_id_cache__remove_file(const char *filename,
-                                      const char *debugdir)
+static int build_id_cache__remove_file(const char *filename)
 {
        u8 build_id[BUILD_ID_SIZE];
        char sbuild_id[BUILD_ID_SIZE * 2 + 1];
@@ -217,7 +215,7 @@ static int build_id_cache__remove_file(const char *filename,
        }
 
        build_id__sprintf(build_id, sizeof(build_id), sbuild_id);
-       err = build_id_cache__remove_s(sbuild_id, debugdir);
+       err = build_id_cache__remove_s(sbuild_id);
        if (verbose)
                pr_info("Removing %s %s: %s\n", sbuild_id, filename,
                        err ? "FAIL" : "Ok");
@@ -252,8 +250,7 @@ static int build_id_cache__fprintf_missing(struct perf_session *session, FILE *f
        return 0;
 }
 
-static int build_id_cache__update_file(const char *filename,
-                                      const char *debugdir)
+static int build_id_cache__update_file(const char *filename)
 {
        u8 build_id[BUILD_ID_SIZE];
        char sbuild_id[BUILD_ID_SIZE * 2 + 1];
@@ -266,11 +263,10 @@ static int build_id_cache__update_file(const char *filename,
        }
 
        build_id__sprintf(build_id, sizeof(build_id), sbuild_id);
-       err = build_id_cache__remove_s(sbuild_id, debugdir);
-       if (!err) {
-               err = build_id_cache__add_s(sbuild_id, debugdir, filename,
-                                           false, false);
-       }
+       err = build_id_cache__remove_s(sbuild_id);
+       if (!err)
+               err = build_id_cache__add_s(sbuild_id, filename, false, false);
+
        if (verbose)
                pr_info("Updating %s %s: %s\n", sbuild_id, filename,
                        err ? "FAIL" : "Ok");
@@ -338,7 +334,7 @@ int cmd_buildid_cache(int argc, const char **argv,
                list = strlist__new(true, add_name_list_str);
                if (list) {
                        strlist__for_each(pos, list)
-                               if (build_id_cache__add_file(pos->s, buildid_dir)) {
+                               if (build_id_cache__add_file(pos->s)) {
                                        if (errno == EEXIST) {
                                                pr_debug("%s already in the cache\n",
                                                         pos->s);
@@ -356,7 +352,7 @@ int cmd_buildid_cache(int argc, const char **argv,
                list = strlist__new(true, remove_name_list_str);
                if (list) {
                        strlist__for_each(pos, list)
-                               if (build_id_cache__remove_file(pos->s, buildid_dir)) {
+                               if (build_id_cache__remove_file(pos->s)) {
                                        if (errno == ENOENT) {
                                                pr_debug("%s wasn't in the cache\n",
                                                         pos->s);
@@ -377,7 +373,7 @@ int cmd_buildid_cache(int argc, const char **argv,
                list = strlist__new(true, update_name_list_str);
                if (list) {
                        strlist__for_each(pos, list)
-                               if (build_id_cache__update_file(pos->s, buildid_dir)) {
+                               if (build_id_cache__update_file(pos->s)) {
                                        if (errno == ENOENT) {
                                                pr_debug("%s wasn't in the cache\n",
                                                         pos->s);
@@ -391,8 +387,7 @@ int cmd_buildid_cache(int argc, const char **argv,
                }
        }
 
-       if (kcore_filename &&
-           build_id_cache__add_kcore(kcore_filename, buildid_dir, force))
+       if (kcore_filename && build_id_cache__add_kcore(kcore_filename, force))
                pr_warning("Couldn't add %s\n", kcore_filename);
 
 out:
index 198f3c3..ad8018e 100644 (file)
@@ -41,6 +41,9 @@ int cmd_list(int argc, const char **argv, const char *prefix __maybe_unused)
                return 0;
        }
 
+       if (!raw_dump)
+               printf("\nList of pre-defined events (to be used in -e):\n\n");
+
        if (argc == 0) {
                print_events(NULL, false);
                return 0;
index 404ab34..d0d02a8 100644 (file)
@@ -658,7 +658,7 @@ error:
 
 static void callchain_debug(void)
 {
-       static const char *str[CALLCHAIN_MAX] = { "NONE", "FP", "DWARF" };
+       static const char *str[CALLCHAIN_MAX] = { "NONE", "FP", "DWARF", "LBR" };
 
        pr_debug("callchain: type %s\n", str[callchain_param.record_mode]);
 
@@ -751,9 +751,9 @@ static struct record record = {
 #define CALLCHAIN_HELP "setup and enables call-graph (stack chain/backtrace) recording: "
 
 #ifdef HAVE_DWARF_UNWIND_SUPPORT
-const char record_callchain_help[] = CALLCHAIN_HELP "fp dwarf";
+const char record_callchain_help[] = CALLCHAIN_HELP "fp dwarf lbr";
 #else
-const char record_callchain_help[] = CALLCHAIN_HELP "fp";
+const char record_callchain_help[] = CALLCHAIN_HELP "fp lbr";
 #endif
 
 /*
index 2f91094..0ba5f07 100644 (file)
@@ -249,6 +249,8 @@ static int report__setup_sample_type(struct report *rep)
                if ((sample_type & PERF_SAMPLE_REGS_USER) &&
                    (sample_type & PERF_SAMPLE_STACK_USER))
                        callchain_param.record_mode = CALLCHAIN_DWARF;
+               else if (sample_type & PERF_SAMPLE_BRANCH_STACK)
+                       callchain_param.record_mode = CALLCHAIN_LBR;
                else
                        callchain_param.record_mode = CALLCHAIN_FP;
        }
index 7e935f1..b1c1df9 100644 (file)
@@ -1219,7 +1219,9 @@ struct trace {
                struct syscall  *table;
        } syscalls;
        struct record_opts      opts;
+       struct perf_evlist      *evlist;
        struct machine          *host;
+       struct thread           *current;
        u64                     base_time;
        FILE                    *output;
        unsigned long           nr_events;
@@ -1642,6 +1644,29 @@ static void thread__update_stats(struct thread_trace *ttrace,
        update_stats(stats, duration);
 }
 
+static int trace__printf_interrupted_entry(struct trace *trace, struct perf_sample *sample)
+{
+       struct thread_trace *ttrace;
+       u64 duration;
+       size_t printed;
+
+       if (trace->current == NULL)
+               return 0;
+
+       ttrace = thread__priv(trace->current);
+
+       if (!ttrace->entry_pending)
+               return 0;
+
+       duration = sample->time - ttrace->entry_time;
+
+       printed  = trace__fprintf_entry_head(trace, trace->current, duration, sample->time, trace->output);
+       printed += fprintf(trace->output, "%-70s) ...\n", ttrace->entry_str);
+       ttrace->entry_pending = false;
+
+       return printed;
+}
+
 static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
                            union perf_event *event __maybe_unused,
                            struct perf_sample *sample)
@@ -1673,6 +1698,8 @@ static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
                        return -1;
        }
 
+       printed += trace__printf_interrupted_entry(trace, sample);
+
        ttrace->entry_time = sample->time;
        msg = ttrace->entry_str;
        printed += scnprintf(msg + printed, 1024 - printed, "%s(", sc->name);
@@ -1688,6 +1715,8 @@ static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
        } else
                ttrace->entry_pending = true;
 
+       trace->current = thread;
+
        return 0;
 }
 
@@ -1805,6 +1834,24 @@ out_dump:
        return 0;
 }
 
+static int trace__event_handler(struct trace *trace, struct perf_evsel *evsel,
+                               union perf_event *event __maybe_unused,
+                               struct perf_sample *sample)
+{
+       trace__printf_interrupted_entry(trace, sample);
+       trace__fprintf_tstamp(trace, sample->time, trace->output);
+       fprintf(trace->output, "(%9.9s): %s:", " ", evsel->name);
+
+       if (evsel->tp_format) {
+               event_format__fprintf(evsel->tp_format, sample->cpu,
+                                     sample->raw_data, sample->raw_size,
+                                     trace->output);
+       }
+
+       fprintf(trace->output, ")\n");
+       return 0;
+}
+
 static void print_location(FILE *f, struct perf_sample *sample,
                           struct addr_location *al,
                           bool print_dso, bool print_sym)
@@ -2039,7 +2086,7 @@ static int perf_evlist__add_pgfault(struct perf_evlist *evlist,
 
 static int trace__run(struct trace *trace, int argc, const char **argv)
 {
-       struct perf_evlist *evlist = perf_evlist__new();
+       struct perf_evlist *evlist = trace->evlist;
        struct perf_evsel *evsel;
        int err = -1, i;
        unsigned long before;
@@ -2048,11 +2095,6 @@ static int trace__run(struct trace *trace, int argc, const char **argv)
 
        trace->live = true;
 
-       if (evlist == NULL) {
-               fprintf(trace->output, "Not enough memory to run!\n");
-               goto out;
-       }
-
        if (trace->trace_syscalls &&
            perf_evlist__add_syscall_newtp(evlist, trace__sys_enter,
                                           trace__sys_exit))
@@ -2109,12 +2151,14 @@ static int trace__run(struct trace *trace, int argc, const char **argv)
        if (err < 0)
                goto out_error_mmap;
 
-       perf_evlist__enable(evlist);
-
        if (forks)
                perf_evlist__start_workload(evlist);
+       else
+               perf_evlist__enable(evlist);
 
-       trace->multiple_threads = evlist->threads->map[0] == -1 || evlist->threads->nr > 1;
+       trace->multiple_threads = evlist->threads->map[0] == -1 ||
+                                 evlist->threads->nr > 1 ||
+                                 perf_evlist__first(evlist)->attr.inherit;
 again:
        before = trace->nr_events;
 
@@ -2197,7 +2241,7 @@ out_disable:
 
 out_delete_evlist:
        perf_evlist__delete(evlist);
-out:
+       trace->evlist = NULL;
        trace->live = false;
        return err;
 {
@@ -2468,6 +2512,14 @@ static int parse_pagefaults(const struct option *opt, const char *str,
        return 0;
 }
 
+static void evlist__set_evsel_handler(struct perf_evlist *evlist, void *handler)
+{
+       struct perf_evsel *evsel;
+
+       evlist__for_each(evlist, evsel)
+               evsel->handler = handler;
+}
+
 int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
 {
        const char * const trace_usage[] = {
@@ -2502,6 +2554,9 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
        const char *output_name = NULL;
        const char *ev_qualifier_str = NULL;
        const struct option trace_options[] = {
+       OPT_CALLBACK(0, "event", &trace.evlist, "event",
+                    "event selector. use 'perf list' to list available events",
+                    parse_events_option),
        OPT_BOOLEAN(0, "comm", &trace.show_comm,
                    "show the thread COMM next to its id"),
        OPT_BOOLEAN(0, "tool_stats", &trace.show_tool_stats, "show tool stats"),
@@ -2543,6 +2598,15 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
        int err;
        char bf[BUFSIZ];
 
+       trace.evlist = perf_evlist__new();
+       if (trace.evlist == NULL)
+               return -ENOMEM;
+
+       if (trace.evlist == NULL) {
+               pr_err("Not enough memory to run!\n");
+               goto out;
+       }
+
        argc = parse_options(argc, argv, trace_options, trace_usage,
                             PARSE_OPT_STOP_AT_NON_OPTION);
 
@@ -2551,6 +2615,9 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
                trace.opts.sample_time = true;
        }
 
+       if (trace.evlist->nr_entries > 0)
+               evlist__set_evsel_handler(trace.evlist, trace__event_handler);
+
        if ((argc >= 1) && (strcmp(argv[0], "record") == 0))
                return trace__record(&trace, argc-1, &argv[1]);
 
@@ -2558,7 +2625,8 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
        if (trace.summary_only)
                trace.summary = trace.summary_only;
 
-       if (!trace.trace_syscalls && !trace.trace_pgfaults) {
+       if (!trace.trace_syscalls && !trace.trace_pgfaults &&
+           trace.evlist->nr_entries == 0 /* Was --events used? */) {
                pr_err("Please specify something to trace.\n");
                return -1;
        }
index cc22408..b97a7b9 100644 (file)
@@ -11,19 +11,27 @@ ifneq ($(obj-perf),)
 obj-perf := $(abspath $(obj-perf))/
 endif
 
+$(shell echo -n > .config-detected)
+detected     = $(shell echo "$(1)=y"       >> .config-detected)
+detected_var = $(shell echo "$(1)=$($(1))" >> .config-detected)
+
 LIB_INCLUDE := $(srctree)/tools/lib/
 CFLAGS := $(EXTRA_CFLAGS) $(EXTRA_WARNINGS)
 
 include $(src-perf)/config/Makefile.arch
 
+$(call detected_var,ARCH)
+
 NO_PERF_REGS := 1
 
 # Additional ARCH settings for x86
 ifeq ($(ARCH),x86)
+  $(call detected,CONFIG_X86)
   ifeq (${IS_64_BIT}, 1)
     CFLAGS += -DHAVE_ARCH_X86_64_SUPPORT
     ARCH_INCLUDE = ../../arch/x86/lib/memcpy_64.S ../../arch/x86/lib/memset_64.S
     LIBUNWIND_LIBS = -lunwind -lunwind-x86_64
+    $(call detected,CONFIG_X86_64)
   else
     LIBUNWIND_LIBS = -lunwind -lunwind-x86
   endif
@@ -40,6 +48,10 @@ ifeq ($(ARCH),arm64)
   LIBUNWIND_LIBS = -lunwind -lunwind-aarch64
 endif
 
+ifeq ($(NO_PERF_REGS),0)
+  $(call detected,CONFIG_PERF_REGS)
+endif
+
 # So far there's only x86 and arm libdw unwind support merged in perf.
 # Disable it on all other architectures in case libdw unwind
 # support is detected in system. Add supported architectures
@@ -114,6 +126,8 @@ ifdef PARSER_DEBUG
   PARSER_DEBUG_BISON := -t
   PARSER_DEBUG_FLEX  := -d
   CFLAGS             += -DPARSER_DEBUG
+  $(call detected_var,PARSER_DEBUG_BISON)
+  $(call detected_var,PARSER_DEBUG_FLEX)
 endif
 
 ifndef NO_LIBPYTHON
@@ -361,6 +375,7 @@ endif # NO_LIBELF
 ifndef NO_LIBELF
   CFLAGS += -DHAVE_LIBELF_SUPPORT
   EXTLIBS += -lelf
+  $(call detected,CONFIG_LIBELF)
 
   ifeq ($(feature-libelf-mmap), 1)
     CFLAGS += -DHAVE_LIBELF_MMAP_SUPPORT
@@ -381,6 +396,7 @@ ifndef NO_LIBELF
       CFLAGS += -DHAVE_DWARF_SUPPORT $(LIBDW_CFLAGS)
       LDFLAGS += $(LIBDW_LDFLAGS)
       EXTLIBS += -ldw
+      $(call detected,CONFIG_DWARF)
     endif # PERF_HAVE_DWARF_REGS
   endif # NO_DWARF
 endif # NO_LIBELF
@@ -408,9 +424,11 @@ ifdef NO_LIBUNWIND
     dwarf-post-unwind := 0
   else
     dwarf-post-unwind-text := libdw
+    $(call detected,CONFIG_LIBDW_DWARF_UNWIND)
   endif
 else
   dwarf-post-unwind-text := libunwind
+  $(call detected,CONFIG_LIBUNWIND)
   # Enable libunwind support by default.
   ifndef NO_LIBDW_DWARF_UNWIND
     NO_LIBDW_DWARF_UNWIND := 1
@@ -419,6 +437,7 @@ endif
 
 ifeq ($(dwarf-post-unwind),1)
   CFLAGS += -DHAVE_DWARF_UNWIND_SUPPORT
+  $(call detected,CONFIG_DWARF_UNWIND)
 else
   NO_DWARF_UNWIND := 1
 endif
@@ -447,6 +466,7 @@ ifndef NO_LIBAUDIT
   else
     CFLAGS += -DHAVE_LIBAUDIT_SUPPORT
     EXTLIBS += -laudit
+    $(call detected,CONFIG_AUDIT)
   endif
 endif
 
@@ -463,6 +483,7 @@ ifndef NO_SLANG
     CFLAGS += -I/usr/include/slang
     CFLAGS += -DHAVE_SLANG_SUPPORT
     EXTLIBS += -lslang
+    $(call detected,CONFIG_SLANG)
   endif
 endif
 
@@ -501,6 +522,7 @@ else
   else
     LDFLAGS += $(PERL_EMBED_LDFLAGS)
     EXTLIBS += $(PERL_EMBED_LIBADD)
+    $(call detected,CONFIG_LIBPERL)
   endif
 endif
 
@@ -560,6 +582,7 @@ else
           LDFLAGS += $(PYTHON_EMBED_LDFLAGS)
           EXTLIBS += $(PYTHON_EMBED_LIBADD)
           LANG_BINDINGS += $(obj-perf)python/perf.so
+          $(call detected,CONFIG_LIBPYTHON)
         endif
       endif
     endif
@@ -617,6 +640,7 @@ ifndef NO_ZLIB
   ifeq ($(feature-zlib), 1)
     CFLAGS += -DHAVE_ZLIB_SUPPORT
     EXTLIBS += -lz
+    $(call detected,CONFIG_ZLIB)
   else
     NO_ZLIB := 1
   endif
@@ -635,6 +659,7 @@ ifndef NO_LIBNUMA
   else
     CFLAGS += -DHAVE_LIBNUMA_SUPPORT
     EXTLIBS += -lnuma
+    $(call detected,CONFIG_NUMA)
   endif
 endif
 
@@ -815,3 +840,19 @@ endif
 ifeq ($(display_lib),1)
   $(info )
 endif
+
+$(call detected_var,bindir_SQ)
+$(call detected_var,PYTHON_WORD)
+ifneq ($(OUTPUT),)
+$(call detected_var,OUTPUT)
+endif
+$(call detected_var,htmldir_SQ)
+$(call detected_var,infodir_SQ)
+$(call detected_var,mandir_SQ)
+$(call detected_var,ETC_PERFCONFIG_SQ)
+$(call detected_var,prefix_SQ)
+$(call detected_var,perfexecdir_SQ)
+$(call detected_var,LIBDIR)
+$(call detected_var,GTK_CFLAGS)
+$(call detected_var,PERL_EMBED_CCOPTS)
+$(call detected_var,PYTHON_EMBED_CCOPTS)
index 42ac05a..b32ff33 100644 (file)
@@ -49,7 +49,7 @@ test-hello.bin:
        $(BUILD)
 
 test-pthread-attr-setaffinity-np.bin:
-       $(BUILD) -Werror -lpthread
+       $(BUILD) -D_GNU_SOURCE -Werror -lpthread
 
 test-stackprotector-all.bin:
        $(BUILD) -Werror -fstack-protector-all
diff --git a/tools/perf/scripts/Build b/tools/perf/scripts/Build
new file mode 100644 (file)
index 0000000..41efd7e
--- /dev/null
@@ -0,0 +1,2 @@
+libperf-$(CONFIG_LIBPERL)   += perl/Perf-Trace-Util/
+libperf-$(CONFIG_LIBPYTHON) += python/Perf-Trace-Util/
diff --git a/tools/perf/scripts/perl/Perf-Trace-Util/Build b/tools/perf/scripts/perl/Perf-Trace-Util/Build
new file mode 100644 (file)
index 0000000..928e110
--- /dev/null
@@ -0,0 +1,3 @@
+libperf-y += Context.o
+
+CFLAGS_Context.o += $(PERL_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-nested-externs -Wno-undef -Wno-switch-default
diff --git a/tools/perf/scripts/python/Perf-Trace-Util/Build b/tools/perf/scripts/python/Perf-Trace-Util/Build
new file mode 100644 (file)
index 0000000..aefc15c
--- /dev/null
@@ -0,0 +1,3 @@
+libperf-y += Context.o
+
+CFLAGS_Context.o += $(PYTHON_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-nested-externs
diff --git a/tools/perf/tests/Build b/tools/perf/tests/Build
new file mode 100644 (file)
index 0000000..2de01a4
--- /dev/null
@@ -0,0 +1,42 @@
+perf-y += builtin-test.o
+perf-y += parse-events.o
+perf-y += dso-data.o
+perf-y += attr.o
+perf-y += vmlinux-kallsyms.o
+perf-y += open-syscall.o
+perf-y += open-syscall-all-cpus.o
+perf-y += open-syscall-tp-fields.o
+perf-y += mmap-basic.o
+perf-y += perf-record.o
+perf-y += rdpmc.o
+perf-y += evsel-roundtrip-name.o
+perf-y += evsel-tp-sched.o
+perf-y += fdarray.o
+perf-y += pmu.o
+perf-y += hists_common.o
+perf-y += hists_link.o
+perf-y += hists_filter.o
+perf-y += hists_output.o
+perf-y += hists_cumulate.o
+perf-y += python-use.o
+perf-y += bp_signal.o
+perf-y += bp_signal_overflow.o
+perf-y += task-exit.o
+perf-y += sw-clock.o
+perf-y += mmap-thread-lookup.o
+perf-y += thread-mg-share.o
+perf-y += switch-tracking.o
+perf-y += keep-tracking.o
+perf-y += code-reading.o
+perf-y += sample-parsing.o
+perf-y += parse-no-sample-id-all.o
+
+perf-$(CONFIG_X86) += perf-time-to-tsc.o
+
+ifeq ($(ARCH),$(filter $(ARCH),x86 arm))
+perf-$(CONFIG_DWARF_UNWIND) += dwarf-unwind.o
+endif
+
+CFLAGS_attr.o         += -DBINDIR="BUILD_STR($(bindir_SQ))" -DPYTHON="BUILD_STR($(PYTHON_WORD))"
+CFLAGS_python-use.o   += -DPYTHONPATH="BUILD_STR($(OUTPUT)python)" -DPYTHON="BUILD_STR($(PYTHON_WORD))"
+CFLAGS_dwarf-unwind.o += -fno-optimize-sibling-calls
index caaf37f..513e5fe 100644 (file)
@@ -112,6 +112,9 @@ int test__dso_data(void)
 
        dso = dso__new((const char *)file);
 
+       TEST_ASSERT_VAL("Failed to access to dso",
+                       dso__data_fd(dso, &machine) >= 0);
+
        /* Basic 10 bytes tests. */
        for (i = 0; i < ARRAY_SIZE(offsets); i++) {
                struct test_data_offset *data = &offsets[i];
@@ -243,8 +246,8 @@ int test__dso_data_cache(void)
        limit = nr * 4;
        TEST_ASSERT_VAL("failed to set file limit", !set_fd_limit(limit));
 
-       /* and this is now our dso open FDs limit + 1 extra */
-       dso_cnt = limit / 2 + 1;
+       /* and this is now our dso open FDs limit */
+       dso_cnt = limit / 2;
        TEST_ASSERT_VAL("failed to create dsos\n",
                !dsos__create(dso_cnt, TEST_FILE_SIZE));
 
@@ -252,13 +255,13 @@ int test__dso_data_cache(void)
                struct dso *dso = dsos[i];
 
                /*
-                * Open dsos via dso__data_fd or dso__data_read_offset.
-                * Both opens the data file and keep it open.
+                * Open dsos via dso__data_fd(), it opens the data
+                * file and keep it open (unless open file limit).
                 */
+               fd = dso__data_fd(dso, &machine);
+               TEST_ASSERT_VAL("failed to get fd", fd > 0);
+
                if (i % 2) {
-                       fd = dso__data_fd(dso, &machine);
-                       TEST_ASSERT_VAL("failed to get fd", fd > 0);
-               } else {
                        #define BUFSIZE 10
                        u8 buf[BUFSIZE];
                        ssize_t n;
@@ -268,7 +271,10 @@ int test__dso_data_cache(void)
                }
        }
 
-       /* open +1 dso over the allowed limit */
+       /* verify the first one is already open */
+       TEST_ASSERT_VAL("dsos[0] is not open", dsos[0]->data.fd != -1);
+
+       /* open +1 dso to reach the allowed limit */
        fd = dso__data_fd(dsos[i], &machine);
        TEST_ASSERT_VAL("failed to get fd", fd > 0);
 
index 8fa82d1..3ec885c 100644 (file)
@@ -29,7 +29,12 @@ int test__open_syscall_event_on_all_cpus(void)
 
        evsel = perf_evsel__newtp("syscalls", "sys_enter_open");
        if (evsel == NULL) {
-               pr_debug("is debugfs mounted on /sys/kernel/debug?\n");
+               if (tracefs_configured())
+                       pr_debug("is tracefs mounted on /sys/kernel/tracing?\n");
+               else if (debugfs_configured())
+                       pr_debug("is debugfs mounted on /sys/kernel/debug?\n");
+               else
+                       pr_debug("Neither tracefs or debugfs is enabled in this kernel\n");
                goto out_thread_map_delete;
        }
 
index a33b2da..07aa319 100644 (file)
@@ -18,7 +18,12 @@ int test__open_syscall_event(void)
 
        evsel = perf_evsel__newtp("syscalls", "sys_enter_open");
        if (evsel == NULL) {
-               pr_debug("is debugfs mounted on /sys/kernel/debug?\n");
+               if (tracefs_configured())
+                       pr_debug("is tracefs mounted on /sys/kernel/tracing?\n");
+               else if (debugfs_configured())
+                       pr_debug("is debugfs mounted on /sys/kernel/debug?\n");
+               else
+                       pr_debug("Neither tracefs or debugfs is enabled in this kernel\n");
                goto out_thread_map_delete;
        }
 
index 1cdab0c..ac243eb 100644 (file)
@@ -3,6 +3,7 @@
 #include "evsel.h"
 #include "evlist.h"
 #include <api/fs/fs.h>
+#include <api/fs/tracefs.h>
 #include <api/fs/debugfs.h>
 #include "tests.h"
 #include "debug.h"
@@ -1192,11 +1193,19 @@ static int count_tracepoints(void)
 {
        char events_path[PATH_MAX];
        struct dirent *events_ent;
+       const char *mountpoint;
        DIR *events_dir;
        int cnt = 0;
 
-       scnprintf(events_path, PATH_MAX, "%s/tracing/events",
-                 debugfs_find_mountpoint());
+       mountpoint = tracefs_find_mountpoint();
+       if (mountpoint) {
+               scnprintf(events_path, PATH_MAX, "%s/events",
+                         mountpoint);
+       } else {
+               mountpoint = debugfs_find_mountpoint();
+               scnprintf(events_path, PATH_MAX, "%s/tracing/events",
+                         mountpoint);
+       }
 
        events_dir = opendir(events_path);
 
diff --git a/tools/perf/ui/Build b/tools/perf/ui/Build
new file mode 100644 (file)
index 0000000..0a73538
--- /dev/null
@@ -0,0 +1,14 @@
+libperf-y += setup.o
+libperf-y += helpline.o
+libperf-y += progress.o
+libperf-y += util.o
+libperf-y += hist.o
+libperf-y += stdio/hist.o
+
+CFLAGS_setup.o += -DLIBDIR="BUILD_STR($(LIBDIR))"
+
+libperf-$(CONFIG_SLANG) += browser.o
+libperf-$(CONFIG_SLANG) += browsers/
+libperf-$(CONFIG_SLANG) += tui/
+
+CFLAGS_browser.o += -DENABLE_SLFUTURE_CONST
diff --git a/tools/perf/ui/browsers/Build b/tools/perf/ui/browsers/Build
new file mode 100644 (file)
index 0000000..de223f5
--- /dev/null
@@ -0,0 +1,10 @@
+libperf-y += annotate.o
+libperf-y += hists.o
+libperf-y += map.o
+libperf-y += scripts.o
+libperf-y += header.o
+
+CFLAGS_annotate.o += -DENABLE_SLFUTURE_CONST
+CFLAGS_hists.o    += -DENABLE_SLFUTURE_CONST
+CFLAGS_map.o      += -DENABLE_SLFUTURE_CONST
+CFLAGS_scripts.o  += -DENABLE_SLFUTURE_CONST
diff --git a/tools/perf/ui/gtk/Build b/tools/perf/ui/gtk/Build
new file mode 100644 (file)
index 0000000..ec22e89
--- /dev/null
@@ -0,0 +1,9 @@
+CFLAGS_gtk += -fPIC $(GTK_CFLAGS)
+
+gtk-y += browser.o
+gtk-y += hists.o
+gtk-y += setup.o
+gtk-y += util.o
+gtk-y += helpline.o
+gtk-y += progress.o
+gtk-y += annotate.o
diff --git a/tools/perf/ui/tui/Build b/tools/perf/ui/tui/Build
new file mode 100644 (file)
index 0000000..9e4c6ca
--- /dev/null
@@ -0,0 +1,4 @@
+libperf-y += setup.o
+libperf-y += util.o
+libperf-y += helpline.o
+libperf-y += progress.o
diff --git a/tools/perf/util/Build b/tools/perf/util/Build
new file mode 100644 (file)
index 0000000..32f9327
--- /dev/null
@@ -0,0 +1,142 @@
+libperf-y += abspath.o
+libperf-y += alias.o
+libperf-y += annotate.o
+libperf-y += build-id.o
+libperf-y += config.o
+libperf-y += ctype.o
+libperf-y += db-export.o
+libperf-y += environment.o
+libperf-y += event.o
+libperf-y += evlist.o
+libperf-y += evsel.o
+libperf-y += exec_cmd.o
+libperf-y += find_next_bit.o
+libperf-y += help.o
+libperf-y += kallsyms.o
+libperf-y += levenshtein.o
+libperf-y += parse-options.o
+libperf-y += parse-events.o
+libperf-y += path.o
+libperf-y += rbtree.o
+libperf-y += bitmap.o
+libperf-y += hweight.o
+libperf-y += run-command.o
+libperf-y += quote.o
+libperf-y += strbuf.o
+libperf-y += string.o
+libperf-y += strlist.o
+libperf-y += strfilter.o
+libperf-y += top.o
+libperf-y += usage.o
+libperf-y += wrapper.o
+libperf-y += sigchain.o
+libperf-y += dso.o
+libperf-y += symbol.o
+libperf-y += color.o
+libperf-y += pager.o
+libperf-y += header.o
+libperf-y += callchain.o
+libperf-y += values.o
+libperf-y += debug.o
+libperf-y += machine.o
+libperf-y += map.o
+libperf-y += pstack.o
+libperf-y += session.o
+libperf-y += ordered-events.o
+libperf-y += comm.o
+libperf-y += thread.o
+libperf-y += thread_map.o
+libperf-y += trace-event-parse.o
+libperf-y += parse-events-flex.o
+libperf-y += parse-events-bison.o
+libperf-y += pmu.o
+libperf-y += pmu-flex.o
+libperf-y += pmu-bison.o
+libperf-y += trace-event-read.o
+libperf-y += trace-event-info.o
+libperf-y += trace-event-scripting.o
+libperf-y += trace-event.o
+libperf-y += svghelper.o
+libperf-y += sort.o
+libperf-y += hist.o
+libperf-y += util.o
+libperf-y += xyarray.o
+libperf-y += cpumap.o
+libperf-y += cgroup.o
+libperf-y += target.o
+libperf-y += rblist.o
+libperf-y += intlist.o
+libperf-y += vdso.o
+libperf-y += stat.o
+libperf-y += record.o
+libperf-y += srcline.o
+libperf-y += data.o
+libperf-y += tsc.o
+libperf-y += cloexec.o
+libperf-y += thread-stack.o
+
+libperf-$(CONFIG_LIBELF) += symbol-elf.o
+libperf-$(CONFIG_LIBELF) += probe-event.o
+
+ifndef CONFIG_LIBELF
+libperf-y += symbol-minimal.o
+endif
+
+libperf-$(CONFIG_DWARF) += probe-finder.o
+libperf-$(CONFIG_DWARF) += dwarf-aux.o
+
+libperf-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o
+libperf-$(CONFIG_LIBUNWIND)          += unwind-libunwind.o
+
+libperf-y += scripting-engines/
+
+libperf-$(CONFIG_PERF_REGS) += perf_regs.o
+libperf-$(CONFIG_ZLIB) += zlib.o
+
+CFLAGS_config.o   += -DETC_PERFCONFIG="BUILD_STR($(ETC_PERFCONFIG_SQ))"
+CFLAGS_exec_cmd.o += -DPERF_EXEC_PATH="BUILD_STR($(perfexecdir_SQ))" -DPREFIX="BUILD_STR($(prefix_SQ))"
+
+$(OUTPUT)util/parse-events-flex.c: util/parse-events.l $(OUTPUT)util/parse-events-bison.c
+       $(call rule_mkdir)
+       @$(call echo-cmd,flex)$(FLEX) -o $@ --header-file=$(OUTPUT)util/parse-events-flex.h $(PARSER_DEBUG_FLEX) util/parse-events.l
+
+$(OUTPUT)util/parse-events-bison.c: util/parse-events.y
+       $(call rule_mkdir)
+       @$(call echo-cmd,bison)$(BISON) -v util/parse-events.y -d $(PARSER_DEBUG_BISON) -o $@ -p parse_events_
+
+$(OUTPUT)util/pmu-flex.c: util/pmu.l $(OUTPUT)util/pmu-bison.c
+       $(call rule_mkdir)
+       @$(call echo-cmd,flex)$(FLEX) -o $@ --header-file=$(OUTPUT)util/pmu-flex.h util/pmu.l
+
+$(OUTPUT)util/pmu-bison.c: util/pmu.y
+       $(call rule_mkdir)
+       @$(call echo-cmd,bison)$(BISON) -v util/pmu.y -d -o $@ -p perf_pmu_
+
+CFLAGS_parse-events-flex.o  += -w
+CFLAGS_pmu-flex.o           += -w
+CFLAGS_parse-events-bison.o += -DYYENABLE_NLS=0 -DYYLTYPE_IS_TRIVIAL=0 -w
+CFLAGS_pmu-bison.o          += -DYYENABLE_NLS=0 -DYYLTYPE_IS_TRIVIAL=0 -w
+
+$(OUTPUT)util/parse-events.o: $(OUTPUT)util/parse-events-flex.c $(OUTPUT)util/parse-events-bison.c
+$(OUTPUT)util/pmu.o: $(OUTPUT)util/pmu-flex.c $(OUTPUT)util/pmu-bison.c
+
+CFLAGS_find_next_bit.o += -Wno-unused-parameter -DETC_PERFCONFIG="BUILD_STR($(ETC_PERFCONFIG_SQ))"
+CFLAGS_rbtree.o        += -Wno-unused-parameter -DETC_PERFCONFIG="BUILD_STR($(ETC_PERFCONFIG_SQ))"
+CFLAGS_hweight.o       += -Wno-unused-parameter -DETC_PERFCONFIG="BUILD_STR($(ETC_PERFCONFIG_SQ))"
+CFLAGS_parse-events.o  += -Wno-redundant-decls
+
+$(OUTPUT)util/kallsyms.o: ../lib/symbol/kallsyms.c FORCE
+       $(call rule_mkdir)
+       $(call if_changed_dep,cc_o_c)
+
+$(OUTPUT)util/find_next_bit.o: ../lib/util/find_next_bit.c FORCE
+       $(call rule_mkdir)
+       $(call if_changed_dep,cc_o_c)
+
+$(OUTPUT)util/rbtree.o: ../../lib/rbtree.c FORCE
+       $(call rule_mkdir)
+       $(call if_changed_dep,cc_o_c)
+
+$(OUTPUT)util/hweight.o: ../../lib/hweight.c FORCE
+       $(call rule_mkdir)
+       $(call if_changed_dep,cc_o_c)
index 0c72680..adbc360 100644 (file)
@@ -93,6 +93,35 @@ int build_id__sprintf(const u8 *build_id, int len, char *bf)
        return raw - build_id;
 }
 
+/* asnprintf consolidates asprintf and snprintf */
+static int asnprintf(char **strp, size_t size, const char *fmt, ...)
+{
+       va_list ap;
+       int ret;
+
+       if (!strp)
+               return -EINVAL;
+
+       va_start(ap, fmt);
+       if (*strp)
+               ret = vsnprintf(*strp, size, fmt, ap);
+       else
+               ret = vasprintf(strp, fmt, ap);
+       va_end(ap);
+
+       return ret;
+}
+
+static char *build_id__filename(const char *sbuild_id, char *bf, size_t size)
+{
+       char *tmp = bf;
+       int ret = asnprintf(&bf, size, "%s/.build-id/%.2s/%s", buildid_dir,
+                           sbuild_id, sbuild_id + 2);
+       if (ret < 0 || (tmp && size < (unsigned int)ret))
+               return NULL;
+       return bf;
+}
+
 char *dso__build_id_filename(const struct dso *dso, char *bf, size_t size)
 {
        char build_id_hex[BUILD_ID_SIZE * 2 + 1];
@@ -101,14 +130,7 @@ char *dso__build_id_filename(const struct dso *dso, char *bf, size_t size)
                return NULL;
 
        build_id__sprintf(dso->build_id, sizeof(dso->build_id), build_id_hex);
-       if (bf == NULL) {
-               if (asprintf(&bf, "%s/.build-id/%.2s/%s", buildid_dir,
-                            build_id_hex, build_id_hex + 2) < 0)
-                       return NULL;
-       } else
-               snprintf(bf, size, "%s/.build-id/%.2s/%s", buildid_dir,
-                        build_id_hex, build_id_hex + 2);
-       return bf;
+       return build_id__filename(build_id_hex, bf, size);
 }
 
 #define dsos__for_each_with_build_id(pos, head)        \
@@ -259,12 +281,12 @@ void disable_buildid_cache(void)
        no_buildid_cache = true;
 }
 
-int build_id_cache__add_s(const char *sbuild_id, const char *debugdir,
-                         const char *name, bool is_kallsyms, bool is_vdso)
+int build_id_cache__add_s(const char *sbuild_id, const char *name,
+                         bool is_kallsyms, bool is_vdso)
 {
        const size_t size = PATH_MAX;
        char *realname, *filename = zalloc(size),
-            *linkname = zalloc(size), *targetname;
+            *linkname = zalloc(size), *targetname, *tmp;
        int len, err = -1;
        bool slash = is_kallsyms || is_vdso;
 
@@ -282,7 +304,7 @@ int build_id_cache__add_s(const char *sbuild_id, const char *debugdir,
                goto out_free;
 
        len = scnprintf(filename, size, "%s%s%s",
-                      debugdir, slash ? "/" : "",
+                      buildid_dir, slash ? "/" : "",
                       is_vdso ? DSO__NAME_VDSO : realname);
        if (mkdir_p(filename, 0755))
                goto out_free;
@@ -297,14 +319,16 @@ int build_id_cache__add_s(const char *sbuild_id, const char *debugdir,
                        goto out_free;
        }
 
-       len = scnprintf(linkname, size, "%s/.build-id/%.2s",
-                      debugdir, sbuild_id);
+       if (!build_id__filename(sbuild_id, linkname, size))
+               goto out_free;
+       tmp = strrchr(linkname, '/');
+       *tmp = '\0';
 
        if (access(linkname, X_OK) && mkdir_p(linkname, 0755))
                goto out_free;
 
-       snprintf(linkname + len, size - len, "/%s", sbuild_id + 2);
-       targetname = filename + strlen(debugdir) - 5;
+       *tmp = '/';
+       targetname = filename + strlen(buildid_dir) - 5;
        memcpy(targetname, "../..", 5);
 
        if (symlink(targetname, linkname) == 0)
@@ -318,29 +342,28 @@ out_free:
 }
 
 static int build_id_cache__add_b(const u8 *build_id, size_t build_id_size,
-                                const char *name, const char *debugdir,
-                                bool is_kallsyms, bool is_vdso)
+                                const char *name, bool is_kallsyms,
+                                bool is_vdso)
 {
        char sbuild_id[BUILD_ID_SIZE * 2 + 1];
 
        build_id__sprintf(build_id, build_id_size, sbuild_id);
 
-       return build_id_cache__add_s(sbuild_id, debugdir, name,
-                                    is_kallsyms, is_vdso);
+       return build_id_cache__add_s(sbuild_id, name, is_kallsyms, is_vdso);
 }
 
-int build_id_cache__remove_s(const char *sbuild_id, const char *debugdir)
+int build_id_cache__remove_s(const char *sbuild_id)
 {
        const size_t size = PATH_MAX;
        char *filename = zalloc(size),
-            *linkname = zalloc(size);
+            *linkname = zalloc(size), *tmp;
        int err = -1;
 
        if (filename == NULL || linkname == NULL)
                goto out_free;
 
-       snprintf(linkname, size, "%s/.build-id/%.2s/%s",
-                debugdir, sbuild_id, sbuild_id + 2);
+       if (!build_id__filename(sbuild_id, linkname, size))
+               goto out_free;
 
        if (access(linkname, F_OK))
                goto out_free;
@@ -354,8 +377,8 @@ int build_id_cache__remove_s(const char *sbuild_id, const char *debugdir)
        /*
         * Since the link is relative, we must make it absolute:
         */
-       snprintf(linkname, size, "%s/.build-id/%.2s/%s",
-                debugdir, sbuild_id, filename);
+       tmp = strrchr(linkname, '/') + 1;
+       snprintf(tmp, size - (tmp - linkname), "%s", filename);
 
        if (unlink(linkname))
                goto out_free;
@@ -367,8 +390,7 @@ out_free:
        return err;
 }
 
-static int dso__cache_build_id(struct dso *dso, struct machine *machine,
-                              const char *debugdir)
+static int dso__cache_build_id(struct dso *dso, struct machine *machine)
 {
        bool is_kallsyms = dso->kernel && dso->long_name[0] != '/';
        bool is_vdso = dso__is_vdso(dso);
@@ -381,28 +403,26 @@ static int dso__cache_build_id(struct dso *dso, struct machine *machine,
                name = nm;
        }
        return build_id_cache__add_b(dso->build_id, sizeof(dso->build_id), name,
-                                    debugdir, is_kallsyms, is_vdso);
+                                    is_kallsyms, is_vdso);
 }
 
 static int __dsos__cache_build_ids(struct list_head *head,
-                                  struct machine *machine, const char *debugdir)
+                                  struct machine *machine)
 {
        struct dso *pos;
        int err = 0;
 
        dsos__for_each_with_build_id(pos, head)
-               if (dso__cache_build_id(pos, machine, debugdir))
+               if (dso__cache_build_id(pos, machine))
                        err = -1;
 
        return err;
 }
 
-static int machine__cache_build_ids(struct machine *machine, const char *debugdir)
+static int machine__cache_build_ids(struct machine *machine)
 {
-       int ret = __dsos__cache_build_ids(&machine->kernel_dsos.head, machine,
-                                         debugdir);
-       ret |= __dsos__cache_build_ids(&machine->user_dsos.head, machine,
-                                      debugdir);
+       int ret = __dsos__cache_build_ids(&machine->kernel_dsos.head, machine);
+       ret |= __dsos__cache_build_ids(&machine->user_dsos.head, machine);
        return ret;
 }
 
@@ -417,11 +437,11 @@ int perf_session__cache_build_ids(struct perf_session *session)
        if (mkdir(buildid_dir, 0755) != 0 && errno != EEXIST)
                return -1;
 
-       ret = machine__cache_build_ids(&session->machines.host, buildid_dir);
+       ret = machine__cache_build_ids(&session->machines.host);
 
        for (nd = rb_first(&session->machines.guests); nd; nd = rb_next(nd)) {
                struct machine *pos = rb_entry(nd, struct machine, rb_node);
-               ret |= machine__cache_build_ids(pos, buildid_dir);
+               ret |= machine__cache_build_ids(pos);
        }
        return ret ? -1 : 0;
 }
index 8236319..31b3c63 100644 (file)
@@ -22,9 +22,9 @@ bool perf_session__read_build_ids(struct perf_session *session, bool with_hits);
 int perf_session__write_buildid_table(struct perf_session *session, int fd);
 int perf_session__cache_build_ids(struct perf_session *session);
 
-int build_id_cache__add_s(const char *sbuild_id, const char *debugdir,
+int build_id_cache__add_s(const char *sbuild_id,
                          const char *name, bool is_kallsyms, bool is_vdso);
-int build_id_cache__remove_s(const char *sbuild_id, const char *debugdir);
+int build_id_cache__remove_s(const char *sbuild_id);
 void disable_buildid_cache(void);
 
 #endif
index d04d770..fbcca21 100644 (file)
@@ -17,6 +17,7 @@
 #define EXEC_PATH_ENVIRONMENT "PERF_EXEC_PATH"
 #define DEFAULT_PERF_DIR_ENVIRONMENT ".perf"
 #define PERF_DEBUGFS_ENVIRONMENT "PERF_DEBUGFS_DIR"
+#define PERF_TRACEFS_ENVIRONMENT "PERF_TRACEFS_DIR"
 
 typedef int (*config_fn_t)(const char *, const char *, void *);
 extern int perf_default_config(const char *, const char *, void *);
index 14e7a12..9f643ee 100644 (file)
@@ -97,6 +97,14 @@ int parse_callchain_record_opt(const char *arg)
                                callchain_param.dump_size = size;
                        }
 #endif /* HAVE_DWARF_UNWIND_SUPPORT */
+               } else if (!strncmp(name, "lbr", sizeof("lbr"))) {
+                       if (!strtok_r(NULL, ",", &saveptr)) {
+                               callchain_param.record_mode = CALLCHAIN_LBR;
+                               ret = 0;
+                       } else
+                               pr_err("callchain: No more arguments "
+                                       "needed for --call-graph lbr\n");
+                       break;
                } else {
                        pr_err("callchain: Unknown --call-graph option "
                               "value: %s\n", arg);
index c0ec1ac..6033a0a 100644 (file)
@@ -11,6 +11,7 @@ enum perf_call_graph_mode {
        CALLCHAIN_NONE,
        CALLCHAIN_FP,
        CALLCHAIN_DWARF,
+       CALLCHAIN_LBR,
        CALLCHAIN_MAX
 };
 
index c2f7d3b..814554d 100644 (file)
@@ -45,13 +45,13 @@ int dso__read_binary_type_filename(const struct dso *dso,
        case DSO_BINARY_TYPE__DEBUGLINK: {
                char *debuglink;
 
-               strncpy(filename, dso->long_name, size);
-               debuglink = filename + dso->long_name_len;
+               len = __symbol__join_symfs(filename, size, dso->long_name);
+               debuglink = filename + len;
                while (debuglink != filename && *debuglink != '/')
                        debuglink--;
                if (*debuglink == '/')
                        debuglink++;
-               ret = filename__read_debuglink(dso->long_name, debuglink,
+               ret = filename__read_debuglink(filename, debuglink,
                                               size - (debuglink - filename));
                }
                break;
@@ -240,7 +240,7 @@ static int do_open(char *name)
                if (fd >= 0)
                        return fd;
 
-               pr_debug("dso open failed, mmap: %s\n",
+               pr_debug("dso open failed: %s\n",
                         strerror_r(errno, sbuf, sizeof(sbuf)));
                if (!dso__data_open_cnt || errno != EMFILE)
                        break;
index cc66c40..780b2bc 100644 (file)
@@ -277,6 +277,21 @@ bool die_is_func_def(Dwarf_Die *dw_die)
                dwarf_attr(dw_die, DW_AT_declaration, &attr) == NULL);
 }
 
+/**
+ * die_is_func_instance - Ensure that this DIE is an instance of a subprogram
+ * @dw_die: a DIE
+ *
+ * Ensure that this DIE is an instance (which has an entry address).
+ * This returns true if @dw_die is a function instance. If not, you need to
+ * call die_walk_instances() to find actual instances.
+ **/
+bool die_is_func_instance(Dwarf_Die *dw_die)
+{
+       Dwarf_Addr tmp;
+
+       /* Actually gcc optimizes non-inline as like as inlined */
+       return !dwarf_func_inline(dw_die) && dwarf_entrypc(dw_die, &tmp) == 0;
+}
 /**
  * die_get_data_member_location - Get the data-member offset
  * @mb_die: a DIE of a member of a data structure
index b4fe90c..af7dbcd 100644 (file)
@@ -41,6 +41,9 @@ extern int cu_walk_functions_at(Dwarf_Die *cu_die, Dwarf_Addr addr,
 /* Ensure that this DIE is a subprogram and definition (not declaration) */
 extern bool die_is_func_def(Dwarf_Die *dw_die);
 
+/* Ensure that this DIE is an instance of a subprogram */
+extern bool die_is_func_instance(Dwarf_Die *dw_die);
+
 /* Compare diename and tname */
 extern bool die_compare_name(Dwarf_Die *dw_die, const char *tname);
 
index 28b8ce8..a8b2c57 100644 (file)
@@ -7,7 +7,6 @@
  * Released under the GPL v2. (and only v2, not any later version)
  */
 #include "util.h"
-#include <api/fs/debugfs.h>
 #include <api/fs/fs.h>
 #include <poll.h>
 #include "cpumap.h"
@@ -1329,7 +1328,7 @@ int perf_evlist__prepare_workload(struct perf_evlist *evlist, struct target *tar
                 * writing exactly one byte, in workload.cork_fd, usually via
                 * perf_evlist__start_workload().
                 *
-                * For cancelling the workload without actuallin running it,
+                * For cancelling the workload without actually running it,
                 * the parent will just close workload.cork_fd, without writing
                 * anything, i.e. read will return zero and we just exit()
                 * here.
index ea51a90..f93e520 100644 (file)
@@ -537,13 +537,30 @@ int perf_evsel__group_desc(struct perf_evsel *evsel, char *buf, size_t size)
 }
 
 static void
-perf_evsel__config_callgraph(struct perf_evsel *evsel)
+perf_evsel__config_callgraph(struct perf_evsel *evsel,
+                            struct record_opts *opts)
 {
        bool function = perf_evsel__is_function_event(evsel);
        struct perf_event_attr *attr = &evsel->attr;
 
        perf_evsel__set_sample_bit(evsel, CALLCHAIN);
 
+       if (callchain_param.record_mode == CALLCHAIN_LBR) {
+               if (!opts->branch_stack) {
+                       if (attr->exclude_user) {
+                               pr_warning("LBR callstack option is only available "
+                                          "to get user callchain information. "
+                                          "Falling back to framepointers.\n");
+                       } else {
+                               perf_evsel__set_sample_bit(evsel, BRANCH_STACK);
+                               attr->branch_sample_type = PERF_SAMPLE_BRANCH_USER |
+                                                       PERF_SAMPLE_BRANCH_CALL_STACK;
+                       }
+               } else
+                        pr_warning("Cannot use LBR callstack with branch stack. "
+                                   "Falling back to framepointers.\n");
+       }
+
        if (callchain_param.record_mode == CALLCHAIN_DWARF) {
                if (!function) {
                        perf_evsel__set_sample_bit(evsel, REGS_USER);
@@ -667,7 +684,7 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts)
                evsel->attr.exclude_callchain_user = 1;
 
        if (callchain_param.enabled && !evsel->no_aux_samples)
-               perf_evsel__config_callgraph(evsel);
+               perf_evsel__config_callgraph(evsel, opts);
 
        if (opts->sample_intr_regs) {
                attr->sample_regs_intr = PERF_REGS_MASK;
index 3862274..dcf202a 100644 (file)
@@ -355,4 +355,8 @@ for ((_evsel) = list_entry((_leader)->node.next, struct perf_evsel, node);  \
      (_evsel) && (_evsel)->leader == (_leader);                                        \
      (_evsel) = list_entry((_evsel)->node.next, struct perf_evsel, node))
 
+static inline bool has_branch_callstack(struct perf_evsel *evsel)
+{
+       return evsel->attr.branch_sample_type & PERF_SAMPLE_BRANCH_CALL_STACK;
+}
 #endif /* __PERF_EVSEL_H */
index 1bca3a9..9e0f60a 100644 (file)
@@ -1502,18 +1502,100 @@ static int remove_loops(struct branch_entry *l, int nr)
        return nr;
 }
 
-static int thread__resolve_callchain_sample(struct thread *thread,
-                                            struct ip_callchain *chain,
-                                            struct branch_stack *branch,
-                                            struct symbol **parent,
-                                            struct addr_location *root_al,
-                                            int max_stack)
+/*
+ * Recolve LBR callstack chain sample
+ * Return:
+ * 1 on success get LBR callchain information
+ * 0 no available LBR callchain information, should try fp
+ * negative error code on other errors.
+ */
+static int resolve_lbr_callchain_sample(struct thread *thread,
+                                       struct perf_sample *sample,
+                                       struct symbol **parent,
+                                       struct addr_location *root_al,
+                                       int max_stack)
 {
+       struct ip_callchain *chain = sample->callchain;
+       int chain_nr = min(max_stack, (int)chain->nr);
+       int i, j, err;
+       u64 ip;
+
+       for (i = 0; i < chain_nr; i++) {
+               if (chain->ips[i] == PERF_CONTEXT_USER)
+                       break;
+       }
+
+       /* LBR only affects the user callchain */
+       if (i != chain_nr) {
+               struct branch_stack *lbr_stack = sample->branch_stack;
+               int lbr_nr = lbr_stack->nr;
+               /*
+                * LBR callstack can only get user call chain.
+                * The mix_chain_nr is kernel call chain
+                * number plus LBR user call chain number.
+                * i is kernel call chain number,
+                * 1 is PERF_CONTEXT_USER,
+                * lbr_nr + 1 is the user call chain number.
+                * For details, please refer to the comments
+                * in callchain__printf
+                */
+               int mix_chain_nr = i + 1 + lbr_nr + 1;
+
+               if (mix_chain_nr > PERF_MAX_STACK_DEPTH + PERF_MAX_BRANCH_DEPTH) {
+                       pr_warning("corrupted callchain. skipping...\n");
+                       return 0;
+               }
+
+               for (j = 0; j < mix_chain_nr; j++) {
+                       if (callchain_param.order == ORDER_CALLEE) {
+                               if (j < i + 1)
+                                       ip = chain->ips[j];
+                               else if (j > i + 1)
+                                       ip = lbr_stack->entries[j - i - 2].from;
+                               else
+                                       ip = lbr_stack->entries[0].to;
+                       } else {
+                               if (j < lbr_nr)
+                                       ip = lbr_stack->entries[lbr_nr - j - 1].from;
+                               else if (j > lbr_nr)
+                                       ip = chain->ips[i + 1 - (j - lbr_nr)];
+                               else
+                                       ip = lbr_stack->entries[0].to;
+                       }
+
+                       err = add_callchain_ip(thread, parent, root_al, false, ip);
+                       if (err)
+                               return (err < 0) ? err : 0;
+               }
+               return 1;
+       }
+
+       return 0;
+}
+
+static int thread__resolve_callchain_sample(struct thread *thread,
+                                           struct perf_evsel *evsel,
+                                           struct perf_sample *sample,
+                                           struct symbol **parent,
+                                           struct addr_location *root_al,
+                                           int max_stack)
+{
+       struct branch_stack *branch = sample->branch_stack;
+       struct ip_callchain *chain = sample->callchain;
        int chain_nr = min(max_stack, (int)chain->nr);
        int i, j, err;
        int skip_idx = -1;
        int first_call = 0;
 
+       callchain_cursor_reset(&callchain_cursor);
+
+       if (has_branch_callstack(evsel)) {
+               err = resolve_lbr_callchain_sample(thread, sample, parent,
+                                                  root_al, max_stack);
+               if (err)
+                       return (err < 0) ? err : 0;
+       }
+
        /*
         * Based on DWARF debug information, some architectures skip
         * a callchain entry saved by the kernel.
@@ -1521,8 +1603,6 @@ static int thread__resolve_callchain_sample(struct thread *thread,
        if (chain->nr < PERF_MAX_STACK_DEPTH)
                skip_idx = arch_skip_callchain_idx(thread, chain);
 
-       callchain_cursor_reset(&callchain_cursor);
-
        /*
         * Add branches to call stack for easier browsing. This gives
         * more context for a sample than just the callers.
@@ -1623,9 +1703,9 @@ int thread__resolve_callchain(struct thread *thread,
                              struct addr_location *root_al,
                              int max_stack)
 {
-       int ret = thread__resolve_callchain_sample(thread, sample->callchain,
-                                                  sample->branch_stack,
-                                                  parent, root_al, max_stack);
+       int ret = thread__resolve_callchain_sample(thread, evsel,
+                                                  sample, parent,
+                                                  root_al, max_stack);
        if (ret)
                return ret;
 
index 7f8ec6c..109ba5c 100644 (file)
@@ -175,9 +175,6 @@ struct tracepoint_path *tracepoint_id_to_path(u64 config)
        char evt_path[MAXPATHLEN];
        char dir_path[MAXPATHLEN];
 
-       if (debugfs_valid_mountpoint(tracing_events_path))
-               return NULL;
-
        sys_dir = opendir(tracing_events_path);
        if (!sys_dir)
                return NULL;
@@ -473,12 +470,6 @@ static int add_tracepoint_multi_sys(struct list_head *list, int *idx,
 int parse_events_add_tracepoint(struct list_head *list, int *idx,
                                char *sys, char *event)
 {
-       int ret;
-
-       ret = debugfs_valid_mountpoint(tracing_events_path);
-       if (ret)
-               return ret;
-
        if (strpbrk(sys, "*?"))
                return add_tracepoint_multi_sys(list, idx, sys, event);
        else
@@ -1109,13 +1100,6 @@ 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_r(errno, sbuf, sizeof(sbuf)));
-               return;
-       }
 
        sys_dir = opendir(tracing_events_path);
        if (!sys_dir)
@@ -1163,9 +1147,6 @@ int is_valid_tracepoint(const char *event_string)
        char evt_path[MAXPATHLEN];
        char dir_path[MAXPATHLEN];
 
-       if (debugfs_valid_mountpoint(tracing_events_path))
-               return 0;
-
        sys_dir = opendir(tracing_events_path);
        if (!sys_dir)
                return 0;
@@ -1338,11 +1319,6 @@ static void print_symbol_events(const char *event_glob, unsigned type,
  */
 void print_events(const char *event_glob, bool name_only)
 {
-       if (!name_only) {
-               printf("\n");
-               printf("List of pre-defined events (to be used in -e):\n");
-       }
-
        print_symbol_events(event_glob, PERF_TYPE_HARDWARE,
                            event_symbols_hw, PERF_COUNT_HW_MAX, name_only);
 
index ff6e1fa..39c3b57 100644 (file)
@@ -122,6 +122,6 @@ void print_tracepoint_events(const char *subsys_glob, const char *event_glob,
 int print_hwcache_events(const char *event_glob, bool name_only);
 extern int is_valid_tracepoint(const char *event_string);
 
-extern int valid_debugfs_mount(const char *debugfs);
+int valid_event_mount(const char *eventfs);
 
 #endif /* __PERF_PARSE_EVENTS_H */
index 4a015f7..4ee9a86 100644 (file)
@@ -510,8 +510,10 @@ int parse_options_subcommand(int argc, const char **argv, const struct option *o
                }
                exit(130);
        case PARSE_OPT_LIST_SUBCMDS:
-               for (int i = 0; subcommands[i]; i++)
-                       printf("%s ", subcommands[i]);
+               if (subcommands) {
+                       for (int i = 0; subcommands[i]; i++)
+                               printf("%s ", subcommands[i]);
+               }
                exit(130);
        default: /* PARSE_OPT_UNKNOWN */
                if (ctx.argv[0][1] == '-') {
index 919937e..9dfbed9 100644 (file)
@@ -41,6 +41,7 @@
 #include "symbol.h"
 #include "thread.h"
 #include <api/fs/debugfs.h>
+#include <api/fs/tracefs.h>
 #include "trace-event.h"       /* For __maybe_unused */
 #include "probe-event.h"
 #include "probe-finder.h"
@@ -1805,7 +1806,7 @@ static void print_open_warning(int err, bool is_kprobe)
                           " - please rebuild kernel with %s.\n",
                           is_kprobe ? 'k' : 'u', config);
        } else if (err == -ENOTSUP)
-               pr_warning("Debugfs is not mounted.\n");
+               pr_warning("Tracefs or debugfs is not mounted.\n");
        else
                pr_warning("Failed to open %cprobe_events: %s\n",
                           is_kprobe ? 'k' : 'u',
@@ -1816,7 +1817,7 @@ 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");
+               pr_warning("Tracefs or 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");
@@ -1833,13 +1834,20 @@ static int open_probe_events(const char *trace_file, bool readwrite)
 {
        char buf[PATH_MAX];
        const char *__debugfs;
+       const char *tracing_dir = "";
        int ret;
 
-       __debugfs = debugfs_find_mountpoint();
-       if (__debugfs == NULL)
-               return -ENOTSUP;
+       __debugfs = tracefs_find_mountpoint();
+       if (__debugfs == NULL) {
+               tracing_dir = "tracing/";
 
-       ret = e_snprintf(buf, PATH_MAX, "%s/%s", __debugfs, trace_file);
+               __debugfs = debugfs_find_mountpoint();
+               if (__debugfs == NULL)
+                       return -ENOTSUP;
+       }
+
+       ret = e_snprintf(buf, PATH_MAX, "%s/%s%s",
+                        __debugfs, tracing_dir, trace_file);
        if (ret >= 0) {
                pr_debug("Opening %s write=%d\n", buf, readwrite);
                if (readwrite && !probe_event_dry_run)
@@ -1855,12 +1863,12 @@ static int open_probe_events(const char *trace_file, bool readwrite)
 
 static int open_kprobe_events(bool readwrite)
 {
-       return open_probe_events("tracing/kprobe_events", readwrite);
+       return open_probe_events("kprobe_events", readwrite);
 }
 
 static int open_uprobe_events(bool readwrite)
 {
-       return open_probe_events("tracing/uprobe_events", readwrite);
+       return open_probe_events("uprobe_events", readwrite);
 }
 
 /* Get raw string list of current kprobe_events  or uprobe_events */
index b5247d7..d141935 100644 (file)
@@ -915,17 +915,13 @@ static int probe_point_search_cb(Dwarf_Die *sp_die, void *data)
                dwarf_decl_line(sp_die, &pf->lno);
                pf->lno += pp->line;
                param->retval = find_probe_point_by_line(pf);
-       } else if (!dwarf_func_inline(sp_die)) {
+       } else if (die_is_func_instance(sp_die)) {
+               /* Instances always have the entry address */
+               dwarf_entrypc(sp_die, &pf->addr);
                /* Real function */
                if (pp->lazy_line)
                        param->retval = find_probe_point_lazy(sp_die, pf);
                else {
-                       if (dwarf_entrypc(sp_die, &pf->addr) != 0) {
-                               pr_warning("Failed to get entry address of "
-                                          "%s.\n", dwarf_diename(sp_die));
-                               param->retval = -ENOENT;
-                               return DWARF_CB_ABORT;
-                       }
                        pf->addr += pp->offset;
                        /* TODO: Check the address in this function */
                        param->retval = call_probe_finder(sp_die, pf);
@@ -1536,7 +1532,7 @@ static int line_range_search_cb(Dwarf_Die *sp_die, void *data)
                pr_debug("New line range: %d to %d\n", lf->lno_s, lf->lno_e);
                lr->start = lf->lno_s;
                lr->end = lf->lno_e;
-               if (dwarf_func_inline(sp_die))
+               if (!die_is_func_instance(sp_die))
                        param->retval = die_walk_instances(sp_die,
                                                line_range_inline_cb, lf);
                else
index 6c6a695..4d28624 100644 (file)
@@ -17,6 +17,5 @@ util/xyarray.c
 util/cgroup.c
 util/rblist.c
 util/strlist.c
-../lib/api/fs/fs.c
 util/trace-event.c
 ../../lib/rbtree.c
diff --git a/tools/perf/util/scripting-engines/Build b/tools/perf/util/scripting-engines/Build
new file mode 100644 (file)
index 0000000..6516e22
--- /dev/null
@@ -0,0 +1,6 @@
+libperf-$(CONFIG_LIBPERL)   += trace-event-perl.o
+libperf-$(CONFIG_LIBPYTHON) += trace-event-python.o
+
+CFLAGS_trace-event-perl.o += $(PERL_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-shadow -Wno-undef -Wno-switch-default
+
+CFLAGS_trace-event-python.o += $(PYTHON_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-shadow
index 0baf75f..504b7e6 100644 (file)
@@ -553,15 +553,67 @@ int perf_session_queue_event(struct perf_session *s, union perf_event *event,
        return 0;
 }
 
-static void callchain__printf(struct perf_sample *sample)
+static void callchain__lbr_callstack_printf(struct perf_sample *sample)
 {
+       struct ip_callchain *callchain = sample->callchain;
+       struct branch_stack *lbr_stack = sample->branch_stack;
+       u64 kernel_callchain_nr = callchain->nr;
        unsigned int i;
 
-       printf("... chain: nr:%" PRIu64 "\n", sample->callchain->nr);
+       for (i = 0; i < kernel_callchain_nr; i++) {
+               if (callchain->ips[i] == PERF_CONTEXT_USER)
+                       break;
+       }
+
+       if ((i != kernel_callchain_nr) && lbr_stack->nr) {
+               u64 total_nr;
+               /*
+                * LBR callstack can only get user call chain,
+                * i is kernel call chain number,
+                * 1 is PERF_CONTEXT_USER.
+                *
+                * The user call chain is stored in LBR registers.
+                * LBR are pair registers. The caller is stored
+                * in "from" register, while the callee is stored
+                * in "to" register.
+                * For example, there is a call stack
+                * "A"->"B"->"C"->"D".
+                * The LBR registers will recorde like
+                * "C"->"D", "B"->"C", "A"->"B".
+                * So only the first "to" register and all "from"
+                * registers are needed to construct the whole stack.
+                */
+               total_nr = i + 1 + lbr_stack->nr + 1;
+               kernel_callchain_nr = i + 1;
+
+               printf("... LBR call chain: nr:%" PRIu64 "\n", total_nr);
+
+               for (i = 0; i < kernel_callchain_nr; i++)
+                       printf("..... %2d: %016" PRIx64 "\n",
+                              i, callchain->ips[i]);
+
+               printf("..... %2d: %016" PRIx64 "\n",
+                      (int)(kernel_callchain_nr), lbr_stack->entries[0].to);
+               for (i = 0; i < lbr_stack->nr; i++)
+                       printf("..... %2d: %016" PRIx64 "\n",
+                              (int)(i + kernel_callchain_nr + 1), lbr_stack->entries[i].from);
+       }
+}
+
+static void callchain__printf(struct perf_evsel *evsel,
+                             struct perf_sample *sample)
+{
+       unsigned int i;
+       struct ip_callchain *callchain = sample->callchain;
+
+       if (has_branch_callstack(evsel))
+               callchain__lbr_callstack_printf(sample);
+
+       printf("... FP chain: nr:%" PRIu64 "\n", callchain->nr);
 
-       for (i = 0; i < sample->callchain->nr; i++)
+       for (i = 0; i < callchain->nr; i++)
                printf("..... %2d: %016" PRIx64 "\n",
-                      i, sample->callchain->ips[i]);
+                      i, callchain->ips[i]);
 }
 
 static void branch_stack__printf(struct perf_sample *sample)
@@ -718,9 +770,9 @@ static void dump_sample(struct perf_evsel *evsel, union perf_event *event,
        sample_type = evsel->attr.sample_type;
 
        if (sample_type & PERF_SAMPLE_CALLCHAIN)
-               callchain__printf(sample);
+               callchain__printf(evsel, sample);
 
-       if (sample_type & PERF_SAMPLE_BRANCH_STACK)
+       if ((sample_type & PERF_SAMPLE_BRANCH_STACK) && !has_branch_callstack(evsel))
                branch_stack__printf(sample);
 
        if (sample_type & PERF_SAMPLE_REGS_USER)
index d0aee4b..1833103 100644 (file)
@@ -25,7 +25,7 @@ cflags += ['-fno-strict-aliasing', '-Wno-write-strings', '-Wno-unused-parameter'
 build_lib = getenv('PYTHON_EXTBUILD_LIB')
 build_tmp = getenv('PYTHON_EXTBUILD_TMP')
 libtraceevent = getenv('LIBTRACEEVENT')
-libapikfs = getenv('LIBAPIKFS')
+libapikfs = getenv('LIBAPI')
 
 ext_sources = [f.strip() for f in file('util/python-ext-sources')
                                if len(f.strip()) > 0 and f[0] != '#']
index b24f9d8..b02731a 100644 (file)
@@ -69,6 +69,10 @@ static inline uint8_t elf_sym__type(const GElf_Sym *sym)
        return GELF_ST_TYPE(sym->st_info);
 }
 
+#ifndef STT_GNU_IFUNC
+#define STT_GNU_IFUNC 10
+#endif
+
 static inline int elf_sym__is_function(const GElf_Sym *sym)
 {
        return (elf_sym__type(sym) == STT_FUNC ||
@@ -859,10 +863,9 @@ int dso__load_sym(struct dso *dso, struct map *map,
                /* Reject ARM ELF "mapping symbols": these aren't unique and
                 * don't identify functions, so will confuse the profile
                 * output: */
-               if (ehdr.e_machine == EM_ARM) {
-                       if (!strcmp(elf_name, "$a") ||
-                           !strcmp(elf_name, "$d") ||
-                           !strcmp(elf_name, "$t"))
+               if (ehdr.e_machine == EM_ARM || ehdr.e_machine == EM_AARCH64) {
+                       if (elf_name[0] == '$' && strchr("adtx", elf_name[1])
+                           && (elf_name[2] == '\0' || elf_name[2] == '.'))
                                continue;
                }
 
index c36636f..25d6c73 100644 (file)
@@ -112,8 +112,8 @@ unsigned long long read_size(struct event_format *event, void *ptr, int size)
        return pevent_read_number(event->pevent, ptr, size);
 }
 
-void event_format__print(struct event_format *event,
-                        int cpu, void *data, int size)
+void event_format__fprintf(struct event_format *event,
+                          int cpu, void *data, int size, FILE *fp)
 {
        struct pevent_record record;
        struct trace_seq s;
@@ -125,10 +125,16 @@ void event_format__print(struct event_format *event,
 
        trace_seq_init(&s);
        pevent_event_info(&s, event, &record);
-       trace_seq_do_printf(&s);
+       trace_seq_do_fprintf(&s, fp);
        trace_seq_destroy(&s);
 }
 
+void event_format__print(struct event_format *event,
+                        int cpu, void *data, int size)
+{
+       return event_format__fprintf(event, cpu, data, size, stdout);
+}
+
 void parse_proc_kallsyms(struct pevent *pevent,
                         char *file, unsigned int size __maybe_unused)
 {
index 52aaa19..356629a 100644 (file)
@@ -23,6 +23,9 @@ trace_event__tp_format(const char *sys, const char *name);
 
 int bigendian(void);
 
+void event_format__fprintf(struct event_format *event,
+                          int cpu, void *data, int size, FILE *fp);
+
 void event_format__print(struct event_format *event,
                         int cpu, void *data, int size);
 
index b86744f..92db3f1 100644 (file)
@@ -303,13 +303,26 @@ void set_term_quiet_input(struct termios *old)
        tcsetattr(0, TCSANOW, &tc);
 }
 
-static void set_tracing_events_path(const char *mountpoint)
+static void set_tracing_events_path(const char *tracing, const char *mountpoint)
 {
-       snprintf(tracing_events_path, sizeof(tracing_events_path), "%s/%s",
-                mountpoint, "tracing/events");
+       snprintf(tracing_events_path, sizeof(tracing_events_path), "%s/%s%s",
+                mountpoint, tracing, "events");
 }
 
-const char *perf_debugfs_mount(const char *mountpoint)
+static const char *__perf_tracefs_mount(const char *mountpoint)
+{
+       const char *mnt;
+
+       mnt = tracefs_mount(mountpoint);
+       if (!mnt)
+               return NULL;
+
+       set_tracing_events_path("", mnt);
+
+       return mnt;
+}
+
+static const char *__perf_debugfs_mount(const char *mountpoint)
 {
        const char *mnt;
 
@@ -317,7 +330,20 @@ const char *perf_debugfs_mount(const char *mountpoint)
        if (!mnt)
                return NULL;
 
-       set_tracing_events_path(mnt);
+       set_tracing_events_path("tracing/", mnt);
+
+       return mnt;
+}
+
+const char *perf_debugfs_mount(const char *mountpoint)
+{
+       const char *mnt;
+
+       mnt = __perf_tracefs_mount(mountpoint);
+       if (mnt)
+               return mnt;
+
+       mnt = __perf_debugfs_mount(mountpoint);
 
        return mnt;
 }
@@ -325,12 +351,19 @@ const char *perf_debugfs_mount(const char *mountpoint)
 void perf_debugfs_set_path(const char *mntpt)
 {
        snprintf(debugfs_mountpoint, strlen(debugfs_mountpoint), "%s", mntpt);
-       set_tracing_events_path(mntpt);
+       set_tracing_events_path("tracing/", mntpt);
+}
+
+static const char *find_tracefs(void)
+{
+       const char *path = __perf_tracefs_mount(NULL);
+
+       return path;
 }
 
 static const char *find_debugfs(void)
 {
-       const char *path = perf_debugfs_mount(NULL);
+       const char *path = __perf_debugfs_mount(NULL);
 
        if (!path)
                fprintf(stderr, "Your kernel does not support the debugfs filesystem");
@@ -344,6 +377,7 @@ static const char *find_debugfs(void)
  */
 const char *find_tracing_dir(void)
 {
+       const char *tracing_dir = "";
        static char *tracing;
        static int tracing_found;
        const char *debugfs;
@@ -351,11 +385,15 @@ const char *find_tracing_dir(void)
        if (tracing_found)
                return tracing;
 
-       debugfs = find_debugfs();
-       if (!debugfs)
-               return NULL;
+       debugfs = find_tracefs();
+       if (!debugfs) {
+               tracing_dir = "/tracing";
+               debugfs = find_debugfs();
+               if (!debugfs)
+                       return NULL;
+       }
 
-       if (asprintf(&tracing, "%s/tracing", debugfs) < 0)
+       if (asprintf(&tracing, "%s%s", debugfs, tracing_dir) < 0)
                return NULL;
 
        tracing_found = 1;
index 027a515..73c2f8e 100644 (file)
@@ -75,6 +75,7 @@
 #include <linux/types.h>
 #include <sys/ttydefaults.h>
 #include <api/fs/debugfs.h>
+#include <api/fs/tracefs.h>
 #include <termios.h>
 #include <linux/bitops.h>
 #include <termios.h>