Merge branch 'perf/urgent' into perf/core, to pick up fixes
authorIngo Molnar <mingo@kernel.org>
Fri, 23 Sep 2016 05:20:33 +0000 (07:20 +0200)
committerIngo Molnar <mingo@kernel.org>
Fri, 23 Sep 2016 05:20:33 +0000 (07:20 +0200)
Signed-off-by: Ingo Molnar <mingo@kernel.org>
148 files changed:
Documentation/trace/kprobetrace.txt
Documentation/trace/uprobetracer.txt
arch/x86/events/core.c
arch/x86/events/intel/core.c
arch/x86/events/intel/ds.c
arch/x86/events/intel/lbr.c
arch/x86/events/intel/pt.c
arch/x86/events/intel/pt.h
arch/x86/events/intel/rapl.c
arch/x86/events/intel/uncore.c
arch/x86/events/intel/uncore.h
arch/x86/events/intel/uncore_snb.c
arch/x86/events/intel/uncore_snbep.c
arch/x86/events/perf_event.h
include/linux/bitmap.h
include/linux/perf_event.h
kernel/events/core.c
kernel/events/uprobes.c
kernel/trace/trace.c
kernel/trace/trace_kprobe.c
kernel/trace/trace_probe.c
kernel/trace/trace_probe.h
kernel/trace/trace_uprobe.c
tools/arch/alpha/include/uapi/asm/mman.h [new file with mode: 0644]
tools/arch/arc/include/uapi/asm/mman.h [new file with mode: 0644]
tools/arch/arm/include/uapi/asm/mman.h [new file with mode: 0644]
tools/arch/arm64/include/uapi/asm/mman.h [new file with mode: 0644]
tools/arch/frv/include/uapi/asm/mman.h [new file with mode: 0644]
tools/arch/h8300/include/uapi/asm/mman.h [new file with mode: 0644]
tools/arch/hexagon/include/uapi/asm/mman.h [new file with mode: 0644]
tools/arch/ia64/include/uapi/asm/mman.h [new file with mode: 0644]
tools/arch/m32r/include/uapi/asm/mman.h [new file with mode: 0644]
tools/arch/microblaze/include/uapi/asm/mman.h [new file with mode: 0644]
tools/arch/mips/include/uapi/asm/mman.h [new file with mode: 0644]
tools/arch/mn10300/include/uapi/asm/mman.h [new file with mode: 0644]
tools/arch/parisc/include/uapi/asm/mman.h [new file with mode: 0644]
tools/arch/powerpc/include/uapi/asm/mman.h [new file with mode: 0644]
tools/arch/s390/include/uapi/asm/mman.h [new file with mode: 0644]
tools/arch/score/include/uapi/asm/mman.h [new file with mode: 0644]
tools/arch/sh/include/uapi/asm/mman.h [new file with mode: 0644]
tools/arch/sparc/include/uapi/asm/mman.h [new file with mode: 0644]
tools/arch/tile/include/uapi/asm/mman.h [new file with mode: 0644]
tools/arch/x86/include/uapi/asm/mman.h [new file with mode: 0644]
tools/arch/xtensa/include/uapi/asm/mman.h [new file with mode: 0644]
tools/include/linux/coresight-pmu.h [new file with mode: 0644]
tools/include/linux/time64.h [new file with mode: 0644]
tools/include/uapi/asm-generic/mman-common.h [new file with mode: 0644]
tools/include/uapi/asm-generic/mman.h [new file with mode: 0644]
tools/include/uapi/linux/mman.h [new file with mode: 0644]
tools/lib/api/fs/fs.c
tools/lib/api/fs/fs.h
tools/perf/Documentation/perf-config.txt
tools/perf/Documentation/perf-probe.txt
tools/perf/Documentation/perf-record.txt
tools/perf/Documentation/perfconfig.example
tools/perf/MANIFEST
tools/perf/Makefile.perf
tools/perf/arch/arm/include/dwarf-regs-table.h [new file with mode: 0644]
tools/perf/arch/arm64/include/dwarf-regs-table.h [new file with mode: 0644]
tools/perf/arch/powerpc/include/dwarf-regs-table.h [new file with mode: 0644]
tools/perf/arch/powerpc/util/sym-handling.c
tools/perf/arch/s390/include/dwarf-regs-table.h [new file with mode: 0644]
tools/perf/arch/sh/include/dwarf-regs-table.h [new file with mode: 0644]
tools/perf/arch/sparc/include/dwarf-regs-table.h [new file with mode: 0644]
tools/perf/arch/x86/include/dwarf-regs-table.h [new file with mode: 0644]
tools/perf/arch/xtensa/include/dwarf-regs-table.h [new file with mode: 0644]
tools/perf/bench/futex-requeue.c
tools/perf/bench/futex-wake-parallel.c
tools/perf/bench/futex-wake.c
tools/perf/bench/mem-functions.c
tools/perf/bench/numa.c
tools/perf/bench/sched-messaging.c
tools/perf/bench/sched-pipe.c
tools/perf/builtin-annotate.c
tools/perf/builtin-diff.c
tools/perf/builtin-inject.c
tools/perf/builtin-kmem.c
tools/perf/builtin-kvm.c
tools/perf/builtin-probe.c
tools/perf/builtin-record.c
tools/perf/builtin-report.c
tools/perf/builtin-sched.c
tools/perf/builtin-script.c
tools/perf/builtin-stat.c
tools/perf/builtin-timechart.c
tools/perf/builtin-top.c
tools/perf/builtin-trace.c
tools/perf/perf-sys.h
tools/perf/perf.h
tools/perf/tests/backward-ring-buffer.c
tools/perf/tests/bpf.c
tools/perf/tests/code-reading.c
tools/perf/tests/vmlinux-kallsyms.c
tools/perf/trace/beauty/mmap.c
tools/perf/ui/browsers/annotate.c
tools/perf/ui/browsers/hists.c
tools/perf/ui/browsers/map.c
tools/perf/ui/gtk/hists.c
tools/perf/ui/hist.c
tools/perf/ui/stdio/hist.c
tools/perf/util/Build
tools/perf/util/annotate.c
tools/perf/util/annotate.h
tools/perf/util/block-range.c [new file with mode: 0644]
tools/perf/util/block-range.h [new file with mode: 0644]
tools/perf/util/bpf-loader.c
tools/perf/util/debug.c
tools/perf/util/dso.c
tools/perf/util/dwarf-aux.c
tools/perf/util/dwarf-aux.h
tools/perf/util/dwarf-regs.c [new file with mode: 0644]
tools/perf/util/event.c
tools/perf/util/evlist.c
tools/perf/util/evsel.h
tools/perf/util/evsel_fprintf.c
tools/perf/util/header.c
tools/perf/util/hist.c
tools/perf/util/hist.h
tools/perf/util/include/dwarf-regs.h
tools/perf/util/intel-bts.c
tools/perf/util/intel-pt.c
tools/perf/util/lzma.c
tools/perf/util/machine.c
tools/perf/util/machine.h
tools/perf/util/map.c
tools/perf/util/map.h
tools/perf/util/parse-events.c
tools/perf/util/parse-events.h
tools/perf/util/parse-events.l
tools/perf/util/parse-events.y
tools/perf/util/pmu.c
tools/perf/util/probe-event.c
tools/perf/util/probe-event.h
tools/perf/util/probe-file.c
tools/perf/util/probe-file.h
tools/perf/util/probe-finder.c
tools/perf/util/probe-finder.h
tools/perf/util/scripting-engines/trace-event-perl.c
tools/perf/util/scripting-engines/trace-event-python.c
tools/perf/util/sort.c
tools/perf/util/sort.h
tools/perf/util/svghelper.c
tools/perf/util/symbol-elf.c
tools/perf/util/symbol-minimal.c
tools/perf/util/symbol.c
tools/perf/util/symbol.h
tools/perf/util/util.c
tools/perf/util/util.h

index ea52ec1f8484353b904431a59f4f2e6cedce5830..e4991fb1eedcd4efcd258a7b1290fd087e5f9923 100644 (file)
@@ -44,8 +44,8 @@ Synopsis of kprobe_events
   +|-offs(FETCHARG) : Fetch memory at FETCHARG +|- offs address.(**)
   NAME=FETCHARG : Set NAME as the argument name of FETCHARG.
   FETCHARG:TYPE : Set TYPE as the type of FETCHARG. Currently, basic types
-                 (u8/u16/u32/u64/s8/s16/s32/s64), "string" and bitfield
-                 are supported.
+                 (u8/u16/u32/u64/s8/s16/s32/s64), hexadecimal types
+                 (x8/x16/x32/x64), "string" and bitfield are supported.
 
   (*) only for return probe.
   (**) this is useful for fetching a field of data structures.
@@ -54,7 +54,10 @@ Types
 -----
 Several types are supported for fetch-args. Kprobe tracer will access memory
 by given type. Prefix 's' and 'u' means those types are signed and unsigned
-respectively. Traced arguments are shown in decimal (signed) or hex (unsigned).
+respectively. 'x' prefix implies it is unsigned. Traced arguments are shown
+in decimal ('s' and 'u') or hexadecimal ('x'). Without type casting, 'x32'
+or 'x64' is used depends on the architecture (e.g. x86-32 uses x32, and
+x86-64 uses x64).
 String type is a special type, which fetches a "null-terminated" string from
 kernel space. This means it will fail and store NULL if the string container
 has been paged out.
index 72d1cd4f7bf3b2a3098f6b4f87fac3a91c859716..94b6b45817635b25b4c68a75cf393f78f2388b21 100644 (file)
@@ -40,8 +40,8 @@ Synopsis of uprobe_tracer
    +|-offs(FETCHARG) : Fetch memory at FETCHARG +|- offs address.(**)
    NAME=FETCHARG     : Set NAME as the argument name of FETCHARG.
    FETCHARG:TYPE     : Set TYPE as the type of FETCHARG. Currently, basic types
-                      (u8/u16/u32/u64/s8/s16/s32/s64), "string" and bitfield
-                      are supported.
+                      (u8/u16/u32/u64/s8/s16/s32/s64), hexadecimal types
+                      (x8/x16/x32/x64), "string" and bitfield are supported.
 
   (*) only for return probe.
   (**) this is useful for fetching a field of data structures.
@@ -50,7 +50,10 @@ Types
 -----
 Several types are supported for fetch-args. Uprobe tracer will access memory
 by given type. Prefix 's' and 'u' means those types are signed and unsigned
-respectively. Traced arguments are shown in decimal (signed) or hex (unsigned).
+respectively. 'x' prefix implies it is unsigned. Traced arguments are shown
+in decimal ('s' and 'u') or hexadecimal ('x'). Without type casting, 'x32'
+or 'x64' is used depends on the architecture (e.g. x86-32 uses x32, and
+x86-64 uses x64).
 String type is a special type, which fetches a "null-terminated" string from
 user space.
 Bitfield is another special type, which takes 3 parameters, bit-width, bit-
index d0efb5cb1b00ece9656805cc62124454d00cda2d..18a1acf86c907cfec47b8b31d90c868cdc20211f 100644 (file)
@@ -1201,6 +1201,9 @@ static int x86_pmu_add(struct perf_event *event, int flags)
         * If group events scheduling transaction was started,
         * skip the schedulability test here, it will be performed
         * at commit time (->commit_txn) as a whole.
+        *
+        * If commit fails, we'll call ->del() on all events
+        * for which ->add() was called.
         */
        if (cpuc->txn_flags & PERF_PMU_TXN_ADD)
                goto done_collect;
@@ -1223,6 +1226,14 @@ done_collect:
        cpuc->n_added += n - n0;
        cpuc->n_txn += n - n0;
 
+       if (x86_pmu.add) {
+               /*
+                * This is before x86_pmu_enable() will call x86_pmu_start(),
+                * so we enable LBRs before an event needs them etc..
+                */
+               x86_pmu.add(event);
+       }
+
        ret = 0;
 out:
        return ret;
@@ -1346,7 +1357,7 @@ static void x86_pmu_del(struct perf_event *event, int flags)
        event->hw.flags &= ~PERF_X86_EVENT_COMMITTED;
 
        /*
-        * If we're called during a txn, we don't need to do anything.
+        * If we're called during a txn, we only need to undo x86_pmu.add.
         * The events never got scheduled and ->cancel_txn will truncate
         * the event_list.
         *
@@ -1354,7 +1365,7 @@ static void x86_pmu_del(struct perf_event *event, int flags)
         * an event added during that same TXN.
         */
        if (cpuc->txn_flags & PERF_PMU_TXN_ADD)
-               return;
+               goto do_del;
 
        /*
         * Not a TXN, therefore cleanup properly.
@@ -1384,6 +1395,15 @@ static void x86_pmu_del(struct perf_event *event, int flags)
        --cpuc->n_events;
 
        perf_event_update_userpage(event);
+
+do_del:
+       if (x86_pmu.del) {
+               /*
+                * This is after x86_pmu_stop(); so we disable LBRs after any
+                * event can need them etc..
+                */
+               x86_pmu.del(event);
+       }
 }
 
 int x86_pmu_handle_irq(struct pt_regs *regs)
index 4c9a79b9cd691ad8b44650ca8ea1b3b1295c0d3d..a3a9eb84b5cf16ffebd5bf46c69037db4d1e3794 100644 (file)
@@ -1906,13 +1906,6 @@ static void intel_pmu_disable_event(struct perf_event *event)
        cpuc->intel_ctrl_host_mask &= ~(1ull << hwc->idx);
        cpuc->intel_cp_status &= ~(1ull << hwc->idx);
 
-       /*
-        * must disable before any actual event
-        * because any event may be combined with LBR
-        */
-       if (needs_branch_stack(event))
-               intel_pmu_lbr_disable(event);
-
        if (unlikely(hwc->config_base == MSR_ARCH_PERFMON_FIXED_CTR_CTRL)) {
                intel_pmu_disable_fixed(hwc);
                return;
@@ -1924,6 +1917,14 @@ static void intel_pmu_disable_event(struct perf_event *event)
                intel_pmu_pebs_disable(event);
 }
 
+static void intel_pmu_del_event(struct perf_event *event)
+{
+       if (needs_branch_stack(event))
+               intel_pmu_lbr_del(event);
+       if (event->attr.precise_ip)
+               intel_pmu_pebs_del(event);
+}
+
 static void intel_pmu_enable_fixed(struct hw_perf_event *hwc)
 {
        int idx = hwc->idx - INTEL_PMC_IDX_FIXED;
@@ -1967,12 +1968,6 @@ static void intel_pmu_enable_event(struct perf_event *event)
                intel_pmu_enable_bts(hwc->config);
                return;
        }
-       /*
-        * must enabled before any actual event
-        * because any event may be combined with LBR
-        */
-       if (needs_branch_stack(event))
-               intel_pmu_lbr_enable(event);
 
        if (event->attr.exclude_host)
                cpuc->intel_ctrl_guest_mask |= (1ull << hwc->idx);
@@ -1993,6 +1988,14 @@ static void intel_pmu_enable_event(struct perf_event *event)
        __x86_pmu_enable_event(hwc, ARCH_PERFMON_EVENTSEL_ENABLE);
 }
 
+static void intel_pmu_add_event(struct perf_event *event)
+{
+       if (event->attr.precise_ip)
+               intel_pmu_pebs_add(event);
+       if (needs_branch_stack(event))
+               intel_pmu_lbr_add(event);
+}
+
 /*
  * Save and restart an expired event. Called by NMI contexts,
  * so it has to be careful about preempting normal event ops:
@@ -3291,6 +3294,8 @@ static __initconst const struct x86_pmu intel_pmu = {
        .enable_all             = intel_pmu_enable_all,
        .enable                 = intel_pmu_enable_event,
        .disable                = intel_pmu_disable_event,
+       .add                    = intel_pmu_add_event,
+       .del                    = intel_pmu_del_event,
        .hw_config              = intel_pmu_hw_config,
        .schedule_events        = x86_schedule_events,
        .eventsel               = MSR_ARCH_PERFMON_EVENTSEL0,
index 9b983a474253768d172c5db3dee8a1d50098bf4f..0319311dbdbb548eef4f5b2431c285deea5dd00c 100644 (file)
@@ -806,9 +806,65 @@ struct event_constraint *intel_pebs_constraints(struct perf_event *event)
        return &emptyconstraint;
 }
 
-static inline bool pebs_is_enabled(struct cpu_hw_events *cpuc)
+/*
+ * We need the sched_task callback even for per-cpu events when we use
+ * the large interrupt threshold, such that we can provide PID and TID
+ * to PEBS samples.
+ */
+static inline bool pebs_needs_sched_cb(struct cpu_hw_events *cpuc)
+{
+       return cpuc->n_pebs && (cpuc->n_pebs == cpuc->n_large_pebs);
+}
+
+static inline void pebs_update_threshold(struct cpu_hw_events *cpuc)
+{
+       struct debug_store *ds = cpuc->ds;
+       u64 threshold;
+
+       if (cpuc->n_pebs == cpuc->n_large_pebs) {
+               threshold = ds->pebs_absolute_maximum -
+                       x86_pmu.max_pebs_events * x86_pmu.pebs_record_size;
+       } else {
+               threshold = ds->pebs_buffer_base + x86_pmu.pebs_record_size;
+       }
+
+       ds->pebs_interrupt_threshold = threshold;
+}
+
+static void
+pebs_update_state(bool needed_cb, struct cpu_hw_events *cpuc, struct pmu *pmu)
+{
+       /*
+        * Make sure we get updated with the first PEBS
+        * event. It will trigger also during removal, but
+        * that does not hurt:
+        */
+       bool update = cpuc->n_pebs == 1;
+
+       if (needed_cb != pebs_needs_sched_cb(cpuc)) {
+               if (!needed_cb)
+                       perf_sched_cb_inc(pmu);
+               else
+                       perf_sched_cb_dec(pmu);
+
+               update = true;
+       }
+
+       if (update)
+               pebs_update_threshold(cpuc);
+}
+
+void intel_pmu_pebs_add(struct perf_event *event)
 {
-       return (cpuc->pebs_enabled & ((1ULL << MAX_PEBS_EVENTS) - 1));
+       struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
+       struct hw_perf_event *hwc = &event->hw;
+       bool needed_cb = pebs_needs_sched_cb(cpuc);
+
+       cpuc->n_pebs++;
+       if (hwc->flags & PERF_X86_EVENT_FREERUNNING)
+               cpuc->n_large_pebs++;
+
+       pebs_update_state(needed_cb, cpuc, event->ctx->pmu);
 }
 
 void intel_pmu_pebs_enable(struct perf_event *event)
@@ -816,12 +872,9 @@ void intel_pmu_pebs_enable(struct perf_event *event)
        struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
        struct hw_perf_event *hwc = &event->hw;
        struct debug_store *ds = cpuc->ds;
-       bool first_pebs;
-       u64 threshold;
 
        hwc->config &= ~ARCH_PERFMON_EVENTSEL_INT;
 
-       first_pebs = !pebs_is_enabled(cpuc);
        cpuc->pebs_enabled |= 1ULL << hwc->idx;
 
        if (event->hw.flags & PERF_X86_EVENT_PEBS_LDLAT)
@@ -830,46 +883,34 @@ void intel_pmu_pebs_enable(struct perf_event *event)
                cpuc->pebs_enabled |= 1ULL << 63;
 
        /*
-        * When the event is constrained enough we can use a larger
-        * threshold and run the event with less frequent PMI.
+        * Use auto-reload if possible to save a MSR write in the PMI.
+        * This must be done in pmu::start(), because PERF_EVENT_IOC_PERIOD.
         */
-       if (hwc->flags & PERF_X86_EVENT_FREERUNNING) {
-               threshold = ds->pebs_absolute_maximum -
-                       x86_pmu.max_pebs_events * x86_pmu.pebs_record_size;
-
-               if (first_pebs)
-                       perf_sched_cb_inc(event->ctx->pmu);
-       } else {
-               threshold = ds->pebs_buffer_base + x86_pmu.pebs_record_size;
-
-               /*
-                * If not all events can use larger buffer,
-                * roll back to threshold = 1
-                */
-               if (!first_pebs &&
-                   (ds->pebs_interrupt_threshold > threshold))
-                       perf_sched_cb_dec(event->ctx->pmu);
-       }
-
-       /* Use auto-reload if possible to save a MSR write in the PMI */
        if (hwc->flags & PERF_X86_EVENT_AUTO_RELOAD) {
                ds->pebs_event_reset[hwc->idx] =
                        (u64)(-hwc->sample_period) & x86_pmu.cntval_mask;
        }
+}
+
+void intel_pmu_pebs_del(struct perf_event *event)
+{
+       struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
+       struct hw_perf_event *hwc = &event->hw;
+       bool needed_cb = pebs_needs_sched_cb(cpuc);
 
-       if (first_pebs || ds->pebs_interrupt_threshold > threshold)
-               ds->pebs_interrupt_threshold = threshold;
+       cpuc->n_pebs--;
+       if (hwc->flags & PERF_X86_EVENT_FREERUNNING)
+               cpuc->n_large_pebs--;
+
+       pebs_update_state(needed_cb, cpuc, event->ctx->pmu);
 }
 
 void intel_pmu_pebs_disable(struct perf_event *event)
 {
        struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
        struct hw_perf_event *hwc = &event->hw;
-       struct debug_store *ds = cpuc->ds;
-       bool large_pebs = ds->pebs_interrupt_threshold >
-               ds->pebs_buffer_base + x86_pmu.pebs_record_size;
 
-       if (large_pebs)
+       if (cpuc->n_pebs == cpuc->n_large_pebs)
                intel_pmu_drain_pebs_buffer();
 
        cpuc->pebs_enabled &= ~(1ULL << hwc->idx);
@@ -879,9 +920,6 @@ void intel_pmu_pebs_disable(struct perf_event *event)
        else if (event->hw.flags & PERF_X86_EVENT_PEBS_ST)
                cpuc->pebs_enabled &= ~(1ULL << 63);
 
-       if (large_pebs && !pebs_is_enabled(cpuc))
-               perf_sched_cb_dec(event->ctx->pmu);
-
        if (cpuc->enabled)
                wrmsrl(MSR_IA32_PEBS_ENABLE, cpuc->pebs_enabled);
 
index 707d358e0dff59ed5871bc49ceda0462c4f818be..fc6cf21c535e19f4c07deccf4a6444199e5ae39c 100644 (file)
@@ -380,7 +380,6 @@ static void __intel_pmu_lbr_save(struct x86_perf_task_context *task_ctx)
 
 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;
 
        /*
@@ -390,31 +389,21 @@ void intel_pmu_lbr_sched_task(struct perf_event_context *ctx, bool sched_in)
         */
        task_ctx = ctx ? ctx->task_ctx_data : NULL;
        if (task_ctx) {
-               if (sched_in) {
+               if (sched_in)
                        __intel_pmu_lbr_restore(task_ctx);
-                       cpuc->lbr_context = ctx;
-               } else {
+               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) {
+        * Since a context switch can flip the address space and LBR entries
+        * are not tagged with an identifier, we need to wipe the LBR, even for
+        * per-cpu events. You simply cannot resolve the branches from the old
+        * address space.
+        */
+       if (sched_in)
                intel_pmu_lbr_reset();
-               cpuc->lbr_context = ctx;
-       }
 }
 
 static inline bool branch_user_callstack(unsigned br_sel)
@@ -422,7 +411,7 @@ 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)
+void intel_pmu_lbr_add(struct perf_event *event)
 {
        struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
        struct x86_perf_task_context *task_ctx;
@@ -430,27 +419,38 @@ void intel_pmu_lbr_enable(struct perf_event *event)
        if (!x86_pmu.lbr_nr)
                return;
 
-       /*
-        * Reset the LBR stack if we changed task context to
-        * avoid data leaks.
-        */
-       if (event->ctx->task && cpuc->lbr_context != event->ctx) {
-               intel_pmu_lbr_reset();
-               cpuc->lbr_context = event->ctx;
-       }
        cpuc->br_sel = event->hw.branch_reg.reg;
 
-       if (branch_user_callstack(cpuc->br_sel) && event->ctx &&
-                                       event->ctx->task_ctx_data) {
+       if (branch_user_callstack(cpuc->br_sel) && event->ctx->task_ctx_data) {
                task_ctx = event->ctx->task_ctx_data;
                task_ctx->lbr_callstack_users++;
        }
 
-       cpuc->lbr_users++;
+       /*
+        * Request pmu::sched_task() callback, which will fire inside the
+        * regular perf event scheduling, so that call will:
+        *
+        *  - restore or wipe; when LBR-callstack,
+        *  - wipe; otherwise,
+        *
+        * when this is from __perf_event_task_sched_in().
+        *
+        * However, if this is from perf_install_in_context(), no such callback
+        * will follow and we'll need to reset the LBR here if this is the
+        * first LBR event.
+        *
+        * The problem is, we cannot tell these cases apart... but we can
+        * exclude the biggest chunk of cases by looking at
+        * event->total_time_running. An event that has accrued runtime cannot
+        * be 'new'. Conversely, a new event can get installed through the
+        * context switch path for the first time.
+        */
        perf_sched_cb_inc(event->ctx->pmu);
+       if (!cpuc->lbr_users++ && !event->total_time_running)
+               intel_pmu_lbr_reset();
 }
 
-void intel_pmu_lbr_disable(struct perf_event *event)
+void intel_pmu_lbr_del(struct perf_event *event)
 {
        struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
        struct x86_perf_task_context *task_ctx;
@@ -467,12 +467,6 @@ void intel_pmu_lbr_disable(struct perf_event *event)
        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();
-               /* avoid stale pointer */
-               cpuc->lbr_context = NULL;
-       }
 }
 
 void intel_pmu_lbr_enable_all(bool pmi)
index 861a7d9cb60f6c1c19b560a4912c7eef1effd8b3..c5047b8f777b27e918b3c5e0982dd274cf652dd0 100644 (file)
@@ -69,6 +69,8 @@ static struct pt_cap_desc {
        PT_CAP(psb_cyc,                 0, CR_EBX, BIT(1)),
        PT_CAP(ip_filtering,            0, CR_EBX, BIT(2)),
        PT_CAP(mtc,                     0, CR_EBX, BIT(3)),
+       PT_CAP(ptwrite,                 0, CR_EBX, BIT(4)),
+       PT_CAP(power_event_trace,       0, CR_EBX, BIT(5)),
        PT_CAP(topa_output,             0, CR_ECX, BIT(0)),
        PT_CAP(topa_multiple_entries,   0, CR_ECX, BIT(1)),
        PT_CAP(single_range_output,     0, CR_ECX, BIT(2)),
@@ -259,10 +261,16 @@ fail:
 #define RTIT_CTL_MTC   (RTIT_CTL_MTC_EN        | \
                         RTIT_CTL_MTC_RANGE)
 
+#define RTIT_CTL_PTW   (RTIT_CTL_PTW_EN        | \
+                        RTIT_CTL_FUP_ON_PTW)
+
 #define PT_CONFIG_MASK (RTIT_CTL_TSC_EN                | \
                        RTIT_CTL_DISRETC        | \
                        RTIT_CTL_CYC_PSB        | \
-                       RTIT_CTL_MTC)
+                       RTIT_CTL_MTC            | \
+                       RTIT_CTL_PWR_EVT_EN     | \
+                       RTIT_CTL_FUP_ON_PTW     | \
+                       RTIT_CTL_PTW_EN)
 
 static bool pt_event_valid(struct perf_event *event)
 {
@@ -311,6 +319,20 @@ static bool pt_event_valid(struct perf_event *event)
                        return false;
        }
 
+       if (config & RTIT_CTL_PWR_EVT_EN &&
+           !pt_cap_get(PT_CAP_power_event_trace))
+               return false;
+
+       if (config & RTIT_CTL_PTW) {
+               if (!pt_cap_get(PT_CAP_ptwrite))
+                       return false;
+
+               /* FUPonPTW without PTW doesn't make sense */
+               if ((config & RTIT_CTL_FUP_ON_PTW) &&
+                   !(config & RTIT_CTL_PTW_EN))
+                       return false;
+       }
+
        return true;
 }
 
index efffa4a09f687f9578a6d8b99a89b3d2595ded4c..53473c21b5543f4aae0f65b8a2bceade17509d19 100644 (file)
 #define RTIT_CTL_CYCLEACC              BIT(1)
 #define RTIT_CTL_OS                    BIT(2)
 #define RTIT_CTL_USR                   BIT(3)
+#define RTIT_CTL_PWR_EVT_EN            BIT(4)
+#define RTIT_CTL_FUP_ON_PTW            BIT(5)
 #define RTIT_CTL_CR3EN                 BIT(7)
 #define RTIT_CTL_TOPA                  BIT(8)
 #define RTIT_CTL_MTC_EN                        BIT(9)
 #define RTIT_CTL_TSC_EN                        BIT(10)
 #define RTIT_CTL_DISRETC               BIT(11)
+#define RTIT_CTL_PTW_EN                        BIT(12)
 #define RTIT_CTL_BRANCH_EN             BIT(13)
 #define RTIT_CTL_MTC_RANGE_OFFSET      14
 #define RTIT_CTL_MTC_RANGE             (0x0full << RTIT_CTL_MTC_RANGE_OFFSET)
@@ -91,6 +94,8 @@ enum pt_capabilities {
        PT_CAP_psb_cyc,
        PT_CAP_ip_filtering,
        PT_CAP_mtc,
+       PT_CAP_ptwrite,
+       PT_CAP_power_event_trace,
        PT_CAP_topa_output,
        PT_CAP_topa_multiple_entries,
        PT_CAP_single_range_output,
index 28865938aadf267e42829c3393cc405b0bf0672e..b0f0e835a770f7ee959681513bd7e41af39827a0 100644 (file)
@@ -357,6 +357,8 @@ static int rapl_pmu_event_init(struct perf_event *event)
        if (event->cpu < 0)
                return -EINVAL;
 
+       event->event_caps |= PERF_EV_CAP_READ_ACTIVE_PKG;
+
        /*
         * check event is known (determines counter)
         */
@@ -765,6 +767,8 @@ static const struct x86_cpu_id rapl_cpu_match[] __initconst = {
        X86_RAPL_MODEL_MATCH(INTEL_FAM6_SKYLAKE_MOBILE,  skl_rapl_init),
        X86_RAPL_MODEL_MATCH(INTEL_FAM6_SKYLAKE_DESKTOP, skl_rapl_init),
        X86_RAPL_MODEL_MATCH(INTEL_FAM6_SKYLAKE_X,       hsx_rapl_init),
+
+       X86_RAPL_MODEL_MATCH(INTEL_FAM6_ATOM_GOLDMONT, hsw_rapl_init),
        {},
 };
 
index 463dc7a5a6c3b1ad8aff48aa6507db85f857463c..d9844cc74486e602c7b768e225856323a37025b8 100644 (file)
@@ -664,6 +664,8 @@ static int uncore_pmu_event_init(struct perf_event *event)
        event->cpu = box->cpu;
        event->pmu_private = box;
 
+       event->event_caps |= PERF_EV_CAP_READ_ACTIVE_PKG;
+
        event->hw.idx = -1;
        event->hw.last_tag = ~0ULL;
        event->hw.extra_reg.idx = EXTRA_REG_NONE;
@@ -683,7 +685,8 @@ static int uncore_pmu_event_init(struct perf_event *event)
                /* fixed counters have event field hardcoded to zero */
                hwc->config = 0ULL;
        } else {
-               hwc->config = event->attr.config & pmu->type->event_mask;
+               hwc->config = event->attr.config &
+                             (pmu->type->event_mask | ((u64)pmu->type->event_mask_ext << 32));
                if (pmu->type->ops->hw_config) {
                        ret = pmu->type->ops->hw_config(box, event);
                        if (ret)
@@ -1321,6 +1324,11 @@ static const struct intel_uncore_init_fun skl_uncore_init __initconst = {
        .pci_init = skl_uncore_pci_init,
 };
 
+static const struct intel_uncore_init_fun skx_uncore_init __initconst = {
+       .cpu_init = skx_uncore_cpu_init,
+       .pci_init = skx_uncore_pci_init,
+};
+
 static const struct x86_cpu_id intel_uncore_match[] __initconst = {
        X86_UNCORE_MODEL_MATCH(INTEL_FAM6_NEHALEM_EP,     nhm_uncore_init),
        X86_UNCORE_MODEL_MATCH(INTEL_FAM6_NEHALEM,        nhm_uncore_init),
@@ -1343,6 +1351,7 @@ static const struct x86_cpu_id intel_uncore_match[] __initconst = {
        X86_UNCORE_MODEL_MATCH(INTEL_FAM6_XEON_PHI_KNL,   knl_uncore_init),
        X86_UNCORE_MODEL_MATCH(INTEL_FAM6_SKYLAKE_DESKTOP,skl_uncore_init),
        X86_UNCORE_MODEL_MATCH(INTEL_FAM6_SKYLAKE_MOBILE, skl_uncore_init),
+       X86_UNCORE_MODEL_MATCH(INTEL_FAM6_SKYLAKE_X,      skx_uncore_init),
        {},
 };
 
index 78b9c23e2d8defc2325c7edbd2d5b339605a75dc..ad986c1e29bccd7d5303d94bcbf2caa9223fcf74 100644 (file)
@@ -44,6 +44,7 @@ struct intel_uncore_type {
        unsigned perf_ctr;
        unsigned event_ctl;
        unsigned event_mask;
+       unsigned event_mask_ext;
        unsigned fixed_ctr;
        unsigned fixed_ctl;
        unsigned box_ctl;
@@ -120,6 +121,7 @@ struct intel_uncore_box {
 };
 
 #define UNCORE_BOX_FLAG_INITIATED      0
+#define UNCORE_BOX_FLAG_CTL_OFFS8      1 /* event config registers are 8-byte apart */
 
 struct uncore_event_desc {
        struct kobj_attribute attr;
@@ -172,6 +174,9 @@ static inline unsigned uncore_pci_fixed_ctr(struct intel_uncore_box *box)
 static inline
 unsigned uncore_pci_event_ctl(struct intel_uncore_box *box, int idx)
 {
+       if (test_bit(UNCORE_BOX_FLAG_CTL_OFFS8, &box->flags))
+               return idx * 8 + box->pmu->type->event_ctl;
+
        return idx * 4 + box->pmu->type->event_ctl;
 }
 
@@ -377,6 +382,8 @@ int bdx_uncore_pci_init(void);
 void bdx_uncore_cpu_init(void);
 int knl_uncore_pci_init(void);
 void knl_uncore_cpu_init(void);
+int skx_uncore_pci_init(void);
+void skx_uncore_cpu_init(void);
 
 /* perf_event_intel_uncore_nhmex.c */
 void nhmex_uncore_cpu_init(void);
index 9d35ec0cb8fc916ba3b4b63f5bdb1b6ebda5de55..5f845eef9a4d682a3598c13946dbdec9fb70adeb 100644 (file)
@@ -388,6 +388,8 @@ static int snb_uncore_imc_event_init(struct perf_event *event)
        event->cpu = box->cpu;
        event->pmu_private = box;
 
+       event->event_caps |= PERF_EV_CAP_READ_ACTIVE_PKG;
+
        event->hw.idx = -1;
        event->hw.last_tag = ~0ULL;
        event->hw.extra_reg.idx = EXTRA_REG_NONE;
index 8aee83bcf71f2dc5a380009957d0858a7b4a2507..272427700d48deebdbcb582b1bd4af143e44a58c 100644 (file)
@@ -1,6 +1,10 @@
 /* SandyBridge-EP/IvyTown uncore support */
 #include "uncore.h"
 
+/* SNB-EP pci bus to socket mapping */
+#define SNBEP_CPUNODEID                        0x40
+#define SNBEP_GIDNIDMAP                        0x54
+
 /* SNB-EP Box level control */
 #define SNBEP_PMON_BOX_CTL_RST_CTRL    (1 << 0)
 #define SNBEP_PMON_BOX_CTL_RST_CTRS    (1 << 1)
                                 SNBEP_PCU_MSR_PMON_CTL_OCC_INVERT | \
                                 SNBEP_PCU_MSR_PMON_CTL_OCC_EDGE_DET)
 
+/* SKX pci bus to socket mapping */
+#define SKX_CPUNODEID                  0xc0
+#define SKX_GIDNIDMAP                  0xd4
+
+/* SKX CHA */
+#define SKX_CHA_MSR_PMON_BOX_FILTER_TID                (0x1ffULL << 0)
+#define SKX_CHA_MSR_PMON_BOX_FILTER_LINK       (0xfULL << 9)
+#define SKX_CHA_MSR_PMON_BOX_FILTER_STATE      (0x3ffULL << 17)
+#define SKX_CHA_MSR_PMON_BOX_FILTER_REM                (0x1ULL << 32)
+#define SKX_CHA_MSR_PMON_BOX_FILTER_LOC                (0x1ULL << 33)
+#define SKX_CHA_MSR_PMON_BOX_FILTER_ALL_OPC    (0x1ULL << 35)
+#define SKX_CHA_MSR_PMON_BOX_FILTER_NM         (0x1ULL << 36)
+#define SKX_CHA_MSR_PMON_BOX_FILTER_NOT_NM     (0x1ULL << 37)
+#define SKX_CHA_MSR_PMON_BOX_FILTER_OPC0       (0x3ffULL << 41)
+#define SKX_CHA_MSR_PMON_BOX_FILTER_OPC1       (0x3ffULL << 51)
+#define SKX_CHA_MSR_PMON_BOX_FILTER_C6         (0x1ULL << 61)
+#define SKX_CHA_MSR_PMON_BOX_FILTER_NC         (0x1ULL << 62)
+#define SKX_CHA_MSR_PMON_BOX_FILTER_ISOC       (0x1ULL << 63)
+
+/* SKX IIO */
+#define SKX_IIO0_MSR_PMON_CTL0         0xa48
+#define SKX_IIO0_MSR_PMON_CTR0         0xa41
+#define SKX_IIO0_MSR_PMON_BOX_CTL      0xa40
+#define SKX_IIO_MSR_OFFSET             0x20
+
+#define SKX_PMON_CTL_TRESH_MASK                (0xff << 24)
+#define SKX_PMON_CTL_TRESH_MASK_EXT    (0xf)
+#define SKX_PMON_CTL_CH_MASK           (0xff << 4)
+#define SKX_PMON_CTL_FC_MASK           (0x7 << 12)
+#define SKX_IIO_PMON_RAW_EVENT_MASK    (SNBEP_PMON_CTL_EV_SEL_MASK | \
+                                        SNBEP_PMON_CTL_UMASK_MASK | \
+                                        SNBEP_PMON_CTL_EDGE_DET | \
+                                        SNBEP_PMON_CTL_INVERT | \
+                                        SKX_PMON_CTL_TRESH_MASK)
+#define SKX_IIO_PMON_RAW_EVENT_MASK_EXT        (SKX_PMON_CTL_TRESH_MASK_EXT | \
+                                        SKX_PMON_CTL_CH_MASK | \
+                                        SKX_PMON_CTL_FC_MASK)
+
+/* SKX IRP */
+#define SKX_IRP0_MSR_PMON_CTL0         0xa5b
+#define SKX_IRP0_MSR_PMON_CTR0         0xa59
+#define SKX_IRP0_MSR_PMON_BOX_CTL      0xa58
+#define SKX_IRP_MSR_OFFSET             0x20
+
+/* SKX UPI */
+#define SKX_UPI_PCI_PMON_CTL0          0x350
+#define SKX_UPI_PCI_PMON_CTR0          0x318
+#define SKX_UPI_PCI_PMON_BOX_CTL       0x378
+#define SKX_PMON_CTL_UMASK_EXT         0xff
+
+/* SKX M2M */
+#define SKX_M2M_PCI_PMON_CTL0          0x228
+#define SKX_M2M_PCI_PMON_CTR0          0x200
+#define SKX_M2M_PCI_PMON_BOX_CTL       0x258
+
 DEFINE_UNCORE_FORMAT_ATTR(event, event, "config:0-7");
 DEFINE_UNCORE_FORMAT_ATTR(event2, event, "config:0-6");
 DEFINE_UNCORE_FORMAT_ATTR(event_ext, event, "config:0-7,21");
 DEFINE_UNCORE_FORMAT_ATTR(use_occ_ctr, use_occ_ctr, "config:7");
 DEFINE_UNCORE_FORMAT_ATTR(umask, umask, "config:8-15");
+DEFINE_UNCORE_FORMAT_ATTR(umask_ext, umask, "config:8-15,32-39");
 DEFINE_UNCORE_FORMAT_ATTR(qor, qor, "config:16");
 DEFINE_UNCORE_FORMAT_ATTR(edge, edge, "config:18");
 DEFINE_UNCORE_FORMAT_ATTR(tid_en, tid_en, "config:19");
 DEFINE_UNCORE_FORMAT_ATTR(inv, inv, "config:23");
+DEFINE_UNCORE_FORMAT_ATTR(thresh9, thresh, "config:24-35");
 DEFINE_UNCORE_FORMAT_ATTR(thresh8, thresh, "config:24-31");
 DEFINE_UNCORE_FORMAT_ATTR(thresh6, thresh, "config:24-29");
 DEFINE_UNCORE_FORMAT_ATTR(thresh5, thresh, "config:24-28");
@@ -280,6 +341,8 @@ DEFINE_UNCORE_FORMAT_ATTR(occ_sel, occ_sel, "config:14-15");
 DEFINE_UNCORE_FORMAT_ATTR(occ_invert, occ_invert, "config:30");
 DEFINE_UNCORE_FORMAT_ATTR(occ_edge, occ_edge, "config:14-51");
 DEFINE_UNCORE_FORMAT_ATTR(occ_edge_det, occ_edge_det, "config:31");
+DEFINE_UNCORE_FORMAT_ATTR(ch_mask, ch_mask, "config:36-43");
+DEFINE_UNCORE_FORMAT_ATTR(fc_mask, fc_mask, "config:44-46");
 DEFINE_UNCORE_FORMAT_ATTR(filter_tid, filter_tid, "config1:0-4");
 DEFINE_UNCORE_FORMAT_ATTR(filter_tid2, filter_tid, "config1:0");
 DEFINE_UNCORE_FORMAT_ATTR(filter_tid3, filter_tid, "config1:0-5");
@@ -288,18 +351,26 @@ DEFINE_UNCORE_FORMAT_ATTR(filter_cid, filter_cid, "config1:5");
 DEFINE_UNCORE_FORMAT_ATTR(filter_link, filter_link, "config1:5-8");
 DEFINE_UNCORE_FORMAT_ATTR(filter_link2, filter_link, "config1:6-8");
 DEFINE_UNCORE_FORMAT_ATTR(filter_link3, filter_link, "config1:12");
+DEFINE_UNCORE_FORMAT_ATTR(filter_link4, filter_link, "config1:9-12");
 DEFINE_UNCORE_FORMAT_ATTR(filter_nid, filter_nid, "config1:10-17");
 DEFINE_UNCORE_FORMAT_ATTR(filter_nid2, filter_nid, "config1:32-47");
 DEFINE_UNCORE_FORMAT_ATTR(filter_state, filter_state, "config1:18-22");
 DEFINE_UNCORE_FORMAT_ATTR(filter_state2, filter_state, "config1:17-22");
 DEFINE_UNCORE_FORMAT_ATTR(filter_state3, filter_state, "config1:17-23");
 DEFINE_UNCORE_FORMAT_ATTR(filter_state4, filter_state, "config1:18-20");
+DEFINE_UNCORE_FORMAT_ATTR(filter_state5, filter_state, "config1:17-26");
+DEFINE_UNCORE_FORMAT_ATTR(filter_rem, filter_rem, "config1:32");
+DEFINE_UNCORE_FORMAT_ATTR(filter_loc, filter_loc, "config1:33");
+DEFINE_UNCORE_FORMAT_ATTR(filter_nm, filter_nm, "config1:36");
+DEFINE_UNCORE_FORMAT_ATTR(filter_not_nm, filter_not_nm, "config1:37");
 DEFINE_UNCORE_FORMAT_ATTR(filter_local, filter_local, "config1:33");
 DEFINE_UNCORE_FORMAT_ATTR(filter_all_op, filter_all_op, "config1:35");
 DEFINE_UNCORE_FORMAT_ATTR(filter_nnm, filter_nnm, "config1:37");
 DEFINE_UNCORE_FORMAT_ATTR(filter_opc, filter_opc, "config1:23-31");
 DEFINE_UNCORE_FORMAT_ATTR(filter_opc2, filter_opc, "config1:52-60");
 DEFINE_UNCORE_FORMAT_ATTR(filter_opc3, filter_opc, "config1:41-60");
+DEFINE_UNCORE_FORMAT_ATTR(filter_opc_0, filter_opc0, "config1:41-50");
+DEFINE_UNCORE_FORMAT_ATTR(filter_opc_1, filter_opc1, "config1:51-60");
 DEFINE_UNCORE_FORMAT_ATTR(filter_nc, filter_nc, "config1:62");
 DEFINE_UNCORE_FORMAT_ATTR(filter_c6, filter_c6, "config1:61");
 DEFINE_UNCORE_FORMAT_ATTR(filter_isoc, filter_isoc, "config1:63");
@@ -1153,7 +1224,7 @@ static struct pci_driver snbep_uncore_pci_driver = {
 /*
  * build pci bus to socket mapping
  */
-static int snbep_pci2phy_map_init(int devid)
+static int snbep_pci2phy_map_init(int devid, int nodeid_loc, int idmap_loc, bool reverse)
 {
        struct pci_dev *ubox_dev = NULL;
        int i, bus, nodeid, segment;
@@ -1168,12 +1239,12 @@ static int snbep_pci2phy_map_init(int devid)
                        break;
                bus = ubox_dev->bus->number;
                /* get the Node ID of the local register */
-               err = pci_read_config_dword(ubox_dev, 0x40, &config);
+               err = pci_read_config_dword(ubox_dev, nodeid_loc, &config);
                if (err)
                        break;
                nodeid = config;
                /* get the Node ID mapping */
-               err = pci_read_config_dword(ubox_dev, 0x54, &config);
+               err = pci_read_config_dword(ubox_dev, idmap_loc, &config);
                if (err)
                        break;
 
@@ -1207,11 +1278,20 @@ static int snbep_pci2phy_map_init(int devid)
                raw_spin_lock(&pci2phy_map_lock);
                list_for_each_entry(map, &pci2phy_map_head, list) {
                        i = -1;
-                       for (bus = 255; bus >= 0; bus--) {
-                               if (map->pbus_to_physid[bus] >= 0)
-                                       i = map->pbus_to_physid[bus];
-                               else
-                                       map->pbus_to_physid[bus] = i;
+                       if (reverse) {
+                               for (bus = 255; bus >= 0; bus--) {
+                                       if (map->pbus_to_physid[bus] >= 0)
+                                               i = map->pbus_to_physid[bus];
+                                       else
+                                               map->pbus_to_physid[bus] = i;
+                               }
+                       } else {
+                               for (bus = 0; bus <= 255; bus++) {
+                                       if (map->pbus_to_physid[bus] >= 0)
+                                               i = map->pbus_to_physid[bus];
+                                       else
+                                               map->pbus_to_physid[bus] = i;
+                               }
                        }
                }
                raw_spin_unlock(&pci2phy_map_lock);
@@ -1224,7 +1304,7 @@ static int snbep_pci2phy_map_init(int devid)
 
 int snbep_uncore_pci_init(void)
 {
-       int ret = snbep_pci2phy_map_init(0x3ce0);
+       int ret = snbep_pci2phy_map_init(0x3ce0, SNBEP_CPUNODEID, SNBEP_GIDNIDMAP, true);
        if (ret)
                return ret;
        uncore_pci_uncores = snbep_pci_uncores;
@@ -1788,7 +1868,7 @@ static struct pci_driver ivbep_uncore_pci_driver = {
 
 int ivbep_uncore_pci_init(void)
 {
-       int ret = snbep_pci2phy_map_init(0x0e1e);
+       int ret = snbep_pci2phy_map_init(0x0e1e, SNBEP_CPUNODEID, SNBEP_GIDNIDMAP, true);
        if (ret)
                return ret;
        uncore_pci_uncores = ivbep_pci_uncores;
@@ -2897,7 +2977,7 @@ static struct pci_driver hswep_uncore_pci_driver = {
 
 int hswep_uncore_pci_init(void)
 {
-       int ret = snbep_pci2phy_map_init(0x2f1e);
+       int ret = snbep_pci2phy_map_init(0x2f1e, SNBEP_CPUNODEID, SNBEP_GIDNIDMAP, true);
        if (ret)
                return ret;
        uncore_pci_uncores = hswep_pci_uncores;
@@ -3186,7 +3266,7 @@ static struct pci_driver bdx_uncore_pci_driver = {
 
 int bdx_uncore_pci_init(void)
 {
-       int ret = snbep_pci2phy_map_init(0x6f1e);
+       int ret = snbep_pci2phy_map_init(0x6f1e, SNBEP_CPUNODEID, SNBEP_GIDNIDMAP, true);
 
        if (ret)
                return ret;
@@ -3196,3 +3276,525 @@ int bdx_uncore_pci_init(void)
 }
 
 /* end of BDX uncore support */
+
+/* SKX uncore support */
+
+static struct intel_uncore_type skx_uncore_ubox = {
+       .name                   = "ubox",
+       .num_counters           = 2,
+       .num_boxes              = 1,
+       .perf_ctr_bits          = 48,
+       .fixed_ctr_bits         = 48,
+       .perf_ctr               = HSWEP_U_MSR_PMON_CTR0,
+       .event_ctl              = HSWEP_U_MSR_PMON_CTL0,
+       .event_mask             = SNBEP_U_MSR_PMON_RAW_EVENT_MASK,
+       .fixed_ctr              = HSWEP_U_MSR_PMON_UCLK_FIXED_CTR,
+       .fixed_ctl              = HSWEP_U_MSR_PMON_UCLK_FIXED_CTL,
+       .ops                    = &ivbep_uncore_msr_ops,
+       .format_group           = &ivbep_uncore_ubox_format_group,
+};
+
+static struct attribute *skx_uncore_cha_formats_attr[] = {
+       &format_attr_event.attr,
+       &format_attr_umask.attr,
+       &format_attr_edge.attr,
+       &format_attr_tid_en.attr,
+       &format_attr_inv.attr,
+       &format_attr_thresh8.attr,
+       &format_attr_filter_tid4.attr,
+       &format_attr_filter_link4.attr,
+       &format_attr_filter_state5.attr,
+       &format_attr_filter_rem.attr,
+       &format_attr_filter_loc.attr,
+       &format_attr_filter_nm.attr,
+       &format_attr_filter_all_op.attr,
+       &format_attr_filter_not_nm.attr,
+       &format_attr_filter_opc_0.attr,
+       &format_attr_filter_opc_1.attr,
+       &format_attr_filter_nc.attr,
+       &format_attr_filter_c6.attr,
+       &format_attr_filter_isoc.attr,
+       NULL,
+};
+
+static struct attribute_group skx_uncore_chabox_format_group = {
+       .name = "format",
+       .attrs = skx_uncore_cha_formats_attr,
+};
+
+static struct event_constraint skx_uncore_chabox_constraints[] = {
+       UNCORE_EVENT_CONSTRAINT(0x11, 0x1),
+       UNCORE_EVENT_CONSTRAINT(0x36, 0x1),
+       EVENT_CONSTRAINT_END
+};
+
+static struct extra_reg skx_uncore_cha_extra_regs[] = {
+       SNBEP_CBO_EVENT_EXTRA_REG(0x0334, 0xffff, 0x4),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x0534, 0xffff, 0x4),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x0934, 0xffff, 0x4),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x1134, 0xffff, 0x4),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x2134, 0xffff, 0x4),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x8134, 0xffff, 0x4),
+};
+
+static u64 skx_cha_filter_mask(int fields)
+{
+       u64 mask = 0;
+
+       if (fields & 0x1)
+               mask |= SKX_CHA_MSR_PMON_BOX_FILTER_TID;
+       if (fields & 0x2)
+               mask |= SKX_CHA_MSR_PMON_BOX_FILTER_LINK;
+       if (fields & 0x4)
+               mask |= SKX_CHA_MSR_PMON_BOX_FILTER_STATE;
+       return mask;
+}
+
+static struct event_constraint *
+skx_cha_get_constraint(struct intel_uncore_box *box, struct perf_event *event)
+{
+       return __snbep_cbox_get_constraint(box, event, skx_cha_filter_mask);
+}
+
+static int skx_cha_hw_config(struct intel_uncore_box *box, struct perf_event *event)
+{
+       struct hw_perf_event_extra *reg1 = &event->hw.extra_reg;
+       struct extra_reg *er;
+       int idx = 0;
+
+       for (er = skx_uncore_cha_extra_regs; er->msr; er++) {
+               if (er->event != (event->hw.config & er->config_mask))
+                       continue;
+               idx |= er->idx;
+       }
+
+       if (idx) {
+               reg1->reg = HSWEP_C0_MSR_PMON_BOX_FILTER0 +
+                           HSWEP_CBO_MSR_OFFSET * box->pmu->pmu_idx;
+               reg1->config = event->attr.config1 & skx_cha_filter_mask(idx);
+               reg1->idx = idx;
+       }
+       return 0;
+}
+
+static struct intel_uncore_ops skx_uncore_chabox_ops = {
+       /* There is no frz_en for chabox ctl */
+       .init_box               = ivbep_uncore_msr_init_box,
+       .disable_box            = snbep_uncore_msr_disable_box,
+       .enable_box             = snbep_uncore_msr_enable_box,
+       .disable_event          = snbep_uncore_msr_disable_event,
+       .enable_event           = hswep_cbox_enable_event,
+       .read_counter           = uncore_msr_read_counter,
+       .hw_config              = skx_cha_hw_config,
+       .get_constraint         = skx_cha_get_constraint,
+       .put_constraint         = snbep_cbox_put_constraint,
+};
+
+static struct intel_uncore_type skx_uncore_chabox = {
+       .name                   = "cha",
+       .num_counters           = 4,
+       .perf_ctr_bits          = 48,
+       .event_ctl              = HSWEP_C0_MSR_PMON_CTL0,
+       .perf_ctr               = HSWEP_C0_MSR_PMON_CTR0,
+       .event_mask             = HSWEP_S_MSR_PMON_RAW_EVENT_MASK,
+       .box_ctl                = HSWEP_C0_MSR_PMON_BOX_CTL,
+       .msr_offset             = HSWEP_CBO_MSR_OFFSET,
+       .num_shared_regs        = 1,
+       .constraints            = skx_uncore_chabox_constraints,
+       .ops                    = &skx_uncore_chabox_ops,
+       .format_group           = &skx_uncore_chabox_format_group,
+};
+
+static struct attribute *skx_uncore_iio_formats_attr[] = {
+       &format_attr_event.attr,
+       &format_attr_umask.attr,
+       &format_attr_edge.attr,
+       &format_attr_inv.attr,
+       &format_attr_thresh9.attr,
+       &format_attr_ch_mask.attr,
+       &format_attr_fc_mask.attr,
+       NULL,
+};
+
+static struct attribute_group skx_uncore_iio_format_group = {
+       .name = "format",
+       .attrs = skx_uncore_iio_formats_attr,
+};
+
+static struct event_constraint skx_uncore_iio_constraints[] = {
+       UNCORE_EVENT_CONSTRAINT(0x83, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x88, 0xc),
+       UNCORE_EVENT_CONSTRAINT(0x95, 0xc),
+       UNCORE_EVENT_CONSTRAINT(0xc0, 0xc),
+       UNCORE_EVENT_CONSTRAINT(0xc5, 0xc),
+       UNCORE_EVENT_CONSTRAINT(0xd4, 0xc),
+       EVENT_CONSTRAINT_END
+};
+
+static void skx_iio_enable_event(struct intel_uncore_box *box,
+                                struct perf_event *event)
+{
+       struct hw_perf_event *hwc = &event->hw;
+
+       wrmsrl(hwc->config_base, hwc->config | SNBEP_PMON_CTL_EN);
+}
+
+static struct intel_uncore_ops skx_uncore_iio_ops = {
+       .init_box               = ivbep_uncore_msr_init_box,
+       .disable_box            = snbep_uncore_msr_disable_box,
+       .enable_box             = snbep_uncore_msr_enable_box,
+       .disable_event          = snbep_uncore_msr_disable_event,
+       .enable_event           = skx_iio_enable_event,
+       .read_counter           = uncore_msr_read_counter,
+};
+
+static struct intel_uncore_type skx_uncore_iio = {
+       .name                   = "iio",
+       .num_counters           = 4,
+       .num_boxes              = 5,
+       .perf_ctr_bits          = 48,
+       .event_ctl              = SKX_IIO0_MSR_PMON_CTL0,
+       .perf_ctr               = SKX_IIO0_MSR_PMON_CTR0,
+       .event_mask             = SKX_IIO_PMON_RAW_EVENT_MASK,
+       .event_mask_ext         = SKX_IIO_PMON_RAW_EVENT_MASK_EXT,
+       .box_ctl                = SKX_IIO0_MSR_PMON_BOX_CTL,
+       .msr_offset             = SKX_IIO_MSR_OFFSET,
+       .constraints            = skx_uncore_iio_constraints,
+       .ops                    = &skx_uncore_iio_ops,
+       .format_group           = &skx_uncore_iio_format_group,
+};
+
+static struct attribute *skx_uncore_formats_attr[] = {
+       &format_attr_event.attr,
+       &format_attr_umask.attr,
+       &format_attr_edge.attr,
+       &format_attr_inv.attr,
+       &format_attr_thresh8.attr,
+       NULL,
+};
+
+static struct attribute_group skx_uncore_format_group = {
+       .name = "format",
+       .attrs = skx_uncore_formats_attr,
+};
+
+static struct intel_uncore_type skx_uncore_irp = {
+       .name                   = "irp",
+       .num_counters           = 2,
+       .num_boxes              = 5,
+       .perf_ctr_bits          = 48,
+       .event_ctl              = SKX_IRP0_MSR_PMON_CTL0,
+       .perf_ctr               = SKX_IRP0_MSR_PMON_CTR0,
+       .event_mask             = SNBEP_PMON_RAW_EVENT_MASK,
+       .box_ctl                = SKX_IRP0_MSR_PMON_BOX_CTL,
+       .msr_offset             = SKX_IRP_MSR_OFFSET,
+       .ops                    = &skx_uncore_iio_ops,
+       .format_group           = &skx_uncore_format_group,
+};
+
+static struct intel_uncore_ops skx_uncore_pcu_ops = {
+       IVBEP_UNCORE_MSR_OPS_COMMON_INIT(),
+       .hw_config              = hswep_pcu_hw_config,
+       .get_constraint         = snbep_pcu_get_constraint,
+       .put_constraint         = snbep_pcu_put_constraint,
+};
+
+static struct intel_uncore_type skx_uncore_pcu = {
+       .name                   = "pcu",
+       .num_counters           = 4,
+       .num_boxes              = 1,
+       .perf_ctr_bits          = 48,
+       .perf_ctr               = HSWEP_PCU_MSR_PMON_CTR0,
+       .event_ctl              = HSWEP_PCU_MSR_PMON_CTL0,
+       .event_mask             = SNBEP_PCU_MSR_PMON_RAW_EVENT_MASK,
+       .box_ctl                = HSWEP_PCU_MSR_PMON_BOX_CTL,
+       .num_shared_regs        = 1,
+       .ops                    = &skx_uncore_pcu_ops,
+       .format_group           = &snbep_uncore_pcu_format_group,
+};
+
+static struct intel_uncore_type *skx_msr_uncores[] = {
+       &skx_uncore_ubox,
+       &skx_uncore_chabox,
+       &skx_uncore_iio,
+       &skx_uncore_irp,
+       &skx_uncore_pcu,
+       NULL,
+};
+
+static int skx_count_chabox(void)
+{
+       struct pci_dev *chabox_dev = NULL;
+       int bus, count = 0;
+
+       while (1) {
+               chabox_dev = pci_get_device(PCI_VENDOR_ID_INTEL, 0x208d, chabox_dev);
+               if (!chabox_dev)
+                       break;
+               if (count == 0)
+                       bus = chabox_dev->bus->number;
+               if (bus != chabox_dev->bus->number)
+                       break;
+               count++;
+       }
+
+       pci_dev_put(chabox_dev);
+       return count;
+}
+
+void skx_uncore_cpu_init(void)
+{
+       skx_uncore_chabox.num_boxes = skx_count_chabox();
+       uncore_msr_uncores = skx_msr_uncores;
+}
+
+static struct intel_uncore_type skx_uncore_imc = {
+       .name           = "imc",
+       .num_counters   = 4,
+       .num_boxes      = 6,
+       .perf_ctr_bits  = 48,
+       .fixed_ctr_bits = 48,
+       .fixed_ctr      = SNBEP_MC_CHy_PCI_PMON_FIXED_CTR,
+       .fixed_ctl      = SNBEP_MC_CHy_PCI_PMON_FIXED_CTL,
+       .event_descs    = hswep_uncore_imc_events,
+       .perf_ctr       = SNBEP_PCI_PMON_CTR0,
+       .event_ctl      = SNBEP_PCI_PMON_CTL0,
+       .event_mask     = SNBEP_PMON_RAW_EVENT_MASK,
+       .box_ctl        = SNBEP_PCI_PMON_BOX_CTL,
+       .ops            = &ivbep_uncore_pci_ops,
+       .format_group   = &skx_uncore_format_group,
+};
+
+static struct attribute *skx_upi_uncore_formats_attr[] = {
+       &format_attr_event_ext.attr,
+       &format_attr_umask_ext.attr,
+       &format_attr_edge.attr,
+       &format_attr_inv.attr,
+       &format_attr_thresh8.attr,
+       NULL,
+};
+
+static struct attribute_group skx_upi_uncore_format_group = {
+       .name = "format",
+       .attrs = skx_upi_uncore_formats_attr,
+};
+
+static void skx_upi_uncore_pci_init_box(struct intel_uncore_box *box)
+{
+       struct pci_dev *pdev = box->pci_dev;
+
+       __set_bit(UNCORE_BOX_FLAG_CTL_OFFS8, &box->flags);
+       pci_write_config_dword(pdev, SKX_UPI_PCI_PMON_BOX_CTL, IVBEP_PMON_BOX_CTL_INT);
+}
+
+static struct intel_uncore_ops skx_upi_uncore_pci_ops = {
+       .init_box       = skx_upi_uncore_pci_init_box,
+       .disable_box    = snbep_uncore_pci_disable_box,
+       .enable_box     = snbep_uncore_pci_enable_box,
+       .disable_event  = snbep_uncore_pci_disable_event,
+       .enable_event   = snbep_uncore_pci_enable_event,
+       .read_counter   = snbep_uncore_pci_read_counter,
+};
+
+static struct intel_uncore_type skx_uncore_upi = {
+       .name           = "upi",
+       .num_counters   = 4,
+       .num_boxes      = 3,
+       .perf_ctr_bits  = 48,
+       .perf_ctr       = SKX_UPI_PCI_PMON_CTR0,
+       .event_ctl      = SKX_UPI_PCI_PMON_CTL0,
+       .event_mask     = SNBEP_QPI_PCI_PMON_RAW_EVENT_MASK,
+       .event_mask_ext = SKX_PMON_CTL_UMASK_EXT,
+       .box_ctl        = SKX_UPI_PCI_PMON_BOX_CTL,
+       .ops            = &skx_upi_uncore_pci_ops,
+       .format_group   = &skx_upi_uncore_format_group,
+};
+
+static void skx_m2m_uncore_pci_init_box(struct intel_uncore_box *box)
+{
+       struct pci_dev *pdev = box->pci_dev;
+
+       __set_bit(UNCORE_BOX_FLAG_CTL_OFFS8, &box->flags);
+       pci_write_config_dword(pdev, SKX_M2M_PCI_PMON_BOX_CTL, IVBEP_PMON_BOX_CTL_INT);
+}
+
+static struct intel_uncore_ops skx_m2m_uncore_pci_ops = {
+       .init_box       = skx_m2m_uncore_pci_init_box,
+       .disable_box    = snbep_uncore_pci_disable_box,
+       .enable_box     = snbep_uncore_pci_enable_box,
+       .disable_event  = snbep_uncore_pci_disable_event,
+       .enable_event   = snbep_uncore_pci_enable_event,
+       .read_counter   = snbep_uncore_pci_read_counter,
+};
+
+static struct intel_uncore_type skx_uncore_m2m = {
+       .name           = "m2m",
+       .num_counters   = 4,
+       .num_boxes      = 2,
+       .perf_ctr_bits  = 48,
+       .perf_ctr       = SKX_M2M_PCI_PMON_CTR0,
+       .event_ctl      = SKX_M2M_PCI_PMON_CTL0,
+       .event_mask     = SNBEP_PMON_RAW_EVENT_MASK,
+       .box_ctl        = SKX_M2M_PCI_PMON_BOX_CTL,
+       .ops            = &skx_m2m_uncore_pci_ops,
+       .format_group   = &skx_uncore_format_group,
+};
+
+static struct event_constraint skx_uncore_m2pcie_constraints[] = {
+       UNCORE_EVENT_CONSTRAINT(0x23, 0x3),
+       EVENT_CONSTRAINT_END
+};
+
+static struct intel_uncore_type skx_uncore_m2pcie = {
+       .name           = "m2pcie",
+       .num_counters   = 4,
+       .num_boxes      = 4,
+       .perf_ctr_bits  = 48,
+       .constraints    = skx_uncore_m2pcie_constraints,
+       .perf_ctr       = SNBEP_PCI_PMON_CTR0,
+       .event_ctl      = SNBEP_PCI_PMON_CTL0,
+       .event_mask     = SNBEP_PMON_RAW_EVENT_MASK,
+       .box_ctl        = SNBEP_PCI_PMON_BOX_CTL,
+       .ops            = &ivbep_uncore_pci_ops,
+       .format_group   = &skx_uncore_format_group,
+};
+
+static struct event_constraint skx_uncore_m3upi_constraints[] = {
+       UNCORE_EVENT_CONSTRAINT(0x1d, 0x1),
+       UNCORE_EVENT_CONSTRAINT(0x1e, 0x1),
+       UNCORE_EVENT_CONSTRAINT(0x40, 0x7),
+       UNCORE_EVENT_CONSTRAINT(0x4e, 0x7),
+       UNCORE_EVENT_CONSTRAINT(0x4f, 0x7),
+       UNCORE_EVENT_CONSTRAINT(0x50, 0x7),
+       UNCORE_EVENT_CONSTRAINT(0x51, 0x7),
+       UNCORE_EVENT_CONSTRAINT(0x52, 0x7),
+       EVENT_CONSTRAINT_END
+};
+
+static struct intel_uncore_type skx_uncore_m3upi = {
+       .name           = "m3upi",
+       .num_counters   = 3,
+       .num_boxes      = 3,
+       .perf_ctr_bits  = 48,
+       .constraints    = skx_uncore_m3upi_constraints,
+       .perf_ctr       = SNBEP_PCI_PMON_CTR0,
+       .event_ctl      = SNBEP_PCI_PMON_CTL0,
+       .event_mask     = SNBEP_PMON_RAW_EVENT_MASK,
+       .box_ctl        = SNBEP_PCI_PMON_BOX_CTL,
+       .ops            = &ivbep_uncore_pci_ops,
+       .format_group   = &skx_uncore_format_group,
+};
+
+enum {
+       SKX_PCI_UNCORE_IMC,
+       SKX_PCI_UNCORE_M2M,
+       SKX_PCI_UNCORE_UPI,
+       SKX_PCI_UNCORE_M2PCIE,
+       SKX_PCI_UNCORE_M3UPI,
+};
+
+static struct intel_uncore_type *skx_pci_uncores[] = {
+       [SKX_PCI_UNCORE_IMC]    = &skx_uncore_imc,
+       [SKX_PCI_UNCORE_M2M]    = &skx_uncore_m2m,
+       [SKX_PCI_UNCORE_UPI]    = &skx_uncore_upi,
+       [SKX_PCI_UNCORE_M2PCIE] = &skx_uncore_m2pcie,
+       [SKX_PCI_UNCORE_M3UPI]  = &skx_uncore_m3upi,
+       NULL,
+};
+
+static const struct pci_device_id skx_uncore_pci_ids[] = {
+       { /* MC0 Channel 0 */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x2042),
+               .driver_data = UNCORE_PCI_DEV_FULL_DATA(10, 2, SKX_PCI_UNCORE_IMC, 0),
+       },
+       { /* MC0 Channel 1 */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x2046),
+               .driver_data = UNCORE_PCI_DEV_FULL_DATA(10, 6, SKX_PCI_UNCORE_IMC, 1),
+       },
+       { /* MC0 Channel 2 */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x204a),
+               .driver_data = UNCORE_PCI_DEV_FULL_DATA(11, 2, SKX_PCI_UNCORE_IMC, 2),
+       },
+       { /* MC1 Channel 0 */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x2042),
+               .driver_data = UNCORE_PCI_DEV_FULL_DATA(12, 2, SKX_PCI_UNCORE_IMC, 3),
+       },
+       { /* MC1 Channel 1 */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x2046),
+               .driver_data = UNCORE_PCI_DEV_FULL_DATA(12, 6, SKX_PCI_UNCORE_IMC, 4),
+       },
+       { /* MC1 Channel 2 */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x204a),
+               .driver_data = UNCORE_PCI_DEV_FULL_DATA(13, 2, SKX_PCI_UNCORE_IMC, 5),
+       },
+       { /* M2M0 */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x2066),
+               .driver_data = UNCORE_PCI_DEV_FULL_DATA(8, 0, SKX_PCI_UNCORE_M2M, 0),
+       },
+       { /* M2M1 */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x2066),
+               .driver_data = UNCORE_PCI_DEV_FULL_DATA(9, 0, SKX_PCI_UNCORE_M2M, 1),
+       },
+       { /* UPI0 Link 0 */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x2058),
+               .driver_data = UNCORE_PCI_DEV_FULL_DATA(14, 0, SKX_PCI_UNCORE_UPI, 0),
+       },
+       { /* UPI0 Link 1 */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x2058),
+               .driver_data = UNCORE_PCI_DEV_FULL_DATA(15, 0, SKX_PCI_UNCORE_UPI, 1),
+       },
+       { /* UPI1 Link 2 */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x2058),
+               .driver_data = UNCORE_PCI_DEV_FULL_DATA(16, 0, SKX_PCI_UNCORE_UPI, 2),
+       },
+       { /* M2PCIe 0 */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x2088),
+               .driver_data = UNCORE_PCI_DEV_FULL_DATA(21, 1, SKX_PCI_UNCORE_M2PCIE, 0),
+       },
+       { /* M2PCIe 1 */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x2088),
+               .driver_data = UNCORE_PCI_DEV_FULL_DATA(22, 1, SKX_PCI_UNCORE_M2PCIE, 1),
+       },
+       { /* M2PCIe 2 */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x2088),
+               .driver_data = UNCORE_PCI_DEV_FULL_DATA(23, 1, SKX_PCI_UNCORE_M2PCIE, 2),
+       },
+       { /* M2PCIe 3 */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x2088),
+               .driver_data = UNCORE_PCI_DEV_FULL_DATA(21, 5, SKX_PCI_UNCORE_M2PCIE, 3),
+       },
+       { /* M3UPI0 Link 0 */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x204C),
+               .driver_data = UNCORE_PCI_DEV_FULL_DATA(18, 0, SKX_PCI_UNCORE_M3UPI, 0),
+       },
+       { /* M3UPI0 Link 1 */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x204D),
+               .driver_data = UNCORE_PCI_DEV_FULL_DATA(18, 1, SKX_PCI_UNCORE_M3UPI, 1),
+       },
+       { /* M3UPI1 Link 2 */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x204C),
+               .driver_data = UNCORE_PCI_DEV_FULL_DATA(18, 4, SKX_PCI_UNCORE_M3UPI, 2),
+       },
+       { /* end: all zeroes */ }
+};
+
+
+static struct pci_driver skx_uncore_pci_driver = {
+       .name           = "skx_uncore",
+       .id_table       = skx_uncore_pci_ids,
+};
+
+int skx_uncore_pci_init(void)
+{
+       /* need to double check pci address */
+       int ret = snbep_pci2phy_map_init(0x2014, SKX_CPUNODEID, SKX_GIDNIDMAP, false);
+
+       if (ret)
+               return ret;
+
+       uncore_pci_uncores = skx_pci_uncores;
+       uncore_pci_driver = &skx_uncore_pci_driver;
+       return 0;
+}
+
+/* end of SKX uncore support */
index 8c4a47706296ab49a2c3825c6312e207e608bdeb..5874d8de1f8da111e3e0a682835e42b23af875ff 100644 (file)
@@ -194,12 +194,13 @@ struct cpu_hw_events {
         */
        struct debug_store      *ds;
        u64                     pebs_enabled;
+       int                     n_pebs;
+       int                     n_large_pebs;
 
        /*
         * Intel LBR bits
         */
        int                             lbr_users;
-       void                            *lbr_context;
        struct perf_branch_stack        lbr_stack;
        struct perf_branch_entry        lbr_entries[MAX_LBR_ENTRIES];
        struct er_account               *lbr_sel;
@@ -508,6 +509,8 @@ struct x86_pmu {
        void            (*enable_all)(int added);
        void            (*enable)(struct perf_event *);
        void            (*disable)(struct perf_event *);
+       void            (*add)(struct perf_event *);
+       void            (*del)(struct perf_event *);
        int             (*hw_config)(struct perf_event *event);
        int             (*schedule_events)(struct cpu_hw_events *cpuc, int n, int *assign);
        unsigned        eventsel;
@@ -888,6 +891,10 @@ extern struct event_constraint intel_skl_pebs_event_constraints[];
 
 struct event_constraint *intel_pebs_constraints(struct perf_event *event);
 
+void intel_pmu_pebs_add(struct perf_event *event);
+
+void intel_pmu_pebs_del(struct perf_event *event);
+
 void intel_pmu_pebs_enable(struct perf_event *event);
 
 void intel_pmu_pebs_disable(struct perf_event *event);
@@ -906,9 +913,9 @@ u64 lbr_from_signext_quirk_wr(u64 val);
 
 void intel_pmu_lbr_reset(void);
 
-void intel_pmu_lbr_enable(struct perf_event *event);
+void intel_pmu_lbr_add(struct perf_event *event);
 
-void intel_pmu_lbr_disable(struct perf_event *event);
+void intel_pmu_lbr_del(struct perf_event *event);
 
 void intel_pmu_lbr_enable_all(bool pmi);
 
index 598bc999f4c2860969771b77d67872348f1f87f1..3b77588a93602eecd5d73d30d6fd77377286f07e 100644 (file)
@@ -339,6 +339,24 @@ static inline int bitmap_parse(const char *buf, unsigned int buflen,
        return __bitmap_parse(buf, buflen, 0, maskp, nmaskbits);
 }
 
+/*
+ * bitmap_from_u64 - Check and swap words within u64.
+ *  @mask: source bitmap
+ *  @dst:  destination bitmap
+ *
+ * In 32-bit Big Endian kernel, when using (u32 *)(&val)[*]
+ * to read u64 mask, we will get the wrong word.
+ * That is "(u32 *)(&val)[0]" gets the upper 32 bits,
+ * but we expect the lower 32-bits of u64.
+ */
+static inline void bitmap_from_u64(unsigned long *dst, u64 mask)
+{
+       dst[0] = mask & ULONG_MAX;
+
+       if (sizeof(mask) > sizeof(unsigned long))
+               dst[1] = mask >> 32;
+}
+
 #endif /* __ASSEMBLY__ */
 
 #endif /* __LINUX_BITMAP_H */
index 2b6b43cc0dd5121d8d4f6024f8ec67f862ff3328..5c5362584aba12095b03d66e18447d7e412a06f1 100644 (file)
@@ -510,9 +510,15 @@ typedef void (*perf_overflow_handler_t)(struct perf_event *,
                                        struct perf_sample_data *,
                                        struct pt_regs *regs);
 
-enum perf_group_flag {
-       PERF_GROUP_SOFTWARE             = 0x1,
-};
+/*
+ * Event capabilities. For event_caps and groups caps.
+ *
+ * PERF_EV_CAP_SOFTWARE: Is a software event.
+ * PERF_EV_CAP_READ_ACTIVE_PKG: A CPU event (or cgroup event) that can be read
+ * from any CPU in the package where it is active.
+ */
+#define PERF_EV_CAP_SOFTWARE           BIT(0)
+#define PERF_EV_CAP_READ_ACTIVE_PKG    BIT(1)
 
 #define SWEVENT_HLIST_BITS             8
 #define SWEVENT_HLIST_SIZE             (1 << SWEVENT_HLIST_BITS)
@@ -568,7 +574,12 @@ struct perf_event {
        struct hlist_node               hlist_entry;
        struct list_head                active_entry;
        int                             nr_siblings;
-       int                             group_flags;
+
+       /* Not serialized. Only written during event initialization. */
+       int                             event_caps;
+       /* The cumulative AND of all event_caps for events in this group. */
+       int                             group_caps;
+
        struct perf_event               *group_leader;
        struct pmu                      *pmu;
        void                            *pmu_private;
@@ -774,6 +785,9 @@ struct perf_cpu_context {
 #ifdef CONFIG_CGROUP_PERF
        struct perf_cgroup              *cgrp;
 #endif
+
+       struct list_head                sched_cb_entry;
+       int                             sched_cb_usage;
 };
 
 struct perf_output_handle {
@@ -985,7 +999,7 @@ static inline bool is_sampling_event(struct perf_event *event)
  */
 static inline int is_software_event(struct perf_event *event)
 {
-       return event->pmu->task_ctx_nr == perf_sw_context;
+       return event->event_caps & PERF_EV_CAP_SOFTWARE;
 }
 
 extern struct static_key perf_swevent_enabled[PERF_COUNT_SW_MAX];
index fc9bb22252913acd34cf35be26fe5777a43c4506..7c0d263f6bc5381eed063c5fda57857edbab3a85 100644 (file)
@@ -1475,8 +1475,7 @@ list_add_event(struct perf_event *event, struct perf_event_context *ctx)
        if (event->group_leader == event) {
                struct list_head *list;
 
-               if (is_software_event(event))
-                       event->group_flags |= PERF_GROUP_SOFTWARE;
+               event->group_caps = event->event_caps;
 
                list = ctx_group_list(event, ctx);
                list_add_tail(&event->group_entry, list);
@@ -1630,9 +1629,7 @@ static void perf_group_attach(struct perf_event *event)
 
        WARN_ON_ONCE(group_leader->ctx != event->ctx);
 
-       if (group_leader->group_flags & PERF_GROUP_SOFTWARE &&
-                       !is_software_event(event))
-               group_leader->group_flags &= ~PERF_GROUP_SOFTWARE;
+       group_leader->group_caps &= event->event_caps;
 
        list_add_tail(&event->group_entry, &group_leader->sibling_list);
        group_leader->nr_siblings++;
@@ -1723,7 +1720,7 @@ static void perf_group_detach(struct perf_event *event)
                sibling->group_leader = sibling;
 
                /* Inherit group flags from the previous leader */
-               sibling->group_flags = event->group_flags;
+               sibling->group_caps = event->group_caps;
 
                WARN_ON_ONCE(sibling->ctx != event->ctx);
        }
@@ -1832,6 +1829,8 @@ group_sched_out(struct perf_event *group_event,
        struct perf_event *event;
        int state = group_event->state;
 
+       perf_pmu_disable(ctx->pmu);
+
        event_sched_out(group_event, cpuctx, ctx);
 
        /*
@@ -1840,6 +1839,8 @@ group_sched_out(struct perf_event *group_event,
        list_for_each_entry(event, &group_event->sibling_list, group_entry)
                event_sched_out(event, cpuctx, ctx);
 
+       perf_pmu_enable(ctx->pmu);
+
        if (state == PERF_EVENT_STATE_ACTIVE && group_event->attr.exclusive)
                cpuctx->exclusive = 0;
 }
@@ -2145,7 +2146,7 @@ static int group_can_go_on(struct perf_event *event,
        /*
         * Groups consisting entirely of software events can always go on.
         */
-       if (event->group_flags & PERF_GROUP_SOFTWARE)
+       if (event->group_caps & PERF_EV_CAP_SOFTWARE)
                return 1;
        /*
         * If an exclusive group is already on, no other hardware
@@ -2491,7 +2492,7 @@ static int __perf_event_stop(void *info)
         * while restarting.
         */
        if (sd->restart)
-               event->pmu->start(event, PERF_EF_START);
+               event->pmu->start(event, 0);
 
        return 0;
 }
@@ -2837,19 +2838,36 @@ unlock:
        }
 }
 
+static DEFINE_PER_CPU(struct list_head, sched_cb_list);
+
 void perf_sched_cb_dec(struct pmu *pmu)
 {
+       struct perf_cpu_context *cpuctx = this_cpu_ptr(pmu->pmu_cpu_context);
+
        this_cpu_dec(perf_sched_cb_usages);
+
+       if (!--cpuctx->sched_cb_usage)
+               list_del(&cpuctx->sched_cb_entry);
 }
 
+
 void perf_sched_cb_inc(struct pmu *pmu)
 {
+       struct perf_cpu_context *cpuctx = this_cpu_ptr(pmu->pmu_cpu_context);
+
+       if (!cpuctx->sched_cb_usage++)
+               list_add(&cpuctx->sched_cb_entry, this_cpu_ptr(&sched_cb_list));
+
        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.
+ *
+ * This callback is relevant even to per-cpu events; for example multi event
+ * PEBS requires this to provide PID/TID information. This requires we flush
+ * all queued PEBS records before we context switch to a new task.
  */
 static void perf_pmu_sched_task(struct task_struct *prev,
                                struct task_struct *next,
@@ -2857,34 +2875,24 @@ static void perf_pmu_sched_task(struct task_struct *prev,
 {
        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);
+       list_for_each_entry(cpuctx, this_cpu_ptr(&sched_cb_list), sched_cb_entry) {
+               pmu = cpuctx->unique_pmu; /* software PMUs will not have sched_task */
 
-                       perf_pmu_disable(pmu);
+               if (WARN_ON_ONCE(!pmu->sched_task))
+                       continue;
 
-                       pmu->sched_task(cpuctx->task_ctx, sched_in);
+               perf_ctx_lock(cpuctx, cpuctx->task_ctx);
+               perf_pmu_disable(pmu);
 
-                       perf_pmu_enable(pmu);
+               pmu->sched_task(cpuctx->task_ctx, sched_in);
 
-                       perf_ctx_unlock(cpuctx, cpuctx->task_ctx);
-               }
+               perf_pmu_enable(pmu);
+               perf_ctx_unlock(cpuctx, cpuctx->task_ctx);
        }
-
-       rcu_read_unlock();
-
-       local_irq_restore(flags);
 }
 
 static void perf_event_switch(struct task_struct *task,
@@ -3416,6 +3424,22 @@ struct perf_read_data {
        int ret;
 };
 
+static int find_cpu_to_read(struct perf_event *event, int local_cpu)
+{
+       int event_cpu = event->oncpu;
+       u16 local_pkg, event_pkg;
+
+       if (event->group_caps & PERF_EV_CAP_READ_ACTIVE_PKG) {
+               event_pkg =  topology_physical_package_id(event_cpu);
+               local_pkg =  topology_physical_package_id(local_cpu);
+
+               if (event_pkg == local_pkg)
+                       return local_cpu;
+       }
+
+       return event_cpu;
+}
+
 /*
  * Cross CPU call to read the hardware event
  */
@@ -3537,7 +3561,7 @@ u64 perf_event_read_local(struct perf_event *event)
 
 static int perf_event_read(struct perf_event *event, bool group)
 {
-       int ret = 0;
+       int ret = 0, cpu_to_read, local_cpu;
 
        /*
         * If event is enabled and currently active on a CPU, update the
@@ -3549,6 +3573,11 @@ static int perf_event_read(struct perf_event *event, bool group)
                        .group = group,
                        .ret = 0,
                };
+
+               local_cpu = get_cpu();
+               cpu_to_read = find_cpu_to_read(event, local_cpu);
+               put_cpu();
+
                /*
                 * Purposely ignore the smp_call_function_single() return
                 * value.
@@ -3559,7 +3588,7 @@ static int perf_event_read(struct perf_event *event, bool group)
                 * Therefore, either way, we'll have an up-to-date event count
                 * after this.
                 */
-               (void)smp_call_function_single(event->oncpu, __perf_event_read, &data, 1);
+               (void)smp_call_function_single(cpu_to_read, __perf_event_read, &data, 1);
                ret = data.ret;
        } else if (event->state == PERF_EVENT_STATE_INACTIVE) {
                struct perf_event_context *ctx = event->ctx;
@@ -5350,9 +5379,10 @@ perf_output_sample_regs(struct perf_output_handle *handle,
                        struct pt_regs *regs, u64 mask)
 {
        int bit;
+       DECLARE_BITMAP(_mask, 64);
 
-       for_each_set_bit(bit, (const unsigned long *) &mask,
-                        sizeof(mask) * BITS_PER_BYTE) {
+       bitmap_from_u64(_mask, mask);
+       for_each_set_bit(bit, _mask, sizeof(mask) * BITS_PER_BYTE) {
                u64 val;
 
                val = perf_reg_value(regs, bit);
@@ -9505,6 +9535,9 @@ SYSCALL_DEFINE5(perf_event_open,
                        goto err_alloc;
        }
 
+       if (pmu->task_ctx_nr == perf_sw_context)
+               event->event_caps |= PERF_EV_CAP_SOFTWARE;
+
        if (group_leader &&
            (is_software_event(event) != is_software_event(group_leader))) {
                if (is_software_event(event)) {
@@ -9518,7 +9551,7 @@ SYSCALL_DEFINE5(perf_event_open,
                         */
                        pmu = group_leader->pmu;
                } else if (is_software_event(group_leader) &&
-                          (group_leader->group_flags & PERF_GROUP_SOFTWARE)) {
+                          (group_leader->group_caps & PERF_EV_CAP_SOFTWARE)) {
                        /*
                         * In case the group is a pure software group, and we
                         * try to add a hardware event, move the whole group to
@@ -10453,6 +10486,8 @@ static void __init perf_event_init_all_cpus(void)
 
                INIT_LIST_HEAD(&per_cpu(pmu_sb_events.list, cpu));
                raw_spin_lock_init(&per_cpu(pmu_sb_events.lock, cpu));
+
+               INIT_LIST_HEAD(&per_cpu(sched_cb_list, cpu));
        }
 }
 
index 8c50276b60d1c7fb75da997f85819f5b9a313c27..d4129bb05e5d044101ba2cbea672f96954b69a51 100644 (file)
@@ -150,7 +150,7 @@ static loff_t vaddr_to_offset(struct vm_area_struct *vma, unsigned long vaddr)
  * Returns 0 on success, -EFAULT on failure.
  */
 static int __replace_page(struct vm_area_struct *vma, unsigned long addr,
-                               struct page *page, struct page *kpage)
+                               struct page *old_page, struct page *new_page)
 {
        struct mm_struct *mm = vma->vm_mm;
        spinlock_t *ptl;
@@ -161,49 +161,49 @@ static int __replace_page(struct vm_area_struct *vma, unsigned long addr,
        const unsigned long mmun_end   = addr + PAGE_SIZE;
        struct mem_cgroup *memcg;
 
-       err = mem_cgroup_try_charge(kpage, vma->vm_mm, GFP_KERNEL, &memcg,
+       err = mem_cgroup_try_charge(new_page, vma->vm_mm, GFP_KERNEL, &memcg,
                        false);
        if (err)
                return err;
 
        /* For try_to_free_swap() and munlock_vma_page() below */
-       lock_page(page);
+       lock_page(old_page);
 
        mmu_notifier_invalidate_range_start(mm, mmun_start, mmun_end);
        err = -EAGAIN;
-       ptep = page_check_address(page, mm, addr, &ptl, 0);
+       ptep = page_check_address(old_page, mm, addr, &ptl, 0);
        if (!ptep) {
-               mem_cgroup_cancel_charge(kpage, memcg, false);
+               mem_cgroup_cancel_charge(new_page, memcg, false);
                goto unlock;
        }
 
-       get_page(kpage);
-       page_add_new_anon_rmap(kpage, vma, addr, false);
-       mem_cgroup_commit_charge(kpage, memcg, false, false);
-       lru_cache_add_active_or_unevictable(kpage, vma);
+       get_page(new_page);
+       page_add_new_anon_rmap(new_page, vma, addr, false);
+       mem_cgroup_commit_charge(new_page, memcg, false, false);
+       lru_cache_add_active_or_unevictable(new_page, vma);
 
-       if (!PageAnon(page)) {
-               dec_mm_counter(mm, mm_counter_file(page));
+       if (!PageAnon(old_page)) {
+               dec_mm_counter(mm, mm_counter_file(old_page));
                inc_mm_counter(mm, MM_ANONPAGES);
        }
 
        flush_cache_page(vma, addr, pte_pfn(*ptep));
        ptep_clear_flush_notify(vma, addr, ptep);
-       set_pte_at_notify(mm, addr, ptep, mk_pte(kpage, vma->vm_page_prot));
+       set_pte_at_notify(mm, addr, ptep, mk_pte(new_page, vma->vm_page_prot));
 
-       page_remove_rmap(page, false);
-       if (!page_mapped(page))
-               try_to_free_swap(page);
+       page_remove_rmap(old_page, false);
+       if (!page_mapped(old_page))
+               try_to_free_swap(old_page);
        pte_unmap_unlock(ptep, ptl);
 
        if (vma->vm_flags & VM_LOCKED)
-               munlock_vma_page(page);
-       put_page(page);
+               munlock_vma_page(old_page);
+       put_page(old_page);
 
        err = 0;
  unlock:
        mmu_notifier_invalidate_range_end(mm, mmun_start, mmun_end);
-       unlock_page(page);
+       unlock_page(old_page);
        return err;
 }
 
index dade4c9559cc036c1b6aa8567abf0b0887847923..1e2ce3b52e51fdd843995350a3dffc11c98b584e 100644 (file)
@@ -4123,6 +4123,30 @@ static const char readme_msg[] =
        "\t\t\t  traces\n"
 #endif
 #endif /* CONFIG_STACK_TRACER */
+#ifdef CONFIG_KPROBE_EVENT
+       "  kprobe_events\t\t- Add/remove/show the kernel dynamic events\n"
+       "\t\t\t  Write into this file to define/undefine new trace events.\n"
+#endif
+#ifdef CONFIG_UPROBE_EVENT
+       "  uprobe_events\t\t- Add/remove/show the userspace dynamic events\n"
+       "\t\t\t  Write into this file to define/undefine new trace events.\n"
+#endif
+#if defined(CONFIG_KPROBE_EVENT) || defined(CONFIG_UPROBE_EVENT)
+       "\t  accepts: event-definitions (one definition per line)\n"
+       "\t   Format: p|r[:[<group>/]<event>] <place> [<args>]\n"
+       "\t           -:[<group>/]<event>\n"
+#ifdef CONFIG_KPROBE_EVENT
+       "\t    place: [<module>:]<symbol>[+<offset>]|<memaddr>\n"
+#endif
+#ifdef CONFIG_UPROBE_EVENT
+       "\t    place: <path>:<offset>\n"
+#endif
+       "\t     args: <name>=fetcharg[:type]\n"
+       "\t fetcharg: %<register>, @<address>, @<symbol>[+|-<offset>],\n"
+       "\t           $stack<index>, $stack, $retval, $comm\n"
+       "\t     type: s8/16/32/64, u8/16/32/64, x8/16/32/64, string,\n"
+       "\t           b<bit-width>@<bit-offset>/<container-size>\n"
+#endif
        "  events/\t\t- Directory containing all trace event subsystems:\n"
        "      enable\t\t- Write 0/1 to enable/disable tracing of all events\n"
        "  events/<system>/\t- Directory containing all trace events for <system>:\n"
index 9aedb0b06683765f4293eb750465ed5849c2902f..eb6c9f1d3a932f93a9a88b3d6b9c742457f84d11 100644 (file)
@@ -253,6 +253,10 @@ static const struct fetch_type kprobes_fetch_type_table[] = {
        ASSIGN_FETCH_TYPE(s16, u16, 1),
        ASSIGN_FETCH_TYPE(s32, u32, 1),
        ASSIGN_FETCH_TYPE(s64, u64, 1),
+       ASSIGN_FETCH_TYPE_ALIAS(x8,  u8,  u8,  0),
+       ASSIGN_FETCH_TYPE_ALIAS(x16, u16, u16, 0),
+       ASSIGN_FETCH_TYPE_ALIAS(x32, u32, u32, 0),
+       ASSIGN_FETCH_TYPE_ALIAS(x64, u64, u64, 0),
 
        ASSIGN_FETCH_TYPE_END
 };
index 74e80a582c28988fbc0227453378d36bf4346999..8c0553d9afd3f2563756641cfa0e659a4ab7ff99 100644 (file)
@@ -36,24 +36,28 @@ const char *reserved_field_names[] = {
 };
 
 /* Printing  in basic type function template */
-#define DEFINE_BASIC_PRINT_TYPE_FUNC(type, fmt)                                \
-int PRINT_TYPE_FUNC_NAME(type)(struct trace_seq *s, const char *name,  \
+#define DEFINE_BASIC_PRINT_TYPE_FUNC(tname, type, fmt)                 \
+int PRINT_TYPE_FUNC_NAME(tname)(struct trace_seq *s, const char *name, \
                                void *data, void *ent)                  \
 {                                                                      \
        trace_seq_printf(s, " %s=" fmt, name, *(type *)data);           \
        return !trace_seq_has_overflowed(s);                            \
 }                                                                      \
-const char PRINT_TYPE_FMT_NAME(type)[] = fmt;                          \
-NOKPROBE_SYMBOL(PRINT_TYPE_FUNC_NAME(type));
-
-DEFINE_BASIC_PRINT_TYPE_FUNC(u8 , "0x%x")
-DEFINE_BASIC_PRINT_TYPE_FUNC(u16, "0x%x")
-DEFINE_BASIC_PRINT_TYPE_FUNC(u32, "0x%x")
-DEFINE_BASIC_PRINT_TYPE_FUNC(u64, "0x%Lx")
-DEFINE_BASIC_PRINT_TYPE_FUNC(s8,  "%d")
-DEFINE_BASIC_PRINT_TYPE_FUNC(s16, "%d")
-DEFINE_BASIC_PRINT_TYPE_FUNC(s32, "%d")
-DEFINE_BASIC_PRINT_TYPE_FUNC(s64, "%Ld")
+const char PRINT_TYPE_FMT_NAME(tname)[] = fmt;                         \
+NOKPROBE_SYMBOL(PRINT_TYPE_FUNC_NAME(tname));
+
+DEFINE_BASIC_PRINT_TYPE_FUNC(u8,  u8,  "%u")
+DEFINE_BASIC_PRINT_TYPE_FUNC(u16, u16, "%u")
+DEFINE_BASIC_PRINT_TYPE_FUNC(u32, u32, "%u")
+DEFINE_BASIC_PRINT_TYPE_FUNC(u64, u64, "%Lu")
+DEFINE_BASIC_PRINT_TYPE_FUNC(s8,  s8,  "%d")
+DEFINE_BASIC_PRINT_TYPE_FUNC(s16, s16, "%d")
+DEFINE_BASIC_PRINT_TYPE_FUNC(s32, s32, "%d")
+DEFINE_BASIC_PRINT_TYPE_FUNC(s64, s64, "%Ld")
+DEFINE_BASIC_PRINT_TYPE_FUNC(x8,  u8,  "0x%x")
+DEFINE_BASIC_PRINT_TYPE_FUNC(x16, u16, "0x%x")
+DEFINE_BASIC_PRINT_TYPE_FUNC(x32, u32, "0x%x")
+DEFINE_BASIC_PRINT_TYPE_FUNC(x64, u64, "0x%Lx")
 
 /* Print type function for string type */
 int PRINT_TYPE_FUNC_NAME(string)(struct trace_seq *s, const char *name,
index 45400ca5ded1acf673d713851f930425b1d20849..0c0ae54d44c616d5d09876165c2516c3e032af77 100644 (file)
@@ -149,6 +149,11 @@ DECLARE_BASIC_PRINT_TYPE_FUNC(s8);
 DECLARE_BASIC_PRINT_TYPE_FUNC(s16);
 DECLARE_BASIC_PRINT_TYPE_FUNC(s32);
 DECLARE_BASIC_PRINT_TYPE_FUNC(s64);
+DECLARE_BASIC_PRINT_TYPE_FUNC(x8);
+DECLARE_BASIC_PRINT_TYPE_FUNC(x16);
+DECLARE_BASIC_PRINT_TYPE_FUNC(x32);
+DECLARE_BASIC_PRINT_TYPE_FUNC(x64);
+
 DECLARE_BASIC_PRINT_TYPE_FUNC(string);
 
 #define FETCH_FUNC_NAME(method, type)  fetch_##method##_##type
@@ -203,7 +208,7 @@ DEFINE_FETCH_##method(u32)          \
 DEFINE_FETCH_##method(u64)
 
 /* Default (unsigned long) fetch type */
-#define __DEFAULT_FETCH_TYPE(t) u##t
+#define __DEFAULT_FETCH_TYPE(t) x##t
 #define _DEFAULT_FETCH_TYPE(t) __DEFAULT_FETCH_TYPE(t)
 #define DEFAULT_FETCH_TYPE _DEFAULT_FETCH_TYPE(BITS_PER_LONG)
 #define DEFAULT_FETCH_TYPE_STR __stringify(DEFAULT_FETCH_TYPE)
@@ -234,6 +239,10 @@ ASSIGN_FETCH_FUNC(file_offset, ftype),                     \
 #define ASSIGN_FETCH_TYPE(ptype, ftype, sign)                  \
        __ASSIGN_FETCH_TYPE(#ptype, ptype, ftype, sizeof(ftype), sign, #ptype)
 
+/* If ptype is an alias of atype, use this macro (show atype in format) */
+#define ASSIGN_FETCH_TYPE_ALIAS(ptype, atype, ftype, sign)             \
+       __ASSIGN_FETCH_TYPE(#ptype, ptype, ftype, sizeof(ftype), sign, #atype)
+
 #define ASSIGN_FETCH_TYPE_END {}
 
 #define FETCH_TYPE_STRING      0
index c53485441c88ad142cbab7bb7edfd4e5139832d1..7a687320f8671c7e82ee1c5ebca6dc7d2b77380c 100644 (file)
@@ -211,6 +211,10 @@ static const struct fetch_type uprobes_fetch_type_table[] = {
        ASSIGN_FETCH_TYPE(s16, u16, 1),
        ASSIGN_FETCH_TYPE(s32, u32, 1),
        ASSIGN_FETCH_TYPE(s64, u64, 1),
+       ASSIGN_FETCH_TYPE_ALIAS(x8,  u8,  u8,  0),
+       ASSIGN_FETCH_TYPE_ALIAS(x16, u16, u16, 0),
+       ASSIGN_FETCH_TYPE_ALIAS(x32, u32, u32, 0),
+       ASSIGN_FETCH_TYPE_ALIAS(x64, u64, u64, 0),
 
        ASSIGN_FETCH_TYPE_END
 };
diff --git a/tools/arch/alpha/include/uapi/asm/mman.h b/tools/arch/alpha/include/uapi/asm/mman.h
new file mode 100644 (file)
index 0000000..e38b64c
--- /dev/null
@@ -0,0 +1,47 @@
+#ifndef TOOLS_ARCH_ALPHA_UAPI_ASM_MMAN_FIX_H
+#define TOOLS_ARCH_ALPHA_UAPI_ASM_MMAN_FIX_H
+#define MADV_DODUMP    17
+#define MADV_DOFORK    11
+#define MADV_DONTDUMP   16
+#define MADV_DONTFORK  10
+#define MADV_DONTNEED  6
+#define MADV_FREE      8
+#define MADV_HUGEPAGE  14
+#define MADV_MERGEABLE   12
+#define MADV_NOHUGEPAGE        15
+#define MADV_NORMAL    0
+#define MADV_RANDOM    1
+#define MADV_REMOVE    9
+#define MADV_SEQUENTIAL        2
+#define MADV_UNMERGEABLE 13
+#define MADV_WILLNEED  3
+#define MAP_ANONYMOUS  0x10
+#define MAP_DENYWRITE  0x02000
+#define MAP_EXECUTABLE 0x04000
+#define MAP_FILE       0
+#define MAP_FIXED      0x100
+#define MAP_GROWSDOWN  0x01000
+#define MAP_HUGETLB    0x100000
+#define MAP_LOCKED     0x08000
+#define MAP_NONBLOCK   0x40000
+#define MAP_NORESERVE  0x10000
+#define MAP_POPULATE   0x20000
+#define MAP_PRIVATE    0x02
+#define MAP_SHARED     0x01
+#define MAP_STACK      0x80000
+#define PROT_EXEC      0x4
+#define PROT_GROWSDOWN 0x01000000
+#define PROT_GROWSUP   0x02000000
+#define PROT_NONE      0x0
+#define PROT_READ      0x1
+#define PROT_SEM       0x8
+#define PROT_WRITE     0x2
+/* MADV_HWPOISON is undefined on alpha, fix it for perf */
+#define MADV_HWPOISON  100
+/* MADV_SOFT_OFFLINE is undefined on alpha, fix it for perf */
+#define MADV_SOFT_OFFLINE 101
+/* MAP_32BIT is undefined on alpha, fix it for perf */
+#define MAP_32BIT      0
+/* MAP_UNINITIALIZED is undefined on alpha, fix it for perf */
+#define MAP_UNINITIALIZED      0
+#endif
diff --git a/tools/arch/arc/include/uapi/asm/mman.h b/tools/arch/arc/include/uapi/asm/mman.h
new file mode 100644 (file)
index 0000000..aa3acd2
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef TOOLS_ARCH_ARC_UAPI_ASM_MMAN_FIX_H
+#define TOOLS_ARCH_ARC_UAPI_ASM_MMAN_FIX_H
+#include <uapi/asm-generic/mman.h>
+/* MAP_32BIT is undefined on arc, fix it for perf */
+#define MAP_32BIT      0
+#endif
diff --git a/tools/arch/arm/include/uapi/asm/mman.h b/tools/arch/arm/include/uapi/asm/mman.h
new file mode 100644 (file)
index 0000000..478f699
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef TOOLS_ARCH_ARM_UAPI_ASM_MMAN_FIX_H
+#define TOOLS_ARCH_ARM_UAPI_ASM_MMAN_FIX_H
+#include <uapi/asm-generic/mman.h>
+/* MAP_32BIT is undefined on arm, fix it for perf */
+#define MAP_32BIT      0
+#endif
diff --git a/tools/arch/arm64/include/uapi/asm/mman.h b/tools/arch/arm64/include/uapi/asm/mman.h
new file mode 100644 (file)
index 0000000..70fd311
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef TOOLS_ARCH_ARM64_UAPI_ASM_MMAN_FIX_H
+#define TOOLS_ARCH_ARM64_UAPI_ASM_MMAN_FIX_H
+#include <uapi/asm-generic/mman.h>
+/* MAP_32BIT is undefined on arm64, fix it for perf */
+#define MAP_32BIT      0
+#endif
diff --git a/tools/arch/frv/include/uapi/asm/mman.h b/tools/arch/frv/include/uapi/asm/mman.h
new file mode 100644 (file)
index 0000000..5be78ac
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef TOOLS_ARCH_FRV_UAPI_ASM_MMAN_FIX_H
+#define TOOLS_ARCH_FRV_UAPI_ASM_MMAN_FIX_H
+#include <uapi/asm-generic/mman.h>
+/* MAP_32BIT is undefined on frv, fix it for perf */
+#define MAP_32BIT      0
+#endif
diff --git a/tools/arch/h8300/include/uapi/asm/mman.h b/tools/arch/h8300/include/uapi/asm/mman.h
new file mode 100644 (file)
index 0000000..9d9ac54
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef TOOLS_ARCH_H8300_UAPI_ASM_MMAN_FIX_H
+#define TOOLS_ARCH_H8300_UAPI_ASM_MMAN_FIX_H
+#include <uapi/asm-generic/mman.h>
+/* MAP_32BIT is undefined on h8300, fix it for perf */
+#define MAP_32BIT      0
+#endif
diff --git a/tools/arch/hexagon/include/uapi/asm/mman.h b/tools/arch/hexagon/include/uapi/asm/mman.h
new file mode 100644 (file)
index 0000000..102f3fa
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef TOOLS_ARCH_HEXAGON_UAPI_ASM_MMAN_FIX_H
+#define TOOLS_ARCH_HEXAGON_UAPI_ASM_MMAN_FIX_H
+#include <uapi/asm-generic/mman.h>
+/* MAP_32BIT is undefined on hexagon, fix it for perf */
+#define MAP_32BIT      0
+#endif
diff --git a/tools/arch/ia64/include/uapi/asm/mman.h b/tools/arch/ia64/include/uapi/asm/mman.h
new file mode 100644 (file)
index 0000000..1d6e5ac
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef TOOLS_ARCH_IA64_UAPI_ASM_MMAN_FIX_H
+#define TOOLS_ARCH_IA64_UAPI_ASM_MMAN_FIX_H
+#include <uapi/asm-generic/mman.h>
+/* MAP_32BIT is undefined on ia64, fix it for perf */
+#define MAP_32BIT      0
+#endif
diff --git a/tools/arch/m32r/include/uapi/asm/mman.h b/tools/arch/m32r/include/uapi/asm/mman.h
new file mode 100644 (file)
index 0000000..1c29635
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef TOOLS_ARCH_M32R_UAPI_ASM_MMAN_FIX_H
+#define TOOLS_ARCH_M32R_UAPI_ASM_MMAN_FIX_H
+#include <uapi/asm-generic/mman.h>
+/* MAP_32BIT is undefined on m32r, fix it for perf */
+#define MAP_32BIT      0
+#endif
diff --git a/tools/arch/microblaze/include/uapi/asm/mman.h b/tools/arch/microblaze/include/uapi/asm/mman.h
new file mode 100644 (file)
index 0000000..005cd50
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef TOOLS_ARCH_MICROBLAZE_UAPI_ASM_MMAN_FIX_H
+#define TOOLS_ARCH_MICROBLAZE_UAPI_ASM_MMAN_FIX_H
+#include <uapi/asm-generic/mman.h>
+/* MAP_32BIT is undefined on microblaze, fix it for perf */
+#define MAP_32BIT      0
+#endif
diff --git a/tools/arch/mips/include/uapi/asm/mman.h b/tools/arch/mips/include/uapi/asm/mman.h
new file mode 100644 (file)
index 0000000..c020529
--- /dev/null
@@ -0,0 +1,46 @@
+#ifndef TOOLS_ARCH_MIPS_UAPI_ASM_MMAN_FIX_H
+#define TOOLS_ARCH_MIPS_UAPI_ASM_MMAN_FIX_H
+#define MADV_DODUMP    17
+#define MADV_DOFORK    11
+#define MADV_DONTDUMP  16
+#define MADV_DONTFORK  10
+#define MADV_DONTNEED  4
+#define MADV_FREE      8
+#define MADV_HUGEPAGE  14
+#define MADV_HWPOISON   100
+#define MADV_MERGEABLE  12
+#define MADV_NOHUGEPAGE 15
+#define MADV_NORMAL    0
+#define MADV_RANDOM    1
+#define MADV_REMOVE    9
+#define MADV_SEQUENTIAL 2
+#define MADV_UNMERGEABLE 13
+#define MADV_WILLNEED  3
+#define MAP_ANONYMOUS  0x0800
+#define MAP_DENYWRITE  0x2000
+#define MAP_EXECUTABLE 0x4000
+#define MAP_FILE       0
+#define MAP_FIXED      0x010
+#define MAP_GROWSDOWN  0x1000
+#define MAP_HUGETLB    0x80000
+#define MAP_LOCKED     0x8000
+#define MAP_NONBLOCK   0x20000
+#define MAP_NORESERVE  0x0400
+#define MAP_POPULATE   0x10000
+#define MAP_PRIVATE    0x002
+#define MAP_SHARED     0x001
+#define MAP_STACK      0x40000
+#define PROT_EXEC      0x04
+#define PROT_GROWSDOWN 0x01000000
+#define PROT_GROWSUP   0x02000000
+#define PROT_NONE      0x00
+#define PROT_READ      0x01
+#define PROT_SEM       0x10
+#define PROT_WRITE     0x02
+/* MADV_SOFT_OFFLINE is undefined on mips, fix it for perf */
+#define MADV_SOFT_OFFLINE 101
+/* MAP_32BIT is undefined on mips, fix it for perf */
+#define MAP_32BIT      0
+/* MAP_UNINITIALIZED is undefined on mips, fix it for perf */
+#define MAP_UNINITIALIZED      0
+#endif
diff --git a/tools/arch/mn10300/include/uapi/asm/mman.h b/tools/arch/mn10300/include/uapi/asm/mman.h
new file mode 100644 (file)
index 0000000..c1ea36d
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef TOOLS_ARCH_MN10300_UAPI_ASM_MMAN_FIX_H
+#define TOOLS_ARCH_MN10300_UAPI_ASM_MMAN_FIX_H
+#include <uapi/asm-generic/mman.h>
+/* MAP_32BIT is undefined on mn10300, fix it for perf */
+#define MAP_32BIT      0
+#endif
diff --git a/tools/arch/parisc/include/uapi/asm/mman.h b/tools/arch/parisc/include/uapi/asm/mman.h
new file mode 100644 (file)
index 0000000..03d8d5b
--- /dev/null
@@ -0,0 +1,47 @@
+#ifndef TOOLS_ARCH_PARISC_UAPI_ASM_MMAN_FIX_H
+#define TOOLS_ARCH_PARISC_UAPI_ASM_MMAN_FIX_H
+#define MADV_DODUMP    70
+#define MADV_DOFORK    11
+#define MADV_DONTDUMP   69
+#define MADV_DONTFORK  10
+#define MADV_DONTNEED   4
+#define MADV_FREE      8
+#define MADV_HUGEPAGE  67
+#define MADV_MERGEABLE   65
+#define MADV_NOHUGEPAGE        68
+#define MADV_NORMAL     0
+#define MADV_RANDOM     1
+#define MADV_REMOVE    9
+#define MADV_SEQUENTIAL 2
+#define MADV_UNMERGEABLE 66
+#define MADV_WILLNEED   3
+#define MAP_ANONYMOUS  0x10
+#define MAP_DENYWRITE  0x0800
+#define MAP_EXECUTABLE 0x1000
+#define MAP_FILE       0
+#define MAP_FIXED      0x04
+#define MAP_GROWSDOWN  0x8000
+#define MAP_HUGETLB    0x80000
+#define MAP_LOCKED     0x2000
+#define MAP_NONBLOCK   0x20000
+#define MAP_NORESERVE  0x4000
+#define MAP_POPULATE   0x10000
+#define MAP_PRIVATE    0x02
+#define MAP_SHARED     0x01
+#define MAP_STACK      0x40000
+#define PROT_EXEC      0x4
+#define PROT_GROWSDOWN 0x01000000
+#define PROT_GROWSUP   0x02000000
+#define PROT_NONE      0x0
+#define PROT_READ      0x1
+#define PROT_SEM       0x8
+#define PROT_WRITE     0x2
+/* MADV_HWPOISON is undefined on parisc, fix it for perf */
+#define MADV_HWPOISON  100
+/* MADV_SOFT_OFFLINE is undefined on parisc, fix it for perf */
+#define MADV_SOFT_OFFLINE 101
+/* MAP_32BIT is undefined on parisc, fix it for perf */
+#define MAP_32BIT      0
+/* MAP_UNINITIALIZED is undefined on parisc, fix it for perf */
+#define MAP_UNINITIALIZED      0
+#endif
diff --git a/tools/arch/powerpc/include/uapi/asm/mman.h b/tools/arch/powerpc/include/uapi/asm/mman.h
new file mode 100644 (file)
index 0000000..761db43
--- /dev/null
@@ -0,0 +1,15 @@
+#ifndef TOOLS_ARCH_POWERPC_UAPI_ASM_MMAN_FIX_H
+#define TOOLS_ARCH_POWERPC_UAPI_ASM_MMAN_FIX_H
+#define MAP_DENYWRITE  0x0800
+#define MAP_EXECUTABLE 0x1000
+#define MAP_GROWSDOWN  0x0100
+#define MAP_HUGETLB    0x40000
+#define MAP_LOCKED     0x80
+#define MAP_NONBLOCK   0x10000
+#define MAP_NORESERVE   0x40
+#define MAP_POPULATE   0x8000
+#define MAP_STACK      0x20000
+#include <uapi/asm-generic/mman-common.h>
+/* MAP_32BIT is undefined on powerpc, fix it for perf */
+#define MAP_32BIT      0
+#endif
diff --git a/tools/arch/s390/include/uapi/asm/mman.h b/tools/arch/s390/include/uapi/asm/mman.h
new file mode 100644 (file)
index 0000000..b03dea9
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef TOOLS_ARCH_S390_UAPI_ASM_MMAN_FIX_H
+#define TOOLS_ARCH_S390_UAPI_ASM_MMAN_FIX_H
+#include <uapi/asm-generic/mman.h>
+/* MAP_32BIT is undefined on s390, fix it for perf */
+#define MAP_32BIT      0
+#endif
diff --git a/tools/arch/score/include/uapi/asm/mman.h b/tools/arch/score/include/uapi/asm/mman.h
new file mode 100644 (file)
index 0000000..2f8fb89
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef TOOLS_ARCH_SCORE_UAPI_ASM_MMAN_FIX_H
+#define TOOLS_ARCH_SCORE_UAPI_ASM_MMAN_FIX_H
+#include <uapi/asm-generic/mman.h>
+/* MAP_32BIT is undefined on score, fix it for perf */
+#define MAP_32BIT      0
+#endif
diff --git a/tools/arch/sh/include/uapi/asm/mman.h b/tools/arch/sh/include/uapi/asm/mman.h
new file mode 100644 (file)
index 0000000..26504f6
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef TOOLS_ARCH_SH_UAPI_ASM_MMAN_FIX_H
+#define TOOLS_ARCH_SH_UAPI_ASM_MMAN_FIX_H
+#include <uapi/asm-generic/mman.h>
+/* MAP_32BIT is undefined on sh, fix it for perf */
+#define MAP_32BIT      0
+#endif
diff --git a/tools/arch/sparc/include/uapi/asm/mman.h b/tools/arch/sparc/include/uapi/asm/mman.h
new file mode 100644 (file)
index 0000000..8640525
--- /dev/null
@@ -0,0 +1,15 @@
+#ifndef TOOLS_ARCH_SPARC_UAPI_ASM_MMAN_FIX_H
+#define TOOLS_ARCH_SPARC_UAPI_ASM_MMAN_FIX_H
+#define MAP_DENYWRITE  0x0800
+#define MAP_EXECUTABLE 0x1000
+#define MAP_GROWSDOWN  0x0200
+#define MAP_HUGETLB    0x40000
+#define MAP_LOCKED      0x100
+#define MAP_NONBLOCK   0x10000
+#define MAP_NORESERVE   0x40
+#define MAP_POPULATE   0x8000
+#define MAP_STACK      0x20000
+#include <uapi/asm-generic/mman-common.h>
+/* MAP_32BIT is undefined on sparc, fix it for perf */
+#define MAP_32BIT      0
+#endif
diff --git a/tools/arch/tile/include/uapi/asm/mman.h b/tools/arch/tile/include/uapi/asm/mman.h
new file mode 100644 (file)
index 0000000..7116c4b
--- /dev/null
@@ -0,0 +1,15 @@
+#ifndef TOOLS_ARCH_TILE_UAPI_ASM_MMAN_FIX_H
+#define TOOLS_ARCH_TILE_UAPI_ASM_MMAN_FIX_H
+#define MAP_DENYWRITE  0x0800
+#define MAP_EXECUTABLE 0x1000
+#define MAP_GROWSDOWN  0x0100
+#define MAP_HUGETLB    0x4000
+#define MAP_LOCKED     0x0200
+#define MAP_NONBLOCK   0x0080
+#define MAP_NORESERVE  0x0400
+#define MAP_POPULATE   0x0040
+#define MAP_STACK      MAP_GROWSDOWN
+#include <uapi/asm-generic/mman-common.h>
+/* MAP_32BIT is undefined on tile, fix it for perf */
+#define MAP_32BIT      0
+#endif
diff --git a/tools/arch/x86/include/uapi/asm/mman.h b/tools/arch/x86/include/uapi/asm/mman.h
new file mode 100644 (file)
index 0000000..b73c1af
--- /dev/null
@@ -0,0 +1,5 @@
+#ifndef TOOLS_ARCH_X86_UAPI_ASM_MMAN_FIX_H
+#define TOOLS_ARCH_X86_UAPI_ASM_MMAN_FIX_H
+#define MAP_32BIT      0x40
+#include <uapi/asm-generic/mman.h>
+#endif
diff --git a/tools/arch/xtensa/include/uapi/asm/mman.h b/tools/arch/xtensa/include/uapi/asm/mman.h
new file mode 100644 (file)
index 0000000..4453195
--- /dev/null
@@ -0,0 +1,47 @@
+#ifndef TOOLS_ARCH_XTENSA_UAPI_ASM_MMAN_FIX_H
+#define TOOLS_ARCH_XTENSA_UAPI_ASM_MMAN_FIX_H
+#define MADV_DODUMP    17
+#define MADV_DOFORK    11
+#define MADV_DONTDUMP   16
+#define MADV_DONTFORK  10
+#define MADV_DONTNEED  4
+#define MADV_FREE      8
+#define MADV_HUGEPAGE  14
+#define MADV_MERGEABLE   12
+#define MADV_NOHUGEPAGE        15
+#define MADV_NORMAL    0
+#define MADV_RANDOM    1
+#define MADV_REMOVE    9
+#define MADV_SEQUENTIAL        2
+#define MADV_UNMERGEABLE 13
+#define MADV_WILLNEED  3
+#define MAP_ANONYMOUS  0x0800
+#define MAP_DENYWRITE  0x2000
+#define MAP_EXECUTABLE 0x4000
+#define MAP_FILE       0
+#define MAP_FIXED      0x010
+#define MAP_GROWSDOWN  0x1000
+#define MAP_HUGETLB    0x80000
+#define MAP_LOCKED     0x8000
+#define MAP_NONBLOCK   0x20000
+#define MAP_NORESERVE  0x0400
+#define MAP_POPULATE   0x10000
+#define MAP_PRIVATE    0x002
+#define MAP_SHARED     0x001
+#define MAP_STACK      0x40000
+#define PROT_EXEC      0x4
+#define PROT_GROWSDOWN 0x01000000
+#define PROT_GROWSUP   0x02000000
+#define PROT_NONE      0x0
+#define PROT_READ      0x1
+#define PROT_SEM       0x10
+#define PROT_WRITE     0x2
+/* MADV_HWPOISON is undefined on xtensa, fix it for perf */
+#define MADV_HWPOISON  100
+/* MADV_SOFT_OFFLINE is undefined on xtensa, fix it for perf */
+#define MADV_SOFT_OFFLINE 101
+/* MAP_32BIT is undefined on xtensa, fix it for perf */
+#define MAP_32BIT      0
+/* MAP_UNINITIALIZED is undefined on xtensa, fix it for perf */
+#define MAP_UNINITIALIZED      0
+#endif
diff --git a/tools/include/linux/coresight-pmu.h b/tools/include/linux/coresight-pmu.h
new file mode 100644 (file)
index 0000000..7d41026
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * Copyright(C) 2015 Linaro Limited. All rights reserved.
+ * Author: Mathieu Poirier <mathieu.poirier@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _LINUX_CORESIGHT_PMU_H
+#define _LINUX_CORESIGHT_PMU_H
+
+#define CORESIGHT_ETM_PMU_NAME "cs_etm"
+#define CORESIGHT_ETM_PMU_SEED  0x10
+
+/* ETMv3.5/PTM's ETMCR config bit */
+#define ETM_OPT_CYCACC  12
+#define ETM_OPT_TS      28
+
+static inline int coresight_get_trace_id(int cpu)
+{
+       /*
+        * A trace ID of value 0 is invalid, so let's start at some
+        * random value that fits in 7 bits and go from there.  Since
+        * the common convention is to have data trace IDs be I(N) + 1,
+        * set instruction trace IDs as a function of the CPU number.
+        */
+       return (CORESIGHT_ETM_PMU_SEED + (cpu * 2));
+}
+
+#endif
diff --git a/tools/include/linux/time64.h b/tools/include/linux/time64.h
new file mode 100644 (file)
index 0000000..df92654
--- /dev/null
@@ -0,0 +1,12 @@
+#ifndef _TOOLS_LINUX_TIME64_H
+#define _TOOLS_LINUX_TIME64_H
+
+#define MSEC_PER_SEC   1000L
+#define USEC_PER_MSEC  1000L
+#define NSEC_PER_USEC  1000L
+#define NSEC_PER_MSEC  1000000L
+#define USEC_PER_SEC   1000000L
+#define NSEC_PER_SEC   1000000000L
+#define FSEC_PER_SEC   1000000000000000LL
+
+#endif /* _LINUX_TIME64_H */
diff --git a/tools/include/uapi/asm-generic/mman-common.h b/tools/include/uapi/asm-generic/mman-common.h
new file mode 100644 (file)
index 0000000..5827438
--- /dev/null
@@ -0,0 +1,75 @@
+#ifndef __ASM_GENERIC_MMAN_COMMON_H
+#define __ASM_GENERIC_MMAN_COMMON_H
+
+/*
+ Author: Michael S. Tsirkin <mst@mellanox.co.il>, Mellanox Technologies Ltd.
+ Based on: asm-xxx/mman.h
+*/
+
+#define PROT_READ      0x1             /* page can be read */
+#define PROT_WRITE     0x2             /* page can be written */
+#define PROT_EXEC      0x4             /* page can be executed */
+#define PROT_SEM       0x8             /* page may be used for atomic ops */
+#define PROT_NONE      0x0             /* page can not be accessed */
+#define PROT_GROWSDOWN 0x01000000      /* mprotect flag: extend change to start of growsdown vma */
+#define PROT_GROWSUP   0x02000000      /* mprotect flag: extend change to end of growsup vma */
+
+#define MAP_SHARED     0x01            /* Share changes */
+#define MAP_PRIVATE    0x02            /* Changes are private */
+#define MAP_TYPE       0x0f            /* Mask for type of mapping */
+#define MAP_FIXED      0x10            /* Interpret addr exactly */
+#define MAP_ANONYMOUS  0x20            /* don't use a file */
+#ifdef CONFIG_MMAP_ALLOW_UNINITIALIZED
+# define MAP_UNINITIALIZED 0x4000000   /* For anonymous mmap, memory could be uninitialized */
+#else
+# define MAP_UNINITIALIZED 0x0         /* Don't support this flag */
+#endif
+
+/*
+ * Flags for mlock
+ */
+#define MLOCK_ONFAULT  0x01            /* Lock pages in range after they are faulted in, do not prefault */
+
+#define MS_ASYNC       1               /* sync memory asynchronously */
+#define MS_INVALIDATE  2               /* invalidate the caches */
+#define MS_SYNC                4               /* synchronous memory sync */
+
+#define MADV_NORMAL    0               /* no further special treatment */
+#define MADV_RANDOM    1               /* expect random page references */
+#define MADV_SEQUENTIAL        2               /* expect sequential page references */
+#define MADV_WILLNEED  3               /* will need these pages */
+#define MADV_DONTNEED  4               /* don't need these pages */
+
+/* common parameters: try to keep these consistent across architectures */
+#define MADV_FREE      8               /* free pages only if memory pressure */
+#define MADV_REMOVE    9               /* remove these pages & resources */
+#define MADV_DONTFORK  10              /* don't inherit across fork */
+#define MADV_DOFORK    11              /* do inherit across fork */
+#define MADV_HWPOISON  100             /* poison a page for testing */
+#define MADV_SOFT_OFFLINE 101          /* soft offline page for testing */
+
+#define MADV_MERGEABLE   12            /* KSM may merge identical pages */
+#define MADV_UNMERGEABLE 13            /* KSM may not merge identical pages */
+
+#define MADV_HUGEPAGE  14              /* Worth backing with hugepages */
+#define MADV_NOHUGEPAGE        15              /* Not worth backing with hugepages */
+
+#define MADV_DONTDUMP   16             /* Explicity exclude from the core dump,
+                                          overrides the coredump filter bits */
+#define MADV_DODUMP    17              /* Clear the MADV_DONTDUMP flag */
+
+/* compatibility flags */
+#define MAP_FILE       0
+
+/*
+ * When MAP_HUGETLB is set bits [26:31] encode the log2 of the huge page size.
+ * This gives us 6 bits, which is enough until someone invents 128 bit address
+ * spaces.
+ *
+ * Assume these are all power of twos.
+ * When 0 use the default page size.
+ */
+#define MAP_HUGE_SHIFT 26
+#define MAP_HUGE_MASK  0x3f
+
+#endif /* __ASM_GENERIC_MMAN_COMMON_H */
diff --git a/tools/include/uapi/asm-generic/mman.h b/tools/include/uapi/asm-generic/mman.h
new file mode 100644 (file)
index 0000000..10fa785
--- /dev/null
@@ -0,0 +1,22 @@
+#ifndef __ASM_GENERIC_MMAN_H
+#define __ASM_GENERIC_MMAN_H
+
+#include <uapi/asm-generic/mman-common.h>
+
+#define MAP_GROWSDOWN  0x0100          /* stack-like segment */
+#define MAP_DENYWRITE  0x0800          /* ETXTBSY */
+#define MAP_EXECUTABLE 0x1000          /* mark it as an executable */
+#define MAP_LOCKED     0x2000          /* pages are locked */
+#define MAP_NORESERVE  0x4000          /* don't check for reservations */
+#define MAP_POPULATE   0x8000          /* populate (prefault) pagetables */
+#define MAP_NONBLOCK   0x10000         /* do not block on IO */
+#define MAP_STACK      0x20000         /* give out an address that is best suited for process/thread stacks */
+#define MAP_HUGETLB    0x40000         /* create a huge page mapping */
+
+/* Bits [26:31] are reserved, see mman-common.h for MAP_HUGETLB usage */
+
+#define MCL_CURRENT    1               /* lock all current mappings */
+#define MCL_FUTURE     2               /* lock all future mappings */
+#define MCL_ONFAULT    4               /* lock all pages that are faulted in */
+
+#endif /* __ASM_GENERIC_MMAN_H */
diff --git a/tools/include/uapi/linux/mman.h b/tools/include/uapi/linux/mman.h
new file mode 100644 (file)
index 0000000..81d8edf
--- /dev/null
@@ -0,0 +1,13 @@
+#ifndef _UAPI_LINUX_MMAN_H
+#define _UAPI_LINUX_MMAN_H
+
+#include <uapi/asm/mman.h>
+
+#define MREMAP_MAYMOVE 1
+#define MREMAP_FIXED   2
+
+#define OVERCOMMIT_GUESS               0
+#define OVERCOMMIT_ALWAYS              1
+#define OVERCOMMIT_NEVER               2
+
+#endif /* _UAPI_LINUX_MMAN_H */
index ba7094b945ffc7d312902dc8723acf86be68a6f5..f99f49e4a31e65faba6bad4b1c82b99a01de7ded 100644 (file)
 #define TRACEFS_MAGIC          0x74726163
 #endif
 
+#ifndef HUGETLBFS_MAGIC
+#define HUGETLBFS_MAGIC        0x958458f6
+#endif
+
 static const char * const sysfs__fs_known_mountpoints[] = {
        "/sys",
        0,
@@ -67,6 +71,10 @@ static const char * const tracefs__known_mountpoints[] = {
        0,
 };
 
+static const char * const hugetlbfs__known_mountpoints[] = {
+       0,
+};
+
 struct fs {
        const char              *name;
        const char * const      *mounts;
@@ -80,6 +88,7 @@ enum {
        FS__PROCFS  = 1,
        FS__DEBUGFS = 2,
        FS__TRACEFS = 3,
+       FS__HUGETLBFS = 4,
 };
 
 #ifndef TRACEFS_MAGIC
@@ -107,6 +116,11 @@ static struct fs fs__entries[] = {
                .mounts = tracefs__known_mountpoints,
                .magic  = TRACEFS_MAGIC,
        },
+       [FS__HUGETLBFS] = {
+               .name   = "hugetlbfs",
+               .mounts = hugetlbfs__known_mountpoints,
+               .magic  = HUGETLBFS_MAGIC,
+       },
 };
 
 static bool fs__read_mounts(struct fs *fs)
@@ -265,6 +279,7 @@ FS(sysfs,   FS__SYSFS);
 FS(procfs,  FS__PROCFS);
 FS(debugfs, FS__DEBUGFS);
 FS(tracefs, FS__TRACEFS);
+FS(hugetlbfs, FS__HUGETLBFS);
 
 int filename__read_int(const char *filename, int *value)
 {
index 16c9c2ed7c5bfb85e270399f4d6a7253d9a367b3..a63269f5d20cbe5b9c794f64ad64bf7a16d0ce7d 100644 (file)
@@ -21,6 +21,7 @@ FS(sysfs)
 FS(procfs)
 FS(debugfs)
 FS(tracefs)
+FS(hugetlbfs)
 
 #undef FS
 
index 15949e2a7805cc6e7d848ddbf2f99b249e332f3b..cb081ac59fd11457b909a0f98b398993eaf76119 100644 (file)
@@ -110,6 +110,14 @@ Given a $HOME/.perfconfig like this:
                order = caller
                sort-key = function
 
+       [report]
+               # Defaults
+               sort-order = comm,dso,symbol
+               percent-limit = 0
+               queue-size = 0
+               children = true
+               group = true
+
 Variables
 ~~~~~~~~~
 
@@ -382,6 +390,10 @@ call-graph.*::
                histogram entry. Default is 0 which means no limitation.
 
 report.*::
+       report.sort_order::
+               Allows changing the default sort order from "comm,dso,symbol" to
+               some other default, for instance "sym,dso" may be more fitting for
+               kernel developers.
        report.percent-limit::
                This one is mostly the same as call-graph.threshold but works for
                histogram entries. Entries having an overhead lower than this
index b303bcdd8ed15fb9d140e0e7369388bc714aaace..e6c9902c6d82b0e2535059c1a915356e84856589 100644 (file)
@@ -21,6 +21,8 @@ or
 'perf probe' [options] --vars='PROBEPOINT'
 or
 'perf probe' [options] --funcs
+or
+'perf probe' [options] --definition='PROBE' [...]
 
 DESCRIPTION
 -----------
@@ -34,6 +36,8 @@ OPTIONS
 -k::
 --vmlinux=PATH::
        Specify vmlinux path which has debuginfo (Dwarf binary).
+       Only when using this with --definition, you can give an offline
+       vmlinux file.
 
 -m::
 --module=MODNAME|PATH::
@@ -96,6 +100,11 @@ OPTIONS
        can also list functions in a user space executable / shared library.
        This also can accept a FILTER rule argument.
 
+-D::
+--definition=::
+       Show trace-event definition converted from given probe-event instead
+       of write it into tracing/[k,u]probe_events.
+
 --filter=FILTER::
        (Only for --vars and --funcs) Set filter. FILTER is a combination of glob
        pattern, see FILTER PATTERN for detail.
@@ -176,13 +185,12 @@ Each probe argument follows below syntax.
 
 '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' and '$params' special arguments are also available for NAME, '$vars' is expanded to the local variables (including function parameters) which can access at given probe point. '$params' is expanded to only the function parameters.
-'TYPE' casts the type of this argument (optional). If omitted, perf probe automatically set the type based on debuginfo. Currently, basic types (u8/u16/u32/u64/s8/s16/s32/s64), signedness casting (u/s), "string" and bitfield are supported. (see TYPES for detail)
-
+'TYPE' casts the type of this argument (optional). If omitted, perf probe automatically set the type based on debuginfo (*). Currently, basic types (u8/u16/u32/u64/s8/s16/s32/s64), hexadecimal integers (x/x8/x16/x32/x64), signedness casting (u/s), "string" and bitfield are supported. (see TYPES for detail)
 On x86 systems %REG is always the short form of the register: for example %AX. %RAX or %EAX is not valid.
 
 TYPES
 -----
-Basic types (u8/u16/u32/u64/s8/s16/s32/s64) are integer types. Prefix 's' and 'u' means those types are signed and unsigned respectively. Traced arguments are shown in decimal (signed) or hex (unsigned). You can also use 's' or 'u' to specify only signedness and leave its size auto-detected by perf probe.
+Basic types (u8/u16/u32/u64/s8/s16/s32/s64) and hexadecimal integers (x8/x16/x32/x64) are integer types. Prefix 's' and 'u' means those types are signed and unsigned respectively, and 'x' means that is shown in hexadecimal format. Traced arguments are shown in decimal (sNN/uNN) or hex (xNN). You can also use 's' or 'u' to specify only signedness and leave its size auto-detected by perf probe. Moreover, you can use 'x' to explicitly specify to be shown in hexadecimal (the size is also auto-detected).
 String type is a special type, which fetches a "null-terminated" string from kernel space. This means it will fail and store NULL if the string container has been paged out. 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.
 Bitfield is another special type, which takes 3 parameters, bit-width, bit-offset, and container-size (usually 32). The syntax is;
 
index 379a2bed07c09da5698f0555f567512c33453146..1a24f4d64328c1e7551822c12c12fd9854c68284 100644 (file)
@@ -60,6 +60,18 @@ OPTIONS
          Note: If user explicitly sets options which conflict with the params,
          the value set by the params will be overridden.
 
+         Also not defined in .../<pmu>/format/* are PMU driver specific
+         configuration parameters.  Any configuration parameter preceded by
+         the letter '@' is not interpreted in user space and sent down directly
+         to the PMU driver.  For example:
+
+         perf record -e some_event/@cfg1,@cfg2=config/ ...
+
+         will see 'cfg1' and 'cfg2=config' pushed to the PMU driver associated
+         with the event for further processing.  There is no restriction on
+         what the configuration parameters are, as long as their semantic is
+         understood and supported by the PMU driver.
+
         - a hardware breakpoint event in the form of '\mem:addr[/len][:access]'
           where addr is the address in memory you want to break in.
           Access is the memory access type (read, write, execute) it can
index 1d8d5bc4cd2de6601f926696d5c172b30fa735d4..2b477c1d1efe60b280394d8b407f9a18c3544dd6 100644 (file)
        use_offset = true
        jump_arrows = true
        show_nr_jumps = false
+
+[report]
+
+       # Defaults
+       sort-order = comm,dso,symbol
+       percent-limit = 0
+       queue-size = 0
+       children = true
+       group = true
index ad2534df4ba6ce988429510b5c35360c253299cf..0bda2cca2b3a641fa0a13531c02114b548cddcb6 100644 (file)
@@ -60,14 +60,18 @@ tools/include/asm-generic/bitops.h
 tools/include/linux/atomic.h
 tools/include/linux/bitops.h
 tools/include/linux/compiler.h
+tools/include/linux/coresight-pmu.h
 tools/include/linux/filter.h
 tools/include/linux/hash.h
 tools/include/linux/kernel.h
 tools/include/linux/list.h
 tools/include/linux/log2.h
+tools/include/uapi/asm-generic/mman-common.h
+tools/include/uapi/asm-generic/mman.h
 tools/include/uapi/linux/bpf.h
 tools/include/uapi/linux/bpf_common.h
 tools/include/uapi/linux/hw_breakpoint.h
+tools/include/uapi/linux/mman.h
 tools/include/uapi/linux/perf_event.h
 tools/include/linux/poison.h
 tools/include/linux/rbtree.h
@@ -77,4 +81,6 @@ tools/include/linux/stringify.h
 tools/include/linux/types.h
 tools/include/linux/err.h
 tools/include/linux/bitmap.h
+tools/include/linux/time64.h
+tools/arch/*/include/uapi/asm/mman.h
 tools/arch/*/include/uapi/asm/perf_regs.h
index 2d908750163368e9d1ac7af4177c6717ce556300..d710db16b9639a14e1b7cb5a662f154c0bff53b3 100644 (file)
@@ -165,7 +165,7 @@ SUBCMD_DIR  = $(srctree)/tools/lib/subcmd/
 # non-config cases
 config := 1
 
-NON_CONFIG_TARGETS := clean TAGS tags cscope help
+NON_CONFIG_TARGETS := clean TAGS tags cscope help install-doc
 
 ifdef MAKECMDGOALS
 ifeq ($(filter-out $(NON_CONFIG_TARGETS),$(MAKECMDGOALS)),)
@@ -429,6 +429,18 @@ $(PERF_IN): prepare FORCE
        @(test -f ../../include/asm-generic/bitops/fls64.h && ( \
         (diff -B ../include/asm-generic/bitops/fls64.h ../../include/asm-generic/bitops/fls64.h >/dev/null) \
         || echo "Warning: tools/include/asm-generic/bitops/fls64.h differs from kernel" >&2 )) || true
+       @(test -f ../../include/linux/coresight-pmu.h && ( \
+       (diff -B ../include/linux/coresight-pmu.h ../../include/linux/coresight-pmu.h >/dev/null) \
+       || echo "Warning: tools/include/linux/coresight-pmu.h differs from kernel" >&2 )) || true
+       @(test -f ../../include/uapi/asm-generic/mman-common.h && ( \
+       (diff -B ../include/uapi/asm-generic/mman-common.h ../../include/uapi/asm-generic/mman-common.h >/dev/null) \
+       || echo "Warning: tools/include/uapi/asm-generic/mman-common.h differs from kernel" >&2 )) || true
+       @(test -f ../../include/uapi/asm-generic/mman.h && ( \
+       (diff -B -I "^#include <\(uapi/\)*asm-generic/mman-common.h>$$" ../include/uapi/asm-generic/mman.h ../../include/uapi/asm-generic/mman.h >/dev/null) \
+       || echo "Warning: tools/include/uapi/asm-generic/mman.h differs from kernel" >&2 )) || true
+       @(test -f ../../include/uapi/linux/mman.h && ( \
+       (diff -B -I "^#include <\(uapi/\)*asm/mman.h>$$" ../include/uapi/linux/mman.h ../../include/uapi/linux/mman.h >/dev/null) \
+       || echo "Warning: tools/include/uapi/linux/mman.h differs from kernel" >&2 )) || true
        $(Q)$(MAKE) $(build)=perf
 
 $(OUTPUT)perf: $(PERFLIBS) $(PERF_IN) $(LIBTRACEEVENT_DYNAMIC_LIST)
diff --git a/tools/perf/arch/arm/include/dwarf-regs-table.h b/tools/perf/arch/arm/include/dwarf-regs-table.h
new file mode 100644 (file)
index 0000000..f298d03
--- /dev/null
@@ -0,0 +1,9 @@
+#ifdef DEFINE_DWARF_REGSTR_TABLE
+/* This is included in perf/util/dwarf-regs.c */
+
+static const char * const arm_regstr_tbl[] = {
+       "%r0", "%r1", "%r2", "%r3", "%r4",
+       "%r5", "%r6", "%r7", "%r8", "%r9", "%r10",
+       "%fp", "%ip", "%sp", "%lr", "%pc",
+};
+#endif
diff --git a/tools/perf/arch/arm64/include/dwarf-regs-table.h b/tools/perf/arch/arm64/include/dwarf-regs-table.h
new file mode 100644 (file)
index 0000000..2675936
--- /dev/null
@@ -0,0 +1,13 @@
+#ifdef DEFINE_DWARF_REGSTR_TABLE
+/* This is included in perf/util/dwarf-regs.c */
+
+static const char * const aarch64_regstr_tbl[] = {
+       "%r0", "%r1", "%r2", "%r3", "%r4",
+       "%r5", "%r6", "%r7", "%r8", "%r9",
+       "%r10", "%r11", "%r12", "%r13", "%r14",
+       "%r15", "%r16", "%r17", "%r18", "%r19",
+       "%r20", "%r21", "%r22", "%r23", "%r24",
+       "%r25", "%r26", "%r27", "%r28", "%r29",
+       "%lr", "%sp",
+};
+#endif
diff --git a/tools/perf/arch/powerpc/include/dwarf-regs-table.h b/tools/perf/arch/powerpc/include/dwarf-regs-table.h
new file mode 100644 (file)
index 0000000..db4730f
--- /dev/null
@@ -0,0 +1,27 @@
+#ifdef DEFINE_DWARF_REGSTR_TABLE
+/* This is included in perf/util/dwarf-regs.c */
+
+/*
+ * Reference:
+ * http://refspecs.linuxfoundation.org/ELF/ppc64/PPC-elf64abi-1.9.html
+ * http://refspecs.linux-foundation.org/elf/elfspec_ppc.pdf
+ */
+#define REG_DWARFNUM_NAME(reg, idx)    [idx] = "%" #reg
+
+static const char * const powerpc_regstr_tbl[] = {
+       "%gpr0", "%gpr1", "%gpr2", "%gpr3", "%gpr4",
+       "%gpr5", "%gpr6", "%gpr7", "%gpr8", "%gpr9",
+       "%gpr10", "%gpr11", "%gpr12", "%gpr13", "%gpr14",
+       "%gpr15", "%gpr16", "%gpr17", "%gpr18", "%gpr19",
+       "%gpr20", "%gpr21", "%gpr22", "%gpr23", "%gpr24",
+       "%gpr25", "%gpr26", "%gpr27", "%gpr28", "%gpr29",
+       "%gpr30", "%gpr31",
+       REG_DWARFNUM_NAME(msr,   66),
+       REG_DWARFNUM_NAME(ctr,   109),
+       REG_DWARFNUM_NAME(link,  108),
+       REG_DWARFNUM_NAME(xer,   101),
+       REG_DWARFNUM_NAME(dar,   119),
+       REG_DWARFNUM_NAME(dsisr, 118),
+};
+
+#endif
index 35745a733100e70f27c6c95ce97ce4ef5a6fabfa..ed9d5d15d5b69223b7fd915cae1a982d53b73e4b 100644 (file)
@@ -108,7 +108,7 @@ void arch__post_process_probe_trace_events(struct perf_probe_event *pev,
        int i = 0;
 
        map = get_target_map(pev->target, pev->uprobes);
-       if (!map || map__load(map, NULL) < 0)
+       if (!map || map__load(map) < 0)
                return;
 
        for (i = 0; i < ntevs; i++) {
diff --git a/tools/perf/arch/s390/include/dwarf-regs-table.h b/tools/perf/arch/s390/include/dwarf-regs-table.h
new file mode 100644 (file)
index 0000000..9da74a9
--- /dev/null
@@ -0,0 +1,8 @@
+#ifdef DEFINE_DWARF_REGSTR_TABLE
+/* This is included in perf/util/dwarf-regs.c */
+
+static const char * const s390_regstr_tbl[] = {
+       "%r0", "%r1",  "%r2",  "%r3",  "%r4",  "%r5",  "%r6",  "%r7",
+       "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15",
+};
+#endif
diff --git a/tools/perf/arch/sh/include/dwarf-regs-table.h b/tools/perf/arch/sh/include/dwarf-regs-table.h
new file mode 100644 (file)
index 0000000..3a2deaf
--- /dev/null
@@ -0,0 +1,25 @@
+#ifdef DEFINE_DWARF_REGSTR_TABLE
+/* This is included in perf/util/dwarf-regs.c */
+
+const char * const sh_regstr_tbl[] = {
+       "r0",
+       "r1",
+       "r2",
+       "r3",
+       "r4",
+       "r5",
+       "r6",
+       "r7",
+       "r8",
+       "r9",
+       "r10",
+       "r11",
+       "r12",
+       "r13",
+       "r14",
+       "r15",
+       "pc",
+       "pr",
+};
+
+#endif
diff --git a/tools/perf/arch/sparc/include/dwarf-regs-table.h b/tools/perf/arch/sparc/include/dwarf-regs-table.h
new file mode 100644 (file)
index 0000000..12c0761
--- /dev/null
@@ -0,0 +1,18 @@
+#ifdef DEFINE_DWARF_REGSTR_TABLE
+/* This is included in perf/util/dwarf-regs.c */
+
+static const char * const sparc_regstr_tbl[] = {
+       "%g0", "%g1", "%g2", "%g3", "%g4", "%g5", "%g6", "%g7",
+       "%o0", "%o1", "%o2", "%o3", "%o4", "%o5", "%sp", "%o7",
+       "%l0", "%l1", "%l2", "%l3", "%l4", "%l5", "%l6", "%l7",
+       "%i0", "%i1", "%i2", "%i3", "%i4", "%i5", "%fp", "%i7",
+       "%f0", "%f1", "%f2", "%f3", "%f4", "%f5", "%f6", "%f7",
+       "%f8", "%f9", "%f10", "%f11", "%f12", "%f13", "%f14", "%f15",
+       "%f16", "%f17", "%f18", "%f19", "%f20", "%f21", "%f22", "%f23",
+       "%f24", "%f25", "%f26", "%f27", "%f28", "%f29", "%f30", "%f31",
+       "%f32", "%f33", "%f34", "%f35", "%f36", "%f37", "%f38", "%f39",
+       "%f40", "%f41", "%f42", "%f43", "%f44", "%f45", "%f46", "%f47",
+       "%f48", "%f49", "%f50", "%f51", "%f52", "%f53", "%f54", "%f55",
+       "%f56", "%f57", "%f58", "%f59", "%f60", "%f61", "%f62", "%f63",
+};
+#endif
diff --git a/tools/perf/arch/x86/include/dwarf-regs-table.h b/tools/perf/arch/x86/include/dwarf-regs-table.h
new file mode 100644 (file)
index 0000000..9b5e5cb
--- /dev/null
@@ -0,0 +1,14 @@
+#ifdef DEFINE_DWARF_REGSTR_TABLE
+/* This is included in perf/util/dwarf-regs.c */
+
+static const char * const x86_32_regstr_tbl[] = {
+       "%ax", "%cx", "%dx", "%bx", "$stack",/* Stack address instead of %sp */
+       "%bp", "%si", "%di",
+};
+
+static const char * const x86_64_regstr_tbl[] = {
+       "%ax", "%dx", "%cx", "%bx", "%si", "%di",
+       "%bp", "%sp", "%r8", "%r9", "%r10", "%r11",
+       "%r12", "%r13", "%r14", "%r15",
+};
+#endif
diff --git a/tools/perf/arch/xtensa/include/dwarf-regs-table.h b/tools/perf/arch/xtensa/include/dwarf-regs-table.h
new file mode 100644 (file)
index 0000000..aa0444a
--- /dev/null
@@ -0,0 +1,8 @@
+#ifdef DEFINE_DWARF_REGSTR_TABLE
+/* This is included in perf/util/dwarf-regs.c */
+
+static const char * const xtensa_regstr_tbl[] = {
+       "a0", "a1", "a2", "a3", "a4", "a5", "a6", "a7",
+       "a8", "a9", "a10", "a11", "a12", "a13", "a14", "a15",
+};
+#endif
index f96e22ed9f873de6aada5bb9a3e5ac0fdc902b35..2b9705a8734cd6005fd3149943e2ff20eecf4bbe 100644 (file)
@@ -16,6 +16,7 @@
 #include <subcmd/parse-options.h>
 #include <linux/compiler.h>
 #include <linux/kernel.h>
+#include <linux/time64.h>
 #include <errno.h>
 #include "bench.h"
 #include "futex.h"
@@ -62,7 +63,7 @@ static void print_summary(void)
        printf("Requeued %d of %d threads in %.4f ms (+-%.2f%%)\n",
               requeued_avg,
               nthreads,
-              requeuetime_avg/1e3,
+              requeuetime_avg / USEC_PER_MSEC,
               rel_stddev_stats(requeuetime_stddev, requeuetime_avg));
 }
 
@@ -184,7 +185,7 @@ int bench_futex_requeue(int argc, const char **argv,
 
                if (!silent) {
                        printf("[Run %d]: Requeued %d of %d threads in %.4f ms\n",
-                              j + 1, nrequeued, nthreads, runtime.tv_usec/1e3);
+                              j + 1, nrequeued, nthreads, runtime.tv_usec / (double)USEC_PER_MSEC);
                }
 
                /* everybody should be blocked on futex2, wake'em up */
index 4a2ecd7438ca0ffeb3f9e354e1a24668f06db338..2c8fa67ad53767e43c7e91dc84279528268fcb3a 100644 (file)
@@ -15,6 +15,7 @@
 #include <subcmd/parse-options.h>
 #include <linux/compiler.h>
 #include <linux/kernel.h>
+#include <linux/time64.h>
 #include <errno.h>
 #include "bench.h"
 #include "futex.h"
@@ -156,7 +157,7 @@ static void print_run(struct thread_data *waking_worker, unsigned int run_num)
 
        printf("[Run %d]: Avg per-thread latency (waking %d/%d threads) "
               "in %.4f ms (+-%.2f%%)\n", run_num + 1, wakeup_avg,
-              nblocked_threads, waketime_avg/1e3,
+              nblocked_threads, waketime_avg / USEC_PER_MSEC,
               rel_stddev_stats(waketime_stddev, waketime_avg));
 }
 
@@ -172,7 +173,7 @@ static void print_summary(void)
        printf("Avg per-thread latency (waking %d/%d threads) in %.4f ms (+-%.2f%%)\n",
               wakeup_avg,
               nblocked_threads,
-              waketime_avg/1e3,
+              waketime_avg / USEC_PER_MSEC,
               rel_stddev_stats(waketime_stddev, waketime_avg));
 }
 
index 87d8f4f292d95bfa715c8c2408a69a712c33da78..e246b1b8388a3fd3bfc7c9c398a90efc26d86c79 100644 (file)
@@ -16,6 +16,7 @@
 #include <subcmd/parse-options.h>
 #include <linux/compiler.h>
 #include <linux/kernel.h>
+#include <linux/time64.h>
 #include <errno.h>
 #include "bench.h"
 #include "futex.h"
@@ -81,7 +82,7 @@ static void print_summary(void)
        printf("Wokeup %d of %d threads in %.4f ms (+-%.2f%%)\n",
               wakeup_avg,
               nthreads,
-              waketime_avg/1e3,
+              waketime_avg / USEC_PER_MSEC,
               rel_stddev_stats(waketime_stddev, waketime_avg));
 }
 
@@ -182,7 +183,7 @@ int bench_futex_wake(int argc, const char **argv,
 
                if (!silent) {
                        printf("[Run %d]: Wokeup %d of %d threads in %.4f ms\n",
-                              j + 1, nwoken, nthreads, runtime.tv_usec/1e3);
+                              j + 1, nwoken, nthreads, runtime.tv_usec / (double)USEC_PER_MSEC);
                }
 
                for (i = 0; i < nthreads; i++) {
index 2b54d0f2672a39eaee68c5b5a48de2c01ba2956f..c684910e5a482af6bee4ebd15c86708813ff6777 100644 (file)
@@ -21,6 +21,7 @@
 #include <string.h>
 #include <sys/time.h>
 #include <errno.h>
+#include <linux/time64.h>
 
 #define K 1024
 
@@ -89,7 +90,7 @@ static u64 get_cycles(void)
 
 static double timeval2double(struct timeval *ts)
 {
-       return (double)ts->tv_sec + (double)ts->tv_usec / (double)1000000;
+       return (double)ts->tv_sec + (double)ts->tv_usec / (double)USEC_PER_SEC;
 }
 
 #define print_bps(x) do {                                              \
index f7f530081aa9421a0e01ae362fa02c3192c2896c..8efe904e486bf98b63e24b7904652f10ca5ec7e9 100644 (file)
@@ -30,6 +30,7 @@
 #include <sys/wait.h>
 #include <sys/prctl.h>
 #include <sys/types.h>
+#include <linux/time64.h>
 
 #include <numa.h>
 #include <numaif.h>
@@ -1004,7 +1005,7 @@ static void calc_convergence(double runtime_ns_max, double *convergence)
        if (strong && process_groups == g->p.nr_proc) {
                if (!*convergence) {
                        *convergence = runtime_ns_max;
-                       tprintf(" (%6.1fs converged)\n", *convergence/1e9);
+                       tprintf(" (%6.1fs converged)\n", *convergence / NSEC_PER_SEC);
                        if (g->p.measure_convergence) {
                                g->all_converged = true;
                                g->stop_work = true;
@@ -1012,7 +1013,7 @@ static void calc_convergence(double runtime_ns_max, double *convergence)
                }
        } else {
                if (*convergence) {
-                       tprintf(" (%6.1fs de-converged)", runtime_ns_max/1e9);
+                       tprintf(" (%6.1fs de-converged)", runtime_ns_max / NSEC_PER_SEC);
                        *convergence = 0;
                }
                tprintf("\n");
@@ -1022,7 +1023,7 @@ static void calc_convergence(double runtime_ns_max, double *convergence)
 static void show_summary(double runtime_ns_max, int l, double *convergence)
 {
        tprintf("\r #  %5.1f%%  [%.1f mins]",
-               (double)(l+1)/g->p.nr_loops*100.0, runtime_ns_max/1e9 / 60.0);
+               (double)(l+1)/g->p.nr_loops*100.0, runtime_ns_max / NSEC_PER_SEC / 60.0);
 
        calc_convergence(runtime_ns_max, convergence);
 
@@ -1179,8 +1180,8 @@ static void *worker_thread(void *__tdata)
 
                if (details >= 3) {
                        timersub(&stop, &start, &diff);
-                       runtime_ns_max = diff.tv_sec * 1000000000;
-                       runtime_ns_max += diff.tv_usec * 1000;
+                       runtime_ns_max = diff.tv_sec * NSEC_PER_SEC;
+                       runtime_ns_max += diff.tv_usec * NSEC_PER_USEC;
 
                        if (details >= 0) {
                                printf(" #%2d / %2d: %14.2lf nsecs/op [val: %016"PRIx64"]\n",
@@ -1192,23 +1193,23 @@ static void *worker_thread(void *__tdata)
                        continue;
 
                timersub(&stop, &start0, &diff);
-               runtime_ns_max = diff.tv_sec * 1000000000ULL;
-               runtime_ns_max += diff.tv_usec * 1000ULL;
+               runtime_ns_max = diff.tv_sec * NSEC_PER_SEC;
+               runtime_ns_max += diff.tv_usec * NSEC_PER_USEC;
 
                show_summary(runtime_ns_max, l, &convergence);
        }
 
        gettimeofday(&stop, NULL);
        timersub(&stop, &start0, &diff);
-       td->runtime_ns = diff.tv_sec * 1000000000ULL;
-       td->runtime_ns += diff.tv_usec * 1000ULL;
-       td->speed_gbs = bytes_done / (td->runtime_ns / 1e9) / 1e9;
+       td->runtime_ns = diff.tv_sec * NSEC_PER_SEC;
+       td->runtime_ns += diff.tv_usec * NSEC_PER_USEC;
+       td->speed_gbs = bytes_done / (td->runtime_ns / NSEC_PER_SEC) / 1e9;
 
        getrusage(RUSAGE_THREAD, &rusage);
-       td->system_time_ns = rusage.ru_stime.tv_sec * 1000000000ULL;
-       td->system_time_ns += rusage.ru_stime.tv_usec * 1000ULL;
-       td->user_time_ns = rusage.ru_utime.tv_sec * 1000000000ULL;
-       td->user_time_ns += rusage.ru_utime.tv_usec * 1000ULL;
+       td->system_time_ns = rusage.ru_stime.tv_sec * NSEC_PER_SEC;
+       td->system_time_ns += rusage.ru_stime.tv_usec * NSEC_PER_USEC;
+       td->user_time_ns = rusage.ru_utime.tv_sec * NSEC_PER_SEC;
+       td->user_time_ns += rusage.ru_utime.tv_usec * NSEC_PER_USEC;
 
        free_data(thread_data, g->p.bytes_thread);
 
@@ -1469,7 +1470,7 @@ static int __bench_numa(const char *name)
        }
        /* Wait for all the threads to start up: */
        while (g->nr_tasks_started != g->p.nr_tasks)
-               usleep(1000);
+               usleep(USEC_PER_MSEC);
 
        BUG_ON(g->nr_tasks_started != g->p.nr_tasks);
 
@@ -1488,9 +1489,9 @@ static int __bench_numa(const char *name)
 
                timersub(&stop, &start, &diff);
 
-               startup_sec = diff.tv_sec * 1000000000.0;
-               startup_sec += diff.tv_usec * 1000.0;
-               startup_sec /= 1e9;
+               startup_sec = diff.tv_sec * NSEC_PER_SEC;
+               startup_sec += diff.tv_usec * NSEC_PER_USEC;
+               startup_sec /= NSEC_PER_SEC;
 
                tprintf(" threads initialized in %.6f seconds.\n", startup_sec);
                tprintf(" #\n");
@@ -1529,14 +1530,14 @@ static int __bench_numa(const char *name)
        tprintf("\n ###\n");
        tprintf("\n");
 
-       runtime_sec_max = diff.tv_sec * 1000000000.0;
-       runtime_sec_max += diff.tv_usec * 1000.0;
-       runtime_sec_max /= 1e9;
+       runtime_sec_max = diff.tv_sec * NSEC_PER_SEC;
+       runtime_sec_max += diff.tv_usec * NSEC_PER_USEC;
+       runtime_sec_max /= NSEC_PER_SEC;
 
-       runtime_sec_min = runtime_ns_min/1e9;
+       runtime_sec_min = runtime_ns_min / NSEC_PER_SEC;
 
        bytes = g->bytes_done;
-       runtime_avg = (double)runtime_ns_sum / g->p.nr_tasks / 1e9;
+       runtime_avg = (double)runtime_ns_sum / g->p.nr_tasks / NSEC_PER_SEC;
 
        if (g->p.measure_convergence) {
                print_res(name, runtime_sec_max,
@@ -1562,7 +1563,7 @@ static int __bench_numa(const char *name)
        print_res(name, bytes / 1e9,
                "GB,", "data-total",            "GB data processed, total");
 
-       print_res(name, runtime_sec_max * 1e9 / (bytes / g->p.nr_tasks),
+       print_res(name, runtime_sec_max * NSEC_PER_SEC / (bytes / g->p.nr_tasks),
                "nsecs,", "runtime/byte/thread","nsecs/byte/thread runtime");
 
        print_res(name, bytes / g->p.nr_tasks / 1e9 / runtime_sec_max,
@@ -1581,9 +1582,9 @@ static int __bench_numa(const char *name)
                                snprintf(tname, 32, "process%d:thread%d", p, t);
                                print_res(tname, td->speed_gbs,
                                        "GB/sec",       "thread-speed", "GB/sec/thread speed");
-                               print_res(tname, td->system_time_ns / 1e9,
+                               print_res(tname, td->system_time_ns / NSEC_PER_SEC,
                                        "secs", "thread-system-time", "system CPU time/thread");
-                               print_res(tname, td->user_time_ns / 1e9,
+                               print_res(tname, td->user_time_ns / NSEC_PER_SEC,
                                        "secs", "thread-user-time", "user CPU time/thread");
                        }
                }
index bfaf9503de8ef4d96a85770afb4f658c11e7d2e2..6a111e775210f700de6e3b796b703675748a0b05 100644 (file)
@@ -29,6 +29,7 @@
 #include <poll.h>
 #include <limits.h>
 #include <err.h>
+#include <linux/time64.h>
 
 #define DATASIZE 100
 
@@ -312,11 +313,11 @@ int bench_sched_messaging(int argc, const char **argv,
                       thread_mode ? "threads" : "processes");
                printf(" %14s: %lu.%03lu [sec]\n", "Total time",
                       diff.tv_sec,
-                      (unsigned long) (diff.tv_usec/1000));
+                      (unsigned long) (diff.tv_usec / USEC_PER_MSEC));
                break;
        case BENCH_FORMAT_SIMPLE:
                printf("%lu.%03lu\n", diff.tv_sec,
-                      (unsigned long) (diff.tv_usec/1000));
+                      (unsigned long) (diff.tv_usec / USEC_PER_MSEC));
                break;
        default:
                /* reaching here is something disaster */
index 1dc2d13cc2722c7c0207edc4fafb1b7f77b7697d..2243f0150d76452da3502c0d5f3ead12b85de512 100644 (file)
@@ -25,6 +25,7 @@
 #include <sys/time.h>
 #include <sys/types.h>
 #include <sys/syscall.h>
+#include <linux/time64.h>
 
 #include <pthread.h>
 
@@ -153,24 +154,24 @@ int bench_sched_pipe(int argc, const char **argv, const char *prefix __maybe_unu
                printf("# Executed %d pipe operations between two %s\n\n",
                        loops, threaded ? "threads" : "processes");
 
-               result_usec = diff.tv_sec * 1000000;
+               result_usec = diff.tv_sec * USEC_PER_SEC;
                result_usec += diff.tv_usec;
 
                printf(" %14s: %lu.%03lu [sec]\n\n", "Total time",
                       diff.tv_sec,
-                      (unsigned long) (diff.tv_usec/1000));
+                      (unsigned long) (diff.tv_usec / USEC_PER_MSEC));
 
                printf(" %14lf usecs/op\n",
                       (double)result_usec / (double)loops);
                printf(" %14d ops/sec\n",
                       (int)((double)loops /
-                            ((double)result_usec / (double)1000000)));
+                            ((double)result_usec / (double)USEC_PER_SEC)));
                break;
 
        case BENCH_FORMAT_SIMPLE:
                printf("%lu.%03lu\n",
                       diff.tv_sec,
-                      (unsigned long) (diff.tv_usec / 1000));
+                      (unsigned long) (diff.tv_usec / USEC_PER_MSEC));
                break;
 
        default:
index 9c1034d81b4fe3cc72d4b3b09ac8d527d07b0da0..ebb628332a6e59a938347eca53c3da81c859aee5 100644 (file)
@@ -30,6 +30,7 @@
 #include "util/tool.h"
 #include "util/data.h"
 #include "arch/common.h"
+#include "util/block-range.h"
 
 #include <dlfcn.h>
 #include <linux/bitmap.h>
@@ -46,6 +47,103 @@ struct perf_annotate {
        DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS);
 };
 
+/*
+ * Given one basic block:
+ *
+ *     from    to              branch_i
+ *     * ----> *
+ *             |
+ *             | block
+ *             v
+ *             * ----> *
+ *             from    to      branch_i+1
+ *
+ * where the horizontal are the branches and the vertical is the executed
+ * block of instructions.
+ *
+ * We count, for each 'instruction', the number of blocks that covered it as
+ * well as count the ratio each branch is taken.
+ *
+ * We can do this without knowing the actual instruction stream by keeping
+ * track of the address ranges. We break down ranges such that there is no
+ * overlap and iterate from the start until the end.
+ *
+ * @acme: once we parse the objdump output _before_ processing the samples,
+ * we can easily fold the branch.cycles IPC bits in.
+ */
+static void process_basic_block(struct addr_map_symbol *start,
+                               struct addr_map_symbol *end,
+                               struct branch_flags *flags)
+{
+       struct symbol *sym = start->sym;
+       struct annotation *notes = sym ? symbol__annotation(sym) : NULL;
+       struct block_range_iter iter;
+       struct block_range *entry;
+
+       /*
+        * Sanity; NULL isn't executable and the CPU cannot execute backwards
+        */
+       if (!start->addr || start->addr > end->addr)
+               return;
+
+       iter = block_range__create(start->addr, end->addr);
+       if (!block_range_iter__valid(&iter))
+               return;
+
+       /*
+        * First block in range is a branch target.
+        */
+       entry = block_range_iter(&iter);
+       assert(entry->is_target);
+       entry->entry++;
+
+       do {
+               entry = block_range_iter(&iter);
+
+               entry->coverage++;
+               entry->sym = sym;
+
+               if (notes)
+                       notes->max_coverage = max(notes->max_coverage, entry->coverage);
+
+       } while (block_range_iter__next(&iter));
+
+       /*
+        * Last block in rage is a branch.
+        */
+       entry = block_range_iter(&iter);
+       assert(entry->is_branch);
+       entry->taken++;
+       if (flags->predicted)
+               entry->pred++;
+}
+
+static void process_branch_stack(struct branch_stack *bs, struct addr_location *al,
+                                struct perf_sample *sample)
+{
+       struct addr_map_symbol *prev = NULL;
+       struct branch_info *bi;
+       int i;
+
+       if (!bs || !bs->nr)
+               return;
+
+       bi = sample__resolve_bstack(sample, al);
+       if (!bi)
+               return;
+
+       for (i = bs->nr - 1; i >= 0; i--) {
+               /*
+                * XXX filter against symbol
+                */
+               if (prev)
+                       process_basic_block(prev, &bi[i].from, &bi[i].flags);
+               prev = &bi[i].to;
+       }
+
+       free(bi);
+}
+
 static int perf_evsel__add_sample(struct perf_evsel *evsel,
                                  struct perf_sample *sample,
                                  struct addr_location *al,
@@ -72,6 +170,12 @@ static int perf_evsel__add_sample(struct perf_evsel *evsel,
                return 0;
        }
 
+       /*
+        * XXX filtered samples can still have branch entires pointing into our
+        * symbol and are missed.
+        */
+       process_branch_stack(sample->branch_stack, al, sample);
+
        sample->period = 1;
        sample->weight = 1;
 
@@ -204,8 +308,6 @@ static int __cmd_annotate(struct perf_annotate *ann)
        struct perf_evsel *pos;
        u64 total_nr_samples;
 
-       machines__set_symbol_filter(&session->machines, symbol__annotate_init);
-
        if (ann->cpu_list) {
                ret = perf_session__cpu_bitmap(session, ann->cpu_list,
                                               ann->cpu_bitmap);
@@ -367,7 +469,10 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __maybe_unused)
        if (annotate.session == NULL)
                return -1;
 
-       symbol_conf.priv_size = sizeof(struct annotation);
+       ret = symbol__annotation_init();
+       if (ret < 0)
+               goto out_delete;
+
        symbol_conf.try_vmlinux_path = true;
 
        ret = symbol__init(&annotate.session->header.env);
index 21ee753211adfa954b9e25fb1df9be8354dfc8a5..9ff0db4e2d0cd1bcc35d2ea137871093ebfcb405 100644 (file)
@@ -1033,7 +1033,9 @@ static int hpp__entry_global(struct perf_hpp_fmt *_fmt, struct perf_hpp *hpp,
 }
 
 static int hpp__header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
-                      struct hists *hists __maybe_unused)
+                      struct hists *hists __maybe_unused,
+                      int line __maybe_unused,
+                      int *span __maybe_unused)
 {
        struct diff_hpp_fmt *dfmt =
                container_of(fmt, struct diff_hpp_fmt, fmt);
index 73c1c4cc36009d79a3f33c80db6e4834dc21b81a..b9bc7e39833a47055608feffa1f5917aada33174 100644 (file)
@@ -429,7 +429,7 @@ static int perf_event__inject_buildid(struct perf_tool *tool,
        if (al.map != NULL) {
                if (!al.map->dso->hit) {
                        al.map->dso->hit = 1;
-                       if (map__load(al.map, NULL) >= 0) {
+                       if (map__load(al.map) >= 0) {
                                dso__inject_build_id(al.map->dso, tool, machine);
                                /*
                                 * If this fails, too bad, let the other side
index fdde1bd3e3062bbf266ef165eb4dce8512f4d9b3..d426dcb18ce9a0d9756c274844bc84af9bcc5b0a 100644 (file)
@@ -330,7 +330,7 @@ static int build_alloc_func_list(void)
        }
 
        kernel_map = machine__kernel_map(machine);
-       if (map__load(kernel_map, NULL) < 0) {
+       if (map__load(kernel_map) < 0) {
                pr_err("cannot load kernel map\n");
                return -ENOENT;
        }
@@ -979,7 +979,7 @@ static void __print_slab_result(struct rb_root *root,
                if (is_caller) {
                        addr = data->call_site;
                        if (!raw_ip)
-                               sym = machine__find_kernel_function(machine, addr, &map, NULL);
+                               sym = machine__find_kernel_function(machine, addr, &map);
                } else
                        addr = data->ptr;
 
@@ -1043,8 +1043,7 @@ static void __print_page_alloc_result(struct perf_session *session, int n_lines)
                char *caller = buf;
 
                data = rb_entry(next, struct page_stat, node);
-               sym = machine__find_kernel_function(machine, data->callsite,
-                                                   &map, NULL);
+               sym = machine__find_kernel_function(machine, data->callsite, &map);
                if (sym && sym->name)
                        caller = sym->name;
                else
@@ -1086,8 +1085,7 @@ static void __print_page_caller_result(struct perf_session *session, int n_lines
                char *caller = buf;
 
                data = rb_entry(next, struct page_stat, node);
-               sym = machine__find_kernel_function(machine, data->callsite,
-                                                   &map, NULL);
+               sym = machine__find_kernel_function(machine, data->callsite, &map);
                if (sym && sym->name)
                        caller = sym->name;
                else
index 5e2127e04f8386c4aa92b62e0370afff08d9e9b5..08fa88f62a246f4f309410da45379aa21949f14e 100644 (file)
@@ -24,6 +24,7 @@
 #include <sys/timerfd.h>
 #endif
 
+#include <linux/time64.h>
 #include <termios.h>
 #include <semaphore.h>
 #include <pthread.h>
@@ -362,7 +363,7 @@ static bool handle_end_event(struct perf_kvm_stat *kvm,
                if (!skip_event(decode)) {
                        pr_info("%" PRIu64 " VM %d, vcpu %d: %s event took %" PRIu64 "usec\n",
                                 sample->time, sample->pid, vcpu_record->vcpu_id,
-                                decode, time_diff/1000);
+                                decode, time_diff / NSEC_PER_USEC);
                }
        }
 
@@ -608,15 +609,15 @@ static void print_result(struct perf_kvm_stat *kvm)
                pr_info("%10llu ", (unsigned long long)ecount);
                pr_info("%8.2f%% ", (double)ecount / kvm->total_count * 100);
                pr_info("%8.2f%% ", (double)etime / kvm->total_time * 100);
-               pr_info("%9.2fus ", (double)min / 1e3);
-               pr_info("%9.2fus ", (double)max / 1e3);
-               pr_info("%9.2fus ( +-%7.2f%% )", (double)etime / ecount/1e3,
+               pr_info("%9.2fus ", (double)min / NSEC_PER_USEC);
+               pr_info("%9.2fus ", (double)max / NSEC_PER_USEC);
+               pr_info("%9.2fus ( +-%7.2f%% )", (double)etime / ecount / NSEC_PER_USEC,
                        kvm_event_rel_stddev(vcpu, event));
                pr_info("\n");
        }
 
        pr_info("\nTotal Samples:%" PRIu64 ", Total events handled time:%.2fus.\n\n",
-               kvm->total_count, kvm->total_time / 1e3);
+               kvm->total_count, kvm->total_time / (double)NSEC_PER_USEC);
 
        if (kvm->lost_events)
                pr_info("\nLost events: %" PRIu64 "\n\n", kvm->lost_events);
index ee5b42173ba374e066551f32eba24be8c863aebc..f87996b0cb299636e5803a699710be944d3924e3 100644 (file)
@@ -326,6 +326,11 @@ static int perf_add_probe_events(struct perf_probe_event *pevs, int npevs)
        if (ret < 0)
                goto out_cleanup;
 
+       if (params.command == 'D') {    /* it shows definition */
+               ret = show_probe_trace_events(pevs, npevs);
+               goto out_cleanup;
+       }
+
        ret = apply_perf_probe_events(pevs, npevs);
        if (ret < 0)
                goto out_cleanup;
@@ -454,6 +459,14 @@ out:
        return ret;
 }
 
+#ifdef HAVE_DWARF_SUPPORT
+#define PROBEDEF_STR   \
+       "[EVENT=]FUNC[@SRC][+OFF|%return|:RL|;PT]|SRC:AL|SRC;PT [[NAME=]ARG ...]"
+#else
+#define PROBEDEF_STR   "[EVENT=]FUNC[+OFF|%return] [[NAME=]ARG ...]"
+#endif
+
+
 static int
 __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
 {
@@ -479,13 +492,7 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
                             opt_set_filter_with_command, DEFAULT_LIST_FILTER),
        OPT_CALLBACK('d', "del", NULL, "[GROUP:]EVENT", "delete a probe event.",
                     opt_set_filter_with_command),
-       OPT_CALLBACK('a', "add", NULL,
-#ifdef HAVE_DWARF_SUPPORT
-               "[EVENT=]FUNC[@SRC][+OFF|%return|:RL|;PT]|SRC:AL|SRC;PT"
-               " [[NAME=]ARG ...]",
-#else
-               "[EVENT=]FUNC[+OFF|%return] [[NAME=]ARG ...]",
-#endif
+       OPT_CALLBACK('a', "add", NULL, PROBEDEF_STR,
                "probe point definition, where\n"
                "\t\tGROUP:\tGroup name (optional)\n"
                "\t\tEVENT:\tEvent name\n"
@@ -503,6 +510,9 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
                "\t\tARG:\tProbe argument (kprobe-tracer argument format.)\n",
 #endif
                opt_add_probe_event),
+       OPT_CALLBACK('D', "definition", NULL, PROBEDEF_STR,
+               "Show trace event definition of given traceevent for k/uprobe_events.",
+               opt_add_probe_event),
        OPT_BOOLEAN('f', "force", &probe_conf.force_add, "forcibly add events"
                    " with existing name"),
        OPT_CALLBACK('L', "line", NULL,
@@ -548,6 +558,7 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
 
        set_option_flag(options, 'a', "add", PARSE_OPT_EXCLUSIVE);
        set_option_flag(options, 'd', "del", PARSE_OPT_EXCLUSIVE);
+       set_option_flag(options, 'D', "definition", PARSE_OPT_EXCLUSIVE);
        set_option_flag(options, 'l', "list", PARSE_OPT_EXCLUSIVE);
 #ifdef HAVE_DWARF_SUPPORT
        set_option_flag(options, 'L', "line", PARSE_OPT_EXCLUSIVE);
@@ -600,6 +611,14 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
         */
        symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL);
 
+       /*
+        * Except for --list, --del and --add, other command doesn't depend
+        * nor change running kernel. So if user gives offline vmlinux,
+        * ignore its buildid.
+        */
+       if (!strchr("lda", params.command) && symbol_conf.vmlinux_name)
+               symbol_conf.ignore_vmlinux_buildid = true;
+
        switch (params.command) {
        case 'l':
                if (params.uprobes) {
@@ -643,7 +662,9 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
                        return ret;
                }
                break;
+       case 'D':
        case 'a':
+
                /* Ensure the last given target is used */
                if (params.target && !params.target_used) {
                        pr_err("  Error: -x/-m must follow the probe definitions.\n");
index 6355902fbfc8a28137335c49450ca4cf27a21ddb..03251c7f14ecca1dcc2477333f743f6f89ad8dff 100644 (file)
@@ -42,7 +42,7 @@
 #include <sched.h>
 #include <sys/mman.h>
 #include <asm/bug.h>
-
+#include <linux/time64.h>
 
 struct record {
        struct perf_tool        tool;
@@ -96,7 +96,7 @@ backward_rb_find_range(void *buf, int mask, u64 head, u64 *start, u64 *end)
        *start = head;
        while (true) {
                if (evt_head - head >= (unsigned int)size) {
-                       pr_debug("Finshed reading backward ring buffer: rewind\n");
+                       pr_debug("Finished reading backward ring buffer: rewind\n");
                        if (evt_head - head > (unsigned int)size)
                                evt_head -= pheader->size;
                        *end = evt_head;
@@ -106,7 +106,7 @@ backward_rb_find_range(void *buf, int mask, u64 head, u64 *start, u64 *end)
                pheader = (struct perf_event_header *)(buf + (evt_head & mask));
 
                if (pheader->size == 0) {
-                       pr_debug("Finshed reading backward ring buffer: get start\n");
+                       pr_debug("Finished reading backward ring buffer: get start\n");
                        *end = evt_head;
                        return 0;
                }
@@ -954,7 +954,7 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
        }
 
        if (opts->initial_delay) {
-               usleep(opts->initial_delay * 1000);
+               usleep(opts->initial_delay * USEC_PER_MSEC);
                perf_evlist__enable(rec->evlist);
        }
 
index 949e5a15c960e2ef190cc97217df29d561c73777..6e88460cd13d3d65ad54f18470a1e8d7e445b06d 100644 (file)
@@ -89,6 +89,10 @@ static int report__config(const char *var, const char *value, void *cb)
                rep->queue_size = perf_config_u64(var, value);
                return 0;
        }
+       if (!strcmp(var, "report.sort_order")) {
+               default_sort_order = strdup(value);
+               return 0;
+       }
 
        return 0;
 }
@@ -931,7 +935,6 @@ repeat:
 
        if (symbol_conf.report_hierarchy) {
                /* disable incompatible options */
-               symbol_conf.event_group = false;
                symbol_conf.cumulate_callchain = false;
 
                if (field_order) {
@@ -980,9 +983,9 @@ repeat:
         * implementation.
         */
        if (ui__has_annotation()) {
-               symbol_conf.priv_size = sizeof(struct annotation);
-               machines__set_symbol_filter(&session->machines,
-                                           symbol__annotate_init);
+               ret = symbol__annotation_init();
+               if (ret < 0)
+                       goto error;
                /*
                 * For searching by name on the "Browse map details".
                 * providing it only in verbose mode not to bloat too
index 0dfe8df2ab9b237b2530bbb4c81967b9eac6a689..f5503ca22e1c514493567fa0e785073c23de96ee 100644 (file)
@@ -26,6 +26,7 @@
 #include <pthread.h>
 #include <math.h>
 #include <api/fs/fs.h>
+#include <linux/time64.h>
 
 #define PR_SET_NAME            15               /* Set process name */
 #define MAX_CPUS               4096
@@ -199,7 +200,7 @@ static u64 get_nsecs(void)
 
        clock_gettime(CLOCK_MONOTONIC, &ts);
 
-       return ts.tv_sec * 1000000000ULL + ts.tv_nsec;
+       return ts.tv_sec * NSEC_PER_SEC + ts.tv_nsec;
 }
 
 static void burn_nsecs(struct perf_sched *sched, u64 nsecs)
@@ -223,7 +224,7 @@ static void sleep_nsecs(u64 nsecs)
 
 static void calibrate_run_measurement_overhead(struct perf_sched *sched)
 {
-       u64 T0, T1, delta, min_delta = 1000000000ULL;
+       u64 T0, T1, delta, min_delta = NSEC_PER_SEC;
        int i;
 
        for (i = 0; i < 10; i++) {
@@ -240,7 +241,7 @@ static void calibrate_run_measurement_overhead(struct perf_sched *sched)
 
 static void calibrate_sleep_measurement_overhead(struct perf_sched *sched)
 {
-       u64 T0, T1, delta, min_delta = 1000000000ULL;
+       u64 T0, T1, delta, min_delta = NSEC_PER_SEC;
        int i;
 
        for (i = 0; i < 10; i++) {
@@ -452,8 +453,8 @@ static u64 get_cpu_usage_nsec_parent(void)
        err = getrusage(RUSAGE_SELF, &ru);
        BUG_ON(err);
 
-       sum =  ru.ru_utime.tv_sec*1e9 + ru.ru_utime.tv_usec*1e3;
-       sum += ru.ru_stime.tv_sec*1e9 + ru.ru_stime.tv_usec*1e3;
+       sum =  ru.ru_utime.tv_sec * NSEC_PER_SEC + ru.ru_utime.tv_usec * NSEC_PER_USEC;
+       sum += ru.ru_stime.tv_sec * NSEC_PER_SEC + ru.ru_stime.tv_usec * NSEC_PER_USEC;
 
        return sum;
 }
@@ -667,12 +668,12 @@ static void run_one_test(struct perf_sched *sched)
                sched->run_avg = delta;
        sched->run_avg = (sched->run_avg * (sched->replay_repeat - 1) + delta) / sched->replay_repeat;
 
-       printf("#%-3ld: %0.3f, ", sched->nr_runs, (double)delta / 1000000.0);
+       printf("#%-3ld: %0.3f, ", sched->nr_runs, (double)delta / NSEC_PER_MSEC);
 
-       printf("ravg: %0.2f, ", (double)sched->run_avg / 1e6);
+       printf("ravg: %0.2f, ", (double)sched->run_avg / NSEC_PER_MSEC);
 
        printf("cpu: %0.2f / %0.2f",
-               (double)sched->cpu_usage / 1e6, (double)sched->runavg_cpu_usage / 1e6);
+               (double)sched->cpu_usage / NSEC_PER_MSEC, (double)sched->runavg_cpu_usage / NSEC_PER_MSEC);
 
 #if 0
        /*
@@ -680,8 +681,8 @@ static void run_one_test(struct perf_sched *sched)
         * accurate than the sched->sum_exec_runtime based statistics:
         */
        printf(" [%0.2f / %0.2f]",
-               (double)sched->parent_cpu_usage/1e6,
-               (double)sched->runavg_parent_cpu_usage/1e6);
+               (double)sched->parent_cpu_usage / NSEC_PER_MSEC,
+               (double)sched->runavg_parent_cpu_usage / NSEC_PER_MSEC);
 #endif
 
        printf("\n");
@@ -696,13 +697,13 @@ static void test_calibrations(struct perf_sched *sched)
        u64 T0, T1;
 
        T0 = get_nsecs();
-       burn_nsecs(sched, 1e6);
+       burn_nsecs(sched, NSEC_PER_MSEC);
        T1 = get_nsecs();
 
        printf("the run test took %" PRIu64 " nsecs\n", T1 - T0);
 
        T0 = get_nsecs();
-       sleep_nsecs(1e6);
+       sleep_nsecs(NSEC_PER_MSEC);
        T1 = get_nsecs();
 
        printf("the sleep test took %" PRIu64 " nsecs\n", T1 - T0);
@@ -1213,10 +1214,10 @@ static void output_lat_thread(struct perf_sched *sched, struct work_atoms *work_
        avg = work_list->total_lat / work_list->nb_atoms;
 
        printf("|%11.3f ms |%9" PRIu64 " | avg:%9.3f ms | max:%9.3f ms | max at: %13.6f s\n",
-             (double)work_list->total_runtime / 1e6,
-                work_list->nb_atoms, (double)avg / 1e6,
-                (double)work_list->max_lat / 1e6,
-                (double)work_list->max_lat_at / 1e9);
+             (double)work_list->total_runtime / NSEC_PER_MSEC,
+                work_list->nb_atoms, (double)avg / NSEC_PER_MSEC,
+                (double)work_list->max_lat / NSEC_PER_MSEC,
+                (double)work_list->max_lat_at / NSEC_PER_SEC);
 }
 
 static int pid_cmp(struct work_atoms *l, struct work_atoms *r)
@@ -1491,7 +1492,7 @@ static int map_switch_event(struct perf_sched *sched, struct perf_evsel *evsel,
        if (sched->map.cpus && !cpu_map__has(sched->map.cpus, this_cpu))
                goto out;
 
-       color_fprintf(stdout, color, "  %12.6f secs ", (double)timestamp/1e9);
+       color_fprintf(stdout, color, "  %12.6f secs ", (double)timestamp / NSEC_PER_SEC);
        if (new_shortname) {
                const char *pid_color = color;
 
@@ -1753,7 +1754,7 @@ static int perf_sched__lat(struct perf_sched *sched)
 
        printf(" -----------------------------------------------------------------------------------------------------------------\n");
        printf("  TOTAL:                |%11.3f ms |%9" PRIu64 " |\n",
-               (double)sched->all_runtime / 1e6, sched->all_count);
+               (double)sched->all_runtime / NSEC_PER_MSEC, sched->all_count);
 
        printf(" ---------------------------------------------------\n");
 
index c859e59dfe3e7efae711fa056967c910a987d989..7228d141a789d8d50dd4386df0e38e9bba7e9183 100644 (file)
@@ -24,6 +24,7 @@
 #include "util/thread-stack.h"
 #include <linux/bitmap.h>
 #include <linux/stringify.h>
+#include <linux/time64.h>
 #include "asm/bug.h"
 #include "util/mem-events.h"
 
@@ -464,9 +465,9 @@ static void print_sample_start(struct perf_sample *sample,
 
        if (PRINT_FIELD(TIME)) {
                nsecs = sample->time;
-               secs = nsecs / NSECS_PER_SEC;
-               nsecs -= secs * NSECS_PER_SEC;
-               usecs = nsecs / NSECS_PER_USEC;
+               secs = nsecs / NSEC_PER_SEC;
+               nsecs -= secs * NSEC_PER_SEC;
+               usecs = nsecs / NSEC_PER_USEC;
                if (nanosecs)
                        printf("%5lu.%09llu: ", secs, nsecs);
                else
@@ -521,11 +522,11 @@ static void print_sample_brstacksym(struct perf_sample *sample,
 
                thread__find_addr_map(thread, sample->cpumode, MAP__FUNCTION, from, &alf);
                if (alf.map)
-                       alf.sym = map__find_symbol(alf.map, alf.addr, NULL);
+                       alf.sym = map__find_symbol(alf.map, alf.addr);
 
                thread__find_addr_map(thread, sample->cpumode, MAP__FUNCTION, to, &alt);
                if (alt.map)
-                       alt.sym = map__find_symbol(alt.map, alt.addr, NULL);
+                       alt.sym = map__find_symbol(alt.map, alt.addr);
 
                symbol__fprintf_symname_offs(alf.sym, &alf, stdout);
                putchar('/');
index 3c7452b39f57649b05d675db3d19395fb765df2d..90882b1d6a915db8288d5705e88c277e3e8be0cc 100644 (file)
@@ -65,6 +65,7 @@
 #include "util/group.h"
 #include "asm/bug.h"
 
+#include <linux/time64.h>
 #include <api/fs/fs.h>
 #include <stdlib.h>
 #include <sys/prctl.h>
@@ -172,7 +173,7 @@ static inline void diff_timespec(struct timespec *r, struct timespec *a,
 {
        r->tv_sec = a->tv_sec - b->tv_sec;
        if (a->tv_nsec < b->tv_nsec) {
-               r->tv_nsec = a->tv_nsec + 1000000000L - b->tv_nsec;
+               r->tv_nsec = a->tv_nsec + NSEC_PER_SEC - b->tv_nsec;
                r->tv_sec--;
        } else {
                r->tv_nsec = a->tv_nsec - b->tv_nsec ;
@@ -354,7 +355,7 @@ static void process_interval(void)
        diff_timespec(&rs, &ts, &ref_time);
 
        if (STAT_RECORD) {
-               if (WRITE_STAT_ROUND_EVENT(rs.tv_sec * NSECS_PER_SEC + rs.tv_nsec, INTERVAL))
+               if (WRITE_STAT_ROUND_EVENT(rs.tv_sec * NSEC_PER_SEC + rs.tv_nsec, INTERVAL))
                        pr_err("failed to write stat round event\n");
        }
 
@@ -364,7 +365,7 @@ static void process_interval(void)
 static void enable_counters(void)
 {
        if (initial_delay)
-               usleep(initial_delay * 1000);
+               usleep(initial_delay * USEC_PER_MSEC);
 
        /*
         * We need to enable counters only if:
@@ -541,8 +542,8 @@ static int __run_perf_stat(int argc, const char **argv)
        bool is_pipe = STAT_RECORD ? perf_stat.file.is_pipe : false;
 
        if (interval) {
-               ts.tv_sec  = interval / 1000;
-               ts.tv_nsec = (interval % 1000) * 1000000;
+               ts.tv_sec  = interval / USEC_PER_MSEC;
+               ts.tv_nsec = (interval % USEC_PER_MSEC) * NSEC_PER_MSEC;
        } else {
                ts.tv_sec  = 1;
                ts.tv_nsec = 0;
@@ -971,7 +972,7 @@ static void print_metric_header(void *ctx, const char *color __maybe_unused,
 static void nsec_printout(int id, int nr, struct perf_evsel *evsel, double avg)
 {
        FILE *output = stat_config.output;
-       double msecs = avg / 1e6;
+       double msecs = avg / NSEC_PER_MSEC;
        const char *fmt_v, *fmt_n;
        char name[25];
 
@@ -1460,7 +1461,7 @@ static void print_footer(void)
        if (!null_run)
                fprintf(output, "\n");
        fprintf(output, " %17.9f seconds time elapsed",
-                       avg_stats(&walltime_nsecs_stats)/1e9);
+                       avg_stats(&walltime_nsecs_stats) / NSEC_PER_SEC);
        if (run_count > 1) {
                fprintf(output, "                                        ");
                print_noise_pct(stddev_stats(&walltime_nsecs_stats),
@@ -2175,8 +2176,8 @@ static int process_stat_round_event(struct perf_tool *tool __maybe_unused,
                update_stats(&walltime_nsecs_stats, stat_round->time);
 
        if (stat_config.interval && stat_round->time) {
-               tsh.tv_sec  = stat_round->time / NSECS_PER_SEC;
-               tsh.tv_nsec = stat_round->time % NSECS_PER_SEC;
+               tsh.tv_sec  = stat_round->time / NSEC_PER_SEC;
+               tsh.tv_nsec = stat_round->time % NSEC_PER_SEC;
                ts = &tsh;
        }
 
index 733a55422d030037ab1c84bbf4b351c45074cd2c..e7eaa298d34a1ec020a123ade8296451ffe30b73 100644 (file)
@@ -24,6 +24,7 @@
 #include "util/evlist.h"
 #include "util/evsel.h"
 #include <linux/rbtree.h>
+#include <linux/time64.h>
 #include "util/symbol.h"
 #include "util/callchain.h"
 #include "util/strlist.h"
@@ -1288,9 +1289,9 @@ static void draw_process_bars(struct timechart *tchart)
                        if (c->comm) {
                                char comm[256];
                                if (c->total_time > 5000000000) /* 5 seconds */
-                                       sprintf(comm, "%s:%i (%2.2fs)", c->comm, p->pid, c->total_time / 1000000000.0);
+                                       sprintf(comm, "%s:%i (%2.2fs)", c->comm, p->pid, c->total_time / (double)NSEC_PER_SEC);
                                else
-                                       sprintf(comm, "%s:%i (%3.1fms)", c->comm, p->pid, c->total_time / 1000000.0);
+                                       sprintf(comm, "%s:%i (%3.1fms)", c->comm, p->pid, c->total_time / (double)NSEC_PER_MSEC);
 
                                svg_text(Y, c->start_time, comm);
                        }
@@ -1637,7 +1638,7 @@ static int __cmd_timechart(struct timechart *tchart, const char *output_name)
        write_svg_file(tchart, output_name);
 
        pr_info("Written %2.1f seconds of trace to %s.\n",
-               (tchart->last_time - tchart->first_time) / 1000000000.0, output_name);
+               (tchart->last_time - tchart->first_time) / (double)NSEC_PER_SEC, output_name);
 out_delete:
        perf_session__delete(session);
        return ret;
@@ -1901,10 +1902,10 @@ parse_time(const struct option *opt, const char *arg, int __maybe_unused unset)
        if (sscanf(arg, "%" PRIu64 "%cs", value, &unit) > 0) {
                switch (unit) {
                case 'm':
-                       *value *= 1000000;
+                       *value *= NSEC_PER_MSEC;
                        break;
                case 'u':
-                       *value *= 1000;
+                       *value *= NSEC_PER_USEC;
                        break;
                case 'n':
                        break;
@@ -1928,7 +1929,7 @@ int cmd_timechart(int argc, const char **argv,
                        .ordered_events  = true,
                },
                .proc_num = 15,
-               .min_time = 1000000,
+               .min_time = NSEC_PER_MSEC,
                .merge_dist = 1000,
        };
        const char *output_name = "output.svg";
index 418ed94756d357f5101713945ae37b77178acb38..40078570256640c5268fbd5c8d2a450960e95924 100644 (file)
@@ -68,6 +68,7 @@
 #include <sys/mman.h>
 
 #include <linux/stringify.h>
+#include <linux/time64.h>
 #include <linux/types.h>
 
 static volatile int done;
@@ -624,7 +625,7 @@ static void *display_thread(void *arg)
        display_setup_sig();
        pthread__unblock_sigwinch();
 repeat:
-       delay_msecs = top->delay_secs * 1000;
+       delay_msecs = top->delay_secs * MSEC_PER_SEC;
        set_term_quiet_input(&save);
        /* trash return*/
        getc(stdin);
@@ -656,34 +657,6 @@ repeat:
        return NULL;
 }
 
-static int symbol_filter(struct map *map, struct symbol *sym)
-{
-       const char *name = sym->name;
-
-       if (!__map__is_kernel(map))
-               return 0;
-       /*
-        * ppc64 uses function descriptors and appends a '.' to the
-        * start of every instruction address. Remove it.
-        */
-       if (name[0] == '.')
-               name++;
-
-       if (!strcmp(name, "_text") ||
-           !strcmp(name, "_etext") ||
-           !strcmp(name, "_sinittext") ||
-           !strncmp("init_module", name, 11) ||
-           !strncmp("cleanup_module", name, 14) ||
-           strstr(name, "_text_start") ||
-           strstr(name, "_text_end"))
-               return 1;
-
-       if (symbol__is_idle(sym))
-               sym->ignore = true;
-
-       return 0;
-}
-
 static int hist_iter__top_callback(struct hist_entry_iter *iter,
                                   struct addr_location *al, bool single,
                                   void *arg)
@@ -782,7 +755,7 @@ static void perf_event__process_sample(struct perf_tool *tool,
                }
        }
 
-       if (al.sym == NULL || !al.sym->ignore) {
+       if (al.sym == NULL || !al.sym->idle) {
                struct hists *hists = evsel__hists(evsel);
                struct hist_entry_iter iter = {
                        .evsel          = evsel,
@@ -948,8 +921,6 @@ static int __cmd_top(struct perf_top *top)
        if (top->session == NULL)
                return -1;
 
-       machines__set_symbol_filter(&top->session->machines, symbol_filter);
-
        if (!objdump_path) {
                ret = perf_env__lookup_objdump(&top->session->header.env);
                if (ret)
@@ -1323,7 +1294,9 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
        if (symbol_conf.cumulate_callchain && !callchain_param.order_set)
                callchain_param.order = ORDER_CALLER;
 
-       symbol_conf.priv_size = sizeof(struct annotation);
+       status = symbol__annotation_init();
+       if (status < 0)
+               goto out_delete_evlist;
 
        symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL);
        if (symbol__init(NULL) < 0)
index b8c6766301db90ddbe1dfa1fb65d2ab0a024ecc7..b4fc1ab3d2a706b3b684d3699988fcb7bd663900 100644 (file)
@@ -45,6 +45,7 @@
 #include <linux/audit.h>
 #include <linux/random.h>
 #include <linux/stringify.h>
+#include <linux/time64.h>
 
 #ifndef O_CLOEXEC
 # define O_CLOEXEC             02000000
index 7ed72a475c57b217ff88504fd2903496f2daf25c..e4b717e9eb6cf532c2d9c823c1b8f71e8da4256b 100644 (file)
@@ -20,7 +20,6 @@
 #endif
 
 #ifdef __powerpc__
-#include "../../arch/powerpc/include/uapi/asm/unistd.h"
 #define CPUINFO_PROC   {"cpu"}
 #endif
 
index cb0f1356ff8149b4d0790e3d181cd6802f6886f0..9a0236a4cf95fb7226af43e33b88e351359b8a2b 100644 (file)
@@ -14,13 +14,6 @@ void test_attr__open(struct perf_event_attr *attr, pid_t pid, int cpu,
 #define HAVE_ATTR_TEST
 #include "perf-sys.h"
 
-#ifndef NSEC_PER_SEC
-# define NSEC_PER_SEC                  1000000000ULL
-#endif
-#ifndef NSEC_PER_USEC
-# define NSEC_PER_USEC                 1000ULL
-#endif
-
 static inline unsigned long long rdclock(void)
 {
        struct timespec ts;
index 615780cbfe1d86dce93bc4dfb60e6850a42797b0..e6d1816e431a9c3bd0839db29dd8b231c40b8455 100644 (file)
@@ -97,7 +97,7 @@ int test__backward_ring_buffer(int subtest __maybe_unused)
 
        evlist = perf_evlist__new();
        if (!evlist) {
-               pr_debug("No ehough memory to create evlist\n");
+               pr_debug("No enough memory to create evlist\n");
                return TEST_FAIL;
        }
 
index fc54064b91860edf0b1d173f1c05eee2bac4762c..2673e86ed50fad3496e1b50c7770142e21d6d32c 100644 (file)
@@ -125,7 +125,7 @@ static int do_test(struct bpf_object *obj, int (*func)(void),
        /* Instead of perf_evlist__new_default, don't add default events */
        evlist = perf_evlist__new();
        if (!evlist) {
-               pr_debug("No ehough memory to create evlist\n");
+               pr_debug("No enough memory to create evlist\n");
                return TEST_FAIL;
        }
 
index 2af156a8d4e5d9a1fe5ebfcc435f0c5540f17399..ff5bc6363a79de05084aca11ec856f468ce9903d 100644 (file)
@@ -263,7 +263,7 @@ static int read_object_code(u64 addr, size_t len, u8 cpumode,
         * Converting addresses for use by objdump requires more information.
         * map__load() does that.  See map__rip_2objdump() for details.
         */
-       if (map__load(al.map, NULL))
+       if (map__load(al.map))
                return -1;
 
        /* objdump struggles with kcore - try each map only once */
@@ -511,7 +511,7 @@ static int do_test_code_reading(bool try_kcore)
 
        /* Load kernel map */
        map = machine__kernel_map(machine);
-       ret = map__load(map, NULL);
+       ret = map__load(map);
        if (ret < 0) {
                pr_debug("map__load failed\n");
                goto out_err;
index e63abab7d5a17c1f283b3a90a68e19918edf420d..a5082331f2464929ed4ff6d3cae9869c41b1772e 100644 (file)
@@ -8,14 +8,6 @@
 #include "debug.h"
 #include "machine.h"
 
-static int vmlinux_matches_kallsyms_filter(struct map *map __maybe_unused,
-                                          struct symbol *sym)
-{
-       bool *visited = symbol__priv(sym);
-       *visited = true;
-       return 0;
-}
-
 #define UM(x) kallsyms_map->unmap_ip(kallsyms_map, (x))
 
 int test__vmlinux_matches_kallsyms(int subtest __maybe_unused)
@@ -28,6 +20,7 @@ int test__vmlinux_matches_kallsyms(int subtest __maybe_unused)
        enum map_type type = MAP__FUNCTION;
        struct maps *maps = &vmlinux.kmaps.maps[type];
        u64 mem_start, mem_end;
+       bool header_printed;
 
        /*
         * Step 1:
@@ -61,7 +54,7 @@ int test__vmlinux_matches_kallsyms(int subtest __maybe_unused)
         * be compacted against the list of modules found in the "vmlinux"
         * code and with the one got from /proc/modules from the "kallsyms" code.
         */
-       if (__machine__load_kallsyms(&kallsyms, "/proc/kallsyms", type, true, NULL) <= 0) {
+       if (__machine__load_kallsyms(&kallsyms, "/proc/kallsyms", type, true) <= 0) {
                pr_debug("dso__load_kallsyms ");
                goto out;
        }
@@ -99,8 +92,7 @@ int test__vmlinux_matches_kallsyms(int subtest __maybe_unused)
         * maps__reloc_vmlinux will notice and set proper ->[un]map_ip routines
         * to fixup the symbols.
         */
-       if (machine__load_vmlinux_path(&vmlinux, type,
-                                      vmlinux_matches_kallsyms_filter) <= 0) {
+       if (machine__load_vmlinux_path(&vmlinux, type) <= 0) {
                pr_debug("Couldn't find a vmlinux that matches the kernel running on this machine, skipping test\n");
                err = TEST_SKIP;
                goto out;
@@ -126,7 +118,7 @@ int test__vmlinux_matches_kallsyms(int subtest __maybe_unused)
                mem_end = vmlinux_map->unmap_ip(vmlinux_map, sym->end);
 
                first_pair = machine__find_kernel_symbol(&kallsyms, type,
-                                                        mem_start, NULL, NULL);
+                                                        mem_start, NULL);
                pair = first_pair;
 
                if (pair && UM(pair->start) == mem_start) {
@@ -143,7 +135,7 @@ next_pair:
                                 */
                                s64 skew = mem_end - UM(pair->end);
                                if (llabs(skew) >= page_size)
-                                       pr_debug("%#" PRIx64 ": diff end addr for %s v: %#" PRIx64 " k: %#" PRIx64 "\n",
+                                       pr_debug("WARN: %#" PRIx64 ": diff end addr for %s v: %#" PRIx64 " k: %#" PRIx64 "\n",
                                                 mem_start, sym->name, mem_end,
                                                 UM(pair->end));
 
@@ -154,22 +146,23 @@ next_pair:
                                 * kallsyms.
                                 */
                                continue;
-
                        } else {
-                               pair = machine__find_kernel_symbol_by_name(&kallsyms, type, sym->name, NULL, NULL);
+                               pair = machine__find_kernel_symbol_by_name(&kallsyms, type, sym->name, NULL);
                                if (pair) {
                                        if (UM(pair->start) == mem_start)
                                                goto next_pair;
 
-                                       pr_debug("%#" PRIx64 ": diff name v: %s k: %s\n",
+                                       pr_debug("WARN: %#" PRIx64 ": diff name v: %s k: %s\n",
                                                 mem_start, sym->name, pair->name);
                                } else {
-                                       pr_debug("%#" PRIx64 ": diff name v: %s k: %s\n",
+                                       pr_debug("WARN: %#" PRIx64 ": diff name v: %s k: %s\n",
                                                 mem_start, sym->name, first_pair->name);
                                }
+
+                               continue;
                        }
                } else
-                       pr_debug("%#" PRIx64 ": %s not on kallsyms\n",
+                       pr_debug("ERR : %#" PRIx64 ": %s not on kallsyms\n",
                                 mem_start, sym->name);
 
                err = -1;
@@ -178,7 +171,7 @@ next_pair:
        if (!verbose)
                goto out;
 
-       pr_info("Maps only in vmlinux:\n");
+       header_printed = false;
 
        for (map = maps__first(maps); map; map = map__next(map)) {
                struct map *
@@ -192,13 +185,18 @@ next_pair:
                                                (map->dso->kernel ?
                                                        map->dso->short_name :
                                                        map->dso->name));
-               if (pair)
+               if (pair) {
                        pair->priv = 1;
-               else
+               } else {
+                       if (!header_printed) {
+                               pr_info("WARN: Maps only in vmlinux:\n");
+                               header_printed = true;
+                       }
                        map__fprintf(map, stderr);
+               }
        }
 
-       pr_info("Maps in vmlinux with a different name in kallsyms:\n");
+       header_printed = false;
 
        for (map = maps__first(maps); map; map = map__next(map)) {
                struct map *pair;
@@ -211,24 +209,33 @@ next_pair:
                        continue;
 
                if (pair->start == mem_start) {
-                       pair->priv = 1;
-                       pr_info(" %" PRIx64 "-%" PRIx64 " %" PRIx64 " %s in kallsyms as",
+                       if (!header_printed) {
+                               pr_info("WARN: Maps in vmlinux with a different name in kallsyms:\n");
+                               header_printed = true;
+                       }
+
+                       pr_info("WARN: %" PRIx64 "-%" PRIx64 " %" PRIx64 " %s in kallsyms as",
                                map->start, map->end, map->pgoff, map->dso->name);
                        if (mem_end != pair->end)
-                               pr_info(":\n*%" PRIx64 "-%" PRIx64 " %" PRIx64,
+                               pr_info(":\nWARN: *%" PRIx64 "-%" PRIx64 " %" PRIx64,
                                        pair->start, pair->end, pair->pgoff);
                        pr_info(" %s\n", pair->dso->name);
                        pair->priv = 1;
                }
        }
 
-       pr_info("Maps only in kallsyms:\n");
+       header_printed = false;
 
        maps = &kallsyms.kmaps.maps[type];
 
        for (map = maps__first(maps); map; map = map__next(map)) {
-               if (!map->priv)
+               if (!map->priv) {
+                       if (!header_printed) {
+                               pr_info("WARN: Maps only in kallsyms:\n");
+                               header_printed = true;
+                       }
                        map__fprintf(map, stderr);
+               }
        }
 out:
        machine__exit(&kallsyms);
index d0a3a8e402e7483c1b4ef81ee27ff9884d629fba..fd710ab33684e65e6b62acc62ac51b5e12d02b35 100644 (file)
@@ -1,8 +1,4 @@
-#include <sys/mman.h>
-
-#ifndef PROT_SEM
-#define PROT_SEM 0x8
-#endif
+#include <uapi/linux/mman.h>
 
 static size_t syscall_arg__scnprintf_mmap_prot(char *bf, size_t size,
                                               struct syscall_arg *arg)
@@ -33,31 +29,6 @@ static size_t syscall_arg__scnprintf_mmap_prot(char *bf, size_t size,
 
 #define SCA_MMAP_PROT syscall_arg__scnprintf_mmap_prot
 
-#ifndef MAP_FIXED
-#define MAP_FIXED                   0x10
-#endif
-
-#ifndef MAP_ANONYMOUS
-#define MAP_ANONYMOUS               0x20
-#endif
-
-#ifndef MAP_32BIT
-#define MAP_32BIT                   0x40
-#endif
-
-#ifndef MAP_STACK
-#define MAP_STACK                0x20000
-#endif
-
-#ifndef MAP_HUGETLB
-#define MAP_HUGETLB              0x40000
-#endif
-
-#ifndef MAP_UNINITIALIZED
-#define MAP_UNINITIALIZED      0x4000000
-#endif
-
-
 static size_t syscall_arg__scnprintf_mmap_flags(char *bf, size_t size,
                                                struct syscall_arg *arg)
 {
@@ -95,13 +66,6 @@ static size_t syscall_arg__scnprintf_mmap_flags(char *bf, size_t size,
 
 #define SCA_MMAP_FLAGS syscall_arg__scnprintf_mmap_flags
 
-#ifndef MREMAP_MAYMOVE
-#define MREMAP_MAYMOVE 1
-#endif
-#ifndef MREMAP_FIXED
-#define MREMAP_FIXED 2
-#endif
-
 static size_t syscall_arg__scnprintf_mremap_flags(char *bf, size_t size,
                                                  struct syscall_arg *arg)
 {
@@ -125,39 +89,6 @@ static size_t syscall_arg__scnprintf_mremap_flags(char *bf, size_t size,
 
 #define SCA_MREMAP_FLAGS syscall_arg__scnprintf_mremap_flags
 
-#ifndef MADV_HWPOISON
-#define MADV_HWPOISON          100
-#endif
-
-#ifndef MADV_SOFT_OFFLINE
-#define MADV_SOFT_OFFLINE      101
-#endif
-
-#ifndef MADV_MERGEABLE
-#define MADV_MERGEABLE          12
-#endif
-
-#ifndef MADV_UNMERGEABLE
-#define MADV_UNMERGEABLE        13
-#endif
-
-#ifndef MADV_HUGEPAGE
-#define MADV_HUGEPAGE           14
-#endif
-
-#ifndef MADV_NOHUGEPAGE
-#define MADV_NOHUGEPAGE                 15
-#endif
-
-#ifndef MADV_DONTDUMP
-#define MADV_DONTDUMP           16
-#endif
-
-#ifndef MADV_DODUMP
-#define MADV_DODUMP             17
-#endif
-
-
 static size_t syscall_arg__scnprintf_madvise_behavior(char *bf, size_t size,
                                                      struct syscall_arg *arg)
 {
@@ -170,6 +101,7 @@ static size_t syscall_arg__scnprintf_madvise_behavior(char *bf, size_t size,
        P_MADV_BHV(SEQUENTIAL);
        P_MADV_BHV(WILLNEED);
        P_MADV_BHV(DONTNEED);
+       P_MADV_BHV(FREE);
        P_MADV_BHV(REMOVE);
        P_MADV_BHV(DONTFORK);
        P_MADV_BHV(DOFORK);
index 2e2d10022355ba0303f4462a21758eec773986d0..4c18271c71c9a14458e03624c110f771d2513060 100644 (file)
@@ -495,7 +495,7 @@ static bool annotate_browser__callq(struct annotate_browser *browser,
        if (!ins__is_call(dl->ins))
                return false;
 
-       if (map_groups__find_ams(&target, NULL) ||
+       if (map_groups__find_ams(&target) ||
            map__rip_2objdump(target.map, target.map->map_ip(target.map,
                                                             target.addr)) !=
            dl->ops.target.addr) {
index 13d414384739d9673089958aa2daa56de9a5b255..a6d5d248b8fb3adb0aad10a2e2dd007345041a5e 100644 (file)
@@ -69,8 +69,11 @@ static u32 hist_browser__nr_entries(struct hist_browser *hb)
 static void hist_browser__update_rows(struct hist_browser *hb)
 {
        struct ui_browser *browser = &hb->b;
-       u16 header_offset = hb->show_headers ? 1 : 0, index_row;
+       struct hists *hists = hb->hists;
+       struct perf_hpp_list *hpp_list = hists->hpp_list;
+       u16 header_offset, index_row;
 
+       header_offset = hb->show_headers ? hpp_list->nr_header_lines : 0;
        browser->rows = browser->height - header_offset;
        /*
         * Verify if we were at the last line and that line isn't
@@ -99,8 +102,11 @@ static void hist_browser__refresh_dimensions(struct ui_browser *browser)
 
 static void hist_browser__gotorc(struct hist_browser *browser, int row, int column)
 {
-       u16 header_offset = browser->show_headers ? 1 : 0;
+       struct hists *hists = browser->hists;
+       struct perf_hpp_list *hpp_list = hists->hpp_list;
+       u16 header_offset;
 
+       header_offset = browser->show_headers ? hpp_list->nr_header_lines : 0;
        ui_browser__gotorc(&browser->b, row + header_offset, column);
 }
 
@@ -1091,7 +1097,6 @@ static int __hpp__slsmg_color_printf(struct perf_hpp *hpp, const char *fmt, ...)
        ret = scnprintf(hpp->buf, hpp->size, fmt, len, percent);
        ui_browser__printf(arg->b, "%s", hpp->buf);
 
-       advance_hpp(hpp, ret);
        return ret;
 }
 
@@ -1496,7 +1501,9 @@ static int advance_hpp_check(struct perf_hpp *hpp, int inc)
        return hpp->size <= 0;
 }
 
-static int hists_browser__scnprintf_headers(struct hist_browser *browser, char *buf, size_t size)
+static int
+hists_browser__scnprintf_headers(struct hist_browser *browser, char *buf,
+                                size_t size, int line)
 {
        struct hists *hists = browser->hists;
        struct perf_hpp dummy_hpp = {
@@ -1506,6 +1513,7 @@ static int hists_browser__scnprintf_headers(struct hist_browser *browser, char *
        struct perf_hpp_fmt *fmt;
        size_t ret = 0;
        int column = 0;
+       int span = 0;
 
        if (symbol_conf.use_callchain) {
                ret = scnprintf(buf, size, "  ");
@@ -1517,10 +1525,13 @@ static int hists_browser__scnprintf_headers(struct hist_browser *browser, char *
                if (perf_hpp__should_skip(fmt, hists)  || column++ < browser->b.horiz_scroll)
                        continue;
 
-               ret = fmt->header(fmt, &dummy_hpp, hists);
+               ret = fmt->header(fmt, &dummy_hpp, hists, line, &span);
                if (advance_hpp_check(&dummy_hpp, ret))
                        break;
 
+               if (span)
+                       continue;
+
                ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, "  ");
                if (advance_hpp_check(&dummy_hpp, ret))
                        break;
@@ -1554,7 +1565,7 @@ static int hists_browser__scnprintf_hierarchy_headers(struct hist_browser *brows
                if (column++ < browser->b.horiz_scroll)
                        continue;
 
-               ret = fmt->header(fmt, &dummy_hpp, hists);
+               ret = fmt->header(fmt, &dummy_hpp, hists, 0, NULL);
                if (advance_hpp_check(&dummy_hpp, ret))
                        break;
 
@@ -1591,7 +1602,7 @@ static int hists_browser__scnprintf_hierarchy_headers(struct hist_browser *brows
                        }
                        first_col = false;
 
-                       ret = fmt->header(fmt, &dummy_hpp, hists);
+                       ret = fmt->header(fmt, &dummy_hpp, hists, 0, NULL);
                        dummy_hpp.buf[ret] = '\0';
 
                        start = trim(dummy_hpp.buf);
@@ -1622,14 +1633,21 @@ static void hists_browser__hierarchy_headers(struct hist_browser *browser)
 
 static void hists_browser__headers(struct hist_browser *browser)
 {
-       char headers[1024];
+       struct hists *hists = browser->hists;
+       struct perf_hpp_list *hpp_list = hists->hpp_list;
 
-       hists_browser__scnprintf_headers(browser, headers,
-                                        sizeof(headers));
+       int line;
 
-       ui_browser__gotorc(&browser->b, 0, 0);
-       ui_browser__set_color(&browser->b, HE_COLORSET_ROOT);
-       ui_browser__write_nstring(&browser->b, headers, browser->b.width + 1);
+       for (line = 0; line < hpp_list->nr_header_lines; line++) {
+               char headers[1024];
+
+               hists_browser__scnprintf_headers(browser, headers,
+                                                sizeof(headers), line);
+
+               ui_browser__gotorc(&browser->b, line, 0);
+               ui_browser__set_color(&browser->b, HE_COLORSET_ROOT);
+               ui_browser__write_nstring(&browser->b, headers, browser->b.width + 1);
+       }
 }
 
 static void hist_browser__show_headers(struct hist_browser *browser)
@@ -1656,10 +1674,13 @@ static unsigned int hist_browser__refresh(struct ui_browser *browser)
        u16 header_offset = 0;
        struct rb_node *nd;
        struct hist_browser *hb = container_of(browser, struct hist_browser, b);
+       struct hists *hists = hb->hists;
 
        if (hb->show_headers) {
+               struct perf_hpp_list *hpp_list = hists->hpp_list;
+
                hist_browser__show_headers(hb);
-               header_offset = 1;
+               header_offset = hpp_list->nr_header_lines;
        }
 
        ui_browser__hists_init_top(browser);
@@ -2054,10 +2075,10 @@ void hist_browser__init(struct hist_browser *browser,
        browser->b.use_navkeypressed    = true;
        browser->show_headers           = symbol_conf.show_hist_headers;
 
-       hists__for_each_format(hists, fmt) {
-               perf_hpp__reset_width(fmt, hists);
+       hists__for_each_format(hists, fmt)
                ++browser->b.columns;
-       }
+
+       hists__reset_column_width(hists);
 }
 
 struct hist_browser *hist_browser__new(struct hists *hists)
@@ -2418,8 +2439,6 @@ do_zoom_dso(struct hist_browser *browser, struct popup_action *act)
                browser->hists->dso_filter = NULL;
                ui_helpline__pop();
        } else {
-               if (map == NULL)
-                       return 0;
                ui_helpline__fpush("To zoom out press ESC or ENTER + \"Zoom out of %s DSO\"",
                                   __map__is_kernel(map) ? "the Kernel" : map->dso->short_name);
                browser->hists->dso_filter = map->dso;
index 80912778bb6d5623bd6555fd7f843a84acb1d51a..98a34664bb7eb16667ee7169129e7e5b5b8022db 100644 (file)
@@ -52,9 +52,9 @@ static int map_browser__search(struct map_browser *browser)
 
        if (target[0] == '0' && tolower(target[1]) == 'x') {
                u64 addr = strtoull(target, NULL, 16);
-               sym = map__find_symbol(browser->map, addr, NULL);
+               sym = map__find_symbol(browser->map, addr);
        } else
-               sym = map__find_symbol_by_name(browser->map, target, NULL);
+               sym = map__find_symbol_by_name(browser->map, target);
 
        if (sym != NULL) {
                u32 *idx = symbol__browser_index(sym);
index c5f3677f66797bdbf34c171cfc398009a15b60cd..a4f02de7c1b54d426bb1b3f50b7fc2ba39ae5fa8 100644 (file)
@@ -549,7 +549,7 @@ static void perf_gtk__show_hierarchy(GtkWidget *window, struct hists *hists,
                                strcat(buf, "+");
                        first_col = false;
 
-                       fmt->header(fmt, &hpp, hists);
+                       fmt->header(fmt, &hpp, hists, 0, NULL);
                        strcat(buf, ltrim(rtrim(hpp.buf)));
                }
        }
index 4274969ddc89471e962dcf0097314b73963c65be..60c4a4d08374c0dc2c14614cfab9f05ca53690fc 100644 (file)
@@ -230,7 +230,8 @@ static int hpp__width_fn(struct perf_hpp_fmt *fmt,
 }
 
 static int hpp__header_fn(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
-                         struct hists *hists)
+                         struct hists *hists, int line __maybe_unused,
+                         int *span __maybe_unused)
 {
        int len = hpp__width_fn(fmt, hpp, hists);
        return scnprintf(hpp->buf, hpp->size, "%*s", len, fmt->name);
@@ -441,6 +442,7 @@ struct perf_hpp_fmt perf_hpp__format[] = {
 struct perf_hpp_list perf_hpp_list = {
        .fields = LIST_HEAD_INIT(perf_hpp_list.fields),
        .sorts  = LIST_HEAD_INIT(perf_hpp_list.sorts),
+       .nr_header_lines = 1,
 };
 
 #undef HPP__COLOR_PRINT_FNS
@@ -697,6 +699,21 @@ void perf_hpp__reset_width(struct perf_hpp_fmt *fmt, struct hists *hists)
        }
 }
 
+void hists__reset_column_width(struct hists *hists)
+{
+       struct perf_hpp_fmt *fmt;
+       struct perf_hpp_list_node *node;
+
+       hists__for_each_format(hists, fmt)
+               perf_hpp__reset_width(fmt, hists);
+
+       /* hierarchy entries have their own hpp list */
+       list_for_each_entry(node, &hists->hpp_formats, list) {
+               perf_hpp_list__for_each_format(&node->hpp, fmt)
+                       perf_hpp__reset_width(fmt, hists);
+       }
+}
+
 void perf_hpp__set_user_width(const char *width_list_str)
 {
        struct perf_hpp_fmt *fmt;
index f04a6311207935fc022ca0b9557db8639d6c00a9..8e1840bff29d6ede2110ce2c0482923ce75a9af8 100644 (file)
@@ -528,8 +528,8 @@ static int print_hierarchy_indent(const char *sep, int indent,
        return fprintf(fp, "%-.*s", (indent - 2) * HIERARCHY_INDENT, line);
 }
 
-static int print_hierarchy_header(struct hists *hists, struct perf_hpp *hpp,
-                                 const char *sep, FILE *fp)
+static int hists__fprintf_hierarchy_headers(struct hists *hists,
+                                           struct perf_hpp *hpp, FILE *fp)
 {
        bool first_node, first_col;
        int indent;
@@ -538,6 +538,7 @@ static int print_hierarchy_header(struct hists *hists, struct perf_hpp *hpp,
        unsigned header_width = 0;
        struct perf_hpp_fmt *fmt;
        struct perf_hpp_list_node *fmt_node;
+       const char *sep = symbol_conf.field_sep;
 
        indent = hists->nr_hpp_node;
 
@@ -549,7 +550,7 @@ static int print_hierarchy_header(struct hists *hists, struct perf_hpp *hpp,
                                    struct perf_hpp_list_node, list);
 
        perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
-               fmt->header(fmt, hpp, hists);
+               fmt->header(fmt, hpp, hists, 0, NULL);
                fprintf(fp, "%s%s", hpp->buf, sep ?: "  ");
        }
 
@@ -569,7 +570,7 @@ static int print_hierarchy_header(struct hists *hists, struct perf_hpp *hpp,
                                header_width += fprintf(fp, "+");
                        first_col = false;
 
-                       fmt->header(fmt, hpp, hists);
+                       fmt->header(fmt, hpp, hists, 0, NULL);
 
                        header_width += fprintf(fp, "%s", trim(hpp->buf));
                }
@@ -623,20 +624,28 @@ static int print_hierarchy_header(struct hists *hists, struct perf_hpp *hpp,
        return 2;
 }
 
-static int
-hists__fprintf_hierarchy_headers(struct hists *hists,
-                                struct perf_hpp *hpp,
-                                FILE *fp)
+static void fprintf_line(struct hists *hists, struct perf_hpp *hpp,
+                        int line, FILE *fp)
 {
-       struct perf_hpp_list_node *fmt_node;
        struct perf_hpp_fmt *fmt;
+       const char *sep = symbol_conf.field_sep;
+       bool first = true;
+       int span = 0;
 
-       list_for_each_entry(fmt_node, &hists->hpp_formats, list) {
-               perf_hpp_list__for_each_format(&fmt_node->hpp, fmt)
-                       perf_hpp__reset_width(fmt, hists);
-       }
+       hists__for_each_format(hists, fmt) {
+               if (perf_hpp__should_skip(fmt, hists))
+                       continue;
+
+               if (!first && !span)
+                       fprintf(fp, "%s", sep ?: "  ");
+               else
+                       first = false;
+
+               fmt->header(fmt, hpp, hists, line, &span);
 
-       return print_hierarchy_header(hists, hpp, symbol_conf.field_sep, fp);
+               if (!span)
+                       fprintf(fp, "%s", hpp->buf);
+       }
 }
 
 static int
@@ -644,28 +653,23 @@ hists__fprintf_standard_headers(struct hists *hists,
                                struct perf_hpp *hpp,
                                FILE *fp)
 {
+       struct perf_hpp_list *hpp_list = hists->hpp_list;
        struct perf_hpp_fmt *fmt;
        unsigned int width;
        const char *sep = symbol_conf.field_sep;
        bool first = true;
-
-       hists__for_each_format(hists, fmt) {
-               if (perf_hpp__should_skip(fmt, hists))
-                       continue;
-
-               if (!first)
-                       fprintf(fp, "%s", sep ?: "  ");
-               else
-                       first = false;
-
-               fmt->header(fmt, hpp, hists);
-               fprintf(fp, "%s", hpp->buf);
+       int line;
+
+       for (line = 0; line < hpp_list->nr_header_lines; line++) {
+               /* first # is displayed one level up */
+               if (line)
+                       fprintf(fp, "# ");
+               fprintf_line(hists, hpp, line, fp);
+               fprintf(fp, "\n");
        }
 
-       fprintf(fp, "\n");
-
        if (sep)
-               return 1;
+               return hpp_list->nr_header_lines;
 
        first = true;
 
@@ -689,7 +693,7 @@ hists__fprintf_standard_headers(struct hists *hists,
 
        fprintf(fp, "\n");
        fprintf(fp, "#\n");
-       return 3;
+       return hpp_list->nr_header_lines + 2;
 }
 
 static int hists__fprintf_headers(struct hists *hists, FILE *fp)
@@ -713,7 +717,6 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,
                      int max_cols, float min_pcnt, FILE *fp,
                      bool use_callchain)
 {
-       struct perf_hpp_fmt *fmt;
        struct rb_node *nd;
        size_t ret = 0;
        const char *sep = symbol_conf.field_sep;
@@ -724,8 +727,7 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,
 
        init_rem_hits();
 
-       hists__for_each_format(hists, fmt)
-               perf_hpp__reset_width(fmt, hists);
+       hists__reset_column_width(hists);
 
        if (symbol_conf.col_width_list_str)
                perf_hpp__set_user_width(symbol_conf.col_width_list_str);
index 91c5f6e1af59a23e23013f52d4058dca9825ff7c..96f99d608d0049491cae7cb6d3907390afaee562 100644 (file)
@@ -1,5 +1,6 @@
 libperf-y += alias.o
 libperf-y += annotate.o
+libperf-y += block-range.o
 libperf-y += build-id.o
 libperf-y += config.o
 libperf-y += ctype.o
@@ -98,6 +99,7 @@ endif
 
 libperf-$(CONFIG_DWARF) += probe-finder.o
 libperf-$(CONFIG_DWARF) += dwarf-aux.o
+libperf-$(CONFIG_DWARF) += dwarf-regs.o
 
 libperf-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o
 libperf-$(CONFIG_LOCAL_LIBUNWIND)    += unwind-libunwind-local.o
index 4024d309bb00adaa2dbdb0a6e80afa2e6a5935a9..aeb5a441bd7416744598f7dfa6d18809cf4fa883 100644 (file)
@@ -17,6 +17,7 @@
 #include "debug.h"
 #include "annotate.h"
 #include "evsel.h"
+#include "block-range.h"
 #include <regex.h>
 #include <pthread.h>
 #include <linux/bitops.h>
@@ -53,7 +54,7 @@ int ins__scnprintf(struct ins *ins, char *bf, size_t size,
        return ins__raw_scnprintf(ins, bf, size, ops);
 }
 
-static int call__parse(struct ins_operands *ops)
+static int call__parse(struct ins_operands *ops, struct map *map)
 {
        char *endptr, *tok, *name;
 
@@ -81,16 +82,16 @@ static int call__parse(struct ins_operands *ops)
        return ops->target.name == NULL ? -1 : 0;
 
 indirect_call:
-       tok = strchr(endptr, '(');
-       if (tok != NULL) {
-               ops->target.addr = 0;
+       tok = strchr(endptr, '*');
+       if (tok == NULL) {
+               struct symbol *sym = map__find_symbol(map, map->map_ip(map, ops->target.addr));
+               if (sym != NULL)
+                       ops->target.name = strdup(sym->name);
+               else
+                       ops->target.addr = 0;
                return 0;
        }
 
-       tok = strchr(endptr, '*');
-       if (tok == NULL)
-               return -1;
-
        ops->target.addr = strtoull(tok + 1, NULL, 16);
        return 0;
 }
@@ -117,7 +118,7 @@ bool ins__is_call(const struct ins *ins)
        return ins->ops == &call_ops;
 }
 
-static int jump__parse(struct ins_operands *ops)
+static int jump__parse(struct ins_operands *ops, struct map *map __maybe_unused)
 {
        const char *s = strchr(ops->raw, '+');
 
@@ -172,7 +173,7 @@ static int comment__symbol(char *raw, char *comment, u64 *addrp, char **namep)
        return 0;
 }
 
-static int lock__parse(struct ins_operands *ops)
+static int lock__parse(struct ins_operands *ops, struct map *map)
 {
        char *name;
 
@@ -193,7 +194,7 @@ static int lock__parse(struct ins_operands *ops)
                return 0;
 
        if (ops->locked.ins->ops->parse &&
-           ops->locked.ins->ops->parse(ops->locked.ops) < 0)
+           ops->locked.ins->ops->parse(ops->locked.ops, map) < 0)
                goto out_free_ops;
 
        return 0;
@@ -236,7 +237,7 @@ static struct ins_ops lock_ops = {
        .scnprintf = lock__scnprintf,
 };
 
-static int mov__parse(struct ins_operands *ops)
+static int mov__parse(struct ins_operands *ops, struct map *map __maybe_unused)
 {
        char *s = strchr(ops->raw, ','), *target, *comment, prev;
 
@@ -303,7 +304,7 @@ static struct ins_ops mov_ops = {
        .scnprintf = mov__scnprintf,
 };
 
-static int dec__parse(struct ins_operands *ops)
+static int dec__parse(struct ins_operands *ops, struct map *map __maybe_unused)
 {
        char *target, *comment, *s, prev;
 
@@ -491,13 +492,6 @@ static struct ins *ins__find(const char *name)
        return bsearch(name, instructions, nmemb, sizeof(struct ins), ins__key_cmp);
 }
 
-int symbol__annotate_init(struct map *map __maybe_unused, struct symbol *sym)
-{
-       struct annotation *notes = symbol__annotation(sym);
-       pthread_mutex_init(&notes->lock, NULL);
-       return 0;
-}
-
 int symbol__alloc_hist(struct symbol *sym)
 {
        struct annotation *notes = symbol__annotation(sym);
@@ -715,7 +709,7 @@ int hist_entry__inc_addr_samples(struct hist_entry *he, int evidx, u64 ip)
        return symbol__inc_addr_samples(he->ms.sym, he->ms.map, evidx, ip);
 }
 
-static void disasm_line__init_ins(struct disasm_line *dl)
+static void disasm_line__init_ins(struct disasm_line *dl, struct map *map)
 {
        dl->ins = ins__find(dl->name);
 
@@ -725,7 +719,7 @@ static void disasm_line__init_ins(struct disasm_line *dl)
        if (!dl->ins->ops)
                return;
 
-       if (dl->ins->ops->parse && dl->ins->ops->parse(&dl->ops) < 0)
+       if (dl->ins->ops->parse && dl->ins->ops->parse(&dl->ops, map) < 0)
                dl->ins = NULL;
 }
 
@@ -767,7 +761,8 @@ out_free_name:
 }
 
 static struct disasm_line *disasm_line__new(s64 offset, char *line,
-                                       size_t privsize, int line_nr)
+                                           size_t privsize, int line_nr,
+                                           struct map *map)
 {
        struct disasm_line *dl = zalloc(sizeof(*dl) + privsize);
 
@@ -782,7 +777,7 @@ static struct disasm_line *disasm_line__new(s64 offset, char *line,
                        if (disasm_line__parse(dl->line, &dl->name, &dl->ops.raw) < 0)
                                goto out_free_line;
 
-                       disasm_line__init_ins(dl);
+                       disasm_line__init_ins(dl, map);
                }
        }
 
@@ -866,6 +861,89 @@ double disasm__calc_percent(struct annotation *notes, int evidx, s64 offset,
        return percent;
 }
 
+static const char *annotate__address_color(struct block_range *br)
+{
+       double cov = block_range__coverage(br);
+
+       if (cov >= 0) {
+               /* mark red for >75% coverage */
+               if (cov > 0.75)
+                       return PERF_COLOR_RED;
+
+               /* mark dull for <1% coverage */
+               if (cov < 0.01)
+                       return PERF_COLOR_NORMAL;
+       }
+
+       return PERF_COLOR_MAGENTA;
+}
+
+static const char *annotate__asm_color(struct block_range *br)
+{
+       double cov = block_range__coverage(br);
+
+       if (cov >= 0) {
+               /* mark dull for <1% coverage */
+               if (cov < 0.01)
+                       return PERF_COLOR_NORMAL;
+       }
+
+       return PERF_COLOR_BLUE;
+}
+
+static void annotate__branch_printf(struct block_range *br, u64 addr)
+{
+       bool emit_comment = true;
+
+       if (!br)
+               return;
+
+#if 1
+       if (br->is_target && br->start == addr) {
+               struct block_range *branch = br;
+               double p;
+
+               /*
+                * Find matching branch to our target.
+                */
+               while (!branch->is_branch)
+                       branch = block_range__next(branch);
+
+               p = 100 *(double)br->entry / branch->coverage;
+
+               if (p > 0.1) {
+                       if (emit_comment) {
+                               emit_comment = false;
+                               printf("\t#");
+                       }
+
+                       /*
+                        * The percentage of coverage joined at this target in relation
+                        * to the next branch.
+                        */
+                       printf(" +%.2f%%", p);
+               }
+       }
+#endif
+       if (br->is_branch && br->end == addr) {
+               double p = 100*(double)br->taken / br->coverage;
+
+               if (p > 0.1) {
+                       if (emit_comment) {
+                               emit_comment = false;
+                               printf("\t#");
+                       }
+
+                       /*
+                        * The percentage of coverage leaving at this branch, and
+                        * its prediction ratio.
+                        */
+                       printf(" -%.2f%% (p:%.2f%%)", p, 100*(double)br->pred  / br->taken);
+               }
+       }
+}
+
+
 static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 start,
                      struct perf_evsel *evsel, u64 len, int min_pcnt, int printed,
                      int max_lines, struct disasm_line *queue)
@@ -885,6 +963,7 @@ static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 st
                s64 offset = dl->offset;
                const u64 addr = start + offset;
                struct disasm_line *next;
+               struct block_range *br;
 
                next = disasm__get_next_ip_line(&notes->src->source, dl);
 
@@ -954,8 +1033,12 @@ static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 st
                }
 
                printf(" :      ");
-               color_fprintf(stdout, PERF_COLOR_MAGENTA, "  %" PRIx64 ":", addr);
-               color_fprintf(stdout, PERF_COLOR_BLUE, "%s\n", dl->line);
+
+               br = block_range__find(addr);
+               color_fprintf(stdout, annotate__address_color(br), "  %" PRIx64 ":", addr);
+               color_fprintf(stdout, annotate__asm_color(br), "%s", dl->line);
+               annotate__branch_printf(br, addr);
+               printf("\n");
 
                if (ppercents != &percent)
                        free(ppercents);
@@ -1066,7 +1149,7 @@ static int symbol__parse_objdump_line(struct symbol *sym, struct map *map,
                        parsed_line = tmp2 + 1;
        }
 
-       dl = disasm_line__new(offset, parsed_line, privsize, *line_nr);
+       dl = disasm_line__new(offset, parsed_line, privsize, *line_nr, map);
        free(line);
        (*line_nr)++;
 
@@ -1084,7 +1167,7 @@ static int symbol__parse_objdump_line(struct symbol *sym, struct map *map,
                        .addr = dl->ops.target.addr,
                };
 
-               if (!map_groups__find_ams(&target, NULL) &&
+               if (!map_groups__find_ams(&target) &&
                    target.sym->start == target.al_addr)
                        dl->ops.target.name = strdup(target.sym->name);
        }
@@ -1162,53 +1245,60 @@ int symbol__strerror_disassemble(struct symbol *sym __maybe_unused, struct map *
        return 0;
 }
 
-int symbol__disassemble(struct symbol *sym, struct map *map, size_t privsize)
+static int dso__disassemble_filename(struct dso *dso, char *filename, size_t filename_size)
 {
-       struct dso *dso = map->dso;
-       char *filename = dso__build_id_filename(dso, NULL, 0);
-       bool free_filename = true;
-       char command[PATH_MAX * 2];
-       FILE *file;
-       int err = 0;
-       char symfs_filename[PATH_MAX];
-       struct kcore_extract kce;
-       bool delete_extract = false;
-       int stdout_fd[2];
-       int lineno = 0;
-       int nline;
-       pid_t pid;
+       char linkname[PATH_MAX];
+       char *build_id_filename;
 
-       if (filename)
-               symbol__join_symfs(symfs_filename, filename);
+       if (dso->symtab_type == DSO_BINARY_TYPE__KALLSYMS &&
+           !dso__is_kcore(dso))
+               return SYMBOL_ANNOTATE_ERRNO__NO_VMLINUX;
 
-       if (filename == NULL) {
+       build_id_filename = dso__build_id_filename(dso, NULL, 0);
+       if (build_id_filename) {
+               __symbol__join_symfs(filename, filename_size, build_id_filename);
+               free(build_id_filename);
+       } else {
                if (dso->has_build_id)
                        return ENOMEM;
                goto fallback;
-       } else if (dso__is_kcore(dso) ||
-                  readlink(symfs_filename, command, sizeof(command)) < 0 ||
-                  strstr(command, DSO__NAME_KALLSYMS) ||
-                  access(symfs_filename, R_OK)) {
-               free(filename);
+       }
+
+       if (dso__is_kcore(dso) ||
+           readlink(filename, linkname, sizeof(linkname)) < 0 ||
+           strstr(linkname, DSO__NAME_KALLSYMS) ||
+           access(filename, R_OK)) {
 fallback:
                /*
                 * If we don't have build-ids or the build-id file isn't in the
                 * cache, or is just a kallsyms file, well, lets hope that this
                 * DSO is the same as when 'perf record' ran.
                 */
-               filename = (char *)dso->long_name;
-               symbol__join_symfs(symfs_filename, filename);
-               free_filename = false;
+               __symbol__join_symfs(filename, filename_size, dso->long_name);
        }
 
-       if (dso->symtab_type == DSO_BINARY_TYPE__KALLSYMS &&
-           !dso__is_kcore(dso)) {
-               err = SYMBOL_ANNOTATE_ERRNO__NO_VMLINUX;
-               goto out_free_filename;
-       }
+       return 0;
+}
+
+int symbol__disassemble(struct symbol *sym, struct map *map, size_t privsize)
+{
+       struct dso *dso = map->dso;
+       char command[PATH_MAX * 2];
+       FILE *file;
+       char symfs_filename[PATH_MAX];
+       struct kcore_extract kce;
+       bool delete_extract = false;
+       int stdout_fd[2];
+       int lineno = 0;
+       int nline;
+       pid_t pid;
+       int err = dso__disassemble_filename(dso, symfs_filename, sizeof(symfs_filename));
+
+       if (err)
+               return err;
 
        pr_debug("%s: filename=%s, sym=%s, start=%#" PRIx64 ", end=%#" PRIx64 "\n", __func__,
-                filename, sym->name, map->unmap_ip(map, sym->start),
+                symfs_filename, sym->name, map->unmap_ip(map, sym->start),
                 map->unmap_ip(map, sym->end));
 
        pr_debug("annotating [%p] %30s : [%p] %30s\n",
@@ -1223,11 +1313,6 @@ fallback:
                        delete_extract = true;
                        strlcpy(symfs_filename, kce.extract_filename,
                                sizeof(symfs_filename));
-                       if (free_filename) {
-                               free(filename);
-                               free_filename = false;
-                       }
-                       filename = symfs_filename;
                }
        } else if (dso__needs_decompress(dso)) {
                char tmp[PATH_MAX];
@@ -1236,14 +1321,14 @@ fallback:
                bool ret;
 
                if (kmod_path__parse_ext(&m, symfs_filename))
-                       goto out_free_filename;
+                       goto out;
 
                snprintf(tmp, PATH_MAX, "/tmp/perf-kmod-XXXXXX");
 
                fd = mkstemp(tmp);
                if (fd < 0) {
                        free(m.ext);
-                       goto out_free_filename;
+                       goto out;
                }
 
                ret = decompress_to_file(m.ext, symfs_filename, fd);
@@ -1255,7 +1340,7 @@ fallback:
                close(fd);
 
                if (!ret)
-                       goto out_free_filename;
+                       goto out;
 
                strcpy(symfs_filename, tmp);
        }
@@ -1271,7 +1356,7 @@ fallback:
                 map__rip_2objdump(map, sym->end),
                 symbol_conf.annotate_asm_raw ? "" : "--no-show-raw",
                 symbol_conf.annotate_src ? "-S" : "",
-                symfs_filename, filename);
+                symfs_filename, symfs_filename);
 
        pr_debug("Executing: %s\n", command);
 
@@ -1333,11 +1418,10 @@ out_remove_tmp:
 
        if (dso__needs_decompress(dso))
                unlink(symfs_filename);
-out_free_filename:
+
        if (delete_extract)
                kcore_extract__delete(&kce);
-       if (free_filename)
-               free(filename);
+out:
        return err;
 
 out_close_stdout:
index f67ccb0275615c1632d86eb5f09815eaf596b905..5bbcec173b8257c2804a7a210ce70b46961988e0 100644 (file)
@@ -36,7 +36,7 @@ struct ins_operands {
 
 struct ins_ops {
        void (*free)(struct ins_operands *ops);
-       int (*parse)(struct ins_operands *ops);
+       int (*parse)(struct ins_operands *ops, struct map *map);
        int (*scnprintf)(struct ins *ins, char *bf, size_t size,
                         struct ins_operands *ops);
 };
@@ -130,6 +130,7 @@ struct annotated_source {
 
 struct annotation {
        pthread_mutex_t         lock;
+       u64                     max_coverage;
        struct annotated_source *src;
 };
 
@@ -177,7 +178,6 @@ enum symbol_disassemble_errno {
 int symbol__strerror_disassemble(struct symbol *sym, struct map *map,
                                 int errnum, char *buf, size_t buflen);
 
-int symbol__annotate_init(struct map *map, struct symbol *sym);
 int symbol__annotate_printf(struct symbol *sym, struct map *map,
                            struct perf_evsel *evsel, bool full_paths,
                            int min_pcnt, int max_lines, int context);
diff --git a/tools/perf/util/block-range.c b/tools/perf/util/block-range.c
new file mode 100644 (file)
index 0000000..7b3e1d7
--- /dev/null
@@ -0,0 +1,328 @@
+#include "block-range.h"
+#include "annotate.h"
+
+struct {
+       struct rb_root root;
+       u64 blocks;
+} block_ranges;
+
+static void block_range__debug(void)
+{
+       /*
+        * XXX still paranoid for now; see if we can make this depend on
+        * DEBUG=1 builds.
+        */
+#if 1
+       struct rb_node *rb;
+       u64 old = 0; /* NULL isn't executable */
+
+       for (rb = rb_first(&block_ranges.root); rb; rb = rb_next(rb)) {
+               struct block_range *entry = rb_entry(rb, struct block_range, node);
+
+               assert(old < entry->start);
+               assert(entry->start <= entry->end); /* single instruction block; jump to a jump */
+
+               old = entry->end;
+       }
+#endif
+}
+
+struct block_range *block_range__find(u64 addr)
+{
+       struct rb_node **p = &block_ranges.root.rb_node;
+       struct rb_node *parent = NULL;
+       struct block_range *entry;
+
+       while (*p != NULL) {
+               parent = *p;
+               entry = rb_entry(parent, struct block_range, node);
+
+               if (addr < entry->start)
+                       p = &parent->rb_left;
+               else if (addr > entry->end)
+                       p = &parent->rb_right;
+               else
+                       return entry;
+       }
+
+       return NULL;
+}
+
+static inline void rb_link_left_of_node(struct rb_node *left, struct rb_node *node)
+{
+       struct rb_node **p = &node->rb_left;
+       while (*p) {
+               node = *p;
+               p = &node->rb_right;
+       }
+       rb_link_node(left, node, p);
+}
+
+static inline void rb_link_right_of_node(struct rb_node *right, struct rb_node *node)
+{
+       struct rb_node **p = &node->rb_right;
+       while (*p) {
+               node = *p;
+               p = &node->rb_left;
+       }
+       rb_link_node(right, node, p);
+}
+
+/**
+ * block_range__create
+ * @start: branch target starting this basic block
+ * @end:   branch ending this basic block
+ *
+ * Create all the required block ranges to precisely span the given range.
+ */
+struct block_range_iter block_range__create(u64 start, u64 end)
+{
+       struct rb_node **p = &block_ranges.root.rb_node;
+       struct rb_node *n, *parent = NULL;
+       struct block_range *next, *entry = NULL;
+       struct block_range_iter iter = { NULL, NULL };
+
+       while (*p != NULL) {
+               parent = *p;
+               entry = rb_entry(parent, struct block_range, node);
+
+               if (start < entry->start)
+                       p = &parent->rb_left;
+               else if (start > entry->end)
+                       p = &parent->rb_right;
+               else
+                       break;
+       }
+
+       /*
+        * Didn't find anything.. there's a hole at @start, however @end might
+        * be inside/behind the next range.
+        */
+       if (!*p) {
+               if (!entry) /* tree empty */
+                       goto do_whole;
+
+               /*
+                * If the last node is before, advance one to find the next.
+                */
+               n = parent;
+               if (entry->end < start) {
+                       n = rb_next(n);
+                       if (!n)
+                               goto do_whole;
+               }
+               next = rb_entry(n, struct block_range, node);
+
+               if (next->start <= end) { /* add head: [start...][n->start...] */
+                       struct block_range *head = malloc(sizeof(struct block_range));
+                       if (!head)
+                               return iter;
+
+                       *head = (struct block_range){
+                               .start          = start,
+                               .end            = next->start - 1,
+                               .is_target      = 1,
+                               .is_branch      = 0,
+                       };
+
+                       rb_link_left_of_node(&head->node, &next->node);
+                       rb_insert_color(&head->node, &block_ranges.root);
+                       block_range__debug();
+
+                       iter.start = head;
+                       goto do_tail;
+               }
+
+do_whole:
+               /*
+                * The whole [start..end] range is non-overlapping.
+                */
+               entry = malloc(sizeof(struct block_range));
+               if (!entry)
+                       return iter;
+
+               *entry = (struct block_range){
+                       .start          = start,
+                       .end            = end,
+                       .is_target      = 1,
+                       .is_branch      = 1,
+               };
+
+               rb_link_node(&entry->node, parent, p);
+               rb_insert_color(&entry->node, &block_ranges.root);
+               block_range__debug();
+
+               iter.start = entry;
+               iter.end   = entry;
+               goto done;
+       }
+
+       /*
+        * We found a range that overlapped with ours, split if needed.
+        */
+       if (entry->start < start) { /* split: [e->start...][start...] */
+               struct block_range *head = malloc(sizeof(struct block_range));
+               if (!head)
+                       return iter;
+
+               *head = (struct block_range){
+                       .start          = entry->start,
+                       .end            = start - 1,
+                       .is_target      = entry->is_target,
+                       .is_branch      = 0,
+
+                       .coverage       = entry->coverage,
+                       .entry          = entry->entry,
+               };
+
+               entry->start            = start;
+               entry->is_target        = 1;
+               entry->entry            = 0;
+
+               rb_link_left_of_node(&head->node, &entry->node);
+               rb_insert_color(&head->node, &block_ranges.root);
+               block_range__debug();
+
+       } else if (entry->start == start)
+               entry->is_target = 1;
+
+       iter.start = entry;
+
+do_tail:
+       /*
+        * At this point we've got: @iter.start = [@start...] but @end can still be
+        * inside or beyond it.
+        */
+       entry = iter.start;
+       for (;;) {
+               /*
+                * If @end is inside @entry, split.
+                */
+               if (end < entry->end) { /* split: [...end][...e->end] */
+                       struct block_range *tail = malloc(sizeof(struct block_range));
+                       if (!tail)
+                               return iter;
+
+                       *tail = (struct block_range){
+                               .start          = end + 1,
+                               .end            = entry->end,
+                               .is_target      = 0,
+                               .is_branch      = entry->is_branch,
+
+                               .coverage       = entry->coverage,
+                               .taken          = entry->taken,
+                               .pred           = entry->pred,
+                       };
+
+                       entry->end              = end;
+                       entry->is_branch        = 1;
+                       entry->taken            = 0;
+                       entry->pred             = 0;
+
+                       rb_link_right_of_node(&tail->node, &entry->node);
+                       rb_insert_color(&tail->node, &block_ranges.root);
+                       block_range__debug();
+
+                       iter.end = entry;
+                       goto done;
+               }
+
+               /*
+                * If @end matches @entry, done
+                */
+               if (end == entry->end) {
+                       entry->is_branch = 1;
+                       iter.end = entry;
+                       goto done;
+               }
+
+               next = block_range__next(entry);
+               if (!next)
+                       goto add_tail;
+
+               /*
+                * If @end is in beyond @entry but not inside @next, add tail.
+                */
+               if (end < next->start) { /* add tail: [...e->end][...end] */
+                       struct block_range *tail;
+add_tail:
+                       tail = malloc(sizeof(struct block_range));
+                       if (!tail)
+                               return iter;
+
+                       *tail = (struct block_range){
+                               .start          = entry->end + 1,
+                               .end            = end,
+                               .is_target      = 0,
+                               .is_branch      = 1,
+                       };
+
+                       rb_link_right_of_node(&tail->node, &entry->node);
+                       rb_insert_color(&tail->node, &block_ranges.root);
+                       block_range__debug();
+
+                       iter.end = tail;
+                       goto done;
+               }
+
+               /*
+                * If there is a hole between @entry and @next, fill it.
+                */
+               if (entry->end + 1 != next->start) {
+                       struct block_range *hole = malloc(sizeof(struct block_range));
+                       if (!hole)
+                               return iter;
+
+                       *hole = (struct block_range){
+                               .start          = entry->end + 1,
+                               .end            = next->start - 1,
+                               .is_target      = 0,
+                               .is_branch      = 0,
+                       };
+
+                       rb_link_left_of_node(&hole->node, &next->node);
+                       rb_insert_color(&hole->node, &block_ranges.root);
+                       block_range__debug();
+               }
+
+               entry = next;
+       }
+
+done:
+       assert(iter.start->start == start && iter.start->is_target);
+       assert(iter.end->end == end && iter.end->is_branch);
+
+       block_ranges.blocks++;
+
+       return iter;
+}
+
+
+/*
+ * Compute coverage as:
+ *
+ *    br->coverage / br->sym->max_coverage
+ *
+ * This ensures each symbol has a 100% spot, to reflect that each symbol has a
+ * most covered section.
+ *
+ * Returns [0-1] for coverage and -1 if we had no data what so ever or the
+ * symbol does not exist.
+ */
+double block_range__coverage(struct block_range *br)
+{
+       struct symbol *sym;
+
+       if (!br) {
+               if (block_ranges.blocks)
+                       return 0;
+
+               return -1;
+       }
+
+       sym = br->sym;
+       if (!sym)
+               return -1;
+
+       return (double)br->coverage / symbol__annotation(sym)->max_coverage;
+}
diff --git a/tools/perf/util/block-range.h b/tools/perf/util/block-range.h
new file mode 100644 (file)
index 0000000..a8c8413
--- /dev/null
@@ -0,0 +1,71 @@
+#ifndef __PERF_BLOCK_RANGE_H
+#define __PERF_BLOCK_RANGE_H
+
+#include "symbol.h"
+
+/*
+ * struct block_range - non-overlapping parts of basic blocks
+ * @node:      treenode
+ * @start:     inclusive start of range
+ * @end:       inclusive end of range
+ * @is_target: @start is a jump target
+ * @is_branch: @end is a branch instruction
+ * @coverage:  number of blocks that cover this range
+ * @taken:     number of times the branch is taken (requires @is_branch)
+ * @pred:      number of times the taken branch was predicted
+ */
+struct block_range {
+       struct rb_node node;
+
+       struct symbol *sym;
+
+       u64 start;
+       u64 end;
+
+       int is_target, is_branch;
+
+       u64 coverage;
+       u64 entry;
+       u64 taken;
+       u64 pred;
+};
+
+static inline struct block_range *block_range__next(struct block_range *br)
+{
+       struct rb_node *n = rb_next(&br->node);
+       if (!n)
+               return NULL;
+       return rb_entry(n, struct block_range, node);
+}
+
+struct block_range_iter {
+       struct block_range *start;
+       struct block_range *end;
+};
+
+static inline struct block_range *block_range_iter(struct block_range_iter *iter)
+{
+       return iter->start;
+}
+
+static inline bool block_range_iter__next(struct block_range_iter *iter)
+{
+       if (iter->start == iter->end)
+               return false;
+
+       iter->start = block_range__next(iter->start);
+       return true;
+}
+
+static inline bool block_range_iter__valid(struct block_range_iter *iter)
+{
+       if (!iter->start || !iter->end)
+               return false;
+       return true;
+}
+
+extern struct block_range *block_range__find(u64 addr);
+extern struct block_range_iter block_range__create(u64 start, u64 end);
+extern double block_range__coverage(struct block_range *br);
+
+#endif /* __PERF_BLOCK_RANGE_H */
index 1f12e4e4000605e68351194731969df0c9081005..2b2c9b82f5abc55d22ff451ec32161c558091895 100644 (file)
@@ -531,7 +531,7 @@ static int map_prologue(struct perf_probe_event *pev, int *mapping,
 
        ptevs = malloc(array_sz);
        if (!ptevs) {
-               pr_debug("No ehough memory: alloc ptevs failed\n");
+               pr_debug("No enough memory: alloc ptevs failed\n");
                return -ENOMEM;
        }
 
index 8c4212abd19b48b9e84ca1f9978f06561c05576a..c1838b643108bda4d6fc536ae232f20e643a9ce2 100644 (file)
@@ -6,6 +6,7 @@
 #include <stdarg.h>
 #include <stdio.h>
 #include <api/debug.h>
+#include <linux/time64.h>
 
 #include "cache.h"
 #include "color.h"
@@ -14,9 +15,6 @@
 #include "util.h"
 #include "target.h"
 
-#define NSECS_PER_SEC  1000000000ULL
-#define NSECS_PER_USEC 1000ULL
-
 int verbose;
 bool dump_trace = false, quiet = false;
 int debug_ordered_events;
@@ -54,9 +52,9 @@ static int veprintf_time(u64 t, const char *fmt, va_list args)
        int ret = 0;
        u64 secs, usecs, nsecs = t;
 
-       secs   = nsecs / NSECS_PER_SEC;
-       nsecs -= secs  * NSECS_PER_SEC;
-       usecs  = nsecs / NSECS_PER_USEC;
+       secs   = nsecs / NSEC_PER_SEC;
+       nsecs -= secs  * NSEC_PER_SEC;
+       usecs  = nsecs / NSEC_PER_USEC;
 
        ret = fprintf(stderr, "[%13" PRIu64 ".%06" PRIu64 "] ",
                      secs, usecs);
index 774f6ec884d50cf0d2d3696689e0ca8c4e8e27c5..d2c6cdd9d42b72a194d913bdc1840d5ff72bb281 100644 (file)
@@ -363,6 +363,9 @@ static int __open_dso(struct dso *dso, struct machine *machine)
                return -EINVAL;
        }
 
+       if (!is_regular_file(name))
+               return -EINVAL;
+
        fd = do_open(name);
        free(name);
        return fd;
index a347b19c961a4bf87949b0cc3ae6feb4f496e774..faec899435f2cf2ca1b035f3aff7dec9a9b47f1b 100644 (file)
@@ -1085,3 +1085,182 @@ int die_get_var_range(Dwarf_Die *sp_die __maybe_unused,
        return -ENOTSUP;
 }
 #endif
+
+/*
+ * die_has_loclist - Check if DW_AT_location of @vr_die is a location list
+ * @vr_die: a variable DIE
+ */
+static bool die_has_loclist(Dwarf_Die *vr_die)
+{
+       Dwarf_Attribute loc;
+       int tag = dwarf_tag(vr_die);
+
+       if (tag != DW_TAG_formal_parameter &&
+           tag != DW_TAG_variable)
+               return false;
+
+       return (dwarf_attr_integrate(vr_die, DW_AT_location, &loc) &&
+               dwarf_whatform(&loc) == DW_FORM_sec_offset);
+}
+
+/*
+ * die_is_optimized_target - Check if target program is compiled with
+ * optimization
+ * @cu_die: a CU DIE
+ *
+ * For any object in given CU whose DW_AT_location is a location list,
+ * target program is compiled with optimization. This is applicable to
+ * clang as well.
+ */
+bool die_is_optimized_target(Dwarf_Die *cu_die)
+{
+       Dwarf_Die tmp_die;
+
+       if (die_has_loclist(cu_die))
+               return true;
+
+       if (!dwarf_child(cu_die, &tmp_die) &&
+           die_is_optimized_target(&tmp_die))
+               return true;
+
+       if (!dwarf_siblingof(cu_die, &tmp_die) &&
+           die_is_optimized_target(&tmp_die))
+               return true;
+
+       return false;
+}
+
+/*
+ * die_search_idx - Search index of given line address
+ * @lines: Line records of single CU
+ * @nr_lines: Number of @lines
+ * @addr: address we are looking for
+ * @idx: index to be set by this function (return value)
+ *
+ * Search for @addr by looping over every lines of CU. If address
+ * matches, set index of that line in @idx. Note that single source
+ * line can have multiple line records. i.e. single source line can
+ * have multiple index.
+ */
+static bool die_search_idx(Dwarf_Lines *lines, unsigned long nr_lines,
+                          Dwarf_Addr addr, unsigned long *idx)
+{
+       unsigned long i;
+       Dwarf_Addr tmp;
+
+       for (i = 0; i < nr_lines; i++) {
+               if (dwarf_lineaddr(dwarf_onesrcline(lines, i), &tmp))
+                       return false;
+
+               if (tmp == addr) {
+                       *idx = i;
+                       return true;
+               }
+       }
+       return false;
+}
+
+/*
+ * die_get_postprologue_addr - Search next address after function prologue
+ * @entrypc_idx: entrypc index
+ * @lines: Line records of single CU
+ * @nr_lines: Number of @lines
+ * @hignpc: high PC address of function
+ * @postprologue_addr: Next address after function prologue (return value)
+ *
+ * Look for prologue-end marker. If there is no explicit marker, return
+ * address of next line record or next source line.
+ */
+static bool die_get_postprologue_addr(unsigned long entrypc_idx,
+                                     Dwarf_Lines *lines,
+                                     unsigned long nr_lines,
+                                     Dwarf_Addr highpc,
+                                     Dwarf_Addr *postprologue_addr)
+{
+       unsigned long i;
+       int entrypc_lno, lno;
+       Dwarf_Line *line;
+       Dwarf_Addr addr;
+       bool p_end;
+
+       /* entrypc_lno is actual source line number */
+       line = dwarf_onesrcline(lines, entrypc_idx);
+       if (dwarf_lineno(line, &entrypc_lno))
+               return false;
+
+       for (i = entrypc_idx; i < nr_lines; i++) {
+               line = dwarf_onesrcline(lines, i);
+
+               if (dwarf_lineaddr(line, &addr) ||
+                   dwarf_lineno(line, &lno)    ||
+                   dwarf_lineprologueend(line, &p_end))
+                       return false;
+
+               /* highpc is exclusive. [entrypc,highpc) */
+               if (addr >= highpc)
+                       break;
+
+               /* clang supports prologue-end marker */
+               if (p_end)
+                       break;
+
+               /* Actual next line in source */
+               if (lno != entrypc_lno)
+                       break;
+
+               /*
+                * Single source line can have multiple line records.
+                * For Example,
+                *     void foo() { printf("hello\n"); }
+                * contains two line records. One points to declaration and
+                * other points to printf() line. Variable 'lno' won't get
+                * incremented in this case but 'i' will.
+                */
+               if (i != entrypc_idx)
+                       break;
+       }
+
+       dwarf_lineaddr(line, postprologue_addr);
+       if (*postprologue_addr >= highpc)
+               dwarf_lineaddr(dwarf_onesrcline(lines, i - 1),
+                              postprologue_addr);
+
+       return true;
+}
+
+/*
+ * die_skip_prologue - Use next address after prologue as probe location
+ * @sp_die: a subprogram DIE
+ * @cu_die: a CU DIE
+ * @entrypc: entrypc of the function
+ *
+ * Function prologue prepares stack and registers before executing function
+ * logic. When target program is compiled without optimization, function
+ * parameter information is only valid after prologue. When we probe entrypc
+ * of the function, and try to record function parameter, it contains
+ * garbage value.
+ */
+void die_skip_prologue(Dwarf_Die *sp_die, Dwarf_Die *cu_die,
+                      Dwarf_Addr *entrypc)
+{
+       size_t nr_lines = 0;
+       unsigned long entrypc_idx = 0;
+       Dwarf_Lines *lines = NULL;
+       Dwarf_Addr postprologue_addr;
+       Dwarf_Addr highpc;
+
+       if (dwarf_highpc(sp_die, &highpc))
+               return;
+
+       if (dwarf_getsrclines(cu_die, &lines, &nr_lines))
+               return;
+
+       if (!die_search_idx(lines, nr_lines, *entrypc, &entrypc_idx))
+               return;
+
+       if (!die_get_postprologue_addr(entrypc_idx, lines, nr_lines,
+                                      highpc, &postprologue_addr))
+               return;
+
+       *entrypc = postprologue_addr;
+}
index dc0ce1adb075bf6fac0a7296fdd0050b5bdeb4b7..8b6d2f83af0210feca3b6cbd9ee190d5986de699 100644 (file)
@@ -125,4 +125,12 @@ int die_get_typename(Dwarf_Die *vr_die, struct strbuf *buf);
 /* Get the name and type of given variable DIE, stored as "type\tname" */
 int die_get_varname(Dwarf_Die *vr_die, struct strbuf *buf);
 int die_get_var_range(Dwarf_Die *sp_die, Dwarf_Die *vr_die, struct strbuf *buf);
+
+/* Check if target program is compiled with optimization */
+bool die_is_optimized_target(Dwarf_Die *cu_die);
+
+/* Use next address after prologue as probe location */
+void die_skip_prologue(Dwarf_Die *sp_die, Dwarf_Die *cu_die,
+                      Dwarf_Addr *entrypc);
+
 #endif
diff --git a/tools/perf/util/dwarf-regs.c b/tools/perf/util/dwarf-regs.c
new file mode 100644 (file)
index 0000000..62bc4a8
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * dwarf-regs.c : Mapping of DWARF debug register numbers into register names.
+ *
+ * Written by: Masami Hiramatsu <mhiramat@kernel.org>
+ */
+
+#include <util.h>
+#include <debug.h>
+#include <dwarf-regs.h>
+#include <elf.h>
+
+#ifndef EM_AARCH64
+#define EM_AARCH64     183  /* ARM 64 bit */
+#endif
+
+/* Define const char * {arch}_register_tbl[] */
+#define DEFINE_DWARF_REGSTR_TABLE
+#include "../arch/x86/include/dwarf-regs-table.h"
+#include "../arch/arm/include/dwarf-regs-table.h"
+#include "../arch/arm64/include/dwarf-regs-table.h"
+#include "../arch/sh/include/dwarf-regs-table.h"
+#include "../arch/powerpc/include/dwarf-regs-table.h"
+#include "../arch/s390/include/dwarf-regs-table.h"
+#include "../arch/sparc/include/dwarf-regs-table.h"
+#include "../arch/xtensa/include/dwarf-regs-table.h"
+
+#define __get_dwarf_regstr(tbl, n) (((n) < ARRAY_SIZE(tbl)) ? (tbl)[(n)] : NULL)
+
+/* Return architecture dependent register string (for kprobe-tracer) */
+const char *get_dwarf_regstr(unsigned int n, unsigned int machine)
+{
+       switch (machine) {
+       case EM_NONE:   /* Generic arch - use host arch */
+               return get_arch_regstr(n);
+       case EM_386:
+               return __get_dwarf_regstr(x86_32_regstr_tbl, n);
+       case EM_X86_64:
+               return __get_dwarf_regstr(x86_64_regstr_tbl, n);
+       case EM_ARM:
+               return __get_dwarf_regstr(arm_regstr_tbl, n);
+       case EM_AARCH64:
+               return __get_dwarf_regstr(aarch64_regstr_tbl, n);
+       case EM_SH:
+               return __get_dwarf_regstr(sh_regstr_tbl, n);
+       case EM_S390:
+               return __get_dwarf_regstr(s390_regstr_tbl, n);
+       case EM_PPC:
+       case EM_PPC64:
+               return __get_dwarf_regstr(powerpc_regstr_tbl, n);
+       case EM_SPARC:
+       case EM_SPARCV9:
+               return __get_dwarf_regstr(sparc_regstr_tbl, n);
+       case EM_XTENSA:
+               return __get_dwarf_regstr(xtensa_regstr_tbl, n);
+       default:
+               pr_err("ELF MACHINE %x is not supported.\n", machine);
+       }
+       return NULL;
+}
index e20438b784bed4019e50080e54fd06fad2c0776e..2880e2226fdb5dc0b12e8af693c9e537fa114a9a 100644 (file)
@@ -1,5 +1,6 @@
 #include <linux/types.h>
-#include <sys/mman.h>
+#include <uapi/linux/mman.h> /* To get things like MAP_HUGETLB even on older libc headers */
+#include <api/fs/fs.h>
 #include "event.h"
 #include "debug.h"
 #include "hist.h"
@@ -248,6 +249,8 @@ int perf_event__synthesize_mmap_events(struct perf_tool *tool,
        bool truncation = false;
        unsigned long long timeout = proc_map_timeout * 1000000ULL;
        int rc = 0;
+       const char *hugetlbfs_mnt = hugetlbfs__mountpoint();
+       int hugetlbfs_mnt_len = hugetlbfs_mnt ? strlen(hugetlbfs_mnt) : 0;
 
        if (machine__is_default_guest(machine))
                return 0;
@@ -343,6 +346,11 @@ out:
                if (!strcmp(execname, ""))
                        strcpy(execname, anonstr);
 
+               if (!strncmp(execname, hugetlbfs_mnt, hugetlbfs_mnt_len)) {
+                       strcpy(execname, anonstr);
+                       event->mmap2.flags |= MAP_HUGETLB;
+               }
+
                size = strlen(execname) + 1;
                memcpy(event->mmap2.filename, execname, size);
                size = PERF_ALIGN(size, sizeof(u64));
@@ -1286,7 +1294,7 @@ try_again:
                 * must be done prior to using kernel maps.
                 */
                if (load_map)
-                       map__load(al->map, machine->symbol_filter);
+                       map__load(al->map);
                al->addr = al->map->map_ip(al->map, al->addr);
        }
 }
@@ -1297,8 +1305,7 @@ void thread__find_addr_location(struct thread *thread,
 {
        thread__find_addr_map(thread, cpumode, type, addr, al);
        if (al->map != NULL)
-               al->sym = map__find_symbol(al->map, al->addr,
-                                          thread->mg->machine->symbol_filter);
+               al->sym = map__find_symbol(al->map, al->addr);
        else
                al->sym = NULL;
 }
@@ -1359,8 +1366,7 @@ int machine__resolve(struct machine *machine, struct addr_location *al,
                        al->filtered |= (1 << HIST_FILTER__DSO);
                }
 
-               al->sym = map__find_symbol(al->map, al->addr,
-                                          machine->symbol_filter);
+               al->sym = map__find_symbol(al->map, al->addr);
        }
 
        if (symbol_conf.sym_list &&
@@ -1416,5 +1422,5 @@ void thread__resolve(struct thread *thread, struct addr_location *al,
        al->sym = NULL;
 
        if (al->map)
-               al->sym = map__find_symbol(al->map, al->addr, NULL);
+               al->sym = map__find_symbol(al->map, al->addr);
 }
index 097b3ed77fddcffe39f7530d75ff5b665f9314a7..ea34c5a32c11c78a73575f6c7d666202180e2903 100644 (file)
@@ -1032,16 +1032,18 @@ perf_evlist__should_poll(struct perf_evlist *evlist __maybe_unused,
 }
 
 static int perf_evlist__mmap_per_evsel(struct perf_evlist *evlist, int idx,
-                                      struct mmap_params *mp, int cpu,
+                                      struct mmap_params *mp, int cpu_idx,
                                       int thread, int *_output, int *_output_backward)
 {
        struct perf_evsel *evsel;
        int revent;
+       int evlist_cpu = cpu_map__cpu(evlist->cpus, cpu_idx);
 
        evlist__for_each_entry(evlist, evsel) {
                struct perf_mmap *maps = evlist->mmap;
                int *output = _output;
                int fd;
+               int cpu;
 
                if (evsel->attr.write_backward) {
                        output = _output_backward;
@@ -1060,6 +1062,10 @@ static int perf_evlist__mmap_per_evsel(struct perf_evlist *evlist, int idx,
                if (evsel->system_wide && thread)
                        continue;
 
+               cpu = cpu_map__idx(evsel->cpus, evlist_cpu);
+               if (cpu == -1)
+                       continue;
+
                fd = FD(evsel, cpu, thread);
 
                if (*output == -1) {
index 4d44129e050b0fef0ddc43ef2fd9c9c446349f0a..323806082c58592256913fa155def7cc2f28eaee 100644 (file)
@@ -46,6 +46,7 @@ enum {
        PERF_EVSEL__CONFIG_TERM_INHERIT,
        PERF_EVSEL__CONFIG_TERM_MAX_STACK,
        PERF_EVSEL__CONFIG_TERM_OVERWRITE,
+       PERF_EVSEL__CONFIG_TERM_DRV_CFG,
        PERF_EVSEL__CONFIG_TERM_MAX,
 };
 
@@ -57,6 +58,7 @@ struct perf_evsel_config_term {
                u64     freq;
                bool    time;
                char    *callgraph;
+               char    *drv_cfg;
                u64     stack_user;
                int     max_stack;
                bool    inherit;
index 3674e77ad64049dddf34e99674d72eaa77792a30..9111e0666950dd535e2f4d8cf1df9fbefe145204 100644 (file)
@@ -122,7 +122,7 @@ int sample__fprintf_callchain(struct perf_sample *sample, int left_alignment,
                        if (!node)
                                break;
 
-                       if (node->sym && node->sym->ignore)
+                       if (node->sym && node->sym->idle)
                                goto next;
 
                        printed += fprintf(fp, "%-*.*s", left_alignment, left_alignment, " ");
@@ -181,7 +181,7 @@ int sample__fprintf_sym(struct perf_sample *sample, struct addr_location *al,
        if (cursor != NULL) {
                printed += sample__fprintf_callchain(sample, left_alignment,
                                                     print_opts, cursor, fp);
-       } else if (!(al->sym && al->sym->ignore)) {
+       } else if (!(al->sym && al->sym->idle)) {
                printed += fprintf(fp, "%-*.*s", left_alignment, left_alignment, " ");
 
                if (print_ip)
index 8f0db4007282fabfe99fdcdc80de480d38e30510..85dd0db0a127995a725eade74a12e5da8569b80c 100644 (file)
@@ -828,8 +828,7 @@ static int write_group_desc(int fd, struct perf_header *h __maybe_unused,
  * default get_cpuid(): nothing gets recorded
  * actual implementation must be in arch/$(ARCH)/util/header.c
  */
-int __attribute__ ((weak)) get_cpuid(char *buffer __maybe_unused,
-                                    size_t sz __maybe_unused)
+int __weak get_cpuid(char *buffer __maybe_unused, size_t sz __maybe_unused)
 {
        return -1;
 }
index de15dbcdcecf8af9d37d06fbbcbaf0bb38e2f29d..b02992efb51383c06ce507adcba261100e101dd8 100644 (file)
@@ -177,8 +177,10 @@ void hists__calc_col_len(struct hists *hists, struct hist_entry *h)
        hists__new_col_len(hists, HISTC_LOCAL_WEIGHT, 12);
        hists__new_col_len(hists, HISTC_GLOBAL_WEIGHT, 12);
 
-       if (h->srcline)
-               hists__new_col_len(hists, HISTC_SRCLINE, strlen(h->srcline));
+       if (h->srcline) {
+               len = MAX(strlen(h->srcline), strlen(sort_srcline.se_header));
+               hists__new_col_len(hists, HISTC_SRCLINE, len);
+       }
 
        if (h->srcfile)
                hists__new_col_len(hists, HISTC_SRCFILE, strlen(h->srcfile));
@@ -417,6 +419,8 @@ static int hist_entry__init(struct hist_entry *he,
        }
        INIT_LIST_HEAD(&he->pairs.node);
        thread__get(he->thread);
+       he->hroot_in  = RB_ROOT;
+       he->hroot_out = RB_ROOT;
 
        if (!symbol_conf.report_hierarchy)
                he->leaf = true;
@@ -2149,6 +2153,50 @@ out:
        return he;
 }
 
+static struct hist_entry *add_dummy_hierarchy_entry(struct hists *hists,
+                                                   struct rb_root *root,
+                                                   struct hist_entry *pair)
+{
+       struct rb_node **p;
+       struct rb_node *parent = NULL;
+       struct hist_entry *he;
+       struct perf_hpp_fmt *fmt;
+
+       p = &root->rb_node;
+       while (*p != NULL) {
+               int64_t cmp = 0;
+
+               parent = *p;
+               he = rb_entry(parent, struct hist_entry, rb_node_in);
+
+               perf_hpp_list__for_each_sort_list(he->hpp_list, fmt) {
+                       cmp = fmt->collapse(fmt, he, pair);
+                       if (cmp)
+                               break;
+               }
+               if (!cmp)
+                       goto out;
+
+               if (cmp < 0)
+                       p = &parent->rb_left;
+               else
+                       p = &parent->rb_right;
+       }
+
+       he = hist_entry__new(pair, true);
+       if (he) {
+               rb_link_node(&he->rb_node_in, parent, p);
+               rb_insert_color(&he->rb_node_in, root);
+
+               he->dummy = true;
+               he->hists = hists;
+               memset(&he->stat, 0, sizeof(he->stat));
+               hists__inc_stats(hists, he);
+       }
+out:
+       return he;
+}
+
 static struct hist_entry *hists__find_entry(struct hists *hists,
                                            struct hist_entry *he)
 {
@@ -2174,6 +2222,51 @@ static struct hist_entry *hists__find_entry(struct hists *hists,
        return NULL;
 }
 
+static struct hist_entry *hists__find_hierarchy_entry(struct rb_root *root,
+                                                     struct hist_entry *he)
+{
+       struct rb_node *n = root->rb_node;
+
+       while (n) {
+               struct hist_entry *iter;
+               struct perf_hpp_fmt *fmt;
+               int64_t cmp = 0;
+
+               iter = rb_entry(n, struct hist_entry, rb_node_in);
+               perf_hpp_list__for_each_sort_list(he->hpp_list, fmt) {
+                       cmp = fmt->collapse(fmt, iter, he);
+                       if (cmp)
+                               break;
+               }
+
+               if (cmp < 0)
+                       n = n->rb_left;
+               else if (cmp > 0)
+                       n = n->rb_right;
+               else
+                       return iter;
+       }
+
+       return NULL;
+}
+
+static void hists__match_hierarchy(struct rb_root *leader_root,
+                                  struct rb_root *other_root)
+{
+       struct rb_node *nd;
+       struct hist_entry *pos, *pair;
+
+       for (nd = rb_first(leader_root); nd; nd = rb_next(nd)) {
+               pos  = rb_entry(nd, struct hist_entry, rb_node_in);
+               pair = hists__find_hierarchy_entry(other_root, pos);
+
+               if (pair) {
+                       hist_entry__add_pair(pair, pos);
+                       hists__match_hierarchy(&pos->hroot_in, &pair->hroot_in);
+               }
+       }
+}
+
 /*
  * Look for pairs to link to the leader buckets (hist_entries):
  */
@@ -2183,6 +2276,12 @@ void hists__match(struct hists *leader, struct hists *other)
        struct rb_node *nd;
        struct hist_entry *pos, *pair;
 
+       if (symbol_conf.report_hierarchy) {
+               /* hierarchy report always collapses entries */
+               return hists__match_hierarchy(&leader->entries_collapsed,
+                                             &other->entries_collapsed);
+       }
+
        if (hists__has(leader, need_collapse))
                root = &leader->entries_collapsed;
        else
@@ -2197,6 +2296,50 @@ void hists__match(struct hists *leader, struct hists *other)
        }
 }
 
+static int hists__link_hierarchy(struct hists *leader_hists,
+                                struct hist_entry *parent,
+                                struct rb_root *leader_root,
+                                struct rb_root *other_root)
+{
+       struct rb_node *nd;
+       struct hist_entry *pos, *leader;
+
+       for (nd = rb_first(other_root); nd; nd = rb_next(nd)) {
+               pos = rb_entry(nd, struct hist_entry, rb_node_in);
+
+               if (hist_entry__has_pairs(pos)) {
+                       bool found = false;
+
+                       list_for_each_entry(leader, &pos->pairs.head, pairs.node) {
+                               if (leader->hists == leader_hists) {
+                                       found = true;
+                                       break;
+                               }
+                       }
+                       if (!found)
+                               return -1;
+               } else {
+                       leader = add_dummy_hierarchy_entry(leader_hists,
+                                                          leader_root, pos);
+                       if (leader == NULL)
+                               return -1;
+
+                       /* do not point parent in the pos */
+                       leader->parent_he = parent;
+
+                       hist_entry__add_pair(pos, leader);
+               }
+
+               if (!pos->leaf) {
+                       if (hists__link_hierarchy(leader_hists, leader,
+                                                 &leader->hroot_in,
+                                                 &pos->hroot_in) < 0)
+                               return -1;
+               }
+       }
+       return 0;
+}
+
 /*
  * Look for entries in the other hists that are not present in the leader, if
  * we find them, just add a dummy entry on the leader hists, with period=0,
@@ -2208,6 +2351,13 @@ int hists__link(struct hists *leader, struct hists *other)
        struct rb_node *nd;
        struct hist_entry *pos, *pair;
 
+       if (symbol_conf.report_hierarchy) {
+               /* hierarchy report always collapses entries */
+               return hists__link_hierarchy(leader, NULL,
+                                            &leader->entries_collapsed,
+                                            &other->entries_collapsed);
+       }
+
        if (hists__has(other, need_collapse))
                root = &other->entries_collapsed;
        else
index 0a1edf1ab4502f5bbc84396633ed92f8e4ce500b..defa957f27dfffc368d253d577e6b0bbc65238aa 100644 (file)
@@ -230,7 +230,7 @@ struct perf_hpp {
 struct perf_hpp_fmt {
        const char *name;
        int (*header)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
-                     struct hists *hists);
+                     struct hists *hists, int line, int *span);
        int (*width)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
                     struct hists *hists);
        int (*color)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
@@ -259,6 +259,7 @@ struct perf_hpp_list {
        struct list_head fields;
        struct list_head sorts;
 
+       int nr_header_lines;
        int need_collapse;
        int parent;
        int sym;
@@ -367,6 +368,7 @@ static inline bool perf_hpp__should_skip(struct perf_hpp_fmt *format,
 void perf_hpp__reset_width(struct perf_hpp_fmt *fmt, struct hists *hists);
 void perf_hpp__reset_sort_width(struct perf_hpp_fmt *fmt, struct hists *hists);
 void perf_hpp__set_user_width(const char *width_list_str);
+void hists__reset_column_width(struct hists *hists);
 
 typedef u64 (*hpp_field_fn)(struct hist_entry *he);
 typedef int (*hpp_callback_fn)(struct perf_hpp *hpp, bool front);
index 07c644ed64c4ecd9809bf322297e5a3876e83aad..43bfd8da7919a68e41ab98032221edad25f1cd9c 100644 (file)
@@ -3,6 +3,12 @@
 
 #ifdef HAVE_DWARF_SUPPORT
 const char *get_arch_regstr(unsigned int n);
+/*
+ * get_dwarf_regstr - Returns ftrace register string from DWARF regnum
+ * n: DWARF register number
+ * machine: ELF machine signature (EM_*)
+ */
+const char *get_dwarf_regstr(unsigned int n, unsigned int machine);
 #endif
 
 #ifdef HAVE_ARCH_REGS_QUERY_REGISTER_OFFSET
index 749e6f2e37ca800b6fb4ab5009ed13cfbe2ab956..f545ec1e758a722d1d462e9defd6ff1ba186145f 100644 (file)
@@ -346,7 +346,7 @@ static int intel_bts_get_next_insn(struct intel_bts_queue *btsq, u64 ip)
                goto out_put;
 
        /* Load maps to ensure dso->is_64_bit has been updated */
-       map__load(al.map, machine->symbol_filter);
+       map__load(al.map);
 
        x86_64 = al.map->dso->is_64_bit;
 
index 551ff6f640be85fef9362034a487ff5d4ea0c807..b9cc353cace211d5cff3508c779ca083b4691010 100644 (file)
@@ -477,7 +477,7 @@ static int intel_pt_walk_next_insn(struct intel_pt_insn *intel_pt_insn,
                start_ip = *ip;
 
                /* Load maps to ensure dso->is_64_bit has been updated */
-               map__load(al.map, machine->symbol_filter);
+               map__load(al.map);
 
                x86_64 = al.map->dso->is_64_bit;
 
@@ -1294,7 +1294,7 @@ static u64 intel_pt_switch_ip(struct intel_pt *pt, u64 *ptss_ip)
        if (!map)
                return 0;
 
-       if (map__load(map, machine->symbol_filter))
+       if (map__load(map))
                return 0;
 
        start = dso__first_symbol(map->dso, MAP__FUNCTION);
index 95a1acb61245983660ff0f2e0423c7403f80c4f4..9ddea5cecd94b57f9d177f94f447d89f4716a5a8 100644 (file)
@@ -29,6 +29,7 @@ int lzma_decompress_to_file(const char *input, int output_fd)
        lzma_action action = LZMA_RUN;
        lzma_stream strm   = LZMA_STREAM_INIT;
        lzma_ret ret;
+       int err = -1;
 
        u8 buf_in[BUFSIZE];
        u8 buf_out[BUFSIZE];
@@ -45,7 +46,7 @@ int lzma_decompress_to_file(const char *input, int output_fd)
        if (ret != LZMA_OK) {
                pr_err("lzma: lzma_stream_decoder failed %s (%d)\n",
                        lzma_strerror(ret), ret);
-               return -1;
+               goto err_fclose;
        }
 
        strm.next_in   = NULL;
@@ -60,7 +61,7 @@ int lzma_decompress_to_file(const char *input, int output_fd)
 
                        if (ferror(infile)) {
                                pr_err("lzma: read error: %s\n", strerror(errno));
-                               return -1;
+                               goto err_fclose;
                        }
 
                        if (feof(infile))
@@ -74,7 +75,7 @@ int lzma_decompress_to_file(const char *input, int output_fd)
 
                        if (writen(output_fd, buf_out, write_size) != write_size) {
                                pr_err("lzma: write error: %s\n", strerror(errno));
-                               return -1;
+                               goto err_fclose;
                        }
 
                        strm.next_out  = buf_out;
@@ -83,13 +84,15 @@ int lzma_decompress_to_file(const char *input, int output_fd)
 
                if (ret != LZMA_OK) {
                        if (ret == LZMA_STREAM_END)
-                               return 0;
+                               break;
 
                        pr_err("lzma: failed %s\n", lzma_strerror(ret));
-                       return -1;
+                       goto err_fclose;
                }
        }
 
+       err = 0;
+err_fclose:
        fclose(infile);
-       return 0;
+       return err;
 }
index cb6388dbdd9875a588207286946cb5bea7887767..18e4519abef2ca0a52d1fccd1e3d8c4bc7b5f346 100644 (file)
@@ -41,7 +41,6 @@ int machine__init(struct machine *machine, const char *root_dir, pid_t pid)
 
        machine->pid = pid;
 
-       machine->symbol_filter = NULL;
        machine->id_hdr_size = 0;
        machine->kptr_restrict_warned = false;
        machine->comm_exec = false;
@@ -148,7 +147,6 @@ void machines__init(struct machines *machines)
 {
        machine__init(&machines->host, "", HOST_KERNEL_ID);
        machines->guests = RB_ROOT;
-       machines->symbol_filter = NULL;
 }
 
 void machines__exit(struct machines *machines)
@@ -172,8 +170,6 @@ struct machine *machines__add(struct machines *machines, pid_t pid,
                return NULL;
        }
 
-       machine->symbol_filter = machines->symbol_filter;
-
        while (*p != NULL) {
                parent = *p;
                pos = rb_entry(parent, struct machine, rb_node);
@@ -189,21 +185,6 @@ struct machine *machines__add(struct machines *machines, pid_t pid,
        return machine;
 }
 
-void machines__set_symbol_filter(struct machines *machines,
-                                symbol_filter_t symbol_filter)
-{
-       struct rb_node *nd;
-
-       machines->symbol_filter = symbol_filter;
-       machines->host.symbol_filter = symbol_filter;
-
-       for (nd = rb_first(&machines->guests); nd; nd = rb_next(nd)) {
-               struct machine *machine = rb_entry(nd, struct machine, rb_node);
-
-               machine->symbol_filter = symbol_filter;
-       }
-}
-
 void machines__set_comm_exec(struct machines *machines, bool comm_exec)
 {
        struct rb_node *nd;
@@ -916,10 +897,10 @@ int machines__create_kernel_maps(struct machines *machines, pid_t pid)
 }
 
 int __machine__load_kallsyms(struct machine *machine, const char *filename,
-                            enum map_type type, bool no_kcore, symbol_filter_t filter)
+                            enum map_type type, bool no_kcore)
 {
        struct map *map = machine__kernel_map(machine);
-       int ret = __dso__load_kallsyms(map->dso, filename, map, no_kcore, filter);
+       int ret = __dso__load_kallsyms(map->dso, filename, map, no_kcore);
 
        if (ret > 0) {
                dso__set_loaded(map->dso, type);
@@ -935,16 +916,15 @@ int __machine__load_kallsyms(struct machine *machine, const char *filename,
 }
 
 int machine__load_kallsyms(struct machine *machine, const char *filename,
-                          enum map_type type, symbol_filter_t filter)
+                          enum map_type type)
 {
-       return __machine__load_kallsyms(machine, filename, type, false, filter);
+       return __machine__load_kallsyms(machine, filename, type, false);
 }
 
-int machine__load_vmlinux_path(struct machine *machine, enum map_type type,
-                              symbol_filter_t filter)
+int machine__load_vmlinux_path(struct machine *machine, enum map_type type)
 {
        struct map *map = machine__kernel_map(machine);
-       int ret = dso__load_vmlinux_path(map->dso, map, filter);
+       int ret = dso__load_vmlinux_path(map->dso, map);
 
        if (ret > 0)
                dso__set_loaded(map->dso, type);
@@ -1313,7 +1293,7 @@ static int machine__process_kernel_mmap_event(struct machine *machine,
                        /*
                         * preload dso of guest kernel and modules
                         */
-                       dso__load(kernel, machine__kernel_map(machine), NULL);
+                       dso__load(kernel, machine__kernel_map(machine));
                }
        }
        return 0;
@@ -2115,7 +2095,7 @@ int machine__get_kernel_start(struct machine *machine)
         */
        machine->kernel_start = 1ULL << 63;
        if (map) {
-               err = map__load(map, machine->symbol_filter);
+               err = map__load(map);
                if (map->start)
                        machine->kernel_start = map->start;
        }
@@ -2131,7 +2111,7 @@ char *machine__resolve_kernel_addr(void *vmachine, unsigned long long *addrp, ch
 {
        struct machine *machine = vmachine;
        struct map *map;
-       struct symbol *sym = map_groups__find_symbol(&machine->kmaps, MAP__FUNCTION, *addrp, &map,  NULL);
+       struct symbol *sym = map_groups__find_symbol(&machine->kmaps, MAP__FUNCTION, *addrp, &map);
 
        if (sym == NULL)
                return NULL;
index 20739f746bc4e583cbeaf9e20673af115b3256a4..354de6e56109aa7f5ecc770ad186332d818d42c6 100644 (file)
@@ -41,7 +41,6 @@ struct machine {
        struct map_groups kmaps;
        struct map        *vmlinux_maps[MAP__NR_TYPES];
        u64               kernel_start;
-       symbol_filter_t   symbol_filter;
        pid_t             *current_tid;
        union { /* Tool specific area */
                void      *priv;
@@ -110,7 +109,6 @@ typedef void (*machine__process_t)(struct machine *machine, void *data);
 struct machines {
        struct machine host;
        struct rb_root guests;
-       symbol_filter_t symbol_filter;
 };
 
 void machines__init(struct machines *machines);
@@ -128,8 +126,6 @@ struct machine *machines__findnew(struct machines *machines, pid_t pid);
 void machines__set_id_hdr_size(struct machines *machines, u16 id_hdr_size);
 char *machine__mmap_name(struct machine *machine, char *bf, size_t size);
 
-void machines__set_symbol_filter(struct machines *machines,
-                                symbol_filter_t symbol_filter);
 void machines__set_comm_exec(struct machines *machines, bool comm_exec);
 
 struct machine *machine__new_host(void);
@@ -178,40 +174,33 @@ size_t machine__fprintf(struct machine *machine, FILE *fp);
 static inline
 struct symbol *machine__find_kernel_symbol(struct machine *machine,
                                           enum map_type type, u64 addr,
-                                          struct map **mapp,
-                                          symbol_filter_t filter)
+                                          struct map **mapp)
 {
-       return map_groups__find_symbol(&machine->kmaps, type, addr,
-                                      mapp, filter);
+       return map_groups__find_symbol(&machine->kmaps, type, addr, mapp);
 }
 
 static inline
 struct symbol *machine__find_kernel_symbol_by_name(struct machine *machine,
                                                   enum map_type type, const char *name,
-                                                  struct map **mapp,
-                                                  symbol_filter_t filter)
+                                                  struct map **mapp)
 {
-       return map_groups__find_symbol_by_name(&machine->kmaps, type, name,
-                                              mapp, filter);
+       return map_groups__find_symbol_by_name(&machine->kmaps, type, name, mapp);
 }
 
 static inline
 struct symbol *machine__find_kernel_function(struct machine *machine, u64 addr,
-                                            struct map **mapp,
-                                            symbol_filter_t filter)
+                                            struct map **mapp)
 {
        return machine__find_kernel_symbol(machine, MAP__FUNCTION, addr,
-                                          mapp, filter);
+                                          mapp);
 }
 
 static inline
 struct symbol *machine__find_kernel_function_by_name(struct machine *machine,
                                                     const char *name,
-                                                    struct map **mapp,
-                                                    symbol_filter_t filter)
+                                                    struct map **mapp)
 {
-       return map_groups__find_function_by_name(&machine->kmaps, name, mapp,
-                                                filter);
+       return map_groups__find_function_by_name(&machine->kmaps, name, mapp);
 }
 
 struct map *machine__findnew_module_map(struct machine *machine, u64 start,
@@ -219,11 +208,10 @@ struct map *machine__findnew_module_map(struct machine *machine, u64 start,
 int arch__fix_module_text_start(u64 *start, const char *name);
 
 int __machine__load_kallsyms(struct machine *machine, const char *filename,
-                            enum map_type type, bool no_kcore, symbol_filter_t filter);
+                            enum map_type type, bool no_kcore);
 int machine__load_kallsyms(struct machine *machine, const char *filename,
-                          enum map_type type, symbol_filter_t filter);
-int machine__load_vmlinux_path(struct machine *machine, enum map_type type,
-                              symbol_filter_t filter);
+                          enum map_type type);
+int machine__load_vmlinux_path(struct machine *machine, enum map_type type);
 
 size_t machine__fprintf_dsos_buildid(struct machine *machine, FILE *fp,
                                     bool (skip)(struct dso *dso, int parm), int parm);
index 728129ac653a7e371fae4ebf13c67bd7e4d3de58..c662fef95d1444f243195e90370a7d5e97d06856 100644 (file)
@@ -6,6 +6,7 @@
 #include <string.h>
 #include <stdio.h>
 #include <unistd.h>
+#include <uapi/linux/mman.h> /* To get things like MAP_HUGETLB even on older libc headers */
 #include "map.h"
 #include "thread.h"
 #include "strlist.h"
@@ -24,9 +25,10 @@ const char *map_type__name[MAP__NR_TYPES] = {
        [MAP__VARIABLE] = "Variables",
 };
 
-static inline int is_anon_memory(const char *filename)
+static inline int is_anon_memory(const char *filename, u32 flags)
 {
-       return !strcmp(filename, "//anon") ||
+       return flags & MAP_HUGETLB ||
+              !strcmp(filename, "//anon") ||
               !strncmp(filename, "/dev/zero", sizeof("/dev/zero") - 1) ||
               !strncmp(filename, "/anon_hugepage", sizeof("/anon_hugepage") - 1);
 }
@@ -155,7 +157,7 @@ struct map *map__new(struct machine *machine, u64 start, u64 len,
                int anon, no_dso, vdso, android;
 
                android = is_android_lib(filename);
-               anon = is_anon_memory(filename);
+               anon = is_anon_memory(filename, flags);
                vdso = is_vdso_map(filename);
                no_dso = is_no_dso_memory(filename);
 
@@ -279,7 +281,7 @@ void map__fixup_end(struct map *map)
 
 #define DSO__DELETED "(deleted)"
 
-int map__load(struct map *map, symbol_filter_t filter)
+int map__load(struct map *map)
 {
        const char *name = map->dso->long_name;
        int nr;
@@ -287,7 +289,7 @@ int map__load(struct map *map, symbol_filter_t filter)
        if (dso__loaded(map->dso, map->type))
                return 0;
 
-       nr = dso__load(map->dso, map, filter);
+       nr = dso__load(map->dso, map);
        if (nr < 0) {
                if (map->dso->has_build_id) {
                        char sbuild_id[SBUILD_ID_SIZE];
@@ -312,9 +314,6 @@ int map__load(struct map *map, symbol_filter_t filter)
                        pr_warning("%.*s was updated (is prelink enabled?). "
                                "Restart the long running apps that use it!\n",
                                   (int)real_len, name);
-               } else if (filter) {
-                       pr_warning("no symbols passed the given filter.\n");
-                       return -2;      /* Empty but maybe by the filter */
                } else {
                        pr_warning("no symbols found in %s, maybe install "
                                   "a debug package?\n", name);
@@ -331,19 +330,17 @@ int __weak arch__compare_symbol_names(const char *namea, const char *nameb)
        return strcmp(namea, nameb);
 }
 
-struct symbol *map__find_symbol(struct map *map, u64 addr,
-                               symbol_filter_t filter)
+struct symbol *map__find_symbol(struct map *map, u64 addr)
 {
-       if (map__load(map, filter) < 0)
+       if (map__load(map) < 0)
                return NULL;
 
        return dso__find_symbol(map->dso, map->type, addr);
 }
 
-struct symbol *map__find_symbol_by_name(struct map *map, const char *name,
-                                       symbol_filter_t filter)
+struct symbol *map__find_symbol_by_name(struct map *map, const char *name)
 {
-       if (map__load(map, filter) < 0)
+       if (map__load(map) < 0)
                return NULL;
 
        if (!dso__sorted_by_name(map->dso, map->type))
@@ -556,23 +553,22 @@ void map_groups__put(struct map_groups *mg)
 
 struct symbol *map_groups__find_symbol(struct map_groups *mg,
                                       enum map_type type, u64 addr,
-                                      struct map **mapp,
-                                      symbol_filter_t filter)
+                                      struct map **mapp)
 {
        struct map *map = map_groups__find(mg, type, addr);
 
        /* Ensure map is loaded before using map->map_ip */
-       if (map != NULL && map__load(map, filter) >= 0) {
+       if (map != NULL && map__load(map) >= 0) {
                if (mapp != NULL)
                        *mapp = map;
-               return map__find_symbol(map, map->map_ip(map, addr), filter);
+               return map__find_symbol(map, map->map_ip(map, addr));
        }
 
        return NULL;
 }
 
 struct symbol *maps__find_symbol_by_name(struct maps *maps, const char *name,
-                                        struct map **mapp, symbol_filter_t filter)
+                                        struct map **mapp)
 {
        struct symbol *sym;
        struct rb_node *nd;
@@ -582,7 +578,7 @@ struct symbol *maps__find_symbol_by_name(struct maps *maps, const char *name,
        for (nd = rb_first(&maps->entries); nd; nd = rb_next(nd)) {
                struct map *pos = rb_entry(nd, struct map, rb_node);
 
-               sym = map__find_symbol_by_name(pos, name, filter);
+               sym = map__find_symbol_by_name(pos, name);
 
                if (sym == NULL)
                        continue;
@@ -600,15 +596,14 @@ out:
 struct symbol *map_groups__find_symbol_by_name(struct map_groups *mg,
                                               enum map_type type,
                                               const char *name,
-                                              struct map **mapp,
-                                              symbol_filter_t filter)
+                                              struct map **mapp)
 {
-       struct symbol *sym = maps__find_symbol_by_name(&mg->maps[type], name, mapp, filter);
+       struct symbol *sym = maps__find_symbol_by_name(&mg->maps[type], name, mapp);
 
        return sym;
 }
 
-int map_groups__find_ams(struct addr_map_symbol *ams, symbol_filter_t filter)
+int map_groups__find_ams(struct addr_map_symbol *ams)
 {
        if (ams->addr < ams->map->start || ams->addr >= ams->map->end) {
                if (ams->map->groups == NULL)
@@ -620,7 +615,7 @@ int map_groups__find_ams(struct addr_map_symbol *ams, symbol_filter_t filter)
        }
 
        ams->al_addr = ams->map->map_ip(ams->map, ams->addr);
-       ams->sym = map__find_symbol(ams->map, ams->al_addr, filter);
+       ams->sym = map__find_symbol(ams->map, ams->al_addr);
 
        return ams->sym ? 0 : -1;
 }
index d83396ceecba686450f3c398593b1824a8f8efbd..abdacf800c98a78148565f23b7d9b4c916cbacaf 100644 (file)
@@ -127,17 +127,14 @@ struct thread;
  * @map: the 'struct map *' in which symbols itereated
  * @sym_name: the symbol name
  * @pos: the 'struct symbol *' to use as a loop cursor
- * @filter: to use when loading the DSO
  */
-#define __map__for_each_symbol_by_name(map, sym_name, pos, filter)     \
-       for (pos = map__find_symbol_by_name(map, sym_name, filter);     \
+#define __map__for_each_symbol_by_name(map, sym_name, pos)     \
+       for (pos = map__find_symbol_by_name(map, sym_name);     \
             pos && arch__compare_symbol_names(pos->name, sym_name) == 0;       \
             pos = symbol__next_by_name(pos))
 
 #define map__for_each_symbol_by_name(map, sym_name, pos)               \
-       __map__for_each_symbol_by_name(map, sym_name, (pos), NULL)
-
-typedef int (*symbol_filter_t)(struct map *map, struct symbol *sym);
+       __map__for_each_symbol_by_name(map, sym_name, (pos))
 
 int arch__compare_symbol_names(const char *namea, const char *nameb);
 void map__init(struct map *map, enum map_type type,
@@ -173,11 +170,9 @@ size_t map__fprintf_dsoname(struct map *map, FILE *fp);
 int map__fprintf_srcline(struct map *map, u64 addr, const char *prefix,
                         FILE *fp);
 
-int map__load(struct map *map, symbol_filter_t filter);
-struct symbol *map__find_symbol(struct map *map,
-                               u64 addr, symbol_filter_t filter);
-struct symbol *map__find_symbol_by_name(struct map *map, const char *name,
-                                       symbol_filter_t filter);
+int map__load(struct map *map);
+struct symbol *map__find_symbol(struct map *map, u64 addr);
+struct symbol *map__find_symbol_by_name(struct map *map, const char *name);
 void map__fixup_start(struct map *map);
 void map__fixup_end(struct map *map);
 
@@ -191,7 +186,7 @@ struct map *maps__find(struct maps *maps, u64 addr);
 struct map *maps__first(struct maps *maps);
 struct map *map__next(struct map *map);
 struct symbol *maps__find_symbol_by_name(struct maps *maps, const char *name,
-                                         struct map **mapp, symbol_filter_t filter);
+                                         struct map **mapp);
 void map_groups__init(struct map_groups *mg, struct machine *machine);
 void map_groups__exit(struct map_groups *mg);
 int map_groups__clone(struct thread *thread,
@@ -231,25 +226,22 @@ static inline struct map *map_groups__next(struct map *map)
 
 struct symbol *map_groups__find_symbol(struct map_groups *mg,
                                       enum map_type type, u64 addr,
-                                      struct map **mapp,
-                                      symbol_filter_t filter);
+                                      struct map **mapp);
 
 struct symbol *map_groups__find_symbol_by_name(struct map_groups *mg,
                                               enum map_type type,
                                               const char *name,
-                                              struct map **mapp,
-                                              symbol_filter_t filter);
+                                              struct map **mapp);
 
 struct addr_map_symbol;
 
-int map_groups__find_ams(struct addr_map_symbol *ams, symbol_filter_t filter);
+int map_groups__find_ams(struct addr_map_symbol *ams);
 
 static inline
 struct symbol *map_groups__find_function_by_name(struct map_groups *mg,
-                                                const char *name, struct map **mapp,
-                                                symbol_filter_t filter)
+                                                const char *name, struct map **mapp)
 {
-       return map_groups__find_symbol_by_name(mg, MAP__FUNCTION, name, mapp, filter);
+       return map_groups__find_symbol_by_name(mg, MAP__FUNCTION, name, mapp);
 }
 
 int map_groups__fixup_overlappings(struct map_groups *mg, struct map *map,
index 6c913c3914fb92163a6f8cabda62c0282b64c38e..2eb8b1ed4cc8dcc2db13d9bbb8a8da6bb1f1f84f 100644 (file)
@@ -904,6 +904,7 @@ static const char *config_term_names[__PARSE_EVENTS__TERM_TYPE_NR] = {
        [PARSE_EVENTS__TERM_TYPE_MAX_STACK]             = "max-stack",
        [PARSE_EVENTS__TERM_TYPE_OVERWRITE]             = "overwrite",
        [PARSE_EVENTS__TERM_TYPE_NOOVERWRITE]           = "no-overwrite",
+       [PARSE_EVENTS__TERM_TYPE_DRV_CFG]               = "driver-config",
 };
 
 static bool config_term_shrinked;
@@ -1034,7 +1035,8 @@ static int config_term_pmu(struct perf_event_attr *attr,
                           struct parse_events_term *term,
                           struct parse_events_error *err)
 {
-       if (term->type_term == PARSE_EVENTS__TERM_TYPE_USER)
+       if (term->type_term == PARSE_EVENTS__TERM_TYPE_USER ||
+           term->type_term == PARSE_EVENTS__TERM_TYPE_DRV_CFG)
                /*
                 * Always succeed for sysfs terms, as we dont know
                 * at this point what type they need to have.
@@ -1134,6 +1136,9 @@ do {                                                              \
                case PARSE_EVENTS__TERM_TYPE_NOOVERWRITE:
                        ADD_CONFIG_TERM(OVERWRITE, overwrite, term->val.num ? 0 : 1);
                        break;
+               case PARSE_EVENTS__TERM_TYPE_DRV_CFG:
+                       ADD_CONFIG_TERM(DRV_CFG, drv_cfg, term->val.str);
+                       break;
                default:
                        break;
                }
index d1edbf8cc66a7704cf774c3f3fc80fee8f1a31bd..8d09a976fca80cb4a481158e79c1751c7f9a4f26 100644 (file)
@@ -71,6 +71,7 @@ enum {
        PARSE_EVENTS__TERM_TYPE_MAX_STACK,
        PARSE_EVENTS__TERM_TYPE_NOOVERWRITE,
        PARSE_EVENTS__TERM_TYPE_OVERWRITE,
+       PARSE_EVENTS__TERM_TYPE_DRV_CFG,
        __PARSE_EVENTS__TERM_TYPE_NR,
 };
 
index 7a2519435da05273febd9af1974637cbc1c5d8c7..9f43fda2570f959833c85b89aa29b3612c6d6abb 100644 (file)
@@ -53,6 +53,26 @@ static int str(yyscan_t scanner, int token)
        return token;
 }
 
+/*
+ * This function is called when the parser gets two kind of input:
+ *
+ *     @cfg1 or @cfg2=config
+ *
+ * The leading '@' is stripped off before 'cfg1' and 'cfg2=config' are given to
+ * bison.  In the latter case it is necessary to keep the string intact so that
+ * the PMU kernel driver can determine what configurable is associated to
+ * 'config'.
+ */
+static int drv_str(yyscan_t scanner, int token)
+{
+       YYSTYPE *yylval = parse_events_get_lval(scanner);
+       char *text = parse_events_get_text(scanner);
+
+       /* Strip off the '@' */
+       yylval->str = strdup(text + 1);
+       return token;
+}
+
 #define REWIND(__alloc)                                \
 do {                                                           \
        YYSTYPE *__yylval = parse_events_get_lval(yyscanner);   \
@@ -124,6 +144,7 @@ num_hex             0x[a-fA-F0-9]+
 num_raw_hex    [a-fA-F0-9]+
 name           [a-zA-Z_*?][a-zA-Z0-9_*?.]*
 name_minus     [a-zA-Z_*?][a-zA-Z0-9\-_*?.:]*
+drv_cfg_term   [a-zA-Z0-9_\.]+(=[a-zA-Z0-9_*?\.:]+)?
 /* If you add a modifier you need to update check_modifier() */
 modifier_event [ukhpPGHSDI]+
 modifier_bp    [rwx]{1,3}
@@ -209,6 +230,7 @@ no-overwrite                { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_NOOVERWRITE); }
 {name_minus}           { return str(yyscanner, PE_NAME); }
 \[all\]                        { return PE_ARRAY_ALL; }
 "["                    { BEGIN(array); return '['; }
+@{drv_cfg_term}                { return drv_str(yyscanner, PE_DRV_CFG_TERM); }
 }
 
 <mem>{
index 5be4a5f216d6d23889e07e225810fec40df67c30..879115f93edcdc52171b42fc6e544662b579da1f 100644 (file)
@@ -49,6 +49,7 @@ static void inc_group_count(struct list_head *list,
 %token PE_ERROR
 %token PE_PMU_EVENT_PRE PE_PMU_EVENT_SUF PE_KERNEL_PMU_EVENT
 %token PE_ARRAY_ALL PE_ARRAY_RANGE
+%token PE_DRV_CFG_TERM
 %type <num> PE_VALUE
 %type <num> PE_VALUE_SYM_HW
 %type <num> PE_VALUE_SYM_SW
@@ -63,6 +64,7 @@ static void inc_group_count(struct list_head *list,
 %type <str> PE_MODIFIER_BP
 %type <str> PE_EVENT_NAME
 %type <str> PE_PMU_EVENT_PRE PE_PMU_EVENT_SUF PE_KERNEL_PMU_EVENT
+%type <str> PE_DRV_CFG_TERM
 %type <num> value_sym
 %type <head> event_config
 %type <head> opt_event_config
@@ -599,6 +601,15 @@ PE_NAME array '=' PE_VALUE
        term->array = $2;
        $$ = term;
 }
+|
+PE_DRV_CFG_TERM
+{
+       struct parse_events_term *term;
+
+       ABORT_ON(parse_events_term__str(&term, PARSE_EVENTS__TERM_TYPE_DRV_CFG,
+                                       $1, $1, &@1, NULL));
+       $$ = term;
+}
 
 array:
 '[' array_terms ']'
index ddb0261b2577a2caf5fb532f7c343bd17cb9c972..2babcdf6283983b6cef131cca0e7bfb7df68cc06 100644 (file)
@@ -445,14 +445,23 @@ static struct cpu_map *pmu_cpumask(const char *name)
        FILE *file;
        struct cpu_map *cpus;
        const char *sysfs = sysfs__mountpoint();
+       const char *templates[] = {
+                "%s/bus/event_source/devices/%s/cpumask",
+                "%s/bus/event_source/devices/%s/cpus",
+                NULL
+       };
+       const char **template;
 
        if (!sysfs)
                return NULL;
 
-       snprintf(path, PATH_MAX,
-                "%s/bus/event_source/devices/%s/cpumask", sysfs, name);
+       for (template = templates; *template; template++) {
+               snprintf(path, PATH_MAX, *template, sysfs, name);
+               if (stat(path, &st) == 0)
+                       break;
+       }
 
-       if (stat(path, &st) < 0)
+       if (!*template)
                return NULL;
 
        file = fopen(path, "r");
index 28733962cd80a63e1376b5b71f4771ab8f8857f7..bc60ce49720ba1fae3ee77adf51e9b33e2caa00f 100644 (file)
@@ -110,13 +110,12 @@ void exit_probe_symbol_maps(void)
 static struct symbol *__find_kernel_function_by_name(const char *name,
                                                     struct map **mapp)
 {
-       return machine__find_kernel_function_by_name(host_machine, name, mapp,
-                                                    NULL);
+       return machine__find_kernel_function_by_name(host_machine, name, mapp);
 }
 
 static struct symbol *__find_kernel_function(u64 addr, struct map **mapp)
 {
-       return machine__find_kernel_function(host_machine, addr, mapp, NULL);
+       return machine__find_kernel_function(host_machine, addr, mapp);
 }
 
 static struct ref_reloc_sym *kernel_get_ref_reloc_sym(void)
@@ -125,7 +124,7 @@ static struct ref_reloc_sym *kernel_get_ref_reloc_sym(void)
        struct kmap *kmap;
        struct map *map = machine__kernel_map(host_machine);
 
-       if (map__load(map, NULL) < 0)
+       if (map__load(map) < 0)
                return NULL;
 
        kmap = map__kmap(map);
@@ -351,9 +350,9 @@ static int kernel_get_module_dso(const char *module, struct dso **pdso)
        vmlinux_name = symbol_conf.vmlinux_name;
        dso->load_errno = 0;
        if (vmlinux_name)
-               ret = dso__load_vmlinux(dso, map, vmlinux_name, false, NULL);
+               ret = dso__load_vmlinux(dso, map, vmlinux_name, false);
        else
-               ret = dso__load_vmlinux_path(dso, map, NULL);
+               ret = dso__load_vmlinux_path(dso, map);
 found:
        *pdso = dso;
        return ret;
@@ -674,6 +673,10 @@ post_process_kernel_probe_trace_events(struct probe_trace_event *tevs,
        char *tmp;
        int i, skipped = 0;
 
+       /* Skip post process if the target is an offline kernel */
+       if (symbol_conf.ignore_vmlinux_buildid)
+               return 0;
+
        reloc_sym = kernel_get_ref_reloc_sym();
        if (!reloc_sym) {
                pr_warning("Relocated base symbol is not found!\n");
@@ -1614,19 +1617,27 @@ out:
        return ret;
 }
 
+/* Returns true if *any* ARG is either C variable, $params or $vars. */
+bool perf_probe_with_var(struct perf_probe_event *pev)
+{
+       int i = 0;
+
+       for (i = 0; i < pev->nargs; i++)
+               if (is_c_varname(pev->args[i].var)              ||
+                   !strcmp(pev->args[i].var, PROBE_ARG_PARAMS) ||
+                   !strcmp(pev->args[i].var, PROBE_ARG_VARS))
+                       return true;
+       return false;
+}
+
 /* Return true if this perf_probe_event requires debuginfo */
 bool perf_probe_event_need_dwarf(struct perf_probe_event *pev)
 {
-       int i;
-
        if (pev->point.file || pev->point.line || pev->point.lazy_line)
                return true;
 
-       for (i = 0; i < pev->nargs; i++)
-               if (is_c_varname(pev->args[i].var) ||
-                   !strcmp(pev->args[i].var, "$params") ||
-                   !strcmp(pev->args[i].var, "$vars"))
-                       return true;
+       if (perf_probe_with_var(pev))
+               return true;
 
        return false;
 }
@@ -1987,7 +1998,7 @@ static int find_perf_probe_point_from_map(struct probe_trace_point *tp,
                map = dso__new_map(tp->module);
                if (!map)
                        goto out;
-               sym = map__find_symbol(map, addr, NULL);
+               sym = map__find_symbol(map, addr);
        } else {
                if (tp->symbol && !addr) {
                        if (kernel_get_symbol_address_by_name(tp->symbol,
@@ -2692,7 +2703,7 @@ static int find_probe_functions(struct map *map, char *name,
        struct symbol *sym;
        struct rb_node *tmp;
 
-       if (map__load(map, NULL) < 0)
+       if (map__load(map) < 0)
                return 0;
 
        map__for_each_symbol(map, sym, tmp) {
@@ -3207,6 +3218,52 @@ int convert_perf_probe_events(struct perf_probe_event *pevs, int npevs)
        return 0;
 }
 
+static int show_probe_trace_event(struct probe_trace_event *tev)
+{
+       char *buf = synthesize_probe_trace_command(tev);
+
+       if (!buf) {
+               pr_debug("Failed to synthesize probe trace event.\n");
+               return -EINVAL;
+       }
+
+       /* Showing definition always go stdout */
+       printf("%s\n", buf);
+       free(buf);
+
+       return 0;
+}
+
+int show_probe_trace_events(struct perf_probe_event *pevs, int npevs)
+{
+       struct strlist *namelist = strlist__new(NULL, NULL);
+       struct probe_trace_event *tev;
+       struct perf_probe_event *pev;
+       int i, j, ret = 0;
+
+       if (!namelist)
+               return -ENOMEM;
+
+       for (j = 0; j < npevs && !ret; j++) {
+               pev = &pevs[j];
+               for (i = 0; i < pev->ntevs && !ret; i++) {
+                       tev = &pev->tevs[i];
+                       /* Skip if the symbol is out of .text or blacklisted */
+                       if (!tev->point.symbol && !pev->uprobes)
+                               continue;
+
+                       /* Set new name for tev (and update namelist) */
+                       ret = probe_trace_event__set_name(tev, pev,
+                                                         namelist, true);
+                       if (!ret)
+                               ret = show_probe_trace_event(tev);
+               }
+       }
+       strlist__delete(namelist);
+
+       return ret;
+}
+
 int apply_perf_probe_events(struct perf_probe_event *pevs, int npevs)
 {
        int i, ret = 0;
@@ -3289,24 +3346,10 @@ out:
        return ret;
 }
 
-/* TODO: don't use a global variable for filter ... */
-static struct strfilter *available_func_filter;
-
-/*
- * If a symbol corresponds to a function with global binding and
- * matches filter return 0. For all others return 1.
- */
-static int filter_available_functions(struct map *map __maybe_unused,
-                                     struct symbol *sym)
-{
-       if (strfilter__compare(available_func_filter, sym->name))
-               return 0;
-       return 1;
-}
-
 int show_available_funcs(const char *target, struct strfilter *_filter,
                                        bool user)
 {
+        struct rb_node *nd;
        struct map *map;
        int ret;
 
@@ -3324,9 +3367,7 @@ int show_available_funcs(const char *target, struct strfilter *_filter,
                return -EINVAL;
        }
 
-       /* Load symbols with given filter */
-       available_func_filter = _filter;
-       ret = map__load(map, filter_available_functions);
+       ret = map__load(map);
        if (ret) {
                if (ret == -2) {
                        char *str = strfilter__string(_filter);
@@ -3343,7 +3384,14 @@ int show_available_funcs(const char *target, struct strfilter *_filter,
 
        /* Show all (filtered) symbols */
        setup_pager();
-       dso__fprintf_symbols_by_name(map->dso, map->type, stdout);
+
+        for (nd = rb_first(&map->dso->symbol_names[map->type]); nd; nd = rb_next(nd)) {
+               struct symbol_name_rb_node *pos = rb_entry(nd, struct symbol_name_rb_node, rb_node);
+
+               if (strfilter__compare(_filter, pos->sym.name))
+                       printf("%s\n", pos->sym.name);
+        }
+
 end:
        if (user) {
                map__put(map);
index f4f45db77c1c1ec59c3ee505f525f2b2561530ee..8091d15113f7a465437e8aa2e7d731583428fedd 100644 (file)
@@ -128,6 +128,8 @@ char *synthesize_perf_probe_point(struct perf_probe_point *pp);
 int perf_probe_event__copy(struct perf_probe_event *dst,
                           struct perf_probe_event *src);
 
+bool perf_probe_with_var(struct perf_probe_event *pev);
+
 /* Check the perf_probe_event needs debuginfo */
 bool perf_probe_event_need_dwarf(struct perf_probe_event *pev);
 
@@ -147,6 +149,7 @@ int line_range__init(struct line_range *lr);
 int add_perf_probe_events(struct perf_probe_event *pevs, int npevs);
 int convert_perf_probe_events(struct perf_probe_event *pevs, int npevs);
 int apply_perf_probe_events(struct perf_probe_event *pevs, int npevs);
+int show_probe_trace_events(struct perf_probe_event *pevs, int npevs);
 void cleanup_perf_probe_events(struct perf_probe_event *pevs, int npevs);
 int del_perf_probe_events(struct strfilter *filter);
 
index 9c3b9ed5b3c3ec68ee175b6bec91d1c90211798b..6f931e442f14ab157fed25fdb7ab282932943f8b 100644 (file)
@@ -73,11 +73,10 @@ static void print_both_open_warning(int kerr, int uerr)
 static int open_probe_events(const char *trace_file, bool readwrite)
 {
        char buf[PATH_MAX];
-       const char *tracing_dir = "";
        int ret;
 
-       ret = e_snprintf(buf, PATH_MAX, "%s/%s%s",
-                        tracing_path, tracing_dir, trace_file);
+       ret = e_snprintf(buf, PATH_MAX, "%s/%s",
+                        tracing_path, trace_file);
        if (ret >= 0) {
                pr_debug("Opening %s write=%d\n", buf, readwrite);
                if (readwrite && !probe_event_dry_run)
@@ -877,3 +876,60 @@ int probe_cache__show_all_caches(struct strfilter *filter)
 
        return 0;
 }
+
+static struct {
+       const char *pattern;
+       bool    avail;
+       bool    checked;
+} probe_type_table[] = {
+#define DEFINE_TYPE(idx, pat, def_avail)       \
+       [idx] = {.pattern = pat, .avail = (def_avail)}
+       DEFINE_TYPE(PROBE_TYPE_U, "* u8/16/32/64,*", true),
+       DEFINE_TYPE(PROBE_TYPE_S, "* s8/16/32/64,*", true),
+       DEFINE_TYPE(PROBE_TYPE_X, "* x8/16/32/64,*", false),
+       DEFINE_TYPE(PROBE_TYPE_STRING, "* string,*", true),
+       DEFINE_TYPE(PROBE_TYPE_BITFIELD,
+                   "* b<bit-width>@<bit-offset>/<container-size>", true),
+};
+
+bool probe_type_is_available(enum probe_type type)
+{
+       FILE *fp;
+       char *buf = NULL;
+       size_t len = 0;
+       bool target_line = false;
+       bool ret = probe_type_table[type].avail;
+
+       if (type >= PROBE_TYPE_END)
+               return false;
+       /* We don't have to check the type which supported by default */
+       if (ret || probe_type_table[type].checked)
+               return ret;
+
+       if (asprintf(&buf, "%s/README", tracing_path) < 0)
+               return ret;
+
+       fp = fopen(buf, "r");
+       if (!fp)
+               goto end;
+
+       zfree(&buf);
+       while (getline(&buf, &len, fp) > 0 && !ret) {
+               if (!target_line) {
+                       target_line = !!strstr(buf, " type: ");
+                       if (!target_line)
+                               continue;
+               } else if (strstr(buf, "\t          ") != buf)
+                       break;
+               ret = strglobmatch(buf, probe_type_table[type].pattern);
+       }
+       /* Cache the result */
+       probe_type_table[type].checked = true;
+       probe_type_table[type].avail = ret;
+
+       fclose(fp);
+end:
+       free(buf);
+
+       return ret;
+}
index 9577b5c0b487ee6adb017555521ad6dcd497a621..eba44c3e9dca9ac670d06736237feb49fb21734b 100644 (file)
@@ -19,6 +19,15 @@ struct probe_cache {
        struct list_head entries;
 };
 
+enum probe_type {
+       PROBE_TYPE_U = 0,
+       PROBE_TYPE_S,
+       PROBE_TYPE_X,
+       PROBE_TYPE_STRING,
+       PROBE_TYPE_BITFIELD,
+       PROBE_TYPE_END,
+};
+
 #define PF_FL_UPROBE   1
 #define PF_FL_RW       2
 #define for_each_probe_cache_entry(entry, pcache) \
@@ -54,6 +63,7 @@ struct probe_cache_entry *probe_cache__find(struct probe_cache *pcache,
 struct probe_cache_entry *probe_cache__find_by_name(struct probe_cache *pcache,
                                        const char *group, const char *event);
 int probe_cache__show_all_caches(struct strfilter *filter);
+bool probe_type_is_available(enum probe_type type);
 #else  /* ! HAVE_LIBELF_SUPPORT */
 static inline struct probe_cache *probe_cache__new(const char *tgt __maybe_unused)
 {
index 5c290c682afe7176607fe01f4d29742b1821f1a9..8daca4fc1f8d2189cd0450157968901d4ff8e760 100644 (file)
@@ -39,6 +39,7 @@
 #include "util.h"
 #include "symbol.h"
 #include "probe-finder.h"
+#include "probe-file.h"
 
 /* Kprobe tracer basic type is up to u64 */
 #define MAX_BASIC_TYPE_BITS    64
@@ -170,6 +171,7 @@ static struct probe_trace_arg_ref *alloc_trace_arg_ref(long offs)
  */
 static int convert_variable_location(Dwarf_Die *vr_die, Dwarf_Addr addr,
                                     Dwarf_Op *fb_ops, Dwarf_Die *sp_die,
+                                    unsigned int machine,
                                     struct probe_trace_arg *tvar)
 {
        Dwarf_Attribute attr;
@@ -265,7 +267,7 @@ static_var:
        if (!tvar)
                return ret2;
 
-       regs = get_arch_regstr(regn);
+       regs = get_dwarf_regstr(regn, machine);
        if (!regs) {
                /* This should be a bug in DWARF or this tool */
                pr_warning("Mapping for the register number %u "
@@ -297,13 +299,13 @@ static int convert_variable_type(Dwarf_Die *vr_die,
        char sbuf[STRERR_BUFSIZE];
        int bsize, boffs, total;
        int ret;
-       char sign;
+       char prefix;
 
        /* TODO: check all types */
-       if (cast && strcmp(cast, "string") != 0 &&
+       if (cast && strcmp(cast, "string") != 0 && strcmp(cast, "x") != 0 &&
            strcmp(cast, "s") != 0 && strcmp(cast, "u") != 0) {
                /* Non string type is OK */
-               /* and respect signedness cast */
+               /* and respect signedness/hexadecimal cast */
                tvar->type = strdup(cast);
                return (tvar->type == NULL) ? -ENOMEM : 0;
        }
@@ -365,11 +367,15 @@ static int convert_variable_type(Dwarf_Die *vr_die,
        }
 
        if (cast && (strcmp(cast, "u") == 0))
-               sign = 'u';
+               prefix = 'u';
        else if (cast && (strcmp(cast, "s") == 0))
-               sign = 's';
+               prefix = 's';
+       else if (cast && (strcmp(cast, "x") == 0) &&
+                probe_type_is_available(PROBE_TYPE_X))
+               prefix = 'x';
        else
-               sign = die_is_signed_type(&type) ? 's' : 'u';
+               prefix = die_is_signed_type(&type) ? 's' :
+                        probe_type_is_available(PROBE_TYPE_X) ? 'x' : 'u';
 
        ret = dwarf_bytesize(&type);
        if (ret <= 0)
@@ -383,7 +389,7 @@ static int convert_variable_type(Dwarf_Die *vr_die,
                        dwarf_diename(&type), MAX_BASIC_TYPE_BITS);
                ret = MAX_BASIC_TYPE_BITS;
        }
-       ret = snprintf(buf, 16, "%c%d", sign, ret);
+       ret = snprintf(buf, 16, "%c%d", prefix, ret);
 
 formatted:
        if (ret < 0 || ret >= 16) {
@@ -538,7 +544,7 @@ static int convert_variable(Dwarf_Die *vr_die, struct probe_finder *pf)
                 dwarf_diename(vr_die));
 
        ret = convert_variable_location(vr_die, pf->addr, pf->fb_ops,
-                                       &pf->sp_die, pf->tvar);
+                                       &pf->sp_die, pf->machine, pf->tvar);
        if (ret == -ENOENT || ret == -EINVAL) {
                pr_err("Failed to find the location of the '%s' variable at this address.\n"
                       " Perhaps it has been optimized out.\n"
@@ -901,6 +907,38 @@ static int find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf)
        return die_walk_lines(sp_die, probe_point_lazy_walker, pf);
 }
 
+static void skip_prologue(Dwarf_Die *sp_die, struct probe_finder *pf)
+{
+       struct perf_probe_point *pp = &pf->pev->point;
+
+       /* Not uprobe? */
+       if (!pf->pev->uprobes)
+               return;
+
+       /* Compiled with optimization? */
+       if (die_is_optimized_target(&pf->cu_die))
+               return;
+
+       /* Don't know entrypc? */
+       if (!pf->addr)
+               return;
+
+       /* Only FUNC and FUNC@SRC are eligible. */
+       if (!pp->function || pp->line || pp->retprobe || pp->lazy_line ||
+           pp->offset || pp->abs_address)
+               return;
+
+       /* Not interested in func parameter? */
+       if (!perf_probe_with_var(pf->pev))
+               return;
+
+       pr_info("Target program is compiled without optimization. Skipping prologue.\n"
+               "Probe on address 0x%" PRIx64 " to force probing at the function entry.\n\n",
+               pf->addr);
+
+       die_skip_prologue(sp_die, &pf->cu_die, &pf->addr);
+}
+
 static int probe_point_inline_cb(Dwarf_Die *in_die, void *data)
 {
        struct probe_finder *pf = data;
@@ -963,6 +1001,7 @@ static int probe_point_search_cb(Dwarf_Die *sp_die, void *data)
                if (pp->lazy_line)
                        param->retval = find_probe_point_lazy(sp_die, pf);
                else {
+                       skip_prologue(sp_die, pf);
                        pf->addr += pp->offset;
                        /* TODO: Check the address in this function */
                        param->retval = call_probe_finder(sp_die, pf);
@@ -1101,11 +1140,8 @@ static int debuginfo__find_probes(struct debuginfo *dbg,
                                  struct probe_finder *pf)
 {
        int ret = 0;
-
-#if _ELFUTILS_PREREQ(0, 142)
        Elf *elf;
        GElf_Ehdr ehdr;
-       GElf_Shdr shdr;
 
        if (pf->cfi_eh || pf->cfi_dbg)
                return debuginfo__find_probe_location(dbg, pf);
@@ -1118,11 +1154,18 @@ static int debuginfo__find_probes(struct debuginfo *dbg,
        if (gelf_getehdr(elf, &ehdr) == NULL)
                return -EINVAL;
 
-       if (elf_section_by_name(elf, &ehdr, &shdr, ".eh_frame", NULL) &&
-           shdr.sh_type == SHT_PROGBITS)
-               pf->cfi_eh = dwarf_getcfi_elf(elf);
+       pf->machine = ehdr.e_machine;
+
+#if _ELFUTILS_PREREQ(0, 142)
+       do {
+               GElf_Shdr shdr;
+
+               if (elf_section_by_name(elf, &ehdr, &shdr, ".eh_frame", NULL) &&
+                   shdr.sh_type == SHT_PROGBITS)
+                       pf->cfi_eh = dwarf_getcfi_elf(elf);
 
-       pf->cfi_dbg = dwarf_getcfi(dbg->dbg);
+               pf->cfi_dbg = dwarf_getcfi(dbg->dbg);
+       } while (0);
 #endif
 
        ret = debuginfo__find_probe_location(dbg, pf);
@@ -1150,7 +1193,7 @@ static int copy_variables_cb(Dwarf_Die *die_mem, void *data)
            (tag == DW_TAG_variable && vf->vars)) {
                if (convert_variable_location(die_mem, vf->pf->addr,
                                              vf->pf->fb_ops, &pf->sp_die,
-                                             NULL) == 0) {
+                                             pf->machine, NULL) == 0) {
                        vf->args[vf->nargs].var = (char *)dwarf_diename(die_mem);
                        if (vf->args[vf->nargs].var == NULL) {
                                vf->ret = -ENOMEM;
@@ -1313,7 +1356,7 @@ static int collect_variables_cb(Dwarf_Die *die_mem, void *data)
            tag == DW_TAG_variable) {
                ret = convert_variable_location(die_mem, af->pf.addr,
                                                af->pf.fb_ops, &af->pf.sp_die,
-                                               NULL);
+                                               af->pf.machine, NULL);
                if (ret == 0 || ret == -ERANGE) {
                        int ret2;
                        bool externs = !af->child;
index 51137fccb9c81abf96f2fc0559437f552f6254f6..f1d8558f498e96771c13b3f42046a757e888bdf2 100644 (file)
@@ -80,6 +80,7 @@ struct probe_finder {
        Dwarf_CFI               *cfi_dbg;
 #endif
        Dwarf_Op                *fb_ops;        /* Frame base attribute */
+       unsigned int            machine;        /* Target machine arch */
        struct perf_probe_arg   *pvar;          /* Current target variable */
        struct probe_trace_arg  *tvar;          /* Current result variable */
 };
index 5d1eb1ccd96c3e0cf73449c97aaee9246d1f9619..e55a132f69b73e23661bf1a6e21aaac36cbb85ad 100644 (file)
@@ -25,6 +25,7 @@
 #include <ctype.h>
 #include <errno.h>
 #include <linux/bitmap.h>
+#include <linux/time64.h>
 
 #include "../util.h"
 #include <EXTERN.h>
@@ -359,8 +360,8 @@ static void perl_process_tracepoint(struct perf_sample *sample,
        if (!test_and_set_bit(event->id, events_defined))
                define_event_symbols(event, handler, event->print_fmt.args);
 
-       s = nsecs / NSECS_PER_SEC;
-       ns = nsecs - s * NSECS_PER_SEC;
+       s = nsecs / NSEC_PER_SEC;
+       ns = nsecs - s * NSEC_PER_SEC;
 
        scripting_context->event_data = data;
        scripting_context->pevent = evsel->tp_format->pevent;
index e0203b97947483d82042c3a568f01c73878eb6a9..089438da1f7f76b2318dd2f5b10bc039441e2fc4 100644 (file)
@@ -27,6 +27,7 @@
 #include <stdbool.h>
 #include <errno.h>
 #include <linux/bitmap.h>
+#include <linux/time64.h>
 
 #include "../../perf.h"
 #include "../debug.h"
@@ -426,8 +427,8 @@ static void python_process_tracepoint(struct perf_sample *sample,
                if (!dict)
                        Py_FatalError("couldn't create Python dict");
        }
-       s = nsecs / NSECS_PER_SEC;
-       ns = nsecs - s * NSECS_PER_SEC;
+       s = nsecs / NSEC_PER_SEC;
+       ns = nsecs - s * NSEC_PER_SEC;
 
        scripting_context->event_data = data;
        scripting_context->pevent = evsel->tp_format->pevent;
index 3d3cb8392c86029bb488f737564730e0cd8995bc..1884d7f9b9d2abc516653c479ab3dfb85ecf8a70 100644 (file)
@@ -11,7 +11,7 @@
 regex_t                parent_regex;
 const char     default_parent_pattern[] = "^sys_|^do_page_fault";
 const char     *parent_pattern = default_parent_pattern;
-const char     default_sort_order[] = "comm,dso,symbol";
+const char     *default_sort_order = "comm,dso,symbol";
 const char     default_branch_sort_order[] = "comm,dso_from,symbol_from,symbol_to,cycles";
 const char     default_mem_sort_order[] = "local_weight,mem,sym,dso,symbol_daddr,dso_daddr,snoop,tlb,locked";
 const char     default_top_sort_order[] = "dso,symbol";
@@ -1492,7 +1492,8 @@ void perf_hpp__reset_sort_width(struct perf_hpp_fmt *fmt, struct hists *hists)
 }
 
 static int __sort__hpp_header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
-                             struct hists *hists)
+                             struct hists *hists, int line __maybe_unused,
+                             int *span __maybe_unused)
 {
        struct hpp_sort_entry *hse;
        size_t len = fmt->user_len;
@@ -1797,7 +1798,9 @@ static void update_dynamic_len(struct hpp_dynamic_entry *hde,
 }
 
 static int __sort__hde_header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
-                             struct hists *hists __maybe_unused)
+                             struct hists *hists __maybe_unused,
+                             int line __maybe_unused,
+                             int *span __maybe_unused)
 {
        struct hpp_dynamic_entry *hde;
        size_t len = fmt->user_len;
index 7ca37ea1739559e1e3f064c9260d5d078cb5b84f..9505483cb95cbaf40a9082b46371a2e0287f91b9 100644 (file)
@@ -28,7 +28,7 @@ extern const char *sort_order;
 extern const char *field_order;
 extern const char default_parent_pattern[];
 extern const char *parent_pattern;
-extern const char default_sort_order[];
+extern const char *default_sort_order;
 extern regex_t ignore_callees_regex;
 extern int have_ignore_callees;
 extern enum sort_mode sort__mode;
@@ -40,6 +40,7 @@ extern struct sort_entry sort_dso_from;
 extern struct sort_entry sort_dso_to;
 extern struct sort_entry sort_sym_from;
 extern struct sort_entry sort_sym_to;
+extern struct sort_entry sort_srcline;
 extern enum sort_type sort__first_dimension;
 extern const char default_mem_sort_order[];
 
index eec6c1149f44758ebe22c37fb07cd4cd6fd0aef7..1cbada2dc6be67fc9afeb0c4298aafe17824ac3f 100644 (file)
@@ -18,6 +18,7 @@
 #include <unistd.h>
 #include <string.h>
 #include <linux/bitmap.h>
+#include <linux/time64.h>
 
 #include "perf.h"
 #include "svghelper.h"
@@ -274,14 +275,14 @@ static char *time_to_string(u64 duration)
 
        text[0] = 0;
 
-       if (duration < 1000) /* less than 1 usec */
+       if (duration < NSEC_PER_USEC) /* less than 1 usec */
                return text;
 
-       if (duration < 1000 * 1000) { /* less than 1 msec */
-               sprintf(text, "%.1f us", duration / 1000.0);
+       if (duration < NSEC_PER_MSEC) { /* less than 1 msec */
+               sprintf(text, "%.1f us", duration / (double)NSEC_PER_USEC);
                return text;
        }
-       sprintf(text, "%.1f ms", duration / 1000.0 / 1000);
+       sprintf(text, "%.1f ms", duration / (double)NSEC_PER_MSEC);
 
        return text;
 }
@@ -297,7 +298,7 @@ void svg_waiting(int Yslot, int cpu, u64 start, u64 end, const char *backtrace)
 
        style = "waiting";
 
-       if (end-start > 10 * 1000000) /* 10 msec */
+       if (end-start > 10 * NSEC_PER_MSEC) /* 10 msec */
                style = "WAITING";
 
        text = time_to_string(end-start);
index a811c13a74d663ac40efdf03333145450e7d7c19..99400b0e8f2a892dcfbfe2572758ef3eae73be59 100644 (file)
@@ -206,6 +206,37 @@ Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep,
        return NULL;
 }
 
+static bool want_demangle(bool is_kernel_sym)
+{
+       return is_kernel_sym ? symbol_conf.demangle_kernel : symbol_conf.demangle;
+}
+
+static char *demangle_sym(struct dso *dso, int kmodule, const char *elf_name)
+{
+       int demangle_flags = verbose ? (DMGL_PARAMS | DMGL_ANSI) : DMGL_NO_OPTS;
+       char *demangled = NULL;
+
+       /*
+        * We need to figure out if the object was created from C++ sources
+        * DWARF DW_compile_unit has this, but we don't always have access
+        * to it...
+        */
+       if (!want_demangle(dso->kernel || kmodule))
+           return demangled;
+
+       demangled = bfd_demangle(NULL, elf_name, demangle_flags);
+       if (demangled == NULL)
+               demangled = java_demangle_sym(elf_name, JAVA_DEMANGLE_NORET);
+       else if (rust_is_mangled(demangled))
+               /*
+                   * Input to Rust demangling is the BFD-demangled
+                   * name which it Rust-demangles in place.
+                   */
+               rust_demangle_sym(demangled);
+
+       return demangled;
+}
+
 #define elf_section__for_each_rel(reldata, pos, pos_mem, idx, nr_entries) \
        for (idx = 0, pos = gelf_getrel(reldata, 0, &pos_mem); \
             idx < nr_entries; \
@@ -223,8 +254,7 @@ Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep,
  * And always look at the original dso, not at debuginfo packages, that
  * have the PLT data stripped out (shdr_rel_plt.sh_type == SHT_NOBITS).
  */
-int dso__synthesize_plt_symbols(struct dso *dso, struct symsrc *ss, struct map *map,
-                               symbol_filter_t filter)
+int dso__synthesize_plt_symbols(struct dso *dso, struct symsrc *ss, struct map *map)
 {
        uint32_t nr_rel_entries, idx;
        GElf_Sym sym;
@@ -301,45 +331,53 @@ int dso__synthesize_plt_symbols(struct dso *dso, struct symsrc *ss, struct map *
 
                elf_section__for_each_rela(reldata, pos, pos_mem, idx,
                                           nr_rel_entries) {
+                       const char *elf_name = NULL;
+                       char *demangled = NULL;
                        symidx = GELF_R_SYM(pos->r_info);
                        plt_offset += shdr_plt.sh_entsize;
                        gelf_getsym(syms, symidx, &sym);
+
+                       elf_name = elf_sym__name(&sym, symstrs);
+                       demangled = demangle_sym(dso, 0, elf_name);
+                       if (demangled != NULL)
+                               elf_name = demangled;
                        snprintf(sympltname, sizeof(sympltname),
-                                "%s@plt", elf_sym__name(&sym, symstrs));
+                                "%s@plt", elf_name);
+                       free(demangled);
 
                        f = symbol__new(plt_offset, shdr_plt.sh_entsize,
                                        STB_GLOBAL, sympltname);
                        if (!f)
                                goto out_elf_end;
 
-                       if (filter && filter(map, f))
-                               symbol__delete(f);
-                       else {
-                               symbols__insert(&dso->symbols[map->type], f);
-                               ++nr;
-                       }
+                       symbols__insert(&dso->symbols[map->type], f);
+                       ++nr;
                }
        } else if (shdr_rel_plt.sh_type == SHT_REL) {
                GElf_Rel pos_mem, *pos;
                elf_section__for_each_rel(reldata, pos, pos_mem, idx,
                                          nr_rel_entries) {
+                       const char *elf_name = NULL;
+                       char *demangled = NULL;
                        symidx = GELF_R_SYM(pos->r_info);
                        plt_offset += shdr_plt.sh_entsize;
                        gelf_getsym(syms, symidx, &sym);
+
+                       elf_name = elf_sym__name(&sym, symstrs);
+                       demangled = demangle_sym(dso, 0, elf_name);
+                       if (demangled != NULL)
+                               elf_name = demangled;
                        snprintf(sympltname, sizeof(sympltname),
-                                "%s@plt", elf_sym__name(&sym, symstrs));
+                                "%s@plt", elf_name);
+                       free(demangled);
 
                        f = symbol__new(plt_offset, shdr_plt.sh_entsize,
                                        STB_GLOBAL, sympltname);
                        if (!f)
                                goto out_elf_end;
 
-                       if (filter && filter(map, f))
-                               symbol__delete(f);
-                       else {
-                               symbols__insert(&dso->symbols[map->type], f);
-                               ++nr;
-                       }
+                       symbols__insert(&dso->symbols[map->type], f);
+                       ++nr;
                }
        }
 
@@ -685,7 +723,7 @@ int symsrc__init(struct symsrc *ss, struct dso *dso, const char *name,
        }
 
        /* Always reject images with a mismatched build-id: */
-       if (dso->has_build_id) {
+       if (dso->has_build_id && !symbol_conf.ignore_vmlinux_buildid) {
                u8 build_id[BUILD_ID_SIZE];
 
                if (elf_read_build_id(elf, build_id, BUILD_ID_SIZE) < 0) {
@@ -775,17 +813,11 @@ static u64 ref_reloc(struct kmap *kmap)
        return 0;
 }
 
-static bool want_demangle(bool is_kernel_sym)
-{
-       return is_kernel_sym ? symbol_conf.demangle_kernel : symbol_conf.demangle;
-}
-
 void __weak arch__sym_update(struct symbol *s __maybe_unused,
                GElf_Sym *sym __maybe_unused) { }
 
-int dso__load_sym(struct dso *dso, struct map *map,
-                 struct symsrc *syms_ss, struct symsrc *runtime_ss,
-                 symbol_filter_t filter, int kmodule)
+int dso__load_sym(struct dso *dso, struct map *map, struct symsrc *syms_ss,
+                 struct symsrc *runtime_ss, int kmodule)
 {
        struct kmap *kmap = dso->kernel ? map__kmap(map) : NULL;
        struct map_groups *kmaps = kmap ? map__kmaps(map) : NULL;
@@ -1070,29 +1102,10 @@ int dso__load_sym(struct dso *dso, struct map *map,
                        sym.st_value -= shdr.sh_addr - shdr.sh_offset;
                }
 new_symbol:
-               /*
-                * We need to figure out if the object was created from C++ sources
-                * DWARF DW_compile_unit has this, but we don't always have access
-                * to it...
-                */
-               if (want_demangle(dso->kernel || kmodule)) {
-                       int demangle_flags = DMGL_NO_OPTS;
-                       if (verbose)
-                               demangle_flags = DMGL_PARAMS | DMGL_ANSI;
-
-                       demangled = bfd_demangle(NULL, elf_name, demangle_flags);
-                       if (demangled == NULL)
-                               demangled = java_demangle_sym(elf_name, JAVA_DEMANGLE_NORET);
-                       else if (rust_is_mangled(demangled))
-                               /*
-                                * Input to Rust demangling is the BFD-demangled
-                                * name which it Rust-demangles in place.
-                                */
-                               rust_demangle_sym(demangled);
+               demangled = demangle_sym(dso, kmodule, elf_name);
+               if (demangled != NULL)
+                       elf_name = demangled;
 
-                       if (demangled != NULL)
-                               elf_name = demangled;
-               }
                f = symbol__new(sym.st_value, sym.st_size,
                                GELF_ST_BIND(sym.st_info), elf_name);
                free(demangled);
@@ -1101,21 +1114,16 @@ new_symbol:
 
                arch__sym_update(f, &sym);
 
-               if (filter && filter(curr_map, f))
-                       symbol__delete(f);
-               else {
-                       symbols__insert(&curr_dso->symbols[curr_map->type], f);
-                       nr++;
-               }
+               __symbols__insert(&curr_dso->symbols[curr_map->type], f, dso->kernel);
+               nr++;
        }
 
        /*
         * For misannotated, zeroed, ASM function sizes.
         */
        if (nr > 0) {
-               if (!symbol_conf.allow_aliases)
-                       symbols__fixup_duplicate(&dso->symbols[map->type]);
                symbols__fixup_end(&dso->symbols[map->type]);
+               symbols__fixup_duplicate(&dso->symbols[map->type]);
                if (kmap) {
                        /*
                         * We need to fixup this here too because we create new
index 48906333a858c06b41991f33cb0f5f2cdd4f68d9..11cdde9805455b52563af827a9d9d352bd2ede35 100644 (file)
@@ -287,8 +287,7 @@ void symsrc__destroy(struct symsrc *ss)
 
 int dso__synthesize_plt_symbols(struct dso *dso __maybe_unused,
                                struct symsrc *ss __maybe_unused,
-                               struct map *map __maybe_unused,
-                               symbol_filter_t filter __maybe_unused)
+                               struct map *map __maybe_unused)
 {
        return 0;
 }
@@ -334,7 +333,6 @@ enum dso_type dso__type_fd(int fd)
 int dso__load_sym(struct dso *dso, struct map *map __maybe_unused,
                  struct symsrc *ss,
                  struct symsrc *runtime_ss __maybe_unused,
-                 symbol_filter_t filter __maybe_unused,
                  int kmodule __maybe_unused)
 {
        unsigned char build_id[BUILD_ID_SIZE];
index 37e8d20ae03e29ef2a9fbc48e048858a4f820785..19c9c558454f671684938147b1061635b3f188f0 100644 (file)
@@ -9,6 +9,7 @@
 #include <fcntl.h>
 #include <unistd.h>
 #include <inttypes.h>
+#include "annotate.h"
 #include "build-id.h"
 #include "util.h"
 #include "debug.h"
 #include <symbol/kallsyms.h>
 #include <sys/utsname.h>
 
-static int dso__load_kernel_sym(struct dso *dso, struct map *map,
-                               symbol_filter_t filter);
-static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map,
-                       symbol_filter_t filter);
+static int dso__load_kernel_sym(struct dso *dso, struct map *map);
+static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map);
+static bool symbol__is_idle(const char *name);
+
 int vmlinux_path__nr_entries;
 char **vmlinux_path;
 
@@ -152,6 +153,9 @@ void symbols__fixup_duplicate(struct rb_root *symbols)
        struct rb_node *nd;
        struct symbol *curr, *next;
 
+       if (symbol_conf.allow_aliases)
+               return;
+
        nd = rb_first(symbols);
 
        while (nd) {
@@ -235,8 +239,13 @@ struct symbol *symbol__new(u64 start, u64 len, u8 binding, const char *name)
        if (sym == NULL)
                return NULL;
 
-       if (symbol_conf.priv_size)
+       if (symbol_conf.priv_size) {
+               if (symbol_conf.init_annotation) {
+                       struct annotation *notes = (void *)sym;
+                       pthread_mutex_init(&notes->lock, NULL);
+               }
                sym = ((void *)sym) + symbol_conf.priv_size;
+       }
 
        sym->start   = start;
        sym->end     = len ? start + len : start;
@@ -268,13 +277,24 @@ void symbols__delete(struct rb_root *symbols)
        }
 }
 
-void symbols__insert(struct rb_root *symbols, struct symbol *sym)
+void __symbols__insert(struct rb_root *symbols, struct symbol *sym, bool kernel)
 {
        struct rb_node **p = &symbols->rb_node;
        struct rb_node *parent = NULL;
        const u64 ip = sym->start;
        struct symbol *s;
 
+       if (kernel) {
+               const char *name = sym->name;
+               /*
+                * ppc64 uses function descriptors and appends a '.' to the
+                * start of every instruction address. Remove it.
+                */
+               if (name[0] == '.')
+                       name++;
+               sym->idle = symbol__is_idle(name);
+       }
+
        while (*p != NULL) {
                parent = *p;
                s = rb_entry(parent, struct symbol, rb_node);
@@ -287,6 +307,11 @@ void symbols__insert(struct rb_root *symbols, struct symbol *sym)
        rb_insert_color(&sym->rb_node, symbols);
 }
 
+void symbols__insert(struct rb_root *symbols, struct symbol *sym)
+{
+       __symbols__insert(symbols, sym, false);
+}
+
 static struct symbol *symbols__find(struct rb_root *symbols, u64 ip)
 {
        struct rb_node *n;
@@ -415,7 +440,7 @@ void dso__reset_find_symbol_cache(struct dso *dso)
 
 void dso__insert_symbol(struct dso *dso, enum map_type type, struct symbol *sym)
 {
-       symbols__insert(&dso->symbols[type], sym);
+       __symbols__insert(&dso->symbols[type], sym, dso->kernel);
 
        /* update the symbol cache if necessary */
        if (dso->last_find_result[type].addr >= sym->start &&
@@ -537,7 +562,7 @@ struct process_kallsyms_args {
  * These are symbols in the kernel image, so make sure that
  * sym is from a kernel DSO.
  */
-bool symbol__is_idle(struct symbol *sym)
+static bool symbol__is_idle(const char *name)
 {
        const char * const idle_symbols[] = {
                "cpu_idle",
@@ -554,14 +579,10 @@ bool symbol__is_idle(struct symbol *sym)
                "pseries_dedicated_idle_sleep",
                NULL
        };
-
        int i;
 
-       if (!sym)
-               return false;
-
        for (i = 0; idle_symbols[i]; i++) {
-               if (!strcmp(idle_symbols[i], sym->name))
+               if (!strcmp(idle_symbols[i], name))
                        return true;
        }
 
@@ -590,7 +611,7 @@ static int map__process_kallsym_symbol(void *arg, const char *name,
         * We will pass the symbols to the filter later, in
         * map__split_kallsyms, when we have split the maps per module
         */
-       symbols__insert(root, sym);
+       __symbols__insert(root, sym, !strchr(name, '['));
 
        return 0;
 }
@@ -607,8 +628,7 @@ static int dso__load_all_kallsyms(struct dso *dso, const char *filename,
        return kallsyms__parse(filename, &args, map__process_kallsym_symbol);
 }
 
-static int dso__split_kallsyms_for_kcore(struct dso *dso, struct map *map,
-                                        symbol_filter_t filter)
+static int dso__split_kallsyms_for_kcore(struct dso *dso, struct map *map)
 {
        struct map_groups *kmaps = map__kmaps(map);
        struct map *curr_map;
@@ -637,7 +657,7 @@ static int dso__split_kallsyms_for_kcore(struct dso *dso, struct map *map,
 
                curr_map = map_groups__find(kmaps, map->type, pos->start);
 
-               if (!curr_map || (filter && filter(curr_map, pos))) {
+               if (!curr_map) {
                        symbol__delete(pos);
                        continue;
                }
@@ -660,8 +680,7 @@ static int dso__split_kallsyms_for_kcore(struct dso *dso, struct map *map,
  * kernel range is broken in several maps, named [kernel].N, as we don't have
  * the original ELF section names vmlinux have.
  */
-static int dso__split_kallsyms(struct dso *dso, struct map *map, u64 delta,
-                              symbol_filter_t filter)
+static int dso__split_kallsyms(struct dso *dso, struct map *map, u64 delta)
 {
        struct map_groups *kmaps = map__kmaps(map);
        struct machine *machine;
@@ -738,7 +757,7 @@ static int dso__split_kallsyms(struct dso *dso, struct map *map, u64 delta,
 
                        if (count == 0) {
                                curr_map = map;
-                               goto filter_symbol;
+                               goto add_symbol;
                        }
 
                        if (dso->kernel == DSO_TYPE_GUEST_KERNEL)
@@ -770,18 +789,18 @@ static int dso__split_kallsyms(struct dso *dso, struct map *map, u64 delta,
                        pos->start -= delta;
                        pos->end -= delta;
                }
-filter_symbol:
-               if (filter && filter(curr_map, pos)) {
-discard_symbol:                rb_erase(&pos->rb_node, root);
-                       symbol__delete(pos);
-               } else {
-                       if (curr_map != map) {
-                               rb_erase(&pos->rb_node, root);
-                               symbols__insert(&curr_map->dso->symbols[curr_map->type], pos);
-                               ++moved;
-                       } else
-                               ++count;
-               }
+add_symbol:
+               if (curr_map != map) {
+                       rb_erase(&pos->rb_node, root);
+                       symbols__insert(&curr_map->dso->symbols[curr_map->type], pos);
+                       ++moved;
+               } else
+                       ++count;
+
+               continue;
+discard_symbol:
+               rb_erase(&pos->rb_node, root);
+               symbol__delete(pos);
        }
 
        if (curr_map != map &&
@@ -1221,7 +1240,7 @@ static int kallsyms__delta(struct map *map, const char *filename, u64 *delta)
 }
 
 int __dso__load_kallsyms(struct dso *dso, const char *filename,
-                        struct map *map, bool no_kcore, symbol_filter_t filter)
+                        struct map *map, bool no_kcore)
 {
        u64 delta = 0;
 
@@ -1234,8 +1253,8 @@ int __dso__load_kallsyms(struct dso *dso, const char *filename,
        if (kallsyms__delta(map, filename, &delta))
                return -1;
 
-       symbols__fixup_duplicate(&dso->symbols[map->type]);
        symbols__fixup_end(&dso->symbols[map->type]);
+       symbols__fixup_duplicate(&dso->symbols[map->type]);
 
        if (dso->kernel == DSO_TYPE_GUEST_KERNEL)
                dso->symtab_type = DSO_BINARY_TYPE__GUEST_KALLSYMS;
@@ -1243,19 +1262,18 @@ int __dso__load_kallsyms(struct dso *dso, const char *filename,
                dso->symtab_type = DSO_BINARY_TYPE__KALLSYMS;
 
        if (!no_kcore && !dso__load_kcore(dso, map, filename))
-               return dso__split_kallsyms_for_kcore(dso, map, filter);
+               return dso__split_kallsyms_for_kcore(dso, map);
        else
-               return dso__split_kallsyms(dso, map, delta, filter);
+               return dso__split_kallsyms(dso, map, delta);
 }
 
 int dso__load_kallsyms(struct dso *dso, const char *filename,
-                      struct map *map, symbol_filter_t filter)
+                      struct map *map)
 {
-       return __dso__load_kallsyms(dso, filename, map, false, filter);
+       return __dso__load_kallsyms(dso, filename, map, false);
 }
 
-static int dso__load_perf_map(struct dso *dso, struct map *map,
-                             symbol_filter_t filter)
+static int dso__load_perf_map(struct dso *dso, struct map *map)
 {
        char *line = NULL;
        size_t n;
@@ -1297,12 +1315,8 @@ static int dso__load_perf_map(struct dso *dso, struct map *map,
                if (sym == NULL)
                        goto out_delete_line;
 
-               if (filter && filter(map, sym))
-                       symbol__delete(sym);
-               else {
-                       symbols__insert(&dso->symbols[map->type], sym);
-                       nr_syms++;
-               }
+               symbols__insert(&dso->symbols[map->type], sym);
+               nr_syms++;
        }
 
        free(line);
@@ -1358,7 +1372,7 @@ static bool dso__is_compatible_symtab_type(struct dso *dso, bool kmod,
        }
 }
 
-int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
+int dso__load(struct dso *dso, struct map *map)
 {
        char *name;
        int ret = -1;
@@ -1381,9 +1395,9 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
 
        if (dso->kernel) {
                if (dso->kernel == DSO_TYPE_KERNEL)
-                       ret = dso__load_kernel_sym(dso, map, filter);
+                       ret = dso__load_kernel_sym(dso, map);
                else if (dso->kernel == DSO_TYPE_GUEST_KERNEL)
-                       ret = dso__load_guest_kernel_sym(dso, map, filter);
+                       ret = dso__load_guest_kernel_sym(dso, map);
 
                goto out;
        }
@@ -1407,7 +1421,7 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
                        goto out;
                }
 
-               ret = dso__load_perf_map(dso, map, filter);
+               ret = dso__load_perf_map(dso, map);
                dso->symtab_type = ret > 0 ? DSO_BINARY_TYPE__JAVA_JIT :
                                             DSO_BINARY_TYPE__NOT_FOUND;
                goto out;
@@ -1498,14 +1512,14 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
                        kmod = true;
 
        if (syms_ss)
-               ret = dso__load_sym(dso, map, syms_ss, runtime_ss, filter, kmod);
+               ret = dso__load_sym(dso, map, syms_ss, runtime_ss, kmod);
        else
                ret = -1;
 
        if (ret > 0) {
                int nr_plt;
 
-               nr_plt = dso__synthesize_plt_symbols(dso, runtime_ss, map, filter);
+               nr_plt = dso__synthesize_plt_symbols(dso, runtime_ss, map);
                if (nr_plt > 0)
                        ret += nr_plt;
        }
@@ -1544,8 +1558,7 @@ out_unlock:
 }
 
 int dso__load_vmlinux(struct dso *dso, struct map *map,
-                     const char *vmlinux, bool vmlinux_allocated,
-                     symbol_filter_t filter)
+                     const char *vmlinux, bool vmlinux_allocated)
 {
        int err = -1;
        struct symsrc ss;
@@ -1565,7 +1578,7 @@ int dso__load_vmlinux(struct dso *dso, struct map *map,
        if (symsrc__init(&ss, dso, symfs_vmlinux, symtab_type))
                return -1;
 
-       err = dso__load_sym(dso, map, &ss, &ss, filter, 0);
+       err = dso__load_sym(dso, map, &ss, &ss, 0);
        symsrc__destroy(&ss);
 
        if (err > 0) {
@@ -1581,8 +1594,7 @@ int dso__load_vmlinux(struct dso *dso, struct map *map,
        return err;
 }
 
-int dso__load_vmlinux_path(struct dso *dso, struct map *map,
-                          symbol_filter_t filter)
+int dso__load_vmlinux_path(struct dso *dso, struct map *map)
 {
        int i, err = 0;
        char *filename = NULL;
@@ -1591,7 +1603,7 @@ int dso__load_vmlinux_path(struct dso *dso, struct map *map,
                 vmlinux_path__nr_entries + 1);
 
        for (i = 0; i < vmlinux_path__nr_entries; ++i) {
-               err = dso__load_vmlinux(dso, map, vmlinux_path[i], false, filter);
+               err = dso__load_vmlinux(dso, map, vmlinux_path[i], false);
                if (err > 0)
                        goto out;
        }
@@ -1599,7 +1611,7 @@ int dso__load_vmlinux_path(struct dso *dso, struct map *map,
        if (!symbol_conf.ignore_vmlinux_buildid)
                filename = dso__build_id_filename(dso, NULL, 0);
        if (filename != NULL) {
-               err = dso__load_vmlinux(dso, map, filename, true, filter);
+               err = dso__load_vmlinux(dso, map, filename, true);
                if (err > 0)
                        goto out;
                free(filename);
@@ -1713,8 +1725,7 @@ proc_kallsyms:
        return strdup(path);
 }
 
-static int dso__load_kernel_sym(struct dso *dso, struct map *map,
-                               symbol_filter_t filter)
+static int dso__load_kernel_sym(struct dso *dso, struct map *map)
 {
        int err;
        const char *kallsyms_filename = NULL;
@@ -1740,12 +1751,11 @@ static int dso__load_kernel_sym(struct dso *dso, struct map *map,
        }
 
        if (!symbol_conf.ignore_vmlinux && symbol_conf.vmlinux_name != NULL) {
-               return dso__load_vmlinux(dso, map, symbol_conf.vmlinux_name,
-                                        false, filter);
+               return dso__load_vmlinux(dso, map, symbol_conf.vmlinux_name, false);
        }
 
        if (!symbol_conf.ignore_vmlinux && vmlinux_path != NULL) {
-               err = dso__load_vmlinux_path(dso, map, filter);
+               err = dso__load_vmlinux_path(dso, map);
                if (err > 0)
                        return err;
        }
@@ -1761,7 +1771,7 @@ static int dso__load_kernel_sym(struct dso *dso, struct map *map,
        kallsyms_filename = kallsyms_allocated_filename;
 
 do_kallsyms:
-       err = dso__load_kallsyms(dso, kallsyms_filename, map, filter);
+       err = dso__load_kallsyms(dso, kallsyms_filename, map);
        if (err > 0)
                pr_debug("Using %s for symbols\n", kallsyms_filename);
        free(kallsyms_allocated_filename);
@@ -1776,8 +1786,7 @@ do_kallsyms:
        return err;
 }
 
-static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map,
-                                     symbol_filter_t filter)
+static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map)
 {
        int err;
        const char *kallsyms_filename = NULL;
@@ -1799,7 +1808,7 @@ static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map,
                if (symbol_conf.default_guest_vmlinux_name != NULL) {
                        err = dso__load_vmlinux(dso, map,
                                                symbol_conf.default_guest_vmlinux_name,
-                                               false, filter);
+                                               false);
                        return err;
                }
 
@@ -1811,7 +1820,7 @@ static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map,
                kallsyms_filename = path;
        }
 
-       err = dso__load_kallsyms(dso, kallsyms_filename, map, filter);
+       err = dso__load_kallsyms(dso, kallsyms_filename, map);
        if (err > 0)
                pr_debug("Using %s for symbols\n", kallsyms_filename);
        if (err > 0 && !dso__is_kcore(dso)) {
@@ -1948,6 +1957,23 @@ static bool symbol__read_kptr_restrict(void)
        return value;
 }
 
+int symbol__annotation_init(void)
+{
+       if (symbol_conf.initialized) {
+               pr_err("Annotation needs to be init before symbol__init()\n");
+               return -1;
+       }
+
+       if (symbol_conf.init_annotation) {
+               pr_warning("Annotation being initialized multiple times\n");
+               return 0;
+       }
+
+       symbol_conf.priv_size += sizeof(struct annotation);
+       symbol_conf.init_annotation = true;
+       return 0;
+}
+
 int symbol__init(struct perf_env *env)
 {
        const char *symfs;
index 699f7cbcfe720b3ac9ed4fbf0e110db1136aae35..0dacfb7d5b67b0b39bd481342e09bed3600ef7d9 100644 (file)
@@ -57,7 +57,7 @@ struct symbol {
        u64             end;
        u16             namelen;
        u8              binding;
-       bool            ignore;
+       u8              idle:1;
        u8              arch_sym;
        char            name[0];
 };
@@ -88,6 +88,7 @@ struct symbol_conf {
        unsigned short  priv_size;
        unsigned short  nr_events;
        bool            try_vmlinux_path,
+                       init_annotation,
                        force,
                        ignore_vmlinux,
                        ignore_vmlinux_buildid,
@@ -240,16 +241,13 @@ int symsrc__init(struct symsrc *ss, struct dso *dso, const char *name,
 bool symsrc__has_symtab(struct symsrc *ss);
 bool symsrc__possibly_runtime(struct symsrc *ss);
 
-int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter);
+int dso__load(struct dso *dso, struct map *map);
 int dso__load_vmlinux(struct dso *dso, struct map *map,
-                     const char *vmlinux, bool vmlinux_allocated,
-                     symbol_filter_t filter);
-int dso__load_vmlinux_path(struct dso *dso, struct map *map,
-                          symbol_filter_t filter);
+                     const char *vmlinux, bool vmlinux_allocated);
+int dso__load_vmlinux_path(struct dso *dso, struct map *map);
 int __dso__load_kallsyms(struct dso *dso, const char *filename, struct map *map,
-                        bool no_kcore, symbol_filter_t filter);
-int dso__load_kallsyms(struct dso *dso, const char *filename, struct map *map,
-                      symbol_filter_t filter);
+                        bool no_kcore);
+int dso__load_kallsyms(struct dso *dso, const char *filename, struct map *map);
 
 void dso__insert_symbol(struct dso *dso, enum map_type type,
                        struct symbol *sym);
@@ -277,6 +275,8 @@ struct perf_env;
 int symbol__init(struct perf_env *env);
 void symbol__exit(void);
 void symbol__elf_init(void);
+int symbol__annotation_init(void);
+
 struct symbol *symbol__new(u64 start, u64 len, u8 binding, const char *name);
 size_t __symbol__fprintf_symname_offs(const struct symbol *sym,
                                      const struct addr_location *al,
@@ -291,16 +291,15 @@ size_t symbol__fprintf(struct symbol *sym, FILE *fp);
 bool symbol_type__is_a(char symbol_type, enum map_type map_type);
 bool symbol__restricted_filename(const char *filename,
                                 const char *restricted_filename);
-bool symbol__is_idle(struct symbol *sym);
 int symbol__config_symfs(const struct option *opt __maybe_unused,
                         const char *dir, int unset __maybe_unused);
 
 int dso__load_sym(struct dso *dso, struct map *map, struct symsrc *syms_ss,
-                 struct symsrc *runtime_ss, symbol_filter_t filter,
-                 int kmodule);
+                 struct symsrc *runtime_ss, int kmodule);
 int dso__synthesize_plt_symbols(struct dso *dso, struct symsrc *ss,
-                               struct map *map, symbol_filter_t filter);
+                               struct map *map);
 
+void __symbols__insert(struct rb_root *symbols, struct symbol *sym, bool kernel);
 void symbols__insert(struct rb_root *symbols, struct symbol *sym);
 void symbols__fixup_duplicate(struct rb_root *symbols);
 void symbols__fixup_end(struct rb_root *symbols);
index cee559d8c9e8e14ebedbbb5c8de081c00af7f63d..85c56800f17a6018eb080db40e9a08b03f9a460c 100644 (file)
@@ -15,6 +15,7 @@
 #include <byteswap.h>
 #include <linux/kernel.h>
 #include <linux/log2.h>
+#include <linux/time64.h>
 #include <unistd.h>
 #include "callchain.h"
 #include "strlist.h"
index e5f55477491d6c60f02053f9b19ae1ba57eb5b80..43899e0d6fa148d80ebc08643d1fa9cf73ef93e9 100644 (file)
@@ -179,10 +179,6 @@ static inline void *zalloc(size_t size)
 #undef tolower
 #undef toupper
 
-#ifndef NSEC_PER_MSEC
-#define NSEC_PER_MSEC  1000000L
-#endif
-
 int parse_nsec_time(const char *str, u64 *ptime);
 
 extern unsigned char sane_ctype[256];