Merge branch 'perf/urgent' into perf/core, to pick up fixes
authorIngo Molnar <mingo@kernel.org>
Sat, 10 Sep 2016 09:17:54 +0000 (11:17 +0200)
committerIngo Molnar <mingo@kernel.org>
Sat, 10 Sep 2016 09:17:54 +0000 (11:17 +0200)
Signed-off-by: Ingo Molnar <mingo@kernel.org>
113 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/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/include/linux/coresight-pmu.h [new file with mode: 0644]
tools/include/linux/time64.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/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/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/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_fprintf.c
tools/perf/util/header.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/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 ea52ec1..e4991fb 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 72d1cd4..94b6b45 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 d0efb5c..18a1acf 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 2cbde2f..88792f8 100644 (file)
@@ -1907,13 +1907,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;
@@ -1925,6 +1918,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;
@@ -1968,12 +1969,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);
@@ -1994,6 +1989,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:
@@ -3290,6 +3293,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 9b983a4..0319311 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 707d358..fc6cf21 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 2886593..62bebcc 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)
         */
index 463dc7a..7b3cc8b 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;
index 78b9c23..a43175f 100644 (file)
@@ -120,6 +120,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 +173,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;
 }
 
index 9d35ec0..5f845ee 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 8aee83b..3719af5 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)
@@ -1153,7 +1157,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 +1172,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 +1211,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 +1237,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 +1801,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 +2910,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 +3199,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;
index 8c4a477..5874d8d 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 598bc99..3b77588 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 2b6b43c..5c53625 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 a54f2c2..fedba31 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 8c50276..d4129bb 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 dade4c9..1e2ce3b 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 9aedb0b..eb6c9f1 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 74e80a5..8c0553d 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 45400ca..0c0ae54 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 c534854..7a68732 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/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 */
index ba7094b..f99f49e 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 16c9c2e..a63269f 100644 (file)
@@ -21,6 +21,7 @@ FS(sysfs)
 FS(procfs)
 FS(debugfs)
 FS(tracefs)
+FS(hugetlbfs)
 
 #undef FS
 
index 15949e2..cb081ac 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 b303bcd..e6c9902 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 1d8d5bc..2b477c1 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 ad2534d..ff200c6 100644 (file)
@@ -60,6 +60,7 @@ 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
@@ -77,4 +78,5 @@ 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/perf_regs.h
index 2d90875..828cfd7 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,9 @@ $(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
        $(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 35745a7..ed9d5d1 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..39ac7cb
--- /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 f96e22e..2b9705a 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 4a2ecd7..2c8fa67 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 87d8f4f..e246b1b 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 2b54d0f..c684910 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 f7f5300..8efe904 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 bfaf950..6a111e7 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 1dc2d13..2243f01 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 9c1034d..ebb6283 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 21ee753..9ff0db4 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 73c1c4c..b9bc7e3 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 fdde1bd..d426dcb 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 5e2127e..08fa88f 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 ee5b421..f87996b 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 6355902..03251c7 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 949e5a1..1a07c4c 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;
 }
@@ -980,9 +984,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 0dfe8df..f5503ca 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 c859e59..7228d14 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 3c7452b..90882b1 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 733a554..e7eaa29 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 418ed94..4007857 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 b8c6766..b4fc1ab 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 7ed72a4..e4b717e 100644 (file)
@@ -20,7 +20,6 @@
 #endif
 
 #ifdef __powerpc__
-#include "../../arch/powerpc/include/uapi/asm/unistd.h"
 #define CPUINFO_PROC   {"cpu"}
 #endif
 
index cb0f135..9a0236a 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 615780c..e6d1816 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 fc54064..2673e86 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 2af156a..ff5bc63 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 e63abab..a508233 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 2e2d100..4c18271 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 13d4143..f0611c9 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);
 }
 
@@ -1496,7 +1502,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 +1514,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 +1526,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 +1566,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 +1603,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 +1634,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 +1675,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);
@@ -2418,8 +2440,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 8091277..98a3466 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 c5f3677..a4f02de 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 4274969..b47fafc 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
index f04a631..9b65f4a 100644 (file)
@@ -549,7 +549,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 +569,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));
                }
@@ -639,33 +639,52 @@ hists__fprintf_hierarchy_headers(struct hists *hists,
        return print_hierarchy_header(hists, hpp, symbol_conf.field_sep, fp);
 }
 
-static int
-hists__fprintf_standard_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_fmt *fmt;
-       unsigned int width;
        const char *sep = symbol_conf.field_sep;
        bool first = true;
