diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-10-12 21:20:11 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-10-12 21:20:11 -0400 |
| commit | ade0899b298ba2c43bfd6abd8cbc2545944cde0c (patch) | |
| tree | a448dfb440b3b958b6306bb43620cd5d76f504bf | |
| parent | 871a0596cb2f51b57dc583d1a7c4be0186582fe7 (diff) | |
| parent | 95cf59ea72331d0093010543b8951bb43f262cac (diff) | |
Merge branch 'perf-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull perf updates from Ingo Molnar:
"This tree includes some late late perf items that missed the first
round:
tools:
- Bash auto completion improvements, now we can auto complete the
tools long options, tracepoint event names, etc, from Namhyung Kim.
- Look up thread using tid instead of pid in 'perf sched'.
- Move global variables into a perf_kvm struct, from David Ahern.
- Hists refactorings, preparatory for improved 'diff' command, from
Jiri Olsa.
- Hists refactorings, preparatory for event group viewieng work, from
Namhyung Kim.
- Remove double negation on optional feature macro definitions, from
Namhyung Kim.
- Remove several cases of needless global variables, on most
builtins.
- misc fixes
kernel:
- sysfs support for IBS on AMD CPUs, from Robert Richter.
- Support for an upcoming Intel CPU, the Xeon-Phi / Knights Corner
HPC blade PMU, from Vince Weaver.
- misc fixes"
* 'perf-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (46 commits)
perf: Fix perf_cgroup_switch for sw-events
perf: Clarify perf_cpu_context::active_pmu usage by renaming it to ::unique_pmu
perf/AMD/IBS: Add sysfs support
perf hists: Add more helpers for hist entry stat
perf hists: Move he->stat.nr_events initialization to a template
perf hists: Introduce struct he_stat
perf diff: Removing the total_period argument from output code
perf tool: Add hpp interface to enable/disable hpp column
perf tools: Removing hists pair argument from output path
perf hists: Separate overhead and baseline columns
perf diff: Refactor diff displacement possition info
perf hists: Add struct hists pointer to struct hist_entry
perf tools: Complete tracepoint event names
perf/x86: Add support for Intel Xeon-Phi Knights Corner PMU
perf evlist: Remove some unused methods
perf evlist: Introduce add_newtp method
perf kvm: Move global variables into a perf_kvm struct
perf tools: Convert to BACKTRACE_SUPPORT
perf tools: Long option completion support for each subcommands
perf tools: Complete long option names of perf command
...
55 files changed, 1517 insertions, 1198 deletions
diff --git a/arch/x86/include/asm/msr-index.h b/arch/x86/include/asm/msr-index.h index fbee9714d9ab..7f0edceb7563 100644 --- a/arch/x86/include/asm/msr-index.h +++ b/arch/x86/include/asm/msr-index.h | |||
| @@ -121,6 +121,11 @@ | |||
| 121 | #define MSR_P6_EVNTSEL0 0x00000186 | 121 | #define MSR_P6_EVNTSEL0 0x00000186 |
| 122 | #define MSR_P6_EVNTSEL1 0x00000187 | 122 | #define MSR_P6_EVNTSEL1 0x00000187 |
| 123 | 123 | ||
| 124 | #define MSR_KNC_PERFCTR0 0x00000020 | ||
| 125 | #define MSR_KNC_PERFCTR1 0x00000021 | ||
| 126 | #define MSR_KNC_EVNTSEL0 0x00000028 | ||
| 127 | #define MSR_KNC_EVNTSEL1 0x00000029 | ||
| 128 | |||
| 124 | /* AMD64 MSRs. Not complete. See the architecture manual for a more | 129 | /* AMD64 MSRs. Not complete. See the architecture manual for a more |
| 125 | complete list. */ | 130 | complete list. */ |
| 126 | 131 | ||
diff --git a/arch/x86/kernel/cpu/Makefile b/arch/x86/kernel/cpu/Makefile index d30a6a9a0121..a0e067d3d96c 100644 --- a/arch/x86/kernel/cpu/Makefile +++ b/arch/x86/kernel/cpu/Makefile | |||
| @@ -32,7 +32,7 @@ obj-$(CONFIG_PERF_EVENTS) += perf_event.o | |||
| 32 | 32 | ||
| 33 | ifdef CONFIG_PERF_EVENTS | 33 | ifdef CONFIG_PERF_EVENTS |
| 34 | obj-$(CONFIG_CPU_SUP_AMD) += perf_event_amd.o | 34 | obj-$(CONFIG_CPU_SUP_AMD) += perf_event_amd.o |
| 35 | obj-$(CONFIG_CPU_SUP_INTEL) += perf_event_p6.o perf_event_p4.o | 35 | obj-$(CONFIG_CPU_SUP_INTEL) += perf_event_p6.o perf_event_knc.o perf_event_p4.o |
| 36 | obj-$(CONFIG_CPU_SUP_INTEL) += perf_event_intel_lbr.o perf_event_intel_ds.o perf_event_intel.o | 36 | obj-$(CONFIG_CPU_SUP_INTEL) += perf_event_intel_lbr.o perf_event_intel_ds.o perf_event_intel.o |
| 37 | obj-$(CONFIG_CPU_SUP_INTEL) += perf_event_intel_uncore.o | 37 | obj-$(CONFIG_CPU_SUP_INTEL) += perf_event_intel_uncore.o |
| 38 | endif | 38 | endif |
diff --git a/arch/x86/kernel/cpu/perf_event.h b/arch/x86/kernel/cpu/perf_event.h index 8b6defe7eefc..271d25700297 100644 --- a/arch/x86/kernel/cpu/perf_event.h +++ b/arch/x86/kernel/cpu/perf_event.h | |||
| @@ -626,6 +626,8 @@ int p4_pmu_init(void); | |||
| 626 | 626 | ||
| 627 | int p6_pmu_init(void); | 627 | int p6_pmu_init(void); |
| 628 | 628 | ||
| 629 | int knc_pmu_init(void); | ||
| 630 | |||
| 629 | #else /* CONFIG_CPU_SUP_INTEL */ | 631 | #else /* CONFIG_CPU_SUP_INTEL */ |
| 630 | 632 | ||
| 631 | static inline void reserve_ds_buffers(void) | 633 | static inline void reserve_ds_buffers(void) |
diff --git a/arch/x86/kernel/cpu/perf_event_amd_ibs.c b/arch/x86/kernel/cpu/perf_event_amd_ibs.c index eebd5ffe1bba..6336bcbd0618 100644 --- a/arch/x86/kernel/cpu/perf_event_amd_ibs.c +++ b/arch/x86/kernel/cpu/perf_event_amd_ibs.c | |||
| @@ -41,17 +41,22 @@ struct cpu_perf_ibs { | |||
| 41 | }; | 41 | }; |
| 42 | 42 | ||
| 43 | struct perf_ibs { | 43 | struct perf_ibs { |
| 44 | struct pmu pmu; | 44 | struct pmu pmu; |
| 45 | unsigned int msr; | 45 | unsigned int msr; |
| 46 | u64 config_mask; | 46 | u64 config_mask; |
| 47 | u64 cnt_mask; | 47 | u64 cnt_mask; |
| 48 | u64 enable_mask; | 48 | u64 enable_mask; |
| 49 | u64 valid_mask; | 49 | u64 valid_mask; |
| 50 | u64 max_period; | 50 | u64 max_period; |
| 51 | unsigned long offset_mask[1]; | 51 | unsigned long offset_mask[1]; |
| 52 | int offset_max; | 52 | int offset_max; |
| 53 | struct cpu_perf_ibs __percpu *pcpu; | 53 | struct cpu_perf_ibs __percpu *pcpu; |
| 54 | u64 (*get_count)(u64 config); | 54 | |
| 55 | struct attribute **format_attrs; | ||
| 56 | struct attribute_group format_group; | ||
| 57 | const struct attribute_group *attr_groups[2]; | ||
| 58 | |||
| 59 | u64 (*get_count)(u64 config); | ||
| 55 | }; | 60 | }; |
| 56 | 61 | ||
| 57 | struct perf_ibs_data { | 62 | struct perf_ibs_data { |
| @@ -446,6 +451,19 @@ static void perf_ibs_del(struct perf_event *event, int flags) | |||
| 446 | 451 | ||
| 447 | static void perf_ibs_read(struct perf_event *event) { } | 452 | static void perf_ibs_read(struct perf_event *event) { } |
| 448 | 453 | ||
| 454 | PMU_FORMAT_ATTR(rand_en, "config:57"); | ||
| 455 | PMU_FORMAT_ATTR(cnt_ctl, "config:19"); | ||
| 456 | |||
| 457 | static struct attribute *ibs_fetch_format_attrs[] = { | ||
| 458 | &format_attr_rand_en.attr, | ||
| 459 | NULL, | ||
| 460 | }; | ||
| 461 | |||
| 462 | static struct attribute *ibs_op_format_attrs[] = { | ||
| 463 | NULL, /* &format_attr_cnt_ctl.attr if IBS_CAPS_OPCNT */ | ||
| 464 | NULL, | ||
| 465 | }; | ||
| 466 | |||
| 449 | static struct perf_ibs perf_ibs_fetch = { | 467 | static struct perf_ibs perf_ibs_fetch = { |
| 450 | .pmu = { | 468 | .pmu = { |
| 451 | .task_ctx_nr = perf_invalid_context, | 469 | .task_ctx_nr = perf_invalid_context, |
| @@ -465,6 +483,7 @@ static struct perf_ibs perf_ibs_fetch = { | |||
| 465 | .max_period = IBS_FETCH_MAX_CNT << 4, | 483 | .max_period = IBS_FETCH_MAX_CNT << 4, |
| 466 | .offset_mask = { MSR_AMD64_IBSFETCH_REG_MASK }, | 484 | .offset_mask = { MSR_AMD64_IBSFETCH_REG_MASK }, |
| 467 | .offset_max = MSR_AMD64_IBSFETCH_REG_COUNT, | 485 | .offset_max = MSR_AMD64_IBSFETCH_REG_COUNT, |
| 486 | .format_attrs = ibs_fetch_format_attrs, | ||
| 468 | 487 | ||
| 469 | .get_count = get_ibs_fetch_count, | 488 | .get_count = get_ibs_fetch_count, |
| 470 | }; | 489 | }; |
| @@ -488,6 +507,7 @@ static struct perf_ibs perf_ibs_op = { | |||
| 488 | .max_period = IBS_OP_MAX_CNT << 4, | 507 | .max_period = IBS_OP_MAX_CNT << 4, |
| 489 | .offset_mask = { MSR_AMD64_IBSOP_REG_MASK }, | 508 | .offset_mask = { MSR_AMD64_IBSOP_REG_MASK }, |
| 490 | .offset_max = MSR_AMD64_IBSOP_REG_COUNT, | 509 | .offset_max = MSR_AMD64_IBSOP_REG_COUNT, |
| 510 | .format_attrs = ibs_op_format_attrs, | ||
| 491 | 511 | ||
| 492 | .get_count = get_ibs_op_count, | 512 | .get_count = get_ibs_op_count, |
| 493 | }; | 513 | }; |
| @@ -597,6 +617,17 @@ static __init int perf_ibs_pmu_init(struct perf_ibs *perf_ibs, char *name) | |||
| 597 | 617 | ||
| 598 | perf_ibs->pcpu = pcpu; | 618 | perf_ibs->pcpu = pcpu; |
| 599 | 619 | ||
| 620 | /* register attributes */ | ||
| 621 | if (perf_ibs->format_attrs[0]) { | ||
| 622 | memset(&perf_ibs->format_group, 0, sizeof(perf_ibs->format_group)); | ||
| 623 | perf_ibs->format_group.name = "format"; | ||
| 624 | perf_ibs->format_group.attrs = perf_ibs->format_attrs; | ||
| 625 | |||
| 626 | memset(&perf_ibs->attr_groups, 0, sizeof(perf_ibs->attr_groups)); | ||
| 627 | perf_ibs->attr_groups[0] = &perf_ibs->format_group; | ||
| 628 | perf_ibs->pmu.attr_groups = perf_ibs->attr_groups; | ||
| 629 | } | ||
| 630 | |||
| 600 | ret = perf_pmu_register(&perf_ibs->pmu, name, -1); | 631 | ret = perf_pmu_register(&perf_ibs->pmu, name, -1); |
| 601 | if (ret) { | 632 | if (ret) { |
| 602 | perf_ibs->pcpu = NULL; | 633 | perf_ibs->pcpu = NULL; |
| @@ -608,13 +639,19 @@ static __init int perf_ibs_pmu_init(struct perf_ibs *perf_ibs, char *name) | |||
| 608 | 639 | ||
| 609 | static __init int perf_event_ibs_init(void) | 640 | static __init int perf_event_ibs_init(void) |
| 610 | { | 641 | { |
| 642 | struct attribute **attr = ibs_op_format_attrs; | ||
| 643 | |||
| 611 | if (!ibs_caps) | 644 | if (!ibs_caps) |
| 612 | return -ENODEV; /* ibs not supported by the cpu */ | 645 | return -ENODEV; /* ibs not supported by the cpu */ |
| 613 | 646 | ||
| 614 | perf_ibs_pmu_init(&perf_ibs_fetch, "ibs_fetch"); | 647 | perf_ibs_pmu_init(&perf_ibs_fetch, "ibs_fetch"); |
| 615 | if (ibs_caps & IBS_CAPS_OPCNT) | 648 | |
| 649 | if (ibs_caps & IBS_CAPS_OPCNT) { | ||
| 616 | perf_ibs_op.config_mask |= IBS_OP_CNT_CTL; | 650 | perf_ibs_op.config_mask |= IBS_OP_CNT_CTL; |
| 651 | *attr++ = &format_attr_cnt_ctl.attr; | ||
| 652 | } | ||
| 617 | perf_ibs_pmu_init(&perf_ibs_op, "ibs_op"); | 653 | perf_ibs_pmu_init(&perf_ibs_op, "ibs_op"); |
| 654 | |||
| 618 | register_nmi_handler(NMI_LOCAL, perf_ibs_nmi_handler, 0, "perf_ibs"); | 655 | register_nmi_handler(NMI_LOCAL, perf_ibs_nmi_handler, 0, "perf_ibs"); |
| 619 | printk(KERN_INFO "perf: AMD IBS detected (0x%08x)\n", ibs_caps); | 656 | printk(KERN_INFO "perf: AMD IBS detected (0x%08x)\n", ibs_caps); |
| 620 | 657 | ||
diff --git a/arch/x86/kernel/cpu/perf_event_intel.c b/arch/x86/kernel/cpu/perf_event_intel.c index 6bca492b8547..324bb523d9d9 100644 --- a/arch/x86/kernel/cpu/perf_event_intel.c +++ b/arch/x86/kernel/cpu/perf_event_intel.c | |||
| @@ -1906,6 +1906,8 @@ __init int intel_pmu_init(void) | |||
| 1906 | switch (boot_cpu_data.x86) { | 1906 | switch (boot_cpu_data.x86) { |
| 1907 | case 0x6: | 1907 | case 0x6: |
| 1908 | return p6_pmu_init(); | 1908 | return p6_pmu_init(); |
| 1909 | case 0xb: | ||
| 1910 | return knc_pmu_init(); | ||
| 1909 | case 0xf: | 1911 | case 0xf: |
| 1910 | return p4_pmu_init(); | 1912 | return p4_pmu_init(); |
| 1911 | } | 1913 | } |
diff --git a/arch/x86/kernel/cpu/perf_event_knc.c b/arch/x86/kernel/cpu/perf_event_knc.c new file mode 100644 index 000000000000..7c46bfdbc373 --- /dev/null +++ b/arch/x86/kernel/cpu/perf_event_knc.c | |||
| @@ -0,0 +1,248 @@ | |||
| 1 | /* Driver for Intel Xeon Phi "Knights Corner" PMU */ | ||
| 2 | |||
| 3 | #include <linux/perf_event.h> | ||
| 4 | #include <linux/types.h> | ||
| 5 | |||
| 6 | #include "perf_event.h" | ||
| 7 | |||
| 8 | static const u64 knc_perfmon_event_map[] = | ||
| 9 | { | ||
| 10 | [PERF_COUNT_HW_CPU_CYCLES] = 0x002a, | ||
| 11 | [PERF_COUNT_HW_INSTRUCTIONS] = 0x0016, | ||
| 12 | [PERF_COUNT_HW_CACHE_REFERENCES] = 0x0028, | ||
| 13 | [PERF_COUNT_HW_CACHE_MISSES] = 0x0029, | ||
| 14 | [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = 0x0012, | ||
| 15 | [PERF_COUNT_HW_BRANCH_MISSES] = 0x002b, | ||
| 16 | }; | ||
| 17 | |||
| 18 | static __initconst u64 knc_hw_cache_event_ids | ||
| 19 | [PERF_COUNT_HW_CACHE_MAX] | ||
| 20 | [PERF_COUNT_HW_CACHE_OP_MAX] | ||
| 21 | [PERF_COUNT_HW_CACHE_RESULT_MAX] = | ||
| 22 | { | ||
| 23 | [ C(L1D) ] = { | ||
| 24 | [ C(OP_READ) ] = { | ||
| 25 | /* On Xeon Phi event "0" is a valid DATA_READ */ | ||
| 26 | /* (L1 Data Cache Reads) Instruction. */ | ||
| 27 | /* We code this as ARCH_PERFMON_EVENTSEL_INT as this */ | ||
| 28 | /* bit will always be set in x86_pmu_hw_config(). */ | ||
| 29 | [ C(RESULT_ACCESS) ] = ARCH_PERFMON_EVENTSEL_INT, | ||
| 30 | /* DATA_READ */ | ||
| 31 | [ C(RESULT_MISS) ] = 0x0003, /* DATA_READ_MISS */ | ||
| 32 | }, | ||
| 33 | [ C(OP_WRITE) ] = { | ||
| 34 | [ C(RESULT_ACCESS) ] = 0x0001, /* DATA_WRITE */ | ||
| 35 | [ C(RESULT_MISS) ] = 0x0004, /* DATA_WRITE_MISS */ | ||
| 36 | }, | ||
| 37 | [ C(OP_PREFETCH) ] = { | ||
| 38 | [ C(RESULT_ACCESS) ] = 0x0011, /* L1_DATA_PF1 */ | ||
| 39 | [ C(RESULT_MISS) ] = 0x001c, /* L1_DATA_PF1_MISS */ | ||
| 40 | }, | ||
| 41 | }, | ||
| 42 | [ C(L1I ) ] = { | ||
| 43 | [ C(OP_READ) ] = { | ||
| 44 | [ C(RESULT_ACCESS) ] = 0x000c, /* CODE_READ */ | ||
| 45 | [ C(RESULT_MISS) ] = 0x000e, /* CODE_CACHE_MISS */ | ||
| 46 | }, | ||
| 47 | [ C(OP_WRITE) ] = { | ||
| 48 | [ C(RESULT_ACCESS) ] = -1, | ||
| 49 | [ C(RESULT_MISS) ] = -1, | ||
| 50 | }, | ||
| 51 | [ C(OP_PREFETCH) ] = { | ||
| 52 | [ C(RESULT_ACCESS) ] = 0x0, | ||
| 53 | [ C(RESULT_MISS) ] = 0x0, | ||
| 54 | }, | ||
| 55 | }, | ||
| 56 | [ C(LL ) ] = { | ||
| 57 | [ C(OP_READ) ] = { | ||
| 58 | [ C(RESULT_ACCESS) ] = 0, | ||
| 59 | [ C(RESULT_MISS) ] = 0x10cb, /* L2_READ_MISS */ | ||
| 60 | }, | ||
| 61 | [ C(OP_WRITE) ] = { | ||
| 62 | [ C(RESULT_ACCESS) ] = 0x10cc, /* L2_WRITE_HIT */ | ||
| 63 | [ C(RESULT_MISS) ] = 0, | ||
| 64 | }, | ||
| 65 | [ C(OP_PREFETCH) ] = { | ||
| 66 | [ C(RESULT_ACCESS) ] = 0x10fc, /* L2_DATA_PF2 */ | ||
| 67 | [ C(RESULT_MISS) ] = 0x10fe, /* L2_DATA_PF2_MISS */ | ||
| 68 | }, | ||
| 69 | }, | ||
| 70 | [ C(DTLB) ] = { | ||
| 71 | [ C(OP_READ) ] = { | ||
| 72 | [ C(RESULT_ACCESS) ] = ARCH_PERFMON_EVENTSEL_INT, | ||
| 73 | /* DATA_READ */ | ||
| 74 | /* see note on L1 OP_READ */ | ||
| 75 | [ C(RESULT_MISS) ] = 0x0002, /* DATA_PAGE_WALK */ | ||
| 76 | }, | ||
| 77 | [ C(OP_WRITE) ] = { | ||
| 78 | [ C(RESULT_ACCESS) ] = 0x0001, /* DATA_WRITE */ | ||
| 79 | [ C(RESULT_MISS) ] = 0x0002, /* DATA_PAGE_WALK */ | ||
| 80 | }, | ||
| 81 | [ C(OP_PREFETCH) ] = { | ||
| 82 | [ C(RESULT_ACCESS) ] = 0x0, | ||
| 83 | [ C(RESULT_MISS) ] = 0x0, | ||
| 84 | }, | ||
| 85 | }, | ||
| 86 | [ C(ITLB) ] = { | ||
| 87 | [ C(OP_READ) ] = { | ||
| 88 | [ C(RESULT_ACCESS) ] = 0x000c, /* CODE_READ */ | ||
| 89 | [ C(RESULT_MISS) ] = 0x000d, /* CODE_PAGE_WALK */ | ||
| 90 | }, | ||
| 91 | [ C(OP_WRITE) ] = { | ||
| 92 | [ C(RESULT_ACCESS) ] = -1, | ||
| 93 | [ C(RESULT_MISS) ] = -1, | ||
| 94 | }, | ||
| 95 | [ C(OP_PREFETCH) ] = { | ||
| 96 | [ C(RESULT_ACCESS) ] = -1, | ||
| 97 | [ C(RESULT_MISS) ] = -1, | ||
| 98 | }, | ||
| 99 | }, | ||
| 100 | [ C(BPU ) ] = { | ||
| 101 | [ C(OP_READ) ] = { | ||
| 102 | [ C(RESULT_ACCESS) ] = 0x0012, /* BRANCHES */ | ||
| 103 | [ C(RESULT_MISS) ] = 0x002b, /* BRANCHES_MISPREDICTED */ | ||
| 104 | }, | ||
| 105 | [ C(OP_WRITE) ] = { | ||
| 106 | [ C(RESULT_ACCESS) ] = -1, | ||
| 107 | [ C(RESULT_MISS) ] = -1, | ||
| 108 | }, | ||
| 109 | [ C(OP_PREFETCH) ] = { | ||
| 110 | [ C(RESULT_ACCESS) ] = -1, | ||
| 111 | [ C(RESULT_MISS) ] = -1, | ||
| 112 | }, | ||
| 113 | }, | ||
| 114 | }; | ||
| 115 | |||
| 116 | |||
| 117 | static u64 knc_pmu_event_map(int hw_event) | ||
| 118 | { | ||
| 119 | return knc_perfmon_event_map[hw_event]; | ||
| 120 | } | ||
| 121 | |||
| 122 | static struct event_constraint knc_event_constraints[] = | ||
| 123 | { | ||
| 124 | INTEL_EVENT_CONSTRAINT(0xc3, 0x1), /* HWP_L2HIT */ | ||
| 125 | INTEL_EVENT_CONSTRAINT(0xc4, 0x1), /* HWP_L2MISS */ | ||
| 126 | INTEL_EVENT_CONSTRAINT(0xc8, 0x1), /* L2_READ_HIT_E */ | ||
| 127 | INTEL_EVENT_CONSTRAINT(0xc9, 0x1), /* L2_READ_HIT_M */ | ||
| 128 | INTEL_EVENT_CONSTRAINT(0xca, 0x1), /* L2_READ_HIT_S */ | ||
| 129 | INTEL_EVENT_CONSTRAINT(0xcb, 0x1), /* L2_READ_MISS */ | ||
| 130 | INTEL_EVENT_CONSTRAINT(0xcc, 0x1), /* L2_WRITE_HIT */ | ||
| 131 | INTEL_EVENT_CONSTRAINT(0xce, 0x1), /* L2_STRONGLY_ORDERED_STREAMING_VSTORES_MISS */ | ||
| 132 | INTEL_EVENT_CONSTRAINT(0xcf, 0x1), /* L2_WEAKLY_ORDERED_STREAMING_VSTORE_MISS */ | ||
| 133 | INTEL_EVENT_CONSTRAINT(0xd7, 0x1), /* L2_VICTIM_REQ_WITH_DATA */ | ||
| 134 | INTEL_EVENT_CONSTRAINT(0xe3, 0x1), /* SNP_HITM_BUNIT */ | ||
| 135 | INTEL_EVENT_CONSTRAINT(0xe6, 0x1), /* SNP_HIT_L2 */ | ||
| 136 | INTEL_EVENT_CONSTRAINT(0xe7, 0x1), /* SNP_HITM_L2 */ | ||
| 137 | INTEL_EVENT_CONSTRAINT(0xf1, 0x1), /* L2_DATA_READ_MISS_CACHE_FILL */ | ||
| 138 | INTEL_EVENT_CONSTRAINT(0xf2, 0x1), /* L2_DATA_WRITE_MISS_CACHE_FILL */ | ||
| 139 | INTEL_EVENT_CONSTRAINT(0xf6, 0x1), /* L2_DATA_READ_MISS_MEM_FILL */ | ||
| 140 | INTEL_EVENT_CONSTRAINT(0xf7, 0x1), /* L2_DATA_WRITE_MISS_MEM_FILL */ | ||
| 141 | INTEL_EVENT_CONSTRAINT(0xfc, 0x1), /* L2_DATA_PF2 */ | ||
| 142 | INTEL_EVENT_CONSTRAINT(0xfd, 0x1), /* L2_DATA_PF2_DROP */ | ||
| 143 | INTEL_EVENT_CONSTRAINT(0xfe, 0x1), /* L2_DATA_PF2_MISS */ | ||
| 144 | INTEL_EVENT_CONSTRAINT(0xff, 0x1), /* L2_DATA_HIT_INFLIGHT_PF2 */ | ||
| 145 | EVENT_CONSTRAINT_END | ||
| 146 | }; | ||
| 147 | |||
| 148 | #define MSR_KNC_IA32_PERF_GLOBAL_STATUS 0x0000002d | ||
| 149 | #define MSR_KNC_IA32_PERF_GLOBAL_OVF_CONTROL 0x0000002e | ||
| 150 | #define MSR_KNC_IA32_PERF_GLOBAL_CTRL 0x0000002f | ||
| 151 | |||
| 152 | #define KNC_ENABLE_COUNTER0 0x00000001 | ||
| 153 | #define KNC_ENABLE_COUNTER1 0x00000002 | ||
| 154 | |||
| 155 | static void knc_pmu_disable_all(void) | ||
| 156 | { | ||
| 157 | u64 val; | ||
| 158 | |||
| 159 | rdmsrl(MSR_KNC_IA32_PERF_GLOBAL_CTRL, val); | ||
| 160 | val &= ~(KNC_ENABLE_COUNTER0|KNC_ENABLE_COUNTER1); | ||
| 161 | wrmsrl(MSR_KNC_IA32_PERF_GLOBAL_CTRL, val); | ||
| 162 | } | ||
| 163 | |||
| 164 | static void knc_pmu_enable_all(int added) | ||
| 165 | { | ||
| 166 | u64 val; | ||
| 167 | |||
| 168 | rdmsrl(MSR_KNC_IA32_PERF_GLOBAL_CTRL, val); | ||
| 169 | val |= (KNC_ENABLE_COUNTER0|KNC_ENABLE_COUNTER1); | ||
| 170 | wrmsrl(MSR_KNC_IA32_PERF_GLOBAL_CTRL, val); | ||
| 171 | } | ||
| 172 | |||
| 173 | static inline void | ||
| 174 | knc_pmu_disable_event(struct perf_event *event) | ||
| 175 | { | ||
| 176 | struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); | ||
| 177 | struct hw_perf_event *hwc = &event->hw; | ||
| 178 | u64 val; | ||
| 179 | |||
| 180 | val = hwc->config; | ||
| 181 | if (cpuc->enabled) | ||
| 182 | val &= ~ARCH_PERFMON_EVENTSEL_ENABLE; | ||
| 183 | |||
| 184 | (void)wrmsrl_safe(hwc->config_base + hwc->idx, val); | ||
| 185 | } | ||
| 186 | |||
| 187 | static void knc_pmu_enable_event(struct perf_event *event) | ||
| 188 | { | ||
| 189 | struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); | ||
| 190 | struct hw_perf_event *hwc = &event->hw; | ||
| 191 | u64 val; | ||
| 192 | |||
| 193 | val = hwc->config; | ||
| 194 | if (cpuc->enabled) | ||
| 195 | val |= ARCH_PERFMON_EVENTSEL_ENABLE; | ||
| 196 | |||
| 197 | (void)wrmsrl_safe(hwc->config_base + hwc->idx, val); | ||
| 198 | } | ||
| 199 | |||
| 200 | PMU_FORMAT_ATTR(event, "config:0-7" ); | ||
| 201 | PMU_FORMAT_ATTR(umask, "config:8-15" ); | ||
| 202 | PMU_FORMAT_ATTR(edge, "config:18" ); | ||
| 203 | PMU_FORMAT_ATTR(inv, "config:23" ); | ||
| 204 | PMU_FORMAT_ATTR(cmask, "config:24-31" ); | ||
| 205 | |||
| 206 | static struct attribute *intel_knc_formats_attr[] = { | ||
| 207 | &format_attr_event.attr, | ||
| 208 | &format_attr_umask.attr, | ||
| 209 | &format_attr_edge.attr, | ||
| 210 | &format_attr_inv.attr, | ||
| 211 | &format_attr_cmask.attr, | ||
| 212 | NULL, | ||
| 213 | }; | ||
| 214 | |||
| 215 | static __initconst struct x86_pmu knc_pmu = { | ||
| 216 | .name = "knc", | ||
| 217 | .handle_irq = x86_pmu_handle_irq, | ||
| 218 | .disable_all = knc_pmu_disable_all, | ||
| 219 | .enable_all = knc_pmu_enable_all, | ||
| 220 | .enable = knc_pmu_enable_event, | ||
| 221 | .disable = knc_pmu_disable_event, | ||
| 222 | .hw_config = x86_pmu_hw_config, | ||
| 223 | .schedule_events = x86_schedule_events, | ||
| 224 | .eventsel = MSR_KNC_EVNTSEL0, | ||
| 225 | .perfctr = MSR_KNC_PERFCTR0, | ||
| 226 | .event_map = knc_pmu_event_map, | ||
| 227 | .max_events = ARRAY_SIZE(knc_perfmon_event_map), | ||
| 228 | .apic = 1, | ||
| 229 | .max_period = (1ULL << 31) - 1, | ||
| 230 | .version = 0, | ||
| 231 | .num_counters = 2, | ||
| 232 | /* in theory 40 bits, early silicon is buggy though */ | ||
| 233 | .cntval_bits = 32, | ||
| 234 | .cntval_mask = (1ULL << 32) - 1, | ||
| 235 | .get_event_constraints = x86_get_event_constraints, | ||
| 236 | .event_constraints = knc_event_constraints, | ||
| 237 | .format_attrs = intel_knc_formats_attr, | ||
| 238 | }; | ||
| 239 | |||
| 240 | __init int knc_pmu_init(void) | ||
| 241 | { | ||
| 242 | x86_pmu = knc_pmu; | ||
| 243 | |||
| 244 | memcpy(hw_cache_event_ids, knc_hw_cache_event_ids, | ||
| 245 | sizeof(hw_cache_event_ids)); | ||
| 246 | |||
| 247 | return 0; | ||
| 248 | } | ||
diff --git a/arch/x86/kernel/cpu/perfctr-watchdog.c b/arch/x86/kernel/cpu/perfctr-watchdog.c index 966512b2cacf..2e8caf03f593 100644 --- a/arch/x86/kernel/cpu/perfctr-watchdog.c +++ b/arch/x86/kernel/cpu/perfctr-watchdog.c | |||
| @@ -56,6 +56,8 @@ static inline unsigned int nmi_perfctr_msr_to_bit(unsigned int msr) | |||
| 56 | switch (boot_cpu_data.x86) { | 56 | switch (boot_cpu_data.x86) { |
| 57 | case 6: | 57 | case 6: |
| 58 | return msr - MSR_P6_PERFCTR0; | 58 | return msr - MSR_P6_PERFCTR0; |
| 59 | case 11: | ||
| 60 | return msr - MSR_KNC_PERFCTR0; | ||
| 59 | case 15: | 61 | case 15: |
| 60 | return msr - MSR_P4_BPU_PERFCTR0; | 62 | return msr - MSR_P4_BPU_PERFCTR0; |
| 61 | } | 63 | } |
| @@ -82,6 +84,8 @@ static inline unsigned int nmi_evntsel_msr_to_bit(unsigned int msr) | |||
| 82 | switch (boot_cpu_data.x86) { | 84 | switch (boot_cpu_data.x86) { |
| 83 | case 6: | 85 | case 6: |
| 84 | return msr - MSR_P6_EVNTSEL0; | 86 | return msr - MSR_P6_EVNTSEL0; |
| 87 | case 11: | ||
| 88 | return msr - MSR_KNC_EVNTSEL0; | ||
| 85 | case 15: | 89 | case 15: |
| 86 | return msr - MSR_P4_BSU_ESCR0; | 90 | return msr - MSR_P4_BSU_ESCR0; |
| 87 | } | 91 | } |
diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h index 599afc4bb67e..b4166cdfa7a2 100644 --- a/include/linux/perf_event.h +++ b/include/linux/perf_event.h | |||
| @@ -1110,7 +1110,7 @@ struct perf_cpu_context { | |||
| 1110 | int exclusive; | 1110 | int exclusive; |
| 1111 | struct list_head rotation_list; | 1111 | struct list_head rotation_list; |
| 1112 | int jiffies_interval; | 1112 | int jiffies_interval; |
| 1113 | struct pmu *active_pmu; | 1113 | struct pmu *unique_pmu; |
| 1114 | struct perf_cgroup *cgrp; | 1114 | struct perf_cgroup *cgrp; |
| 1115 | }; | 1115 | }; |
| 1116 | 1116 | ||
diff --git a/kernel/events/core.c b/kernel/events/core.c index cda3ebd49e86..dbccf83c134d 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c | |||
| @@ -372,6 +372,8 @@ void perf_cgroup_switch(struct task_struct *task, int mode) | |||
| 372 | 372 | ||
| 373 | list_for_each_entry_rcu(pmu, &pmus, entry) { | 373 | list_for_each_entry_rcu(pmu, &pmus, entry) { |
| 374 | cpuctx = this_cpu_ptr(pmu->pmu_cpu_context); | 374 | cpuctx = this_cpu_ptr(pmu->pmu_cpu_context); |
| 375 | if (cpuctx->unique_pmu != pmu) | ||
| 376 | continue; /* ensure we process each cpuctx once */ | ||
| 375 | 377 | ||
| 376 | /* | 378 | /* |
| 377 | * perf_cgroup_events says at least one | 379 | * perf_cgroup_events says at least one |
| @@ -395,9 +397,10 @@ void perf_cgroup_switch(struct task_struct *task, int mode) | |||
| 395 | 397 | ||
| 396 | if (mode & PERF_CGROUP_SWIN) { | 398 | if (mode & PERF_CGROUP_SWIN) { |
| 397 | WARN_ON_ONCE(cpuctx->cgrp); | 399 | WARN_ON_ONCE(cpuctx->cgrp); |
| 398 | /* set cgrp before ctxsw in to | 400 | /* |
| 399 | * allow event_filter_match() to not | 401 | * set cgrp before ctxsw in to allow |
| 400 | * have to pass task around | 402 | * event_filter_match() to not have to pass |
| 403 | * task around | ||
| 401 | */ | 404 | */ |
| 402 | cpuctx->cgrp = perf_cgroup_from_task(task); | 405 | cpuctx->cgrp = perf_cgroup_from_task(task); |
| 403 | cpu_ctx_sched_in(cpuctx, EVENT_ALL, task); | 406 | cpu_ctx_sched_in(cpuctx, EVENT_ALL, task); |
| @@ -4412,7 +4415,7 @@ static void perf_event_task_event(struct perf_task_event *task_event) | |||
| 4412 | rcu_read_lock(); | 4415 | rcu_read_lock(); |
| 4413 | list_for_each_entry_rcu(pmu, &pmus, entry) { | 4416 | list_for_each_entry_rcu(pmu, &pmus, entry) { |
| 4414 | cpuctx = get_cpu_ptr(pmu->pmu_cpu_context); | 4417 | cpuctx = get_cpu_ptr(pmu->pmu_cpu_context); |
| 4415 | if (cpuctx->active_pmu != pmu) | 4418 | if (cpuctx->unique_pmu != pmu) |
| 4416 | goto next; | 4419 | goto next; |
| 4417 | perf_event_task_ctx(&cpuctx->ctx, task_event); | 4420 | perf_event_task_ctx(&cpuctx->ctx, task_event); |
| 4418 | 4421 | ||
| @@ -4558,7 +4561,7 @@ static void perf_event_comm_event(struct perf_comm_event *comm_event) | |||
| 4558 | rcu_read_lock(); | 4561 | rcu_read_lock(); |
| 4559 | list_for_each_entry_rcu(pmu, &pmus, entry) { | 4562 | list_for_each_entry_rcu(pmu, &pmus, entry) { |
| 4560 | cpuctx = get_cpu_ptr(pmu->pmu_cpu_context); | 4563 | cpuctx = get_cpu_ptr(pmu->pmu_cpu_context); |
| 4561 | if (cpuctx->active_pmu != pmu) | 4564 | if (cpuctx->unique_pmu != pmu) |
| 4562 | goto next; | 4565 | goto next; |
| 4563 | perf_event_comm_ctx(&cpuctx->ctx, comm_event); | 4566 | perf_event_comm_ctx(&cpuctx->ctx, comm_event); |
| 4564 | 4567 | ||
| @@ -4754,7 +4757,7 @@ got_name: | |||
| 4754 | rcu_read_lock(); | 4757 | rcu_read_lock(); |
| 4755 | list_for_each_entry_rcu(pmu, &pmus, entry) { | 4758 | list_for_each_entry_rcu(pmu, &pmus, entry) { |
| 4756 | cpuctx = get_cpu_ptr(pmu->pmu_cpu_context); | 4759 | cpuctx = get_cpu_ptr(pmu->pmu_cpu_context); |
| 4757 | if (cpuctx->active_pmu != pmu) | 4760 | if (cpuctx->unique_pmu != pmu) |
| 4758 | goto next; | 4761 | goto next; |
| 4759 | perf_event_mmap_ctx(&cpuctx->ctx, mmap_event, | 4762 | perf_event_mmap_ctx(&cpuctx->ctx, mmap_event, |
| 4760 | vma->vm_flags & VM_EXEC); | 4763 | vma->vm_flags & VM_EXEC); |
| @@ -5855,8 +5858,8 @@ static void update_pmu_context(struct pmu *pmu, struct pmu *old_pmu) | |||
| 5855 | 5858 | ||
| 5856 | cpuctx = per_cpu_ptr(pmu->pmu_cpu_context, cpu); | 5859 | cpuctx = per_cpu_ptr(pmu->pmu_cpu_context, cpu); |
| 5857 | 5860 | ||
| 5858 | if (cpuctx->active_pmu == old_pmu) | 5861 | if (cpuctx->unique_pmu == old_pmu) |
| 5859 | cpuctx->active_pmu = pmu; | 5862 | cpuctx->unique_pmu = pmu; |
| 5860 | } | 5863 | } |
| 5861 | } | 5864 | } |
| 5862 | 5865 | ||
| @@ -5991,7 +5994,7 @@ skip_type: | |||
| 5991 | cpuctx->ctx.pmu = pmu; | 5994 | cpuctx->ctx.pmu = pmu; |
| 5992 | cpuctx->jiffies_interval = 1; | 5995 | cpuctx->jiffies_interval = 1; |
| 5993 | INIT_LIST_HEAD(&cpuctx->rotation_list); | 5996 | INIT_LIST_HEAD(&cpuctx->rotation_list); |
| 5994 | cpuctx->active_pmu = pmu; | 5997 | cpuctx->unique_pmu = pmu; |
| 5995 | } | 5998 | } |
| 5996 | 5999 | ||
| 5997 | got_cpu_context: | 6000 | got_cpu_context: |
diff --git a/tools/perf/Makefile b/tools/perf/Makefile index 9546ff58f024..247264502fb7 100644 --- a/tools/perf/Makefile +++ b/tools/perf/Makefile | |||
| @@ -45,6 +45,8 @@ include config/utilities.mak | |||
| 45 | # | 45 | # |
| 46 | # Define NO_LIBUNWIND if you do not want libunwind dependency for dwarf | 46 | # Define NO_LIBUNWIND if you do not want libunwind dependency for dwarf |
| 47 | # backtrace post unwind. | 47 | # backtrace post unwind. |
| 48 | # | ||
| 49 | # Define NO_BACKTRACE if you do not want stack backtrace debug feature | ||
| 48 | 50 | ||
| 49 | $(OUTPUT)PERF-VERSION-FILE: .FORCE-PERF-VERSION-FILE | 51 | $(OUTPUT)PERF-VERSION-FILE: .FORCE-PERF-VERSION-FILE |
| 50 | @$(SHELL_PATH) util/PERF-VERSION-GEN $(OUTPUT) | 52 | @$(SHELL_PATH) util/PERF-VERSION-GEN $(OUTPUT) |
| @@ -185,7 +187,7 @@ strip-libs = $(filter-out -l%,$(1)) | |||
| 185 | PYTHON_EXT_SRCS := $(shell grep -v ^\# util/python-ext-sources) | 187 | PYTHON_EXT_SRCS := $(shell grep -v ^\# util/python-ext-sources) |
| 186 | PYTHON_EXT_DEPS := util/python-ext-sources util/setup.py | 188 | PYTHON_EXT_DEPS := util/python-ext-sources util/setup.py |
| 187 | 189 | ||
| 188 | $(OUTPUT)python/perf.so: $(PYRF_OBJS) $(PYTHON_EXT_SRCS) $(PYTHON_EXT_DEPS) | 190 | $(OUTPUT)python/perf.so: $(PYTHON_EXT_SRCS) $(PYTHON_EXT_DEPS) |
| 189 | $(QUIET_GEN)CFLAGS='$(BASIC_CFLAGS)' $(PYTHON_WORD) util/setup.py \ | 191 | $(QUIET_GEN)CFLAGS='$(BASIC_CFLAGS)' $(PYTHON_WORD) util/setup.py \ |
| 190 | --quiet build_ext; \ | 192 | --quiet build_ext; \ |
| 191 | mkdir -p $(OUTPUT)python && \ | 193 | mkdir -p $(OUTPUT)python && \ |
| @@ -447,20 +449,6 @@ BUILTIN_OBJS += $(OUTPUT)builtin-inject.o | |||
| 447 | 449 | ||
| 448 | PERFLIBS = $(LIB_FILE) $(LIBTRACEEVENT) | 450 | PERFLIBS = $(LIB_FILE) $(LIBTRACEEVENT) |
| 449 | 451 | ||
| 450 | # Files needed for the python binding, perf.so | ||
| 451 | # pyrf is just an internal name needed for all those wrappers. | ||
| 452 | # This has to be in sync with what is in the 'sources' variable in | ||
| 453 | # tools/perf/util/setup.py | ||
| 454 | |||
| 455 | PYRF_OBJS += $(OUTPUT)util/cpumap.o | ||
| 456 | PYRF_OBJS += $(OUTPUT)util/ctype.o | ||
| 457 | PYRF_OBJS += $(OUTPUT)util/evlist.o | ||
| 458 | PYRF_OBJS += $(OUTPUT)util/evsel.o | ||
| 459 | PYRF_OBJS += $(OUTPUT)util/python.o | ||
| 460 | PYRF_OBJS += $(OUTPUT)util/thread_map.o | ||
| 461 | PYRF_OBJS += $(OUTPUT)util/util.o | ||
| 462 | PYRF_OBJS += $(OUTPUT)util/xyarray.o | ||
| 463 | |||
| 464 | # | 452 | # |
| 465 | # Platform specific tweaks | 453 | # Platform specific tweaks |
| 466 | # | 454 | # |
| @@ -487,7 +475,13 @@ ifneq ($(call try-cc,$(SOURCE_LIBELF),$(FLAGS_LIBELF)),y) | |||
| 487 | NO_DWARF := 1 | 475 | NO_DWARF := 1 |
| 488 | NO_DEMANGLE := 1 | 476 | NO_DEMANGLE := 1 |
| 489 | endif | 477 | endif |
| 490 | endif | 478 | else |
| 479 | FLAGS_DWARF=$(ALL_CFLAGS) -ldw -lelf $(ALL_LDFLAGS) $(EXTLIBS) | ||
| 480 | ifneq ($(call try-cc,$(SOURCE_DWARF),$(FLAGS_DWARF)),y) | ||
| 481 | msg := $(warning No libdw.h found or old libdw.h found or elfutils is older than 0.138, disables dwarf support. Please install new elfutils-devel/libdw-dev); | ||
| 482 | NO_DWARF := 1 | ||
| 483 | endif # Dwarf support | ||
| 484 | endif # SOURCE_LIBELF | ||
| 491 | endif # NO_LIBELF | 485 | endif # NO_LIBELF |
| 492 | 486 | ||
| 493 | ifndef NO_LIBUNWIND | 487 | ifndef NO_LIBUNWIND |
| @@ -512,8 +506,6 @@ ifneq ($(OUTPUT),) | |||
| 512 | endif | 506 | endif |
| 513 | 507 | ||
| 514 | ifdef NO_LIBELF | 508 | ifdef NO_LIBELF |
| 515 | BASIC_CFLAGS += -DNO_LIBELF_SUPPORT | ||
| 516 | |||
| 517 | EXTLIBS := $(filter-out -lelf,$(EXTLIBS)) | 509 | EXTLIBS := $(filter-out -lelf,$(EXTLIBS)) |
| 518 | 510 | ||
| 519 | # Remove ELF/DWARF dependent codes | 511 | # Remove ELF/DWARF dependent codes |
| @@ -528,17 +520,12 @@ BUILTIN_OBJS := $(filter-out $(OUTPUT)builtin-probe.o,$(BUILTIN_OBJS)) | |||
| 528 | LIB_OBJS += $(OUTPUT)util/symbol-minimal.o | 520 | LIB_OBJS += $(OUTPUT)util/symbol-minimal.o |
| 529 | 521 | ||
| 530 | else # NO_LIBELF | 522 | else # NO_LIBELF |
| 523 | BASIC_CFLAGS += -DLIBELF_SUPPORT | ||
| 531 | 524 | ||
| 532 | ifneq ($(call try-cc,$(SOURCE_ELF_MMAP),$(FLAGS_COMMON)),y) | 525 | ifeq ($(call try-cc,$(SOURCE_ELF_MMAP),$(FLAGS_COMMON)),y) |
| 533 | BASIC_CFLAGS += -DLIBELF_NO_MMAP | 526 | BASIC_CFLAGS += -DLIBELF_MMAP |
| 534 | endif | 527 | endif |
| 535 | 528 | ||
| 536 | FLAGS_DWARF=$(ALL_CFLAGS) -ldw -lelf $(ALL_LDFLAGS) $(EXTLIBS) | ||
| 537 | ifneq ($(call try-cc,$(SOURCE_DWARF),$(FLAGS_DWARF)),y) | ||
| 538 | msg := $(warning No libdw.h found or old libdw.h found or elfutils is older than 0.138, disables dwarf support. Please install new elfutils-devel/libdw-dev); | ||
| 539 | NO_DWARF := 1 | ||
| 540 | endif # Dwarf support | ||
| 541 | |||
| 542 | ifndef NO_DWARF | 529 | ifndef NO_DWARF |
| 543 | ifeq ($(origin PERF_HAVE_DWARF_REGS), undefined) | 530 | ifeq ($(origin PERF_HAVE_DWARF_REGS), undefined) |
| 544 | msg := $(warning DWARF register mappings have not been defined for architecture $(ARCH), DWARF support disabled); | 531 | msg := $(warning DWARF register mappings have not been defined for architecture $(ARCH), DWARF support disabled); |
| @@ -551,38 +538,33 @@ endif # PERF_HAVE_DWARF_REGS | |||
| 551 | endif # NO_DWARF | 538 | endif # NO_DWARF |
| 552 | endif # NO_LIBELF | 539 | endif # NO_LIBELF |
| 553 | 540 | ||
| 554 | ifdef NO_LIBUNWIND | 541 | ifndef NO_LIBUNWIND |
| 555 | BASIC_CFLAGS += -DNO_LIBUNWIND_SUPPORT | 542 | BASIC_CFLAGS += -DLIBUNWIND_SUPPORT |
| 556 | else | ||
| 557 | EXTLIBS += $(LIBUNWIND_LIBS) | 543 | EXTLIBS += $(LIBUNWIND_LIBS) |
| 558 | BASIC_CFLAGS := $(LIBUNWIND_CFLAGS) $(BASIC_CFLAGS) | 544 | BASIC_CFLAGS := $(LIBUNWIND_CFLAGS) $(BASIC_CFLAGS) |
| 559 | BASIC_LDFLAGS := $(LIBUNWIND_LDFLAGS) $(BASIC_LDFLAGS) | 545 | BASIC_LDFLAGS := $(LIBUNWIND_LDFLAGS) $(BASIC_LDFLAGS) |
| 560 | LIB_OBJS += $(OUTPUT)util/unwind.o | 546 | LIB_OBJS += $(OUTPUT)util/unwind.o |
| 561 | endif | 547 | endif |
| 562 | 548 | ||
| 563 | ifdef NO_LIBAUDIT | 549 | ifndef NO_LIBAUDIT |
| 564 | BASIC_CFLAGS += -DNO_LIBAUDIT_SUPPORT | ||
| 565 | else | ||
| 566 | FLAGS_LIBAUDIT = $(ALL_CFLAGS) $(ALL_LDFLAGS) -laudit | 550 | FLAGS_LIBAUDIT = $(ALL_CFLAGS) $(ALL_LDFLAGS) -laudit |
| 567 | ifneq ($(call try-cc,$(SOURCE_LIBAUDIT),$(FLAGS_LIBAUDIT)),y) | 551 | ifneq ($(call try-cc,$(SOURCE_LIBAUDIT),$(FLAGS_LIBAUDIT)),y) |
| 568 | msg := $(warning No libaudit.h found, disables 'trace' tool, please install audit-libs-devel or libaudit-dev); | 552 | msg := $(warning No libaudit.h found, disables 'trace' tool, please install audit-libs-devel or libaudit-dev); |
| 569 | BASIC_CFLAGS += -DNO_LIBAUDIT_SUPPORT | ||
| 570 | else | 553 | else |
| 554 | BASIC_CFLAGS += -DLIBAUDIT_SUPPORT | ||
| 571 | BUILTIN_OBJS += $(OUTPUT)builtin-trace.o | 555 | BUILTIN_OBJS += $(OUTPUT)builtin-trace.o |
| 572 | EXTLIBS += -laudit | 556 | EXTLIBS += -laudit |
| 573 | endif | 557 | endif |
| 574 | endif | 558 | endif |
| 575 | 559 | ||
| 576 | ifdef NO_NEWT | 560 | ifndef NO_NEWT |
| 577 | BASIC_CFLAGS += -DNO_NEWT_SUPPORT | ||
| 578 | else | ||
| 579 | FLAGS_NEWT=$(ALL_CFLAGS) $(ALL_LDFLAGS) $(EXTLIBS) -lnewt | 561 | FLAGS_NEWT=$(ALL_CFLAGS) $(ALL_LDFLAGS) $(EXTLIBS) -lnewt |
| 580 | ifneq ($(call try-cc,$(SOURCE_NEWT),$(FLAGS_NEWT)),y) | 562 | ifneq ($(call try-cc,$(SOURCE_NEWT),$(FLAGS_NEWT)),y) |
| 581 | msg := $(warning newt not found, disables TUI support. Please install newt-devel or libnewt-dev); | 563 | msg := $(warning newt not found, disables TUI support. Please install newt-devel or libnewt-dev); |
| 582 | BASIC_CFLAGS += -DNO_NEWT_SUPPORT | ||
| 583 | else | 564 | else |
| 584 | # Fedora has /usr/include/slang/slang.h, but ubuntu /usr/include/slang.h | 565 | # Fedora has /usr/include/slang/slang.h, but ubuntu /usr/include/slang.h |
| 585 | BASIC_CFLAGS += -I/usr/include/slang | 566 | BASIC_CFLAGS += -I/usr/include/slang |
| 567 | BASIC_CFLAGS += -DNEWT_SUPPORT | ||
| 586 | EXTLIBS += -lnewt -lslang | 568 | EXTLIBS += -lnewt -lslang |
| 587 | LIB_OBJS += $(OUTPUT)ui/setup.o | 569 | LIB_OBJS += $(OUTPUT)ui/setup.o |
| 588 | LIB_OBJS += $(OUTPUT)ui/browser.o | 570 | LIB_OBJS += $(OUTPUT)ui/browser.o |
| @@ -604,17 +586,15 @@ else | |||
| 604 | endif | 586 | endif |
| 605 | endif | 587 | endif |
| 606 | 588 | ||
| 607 | ifdef NO_GTK2 | 589 | ifndef NO_GTK2 |
| 608 | BASIC_CFLAGS += -DNO_GTK2_SUPPORT | ||
| 609 | else | ||
| 610 | FLAGS_GTK2=$(ALL_CFLAGS) $(ALL_LDFLAGS) $(EXTLIBS) $(shell pkg-config --libs --cflags gtk+-2.0 2>/dev/null) | 590 | FLAGS_GTK2=$(ALL_CFLAGS) $(ALL_LDFLAGS) $(EXTLIBS) $(shell pkg-config --libs --cflags gtk+-2.0 2>/dev/null) |
| 611 | ifneq ($(call try-cc,$(SOURCE_GTK2),$(FLAGS_GTK2)),y) | 591 | ifneq ($(call try-cc,$(SOURCE_GTK2),$(FLAGS_GTK2)),y) |
| 612 | msg := $(warning GTK2 not found, disables GTK2 support. Please install gtk2-devel or libgtk2.0-dev); | 592 | msg := $(warning GTK2 not found, disables GTK2 support. Please install gtk2-devel or libgtk2.0-dev); |
| 613 | BASIC_CFLAGS += -DNO_GTK2_SUPPORT | ||
| 614 | else | 593 | else |
| 615 | ifeq ($(call try-cc,$(SOURCE_GTK2_INFOBAR),$(FLAGS_GTK2)),y) | 594 | ifeq ($(call try-cc,$(SOURCE_GTK2_INFOBAR),$(FLAGS_GTK2)),y) |
| 616 | BASIC_CFLAGS += -DHAVE_GTK_INFO_BAR | 595 | BASIC_CFLAGS += -DHAVE_GTK_INFO_BAR |
| 617 | endif | 596 | endif |
| 597 | BASIC_CFLAGS += -DGTK2_SUPPORT | ||
| 618 | BASIC_CFLAGS += $(shell pkg-config --cflags gtk+-2.0 2>/dev/null) | 598 | BASIC_CFLAGS += $(shell pkg-config --cflags gtk+-2.0 2>/dev/null) |
| 619 | EXTLIBS += $(shell pkg-config --libs gtk+-2.0 2>/dev/null) | 599 | EXTLIBS += $(shell pkg-config --libs gtk+-2.0 2>/dev/null) |
| 620 | LIB_OBJS += $(OUTPUT)ui/gtk/browser.o | 600 | LIB_OBJS += $(OUTPUT)ui/gtk/browser.o |
| @@ -622,7 +602,7 @@ else | |||
| 622 | LIB_OBJS += $(OUTPUT)ui/gtk/util.o | 602 | LIB_OBJS += $(OUTPUT)ui/gtk/util.o |
| 623 | LIB_OBJS += $(OUTPUT)ui/gtk/helpline.o | 603 | LIB_OBJS += $(OUTPUT)ui/gtk/helpline.o |
| 624 | # Make sure that it'd be included only once. | 604 | # Make sure that it'd be included only once. |
| 625 | ifneq ($(findstring -DNO_NEWT_SUPPORT,$(BASIC_CFLAGS)),) | 605 | ifeq ($(findstring -DNEWT_SUPPORT,$(BASIC_CFLAGS)),) |
| 626 | LIB_OBJS += $(OUTPUT)ui/setup.o | 606 | LIB_OBJS += $(OUTPUT)ui/setup.o |
| 627 | LIB_OBJS += $(OUTPUT)ui/util.o | 607 | LIB_OBJS += $(OUTPUT)ui/util.o |
| 628 | endif | 608 | endif |
| @@ -763,23 +743,18 @@ ifeq ($(NO_PERF_REGS),0) | |||
| 763 | ifeq ($(ARCH),x86) | 743 | ifeq ($(ARCH),x86) |
| 764 | LIB_H += arch/x86/include/perf_regs.h | 744 | LIB_H += arch/x86/include/perf_regs.h |
| 765 | endif | 745 | endif |
| 766 | else | 746 | BASIC_CFLAGS += -DHAVE_PERF_REGS |
| 767 | BASIC_CFLAGS += -DNO_PERF_REGS | ||
| 768 | endif | 747 | endif |
| 769 | 748 | ||
| 770 | ifdef NO_STRLCPY | 749 | ifndef NO_STRLCPY |
| 771 | BASIC_CFLAGS += -DNO_STRLCPY | 750 | ifeq ($(call try-cc,$(SOURCE_STRLCPY),),y) |
| 772 | else | 751 | BASIC_CFLAGS += -DHAVE_STRLCPY |
| 773 | ifneq ($(call try-cc,$(SOURCE_STRLCPY),),y) | ||
| 774 | BASIC_CFLAGS += -DNO_STRLCPY | ||
| 775 | endif | 752 | endif |
| 776 | endif | 753 | endif |
| 777 | 754 | ||
| 778 | ifdef NO_BACKTRACE | 755 | ifndef NO_BACKTRACE |
| 779 | BASIC_CFLAGS += -DNO_BACKTRACE | 756 | ifeq ($(call try-cc,$(SOURCE_BACKTRACE),),y) |
| 780 | else | 757 | BASIC_CFLAGS += -DBACKTRACE_SUPPORT |
| 781 | ifneq ($(call try-cc,$(SOURCE_BACKTRACE),),y) | ||
| 782 | BASIC_CFLAGS += -DNO_BACKTRACE | ||
| 783 | endif | 758 | endif |
| 784 | endif | 759 | endif |
| 785 | 760 | ||
diff --git a/tools/perf/bash_completion b/tools/perf/bash_completion index 1958fa539d0f..56e6a12aab59 100644 --- a/tools/perf/bash_completion +++ b/tools/perf/bash_completion | |||
| @@ -1,23 +1,59 @@ | |||
| 1 | # perf completion | 1 | # perf completion |
| 2 | 2 | ||
| 3 | function_exists() | ||
| 4 | { | ||
| 5 | declare -F $1 > /dev/null | ||
| 6 | return $? | ||
| 7 | } | ||
| 8 | |||
| 9 | function_exists __ltrim_colon_completions || | ||
| 10 | __ltrim_colon_completions() | ||
| 11 | { | ||
| 12 | if [[ "$1" == *:* && "$COMP_WORDBREAKS" == *:* ]]; then | ||
| 13 | # Remove colon-word prefix from COMPREPLY items | ||
| 14 | local colon_word=${1%${1##*:}} | ||
| 15 | local i=${#COMPREPLY[*]} | ||
| 16 | while [[ $((--i)) -ge 0 ]]; do | ||
| 17 | COMPREPLY[$i]=${COMPREPLY[$i]#"$colon_word"} | ||
| 18 | done | ||
| 19 | fi | ||
| 20 | } | ||
| 21 | |||
| 3 | have perf && | 22 | have perf && |
| 4 | _perf() | 23 | _perf() |
| 5 | { | 24 | { |
| 6 | local cur cmd | 25 | local cur prev cmd |
| 7 | 26 | ||
| 8 | COMPREPLY=() | 27 | COMPREPLY=() |
| 9 | _get_comp_words_by_ref cur prev | 28 | if function_exists _get_comp_words_by_ref; then |
| 29 | _get_comp_words_by_ref -n : cur prev | ||
| 30 | else | ||
| 31 | cur=$(_get_cword :) | ||
| 32 | prev=${COMP_WORDS[COMP_CWORD-1]} | ||
| 33 | fi | ||
| 10 | 34 | ||
| 11 | cmd=${COMP_WORDS[0]} | 35 | cmd=${COMP_WORDS[0]} |
| 12 | 36 | ||
| 13 | # List perf subcommands | 37 | # List perf subcommands or long options |
| 14 | if [ $COMP_CWORD -eq 1 ]; then | 38 | if [ $COMP_CWORD -eq 1 ]; then |
| 15 | cmds=$($cmd --list-cmds) | 39 | if [[ $cur == --* ]]; then |
| 16 | COMPREPLY=( $( compgen -W '$cmds' -- "$cur" ) ) | 40 | COMPREPLY=( $( compgen -W '--help --version \ |
| 41 | --exec-path --html-path --paginate --no-pager \ | ||
| 42 | --perf-dir --work-tree --debugfs-dir' -- "$cur" ) ) | ||
| 43 | else | ||
| 44 | cmds=$($cmd --list-cmds) | ||
| 45 | COMPREPLY=( $( compgen -W '$cmds' -- "$cur" ) ) | ||
| 46 | fi | ||
| 17 | # List possible events for -e option | 47 | # List possible events for -e option |
| 18 | elif [[ $prev == "-e" && "${COMP_WORDS[1]}" == @(record|stat|top) ]]; then | 48 | elif [[ $prev == "-e" && "${COMP_WORDS[1]}" == @(record|stat|top) ]]; then |
| 19 | cmds=$($cmd list --raw-dump) | 49 | evts=$($cmd list --raw-dump) |
| 20 | COMPREPLY=( $( compgen -W '$cmds' -- "$cur" ) ) | 50 | COMPREPLY=( $( compgen -W '$evts' -- "$cur" ) ) |
| 51 | __ltrim_colon_completions $cur | ||
| 52 | # List long option names | ||
| 53 | elif [[ $cur == --* ]]; then | ||
| 54 | subcmd=${COMP_WORDS[1]} | ||
| 55 | opts=$($cmd $subcmd --list-opts) | ||
| 56 | COMPREPLY=( $( compgen -W '$opts' -- "$cur" ) ) | ||
| 21 | # Fall down to list regular files | 57 | # Fall down to list regular files |
| 22 | else | 58 | else |
| 23 | _filedir | 59 | _filedir |
diff --git a/tools/perf/builtin-buildid-cache.c b/tools/perf/builtin-buildid-cache.c index 83654557e108..d37e077f4b14 100644 --- a/tools/perf/builtin-buildid-cache.c +++ b/tools/perf/builtin-buildid-cache.c | |||
| @@ -15,22 +15,6 @@ | |||
| 15 | #include "util/strlist.h" | 15 | #include "util/strlist.h" |
| 16 | #include "util/symbol.h" | 16 | #include "util/symbol.h" |
| 17 | 17 | ||
| 18 | static char const *add_name_list_str, *remove_name_list_str; | ||
| 19 | |||
| 20 | static const char * const buildid_cache_usage[] = { | ||
| 21 | "perf buildid-cache [<options>]", | ||
| 22 | NULL | ||
| 23 | }; | ||
| 24 | |||
| 25 | static const struct option buildid_cache_options[] = { | ||
| 26 | OPT_STRING('a', "add", &add_name_list_str, | ||
| 27 | "file list", "file(s) to add"), | ||
| 28 | OPT_STRING('r', "remove", &remove_name_list_str, "file list", | ||
| 29 | "file(s) to remove"), | ||
| 30 | OPT_INCR('v', "verbose", &verbose, "be more verbose"), | ||
| 31 | OPT_END() | ||
| 32 | }; | ||
| 33 | |||
| 34 | static int build_id_cache__add_file(const char *filename, const char *debugdir) | 18 | static int build_id_cache__add_file(const char *filename, const char *debugdir) |
| 35 | { | 19 | { |
| 36 | char sbuild_id[BUILD_ID_SIZE * 2 + 1]; | 20 | char sbuild_id[BUILD_ID_SIZE * 2 + 1]; |
| @@ -51,8 +35,8 @@ static int build_id_cache__add_file(const char *filename, const char *debugdir) | |||
| 51 | return err; | 35 | return err; |
| 52 | } | 36 | } |
| 53 | 37 | ||
| 54 | static int build_id_cache__remove_file(const char *filename __maybe_unused, | 38 | static int build_id_cache__remove_file(const char *filename, |
| 55 | const char *debugdir __maybe_unused) | 39 | const char *debugdir) |
| 56 | { | 40 | { |
| 57 | u8 build_id[BUILD_ID_SIZE]; | 41 | u8 build_id[BUILD_ID_SIZE]; |
| 58 | char sbuild_id[BUILD_ID_SIZE * 2 + 1]; | 42 | char sbuild_id[BUILD_ID_SIZE * 2 + 1]; |
| @@ -73,11 +57,34 @@ static int build_id_cache__remove_file(const char *filename __maybe_unused, | |||
| 73 | return err; | 57 | return err; |
| 74 | } | 58 | } |
| 75 | 59 | ||
| 76 | static int __cmd_buildid_cache(void) | 60 | int cmd_buildid_cache(int argc, const char **argv, |
| 61 | const char *prefix __maybe_unused) | ||
| 77 | { | 62 | { |
| 78 | struct strlist *list; | 63 | struct strlist *list; |
| 79 | struct str_node *pos; | 64 | struct str_node *pos; |
| 80 | char debugdir[PATH_MAX]; | 65 | char debugdir[PATH_MAX]; |
| 66 | char const *add_name_list_str = NULL, | ||
| 67 | *remove_name_list_str = NULL; | ||
| 68 | const struct option buildid_cache_options[] = { | ||
| 69 | OPT_STRING('a', "add", &add_name_list_str, | ||
| 70 | "file list", "file(s) to add"), | ||
| 71 | OPT_STRING('r', "remove", &remove_name_list_str, "file list", | ||
| 72 | "file(s) to remove"), | ||
| 73 | OPT_INCR('v', "verbose", &verbose, "be more verbose"), | ||
| 74 | OPT_END() | ||
| 75 | }; | ||
| 76 | const char * const buildid_cache_usage[] = { | ||
| 77 | "perf buildid-cache [<options>]", | ||
| 78 | NULL | ||
| 79 | }; | ||
| 80 | |||
| 81 | argc = parse_options(argc, argv, buildid_cache_options, | ||
| 82 | buildid_cache_usage, 0); | ||
| 83 | |||
| 84 | if (symbol__init() < 0) | ||
| 85 | return -1; | ||
| 86 | |||
| 87 | setup_pager(); | ||
| 81 | 88 | ||
| 82 | snprintf(debugdir, sizeof(debugdir), "%s", buildid_dir); | 89 | snprintf(debugdir, sizeof(debugdir), "%s", buildid_dir); |
| 83 | 90 | ||
| @@ -119,16 +126,3 @@ static int __cmd_buildid_cache(void) | |||
| 119 | 126 | ||
| 120 | return 0; | 127 | return 0; |
| 121 | } | 128 | } |
| 122 | |||
| 123 | int cmd_buildid_cache(int argc, const char **argv, | ||
| 124 | const char *prefix __maybe_unused) | ||
| 125 | { | ||
| 126 | argc = parse_options(argc, argv, buildid_cache_options, | ||
| 127 | buildid_cache_usage, 0); | ||
| 128 | |||
| 129 | if (symbol__init() < 0) | ||
| 130 | return -1; | ||
| 131 | |||
| 132 | setup_pager(); | ||
| 133 | return __cmd_buildid_cache(); | ||
| 134 | } | ||
diff --git a/tools/perf/builtin-buildid-list.c b/tools/perf/builtin-buildid-list.c index 1159feeebb19..a0e94fffa03e 100644 --- a/tools/perf/builtin-buildid-list.c +++ b/tools/perf/builtin-buildid-list.c | |||
| @@ -16,27 +16,6 @@ | |||
| 16 | #include "util/session.h" | 16 | #include "util/session.h" |
| 17 | #include "util/symbol.h" | 17 | #include "util/symbol.h" |
| 18 | 18 | ||
| 19 | static const char *input_name; | ||
| 20 | static bool force; | ||
| 21 | static bool show_kernel; | ||
| 22 | static bool with_hits; | ||
| 23 | |||
| 24 | static const char * const buildid_list_usage[] = { | ||
| 25 | "perf buildid-list [<options>]", | ||
| 26 | NULL | ||
| 27 | }; | ||
| 28 | |||
| 29 | static const struct option options[] = { | ||
| 30 | OPT_BOOLEAN('H', "with-hits", &with_hits, "Show only DSOs with hits"), | ||
| 31 | OPT_STRING('i', "input", &input_name, "file", | ||
| 32 | "input file name"), | ||
| 33 | OPT_BOOLEAN('f', "force", &force, "don't complain, do it"), | ||
| 34 | OPT_BOOLEAN('k', "kernel", &show_kernel, "Show current kernel build id"), | ||
| 35 | OPT_INCR('v', "verbose", &verbose, | ||
| 36 | "be more verbose"), | ||
| 37 | OPT_END() | ||
| 38 | }; | ||
| 39 | |||
| 40 | static int sysfs__fprintf_build_id(FILE *fp) | 19 | static int sysfs__fprintf_build_id(FILE *fp) |
| 41 | { | 20 | { |
| 42 | u8 kallsyms_build_id[BUILD_ID_SIZE]; | 21 | u8 kallsyms_build_id[BUILD_ID_SIZE]; |
| @@ -65,7 +44,8 @@ static int filename__fprintf_build_id(const char *name, FILE *fp) | |||
| 65 | return fprintf(fp, "%s\n", sbuild_id); | 44 | return fprintf(fp, "%s\n", sbuild_id); |
| 66 | } | 45 | } |
| 67 | 46 | ||
| 68 | static int perf_session__list_build_ids(void) | 47 | static int perf_session__list_build_ids(const char *input_name, |
| 48 | bool force, bool with_hits) | ||
| 69 | { | 49 | { |
| 70 | struct perf_session *session; | 50 | struct perf_session *session; |
| 71 | 51 | ||
| @@ -95,18 +75,31 @@ out: | |||
| 95 | return 0; | 75 | return 0; |
| 96 | } | 76 | } |
| 97 | 77 | ||
| 98 | static int __cmd_buildid_list(void) | ||
| 99 | { | ||
| 100 | if (show_kernel) | ||
| 101 | return sysfs__fprintf_build_id(stdout); | ||
| 102 | |||
| 103 | return perf_session__list_build_ids(); | ||
| 104 | } | ||
| 105 | |||
| 106 | int cmd_buildid_list(int argc, const char **argv, | 78 | int cmd_buildid_list(int argc, const char **argv, |
| 107 | const char *prefix __maybe_unused) | 79 | const char *prefix __maybe_unused) |
| 108 | { | 80 | { |
| 81 | bool show_kernel = false; | ||
| 82 | bool with_hits = false; | ||
| 83 | bool force = false; | ||
| 84 | const char *input_name = NULL; | ||
| 85 | const struct option options[] = { | ||
| 86 | OPT_BOOLEAN('H', "with-hits", &with_hits, "Show only DSOs with hits"), | ||
| 87 | OPT_STRING('i', "input", &input_name, "file", "input file name"), | ||
| 88 | OPT_BOOLEAN('f', "force", &force, "don't complain, do it"), | ||
| 89 | OPT_BOOLEAN('k', "kernel", &show_kernel, "Show current kernel build id"), | ||
| 90 | OPT_INCR('v', "verbose", &verbose, "be more verbose"), | ||
| 91 | OPT_END() | ||
| 92 | }; | ||
| 93 | const char * const buildid_list_usage[] = { | ||
| 94 | "perf buildid-list [<options>]", | ||
| 95 | NULL | ||
| 96 | }; | ||
| 97 | |||
| 109 | argc = parse_options(argc, argv, options, buildid_list_usage, 0); | 98 | argc = parse_options(argc, argv, options, buildid_list_usage, 0); |
| 110 | setup_pager(); | 99 | setup_pager(); |
| 111 | return __cmd_buildid_list(); | 100 | |
| 101 | if (show_kernel) | ||
| 102 | return sysfs__fprintf_build_id(stdout); | ||
| 103 | |||
| 104 | return perf_session__list_build_ids(input_name, force, with_hits); | ||
| 112 | } | 105 | } |
diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c index 761f4197a9e2..a0b531c14b97 100644 --- a/tools/perf/builtin-diff.c +++ b/tools/perf/builtin-diff.c | |||
| @@ -70,8 +70,8 @@ static struct perf_tool tool = { | |||
| 70 | .ordering_requires_timestamps = true, | 70 | .ordering_requires_timestamps = true, |
| 71 | }; | 71 | }; |
| 72 | 72 | ||
| 73 | static void perf_session__insert_hist_entry_by_name(struct rb_root *root, | 73 | static void insert_hist_entry_by_name(struct rb_root *root, |
| 74 | struct hist_entry *he) | 74 | struct hist_entry *he) |
| 75 | { | 75 | { |
| 76 | struct rb_node **p = &root->rb_node; | 76 | struct rb_node **p = &root->rb_node; |
| 77 | struct rb_node *parent = NULL; | 77 | struct rb_node *parent = NULL; |
| @@ -90,7 +90,7 @@ static void perf_session__insert_hist_entry_by_name(struct rb_root *root, | |||
| 90 | rb_insert_color(&he->rb_node, root); | 90 | rb_insert_color(&he->rb_node, root); |
| 91 | } | 91 | } |
| 92 | 92 | ||
| 93 | static void hists__resort_entries(struct hists *self) | 93 | static void hists__name_resort(struct hists *self, bool sort) |
| 94 | { | 94 | { |
| 95 | unsigned long position = 1; | 95 | unsigned long position = 1; |
| 96 | struct rb_root tmp = RB_ROOT; | 96 | struct rb_root tmp = RB_ROOT; |
| @@ -100,12 +100,16 @@ static void hists__resort_entries(struct hists *self) | |||
| 100 | struct hist_entry *n = rb_entry(next, struct hist_entry, rb_node); | 100 | struct hist_entry *n = rb_entry(next, struct hist_entry, rb_node); |
| 101 | 101 | ||
| 102 | next = rb_next(&n->rb_node); | 102 | next = rb_next(&n->rb_node); |
| 103 | rb_erase(&n->rb_node, &self->entries); | ||
| 104 | n->position = position++; | 103 | n->position = position++; |
| 105 | perf_session__insert_hist_entry_by_name(&tmp, n); | 104 | |
| 105 | if (sort) { | ||
| 106 | rb_erase(&n->rb_node, &self->entries); | ||
| 107 | insert_hist_entry_by_name(&tmp, n); | ||
| 108 | } | ||
| 106 | } | 109 | } |
| 107 | 110 | ||
| 108 | self->entries = tmp; | 111 | if (sort) |
| 112 | self->entries = tmp; | ||
| 109 | } | 113 | } |
| 110 | 114 | ||
| 111 | static struct hist_entry *hists__find_entry(struct hists *self, | 115 | static struct hist_entry *hists__find_entry(struct hists *self, |
| @@ -121,7 +125,7 @@ static struct hist_entry *hists__find_entry(struct hists *self, | |||
| 121 | n = n->rb_left; | 125 | n = n->rb_left; |
| 122 | else if (cmp > 0) | 126 | else if (cmp > 0) |
| 123 | n = n->rb_right; | 127 | n = n->rb_right; |
| 124 | else | 128 | else |
| 125 | return iter; | 129 | return iter; |
| 126 | } | 130 | } |
| 127 | 131 | ||
| @@ -150,6 +154,24 @@ static struct perf_evsel *evsel_match(struct perf_evsel *evsel, | |||
| 150 | return NULL; | 154 | return NULL; |
| 151 | } | 155 | } |
| 152 | 156 | ||
| 157 | static void perf_evlist__resort_hists(struct perf_evlist *evlist, bool name) | ||
| 158 | { | ||
| 159 | struct perf_evsel *evsel; | ||
| 160 | |||
| 161 | list_for_each_entry(evsel, &evlist->entries, node) { | ||
| 162 | struct hists *hists = &evsel->hists; | ||
| 163 | |||
| 164 | hists__output_resort(hists); | ||
| 165 | |||
| 166 | /* | ||
| 167 | * The hists__name_resort only sets possition | ||
| 168 | * if name is false. | ||
| 169 | */ | ||
| 170 | if (name || ((!name) && show_displacement)) | ||
| 171 | hists__name_resort(hists, name); | ||
| 172 | } | ||
| 173 | } | ||
| 174 | |||
| 153 | static int __cmd_diff(void) | 175 | static int __cmd_diff(void) |
| 154 | { | 176 | { |
| 155 | int ret, i; | 177 | int ret, i; |
| @@ -176,15 +198,8 @@ static int __cmd_diff(void) | |||
| 176 | evlist_old = older->evlist; | 198 | evlist_old = older->evlist; |
| 177 | evlist_new = newer->evlist; | 199 | evlist_new = newer->evlist; |
| 178 | 200 | ||
| 179 | list_for_each_entry(evsel, &evlist_new->entries, node) | 201 | perf_evlist__resort_hists(evlist_old, true); |
| 180 | hists__output_resort(&evsel->hists); | 202 | perf_evlist__resort_hists(evlist_new, false); |
| 181 | |||
| 182 | list_for_each_entry(evsel, &evlist_old->entries, node) { | ||
| 183 | hists__output_resort(&evsel->hists); | ||
| 184 | |||
| 185 | if (show_displacement) | ||
| 186 | hists__resort_entries(&evsel->hists); | ||
| 187 | } | ||
| 188 | 203 | ||
| 189 | list_for_each_entry(evsel, &evlist_new->entries, node) { | 204 | list_for_each_entry(evsel, &evlist_new->entries, node) { |
| 190 | struct perf_evsel *evsel_old; | 205 | struct perf_evsel *evsel_old; |
| @@ -199,8 +214,7 @@ static int __cmd_diff(void) | |||
| 199 | first = false; | 214 | first = false; |
| 200 | 215 | ||
| 201 | hists__match(&evsel_old->hists, &evsel->hists); | 216 | hists__match(&evsel_old->hists, &evsel->hists); |
| 202 | hists__fprintf(&evsel->hists, &evsel_old->hists, | 217 | hists__fprintf(&evsel->hists, true, 0, 0, stdout); |
| 203 | show_displacement, true, 0, 0, stdout); | ||
| 204 | } | 218 | } |
| 205 | 219 | ||
| 206 | out_delete: | 220 | out_delete: |
| @@ -242,6 +256,21 @@ static const struct option options[] = { | |||
| 242 | OPT_END() | 256 | OPT_END() |
| 243 | }; | 257 | }; |
| 244 | 258 | ||
| 259 | static void ui_init(void) | ||
| 260 | { | ||
| 261 | perf_hpp__init(); | ||
| 262 | |||
| 263 | /* No overhead column. */ | ||
| 264 | perf_hpp__column_enable(PERF_HPP__OVERHEAD, false); | ||
| 265 | |||
| 266 | /* Display baseline/delta/displacement columns. */ | ||
| 267 | perf_hpp__column_enable(PERF_HPP__BASELINE, true); | ||
| 268 | perf_hpp__column_enable(PERF_HPP__DELTA, true); | ||
| 269 | |||
| 270 | if (show_displacement) | ||
| 271 | perf_hpp__column_enable(PERF_HPP__DISPL, true); | ||
| 272 | } | ||
| 273 | |||
| 245 | int cmd_diff(int argc, const char **argv, const char *prefix __maybe_unused) | 274 | int cmd_diff(int argc, const char **argv, const char *prefix __maybe_unused) |
| 246 | { | 275 | { |
| 247 | sort_order = diff__default_sort_order; | 276 | sort_order = diff__default_sort_order; |
| @@ -264,7 +293,8 @@ int cmd_diff(int argc, const char **argv, const char *prefix __maybe_unused) | |||
| 264 | if (symbol__init() < 0) | 293 | if (symbol__init() < 0) |
| 265 | return -1; | 294 | return -1; |
| 266 | 295 | ||
| 267 | perf_hpp__init(true, show_displacement); | 296 | ui_init(); |
| 297 | |||
| 268 | setup_sorting(diff_usage, options); | 298 | setup_sorting(diff_usage, options); |
| 269 | setup_pager(); | 299 | setup_pager(); |
| 270 | 300 | ||
diff --git a/tools/perf/builtin-evlist.c b/tools/perf/builtin-evlist.c index 1fb164164fd0..997afb82691b 100644 --- a/tools/perf/builtin-evlist.c +++ b/tools/perf/builtin-evlist.c | |||
| @@ -108,23 +108,20 @@ static int __cmd_evlist(const char *input_name, struct perf_attr_details *detail | |||
| 108 | return 0; | 108 | return 0; |
| 109 | } | 109 | } |
| 110 | 110 | ||
| 111 | static const char * const evlist_usage[] = { | ||
| 112 | "perf evlist [<options>]", | ||
| 113 | NULL | ||
| 114 | }; | ||
| 115 | |||
| 116 | int cmd_evlist(int argc, const char **argv, const char *prefix __maybe_unused) | 111 | int cmd_evlist(int argc, const char **argv, const char *prefix __maybe_unused) |
| 117 | { | 112 | { |
| 118 | struct perf_attr_details details = { .verbose = false, }; | 113 | struct perf_attr_details details = { .verbose = false, }; |
| 119 | const char *input_name = NULL; | 114 | const char *input_name = NULL; |
| 120 | const struct option options[] = { | 115 | const struct option options[] = { |
| 121 | OPT_STRING('i', "input", &input_name, "file", | 116 | OPT_STRING('i', "input", &input_name, "file", "Input file name"), |
| 122 | "Input file name"), | 117 | OPT_BOOLEAN('F', "freq", &details.freq, "Show the sample frequency"), |
| 123 | OPT_BOOLEAN('F', "freq", &details.freq, | 118 | OPT_BOOLEAN('v', "verbose", &details.verbose, |
| 124 | "Show the sample frequency"), | 119 | "Show all event attr details"), |
| 125 | OPT_BOOLEAN('v', "verbose", &details.verbose, | 120 | OPT_END() |
| 126 | "Show all event attr details"), | 121 | }; |
| 127 | OPT_END() | 122 | const char * const evlist_usage[] = { |
| 123 | "perf evlist [<options>]", | ||
| 124 | NULL | ||
| 128 | }; | 125 | }; |
| 129 | 126 | ||
| 130 | argc = parse_options(argc, argv, options, evlist_usage, 0); | 127 | argc = parse_options(argc, argv, options, evlist_usage, 0); |
diff --git a/tools/perf/builtin-help.c b/tools/perf/builtin-help.c index 25c8b942ff85..411ee5664e98 100644 --- a/tools/perf/builtin-help.c +++ b/tools/perf/builtin-help.c | |||
| @@ -30,23 +30,6 @@ enum help_format { | |||
| 30 | HELP_FORMAT_WEB, | 30 | HELP_FORMAT_WEB, |
| 31 | }; | 31 | }; |
| 32 | 32 | ||
| 33 | static bool show_all = false; | ||
| 34 | static enum help_format help_format = HELP_FORMAT_NONE; | ||
| 35 | static struct option builtin_help_options[] = { | ||
| 36 | OPT_BOOLEAN('a', "all", &show_all, "print all available commands"), | ||
| 37 | OPT_SET_UINT('m', "man", &help_format, "show man page", HELP_FORMAT_MAN), | ||
| 38 | OPT_SET_UINT('w', "web", &help_format, "show manual in web browser", | ||
| 39 | HELP_FORMAT_WEB), | ||
| 40 | OPT_SET_UINT('i', "info", &help_format, "show info page", | ||
| 41 | HELP_FORMAT_INFO), | ||
| 42 | OPT_END(), | ||
| 43 | }; | ||
| 44 | |||
| 45 | static const char * const builtin_help_usage[] = { | ||
| 46 | "perf help [--all] [--man|--web|--info] [command]", | ||
| 47 | NULL | ||
| 48 | }; | ||
| 49 | |||
| 50 | static enum help_format parse_help_format(const char *format) | 33 | static enum help_format parse_help_format(const char *format) |
| 51 | { | 34 | { |
| 52 | if (!strcmp(format, "man")) | 35 | if (!strcmp(format, "man")) |
| @@ -258,11 +241,13 @@ static int add_man_viewer_info(const char *var, const char *value) | |||
| 258 | 241 | ||
| 259 | static int perf_help_config(const char *var, const char *value, void *cb) | 242 | static int perf_help_config(const char *var, const char *value, void *cb) |
| 260 | { | 243 | { |
| 244 | enum help_format *help_formatp = cb; | ||
| 245 | |||
| 261 | if (!strcmp(var, "help.format")) { | 246 | if (!strcmp(var, "help.format")) { |
| 262 | if (!value) | 247 | if (!value) |
| 263 | return config_error_nonbool(var); | 248 | return config_error_nonbool(var); |
| 264 | help_format = parse_help_format(value); | 249 | *help_formatp = parse_help_format(value); |
| 265 | if (help_format == HELP_FORMAT_NONE) | 250 | if (*help_formatp == HELP_FORMAT_NONE) |
| 266 | return -1; | 251 | return -1; |
| 267 | return 0; | 252 | return 0; |
| 268 | } | 253 | } |
| @@ -428,12 +413,27 @@ static int show_html_page(const char *perf_cmd) | |||
| 428 | 413 | ||
| 429 | int cmd_help(int argc, const char **argv, const char *prefix __maybe_unused) | 414 | int cmd_help(int argc, const char **argv, const char *prefix __maybe_unused) |
| 430 | { | 415 | { |
| 416 | bool show_all = false; | ||
| 417 | enum help_format help_format = HELP_FORMAT_NONE; | ||
| 418 | struct option builtin_help_options[] = { | ||
| 419 | OPT_BOOLEAN('a', "all", &show_all, "print all available commands"), | ||
| 420 | OPT_SET_UINT('m', "man", &help_format, "show man page", HELP_FORMAT_MAN), | ||
| 421 | OPT_SET_UINT('w', "web", &help_format, "show manual in web browser", | ||
| 422 | HELP_FORMAT_WEB), | ||
| 423 | OPT_SET_UINT('i', "info", &help_format, "show info page", | ||
| 424 | HELP_FORMAT_INFO), | ||
| 425 | OPT_END(), | ||
| 426 | }; | ||
| 427 | const char * const builtin_help_usage[] = { | ||
| 428 | "perf help [--all] [--man|--web|--info] [command]", | ||
| 429 | NULL | ||
| 430 | }; | ||
| 431 | const char *alias; | 431 | const char *alias; |
| 432 | int rc = 0; | 432 | int rc = 0; |
| 433 | 433 | ||
| 434 | load_command_list("perf-", &main_cmds, &other_cmds); | 434 | load_command_list("perf-", &main_cmds, &other_cmds); |
| 435 | 435 | ||
| 436 | perf_config(perf_help_config, NULL); | 436 | perf_config(perf_help_config, &help_format); |
| 437 | 437 | ||
| 438 | argc = parse_options(argc, argv, builtin_help_options, | 438 | argc = parse_options(argc, argv, builtin_help_options, |
| 439 | builtin_help_usage, 0); | 439 | builtin_help_usage, 0); |
diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c index 1eaa6617c814..4688bea95c12 100644 --- a/tools/perf/builtin-inject.c +++ b/tools/perf/builtin-inject.c | |||
| @@ -14,8 +14,10 @@ | |||
| 14 | 14 | ||
| 15 | #include "util/parse-options.h" | 15 | #include "util/parse-options.h" |
| 16 | 16 | ||
| 17 | static char const *input_name = "-"; | 17 | struct perf_inject { |
| 18 | static bool inject_build_ids; | 18 | struct perf_tool tool; |
| 19 | bool build_ids; | ||
| 20 | }; | ||
| 19 | 21 | ||
| 20 | static int perf_event__repipe_synth(struct perf_tool *tool __maybe_unused, | 22 | static int perf_event__repipe_synth(struct perf_tool *tool __maybe_unused, |
| 21 | union perf_event *event, | 23 | union perf_event *event, |
| @@ -194,7 +196,7 @@ static int perf_event__inject_buildid(struct perf_tool *tool, | |||
| 194 | * account this as unresolved. | 196 | * account this as unresolved. |
| 195 | */ | 197 | */ |
| 196 | } else { | 198 | } else { |
| 197 | #ifndef NO_LIBELF_SUPPORT | 199 | #ifdef LIBELF_SUPPORT |
| 198 | pr_warning("no symbols found in %s, maybe " | 200 | pr_warning("no symbols found in %s, maybe " |
| 199 | "install a debug package?\n", | 201 | "install a debug package?\n", |
| 200 | al.map->dso->long_name); | 202 | al.map->dso->long_name); |
| @@ -208,22 +210,6 @@ repipe: | |||
| 208 | return 0; | 210 | return 0; |
| 209 | } | 211 | } |
| 210 | 212 | ||
| 211 | struct perf_tool perf_inject = { | ||
| 212 | .sample = perf_event__repipe_sample, | ||
| 213 | .mmap = perf_event__repipe, | ||
| 214 | .comm = perf_event__repipe, | ||
| 215 | .fork = perf_event__repipe, | ||
| 216 | .exit = perf_event__repipe, | ||
| 217 | .lost = perf_event__repipe, | ||
| 218 | .read = perf_event__repipe_sample, | ||
| 219 | .throttle = perf_event__repipe, | ||
| 220 | .unthrottle = perf_event__repipe, | ||
| 221 | .attr = perf_event__repipe_attr, | ||
| 222 | .event_type = perf_event__repipe_event_type_synth, | ||
| 223 | .tracing_data = perf_event__repipe_tracing_data_synth, | ||
| 224 | .build_id = perf_event__repipe_op2_synth, | ||
| 225 | }; | ||
| 226 | |||
| 227 | extern volatile int session_done; | 213 | extern volatile int session_done; |
| 228 | 214 | ||
| 229 | static void sig_handler(int sig __maybe_unused) | 215 | static void sig_handler(int sig __maybe_unused) |
| @@ -231,56 +217,72 @@ static void sig_handler(int sig __maybe_unused) | |||
| 231 | session_done = 1; | 217 | session_done = 1; |
| 232 | } | 218 | } |
| 233 | 219 | ||
| 234 | static int __cmd_inject(void) | 220 | static int __cmd_inject(struct perf_inject *inject) |
| 235 | { | 221 | { |
| 236 | struct perf_session *session; | 222 | struct perf_session *session; |
| 237 | int ret = -EINVAL; | 223 | int ret = -EINVAL; |
| 238 | 224 | ||
| 239 | signal(SIGINT, sig_handler); | 225 | signal(SIGINT, sig_handler); |
| 240 | 226 | ||
| 241 | if (inject_build_ids) { | 227 | if (inject->build_ids) { |
| 242 | perf_inject.sample = perf_event__inject_buildid; | 228 | inject->tool.sample = perf_event__inject_buildid; |
| 243 | perf_inject.mmap = perf_event__repipe_mmap; | 229 | inject->tool.mmap = perf_event__repipe_mmap; |
| 244 | perf_inject.fork = perf_event__repipe_task; | 230 | inject->tool.fork = perf_event__repipe_task; |
| 245 | perf_inject.tracing_data = perf_event__repipe_tracing_data; | 231 | inject->tool.tracing_data = perf_event__repipe_tracing_data; |
| 246 | } | 232 | } |
| 247 | 233 | ||
| 248 | session = perf_session__new(input_name, O_RDONLY, false, true, &perf_inject); | 234 | session = perf_session__new("-", O_RDONLY, false, true, &inject->tool); |
| 249 | if (session == NULL) | 235 | if (session == NULL) |
| 250 | return -ENOMEM; | 236 | return -ENOMEM; |
| 251 | 237 | ||
| 252 | ret = perf_session__process_events(session, &perf_inject); | 238 | ret = perf_session__process_events(session, &inject->tool); |
| 253 | 239 | ||
| 254 | perf_session__delete(session); | 240 | perf_session__delete(session); |
| 255 | 241 | ||
| 256 | return ret; | 242 | return ret; |
| 257 | } | 243 | } |
| 258 | 244 | ||
| 259 | static const char * const report_usage[] = { | ||
| 260 | "perf inject [<options>]", | ||
| 261 | NULL | ||
| 262 | }; | ||
| 263 | |||
| 264 | static const struct option options[] = { | ||
| 265 | OPT_BOOLEAN('b', "build-ids", &inject_build_ids, | ||
| 266 | "Inject build-ids into the output stream"), | ||
| 267 | OPT_INCR('v', "verbose", &verbose, | ||
| 268 | "be more verbose (show build ids, etc)"), | ||
| 269 | OPT_END() | ||
| 270 | }; | ||
| 271 | |||
| 272 | int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused) | 245 | int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused) |
| 273 | { | 246 | { |
| 274 | argc = parse_options(argc, argv, options, report_usage, 0); | 247 | struct perf_inject inject = { |
| 248 | .tool = { | ||
| 249 | .sample = perf_event__repipe_sample, | ||
| 250 | .mmap = perf_event__repipe, | ||
| 251 | .comm = perf_event__repipe, | ||
| 252 | .fork = perf_event__repipe, | ||
| 253 | .exit = perf_event__repipe, | ||
| 254 | .lost = perf_event__repipe, | ||
| 255 | .read = perf_event__repipe_sample, | ||
| 256 | .throttle = perf_event__repipe, | ||
| 257 | .unthrottle = perf_event__repipe, | ||
| 258 | .attr = perf_event__repipe_attr, | ||
| 259 | .event_type = perf_event__repipe_event_type_synth, | ||
| 260 | .tracing_data = perf_event__repipe_tracing_data_synth, | ||
| 261 | .build_id = perf_event__repipe_op2_synth, | ||
| 262 | }, | ||
| 263 | }; | ||
| 264 | const struct option options[] = { | ||
| 265 | OPT_BOOLEAN('b', "build-ids", &inject.build_ids, | ||
| 266 | "Inject build-ids into the output stream"), | ||
| 267 | OPT_INCR('v', "verbose", &verbose, | ||
| 268 | "be more verbose (show build ids, etc)"), | ||
| 269 | OPT_END() | ||
| 270 | }; | ||
| 271 | const char * const inject_usage[] = { | ||
| 272 | "perf inject [<options>]", | ||
| 273 | NULL | ||
| 274 | }; | ||
| 275 | |||
| 276 | argc = parse_options(argc, argv, options, inject_usage, 0); | ||
| 275 | 277 | ||
| 276 | /* | 278 | /* |
| 277 | * Any (unrecognized) arguments left? | 279 | * Any (unrecognized) arguments left? |
| 278 | */ | 280 | */ |
| 279 | if (argc) | 281 | if (argc) |
| 280 | usage_with_options(report_usage, options); | 282 | usage_with_options(inject_usage, options); |
| 281 | 283 | ||
| 282 | if (symbol__init() < 0) | 284 | if (symbol__init() < 0) |
| 283 | return -1; | 285 | return -1; |
| 284 | 286 | ||
| 285 | return __cmd_inject(); | 287 | return __cmd_inject(&inject); |
| 286 | } | 288 | } |
diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c index bc912c68f49a..14bf82f63659 100644 --- a/tools/perf/builtin-kmem.c +++ b/tools/perf/builtin-kmem.c | |||
| @@ -21,8 +21,6 @@ | |||
| 21 | struct alloc_stat; | 21 | struct alloc_stat; |
| 22 | typedef int (*sort_fn_t)(struct alloc_stat *, struct alloc_stat *); | 22 | typedef int (*sort_fn_t)(struct alloc_stat *, struct alloc_stat *); |
| 23 | 23 | ||
| 24 | static const char *input_name; | ||
| 25 | |||
| 26 | static int alloc_flag; | 24 | static int alloc_flag; |
| 27 | static int caller_flag; | 25 | static int caller_flag; |
| 28 | 26 | ||
| @@ -31,8 +29,6 @@ static int caller_lines = -1; | |||
| 31 | 29 | ||
| 32 | static bool raw_ip; | 30 | static bool raw_ip; |
| 33 | 31 | ||
| 34 | static char default_sort_order[] = "frag,hit,bytes"; | ||
| 35 | |||
| 36 | static int *cpunode_map; | 32 | static int *cpunode_map; |
| 37 | static int max_cpu_num; | 33 | static int max_cpu_num; |
| 38 | 34 | ||
| @@ -481,7 +477,7 @@ static void sort_result(void) | |||
| 481 | __sort_result(&root_caller_stat, &root_caller_sorted, &caller_sort); | 477 | __sort_result(&root_caller_stat, &root_caller_sorted, &caller_sort); |
| 482 | } | 478 | } |
| 483 | 479 | ||
| 484 | static int __cmd_kmem(void) | 480 | static int __cmd_kmem(const char *input_name) |
| 485 | { | 481 | { |
| 486 | int err = -EINVAL; | 482 | int err = -EINVAL; |
| 487 | struct perf_session *session; | 483 | struct perf_session *session; |
| @@ -520,11 +516,6 @@ out_delete: | |||
| 520 | return err; | 516 | return err; |
| 521 | } | 517 | } |
| 522 | 518 | ||
| 523 | static const char * const kmem_usage[] = { | ||
| 524 | "perf kmem [<options>] {record|stat}", | ||
| 525 | NULL | ||
| 526 | }; | ||
| 527 | |||
| 528 | static int ptr_cmp(struct alloc_stat *l, struct alloc_stat *r) | 519 | static int ptr_cmp(struct alloc_stat *l, struct alloc_stat *r) |
| 529 | { | 520 | { |
| 530 | if (l->ptr < r->ptr) | 521 | if (l->ptr < r->ptr) |
| @@ -720,41 +711,17 @@ static int parse_line_opt(const struct option *opt __maybe_unused, | |||
| 720 | return 0; | 711 | return 0; |
| 721 | } | 712 | } |
| 722 | 713 | ||
| 723 | static const struct option kmem_options[] = { | 714 | static int __cmd_record(int argc, const char **argv) |
| 724 | OPT_STRING('i', "input", &input_name, "file", | 715 | { |
| 725 | "input file name"), | 716 | const char * const record_args[] = { |
| 726 | OPT_CALLBACK_NOOPT(0, "caller", NULL, NULL, | 717 | "record", "-a", "-R", "-f", "-c", "1", |
| 727 | "show per-callsite statistics", | ||
| 728 | parse_caller_opt), | ||
| 729 | OPT_CALLBACK_NOOPT(0, "alloc", NULL, NULL, | ||
| 730 | "show per-allocation statistics", | ||
| 731 | parse_alloc_opt), | ||
| 732 | OPT_CALLBACK('s', "sort", NULL, "key[,key2...]", | ||
| 733 | "sort by keys: ptr, call_site, bytes, hit, pingpong, frag", | ||
| 734 | parse_sort_opt), | ||
| 735 | OPT_CALLBACK('l', "line", NULL, "num", | ||
| 736 | "show n lines", | ||
| 737 | parse_line_opt), | ||
| 738 | OPT_BOOLEAN(0, "raw-ip", &raw_ip, "show raw ip instead of symbol"), | ||
| 739 | OPT_END() | ||
| 740 | }; | ||
| 741 | |||
| 742 | static const char *record_args[] = { | ||
| 743 | "record", | ||
| 744 | "-a", | ||
| 745 | "-R", | ||
| 746 | "-f", | ||
| 747 | "-c", "1", | ||
| 748 | "-e", "kmem:kmalloc", | 718 | "-e", "kmem:kmalloc", |
| 749 | "-e", "kmem:kmalloc_node", | 719 | "-e", "kmem:kmalloc_node", |
| 750 | "-e", "kmem:kfree", | 720 | "-e", "kmem:kfree", |
| 751 | "-e", "kmem:kmem_cache_alloc", | 721 | "-e", "kmem:kmem_cache_alloc", |
| 752 | "-e", "kmem:kmem_cache_alloc_node", | 722 | "-e", "kmem:kmem_cache_alloc_node", |
| 753 | "-e", "kmem:kmem_cache_free", | 723 | "-e", "kmem:kmem_cache_free", |
| 754 | }; | 724 | }; |
| 755 | |||
| 756 | static int __cmd_record(int argc, const char **argv) | ||
| 757 | { | ||
| 758 | unsigned int rec_argc, i, j; | 725 | unsigned int rec_argc, i, j; |
| 759 | const char **rec_argv; | 726 | const char **rec_argv; |
| 760 | 727 | ||
| @@ -775,6 +742,25 @@ static int __cmd_record(int argc, const char **argv) | |||
| 775 | 742 | ||
| 776 | int cmd_kmem(int argc, const char **argv, const char *prefix __maybe_unused) | 743 | int cmd_kmem(int argc, const char **argv, const char *prefix __maybe_unused) |
| 777 | { | 744 | { |
| 745 | const char * const default_sort_order = "frag,hit,bytes"; | ||
| 746 | const char *input_name = NULL; | ||
| 747 | const struct option kmem_options[] = { | ||
| 748 | OPT_STRING('i', "input", &input_name, "file", "input file name"), | ||
| 749 | OPT_CALLBACK_NOOPT(0, "caller", NULL, NULL, | ||
| 750 | "show per-callsite statistics", parse_caller_opt), | ||
| 751 | OPT_CALLBACK_NOOPT(0, "alloc", NULL, NULL, | ||
| 752 | "show per-allocation statistics", parse_alloc_opt), | ||
| 753 | OPT_CALLBACK('s', "sort", NULL, "key[,key2...]", | ||
| 754 | "sort by keys: ptr, call_site, bytes, hit, pingpong, frag", | ||
| 755 | parse_sort_opt), | ||
| 756 | OPT_CALLBACK('l', "line", NULL, "num", "show n lines", parse_line_opt), | ||
| 757 | OPT_BOOLEAN(0, "raw-ip", &raw_ip, "show raw ip instead of symbol"), | ||
| 758 | OPT_END() | ||
| 759 | }; | ||
| 760 | const char * const kmem_usage[] = { | ||
| 761 | "perf kmem [<options>] {record|stat}", | ||
| 762 | NULL | ||
| 763 | }; | ||
| 778 | argc = parse_options(argc, argv, kmem_options, kmem_usage, 0); | 764 | argc = parse_options(argc, argv, kmem_options, kmem_usage, 0); |
| 779 | 765 | ||
| 780 | if (!argc) | 766 | if (!argc) |
| @@ -793,7 +779,7 @@ int cmd_kmem(int argc, const char **argv, const char *prefix __maybe_unused) | |||
| 793 | if (list_empty(&alloc_sort)) | 779 | if (list_empty(&alloc_sort)) |
| 794 | setup_sorting(&alloc_sort, default_sort_order); | 780 | setup_sorting(&alloc_sort, default_sort_order); |
| 795 | 781 | ||
| 796 | return __cmd_kmem(); | 782 | return __cmd_kmem(input_name); |
| 797 | } else | 783 | } else |
| 798 | usage_with_options(kmem_usage, kmem_options); | 784 | usage_with_options(kmem_usage, kmem_options); |
| 799 | 785 | ||
diff --git a/tools/perf/builtin-kvm.c b/tools/perf/builtin-kvm.c index a28c9cad9048..260abc535b5b 100644 --- a/tools/perf/builtin-kvm.c +++ b/tools/perf/builtin-kvm.c | |||
| @@ -32,16 +32,76 @@ struct event_key { | |||
| 32 | int info; | 32 | int info; |
| 33 | }; | 33 | }; |
| 34 | 34 | ||
| 35 | struct kvm_event_stats { | ||
| 36 | u64 time; | ||
| 37 | struct stats stats; | ||
| 38 | }; | ||
| 39 | |||
| 40 | struct kvm_event { | ||
| 41 | struct list_head hash_entry; | ||
| 42 | struct rb_node rb; | ||
| 43 | |||
| 44 | struct event_key key; | ||
| 45 | |||
| 46 | struct kvm_event_stats total; | ||
| 47 | |||
| 48 | #define DEFAULT_VCPU_NUM 8 | ||
| 49 | int max_vcpu; | ||
| 50 | struct kvm_event_stats *vcpu; | ||
| 51 | }; | ||
| 52 | |||
| 53 | typedef int (*key_cmp_fun)(struct kvm_event*, struct kvm_event*, int); | ||
| 54 | |||
| 55 | struct kvm_event_key { | ||
| 56 | const char *name; | ||
| 57 | key_cmp_fun key; | ||
| 58 | }; | ||
| 59 | |||
| 60 | |||
| 61 | struct perf_kvm; | ||
| 62 | |||
| 35 | struct kvm_events_ops { | 63 | struct kvm_events_ops { |
| 36 | bool (*is_begin_event)(struct perf_evsel *evsel, | 64 | bool (*is_begin_event)(struct perf_evsel *evsel, |
| 37 | struct perf_sample *sample, | 65 | struct perf_sample *sample, |
| 38 | struct event_key *key); | 66 | struct event_key *key); |
| 39 | bool (*is_end_event)(struct perf_evsel *evsel, | 67 | bool (*is_end_event)(struct perf_evsel *evsel, |
| 40 | struct perf_sample *sample, struct event_key *key); | 68 | struct perf_sample *sample, struct event_key *key); |
| 41 | void (*decode_key)(struct event_key *key, char decode[20]); | 69 | void (*decode_key)(struct perf_kvm *kvm, struct event_key *key, |
| 70 | char decode[20]); | ||
| 42 | const char *name; | 71 | const char *name; |
| 43 | }; | 72 | }; |
| 44 | 73 | ||
| 74 | struct exit_reasons_table { | ||
| 75 | unsigned long exit_code; | ||
| 76 | const char *reason; | ||
| 77 | }; | ||
| 78 | |||
| 79 | #define EVENTS_BITS 12 | ||
| 80 | #define EVENTS_CACHE_SIZE (1UL << EVENTS_BITS) | ||
| 81 | |||
| 82 | struct perf_kvm { | ||
| 83 | struct perf_tool tool; | ||
| 84 | struct perf_session *session; | ||
| 85 | |||
| 86 | const char *file_name; | ||
| 87 | const char *report_event; | ||
| 88 | const char *sort_key; | ||
| 89 | int trace_vcpu; | ||
| 90 | |||
| 91 | struct exit_reasons_table *exit_reasons; | ||
| 92 | int exit_reasons_size; | ||
| 93 | const char *exit_reasons_isa; | ||
| 94 | |||
| 95 | struct kvm_events_ops *events_ops; | ||
| 96 | key_cmp_fun compare; | ||
| 97 | struct list_head kvm_events_cache[EVENTS_CACHE_SIZE]; | ||
| 98 | u64 total_time; | ||
| 99 | u64 total_count; | ||
| 100 | |||
| 101 | struct rb_root result; | ||
| 102 | }; | ||
| 103 | |||
| 104 | |||
| 45 | static void exit_event_get_key(struct perf_evsel *evsel, | 105 | static void exit_event_get_key(struct perf_evsel *evsel, |
| 46 | struct perf_sample *sample, | 106 | struct perf_sample *sample, |
| 47 | struct event_key *key) | 107 | struct event_key *key) |
| @@ -78,45 +138,35 @@ static bool exit_event_end(struct perf_evsel *evsel, | |||
| 78 | return kvm_entry_event(evsel); | 138 | return kvm_entry_event(evsel); |
| 79 | } | 139 | } |
| 80 | 140 | ||
| 81 | struct exit_reasons_table { | 141 | static struct exit_reasons_table vmx_exit_reasons[] = { |
| 82 | unsigned long exit_code; | ||
| 83 | const char *reason; | ||
| 84 | }; | ||
| 85 | |||
| 86 | struct exit_reasons_table vmx_exit_reasons[] = { | ||
| 87 | VMX_EXIT_REASONS | 142 | VMX_EXIT_REASONS |
| 88 | }; | 143 | }; |
| 89 | 144 | ||
| 90 | struct exit_reasons_table svm_exit_reasons[] = { | 145 | static struct exit_reasons_table svm_exit_reasons[] = { |
| 91 | SVM_EXIT_REASONS | 146 | SVM_EXIT_REASONS |
| 92 | }; | 147 | }; |
| 93 | 148 | ||
| 94 | static int cpu_isa; | 149 | static const char *get_exit_reason(struct perf_kvm *kvm, u64 exit_code) |
| 95 | |||
| 96 | static const char *get_exit_reason(u64 exit_code) | ||
| 97 | { | 150 | { |
| 98 | int table_size = ARRAY_SIZE(svm_exit_reasons); | 151 | int i = kvm->exit_reasons_size; |
| 99 | struct exit_reasons_table *table = svm_exit_reasons; | 152 | struct exit_reasons_table *tbl = kvm->exit_reasons; |
| 100 | |||
| 101 | if (cpu_isa == 1) { | ||
| 102 | table = vmx_exit_reasons; | ||
| 103 | table_size = ARRAY_SIZE(vmx_exit_reasons); | ||
| 104 | } | ||
| 105 | 153 | ||
| 106 | while (table_size--) { | 154 | while (i--) { |
| 107 | if (table->exit_code == exit_code) | 155 | if (tbl->exit_code == exit_code) |
| 108 | return table->reason; | 156 | return tbl->reason; |
| 109 | table++; | 157 | tbl++; |
| 110 | } | 158 | } |
| 111 | 159 | ||
| 112 | pr_err("unknown kvm exit code:%lld on %s\n", | 160 | pr_err("unknown kvm exit code:%lld on %s\n", |
| 113 | (unsigned long long)exit_code, cpu_isa ? "VMX" : "SVM"); | 161 | (unsigned long long)exit_code, kvm->exit_reasons_isa); |
| 114 | return "UNKNOWN"; | 162 | return "UNKNOWN"; |
| 115 | } | 163 | } |
| 116 | 164 | ||
| 117 | static void exit_event_decode_key(struct event_key *key, char decode[20]) | 165 | static void exit_event_decode_key(struct perf_kvm *kvm, |
| 166 | struct event_key *key, | ||
| 167 | char decode[20]) | ||
| 118 | { | 168 | { |
| 119 | const char *exit_reason = get_exit_reason(key->key); | 169 | const char *exit_reason = get_exit_reason(kvm, key->key); |
| 120 | 170 | ||
| 121 | scnprintf(decode, 20, "%s", exit_reason); | 171 | scnprintf(decode, 20, "%s", exit_reason); |
| 122 | } | 172 | } |
| @@ -128,11 +178,11 @@ static struct kvm_events_ops exit_events = { | |||
| 128 | .name = "VM-EXIT" | 178 | .name = "VM-EXIT" |
| 129 | }; | 179 | }; |
| 130 | 180 | ||
| 131 | /* | 181 | /* |
| 132 | * For the mmio events, we treat: | 182 | * For the mmio events, we treat: |
| 133 | * the time of MMIO write: kvm_mmio(KVM_TRACE_MMIO_WRITE...) -> kvm_entry | 183 | * the time of MMIO write: kvm_mmio(KVM_TRACE_MMIO_WRITE...) -> kvm_entry |
| 134 | * the time of MMIO read: kvm_exit -> kvm_mmio(KVM_TRACE_MMIO_READ...). | 184 | * the time of MMIO read: kvm_exit -> kvm_mmio(KVM_TRACE_MMIO_READ...). |
| 135 | */ | 185 | */ |
| 136 | static void mmio_event_get_key(struct perf_evsel *evsel, struct perf_sample *sample, | 186 | static void mmio_event_get_key(struct perf_evsel *evsel, struct perf_sample *sample, |
| 137 | struct event_key *key) | 187 | struct event_key *key) |
| 138 | { | 188 | { |
| @@ -178,7 +228,9 @@ static bool mmio_event_end(struct perf_evsel *evsel, struct perf_sample *sample, | |||
| 178 | return false; | 228 | return false; |
| 179 | } | 229 | } |
| 180 | 230 | ||
| 181 | static void mmio_event_decode_key(struct event_key *key, char decode[20]) | 231 | static void mmio_event_decode_key(struct perf_kvm *kvm __maybe_unused, |
| 232 | struct event_key *key, | ||
| 233 | char decode[20]) | ||
| 182 | { | 234 | { |
| 183 | scnprintf(decode, 20, "%#lx:%s", (unsigned long)key->key, | 235 | scnprintf(decode, 20, "%#lx:%s", (unsigned long)key->key, |
| 184 | key->info == KVM_TRACE_MMIO_WRITE ? "W" : "R"); | 236 | key->info == KVM_TRACE_MMIO_WRITE ? "W" : "R"); |
| @@ -219,7 +271,9 @@ static bool ioport_event_end(struct perf_evsel *evsel, | |||
| 219 | return kvm_entry_event(evsel); | 271 | return kvm_entry_event(evsel); |
| 220 | } | 272 | } |
| 221 | 273 | ||
| 222 | static void ioport_event_decode_key(struct event_key *key, char decode[20]) | 274 | static void ioport_event_decode_key(struct perf_kvm *kvm __maybe_unused, |
| 275 | struct event_key *key, | ||
| 276 | char decode[20]) | ||
| 223 | { | 277 | { |
| 224 | scnprintf(decode, 20, "%#llx:%s", (unsigned long long)key->key, | 278 | scnprintf(decode, 20, "%#llx:%s", (unsigned long long)key->key, |
| 225 | key->info ? "POUT" : "PIN"); | 279 | key->info ? "POUT" : "PIN"); |
| @@ -232,64 +286,37 @@ static struct kvm_events_ops ioport_events = { | |||
| 232 | .name = "IO Port Access" | 286 | .name = "IO Port Access" |
| 233 | }; | 287 | }; |
| 234 | 288 | ||
| 235 | static const char *report_event = "vmexit"; | 289 | static bool register_kvm_events_ops(struct perf_kvm *kvm) |
| 236 | struct kvm_events_ops *events_ops; | ||
| 237 | |||
| 238 | static bool register_kvm_events_ops(void) | ||
| 239 | { | 290 | { |
| 240 | bool ret = true; | 291 | bool ret = true; |
| 241 | 292 | ||
| 242 | if (!strcmp(report_event, "vmexit")) | 293 | if (!strcmp(kvm->report_event, "vmexit")) |
| 243 | events_ops = &exit_events; | 294 | kvm->events_ops = &exit_events; |
| 244 | else if (!strcmp(report_event, "mmio")) | 295 | else if (!strcmp(kvm->report_event, "mmio")) |
| 245 | events_ops = &mmio_events; | 296 | kvm->events_ops = &mmio_events; |
| 246 | else if (!strcmp(report_event, "ioport")) | 297 | else if (!strcmp(kvm->report_event, "ioport")) |
| 247 | events_ops = &ioport_events; | 298 | kvm->events_ops = &ioport_events; |
| 248 | else { | 299 | else { |
| 249 | pr_err("Unknown report event:%s\n", report_event); | 300 | pr_err("Unknown report event:%s\n", kvm->report_event); |
| 250 | ret = false; | 301 | ret = false; |
| 251 | } | 302 | } |
| 252 | 303 | ||
| 253 | return ret; | 304 | return ret; |
| 254 | } | 305 | } |
| 255 | 306 | ||
| 256 | struct kvm_event_stats { | ||
| 257 | u64 time; | ||
| 258 | struct stats stats; | ||
| 259 | }; | ||
| 260 | |||
| 261 | struct kvm_event { | ||
| 262 | struct list_head hash_entry; | ||
| 263 | struct rb_node rb; | ||
| 264 | |||
| 265 | struct event_key key; | ||
| 266 | |||
| 267 | struct kvm_event_stats total; | ||
| 268 | |||
| 269 | #define DEFAULT_VCPU_NUM 8 | ||
| 270 | int max_vcpu; | ||
| 271 | struct kvm_event_stats *vcpu; | ||
| 272 | }; | ||
| 273 | |||
| 274 | struct vcpu_event_record { | 307 | struct vcpu_event_record { |
| 275 | int vcpu_id; | 308 | int vcpu_id; |
| 276 | u64 start_time; | 309 | u64 start_time; |
| 277 | struct kvm_event *last_event; | 310 | struct kvm_event *last_event; |
| 278 | }; | 311 | }; |
| 279 | 312 | ||
| 280 | #define EVENTS_BITS 12 | ||
| 281 | #define EVENTS_CACHE_SIZE (1UL << EVENTS_BITS) | ||
| 282 | |||
| 283 | static u64 total_time; | ||
| 284 | static u64 total_count; | ||
| 285 | static struct list_head kvm_events_cache[EVENTS_CACHE_SIZE]; | ||
| 286 | 313 | ||
| 287 | static void init_kvm_event_record(void) | 314 | static void init_kvm_event_record(struct perf_kvm *kvm) |
| 288 | { | 315 | { |
| 289 | int i; | 316 | int i; |
| 290 | 317 | ||
| 291 | for (i = 0; i < (int)EVENTS_CACHE_SIZE; i++) | 318 | for (i = 0; i < (int)EVENTS_CACHE_SIZE; i++) |
| 292 | INIT_LIST_HEAD(&kvm_events_cache[i]); | 319 | INIT_LIST_HEAD(&kvm->kvm_events_cache[i]); |
| 293 | } | 320 | } |
| 294 | 321 | ||
| 295 | static int kvm_events_hash_fn(u64 key) | 322 | static int kvm_events_hash_fn(u64 key) |
| @@ -333,14 +360,15 @@ static struct kvm_event *kvm_alloc_init_event(struct event_key *key) | |||
| 333 | return event; | 360 | return event; |
| 334 | } | 361 | } |
| 335 | 362 | ||
| 336 | static struct kvm_event *find_create_kvm_event(struct event_key *key) | 363 | static struct kvm_event *find_create_kvm_event(struct perf_kvm *kvm, |
| 364 | struct event_key *key) | ||
| 337 | { | 365 | { |
| 338 | struct kvm_event *event; | 366 | struct kvm_event *event; |
| 339 | struct list_head *head; | 367 | struct list_head *head; |
| 340 | 368 | ||
| 341 | BUG_ON(key->key == INVALID_KEY); | 369 | BUG_ON(key->key == INVALID_KEY); |
| 342 | 370 | ||
| 343 | head = &kvm_events_cache[kvm_events_hash_fn(key->key)]; | 371 | head = &kvm->kvm_events_cache[kvm_events_hash_fn(key->key)]; |
| 344 | list_for_each_entry(event, head, hash_entry) | 372 | list_for_each_entry(event, head, hash_entry) |
| 345 | if (event->key.key == key->key && event->key.info == key->info) | 373 | if (event->key.key == key->key && event->key.info == key->info) |
| 346 | return event; | 374 | return event; |
| @@ -353,13 +381,14 @@ static struct kvm_event *find_create_kvm_event(struct event_key *key) | |||
| 353 | return event; | 381 | return event; |
| 354 | } | 382 | } |
| 355 | 383 | ||
| 356 | static bool handle_begin_event(struct vcpu_event_record *vcpu_record, | 384 | static bool handle_begin_event(struct perf_kvm *kvm, |
| 385 | struct vcpu_event_record *vcpu_record, | ||
| 357 | struct event_key *key, u64 timestamp) | 386 | struct event_key *key, u64 timestamp) |
| 358 | { | 387 | { |
| 359 | struct kvm_event *event = NULL; | 388 | struct kvm_event *event = NULL; |
| 360 | 389 | ||
| 361 | if (key->key != INVALID_KEY) | 390 | if (key->key != INVALID_KEY) |
| 362 | event = find_create_kvm_event(key); | 391 | event = find_create_kvm_event(kvm, key); |
| 363 | 392 | ||
| 364 | vcpu_record->last_event = event; | 393 | vcpu_record->last_event = event; |
| 365 | vcpu_record->start_time = timestamp; | 394 | vcpu_record->start_time = timestamp; |
| @@ -396,8 +425,10 @@ static bool update_kvm_event(struct kvm_event *event, int vcpu_id, | |||
| 396 | return true; | 425 | return true; |
| 397 | } | 426 | } |
| 398 | 427 | ||
| 399 | static bool handle_end_event(struct vcpu_event_record *vcpu_record, | 428 | static bool handle_end_event(struct perf_kvm *kvm, |
| 400 | struct event_key *key, u64 timestamp) | 429 | struct vcpu_event_record *vcpu_record, |
| 430 | struct event_key *key, | ||
| 431 | u64 timestamp) | ||
| 401 | { | 432 | { |
| 402 | struct kvm_event *event; | 433 | struct kvm_event *event; |
| 403 | u64 time_begin, time_diff; | 434 | u64 time_begin, time_diff; |
| @@ -419,7 +450,7 @@ static bool handle_end_event(struct vcpu_event_record *vcpu_record, | |||
| 419 | return true; | 450 | return true; |
| 420 | 451 | ||
| 421 | if (!event) | 452 | if (!event) |
| 422 | event = find_create_kvm_event(key); | 453 | event = find_create_kvm_event(kvm, key); |
| 423 | 454 | ||
| 424 | if (!event) | 455 | if (!event) |
| 425 | return false; | 456 | return false; |
| @@ -455,7 +486,9 @@ struct vcpu_event_record *per_vcpu_record(struct thread *thread, | |||
| 455 | return thread->priv; | 486 | return thread->priv; |
| 456 | } | 487 | } |
| 457 | 488 | ||
| 458 | static bool handle_kvm_event(struct thread *thread, struct perf_evsel *evsel, | 489 | static bool handle_kvm_event(struct perf_kvm *kvm, |
| 490 | struct thread *thread, | ||
| 491 | struct perf_evsel *evsel, | ||
| 459 | struct perf_sample *sample) | 492 | struct perf_sample *sample) |
| 460 | { | 493 | { |
| 461 | struct vcpu_event_record *vcpu_record; | 494 | struct vcpu_event_record *vcpu_record; |
| @@ -465,22 +498,15 @@ static bool handle_kvm_event(struct thread *thread, struct perf_evsel *evsel, | |||
| 465 | if (!vcpu_record) | 498 | if (!vcpu_record) |
| 466 | return true; | 499 | return true; |
| 467 | 500 | ||
| 468 | if (events_ops->is_begin_event(evsel, sample, &key)) | 501 | if (kvm->events_ops->is_begin_event(evsel, sample, &key)) |
| 469 | return handle_begin_event(vcpu_record, &key, sample->time); | 502 | return handle_begin_event(kvm, vcpu_record, &key, sample->time); |
| 470 | 503 | ||
| 471 | if (events_ops->is_end_event(evsel, sample, &key)) | 504 | if (kvm->events_ops->is_end_event(evsel, sample, &key)) |
| 472 | return handle_end_event(vcpu_record, &key, sample->time); | 505 | return handle_end_event(kvm, vcpu_record, &key, sample->time); |
| 473 | 506 | ||
| 474 | return true; | 507 | return true; |
| 475 | } | 508 | } |
| 476 | 509 | ||
| 477 | typedef int (*key_cmp_fun)(struct kvm_event*, struct kvm_event*, int); | ||
| 478 | struct kvm_event_key { | ||
| 479 | const char *name; | ||
| 480 | key_cmp_fun key; | ||
| 481 | }; | ||
| 482 | |||
| 483 | static int trace_vcpu = -1; | ||
| 484 | #define GET_EVENT_KEY(func, field) \ | 510 | #define GET_EVENT_KEY(func, field) \ |
| 485 | static u64 get_event_ ##func(struct kvm_event *event, int vcpu) \ | 511 | static u64 get_event_ ##func(struct kvm_event *event, int vcpu) \ |
| 486 | { \ | 512 | { \ |
| @@ -515,29 +541,25 @@ static struct kvm_event_key keys[] = { | |||
| 515 | { NULL, NULL } | 541 | { NULL, NULL } |
| 516 | }; | 542 | }; |
| 517 | 543 | ||
| 518 | static const char *sort_key = "sample"; | 544 | static bool select_key(struct perf_kvm *kvm) |
| 519 | static key_cmp_fun compare; | ||
| 520 | |||
| 521 | static bool select_key(void) | ||
| 522 | { | 545 | { |
| 523 | int i; | 546 | int i; |
| 524 | 547 | ||
| 525 | for (i = 0; keys[i].name; i++) { | 548 | for (i = 0; keys[i].name; i++) { |
| 526 | if (!strcmp(keys[i].name, sort_key)) { | 549 | if (!strcmp(keys[i].name, kvm->sort_key)) { |
| 527 | compare = keys[i].key; | 550 | kvm->compare = keys[i].key; |
| 528 | return true; | 551 | return true; |
| 529 | } | 552 | } |
| 530 | } | 553 | } |
| 531 | 554 | ||
| 532 | pr_err("Unknown compare key:%s\n", sort_key); | 555 | pr_err("Unknown compare key:%s\n", kvm->sort_key); |
| 533 | return false; | 556 | return false; |
| 534 | } | 557 | } |
| 535 | 558 | ||
| 536 | static struct rb_root result; | 559 | static void insert_to_result(struct rb_root *result, struct kvm_event *event, |
| 537 | static void insert_to_result(struct kvm_event *event, key_cmp_fun bigger, | 560 | key_cmp_fun bigger, int vcpu) |
| 538 | int vcpu) | ||
| 539 | { | 561 | { |
| 540 | struct rb_node **rb = &result.rb_node; | 562 | struct rb_node **rb = &result->rb_node; |
| 541 | struct rb_node *parent = NULL; | 563 | struct rb_node *parent = NULL; |
| 542 | struct kvm_event *p; | 564 | struct kvm_event *p; |
| 543 | 565 | ||
| @@ -552,13 +574,15 @@ static void insert_to_result(struct kvm_event *event, key_cmp_fun bigger, | |||
| 552 | } | 574 | } |
| 553 | 575 | ||
| 554 | rb_link_node(&event->rb, parent, rb); | 576 | rb_link_node(&event->rb, parent, rb); |
| 555 | rb_insert_color(&event->rb, &result); | 577 | rb_insert_color(&event->rb, result); |
| 556 | } | 578 | } |
| 557 | 579 | ||
| 558 | static void update_total_count(struct kvm_event *event, int vcpu) | 580 | static void update_total_count(struct perf_kvm *kvm, struct kvm_event *event) |
| 559 | { | 581 | { |
| 560 | total_count += get_event_count(event, vcpu); | 582 | int vcpu = kvm->trace_vcpu; |
| 561 | total_time += get_event_time(event, vcpu); | 583 | |
| 584 | kvm->total_count += get_event_count(event, vcpu); | ||
| 585 | kvm->total_time += get_event_time(event, vcpu); | ||
| 562 | } | 586 | } |
| 563 | 587 | ||
| 564 | static bool event_is_valid(struct kvm_event *event, int vcpu) | 588 | static bool event_is_valid(struct kvm_event *event, int vcpu) |
| @@ -566,28 +590,30 @@ static bool event_is_valid(struct kvm_event *event, int vcpu) | |||
| 566 | return !!get_event_count(event, vcpu); | 590 | return !!get_event_count(event, vcpu); |
| 567 | } | 591 | } |
| 568 | 592 | ||
| 569 | static void sort_result(int vcpu) | 593 | static void sort_result(struct perf_kvm *kvm) |
| 570 | { | 594 | { |
| 571 | unsigned int i; | 595 | unsigned int i; |
| 596 | int vcpu = kvm->trace_vcpu; | ||
| 572 | struct kvm_event *event; | 597 | struct kvm_event *event; |
| 573 | 598 | ||
| 574 | for (i = 0; i < EVENTS_CACHE_SIZE; i++) | 599 | for (i = 0; i < EVENTS_CACHE_SIZE; i++) |
| 575 | list_for_each_entry(event, &kvm_events_cache[i], hash_entry) | 600 | list_for_each_entry(event, &kvm->kvm_events_cache[i], hash_entry) |
| 576 | if (event_is_valid(event, vcpu)) { | 601 | if (event_is_valid(event, vcpu)) { |
| 577 | update_total_count(event, vcpu); | 602 | update_total_count(kvm, event); |
| 578 | insert_to_result(event, compare, vcpu); | 603 | insert_to_result(&kvm->result, event, |
| 604 | kvm->compare, vcpu); | ||
| 579 | } | 605 | } |
| 580 | } | 606 | } |
| 581 | 607 | ||
| 582 | /* returns left most element of result, and erase it */ | 608 | /* returns left most element of result, and erase it */ |
| 583 | static struct kvm_event *pop_from_result(void) | 609 | static struct kvm_event *pop_from_result(struct rb_root *result) |
| 584 | { | 610 | { |
| 585 | struct rb_node *node = rb_first(&result); | 611 | struct rb_node *node = rb_first(result); |
| 586 | 612 | ||
| 587 | if (!node) | 613 | if (!node) |
| 588 | return NULL; | 614 | return NULL; |
| 589 | 615 | ||
| 590 | rb_erase(node, &result); | 616 | rb_erase(node, result); |
| 591 | return container_of(node, struct kvm_event, rb); | 617 | return container_of(node, struct kvm_event, rb); |
| 592 | } | 618 | } |
| 593 | 619 | ||
| @@ -601,14 +627,15 @@ static void print_vcpu_info(int vcpu) | |||
| 601 | pr_info("VCPU %d:\n\n", vcpu); | 627 | pr_info("VCPU %d:\n\n", vcpu); |
| 602 | } | 628 | } |
| 603 | 629 | ||
| 604 | static void print_result(int vcpu) | 630 | static void print_result(struct perf_kvm *kvm) |
| 605 | { | 631 | { |
| 606 | char decode[20]; | 632 | char decode[20]; |
| 607 | struct kvm_event *event; | 633 | struct kvm_event *event; |
| 634 | int vcpu = kvm->trace_vcpu; | ||
| 608 | 635 | ||
| 609 | pr_info("\n\n"); | 636 | pr_info("\n\n"); |
| 610 | print_vcpu_info(vcpu); | 637 | print_vcpu_info(vcpu); |
| 611 | pr_info("%20s ", events_ops->name); | 638 | pr_info("%20s ", kvm->events_ops->name); |
| 612 | pr_info("%10s ", "Samples"); | 639 | pr_info("%10s ", "Samples"); |
| 613 | pr_info("%9s ", "Samples%"); | 640 | pr_info("%9s ", "Samples%"); |
| 614 | 641 | ||
| @@ -616,33 +643,34 @@ static void print_result(int vcpu) | |||
| 616 | pr_info("%16s ", "Avg time"); | 643 | pr_info("%16s ", "Avg time"); |
| 617 | pr_info("\n\n"); | 644 | pr_info("\n\n"); |
| 618 | 645 | ||
| 619 | while ((event = pop_from_result())) { | 646 | while ((event = pop_from_result(&kvm->result))) { |
| 620 | u64 ecount, etime; | 647 | u64 ecount, etime; |
| 621 | 648 | ||
| 622 | ecount = get_event_count(event, vcpu); | 649 | ecount = get_event_count(event, vcpu); |
| 623 | etime = get_event_time(event, vcpu); | 650 | etime = get_event_time(event, vcpu); |
| 624 | 651 | ||
| 625 | events_ops->decode_key(&event->key, decode); | 652 | kvm->events_ops->decode_key(kvm, &event->key, decode); |
| 626 | pr_info("%20s ", decode); | 653 | pr_info("%20s ", decode); |
| 627 | pr_info("%10llu ", (unsigned long long)ecount); | 654 | pr_info("%10llu ", (unsigned long long)ecount); |
| 628 | pr_info("%8.2f%% ", (double)ecount / total_count * 100); | 655 | pr_info("%8.2f%% ", (double)ecount / kvm->total_count * 100); |
| 629 | pr_info("%8.2f%% ", (double)etime / total_time * 100); | 656 | pr_info("%8.2f%% ", (double)etime / kvm->total_time * 100); |
| 630 | pr_info("%9.2fus ( +-%7.2f%% )", (double)etime / ecount/1e3, | 657 | pr_info("%9.2fus ( +-%7.2f%% )", (double)etime / ecount/1e3, |
| 631 | kvm_event_rel_stddev(vcpu, event)); | 658 | kvm_event_rel_stddev(vcpu, event)); |
| 632 | pr_info("\n"); | 659 | pr_info("\n"); |
| 633 | } | 660 | } |
| 634 | 661 | ||
| 635 | pr_info("\nTotal Samples:%lld, Total events handled time:%.2fus.\n\n", | 662 | pr_info("\nTotal Samples:%lld, Total events handled time:%.2fus.\n\n", |
| 636 | (unsigned long long)total_count, total_time / 1e3); | 663 | (unsigned long long)kvm->total_count, kvm->total_time / 1e3); |
| 637 | } | 664 | } |
| 638 | 665 | ||
| 639 | static int process_sample_event(struct perf_tool *tool __maybe_unused, | 666 | static int process_sample_event(struct perf_tool *tool, |
| 640 | union perf_event *event, | 667 | union perf_event *event, |
| 641 | struct perf_sample *sample, | 668 | struct perf_sample *sample, |
| 642 | struct perf_evsel *evsel, | 669 | struct perf_evsel *evsel, |
| 643 | struct machine *machine) | 670 | struct machine *machine) |
| 644 | { | 671 | { |
| 645 | struct thread *thread = machine__findnew_thread(machine, sample->tid); | 672 | struct thread *thread = machine__findnew_thread(machine, sample->tid); |
| 673 | struct perf_kvm *kvm = container_of(tool, struct perf_kvm, tool); | ||
| 646 | 674 | ||
| 647 | if (thread == NULL) { | 675 | if (thread == NULL) { |
| 648 | pr_debug("problem processing %d event, skipping it.\n", | 676 | pr_debug("problem processing %d event, skipping it.\n", |
| @@ -650,18 +678,12 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused, | |||
| 650 | return -1; | 678 | return -1; |
| 651 | } | 679 | } |
| 652 | 680 | ||
| 653 | if (!handle_kvm_event(thread, evsel, sample)) | 681 | if (!handle_kvm_event(kvm, thread, evsel, sample)) |
| 654 | return -1; | 682 | return -1; |
| 655 | 683 | ||
| 656 | return 0; | 684 | return 0; |
| 657 | } | 685 | } |
| 658 | 686 | ||
| 659 | static struct perf_tool eops = { | ||
| 660 | .sample = process_sample_event, | ||
| 661 | .comm = perf_event__process_comm, | ||
| 662 | .ordered_samples = true, | ||
| 663 | }; | ||
| 664 | |||
| 665 | static int get_cpu_isa(struct perf_session *session) | 687 | static int get_cpu_isa(struct perf_session *session) |
| 666 | { | 688 | { |
| 667 | char *cpuid = session->header.env.cpuid; | 689 | char *cpuid = session->header.env.cpuid; |
| @@ -679,34 +701,43 @@ static int get_cpu_isa(struct perf_session *session) | |||
| 679 | return isa; | 701 | return isa; |
| 680 | } | 702 | } |
| 681 | 703 | ||
| 682 | static const char *file_name; | 704 | static int read_events(struct perf_kvm *kvm) |
| 683 | |||
| 684 | static int read_events(void) | ||
| 685 | { | 705 | { |
| 686 | struct perf_session *kvm_session; | ||
| 687 | int ret; | 706 | int ret; |
| 688 | 707 | ||
| 689 | kvm_session = perf_session__new(file_name, O_RDONLY, 0, false, &eops); | 708 | struct perf_tool eops = { |
| 690 | if (!kvm_session) { | 709 | .sample = process_sample_event, |
| 710 | .comm = perf_event__process_comm, | ||
| 711 | .ordered_samples = true, | ||
| 712 | }; | ||
| 713 | |||
| 714 | kvm->tool = eops; | ||
| 715 | kvm->session = perf_session__new(kvm->file_name, O_RDONLY, 0, false, | ||
| 716 | &kvm->tool); | ||
| 717 | if (!kvm->session) { | ||
| 691 | pr_err("Initializing perf session failed\n"); | 718 | pr_err("Initializing perf session failed\n"); |
| 692 | return -EINVAL; | 719 | return -EINVAL; |
| 693 | } | 720 | } |
| 694 | 721 | ||
| 695 | if (!perf_session__has_traces(kvm_session, "kvm record")) | 722 | if (!perf_session__has_traces(kvm->session, "kvm record")) |
| 696 | return -EINVAL; | 723 | return -EINVAL; |
| 697 | 724 | ||
| 698 | /* | 725 | /* |
| 699 | * Do not use 'isa' recorded in kvm_exit tracepoint since it is not | 726 | * Do not use 'isa' recorded in kvm_exit tracepoint since it is not |
| 700 | * traced in the old kernel. | 727 | * traced in the old kernel. |
| 701 | */ | 728 | */ |
| 702 | ret = get_cpu_isa(kvm_session); | 729 | ret = get_cpu_isa(kvm->session); |
| 703 | 730 | ||
| 704 | if (ret < 0) | 731 | if (ret < 0) |
| 705 | return ret; | 732 | return ret; |
| 706 | 733 | ||
| 707 | cpu_isa = ret; | 734 | if (ret == 1) { |
| 735 | kvm->exit_reasons = vmx_exit_reasons; | ||
| 736 | kvm->exit_reasons_size = ARRAY_SIZE(vmx_exit_reasons); | ||
| 737 | kvm->exit_reasons_isa = "VMX"; | ||
| 738 | } | ||
| 708 | 739 | ||
| 709 | return perf_session__process_events(kvm_session, &eops); | 740 | return perf_session__process_events(kvm->session, &kvm->tool); |
| 710 | } | 741 | } |
| 711 | 742 | ||
| 712 | static bool verify_vcpu(int vcpu) | 743 | static bool verify_vcpu(int vcpu) |
| @@ -719,28 +750,30 @@ static bool verify_vcpu(int vcpu) | |||
| 719 | return true; | 750 | return true; |
| 720 | } | 751 | } |
| 721 | 752 | ||
| 722 | static int kvm_events_report_vcpu(int vcpu) | 753 | static int kvm_events_report_vcpu(struct perf_kvm *kvm) |
| 723 | { | 754 | { |
| 724 | int ret = -EINVAL; | 755 | int ret = -EINVAL; |
| 756 | int vcpu = kvm->trace_vcpu; | ||
| 725 | 757 | ||
| 726 | if (!verify_vcpu(vcpu)) | 758 | if (!verify_vcpu(vcpu)) |
| 727 | goto exit; | 759 | goto exit; |
| 728 | 760 | ||
| 729 | if (!select_key()) | 761 | if (!select_key(kvm)) |
| 730 | goto exit; | 762 | goto exit; |
| 731 | 763 | ||
| 732 | if (!register_kvm_events_ops()) | 764 | if (!register_kvm_events_ops(kvm)) |
| 733 | goto exit; | 765 | goto exit; |
| 734 | 766 | ||
| 735 | init_kvm_event_record(); | 767 | init_kvm_event_record(kvm); |
| 736 | setup_pager(); | 768 | setup_pager(); |
| 737 | 769 | ||
| 738 | ret = read_events(); | 770 | ret = read_events(kvm); |
| 739 | if (ret) | 771 | if (ret) |
| 740 | goto exit; | 772 | goto exit; |
| 741 | 773 | ||
| 742 | sort_result(vcpu); | 774 | sort_result(kvm); |
| 743 | print_result(vcpu); | 775 | print_result(kvm); |
| 776 | |||
| 744 | exit: | 777 | exit: |
| 745 | return ret; | 778 | return ret; |
| 746 | } | 779 | } |
| @@ -765,7 +798,7 @@ static const char * const record_args[] = { | |||
| 765 | _p; \ | 798 | _p; \ |
| 766 | }) | 799 | }) |
| 767 | 800 | ||
| 768 | static int kvm_events_record(int argc, const char **argv) | 801 | static int kvm_events_record(struct perf_kvm *kvm, int argc, const char **argv) |
| 769 | { | 802 | { |
| 770 | unsigned int rec_argc, i, j; | 803 | unsigned int rec_argc, i, j; |
| 771 | const char **rec_argv; | 804 | const char **rec_argv; |
| @@ -780,7 +813,7 @@ static int kvm_events_record(int argc, const char **argv) | |||
| 780 | rec_argv[i] = STRDUP_FAIL_EXIT(record_args[i]); | 813 | rec_argv[i] = STRDUP_FAIL_EXIT(record_args[i]); |
| 781 | 814 | ||
| 782 | rec_argv[i++] = STRDUP_FAIL_EXIT("-o"); | 815 | rec_argv[i++] = STRDUP_FAIL_EXIT("-o"); |
| 783 | rec_argv[i++] = STRDUP_FAIL_EXIT(file_name); | 816 | rec_argv[i++] = STRDUP_FAIL_EXIT(kvm->file_name); |
| 784 | 817 | ||
| 785 | for (j = 1; j < (unsigned int)argc; j++, i++) | 818 | for (j = 1; j < (unsigned int)argc; j++, i++) |
| 786 | rec_argv[i] = argv[j]; | 819 | rec_argv[i] = argv[j]; |
| @@ -788,24 +821,24 @@ static int kvm_events_record(int argc, const char **argv) | |||
| 788 | return cmd_record(i, rec_argv, NULL); | 821 | return cmd_record(i, rec_argv, NULL); |
| 789 | } | 822 | } |
| 790 | 823 | ||
| 791 | static const char * const kvm_events_report_usage[] = { | 824 | static int kvm_events_report(struct perf_kvm *kvm, int argc, const char **argv) |
| 792 | "perf kvm stat report [<options>]", | 825 | { |
| 793 | NULL | 826 | const struct option kvm_events_report_options[] = { |
| 794 | }; | 827 | OPT_STRING(0, "event", &kvm->report_event, "report event", |
| 828 | "event for reporting: vmexit, mmio, ioport"), | ||
| 829 | OPT_INTEGER(0, "vcpu", &kvm->trace_vcpu, | ||
| 830 | "vcpu id to report"), | ||
| 831 | OPT_STRING('k', "key", &kvm->sort_key, "sort-key", | ||
| 832 | "key for sorting: sample(sort by samples number)" | ||
| 833 | " time (sort by avg time)"), | ||
| 834 | OPT_END() | ||
| 835 | }; | ||
| 795 | 836 | ||
| 796 | static const struct option kvm_events_report_options[] = { | 837 | const char * const kvm_events_report_usage[] = { |
| 797 | OPT_STRING(0, "event", &report_event, "report event", | 838 | "perf kvm stat report [<options>]", |
| 798 | "event for reporting: vmexit, mmio, ioport"), | 839 | NULL |
| 799 | OPT_INTEGER(0, "vcpu", &trace_vcpu, | 840 | }; |
| 800 | "vcpu id to report"), | ||
| 801 | OPT_STRING('k', "key", &sort_key, "sort-key", | ||
| 802 | "key for sorting: sample(sort by samples number)" | ||
| 803 | " time (sort by avg time)"), | ||
| 804 | OPT_END() | ||
| 805 | }; | ||
| 806 | 841 | ||
| 807 | static int kvm_events_report(int argc, const char **argv) | ||
| 808 | { | ||
| 809 | symbol__init(); | 842 | symbol__init(); |
| 810 | 843 | ||
| 811 | if (argc) { | 844 | if (argc) { |
| @@ -817,7 +850,7 @@ static int kvm_events_report(int argc, const char **argv) | |||
| 817 | kvm_events_report_options); | 850 | kvm_events_report_options); |
| 818 | } | 851 | } |
| 819 | 852 | ||
| 820 | return kvm_events_report_vcpu(trace_vcpu); | 853 | return kvm_events_report_vcpu(kvm); |
| 821 | } | 854 | } |
| 822 | 855 | ||
| 823 | static void print_kvm_stat_usage(void) | 856 | static void print_kvm_stat_usage(void) |
| @@ -831,7 +864,7 @@ static void print_kvm_stat_usage(void) | |||
| 831 | printf("\nOtherwise, it is the alias of 'perf stat':\n"); | 864 | printf("\nOtherwise, it is the alias of 'perf stat':\n"); |
| 832 | } | 865 | } |
| 833 | 866 | ||
| 834 | static int kvm_cmd_stat(int argc, const char **argv) | 867 | static int kvm_cmd_stat(struct perf_kvm *kvm, int argc, const char **argv) |
| 835 | { | 868 | { |
| 836 | if (argc == 1) { | 869 | if (argc == 1) { |
| 837 | print_kvm_stat_usage(); | 870 | print_kvm_stat_usage(); |
| @@ -839,44 +872,16 @@ static int kvm_cmd_stat(int argc, const char **argv) | |||
| 839 | } | 872 | } |
| 840 | 873 | ||
| 841 | if (!strncmp(argv[1], "rec", 3)) | 874 | if (!strncmp(argv[1], "rec", 3)) |
| 842 | return kvm_events_record(argc - 1, argv + 1); | 875 | return kvm_events_record(kvm, argc - 1, argv + 1); |
| 843 | 876 | ||
| 844 | if (!strncmp(argv[1], "rep", 3)) | 877 | if (!strncmp(argv[1], "rep", 3)) |
| 845 | return kvm_events_report(argc - 1 , argv + 1); | 878 | return kvm_events_report(kvm, argc - 1 , argv + 1); |
| 846 | 879 | ||
| 847 | perf_stat: | 880 | perf_stat: |
| 848 | return cmd_stat(argc, argv, NULL); | 881 | return cmd_stat(argc, argv, NULL); |
| 849 | } | 882 | } |
| 850 | 883 | ||
| 851 | static char name_buffer[256]; | 884 | static int __cmd_record(struct perf_kvm *kvm, int argc, const char **argv) |
| 852 | |||
| 853 | static const char * const kvm_usage[] = { | ||
| 854 | "perf kvm [<options>] {top|record|report|diff|buildid-list|stat}", | ||
| 855 | NULL | ||
| 856 | }; | ||
| 857 | |||
| 858 | static const struct option kvm_options[] = { | ||
| 859 | OPT_STRING('i', "input", &file_name, "file", | ||
| 860 | "Input file name"), | ||
| 861 | OPT_STRING('o', "output", &file_name, "file", | ||
| 862 | "Output file name"), | ||
| 863 | OPT_BOOLEAN(0, "guest", &perf_guest, | ||
| 864 | "Collect guest os data"), | ||
| 865 | OPT_BOOLEAN(0, "host", &perf_host, | ||
| 866 | "Collect host os data"), | ||
| 867 | OPT_STRING(0, "guestmount", &symbol_conf.guestmount, "directory", | ||
| 868 | "guest mount directory under which every guest os" | ||
| 869 | " instance has a subdir"), | ||
| 870 | OPT_STRING(0, "guestvmlinux", &symbol_conf.default_guest_vmlinux_name, | ||
| 871 | "file", "file saving guest os vmlinux"), | ||
| 872 | OPT_STRING(0, "guestkallsyms", &symbol_conf.default_guest_kallsyms, | ||
| 873 | "file", "file saving guest os /proc/kallsyms"), | ||
| 874 | OPT_STRING(0, "guestmodules", &symbol_conf.default_guest_modules, | ||
| 875 | "file", "file saving guest os /proc/modules"), | ||
| 876 | OPT_END() | ||
| 877 | }; | ||
| 878 | |||
| 879 | static int __cmd_record(int argc, const char **argv) | ||
| 880 | { | 885 | { |
| 881 | int rec_argc, i = 0, j; | 886 | int rec_argc, i = 0, j; |
| 882 | const char **rec_argv; | 887 | const char **rec_argv; |
| @@ -885,7 +890,7 @@ static int __cmd_record(int argc, const char **argv) | |||
| 885 | rec_argv = calloc(rec_argc + 1, sizeof(char *)); | 890 | rec_argv = calloc(rec_argc + 1, sizeof(char *)); |
| 886 | rec_argv[i++] = strdup("record"); | 891 | rec_argv[i++] = strdup("record"); |
| 887 | rec_argv[i++] = strdup("-o"); | 892 | rec_argv[i++] = strdup("-o"); |
| 888 | rec_argv[i++] = strdup(file_name); | 893 | rec_argv[i++] = strdup(kvm->file_name); |
| 889 | for (j = 1; j < argc; j++, i++) | 894 | for (j = 1; j < argc; j++, i++) |
| 890 | rec_argv[i] = argv[j]; | 895 | rec_argv[i] = argv[j]; |
| 891 | 896 | ||
| @@ -894,7 +899,7 @@ static int __cmd_record(int argc, const char **argv) | |||
| 894 | return cmd_record(i, rec_argv, NULL); | 899 | return cmd_record(i, rec_argv, NULL); |
| 895 | } | 900 | } |
| 896 | 901 | ||
| 897 | static int __cmd_report(int argc, const char **argv) | 902 | static int __cmd_report(struct perf_kvm *kvm, int argc, const char **argv) |
| 898 | { | 903 | { |
| 899 | int rec_argc, i = 0, j; | 904 | int rec_argc, i = 0, j; |
| 900 | const char **rec_argv; | 905 | const char **rec_argv; |
| @@ -903,7 +908,7 @@ static int __cmd_report(int argc, const char **argv) | |||
| 903 | rec_argv = calloc(rec_argc + 1, sizeof(char *)); | 908 | rec_argv = calloc(rec_argc + 1, sizeof(char *)); |
| 904 | rec_argv[i++] = strdup("report"); | 909 | rec_argv[i++] = strdup("report"); |
| 905 | rec_argv[i++] = strdup("-i"); | 910 | rec_argv[i++] = strdup("-i"); |
| 906 | rec_argv[i++] = strdup(file_name); | 911 | rec_argv[i++] = strdup(kvm->file_name); |
| 907 | for (j = 1; j < argc; j++, i++) | 912 | for (j = 1; j < argc; j++, i++) |
| 908 | rec_argv[i] = argv[j]; | 913 | rec_argv[i] = argv[j]; |
| 909 | 914 | ||
| @@ -912,7 +917,7 @@ static int __cmd_report(int argc, const char **argv) | |||
| 912 | return cmd_report(i, rec_argv, NULL); | 917 | return cmd_report(i, rec_argv, NULL); |
| 913 | } | 918 | } |
| 914 | 919 | ||
| 915 | static int __cmd_buildid_list(int argc, const char **argv) | 920 | static int __cmd_buildid_list(struct perf_kvm *kvm, int argc, const char **argv) |
| 916 | { | 921 | { |
| 917 | int rec_argc, i = 0, j; | 922 | int rec_argc, i = 0, j; |
| 918 | const char **rec_argv; | 923 | const char **rec_argv; |
| @@ -921,7 +926,7 @@ static int __cmd_buildid_list(int argc, const char **argv) | |||
| 921 | rec_argv = calloc(rec_argc + 1, sizeof(char *)); | 926 | rec_argv = calloc(rec_argc + 1, sizeof(char *)); |
| 922 | rec_argv[i++] = strdup("buildid-list"); | 927 | rec_argv[i++] = strdup("buildid-list"); |
| 923 | rec_argv[i++] = strdup("-i"); | 928 | rec_argv[i++] = strdup("-i"); |
| 924 | rec_argv[i++] = strdup(file_name); | 929 | rec_argv[i++] = strdup(kvm->file_name); |
| 925 | for (j = 1; j < argc; j++, i++) | 930 | for (j = 1; j < argc; j++, i++) |
| 926 | rec_argv[i] = argv[j]; | 931 | rec_argv[i] = argv[j]; |
| 927 | 932 | ||
| @@ -932,6 +937,43 @@ static int __cmd_buildid_list(int argc, const char **argv) | |||
| 932 | 937 | ||
| 933 | int cmd_kvm(int argc, const char **argv, const char *prefix __maybe_unused) | 938 | int cmd_kvm(int argc, const char **argv, const char *prefix __maybe_unused) |
| 934 | { | 939 | { |
| 940 | struct perf_kvm kvm = { | ||
| 941 | .trace_vcpu = -1, | ||
| 942 | .report_event = "vmexit", | ||
| 943 | .sort_key = "sample", | ||
| 944 | |||
| 945 | .exit_reasons = svm_exit_reasons, | ||
| 946 | .exit_reasons_size = ARRAY_SIZE(svm_exit_reasons), | ||
| 947 | .exit_reasons_isa = "SVM", | ||
| 948 | }; | ||
| 949 | |||
| 950 | const struct option kvm_options[] = { | ||
| 951 | OPT_STRING('i', "input", &kvm.file_name, "file", | ||
| 952 | "Input file name"), | ||
| 953 | OPT_STRING('o', "output", &kvm.file_name, "file", | ||
| 954 | "Output file name"), | ||
| 955 | OPT_BOOLEAN(0, "guest", &perf_guest, | ||
| 956 | "Collect guest os data"), | ||
| 957 | OPT_BOOLEAN(0, "host", &perf_host, | ||
| 958 | "Collect host os data"), | ||
| 959 | OPT_STRING(0, "guestmount", &symbol_conf.guestmount, "directory", | ||
| 960 | "guest mount directory under which every guest os" | ||
| 961 | " instance has a subdir"), | ||
| 962 | OPT_STRING(0, "guestvmlinux", &symbol_conf.default_guest_vmlinux_name, | ||
| 963 | "file", "file saving guest os vmlinux"), | ||
| 964 | OPT_STRING(0, "guestkallsyms", &symbol_conf.default_guest_kallsyms, | ||
| 965 | "file", "file saving guest os /proc/kallsyms"), | ||
| 966 | OPT_STRING(0, "guestmodules", &symbol_conf.default_guest_modules, | ||
| 967 | "file", "file saving guest os /proc/modules"), | ||
| 968 | OPT_END() | ||
| 969 | }; | ||
| 970 | |||
| 971 | |||
| 972 | const char * const kvm_usage[] = { | ||
| 973 | "perf kvm [<options>] {top|record|report|diff|buildid-list|stat}", | ||
| 974 | NULL | ||
| 975 | }; | ||
| 976 | |||
| 935 | perf_host = 0; | 977 | perf_host = 0; |
| 936 | perf_guest = 1; | 978 | perf_guest = 1; |
| 937 | 979 | ||
| @@ -943,28 +985,32 @@ int cmd_kvm(int argc, const char **argv, const char *prefix __maybe_unused) | |||
| 943 | if (!perf_host) | 985 | if (!perf_host) |
| 944 | perf_guest = 1; | 986 | perf_guest = 1; |
| 945 | 987 | ||
| 946 | if (!file_name) { | 988 | if (!kvm.file_name) { |
| 947 | if (perf_host && !perf_guest) | 989 | if (perf_host && !perf_guest) |
| 948 | sprintf(name_buffer, "perf.data.host"); | 990 | kvm.file_name = strdup("perf.data.host"); |
| 949 | else if (!perf_host && perf_guest) | 991 | else if (!perf_host && perf_guest) |
| 950 | sprintf(name_buffer, "perf.data.guest"); | 992 | kvm.file_name = strdup("perf.data.guest"); |
| 951 | else | 993 | else |
| 952 | sprintf(name_buffer, "perf.data.kvm"); | 994 | kvm.file_name = strdup("perf.data.kvm"); |
| 953 | file_name = name_buffer; | 995 | |
| 996 | if (!kvm.file_name) { | ||
| 997 | pr_err("Failed to allocate memory for filename\n"); | ||
| 998 | return -ENOMEM; | ||
| 999 | } | ||
| 954 | } | 1000 | } |
| 955 | 1001 | ||
| 956 | if (!strncmp(argv[0], "rec", 3)) | 1002 | if (!strncmp(argv[0], "rec", 3)) |
| 957 | return __cmd_record(argc, argv); | 1003 | return __cmd_record(&kvm, argc, argv); |
| 958 | else if (!strncmp(argv[0], "rep", 3)) | 1004 | else if (!strncmp(argv[0], "rep", 3)) |
| 959 | return __cmd_report(argc, argv); | 1005 | return __cmd_report(&kvm, argc, argv); |
| 960 | else if (!strncmp(argv[0], "diff", 4)) | 1006 | else if (!strncmp(argv[0], "diff", 4)) |
| 961 | return cmd_diff(argc, argv, NULL); | 1007 | return cmd_diff(argc, argv, NULL); |
| 962 | else if (!strncmp(argv[0], "top", 3)) | 1008 | else if (!strncmp(argv[0], "top", 3)) |
| 963 | return cmd_top(argc, argv, NULL); | 1009 | return cmd_top(argc, argv, NULL); |
| 964 | else if (!strncmp(argv[0], "buildid-list", 12)) | 1010 | else if (!strncmp(argv[0], "buildid-list", 12)) |
| 965 | return __cmd_buildid_list(argc, argv); | 1011 | return __cmd_buildid_list(&kvm, argc, argv); |
| 966 | else if (!strncmp(argv[0], "stat", 4)) | 1012 | else if (!strncmp(argv[0], "stat", 4)) |
| 967 | return kvm_cmd_stat(argc, argv); | 1013 | return kvm_cmd_stat(&kvm, argc, argv); |
| 968 | else | 1014 | else |
| 969 | usage_with_options(kvm_usage, kvm_options); | 1015 | usage_with_options(kvm_usage, kvm_options); |
| 970 | 1016 | ||
diff --git a/tools/perf/builtin-lock.c b/tools/perf/builtin-lock.c index 7d6e09949880..6f5f328157aa 100644 --- a/tools/perf/builtin-lock.c +++ b/tools/perf/builtin-lock.c | |||
| @@ -823,12 +823,6 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused, | |||
| 823 | return 0; | 823 | return 0; |
| 824 | } | 824 | } |
| 825 | 825 | ||
| 826 | static struct perf_tool eops = { | ||
| 827 | .sample = process_sample_event, | ||
| 828 | .comm = perf_event__process_comm, | ||
| 829 | .ordered_samples = true, | ||
| 830 | }; | ||
| 831 | |||
| 832 | static const struct perf_evsel_str_handler lock_tracepoints[] = { | 826 | static const struct perf_evsel_str_handler lock_tracepoints[] = { |
| 833 | { "lock:lock_acquire", perf_evsel__process_lock_acquire, }, /* CONFIG_LOCKDEP */ | 827 | { "lock:lock_acquire", perf_evsel__process_lock_acquire, }, /* CONFIG_LOCKDEP */ |
| 834 | { "lock:lock_acquired", perf_evsel__process_lock_acquired, }, /* CONFIG_LOCKDEP, CONFIG_LOCK_STAT */ | 828 | { "lock:lock_acquired", perf_evsel__process_lock_acquired, }, /* CONFIG_LOCKDEP, CONFIG_LOCK_STAT */ |
| @@ -838,6 +832,11 @@ static const struct perf_evsel_str_handler lock_tracepoints[] = { | |||
| 838 | 832 | ||
| 839 | static int read_events(void) | 833 | static int read_events(void) |
| 840 | { | 834 | { |
| 835 | struct perf_tool eops = { | ||
| 836 | .sample = process_sample_event, | ||
| 837 | .comm = perf_event__process_comm, | ||
| 838 | .ordered_samples = true, | ||
| 839 | }; | ||
| 841 | session = perf_session__new(input_name, O_RDONLY, 0, false, &eops); | 840 | session = perf_session__new(input_name, O_RDONLY, 0, false, &eops); |
| 842 | if (!session) { | 841 | if (!session) { |
| 843 | pr_err("Initializing perf session failed\n"); | 842 | pr_err("Initializing perf session failed\n"); |
| @@ -878,53 +877,11 @@ static int __cmd_report(void) | |||
| 878 | return 0; | 877 | return 0; |
| 879 | } | 878 | } |
| 880 | 879 | ||
| 881 | static const char * const report_usage[] = { | ||
| 882 | "perf lock report [<options>]", | ||
| 883 | NULL | ||
| 884 | }; | ||
| 885 | |||
| 886 | static const struct option report_options[] = { | ||
| 887 | OPT_STRING('k', "key", &sort_key, "acquired", | ||
| 888 | "key for sorting (acquired / contended / wait_total / wait_max / wait_min)"), | ||
| 889 | /* TODO: type */ | ||
| 890 | OPT_END() | ||
| 891 | }; | ||
| 892 | |||
| 893 | static const char * const info_usage[] = { | ||
| 894 | "perf lock info [<options>]", | ||
| 895 | NULL | ||
| 896 | }; | ||
| 897 | |||
| 898 | static const struct option info_options[] = { | ||
| 899 | OPT_BOOLEAN('t', "threads", &info_threads, | ||
| 900 | "dump thread list in perf.data"), | ||
| 901 | OPT_BOOLEAN('m', "map", &info_map, | ||
| 902 | "map of lock instances (address:name table)"), | ||
| 903 | OPT_END() | ||
| 904 | }; | ||
| 905 | |||
| 906 | static const char * const lock_usage[] = { | ||
| 907 | "perf lock [<options>] {record|report|script|info}", | ||
| 908 | NULL | ||
| 909 | }; | ||
| 910 | |||
| 911 | static const struct option lock_options[] = { | ||
| 912 | OPT_STRING('i', "input", &input_name, "file", "input file name"), | ||
| 913 | OPT_INCR('v', "verbose", &verbose, "be more verbose (show symbol address, etc)"), | ||
| 914 | OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, "dump raw trace in ASCII"), | ||
| 915 | OPT_END() | ||
| 916 | }; | ||
| 917 | |||
| 918 | static const char *record_args[] = { | ||
| 919 | "record", | ||
| 920 | "-R", | ||
| 921 | "-f", | ||
| 922 | "-m", "1024", | ||
| 923 | "-c", "1", | ||
| 924 | }; | ||
| 925 | |||
| 926 | static int __cmd_record(int argc, const char **argv) | 880 | static int __cmd_record(int argc, const char **argv) |
| 927 | { | 881 | { |
| 882 | const char *record_args[] = { | ||
| 883 | "record", "-R", "-f", "-m", "1024", "-c", "1", | ||
| 884 | }; | ||
| 928 | unsigned int rec_argc, i, j; | 885 | unsigned int rec_argc, i, j; |
| 929 | const char **rec_argv; | 886 | const char **rec_argv; |
| 930 | 887 | ||
| @@ -963,6 +920,37 @@ static int __cmd_record(int argc, const char **argv) | |||
| 963 | 920 | ||
| 964 | int cmd_lock(int argc, const char **argv, const char *prefix __maybe_unused) | 921 | int cmd_lock(int argc, const char **argv, const char *prefix __maybe_unused) |
| 965 | { | 922 | { |
| 923 | const struct option info_options[] = { | ||
| 924 | OPT_BOOLEAN('t', "threads", &info_threads, | ||
| 925 | "dump thread list in perf.data"), | ||
| 926 | OPT_BOOLEAN('m', "map", &info_map, | ||
| 927 | "map of lock instances (address:name table)"), | ||
| 928 | OPT_END() | ||
| 929 | }; | ||
| 930 | const struct option lock_options[] = { | ||
| 931 | OPT_STRING('i', "input", &input_name, "file", "input file name"), | ||
| 932 | OPT_INCR('v', "verbose", &verbose, "be more verbose (show symbol address, etc)"), | ||
| 933 | OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, "dump raw trace in ASCII"), | ||
| 934 | OPT_END() | ||
| 935 | }; | ||
| 936 | const struct option report_options[] = { | ||
| 937 | OPT_STRING('k', "key", &sort_key, "acquired", | ||
| 938 | "key for sorting (acquired / contended / wait_total / wait_max / wait_min)"), | ||
| 939 | /* TODO: type */ | ||
| 940 | OPT_END() | ||
| 941 | }; | ||
| 942 | const char * const info_usage[] = { | ||
| 943 | "perf lock info [<options>]", | ||
| 944 | NULL | ||
| 945 | }; | ||
| 946 | const char * const lock_usage[] = { | ||
| 947 | "perf lock [<options>] {record|report|script|info}", | ||
| 948 | NULL | ||
| 949 | }; | ||
| 950 | const char * const report_usage[] = { | ||
| 951 | "perf lock report [<options>]", | ||
| 952 | NULL | ||
| 953 | }; | ||
| 966 | unsigned int i; | 954 | unsigned int i; |
| 967 | int rc = 0; | 955 | int rc = 0; |
| 968 | 956 | ||
diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c index 118aa8946573..de38a034b129 100644 --- a/tools/perf/builtin-probe.c +++ b/tools/perf/builtin-probe.c | |||
| @@ -250,19 +250,20 @@ static int opt_set_filter(const struct option *opt __maybe_unused, | |||
| 250 | return 0; | 250 | return 0; |
| 251 | } | 251 | } |
| 252 | 252 | ||
| 253 | static const char * const probe_usage[] = { | 253 | int cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused) |
| 254 | "perf probe [<options>] 'PROBEDEF' ['PROBEDEF' ...]", | 254 | { |
| 255 | "perf probe [<options>] --add 'PROBEDEF' [--add 'PROBEDEF' ...]", | 255 | const char * const probe_usage[] = { |
| 256 | "perf probe [<options>] --del '[GROUP:]EVENT' ...", | 256 | "perf probe [<options>] 'PROBEDEF' ['PROBEDEF' ...]", |
| 257 | "perf probe --list", | 257 | "perf probe [<options>] --add 'PROBEDEF' [--add 'PROBEDEF' ...]", |
| 258 | "perf probe [<options>] --del '[GROUP:]EVENT' ...", | ||
| 259 | "perf probe --list", | ||
| 258 | #ifdef DWARF_SUPPORT | 260 | #ifdef DWARF_SUPPORT |
| 259 | "perf probe [<options>] --line 'LINEDESC'", | 261 | "perf probe [<options>] --line 'LINEDESC'", |
| 260 | "perf probe [<options>] --vars 'PROBEPOINT'", | 262 | "perf probe [<options>] --vars 'PROBEPOINT'", |
| 261 | #endif | 263 | #endif |
| 262 | NULL | 264 | NULL |
| 263 | }; | 265 | }; |
| 264 | 266 | const struct option options[] = { | |
| 265 | static const struct option options[] = { | ||
| 266 | OPT_INCR('v', "verbose", &verbose, | 267 | OPT_INCR('v', "verbose", &verbose, |
| 267 | "be more verbose (show parsed arguments, etc)"), | 268 | "be more verbose (show parsed arguments, etc)"), |
| 268 | OPT_BOOLEAN('l', "list", ¶ms.list_events, | 269 | OPT_BOOLEAN('l', "list", ¶ms.list_events, |
| @@ -325,10 +326,7 @@ static const struct option options[] = { | |||
| 325 | OPT_CALLBACK('x', "exec", NULL, "executable|path", | 326 | OPT_CALLBACK('x', "exec", NULL, "executable|path", |
| 326 | "target executable name or path", opt_set_target), | 327 | "target executable name or path", opt_set_target), |
| 327 | OPT_END() | 328 | OPT_END() |
| 328 | }; | 329 | }; |
| 329 | |||
| 330 | int cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused) | ||
| 331 | { | ||
| 332 | int ret; | 330 | int ret; |
| 333 | 331 | ||
| 334 | argc = parse_options(argc, argv, options, probe_usage, | 332 | argc = parse_options(argc, argv, options, probe_usage, |
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index f14cb5fdb91f..e9231659754d 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c | |||
| @@ -31,15 +31,6 @@ | |||
| 31 | #include <sched.h> | 31 | #include <sched.h> |
| 32 | #include <sys/mman.h> | 32 | #include <sys/mman.h> |
| 33 | 33 | ||
| 34 | #define CALLCHAIN_HELP "do call-graph (stack chain/backtrace) recording: " | ||
| 35 | |||
| 36 | #ifdef NO_LIBUNWIND_SUPPORT | ||
| 37 | static char callchain_help[] = CALLCHAIN_HELP "[fp]"; | ||
| 38 | #else | ||
| 39 | static unsigned long default_stack_dump_size = 8192; | ||
| 40 | static char callchain_help[] = CALLCHAIN_HELP "[fp] dwarf"; | ||
| 41 | #endif | ||
| 42 | |||
| 43 | enum write_mode_t { | 34 | enum write_mode_t { |
| 44 | WRITE_FORCE, | 35 | WRITE_FORCE, |
| 45 | WRITE_APPEND | 36 | WRITE_APPEND |
| @@ -800,7 +791,7 @@ error: | |||
| 800 | return ret; | 791 | return ret; |
| 801 | } | 792 | } |
| 802 | 793 | ||
| 803 | #ifndef NO_LIBUNWIND_SUPPORT | 794 | #ifdef LIBUNWIND_SUPPORT |
| 804 | static int get_stack_size(char *str, unsigned long *_size) | 795 | static int get_stack_size(char *str, unsigned long *_size) |
| 805 | { | 796 | { |
| 806 | char *endptr; | 797 | char *endptr; |
| @@ -826,7 +817,7 @@ static int get_stack_size(char *str, unsigned long *_size) | |||
| 826 | max_size, str); | 817 | max_size, str); |
| 827 | return -1; | 818 | return -1; |
| 828 | } | 819 | } |
| 829 | #endif /* !NO_LIBUNWIND_SUPPORT */ | 820 | #endif /* LIBUNWIND_SUPPORT */ |
| 830 | 821 | ||
| 831 | static int | 822 | static int |
| 832 | parse_callchain_opt(const struct option *opt __maybe_unused, const char *arg, | 823 | parse_callchain_opt(const struct option *opt __maybe_unused, const char *arg, |
| @@ -865,9 +856,11 @@ parse_callchain_opt(const struct option *opt __maybe_unused, const char *arg, | |||
| 865 | "needed for -g fp\n"); | 856 | "needed for -g fp\n"); |
| 866 | break; | 857 | break; |
| 867 | 858 | ||
| 868 | #ifndef NO_LIBUNWIND_SUPPORT | 859 | #ifdef LIBUNWIND_SUPPORT |
| 869 | /* Dwarf style */ | 860 | /* Dwarf style */ |
| 870 | } else if (!strncmp(name, "dwarf", sizeof("dwarf"))) { | 861 | } else if (!strncmp(name, "dwarf", sizeof("dwarf"))) { |
| 862 | const unsigned long default_stack_dump_size = 8192; | ||
| 863 | |||
| 871 | ret = 0; | 864 | ret = 0; |
| 872 | rec->opts.call_graph = CALLCHAIN_DWARF; | 865 | rec->opts.call_graph = CALLCHAIN_DWARF; |
| 873 | rec->opts.stack_dump_size = default_stack_dump_size; | 866 | rec->opts.stack_dump_size = default_stack_dump_size; |
| @@ -883,7 +876,7 @@ parse_callchain_opt(const struct option *opt __maybe_unused, const char *arg, | |||
| 883 | if (!ret) | 876 | if (!ret) |
| 884 | pr_debug("callchain: stack dump size %d\n", | 877 | pr_debug("callchain: stack dump size %d\n", |
| 885 | rec->opts.stack_dump_size); | 878 | rec->opts.stack_dump_size); |
| 886 | #endif /* !NO_LIBUNWIND_SUPPORT */ | 879 | #endif /* LIBUNWIND_SUPPORT */ |
| 887 | } else { | 880 | } else { |
| 888 | pr_err("callchain: Unknown -g option " | 881 | pr_err("callchain: Unknown -g option " |
| 889 | "value: %s\n", arg); | 882 | "value: %s\n", arg); |
| @@ -930,6 +923,14 @@ static struct perf_record record = { | |||
| 930 | .file_new = true, | 923 | .file_new = true, |
| 931 | }; | 924 | }; |
| 932 | 925 | ||
| 926 | #define CALLCHAIN_HELP "do call-graph (stack chain/backtrace) recording: " | ||
| 927 | |||
| 928 | #ifdef LIBUNWIND_SUPPORT | ||
| 929 | static const char callchain_help[] = CALLCHAIN_HELP "[fp] dwarf"; | ||
| 930 | #else | ||
| 931 | static const char callchain_help[] = CALLCHAIN_HELP "[fp]"; | ||
| 932 | #endif | ||
| 933 | |||
| 933 | /* | 934 | /* |
| 934 | * XXX Will stay a global variable till we fix builtin-script.c to stop messing | 935 | * XXX Will stay a global variable till we fix builtin-script.c to stop messing |
| 935 | * with it and switch to use the library functions in perf_evlist that came | 936 | * with it and switch to use the library functions in perf_evlist that came |
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 1da243dfbc3e..a61725d89d3e 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c | |||
| @@ -320,7 +320,7 @@ static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist, | |||
| 320 | const char *evname = perf_evsel__name(pos); | 320 | const char *evname = perf_evsel__name(pos); |
| 321 | 321 | ||
| 322 | hists__fprintf_nr_sample_events(hists, evname, stdout); | 322 | hists__fprintf_nr_sample_events(hists, evname, stdout); |
| 323 | hists__fprintf(hists, NULL, false, true, 0, 0, stdout); | 323 | hists__fprintf(hists, true, 0, 0, stdout); |
| 324 | fprintf(stdout, "\n\n"); | 324 | fprintf(stdout, "\n\n"); |
| 325 | } | 325 | } |
| 326 | 326 | ||
| @@ -691,7 +691,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused) | |||
| 691 | setup_browser(true); | 691 | setup_browser(true); |
| 692 | else { | 692 | else { |
| 693 | use_browser = 0; | 693 | use_browser = 0; |
| 694 | perf_hpp__init(false, false); | 694 | perf_hpp__init(); |
| 695 | } | 695 | } |
| 696 | 696 | ||
| 697 | setup_sorting(report_usage, options); | 697 | setup_sorting(report_usage, options); |
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c index 9b9e32eaa805..3488ead3b60c 100644 --- a/tools/perf/builtin-sched.c +++ b/tools/perf/builtin-sched.c | |||
| @@ -1426,7 +1426,7 @@ static int perf_sched__process_tracepoint_sample(struct perf_tool *tool __maybe_ | |||
| 1426 | struct perf_evsel *evsel, | 1426 | struct perf_evsel *evsel, |
| 1427 | struct machine *machine) | 1427 | struct machine *machine) |
| 1428 | { | 1428 | { |
| 1429 | struct thread *thread = machine__findnew_thread(machine, sample->pid); | 1429 | struct thread *thread = machine__findnew_thread(machine, sample->tid); |
| 1430 | int err = 0; | 1430 | int err = 0; |
| 1431 | 1431 | ||
| 1432 | if (thread == NULL) { | 1432 | if (thread == NULL) { |
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index 1be843aa1546..fb9625083a2e 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c | |||
| @@ -24,7 +24,6 @@ static u64 last_timestamp; | |||
| 24 | static u64 nr_unordered; | 24 | static u64 nr_unordered; |
| 25 | extern const struct option record_options[]; | 25 | extern const struct option record_options[]; |
| 26 | static bool no_callchain; | 26 | static bool no_callchain; |
| 27 | static bool show_full_info; | ||
| 28 | static bool system_wide; | 27 | static bool system_wide; |
| 29 | static const char *cpu_list; | 28 | static const char *cpu_list; |
| 30 | static DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS); | 29 | static DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS); |
| @@ -473,8 +472,6 @@ static int cleanup_scripting(void) | |||
| 473 | return scripting_ops->stop_script(); | 472 | return scripting_ops->stop_script(); |
| 474 | } | 473 | } |
| 475 | 474 | ||
| 476 | static const char *input_name; | ||
| 477 | |||
| 478 | static int process_sample_event(struct perf_tool *tool __maybe_unused, | 475 | static int process_sample_event(struct perf_tool *tool __maybe_unused, |
| 479 | union perf_event *event, | 476 | union perf_event *event, |
| 480 | struct perf_sample *sample, | 477 | struct perf_sample *sample, |
| @@ -1156,20 +1153,40 @@ out: | |||
| 1156 | return n_args; | 1153 | return n_args; |
| 1157 | } | 1154 | } |
| 1158 | 1155 | ||
| 1159 | static const char * const script_usage[] = { | 1156 | static int have_cmd(int argc, const char **argv) |
| 1160 | "perf script [<options>]", | 1157 | { |
| 1161 | "perf script [<options>] record <script> [<record-options>] <command>", | 1158 | char **__argv = malloc(sizeof(const char *) * argc); |
| 1162 | "perf script [<options>] report <script> [script-args]", | 1159 | |
| 1163 | "perf script [<options>] <script> [<record-options>] <command>", | 1160 | if (!__argv) { |
| 1164 | "perf script [<options>] <top-script> [script-args]", | 1161 | pr_err("malloc failed\n"); |
| 1165 | NULL | 1162 | return -1; |
| 1166 | }; | 1163 | } |
| 1164 | |||
| 1165 | memcpy(__argv, argv, sizeof(const char *) * argc); | ||
| 1166 | argc = parse_options(argc, (const char **)__argv, record_options, | ||
| 1167 | NULL, PARSE_OPT_STOP_AT_NON_OPTION); | ||
| 1168 | free(__argv); | ||
| 1167 | 1169 | ||
| 1168 | static const struct option options[] = { | 1170 | system_wide = (argc == 0); |
| 1171 | |||
| 1172 | return 0; | ||
| 1173 | } | ||
| 1174 | |||
| 1175 | int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused) | ||
| 1176 | { | ||
| 1177 | bool show_full_info = false; | ||
| 1178 | const char *input_name = NULL; | ||
| 1179 | char *rec_script_path = NULL; | ||
| 1180 | char *rep_script_path = NULL; | ||
| 1181 | struct perf_session *session; | ||
| 1182 | char *script_path = NULL; | ||
| 1183 | const char **__argv; | ||
| 1184 | int i, j, err; | ||
| 1185 | const struct option options[] = { | ||
| 1169 | OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, | 1186 | OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, |
| 1170 | "dump raw trace in ASCII"), | 1187 | "dump raw trace in ASCII"), |
| 1171 | OPT_INCR('v', "verbose", &verbose, | 1188 | OPT_INCR('v', "verbose", &verbose, |
| 1172 | "be more verbose (show symbol address, etc)"), | 1189 | "be more verbose (show symbol address, etc)"), |
| 1173 | OPT_BOOLEAN('L', "Latency", &latency_format, | 1190 | OPT_BOOLEAN('L', "Latency", &latency_format, |
| 1174 | "show latency attributes (irqs/preemption disabled, etc)"), | 1191 | "show latency attributes (irqs/preemption disabled, etc)"), |
| 1175 | OPT_CALLBACK_NOOPT('l', "list", NULL, NULL, "list available scripts", | 1192 | OPT_CALLBACK_NOOPT('l', "list", NULL, NULL, "list available scripts", |
| @@ -1179,8 +1196,7 @@ static const struct option options[] = { | |||
| 1179 | parse_scriptname), | 1196 | parse_scriptname), |
| 1180 | OPT_STRING('g', "gen-script", &generate_script_lang, "lang", | 1197 | OPT_STRING('g', "gen-script", &generate_script_lang, "lang", |
| 1181 | "generate perf-script.xx script in specified language"), | 1198 | "generate perf-script.xx script in specified language"), |
| 1182 | OPT_STRING('i', "input", &input_name, "file", | 1199 | OPT_STRING('i', "input", &input_name, "file", "input file name"), |
| 1183 | "input file name"), | ||
| 1184 | OPT_BOOLEAN('d', "debug-mode", &debug_mode, | 1200 | OPT_BOOLEAN('d', "debug-mode", &debug_mode, |
| 1185 | "do various checks like samples ordering and lost events"), | 1201 | "do various checks like samples ordering and lost events"), |
| 1186 | OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name, | 1202 | OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name, |
| @@ -1195,10 +1211,9 @@ static const struct option options[] = { | |||
| 1195 | "comma separated output fields prepend with 'type:'. " | 1211 | "comma separated output fields prepend with 'type:'. " |
| 1196 | "Valid types: hw,sw,trace,raw. " | 1212 | "Valid types: hw,sw,trace,raw. " |
| 1197 | "Fields: comm,tid,pid,time,cpu,event,trace,ip,sym,dso," | 1213 | "Fields: comm,tid,pid,time,cpu,event,trace,ip,sym,dso," |
| 1198 | "addr,symoff", | 1214 | "addr,symoff", parse_output_fields), |
| 1199 | parse_output_fields), | ||
| 1200 | OPT_BOOLEAN('a', "all-cpus", &system_wide, | 1215 | OPT_BOOLEAN('a', "all-cpus", &system_wide, |
| 1201 | "system-wide collection from all CPUs"), | 1216 | "system-wide collection from all CPUs"), |
| 1202 | OPT_STRING('S', "symbols", &symbol_conf.sym_list_str, "symbol[,symbol...]", | 1217 | OPT_STRING('S', "symbols", &symbol_conf.sym_list_str, "symbol[,symbol...]", |
| 1203 | "only consider these symbols"), | 1218 | "only consider these symbols"), |
| 1204 | OPT_STRING('C', "cpu", &cpu_list, "cpu", "list of cpus to profile"), | 1219 | OPT_STRING('C', "cpu", &cpu_list, "cpu", "list of cpus to profile"), |
| @@ -1208,37 +1223,16 @@ static const struct option options[] = { | |||
| 1208 | "display extended information from perf.data file"), | 1223 | "display extended information from perf.data file"), |
| 1209 | OPT_BOOLEAN('\0', "show-kernel-path", &symbol_conf.show_kernel_path, | 1224 | OPT_BOOLEAN('\0', "show-kernel-path", &symbol_conf.show_kernel_path, |
| 1210 | "Show the path of [kernel.kallsyms]"), | 1225 | "Show the path of [kernel.kallsyms]"), |
| 1211 | |||
| 1212 | OPT_END() | 1226 | OPT_END() |
| 1213 | }; | 1227 | }; |
| 1214 | 1228 | const char * const script_usage[] = { | |
| 1215 | static int have_cmd(int argc, const char **argv) | 1229 | "perf script [<options>]", |
| 1216 | { | 1230 | "perf script [<options>] record <script> [<record-options>] <command>", |
| 1217 | char **__argv = malloc(sizeof(const char *) * argc); | 1231 | "perf script [<options>] report <script> [script-args]", |
| 1218 | 1232 | "perf script [<options>] <script> [<record-options>] <command>", | |
| 1219 | if (!__argv) { | 1233 | "perf script [<options>] <top-script> [script-args]", |
| 1220 | pr_err("malloc failed\n"); | 1234 | NULL |
| 1221 | return -1; | 1235 | }; |
| 1222 | } | ||
| 1223 | |||
| 1224 | memcpy(__argv, argv, sizeof(const char *) * argc); | ||
| 1225 | argc = parse_options(argc, (const char **)__argv, record_options, | ||
| 1226 | NULL, PARSE_OPT_STOP_AT_NON_OPTION); | ||
| 1227 | free(__argv); | ||
| 1228 | |||
| 1229 | system_wide = (argc == 0); | ||
| 1230 | |||
| 1231 | return 0; | ||
| 1232 | } | ||
| 1233 | |||
| 1234 | int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused) | ||
| 1235 | { | ||
| 1236 | char *rec_script_path = NULL; | ||
| 1237 | char *rep_script_path = NULL; | ||
| 1238 | struct perf_session *session; | ||
| 1239 | char *script_path = NULL; | ||
| 1240 | const char **__argv; | ||
| 1241 | int i, j, err; | ||
| 1242 | 1236 | ||
| 1243 | setup_scripting(); | 1237 | setup_scripting(); |
| 1244 | 1238 | ||
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index e8cd4d81b06e..93b9011fa3e2 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c | |||
| @@ -64,122 +64,12 @@ | |||
| 64 | #define CNTR_NOT_SUPPORTED "<not supported>" | 64 | #define CNTR_NOT_SUPPORTED "<not supported>" |
| 65 | #define CNTR_NOT_COUNTED "<not counted>" | 65 | #define CNTR_NOT_COUNTED "<not counted>" |
| 66 | 66 | ||
| 67 | static struct perf_event_attr default_attrs[] = { | ||
| 68 | |||
| 69 | { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_TASK_CLOCK }, | ||
| 70 | { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_CONTEXT_SWITCHES }, | ||
| 71 | { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_CPU_MIGRATIONS }, | ||
| 72 | { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_PAGE_FAULTS }, | ||
| 73 | |||
| 74 | { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_CPU_CYCLES }, | ||
| 75 | { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_STALLED_CYCLES_FRONTEND }, | ||
| 76 | { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_STALLED_CYCLES_BACKEND }, | ||
| 77 | { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_INSTRUCTIONS }, | ||
| 78 | { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_BRANCH_INSTRUCTIONS }, | ||
| 79 | { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_BRANCH_MISSES }, | ||
| 80 | |||
| 81 | }; | ||
| 82 | |||
| 83 | /* | ||
| 84 | * Detailed stats (-d), covering the L1 and last level data caches: | ||
| 85 | */ | ||
| 86 | static struct perf_event_attr detailed_attrs[] = { | ||
| 87 | |||
| 88 | { .type = PERF_TYPE_HW_CACHE, | ||
| 89 | .config = | ||
| 90 | PERF_COUNT_HW_CACHE_L1D << 0 | | ||
| 91 | (PERF_COUNT_HW_CACHE_OP_READ << 8) | | ||
| 92 | (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) }, | ||
| 93 | |||
| 94 | { .type = PERF_TYPE_HW_CACHE, | ||
| 95 | .config = | ||
| 96 | PERF_COUNT_HW_CACHE_L1D << 0 | | ||
| 97 | (PERF_COUNT_HW_CACHE_OP_READ << 8) | | ||
| 98 | (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) }, | ||
| 99 | |||
| 100 | { .type = PERF_TYPE_HW_CACHE, | ||
| 101 | .config = | ||
| 102 | PERF_COUNT_HW_CACHE_LL << 0 | | ||
| 103 | (PERF_COUNT_HW_CACHE_OP_READ << 8) | | ||
| 104 | (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) }, | ||
| 105 | |||
| 106 | { .type = PERF_TYPE_HW_CACHE, | ||
| 107 | .config = | ||
| 108 | PERF_COUNT_HW_CACHE_LL << 0 | | ||
| 109 | (PERF_COUNT_HW_CACHE_OP_READ << 8) | | ||
| 110 | (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) }, | ||
| 111 | }; | ||
| 112 | |||
| 113 | /* | ||
| 114 | * Very detailed stats (-d -d), covering the instruction cache and the TLB caches: | ||
| 115 | */ | ||
| 116 | static struct perf_event_attr very_detailed_attrs[] = { | ||
| 117 | |||
| 118 | { .type = PERF_TYPE_HW_CACHE, | ||
| 119 | .config = | ||
| 120 | PERF_COUNT_HW_CACHE_L1I << 0 | | ||
| 121 | (PERF_COUNT_HW_CACHE_OP_READ << 8) | | ||
| 122 | (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) }, | ||
| 123 | |||
| 124 | { .type = PERF_TYPE_HW_CACHE, | ||
| 125 | .config = | ||
| 126 | PERF_COUNT_HW_CACHE_L1I << 0 | | ||
| 127 | (PERF_COUNT_HW_CACHE_OP_READ << 8) | | ||
| 128 | (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) }, | ||
| 129 | |||
| 130 | { .type = PERF_TYPE_HW_CACHE, | ||
| 131 | .config = | ||
| 132 | PERF_COUNT_HW_CACHE_DTLB << 0 | | ||
| 133 | (PERF_COUNT_HW_CACHE_OP_READ << 8) | | ||
| 134 | (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) }, | ||
| 135 | |||
| 136 | { .type = PERF_TYPE_HW_CACHE, | ||
| 137 | .config = | ||
| 138 | PERF_COUNT_HW_CACHE_DTLB << 0 | | ||
| 139 | (PERF_COUNT_HW_CACHE_OP_READ << 8) | | ||
| 140 | (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) }, | ||
| 141 | |||
| 142 | { .type = PERF_TYPE_HW_CACHE, | ||
| 143 | .config = | ||
| 144 | PERF_COUNT_HW_CACHE_ITLB << 0 | | ||
| 145 | (PERF_COUNT_HW_CACHE_OP_READ << 8) | | ||
| 146 | (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) }, | ||
| 147 | |||
| 148 | { .type = PERF_TYPE_HW_CACHE, | ||
| 149 | .config = | ||
| 150 | PERF_COUNT_HW_CACHE_ITLB << 0 | | ||
| 151 | (PERF_COUNT_HW_CACHE_OP_READ << 8) | | ||
| 152 | (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) }, | ||
| 153 | |||
| 154 | }; | ||
| 155 | |||
| 156 | /* | ||
| 157 | * Very, very detailed stats (-d -d -d), adding prefetch events: | ||
| 158 | */ | ||
| 159 | static struct perf_event_attr very_very_detailed_attrs[] = { | ||
| 160 | |||
| 161 | { .type = PERF_TYPE_HW_CACHE, | ||
| 162 | .config = | ||
| 163 | PERF_COUNT_HW_CACHE_L1D << 0 | | ||
| 164 | (PERF_COUNT_HW_CACHE_OP_PREFETCH << 8) | | ||
| 165 | (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) }, | ||
| 166 | |||
| 167 | { .type = PERF_TYPE_HW_CACHE, | ||
| 168 | .config = | ||
| 169 | PERF_COUNT_HW_CACHE_L1D << 0 | | ||
| 170 | (PERF_COUNT_HW_CACHE_OP_PREFETCH << 8) | | ||
| 171 | (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) }, | ||
| 172 | }; | ||
| 173 | |||
| 174 | |||
| 175 | |||
| 176 | static struct perf_evlist *evsel_list; | 67 | static struct perf_evlist *evsel_list; |
| 177 | 68 | ||
| 178 | static struct perf_target target = { | 69 | static struct perf_target target = { |
| 179 | .uid = UINT_MAX, | 70 | .uid = UINT_MAX, |
| 180 | }; | 71 | }; |
| 181 | 72 | ||
| 182 | static int run_idx = 0; | ||
| 183 | static int run_count = 1; | 73 | static int run_count = 1; |
| 184 | static bool no_inherit = false; | 74 | static bool no_inherit = false; |
| 185 | static bool scale = true; | 75 | static bool scale = true; |
| @@ -187,15 +77,12 @@ static bool no_aggr = false; | |||
| 187 | static pid_t child_pid = -1; | 77 | static pid_t child_pid = -1; |
| 188 | static bool null_run = false; | 78 | static bool null_run = false; |
| 189 | static int detailed_run = 0; | 79 | static int detailed_run = 0; |
| 190 | static bool sync_run = false; | ||
| 191 | static bool big_num = true; | 80 | static bool big_num = true; |
| 192 | static int big_num_opt = -1; | 81 | static int big_num_opt = -1; |
| 193 | static const char *csv_sep = NULL; | 82 | static const char *csv_sep = NULL; |
| 194 | static bool csv_output = false; | 83 | static bool csv_output = false; |
| 195 | static bool group = false; | 84 | static bool group = false; |
| 196 | static const char *output_name = NULL; | ||
| 197 | static FILE *output = NULL; | 85 | static FILE *output = NULL; |
| 198 | static int output_fd; | ||
| 199 | 86 | ||
| 200 | static volatile int done = 0; | 87 | static volatile int done = 0; |
| 201 | 88 | ||
| @@ -1028,11 +915,6 @@ static void sig_atexit(void) | |||
| 1028 | kill(getpid(), signr); | 915 | kill(getpid(), signr); |
| 1029 | } | 916 | } |
| 1030 | 917 | ||
| 1031 | static const char * const stat_usage[] = { | ||
| 1032 | "perf stat [<options>] [<command>]", | ||
| 1033 | NULL | ||
| 1034 | }; | ||
| 1035 | |||
| 1036 | static int stat__set_big_num(const struct option *opt __maybe_unused, | 918 | static int stat__set_big_num(const struct option *opt __maybe_unused, |
| 1037 | const char *s __maybe_unused, int unset) | 919 | const char *s __maybe_unused, int unset) |
| 1038 | { | 920 | { |
| @@ -1040,62 +922,119 @@ static int stat__set_big_num(const struct option *opt __maybe_unused, | |||
| 1040 | return 0; | 922 | return 0; |
| 1041 | } | 923 | } |
| 1042 | 924 | ||
| 1043 | static bool append_file; | ||
| 1044 | |||
| 1045 | static const struct option options[] = { | ||
| 1046 | OPT_CALLBACK('e', "event", &evsel_list, "event", | ||
| 1047 | "event selector. use 'perf list' to list available events", | ||
| 1048 | parse_events_option), | ||
| 1049 | OPT_CALLBACK(0, "filter", &evsel_list, "filter", | ||
| 1050 | "event filter", parse_filter), | ||
| 1051 | OPT_BOOLEAN('i', "no-inherit", &no_inherit, | ||
| 1052 | "child tasks do not inherit counters"), | ||
| 1053 | OPT_STRING('p', "pid", &target.pid, "pid", | ||
| 1054 | "stat events on existing process id"), | ||
| 1055 | OPT_STRING('t', "tid", &target.tid, "tid", | ||
| 1056 | "stat events on existing thread id"), | ||
| 1057 | OPT_BOOLEAN('a', "all-cpus", &target.system_wide, | ||
| 1058 | "system-wide collection from all CPUs"), | ||
| 1059 | OPT_BOOLEAN('g', "group", &group, | ||
| 1060 | "put the counters into a counter group"), | ||
| 1061 | OPT_BOOLEAN('c', "scale", &scale, | ||
| 1062 | "scale/normalize counters"), | ||
| 1063 | OPT_INCR('v', "verbose", &verbose, | ||
| 1064 | "be more verbose (show counter open errors, etc)"), | ||
| 1065 | OPT_INTEGER('r', "repeat", &run_count, | ||
| 1066 | "repeat command and print average + stddev (max: 100)"), | ||
| 1067 | OPT_BOOLEAN('n', "null", &null_run, | ||
| 1068 | "null run - dont start any counters"), | ||
| 1069 | OPT_INCR('d', "detailed", &detailed_run, | ||
| 1070 | "detailed run - start a lot of events"), | ||
| 1071 | OPT_BOOLEAN('S', "sync", &sync_run, | ||
| 1072 | "call sync() before starting a run"), | ||
| 1073 | OPT_CALLBACK_NOOPT('B', "big-num", NULL, NULL, | ||
| 1074 | "print large numbers with thousands\' separators", | ||
| 1075 | stat__set_big_num), | ||
| 1076 | OPT_STRING('C', "cpu", &target.cpu_list, "cpu", | ||
| 1077 | "list of cpus to monitor in system-wide"), | ||
| 1078 | OPT_BOOLEAN('A', "no-aggr", &no_aggr, | ||
| 1079 | "disable CPU count aggregation"), | ||
| 1080 | OPT_STRING('x', "field-separator", &csv_sep, "separator", | ||
| 1081 | "print counts with custom separator"), | ||
| 1082 | OPT_CALLBACK('G', "cgroup", &evsel_list, "name", | ||
| 1083 | "monitor event in cgroup name only", | ||
| 1084 | parse_cgroups), | ||
| 1085 | OPT_STRING('o', "output", &output_name, "file", | ||
| 1086 | "output file name"), | ||
| 1087 | OPT_BOOLEAN(0, "append", &append_file, "append to the output file"), | ||
| 1088 | OPT_INTEGER(0, "log-fd", &output_fd, | ||
| 1089 | "log output to fd, instead of stderr"), | ||
| 1090 | OPT_END() | ||
| 1091 | }; | ||
| 1092 | |||
| 1093 | /* | 925 | /* |
| 1094 | * Add default attributes, if there were no attributes specified or | 926 | * Add default attributes, if there were no attributes specified or |
| 1095 | * if -d/--detailed, -d -d or -d -d -d is used: | 927 | * if -d/--detailed, -d -d or -d -d -d is used: |
| 1096 | */ | 928 | */ |
| 1097 | static int add_default_attributes(void) | 929 | static int add_default_attributes(void) |
| 1098 | { | 930 | { |
| 931 | struct perf_event_attr default_attrs[] = { | ||
| 932 | |||
| 933 | { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_TASK_CLOCK }, | ||
| 934 | { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_CONTEXT_SWITCHES }, | ||
| 935 | { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_CPU_MIGRATIONS }, | ||
| 936 | { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_PAGE_FAULTS }, | ||
| 937 | |||
| 938 | { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_CPU_CYCLES }, | ||
| 939 | { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_STALLED_CYCLES_FRONTEND }, | ||
| 940 | { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_STALLED_CYCLES_BACKEND }, | ||
| 941 | { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_INSTRUCTIONS }, | ||
| 942 | { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_BRANCH_INSTRUCTIONS }, | ||
| 943 | { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_BRANCH_MISSES }, | ||
| 944 | |||
| 945 | }; | ||
| 946 | |||
| 947 | /* | ||
| 948 | * Detailed stats (-d), covering the L1 and last level data caches: | ||
| 949 | */ | ||
| 950 | struct perf_event_attr detailed_attrs[] = { | ||
| 951 | |||
| 952 | { .type = PERF_TYPE_HW_CACHE, | ||
| 953 | .config = | ||
| 954 | PERF_COUNT_HW_CACHE_L1D << 0 | | ||
| 955 | (PERF_COUNT_HW_CACHE_OP_READ << 8) | | ||
| 956 | (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) }, | ||
| 957 | |||
| 958 | { .type = PERF_TYPE_HW_CACHE, | ||
| 959 | .config = | ||
| 960 | PERF_COUNT_HW_CACHE_L1D << 0 | | ||
| 961 | (PERF_COUNT_HW_CACHE_OP_READ << 8) | | ||
| 962 | (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) }, | ||
| 963 | |||
| 964 | { .type = PERF_TYPE_HW_CACHE, | ||
| 965 | .config = | ||
| 966 | PERF_COUNT_HW_CACHE_LL << 0 | | ||
| 967 | (PERF_COUNT_HW_CACHE_OP_READ << 8) | | ||
| 968 | (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) }, | ||
| 969 | |||
| 970 | { .type = PERF_TYPE_HW_CACHE, | ||
| 971 | .config = | ||
| 972 | PERF_COUNT_HW_CACHE_LL << 0 | | ||
| 973 | (PERF_COUNT_HW_CACHE_OP_READ << 8) | | ||
| 974 | (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) }, | ||
| 975 | }; | ||
| 976 | |||
| 977 | /* | ||
| 978 | * Very detailed stats (-d -d), covering the instruction cache and the TLB caches: | ||
| 979 | */ | ||
| 980 | struct perf_event_attr very_detailed_attrs[] = { | ||
| 981 | |||
| 982 | { .type = PERF_TYPE_HW_CACHE, | ||
| 983 | .config = | ||
| 984 | PERF_COUNT_HW_CACHE_L1I << 0 | | ||
| 985 | (PERF_COUNT_HW_CACHE_OP_READ << 8) | | ||
| 986 | (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) }, | ||
| 987 | |||
| 988 | { .type = PERF_TYPE_HW_CACHE, | ||
| 989 | .config = | ||
| 990 | PERF_COUNT_HW_CACHE_L1I << 0 | | ||
| 991 | (PERF_COUNT_HW_CACHE_OP_READ << 8) | | ||
| 992 | (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) }, | ||
| 993 | |||
| 994 | { .type = PERF_TYPE_HW_CACHE, | ||
| 995 | .config = | ||
| 996 | PERF_COUNT_HW_CACHE_DTLB << 0 | | ||
| 997 | (PERF_COUNT_HW_CACHE_OP_READ << 8) | | ||
| 998 | (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) }, | ||
| 999 | |||
| 1000 | { .type = PERF_TYPE_HW_CACHE, | ||
| 1001 | .config = | ||
| 1002 | PERF_COUNT_HW_CACHE_DTLB << 0 | | ||
| 1003 | (PERF_COUNT_HW_CACHE_OP_READ << 8) | | ||
| 1004 | (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) }, | ||
| 1005 | |||
| 1006 | { .type = PERF_TYPE_HW_CACHE, | ||
| 1007 | .config = | ||
| 1008 | PERF_COUNT_HW_CACHE_ITLB << 0 | | ||
| 1009 | (PERF_COUNT_HW_CACHE_OP_READ << 8) | | ||
| 1010 | (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) }, | ||
| 1011 | |||
| 1012 | { .type = PERF_TYPE_HW_CACHE, | ||
| 1013 | .config = | ||
| 1014 | PERF_COUNT_HW_CACHE_ITLB << 0 | | ||
| 1015 | (PERF_COUNT_HW_CACHE_OP_READ << 8) | | ||
| 1016 | (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) }, | ||
| 1017 | |||
| 1018 | }; | ||
| 1019 | |||
| 1020 | /* | ||
| 1021 | * Very, very detailed stats (-d -d -d), adding prefetch events: | ||
| 1022 | */ | ||
| 1023 | struct perf_event_attr very_very_detailed_attrs[] = { | ||
| 1024 | |||
| 1025 | { .type = PERF_TYPE_HW_CACHE, | ||
| 1026 | .config = | ||
| 1027 | PERF_COUNT_HW_CACHE_L1D << 0 | | ||
| 1028 | (PERF_COUNT_HW_CACHE_OP_PREFETCH << 8) | | ||
| 1029 | (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) }, | ||
| 1030 | |||
| 1031 | { .type = PERF_TYPE_HW_CACHE, | ||
| 1032 | .config = | ||
| 1033 | PERF_COUNT_HW_CACHE_L1D << 0 | | ||
| 1034 | (PERF_COUNT_HW_CACHE_OP_PREFETCH << 8) | | ||
| 1035 | (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) }, | ||
| 1036 | }; | ||
| 1037 | |||
| 1099 | /* Set attrs if no event is selected and !null_run: */ | 1038 | /* Set attrs if no event is selected and !null_run: */ |
| 1100 | if (null_run) | 1039 | if (null_run) |
| 1101 | return 0; | 1040 | return 0; |
| @@ -1130,8 +1069,59 @@ static int add_default_attributes(void) | |||
| 1130 | 1069 | ||
| 1131 | int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused) | 1070 | int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused) |
| 1132 | { | 1071 | { |
| 1072 | bool append_file = false, | ||
| 1073 | sync_run = false; | ||
| 1074 | int output_fd = 0; | ||
| 1075 | const char *output_name = NULL; | ||
| 1076 | const struct option options[] = { | ||
| 1077 | OPT_CALLBACK('e', "event", &evsel_list, "event", | ||
| 1078 | "event selector. use 'perf list' to list available events", | ||
| 1079 | parse_events_option), | ||
| 1080 | OPT_CALLBACK(0, "filter", &evsel_list, "filter", | ||
| 1081 | "event filter", parse_filter), | ||
| 1082 | OPT_BOOLEAN('i', "no-inherit", &no_inherit, | ||
| 1083 | "child tasks do not inherit counters"), | ||
| 1084 | OPT_STRING('p', "pid", &target.pid, "pid", | ||
| 1085 | "stat events on existing process id"), | ||
| 1086 | OPT_STRING('t', "tid", &target.tid, "tid", | ||
| 1087 | "stat events on existing thread id"), | ||
| 1088 | OPT_BOOLEAN('a', "all-cpus", &target.system_wide, | ||
| 1089 | "system-wide collection from all CPUs"), | ||
| 1090 | OPT_BOOLEAN('g', "group", &group, | ||
| 1091 | "put the counters into a counter group"), | ||
| 1092 | OPT_BOOLEAN('c', "scale", &scale, "scale/normalize counters"), | ||
| 1093 | OPT_INCR('v', "verbose", &verbose, | ||
| 1094 | "be more verbose (show counter open errors, etc)"), | ||
| 1095 | OPT_INTEGER('r', "repeat", &run_count, | ||
| 1096 | "repeat command and print average + stddev (max: 100)"), | ||
| 1097 | OPT_BOOLEAN('n', "null", &null_run, | ||
| 1098 | "null run - dont start any counters"), | ||
| 1099 | OPT_INCR('d', "detailed", &detailed_run, | ||
| 1100 | "detailed run - start a lot of events"), | ||
| 1101 | OPT_BOOLEAN('S', "sync", &sync_run, | ||
| 1102 | "call sync() before starting a run"), | ||
| 1103 | OPT_CALLBACK_NOOPT('B', "big-num", NULL, NULL, | ||
| 1104 | "print large numbers with thousands\' separators", | ||
| 1105 | stat__set_big_num), | ||
| 1106 | OPT_STRING('C', "cpu", &target.cpu_list, "cpu", | ||
| 1107 | "list of cpus to monitor in system-wide"), | ||
| 1108 | OPT_BOOLEAN('A', "no-aggr", &no_aggr, "disable CPU count aggregation"), | ||
| 1109 | OPT_STRING('x', "field-separator", &csv_sep, "separator", | ||
| 1110 | "print counts with custom separator"), | ||
| 1111 | OPT_CALLBACK('G', "cgroup", &evsel_list, "name", | ||
| 1112 | "monitor event in cgroup name only", parse_cgroups), | ||
| 1113 | OPT_STRING('o', "output", &output_name, "file", "output file name"), | ||
| 1114 | OPT_BOOLEAN(0, "append", &append_file, "append to the output file"), | ||
| 1115 | OPT_INTEGER(0, "log-fd", &output_fd, | ||
| 1116 | "log output to fd, instead of stderr"), | ||
| 1117 | OPT_END() | ||
| 1118 | }; | ||
| 1119 | const char * const stat_usage[] = { | ||
| 1120 | "perf stat [<options>] [<command>]", | ||
| 1121 | NULL | ||
| 1122 | }; | ||
| 1133 | struct perf_evsel *pos; | 1123 | struct perf_evsel *pos; |
| 1134 | int status = -ENOMEM; | 1124 | int status = -ENOMEM, run_idx; |
| 1135 | const char *mode; | 1125 | const char *mode; |
| 1136 | 1126 | ||
| 1137 | setlocale(LC_ALL, ""); | 1127 | setlocale(LC_ALL, ""); |
diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c index b1a8a3b841cc..f251b613b2f3 100644 --- a/tools/perf/builtin-timechart.c +++ b/tools/perf/builtin-timechart.c | |||
| @@ -38,9 +38,6 @@ | |||
| 38 | #define PWR_EVENT_EXIT -1 | 38 | #define PWR_EVENT_EXIT -1 |
| 39 | 39 | ||
| 40 | 40 | ||
| 41 | static const char *input_name; | ||
| 42 | static const char *output_name = "output.svg"; | ||
| 43 | |||
| 44 | static unsigned int numcpus; | 41 | static unsigned int numcpus; |
| 45 | static u64 min_freq; /* Lowest CPU frequency seen */ | 42 | static u64 min_freq; /* Lowest CPU frequency seen */ |
| 46 | static u64 max_freq; /* Highest CPU frequency seen */ | 43 | static u64 max_freq; /* Highest CPU frequency seen */ |
| @@ -968,16 +965,15 @@ static void write_svg_file(const char *filename) | |||
| 968 | svg_close(); | 965 | svg_close(); |
| 969 | } | 966 | } |
| 970 | 967 | ||
| 971 | static struct perf_tool perf_timechart = { | 968 | static int __cmd_timechart(const char *input_name, const char *output_name) |
| 972 | .comm = process_comm_event, | ||
| 973 | .fork = process_fork_event, | ||
| 974 | .exit = process_exit_event, | ||
| 975 | .sample = process_sample_event, | ||
| 976 | .ordered_samples = true, | ||
| 977 | }; | ||
| 978 | |||
| 979 | static int __cmd_timechart(void) | ||
| 980 | { | 969 | { |
| 970 | struct perf_tool perf_timechart = { | ||
| 971 | .comm = process_comm_event, | ||
| 972 | .fork = process_fork_event, | ||
| 973 | .exit = process_exit_event, | ||
| 974 | .sample = process_sample_event, | ||
| 975 | .ordered_samples = true, | ||
| 976 | }; | ||
| 981 | struct perf_session *session = perf_session__new(input_name, O_RDONLY, | 977 | struct perf_session *session = perf_session__new(input_name, O_RDONLY, |
| 982 | 0, false, &perf_timechart); | 978 | 0, false, &perf_timechart); |
| 983 | int ret = -EINVAL; | 979 | int ret = -EINVAL; |
| @@ -1005,40 +1001,25 @@ out_delete: | |||
| 1005 | return ret; | 1001 | return ret; |
| 1006 | } | 1002 | } |
| 1007 | 1003 | ||
| 1008 | static const char * const timechart_usage[] = { | ||
| 1009 | "perf timechart [<options>] {record}", | ||
| 1010 | NULL | ||
| 1011 | }; | ||
| 1012 | |||
| 1013 | #ifdef SUPPORT_OLD_POWER_EVENTS | ||
| 1014 | static const char * const record_old_args[] = { | ||
| 1015 | "record", | ||
| 1016 | "-a", | ||
| 1017 | "-R", | ||
| 1018 | "-f", | ||
| 1019 | "-c", "1", | ||
| 1020 | "-e", "power:power_start", | ||
| 1021 | "-e", "power:power_end", | ||
| 1022 | "-e", "power:power_frequency", | ||
| 1023 | "-e", "sched:sched_wakeup", | ||
| 1024 | "-e", "sched:sched_switch", | ||
| 1025 | }; | ||
| 1026 | #endif | ||
| 1027 | |||
| 1028 | static const char * const record_new_args[] = { | ||
| 1029 | "record", | ||
| 1030 | "-a", | ||
| 1031 | "-R", | ||
| 1032 | "-f", | ||
| 1033 | "-c", "1", | ||
| 1034 | "-e", "power:cpu_frequency", | ||
| 1035 | "-e", "power:cpu_idle", | ||
| 1036 | "-e", "sched:sched_wakeup", | ||
| 1037 | "-e", "sched:sched_switch", | ||
| 1038 | }; | ||
| 1039 | |||
| 1040 | static int __cmd_record(int argc, const char **argv) | 1004 | static int __cmd_record(int argc, const char **argv) |
| 1041 | { | 1005 | { |
| 1006 | #ifdef SUPPORT_OLD_POWER_EVENTS | ||
| 1007 | const char * const record_old_args[] = { | ||
| 1008 | "record", "-a", "-R", "-f", "-c", "1", | ||
| 1009 | "-e", "power:power_start", | ||
| 1010 | "-e", "power:power_end", | ||
| 1011 | "-e", "power:power_frequency", | ||
| 1012 | "-e", "sched:sched_wakeup", | ||
| 1013 | "-e", "sched:sched_switch", | ||
| 1014 | }; | ||
| 1015 | #endif | ||
| 1016 | const char * const record_new_args[] = { | ||
| 1017 | "record", "-a", "-R", "-f", "-c", "1", | ||
| 1018 | "-e", "power:cpu_frequency", | ||
| 1019 | "-e", "power:cpu_idle", | ||
| 1020 | "-e", "sched:sched_wakeup", | ||
| 1021 | "-e", "sched:sched_switch", | ||
| 1022 | }; | ||
| 1042 | unsigned int rec_argc, i, j; | 1023 | unsigned int rec_argc, i, j; |
| 1043 | const char **rec_argv; | 1024 | const char **rec_argv; |
| 1044 | const char * const *record_args = record_new_args; | 1025 | const char * const *record_args = record_new_args; |
| @@ -1077,27 +1058,28 @@ parse_process(const struct option *opt __maybe_unused, const char *arg, | |||
| 1077 | return 0; | 1058 | return 0; |
| 1078 | } | 1059 | } |
| 1079 | 1060 | ||
| 1080 | static const struct option options[] = { | 1061 | int cmd_timechart(int argc, const char **argv, |
| 1081 | OPT_STRING('i', "input", &input_name, "file", | 1062 | const char *prefix __maybe_unused) |
| 1082 | "input file name"), | 1063 | { |
| 1083 | OPT_STRING('o', "output", &output_name, "file", | 1064 | const char *input_name; |
| 1084 | "output file name"), | 1065 | const char *output_name = "output.svg"; |
| 1085 | OPT_INTEGER('w', "width", &svg_page_width, | 1066 | const struct option options[] = { |
| 1086 | "page width"), | 1067 | OPT_STRING('i', "input", &input_name, "file", "input file name"), |
| 1087 | OPT_BOOLEAN('P', "power-only", &power_only, | 1068 | OPT_STRING('o', "output", &output_name, "file", "output file name"), |
| 1088 | "output power data only"), | 1069 | OPT_INTEGER('w', "width", &svg_page_width, "page width"), |
| 1070 | OPT_BOOLEAN('P', "power-only", &power_only, "output power data only"), | ||
| 1089 | OPT_CALLBACK('p', "process", NULL, "process", | 1071 | OPT_CALLBACK('p', "process", NULL, "process", |
| 1090 | "process selector. Pass a pid or process name.", | 1072 | "process selector. Pass a pid or process name.", |
| 1091 | parse_process), | 1073 | parse_process), |
| 1092 | OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory", | 1074 | OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory", |
| 1093 | "Look for files with symbols relative to this directory"), | 1075 | "Look for files with symbols relative to this directory"), |
| 1094 | OPT_END() | 1076 | OPT_END() |
| 1095 | }; | 1077 | }; |
| 1096 | 1078 | const char * const timechart_usage[] = { | |
| 1079 | "perf timechart [<options>] {record}", | ||
| 1080 | NULL | ||
| 1081 | }; | ||
| 1097 | 1082 | ||
| 1098 | int cmd_timechart(int argc, const char **argv, | ||
| 1099 | const char *prefix __maybe_unused) | ||
| 1100 | { | ||
| 1101 | argc = parse_options(argc, argv, options, timechart_usage, | 1083 | argc = parse_options(argc, argv, options, timechart_usage, |
| 1102 | PARSE_OPT_STOP_AT_NON_OPTION); | 1084 | PARSE_OPT_STOP_AT_NON_OPTION); |
| 1103 | 1085 | ||
| @@ -1110,5 +1092,5 @@ int cmd_timechart(int argc, const char **argv, | |||
| 1110 | 1092 | ||
| 1111 | setup_pager(); | 1093 | setup_pager(); |
| 1112 | 1094 | ||
| 1113 | return __cmd_timechart(); | 1095 | return __cmd_timechart(input_name, output_name); |
| 1114 | } | 1096 | } |
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index e434a16bb5ac..ff6db8086805 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c | |||
| @@ -316,7 +316,7 @@ static void perf_top__print_sym_table(struct perf_top *top) | |||
| 316 | hists__output_recalc_col_len(&top->sym_evsel->hists, | 316 | hists__output_recalc_col_len(&top->sym_evsel->hists, |
| 317 | top->winsize.ws_row - 3); | 317 | top->winsize.ws_row - 3); |
| 318 | putchar('\n'); | 318 | putchar('\n'); |
| 319 | hists__fprintf(&top->sym_evsel->hists, NULL, false, false, | 319 | hists__fprintf(&top->sym_evsel->hists, false, |
| 320 | top->winsize.ws_row - 4 - printed, win_width, stdout); | 320 | top->winsize.ws_row - 4 - printed, win_width, stdout); |
| 321 | } | 321 | } |
| 322 | 322 | ||
| @@ -1159,11 +1159,6 @@ setup: | |||
| 1159 | return 0; | 1159 | return 0; |
| 1160 | } | 1160 | } |
| 1161 | 1161 | ||
| 1162 | static const char * const top_usage[] = { | ||
| 1163 | "perf top [<options>]", | ||
| 1164 | NULL | ||
| 1165 | }; | ||
| 1166 | |||
| 1167 | int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) | 1162 | int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) |
| 1168 | { | 1163 | { |
| 1169 | struct perf_evsel *pos; | 1164 | struct perf_evsel *pos; |
| @@ -1250,6 +1245,10 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) | |||
| 1250 | OPT_STRING('u', "uid", &top.target.uid_str, "user", "user to profile"), | 1245 | OPT_STRING('u', "uid", &top.target.uid_str, "user", "user to profile"), |
| 1251 | OPT_END() | 1246 | OPT_END() |
| 1252 | }; | 1247 | }; |
| 1248 | const char * const top_usage[] = { | ||
| 1249 | "perf top [<options>]", | ||
| 1250 | NULL | ||
| 1251 | }; | ||
| 1253 | 1252 | ||
| 1254 | top.evlist = perf_evlist__new(NULL, NULL); | 1253 | top.evlist = perf_evlist__new(NULL, NULL); |
| 1255 | if (top.evlist == NULL) | 1254 | if (top.evlist == NULL) |
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index 8f113dab8bf1..dec8ced61fb0 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c | |||
| @@ -114,10 +114,85 @@ static size_t syscall__fprintf_args(struct syscall *sc, unsigned long *args, FIL | |||
| 114 | return printed; | 114 | return printed; |
| 115 | } | 115 | } |
| 116 | 116 | ||
| 117 | typedef int (*tracepoint_handler)(struct trace *trace, struct perf_evsel *evsel, | ||
| 118 | struct perf_sample *sample); | ||
| 119 | |||
| 120 | static struct syscall *trace__syscall_info(struct trace *trace, | ||
| 121 | struct perf_evsel *evsel, | ||
| 122 | struct perf_sample *sample) | ||
| 123 | { | ||
| 124 | int id = perf_evsel__intval(evsel, sample, "id"); | ||
| 125 | |||
| 126 | if (id < 0) { | ||
| 127 | printf("Invalid syscall %d id, skipping...\n", id); | ||
| 128 | return NULL; | ||
| 129 | } | ||
| 130 | |||
| 131 | if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL) && | ||
| 132 | trace__read_syscall_info(trace, id)) | ||
| 133 | goto out_cant_read; | ||
| 134 | |||
| 135 | if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL)) | ||
| 136 | goto out_cant_read; | ||
| 137 | |||
| 138 | return &trace->syscalls.table[id]; | ||
| 139 | |||
| 140 | out_cant_read: | ||
| 141 | printf("Problems reading syscall %d information\n", id); | ||
| 142 | return NULL; | ||
| 143 | } | ||
| 144 | |||
| 145 | static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel, | ||
| 146 | struct perf_sample *sample) | ||
| 147 | { | ||
| 148 | void *args; | ||
| 149 | struct syscall *sc = trace__syscall_info(trace, evsel, sample); | ||
| 150 | |||
| 151 | if (sc == NULL) | ||
| 152 | return -1; | ||
| 153 | |||
| 154 | args = perf_evsel__rawptr(evsel, sample, "args"); | ||
| 155 | if (args == NULL) { | ||
| 156 | printf("Problems reading syscall arguments\n"); | ||
| 157 | return -1; | ||
| 158 | } | ||
| 159 | |||
| 160 | printf("%s(", sc->name); | ||
| 161 | syscall__fprintf_args(sc, args, stdout); | ||
| 162 | |||
| 163 | return 0; | ||
| 164 | } | ||
| 165 | |||
| 166 | static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel, | ||
| 167 | struct perf_sample *sample) | ||
| 168 | { | ||
| 169 | int ret; | ||
| 170 | struct syscall *sc = trace__syscall_info(trace, evsel, sample); | ||
| 171 | |||
| 172 | if (sc == NULL) | ||
| 173 | return -1; | ||
| 174 | |||
| 175 | ret = perf_evsel__intval(evsel, sample, "ret"); | ||
| 176 | |||
| 177 | if (ret < 0 && sc->fmt && sc->fmt->errmsg) { | ||
| 178 | char bf[256]; | ||
| 179 | const char *emsg = strerror_r(-ret, bf, sizeof(bf)), | ||
| 180 | *e = audit_errno_to_name(-ret); | ||
| 181 | |||
| 182 | printf(") = -1 %s %s", e, emsg); | ||
| 183 | } else if (ret == 0 && sc->fmt && sc->fmt->timeout) | ||
| 184 | printf(") = 0 Timeout"); | ||
| 185 | else | ||
| 186 | printf(") = %d", ret); | ||
| 187 | |||
| 188 | putchar('\n'); | ||
| 189 | return 0; | ||
| 190 | } | ||
| 191 | |||
| 117 | static int trace__run(struct trace *trace) | 192 | static int trace__run(struct trace *trace) |
| 118 | { | 193 | { |
| 119 | struct perf_evlist *evlist = perf_evlist__new(NULL, NULL); | 194 | struct perf_evlist *evlist = perf_evlist__new(NULL, NULL); |
| 120 | struct perf_evsel *evsel, *evsel_enter, *evsel_exit; | 195 | struct perf_evsel *evsel; |
| 121 | int err = -1, i, nr_events = 0, before; | 196 | int err = -1, i, nr_events = 0, before; |
| 122 | 197 | ||
| 123 | if (evlist == NULL) { | 198 | if (evlist == NULL) { |
| @@ -125,22 +200,12 @@ static int trace__run(struct trace *trace) | |||
| 125 | goto out; | 200 | goto out; |
| 126 | } | 201 | } |
| 127 | 202 | ||
| 128 | evsel_enter = perf_evsel__newtp("raw_syscalls", "sys_enter", 0); | 203 | if (perf_evlist__add_newtp(evlist, "raw_syscalls", "sys_enter", trace__sys_enter) || |
| 129 | if (evsel_enter == NULL) { | 204 | perf_evlist__add_newtp(evlist, "raw_syscalls", "sys_exit", trace__sys_exit)) { |
| 130 | printf("Couldn't read the raw_syscalls:sys_enter tracepoint information!\n"); | 205 | printf("Couldn't read the raw_syscalls tracepoints information!\n"); |
| 131 | goto out_delete_evlist; | ||
| 132 | } | ||
| 133 | |||
| 134 | perf_evlist__add(evlist, evsel_enter); | ||
| 135 | |||
| 136 | evsel_exit = perf_evsel__newtp("raw_syscalls", "sys_exit", 1); | ||
| 137 | if (evsel_exit == NULL) { | ||
| 138 | printf("Couldn't read the raw_syscalls:sys_exit tracepoint information!\n"); | ||
| 139 | goto out_delete_evlist; | 206 | goto out_delete_evlist; |
| 140 | } | 207 | } |
| 141 | 208 | ||
| 142 | perf_evlist__add(evlist, evsel_exit); | ||
| 143 | |||
| 144 | err = perf_evlist__create_maps(evlist, &trace->opts.target); | 209 | err = perf_evlist__create_maps(evlist, &trace->opts.target); |
| 145 | if (err < 0) { | 210 | if (err < 0) { |
| 146 | printf("Problems parsing the target to trace, check your options!\n"); | 211 | printf("Problems parsing the target to trace, check your options!\n"); |
| @@ -170,9 +235,8 @@ again: | |||
| 170 | 235 | ||
| 171 | while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) { | 236 | while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) { |
| 172 | const u32 type = event->header.type; | 237 | const u32 type = event->header.type; |
| 173 | struct syscall *sc; | 238 | tracepoint_handler handler; |
| 174 | struct perf_sample sample; | 239 | struct perf_sample sample; |
| 175 | int id; | ||
| 176 | 240 | ||
| 177 | ++nr_events; | 241 | ++nr_events; |
| 178 | 242 | ||
| @@ -200,45 +264,11 @@ again: | |||
| 200 | continue; | 264 | continue; |
| 201 | } | 265 | } |
| 202 | 266 | ||
| 203 | id = perf_evsel__intval(evsel, &sample, "id"); | ||
| 204 | if (id < 0) { | ||
| 205 | printf("Invalid syscall %d id, skipping...\n", id); | ||
| 206 | continue; | ||
| 207 | } | ||
| 208 | |||
| 209 | if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL) && | ||
| 210 | trace__read_syscall_info(trace, id)) | ||
| 211 | continue; | ||
| 212 | |||
| 213 | if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL)) | ||
| 214 | continue; | ||
| 215 | |||
| 216 | sc = &trace->syscalls.table[id]; | ||
| 217 | |||
| 218 | if (evlist->threads->map[0] == -1 || evlist->threads->nr > 1) | 267 | if (evlist->threads->map[0] == -1 || evlist->threads->nr > 1) |
| 219 | printf("%d ", sample.tid); | 268 | printf("%d ", sample.tid); |
| 220 | 269 | ||
| 221 | if (evsel == evsel_enter) { | 270 | handler = evsel->handler.func; |
| 222 | void *args = perf_evsel__rawptr(evsel, &sample, "args"); | 271 | handler(trace, evsel, &sample); |
| 223 | |||
| 224 | printf("%s(", sc->name); | ||
| 225 | syscall__fprintf_args(sc, args, stdout); | ||
| 226 | } else if (evsel == evsel_exit) { | ||
| 227 | int ret = perf_evsel__intval(evsel, &sample, "ret"); | ||
| 228 | |||
| 229 | if (ret < 0 && sc->fmt && sc->fmt->errmsg) { | ||
| 230 | char bf[256]; | ||
| 231 | const char *emsg = strerror_r(-ret, bf, sizeof(bf)), | ||
| 232 | *e = audit_errno_to_name(-ret); | ||
| 233 | |||
| 234 | printf(") = -1 %s %s", e, emsg); | ||
| 235 | } else if (ret == 0 && sc->fmt && sc->fmt->timeout) | ||
| 236 | printf(") = 0 Timeout"); | ||
| 237 | else | ||
| 238 | printf(") = %d", ret); | ||
| 239 | |||
| 240 | putchar('\n'); | ||
| 241 | } | ||
| 242 | } | 272 | } |
| 243 | } | 273 | } |
| 244 | 274 | ||
diff --git a/tools/perf/perf.c b/tools/perf/perf.c index fc2f770e3027..6d50eb0b4251 100644 --- a/tools/perf/perf.c +++ b/tools/perf/perf.c | |||
| @@ -48,14 +48,14 @@ static struct cmd_struct commands[] = { | |||
| 48 | { "version", cmd_version, 0 }, | 48 | { "version", cmd_version, 0 }, |
| 49 | { "script", cmd_script, 0 }, | 49 | { "script", cmd_script, 0 }, |
| 50 | { "sched", cmd_sched, 0 }, | 50 | { "sched", cmd_sched, 0 }, |
| 51 | #ifndef NO_LIBELF_SUPPORT | 51 | #ifdef LIBELF_SUPPORT |
| 52 | { "probe", cmd_probe, 0 }, | 52 | { "probe", cmd_probe, 0 }, |
| 53 | #endif | 53 | #endif |
| 54 | { "kmem", cmd_kmem, 0 }, | 54 | { "kmem", cmd_kmem, 0 }, |
| 55 | { "lock", cmd_lock, 0 }, | 55 | { "lock", cmd_lock, 0 }, |
| 56 | { "kvm", cmd_kvm, 0 }, | 56 | { "kvm", cmd_kvm, 0 }, |
| 57 | { "test", cmd_test, 0 }, | 57 | { "test", cmd_test, 0 }, |
| 58 | #ifndef NO_LIBAUDIT_SUPPORT | 58 | #ifdef LIBAUDIT_SUPPORT |
| 59 | { "trace", cmd_trace, 0 }, | 59 | { "trace", cmd_trace, 0 }, |
| 60 | #endif | 60 | #endif |
| 61 | { "inject", cmd_inject, 0 }, | 61 | { "inject", cmd_inject, 0 }, |
diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c index a21f40bebbac..0568536ecf67 100644 --- a/tools/perf/ui/browsers/hists.c +++ b/tools/perf/ui/browsers/hists.c | |||
| @@ -569,7 +569,8 @@ static int hist_browser__show_callchain(struct hist_browser *browser, | |||
| 569 | static int hist_browser__hpp_color_ ## _name(struct perf_hpp *hpp, \ | 569 | static int hist_browser__hpp_color_ ## _name(struct perf_hpp *hpp, \ |
| 570 | struct hist_entry *he) \ | 570 | struct hist_entry *he) \ |
| 571 | { \ | 571 | { \ |
| 572 | double percent = 100.0 * he->_field / hpp->total_period; \ | 572 | struct hists *hists = he->hists; \ |
| 573 | double percent = 100.0 * he->stat._field / hists->stats.total_period; \ | ||
| 573 | *(double *)hpp->ptr = percent; \ | 574 | *(double *)hpp->ptr = percent; \ |
| 574 | return scnprintf(hpp->buf, hpp->size, "%6.2f%%", percent); \ | 575 | return scnprintf(hpp->buf, hpp->size, "%6.2f%%", percent); \ |
| 575 | } | 576 | } |
| @@ -584,7 +585,7 @@ HPP__COLOR_FN(overhead_guest_us, period_guest_us) | |||
| 584 | 585 | ||
| 585 | void hist_browser__init_hpp(void) | 586 | void hist_browser__init_hpp(void) |
| 586 | { | 587 | { |
| 587 | perf_hpp__init(false, false); | 588 | perf_hpp__init(); |
| 588 | 589 | ||
| 589 | perf_hpp__format[PERF_HPP__OVERHEAD].color = | 590 | perf_hpp__format[PERF_HPP__OVERHEAD].color = |
| 590 | hist_browser__hpp_color_overhead; | 591 | hist_browser__hpp_color_overhead; |
| @@ -624,7 +625,6 @@ static int hist_browser__show_entry(struct hist_browser *browser, | |||
| 624 | struct perf_hpp hpp = { | 625 | struct perf_hpp hpp = { |
| 625 | .buf = s, | 626 | .buf = s, |
| 626 | .size = sizeof(s), | 627 | .size = sizeof(s), |
| 627 | .total_period = browser->hists->stats.total_period, | ||
| 628 | }; | 628 | }; |
| 629 | 629 | ||
| 630 | ui_browser__gotorc(&browser->b, row, 0); | 630 | ui_browser__gotorc(&browser->b, row, 0); |
| @@ -982,7 +982,7 @@ static int hist_browser__fprintf_entry(struct hist_browser *browser, | |||
| 982 | folded_sign = hist_entry__folded(he); | 982 | folded_sign = hist_entry__folded(he); |
| 983 | 983 | ||
| 984 | hist_entry__sort_snprintf(he, s, sizeof(s), browser->hists); | 984 | hist_entry__sort_snprintf(he, s, sizeof(s), browser->hists); |
| 985 | percent = (he->period * 100.0) / browser->hists->stats.total_period; | 985 | percent = (he->stat.period * 100.0) / browser->hists->stats.total_period; |
| 986 | 986 | ||
| 987 | if (symbol_conf.use_callchain) | 987 | if (symbol_conf.use_callchain) |
| 988 | printed += fprintf(fp, "%c ", folded_sign); | 988 | printed += fprintf(fp, "%c ", folded_sign); |
| @@ -990,10 +990,10 @@ static int hist_browser__fprintf_entry(struct hist_browser *browser, | |||
| 990 | printed += fprintf(fp, " %5.2f%%", percent); | 990 | printed += fprintf(fp, " %5.2f%%", percent); |
| 991 | 991 | ||
| 992 | if (symbol_conf.show_nr_samples) | 992 | if (symbol_conf.show_nr_samples) |
| 993 | printed += fprintf(fp, " %11u", he->nr_events); | 993 | printed += fprintf(fp, " %11u", he->stat.nr_events); |
| 994 | 994 | ||
| 995 | if (symbol_conf.show_total_period) | 995 | if (symbol_conf.show_total_period) |
| 996 | printed += fprintf(fp, " %12" PRIu64, he->period); | 996 | printed += fprintf(fp, " %12" PRIu64, he->stat.period); |
| 997 | 997 | ||
| 998 | printed += fprintf(fp, "%s\n", rtrim(s)); | 998 | printed += fprintf(fp, "%s\n", rtrim(s)); |
| 999 | 999 | ||
diff --git a/tools/perf/ui/gtk/browser.c b/tools/perf/ui/gtk/browser.c index 7ff99ec1d95e..4125c6284114 100644 --- a/tools/perf/ui/gtk/browser.c +++ b/tools/perf/ui/gtk/browser.c | |||
| @@ -49,7 +49,8 @@ static const char *perf_gtk__get_percent_color(double percent) | |||
| 49 | static int perf_gtk__hpp_color_ ## _name(struct perf_hpp *hpp, \ | 49 | static int perf_gtk__hpp_color_ ## _name(struct perf_hpp *hpp, \ |
| 50 | struct hist_entry *he) \ | 50 | struct hist_entry *he) \ |
| 51 | { \ | 51 | { \ |
| 52 | double percent = 100.0 * he->_field / hpp->total_period; \ | 52 | struct hists *hists = he->hists; \ |
| 53 | double percent = 100.0 * he->stat._field / hists->stats.total_period; \ | ||
| 53 | const char *markup; \ | 54 | const char *markup; \ |
| 54 | int ret = 0; \ | 55 | int ret = 0; \ |
| 55 | \ | 56 | \ |
| @@ -73,7 +74,7 @@ HPP__COLOR_FN(overhead_guest_us, period_guest_us) | |||
| 73 | 74 | ||
| 74 | void perf_gtk__init_hpp(void) | 75 | void perf_gtk__init_hpp(void) |
| 75 | { | 76 | { |
| 76 | perf_hpp__init(false, false); | 77 | perf_hpp__init(); |
| 77 | 78 | ||
| 78 | perf_hpp__format[PERF_HPP__OVERHEAD].color = | 79 | perf_hpp__format[PERF_HPP__OVERHEAD].color = |
| 79 | perf_gtk__hpp_color_overhead; | 80 | perf_gtk__hpp_color_overhead; |
| @@ -102,7 +103,6 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists) | |||
| 102 | struct perf_hpp hpp = { | 103 | struct perf_hpp hpp = { |
| 103 | .buf = s, | 104 | .buf = s, |
| 104 | .size = sizeof(s), | 105 | .size = sizeof(s), |
| 105 | .total_period = hists->stats.total_period, | ||
| 106 | }; | 106 | }; |
| 107 | 107 | ||
| 108 | nr_cols = 0; | 108 | nr_cols = 0; |
diff --git a/tools/perf/ui/gtk/util.c b/tools/perf/ui/gtk/util.c index 8aada5b3c04c..ccb046aac98b 100644 --- a/tools/perf/ui/gtk/util.c +++ b/tools/perf/ui/gtk/util.c | |||
| @@ -116,7 +116,7 @@ struct perf_error_ops perf_gtk_eops = { | |||
| 116 | * FIXME: Functions below should be implemented properly. | 116 | * FIXME: Functions below should be implemented properly. |
| 117 | * For now, just add stubs for NO_NEWT=1 build. | 117 | * For now, just add stubs for NO_NEWT=1 build. |
| 118 | */ | 118 | */ |
| 119 | #ifdef NO_NEWT_SUPPORT | 119 | #ifndef NEWT_SUPPORT |
| 120 | void ui_progress__update(u64 curr __maybe_unused, u64 total __maybe_unused, | 120 | void ui_progress__update(u64 curr __maybe_unused, u64 total __maybe_unused, |
| 121 | const char *title __maybe_unused) | 121 | const char *title __maybe_unused) |
| 122 | { | 122 | { |
diff --git a/tools/perf/ui/helpline.h b/tools/perf/ui/helpline.h index 2b667ee454c3..baa28a4d16b9 100644 --- a/tools/perf/ui/helpline.h +++ b/tools/perf/ui/helpline.h | |||
| @@ -23,25 +23,25 @@ void ui_helpline__puts(const char *msg); | |||
| 23 | 23 | ||
| 24 | extern char ui_helpline__current[512]; | 24 | extern char ui_helpline__current[512]; |
| 25 | 25 | ||
| 26 | #ifdef NO_NEWT_SUPPORT | 26 | #ifdef NEWT_SUPPORT |
| 27 | extern char ui_helpline__last_msg[]; | ||
| 28 | int ui_helpline__show_help(const char *format, va_list ap); | ||
| 29 | #else | ||
| 27 | static inline int ui_helpline__show_help(const char *format __maybe_unused, | 30 | static inline int ui_helpline__show_help(const char *format __maybe_unused, |
| 28 | va_list ap __maybe_unused) | 31 | va_list ap __maybe_unused) |
| 29 | { | 32 | { |
| 30 | return 0; | 33 | return 0; |
| 31 | } | 34 | } |
| 32 | #else | 35 | #endif /* NEWT_SUPPORT */ |
| 33 | extern char ui_helpline__last_msg[]; | ||
| 34 | int ui_helpline__show_help(const char *format, va_list ap); | ||
| 35 | #endif /* NO_NEWT_SUPPORT */ | ||
| 36 | 36 | ||
| 37 | #ifdef NO_GTK2_SUPPORT | 37 | #ifdef GTK2_SUPPORT |
| 38 | int perf_gtk__show_helpline(const char *format, va_list ap); | ||
| 39 | #else | ||
| 38 | static inline int perf_gtk__show_helpline(const char *format __maybe_unused, | 40 | static inline int perf_gtk__show_helpline(const char *format __maybe_unused, |
| 39 | va_list ap __maybe_unused) | 41 | va_list ap __maybe_unused) |
| 40 | { | 42 | { |
| 41 | return 0; | 43 | return 0; |
| 42 | } | 44 | } |
| 43 | #else | 45 | #endif /* GTK2_SUPPORT */ |
| 44 | int perf_gtk__show_helpline(const char *format, va_list ap); | ||
| 45 | #endif /* NO_GTK2_SUPPORT */ | ||
| 46 | 46 | ||
| 47 | #endif /* _PERF_UI_HELPLINE_H_ */ | 47 | #endif /* _PERF_UI_HELPLINE_H_ */ |
diff --git a/tools/perf/ui/hist.c b/tools/perf/ui/hist.c index e3f8cd46e7d7..f5a1e4f65263 100644 --- a/tools/perf/ui/hist.c +++ b/tools/perf/ui/hist.c | |||
| @@ -8,9 +8,7 @@ | |||
| 8 | /* hist period print (hpp) functions */ | 8 | /* hist period print (hpp) functions */ |
| 9 | static int hpp__header_overhead(struct perf_hpp *hpp) | 9 | static int hpp__header_overhead(struct perf_hpp *hpp) |
| 10 | { | 10 | { |
| 11 | const char *fmt = hpp->ptr ? "Baseline" : "Overhead"; | 11 | return scnprintf(hpp->buf, hpp->size, "Overhead"); |
| 12 | |||
| 13 | return scnprintf(hpp->buf, hpp->size, fmt); | ||
| 14 | } | 12 | } |
| 15 | 13 | ||
| 16 | static int hpp__width_overhead(struct perf_hpp *hpp __maybe_unused) | 14 | static int hpp__width_overhead(struct perf_hpp *hpp __maybe_unused) |
| @@ -20,38 +18,18 @@ static int hpp__width_overhead(struct perf_hpp *hpp __maybe_unused) | |||
| 20 | 18 | ||
| 21 | static int hpp__color_overhead(struct perf_hpp *hpp, struct hist_entry *he) | 19 | static int hpp__color_overhead(struct perf_hpp *hpp, struct hist_entry *he) |
| 22 | { | 20 | { |
| 23 | double percent = 100.0 * he->period / hpp->total_period; | 21 | struct hists *hists = he->hists; |
| 24 | 22 | double percent = 100.0 * he->stat.period / hists->stats.total_period; | |
| 25 | if (hpp->ptr) { | ||
| 26 | struct hists *old_hists = hpp->ptr; | ||
| 27 | u64 total_period = old_hists->stats.total_period; | ||
| 28 | u64 base_period = he->pair ? he->pair->period : 0; | ||
| 29 | |||
| 30 | if (total_period) | ||
| 31 | percent = 100.0 * base_period / total_period; | ||
| 32 | else | ||
| 33 | percent = 0.0; | ||
| 34 | } | ||
| 35 | 23 | ||
| 36 | return percent_color_snprintf(hpp->buf, hpp->size, " %6.2f%%", percent); | 24 | return percent_color_snprintf(hpp->buf, hpp->size, " %6.2f%%", percent); |
| 37 | } | 25 | } |
| 38 | 26 | ||
| 39 | static int hpp__entry_overhead(struct perf_hpp *hpp, struct hist_entry *he) | 27 | static int hpp__entry_overhead(struct perf_hpp *hpp, struct hist_entry *he) |
| 40 | { | 28 | { |
| 41 | double percent = 100.0 * he->period / hpp->total_period; | 29 | struct hists *hists = he->hists; |
| 30 | double percent = 100.0 * he->stat.period / hists->stats.total_period; | ||
| 42 | const char *fmt = symbol_conf.field_sep ? "%.2f" : " %6.2f%%"; | 31 | const char *fmt = symbol_conf.field_sep ? "%.2f" : " %6.2f%%"; |
| 43 | 32 | ||
| 44 | if (hpp->ptr) { | ||
| 45 | struct hists *old_hists = hpp->ptr; | ||
| 46 | u64 total_period = old_hists->stats.total_period; | ||
| 47 | u64 base_period = he->pair ? he->pair->period : 0; | ||
| 48 | |||
| 49 | if (total_period) | ||
| 50 | percent = 100.0 * base_period / total_period; | ||
| 51 | else | ||
| 52 | percent = 0.0; | ||
| 53 | } | ||
| 54 | |||
| 55 | return scnprintf(hpp->buf, hpp->size, fmt, percent); | 33 | return scnprintf(hpp->buf, hpp->size, fmt, percent); |
| 56 | } | 34 | } |
| 57 | 35 | ||
| @@ -69,13 +47,16 @@ static int hpp__width_overhead_sys(struct perf_hpp *hpp __maybe_unused) | |||
| 69 | 47 | ||
| 70 | static int hpp__color_overhead_sys(struct perf_hpp *hpp, struct hist_entry *he) | 48 | static int hpp__color_overhead_sys(struct perf_hpp *hpp, struct hist_entry *he) |
| 71 | { | 49 | { |
| 72 | double percent = 100.0 * he->period_sys / hpp->total_period; | 50 | struct hists *hists = he->hists; |
| 51 | double percent = 100.0 * he->stat.period_sys / hists->stats.total_period; | ||
| 52 | |||
| 73 | return percent_color_snprintf(hpp->buf, hpp->size, "%6.2f%%", percent); | 53 | return percent_color_snprintf(hpp->buf, hpp->size, "%6.2f%%", percent); |
| 74 | } | 54 | } |
| 75 | 55 | ||
| 76 | static int hpp__entry_overhead_sys(struct perf_hpp *hpp, struct hist_entry *he) | 56 | static int hpp__entry_overhead_sys(struct perf_hpp *hpp, struct hist_entry *he) |
| 77 | { | 57 | { |
| 78 | double percent = 100.0 * he->period_sys / hpp->total_period; | 58 | struct hists *hists = he->hists; |
| 59 | double percent = 100.0 * he->stat.period_sys / hists->stats.total_period; | ||
| 79 | const char *fmt = symbol_conf.field_sep ? "%.2f" : "%6.2f%%"; | 60 | const char *fmt = symbol_conf.field_sep ? "%.2f" : "%6.2f%%"; |
| 80 | 61 | ||
| 81 | return scnprintf(hpp->buf, hpp->size, fmt, percent); | 62 | return scnprintf(hpp->buf, hpp->size, fmt, percent); |
| @@ -95,13 +76,16 @@ static int hpp__width_overhead_us(struct perf_hpp *hpp __maybe_unused) | |||
| 95 | 76 | ||
| 96 | static int hpp__color_overhead_us(struct perf_hpp *hpp, struct hist_entry *he) | 77 | static int hpp__color_overhead_us(struct perf_hpp *hpp, struct hist_entry *he) |
| 97 | { | 78 | { |
| 98 | double percent = 100.0 * he->period_us / hpp->total_period; | 79 | struct hists *hists = he->hists; |
| 80 | double percent = 100.0 * he->stat.period_us / hists->stats.total_period; | ||
| 81 | |||
| 99 | return percent_color_snprintf(hpp->buf, hpp->size, "%6.2f%%", percent); | 82 | return percent_color_snprintf(hpp->buf, hpp->size, "%6.2f%%", percent); |
| 100 | } | 83 | } |
| 101 | 84 | ||
| 102 | static int hpp__entry_overhead_us(struct perf_hpp *hpp, struct hist_entry *he) | 85 | static int hpp__entry_overhead_us(struct perf_hpp *hpp, struct hist_entry *he) |
| 103 | { | 86 | { |
| 104 | double percent = 100.0 * he->period_us / hpp->total_period; | 87 | struct hists *hists = he->hists; |
| 88 | double percent = 100.0 * he->stat.period_us / hists->stats.total_period; | ||
| 105 | const char *fmt = symbol_conf.field_sep ? "%.2f" : "%6.2f%%"; | 89 | const char *fmt = symbol_conf.field_sep ? "%.2f" : "%6.2f%%"; |
| 106 | 90 | ||
| 107 | return scnprintf(hpp->buf, hpp->size, fmt, percent); | 91 | return scnprintf(hpp->buf, hpp->size, fmt, percent); |
| @@ -120,14 +104,17 @@ static int hpp__width_overhead_guest_sys(struct perf_hpp *hpp __maybe_unused) | |||
| 120 | static int hpp__color_overhead_guest_sys(struct perf_hpp *hpp, | 104 | static int hpp__color_overhead_guest_sys(struct perf_hpp *hpp, |
| 121 | struct hist_entry *he) | 105 | struct hist_entry *he) |
| 122 | { | 106 | { |
| 123 | double percent = 100.0 * he->period_guest_sys / hpp->total_period; | 107 | struct hists *hists = he->hists; |
| 108 | double percent = 100.0 * he->stat.period_guest_sys / hists->stats.total_period; | ||
| 109 | |||
| 124 | return percent_color_snprintf(hpp->buf, hpp->size, " %6.2f%% ", percent); | 110 | return percent_color_snprintf(hpp->buf, hpp->size, " %6.2f%% ", percent); |
| 125 | } | 111 | } |
| 126 | 112 | ||
| 127 | static int hpp__entry_overhead_guest_sys(struct perf_hpp *hpp, | 113 | static int hpp__entry_overhead_guest_sys(struct perf_hpp *hpp, |
| 128 | struct hist_entry *he) | 114 | struct hist_entry *he) |
| 129 | { | 115 | { |
| 130 | double percent = 100.0 * he->period_guest_sys / hpp->total_period; | 116 | struct hists *hists = he->hists; |
| 117 | double percent = 100.0 * he->stat.period_guest_sys / hists->stats.total_period; | ||
| 131 | const char *fmt = symbol_conf.field_sep ? "%.2f" : " %6.2f%% "; | 118 | const char *fmt = symbol_conf.field_sep ? "%.2f" : " %6.2f%% "; |
| 132 | 119 | ||
| 133 | return scnprintf(hpp->buf, hpp->size, fmt, percent); | 120 | return scnprintf(hpp->buf, hpp->size, fmt, percent); |
| @@ -146,19 +133,63 @@ static int hpp__width_overhead_guest_us(struct perf_hpp *hpp __maybe_unused) | |||
| 146 | static int hpp__color_overhead_guest_us(struct perf_hpp *hpp, | 133 | static int hpp__color_overhead_guest_us(struct perf_hpp *hpp, |
| 147 | struct hist_entry *he) | 134 | struct hist_entry *he) |
| 148 | { | 135 | { |
| 149 | double percent = 100.0 * he->period_guest_us / hpp->total_period; | 136 | struct hists *hists = he->hists; |
| 137 | double percent = 100.0 * he->stat.period_guest_us / hists->stats.total_period; | ||
| 138 | |||
| 150 | return percent_color_snprintf(hpp->buf, hpp->size, " %6.2f%% ", percent); | 139 | return percent_color_snprintf(hpp->buf, hpp->size, " %6.2f%% ", percent); |
| 151 | } | 140 | } |
| 152 | 141 | ||
| 153 | static int hpp__entry_overhead_guest_us(struct perf_hpp *hpp, | 142 | static int hpp__entry_overhead_guest_us(struct perf_hpp *hpp, |
| 154 | struct hist_entry *he) | 143 | struct hist_entry *he) |
| 155 | { | 144 | { |
| 156 | double percent = 100.0 * he->period_guest_us / hpp->total_period; | 145 | struct hists *hists = he->hists; |
| 146 | double percent = 100.0 * he->stat.period_guest_us / hists->stats.total_period; | ||
| 157 | const char *fmt = symbol_conf.field_sep ? "%.2f" : " %6.2f%% "; | 147 | const char *fmt = symbol_conf.field_sep ? "%.2f" : " %6.2f%% "; |
| 158 | 148 | ||
| 159 | return scnprintf(hpp->buf, hpp->size, fmt, percent); | 149 | return scnprintf(hpp->buf, hpp->size, fmt, percent); |
| 160 | } | 150 | } |
| 161 | 151 | ||
| 152 | static int hpp__header_baseline(struct perf_hpp *hpp) | ||
| 153 | { | ||
| 154 | return scnprintf(hpp->buf, hpp->size, "Baseline"); | ||
| 155 | } | ||
| 156 | |||
| 157 | static int hpp__width_baseline(struct perf_hpp *hpp __maybe_unused) | ||
| 158 | { | ||
| 159 | return 8; | ||
| 160 | } | ||
| 161 | |||
| 162 | static double baseline_percent(struct hist_entry *he) | ||
| 163 | { | ||
| 164 | struct hist_entry *pair = he->pair; | ||
| 165 | struct hists *pair_hists = pair ? pair->hists : NULL; | ||
| 166 | double percent = 0.0; | ||
| 167 | |||
| 168 | if (pair) { | ||
| 169 | u64 total_period = pair_hists->stats.total_period; | ||
| 170 | u64 base_period = pair->stat.period; | ||
| 171 | |||
| 172 | percent = 100.0 * base_period / total_period; | ||
| 173 | } | ||
| 174 | |||
| 175 | return percent; | ||
| 176 | } | ||
| 177 | |||
| 178 | static int hpp__color_baseline(struct perf_hpp *hpp, struct hist_entry *he) | ||
| 179 | { | ||
| 180 | double percent = baseline_percent(he); | ||
| 181 | |||
| 182 | return percent_color_snprintf(hpp->buf, hpp->size, " %6.2f%%", percent); | ||
| 183 | } | ||
| 184 | |||
| 185 | static int hpp__entry_baseline(struct perf_hpp *hpp, struct hist_entry *he) | ||
| 186 | { | ||
| 187 | double percent = baseline_percent(he); | ||
| 188 | const char *fmt = symbol_conf.field_sep ? "%.2f" : " %6.2f%%"; | ||
| 189 | |||
| 190 | return scnprintf(hpp->buf, hpp->size, fmt, percent); | ||
| 191 | } | ||
| 192 | |||
| 162 | static int hpp__header_samples(struct perf_hpp *hpp) | 193 | static int hpp__header_samples(struct perf_hpp *hpp) |
| 163 | { | 194 | { |
| 164 | const char *fmt = symbol_conf.field_sep ? "%s" : "%11s"; | 195 | const char *fmt = symbol_conf.field_sep ? "%s" : "%11s"; |
| @@ -175,7 +206,7 @@ static int hpp__entry_samples(struct perf_hpp *hpp, struct hist_entry *he) | |||
| 175 | { | 206 | { |
| 176 | const char *fmt = symbol_conf.field_sep ? "%" PRIu64 : "%11" PRIu64; | 207 | const char *fmt = symbol_conf.field_sep ? "%" PRIu64 : "%11" PRIu64; |
| 177 | 208 | ||
| 178 | return scnprintf(hpp->buf, hpp->size, fmt, he->nr_events); | 209 | return scnprintf(hpp->buf, hpp->size, fmt, he->stat.nr_events); |
| 179 | } | 210 | } |
| 180 | 211 | ||
| 181 | static int hpp__header_period(struct perf_hpp *hpp) | 212 | static int hpp__header_period(struct perf_hpp *hpp) |
| @@ -194,7 +225,7 @@ static int hpp__entry_period(struct perf_hpp *hpp, struct hist_entry *he) | |||
| 194 | { | 225 | { |
| 195 | const char *fmt = symbol_conf.field_sep ? "%" PRIu64 : "%12" PRIu64; | 226 | const char *fmt = symbol_conf.field_sep ? "%" PRIu64 : "%12" PRIu64; |
| 196 | 227 | ||
| 197 | return scnprintf(hpp->buf, hpp->size, fmt, he->period); | 228 | return scnprintf(hpp->buf, hpp->size, fmt, he->stat.period); |
| 198 | } | 229 | } |
| 199 | 230 | ||
| 200 | static int hpp__header_delta(struct perf_hpp *hpp) | 231 | static int hpp__header_delta(struct perf_hpp *hpp) |
| @@ -211,20 +242,22 @@ static int hpp__width_delta(struct perf_hpp *hpp __maybe_unused) | |||
| 211 | 242 | ||
| 212 | static int hpp__entry_delta(struct perf_hpp *hpp, struct hist_entry *he) | 243 | static int hpp__entry_delta(struct perf_hpp *hpp, struct hist_entry *he) |
| 213 | { | 244 | { |
| 214 | struct hists *pair_hists = hpp->ptr; | 245 | struct hist_entry *pair = he->pair; |
| 246 | struct hists *pair_hists = pair ? pair->hists : NULL; | ||
| 247 | struct hists *hists = he->hists; | ||
| 215 | u64 old_total, new_total; | 248 | u64 old_total, new_total; |
| 216 | double old_percent = 0, new_percent = 0; | 249 | double old_percent = 0, new_percent = 0; |
| 217 | double diff; | 250 | double diff; |
| 218 | const char *fmt = symbol_conf.field_sep ? "%s" : "%7.7s"; | 251 | const char *fmt = symbol_conf.field_sep ? "%s" : "%7.7s"; |
| 219 | char buf[32] = " "; | 252 | char buf[32] = " "; |
| 220 | 253 | ||
| 221 | old_total = pair_hists->stats.total_period; | 254 | old_total = pair_hists ? pair_hists->stats.total_period : 0; |
| 222 | if (old_total > 0 && he->pair) | 255 | if (old_total > 0 && pair) |
| 223 | old_percent = 100.0 * he->pair->period / old_total; | 256 | old_percent = 100.0 * pair->stat.period / old_total; |
| 224 | 257 | ||
| 225 | new_total = hpp->total_period; | 258 | new_total = hists->stats.total_period; |
| 226 | if (new_total > 0) | 259 | if (new_total > 0) |
| 227 | new_percent = 100.0 * he->period / new_total; | 260 | new_percent = 100.0 * he->stat.period / new_total; |
| 228 | 261 | ||
| 229 | diff = new_percent - old_percent; | 262 | diff = new_percent - old_percent; |
| 230 | if (fabs(diff) >= 0.01) | 263 | if (fabs(diff) >= 0.01) |
| @@ -244,13 +277,15 @@ static int hpp__width_displ(struct perf_hpp *hpp __maybe_unused) | |||
| 244 | } | 277 | } |
| 245 | 278 | ||
| 246 | static int hpp__entry_displ(struct perf_hpp *hpp, | 279 | static int hpp__entry_displ(struct perf_hpp *hpp, |
| 247 | struct hist_entry *he __maybe_unused) | 280 | struct hist_entry *he) |
| 248 | { | 281 | { |
| 282 | struct hist_entry *pair = he->pair; | ||
| 283 | long displacement = pair ? pair->position - he->position : 0; | ||
| 249 | const char *fmt = symbol_conf.field_sep ? "%s" : "%6.6s"; | 284 | const char *fmt = symbol_conf.field_sep ? "%s" : "%6.6s"; |
| 250 | char buf[32] = " "; | 285 | char buf[32] = " "; |
| 251 | 286 | ||
| 252 | if (hpp->displacement) | 287 | if (displacement) |
| 253 | scnprintf(buf, sizeof(buf), "%+4ld", hpp->displacement); | 288 | scnprintf(buf, sizeof(buf), "%+4ld", displacement); |
| 254 | 289 | ||
| 255 | return scnprintf(hpp->buf, hpp->size, fmt, buf); | 290 | return scnprintf(hpp->buf, hpp->size, fmt, buf); |
| 256 | } | 291 | } |
| @@ -267,6 +302,7 @@ static int hpp__entry_displ(struct perf_hpp *hpp, | |||
| 267 | .entry = hpp__entry_ ## _name | 302 | .entry = hpp__entry_ ## _name |
| 268 | 303 | ||
| 269 | struct perf_hpp_fmt perf_hpp__format[] = { | 304 | struct perf_hpp_fmt perf_hpp__format[] = { |
| 305 | { .cond = false, HPP__COLOR_PRINT_FNS(baseline) }, | ||
| 270 | { .cond = true, HPP__COLOR_PRINT_FNS(overhead) }, | 306 | { .cond = true, HPP__COLOR_PRINT_FNS(overhead) }, |
| 271 | { .cond = false, HPP__COLOR_PRINT_FNS(overhead_sys) }, | 307 | { .cond = false, HPP__COLOR_PRINT_FNS(overhead_sys) }, |
| 272 | { .cond = false, HPP__COLOR_PRINT_FNS(overhead_us) }, | 308 | { .cond = false, HPP__COLOR_PRINT_FNS(overhead_us) }, |
| @@ -281,7 +317,7 @@ struct perf_hpp_fmt perf_hpp__format[] = { | |||
| 281 | #undef HPP__COLOR_PRINT_FNS | 317 | #undef HPP__COLOR_PRINT_FNS |
| 282 | #undef HPP__PRINT_FNS | 318 | #undef HPP__PRINT_FNS |
| 283 | 319 | ||
| 284 | void perf_hpp__init(bool need_pair, bool show_displacement) | 320 | void perf_hpp__init(void) |
| 285 | { | 321 | { |
| 286 | if (symbol_conf.show_cpu_utilization) { | 322 | if (symbol_conf.show_cpu_utilization) { |
| 287 | perf_hpp__format[PERF_HPP__OVERHEAD_SYS].cond = true; | 323 | perf_hpp__format[PERF_HPP__OVERHEAD_SYS].cond = true; |
| @@ -298,13 +334,12 @@ void perf_hpp__init(bool need_pair, bool show_displacement) | |||
| 298 | 334 | ||
| 299 | if (symbol_conf.show_total_period) | 335 | if (symbol_conf.show_total_period) |
| 300 | perf_hpp__format[PERF_HPP__PERIOD].cond = true; | 336 | perf_hpp__format[PERF_HPP__PERIOD].cond = true; |
| 337 | } | ||
| 301 | 338 | ||
| 302 | if (need_pair) { | 339 | void perf_hpp__column_enable(unsigned col, bool enable) |
| 303 | perf_hpp__format[PERF_HPP__DELTA].cond = true; | 340 | { |
| 304 | 341 | BUG_ON(col >= PERF_HPP__MAX_INDEX); | |
| 305 | if (show_displacement) | 342 | perf_hpp__format[col].cond = enable; |
| 306 | perf_hpp__format[PERF_HPP__DISPL].cond = true; | ||
| 307 | } | ||
| 308 | } | 343 | } |
| 309 | 344 | ||
| 310 | static inline void advance_hpp(struct perf_hpp *hpp, int inc) | 345 | static inline void advance_hpp(struct perf_hpp *hpp, int inc) |
| @@ -319,6 +354,7 @@ int hist_entry__period_snprintf(struct perf_hpp *hpp, struct hist_entry *he, | |||
| 319 | const char *sep = symbol_conf.field_sep; | 354 | const char *sep = symbol_conf.field_sep; |
| 320 | char *start = hpp->buf; | 355 | char *start = hpp->buf; |
| 321 | int i, ret; | 356 | int i, ret; |
| 357 | bool first = true; | ||
| 322 | 358 | ||
| 323 | if (symbol_conf.exclude_other && !he->parent) | 359 | if (symbol_conf.exclude_other && !he->parent) |
| 324 | return 0; | 360 | return 0; |
| @@ -327,9 +363,10 @@ int hist_entry__period_snprintf(struct perf_hpp *hpp, struct hist_entry *he, | |||
| 327 | if (!perf_hpp__format[i].cond) | 363 | if (!perf_hpp__format[i].cond) |
| 328 | continue; | 364 | continue; |
| 329 | 365 | ||
| 330 | if (!sep || i > 0) { | 366 | if (!sep || !first) { |
| 331 | ret = scnprintf(hpp->buf, hpp->size, "%s", sep ?: " "); | 367 | ret = scnprintf(hpp->buf, hpp->size, "%s", sep ?: " "); |
| 332 | advance_hpp(hpp, ret); | 368 | advance_hpp(hpp, ret); |
| 369 | first = false; | ||
| 333 | } | 370 | } |
| 334 | 371 | ||
| 335 | if (color && perf_hpp__format[i].color) | 372 | if (color && perf_hpp__format[i].color) |
diff --git a/tools/perf/ui/setup.c b/tools/perf/ui/setup.c index bd7d460f844c..ebb4cc107876 100644 --- a/tools/perf/ui/setup.c +++ b/tools/perf/ui/setup.c | |||
| @@ -30,7 +30,7 @@ void setup_browser(bool fallback_to_pager) | |||
| 30 | if (fallback_to_pager) | 30 | if (fallback_to_pager) |
| 31 | setup_pager(); | 31 | setup_pager(); |
| 32 | 32 | ||
| 33 | perf_hpp__init(false, false); | 33 | perf_hpp__init(); |
| 34 | break; | 34 | break; |
| 35 | } | 35 | } |
| 36 | } | 36 | } |
diff --git a/tools/perf/ui/stdio/hist.c b/tools/perf/ui/stdio/hist.c index 882461a42830..fbd4e32d0743 100644 --- a/tools/perf/ui/stdio/hist.c +++ b/tools/perf/ui/stdio/hist.c | |||
| @@ -271,7 +271,7 @@ static size_t hist_entry_callchain__fprintf(struct hist_entry *he, | |||
| 271 | { | 271 | { |
| 272 | switch (callchain_param.mode) { | 272 | switch (callchain_param.mode) { |
| 273 | case CHAIN_GRAPH_REL: | 273 | case CHAIN_GRAPH_REL: |
| 274 | return callchain__fprintf_graph(fp, &he->sorted_chain, he->period, | 274 | return callchain__fprintf_graph(fp, &he->sorted_chain, he->stat.period, |
| 275 | left_margin); | 275 | left_margin); |
| 276 | break; | 276 | break; |
| 277 | case CHAIN_GRAPH_ABS: | 277 | case CHAIN_GRAPH_ABS: |
| @@ -292,9 +292,10 @@ static size_t hist_entry_callchain__fprintf(struct hist_entry *he, | |||
| 292 | 292 | ||
| 293 | static size_t hist_entry__callchain_fprintf(struct hist_entry *he, | 293 | static size_t hist_entry__callchain_fprintf(struct hist_entry *he, |
| 294 | struct hists *hists, | 294 | struct hists *hists, |
| 295 | u64 total_period, FILE *fp) | 295 | FILE *fp) |
| 296 | { | 296 | { |
| 297 | int left_margin = 0; | 297 | int left_margin = 0; |
| 298 | u64 total_period = hists->stats.total_period; | ||
| 298 | 299 | ||
| 299 | if (sort__first_dimension == SORT_COMM) { | 300 | if (sort__first_dimension == SORT_COMM) { |
| 300 | struct sort_entry *se = list_first_entry(&hist_entry__sort_list, | 301 | struct sort_entry *se = list_first_entry(&hist_entry__sort_list, |
| @@ -307,17 +308,13 @@ static size_t hist_entry__callchain_fprintf(struct hist_entry *he, | |||
| 307 | } | 308 | } |
| 308 | 309 | ||
| 309 | static int hist_entry__fprintf(struct hist_entry *he, size_t size, | 310 | static int hist_entry__fprintf(struct hist_entry *he, size_t size, |
| 310 | struct hists *hists, struct hists *pair_hists, | 311 | struct hists *hists, FILE *fp) |
| 311 | long displacement, u64 total_period, FILE *fp) | ||
| 312 | { | 312 | { |
| 313 | char bf[512]; | 313 | char bf[512]; |
| 314 | int ret; | 314 | int ret; |
| 315 | struct perf_hpp hpp = { | 315 | struct perf_hpp hpp = { |
| 316 | .buf = bf, | 316 | .buf = bf, |
| 317 | .size = size, | 317 | .size = size, |
| 318 | .total_period = total_period, | ||
| 319 | .displacement = displacement, | ||
| 320 | .ptr = pair_hists, | ||
| 321 | }; | 318 | }; |
| 322 | bool color = !symbol_conf.field_sep; | 319 | bool color = !symbol_conf.field_sep; |
| 323 | 320 | ||
| @@ -330,22 +327,17 @@ static int hist_entry__fprintf(struct hist_entry *he, size_t size, | |||
| 330 | ret = fprintf(fp, "%s\n", bf); | 327 | ret = fprintf(fp, "%s\n", bf); |
| 331 | 328 | ||
| 332 | if (symbol_conf.use_callchain) | 329 | if (symbol_conf.use_callchain) |
| 333 | ret += hist_entry__callchain_fprintf(he, hists, | 330 | ret += hist_entry__callchain_fprintf(he, hists, fp); |
| 334 | total_period, fp); | ||
| 335 | 331 | ||
| 336 | return ret; | 332 | return ret; |
| 337 | } | 333 | } |
| 338 | 334 | ||
| 339 | size_t hists__fprintf(struct hists *hists, struct hists *pair, | 335 | size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows, |
| 340 | bool show_displacement, bool show_header, int max_rows, | ||
| 341 | int max_cols, FILE *fp) | 336 | int max_cols, FILE *fp) |
| 342 | { | 337 | { |
| 343 | struct sort_entry *se; | 338 | struct sort_entry *se; |
| 344 | struct rb_node *nd; | 339 | struct rb_node *nd; |
| 345 | size_t ret = 0; | 340 | size_t ret = 0; |
| 346 | u64 total_period; | ||
| 347 | unsigned long position = 1; | ||
| 348 | long displacement = 0; | ||
| 349 | unsigned int width; | 341 | unsigned int width; |
| 350 | const char *sep = symbol_conf.field_sep; | 342 | const char *sep = symbol_conf.field_sep; |
| 351 | const char *col_width = symbol_conf.col_width_list_str; | 343 | const char *col_width = symbol_conf.col_width_list_str; |
| @@ -354,8 +346,8 @@ size_t hists__fprintf(struct hists *hists, struct hists *pair, | |||
| 354 | struct perf_hpp dummy_hpp = { | 346 | struct perf_hpp dummy_hpp = { |
| 355 | .buf = bf, | 347 | .buf = bf, |
| 356 | .size = sizeof(bf), | 348 | .size = sizeof(bf), |
| 357 | .ptr = pair, | ||
| 358 | }; | 349 | }; |
| 350 | bool first = true; | ||
| 359 | 351 | ||
| 360 | init_rem_hits(); | 352 | init_rem_hits(); |
| 361 | 353 | ||
| @@ -367,8 +359,10 @@ size_t hists__fprintf(struct hists *hists, struct hists *pair, | |||
| 367 | if (!perf_hpp__format[idx].cond) | 359 | if (!perf_hpp__format[idx].cond) |
| 368 | continue; | 360 | continue; |
| 369 | 361 | ||
| 370 | if (idx) | 362 | if (!first) |
| 371 | fprintf(fp, "%s", sep ?: " "); | 363 | fprintf(fp, "%s", sep ?: " "); |
| 364 | else | ||
| 365 | first = false; | ||
| 372 | 366 | ||
| 373 | perf_hpp__format[idx].header(&dummy_hpp); | 367 | perf_hpp__format[idx].header(&dummy_hpp); |
| 374 | fprintf(fp, "%s", bf); | 368 | fprintf(fp, "%s", bf); |
| @@ -403,6 +397,8 @@ size_t hists__fprintf(struct hists *hists, struct hists *pair, | |||
| 403 | if (sep) | 397 | if (sep) |
| 404 | goto print_entries; | 398 | goto print_entries; |
| 405 | 399 | ||
| 400 | first = true; | ||
| 401 | |||
| 406 | fprintf(fp, "# "); | 402 | fprintf(fp, "# "); |
| 407 | for (idx = 0; idx < PERF_HPP__MAX_INDEX; idx++) { | 403 | for (idx = 0; idx < PERF_HPP__MAX_INDEX; idx++) { |
| 408 | unsigned int i; | 404 | unsigned int i; |
| @@ -410,8 +406,10 @@ size_t hists__fprintf(struct hists *hists, struct hists *pair, | |||
| 410 | if (!perf_hpp__format[idx].cond) | 406 | if (!perf_hpp__format[idx].cond) |
| 411 | continue; | 407 | continue; |
| 412 | 408 | ||
| 413 | if (idx) | 409 | if (!first) |
| 414 | fprintf(fp, "%s", sep ?: " "); | 410 | fprintf(fp, "%s", sep ?: " "); |
| 411 | else | ||
| 412 | first = false; | ||
| 415 | 413 | ||
| 416 | width = perf_hpp__format[idx].width(&dummy_hpp); | 414 | width = perf_hpp__format[idx].width(&dummy_hpp); |
| 417 | for (i = 0; i < width; i++) | 415 | for (i = 0; i < width; i++) |
| @@ -441,24 +439,13 @@ size_t hists__fprintf(struct hists *hists, struct hists *pair, | |||
| 441 | goto out; | 439 | goto out; |
| 442 | 440 | ||
| 443 | print_entries: | 441 | print_entries: |
| 444 | total_period = hists->stats.total_period; | ||
| 445 | |||
| 446 | for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) { | 442 | for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) { |
| 447 | struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); | 443 | struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); |
| 448 | 444 | ||
| 449 | if (h->filtered) | 445 | if (h->filtered) |
| 450 | continue; | 446 | continue; |
| 451 | 447 | ||
| 452 | if (show_displacement) { | 448 | ret += hist_entry__fprintf(h, max_cols, hists, fp); |
| 453 | if (h->pair != NULL) | ||
| 454 | displacement = ((long)h->pair->position - | ||
| 455 | (long)position); | ||
| 456 | else | ||
| 457 | displacement = 0; | ||
| 458 | ++position; | ||
| 459 | } | ||
| 460 | ret += hist_entry__fprintf(h, max_cols, hists, pair, displacement, | ||
| 461 | total_period, fp); | ||
| 462 | 449 | ||
| 463 | if (max_rows && ++nr_rows >= max_rows) | 450 | if (max_rows && ++nr_rows >= max_rows) |
| 464 | goto out; | 451 | goto out; |
diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index 9b5b21e7b032..39242dcee8f2 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h | |||
| @@ -138,7 +138,10 @@ int symbol__tty_annotate(struct symbol *sym, struct map *map, int evidx, | |||
| 138 | bool print_lines, bool full_paths, int min_pcnt, | 138 | bool print_lines, bool full_paths, int min_pcnt, |
| 139 | int max_lines); | 139 | int max_lines); |
| 140 | 140 | ||
| 141 | #ifdef NO_NEWT_SUPPORT | 141 | #ifdef NEWT_SUPPORT |
| 142 | int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx, | ||
| 143 | void(*timer)(void *arg), void *arg, int delay_secs); | ||
| 144 | #else | ||
| 142 | static inline int symbol__tui_annotate(struct symbol *sym __maybe_unused, | 145 | static inline int symbol__tui_annotate(struct symbol *sym __maybe_unused, |
| 143 | struct map *map __maybe_unused, | 146 | struct map *map __maybe_unused, |
| 144 | int evidx __maybe_unused, | 147 | int evidx __maybe_unused, |
| @@ -148,9 +151,6 @@ static inline int symbol__tui_annotate(struct symbol *sym __maybe_unused, | |||
| 148 | { | 151 | { |
| 149 | return 0; | 152 | return 0; |
| 150 | } | 153 | } |
| 151 | #else | ||
| 152 | int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx, | ||
| 153 | void(*timer)(void *arg), void *arg, int delay_secs); | ||
| 154 | #endif | 154 | #endif |
| 155 | 155 | ||
| 156 | extern const char *disassembler_style; | 156 | extern const char *disassembler_style; |
diff --git a/tools/perf/util/cache.h b/tools/perf/util/cache.h index ab1769426541..2bd51370ad28 100644 --- a/tools/perf/util/cache.h +++ b/tools/perf/util/cache.h | |||
| @@ -33,39 +33,41 @@ extern int pager_use_color; | |||
| 33 | 33 | ||
| 34 | extern int use_browser; | 34 | extern int use_browser; |
| 35 | 35 | ||
| 36 | #if defined(NO_NEWT_SUPPORT) && defined(NO_GTK2_SUPPORT) | 36 | #if defined(NEWT_SUPPORT) || defined(GTK2_SUPPORT) |
| 37 | static inline void setup_browser(bool fallback_to_pager) | ||
| 38 | { | ||
| 39 | if (fallback_to_pager) | ||
| 40 | setup_pager(); | ||
| 41 | } | ||
| 42 | static inline void exit_browser(bool wait_for_ok __maybe_unused) {} | ||
| 43 | #else | ||
| 44 | void setup_browser(bool fallback_to_pager); | 37 | void setup_browser(bool fallback_to_pager); |
| 45 | void exit_browser(bool wait_for_ok); | 38 | void exit_browser(bool wait_for_ok); |
| 46 | 39 | ||
| 47 | #ifdef NO_NEWT_SUPPORT | 40 | #ifdef NEWT_SUPPORT |
| 41 | int ui__init(void); | ||
| 42 | void ui__exit(bool wait_for_ok); | ||
| 43 | #else | ||
| 48 | static inline int ui__init(void) | 44 | static inline int ui__init(void) |
| 49 | { | 45 | { |
| 50 | return -1; | 46 | return -1; |
| 51 | } | 47 | } |
| 52 | static inline void ui__exit(bool wait_for_ok __maybe_unused) {} | 48 | static inline void ui__exit(bool wait_for_ok __maybe_unused) {} |
| 53 | #else | ||
| 54 | int ui__init(void); | ||
| 55 | void ui__exit(bool wait_for_ok); | ||
| 56 | #endif | 49 | #endif |
| 57 | 50 | ||
| 58 | #ifdef NO_GTK2_SUPPORT | 51 | #ifdef GTK2_SUPPORT |
| 52 | int perf_gtk__init(void); | ||
| 53 | void perf_gtk__exit(bool wait_for_ok); | ||
| 54 | #else | ||
| 59 | static inline int perf_gtk__init(void) | 55 | static inline int perf_gtk__init(void) |
| 60 | { | 56 | { |
| 61 | return -1; | 57 | return -1; |
| 62 | } | 58 | } |
| 63 | static inline void perf_gtk__exit(bool wait_for_ok __maybe_unused) {} | 59 | static inline void perf_gtk__exit(bool wait_for_ok __maybe_unused) {} |
| 64 | #else | ||
| 65 | int perf_gtk__init(void); | ||
| 66 | void perf_gtk__exit(bool wait_for_ok); | ||
| 67 | #endif | 60 | #endif |
| 68 | #endif /* NO_NEWT_SUPPORT && NO_GTK2_SUPPORT */ | 61 | |
| 62 | #else /* NEWT_SUPPORT || GTK2_SUPPORT */ | ||
| 63 | |||
| 64 | static inline void setup_browser(bool fallback_to_pager) | ||
| 65 | { | ||
| 66 | if (fallback_to_pager) | ||
| 67 | setup_pager(); | ||
| 68 | } | ||
| 69 | static inline void exit_browser(bool wait_for_ok __maybe_unused) {} | ||
| 70 | #endif /* NEWT_SUPPORT || GTK2_SUPPORT */ | ||
| 69 | 71 | ||
| 70 | char *alias_lookup(const char *alias); | 72 | char *alias_lookup(const char *alias); |
| 71 | int split_cmdline(char *cmdline, const char ***argv); | 73 | int split_cmdline(char *cmdline, const char ***argv); |
| @@ -105,7 +107,7 @@ extern char *perf_path(const char *fmt, ...) __attribute__((format (printf, 1, 2 | |||
| 105 | extern char *perf_pathdup(const char *fmt, ...) | 107 | extern char *perf_pathdup(const char *fmt, ...) |
| 106 | __attribute__((format (printf, 1, 2))); | 108 | __attribute__((format (printf, 1, 2))); |
| 107 | 109 | ||
| 108 | #ifdef NO_STRLCPY | 110 | #ifndef HAVE_STRLCPY |
| 109 | extern size_t strlcpy(char *dest, const char *src, size_t size); | 111 | extern size_t strlcpy(char *dest, const char *src, size_t size); |
| 110 | #endif | 112 | #endif |
| 111 | 113 | ||
diff --git a/tools/perf/util/debug.c b/tools/perf/util/debug.c index 66eb3828ceb5..03f830b48148 100644 --- a/tools/perf/util/debug.c +++ b/tools/perf/util/debug.c | |||
| @@ -49,7 +49,7 @@ int dump_printf(const char *fmt, ...) | |||
| 49 | return ret; | 49 | return ret; |
| 50 | } | 50 | } |
| 51 | 51 | ||
| 52 | #if defined(NO_NEWT_SUPPORT) && defined(NO_GTK2_SUPPORT) | 52 | #if !defined(NEWT_SUPPORT) && !defined(GTK2_SUPPORT) |
| 53 | int ui__warning(const char *format, ...) | 53 | int ui__warning(const char *format, ...) |
| 54 | { | 54 | { |
| 55 | va_list args; | 55 | va_list args; |
diff --git a/tools/perf/util/debug.h b/tools/perf/util/debug.h index bb2e7d1007ab..dec98750b484 100644 --- a/tools/perf/util/debug.h +++ b/tools/perf/util/debug.h | |||
| @@ -15,7 +15,14 @@ void trace_event(union perf_event *event); | |||
| 15 | struct ui_progress; | 15 | struct ui_progress; |
| 16 | struct perf_error_ops; | 16 | struct perf_error_ops; |
| 17 | 17 | ||
| 18 | #if defined(NO_NEWT_SUPPORT) && defined(NO_GTK2_SUPPORT) | 18 | #if defined(NEWT_SUPPORT) || defined(GTK2_SUPPORT) |
| 19 | |||
| 20 | #include "../ui/progress.h" | ||
| 21 | int ui__error(const char *format, ...) __attribute__((format(printf, 1, 2))); | ||
| 22 | #include "../ui/util.h" | ||
| 23 | |||
| 24 | #else | ||
| 25 | |||
| 19 | static inline void ui_progress__update(u64 curr __maybe_unused, | 26 | static inline void ui_progress__update(u64 curr __maybe_unused, |
| 20 | u64 total __maybe_unused, | 27 | u64 total __maybe_unused, |
| 21 | const char *title __maybe_unused) {} | 28 | const char *title __maybe_unused) {} |
| @@ -34,13 +41,7 @@ perf_error__unregister(struct perf_error_ops *eops __maybe_unused) | |||
| 34 | return 0; | 41 | return 0; |
| 35 | } | 42 | } |
| 36 | 43 | ||
| 37 | #else /* NO_NEWT_SUPPORT && NO_GTK2_SUPPORT */ | 44 | #endif /* NEWT_SUPPORT || GTK2_SUPPORT */ |
| 38 | |||
| 39 | #include "../ui/progress.h" | ||
| 40 | int ui__error(const char *format, ...) __attribute__((format(printf, 1, 2))); | ||
| 41 | #include "../ui/util.h" | ||
| 42 | |||
| 43 | #endif /* NO_NEWT_SUPPORT && NO_GTK2_SUPPORT */ | ||
| 44 | 45 | ||
| 45 | int ui__warning(const char *format, ...) __attribute__((format(printf, 1, 2))); | 46 | int ui__warning(const char *format, ...) __attribute__((format(printf, 1, 2))); |
| 46 | int ui__error_paranoid(void); | 47 | int ui__error_paranoid(void); |
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index ae89686102f4..186b87730396 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c | |||
| @@ -154,8 +154,8 @@ error: | |||
| 154 | return -ENOMEM; | 154 | return -ENOMEM; |
| 155 | } | 155 | } |
| 156 | 156 | ||
| 157 | int perf_evlist__add_attrs(struct perf_evlist *evlist, | 157 | static int perf_evlist__add_attrs(struct perf_evlist *evlist, |
| 158 | struct perf_event_attr *attrs, size_t nr_attrs) | 158 | struct perf_event_attr *attrs, size_t nr_attrs) |
| 159 | { | 159 | { |
| 160 | struct perf_evsel *evsel, *n; | 160 | struct perf_evsel *evsel, *n; |
| 161 | LIST_HEAD(head); | 161 | LIST_HEAD(head); |
| @@ -189,60 +189,6 @@ int __perf_evlist__add_default_attrs(struct perf_evlist *evlist, | |||
| 189 | return perf_evlist__add_attrs(evlist, attrs, nr_attrs); | 189 | return perf_evlist__add_attrs(evlist, attrs, nr_attrs); |
| 190 | } | 190 | } |
| 191 | 191 | ||
| 192 | static int trace_event__id(const char *evname) | ||
| 193 | { | ||
| 194 | char *filename, *colon; | ||
| 195 | int err = -1, fd; | ||
| 196 | |||
| 197 | if (asprintf(&filename, "%s/%s/id", tracing_events_path, evname) < 0) | ||
| 198 | return -1; | ||
| 199 | |||
| 200 | colon = strrchr(filename, ':'); | ||
| 201 | if (colon != NULL) | ||
| 202 | *colon = '/'; | ||
| 203 | |||
| 204 | fd = open(filename, O_RDONLY); | ||
| 205 | if (fd >= 0) { | ||
| 206 | char id[16]; | ||
| 207 | if (read(fd, id, sizeof(id)) > 0) | ||
| 208 | err = atoi(id); | ||
| 209 | close(fd); | ||
| 210 | } | ||
| 211 | |||
| 212 | free(filename); | ||
| 213 | return err; | ||
| 214 | } | ||
| 215 | |||
| 216 | int perf_evlist__add_tracepoints(struct perf_evlist *evlist, | ||
| 217 | const char *tracepoints[], | ||
| 218 | size_t nr_tracepoints) | ||
| 219 | { | ||
| 220 | int err; | ||
| 221 | size_t i; | ||
| 222 | struct perf_event_attr *attrs = zalloc(nr_tracepoints * sizeof(*attrs)); | ||
| 223 | |||
| 224 | if (attrs == NULL) | ||
| 225 | return -1; | ||
| 226 | |||
| 227 | for (i = 0; i < nr_tracepoints; i++) { | ||
| 228 | err = trace_event__id(tracepoints[i]); | ||
| 229 | |||
| 230 | if (err < 0) | ||
| 231 | goto out_free_attrs; | ||
| 232 | |||
| 233 | attrs[i].type = PERF_TYPE_TRACEPOINT; | ||
| 234 | attrs[i].config = err; | ||
| 235 | attrs[i].sample_type = (PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | | ||
| 236 | PERF_SAMPLE_CPU | PERF_SAMPLE_PERIOD); | ||
| 237 | attrs[i].sample_period = 1; | ||
| 238 | } | ||
| 239 | |||
| 240 | err = perf_evlist__add_attrs(evlist, attrs, nr_tracepoints); | ||
| 241 | out_free_attrs: | ||
| 242 | free(attrs); | ||
| 243 | return err; | ||
| 244 | } | ||
| 245 | |||
| 246 | struct perf_evsel * | 192 | struct perf_evsel * |
| 247 | perf_evlist__find_tracepoint_by_id(struct perf_evlist *evlist, int id) | 193 | perf_evlist__find_tracepoint_by_id(struct perf_evlist *evlist, int id) |
| 248 | { | 194 | { |
| @@ -257,32 +203,18 @@ perf_evlist__find_tracepoint_by_id(struct perf_evlist *evlist, int id) | |||
| 257 | return NULL; | 203 | return NULL; |
| 258 | } | 204 | } |
| 259 | 205 | ||
| 260 | int perf_evlist__set_tracepoints_handlers(struct perf_evlist *evlist, | 206 | int perf_evlist__add_newtp(struct perf_evlist *evlist, |
| 261 | const struct perf_evsel_str_handler *assocs, | 207 | const char *sys, const char *name, void *handler) |
| 262 | size_t nr_assocs) | ||
| 263 | { | 208 | { |
| 264 | struct perf_evsel *evsel; | 209 | struct perf_evsel *evsel; |
| 265 | int err; | ||
| 266 | size_t i; | ||
| 267 | |||
| 268 | for (i = 0; i < nr_assocs; i++) { | ||
| 269 | err = trace_event__id(assocs[i].name); | ||
| 270 | if (err < 0) | ||
| 271 | goto out; | ||
| 272 | |||
| 273 | evsel = perf_evlist__find_tracepoint_by_id(evlist, err); | ||
| 274 | if (evsel == NULL) | ||
| 275 | continue; | ||
| 276 | 210 | ||
| 277 | err = -EEXIST; | 211 | evsel = perf_evsel__newtp(sys, name, evlist->nr_entries); |
| 278 | if (evsel->handler.func != NULL) | 212 | if (evsel == NULL) |
| 279 | goto out; | 213 | return -1; |
| 280 | evsel->handler.func = assocs[i].handler; | ||
| 281 | } | ||
| 282 | 214 | ||
| 283 | err = 0; | 215 | evsel->handler.func = handler; |
| 284 | out: | 216 | perf_evlist__add(evlist, evsel); |
| 285 | return err; | 217 | return 0; |
| 286 | } | 218 | } |
| 287 | 219 | ||
| 288 | void perf_evlist__disable(struct perf_evlist *evlist) | 220 | void perf_evlist__disable(struct perf_evlist *evlist) |
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h index 3f1fb66be022..56003f779e60 100644 --- a/tools/perf/util/evlist.h +++ b/tools/perf/util/evlist.h | |||
| @@ -51,26 +51,14 @@ void perf_evlist__delete(struct perf_evlist *evlist); | |||
| 51 | 51 | ||
| 52 | void perf_evlist__add(struct perf_evlist *evlist, struct perf_evsel *entry); | 52 | void perf_evlist__add(struct perf_evlist *evlist, struct perf_evsel *entry); |
| 53 | int perf_evlist__add_default(struct perf_evlist *evlist); | 53 | int perf_evlist__add_default(struct perf_evlist *evlist); |
| 54 | int perf_evlist__add_attrs(struct perf_evlist *evlist, | ||
| 55 | struct perf_event_attr *attrs, size_t nr_attrs); | ||
| 56 | int __perf_evlist__add_default_attrs(struct perf_evlist *evlist, | 54 | int __perf_evlist__add_default_attrs(struct perf_evlist *evlist, |
| 57 | struct perf_event_attr *attrs, size_t nr_attrs); | 55 | struct perf_event_attr *attrs, size_t nr_attrs); |
| 58 | int perf_evlist__add_tracepoints(struct perf_evlist *evlist, | 56 | |
| 59 | const char *tracepoints[], size_t nr_tracepoints); | ||
| 60 | int perf_evlist__set_tracepoints_handlers(struct perf_evlist *evlist, | ||
| 61 | const struct perf_evsel_str_handler *assocs, | ||
| 62 | size_t nr_assocs); | ||
| 63 | |||
| 64 | #define perf_evlist__add_attrs_array(evlist, array) \ | ||
| 65 | perf_evlist__add_attrs(evlist, array, ARRAY_SIZE(array)) | ||
| 66 | #define perf_evlist__add_default_attrs(evlist, array) \ | 57 | #define perf_evlist__add_default_attrs(evlist, array) \ |
| 67 | __perf_evlist__add_default_attrs(evlist, array, ARRAY_SIZE(array)) | 58 | __perf_evlist__add_default_attrs(evlist, array, ARRAY_SIZE(array)) |
| 68 | 59 | ||
| 69 | #define perf_evlist__add_tracepoints_array(evlist, array) \ | 60 | int perf_evlist__add_newtp(struct perf_evlist *evlist, |
| 70 | perf_evlist__add_tracepoints(evlist, array, ARRAY_SIZE(array)) | 61 | const char *sys, const char *name, void *handler); |
| 71 | |||
| 72 | #define perf_evlist__set_tracepoints_handlers_array(evlist, array) \ | ||
| 73 | perf_evlist__set_tracepoints_handlers(evlist, array, ARRAY_SIZE(array)) | ||
| 74 | 62 | ||
| 75 | int perf_evlist__set_filter(struct perf_evlist *evlist, const char *filter); | 63 | int perf_evlist__set_filter(struct perf_evlist *evlist, const char *filter); |
| 76 | 64 | ||
diff --git a/tools/perf/util/generate-cmdlist.sh b/tools/perf/util/generate-cmdlist.sh index 389590c1ad21..3ac38031d534 100755 --- a/tools/perf/util/generate-cmdlist.sh +++ b/tools/perf/util/generate-cmdlist.sh | |||
| @@ -22,7 +22,7 @@ do | |||
| 22 | }' "Documentation/perf-$cmd.txt" | 22 | }' "Documentation/perf-$cmd.txt" |
| 23 | done | 23 | done |
| 24 | 24 | ||
| 25 | echo "#ifndef NO_LIBELF_SUPPORT" | 25 | echo "#ifdef LIBELF_SUPPORT" |
| 26 | sed -n -e 's/^perf-\([^ ]*\)[ ].* full.*/\1/p' command-list.txt | | 26 | sed -n -e 's/^perf-\([^ ]*\)[ ].* full.*/\1/p' command-list.txt | |
| 27 | sort | | 27 | sort | |
| 28 | while read cmd | 28 | while read cmd |
| @@ -35,5 +35,5 @@ do | |||
| 35 | p | 35 | p |
| 36 | }' "Documentation/perf-$cmd.txt" | 36 | }' "Documentation/perf-$cmd.txt" |
| 37 | done | 37 | done |
| 38 | echo "#endif /* NO_LIBELF_SUPPORT */" | 38 | echo "#endif /* LIBELF_SUPPORT */" |
| 39 | echo "};" | 39 | echo "};" |
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index 236bc9d98ff2..277947a669b2 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c | |||
| @@ -135,31 +135,47 @@ static void hist_entry__add_cpumode_period(struct hist_entry *he, | |||
| 135 | { | 135 | { |
| 136 | switch (cpumode) { | 136 | switch (cpumode) { |
| 137 | case PERF_RECORD_MISC_KERNEL: | 137 | case PERF_RECORD_MISC_KERNEL: |
| 138 | he->period_sys += period; | 138 | he->stat.period_sys += period; |
| 139 | break; | 139 | break; |
| 140 | case PERF_RECORD_MISC_USER: | 140 | case PERF_RECORD_MISC_USER: |
| 141 | he->period_us += period; | 141 | he->stat.period_us += period; |
| 142 | break; | 142 | break; |
| 143 | case PERF_RECORD_MISC_GUEST_KERNEL: | 143 | case PERF_RECORD_MISC_GUEST_KERNEL: |
| 144 | he->period_guest_sys += period; | 144 | he->stat.period_guest_sys += period; |
| 145 | break; | 145 | break; |
| 146 | case PERF_RECORD_MISC_GUEST_USER: | 146 | case PERF_RECORD_MISC_GUEST_USER: |
| 147 | he->period_guest_us += period; | 147 | he->stat.period_guest_us += period; |
| 148 | break; | 148 | break; |
| 149 | default: | 149 | default: |
| 150 | break; | 150 | break; |
| 151 | } | 151 | } |
| 152 | } | 152 | } |
| 153 | 153 | ||
| 154 | static void he_stat__add_period(struct he_stat *he_stat, u64 period) | ||
| 155 | { | ||
| 156 | he_stat->period += period; | ||
| 157 | he_stat->nr_events += 1; | ||
| 158 | } | ||
| 159 | |||
| 160 | static void he_stat__add_stat(struct he_stat *dest, struct he_stat *src) | ||
| 161 | { | ||
| 162 | dest->period += src->period; | ||
| 163 | dest->period_sys += src->period_sys; | ||
| 164 | dest->period_us += src->period_us; | ||
| 165 | dest->period_guest_sys += src->period_guest_sys; | ||
| 166 | dest->period_guest_us += src->period_guest_us; | ||
| 167 | dest->nr_events += src->nr_events; | ||
| 168 | } | ||
| 169 | |||
| 154 | static void hist_entry__decay(struct hist_entry *he) | 170 | static void hist_entry__decay(struct hist_entry *he) |
| 155 | { | 171 | { |
| 156 | he->period = (he->period * 7) / 8; | 172 | he->stat.period = (he->stat.period * 7) / 8; |
| 157 | he->nr_events = (he->nr_events * 7) / 8; | 173 | he->stat.nr_events = (he->stat.nr_events * 7) / 8; |
| 158 | } | 174 | } |
| 159 | 175 | ||
| 160 | static bool hists__decay_entry(struct hists *hists, struct hist_entry *he) | 176 | static bool hists__decay_entry(struct hists *hists, struct hist_entry *he) |
| 161 | { | 177 | { |
| 162 | u64 prev_period = he->period; | 178 | u64 prev_period = he->stat.period; |
| 163 | 179 | ||
| 164 | if (prev_period == 0) | 180 | if (prev_period == 0) |
| 165 | return true; | 181 | return true; |
| @@ -167,9 +183,9 @@ static bool hists__decay_entry(struct hists *hists, struct hist_entry *he) | |||
| 167 | hist_entry__decay(he); | 183 | hist_entry__decay(he); |
| 168 | 184 | ||
| 169 | if (!he->filtered) | 185 | if (!he->filtered) |
| 170 | hists->stats.total_period -= prev_period - he->period; | 186 | hists->stats.total_period -= prev_period - he->stat.period; |
| 171 | 187 | ||
| 172 | return he->period == 0; | 188 | return he->stat.period == 0; |
| 173 | } | 189 | } |
| 174 | 190 | ||
| 175 | static void __hists__decay_entries(struct hists *hists, bool zap_user, | 191 | static void __hists__decay_entries(struct hists *hists, bool zap_user, |
| @@ -223,7 +239,7 @@ static struct hist_entry *hist_entry__new(struct hist_entry *template) | |||
| 223 | 239 | ||
| 224 | if (he != NULL) { | 240 | if (he != NULL) { |
| 225 | *he = *template; | 241 | *he = *template; |
| 226 | he->nr_events = 1; | 242 | |
| 227 | if (he->ms.map) | 243 | if (he->ms.map) |
| 228 | he->ms.map->referenced = true; | 244 | he->ms.map->referenced = true; |
| 229 | if (symbol_conf.use_callchain) | 245 | if (symbol_conf.use_callchain) |
| @@ -238,7 +254,7 @@ static void hists__inc_nr_entries(struct hists *hists, struct hist_entry *h) | |||
| 238 | if (!h->filtered) { | 254 | if (!h->filtered) { |
| 239 | hists__calc_col_len(hists, h); | 255 | hists__calc_col_len(hists, h); |
| 240 | ++hists->nr_entries; | 256 | ++hists->nr_entries; |
| 241 | hists->stats.total_period += h->period; | 257 | hists->stats.total_period += h->stat.period; |
| 242 | } | 258 | } |
| 243 | } | 259 | } |
| 244 | 260 | ||
| @@ -270,8 +286,7 @@ static struct hist_entry *add_hist_entry(struct hists *hists, | |||
| 270 | cmp = hist_entry__cmp(entry, he); | 286 | cmp = hist_entry__cmp(entry, he); |
| 271 | 287 | ||
| 272 | if (!cmp) { | 288 | if (!cmp) { |
| 273 | he->period += period; | 289 | he_stat__add_period(&he->stat, period); |
| 274 | ++he->nr_events; | ||
| 275 | 290 | ||
| 276 | /* If the map of an existing hist_entry has | 291 | /* If the map of an existing hist_entry has |
| 277 | * become out-of-date due to an exec() or | 292 | * become out-of-date due to an exec() or |
| @@ -321,10 +336,14 @@ struct hist_entry *__hists__add_branch_entry(struct hists *self, | |||
| 321 | .cpu = al->cpu, | 336 | .cpu = al->cpu, |
| 322 | .ip = bi->to.addr, | 337 | .ip = bi->to.addr, |
| 323 | .level = al->level, | 338 | .level = al->level, |
| 324 | .period = period, | 339 | .stat = { |
| 340 | .period = period, | ||
| 341 | .nr_events = 1, | ||
| 342 | }, | ||
| 325 | .parent = sym_parent, | 343 | .parent = sym_parent, |
| 326 | .filtered = symbol__parent_filter(sym_parent), | 344 | .filtered = symbol__parent_filter(sym_parent), |
| 327 | .branch_info = bi, | 345 | .branch_info = bi, |
| 346 | .hists = self, | ||
| 328 | }; | 347 | }; |
| 329 | 348 | ||
| 330 | return add_hist_entry(self, &entry, al, period); | 349 | return add_hist_entry(self, &entry, al, period); |
| @@ -343,9 +362,13 @@ struct hist_entry *__hists__add_entry(struct hists *self, | |||
| 343 | .cpu = al->cpu, | 362 | .cpu = al->cpu, |
| 344 | .ip = al->addr, | 363 | .ip = al->addr, |
| 345 | .level = al->level, | 364 | .level = al->level, |
| 346 | .period = period, | 365 | .stat = { |
| 366 | .period = period, | ||
| 367 | .nr_events = 1, | ||
| 368 | }, | ||
| 347 | .parent = sym_parent, | 369 | .parent = sym_parent, |
| 348 | .filtered = symbol__parent_filter(sym_parent), | 370 | .filtered = symbol__parent_filter(sym_parent), |
| 371 | .hists = self, | ||
| 349 | }; | 372 | }; |
| 350 | 373 | ||
| 351 | return add_hist_entry(self, &entry, al, period); | 374 | return add_hist_entry(self, &entry, al, period); |
| @@ -410,12 +433,7 @@ static bool hists__collapse_insert_entry(struct hists *hists __maybe_unused, | |||
| 410 | cmp = hist_entry__collapse(iter, he); | 433 | cmp = hist_entry__collapse(iter, he); |
| 411 | 434 | ||
| 412 | if (!cmp) { | 435 | if (!cmp) { |
| 413 | iter->period += he->period; | 436 | he_stat__add_stat(&iter->stat, &he->stat); |
| 414 | iter->period_sys += he->period_sys; | ||
| 415 | iter->period_us += he->period_us; | ||
| 416 | iter->period_guest_sys += he->period_guest_sys; | ||
| 417 | iter->period_guest_us += he->period_guest_us; | ||
| 418 | iter->nr_events += he->nr_events; | ||
| 419 | 437 | ||
| 420 | if (symbol_conf.use_callchain) { | 438 | if (symbol_conf.use_callchain) { |
| 421 | callchain_cursor_reset(&callchain_cursor); | 439 | callchain_cursor_reset(&callchain_cursor); |
| @@ -518,7 +536,7 @@ static void __hists__insert_output_entry(struct rb_root *entries, | |||
| 518 | parent = *p; | 536 | parent = *p; |
| 519 | iter = rb_entry(parent, struct hist_entry, rb_node); | 537 | iter = rb_entry(parent, struct hist_entry, rb_node); |
| 520 | 538 | ||
| 521 | if (he->period > iter->period) | 539 | if (he->stat.period > iter->stat.period) |
| 522 | p = &(*p)->rb_left; | 540 | p = &(*p)->rb_left; |
| 523 | else | 541 | else |
| 524 | p = &(*p)->rb_right; | 542 | p = &(*p)->rb_right; |
| @@ -579,8 +597,8 @@ static void hists__remove_entry_filter(struct hists *hists, struct hist_entry *h | |||
| 579 | if (h->ms.unfolded) | 597 | if (h->ms.unfolded) |
| 580 | hists->nr_entries += h->nr_rows; | 598 | hists->nr_entries += h->nr_rows; |
| 581 | h->row_offset = 0; | 599 | h->row_offset = 0; |
| 582 | hists->stats.total_period += h->period; | 600 | hists->stats.total_period += h->stat.period; |
| 583 | hists->stats.nr_events[PERF_RECORD_SAMPLE] += h->nr_events; | 601 | hists->stats.nr_events[PERF_RECORD_SAMPLE] += h->stat.nr_events; |
| 584 | 602 | ||
| 585 | hists__calc_col_len(hists, h); | 603 | hists__calc_col_len(hists, h); |
| 586 | } | 604 | } |
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index f011ad4756e8..66cb31fe81d2 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h | |||
| @@ -98,9 +98,8 @@ void hists__output_recalc_col_len(struct hists *hists, int max_rows); | |||
| 98 | void hists__inc_nr_events(struct hists *self, u32 type); | 98 | void hists__inc_nr_events(struct hists *self, u32 type); |
| 99 | size_t hists__fprintf_nr_events(struct hists *self, FILE *fp); | 99 | size_t hists__fprintf_nr_events(struct hists *self, FILE *fp); |
| 100 | 100 | ||
| 101 | size_t hists__fprintf(struct hists *self, struct hists *pair, | 101 | size_t hists__fprintf(struct hists *self, bool show_header, int max_rows, |
| 102 | bool show_displacement, bool show_header, | 102 | int max_cols, FILE *fp); |
| 103 | int max_rows, int max_cols, FILE *fp); | ||
| 104 | 103 | ||
| 105 | int hist_entry__inc_addr_samples(struct hist_entry *self, int evidx, u64 addr); | 104 | int hist_entry__inc_addr_samples(struct hist_entry *self, int evidx, u64 addr); |
| 106 | int hist_entry__annotate(struct hist_entry *self, size_t privsize); | 105 | int hist_entry__annotate(struct hist_entry *self, size_t privsize); |
| @@ -118,9 +117,7 @@ void hists__calc_col_len(struct hists *hists, struct hist_entry *he); | |||
| 118 | struct perf_hpp { | 117 | struct perf_hpp { |
| 119 | char *buf; | 118 | char *buf; |
| 120 | size_t size; | 119 | size_t size; |
| 121 | u64 total_period; | ||
| 122 | const char *sep; | 120 | const char *sep; |
| 123 | long displacement; | ||
| 124 | void *ptr; | 121 | void *ptr; |
| 125 | }; | 122 | }; |
| 126 | 123 | ||
| @@ -135,6 +132,7 @@ struct perf_hpp_fmt { | |||
| 135 | extern struct perf_hpp_fmt perf_hpp__format[]; | 132 | extern struct perf_hpp_fmt perf_hpp__format[]; |
| 136 | 133 | ||
| 137 | enum { | 134 | enum { |
| 135 | PERF_HPP__BASELINE, | ||
| 138 | PERF_HPP__OVERHEAD, | 136 | PERF_HPP__OVERHEAD, |
| 139 | PERF_HPP__OVERHEAD_SYS, | 137 | PERF_HPP__OVERHEAD_SYS, |
| 140 | PERF_HPP__OVERHEAD_US, | 138 | PERF_HPP__OVERHEAD_US, |
| @@ -148,13 +146,22 @@ enum { | |||
| 148 | PERF_HPP__MAX_INDEX | 146 | PERF_HPP__MAX_INDEX |
| 149 | }; | 147 | }; |
| 150 | 148 | ||
| 151 | void perf_hpp__init(bool need_pair, bool show_displacement); | 149 | void perf_hpp__init(void); |
| 150 | void perf_hpp__column_enable(unsigned col, bool enable); | ||
| 152 | int hist_entry__period_snprintf(struct perf_hpp *hpp, struct hist_entry *he, | 151 | int hist_entry__period_snprintf(struct perf_hpp *hpp, struct hist_entry *he, |
| 153 | bool color); | 152 | bool color); |
| 154 | 153 | ||
| 155 | struct perf_evlist; | 154 | struct perf_evlist; |
| 156 | 155 | ||
| 157 | #ifdef NO_NEWT_SUPPORT | 156 | #ifdef NEWT_SUPPORT |
| 157 | #include "../ui/keysyms.h" | ||
| 158 | int hist_entry__tui_annotate(struct hist_entry *he, int evidx, | ||
| 159 | void(*timer)(void *arg), void *arg, int delay_secs); | ||
| 160 | |||
| 161 | int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help, | ||
| 162 | void(*timer)(void *arg), void *arg, | ||
| 163 | int refresh); | ||
| 164 | #else | ||
| 158 | static inline | 165 | static inline |
| 159 | int perf_evlist__tui_browse_hists(struct perf_evlist *evlist __maybe_unused, | 166 | int perf_evlist__tui_browse_hists(struct perf_evlist *evlist __maybe_unused, |
| 160 | const char *help __maybe_unused, | 167 | const char *help __maybe_unused, |
| @@ -177,17 +184,13 @@ static inline int hist_entry__tui_annotate(struct hist_entry *self | |||
| 177 | } | 184 | } |
| 178 | #define K_LEFT -1 | 185 | #define K_LEFT -1 |
| 179 | #define K_RIGHT -2 | 186 | #define K_RIGHT -2 |
| 180 | #else | 187 | #endif |
| 181 | #include "../ui/keysyms.h" | ||
| 182 | int hist_entry__tui_annotate(struct hist_entry *he, int evidx, | ||
| 183 | void(*timer)(void *arg), void *arg, int delay_secs); | ||
| 184 | 188 | ||
| 185 | int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help, | 189 | #ifdef GTK2_SUPPORT |
| 190 | int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist, const char *help, | ||
| 186 | void(*timer)(void *arg), void *arg, | 191 | void(*timer)(void *arg), void *arg, |
| 187 | int refresh); | 192 | int refresh); |
| 188 | #endif | 193 | #else |
| 189 | |||
| 190 | #ifdef NO_GTK2_SUPPORT | ||
| 191 | static inline | 194 | static inline |
| 192 | int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist __maybe_unused, | 195 | int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist __maybe_unused, |
| 193 | const char *help __maybe_unused, | 196 | const char *help __maybe_unused, |
| @@ -197,11 +200,6 @@ int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist __maybe_unused, | |||
| 197 | { | 200 | { |
| 198 | return 0; | 201 | return 0; |
| 199 | } | 202 | } |
| 200 | |||
| 201 | #else | ||
| 202 | int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist, const char *help, | ||
| 203 | void(*timer)(void *arg), void *arg, | ||
| 204 | int refresh); | ||
| 205 | #endif | 203 | #endif |
| 206 | 204 | ||
| 207 | unsigned int hists__sort_list_width(struct hists *self); | 205 | unsigned int hists__sort_list_width(struct hists *self); |
diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c index ead5316b3f89..6109fa4d14cd 100644 --- a/tools/perf/util/map.c +++ b/tools/perf/util/map.c | |||
| @@ -162,7 +162,7 @@ int map__load(struct map *self, symbol_filter_t filter) | |||
| 162 | pr_warning(", continuing without symbols\n"); | 162 | pr_warning(", continuing without symbols\n"); |
| 163 | return -1; | 163 | return -1; |
| 164 | } else if (nr == 0) { | 164 | } else if (nr == 0) { |
| 165 | #ifndef NO_LIBELF_SUPPORT | 165 | #ifdef LIBELF_SUPPORT |
| 166 | const size_t len = strlen(name); | 166 | const size_t len = strlen(name); |
| 167 | const size_t real_len = len - sizeof(DSO__DELETED); | 167 | const size_t real_len = len - sizeof(DSO__DELETED); |
| 168 | 168 | ||
diff --git a/tools/perf/util/parse-options.c b/tools/perf/util/parse-options.c index 443fc116512b..2bc9e70df7e2 100644 --- a/tools/perf/util/parse-options.c +++ b/tools/perf/util/parse-options.c | |||
| @@ -384,6 +384,8 @@ int parse_options_step(struct parse_opt_ctx_t *ctx, | |||
| 384 | return usage_with_options_internal(usagestr, options, 1); | 384 | return usage_with_options_internal(usagestr, options, 1); |
| 385 | if (internal_help && !strcmp(arg + 2, "help")) | 385 | if (internal_help && !strcmp(arg + 2, "help")) |
| 386 | return parse_options_usage(usagestr, options); | 386 | return parse_options_usage(usagestr, options); |
| 387 | if (!strcmp(arg + 2, "list-opts")) | ||
| 388 | return PARSE_OPT_LIST; | ||
| 387 | switch (parse_long_opt(ctx, arg + 2, options)) { | 389 | switch (parse_long_opt(ctx, arg + 2, options)) { |
| 388 | case -1: | 390 | case -1: |
| 389 | return parse_options_usage(usagestr, options); | 391 | return parse_options_usage(usagestr, options); |
| @@ -422,6 +424,12 @@ int parse_options(int argc, const char **argv, const struct option *options, | |||
| 422 | exit(129); | 424 | exit(129); |
| 423 | case PARSE_OPT_DONE: | 425 | case PARSE_OPT_DONE: |
| 424 | break; | 426 | break; |
| 427 | case PARSE_OPT_LIST: | ||
| 428 | while (options->type != OPTION_END) { | ||
| 429 | printf("--%s ", options->long_name); | ||
| 430 | options++; | ||
| 431 | } | ||
| 432 | exit(130); | ||
| 425 | default: /* PARSE_OPT_UNKNOWN */ | 433 | default: /* PARSE_OPT_UNKNOWN */ |
| 426 | if (ctx.argv[0][1] == '-') { | 434 | if (ctx.argv[0][1] == '-') { |
| 427 | error("unknown option `%s'", ctx.argv[0] + 2); | 435 | error("unknown option `%s'", ctx.argv[0] + 2); |
diff --git a/tools/perf/util/parse-options.h b/tools/perf/util/parse-options.h index abc31a1dac1a..7bb5999940ca 100644 --- a/tools/perf/util/parse-options.h +++ b/tools/perf/util/parse-options.h | |||
| @@ -140,6 +140,7 @@ extern NORETURN void usage_with_options(const char * const *usagestr, | |||
| 140 | enum { | 140 | enum { |
| 141 | PARSE_OPT_HELP = -1, | 141 | PARSE_OPT_HELP = -1, |
| 142 | PARSE_OPT_DONE, | 142 | PARSE_OPT_DONE, |
| 143 | PARSE_OPT_LIST, | ||
| 143 | PARSE_OPT_UNKNOWN, | 144 | PARSE_OPT_UNKNOWN, |
| 144 | }; | 145 | }; |
| 145 | 146 | ||
diff --git a/tools/perf/util/path.c b/tools/perf/util/path.c index bd7497711424..a8c49548ca48 100644 --- a/tools/perf/util/path.c +++ b/tools/perf/util/path.c | |||
| @@ -22,7 +22,7 @@ static const char *get_perf_dir(void) | |||
| 22 | return "."; | 22 | return "."; |
| 23 | } | 23 | } |
| 24 | 24 | ||
| 25 | #ifdef NO_STRLCPY | 25 | #ifndef HAVE_STRLCPY |
| 26 | size_t strlcpy(char *dest, const char *src, size_t size) | 26 | size_t strlcpy(char *dest, const char *src, size_t size) |
| 27 | { | 27 | { |
| 28 | size_t ret = strlen(src); | 28 | size_t ret = strlen(src); |
diff --git a/tools/perf/util/perf_regs.h b/tools/perf/util/perf_regs.h index 316dbe7f86ed..5a4f2b6f3738 100644 --- a/tools/perf/util/perf_regs.h +++ b/tools/perf/util/perf_regs.h | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | #ifndef __PERF_REGS_H | 1 | #ifndef __PERF_REGS_H |
| 2 | #define __PERF_REGS_H | 2 | #define __PERF_REGS_H |
| 3 | 3 | ||
| 4 | #ifndef NO_PERF_REGS | 4 | #ifdef HAVE_PERF_REGS |
| 5 | #include <perf_regs.h> | 5 | #include <perf_regs.h> |
| 6 | #else | 6 | #else |
| 7 | #define PERF_REGS_MASK 0 | 7 | #define PERF_REGS_MASK 0 |
| @@ -10,5 +10,5 @@ static inline const char *perf_reg_name(int id __maybe_unused) | |||
| 10 | { | 10 | { |
| 11 | return NULL; | 11 | return NULL; |
| 12 | } | 12 | } |
| 13 | #endif /* NO_PERF_REGS */ | 13 | #endif /* HAVE_PERF_REGS */ |
| 14 | #endif /* __PERF_REGS_H */ | 14 | #endif /* __PERF_REGS_H */ |
diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h index 12d634792de5..5786f323b597 100644 --- a/tools/perf/util/sort.h +++ b/tools/perf/util/sort.h | |||
| @@ -43,6 +43,15 @@ extern struct sort_entry sort_sym_from; | |||
| 43 | extern struct sort_entry sort_sym_to; | 43 | extern struct sort_entry sort_sym_to; |
| 44 | extern enum sort_type sort__first_dimension; | 44 | extern enum sort_type sort__first_dimension; |
| 45 | 45 | ||
| 46 | struct he_stat { | ||
| 47 | u64 period; | ||
| 48 | u64 period_sys; | ||
| 49 | u64 period_us; | ||
| 50 | u64 period_guest_sys; | ||
| 51 | u64 period_guest_us; | ||
| 52 | u32 nr_events; | ||
| 53 | }; | ||
| 54 | |||
| 46 | /** | 55 | /** |
| 47 | * struct hist_entry - histogram entry | 56 | * struct hist_entry - histogram entry |
| 48 | * | 57 | * |
| @@ -52,16 +61,11 @@ extern enum sort_type sort__first_dimension; | |||
| 52 | struct hist_entry { | 61 | struct hist_entry { |
| 53 | struct rb_node rb_node_in; | 62 | struct rb_node rb_node_in; |
| 54 | struct rb_node rb_node; | 63 | struct rb_node rb_node; |
| 55 | u64 period; | 64 | struct he_stat stat; |
| 56 | u64 period_sys; | ||
| 57 | u64 period_us; | ||
| 58 | u64 period_guest_sys; | ||
| 59 | u64 period_guest_us; | ||
| 60 | struct map_symbol ms; | 65 | struct map_symbol ms; |
| 61 | struct thread *thread; | 66 | struct thread *thread; |
| 62 | u64 ip; | 67 | u64 ip; |
| 63 | s32 cpu; | 68 | s32 cpu; |
| 64 | u32 nr_events; | ||
| 65 | 69 | ||
| 66 | /* XXX These two should move to some tree widget lib */ | 70 | /* XXX These two should move to some tree widget lib */ |
| 67 | u16 row_offset; | 71 | u16 row_offset; |
| @@ -73,12 +77,13 @@ struct hist_entry { | |||
| 73 | u8 filtered; | 77 | u8 filtered; |
| 74 | char *srcline; | 78 | char *srcline; |
| 75 | struct symbol *parent; | 79 | struct symbol *parent; |
| 80 | unsigned long position; | ||
| 76 | union { | 81 | union { |
| 77 | unsigned long position; | ||
| 78 | struct hist_entry *pair; | 82 | struct hist_entry *pair; |
| 79 | struct rb_root sorted_chain; | 83 | struct rb_root sorted_chain; |
| 80 | }; | 84 | }; |
| 81 | struct branch_info *branch_info; | 85 | struct branch_info *branch_info; |
| 86 | struct hists *hists; | ||
| 82 | struct callchain_root callchain[0]; | 87 | struct callchain_root callchain[0]; |
| 83 | }; | 88 | }; |
| 84 | 89 | ||
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index b441b07172b7..8b6ef7fac745 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h | |||
| @@ -12,7 +12,7 @@ | |||
| 12 | #include <byteswap.h> | 12 | #include <byteswap.h> |
| 13 | #include <libgen.h> | 13 | #include <libgen.h> |
| 14 | 14 | ||
| 15 | #ifndef NO_LIBELF_SUPPORT | 15 | #ifdef LIBELF_SUPPORT |
| 16 | #include <libelf.h> | 16 | #include <libelf.h> |
| 17 | #include <gelf.h> | 17 | #include <gelf.h> |
| 18 | #include <elf.h> | 18 | #include <elf.h> |
| @@ -46,10 +46,10 @@ char *strxfrchar(char *s, char from, char to); | |||
| 46 | * libelf 0.8.x and earlier do not support ELF_C_READ_MMAP; | 46 | * libelf 0.8.x and earlier do not support ELF_C_READ_MMAP; |
| 47 | * for newer versions we can use mmap to reduce memory usage: | 47 | * for newer versions we can use mmap to reduce memory usage: |
| 48 | */ | 48 | */ |
| 49 | #ifdef LIBELF_NO_MMAP | 49 | #ifdef LIBELF_MMAP |
| 50 | # define PERF_ELF_C_READ_MMAP ELF_C_READ | ||
| 51 | #else | ||
| 52 | # define PERF_ELF_C_READ_MMAP ELF_C_READ_MMAP | 50 | # define PERF_ELF_C_READ_MMAP ELF_C_READ_MMAP |
| 51 | #else | ||
| 52 | # define PERF_ELF_C_READ_MMAP ELF_C_READ | ||
| 53 | #endif | 53 | #endif |
| 54 | 54 | ||
| 55 | #ifndef DMGL_PARAMS | 55 | #ifndef DMGL_PARAMS |
| @@ -233,7 +233,7 @@ struct symsrc { | |||
| 233 | int fd; | 233 | int fd; |
| 234 | enum dso_binary_type type; | 234 | enum dso_binary_type type; |
| 235 | 235 | ||
| 236 | #ifndef NO_LIBELF_SUPPORT | 236 | #ifdef LIBELF_SUPPORT |
| 237 | Elf *elf; | 237 | Elf *elf; |
| 238 | GElf_Ehdr ehdr; | 238 | GElf_Ehdr ehdr; |
| 239 | 239 | ||
diff --git a/tools/perf/util/unwind.h b/tools/perf/util/unwind.h index a78c8b303bb5..cb6bc503a792 100644 --- a/tools/perf/util/unwind.h +++ b/tools/perf/util/unwind.h | |||
| @@ -13,7 +13,7 @@ struct unwind_entry { | |||
| 13 | 13 | ||
| 14 | typedef int (*unwind_entry_cb_t)(struct unwind_entry *entry, void *arg); | 14 | typedef int (*unwind_entry_cb_t)(struct unwind_entry *entry, void *arg); |
| 15 | 15 | ||
| 16 | #ifndef NO_LIBUNWIND_SUPPORT | 16 | #ifdef LIBUNWIND_SUPPORT |
| 17 | int unwind__get_entries(unwind_entry_cb_t cb, void *arg, | 17 | int unwind__get_entries(unwind_entry_cb_t cb, void *arg, |
| 18 | struct machine *machine, | 18 | struct machine *machine, |
| 19 | struct thread *thread, | 19 | struct thread *thread, |
| @@ -31,5 +31,5 @@ unwind__get_entries(unwind_entry_cb_t cb __maybe_unused, | |||
| 31 | { | 31 | { |
| 32 | return 0; | 32 | return 0; |
| 33 | } | 33 | } |
| 34 | #endif /* NO_LIBUNWIND_SUPPORT */ | 34 | #endif /* LIBUNWIND_SUPPORT */ |
| 35 | #endif /* __UNWIND_H */ | 35 | #endif /* __UNWIND_H */ |
diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c index 2055cf38041c..99664598bc1a 100644 --- a/tools/perf/util/util.c +++ b/tools/perf/util/util.c | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | #include "../perf.h" | 1 | #include "../perf.h" |
| 2 | #include "util.h" | 2 | #include "util.h" |
| 3 | #include <sys/mman.h> | 3 | #include <sys/mman.h> |
| 4 | #ifndef NO_BACKTRACE | 4 | #ifdef BACKTRACE_SUPPORT |
| 5 | #include <execinfo.h> | 5 | #include <execinfo.h> |
| 6 | #endif | 6 | #endif |
| 7 | #include <stdio.h> | 7 | #include <stdio.h> |
| @@ -165,7 +165,7 @@ size_t hex_width(u64 v) | |||
| 165 | } | 165 | } |
| 166 | 166 | ||
| 167 | /* Obtain a backtrace and print it to stdout. */ | 167 | /* Obtain a backtrace and print it to stdout. */ |
| 168 | #ifndef NO_BACKTRACE | 168 | #ifdef BACKTRACE_SUPPORT |
| 169 | void dump_stack(void) | 169 | void dump_stack(void) |
| 170 | { | 170 | { |
| 171 | void *array[16]; | 171 | void *array[16]; |