+       int span = 0;
 
        hists__for_each_format(hists, fmt) {
                if (perf_hpp__should_skip(fmt, hists))
                        continue;
 
-               if (!first)
+               if (!first && !span)
                        fprintf(fp, "%s", sep ?: "  ");
                else
                        first = false;
 
-               fmt->header(fmt, hpp, hists);
-               fprintf(fp, "%s", hpp->buf);
+               fmt->header(fmt, hpp, hists, line, &span);
+
+               if (!span)
+                       fprintf(fp, "%s", hpp->buf);
        }
+}
 
-       fprintf(fp, "\n");
+static int
+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;
+       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");
+       }
 
        if (sep)
-               return 1;
+               return hpp_list->nr_header_lines;
 
        first = true;
 
@@ -689,7 +708,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)
index 91c5f6e..96f99d6 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 4024d30..7a80c73 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>
@@ -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);
@@ -866,6 +860,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 +962,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 +1032,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);
@@ -1084,7 +1166,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 +1244,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 +1312,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 +1320,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 +1339,7 @@ fallback:
                close(fd);
 
                if (!ret)
-                       goto out_free_filename;
+                       goto out;
 
                strcpy(symfs_filename, tmp);
        }
@@ -1271,7 +1355,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 +1417,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 f67ccb0..ea44e4f 100644 (file)
@@ -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 1f12e4e..2b2c9b8 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 8c4212a..c1838b6 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 a347b19..faec899 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 dc0ce1a..8b6d2f8 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 e20438b..6c30171 100644 (file)
@@ -1,5 +1,6 @@
 #include <linux/types.h>
 #include <sys/mman.h>
+#include <api/fs/fs.h>
 #include "event.h"
 #include "debug.h"
 #include "hist.h"
@@ -248,6 +249,10 @@ int perf_event__synthesize_mmap_events(struct perf_tool *tool,
        bool truncation = false;
        unsigned long long timeout = proc_map_timeout * 1000000ULL;
        int rc = 0;
+#ifdef MAP_HUGETLB
+       const char *hugetlbfs_mnt = hugetlbfs__mountpoint();
+       int hugetlbfs_mnt_len = hugetlbfs_mnt ? strlen(hugetlbfs_mnt) : 0;
+#endif
 
        if (machine__is_default_guest(machine))
                return 0;
@@ -342,6 +347,12 @@ out:
 
                if (!strcmp(execname, ""))
                        strcpy(execname, anonstr);
+#ifdef MAP_HUGETLB
+               if (!strncmp(execname, hugetlbfs_mnt, hugetlbfs_mnt_len)) {
+                       strcpy(execname, anonstr);
+                       event->mmap2.flags |= MAP_HUGETLB;
+               }
+#endif
 
                size = strlen(execname) + 1;
                memcpy(event->mmap2.filename, execname, size);
@@ -1286,7 +1297,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 +1308,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 +1369,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 +1425,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 097b3ed..ea34c5a 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 3674e77..9111e06 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 8f0db40..85dd0db 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 0a1edf1..a002c93 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;
index 07c644e..43bfd8d 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 749e6f2..f545ec1 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 551ff6f..b9cc353 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 95a1acb..9ddea5c 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 cb6388d..18e4519 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 20739f7..354de6e 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 728129a..d51a125 100644 (file)
@@ -6,6 +6,7 @@
 #include <string.h>
 #include <stdio.h>
 #include <unistd.h>
+#include <sys/mman.h>
 #include "map.h"
 #include "thread.h"
 #include "strlist.h"
@@ -24,9 +25,15 @@ 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") ||
+       u32 anon_flags = 0;
+
+#ifdef MAP_HUGETLB
+       anon_flags |= MAP_HUGETLB;
+#endif
+       return flags & anon_flags ||
+              !strcmp(filename, "//anon") ||
               !strncmp(filename, "/dev/zero", sizeof("/dev/zero") - 1) ||
               !strncmp(filename, "/anon_hugepage", sizeof("/anon_hugepage") - 1);
 }
@@ -155,7 +162,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 +286,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 +294,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 +319,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 +335,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 +558,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 +583,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 +601,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 +620,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 d83396c..abdacf8 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 ddb0261..2babcdf 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 2873396..bc60ce4 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 f4f45db..8091d15 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 9c3b9ed..6f931e4 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 9577b5c..eba44c3 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 5c290c6..8daca4f 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 51137fc..f1d8558 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 5d1eb1c..e55a132 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 e0203b9..089438d 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 3d3cb83..1884d7f 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 7ca37ea..28c0524 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;
index eec6c11..1cbada2 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 a811c13..99400b0 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 4890633..11cdde9 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 37e8d20..19c9c55 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 699f7cb..0dacfb7 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 cee559d..85c5680 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 e5f5547..43899e0 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];