From 6089327f5424f227bb6a8cf92363c2617e054453 Mon Sep 17 00:00:00 2001 From: Kan Liang Date: Fri, 12 May 2017 07:51:13 -0700 Subject: perf/x86: Add sysfs entry to freeze counters on SMI Currently, the SMIs are visible to all performance counters, because many users want to measure everything including SMIs. But in some cases, the SMI cycles should not be counted - for example, to calculate the cost of an SMI itself. So a knob is needed. When setting FREEZE_WHILE_SMM bit in IA32_DEBUGCTL, all performance counters will be effected. There is no way to do per-counter freeze on SMI. So it should not use the per-event interface (e.g. ioctl or event attribute) to set FREEZE_WHILE_SMM bit. Adds sysfs entry /sys/device/cpu/freeze_on_smi to set FREEZE_WHILE_SMM bit in IA32_DEBUGCTL. When set, freezes perfmon and trace messages while in SMM. Value has to be 0 or 1. It will be applied to all processors. Also serialize the entire setting so we don't get multiple concurrent threads trying to update to different values. Signed-off-by: Kan Liang Signed-off-by: Peter Zijlstra (Intel) Reviewed-by: Thomas Gleixner Cc: Alexander Shishkin Cc: Arnaldo Carvalho de Melo Cc: Jiri Olsa Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Vince Weaver Cc: acme@kernel.org Cc: bp@alien8.de Cc: jolsa@kernel.org Link: http://lkml.kernel.org/r/1494600673-244667-1-git-send-email-kan.liang@intel.com Signed-off-by: Ingo Molnar --- arch/x86/events/core.c | 10 +++++++ arch/x86/events/intel/core.c | 63 ++++++++++++++++++++++++++++++++++++++++ arch/x86/events/perf_event.h | 3 ++ arch/x86/include/asm/msr-index.h | 2 ++ 4 files changed, 78 insertions(+) diff --git a/arch/x86/events/core.c b/arch/x86/events/core.c index 580b60f5ac83..e6f5e4b163ac 100644 --- a/arch/x86/events/core.c +++ b/arch/x86/events/core.c @@ -1750,6 +1750,8 @@ ssize_t x86_event_sysfs_show(char *page, u64 config, u64 event) return ret; } +static struct attribute_group x86_pmu_attr_group; + static int __init init_hw_perf_events(void) { struct x86_pmu_quirk *quirk; @@ -1813,6 +1815,14 @@ static int __init init_hw_perf_events(void) x86_pmu_events_group.attrs = tmp; } + if (x86_pmu.attrs) { + struct attribute **tmp; + + tmp = merge_attr(x86_pmu_attr_group.attrs, x86_pmu.attrs); + if (!WARN_ON(!tmp)) + x86_pmu_attr_group.attrs = tmp; + } + pr_info("... version: %d\n", x86_pmu.version); pr_info("... bit width: %d\n", x86_pmu.cntval_bits); pr_info("... generic registers: %d\n", x86_pmu.num_counters); diff --git a/arch/x86/events/intel/core.c b/arch/x86/events/intel/core.c index a6d91d4e37a1..da9047eec7ba 100644 --- a/arch/x86/events/intel/core.c +++ b/arch/x86/events/intel/core.c @@ -3160,6 +3160,19 @@ err: return -ENOMEM; } +static void flip_smm_bit(void *data) +{ + unsigned long set = *(unsigned long *)data; + + if (set > 0) { + msr_set_bit(MSR_IA32_DEBUGCTLMSR, + DEBUGCTLMSR_FREEZE_IN_SMM_BIT); + } else { + msr_clear_bit(MSR_IA32_DEBUGCTLMSR, + DEBUGCTLMSR_FREEZE_IN_SMM_BIT); + } +} + static void intel_pmu_cpu_starting(int cpu) { struct cpu_hw_events *cpuc = &per_cpu(cpu_hw_events, cpu); @@ -3174,6 +3187,8 @@ static void intel_pmu_cpu_starting(int cpu) cpuc->lbr_sel = NULL; + flip_smm_bit(&x86_pmu.attr_freeze_on_smi); + if (!cpuc->shared_regs) return; @@ -3595,6 +3610,52 @@ static struct attribute *hsw_events_attrs[] = { NULL }; +static ssize_t freeze_on_smi_show(struct device *cdev, + struct device_attribute *attr, + char *buf) +{ + return sprintf(buf, "%lu\n", x86_pmu.attr_freeze_on_smi); +} + +static DEFINE_MUTEX(freeze_on_smi_mutex); + +static ssize_t freeze_on_smi_store(struct device *cdev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long val; + ssize_t ret; + + ret = kstrtoul(buf, 0, &val); + if (ret) + return ret; + + if (val > 1) + return -EINVAL; + + mutex_lock(&freeze_on_smi_mutex); + + if (x86_pmu.attr_freeze_on_smi == val) + goto done; + + x86_pmu.attr_freeze_on_smi = val; + + get_online_cpus(); + on_each_cpu(flip_smm_bit, &val, 1); + put_online_cpus(); +done: + mutex_unlock(&freeze_on_smi_mutex); + + return count; +} + +static DEVICE_ATTR_RW(freeze_on_smi); + +static struct attribute *intel_pmu_attrs[] = { + &dev_attr_freeze_on_smi.attr, + NULL, +}; + __init int intel_pmu_init(void) { union cpuid10_edx edx; @@ -3641,6 +3702,8 @@ __init int intel_pmu_init(void) x86_pmu.max_pebs_events = min_t(unsigned, MAX_PEBS_EVENTS, x86_pmu.num_counters); + + x86_pmu.attrs = intel_pmu_attrs; /* * Quirk: v2 perfmon does not report fixed-purpose events, so * assume at least 3 events, when not running in a hypervisor: diff --git a/arch/x86/events/perf_event.h b/arch/x86/events/perf_event.h index be3d36254040..53728eea1bed 100644 --- a/arch/x86/events/perf_event.h +++ b/arch/x86/events/perf_event.h @@ -562,6 +562,9 @@ struct x86_pmu { ssize_t (*events_sysfs_show)(char *page, u64 config); struct attribute **cpu_events; + unsigned long attr_freeze_on_smi; + struct attribute **attrs; + /* * CPU Hotplug hooks */ diff --git a/arch/x86/include/asm/msr-index.h b/arch/x86/include/asm/msr-index.h index 673f9ac50f6d..18b162322eff 100644 --- a/arch/x86/include/asm/msr-index.h +++ b/arch/x86/include/asm/msr-index.h @@ -137,6 +137,8 @@ #define DEBUGCTLMSR_BTS_OFF_OS (1UL << 9) #define DEBUGCTLMSR_BTS_OFF_USR (1UL << 10) #define DEBUGCTLMSR_FREEZE_LBRS_ON_PMI (1UL << 11) +#define DEBUGCTLMSR_FREEZE_IN_SMM_BIT 14 +#define DEBUGCTLMSR_FREEZE_IN_SMM (1UL << DEBUGCTLMSR_FREEZE_IN_SMM_BIT) #define MSR_PEBS_FRONTEND 0x000003f7 -- cgit v1.2.3 From 85c617abc786d7da9e95c0b4174159864dd3f85c Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 22 May 2017 12:03:49 +0300 Subject: perf/core: Remove some dead code perf_init_event() can't return NULL. If it did, the error handling is incomplete and we would crash. I have removed this confusing dead code. Signed-off-by: Dan Carpenter Signed-off-by: Peter Zijlstra (Intel) Cc: Alexander Shishkin Cc: Arnaldo Carvalho de Melo Cc: Arnaldo Carvalho de Melo Cc: Jiri Olsa Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Thomas Gleixner Cc: Vince Weaver Link: http://lkml.kernel.org/r/20170522090348.5g7yyld5en3yeky4@mwanda Signed-off-by: Ingo Molnar --- kernel/events/core.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/kernel/events/core.c b/kernel/events/core.c index 6e75a5c9412d..0028efa0abc3 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -9172,7 +9172,7 @@ static int perf_try_init_event(struct pmu *pmu, struct perf_event *event) static struct pmu *perf_init_event(struct perf_event *event) { - struct pmu *pmu = NULL; + struct pmu *pmu; int idx; int ret; @@ -9456,9 +9456,7 @@ perf_event_alloc(struct perf_event_attr *attr, int cpu, } pmu = perf_init_event(event); - if (!pmu) - goto err_ns; - else if (IS_ERR(pmu)) { + if (IS_ERR(pmu)) { err = PTR_ERR(pmu); goto err_ns; } -- cgit v1.2.3 From 36cc2b9222b5106de34085c4dd8635ac67ef5cba Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 22 May 2017 12:04:18 +0300 Subject: perf/core: Fix error handling in perf_event_alloc() We don't set an error code here which means that perf_event_alloc() returns ERR_PTR(0) (in other words NULL). The callers are not expecting that and would Oops. Signed-off-by: Dan Carpenter Signed-off-by: Peter Zijlstra (Intel) Cc: Alexander Shishkin Cc: Arnaldo Carvalho de Melo Cc: Arnaldo Carvalho de Melo Cc: Jiri Olsa Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Thomas Gleixner Cc: Vince Weaver Fixes: 375637bc5249 ("perf/core: Introduce address range filtering") Link: http://lkml.kernel.org/r/20170522090418.hvs6icgpdo53wkn5@mwanda Signed-off-by: Ingo Molnar --- kernel/events/core.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/kernel/events/core.c b/kernel/events/core.c index 0028efa0abc3..f8c27d3ef3a1 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -9469,8 +9469,10 @@ perf_event_alloc(struct perf_event_attr *attr, int cpu, event->addr_filters_offs = kcalloc(pmu->nr_addr_filters, sizeof(unsigned long), GFP_KERNEL); - if (!event->addr_filters_offs) + if (!event->addr_filters_offs) { + err = -ENOMEM; goto err_per_task; + } /* force hw sync on the address filters */ event->addr_filters_gen = 1; -- cgit v1.2.3 From ba5213ae6b88fb170c4771fef6553f759c7d8cdd Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Tue, 30 May 2017 11:45:12 +0200 Subject: perf/core: Correct event creation with PERF_FORMAT_GROUP Andi was asking about PERF_FORMAT_GROUP vs inherited events, which led to the discovery of a bug from commit: 3dab77fb1bf8 ("perf: Rework/fix the whole read vs group stuff") - PERF_SAMPLE_GROUP = 1U << 4, + PERF_SAMPLE_READ = 1U << 4, - if (attr->inherit && (attr->sample_type & PERF_SAMPLE_GROUP)) + if (attr->inherit && (attr->read_format & PERF_FORMAT_GROUP)) is a clear fail :/ While this changes user visible behaviour; it was previously possible to create an inherited event with PERF_SAMPLE_READ; this is deemed acceptible because its results were always incorrect. Reported-by: Andi Kleen Signed-off-by: Peter Zijlstra (Intel) Cc: Alexander Shishkin Cc: Arnaldo Carvalho de Melo Cc: Jiri Olsa Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Thomas Gleixner Cc: Vince Weaver Fixes: 3dab77fb1bf8 ("perf: Rework/fix the whole read vs group stuff") Link: http://lkml.kernel.org/r/20170530094512.dy2nljns2uq7qa3j@hirez.programming.kicks-ass.net Signed-off-by: Ingo Molnar --- kernel/events/core.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/kernel/events/core.c b/kernel/events/core.c index 3de0b98c4414..407dad6cf89a 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -5729,9 +5729,6 @@ static void perf_output_read_one(struct perf_output_handle *handle, __output_copy(handle, values, n * sizeof(u64)); } -/* - * XXX PERF_FORMAT_GROUP vs inherited events seems difficult. - */ static void perf_output_read_group(struct perf_output_handle *handle, struct perf_event *event, u64 enabled, u64 running) @@ -5776,6 +5773,13 @@ static void perf_output_read_group(struct perf_output_handle *handle, #define PERF_FORMAT_TOTAL_TIMES (PERF_FORMAT_TOTAL_TIME_ENABLED|\ PERF_FORMAT_TOTAL_TIME_RUNNING) +/* + * XXX PERF_SAMPLE_READ vs inherited events seems difficult. + * + * The problem is that its both hard and excessively expensive to iterate the + * child list, not to mention that its impossible to IPI the children running + * on another CPU, from interrupt/NMI context. + */ static void perf_output_read(struct perf_output_handle *handle, struct perf_event *event) { @@ -9462,9 +9466,10 @@ perf_event_alloc(struct perf_event_attr *attr, int cpu, local64_set(&hwc->period_left, hwc->sample_period); /* - * we currently do not support PERF_FORMAT_GROUP on inherited events + * We currently do not support PERF_SAMPLE_READ on inherited events. + * See perf_output_read(). */ - if (attr->inherit && (attr->read_format & PERF_FORMAT_GROUP)) + if (attr->inherit && (attr->sample_type & PERF_SAMPLE_READ)) goto err_ns; if (!has_branch_stack(event)) -- cgit v1.2.3 From d0fabd1cb8b70073a0f44f1cf8b663b5e7241c74 Mon Sep 17 00:00:00 2001 From: Matthias Kaehlcke Date: Tue, 23 May 2017 14:51:32 -0700 Subject: perf/core: Remove unused perf_cgroup_event_cgrp_time() function The function was added by commit e5d1367f17ba ("perf: Add cgroup support") in 2011 and hasn't been used since then. Removing it fixes the following warning when building with Clang: kernel/events/core.c:696:19: error: unused function 'perf_cgroup_event_cgrp_time' [-Werror,-Wunused-function] Signed-off-by: Matthias Kaehlcke Signed-off-by: Peter Zijlstra (Intel) Cc: Alexander Shishkin Cc: Arnaldo Carvalho de Melo Cc: Douglas Anderson Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/20170523215132.189049-1-mka@chromium.org Signed-off-by: Ingo Molnar --- kernel/events/core.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/kernel/events/core.c b/kernel/events/core.c index 407dad6cf89a..bc63f8db1b0d 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -925,11 +925,6 @@ static inline int is_cgroup_event(struct perf_event *event) return 0; } -static inline u64 perf_cgroup_event_cgrp_time(struct perf_event *event) -{ - return 0; -} - static inline void update_cgrp_time_from_event(struct perf_event *event) { } -- cgit v1.2.3 From c564f0db92b7f8d734ce530e42a540e12ae3d583 Mon Sep 17 00:00:00 2001 From: Jin Yao Date: Thu, 4 May 2017 22:58:14 +0800 Subject: perf report: Remove unnecessary check in annotate_browser_write() In annotate_browser_write(), if (dl->offset != -1 && percent_max != 0.0) { if (percent_max != 0.0) { ... } ... } The second check of (percent_max != 0.0) is not necessary, remove it. Signed-off-by: Yao Jin Acked-by: Milian Wolff Cc: Alexander Shishkin Cc: Andi Kleen Cc: Jiri Olsa Cc: Kan Liang Cc: Peter Zijlstra Cc: Yao Jin Link: http://lkml.kernel.org/r/1493909895-9668-2-git-send-email-yao.jin@linux.intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/browsers/annotate.c | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index d990ad08a3c6..52c1e8d672b5 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c @@ -132,21 +132,17 @@ static void annotate_browser__write(struct ui_browser *browser, void *entry, int } if (dl->offset != -1 && percent_max != 0.0) { - if (percent_max != 0.0) { - for (i = 0; i < ab->nr_events; i++) { - ui_browser__set_percent_color(browser, - bdl->samples[i].percent, - current_entry); - if (annotate_browser__opts.show_total_period) { - ui_browser__printf(browser, "%6" PRIu64 " ", - bdl->samples[i].nr); - } else { - ui_browser__printf(browser, "%6.2f ", - bdl->samples[i].percent); - } + for (i = 0; i < ab->nr_events; i++) { + ui_browser__set_percent_color(browser, + bdl->samples[i].percent, + current_entry); + if (annotate_browser__opts.show_total_period) { + ui_browser__printf(browser, "%6" PRIu64 " ", + bdl->samples[i].nr); + } else { + ui_browser__printf(browser, "%6.2f ", + bdl->samples[i].percent); } - } else { - ui_browser__write_nstring(browser, " ", 7 * ab->nr_events); } } else { ui_browser__set_percent_color(browser, 0, current_entry); -- cgit v1.2.3 From ec27ae1892f7f8119ce82535ffcc2889ea3bb3d8 Mon Sep 17 00:00:00 2001 From: Jin Yao Date: Thu, 4 May 2017 22:58:15 +0800 Subject: perf annotate browser: Display titles in left frame MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The annotate browser is divided into 2 frames. Left frame contains 3 columns (some platforms only have one column). For example: │26 int compute_flag() │27 { 22.80 1.20 │ sub $0x8,%rsp │25 int i; │ │27 i = rand() % 2; 22.78 1.20 1 │ → callq rand@plt While it's hard for user to understand what the data is. This patch adds the titles "Percent", "IPC" and "Cycle" on columns. Percent IPC Cycle │ │25 __attribute__((noinline)) │26 int compute_flag() │27 { 22.80 1.20 │ sub $0x8,%rsp │25 int i; │ │27 i = rand() % 2; 22.78 1.20 1 │ → callq rand@plt The titles are displayed at row 0 of annotate browser if row 0 doesn't have values of percent, ipc and cycle. Signed-off-by: Yao Jin Acked-by: Milian Wolff Cc: Alexander Shishkin Cc: Andi Kleen Cc: Jiri Olsa Cc: Kan Liang Cc: Peter Zijlstra Cc: Yao Jin Link: http://lkml.kernel.org/r/1493909895-9668-3-git-send-email-yao.jin@linux.intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/browsers/annotate.c | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index 52c1e8d672b5..7a03389b7a03 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c @@ -125,12 +125,21 @@ static void annotate_browser__write(struct ui_browser *browser, void *entry, int int i, pcnt_width = annotate_browser__pcnt_width(ab); double percent_max = 0.0; char bf[256]; + bool show_title = false; for (i = 0; i < ab->nr_events; i++) { if (bdl->samples[i].percent > percent_max) percent_max = bdl->samples[i].percent; } + if ((row == 0) && (dl->offset == -1 || percent_max == 0.0)) { + if (ab->have_cycles) { + if (dl->ipc == 0.0 && dl->cycles == 0) + show_title = true; + } else + show_title = true; + } + if (dl->offset != -1 && percent_max != 0.0) { for (i = 0; i < ab->nr_events; i++) { ui_browser__set_percent_color(browser, @@ -146,18 +155,27 @@ static void annotate_browser__write(struct ui_browser *browser, void *entry, int } } else { ui_browser__set_percent_color(browser, 0, current_entry); - ui_browser__write_nstring(browser, " ", 7 * ab->nr_events); + + if (!show_title) + ui_browser__write_nstring(browser, " ", 7 * ab->nr_events); + else + ui_browser__printf(browser, "%*s", 7, "Percent"); } if (ab->have_cycles) { if (dl->ipc) ui_browser__printf(browser, "%*.2f ", IPC_WIDTH - 1, dl->ipc); - else + else if (!show_title) ui_browser__write_nstring(browser, " ", IPC_WIDTH); + else + ui_browser__printf(browser, "%*s ", IPC_WIDTH - 1, "IPC"); + if (dl->cycles) ui_browser__printf(browser, "%*" PRIu64 " ", CYCLES_WIDTH - 1, dl->cycles); - else + else if (!show_title) ui_browser__write_nstring(browser, " ", CYCLES_WIDTH); + else + ui_browser__printf(browser, "%*s ", CYCLES_WIDTH - 1, "Cycle"); } SLsmg_write_char(' '); -- cgit v1.2.3 From 8c1cedb4466809f9d741a4088314783cb88680a9 Mon Sep 17 00:00:00 2001 From: Taeung Song Date: Mon, 8 May 2017 20:07:30 +0900 Subject: perf config: Invert an if statement to reduce nesting in cmd_config() Signed-off-by: Taeung Song Cc: Jiri Olsa Cc: Namhyung Kim Link: http://lkml.kernel.org/r/1494241650-32210-1-git-send-email-treeze.taeung@gmail.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-config.c | 44 +++++++++++++++++++++++--------------------- 1 file changed, 23 insertions(+), 21 deletions(-) diff --git a/tools/perf/builtin-config.c b/tools/perf/builtin-config.c index 80668fa7556e..75459668edb2 100644 --- a/tools/perf/builtin-config.c +++ b/tools/perf/builtin-config.c @@ -204,31 +204,33 @@ int cmd_config(int argc, const char **argv) } break; default: - if (argc) { - for (i = 0; argv[i]; i++) { - char *var, *value; - char *arg = strdup(argv[i]); - - if (!arg) { - pr_err("%s: strdup failed\n", __func__); - ret = -1; - break; - } + if (!argc) { + usage_with_options(config_usage, config_options); + break; + } - if (parse_config_arg(arg, &var, &value) < 0) { - free(arg); - ret = -1; - break; - } + for (i = 0; argv[i]; i++) { + char *var, *value; + char *arg = strdup(argv[i]); - if (value == NULL) - ret = show_spec_config(set, var); - else - ret = set_config(set, config_filename, var, value); + if (!arg) { + pr_err("%s: strdup failed\n", __func__); + ret = -1; + break; + } + + if (parse_config_arg(arg, &var, &value) < 0) { free(arg); + ret = -1; + break; } - } else - usage_with_options(config_usage, config_options); + + if (value == NULL) + ret = show_spec_config(set, var); + else + ret = set_config(set, config_filename, var, value); + free(arg); + } } perf_config_set__delete(set); -- cgit v1.2.3 From 36ce565114b4e7e3b83f40309675f6b1720957e4 Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Fri, 2 Jun 2017 08:48:10 -0700 Subject: perf script: Allow adding and removing fields With 'perf script' it is common that we just want to add or remove a field. Currently this requires figuring out the long list of default fields and specifying them first, and then adding/removing the new field. This patch adds a new + - syntax to merely add or remove fields, that allows more succint and clearer command lines For example to remove the comm field from PMU samples: Previously $ perf script -F tid,cpu,time,event,sym,ip,dso,period | head -1 swapper 0 [000] 504345.383126: 1 cycles: ffffffff90060c66 native_write_msr ([kernel.kallsyms]) with the new syntax perf script -F -comm | head -1 0 [000] 504345.383126: 1 cycles: ffffffff90060c66 native_write_msr ([kernel.kallsyms]) The new syntax cannot be mixed with normal overriding. v2: Fix example in description. Use tid vs pid. No functional changes. v3: Don't skip initialization when user specified explicit type. v4: Rebase. Remove empty line. Committer testing: # perf record -a usleep 1 [ perf record: Woken up 1 times to write data ] [ perf record: Captured and wrote 1.748 MB perf.data (14 samples) ] Without a explicit field list specified via -F, defaults to: # perf script | head -2 perf 6338 [000] 18467.058607: 1 cycles: ffffffff89060c36 native_write_msr (/lib/modules/4.11.0-rc8+/build/vmlinux) swapper 0 [001] 18467.058617: 1 cycles: ffffffff89060c36 native_write_msr (/lib/modules/4.11.0-rc8+/build/vmlinux) # Which is equivalent to: # perf script -F comm,tid,cpu,time,period,event,ip,sym,dso | head -2 perf 6338 [000] 18467.058607: 1 cycles: ffffffff89060c36 native_write_msr (/lib/modules/4.11.0-rc8+/build/vmlinux) swapper 0 [001] 18467.058617: 1 cycles: ffffffff89060c36 native_write_msr (/lib/modules/4.11.0-rc8+/build/vmlinux) # So if we want to remove the comm, as in your original example, we would have to figure out the default field list and remove ' comm' from it: # perf script -F tid,cpu,time,period,event,ip,sym,dso | head -2 6338 [000] 18467.058607: 1 cycles: ffffffff89060c36 native_write_msr (/lib/modules/4.11.0-rc8+/build/vmlinux) 0 [001] 18467.058617: 1 cycles: ffffffff89060c36 native_write_msr (/lib/modules/4.11.0-rc8+/build/vmlinux) # With your patch this becomes simpler, one can remove fields by prefixing them with '-': # perf script -F -comm | head -2 6338 [000] 18467.058607: 1 cycles: ffffffff89060c36 native_write_msr (/lib/modules/4.11.0-rc8+/build/vmlinux) 0 [001] 18467.058617: 1 cycles: ffffffff89060c36 native_write_msr (/lib/modules/4.11.0-rc8+/build/vmlinux) # Signed-off-by: Andi Kleen Acked-by: Jiri Olsa Tested-by: Arnaldo Carvalho de Melo Tested-by: Milian Wolff Link: http://lkml.kernel.org/r/20170602154810.15875-1-andi@firstfloor.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Documentation/perf-script.txt | 8 +++++++ tools/perf/builtin-script.c | 37 +++++++++++++++++++++++++++++--- 2 files changed, 42 insertions(+), 3 deletions(-) diff --git a/tools/perf/Documentation/perf-script.txt b/tools/perf/Documentation/perf-script.txt index 3517e204a2b3..3eca8c0d3c7b 100644 --- a/tools/perf/Documentation/perf-script.txt +++ b/tools/perf/Documentation/perf-script.txt @@ -130,6 +130,14 @@ OPTIONS i.e., the specified fields apply to all event types if the type string is not given. + In addition to overriding fields, it is also possible to add or remove + fields from the defaults. For example + + -F -cpu,+insn + + removes the cpu field and adds the insn field. Adding/removing fields + cannot be mixed with normal overriding. + The arguments are processed in the order received. A later usage can reset a prior request. e.g.: diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index 4761b0d7fcb5..afa84debc5c4 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c @@ -1727,6 +1727,7 @@ static int parse_output_fields(const struct option *opt __maybe_unused, int rc = 0; char *str = strdup(arg); int type = -1; + enum { DEFAULT, SET, ADD, REMOVE } change = DEFAULT; if (!str) return -ENOMEM; @@ -1772,6 +1773,10 @@ static int parse_output_fields(const struct option *opt __maybe_unused, goto out; } + /* Don't override defaults for +- */ + if (strchr(str, '+') || strchr(str, '-')) + goto parse; + if (output_set_by_user()) pr_warning("Overriding previous field request for all events.\n"); @@ -1782,13 +1787,30 @@ static int parse_output_fields(const struct option *opt __maybe_unused, } } +parse: for (tok = strtok_r(tok, ",", &strtok_saveptr); tok; tok = strtok_r(NULL, ",", &strtok_saveptr)) { + if (*tok == '+') { + if (change == SET) + goto out_badmix; + change = ADD; + tok++; + } else if (*tok == '-') { + if (change == SET) + goto out_badmix; + change = REMOVE; + tok++; + } else { + if (change != SET && change != DEFAULT) + goto out_badmix; + change = SET; + } + for (i = 0; i < imax; ++i) { if (strcmp(tok, all_output_options[i].str) == 0) break; } if (i == imax && strcmp(tok, "flags") == 0) { - print_flags = true; + print_flags = change == REMOVE ? false : true; continue; } if (i == imax) { @@ -1805,8 +1827,12 @@ static int parse_output_fields(const struct option *opt __maybe_unused, if (output[j].invalid_fields & all_output_options[i].field) { pr_warning("\'%s\' not valid for %s events. Ignoring.\n", all_output_options[i].str, event_type(j)); - } else - output[j].fields |= all_output_options[i].field; + } else { + if (change == REMOVE) + output[j].fields &= ~all_output_options[i].field; + else + output[j].fields |= all_output_options[i].field; + } } } else { if (output[type].invalid_fields & all_output_options[i].field) { @@ -1826,7 +1852,11 @@ static int parse_output_fields(const struct option *opt __maybe_unused, "Events will not be displayed.\n", event_type(type)); } } + goto out; +out_badmix: + fprintf(stderr, "Cannot mix +-field with overridden fields\n"); + rc = -EINVAL; out: free(str); return rc; @@ -2444,6 +2474,7 @@ int cmd_script(int argc, const char **argv) symbol__config_symfs), OPT_CALLBACK('F', "fields", NULL, "str", "comma separated output fields prepend with 'type:'. " + "+field to add and -field to remove." "Valid types: hw,sw,trace,raw. " "Fields: comm,tid,pid,time,cpu,event,trace,ip,sym,dso," "addr,symoff,period,iregs,brstack,brstacksym,flags," -- cgit v1.2.3 From 6c3466435b03fb84647f5ad413f98f2ccb12b5c2 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 16 Jun 2017 11:39:15 -0300 Subject: tools: Adopt __noreturn from kernel sources To have a more compact way to specify that a function doesn't return, instead of the open coded: __attribute__((noreturn)) And use it instead of the tools/perf/ specific variation, NORETURN. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-l0y144qzixcy5t4c6i7pdiqj@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/include/linux/compiler-gcc.h | 2 ++ tools/perf/util/scripting-engines/trace-event-python.c | 3 ++- tools/perf/util/usage.c | 6 +++--- tools/perf/util/util.h | 10 ++++------ 4 files changed, 11 insertions(+), 10 deletions(-) diff --git a/tools/include/linux/compiler-gcc.h b/tools/include/linux/compiler-gcc.h index 825d44f89a29..a3deb74cb070 100644 --- a/tools/include/linux/compiler-gcc.h +++ b/tools/include/linux/compiler-gcc.h @@ -19,3 +19,5 @@ /* &a[0] degrades to a pointer: a different type from an array */ #define __must_be_array(a) BUILD_BUG_ON_ZERO(__same_type((a), &(a)[0])) + +#define __noreturn __attribute__((noreturn)) diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c index 40de3cb40d21..57b7a00e6f16 100644 --- a/tools/perf/util/scripting-engines/trace-event-python.c +++ b/tools/perf/util/scripting-engines/trace-event-python.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include "../../perf.h" @@ -84,7 +85,7 @@ struct tables { static struct tables tables_global; -static void handler_call_die(const char *handler_name) NORETURN; +static void handler_call_die(const char *handler_name) __noreturn; static void handler_call_die(const char *handler_name) { PyErr_Print(); diff --git a/tools/perf/util/usage.c b/tools/perf/util/usage.c index 996046a66fe5..aacb65e079aa 100644 --- a/tools/perf/util/usage.c +++ b/tools/perf/util/usage.c @@ -16,13 +16,13 @@ static void report(const char *prefix, const char *err, va_list params) fprintf(stderr, " %s%s\n", prefix, msg); } -static NORETURN void usage_builtin(const char *err) +static __noreturn void usage_builtin(const char *err) { fprintf(stderr, "\n Usage: %s\n", err); exit(129); } -static NORETURN void die_builtin(const char *err, va_list params) +static __noreturn void die_builtin(const char *err, va_list params) { report(" Fatal: ", err, params); exit(128); @@ -40,7 +40,7 @@ static void warn_builtin(const char *warn, va_list params) /* If we are in a dlopen()ed .so write to a global variable would segfault * (ugh), so keep things static. */ -static void (*usage_routine)(const char *err) NORETURN = usage_builtin; +static void (*usage_routine)(const char *err) __noreturn = usage_builtin; static void (*error_routine)(const char *err, va_list params) = error_builtin; static void (*warn_routine)(const char *err, va_list params) = warn_builtin; diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h index 5dfb9bb6482d..024b108dbbf6 100644 --- a/tools/perf/util/util.h +++ b/tools/perf/util/util.h @@ -11,20 +11,18 @@ #include #include #include +#include #include -#ifdef __GNUC__ -#define NORETURN __attribute__((__noreturn__)) -#else -#define NORETURN +#ifndef __GNUC__ #ifndef __attribute__ #define __attribute__(x) #endif #endif /* General helper functions */ -void usage(const char *err) NORETURN; -void die(const char *err, ...) NORETURN __attribute__((format (printf, 1, 2))); +void usage(const char *err) __noreturn; +void die(const char *err, ...) __noreturn __attribute__((format (printf, 1, 2))); int error(const char *err, ...) __attribute__((format (printf, 1, 2))); void warning(const char *err, ...) __attribute__((format (printf, 1, 2))); -- cgit v1.2.3 From afaed6d3e4aa56e939b496aafa5c97852e223122 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 16 Jun 2017 11:57:54 -0300 Subject: tools: Adopt __printf from kernel sources To have a more compact way to ask the compiler to perform printf like vargargs validation. v2: Fixed up build on arm, squashing a patch by Kim Phillips, thanks! Cc: Adrian Hunter Cc: Alexander Shishkin Cc: David Ahern Cc: Jiri Olsa Cc: Kim Phillips Cc: Mathieu Poirier Cc: Namhyung Kim Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-dopkqmmuqs04cxzql0024nnu@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/include/linux/compiler-gcc.h | 2 ++ tools/perf/arch/arm/util/cs-etm.c | 4 ++-- tools/perf/util/cache.h | 3 ++- tools/perf/util/debug.h | 11 ++++++----- tools/perf/util/intel-pt-decoder/intel-pt-log.h | 4 ++-- tools/perf/util/probe-event.h | 4 ++-- tools/perf/util/strbuf.h | 4 ++-- tools/perf/util/util.h | 12 +++--------- 8 files changed, 21 insertions(+), 23 deletions(-) diff --git a/tools/include/linux/compiler-gcc.h b/tools/include/linux/compiler-gcc.h index a3deb74cb070..f531b258ff94 100644 --- a/tools/include/linux/compiler-gcc.h +++ b/tools/include/linux/compiler-gcc.h @@ -21,3 +21,5 @@ #define __must_be_array(a) BUILD_BUG_ON_ZERO(__same_type((a), &(a)[0])) #define __noreturn __attribute__((noreturn)) + +#define __printf(a, b) __attribute__((format(printf, a, b))) diff --git a/tools/perf/arch/arm/util/cs-etm.c b/tools/perf/arch/arm/util/cs-etm.c index 29361d9b635a..02a649bfec3c 100644 --- a/tools/perf/arch/arm/util/cs-etm.c +++ b/tools/perf/arch/arm/util/cs-etm.c @@ -17,6 +17,7 @@ #include #include +#include #include #include #include @@ -583,8 +584,7 @@ static FILE *cs_device__open_file(const char *name) } -static __attribute__((format(printf, 2, 3))) -int cs_device__print_file(const char *name, const char *fmt, ...) +static int __printf(2, 3) cs_device__print_file(const char *name, const char *fmt, ...) { va_list args; FILE *file; diff --git a/tools/perf/util/cache.h b/tools/perf/util/cache.h index 0328f297a748..0175765c05b9 100644 --- a/tools/perf/util/cache.h +++ b/tools/perf/util/cache.h @@ -5,6 +5,7 @@ #include #include "../ui/ui.h" +#include #include #define CMD_EXEC_PATH "--exec-path" @@ -24,6 +25,6 @@ static inline int is_absolute_path(const char *path) return path[0] == '/'; } -char *mkpath(const char *fmt, ...) __attribute__((format (printf, 1, 2))); +char *mkpath(const char *fmt, ...) __printf(1, 2); #endif /* __PERF_CACHE_H */ diff --git a/tools/perf/util/debug.h b/tools/perf/util/debug.h index 8a23ea1a71c7..c818bdb1c1ab 100644 --- a/tools/perf/util/debug.h +++ b/tools/perf/util/debug.h @@ -4,6 +4,7 @@ #include #include +#include #include "event.h" #include "../ui/helpline.h" #include "../ui/progress.h" @@ -40,16 +41,16 @@ extern int debug_data_convert; #define STRERR_BUFSIZE 128 /* For the buffer size of str_error_r */ -int dump_printf(const char *fmt, ...) __attribute__((format(printf, 1, 2))); +int dump_printf(const char *fmt, ...) __printf(1, 2); void trace_event(union perf_event *event); -int ui__error(const char *format, ...) __attribute__((format(printf, 1, 2))); -int ui__warning(const char *format, ...) __attribute__((format(printf, 1, 2))); +int ui__error(const char *format, ...) __printf(1, 2); +int ui__warning(const char *format, ...) __printf(1, 2); void pr_stat(const char *fmt, ...); -int eprintf(int level, int var, const char *fmt, ...) __attribute__((format(printf, 3, 4))); -int eprintf_time(int level, int var, u64 t, const char *fmt, ...) __attribute__((format(printf, 4, 5))); +int eprintf(int level, int var, const char *fmt, ...) __printf(3, 4); +int eprintf_time(int level, int var, u64 t, const char *fmt, ...) __printf(4, 5); int veprintf(int level, int var, const char *fmt, va_list args); int perf_debug_option(const char *str); diff --git a/tools/perf/util/intel-pt-decoder/intel-pt-log.h b/tools/perf/util/intel-pt-decoder/intel-pt-log.h index debe751dc3d6..45b64f93f358 100644 --- a/tools/perf/util/intel-pt-decoder/intel-pt-log.h +++ b/tools/perf/util/intel-pt-decoder/intel-pt-log.h @@ -16,6 +16,7 @@ #ifndef INCLUDE__INTEL_PT_LOG_H__ #define INCLUDE__INTEL_PT_LOG_H__ +#include #include #include @@ -34,8 +35,7 @@ void __intel_pt_log_insn(struct intel_pt_insn *intel_pt_insn, uint64_t ip); void __intel_pt_log_insn_no_data(struct intel_pt_insn *intel_pt_insn, uint64_t ip); -__attribute__((format(printf, 1, 2))) -void __intel_pt_log(const char *fmt, ...); +void __intel_pt_log(const char *fmt, ...) __printf(1, 2); #define intel_pt_log(fmt, ...) \ do { \ diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h index 373842656fb6..5812947418dd 100644 --- a/tools/perf/util/probe-event.h +++ b/tools/perf/util/probe-event.h @@ -1,6 +1,7 @@ #ifndef _PROBE_EVENT_H #define _PROBE_EVENT_H +#include #include #include "intlist.h" @@ -171,8 +172,7 @@ void arch__fix_tev_from_maps(struct perf_probe_event *pev, struct symbol *sym); /* If there is no space to write, returns -E2BIG. */ -int e_snprintf(char *str, size_t size, const char *format, ...) - __attribute__((format(printf, 3, 4))); +int e_snprintf(char *str, size_t size, const char *format, ...) __printf(3, 4); /* Maximum index number of event-name postfix */ #define MAX_EVENT_INDEX 1024 diff --git a/tools/perf/util/strbuf.h b/tools/perf/util/strbuf.h index 318424ea561d..802d743378af 100644 --- a/tools/perf/util/strbuf.h +++ b/tools/perf/util/strbuf.h @@ -42,6 +42,7 @@ #include #include #include +#include #include extern char strbuf_slopbuf[]; @@ -85,8 +86,7 @@ static inline int strbuf_addstr(struct strbuf *sb, const char *s) { return strbuf_add(sb, s, strlen(s)); } -__attribute__((format(printf,2,3))) -int strbuf_addf(struct strbuf *sb, const char *fmt, ...); +int strbuf_addf(struct strbuf *sb, const char *fmt, ...) __printf(2, 3); /* XXX: if read fails, any partial read is undone */ ssize_t strbuf_read(struct strbuf *, int fd, ssize_t hint); diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h index 024b108dbbf6..21c6db173bcc 100644 --- a/tools/perf/util/util.h +++ b/tools/perf/util/util.h @@ -14,17 +14,11 @@ #include #include -#ifndef __GNUC__ -#ifndef __attribute__ -#define __attribute__(x) -#endif -#endif - /* General helper functions */ void usage(const char *err) __noreturn; -void die(const char *err, ...) __noreturn __attribute__((format (printf, 1, 2))); -int error(const char *err, ...) __attribute__((format (printf, 1, 2))); -void warning(const char *err, ...) __attribute__((format (printf, 1, 2))); +void die(const char *err, ...) __noreturn __printf(1, 2); +int error(const char *err, ...) __printf(1, 2); +void warning(const char *err, ...) __printf(1, 2); void set_warning_routine(void (*routine)(const char *err, va_list params)); -- cgit v1.2.3 From 3ee350fb8a2b30fe47dd9e3b299dff0178fc8c88 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 16 Jun 2017 11:57:54 -0300 Subject: tools: Adopt __scanf from kernel sources To have a more compact way to ask the compiler to perform scanf like argument validation. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-yzqrhfjrn26lqqtwf55egg0h@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/include/linux/compiler-gcc.h | 1 + tools/perf/util/pmu.h | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/tools/include/linux/compiler-gcc.h b/tools/include/linux/compiler-gcc.h index f531b258ff94..2846094aad4d 100644 --- a/tools/include/linux/compiler-gcc.h +++ b/tools/include/linux/compiler-gcc.h @@ -23,3 +23,4 @@ #define __noreturn __attribute__((noreturn)) #define __printf(a, b) __attribute__((format(printf, a, b))) +#define __scanf(a, b) __attribute__((format(scanf, a, b))) diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h index ea7f450dc609..389e9729331f 100644 --- a/tools/perf/util/pmu.h +++ b/tools/perf/util/pmu.h @@ -2,6 +2,7 @@ #define __PMU_H #include +#include #include #include #include "evsel.h" @@ -83,8 +84,7 @@ void print_pmu_events(const char *event_glob, bool name_only, bool quiet, bool long_desc, bool details_flag); bool pmu_have_event(const char *pname, const char *name); -int perf_pmu__scan_file(struct perf_pmu *pmu, const char *name, const char *fmt, - ...) __attribute__((format(scanf, 3, 4))); +int perf_pmu__scan_file(struct perf_pmu *pmu, const char *name, const char *fmt, ...) __scanf(3, 4); int perf_pmu__test(void); -- cgit v1.2.3 From 0353631aa73e5e468fae1cd699bf860b59ba100d Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 16 Jun 2017 12:18:27 -0300 Subject: perf tools: Use __maybe_unused consistently Instead of defining __unused or redefining __maybe_unused. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-4eleto5pih31jw1q4dypm9pf@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/bench/numa.c | 2 +- tools/perf/jvmti/jvmti_agent.h | 2 -- tools/perf/jvmti/libjvmti.c | 5 +++-- tools/perf/pmu-events/jevents.c | 4 ---- tools/perf/util/evsel.c | 3 ++- tools/perf/util/header.c | 3 ++- 6 files changed, 8 insertions(+), 11 deletions(-) diff --git a/tools/perf/bench/numa.c b/tools/perf/bench/numa.c index 27de0c8c5c19..469d65b21122 100644 --- a/tools/perf/bench/numa.c +++ b/tools/perf/bench/numa.c @@ -700,7 +700,7 @@ static inline uint32_t lfsr_32(uint32_t lfsr) * kernel (KSM, zero page, etc.) cannot optimize away RAM * accesses: */ -static inline u64 access_data(u64 *data __attribute__((unused)), u64 val) +static inline u64 access_data(u64 *data, u64 val) { if (g->p.data_reads) val += *data; diff --git a/tools/perf/jvmti/jvmti_agent.h b/tools/perf/jvmti/jvmti_agent.h index bedf5d0ba9ff..c53a41f48b63 100644 --- a/tools/perf/jvmti/jvmti_agent.h +++ b/tools/perf/jvmti/jvmti_agent.h @@ -5,8 +5,6 @@ #include #include -#define __unused __attribute__((unused)) - #if defined(__cplusplus) extern "C" { #endif diff --git a/tools/perf/jvmti/libjvmti.c b/tools/perf/jvmti/libjvmti.c index 5612641c69b4..6d710904c837 100644 --- a/tools/perf/jvmti/libjvmti.c +++ b/tools/perf/jvmti/libjvmti.c @@ -1,3 +1,4 @@ +#include #include #include #include @@ -238,7 +239,7 @@ code_generated_cb(jvmtiEnv *jvmti, } JNIEXPORT jint JNICALL -Agent_OnLoad(JavaVM *jvm, char *options, void *reserved __unused) +Agent_OnLoad(JavaVM *jvm, char *options, void *reserved __maybe_unused) { jvmtiEventCallbacks cb; jvmtiCapabilities caps1; @@ -313,7 +314,7 @@ Agent_OnLoad(JavaVM *jvm, char *options, void *reserved __unused) } JNIEXPORT void JNICALL -Agent_OnUnload(JavaVM *jvm __unused) +Agent_OnUnload(JavaVM *jvm __maybe_unused) { int ret; diff --git a/tools/perf/pmu-events/jevents.c b/tools/perf/pmu-events/jevents.c index baa073f38334..bd0aabb2bd0f 100644 --- a/tools/perf/pmu-events/jevents.c +++ b/tools/perf/pmu-events/jevents.c @@ -48,10 +48,6 @@ #include "json.h" #include "jevents.h" -#ifndef __maybe_unused -#define __maybe_unused __attribute__((unused)) -#endif - int verbose; char *prog; diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index cda44b0e821c..7f78f27f5382 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -1441,7 +1442,7 @@ int perf_event_attr__fprintf(FILE *fp, struct perf_event_attr *attr, } static int __open_attr__fprintf(FILE *fp, const char *name, const char *val, - void *priv __attribute__((unused))) + void *priv __maybe_unused) { return fprintf(fp, " %-32s %s\n", name, val); } diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index b5baff3007bb..76ed7d03e500 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -1274,7 +1275,7 @@ error: } static int __desc_attr__fprintf(FILE *fp, const char *name, const char *val, - void *priv __attribute__((unused))) + void *priv __maybe_unused) { return fprintf(fp, ", %s = %s", name, val); } -- cgit v1.2.3 From 9dd4ca470e03334f95cc96529ba090921aac8eab Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 16 Jun 2017 11:39:15 -0300 Subject: tools: Adopt noinline from kernel sources To have a more compact way to ask the compiler not to inline a function and to make tools/ source code look like kernel code. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-bis4pqxegt6gbm5dlqs937tn@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/include/linux/compiler-gcc.h | 2 ++ tools/include/linux/compiler.h | 4 ++++ tools/perf/tests/bp_signal.c | 3 +-- tools/perf/tests/bp_signal_overflow.c | 3 +-- tools/perf/tests/dwarf-unwind.c | 15 +++++---------- 5 files changed, 13 insertions(+), 14 deletions(-) diff --git a/tools/include/linux/compiler-gcc.h b/tools/include/linux/compiler-gcc.h index 2846094aad4d..c13e6f7d5a2a 100644 --- a/tools/include/linux/compiler-gcc.h +++ b/tools/include/linux/compiler-gcc.h @@ -20,6 +20,8 @@ /* &a[0] degrades to a pointer: a different type from an array */ #define __must_be_array(a) BUILD_BUG_ON_ZERO(__same_type((a), &(a)[0])) +#define noinline __attribute__((noinline)) + #define __noreturn __attribute__((noreturn)) #define __printf(a, b) __attribute__((format(printf, a, b))) diff --git a/tools/include/linux/compiler.h b/tools/include/linux/compiler.h index 23299d7e7160..8b129e314c7e 100644 --- a/tools/include/linux/compiler.h +++ b/tools/include/linux/compiler.h @@ -17,6 +17,10 @@ # define __always_inline inline __attribute__((always_inline)) #endif +#ifndef noinline +#define noinline +#endif + /* Are two types/vars the same type (ignoring qualifiers)? */ #ifndef __same_type # define __same_type(a, b) __builtin_types_compatible_p(typeof(a), typeof(b)) diff --git a/tools/perf/tests/bp_signal.c b/tools/perf/tests/bp_signal.c index 8ba2c4618fe9..39bbb97cd30a 100644 --- a/tools/perf/tests/bp_signal.c +++ b/tools/perf/tests/bp_signal.c @@ -62,8 +62,7 @@ static void __test_function(volatile long *ptr) } #endif -__attribute__ ((noinline)) -static int test_function(void) +static noinline int test_function(void) { __test_function(&the_var); the_var++; diff --git a/tools/perf/tests/bp_signal_overflow.c b/tools/perf/tests/bp_signal_overflow.c index 89f92fa67cc4..3b1ac6f31b15 100644 --- a/tools/perf/tests/bp_signal_overflow.c +++ b/tools/perf/tests/bp_signal_overflow.c @@ -28,8 +28,7 @@ static int overflows; -__attribute__ ((noinline)) -static int test_function(void) +static noinline int test_function(void) { return time(NULL); } diff --git a/tools/perf/tests/dwarf-unwind.c b/tools/perf/tests/dwarf-unwind.c index dfe5c89e2049..3e56d08f7995 100644 --- a/tools/perf/tests/dwarf-unwind.c +++ b/tools/perf/tests/dwarf-unwind.c @@ -76,8 +76,7 @@ static int unwind_entry(struct unwind_entry *entry, void *arg) return strcmp((const char *) symbol, funcs[idx]); } -__attribute__ ((noinline)) -static int unwind_thread(struct thread *thread) +static noinline int unwind_thread(struct thread *thread) { struct perf_sample sample; unsigned long cnt = 0; @@ -108,8 +107,7 @@ static int unwind_thread(struct thread *thread) static int global_unwind_retval = -INT_MAX; -__attribute__ ((noinline)) -static int compare(void *p1, void *p2) +static noinline int compare(void *p1, void *p2) { /* Any possible value should be 'thread' */ struct thread *thread = *(struct thread **)p1; @@ -128,8 +126,7 @@ static int compare(void *p1, void *p2) return p1 - p2; } -__attribute__ ((noinline)) -static int krava_3(struct thread *thread) +static noinline int krava_3(struct thread *thread) { struct thread *array[2] = {thread, thread}; void *fp = &bsearch; @@ -147,14 +144,12 @@ static int krava_3(struct thread *thread) return global_unwind_retval; } -__attribute__ ((noinline)) -static int krava_2(struct thread *thread) +static noinline int krava_2(struct thread *thread) { return krava_3(thread); } -__attribute__ ((noinline)) -static int krava_1(struct thread *thread) +static noinline int krava_1(struct thread *thread) { return krava_2(thread); } -- cgit v1.2.3 From c9f5da742fa3dfebc49d03deb312522e5db643ed Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 16 Jun 2017 11:39:15 -0300 Subject: tools: Adopt __packed from kernel sources To have a more compact way to ask the compiler to not insert alignment paddings in a struct, making tools/ look more like kernel source code. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-byp46nr7hsxvvyc9oupfb40q@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/include/linux/compiler-gcc.h | 2 ++ tools/perf/util/genelf_debug.c | 5 +++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/tools/include/linux/compiler-gcc.h b/tools/include/linux/compiler-gcc.h index c13e6f7d5a2a..0f57a48272ab 100644 --- a/tools/include/linux/compiler-gcc.h +++ b/tools/include/linux/compiler-gcc.h @@ -22,6 +22,8 @@ #define noinline __attribute__((noinline)) +#define __packed __attribute__((packed)) + #define __noreturn __attribute__((noreturn)) #define __printf(a, b) __attribute__((format(printf, a, b))) diff --git a/tools/perf/util/genelf_debug.c b/tools/perf/util/genelf_debug.c index 5980f7d256b1..40789d8603d0 100644 --- a/tools/perf/util/genelf_debug.c +++ b/tools/perf/util/genelf_debug.c @@ -11,6 +11,7 @@ * @remark Copyright 2007 OProfile authors * @author Philippe Elie */ +#include #include #include #include @@ -125,7 +126,7 @@ struct debug_line_header { * and filesize, last entry is followed by en empty string. */ /* follow the first program statement */ -} __attribute__((packed)); +} __packed; /* DWARF 2 spec talk only about one possible compilation unit header while * binutils can handle two flavours of dwarf 2, 32 and 64 bits, this is not @@ -138,7 +139,7 @@ struct compilation_unit_header { uhalf version; uword debug_abbrev_offset; ubyte pointer_size; -} __attribute__((packed)); +} __packed; #define DW_LNS_num_opcode (DW_LNS_set_isa + 1) -- cgit v1.2.3 From 5c97cac63ac24c78c8126958a453774e49e706dd Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 16 Jun 2017 11:39:15 -0300 Subject: tools: Adopt __aligned from kernel sources To have a more compact way to ask the compiler to use a specific alignment, making tools/ look more like kernel source code. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-8jiem6ubg9rlpbs7c2p900no@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/include/linux/compiler-gcc.h | 1 + tools/perf/util/evlist.h | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/tools/include/linux/compiler-gcc.h b/tools/include/linux/compiler-gcc.h index 0f57a48272ab..bd39b2090ad1 100644 --- a/tools/include/linux/compiler-gcc.h +++ b/tools/include/linux/compiler-gcc.h @@ -26,5 +26,6 @@ #define __noreturn __attribute__((noreturn)) +#define __aligned(x) __attribute__((aligned(x))) #define __printf(a, b) __attribute__((format(printf, a, b))) #define __scanf(a, b) __attribute__((format(scanf, a, b))) diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h index 94cea4398a13..8d601fbdd8d6 100644 --- a/tools/perf/util/evlist.h +++ b/tools/perf/util/evlist.h @@ -1,6 +1,7 @@ #ifndef __PERF_EVLIST_H #define __PERF_EVLIST_H 1 +#include #include #include #include @@ -34,7 +35,7 @@ struct perf_mmap { refcount_t refcnt; u64 prev; struct auxtrace_mmap auxtrace_mmap; - char event_copy[PERF_SAMPLE_MAX_SIZE] __attribute__((aligned(8))); + char event_copy[PERF_SAMPLE_MAX_SIZE] __aligned(8); }; static inline size_t -- cgit v1.2.3 From 0c788d4726c916544490c17cdbfd1ae2a6347fa8 Mon Sep 17 00:00:00 2001 From: Kim Phillips Date: Thu, 15 Jun 2017 12:55:21 -0500 Subject: perf coresight: Remove superfluous check before use The cs_etm_evsel variable is guaranteed to be set at this point in cs_etm_recording_options(). Signed-off-by: Kim Phillips Acked-by: Mathieu Poirier Cc: Alexander Shishkin Cc: Peter Zijlstra Cc: linux-arm-kernel@lists.infradead.org Link: http://lkml.kernel.org/r/20170615125521.80cc128dc856bc1f2e61b730@arm.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/arch/arm/util/cs-etm.c | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/tools/perf/arch/arm/util/cs-etm.c b/tools/perf/arch/arm/util/cs-etm.c index 02a649bfec3c..7ce3d1a25133 100644 --- a/tools/perf/arch/arm/util/cs-etm.c +++ b/tools/perf/arch/arm/util/cs-etm.c @@ -203,19 +203,18 @@ static int cs_etm_recording_options(struct auxtrace_record *itr, pr_debug2("%s snapshot size: %zu\n", CORESIGHT_ETM_PMU_NAME, opts->auxtrace_snapshot_size); - if (cs_etm_evsel) { - /* - * To obtain the auxtrace buffer file descriptor, the auxtrace - * event must come first. - */ - perf_evlist__to_front(evlist, cs_etm_evsel); - /* - * In the case of per-cpu mmaps, we need the CPU on the - * AUX event. - */ - if (!cpu_map__empty(cpus)) - perf_evsel__set_sample_bit(cs_etm_evsel, CPU); - } + /* + * To obtain the auxtrace buffer file descriptor, the auxtrace + * event must come first. + */ + perf_evlist__to_front(evlist, cs_etm_evsel); + + /* + * In the case of per-cpu mmaps, we need the CPU on the + * AUX event. + */ + if (!cpu_map__empty(cpus)) + perf_evsel__set_sample_bit(cs_etm_evsel, CPU); /* Add dummy event to keep tracking */ if (opts->full_auxtrace) { -- cgit v1.2.3 From d3cef7fe5151eabcd97ad8f9e595ec55f6ffb318 Mon Sep 17 00:00:00 2001 From: Kim Phillips Date: Fri, 16 Jun 2017 11:23:39 -0500 Subject: perf intel-pt/bts: Remove unused SAMPLE_SIZE defines and bts priv array These defines were probably dragged in from sampling support in earlier patches. They can be put back when needed. Signed-off-by: Kim Phillips Acked-by: Adrian Hunter Cc: Alexander Shishkin Cc: Andi Kleen Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/20170616112339.3fb6986e4ff33e353008244b@arm.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/arch/x86/util/intel-bts.c | 4 ---- tools/perf/arch/x86/util/intel-pt.c | 4 ---- tools/perf/util/intel-bts.c | 2 -- 3 files changed, 10 deletions(-) diff --git a/tools/perf/arch/x86/util/intel-bts.c b/tools/perf/arch/x86/util/intel-bts.c index af2bce7a2cd6..781df40b2966 100644 --- a/tools/perf/arch/x86/util/intel-bts.c +++ b/tools/perf/arch/x86/util/intel-bts.c @@ -35,10 +35,6 @@ #define KiB_MASK(x) (KiB(x) - 1) #define MiB_MASK(x) (MiB(x) - 1) -#define INTEL_BTS_DFLT_SAMPLE_SIZE KiB(4) - -#define INTEL_BTS_MAX_SAMPLE_SIZE KiB(60) - struct intel_bts_snapshot_ref { void *ref_buf; size_t ref_offset; diff --git a/tools/perf/arch/x86/util/intel-pt.c b/tools/perf/arch/x86/util/intel-pt.c index f630de0206a1..6fe667b3269e 100644 --- a/tools/perf/arch/x86/util/intel-pt.c +++ b/tools/perf/arch/x86/util/intel-pt.c @@ -40,10 +40,6 @@ #define KiB_MASK(x) (KiB(x) - 1) #define MiB_MASK(x) (MiB(x) - 1) -#define INTEL_PT_DEFAULT_SAMPLE_SIZE KiB(4) - -#define INTEL_PT_MAX_SAMPLE_SIZE KiB(60) - #define INTEL_PT_PSB_PERIOD_NEAR 256 struct intel_pt_snapshot_ref { diff --git a/tools/perf/util/intel-bts.c b/tools/perf/util/intel-bts.c index b2834ac7b1f5..218ee2bac9a5 100644 --- a/tools/perf/util/intel-bts.c +++ b/tools/perf/util/intel-bts.c @@ -866,8 +866,6 @@ static void intel_bts_print_info(u64 *arr, int start, int finish) fprintf(stdout, intel_bts_info_fmts[i], arr[i]); } -u64 intel_bts_auxtrace_info_priv[INTEL_BTS_AUXTRACE_PRIV_SIZE]; - int intel_bts_process_auxtrace_info(union perf_event *event, struct perf_session *session) { -- cgit v1.2.3 From dcaa394807ac219d8597d25bad3fe1bc6c86123b Mon Sep 17 00:00:00 2001 From: Jin Yao Date: Mon, 19 Jun 2017 10:55:56 +0800 Subject: perf annotate: Return arch from symbol__disassemble() and save it in browser In annotate browser, we will add support to check fused instructions. While this is x86-specific feature so we need the annotate browser to know what the arch it runs on. symbol__disassemble() has figured out the arch. This patch just lets the arch return from symbol__disassemble and save the arch in annotate browser. Signed-off-by: Yao Jin Cc: Alexander Shishkin Cc: Andi Kleen Cc: Jiri Olsa Cc: Kan Liang Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1497840958-4759-2-git-send-email-yao.jin@linux.intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-top.c | 2 +- tools/perf/ui/browsers/annotate.c | 6 +++++- tools/perf/ui/gtk/annotate.c | 3 ++- tools/perf/util/annotate.c | 10 ++++++++-- tools/perf/util/annotate.h | 4 +++- 5 files changed, 19 insertions(+), 6 deletions(-) diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 10b6362ca0bf..2bcfa46913c8 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -134,7 +134,7 @@ static int perf_top__parse_source(struct perf_top *top, struct hist_entry *he) return err; } - err = symbol__disassemble(sym, map, NULL, 0); + err = symbol__disassemble(sym, map, NULL, 0, NULL); if (err == 0) { out_assign: top->sym_filter_entry = he; diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index 7a03389b7a03..27f41f28dcb4 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c @@ -46,12 +46,15 @@ static struct annotate_browser_opt { .jump_arrows = true, }; +struct arch; + struct annotate_browser { struct ui_browser b; struct rb_root entries; struct rb_node *curr_hot; struct disasm_line *selection; struct disasm_line **offsets; + struct arch *arch; int nr_events; u64 start; int nr_asm_entries; @@ -1070,7 +1073,8 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, (nr_pcnt - 1); } - err = symbol__disassemble(sym, map, perf_evsel__env_arch(evsel), sizeof_bdl); + err = symbol__disassemble(sym, map, perf_evsel__env_arch(evsel), + sizeof_bdl, &browser.arch); if (err) { char msg[BUFSIZ]; symbol__strerror_disassemble(sym, map, err, msg, sizeof(msg)); diff --git a/tools/perf/ui/gtk/annotate.c b/tools/perf/ui/gtk/annotate.c index e99ba86158d2..d903fd493416 100644 --- a/tools/perf/ui/gtk/annotate.c +++ b/tools/perf/ui/gtk/annotate.c @@ -168,7 +168,8 @@ static int symbol__gtk_annotate(struct symbol *sym, struct map *map, if (map->dso->annotate_warned) return -1; - err = symbol__disassemble(sym, map, perf_evsel__env_arch(evsel), 0); + err = symbol__disassemble(sym, map, perf_evsel__env_arch(evsel), + 0, NULL); if (err) { char msg[BUFSIZ]; symbol__strerror_disassemble(sym, map, err, msg, sizeof(msg)); diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index ddbd56df9187..be1caabb9290 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -1379,7 +1379,9 @@ static const char *annotate__norm_arch(const char *arch_name) return normalize_arch((char *)arch_name); } -int symbol__disassemble(struct symbol *sym, struct map *map, const char *arch_name, size_t privsize) +int symbol__disassemble(struct symbol *sym, struct map *map, + const char *arch_name, size_t privsize, + struct arch **parch) { struct dso *dso = map->dso; char command[PATH_MAX * 2]; @@ -1405,6 +1407,9 @@ int symbol__disassemble(struct symbol *sym, struct map *map, const char *arch_na if (arch == NULL) return -ENOTSUP; + if (parch) + *parch = arch; + if (arch->init) { err = arch->init(arch); if (err) { @@ -1901,7 +1906,8 @@ int symbol__tty_annotate(struct symbol *sym, struct map *map, struct rb_root source_line = RB_ROOT; u64 len; - if (symbol__disassemble(sym, map, perf_evsel__env_arch(evsel), 0) < 0) + if (symbol__disassemble(sym, map, perf_evsel__env_arch(evsel), + 0, NULL) < 0) return -1; len = symbol__size(sym); diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index 948aa8e6fd39..21055034aedd 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -158,7 +158,9 @@ int hist_entry__inc_addr_samples(struct hist_entry *he, int evidx, u64 addr); int symbol__alloc_hist(struct symbol *sym); void symbol__annotate_zero_histograms(struct symbol *sym); -int symbol__disassemble(struct symbol *sym, struct map *map, const char *arch_name, size_t privsize); +int symbol__disassemble(struct symbol *sym, struct map *map, + const char *arch_name, size_t privsize, + struct arch **parch); enum symbol_disassemble_errno { SYMBOL_ANNOTATE_ERRNO__SUCCESS = 0, -- cgit v1.2.3 From 9b57fb7e35957c6838f89f4ed7e3f8433a4bbfc5 Mon Sep 17 00:00:00 2001 From: Wang Nan Date: Wed, 21 Jun 2017 02:32:03 +0800 Subject: perf test llvm: Avoid error when PROFILE_ALL_BRANCHES is set The 'if' keyword is a define that expands to complex code when CONFIG_PROFILE_ALL_BRANCHES is selected, which causes a 'perf test LLVM' failure like: $ ./perf test LLVM 35: LLVM search and compile : 35.1: Basic BPF llvm compile : Ok 35.2: kbuild searching : Ok 35.3: Compile source for BPF prologue generation: FAILED! 35.4: Compile source for BPF relocation : Skip The only affected test case is bpf-script-test-prologue.c because it uses kernel headers and has 'if' inside. This patch undefines 'if' to make it passes perf test. More detailed analysis from a message in this thread, also by Wang: The problem is caused by following relocation information: $ readelf -a ./llvmsubtest3 ... [ 5] _ftrace_branch PROGBITS 0000000000000000 00000260 00000000000000a0 0000000000000000 WA 0 0 4 ... Relocation section '.relfunc=null_lseek file->f_mode offset orig' at offset 0x490 contains 4 entries: Offset Info Type Sym. Value Sym. Name 000000000038 000b00000001 unrecognized: 1 0000000000000000 _ftrace_branch 0000000000b0 000b00000001 unrecognized: 1 0000000000000000 _ftrace_branch 000000000128 000b00000001 unrecognized: 1 0000000000000000 _ftrace_branch 0000000001c0 000b00000001 unrecognized: 1 0000000000000000 _ftrace_branch Relocation section '.rel_ftrace_branch' at offset 0x4d0 contains 8 entries: Offset Info Type Sym. Value Sym. Name 000000000000 000200000001 unrecognized: 1 0000000000000000 .L__func__.bpf_func__n 000000000008 000100000001 unrecognized: 1 0000000000000015 .L.str 000000000028 000200000001 unrecognized: 1 0000000000000000 .L__func__.bpf_func__n 000000000030 000100000001 unrecognized: 1 0000000000000015 .L.str 000000000050 000200000001 unrecognized: 1 0000000000000000 .L__func__.bpf_func__n 000000000058 000100000001 unrecognized: 1 0000000000000015 .L.str 000000000078 000200000001 unrecognized: 1 0000000000000000 .L__func__.bpf_func__n 000000000080 000100000001 unrecognized: 1 0000000000000015 .L.str ... So I think the failure is because you enabled CONFIG_PROFILE_ALL_BRANCHES. I can reproduce your buggy result by selecting CONFIG_PROFILE_ALL_BRANCHES in my kbuild: $ ./perf test LLVM 35: LLVM search and compile : 35.1: Basic BPF llvm compile : Ok 35.2: kbuild searching : Ok 35.3: Compile source for BPF prologue generation: FAILED! 35.4: Compile source for BPF relocation : Skip Simply undef CONFIG_PROFILE_ALL_BRANCHES in clang opts not working because it is introduced by "#include ", which override cmdline options. So I think the best way is to undefine 'if' inside BPF script. Reported-and-Tested-by: Thomas-Mich Richter Signed-off-by: Wang Nan Cc: Alexei Starovoitov Cc: Hendrik Brueckner Cc: Zefan Li Link: http://lkml.kernel.org/r/20170620183203.2517-1-wangnan0@huawei.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/bpf-script-test-prologue.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tools/perf/tests/bpf-script-test-prologue.c b/tools/perf/tests/bpf-script-test-prologue.c index 7230e62c70fc..b4ebc75e25ae 100644 --- a/tools/perf/tests/bpf-script-test-prologue.c +++ b/tools/perf/tests/bpf-script-test-prologue.c @@ -10,6 +10,15 @@ #include +/* + * If CONFIG_PROFILE_ALL_BRANCHES is selected, + * 'if' is redefined after include kernel header. + * Recover 'if' for BPF object code. + */ +#ifdef if +# undef if +#endif + #define FMODE_READ 0x1 #define FMODE_WRITE 0x2 -- cgit v1.2.3 From 55b9b50811ca459e4688543b688b7b2b85ec5ea8 Mon Sep 17 00:00:00 2001 From: Mark Santaniello Date: Mon, 19 Jun 2017 09:38:24 -0700 Subject: perf script: Support -F brstack,dso and brstacksym,dso Perf script can report the dso for "addr" and "ip" fields. This adds the same support for the "brstack" and "brstacksym" fields. This can be helpful for AutoFDO: we can ignore LBR entries unless the source and target address are both in the target module we are about to build. I built a small test akin to "while(1) { do_nothing(); }" where the do_nothing function is loaded from a dso: $ cat burncpu.cpp #include int main() { void* handle = dlopen("./dso.so", RTLD_LAZY); if (!handle) return -1; typedef void (*fp)(); fp do_nothing = (fp) dlsym(handle, "do_nothing"); while(1) { do_nothing(); } } $ cat dso.cpp extern "C" void do_nothing() {} $ cat build.sh #!/bin/bash g++ -shared dso.cpp -o dso.so g++ burncpu.cpp -o burncpu -ldl I sampled the execution with perf record -b. Using the new perf script functionality I can easily find cases where there was a transition from one dso to another: $ perf record -a -b -- sleep 5 [ perf record: Woken up 55 times to write data ] [ perf record: Captured and wrote 18.815 MB perf.data (43593 samples) ] $ perf script -F brstack,dso | sed 's/\/0 /\/0\n/g' | grep burncpu | grep dso.so | head -n 1 0x7f967139b6aa(/tmp/burncpu/dso.so)/0x4006b1(/tmp/burncpu/exe)/P/-/-/0 $ perf script -F brstacksym,dso | sed 's/\/0 /\/0\n/g' | grep burncpu | grep dso.so | head -n 1 do_nothing+0x5(/tmp/burncpu/dso.so)/main+0x44(/tmp/burncpu/exe)/P/-/-/0 Signed-off-by: Mark Santaniello Tested-by: Arnaldo Carvalho de Melo Cc: Alexander Shishkin Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/20170619163825.2012979-1-marksan@fb.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-script.c | 61 ++++++++++++++++++++++++++++++++++++--------- 1 file changed, 49 insertions(+), 12 deletions(-) diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index afa84debc5c4..3c21089f5273 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c @@ -298,10 +298,11 @@ static int perf_evsel__check_attr(struct perf_evsel *evsel, "selected.\n"); return -EINVAL; } - if (PRINT_FIELD(DSO) && !PRINT_FIELD(IP) && !PRINT_FIELD(ADDR)) { - pr_err("Display of DSO requested but neither sample IP nor " - "sample address\nis selected. Hence, no addresses to convert " - "to DSO.\n"); + if (PRINT_FIELD(DSO) && !PRINT_FIELD(IP) && !PRINT_FIELD(ADDR) && + !PRINT_FIELD(BRSTACK) && !PRINT_FIELD(BRSTACKSYM)) { + pr_err("Display of DSO requested but none of sample IP, sample address, " + "brstack\nor brstacksym are selected. Hence, no addresses to " + "convert to DSO.\n"); return -EINVAL; } if (PRINT_FIELD(SRCLINE) && !PRINT_FIELD(IP)) { @@ -514,18 +515,43 @@ mispred_str(struct branch_entry *br) return br->flags.predicted ? 'P' : 'M'; } -static void print_sample_brstack(struct perf_sample *sample) +static void print_sample_brstack(struct perf_sample *sample, + struct thread *thread, + struct perf_event_attr *attr) { struct branch_stack *br = sample->branch_stack; - u64 i; + struct addr_location alf, alt; + u64 i, from, to; if (!(br && br->nr)) return; for (i = 0; i < br->nr; i++) { - printf(" 0x%"PRIx64"/0x%"PRIx64"/%c/%c/%c/%d ", - br->entries[i].from, - br->entries[i].to, + from = br->entries[i].from; + to = br->entries[i].to; + + if (PRINT_FIELD(DSO)) { + memset(&alf, 0, sizeof(alf)); + memset(&alt, 0, sizeof(alt)); + thread__find_addr_map(thread, sample->cpumode, MAP__FUNCTION, from, &alf); + thread__find_addr_map(thread, sample->cpumode, MAP__FUNCTION, to, &alt); + } + + printf("0x%"PRIx64, from); + if (PRINT_FIELD(DSO)) { + printf("("); + map__fprintf_dsoname(alf.map, stdout); + printf(")"); + } + + printf("/0x%"PRIx64, to); + if (PRINT_FIELD(DSO)) { + printf("("); + map__fprintf_dsoname(alt.map, stdout); + printf(")"); + } + + printf("/%c/%c/%c/%d ", mispred_str( br->entries + i), br->entries[i].flags.in_tx? 'X' : '-', br->entries[i].flags.abort? 'A' : '-', @@ -534,7 +560,8 @@ static void print_sample_brstack(struct perf_sample *sample) } static void print_sample_brstacksym(struct perf_sample *sample, - struct thread *thread) + struct thread *thread, + struct perf_event_attr *attr) { struct branch_stack *br = sample->branch_stack; struct addr_location alf, alt; @@ -559,8 +586,18 @@ static void print_sample_brstacksym(struct perf_sample *sample, alt.sym = map__find_symbol(alt.map, alt.addr); symbol__fprintf_symname_offs(alf.sym, &alf, stdout); + if (PRINT_FIELD(DSO)) { + printf("("); + map__fprintf_dsoname(alf.map, stdout); + printf(")"); + } putchar('/'); symbol__fprintf_symname_offs(alt.sym, &alt, stdout); + if (PRINT_FIELD(DSO)) { + printf("("); + map__fprintf_dsoname(alt.map, stdout); + printf(")"); + } printf("/%c/%c/%c/%d ", mispred_str( br->entries + i), br->entries[i].flags.in_tx? 'X' : '-', @@ -1187,9 +1224,9 @@ static void process_event(struct perf_script *script, print_sample_iregs(sample, attr); if (PRINT_FIELD(BRSTACK)) - print_sample_brstack(sample); + print_sample_brstack(sample, thread, attr); else if (PRINT_FIELD(BRSTACKSYM)) - print_sample_brstacksym(sample, thread); + print_sample_brstacksym(sample, thread, attr); if (perf_evsel__is_bpf_output(evsel) && PRINT_FIELD(BPF_OUTPUT)) print_sample_bpf_output(sample); -- cgit v1.2.3 From 106dacd86f042968e0bb974490fcb9cd017cd03a Mon Sep 17 00:00:00 2001 From: Mark Santaniello Date: Mon, 19 Jun 2017 09:38:25 -0700 Subject: perf script: Support -F brstackoff,dso The idea here is to make AutoFDO easier in cloud environment with ASLR. It's easiest to show how this is useful by example. I built a small test akin to "while(1) { do_nothing(); }" where the do_nothing function is loaded from a dso: $ cat burncpu.cpp #include int main() { void* handle = dlopen("./dso.so", RTLD_LAZY); if (!handle) return -1; typedef void (*fp)(); fp do_nothing = (fp) dlsym(handle, "do_nothing"); while(1) { do_nothing(); } } $ cat dso.cpp extern "C" void do_nothing() {} $ cat build.sh #!/bin/bash g++ -shared dso.cpp -o dso.so g++ burncpu.cpp -o burncpu -ldl I sampled the execution of this program with perf record -b. Using the existing "brstack,dso", we get absolute addresses that are affected by ASLR, and could be different on different hosts. The address does not uniquely identify a branch/target in the binary: $ perf script -F brstack,dso | sed 's/\/0 /\/0\n/g' | grep burncpu | grep dso.so | head -n 1 0x7f967139b6aa(/tmp/burncpu/dso.so)/0x4006b1(/tmp/burncpu/exe)/P/-/-/0 Using the existing "brstacksym,dso" is a little better, because the symbol plus offset and dso name *does* uniquely identify a branch/target in the binary. Ultimately, however, AutoFDO wants a simple offset into the binary, so we'd have to undo all the work perf did to symbolize in the first place: $ perf script -F brstacksym,dso | sed 's/\/0 /\/0\n/g' | grep burncpu | grep dso.so | head -n 1 do_nothing+0x5(/tmp/burncpu/dso.so)/main+0x44(/tmp/burncpu/exe)/P/-/-/0 With the new "brstackoff,dso" we get what we need: a simple offset into a specific dso/binary that uniquely identifies a branch/target: $ perf script -F brstackoff,dso | sed 's/\/0 /\/0\n/g' | grep burncpu | grep dso.so | head -n 1 0x6aa(/tmp/burncpu/dso.so)/0x4006b1(/tmp/burncpu/exe)/P/-/-/0 Signed-off-by: Mark Santaniello Tested-by: Arnaldo Carvalho de Melo Cc: Alexander Shishkin Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/20170619163825.2012979-2-marksan@fb.com [ Updated documentation about 'brstackoff' using text from above ] Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Documentation/perf-script.txt | 4 ++- tools/perf/builtin-script.c | 56 +++++++++++++++++++++++++++++--- 2 files changed, 55 insertions(+), 5 deletions(-) diff --git a/tools/perf/Documentation/perf-script.txt b/tools/perf/Documentation/perf-script.txt index 3eca8c0d3c7b..e2468ed6a307 100644 --- a/tools/perf/Documentation/perf-script.txt +++ b/tools/perf/Documentation/perf-script.txt @@ -116,7 +116,7 @@ OPTIONS --fields:: Comma separated list of fields to print. Options are: comm, tid, pid, time, cpu, event, trace, ip, sym, dso, addr, symoff, - srcline, period, iregs, brstack, brstacksym, flags, bpf-output, brstackinsn, + srcline, period, iregs, brstack, brstacksym, flags, bpf-output, brstackinsn, brstackoff, callindent, insn, insnlen. Field list can be prepended with the type, trace, sw or hw, to indicate to which event type the field list applies. e.g., -F sw:comm,tid,time,ip,sym and -F trace:time,cpu,trace @@ -211,6 +211,8 @@ OPTIONS is printed. This is the full execution path leading to the sample. This is only supported when the sample was recorded with perf record -b or -j any. + The brstackoff field will print an offset into a specific dso/binary. + -k:: --vmlinux=:: vmlinux pathname diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index 3c21089f5273..db5261c3f719 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c @@ -85,6 +85,7 @@ enum perf_output_field { PERF_OUTPUT_INSN = 1U << 21, PERF_OUTPUT_INSNLEN = 1U << 22, PERF_OUTPUT_BRSTACKINSN = 1U << 23, + PERF_OUTPUT_BRSTACKOFF = 1U << 24, }; struct output_option { @@ -115,6 +116,7 @@ struct output_option { {.str = "insn", .field = PERF_OUTPUT_INSN}, {.str = "insnlen", .field = PERF_OUTPUT_INSNLEN}, {.str = "brstackinsn", .field = PERF_OUTPUT_BRSTACKINSN}, + {.str = "brstackoff", .field = PERF_OUTPUT_BRSTACKOFF}, }; /* default set to maintain compatibility with current format */ @@ -299,10 +301,9 @@ static int perf_evsel__check_attr(struct perf_evsel *evsel, return -EINVAL; } if (PRINT_FIELD(DSO) && !PRINT_FIELD(IP) && !PRINT_FIELD(ADDR) && - !PRINT_FIELD(BRSTACK) && !PRINT_FIELD(BRSTACKSYM)) { - pr_err("Display of DSO requested but none of sample IP, sample address, " - "brstack\nor brstacksym are selected. Hence, no addresses to " - "convert to DSO.\n"); + !PRINT_FIELD(BRSTACK) && !PRINT_FIELD(BRSTACKSYM) && !PRINT_FIELD(BRSTACKOFF)) { + pr_err("Display of DSO requested but no address to convert. Select\n" + "sample IP, sample address, brstack, brstacksym, or brstackoff.\n"); return -EINVAL; } if (PRINT_FIELD(SRCLINE) && !PRINT_FIELD(IP)) { @@ -606,6 +607,51 @@ static void print_sample_brstacksym(struct perf_sample *sample, } } +static void print_sample_brstackoff(struct perf_sample *sample, + struct thread *thread, + struct perf_event_attr *attr) +{ + struct branch_stack *br = sample->branch_stack; + struct addr_location alf, alt; + u64 i, from, to; + + if (!(br && br->nr)) + return; + + for (i = 0; i < br->nr; i++) { + + memset(&alf, 0, sizeof(alf)); + memset(&alt, 0, sizeof(alt)); + from = br->entries[i].from; + to = br->entries[i].to; + + thread__find_addr_map(thread, sample->cpumode, MAP__FUNCTION, from, &alf); + if (alf.map && !alf.map->dso->adjust_symbols) + from = map__map_ip(alf.map, from); + + thread__find_addr_map(thread, sample->cpumode, MAP__FUNCTION, to, &alt); + if (alt.map && !alt.map->dso->adjust_symbols) + to = map__map_ip(alt.map, to); + + printf("0x%"PRIx64, from); + if (PRINT_FIELD(DSO)) { + printf("("); + map__fprintf_dsoname(alf.map, stdout); + printf(")"); + } + printf("/0x%"PRIx64, to); + if (PRINT_FIELD(DSO)) { + printf("("); + map__fprintf_dsoname(alt.map, stdout); + printf(")"); + } + printf("/%c/%c/%c/%d ", + mispred_str(br->entries + i), + br->entries[i].flags.in_tx ? 'X' : '-', + br->entries[i].flags.abort ? 'A' : '-', + br->entries[i].flags.cycles); + } +} #define MAXBB 16384UL static int grab_bb(u8 *buffer, u64 start, u64 end, @@ -1227,6 +1273,8 @@ static void process_event(struct perf_script *script, print_sample_brstack(sample, thread, attr); else if (PRINT_FIELD(BRSTACKSYM)) print_sample_brstacksym(sample, thread, attr); + else if (PRINT_FIELD(BRSTACKOFF)) + print_sample_brstackoff(sample, thread, attr); if (perf_evsel__is_bpf_output(evsel) && PRINT_FIELD(BPF_OUTPUT)) print_sample_bpf_output(sample); -- cgit v1.2.3 From e7bd9ba20a9ec7024a0566a93c22b9571a48939a Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Sun, 18 Jun 2017 23:22:59 +0900 Subject: perf ftrace: Show error message when fails to set ftrace files It'd be better for debugging to show an error message when it fails to setup ftrace for some reason. Signed-off-by: Namhyung Kim Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Masami Hiramatsu Cc: Peter Zijlstra Cc: Steven Rostedt Cc: kernel-team@lge.com Link: http://lkml.kernel.org/r/20170618142302.25390-1-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-ftrace.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tools/perf/builtin-ftrace.c b/tools/perf/builtin-ftrace.c index 9e0b35cd0eea..966a94fa8200 100644 --- a/tools/perf/builtin-ftrace.c +++ b/tools/perf/builtin-ftrace.c @@ -61,6 +61,7 @@ static int __write_tracing_file(const char *name, const char *val, bool append) int fd, ret = -1; ssize_t size = strlen(val); int flags = O_WRONLY; + char errbuf[512]; file = get_tracing_file(name); if (!file) { @@ -75,14 +76,16 @@ static int __write_tracing_file(const char *name, const char *val, bool append) fd = open(file, flags); if (fd < 0) { - pr_debug("cannot open tracing file: %s\n", name); + pr_debug("cannot open tracing file: %s: %s\n", + name, str_error_r(errno, errbuf, sizeof(errbuf))); goto out; } if (write(fd, val, size) == size) ret = 0; else - pr_debug("write '%s' to tracing/%s failed\n", val, name); + pr_debug("write '%s' to tracing/%s failed: %s\n", + val, name, str_error_r(errno, errbuf, sizeof(errbuf))); close(fd); out: -- cgit v1.2.3 From 29681bc5bb4326c2f9eac5dc68d8fad3e88b4bb5 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Sun, 18 Jun 2017 23:23:00 +0900 Subject: perf ftrace: Move setup_pager before opening trace_pipe The 'perf ftrace' command fails to reset tracer after finishing recording like below: $ sudo perf ftrace -v hello write 'nop' to tracing/current_tracer failed: Device or resource busy ... This is because the trace_pipe file is open in pager process. Move the pager setup to before opening the file. Signed-off-by: Namhyung Kim Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Masami Hiramatsu Cc: Peter Zijlstra Cc: Steven Rostedt Cc: kernel-team@lge.com Fixes: 583359646fde ("perf ftrace: Use pager for displaying result") Link: http://lkml.kernel.org/r/20170618142302.25390-2-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-ftrace.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/perf/builtin-ftrace.c b/tools/perf/builtin-ftrace.c index 966a94fa8200..982b98ee639e 100644 --- a/tools/perf/builtin-ftrace.c +++ b/tools/perf/builtin-ftrace.c @@ -231,6 +231,8 @@ static int __cmd_ftrace(struct perf_ftrace *ftrace, int argc, const char **argv) goto out_reset; } + setup_pager(); + trace_file = get_tracing_file("trace_pipe"); if (!trace_file) { pr_err("failed to open trace_pipe\n"); @@ -254,8 +256,6 @@ static int __cmd_ftrace(struct perf_ftrace *ftrace, int argc, const char **argv) goto out_close_fd; } - setup_pager(); - perf_evlist__start_workload(ftrace->evlist); while (!done) { -- cgit v1.2.3 From 78b83e8b12b4467540ca501c7c019e9d46051957 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Sun, 18 Jun 2017 23:23:01 +0900 Subject: perf ftrace: Add option for function filtering The -T/--trace-funcs and -N/--notrace-funcs options are to specify functions to enable/disable tracing dynamically. The -G/--graph-funcs and -g/--nograph-funcs options are to set filters for function graph tracer. For example, to trace fault handling functions only: $ sudo perf ftrace -T *fault hello 0) | __do_page_fault() { 0) | handle_mm_fault() { 0) 2.117 us | __handle_mm_fault(); 0) 3.627 us | } 0) 7.811 us | } 0) | __do_page_fault() { 0) | handle_mm_fault() { 0) 2.014 us | __handle_mm_fault(); 0) 2.424 us | } 0) 2.951 us | } ... To trace all functions executed in __do_page_fault: $ sudo perf ftrace -G __do_page_fault hello 2) | __do_page_fault() { 3) 0.060 us | down_read_trylock(); 3) | find_vma() { 3) 0.075 us | vmacache_find(); 3) 0.053 us | vmacache_update(); 3) 1.246 us | } 3) | handle_mm_fault() { 3) 0.063 us | __rcu_read_lock(); 3) 0.056 us | mem_cgroup_from_task(); 3) 0.057 us | __rcu_read_unlock(); 3) | __handle_mm_fault() { 3) | filemap_map_pages() { 3) 0.058 us | __rcu_read_lock(); 3) | alloc_set_pte() { ... But don't want to show details in handle_mm_fault: $ sudo perf ftrace -G __do_page_fault -g handle_mm_fault hello 3) | __do_page_fault() { 3) 0.049 us | down_read_trylock(); 3) | find_vma() { 3) 0.048 us | vmacache_find(); 3) 0.041 us | vmacache_update(); 3) 0.680 us | } 3) 0.036 us | up_read(); 3) 4.547 us | } /* __do_page_fault */ ... Signed-off-by: Namhyung Kim Tested-by: Arnaldo Carvalho de Melo Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Masami Hiramatsu Cc: Peter Zijlstra Cc: Steven Rostedt Cc: kernel-team@lge.com Link: http://lkml.kernel.org/r/20170618142302.25390-3-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Documentation/perf-ftrace.txt | 30 ++++++++ tools/perf/builtin-ftrace.c | 117 +++++++++++++++++++++++++++++-- 2 files changed, 141 insertions(+), 6 deletions(-) diff --git a/tools/perf/Documentation/perf-ftrace.txt b/tools/perf/Documentation/perf-ftrace.txt index 6e6a8b22c859..78d6126ca485 100644 --- a/tools/perf/Documentation/perf-ftrace.txt +++ b/tools/perf/Documentation/perf-ftrace.txt @@ -48,6 +48,36 @@ OPTIONS Ranges of CPUs are specified with -: 0-2. Default is to trace on all online CPUs. +-T:: +--trace-funcs=:: + Only trace functions given by the argument. Multiple functions + can be given by using this option more than once. The function + argument also can be a glob pattern. It will be passed to + 'set_ftrace_filter' in tracefs. + +-N:: +--notrace-funcs=:: + Do not trace functions given by the argument. Like -T option, + this can be used more than once to specify multiple functions + (or glob patterns). It will be passed to 'set_ftrace_notrace' + in tracefs. + +-G:: +--graph-funcs=:: + Set graph filter on the given function (or a glob pattern). + This is useful for the function_graph tracer only and enables + tracing for functions executed from the given function. + This can be used more than once to specify multiple functions. + It will be passed to 'set_graph_function' in tracefs. + +-g:: +--nograph-funcs=:: + Set graph notrace filter on the given function (or a glob pattern). + Like -G option, this is useful for the function_graph tracer only + and disables tracing for function executed from the given function. + This can be used more than once to specify multiple functions. + It will be passed to 'set_graph_notrace' in tracefs. + SEE ALSO -------- diff --git a/tools/perf/builtin-ftrace.c b/tools/perf/builtin-ftrace.c index 982b98ee639e..3285375ce3c2 100644 --- a/tools/perf/builtin-ftrace.c +++ b/tools/perf/builtin-ftrace.c @@ -28,9 +28,18 @@ #define DEFAULT_TRACER "function_graph" struct perf_ftrace { - struct perf_evlist *evlist; - struct target target; - const char *tracer; + struct perf_evlist *evlist; + struct target target; + const char *tracer; + struct list_head filters; + struct list_head notrace; + struct list_head graph_funcs; + struct list_head nograph_funcs; +}; + +struct filter_entry { + struct list_head list; + char name[]; }; static bool done; @@ -104,6 +113,7 @@ static int append_tracing_file(const char *name, const char *val) } static int reset_tracing_cpu(void); +static void reset_tracing_filters(void); static int reset_tracing_files(struct perf_ftrace *ftrace __maybe_unused) { @@ -119,6 +129,7 @@ static int reset_tracing_files(struct perf_ftrace *ftrace __maybe_unused) if (reset_tracing_cpu() < 0) return -1; + reset_tracing_filters(); return 0; } @@ -184,6 +195,48 @@ static int reset_tracing_cpu(void) return ret; } +static int __set_tracing_filter(const char *filter_file, struct list_head *funcs) +{ + struct filter_entry *pos; + + list_for_each_entry(pos, funcs, list) { + if (append_tracing_file(filter_file, pos->name) < 0) + return -1; + } + + return 0; +} + +static int set_tracing_filters(struct perf_ftrace *ftrace) +{ + int ret; + + ret = __set_tracing_filter("set_ftrace_filter", &ftrace->filters); + if (ret < 0) + return ret; + + ret = __set_tracing_filter("set_ftrace_notrace", &ftrace->notrace); + if (ret < 0) + return ret; + + ret = __set_tracing_filter("set_graph_function", &ftrace->graph_funcs); + if (ret < 0) + return ret; + + /* old kernels do not have this filter */ + __set_tracing_filter("set_graph_notrace", &ftrace->nograph_funcs); + + return ret; +} + +static void reset_tracing_filters(void) +{ + write_tracing_file("set_ftrace_filter", " "); + write_tracing_file("set_ftrace_notrace", " "); + write_tracing_file("set_graph_function", " "); + write_tracing_file("set_graph_notrace", " "); +} + static int __cmd_ftrace(struct perf_ftrace *ftrace, int argc, const char **argv) { char *trace_file; @@ -226,6 +279,11 @@ static int __cmd_ftrace(struct perf_ftrace *ftrace, int argc, const char **argv) goto out_reset; } + if (set_tracing_filters(ftrace) < 0) { + pr_err("failed to set tracing filters\n"); + goto out_reset; + } + if (write_tracing_file("current_tracer", ftrace->tracer) < 0) { pr_err("failed to set current_tracer to %s\n", ftrace->tracer); goto out_reset; @@ -310,6 +368,32 @@ static int perf_ftrace_config(const char *var, const char *value, void *cb) return -1; } +static int parse_filter_func(const struct option *opt, const char *str, + int unset __maybe_unused) +{ + struct list_head *head = opt->value; + struct filter_entry *entry; + + entry = malloc(sizeof(*entry) + strlen(str) + 1); + if (entry == NULL) + return -ENOMEM; + + strcpy(entry->name, str); + list_add_tail(&entry->list, head); + + return 0; +} + +static void delete_filter_func(struct list_head *head) +{ + struct filter_entry *pos, *tmp; + + list_for_each_entry_safe(pos, tmp, head, list) { + list_del(&pos->list); + free(pos); + } +} + int cmd_ftrace(int argc, const char **argv) { int ret; @@ -333,9 +417,22 @@ int cmd_ftrace(int argc, const char **argv) "system-wide collection from all CPUs"), OPT_STRING('C', "cpu", &ftrace.target.cpu_list, "cpu", "list of cpus to monitor"), + OPT_CALLBACK('T', "trace-funcs", &ftrace.filters, "func", + "trace given functions only", parse_filter_func), + OPT_CALLBACK('N', "notrace-funcs", &ftrace.notrace, "func", + "do not trace given functions", parse_filter_func), + OPT_CALLBACK('G', "graph-funcs", &ftrace.graph_funcs, "func", + "Set graph filter on given functions", parse_filter_func), + OPT_CALLBACK('g', "nograph-funcs", &ftrace.nograph_funcs, "func", + "Set nograph filter on given functions", parse_filter_func), OPT_END() }; + INIT_LIST_HEAD(&ftrace.filters); + INIT_LIST_HEAD(&ftrace.notrace); + INIT_LIST_HEAD(&ftrace.graph_funcs); + INIT_LIST_HEAD(&ftrace.nograph_funcs); + ret = perf_config(perf_ftrace_config, &ftrace); if (ret < 0) return -1; @@ -351,12 +448,14 @@ int cmd_ftrace(int argc, const char **argv) target__strerror(&ftrace.target, ret, errbuf, 512); pr_err("%s\n", errbuf); - return -EINVAL; + goto out_delete_filters; } ftrace.evlist = perf_evlist__new(); - if (ftrace.evlist == NULL) - return -ENOMEM; + if (ftrace.evlist == NULL) { + ret = -ENOMEM; + goto out_delete_filters; + } ret = perf_evlist__create_maps(ftrace.evlist, &ftrace.target); if (ret < 0) @@ -367,5 +466,11 @@ int cmd_ftrace(int argc, const char **argv) out_delete_evlist: perf_evlist__delete(ftrace.evlist); +out_delete_filters: + delete_filter_func(&ftrace.filters); + delete_filter_func(&ftrace.notrace); + delete_filter_func(&ftrace.graph_funcs); + delete_filter_func(&ftrace.nograph_funcs); + return ret; } -- cgit v1.2.3 From 1096c35aa821cc4789a64232a0e210bb87a0e5e8 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Sun, 18 Jun 2017 23:23:02 +0900 Subject: perf ftrace: Add -D option for depth filter The -D/--graph-depth option is to set max graph depth. The following example traces max 2-depth of page fault handler. $ sudo perf ftrace -G __do_page_fault -D 2 -- hello ... 0) | __do_page_fault() { 0) 0.063 us | down_read_trylock(); 0) 0.251 us | find_vma(); 0) 5.374 us | handle_mm_fault(); 0) 0.054 us | up_read(); 0) 7.463 us | } ... Signed-off-by: Namhyung Kim Tested-by: Arnaldo Carvalho de Melo Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Masami Hiramatsu Cc: Peter Zijlstra Cc: Steven Rostedt Cc: kernel-team@lge.com Link: http://lkml.kernel.org/r/20170618142302.25390-4-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Documentation/perf-ftrace.txt | 3 +++ tools/perf/builtin-ftrace.c | 31 +++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/tools/perf/Documentation/perf-ftrace.txt b/tools/perf/Documentation/perf-ftrace.txt index 78d6126ca485..721a447f046e 100644 --- a/tools/perf/Documentation/perf-ftrace.txt +++ b/tools/perf/Documentation/perf-ftrace.txt @@ -78,6 +78,9 @@ OPTIONS This can be used more than once to specify multiple functions. It will be passed to 'set_graph_notrace' in tracefs. +-D:: +--graph-depth=:: + Set max depth for function graph tracer to follow SEE ALSO -------- diff --git a/tools/perf/builtin-ftrace.c b/tools/perf/builtin-ftrace.c index 3285375ce3c2..dd26c62c9893 100644 --- a/tools/perf/builtin-ftrace.c +++ b/tools/perf/builtin-ftrace.c @@ -35,6 +35,7 @@ struct perf_ftrace { struct list_head notrace; struct list_head graph_funcs; struct list_head nograph_funcs; + int graph_depth; }; struct filter_entry { @@ -129,6 +130,9 @@ static int reset_tracing_files(struct perf_ftrace *ftrace __maybe_unused) if (reset_tracing_cpu() < 0) return -1; + if (write_tracing_file("max_graph_depth", "0") < 0) + return -1; + reset_tracing_filters(); return 0; } @@ -237,6 +241,26 @@ static void reset_tracing_filters(void) write_tracing_file("set_graph_notrace", " "); } +static int set_tracing_depth(struct perf_ftrace *ftrace) +{ + char buf[16]; + + if (ftrace->graph_depth == 0) + return 0; + + if (ftrace->graph_depth < 0) { + pr_err("invalid graph depth: %d\n", ftrace->graph_depth); + return -1; + } + + snprintf(buf, sizeof(buf), "%d", ftrace->graph_depth); + + if (write_tracing_file("max_graph_depth", buf) < 0) + return -1; + + return 0; +} + static int __cmd_ftrace(struct perf_ftrace *ftrace, int argc, const char **argv) { char *trace_file; @@ -284,6 +308,11 @@ static int __cmd_ftrace(struct perf_ftrace *ftrace, int argc, const char **argv) goto out_reset; } + if (set_tracing_depth(ftrace) < 0) { + pr_err("failed to set graph depth\n"); + goto out_reset; + } + if (write_tracing_file("current_tracer", ftrace->tracer) < 0) { pr_err("failed to set current_tracer to %s\n", ftrace->tracer); goto out_reset; @@ -425,6 +454,8 @@ int cmd_ftrace(int argc, const char **argv) "Set graph filter on given functions", parse_filter_func), OPT_CALLBACK('g', "nograph-funcs", &ftrace.nograph_funcs, "func", "Set nograph filter on given functions", parse_filter_func), + OPT_INTEGER('D', "graph-depth", &ftrace.graph_depth, + "Max depth for function graph tracer"), OPT_END() }; -- cgit v1.2.3 From 4f1fd74283582f3f5c34d1c9ed55117d775b4a20 Mon Sep 17 00:00:00 2001 From: Taeung Song Date: Sat, 17 Jun 2017 12:46:37 +0900 Subject: perf config: Check error cases of {show_spec, set}_config() show_spec_config() and set_config() can be called multiple times in the loop in cmd_config(). However, The error cases of them wasn't checked, so fix it. Reported-by: Arnaldo Carvalho de Melo Signed-off-by: Taeung Song Cc: Jiri Olsa Cc: Namhyung Kim Link: http://lkml.kernel.org/r/1497671197-20450-1-git-send-email-treeze.taeung@gmail.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-config.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/tools/perf/builtin-config.c b/tools/perf/builtin-config.c index 75459668edb2..bb1be79bceda 100644 --- a/tools/perf/builtin-config.c +++ b/tools/perf/builtin-config.c @@ -225,10 +225,23 @@ int cmd_config(int argc, const char **argv) break; } - if (value == NULL) + if (value == NULL) { ret = show_spec_config(set, var); - else + if (ret < 0) { + pr_err("%s is not configured: %s\n", + var, config_filename); + free(arg); + break; + } + } else { ret = set_config(set, config_filename, var, value); + if (ret < 0) { + pr_err("Failed to set '%s=%s' on %s\n", + var, value, config_filename); + free(arg); + break; + } + } free(arg); } } -- cgit v1.2.3 From dfe1c6d7efa8ead6878b73216d4c891a28207528 Mon Sep 17 00:00:00 2001 From: Taeung Song Date: Sat, 17 Jun 2017 12:46:42 +0900 Subject: perf config: Refactor the code using 'ret' variable in cmd_config() To simplify the code related to 'ret' variable in cmd_config(), initialize 'ret' with -1 instead of 0 and use goto to perform resource release at the end of the function, setting ret to zero just before the out_err label, as usual in the kernel sources. Signed-off-by: Taeung Song Cc: Jiri Olsa Cc: Namhyung Kim Link: http://lkml.kernel.org/r/1497671202-20495-1-git-send-email-treeze.taeung@gmail.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-config.c | 30 +++++++++++++----------------- 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/tools/perf/builtin-config.c b/tools/perf/builtin-config.c index bb1be79bceda..ece45582a48d 100644 --- a/tools/perf/builtin-config.c +++ b/tools/perf/builtin-config.c @@ -156,7 +156,7 @@ static int parse_config_arg(char *arg, char **var, char **value) int cmd_config(int argc, const char **argv) { - int i, ret = 0; + int i, ret = -1; struct perf_config_set *set; char *user_config = mkpath("%s/.perfconfig", getenv("HOME")); const char *config_filename; @@ -186,10 +186,8 @@ int cmd_config(int argc, const char **argv) * because of reinitializing with options config file location. */ set = perf_config_set__new(); - if (!set) { - ret = -1; + if (!set) goto out_err; - } switch (actions) { case ACTION_LIST: @@ -197,10 +195,11 @@ int cmd_config(int argc, const char **argv) pr_err("Error: takes no arguments\n"); parse_options_usage(config_usage, config_options, "l", 1); } else { - ret = show_config(set); - if (ret < 0) + if (show_config(set) < 0) { pr_err("Nothing configured, " "please check your %s \n", config_filename); + goto out_err; + } } break; default: @@ -215,38 +214,35 @@ int cmd_config(int argc, const char **argv) if (!arg) { pr_err("%s: strdup failed\n", __func__); - ret = -1; - break; + goto out_err; } if (parse_config_arg(arg, &var, &value) < 0) { free(arg); - ret = -1; - break; + goto out_err; } if (value == NULL) { - ret = show_spec_config(set, var); - if (ret < 0) { + if (show_spec_config(set, var) < 0) { pr_err("%s is not configured: %s\n", var, config_filename); free(arg); - break; + goto out_err; } } else { - ret = set_config(set, config_filename, var, value); - if (ret < 0) { + if (set_config(set, config_filename, var, value) < 0) { pr_err("Failed to set '%s=%s' on %s\n", var, value, config_filename); free(arg); - break; + goto out_err; } } free(arg); } } - perf_config_set__delete(set); + ret = 0; out_err: + perf_config_set__delete(set); return ret; } -- cgit v1.2.3 From 2157f6ee18ce5224eea2b27582368b60d940bef6 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 20 Jun 2017 12:05:38 -0300 Subject: perf evsel: Adopt find_process() And make it static, nobody else uses it, if we ever need it in more places we can carve a new source file for process related methods, for now lets reduce util.{c,h} a tad more. Link: http://lkml.kernel.org/n/tip-zgb28rllvypjibw52aaz9p15@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/evsel.c | 39 +++++++++++++++++++++++++++++++++++++++ tools/perf/util/util.c | 37 ------------------------------------- tools/perf/util/util.h | 2 -- 3 files changed, 39 insertions(+), 39 deletions(-) diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index 7f78f27f5382..6f4882f8d61f 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -19,6 +20,8 @@ #include #include #include +#include +#include #include "asm/bug.h" #include "callchain.h" #include "cgroup.h" @@ -2472,6 +2475,42 @@ bool perf_evsel__fallback(struct perf_evsel *evsel, int err, return false; } +static bool find_process(const char *name) +{ + size_t len = strlen(name); + DIR *dir; + struct dirent *d; + int ret = -1; + + dir = opendir(procfs__mountpoint()); + if (!dir) + return false; + + /* Walk through the directory. */ + while (ret && (d = readdir(dir)) != NULL) { + char path[PATH_MAX]; + char *data; + size_t size; + + if ((d->d_type != DT_DIR) || + !strcmp(".", d->d_name) || + !strcmp("..", d->d_name)) + continue; + + scnprintf(path, sizeof(path), "%s/%s/comm", + procfs__mountpoint(), d->d_name); + + if (filename__read_str(path, &data, &size)) + continue; + + ret = strncmp(name, data, len); + free(data); + } + + closedir(dir); + return ret ? false : true; +} + int perf_evsel__open_strerror(struct perf_evsel *evsel, struct target *target, int err, char *msg, size_t size) { diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c index 28c9f335006c..3cd42995ac6f 100644 --- a/tools/perf/util/util.c +++ b/tools/perf/util/util.c @@ -343,43 +343,6 @@ int perf_event_paranoid(void) return value; } - -bool find_process(const char *name) -{ - size_t len = strlen(name); - DIR *dir; - struct dirent *d; - int ret = -1; - - dir = opendir(procfs__mountpoint()); - if (!dir) - return false; - - /* Walk through the directory. */ - while (ret && (d = readdir(dir)) != NULL) { - char path[PATH_MAX]; - char *data; - size_t size; - - if ((d->d_type != DT_DIR) || - !strcmp(".", d->d_name) || - !strcmp("..", d->d_name)) - continue; - - scnprintf(path, sizeof(path), "%s/%s/comm", - procfs__mountpoint(), d->d_name); - - if (filename__read_str(path, &data, &size)) - continue; - - ret = strncmp(name, data, len); - free(data); - } - - closedir(dir); - return ret ? false : true; -} - static int fetch_ubuntu_kernel_version(unsigned int *puint) { diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h index 21c6db173bcc..9ae7e6e35f9a 100644 --- a/tools/perf/util/util.h +++ b/tools/perf/util/util.h @@ -49,8 +49,6 @@ int hex2u64(const char *ptr, u64 *val); extern unsigned int page_size; extern int cacheline_size; -bool find_process(const char *name); - int fetch_kernel_version(unsigned int *puint, char *str, size_t str_sz); #define KVER_VERSION(x) (((x) >> 16) & 0xff) -- cgit v1.2.3 From 44b58e06e8e3872b6741e5aee59a7a93dfe3834a Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 20 Jun 2017 12:19:16 -0300 Subject: perf tools: Do parameter validation earlier on fetch_kernel_version() While trying to reduce util.[ch] I noticed that fetch_kernel_version() and fetch_ubuntu_kernel_version() do lots of operations only to check if they are needed, i.e. it checks if the pointer where to return the kernel version is NULL only after obtaining the kernel version from /proc/version_signature or by parsing the results from uname(). Do it earlier not to confuse people reading this code in the future :-) Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-i94qwyekk4tzbu0b9ce1r1mz@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/util.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c index 3cd42995ac6f..988111e0bab5 100644 --- a/tools/perf/util/util.c +++ b/tools/perf/util/util.c @@ -350,8 +350,12 @@ fetch_ubuntu_kernel_version(unsigned int *puint) size_t line_len = 0; char *ptr, *line = NULL; int version, patchlevel, sublevel, err; - FILE *vsig = fopen("/proc/version_signature", "r"); + FILE *vsig; + if (!puint) + return 0; + + vsig = fopen("/proc/version_signature", "r"); if (!vsig) { pr_debug("Open /proc/version_signature failed: %s\n", strerror(errno)); @@ -381,8 +385,7 @@ fetch_ubuntu_kernel_version(unsigned int *puint) goto errout; } - if (puint) - *puint = (version << 16) + (patchlevel << 8) + sublevel; + *puint = (version << 16) + (patchlevel << 8) + sublevel; err = 0; errout: free(line); @@ -409,6 +412,9 @@ fetch_kernel_version(unsigned int *puint, char *str, str[str_size - 1] = '\0'; } + if (!puint || int_ver_ready) + return 0; + err = sscanf(utsname.release, "%d.%d.%d", &version, &patchlevel, &sublevel); @@ -418,8 +424,7 @@ fetch_kernel_version(unsigned int *puint, char *str, return -1; } - if (puint && !int_ver_ready) - *puint = (version << 16) + (patchlevel << 8) + sublevel; + *puint = (version << 16) + (patchlevel << 8) + sublevel; return 0; } -- cgit v1.2.3 From fd25bf8b8c577aef8c0156eddaf63f3e862c659c Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 20 Jun 2017 12:30:07 -0300 Subject: perf tools: Remove unused _ALL_SOURCE define Curious as to what this was for I looked at /usr/include/ and only some python headers define this, and it ends up being to enable "extensions" on some old OSes: /* Enable extensions on AIX 3, Interix */ I guess we can remove this one safely. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-omnundlxo2brs552bdl6m0j1@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/util.h | 1 - 1 file changed, 1 deletion(-) diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h index 9ae7e6e35f9a..978572dfeb14 100644 --- a/tools/perf/util/util.h +++ b/tools/perf/util/util.h @@ -1,7 +1,6 @@ #ifndef GIT_COMPAT_UTIL_H #define GIT_COMPAT_UTIL_H -#define _ALL_SOURCE 1 #define _BSD_SOURCE 1 /* glibc 2.20 deprecates _BSD_SOURCE in favour of _DEFAULT_SOURCE */ #define _DEFAULT_SOURCE 1 -- cgit v1.2.3 From 3b00ea938653d136c8e4bcbe9722d954e128ce2e Mon Sep 17 00:00:00 2001 From: Kan Liang Date: Fri, 26 May 2017 12:05:37 -0700 Subject: tools lib api fs: Add sysfs__write_int function Add sysfs__write_int() to ease up writing int to sysfs. New interface is: int sysfs__write_int(const char *entry, int value); Also, introducing filename__write_int() which is useful for new helpers to write sysctl values. Signed-off-by: Kan Liang Acked-by: Jiri Olsa Cc: Andi Kleen Cc: Kan Liang Cc: Peter Zijlstra Cc: Robert Elliott Cc: Stephane Eranian Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/1495825538-5230-2-git-send-email-kan.liang@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/lib/api/fs/fs.c | 30 ++++++++++++++++++++++++++++++ tools/lib/api/fs/fs.h | 4 ++++ 2 files changed, 34 insertions(+) diff --git a/tools/lib/api/fs/fs.c b/tools/lib/api/fs/fs.c index 809c7721cd24..a7ecf8f469f4 100644 --- a/tools/lib/api/fs/fs.c +++ b/tools/lib/api/fs/fs.c @@ -387,6 +387,22 @@ int filename__read_str(const char *filename, char **buf, size_t *sizep) return err; } +int filename__write_int(const char *filename, int value) +{ + int fd = open(filename, O_WRONLY), err = -1; + char buf[64]; + + if (fd < 0) + return err; + + sprintf(buf, "%d", value); + if (write(fd, buf, sizeof(buf)) == sizeof(buf)) + err = 0; + + close(fd); + return err; +} + int procfs__read_str(const char *entry, char **buf, size_t *sizep) { char path[PATH_MAX]; @@ -480,3 +496,17 @@ int sysctl__read_int(const char *sysctl, int *value) return filename__read_int(path, value); } + +int sysfs__write_int(const char *entry, int value) +{ + char path[PATH_MAX]; + const char *sysfs = sysfs__mountpoint(); + + if (!sysfs) + return -1; + + if (snprintf(path, sizeof(path), "%s/%s", sysfs, entry) >= PATH_MAX) + return -1; + + return filename__write_int(path, value); +} diff --git a/tools/lib/api/fs/fs.h b/tools/lib/api/fs/fs.h index 956c21127d1e..45605348461e 100644 --- a/tools/lib/api/fs/fs.h +++ b/tools/lib/api/fs/fs.h @@ -31,6 +31,8 @@ int filename__read_int(const char *filename, int *value); int filename__read_ull(const char *filename, unsigned long long *value); int filename__read_str(const char *filename, char **buf, size_t *sizep); +int filename__write_int(const char *filename, int value); + int procfs__read_str(const char *entry, char **buf, size_t *sizep); int sysctl__read_int(const char *sysctl, int *value); @@ -38,4 +40,6 @@ int sysfs__read_int(const char *entry, int *value); int sysfs__read_ull(const char *entry, unsigned long long *value); int sysfs__read_str(const char *entry, char **buf, size_t *sizep); int sysfs__read_bool(const char *entry, bool *value); + +int sysfs__write_int(const char *entry, int value); #endif /* __API_FS__ */ -- cgit v1.2.3 From daefd0bc0bd28cea2e6b2f3e1a9da005cd4f58fc Mon Sep 17 00:00:00 2001 From: Kan Liang Date: Fri, 26 May 2017 12:05:38 -0700 Subject: perf stat: Add support to measure SMI cost Implementing a new --smi-cost mode in perf stat to measure SMI cost. During the measurement, the /sys/device/cpu/freeze_on_smi will be set. The measurement can be done with one counter (unhalted core cycles), and two free running MSR counters (IA32_APERF and SMI_COUNT). In practice, the percentages of SMI core cycles should be more useful than absolute value. So the output will be the percentage of SMI core cycles and SMI#. metric_only will be set by default. SMI cycles% = (aperf - unhalted core cycles) / aperf Here is an example output. Performance counter stats for 'sudo echo ': SMI cycles% SMI# 0.1% 1 0.010858678 seconds time elapsed Users who wants to get the actual value can apply additional --no-metric-only. Signed-off-by: Kan Liang Acked-by: Jiri Olsa Cc: Andi Kleen Cc: Kan Liang Cc: Peter Zijlstra Cc: Robert Elliott Cc: Stephane Eranian Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/1495825538-5230-3-git-send-email-kan.liang@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Documentation/perf-stat.txt | 14 ++++++++++ tools/perf/builtin-stat.c | 49 ++++++++++++++++++++++++++++++++++ tools/perf/util/stat-shadow.c | 33 +++++++++++++++++++++++ tools/perf/util/stat.c | 2 ++ tools/perf/util/stat.h | 2 ++ 5 files changed, 100 insertions(+) diff --git a/tools/perf/Documentation/perf-stat.txt b/tools/perf/Documentation/perf-stat.txt index bd0e4417f2be..698076313606 100644 --- a/tools/perf/Documentation/perf-stat.txt +++ b/tools/perf/Documentation/perf-stat.txt @@ -239,6 +239,20 @@ taskset. --no-merge:: Do not merge results from same PMUs. +--smi-cost:: +Measure SMI cost if msr/aperf/ and msr/smi/ events are supported. + +During the measurement, the /sys/device/cpu/freeze_on_smi will be set to +freeze core counters on SMI. +The aperf counter will not be effected by the setting. +The cost of SMI can be measured by (aperf - unhalted core cycles). + +In practice, the percentages of SMI cycles is very useful for performance +oriented analysis. --metric_only will be applied by default. +The output is SMI cycles%, equals to (aperf - unhalted core cycles) / aperf + +Users who wants to get the actual value can apply --no-metric-only. + EXAMPLES -------- diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index ad9324d1daf9..324363054c3f 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -86,6 +86,7 @@ #define DEFAULT_SEPARATOR " " #define CNTR_NOT_SUPPORTED "" #define CNTR_NOT_COUNTED "" +#define FREEZE_ON_SMI_PATH "devices/cpu/freeze_on_smi" static void print_counters(struct timespec *ts, int argc, const char **argv); @@ -122,6 +123,14 @@ static const char * topdown_attrs[] = { NULL, }; +static const char *smi_cost_attrs = { + "{" + "msr/aperf/," + "msr/smi/," + "cycles" + "}" +}; + static struct perf_evlist *evsel_list; static struct target target = { @@ -137,6 +146,8 @@ static bool null_run = false; static int detailed_run = 0; static bool transaction_run; static bool topdown_run = false; +static bool smi_cost = false; +static bool smi_reset = false; static bool big_num = true; static int big_num_opt = -1; static const char *csv_sep = NULL; @@ -1782,6 +1793,8 @@ static const struct option stat_options[] = { "Only print computed metrics. No raw values", enable_metric_only), OPT_BOOLEAN(0, "topdown", &topdown_run, "measure topdown level 1 statistics"), + OPT_BOOLEAN(0, "smi-cost", &smi_cost, + "measure SMI cost"), OPT_END() }; @@ -2160,6 +2173,39 @@ static int add_default_attributes(void) return 0; } + if (smi_cost) { + int smi; + + if (sysfs__read_int(FREEZE_ON_SMI_PATH, &smi) < 0) { + fprintf(stderr, "freeze_on_smi is not supported.\n"); + return -1; + } + + if (!smi) { + if (sysfs__write_int(FREEZE_ON_SMI_PATH, 1) < 0) { + fprintf(stderr, "Failed to set freeze_on_smi.\n"); + return -1; + } + smi_reset = true; + } + + if (pmu_have_event("msr", "aperf") && + pmu_have_event("msr", "smi")) { + if (!force_metric_only) + metric_only = true; + err = parse_events(evsel_list, smi_cost_attrs, NULL); + } else { + fprintf(stderr, "To measure SMI cost, it needs " + "msr/aperf/, msr/smi/ and cpu/cycles/ support\n"); + return -1; + } + if (err) { + fprintf(stderr, "Cannot set up SMI cost events\n"); + return -1; + } + return 0; + } + if (topdown_run) { char *str = NULL; bool warn = false; @@ -2742,6 +2788,9 @@ int cmd_stat(int argc, const char **argv) perf_stat__exit_aggr_mode(); perf_evlist__free_stats(evsel_list); out: + if (smi_cost && smi_reset) + sysfs__write_int(FREEZE_ON_SMI_PATH, 0); + perf_evlist__delete(evsel_list); return status; } diff --git a/tools/perf/util/stat-shadow.c b/tools/perf/util/stat-shadow.c index ac10cc675d39..719d6cb86952 100644 --- a/tools/perf/util/stat-shadow.c +++ b/tools/perf/util/stat-shadow.c @@ -44,6 +44,8 @@ static struct stats runtime_topdown_slots_issued[NUM_CTX][MAX_NR_CPUS]; static struct stats runtime_topdown_slots_retired[NUM_CTX][MAX_NR_CPUS]; static struct stats runtime_topdown_fetch_bubbles[NUM_CTX][MAX_NR_CPUS]; static struct stats runtime_topdown_recovery_bubbles[NUM_CTX][MAX_NR_CPUS]; +static struct stats runtime_smi_num_stats[NUM_CTX][MAX_NR_CPUS]; +static struct stats runtime_aperf_stats[NUM_CTX][MAX_NR_CPUS]; static struct rblist runtime_saved_values; static bool have_frontend_stalled; @@ -157,6 +159,8 @@ void perf_stat__reset_shadow_stats(void) memset(runtime_topdown_slots_issued, 0, sizeof(runtime_topdown_slots_issued)); memset(runtime_topdown_fetch_bubbles, 0, sizeof(runtime_topdown_fetch_bubbles)); memset(runtime_topdown_recovery_bubbles, 0, sizeof(runtime_topdown_recovery_bubbles)); + memset(runtime_smi_num_stats, 0, sizeof(runtime_smi_num_stats)); + memset(runtime_aperf_stats, 0, sizeof(runtime_aperf_stats)); next = rb_first(&runtime_saved_values.entries); while (next) { @@ -217,6 +221,10 @@ void perf_stat__update_shadow_stats(struct perf_evsel *counter, u64 *count, update_stats(&runtime_dtlb_cache_stats[ctx][cpu], count[0]); else if (perf_evsel__match(counter, HW_CACHE, HW_CACHE_ITLB)) update_stats(&runtime_itlb_cache_stats[ctx][cpu], count[0]); + else if (perf_stat_evsel__is(counter, SMI_NUM)) + update_stats(&runtime_smi_num_stats[ctx][cpu], count[0]); + else if (perf_stat_evsel__is(counter, APERF)) + update_stats(&runtime_aperf_stats[ctx][cpu], count[0]); if (counter->collect_stat) { struct saved_value *v = saved_value_lookup(counter, cpu, ctx, @@ -592,6 +600,29 @@ static double td_be_bound(int ctx, int cpu) return sanitize_val(1.0 - sum); } +static void print_smi_cost(int cpu, struct perf_evsel *evsel, + struct perf_stat_output_ctx *out) +{ + double smi_num, aperf, cycles, cost = 0.0; + int ctx = evsel_context(evsel); + const char *color = NULL; + + smi_num = avg_stats(&runtime_smi_num_stats[ctx][cpu]); + aperf = avg_stats(&runtime_aperf_stats[ctx][cpu]); + cycles = avg_stats(&runtime_cycles_stats[ctx][cpu]); + + if ((cycles == 0) || (aperf == 0)) + return; + + if (smi_num) + cost = (aperf - cycles) / aperf * 100.00; + + if (cost > 10) + color = PERF_COLOR_RED; + out->print_metric(out->ctx, color, "%8.1f%%", "SMI cycles%", cost); + out->print_metric(out->ctx, NULL, "%4.0f", "SMI#", smi_num); +} + void perf_stat__print_shadow_stats(struct perf_evsel *evsel, double avg, int cpu, struct perf_stat_output_ctx *out) @@ -825,6 +856,8 @@ void perf_stat__print_shadow_stats(struct perf_evsel *evsel, } snprintf(unit_buf, sizeof(unit_buf), "%c/sec", unit); print_metric(ctxp, NULL, "%8.3f", unit_buf, ratio); + } else if (perf_stat_evsel__is(evsel, SMI_NUM)) { + print_smi_cost(cpu, evsel, out); } else { print_metric(ctxp, NULL, NULL, NULL, 0); } diff --git a/tools/perf/util/stat.c b/tools/perf/util/stat.c index c58174443dc1..53b9a994a3dc 100644 --- a/tools/perf/util/stat.c +++ b/tools/perf/util/stat.c @@ -86,6 +86,8 @@ static const char *id_str[PERF_STAT_EVSEL_ID__MAX] = { ID(TOPDOWN_SLOTS_RETIRED, topdown-slots-retired), ID(TOPDOWN_FETCH_BUBBLES, topdown-fetch-bubbles), ID(TOPDOWN_RECOVERY_BUBBLES, topdown-recovery-bubbles), + ID(SMI_NUM, msr/smi/), + ID(APERF, msr/aperf/), }; #undef ID diff --git a/tools/perf/util/stat.h b/tools/perf/util/stat.h index 0a65ae23f495..7522bf10b03e 100644 --- a/tools/perf/util/stat.h +++ b/tools/perf/util/stat.h @@ -22,6 +22,8 @@ enum perf_stat_evsel_id { PERF_STAT_EVSEL_ID__TOPDOWN_SLOTS_RETIRED, PERF_STAT_EVSEL_ID__TOPDOWN_FETCH_BUBBLES, PERF_STAT_EVSEL_ID__TOPDOWN_RECOVERY_BUBBLES, + PERF_STAT_EVSEL_ID__SMI_NUM, + PERF_STAT_EVSEL_ID__APERF, PERF_STAT_EVSEL_ID__MAX, }; -- cgit v1.2.3 From a7f0fda085870312ab694b19a1304ece161a1217 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 1 Jun 2017 12:24:41 +0200 Subject: perf unwind: Support for powerpc Porting PPC to libdw only needs an architecture-specific hook to move the register state from perf to libdw. The ARM and x86 architectures already use libdw, and it is useful to have as much common code for the unwinder as possible. Mark Wielaard has contributed a frame-based unwinder to libdw, so that unwinding works even for binaries that do not have CFI information. In addition, libunwind is always preferred to libdw by the build machinery so this cannot introduce regressions on machines that have both libunwind and libdw installed. Signed-off-by: Paolo Bonzini Acked-by: Jiri Olsa Acked-by: Milian Wolff Acked-by: Ravi Bangoria Cc: Naveen N. Rao Cc: linuxppc-dev@lists.ozlabs.org Link: http://lkml.kernel.org/r/1496312681-20133-1-git-send-email-pbonzini@redhat.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Makefile.config | 2 +- tools/perf/arch/powerpc/util/Build | 2 + tools/perf/arch/powerpc/util/unwind-libdw.c | 73 +++++++++++++++++++++++++++++ 3 files changed, 76 insertions(+), 1 deletion(-) create mode 100644 tools/perf/arch/powerpc/util/unwind-libdw.c diff --git a/tools/perf/Makefile.config b/tools/perf/Makefile.config index 1f4fbc9a3292..bdf0e87f9b29 100644 --- a/tools/perf/Makefile.config +++ b/tools/perf/Makefile.config @@ -61,7 +61,7 @@ endif # Disable it on all other architectures in case libdw unwind # support is detected in system. Add supported architectures # to the check. -ifneq ($(SRCARCH),$(filter $(SRCARCH),x86 arm)) +ifneq ($(SRCARCH),$(filter $(SRCARCH),x86 arm powerpc)) NO_LIBDW_DWARF_UNWIND := 1 endif diff --git a/tools/perf/arch/powerpc/util/Build b/tools/perf/arch/powerpc/util/Build index 90ad64b231cd..2e6595310420 100644 --- a/tools/perf/arch/powerpc/util/Build +++ b/tools/perf/arch/powerpc/util/Build @@ -5,4 +5,6 @@ libperf-y += perf_regs.o libperf-$(CONFIG_DWARF) += dwarf-regs.o libperf-$(CONFIG_DWARF) += skip-callchain-idx.o + libperf-$(CONFIG_LIBUNWIND) += unwind-libunwind.o +libperf-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o diff --git a/tools/perf/arch/powerpc/util/unwind-libdw.c b/tools/perf/arch/powerpc/util/unwind-libdw.c new file mode 100644 index 000000000000..3a24b3c43273 --- /dev/null +++ b/tools/perf/arch/powerpc/util/unwind-libdw.c @@ -0,0 +1,73 @@ +#include +#include "../../util/unwind-libdw.h" +#include "../../util/perf_regs.h" +#include "../../util/event.h" + +/* See backends/ppc_initreg.c and backends/ppc_regs.c in elfutils. */ +static const int special_regs[3][2] = { + { 65, PERF_REG_POWERPC_LINK }, + { 101, PERF_REG_POWERPC_XER }, + { 109, PERF_REG_POWERPC_CTR }, +}; + +bool libdw__arch_set_initial_registers(Dwfl_Thread *thread, void *arg) +{ + struct unwind_info *ui = arg; + struct regs_dump *user_regs = &ui->sample->user_regs; + Dwarf_Word dwarf_regs[32], dwarf_nip; + size_t i; + +#define REG(r) ({ \ + Dwarf_Word val = 0; \ + perf_reg_value(&val, user_regs, PERF_REG_POWERPC_##r); \ + val; \ +}) + + dwarf_regs[0] = REG(R0); + dwarf_regs[1] = REG(R1); + dwarf_regs[2] = REG(R2); + dwarf_regs[3] = REG(R3); + dwarf_regs[4] = REG(R4); + dwarf_regs[5] = REG(R5); + dwarf_regs[6] = REG(R6); + dwarf_regs[7] = REG(R7); + dwarf_regs[8] = REG(R8); + dwarf_regs[9] = REG(R9); + dwarf_regs[10] = REG(R10); + dwarf_regs[11] = REG(R11); + dwarf_regs[12] = REG(R12); + dwarf_regs[13] = REG(R13); + dwarf_regs[14] = REG(R14); + dwarf_regs[15] = REG(R15); + dwarf_regs[16] = REG(R16); + dwarf_regs[17] = REG(R17); + dwarf_regs[18] = REG(R18); + dwarf_regs[19] = REG(R19); + dwarf_regs[20] = REG(R20); + dwarf_regs[21] = REG(R21); + dwarf_regs[22] = REG(R22); + dwarf_regs[23] = REG(R23); + dwarf_regs[24] = REG(R24); + dwarf_regs[25] = REG(R25); + dwarf_regs[26] = REG(R26); + dwarf_regs[27] = REG(R27); + dwarf_regs[28] = REG(R28); + dwarf_regs[29] = REG(R29); + dwarf_regs[30] = REG(R30); + dwarf_regs[31] = REG(R31); + if (!dwfl_thread_state_registers(thread, 0, 32, dwarf_regs)) + return false; + + dwarf_nip = REG(NIP); + dwfl_thread_state_register_pc(thread, dwarf_nip); + for (i = 0; i < ARRAY_SIZE(special_regs); i++) { + Dwarf_Word val = 0; + perf_reg_value(&val, user_regs, special_regs[i][1]); + if (!dwfl_thread_state_registers(thread, + special_regs[i][0], 1, + &val)) + return false; + } + + return true; +} -- cgit v1.2.3 From 22c06892332d8916115525145b78e606e9cc6492 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Fri, 26 May 2017 11:17:02 +0300 Subject: perf intel-pt: Move decoder error setting into one condition Move decoder error setting into one condition. Cc'ed to stable because later fixes depend on it. Signed-off-by: Adrian Hunter Cc: Andi Kleen Cc: stable@vger.kernel.org Link: http://lkml.kernel.org/r/1495786658-18063-2-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/intel-pt-decoder/intel-pt-decoder.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c index 7cf7f7aca4d2..5a9676c6e23f 100644 --- a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c +++ b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c @@ -2130,15 +2130,18 @@ const struct intel_pt_state *intel_pt_decode(struct intel_pt_decoder *decoder) } } while (err == -ENOLINK); - decoder->state.err = err ? intel_pt_ext_err(err) : 0; + if (err) { + decoder->state.err = intel_pt_ext_err(err); + decoder->state.from_ip = decoder->ip; + } else { + decoder->state.err = 0; + } + decoder->state.timestamp = decoder->timestamp; decoder->state.est_timestamp = intel_pt_est_timestamp(decoder); decoder->state.cr3 = decoder->cr3; decoder->state.tot_insn_cnt = decoder->tot_insn_cnt; - if (err) - decoder->state.from_ip = decoder->ip; - return &decoder->state; } -- cgit v1.2.3 From 3f04d98e972b59706bd43d6cc75efac91f8fba50 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Fri, 26 May 2017 11:17:03 +0300 Subject: perf intel-pt: Improve sample timestamp The decoder uses its current timestamp in samples. Usually that is a timestamp that has already passed, but in some cases it is a timestamp for a branch that the decoder is walking towards, and consequently hasn't reached. Improve that situation by using the pkt_state to determine when to use the current or previous timestamp. Signed-off-by: Adrian Hunter Cc: Andi Kleen Cc: stable@vger.kernel.org Link: http://lkml.kernel.org/r/1495786658-18063-3-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- .../perf/util/intel-pt-decoder/intel-pt-decoder.c | 34 ++++++++++++++++++++-- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c index 5a9676c6e23f..d5c69e822282 100644 --- a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c +++ b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c @@ -64,6 +64,25 @@ enum intel_pt_pkt_state { INTEL_PT_STATE_FUP_NO_TIP, }; +static inline bool intel_pt_sample_time(enum intel_pt_pkt_state pkt_state) +{ + switch (pkt_state) { + case INTEL_PT_STATE_NO_PSB: + case INTEL_PT_STATE_NO_IP: + case INTEL_PT_STATE_ERR_RESYNC: + case INTEL_PT_STATE_IN_SYNC: + case INTEL_PT_STATE_TNT: + return true; + case INTEL_PT_STATE_TIP: + case INTEL_PT_STATE_TIP_PGD: + case INTEL_PT_STATE_FUP: + case INTEL_PT_STATE_FUP_NO_TIP: + return false; + default: + return true; + }; +} + #ifdef INTEL_PT_STRICT #define INTEL_PT_STATE_ERR1 INTEL_PT_STATE_NO_PSB #define INTEL_PT_STATE_ERR2 INTEL_PT_STATE_NO_PSB @@ -99,6 +118,7 @@ struct intel_pt_decoder { uint64_t timestamp; uint64_t tsc_timestamp; uint64_t ref_timestamp; + uint64_t sample_timestamp; uint64_t ret_addr; uint64_t ctc_timestamp; uint64_t ctc_delta; @@ -139,6 +159,7 @@ struct intel_pt_decoder { unsigned int fup_tx_flags; unsigned int tx_flags; uint64_t timestamp_insn_cnt; + uint64_t sample_insn_cnt; uint64_t stuck_ip; int no_progress; int stuck_ip_prd; @@ -898,6 +919,7 @@ static int intel_pt_walk_insn(struct intel_pt_decoder *decoder, decoder->tot_insn_cnt += insn_cnt; decoder->timestamp_insn_cnt += insn_cnt; + decoder->sample_insn_cnt += insn_cnt; decoder->period_insn_cnt += insn_cnt; if (err) { @@ -2069,7 +2091,7 @@ static int intel_pt_sync(struct intel_pt_decoder *decoder) static uint64_t intel_pt_est_timestamp(struct intel_pt_decoder *decoder) { - uint64_t est = decoder->timestamp_insn_cnt << 1; + uint64_t est = decoder->sample_insn_cnt << 1; if (!decoder->cbr || !decoder->max_non_turbo_ratio) goto out; @@ -2077,7 +2099,7 @@ static uint64_t intel_pt_est_timestamp(struct intel_pt_decoder *decoder) est *= decoder->max_non_turbo_ratio; est /= decoder->cbr; out: - return decoder->timestamp + est; + return decoder->sample_timestamp + est; } const struct intel_pt_state *intel_pt_decode(struct intel_pt_decoder *decoder) @@ -2133,11 +2155,17 @@ const struct intel_pt_state *intel_pt_decode(struct intel_pt_decoder *decoder) if (err) { decoder->state.err = intel_pt_ext_err(err); decoder->state.from_ip = decoder->ip; + decoder->sample_timestamp = decoder->timestamp; + decoder->sample_insn_cnt = decoder->timestamp_insn_cnt; } else { decoder->state.err = 0; + if (intel_pt_sample_time(decoder->pkt_state)) { + decoder->sample_timestamp = decoder->timestamp; + decoder->sample_insn_cnt = decoder->timestamp_insn_cnt; + } } - decoder->state.timestamp = decoder->timestamp; + decoder->state.timestamp = decoder->sample_timestamp; decoder->state.est_timestamp = intel_pt_est_timestamp(decoder); decoder->state.cr3 = decoder->cr3; decoder->state.tot_insn_cnt = decoder->tot_insn_cnt; -- cgit v1.2.3 From 12b7080609097753fd8198cc1daf589be3ec1cca Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Fri, 26 May 2017 11:17:04 +0300 Subject: perf intel-pt: Fix missing stack clear The return compression stack must be cleared whenever there is a PSB. Fix one case where that was not happening. Signed-off-by: Adrian Hunter Cc: Andi Kleen Cc: stable@vger.kernel.org Link: http://lkml.kernel.org/r/1495786658-18063-4-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/intel-pt-decoder/intel-pt-decoder.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c index d5c69e822282..28b16c3acdde 100644 --- a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c +++ b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c @@ -1932,6 +1932,7 @@ static int intel_pt_walk_to_ip(struct intel_pt_decoder *decoder) break; case INTEL_PT_PSB: + intel_pt_clear_stack(&decoder->stack); err = intel_pt_walk_psb(decoder); if (err) return err; -- cgit v1.2.3 From ad7167a8cd174ba7d8c0d0ed8d8410521206d104 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Fri, 26 May 2017 11:17:05 +0300 Subject: perf intel-pt: Ensure IP is zero when state is INTEL_PT_STATE_NO_IP A value of zero is used to indicate that there is no IP. Ensure the value is zero when the state is INTEL_PT_STATE_NO_IP. Signed-off-by: Adrian Hunter Cc: Andi Kleen Cc: stable@vger.kernel.org Link: http://lkml.kernel.org/r/1495786658-18063-5-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/intel-pt-decoder/intel-pt-decoder.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c index 28b16c3acdde..f9cd3aaef488 100644 --- a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c +++ b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c @@ -2117,6 +2117,7 @@ const struct intel_pt_state *intel_pt_decode(struct intel_pt_decoder *decoder) break; case INTEL_PT_STATE_NO_IP: decoder->last_ip = 0; + decoder->ip = 0; /* Fall through */ case INTEL_PT_STATE_ERR_RESYNC: err = intel_pt_sync_ip(decoder); -- cgit v1.2.3 From ee14ac0ef6827cd6f9a572cc83dd0191ea17812c Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Fri, 26 May 2017 11:17:06 +0300 Subject: perf intel-pt: Fix last_ip usage Intel PT uses IP compression based on the last IP. For decoding purposes, 'last IP' is considered to be reset to zero whenever there is a synchronization packet (PSB). The decoder wasn't doing that, and was treating the zero value to mean that there was no last IP, whereas compression can be done against the zero value. Fix by setting last_ip to zero when a PSB is received and keep track of have_last_ip. Signed-off-by: Adrian Hunter Cc: Andi Kleen Cc: stable@vger.kernel.org Link: http://lkml.kernel.org/r/1495786658-18063-6-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/intel-pt-decoder/intel-pt-decoder.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c index f9cd3aaef488..62e2c2ad3f1d 100644 --- a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c +++ b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c @@ -111,6 +111,7 @@ struct intel_pt_decoder { bool have_tma; bool have_cyc; bool fixup_last_mtc; + bool have_last_ip; uint64_t pos; uint64_t last_ip; uint64_t ip; @@ -419,6 +420,7 @@ static uint64_t intel_pt_calc_ip(const struct intel_pt_pkt *packet, static inline void intel_pt_set_last_ip(struct intel_pt_decoder *decoder) { decoder->last_ip = intel_pt_calc_ip(&decoder->packet, decoder->last_ip); + decoder->have_last_ip = true; } static inline void intel_pt_set_ip(struct intel_pt_decoder *decoder) @@ -1672,6 +1674,8 @@ next: break; case INTEL_PT_PSB: + decoder->last_ip = 0; + decoder->have_last_ip = true; intel_pt_clear_stack(&decoder->stack); err = intel_pt_walk_psbend(decoder); if (err == -EAGAIN) @@ -1752,7 +1756,7 @@ next: static inline bool intel_pt_have_ip(struct intel_pt_decoder *decoder) { - return decoder->last_ip || decoder->packet.count == 0 || + return decoder->have_last_ip || decoder->packet.count == 0 || decoder->packet.count == 3 || decoder->packet.count == 6; } @@ -1882,7 +1886,7 @@ static int intel_pt_walk_to_ip(struct intel_pt_decoder *decoder) if (decoder->ip) return 0; } - if (decoder->packet.count) + if (decoder->packet.count && decoder->have_last_ip) intel_pt_set_last_ip(decoder); break; @@ -1932,6 +1936,8 @@ static int intel_pt_walk_to_ip(struct intel_pt_decoder *decoder) break; case INTEL_PT_PSB: + decoder->last_ip = 0; + decoder->have_last_ip = true; intel_pt_clear_stack(&decoder->stack); err = intel_pt_walk_psb(decoder); if (err) @@ -2066,6 +2072,7 @@ static int intel_pt_sync(struct intel_pt_decoder *decoder) decoder->pge = false; decoder->continuous_period = false; + decoder->have_last_ip = false; decoder->last_ip = 0; decoder->ip = 0; intel_pt_clear_stack(&decoder->stack); @@ -2074,6 +2081,7 @@ static int intel_pt_sync(struct intel_pt_decoder *decoder) if (err) return err; + decoder->have_last_ip = true; decoder->pkt_state = INTEL_PT_STATE_NO_IP; err = intel_pt_walk_psb(decoder); @@ -2116,6 +2124,7 @@ const struct intel_pt_state *intel_pt_decode(struct intel_pt_decoder *decoder) err = intel_pt_sync(decoder); break; case INTEL_PT_STATE_NO_IP: + decoder->have_last_ip = false; decoder->last_ip = 0; decoder->ip = 0; /* Fall through */ -- cgit v1.2.3 From f952eaceb089b691eba7c4e13686e742a8f26bf5 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Fri, 26 May 2017 11:17:07 +0300 Subject: perf intel-pt: Ensure never to set 'last_ip' when packet 'count' is zero Intel PT uses IP compression based on the last IP. For decoding purposes, 'last IP' is not updated when a branch target has been suppressed, which is indicated by IPBytes == 0. IPBytes is stored in the packet 'count', so ensure never to set 'last_ip' when packet 'count' is zero. Signed-off-by: Adrian Hunter Cc: Andi Kleen Cc: stable@vger.kernel.org Link: http://lkml.kernel.org/r/1495786658-18063-7-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/intel-pt-decoder/intel-pt-decoder.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c index 62e2c2ad3f1d..72b9dc8135a2 100644 --- a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c +++ b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c @@ -1470,7 +1470,8 @@ static int intel_pt_walk_psbend(struct intel_pt_decoder *decoder) case INTEL_PT_FUP: decoder->pge = true; - intel_pt_set_last_ip(decoder); + if (decoder->packet.count) + intel_pt_set_last_ip(decoder); break; case INTEL_PT_MODE_TSX: @@ -1756,8 +1757,9 @@ next: static inline bool intel_pt_have_ip(struct intel_pt_decoder *decoder) { - return decoder->have_last_ip || decoder->packet.count == 0 || - decoder->packet.count == 3 || decoder->packet.count == 6; + return decoder->packet.count && + (decoder->have_last_ip || decoder->packet.count == 3 || + decoder->packet.count == 6); } /* Walk PSB+ packets to get in sync. */ -- cgit v1.2.3 From 622b7a47b843c78626f40c1d1aeef8483383fba2 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Fri, 26 May 2017 11:17:08 +0300 Subject: perf intel-pt: Use FUP always when scanning for an IP The decoder will try to use branch packets to find an IP to start decoding or to recover from errors. Currently the FUP packet is used only in the case of an overflow, however there is no reason for that to be a special case. So just use FUP always when scanning for an IP. Signed-off-by: Adrian Hunter Cc: Andi Kleen Cc: stable@vger.kernel.org Link: http://lkml.kernel.org/r/1495786658-18063-8-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/intel-pt-decoder/intel-pt-decoder.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c index 72b9dc8135a2..923c60efda26 100644 --- a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c +++ b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c @@ -1882,14 +1882,10 @@ static int intel_pt_walk_to_ip(struct intel_pt_decoder *decoder) break; case INTEL_PT_FUP: - if (decoder->overflow) { - if (intel_pt_have_ip(decoder)) - intel_pt_set_ip(decoder); - if (decoder->ip) - return 0; - } - if (decoder->packet.count && decoder->have_last_ip) - intel_pt_set_last_ip(decoder); + if (intel_pt_have_ip(decoder)) + intel_pt_set_ip(decoder); + if (decoder->ip) + return 0; break; case INTEL_PT_MTC: -- cgit v1.2.3 From 6a558f12dbe85437acbdec5e149ea07b5554eced Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Fri, 26 May 2017 11:17:09 +0300 Subject: perf intel-pt: Clear FUP flag on error Sometimes a FUP packet is associated with a TSX transaction and a flag is set to indicate that. Ensure that flag is cleared on any error condition because at that point the decoder can no longer assume it is correct. Signed-off-by: Adrian Hunter Cc: Andi Kleen Cc: stable@vger.kernel.org Link: http://lkml.kernel.org/r/1495786658-18063-9-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/intel-pt-decoder/intel-pt-decoder.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c index 923c60efda26..a97710162e07 100644 --- a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c +++ b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c @@ -1962,6 +1962,8 @@ static int intel_pt_sync_ip(struct intel_pt_decoder *decoder) { int err; + decoder->set_fup_tx_flags = false; + intel_pt_log("Scanning for full IP\n"); err = intel_pt_walk_to_ip(decoder); if (err) -- cgit v1.2.3 From 04194207fe6424c7a1bfd6f43ef7deb90cdf716f Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Fri, 26 May 2017 11:17:10 +0300 Subject: perf intel-pt: Add missing __fallthrough perf tools uses __fallthrough. Add missing __fallthrough to a switch statement. Signed-off-by: Adrian Hunter Cc: Andi Kleen Link: http://lkml.kernel.org/r/1495786658-18063-10-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/intel-pt-decoder/intel-pt-decoder.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c index a97710162e07..cad40fe93bd2 100644 --- a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c +++ b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c @@ -2127,7 +2127,7 @@ const struct intel_pt_state *intel_pt_decode(struct intel_pt_decoder *decoder) decoder->have_last_ip = false; decoder->last_ip = 0; decoder->ip = 0; - /* Fall through */ + __fallthrough; case INTEL_PT_STATE_ERR_RESYNC: err = intel_pt_sync_ip(decoder); break; -- cgit v1.2.3 From 839598176b0554967238234e1e92c7d1e3f0d53d Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Fri, 26 May 2017 11:17:11 +0300 Subject: perf intel-pt: Allow decoding with branch tracing disabled The kernel now supports the disabling of branch tracing, however the decoder assumes branch tracing is always enabled. Pass through a parameter to indicate whether branch tracing is enabled and use it to avoid cases when the decoder is expecting branch packets. There are 2 such cases. First, FUP packets which can bind to an IP even when there is no branch tracing. Secondly, the decoder will try to use branch packets to find an IP to start decoding or to recover from errors. Signed-off-by: Adrian Hunter Cc: Andi Kleen Link: http://lkml.kernel.org/r/1495786658-18063-11-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/intel-pt-decoder/intel-pt-decoder.c | 13 +++++++++++++ tools/perf/util/intel-pt-decoder/intel-pt-decoder.h | 1 + tools/perf/util/intel-pt.c | 14 ++++++++++++++ 3 files changed, 28 insertions(+) diff --git a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c index cad40fe93bd2..dacb9223e743 100644 --- a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c +++ b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c @@ -106,6 +106,7 @@ struct intel_pt_decoder { const unsigned char *buf; size_t len; bool return_compression; + bool branch_enable; bool mtc_insn; bool pge; bool have_tma; @@ -214,6 +215,7 @@ struct intel_pt_decoder *intel_pt_decoder_new(struct intel_pt_params *params) decoder->pgd_ip = params->pgd_ip; decoder->data = params->data; decoder->return_compression = params->return_compression; + decoder->branch_enable = params->branch_enable; decoder->period = params->period; decoder->period_type = params->period_type; @@ -1650,6 +1652,10 @@ next: break; } intel_pt_set_last_ip(decoder); + if (!decoder->branch_enable) { + decoder->ip = decoder->last_ip; + break; + } err = intel_pt_walk_fup(decoder); if (err != -EAGAIN) { if (err) @@ -1964,6 +1970,13 @@ static int intel_pt_sync_ip(struct intel_pt_decoder *decoder) decoder->set_fup_tx_flags = false; + if (!decoder->branch_enable) { + decoder->pkt_state = INTEL_PT_STATE_IN_SYNC; + decoder->overflow = false; + decoder->state.type = 0; /* Do not have a sample */ + return 0; + } + intel_pt_log("Scanning for full IP\n"); err = intel_pt_walk_to_ip(decoder); if (err) diff --git a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.h b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.h index e90619a43c0c..add3bed58349 100644 --- a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.h +++ b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.h @@ -87,6 +87,7 @@ struct intel_pt_params { bool (*pgd_ip)(uint64_t ip, void *data); void *data; bool return_compression; + bool branch_enable; uint64_t period; enum intel_pt_period_type period_type; unsigned max_non_turbo_ratio; diff --git a/tools/perf/util/intel-pt.c b/tools/perf/util/intel-pt.c index 4c7718f87a08..5c59b8c6a719 100644 --- a/tools/perf/util/intel-pt.c +++ b/tools/perf/util/intel-pt.c @@ -668,6 +668,19 @@ static bool intel_pt_return_compression(struct intel_pt *pt) return true; } +static bool intel_pt_branch_enable(struct intel_pt *pt) +{ + struct perf_evsel *evsel; + u64 config; + + evlist__for_each_entry(pt->session->evlist, evsel) { + if (intel_pt_get_config(pt, &evsel->attr, &config) && + (config & 1) && !(config & 0x2000)) + return false; + } + return true; +} + static unsigned int intel_pt_mtc_period(struct intel_pt *pt) { struct perf_evsel *evsel; @@ -799,6 +812,7 @@ static struct intel_pt_queue *intel_pt_alloc_queue(struct intel_pt *pt, params.walk_insn = intel_pt_walk_next_insn; params.data = ptq; params.return_compression = intel_pt_return_compression(pt); + params.branch_enable = intel_pt_branch_enable(pt); params.max_non_turbo_ratio = pt->max_non_turbo_ratio; params.mtc_period = intel_pt_mtc_period(pt); params.tsc_ctc_ratio_n = pt->tsc_ctc_ratio_n; -- cgit v1.2.3 From 9fd629f9a6d0eded133f5f9866226f6bbfe5f50d Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Fri, 26 May 2017 11:17:12 +0300 Subject: perf intel-pt: Add default config for pass-through branch enable Branch tracing is enabled by default, so a fake config bit called 'pt' (pass-through) was added to allow the 'branch enable' bit to have affect. Add default config 'pt,branch' which will allow users to disable branch tracing using 'branch=0' instead of having to specify 'pt,branch=0'. Signed-off-by: Adrian Hunter Cc: Andi Kleen Link: http://lkml.kernel.org/r/1495786658-18063-12-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/arch/x86/util/intel-pt.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tools/perf/arch/x86/util/intel-pt.c b/tools/perf/arch/x86/util/intel-pt.c index 6fe667b3269e..9535be57033f 100644 --- a/tools/perf/arch/x86/util/intel-pt.c +++ b/tools/perf/arch/x86/util/intel-pt.c @@ -192,6 +192,7 @@ static u64 intel_pt_default_config(struct perf_pmu *intel_pt_pmu) int psb_cyc, psb_periods, psb_period; int pos = 0; u64 config; + char c; pos += scnprintf(buf + pos, sizeof(buf) - pos, "tsc"); @@ -225,6 +226,10 @@ static u64 intel_pt_default_config(struct perf_pmu *intel_pt_pmu) } } + if (perf_pmu__scan_file(intel_pt_pmu, "format/pt", "%c", &c) == 1 && + perf_pmu__scan_file(intel_pt_pmu, "format/branch", "%c", &c) == 1) + pos += scnprintf(buf + pos, sizeof(buf) - pos, ",pt,branch"); + pr_debug2("%s default config: %s\n", intel_pt_pmu->name, buf); intel_pt_parse_terms(&intel_pt_pmu->format, buf, &config); -- cgit v1.2.3 From 2bc60ffd663fc706ba70e603c369ae8ba0523b25 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Fri, 26 May 2017 11:17:13 +0300 Subject: perf intel-pt: Add documentation for new config terms Add documentation for new config terms. Signed-off-by: Adrian Hunter Cc: Andi Kleen Link: http://lkml.kernel.org/r/1495786658-18063-13-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Documentation/intel-pt.txt | 36 +++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/tools/perf/Documentation/intel-pt.txt b/tools/perf/Documentation/intel-pt.txt index b0b3007d3c9c..d157dee7a4ec 100644 --- a/tools/perf/Documentation/intel-pt.txt +++ b/tools/perf/Documentation/intel-pt.txt @@ -364,6 +364,42 @@ cyc_thresh Specifies how frequently CYC packets are produced - see cyc CYC packets are not requested by default. +pt Specifies pass-through which enables the 'branch' config term. + + The default config selects 'pt' if it is available, so a user will + never need to specify this term. + +branch Enable branch tracing. Branch tracing is enabled by default so to + disable branch tracing use 'branch=0'. + + The default config selects 'branch' if it is available. + +ptw Enable PTWRITE packets which are produced when a ptwrite instruction + is executed. + + Support for this feature is indicated by: + + /sys/bus/event_source/devices/intel_pt/caps/ptwrite + + which contains "1" if the feature is supported and + "0" otherwise. + +fup_on_ptw Enable a FUP packet to follow the PTWRITE packet. The FUP packet + provides the address of the ptwrite instruction. In the absence of + fup_on_ptw, the decoder will use the address of the previous branch + if branch tracing is enabled, otherwise the address will be zero. + Note that fup_on_ptw will work even when branch tracing is disabled. + +pwr_evt Enable power events. The power events provide information about + changes to the CPU C-state. + + Support for this feature is indicated by: + + /sys/bus/event_source/devices/intel_pt/caps/power_event_trace + + which contains "1" if the feature is supported and + "0" otherwise. + new snapshot option ------------------- -- cgit v1.2.3 From a472e65fc490ab87e30b7fecb8981f02dbb2b865 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Fri, 26 May 2017 11:17:14 +0300 Subject: perf intel-pt: Add decoder support for ptwrite and power event packets Add decoder support for PTWRITE, MWAIT, PWRE, PWRX and EXSTOP packets. This patch only affects the decoder, so the tools still do not select or consume the new information. That is added in subsequent patches. Signed-off-by: Adrian Hunter Cc: Andi Kleen Link: http://lkml.kernel.org/r/1495786658-18063-14-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- .../perf/util/intel-pt-decoder/intel-pt-decoder.c | 176 ++++++++++++++++++++- .../perf/util/intel-pt-decoder/intel-pt-decoder.h | 10 ++ .../util/intel-pt-decoder/intel-pt-pkt-decoder.c | 108 +++++++++++++ .../util/intel-pt-decoder/intel-pt-pkt-decoder.h | 7 + 4 files changed, 293 insertions(+), 8 deletions(-) diff --git a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c index dacb9223e743..e42804d10001 100644 --- a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c +++ b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c @@ -158,8 +158,15 @@ struct intel_pt_decoder { bool continuous_period; bool overflow; bool set_fup_tx_flags; + bool set_fup_ptw; + bool set_fup_mwait; + bool set_fup_pwre; + bool set_fup_exstop; unsigned int fup_tx_flags; unsigned int tx_flags; + uint64_t fup_ptw_payload; + uint64_t fup_mwait_payload; + uint64_t fup_pwre_payload; uint64_t timestamp_insn_cnt; uint64_t sample_insn_cnt; uint64_t stuck_ip; @@ -660,6 +667,8 @@ static int intel_pt_calc_cyc_cb(struct intel_pt_pkt_info *pkt_info) case INTEL_PT_PAD: case INTEL_PT_VMCS: case INTEL_PT_MNT: + case INTEL_PT_PTWRITE: + case INTEL_PT_PTWRITE_IP: return 0; case INTEL_PT_MTC: @@ -758,6 +767,11 @@ static int intel_pt_calc_cyc_cb(struct intel_pt_pkt_info *pkt_info) case INTEL_PT_TIP_PGD: case INTEL_PT_TRACESTOP: + case INTEL_PT_EXSTOP: + case INTEL_PT_EXSTOP_IP: + case INTEL_PT_MWAIT: + case INTEL_PT_PWRE: + case INTEL_PT_PWRX: case INTEL_PT_OVF: case INTEL_PT_BAD: /* Does not happen */ default: @@ -1016,6 +1030,57 @@ out_no_progress: return err; } +static bool intel_pt_fup_event(struct intel_pt_decoder *decoder) +{ + bool ret = false; + + if (decoder->set_fup_tx_flags) { + decoder->set_fup_tx_flags = false; + decoder->tx_flags = decoder->fup_tx_flags; + decoder->state.type = INTEL_PT_TRANSACTION; + decoder->state.from_ip = decoder->ip; + decoder->state.to_ip = 0; + decoder->state.flags = decoder->fup_tx_flags; + return true; + } + if (decoder->set_fup_ptw) { + decoder->set_fup_ptw = false; + decoder->state.type = INTEL_PT_PTW; + decoder->state.flags |= INTEL_PT_FUP_IP; + decoder->state.from_ip = decoder->ip; + decoder->state.to_ip = 0; + decoder->state.ptw_payload = decoder->fup_ptw_payload; + return true; + } + if (decoder->set_fup_mwait) { + decoder->set_fup_mwait = false; + decoder->state.type = INTEL_PT_MWAIT_OP; + decoder->state.from_ip = decoder->ip; + decoder->state.to_ip = 0; + decoder->state.mwait_payload = decoder->fup_mwait_payload; + ret = true; + } + if (decoder->set_fup_pwre) { + decoder->set_fup_pwre = false; + decoder->state.type |= INTEL_PT_PWR_ENTRY; + decoder->state.type &= ~INTEL_PT_BRANCH; + decoder->state.from_ip = decoder->ip; + decoder->state.to_ip = 0; + decoder->state.pwre_payload = decoder->fup_pwre_payload; + ret = true; + } + if (decoder->set_fup_exstop) { + decoder->set_fup_exstop = false; + decoder->state.type |= INTEL_PT_EX_STOP; + decoder->state.type &= ~INTEL_PT_BRANCH; + decoder->state.flags |= INTEL_PT_FUP_IP; + decoder->state.from_ip = decoder->ip; + decoder->state.to_ip = 0; + ret = true; + } + return ret; +} + static int intel_pt_walk_fup(struct intel_pt_decoder *decoder) { struct intel_pt_insn intel_pt_insn; @@ -1029,15 +1094,8 @@ static int intel_pt_walk_fup(struct intel_pt_decoder *decoder) if (err == INTEL_PT_RETURN) return 0; if (err == -EAGAIN) { - if (decoder->set_fup_tx_flags) { - decoder->set_fup_tx_flags = false; - decoder->tx_flags = decoder->fup_tx_flags; - decoder->state.type = INTEL_PT_TRANSACTION; - decoder->state.from_ip = decoder->ip; - decoder->state.to_ip = 0; - decoder->state.flags = decoder->fup_tx_flags; + if (intel_pt_fup_event(decoder)) return 0; - } return err; } decoder->set_fup_tx_flags = false; @@ -1443,6 +1501,13 @@ static int intel_pt_walk_psbend(struct intel_pt_decoder *decoder) case INTEL_PT_TRACESTOP: case INTEL_PT_BAD: case INTEL_PT_PSB: + case INTEL_PT_PTWRITE: + case INTEL_PT_PTWRITE_IP: + case INTEL_PT_EXSTOP: + case INTEL_PT_EXSTOP_IP: + case INTEL_PT_MWAIT: + case INTEL_PT_PWRE: + case INTEL_PT_PWRX: decoder->have_tma = false; intel_pt_log("ERROR: Unexpected packet\n"); return -EAGAIN; @@ -1524,6 +1589,13 @@ static int intel_pt_walk_fup_tip(struct intel_pt_decoder *decoder) case INTEL_PT_MODE_TSX: case INTEL_PT_BAD: case INTEL_PT_PSBEND: + case INTEL_PT_PTWRITE: + case INTEL_PT_PTWRITE_IP: + case INTEL_PT_EXSTOP: + case INTEL_PT_EXSTOP_IP: + case INTEL_PT_MWAIT: + case INTEL_PT_PWRE: + case INTEL_PT_PWRX: intel_pt_log("ERROR: Missing TIP after FUP\n"); decoder->pkt_state = INTEL_PT_STATE_ERR3; return -ENOENT; @@ -1654,8 +1726,13 @@ next: intel_pt_set_last_ip(decoder); if (!decoder->branch_enable) { decoder->ip = decoder->last_ip; + if (intel_pt_fup_event(decoder)) + return 0; + no_tip = false; break; } + if (decoder->set_fup_mwait) + no_tip = true; err = intel_pt_walk_fup(decoder); if (err != -EAGAIN) { if (err) @@ -1755,6 +1832,71 @@ next: case INTEL_PT_PAD: break; + case INTEL_PT_PTWRITE_IP: + decoder->fup_ptw_payload = decoder->packet.payload; + err = intel_pt_get_next_packet(decoder); + if (err) + return err; + if (decoder->packet.type == INTEL_PT_FUP) { + decoder->set_fup_ptw = true; + no_tip = true; + } else { + intel_pt_log_at("ERROR: Missing FUP after PTWRITE", + decoder->pos); + } + goto next; + + case INTEL_PT_PTWRITE: + decoder->state.type = INTEL_PT_PTW; + decoder->state.from_ip = decoder->ip; + decoder->state.to_ip = 0; + decoder->state.ptw_payload = decoder->packet.payload; + return 0; + + case INTEL_PT_MWAIT: + decoder->fup_mwait_payload = decoder->packet.payload; + decoder->set_fup_mwait = true; + break; + + case INTEL_PT_PWRE: + if (decoder->set_fup_mwait) { + decoder->fup_pwre_payload = + decoder->packet.payload; + decoder->set_fup_pwre = true; + break; + } + decoder->state.type = INTEL_PT_PWR_ENTRY; + decoder->state.from_ip = decoder->ip; + decoder->state.to_ip = 0; + decoder->state.pwrx_payload = decoder->packet.payload; + return 0; + + case INTEL_PT_EXSTOP_IP: + err = intel_pt_get_next_packet(decoder); + if (err) + return err; + if (decoder->packet.type == INTEL_PT_FUP) { + decoder->set_fup_exstop = true; + no_tip = true; + } else { + intel_pt_log_at("ERROR: Missing FUP after EXSTOP", + decoder->pos); + } + goto next; + + case INTEL_PT_EXSTOP: + decoder->state.type = INTEL_PT_EX_STOP; + decoder->state.from_ip = decoder->ip; + decoder->state.to_ip = 0; + return 0; + + case INTEL_PT_PWRX: + decoder->state.type = INTEL_PT_PWR_EXIT; + decoder->state.from_ip = decoder->ip; + decoder->state.to_ip = 0; + decoder->state.pwrx_payload = decoder->packet.payload; + return 0; + default: return intel_pt_bug(decoder); } @@ -1784,6 +1926,13 @@ static int intel_pt_walk_psb(struct intel_pt_decoder *decoder) __fallthrough; case INTEL_PT_TIP_PGE: case INTEL_PT_TIP: + case INTEL_PT_PTWRITE: + case INTEL_PT_PTWRITE_IP: + case INTEL_PT_EXSTOP: + case INTEL_PT_EXSTOP_IP: + case INTEL_PT_MWAIT: + case INTEL_PT_PWRE: + case INTEL_PT_PWRX: intel_pt_log("ERROR: Unexpected packet\n"); return -ENOENT; @@ -1958,6 +2107,13 @@ static int intel_pt_walk_to_ip(struct intel_pt_decoder *decoder) case INTEL_PT_VMCS: case INTEL_PT_MNT: case INTEL_PT_PAD: + case INTEL_PT_PTWRITE: + case INTEL_PT_PTWRITE_IP: + case INTEL_PT_EXSTOP: + case INTEL_PT_EXSTOP_IP: + case INTEL_PT_MWAIT: + case INTEL_PT_PWRE: + case INTEL_PT_PWRX: default: break; } @@ -1969,6 +2125,10 @@ static int intel_pt_sync_ip(struct intel_pt_decoder *decoder) int err; decoder->set_fup_tx_flags = false; + decoder->set_fup_ptw = false; + decoder->set_fup_mwait = false; + decoder->set_fup_pwre = false; + decoder->set_fup_exstop = false; if (!decoder->branch_enable) { decoder->pkt_state = INTEL_PT_STATE_IN_SYNC; diff --git a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.h b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.h index add3bed58349..414c88e9e0da 100644 --- a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.h +++ b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.h @@ -25,11 +25,17 @@ #define INTEL_PT_IN_TX (1 << 0) #define INTEL_PT_ABORT_TX (1 << 1) #define INTEL_PT_ASYNC (1 << 2) +#define INTEL_PT_FUP_IP (1 << 3) enum intel_pt_sample_type { INTEL_PT_BRANCH = 1 << 0, INTEL_PT_INSTRUCTION = 1 << 1, INTEL_PT_TRANSACTION = 1 << 2, + INTEL_PT_PTW = 1 << 3, + INTEL_PT_MWAIT_OP = 1 << 4, + INTEL_PT_PWR_ENTRY = 1 << 5, + INTEL_PT_EX_STOP = 1 << 6, + INTEL_PT_PWR_EXIT = 1 << 7, }; enum intel_pt_period_type { @@ -63,6 +69,10 @@ struct intel_pt_state { uint64_t timestamp; uint64_t est_timestamp; uint64_t trace_nr; + uint64_t ptw_payload; + uint64_t mwait_payload; + uint64_t pwre_payload; + uint64_t pwrx_payload; uint32_t flags; enum intel_pt_insn_op insn_op; int insn_len; diff --git a/tools/perf/util/intel-pt-decoder/intel-pt-pkt-decoder.c b/tools/perf/util/intel-pt-decoder/intel-pt-pkt-decoder.c index 7528ae4f7e28..accdb646a03d 100644 --- a/tools/perf/util/intel-pt-decoder/intel-pt-pkt-decoder.c +++ b/tools/perf/util/intel-pt-decoder/intel-pt-pkt-decoder.c @@ -64,6 +64,13 @@ static const char * const packet_name[] = { [INTEL_PT_PIP] = "PIP", [INTEL_PT_OVF] = "OVF", [INTEL_PT_MNT] = "MNT", + [INTEL_PT_PTWRITE] = "PTWRITE", + [INTEL_PT_PTWRITE_IP] = "PTWRITE", + [INTEL_PT_EXSTOP] = "EXSTOP", + [INTEL_PT_EXSTOP_IP] = "EXSTOP", + [INTEL_PT_MWAIT] = "MWAIT", + [INTEL_PT_PWRE] = "PWRE", + [INTEL_PT_PWRX] = "PWRX", }; const char *intel_pt_pkt_name(enum intel_pt_pkt_type type) @@ -217,12 +224,80 @@ static int intel_pt_get_3byte(const unsigned char *buf, size_t len, } } +static int intel_pt_get_ptwrite(const unsigned char *buf, size_t len, + struct intel_pt_pkt *packet) +{ + packet->count = (buf[1] >> 5) & 0x3; + packet->type = buf[1] & BIT(7) ? INTEL_PT_PTWRITE_IP : + INTEL_PT_PTWRITE; + + switch (packet->count) { + case 0: + if (len < 6) + return INTEL_PT_NEED_MORE_BYTES; + packet->payload = le32_to_cpu(*(uint32_t *)(buf + 2)); + return 6; + case 1: + if (len < 10) + return INTEL_PT_NEED_MORE_BYTES; + packet->payload = le64_to_cpu(*(uint64_t *)(buf + 2)); + return 10; + default: + return INTEL_PT_BAD_PACKET; + } +} + +static int intel_pt_get_exstop(struct intel_pt_pkt *packet) +{ + packet->type = INTEL_PT_EXSTOP; + return 2; +} + +static int intel_pt_get_exstop_ip(struct intel_pt_pkt *packet) +{ + packet->type = INTEL_PT_EXSTOP_IP; + return 2; +} + +static int intel_pt_get_mwait(const unsigned char *buf, size_t len, + struct intel_pt_pkt *packet) +{ + if (len < 10) + return INTEL_PT_NEED_MORE_BYTES; + packet->type = INTEL_PT_MWAIT; + packet->payload = le64_to_cpu(*(uint64_t *)(buf + 2)); + return 10; +} + +static int intel_pt_get_pwre(const unsigned char *buf, size_t len, + struct intel_pt_pkt *packet) +{ + if (len < 4) + return INTEL_PT_NEED_MORE_BYTES; + packet->type = INTEL_PT_PWRE; + memcpy_le64(&packet->payload, buf + 2, 2); + return 4; +} + +static int intel_pt_get_pwrx(const unsigned char *buf, size_t len, + struct intel_pt_pkt *packet) +{ + if (len < 7) + return INTEL_PT_NEED_MORE_BYTES; + packet->type = INTEL_PT_PWRX; + memcpy_le64(&packet->payload, buf + 2, 5); + return 7; +} + static int intel_pt_get_ext(const unsigned char *buf, size_t len, struct intel_pt_pkt *packet) { if (len < 2) return INTEL_PT_NEED_MORE_BYTES; + if ((buf[1] & 0x1f) == 0x12) + return intel_pt_get_ptwrite(buf, len, packet); + switch (buf[1]) { case 0xa3: /* Long TNT */ return intel_pt_get_long_tnt(buf, len, packet); @@ -244,6 +319,16 @@ static int intel_pt_get_ext(const unsigned char *buf, size_t len, return intel_pt_get_tma(buf, len, packet); case 0xC3: /* 3-byte header */ return intel_pt_get_3byte(buf, len, packet); + case 0x62: /* EXSTOP no IP */ + return intel_pt_get_exstop(packet); + case 0xE2: /* EXSTOP with IP */ + return intel_pt_get_exstop_ip(packet); + case 0xC2: /* MWAIT */ + return intel_pt_get_mwait(buf, len, packet); + case 0x22: /* PWRE */ + return intel_pt_get_pwre(buf, len, packet); + case 0xA2: /* PWRX */ + return intel_pt_get_pwrx(buf, len, packet); default: return INTEL_PT_BAD_PACKET; } @@ -522,6 +607,29 @@ int intel_pt_pkt_desc(const struct intel_pt_pkt *packet, char *buf, ret = snprintf(buf, buf_len, "%s 0x%llx (NR=%d)", name, payload, nr); return ret; + case INTEL_PT_PTWRITE: + return snprintf(buf, buf_len, "%s 0x%llx IP:0", name, payload); + case INTEL_PT_PTWRITE_IP: + return snprintf(buf, buf_len, "%s 0x%llx IP:1", name, payload); + case INTEL_PT_EXSTOP: + return snprintf(buf, buf_len, "%s IP:0", name); + case INTEL_PT_EXSTOP_IP: + return snprintf(buf, buf_len, "%s IP:1", name); + case INTEL_PT_MWAIT: + return snprintf(buf, buf_len, "%s 0x%llx Hints 0x%x Extensions 0x%x", + name, payload, (unsigned int)(payload & 0xff), + (unsigned int)((payload >> 32) & 0x3)); + case INTEL_PT_PWRE: + return snprintf(buf, buf_len, "%s 0x%llx HW:%u CState:%u Sub-CState:%u", + name, payload, !!(payload & 0x80), + (unsigned int)((payload >> 12) & 0xf), + (unsigned int)((payload >> 8) & 0xf)); + case INTEL_PT_PWRX: + return snprintf(buf, buf_len, "%s 0x%llx Last CState:%u Deepest CState:%u Wake Reason 0x%x", + name, payload, + (unsigned int)((payload >> 4) & 0xf), + (unsigned int)(payload & 0xf), + (unsigned int)((payload >> 8) & 0xf)); default: break; } diff --git a/tools/perf/util/intel-pt-decoder/intel-pt-pkt-decoder.h b/tools/perf/util/intel-pt-decoder/intel-pt-pkt-decoder.h index 781bb79883bd..73ddc3a88d07 100644 --- a/tools/perf/util/intel-pt-decoder/intel-pt-pkt-decoder.h +++ b/tools/perf/util/intel-pt-decoder/intel-pt-pkt-decoder.h @@ -52,6 +52,13 @@ enum intel_pt_pkt_type { INTEL_PT_PIP, INTEL_PT_OVF, INTEL_PT_MNT, + INTEL_PT_PTWRITE, + INTEL_PT_PTWRITE_IP, + INTEL_PT_EXSTOP, + INTEL_PT_EXSTOP_IP, + INTEL_PT_MWAIT, + INTEL_PT_PWRE, + INTEL_PT_PWRX, }; struct intel_pt_pkt { -- cgit v1.2.3 From 26fb2fb19c28ec692d6604bb01cbb4f03a4ee009 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Fri, 26 May 2017 11:17:15 +0300 Subject: perf intel-pt: Add reserved byte to CBR packet payload Future proof CBR packet decoding by passing through also the undefined 'reserved' byte in the packet payload. Signed-off-by: Adrian Hunter Cc: Andi Kleen Link: http://lkml.kernel.org/r/1495786658-18063-15-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/intel-pt-decoder/intel-pt-decoder.c | 2 +- tools/perf/util/intel-pt-decoder/intel-pt-pkt-decoder.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c index e42804d10001..96bf8d8e83c0 100644 --- a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c +++ b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c @@ -1444,7 +1444,7 @@ static void intel_pt_calc_mtc_timestamp(struct intel_pt_decoder *decoder) static void intel_pt_calc_cbr(struct intel_pt_decoder *decoder) { - unsigned int cbr = decoder->packet.payload; + unsigned int cbr = decoder->packet.payload & 0xff; if (decoder->cbr == cbr) return; diff --git a/tools/perf/util/intel-pt-decoder/intel-pt-pkt-decoder.c b/tools/perf/util/intel-pt-decoder/intel-pt-pkt-decoder.c index accdb646a03d..ba4c9dd18643 100644 --- a/tools/perf/util/intel-pt-decoder/intel-pt-pkt-decoder.c +++ b/tools/perf/util/intel-pt-decoder/intel-pt-pkt-decoder.c @@ -130,7 +130,7 @@ static int intel_pt_get_cbr(const unsigned char *buf, size_t len, if (len < 4) return INTEL_PT_NEED_MORE_BYTES; packet->type = INTEL_PT_CBR; - packet->payload = buf[2]; + packet->payload = le16_to_cpu(*(uint16_t *)(buf + 2)); return 4; } -- cgit v1.2.3 From 0a7c700d23450bd4467855d5162920d5edf314b0 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Fri, 26 May 2017 11:17:16 +0300 Subject: perf intel-pt: Add decoder support for CBR events Add decoder support for informing the tools of changes to the core-to-bus ratio (CBR). Signed-off-by: Adrian Hunter Cc: Andi Kleen Link: http://lkml.kernel.org/r/1495786658-18063-16-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/intel-pt-decoder/intel-pt-decoder.c | 19 +++++++++++++++++++ tools/perf/util/intel-pt-decoder/intel-pt-decoder.h | 2 ++ 2 files changed, 21 insertions(+) diff --git a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c index 96bf8d8e83c0..5dea06289db5 100644 --- a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c +++ b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c @@ -141,6 +141,7 @@ struct intel_pt_decoder { int pkt_len; int last_packet_type; unsigned int cbr; + unsigned int cbr_seen; unsigned int max_non_turbo_ratio; double max_non_turbo_ratio_fp; double cbr_cyc_to_tsc; @@ -167,6 +168,7 @@ struct intel_pt_decoder { uint64_t fup_ptw_payload; uint64_t fup_mwait_payload; uint64_t fup_pwre_payload; + uint64_t cbr_payload; uint64_t timestamp_insn_cnt; uint64_t sample_insn_cnt; uint64_t stuck_ip; @@ -1446,6 +1448,8 @@ static void intel_pt_calc_cbr(struct intel_pt_decoder *decoder) { unsigned int cbr = decoder->packet.payload & 0xff; + decoder->cbr_payload = decoder->packet.payload; + if (decoder->cbr == cbr) return; @@ -1806,6 +1810,16 @@ next: case INTEL_PT_CBR: intel_pt_calc_cbr(decoder); + if (!decoder->branch_enable && + decoder->cbr != decoder->cbr_seen) { + decoder->cbr_seen = decoder->cbr; + decoder->state.type = INTEL_PT_CBR_CHG; + decoder->state.from_ip = decoder->ip; + decoder->state.to_ip = 0; + decoder->state.cbr_payload = + decoder->packet.payload; + return 0; + } break; case INTEL_PT_MODE_EXEC: @@ -2343,6 +2357,11 @@ const struct intel_pt_state *intel_pt_decode(struct intel_pt_decoder *decoder) decoder->sample_insn_cnt = decoder->timestamp_insn_cnt; } else { decoder->state.err = 0; + if (decoder->cbr != decoder->cbr_seen && decoder->state.type) { + decoder->cbr_seen = decoder->cbr; + decoder->state.type |= INTEL_PT_CBR_CHG; + decoder->state.cbr_payload = decoder->cbr_payload; + } if (intel_pt_sample_time(decoder->pkt_state)) { decoder->sample_timestamp = decoder->timestamp; decoder->sample_insn_cnt = decoder->timestamp_insn_cnt; diff --git a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.h b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.h index 414c88e9e0da..921b22e8ca0e 100644 --- a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.h +++ b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.h @@ -36,6 +36,7 @@ enum intel_pt_sample_type { INTEL_PT_PWR_ENTRY = 1 << 5, INTEL_PT_EX_STOP = 1 << 6, INTEL_PT_PWR_EXIT = 1 << 7, + INTEL_PT_CBR_CHG = 1 << 8, }; enum intel_pt_period_type { @@ -73,6 +74,7 @@ struct intel_pt_state { uint64_t mwait_payload; uint64_t pwre_payload; uint64_t pwrx_payload; + uint64_t cbr_payload; uint32_t flags; enum intel_pt_insn_op insn_op; int insn_len; -- cgit v1.2.3 From 5da3b23b3b03d34fbb8cb9947c1a99ea77c2203f Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Fri, 26 May 2017 11:17:17 +0300 Subject: perf intel-pt: Remove redundant initial_skip checks 'initial_skip' is checked inside the sample synthesis functions which means it is actually being done twice for 'instructions' and 'transactions' samples. Remove the redundant checks. Signed-off-by: Adrian Hunter Cc: Andi Kleen Link: http://lkml.kernel.org/r/1495786658-18063-17-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/intel-pt.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/tools/perf/util/intel-pt.c b/tools/perf/util/intel-pt.c index 5c59b8c6a719..3ae03f920253 100644 --- a/tools/perf/util/intel-pt.c +++ b/tools/perf/util/intel-pt.c @@ -1322,18 +1322,14 @@ static int intel_pt_sample(struct intel_pt_queue *ptq) ptq->have_sample = false; if (pt->sample_instructions && - (state->type & INTEL_PT_INSTRUCTION) && - (!pt->synth_opts.initial_skip || - pt->num_events++ >= pt->synth_opts.initial_skip)) { + (state->type & INTEL_PT_INSTRUCTION)) { err = intel_pt_synth_instruction_sample(ptq); if (err) return err; } if (pt->sample_transactions && - (state->type & INTEL_PT_TRANSACTION) && - (!pt->synth_opts.initial_skip || - pt->num_events++ >= pt->synth_opts.initial_skip)) { + (state->type & INTEL_PT_TRANSACTION)) { err = intel_pt_synth_transaction_sample(ptq); if (err) return err; -- cgit v1.2.3 From 2116074898ff9ff093963adc0fefcabbbbd7ec41 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Fri, 26 May 2017 11:17:18 +0300 Subject: perf intel-pt: Fix transactions_sample_type 'transactions_sample_type' is needed to correctly inject transactions samples but it was not being set. Set it from the event sample type. Signed-off-by: Adrian Hunter Cc: Andi Kleen Link: http://lkml.kernel.org/r/1495786658-18063-18-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/intel-pt.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/perf/util/intel-pt.c b/tools/perf/util/intel-pt.c index 3ae03f920253..6df836469f2b 100644 --- a/tools/perf/util/intel-pt.c +++ b/tools/perf/util/intel-pt.c @@ -2035,6 +2035,7 @@ static int intel_pt_synth_events(struct intel_pt *pt, return err; } pt->sample_transactions = true; + pt->transactions_sample_type = attr.sample_type; pt->transactions_id = id; id += 1; evlist__for_each_entry(evlist, evsel) { -- cgit v1.2.3 From 30795467e54f3fe0d00f2dba4e58e6475b8fd2e7 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Fri, 26 May 2017 11:17:19 +0300 Subject: perf tools: Fix message because cpu list option is -C not -c Fix message because cpu list option is -C not -c Signed-off-by: Adrian Hunter Cc: Andi Kleen Link: http://lkml.kernel.org/r/1495786658-18063-19-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/session.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 7dc1096264c5..d19c40a81040 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -2035,7 +2035,7 @@ int perf_session__cpu_bitmap(struct perf_session *session, if (!(evsel->attr.sample_type & PERF_SAMPLE_CPU)) { pr_err("File does not contain CPU events. " - "Remove -c option to proceed.\n"); + "Remove -C option to proceed.\n"); return -1; } } -- cgit v1.2.3 From 701516ae3dec801084bc913d21e03fce15c61a0b Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Fri, 26 May 2017 11:17:20 +0300 Subject: perf script: Fix message because field list option is -F not -f Fix message because field list option is -F not -f. Signed-off-by: Adrian Hunter Cc: Andi Kleen Link: http://lkml.kernel.org/r/1495786658-18063-20-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-script.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index db5261c3f719..4bce7d8679cb 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c @@ -385,7 +385,7 @@ static int perf_session__check_output_opt(struct perf_session *session) */ if (!evsel && output[j].user_set && !output[j].wildcard_set) { pr_err("%s events do not exist. " - "Remove corresponding -f option to proceed.\n", + "Remove corresponding -F option to proceed.\n", event_type(j)); return -1; } -- cgit v1.2.3 From 19508c048a2f90facb64624340bf1b7ee555442e Mon Sep 17 00:00:00 2001 From: Thomas Richter Date: Thu, 22 Jun 2017 09:36:25 +0200 Subject: perf tests: Add platform dependency to test 15 This patch adds platform dependency into the test case 15 (perf_event_attr). It is based on a suggestion from Jiri Olsa. Add a new optional attribute named 'arch' in the [config] section of the test case file. It is a comma separated list of architecture names this test can be executed on. For example: arch = x86_64,alpha,ppc If this attribute is missing the test is executed on any platform. This does not break existing behavior. The values listed for this attribute should be identical to uname -m output. If the list starts with an exclamation mark (!) the comparison is inverted, for example for arch = !s390x,ppc the test is not executed on s390x or ppc platforms. The exclamation mark must be at the beginnning of the list. Here is an example debug output: [root@s35lp76]# fgrep arch tests/attr/test-stat-C2 arch = x86_64,alpha,ppc [root@s35lp76]# PERF_TEST_ATTR=/tmp /usr/bin/python2 ./tests/attr.py \ -d ./tests/attr/ -p ./perf -vvvvv -t test-stat-C1 provides the following output: running './tests/attr//test-stat-C1' test limitation 'x86_64,alpha,ppc' <--- new loading expected events Event event:base-stat fd = 1 group_fd = -1 ..... Here is the output when a test is skipped: [root@s35lp76]# fgrep arch tests/attr/test-stat-C1 arch = !s390x [root@s35lp76]# PERF_TEST_ATTR=/tmp /usr/bin/python2 ./tests/attr.py \ -d ./tests/attr/ -p ./perf -vvvvv -t test-stat-C1 provides the following output: test limitation '!s390x' <--- new skipped [s390x] './tests/attr//test-stat-C1' <--- new The test is skipped with return code 0. Suggested-and-Acked-by: Jiri Olsa Reviewed-by: Arnaldo Carvalho de Melo Signed-off-by: Thomas Richter Cc: Hendrik Brueckner Cc: linux-s390@vger.kernel.org Link: http://lkml.kernel.org/r/20170622073625.86762-1-tmricht@linux.vnet.ibm.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/attr.py | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/tools/perf/tests/attr.py b/tools/perf/tests/attr.py index 1091bd47adfd..cdf21a9d0c35 100644 --- a/tools/perf/tests/attr.py +++ b/tools/perf/tests/attr.py @@ -16,6 +16,13 @@ class Fail(Exception): def getMsg(self): return '\'%s\' - %s' % (self.test.path, self.msg) +class Notest(Exception): + def __init__(self, test, arch): + self.arch = arch + self.test = test + def getMsg(self): + return '[%s] \'%s\'' % (self.arch, self.test.path) + class Unsup(Exception): def __init__(self, test): self.test = test @@ -112,6 +119,9 @@ class Event(dict): # 'command' - perf command name # 'args' - special command arguments # 'ret' - expected command return value (0 by default) +# 'arch' - architecture specific test (optional) +# comma separated list, ! at the beginning +# negates it. # # [eventX:base] # - one or multiple instances in file @@ -134,6 +144,12 @@ class Test(object): except: self.ret = 0 + try: + self.arch = parser.get('config', 'arch') + log.warning("test limitation '%s'" % self.arch) + except: + self.arch = '' + self.expect = {} self.result = {} log.debug(" loading expected events"); @@ -145,6 +161,31 @@ class Test(object): else: return True + def skip_test(self, myarch): + # If architecture not set always run test + if self.arch == '': + # log.warning("test for arch %s is ok" % myarch) + return False + + # Allow multiple values in assignment separated by ',' + arch_list = self.arch.split(',') + + # Handle negated list such as !s390x,ppc + if arch_list[0][0] == '!': + arch_list[0] = arch_list[0][1:] + log.warning("excluded architecture list %s" % arch_list) + for arch_item in arch_list: + # log.warning("test for %s arch is %s" % (arch_item, myarch)) + if arch_item == myarch: + return True + return False + + for arch_item in arch_list: + # log.warning("test for architecture '%s' current '%s'" % (arch_item, myarch)) + if arch_item == myarch: + return False + return True + def load_events(self, path, events): parser_event = ConfigParser.SafeConfigParser() parser_event.read(path) @@ -168,6 +209,11 @@ class Test(object): events[section] = e def run_cmd(self, tempdir): + junk1, junk2, junk3, junk4, myarch = (os.uname()) + + if self.skip_test(myarch): + raise Notest(self, myarch) + cmd = "PERF_TEST_ATTR=%s %s %s -o %s/perf.data %s" % (tempdir, self.perf, self.command, tempdir, self.args) ret = os.WEXITSTATUS(os.system(cmd)) @@ -265,6 +311,8 @@ def run_tests(options): Test(f, options).run() except Unsup, obj: log.warning("unsupp %s" % obj.getMsg()) + except Notest, obj: + log.warning("skipped %s" % obj.getMsg()) def setup_log(verbose): global log -- cgit v1.2.3 From 881c362d34ef76600b859e3a034d4155139bad2c Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 27 Jun 2017 10:52:57 -0300 Subject: perf help: Introduce exec_failed() to avoid code duplication The warning(str_error_r(errno)) pattern can be replaced with a function, do it. And while at it use pr_warning(), we have way too many error reporting facilities, time to drop some, starting with the one we got from the git sources. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-lbak5npj1ri1uuvf1en3c0p0@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-help.c | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/tools/perf/builtin-help.c b/tools/perf/builtin-help.c index 492f8e14ab09..e82fa0d5866e 100644 --- a/tools/perf/builtin-help.c +++ b/tools/perf/builtin-help.c @@ -108,10 +108,14 @@ out: return ret; } -static void exec_woman_emacs(const char *path, const char *page) +static void exec_failed(const char *cmd) { char sbuf[STRERR_BUFSIZE]; + pr_warning("failed to exec '%s': %s", cmd, str_error_r(errno, sbuf, sizeof(sbuf))); +} +static void exec_woman_emacs(const char *path, const char *page) +{ if (!check_emacsclient_version()) { /* This works only with emacsclient version >= 22. */ char *man_page; @@ -122,8 +126,7 @@ static void exec_woman_emacs(const char *path, const char *page) execlp(path, "emacsclient", "-e", man_page, NULL); free(man_page); } - warning("failed to exec '%s': %s", path, - str_error_r(errno, sbuf, sizeof(sbuf))); + exec_failed(path); } } @@ -134,7 +137,6 @@ static void exec_man_konqueror(const char *path, const char *page) if (display && *display) { char *man_page; const char *filename = "kfmclient"; - char sbuf[STRERR_BUFSIZE]; /* It's simpler to launch konqueror using kfmclient. */ if (path) { @@ -155,33 +157,27 @@ static void exec_man_konqueror(const char *path, const char *page) execlp(path, filename, "newTab", man_page, NULL); free(man_page); } - warning("failed to exec '%s': %s", path, - str_error_r(errno, sbuf, sizeof(sbuf))); + exec_failed(path); } } static void exec_man_man(const char *path, const char *page) { - char sbuf[STRERR_BUFSIZE]; - if (!path) path = "man"; execlp(path, "man", page, NULL); - warning("failed to exec '%s': %s", path, - str_error_r(errno, sbuf, sizeof(sbuf))); + exec_failed(path); } static void exec_man_cmd(const char *cmd, const char *page) { - char sbuf[STRERR_BUFSIZE]; char *shell_cmd; if (asprintf(&shell_cmd, "%s %s", cmd, page) > 0) { execl("/bin/sh", "sh", "-c", shell_cmd, NULL); free(shell_cmd); } - warning("failed to exec '%s': %s", cmd, - str_error_r(errno, sbuf, sizeof(sbuf))); + exec_failed(cmd); } static void add_man_viewer(const char *name) -- cgit v1.2.3 From 86e474ff870aded90c4ffa3f488cb5c093188ca4 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 27 Jun 2017 10:59:28 -0300 Subject: perf help: Elliminate dup code for reporting And switch from warning() to pr_warning(), to elliminate another duplication: too many error reporting facilities. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-pkzcjrhek3uuqc4i5i9ealwd@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-help.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/tools/perf/builtin-help.c b/tools/perf/builtin-help.c index e82fa0d5866e..ff53e9800b8b 100644 --- a/tools/perf/builtin-help.c +++ b/tools/perf/builtin-help.c @@ -210,6 +210,12 @@ static void do_add_man_viewer_info(const char *name, man_viewer_info_list = new; } +static void unsupported_man_viewer(const char *name, const char *var) +{ + pr_warning("'%s': path for unsupported man viewer.\n" + "Please consider using 'man..%s' instead.", name, var); +} + static int add_man_viewer_path(const char *name, size_t len, const char *value) @@ -217,9 +223,7 @@ static int add_man_viewer_path(const char *name, if (supported_man_viewer(name, len)) do_add_man_viewer_info(name, len, value); else - warning("'%s': path for unsupported man viewer.\n" - "Please consider using 'man..cmd' instead.", - name); + unsupported_man_viewer(name, "cmd"); return 0; } @@ -229,9 +233,7 @@ static int add_man_viewer_cmd(const char *name, const char *value) { if (supported_man_viewer(name, len)) - warning("'%s': cmd for supported man viewer.\n" - "Please consider using 'man..path' instead.", - name); + unsupported_man_viewer(name, "path"); else do_add_man_viewer_info(name, len, value); -- cgit v1.2.3 From 59913aabb06cb13f1bb09d4726a1a00d43d6cff2 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 27 Jun 2017 11:01:17 -0300 Subject: perf help: Use pr_warning() Complete the switch to using te pr_{warning,error,etc} error reporting facilities. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-3l9gr6237b4aqyo0rsspixe2@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-help.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/perf/builtin-help.c b/tools/perf/builtin-help.c index ff53e9800b8b..64a10101fc71 100644 --- a/tools/perf/builtin-help.c +++ b/tools/perf/builtin-help.c @@ -259,7 +259,7 @@ static int add_man_viewer_info(const char *var, const char *value) return add_man_viewer_cmd(name, subkey - name, value); } - warning("'%s': unsupported man viewer sub key.", subkey); + pr_warning("'%s': unsupported man viewer sub key.", subkey); return 0; } @@ -347,7 +347,7 @@ static void exec_viewer(const char *name, const char *page) else if (info) exec_man_cmd(info, page); else - warning("'%s': unknown man viewer.", name); + pr_warning("'%s': unknown man viewer.", name); } static int show_man_page(const char *perf_cmd) -- cgit v1.2.3 From 4cf134e744ba46e5893f9600487c5f7f5eae0519 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 27 Jun 2017 11:03:17 -0300 Subject: perf config: Use pr_warning() warning() is going away, consolidating error reporting. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-5r3636cwl4z1varo90mervai@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/config.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/tools/perf/util/config.c b/tools/perf/util/config.c index 8d724f0fa5a8..1498f38ea7ad 100644 --- a/tools/perf/util/config.c +++ b/tools/perf/util/config.c @@ -657,8 +657,7 @@ static int perf_config_set__init(struct perf_config_set *set) user_config = strdup(mkpath("%s/.perfconfig", home)); if (user_config == NULL) { - warning("Not enough memory to process %s/.perfconfig, " - "ignoring it.", home); + pr_warning("Not enough memory to process %s/.perfconfig, ignoring it.", home); goto out; } @@ -671,8 +670,7 @@ static int perf_config_set__init(struct perf_config_set *set) ret = 0; if (st.st_uid && (st.st_uid != geteuid())) { - warning("File %s not owned by current user or root, " - "ignoring it.", user_config); + pr_warning("File %s not owned by current user or root, ignoring it.", user_config); goto out_free; } -- cgit v1.2.3 From d2a74d53aa896046abcd152c03777209c57b12a2 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 27 Jun 2017 11:08:14 -0300 Subject: perf event-parse: Use pr_warning() Convert sole user of warning() in this file to pr_warning(), consolidating error reporting facilities. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-3y7yf6v673ujl2rcs34tzv8n@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/trace-event-parse.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/perf/util/trace-event-parse.c b/tools/perf/util/trace-event-parse.c index 746bbee645d9..e0a6e9a6a053 100644 --- a/tools/perf/util/trace-event-parse.c +++ b/tools/perf/util/trace-event-parse.c @@ -24,7 +24,7 @@ #include #include "../perf.h" -#include "util.h" +#include "debug.h" #include "trace-event.h" #include "sane_ctype.h" @@ -150,7 +150,7 @@ void parse_ftrace_printk(struct pevent *pevent, while (line) { addr_str = strtok_r(line, ":", &fmt); if (!addr_str) { - warning("printk format with empty entry"); + pr_warning("printk format with empty entry"); break; } addr = strtoull(addr_str, NULL, 16); -- cgit v1.2.3 From b211d79ac1ad43d6d8d82e7f1a5c26055a249135 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 27 Jun 2017 11:13:20 -0300 Subject: perf tools: Remove warning() Now everything uses pr_warning(), so ditch it. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-hv8r0mgdhk73wtfq3zrhavgx@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/parse-events.c | 13 ------------- tools/perf/util/usage.c | 20 -------------------- tools/perf/util/util.h | 3 --- 3 files changed, 36 deletions(-) diff --git a/tools/perf/tests/parse-events.c b/tools/perf/tests/parse-events.c index 7fad885491c5..812a053d1941 100644 --- a/tools/perf/tests/parse-events.c +++ b/tools/perf/tests/parse-events.c @@ -1810,17 +1810,6 @@ static int test_pmu_events(void) return ret; } -static void debug_warn(const char *warn, va_list params) -{ - char msg[1024]; - - if (verbose <= 0) - return; - - vsnprintf(msg, sizeof(msg), warn, params); - fprintf(stderr, " Warning: %s\n", msg); -} - int test__parse_events(int subtest __maybe_unused) { int ret1, ret2 = 0; @@ -1832,8 +1821,6 @@ do { \ ret2 = ret1; \ } while (0) - set_warning_routine(debug_warn); - TEST_EVENTS(test__events); if (test_pmu()) diff --git a/tools/perf/util/usage.c b/tools/perf/util/usage.c index aacb65e079aa..37225dc72738 100644 --- a/tools/perf/util/usage.c +++ b/tools/perf/util/usage.c @@ -33,21 +33,10 @@ static void error_builtin(const char *err, va_list params) report(" Error: ", err, params); } -static void warn_builtin(const char *warn, va_list params) -{ - report(" Warning: ", warn, params); -} - /* If we are in a dlopen()ed .so write to a global variable would segfault * (ugh), so keep things static. */ static void (*usage_routine)(const char *err) __noreturn = usage_builtin; static void (*error_routine)(const char *err, va_list params) = error_builtin; -static void (*warn_routine)(const char *err, va_list params) = warn_builtin; - -void set_warning_routine(void (*routine)(const char *err, va_list params)) -{ - warn_routine = routine; -} void usage(const char *err) { @@ -72,12 +61,3 @@ int error(const char *err, ...) va_end(params); return -1; } - -void warning(const char *warn, ...) -{ - va_list params; - - va_start(params, warn); - warn_routine(warn, params); - va_end(params); -} diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h index 978572dfeb14..3927ab8df5ac 100644 --- a/tools/perf/util/util.h +++ b/tools/perf/util/util.h @@ -17,9 +17,6 @@ void usage(const char *err) __noreturn; void die(const char *err, ...) __noreturn __printf(1, 2); int error(const char *err, ...) __printf(1, 2); -void warning(const char *err, ...) __printf(1, 2); - -void set_warning_routine(void (*routine)(const char *err, va_list params)); static inline void *zalloc(size_t size) { -- cgit v1.2.3 From 62d94b00f80b0ecb7fa9eea0539c59e9f82b0fcd Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 27 Jun 2017 11:22:31 -0300 Subject: perf tools: Replace error() with pr_err() To consolidate the error reporting facility. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-b41iot1094katoffdf19w9zk@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-c2c.c | 4 ++-- tools/perf/builtin-help.c | 8 +++++--- tools/perf/builtin-kmem.c | 4 ++-- tools/perf/builtin-record.c | 4 ++-- tools/perf/builtin-sched.c | 2 +- tools/perf/builtin-stat.c | 4 ++-- tools/perf/builtin-top.c | 2 +- tools/perf/util/config.c | 3 ++- tools/perf/util/sort.c | 22 +++++++++++----------- tools/perf/util/usage.c | 16 ---------------- tools/perf/util/util.h | 1 - 11 files changed, 28 insertions(+), 42 deletions(-) diff --git a/tools/perf/builtin-c2c.c b/tools/perf/builtin-c2c.c index 620a467ee304..475999e48f66 100644 --- a/tools/perf/builtin-c2c.c +++ b/tools/perf/builtin-c2c.c @@ -1725,10 +1725,10 @@ static int c2c_hists__init_sort(struct perf_hpp_list *hpp_list, char *name) tok; tok = strtok_r(NULL, ", ", &tmp)) { \ ret = _fn(hpp_list, tok); \ if (ret == -EINVAL) { \ - error("Invalid --fields key: `%s'", tok); \ + pr_err("Invalid --fields key: `%s'", tok); \ break; \ } else if (ret == -ESRCH) { \ - error("Unknown --fields key: `%s'", tok); \ + pr_err("Unknown --fields key: `%s'", tok); \ break; \ } \ } \ diff --git a/tools/perf/builtin-help.c b/tools/perf/builtin-help.c index 64a10101fc71..530a7f2fa0f3 100644 --- a/tools/perf/builtin-help.c +++ b/tools/perf/builtin-help.c @@ -245,8 +245,10 @@ static int add_man_viewer_info(const char *var, const char *value) const char *name = var + 4; const char *subkey = strrchr(name, '.'); - if (!subkey) - return error("Config with no key for man viewer: %s", name); + if (!subkey) { + pr_err("Config with no key for man viewer: %s", name); + return -1; + } if (!strcmp(subkey, ".path")) { if (!value) @@ -330,7 +332,7 @@ static void setup_man_path(void) setenv("MANPATH", new_path, 1); free(new_path); } else { - error("Unable to setup man path"); + pr_err("Unable to setup man path"); } } diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c index 9409c9464667..0a8a1c45af87 100644 --- a/tools/perf/builtin-kmem.c +++ b/tools/perf/builtin-kmem.c @@ -1715,7 +1715,7 @@ static int setup_slab_sorting(struct list_head *sort_list, const char *arg) if (!tok) break; if (slab_sort_dimension__add(tok, sort_list) < 0) { - error("Unknown slab --sort key: '%s'", tok); + pr_err("Unknown slab --sort key: '%s'", tok); free(str); return -1; } @@ -1741,7 +1741,7 @@ static int setup_page_sorting(struct list_head *sort_list, const char *arg) if (!tok) break; if (page_sort_dimension__add(tok, sort_list) < 0) { - error("Unknown page --sort key: '%s'", tok); + pr_err("Unknown page --sort key: '%s'", tok); free(str); return -1; } diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index ee7d0a82ccd0..17a14bcce34a 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -453,7 +453,7 @@ try_again: } if (perf_evlist__apply_filters(evlist, &pos)) { - error("failed to set filter \"%s\" on event %s with %d (%s)\n", + pr_err("failed to set filter \"%s\" on event %s with %d (%s)\n", pos->filter, perf_evsel__name(pos), errno, str_error_r(errno, msg, sizeof(msg))); rc = -1; @@ -461,7 +461,7 @@ try_again: } if (perf_evlist__apply_drv_configs(evlist, &pos, &err_term)) { - error("failed to set config \"%s\" on event %s with %d (%s)\n", + pr_err("failed to set config \"%s\" on event %s with %d (%s)\n", err_term->val.drv_cfg, perf_evsel__name(pos), errno, str_error_r(errno, msg, sizeof(msg))); rc = -1; diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c index 39996c53995a..322b4def8411 100644 --- a/tools/perf/builtin-sched.c +++ b/tools/perf/builtin-sched.c @@ -2066,7 +2066,7 @@ static void save_task_callchain(struct perf_sched *sched, if (thread__resolve_callchain(thread, cursor, evsel, sample, NULL, NULL, sched->max_stack + 2) != 0) { if (verbose > 0) - error("Failed to resolve callchain. Skipping\n"); + pr_err("Failed to resolve callchain. Skipping\n"); return; } diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index 324363054c3f..48ac53b199fc 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -636,14 +636,14 @@ try_again: } if (perf_evlist__apply_filters(evsel_list, &counter)) { - error("failed to set filter \"%s\" on event %s with %d (%s)\n", + pr_err("failed to set filter \"%s\" on event %s with %d (%s)\n", counter->filter, perf_evsel__name(counter), errno, str_error_r(errno, msg, sizeof(msg))); return -1; } if (perf_evlist__apply_drv_configs(evsel_list, &counter, &err_term)) { - error("failed to set config \"%s\" on event %s with %d (%s)\n", + pr_err("failed to set config \"%s\" on event %s with %d (%s)\n", err_term->val.drv_cfg, perf_evsel__name(counter), errno, str_error_r(errno, msg, sizeof(msg))); return -1; diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 2bcfa46913c8..6052376634c0 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -958,7 +958,7 @@ static int __cmd_top(struct perf_top *top) ret = perf_evlist__apply_drv_configs(evlist, &pos, &err_term); if (ret) { - error("failed to set config \"%s\" on event %s with %d (%s)\n", + pr_err("failed to set config \"%s\" on event %s with %d (%s)\n", err_term->val.drv_cfg, perf_evsel__name(pos), errno, str_error_r(errno, msg, sizeof(msg))); goto out_delete; diff --git a/tools/perf/util/config.c b/tools/perf/util/config.c index 1498f38ea7ad..586afeab2352 100644 --- a/tools/perf/util/config.c +++ b/tools/perf/util/config.c @@ -793,7 +793,8 @@ void perf_config_set__delete(struct perf_config_set *set) */ int config_error_nonbool(const char *var) { - return error("Missing value for '%s'", var); + pr_err("Missing value for '%s'", var); + return -1; } void set_buildid_dir(const char *dir) diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c index 5762ae4e9e91..8b327c955a4f 100644 --- a/tools/perf/util/sort.c +++ b/tools/perf/util/sort.c @@ -2532,12 +2532,12 @@ static int setup_sort_list(struct perf_hpp_list *list, char *str, ret = sort_dimension__add(list, tok, evlist, level); if (ret == -EINVAL) { if (!cacheline_size && !strncasecmp(tok, "dcacheline", strlen(tok))) - error("The \"dcacheline\" --sort key needs to know the cacheline size and it couldn't be determined on this system"); + pr_err("The \"dcacheline\" --sort key needs to know the cacheline size and it couldn't be determined on this system"); else - error("Invalid --sort key: `%s'", tok); + pr_err("Invalid --sort key: `%s'", tok); break; } else if (ret == -ESRCH) { - error("Unknown --sort key: `%s'", tok); + pr_err("Unknown --sort key: `%s'", tok); break; } } @@ -2594,7 +2594,7 @@ static int setup_sort_order(struct perf_evlist *evlist) return 0; if (sort_order[1] == '\0') { - error("Invalid --sort key: `+'"); + pr_err("Invalid --sort key: `+'"); return -EINVAL; } @@ -2604,7 +2604,7 @@ static int setup_sort_order(struct perf_evlist *evlist) */ if (asprintf(&new_sort_order, "%s,%s", get_default_sort_order(evlist), sort_order + 1) < 0) { - error("Not enough memory to set up --sort"); + pr_err("Not enough memory to set up --sort"); return -ENOMEM; } @@ -2668,7 +2668,7 @@ static int __setup_sorting(struct perf_evlist *evlist) str = strdup(sort_keys); if (str == NULL) { - error("Not enough memory to setup sort keys"); + pr_err("Not enough memory to setup sort keys"); return -ENOMEM; } @@ -2678,7 +2678,7 @@ static int __setup_sorting(struct perf_evlist *evlist) if (!is_strict_order(field_order)) { str = setup_overhead(str); if (str == NULL) { - error("Not enough memory to setup overhead keys"); + pr_err("Not enough memory to setup overhead keys"); return -ENOMEM; } } @@ -2834,10 +2834,10 @@ static int setup_output_list(struct perf_hpp_list *list, char *str) tok; tok = strtok_r(NULL, ", ", &tmp)) { ret = output_field_add(list, tok); if (ret == -EINVAL) { - error("Invalid --fields key: `%s'", tok); + pr_err("Invalid --fields key: `%s'", tok); break; } else if (ret == -ESRCH) { - error("Unknown --fields key: `%s'", tok); + pr_err("Unknown --fields key: `%s'", tok); break; } } @@ -2877,7 +2877,7 @@ static int __setup_output_field(void) strp = str = strdup(field_order); if (str == NULL) { - error("Not enough memory to setup output fields"); + pr_err("Not enough memory to setup output fields"); return -ENOMEM; } @@ -2885,7 +2885,7 @@ static int __setup_output_field(void) strp++; if (!strlen(strp)) { - error("Invalid --fields key: `+'"); + pr_err("Invalid --fields key: `+'"); goto out; } diff --git a/tools/perf/util/usage.c b/tools/perf/util/usage.c index 37225dc72738..bf185f28b19e 100644 --- a/tools/perf/util/usage.c +++ b/tools/perf/util/usage.c @@ -28,15 +28,9 @@ static __noreturn void die_builtin(const char *err, va_list params) exit(128); } -static void error_builtin(const char *err, va_list params) -{ - report(" Error: ", err, params); -} - /* If we are in a dlopen()ed .so write to a global variable would segfault * (ugh), so keep things static. */ static void (*usage_routine)(const char *err) __noreturn = usage_builtin; -static void (*error_routine)(const char *err, va_list params) = error_builtin; void usage(const char *err) { @@ -51,13 +45,3 @@ void die(const char *err, ...) die_builtin(err, params); va_end(params); } - -int error(const char *err, ...) -{ - va_list params; - - va_start(params, err); - error_routine(err, params); - va_end(params); - return -1; -} diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h index 3927ab8df5ac..2c9e58a45310 100644 --- a/tools/perf/util/util.h +++ b/tools/perf/util/util.h @@ -16,7 +16,6 @@ /* General helper functions */ void usage(const char *err) __noreturn; void die(const char *err, ...) __noreturn __printf(1, 2); -int error(const char *err, ...) __printf(1, 2); static inline void *zalloc(size_t size) { -- cgit v1.2.3 From 25ce4bb8c50513e922da2709fedc9db112452fbc Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 27 Jun 2017 11:44:58 -0300 Subject: perf config: Do not die when parsing u64 or int config values Just warn the user and ignore those values. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-tbf60nj3ierm6hrkhpothymx@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-diff.c | 5 ++++- tools/perf/builtin-report.c | 7 +++---- tools/perf/util/config.c | 34 ++++++++++++++++++++++------------ tools/perf/util/config.h | 4 ++-- tools/perf/util/data-convert-bt.c | 6 ++---- tools/perf/util/help-unknown-cmd.c | 2 +- 6 files changed, 34 insertions(+), 24 deletions(-) diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c index eec5df80f5a3..0cd4cf6a344b 100644 --- a/tools/perf/builtin-diff.c +++ b/tools/perf/builtin-diff.c @@ -1302,7 +1302,10 @@ static int diff__config(const char *var, const char *value, void *cb __maybe_unused) { if (!strcmp(var, "diff.order")) { - sort_compute = perf_config_int(var, value); + int ret; + if (perf_config_int(&ret, var, value) < 0) + return -1; + sort_compute = ret; return 0; } if (!strcmp(var, "diff.compute")) { diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 22478ff2b706..1174a426d090 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -94,10 +94,9 @@ static int report__config(const char *var, const char *value, void *cb) symbol_conf.cumulate_callchain = perf_config_bool(var, value); return 0; } - if (!strcmp(var, "report.queue-size")) { - rep->queue_size = perf_config_u64(var, value); - return 0; - } + if (!strcmp(var, "report.queue-size")) + return perf_config_u64(&rep->queue_size, var, value); + if (!strcmp(var, "report.sort_order")) { default_sort_order = strdup(value); return 0; diff --git a/tools/perf/util/config.c b/tools/perf/util/config.c index 586afeab2352..31a7dea248d0 100644 --- a/tools/perf/util/config.c +++ b/tools/perf/util/config.c @@ -335,32 +335,42 @@ static int perf_parse_long(const char *value, long *ret) return 0; } -static void die_bad_config(const char *name) +static void bad_config(const char *name) { if (config_file_name) - die("bad config value for '%s' in %s", name, config_file_name); - die("bad config value for '%s'", name); + pr_warning("bad config value for '%s' in %s, ignoring...\n", name, config_file_name); + else + pr_warning("bad config value for '%s', ignoring...\n", name); } -u64 perf_config_u64(const char *name, const char *value) +int perf_config_u64(u64 *dest, const char *name, const char *value) { long long ret = 0; - if (!perf_parse_llong(value, &ret)) - die_bad_config(name); - return (u64) ret; + if (!perf_parse_llong(value, &ret)) { + bad_config(name); + return -1; + } + + *dest = ret; + return 0; } -int perf_config_int(const char *name, const char *value) +int perf_config_int(int *dest, const char *name, const char *value) { long ret = 0; - if (!perf_parse_long(value, &ret)) - die_bad_config(name); - return ret; + if (!perf_parse_long(value, &ret)) { + bad_config(name); + return -1; + } + *dest = ret; + return 0; } static int perf_config_bool_or_int(const char *name, const char *value, int *is_bool) { + int ret; + *is_bool = 1; if (!value) return 1; @@ -371,7 +381,7 @@ static int perf_config_bool_or_int(const char *name, const char *value, int *is_ if (!strcasecmp(value, "false") || !strcasecmp(value, "no") || !strcasecmp(value, "off")) return 0; *is_bool = 0; - return perf_config_int(name, value); + return perf_config_int(&ret, name, value) < 0 ? -1 : ret; } int perf_config_bool(const char *name, const char *value) diff --git a/tools/perf/util/config.h b/tools/perf/util/config.h index 1a59a6b43f8b..b6bb11f3f165 100644 --- a/tools/perf/util/config.h +++ b/tools/perf/util/config.h @@ -27,8 +27,8 @@ extern const char *config_exclusive_filename; typedef int (*config_fn_t)(const char *, const char *, void *); int perf_default_config(const char *, const char *, void *); int perf_config(config_fn_t fn, void *); -int perf_config_int(const char *, const char *); -u64 perf_config_u64(const char *, const char *); +int perf_config_int(int *dest, const char *, const char *); +int perf_config_u64(u64 *dest, const char *, const char *); int perf_config_bool(const char *, const char *); int config_error_nonbool(const char *); const char *perf_etc_perfconfig(void); diff --git a/tools/perf/util/data-convert-bt.c b/tools/perf/util/data-convert-bt.c index 89d50318833d..3149b70799fd 100644 --- a/tools/perf/util/data-convert-bt.c +++ b/tools/perf/util/data-convert-bt.c @@ -1444,10 +1444,8 @@ static int convert__config(const char *var, const char *value, void *cb) { struct convert *c = cb; - if (!strcmp(var, "convert.queue-size")) { - c->queue_size = perf_config_u64(var, value); - return 0; - } + if (!strcmp(var, "convert.queue-size")) + return perf_config_u64(&c->queue_size, var, value); return 0; } diff --git a/tools/perf/util/help-unknown-cmd.c b/tools/perf/util/help-unknown-cmd.c index 1c88ad6425b8..15b95300d7f3 100644 --- a/tools/perf/util/help-unknown-cmd.c +++ b/tools/perf/util/help-unknown-cmd.c @@ -12,7 +12,7 @@ static int perf_unknown_cmd_config(const char *var, const char *value, void *cb __maybe_unused) { if (!strcmp(var, "help.autocorrect")) - autocorrect = perf_config_int(var,value); + return perf_config_int(&autocorrect, var,value); return 0; } -- cgit v1.2.3 From fef2a735167a827a65bbdf1791abe0dd070ce372 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 27 Jun 2017 11:49:13 -0300 Subject: perf tools: Kill die() Finally can nuke this function, no more users. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-eivvvzn8ie6w42gy3batxoy7@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/attr.c | 10 +++++----- tools/perf/util/usage.c | 22 ---------------------- 2 files changed, 5 insertions(+), 27 deletions(-) diff --git a/tools/perf/tests/attr.c b/tools/perf/tests/attr.c index 0dd77494bb58..0e77b2cf61ec 100644 --- a/tools/perf/tests/attr.c +++ b/tools/perf/tests/attr.c @@ -18,6 +18,7 @@ * permissions. All the event text files are stored there. */ +#include #include #include #include @@ -29,14 +30,11 @@ #include #include #include "../perf.h" -#include "util.h" #include #include "tests.h" #define ENV "PERF_TEST_ATTR" -extern int verbose; - static char *dir; void test_attr__init(void) @@ -138,8 +136,10 @@ void test_attr__open(struct perf_event_attr *attr, pid_t pid, int cpu, { int errno_saved = errno; - if (store_event(attr, pid, cpu, fd, group_fd, flags)) - die("test attr FAILED"); + if (store_event(attr, pid, cpu, fd, group_fd, flags)) { + pr_err("test attr FAILED"); + exit(128); + } errno = errno_saved; } diff --git a/tools/perf/util/usage.c b/tools/perf/util/usage.c index bf185f28b19e..6cc9d9888ce0 100644 --- a/tools/perf/util/usage.c +++ b/tools/perf/util/usage.c @@ -9,25 +9,12 @@ #include "util.h" #include "debug.h" -static void report(const char *prefix, const char *err, va_list params) -{ - char msg[1024]; - vsnprintf(msg, sizeof(msg), err, params); - fprintf(stderr, " %s%s\n", prefix, msg); -} - static __noreturn void usage_builtin(const char *err) { fprintf(stderr, "\n Usage: %s\n", err); exit(129); } -static __noreturn void die_builtin(const char *err, va_list params) -{ - report(" Fatal: ", err, params); - exit(128); -} - /* If we are in a dlopen()ed .so write to a global variable would segfault * (ugh), so keep things static. */ static void (*usage_routine)(const char *err) __noreturn = usage_builtin; @@ -36,12 +23,3 @@ void usage(const char *err) { usage_routine(err); } - -void die(const char *err, ...) -{ - va_list params; - - va_start(params, err); - die_builtin(err, params); - va_end(params); -} -- cgit v1.2.3 From 19f0edb980a0f66ccd80b712dadb0239782f8af5 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 27 Jun 2017 13:49:17 +0100 Subject: perf jit: fix typo: "incalid" -> "invalid" Trivial fix to typo in jvmti_close() warnx warning message. Signed-off-by: Colin King Cc: Alexander Shishkin Cc: Dan Carpenter Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/r/20170627124917.19151-1-colin.king@canonical.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/jvmti/jvmti_agent.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/perf/jvmti/jvmti_agent.c b/tools/perf/jvmti/jvmti_agent.c index e9651a9d670e..cf36de7ea255 100644 --- a/tools/perf/jvmti/jvmti_agent.c +++ b/tools/perf/jvmti/jvmti_agent.c @@ -304,7 +304,7 @@ jvmti_close(void *agent) FILE *fp = agent; if (!fp) { - warnx("jvmti: incalid fd in close_agent"); + warnx("jvmti: invalid fd in close_agent"); return -1; } -- cgit v1.2.3 From d5b1a5f660b8594125ea2a372286d767e756102f Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Fri, 19 May 2017 10:50:30 +0300 Subject: x86/insn: perf tools: Add new ptwrite instruction Add ptwrite to the op code map and the perf tools new instructions test. To run the test: $ tools/perf/perf test "x86 ins" 39: Test x86 instruction decoder - new instructions : Ok Or to see the details: $ tools/perf/perf test -v "x86 ins" 2>&1 | grep ptwrite For information about ptwrite, refer the Intel SDM. Signed-off-by: Adrian Hunter Acked-by: Masami Hiramatsu Link: http://lkml.kernel.org/r/1495180230-19367-1-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- arch/x86/lib/x86-opcode-map.txt | 2 +- tools/objtool/arch/x86/insn/x86-opcode-map.txt | 2 +- tools/perf/arch/x86/tests/insn-x86-dat-32.c | 12 +++++++++ tools/perf/arch/x86/tests/insn-x86-dat-64.c | 30 ++++++++++++++++++++++ tools/perf/arch/x86/tests/insn-x86-dat-src.c | 30 ++++++++++++++++++++++ .../perf/util/intel-pt-decoder/x86-opcode-map.txt | 2 +- 6 files changed, 75 insertions(+), 3 deletions(-) diff --git a/arch/x86/lib/x86-opcode-map.txt b/arch/x86/lib/x86-opcode-map.txt index 767be7c76034..12e377184ee4 100644 --- a/arch/x86/lib/x86-opcode-map.txt +++ b/arch/x86/lib/x86-opcode-map.txt @@ -1009,7 +1009,7 @@ GrpTable: Grp15 1: fxstor | RDGSBASE Ry (F3),(11B) 2: vldmxcsr Md (v1) | WRFSBASE Ry (F3),(11B) 3: vstmxcsr Md (v1) | WRGSBASE Ry (F3),(11B) -4: XSAVE +4: XSAVE | ptwrite Ey (F3),(11B) 5: XRSTOR | lfence (11B) 6: XSAVEOPT | clwb (66) | mfence (11B) 7: clflush | clflushopt (66) | sfence (11B) diff --git a/tools/objtool/arch/x86/insn/x86-opcode-map.txt b/tools/objtool/arch/x86/insn/x86-opcode-map.txt index 767be7c76034..12e377184ee4 100644 --- a/tools/objtool/arch/x86/insn/x86-opcode-map.txt +++ b/tools/objtool/arch/x86/insn/x86-opcode-map.txt @@ -1009,7 +1009,7 @@ GrpTable: Grp15 1: fxstor | RDGSBASE Ry (F3),(11B) 2: vldmxcsr Md (v1) | WRFSBASE Ry (F3),(11B) 3: vstmxcsr Md (v1) | WRGSBASE Ry (F3),(11B) -4: XSAVE +4: XSAVE | ptwrite Ey (F3),(11B) 5: XRSTOR | lfence (11B) 6: XSAVEOPT | clwb (66) | mfence (11B) 7: clflush | clflushopt (66) | sfence (11B) diff --git a/tools/perf/arch/x86/tests/insn-x86-dat-32.c b/tools/perf/arch/x86/tests/insn-x86-dat-32.c index 0f196eec9f48..3cbf6fad169f 100644 --- a/tools/perf/arch/x86/tests/insn-x86-dat-32.c +++ b/tools/perf/arch/x86/tests/insn-x86-dat-32.c @@ -1664,3 +1664,15 @@ "0f c7 1d 78 56 34 12 \txrstors 0x12345678",}, {{0x0f, 0xc7, 0x9c, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "", "", "0f c7 9c c8 78 56 34 12 \txrstors 0x12345678(%eax,%ecx,8)",}, +{{0xf3, 0x0f, 0xae, 0x20, }, 4, 0, "", "", +"f3 0f ae 20 \tptwritel (%eax)",}, +{{0xf3, 0x0f, 0xae, 0x25, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "", "", +"f3 0f ae 25 78 56 34 12 \tptwritel 0x12345678",}, +{{0xf3, 0x0f, 0xae, 0xa4, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"f3 0f ae a4 c8 78 56 34 12 \tptwritel 0x12345678(%eax,%ecx,8)",}, +{{0xf3, 0x0f, 0xae, 0x20, }, 4, 0, "", "", +"f3 0f ae 20 \tptwritel (%eax)",}, +{{0xf3, 0x0f, 0xae, 0x25, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "", "", +"f3 0f ae 25 78 56 34 12 \tptwritel 0x12345678",}, +{{0xf3, 0x0f, 0xae, 0xa4, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"f3 0f ae a4 c8 78 56 34 12 \tptwritel 0x12345678(%eax,%ecx,8)",}, diff --git a/tools/perf/arch/x86/tests/insn-x86-dat-64.c b/tools/perf/arch/x86/tests/insn-x86-dat-64.c index af25bc8240d0..aa512fa944dd 100644 --- a/tools/perf/arch/x86/tests/insn-x86-dat-64.c +++ b/tools/perf/arch/x86/tests/insn-x86-dat-64.c @@ -1696,3 +1696,33 @@ "0f c7 9c c8 78 56 34 12 \txrstors 0x12345678(%rax,%rcx,8)",}, {{0x41, 0x0f, 0xc7, 0x9c, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", "41 0f c7 9c c8 78 56 34 12 \txrstors 0x12345678(%r8,%rcx,8)",}, +{{0xf3, 0x0f, 0xae, 0x20, }, 4, 0, "", "", +"f3 0f ae 20 \tptwritel (%rax)",}, +{{0xf3, 0x41, 0x0f, 0xae, 0x20, }, 5, 0, "", "", +"f3 41 0f ae 20 \tptwritel (%r8)",}, +{{0xf3, 0x0f, 0xae, 0x24, 0x25, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"f3 0f ae 24 25 78 56 34 12 \tptwritel 0x12345678",}, +{{0xf3, 0x0f, 0xae, 0xa4, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"f3 0f ae a4 c8 78 56 34 12 \tptwritel 0x12345678(%rax,%rcx,8)",}, +{{0xf3, 0x41, 0x0f, 0xae, 0xa4, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 10, 0, "", "", +"f3 41 0f ae a4 c8 78 56 34 12 \tptwritel 0x12345678(%r8,%rcx,8)",}, +{{0xf3, 0x0f, 0xae, 0x20, }, 4, 0, "", "", +"f3 0f ae 20 \tptwritel (%rax)",}, +{{0xf3, 0x41, 0x0f, 0xae, 0x20, }, 5, 0, "", "", +"f3 41 0f ae 20 \tptwritel (%r8)",}, +{{0xf3, 0x0f, 0xae, 0x24, 0x25, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"f3 0f ae 24 25 78 56 34 12 \tptwritel 0x12345678",}, +{{0xf3, 0x0f, 0xae, 0xa4, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"f3 0f ae a4 c8 78 56 34 12 \tptwritel 0x12345678(%rax,%rcx,8)",}, +{{0xf3, 0x41, 0x0f, 0xae, 0xa4, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 10, 0, "", "", +"f3 41 0f ae a4 c8 78 56 34 12 \tptwritel 0x12345678(%r8,%rcx,8)",}, +{{0xf3, 0x48, 0x0f, 0xae, 0x20, }, 5, 0, "", "", +"f3 48 0f ae 20 \tptwriteq (%rax)",}, +{{0xf3, 0x49, 0x0f, 0xae, 0x20, }, 5, 0, "", "", +"f3 49 0f ae 20 \tptwriteq (%r8)",}, +{{0xf3, 0x48, 0x0f, 0xae, 0x24, 0x25, 0x78, 0x56, 0x34, 0x12, }, 10, 0, "", "", +"f3 48 0f ae 24 25 78 56 34 12 \tptwriteq 0x12345678",}, +{{0xf3, 0x48, 0x0f, 0xae, 0xa4, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 10, 0, "", "", +"f3 48 0f ae a4 c8 78 56 34 12 \tptwriteq 0x12345678(%rax,%rcx,8)",}, +{{0xf3, 0x49, 0x0f, 0xae, 0xa4, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 10, 0, "", "", +"f3 49 0f ae a4 c8 78 56 34 12 \tptwriteq 0x12345678(%r8,%rcx,8)",}, diff --git a/tools/perf/arch/x86/tests/insn-x86-dat-src.c b/tools/perf/arch/x86/tests/insn-x86-dat-src.c index 979487dae8d4..6cdb65d25b79 100644 --- a/tools/perf/arch/x86/tests/insn-x86-dat-src.c +++ b/tools/perf/arch/x86/tests/insn-x86-dat-src.c @@ -1343,6 +1343,26 @@ int main(void) asm volatile("xrstors 0x12345678(%rax,%rcx,8)"); asm volatile("xrstors 0x12345678(%r8,%rcx,8)"); + /* ptwrite */ + + asm volatile("ptwrite (%rax)"); + asm volatile("ptwrite (%r8)"); + asm volatile("ptwrite (0x12345678)"); + asm volatile("ptwrite 0x12345678(%rax,%rcx,8)"); + asm volatile("ptwrite 0x12345678(%r8,%rcx,8)"); + + asm volatile("ptwritel (%rax)"); + asm volatile("ptwritel (%r8)"); + asm volatile("ptwritel (0x12345678)"); + asm volatile("ptwritel 0x12345678(%rax,%rcx,8)"); + asm volatile("ptwritel 0x12345678(%r8,%rcx,8)"); + + asm volatile("ptwriteq (%rax)"); + asm volatile("ptwriteq (%r8)"); + asm volatile("ptwriteq (0x12345678)"); + asm volatile("ptwriteq 0x12345678(%rax,%rcx,8)"); + asm volatile("ptwriteq 0x12345678(%r8,%rcx,8)"); + #else /* #ifdef __x86_64__ */ /* bound r32, mem (same op code as EVEX prefix) */ @@ -2653,6 +2673,16 @@ int main(void) asm volatile("xrstors (0x12345678)"); asm volatile("xrstors 0x12345678(%eax,%ecx,8)"); + /* ptwrite */ + + asm volatile("ptwrite (%eax)"); + asm volatile("ptwrite (0x12345678)"); + asm volatile("ptwrite 0x12345678(%eax,%ecx,8)"); + + asm volatile("ptwritel (%eax)"); + asm volatile("ptwritel (0x12345678)"); + asm volatile("ptwritel 0x12345678(%eax,%ecx,8)"); + #endif /* #ifndef __x86_64__ */ /* Following line is a marker for the awk script - do not change */ diff --git a/tools/perf/util/intel-pt-decoder/x86-opcode-map.txt b/tools/perf/util/intel-pt-decoder/x86-opcode-map.txt index 767be7c76034..12e377184ee4 100644 --- a/tools/perf/util/intel-pt-decoder/x86-opcode-map.txt +++ b/tools/perf/util/intel-pt-decoder/x86-opcode-map.txt @@ -1009,7 +1009,7 @@ GrpTable: Grp15 1: fxstor | RDGSBASE Ry (F3),(11B) 2: vldmxcsr Md (v1) | WRFSBASE Ry (F3),(11B) 3: vstmxcsr Md (v1) | WRGSBASE Ry (F3),(11B) -4: XSAVE +4: XSAVE | ptwrite Ey (F3),(11B) 5: XRSTOR | lfence (11B) 6: XSAVEOPT | clwb (66) | mfence (11B) 7: clflush | clflushopt (66) | sfence (11B) -- cgit v1.2.3 From 1405720d4f2669e5ebaed192bd727aca74f64732 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Wed, 21 Jun 2017 13:17:19 +0300 Subject: perf script: Add 'synth' event type for synthesized events Instruction trace decoders such as Intel PT may have additional information recorded in the trace. For example, Intel PT has power information and a there is a new instruction 'ptwrite' that can write a value into a PTWRITE trace packet. Such information may be associated with an IP and so can be treated as a sample (PERF_RECORD_SAMPLE). Custom data can be incorporated in the sample as raw_data (PERF_SAMPLE_RAW). However a means of identifying the raw data format is needed. That will be done by synthesizing an attribute for it. So add an attribute type for custom synthesized events. Different synthesized events will be identified by the attribute 'config'. Committer notes: Start those PERF_TYPE_ after the PMU range, i.e. after (INT_MAX + 1U), i.e. after perf_pmu_register() -> idr_alloc(end=0). Signed-off-by: Adrian Hunter Cc: Andi Kleen Link: http://lkml.kernel.org/r/1498040239-32418-1-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-script.c | 74 +++++++++++++++++++++++++++++++++++---------- tools/perf/util/event.h | 3 ++ 2 files changed, 61 insertions(+), 16 deletions(-) diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index 4bce7d8679cb..2999e7e425f6 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c @@ -119,6 +119,11 @@ struct output_option { {.str = "brstackoff", .field = PERF_OUTPUT_BRSTACKOFF}, }; +enum { + OUTPUT_TYPE_SYNTH = PERF_TYPE_MAX, + OUTPUT_TYPE_MAX +}; + /* default set to maintain compatibility with current format */ static struct { bool user_set; @@ -126,7 +131,7 @@ static struct { unsigned int print_ip_opts; u64 fields; u64 invalid_fields; -} output[PERF_TYPE_MAX] = { +} output[OUTPUT_TYPE_MAX] = { [PERF_TYPE_HARDWARE] = { .user_set = false, @@ -184,12 +189,43 @@ static struct { .invalid_fields = PERF_OUTPUT_TRACE | PERF_OUTPUT_BPF_OUTPUT, }, + + [OUTPUT_TYPE_SYNTH] = { + .user_set = false, + + .fields = PERF_OUTPUT_COMM | PERF_OUTPUT_TID | + PERF_OUTPUT_CPU | PERF_OUTPUT_TIME | + PERF_OUTPUT_EVNAME | PERF_OUTPUT_IP | + PERF_OUTPUT_SYM | PERF_OUTPUT_DSO, + + .invalid_fields = PERF_OUTPUT_TRACE | PERF_OUTPUT_BPF_OUTPUT, + }, }; +static inline int output_type(unsigned int type) +{ + switch (type) { + case PERF_TYPE_SYNTH: + return OUTPUT_TYPE_SYNTH; + default: + return type; + } +} + +static inline unsigned int attr_type(unsigned int type) +{ + switch (type) { + case OUTPUT_TYPE_SYNTH: + return PERF_TYPE_SYNTH; + default: + return type; + } +} + static bool output_set_by_user(void) { int j; - for (j = 0; j < PERF_TYPE_MAX; ++j) { + for (j = 0; j < OUTPUT_TYPE_MAX; ++j) { if (output[j].user_set) return true; } @@ -210,7 +246,7 @@ static const char *output_field2str(enum perf_output_field field) return str; } -#define PRINT_FIELD(x) (output[attr->type].fields & PERF_OUTPUT_##x) +#define PRINT_FIELD(x) (output[output_type(attr->type)].fields & PERF_OUTPUT_##x) static int perf_evsel__do_check_stype(struct perf_evsel *evsel, u64 sample_type, const char *sample_msg, @@ -218,7 +254,7 @@ static int perf_evsel__do_check_stype(struct perf_evsel *evsel, bool allow_user_set) { struct perf_event_attr *attr = &evsel->attr; - int type = attr->type; + int type = output_type(attr->type); const char *evname; if (attr->sample_type & sample_type) @@ -348,7 +384,7 @@ static int perf_evsel__check_attr(struct perf_evsel *evsel, static void set_print_ip_opts(struct perf_event_attr *attr) { - unsigned int type = attr->type; + unsigned int type = output_type(attr->type); output[type].print_ip_opts = 0; if (PRINT_FIELD(IP)) @@ -376,14 +412,15 @@ static int perf_session__check_output_opt(struct perf_session *session) unsigned int j; struct perf_evsel *evsel; - for (j = 0; j < PERF_TYPE_MAX; ++j) { - evsel = perf_session__find_first_evtype(session, j); + for (j = 0; j < OUTPUT_TYPE_MAX; ++j) { + evsel = perf_session__find_first_evtype(session, attr_type(j)); /* * even if fields is set to 0 (ie., show nothing) event must * exist if user explicitly includes it on the command line */ - if (!evsel && output[j].user_set && !output[j].wildcard_set) { + if (!evsel && output[j].user_set && !output[j].wildcard_set && + j != OUTPUT_TYPE_SYNTH) { pr_err("%s events do not exist. " "Remove corresponding -F option to proceed.\n", event_type(j)); @@ -989,6 +1026,7 @@ static void print_sample_bts(struct perf_sample *sample, struct machine *machine) { struct perf_event_attr *attr = &evsel->attr; + unsigned int type = output_type(attr->type); bool print_srcline_last = false; if (PRINT_FIELD(CALLINDENT)) @@ -996,7 +1034,7 @@ static void print_sample_bts(struct perf_sample *sample, /* print branch_from information */ if (PRINT_FIELD(IP)) { - unsigned int print_opts = output[attr->type].print_ip_opts; + unsigned int print_opts = output[type].print_ip_opts; struct callchain_cursor *cursor = NULL; if (symbol_conf.use_callchain && sample->callchain && @@ -1019,7 +1057,7 @@ static void print_sample_bts(struct perf_sample *sample, /* print branch_to information */ if (PRINT_FIELD(ADDR) || ((evsel->attr.sample_type & PERF_SAMPLE_ADDR) && - !output[attr->type].user_set)) { + !output[type].user_set)) { printf(" => "); print_sample_addr(sample, thread, attr); } @@ -1215,8 +1253,9 @@ static void process_event(struct perf_script *script, { struct thread *thread = al->thread; struct perf_event_attr *attr = &evsel->attr; + unsigned int type = output_type(attr->type); - if (output[attr->type].fields == 0) + if (output[type].fields == 0) return; print_sample_start(sample, thread, evsel); @@ -1263,7 +1302,7 @@ static void process_event(struct perf_script *script, cursor = &callchain_cursor; putchar(cursor ? '\n' : ' '); - sample__fprintf_sym(sample, al, 0, output[attr->type].print_ip_opts, cursor, stdout); + sample__fprintf_sym(sample, al, 0, output[type].print_ip_opts, cursor, stdout); } if (PRINT_FIELD(IREGS)) @@ -1410,7 +1449,8 @@ static int process_attr(struct perf_tool *tool, union perf_event *event, evlist = *pevlist; evsel = perf_evlist__last(*pevlist); - if (evsel->attr.type >= PERF_TYPE_MAX) + if (evsel->attr.type >= PERF_TYPE_MAX && + evsel->attr.type != PERF_TYPE_SYNTH) return 0; evlist__for_each_entry(evlist, pos) { @@ -1835,6 +1875,8 @@ static int parse_output_fields(const struct option *opt __maybe_unused, type = PERF_TYPE_RAW; else if (!strcmp(str, "break")) type = PERF_TYPE_BREAKPOINT; + else if (!strcmp(str, "synth")) + type = OUTPUT_TYPE_SYNTH; else { fprintf(stderr, "Invalid event type in field string.\n"); rc = -EINVAL; @@ -1865,7 +1907,7 @@ static int parse_output_fields(const struct option *opt __maybe_unused, if (output_set_by_user()) pr_warning("Overriding previous field request for all events.\n"); - for (j = 0; j < PERF_TYPE_MAX; ++j) { + for (j = 0; j < OUTPUT_TYPE_MAX; ++j) { output[j].fields = 0; output[j].user_set = true; output[j].wildcard_set = true; @@ -1908,7 +1950,7 @@ parse: /* add user option to all events types for * which it is valid */ - for (j = 0; j < PERF_TYPE_MAX; ++j) { + for (j = 0; j < OUTPUT_TYPE_MAX; ++j) { if (output[j].invalid_fields & all_output_options[i].field) { pr_warning("\'%s\' not valid for %s events. Ignoring.\n", all_output_options[i].str, event_type(j)); @@ -2560,7 +2602,7 @@ int cmd_script(int argc, const char **argv) OPT_CALLBACK('F', "fields", NULL, "str", "comma separated output fields prepend with 'type:'. " "+field to add and -field to remove." - "Valid types: hw,sw,trace,raw. " + "Valid types: hw,sw,trace,raw,synth. " "Fields: comm,tid,pid,time,cpu,event,trace,ip,sym,dso," "addr,symoff,period,iregs,brstack,brstacksym,flags," "bpf-output,callindent,insn,insnlen,brstackinsn", diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h index 7c3fa1c8cbcd..855733c2adcf 100644 --- a/tools/perf/util/event.h +++ b/tools/perf/util/event.h @@ -252,6 +252,9 @@ enum auxtrace_error_type { PERF_AUXTRACE_ERROR_MAX }; +/* Attribute type for custom synthesized events */ +#define PERF_TYPE_SYNTH (INT_MAX + 1U) + /* * The kernel collects the number of events it couldn't send in a stretch and * when possible sends this number in a PERF_RECORD_LOST event. The number of -- cgit v1.2.3 From 07fda552f14830e71f0b5e8e4e31124369903aa3 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Fri, 26 May 2017 11:17:23 +0300 Subject: tools include: Add byte-swapping macros to kernel.h Add byte-swapping macros to kernel.h Signed-off-by: Adrian Hunter Cc: Andi Kleen Link: http://lkml.kernel.org/r/1495786658-18063-23-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/include/linux/kernel.h | 35 +++++++++++++++++++++++++++++------ 1 file changed, 29 insertions(+), 6 deletions(-) diff --git a/tools/include/linux/kernel.h b/tools/include/linux/kernel.h index 73ccc48126bb..039bb85e4171 100644 --- a/tools/include/linux/kernel.h +++ b/tools/include/linux/kernel.h @@ -5,6 +5,8 @@ #include #include #include +#include +#include #ifndef UINT_MAX #define UINT_MAX (~0U) @@ -67,12 +69,33 @@ #endif #endif -/* - * Both need more care to handle endianness - * (Don't use bitmap_copy_le() for now) - */ -#define cpu_to_le64(x) (x) -#define cpu_to_le32(x) (x) +#if __BYTE_ORDER == __BIG_ENDIAN +#define cpu_to_le16 bswap_16 +#define cpu_to_le32 bswap_32 +#define cpu_to_le64 bswap_64 +#define le16_to_cpu bswap_16 +#define le32_to_cpu bswap_32 +#define le64_to_cpu bswap_64 +#define cpu_to_be16 +#define cpu_to_be32 +#define cpu_to_be64 +#define be16_to_cpu +#define be32_to_cpu +#define be64_to_cpu +#else +#define cpu_to_le16 +#define cpu_to_le32 +#define cpu_to_le64 +#define le16_to_cpu +#define le32_to_cpu +#define le64_to_cpu +#define cpu_to_be16 bswap_16 +#define cpu_to_be32 bswap_32 +#define cpu_to_be64 bswap_64 +#define be16_to_cpu bswap_16 +#define be32_to_cpu bswap_32 +#define be64_to_cpu bswap_64 +#endif int vscnprintf(char *buf, size_t size, const char *fmt, va_list args); int scnprintf(char * buf, size_t size, const char * fmt, ...); -- cgit v1.2.3 From 3bdafdffa9baf2b34aebad1c98bc17b50202cb78 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Fri, 26 May 2017 11:17:24 +0300 Subject: perf auxtrace: Add itrace option to output ptwrite events Add itrace option to output ptwrite events. Signed-off-by: Adrian Hunter Cc: Andi Kleen Link: http://lkml.kernel.org/r/1495786658-18063-24-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Documentation/itrace.txt | 7 ++++--- tools/perf/util/auxtrace.c | 4 ++++ tools/perf/util/auxtrace.h | 2 ++ 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/tools/perf/Documentation/itrace.txt b/tools/perf/Documentation/itrace.txt index e2a4c5e0dbe5..deafd16692b6 100644 --- a/tools/perf/Documentation/itrace.txt +++ b/tools/perf/Documentation/itrace.txt @@ -3,13 +3,14 @@ c synthesize branches events (calls only) r synthesize branches events (returns only) x synthesize transactions events + w synthesize ptwrite events e synthesize error events d create a debug log g synthesize a call chain (use with i or x) l synthesize last branch entries (use with i or x) s skip initial number of events - The default is all events i.e. the same as --itrace=ibxe + The default is all events i.e. the same as --itrace=ibxwe In addition, the period (default 100000) for instructions events can be specified in units of: @@ -26,8 +27,8 @@ Also the number of last branch entries (default 64, max. 1024) for instructions or transactions events can be specified. - It is also possible to skip events generated (instructions, branches, transactions) - at the beginning. This is useful to ignore initialization code. + It is also possible to skip events generated (instructions, branches, transactions, + ptwrite) at the beginning. This is useful to ignore initialization code. --itrace=i0nss1000000 diff --git a/tools/perf/util/auxtrace.c b/tools/perf/util/auxtrace.c index 0daf63b9ee3e..baad91ed1e05 100644 --- a/tools/perf/util/auxtrace.c +++ b/tools/perf/util/auxtrace.c @@ -947,6 +947,7 @@ void itrace_synth_opts__set_default(struct itrace_synth_opts *synth_opts) synth_opts->instructions = true; synth_opts->branches = true; synth_opts->transactions = true; + synth_opts->ptwrites = true; synth_opts->errors = true; synth_opts->period_type = PERF_ITRACE_DEFAULT_PERIOD_TYPE; synth_opts->period = PERF_ITRACE_DEFAULT_PERIOD; @@ -1030,6 +1031,9 @@ int itrace_parse_synth_opts(const struct option *opt, const char *str, case 'x': synth_opts->transactions = true; break; + case 'w': + synth_opts->ptwrites = true; + break; case 'e': synth_opts->errors = true; break; diff --git a/tools/perf/util/auxtrace.h b/tools/perf/util/auxtrace.h index 9f0de72d58e2..b48afb2f18f3 100644 --- a/tools/perf/util/auxtrace.h +++ b/tools/perf/util/auxtrace.h @@ -59,6 +59,7 @@ enum itrace_period_type { * @instructions: whether to synthesize 'instructions' events * @branches: whether to synthesize 'branches' events * @transactions: whether to synthesize events for transactions + * @ptwrites: whether to synthesize events for ptwrites * @errors: whether to synthesize decoder error events * @dont_decode: whether to skip decoding entirely * @log: write a decoding log @@ -79,6 +80,7 @@ struct itrace_synth_opts { bool instructions; bool branches; bool transactions; + bool ptwrites; bool errors; bool dont_decode; bool log; -- cgit v1.2.3 From 70d110d775993ff1f63905bbdbc70e3f6bd8da8a Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Fri, 26 May 2017 11:17:25 +0300 Subject: perf auxtrace: Add itrace option to output power events Add itrace option to output power events. Signed-off-by: Adrian Hunter Cc: Andi Kleen Link: http://lkml.kernel.org/r/1495786658-18063-25-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Documentation/itrace.txt | 5 +++-- tools/perf/util/auxtrace.c | 4 ++++ tools/perf/util/auxtrace.h | 2 ++ 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/tools/perf/Documentation/itrace.txt b/tools/perf/Documentation/itrace.txt index deafd16692b6..a3abe04c779d 100644 --- a/tools/perf/Documentation/itrace.txt +++ b/tools/perf/Documentation/itrace.txt @@ -4,13 +4,14 @@ r synthesize branches events (returns only) x synthesize transactions events w synthesize ptwrite events + p synthesize power events e synthesize error events d create a debug log g synthesize a call chain (use with i or x) l synthesize last branch entries (use with i or x) s skip initial number of events - The default is all events i.e. the same as --itrace=ibxwe + The default is all events i.e. the same as --itrace=ibxwpe In addition, the period (default 100000) for instructions events can be specified in units of: @@ -28,7 +29,7 @@ instructions or transactions events can be specified. It is also possible to skip events generated (instructions, branches, transactions, - ptwrite) at the beginning. This is useful to ignore initialization code. + ptwrite, power) at the beginning. This is useful to ignore initialization code. --itrace=i0nss1000000 diff --git a/tools/perf/util/auxtrace.c b/tools/perf/util/auxtrace.c index baad91ed1e05..651c01dfa5d3 100644 --- a/tools/perf/util/auxtrace.c +++ b/tools/perf/util/auxtrace.c @@ -948,6 +948,7 @@ void itrace_synth_opts__set_default(struct itrace_synth_opts *synth_opts) synth_opts->branches = true; synth_opts->transactions = true; synth_opts->ptwrites = true; + synth_opts->pwr_events = true; synth_opts->errors = true; synth_opts->period_type = PERF_ITRACE_DEFAULT_PERIOD_TYPE; synth_opts->period = PERF_ITRACE_DEFAULT_PERIOD; @@ -1034,6 +1035,9 @@ int itrace_parse_synth_opts(const struct option *opt, const char *str, case 'w': synth_opts->ptwrites = true; break; + case 'p': + synth_opts->pwr_events = true; + break; case 'e': synth_opts->errors = true; break; diff --git a/tools/perf/util/auxtrace.h b/tools/perf/util/auxtrace.h index b48afb2f18f3..68e0aa40b24a 100644 --- a/tools/perf/util/auxtrace.h +++ b/tools/perf/util/auxtrace.h @@ -60,6 +60,7 @@ enum itrace_period_type { * @branches: whether to synthesize 'branches' events * @transactions: whether to synthesize events for transactions * @ptwrites: whether to synthesize events for ptwrites + * @pwr_events: whether to synthesize power events * @errors: whether to synthesize decoder error events * @dont_decode: whether to skip decoding entirely * @log: write a decoding log @@ -81,6 +82,7 @@ struct itrace_synth_opts { bool branches; bool transactions; bool ptwrites; + bool pwr_events; bool errors; bool dont_decode; bool log; -- cgit v1.2.3 From 47e780848e6229b102e601deeb1ce571dc69a84a Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Fri, 26 May 2017 11:17:22 +0300 Subject: perf script: Add 'synth' field for synthesized event payloads Add a field to display the content the raw_data of a synthesized event. Signed-off-by: Adrian Hunter Cc: Andi Kleen Link: http://lkml.kernel.org/r/1495786658-18063-22-git-send-email-adrian.hunter@intel.com [ Resolved conflict with 106dacd86f04 ("perf script: Support -F brstackoff,dso") ] Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Documentation/perf-script.txt | 6 +++++- tools/perf/builtin-script.c | 20 ++++++++++++++++++-- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/tools/perf/Documentation/perf-script.txt b/tools/perf/Documentation/perf-script.txt index e2468ed6a307..5ee8796be96e 100644 --- a/tools/perf/Documentation/perf-script.txt +++ b/tools/perf/Documentation/perf-script.txt @@ -117,7 +117,8 @@ OPTIONS Comma separated list of fields to print. Options are: comm, tid, pid, time, cpu, event, trace, ip, sym, dso, addr, symoff, srcline, period, iregs, brstack, brstacksym, flags, bpf-output, brstackinsn, brstackoff, - callindent, insn, insnlen. Field list can be prepended with the type, trace, sw or hw, + callindent, insn, insnlen, synth. + Field list can be prepended with the type, trace, sw or hw, to indicate to which event type the field list applies. e.g., -F sw:comm,tid,time,ip,sym and -F trace:time,cpu,trace @@ -193,6 +194,9 @@ OPTIONS instruction bytes and the instruction length of the current instruction. + The synth field is used by synthesized events which may be created when + Instruction Trace decoding. + Finally, a user may not set fields to none for all event types. i.e., -F "" is not allowed. diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index 2999e7e425f6..e87b480bbdd0 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c @@ -86,6 +86,7 @@ enum perf_output_field { PERF_OUTPUT_INSNLEN = 1U << 22, PERF_OUTPUT_BRSTACKINSN = 1U << 23, PERF_OUTPUT_BRSTACKOFF = 1U << 24, + PERF_OUTPUT_SYNTH = 1U << 25, }; struct output_option { @@ -117,6 +118,7 @@ struct output_option { {.str = "insnlen", .field = PERF_OUTPUT_INSNLEN}, {.str = "brstackinsn", .field = PERF_OUTPUT_BRSTACKINSN}, {.str = "brstackoff", .field = PERF_OUTPUT_BRSTACKOFF}, + {.str = "synth", .field = PERF_OUTPUT_SYNTH}, }; enum { @@ -196,7 +198,8 @@ static struct { .fields = PERF_OUTPUT_COMM | PERF_OUTPUT_TID | PERF_OUTPUT_CPU | PERF_OUTPUT_TIME | PERF_OUTPUT_EVNAME | PERF_OUTPUT_IP | - PERF_OUTPUT_SYM | PERF_OUTPUT_DSO, + PERF_OUTPUT_SYM | PERF_OUTPUT_DSO | + PERF_OUTPUT_SYNTH, .invalid_fields = PERF_OUTPUT_TRACE | PERF_OUTPUT_BPF_OUTPUT, }, @@ -1200,6 +1203,15 @@ static void print_sample_bpf_output(struct perf_sample *sample) (char *)(sample->raw_data)); } +static void print_sample_synth(struct perf_sample *sample __maybe_unused, + struct perf_evsel *evsel) +{ + switch (evsel->attr.config) { + default: + break; + } +} + struct perf_script { struct perf_tool tool; struct perf_session *session; @@ -1284,6 +1296,10 @@ static void process_event(struct perf_script *script, if (PRINT_FIELD(TRACE)) event_format__print(evsel->tp_format, sample->cpu, sample->raw_data, sample->raw_size); + + if (attr->type == PERF_TYPE_SYNTH && PRINT_FIELD(SYNTH)) + print_sample_synth(sample, evsel); + if (PRINT_FIELD(ADDR)) print_sample_addr(sample, thread, attr); @@ -2605,7 +2621,7 @@ int cmd_script(int argc, const char **argv) "Valid types: hw,sw,trace,raw,synth. " "Fields: comm,tid,pid,time,cpu,event,trace,ip,sym,dso," "addr,symoff,period,iregs,brstack,brstacksym,flags," - "bpf-output,callindent,insn,insnlen,brstackinsn", + "bpf-output,callindent,insn,insnlen,brstackinsn,synth", parse_output_fields), OPT_BOOLEAN('a', "all-cpus", &system_wide, "system-wide collection from all CPUs"), -- cgit v1.2.3 From e91c8d97eac74e603481840d950536bcb62b471b Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 29 Jun 2017 10:14:06 +0100 Subject: perf/x86/intel: Constify the 'lbr_desc[]' array and make a function static A few minor clean-ups: constify the lbr_desc[] array and make local function lbr_from_signext_quirk_rd() static to fix a sparse warning: "symbol 'lbr_from_signext_quirk_rd' was not declared. Should it be static?" Signed-off-by: Colin Ian King Cc: Dan Carpenter Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: kernel-janitors@vger.kernel.org Link: http://lkml.kernel.org/r/20170629091406.9870-1-colin.king@canonical.com Signed-off-by: Ingo Molnar --- arch/x86/events/intel/lbr.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/x86/events/intel/lbr.c b/arch/x86/events/intel/lbr.c index f924629836a8..eb261656a320 100644 --- a/arch/x86/events/intel/lbr.c +++ b/arch/x86/events/intel/lbr.c @@ -18,7 +18,7 @@ enum { LBR_FORMAT_MAX_KNOWN = LBR_FORMAT_TIME, }; -static enum { +static const enum { LBR_EIP_FLAGS = 1, LBR_TSX = 2, } lbr_desc[LBR_FORMAT_MAX_KNOWN + 1] = { @@ -287,7 +287,7 @@ inline u64 lbr_from_signext_quirk_wr(u64 val) /* * If quirk is needed, ensure sign extension is 61 bits: */ -u64 lbr_from_signext_quirk_rd(u64 val) +static u64 lbr_from_signext_quirk_rd(u64 val) { if (static_branch_unlikely(&lbr_from_quirk_key)) { /* -- cgit v1.2.3 From 65c5e18f9df078f40abd22a3f6983eb9804b6d02 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Fri, 30 Jun 2017 11:36:42 +0300 Subject: perf script: Add synthesized Intel PT power and ptwrite events Add definitions for synthesized Intel PT events for power and ptwrite. Signed-off-by: Adrian Hunter Cc: Andi Kleen Link: http://lkml.kernel.org/r/1498811802-2301-1-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-script.c | 114 +++++++++++++++++++++++++++++++++++++++++- tools/perf/util/event.h | 118 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 231 insertions(+), 1 deletion(-) diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index e87b480bbdd0..b458a0cc3544 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c @@ -1203,10 +1203,122 @@ static void print_sample_bpf_output(struct perf_sample *sample) (char *)(sample->raw_data)); } -static void print_sample_synth(struct perf_sample *sample __maybe_unused, +static void print_sample_spacing(int len, int spacing) +{ + if (len > 0 && len < spacing) + printf("%*s", spacing - len, ""); +} + +static void print_sample_pt_spacing(int len) +{ + print_sample_spacing(len, 34); +} + +static void print_sample_synth_ptwrite(struct perf_sample *sample) +{ + struct perf_synth_intel_ptwrite *data = perf_sample__synth_ptr(sample); + int len; + + if (perf_sample__bad_synth_size(sample, *data)) + return; + + len = printf(" IP: %u payload: %#" PRIx64 " ", + data->ip, le64_to_cpu(data->payload)); + print_sample_pt_spacing(len); +} + +static void print_sample_synth_mwait(struct perf_sample *sample) +{ + struct perf_synth_intel_mwait *data = perf_sample__synth_ptr(sample); + int len; + + if (perf_sample__bad_synth_size(sample, *data)) + return; + + len = printf(" hints: %#x extensions: %#x ", + data->hints, data->extensions); + print_sample_pt_spacing(len); +} + +static void print_sample_synth_pwre(struct perf_sample *sample) +{ + struct perf_synth_intel_pwre *data = perf_sample__synth_ptr(sample); + int len; + + if (perf_sample__bad_synth_size(sample, *data)) + return; + + len = printf(" hw: %u cstate: %u sub-cstate: %u ", + data->hw, data->cstate, data->subcstate); + print_sample_pt_spacing(len); +} + +static void print_sample_synth_exstop(struct perf_sample *sample) +{ + struct perf_synth_intel_exstop *data = perf_sample__synth_ptr(sample); + int len; + + if (perf_sample__bad_synth_size(sample, *data)) + return; + + len = printf(" IP: %u ", data->ip); + print_sample_pt_spacing(len); +} + +static void print_sample_synth_pwrx(struct perf_sample *sample) +{ + struct perf_synth_intel_pwrx *data = perf_sample__synth_ptr(sample); + int len; + + if (perf_sample__bad_synth_size(sample, *data)) + return; + + len = printf(" deepest cstate: %u last cstate: %u wake reason: %#x ", + data->deepest_cstate, data->last_cstate, + data->wake_reason); + print_sample_pt_spacing(len); +} + +static void print_sample_synth_cbr(struct perf_sample *sample) +{ + struct perf_synth_intel_cbr *data = perf_sample__synth_ptr(sample); + unsigned int percent, freq; + int len; + + if (perf_sample__bad_synth_size(sample, *data)) + return; + + freq = (le32_to_cpu(data->freq) + 500) / 1000; + len = printf(" cbr: %2u freq: %4u MHz ", data->cbr, freq); + if (data->max_nonturbo) { + percent = (5 + (1000 * data->cbr) / data->max_nonturbo) / 10; + len += printf("(%3u%%) ", percent); + } + print_sample_pt_spacing(len); +} + +static void print_sample_synth(struct perf_sample *sample, struct perf_evsel *evsel) { switch (evsel->attr.config) { + case PERF_SYNTH_INTEL_PTWRITE: + print_sample_synth_ptwrite(sample); + break; + case PERF_SYNTH_INTEL_MWAIT: + print_sample_synth_mwait(sample); + break; + case PERF_SYNTH_INTEL_PWRE: + print_sample_synth_pwre(sample); + break; + case PERF_SYNTH_INTEL_EXSTOP: + print_sample_synth_exstop(sample); + break; + case PERF_SYNTH_INTEL_PWRX: + print_sample_synth_pwrx(sample); + break; + case PERF_SYNTH_INTEL_CBR: + print_sample_synth_cbr(sample); + break; default: break; } diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h index 855733c2adcf..9967c87af7a6 100644 --- a/tools/perf/util/event.h +++ b/tools/perf/util/event.h @@ -255,6 +255,124 @@ enum auxtrace_error_type { /* Attribute type for custom synthesized events */ #define PERF_TYPE_SYNTH (INT_MAX + 1U) +/* Attribute config for custom synthesized events */ +enum perf_synth_id { + PERF_SYNTH_INTEL_PTWRITE, + PERF_SYNTH_INTEL_MWAIT, + PERF_SYNTH_INTEL_PWRE, + PERF_SYNTH_INTEL_EXSTOP, + PERF_SYNTH_INTEL_PWRX, + PERF_SYNTH_INTEL_CBR, +}; + +/* + * Raw data formats for synthesized events. Note that 4 bytes of padding are + * present to match the 'size' member of PERF_SAMPLE_RAW data which is always + * 8-byte aligned. That means we must dereference raw_data with an offset of 4. + * Refer perf_sample__synth_ptr() and perf_synth__raw_data(). It also means the + * structure sizes are 4 bytes bigger than the raw_size, refer + * perf_synth__raw_size(). + */ + +struct perf_synth_intel_ptwrite { + u32 padding; + union { + struct { + u32 ip : 1, + reserved : 31; + }; + u32 flags; + }; + u64 payload; +}; + +struct perf_synth_intel_mwait { + u32 padding; + u32 reserved; + union { + struct { + u64 hints : 8, + reserved1 : 24, + extensions : 2, + reserved2 : 30; + }; + u64 payload; + }; +}; + +struct perf_synth_intel_pwre { + u32 padding; + u32 reserved; + union { + struct { + u64 reserved1 : 7, + hw : 1, + subcstate : 4, + cstate : 4, + reserved2 : 48; + }; + u64 payload; + }; +}; + +struct perf_synth_intel_exstop { + u32 padding; + union { + struct { + u32 ip : 1, + reserved : 31; + }; + u32 flags; + }; +}; + +struct perf_synth_intel_pwrx { + u32 padding; + u32 reserved; + union { + struct { + u64 deepest_cstate : 4, + last_cstate : 4, + wake_reason : 4, + reserved1 : 52; + }; + u64 payload; + }; +}; + +struct perf_synth_intel_cbr { + u32 padding; + union { + struct { + u32 cbr : 8, + reserved1 : 8, + max_nonturbo : 8, + reserved2 : 8; + }; + u32 flags; + }; + u32 freq; + u32 reserved3; +}; + +/* + * raw_data is always 4 bytes from an 8-byte boundary, so subtract 4 to get + * 8-byte alignment. + */ +static inline void *perf_sample__synth_ptr(struct perf_sample *sample) +{ + return sample->raw_data - 4; +} + +static inline void *perf_synth__raw_data(void *p) +{ + return p + 4; +} + +#define perf_synth__raw_size(d) (sizeof(d) - 4) + +#define perf_sample__bad_synth_size(s, d) ((s)->raw_size < sizeof(d) - 4) + /* * The kernel collects the number of events it couldn't send in a stretch and * when possible sends this number in a PERF_RECORD_LOST event. The number of -- cgit v1.2.3 From 0f3e53799cd5fad1dcc8c077a3d9cc260243328f Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Fri, 26 May 2017 11:17:27 +0300 Subject: perf intel-pt: Factor out common code synthesizing event samples Factor out common code in functions synthesizing event samples i.e. intel_pt_synth_branch_sample(), intel_pt_synth_instruction_sample() and intel_pt_synth_transaction_sample(). Signed-off-by: Adrian Hunter Cc: Andi Kleen Link: http://lkml.kernel.org/r/1495786658-18063-27-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/intel-pt.c | 222 ++++++++++++++++++++------------------------- 1 file changed, 100 insertions(+), 122 deletions(-) diff --git a/tools/perf/util/intel-pt.c b/tools/perf/util/intel-pt.c index 6df836469f2b..dbff5dca09f0 100644 --- a/tools/perf/util/intel-pt.c +++ b/tools/perf/util/intel-pt.c @@ -1058,6 +1058,36 @@ static void intel_pt_update_last_branch_rb(struct intel_pt_queue *ptq) bs->nr += 1; } +static inline bool intel_pt_skip_event(struct intel_pt *pt) +{ + return pt->synth_opts.initial_skip && + pt->num_events++ < pt->synth_opts.initial_skip; +} + +static void intel_pt_prep_b_sample(struct intel_pt *pt, + struct intel_pt_queue *ptq, + union perf_event *event, + struct perf_sample *sample) +{ + event->sample.header.type = PERF_RECORD_SAMPLE; + event->sample.header.misc = PERF_RECORD_MISC_USER; + event->sample.header.size = sizeof(struct perf_event_header); + + if (!pt->timeless_decoding) + sample->time = tsc_to_perf_time(ptq->timestamp, &pt->tc); + + sample->cpumode = PERF_RECORD_MISC_USER; + sample->ip = ptq->state->from_ip; + sample->pid = ptq->pid; + sample->tid = ptq->tid; + sample->addr = ptq->state->to_ip; + sample->period = 1; + sample->cpu = ptq->cpu; + sample->flags = ptq->flags; + sample->insn_len = ptq->insn_len; + memcpy(sample->insn, ptq->insn, INTEL_PT_INSN_BUF_SZ); +} + static int intel_pt_inject_event(union perf_event *event, struct perf_sample *sample, u64 type, bool swapped) @@ -1066,9 +1096,35 @@ static int intel_pt_inject_event(union perf_event *event, return perf_event__synthesize_sample(event, type, 0, sample, swapped); } -static int intel_pt_synth_branch_sample(struct intel_pt_queue *ptq) +static inline int intel_pt_opt_inject(struct intel_pt *pt, + union perf_event *event, + struct perf_sample *sample, u64 type) +{ + if (!pt->synth_opts.inject) + return 0; + + return intel_pt_inject_event(event, sample, type, pt->synth_needs_swap); +} + +static int intel_pt_deliver_synth_b_event(struct intel_pt *pt, + union perf_event *event, + struct perf_sample *sample, u64 type) { int ret; + + ret = intel_pt_opt_inject(pt, event, sample, type); + if (ret) + return ret; + + ret = perf_session__deliver_synth_event(pt->session, event, sample); + if (ret) + pr_err("Intel PT: failed to deliver event, error %d\n", ret); + + return ret; +} + +static int intel_pt_synth_branch_sample(struct intel_pt_queue *ptq) +{ struct intel_pt *pt = ptq->pt; union perf_event *event = ptq->event_buf; struct perf_sample sample = { .ip = 0, }; @@ -1080,29 +1136,13 @@ static int intel_pt_synth_branch_sample(struct intel_pt_queue *ptq) if (pt->branches_filter && !(pt->branches_filter & ptq->flags)) return 0; - if (pt->synth_opts.initial_skip && - pt->num_events++ < pt->synth_opts.initial_skip) + if (intel_pt_skip_event(pt)) return 0; - event->sample.header.type = PERF_RECORD_SAMPLE; - event->sample.header.misc = PERF_RECORD_MISC_USER; - event->sample.header.size = sizeof(struct perf_event_header); + intel_pt_prep_b_sample(pt, ptq, event, &sample); - if (!pt->timeless_decoding) - sample.time = tsc_to_perf_time(ptq->timestamp, &pt->tc); - - sample.cpumode = PERF_RECORD_MISC_USER; - sample.ip = ptq->state->from_ip; - sample.pid = ptq->pid; - sample.tid = ptq->tid; - sample.addr = ptq->state->to_ip; sample.id = ptq->pt->branches_id; sample.stream_id = ptq->pt->branches_id; - sample.period = 1; - sample.cpu = ptq->cpu; - sample.flags = ptq->flags; - sample.insn_len = ptq->insn_len; - memcpy(sample.insn, ptq->insn, INTEL_PT_INSN_BUF_SZ); /* * perf report cannot handle events without a branch stack when using @@ -1119,78 +1159,38 @@ static int intel_pt_synth_branch_sample(struct intel_pt_queue *ptq) sample.branch_stack = (struct branch_stack *)&dummy_bs; } - if (pt->synth_opts.inject) { - ret = intel_pt_inject_event(event, &sample, - pt->branches_sample_type, - pt->synth_needs_swap); - if (ret) - return ret; - } - - ret = perf_session__deliver_synth_event(pt->session, event, &sample); - if (ret) - pr_err("Intel Processor Trace: failed to deliver branch event, error %d\n", - ret); - - return ret; + return intel_pt_deliver_synth_b_event(pt, event, &sample, + pt->branches_sample_type); } -static int intel_pt_synth_instruction_sample(struct intel_pt_queue *ptq) +static void intel_pt_prep_sample(struct intel_pt *pt, + struct intel_pt_queue *ptq, + union perf_event *event, + struct perf_sample *sample) { - int ret; - struct intel_pt *pt = ptq->pt; - union perf_event *event = ptq->event_buf; - struct perf_sample sample = { .ip = 0, }; - - if (pt->synth_opts.initial_skip && - pt->num_events++ < pt->synth_opts.initial_skip) - return 0; - - event->sample.header.type = PERF_RECORD_SAMPLE; - event->sample.header.misc = PERF_RECORD_MISC_USER; - event->sample.header.size = sizeof(struct perf_event_header); - - if (!pt->timeless_decoding) - sample.time = tsc_to_perf_time(ptq->timestamp, &pt->tc); - - sample.cpumode = PERF_RECORD_MISC_USER; - sample.ip = ptq->state->from_ip; - sample.pid = ptq->pid; - sample.tid = ptq->tid; - sample.addr = ptq->state->to_ip; - sample.id = ptq->pt->instructions_id; - sample.stream_id = ptq->pt->instructions_id; - sample.period = ptq->state->tot_insn_cnt - ptq->last_insn_cnt; - sample.cpu = ptq->cpu; - sample.flags = ptq->flags; - sample.insn_len = ptq->insn_len; - memcpy(sample.insn, ptq->insn, INTEL_PT_INSN_BUF_SZ); - - ptq->last_insn_cnt = ptq->state->tot_insn_cnt; + intel_pt_prep_b_sample(pt, ptq, event, sample); if (pt->synth_opts.callchain) { thread_stack__sample(ptq->thread, ptq->chain, - pt->synth_opts.callchain_sz, sample.ip); - sample.callchain = ptq->chain; + pt->synth_opts.callchain_sz, sample->ip); + sample->callchain = ptq->chain; } if (pt->synth_opts.last_branch) { intel_pt_copy_last_branch_rb(ptq); - sample.branch_stack = ptq->last_branch; + sample->branch_stack = ptq->last_branch; } +} - if (pt->synth_opts.inject) { - ret = intel_pt_inject_event(event, &sample, - pt->instructions_sample_type, - pt->synth_needs_swap); - if (ret) - return ret; - } +static inline int intel_pt_deliver_synth_event(struct intel_pt *pt, + struct intel_pt_queue *ptq, + union perf_event *event, + struct perf_sample *sample, + u64 type) +{ + int ret; - ret = perf_session__deliver_synth_event(pt->session, event, &sample); - if (ret) - pr_err("Intel Processor Trace: failed to deliver instruction event, error %d\n", - ret); + ret = intel_pt_deliver_synth_b_event(pt, event, sample, type); if (pt->synth_opts.last_branch) intel_pt_reset_last_branch_rb(ptq); @@ -1198,65 +1198,43 @@ static int intel_pt_synth_instruction_sample(struct intel_pt_queue *ptq) return ret; } -static int intel_pt_synth_transaction_sample(struct intel_pt_queue *ptq) +static int intel_pt_synth_instruction_sample(struct intel_pt_queue *ptq) { - int ret; struct intel_pt *pt = ptq->pt; union perf_event *event = ptq->event_buf; struct perf_sample sample = { .ip = 0, }; - if (pt->synth_opts.initial_skip && - pt->num_events++ < pt->synth_opts.initial_skip) + if (intel_pt_skip_event(pt)) return 0; - event->sample.header.type = PERF_RECORD_SAMPLE; - event->sample.header.misc = PERF_RECORD_MISC_USER; - event->sample.header.size = sizeof(struct perf_event_header); + intel_pt_prep_sample(pt, ptq, event, &sample); - if (!pt->timeless_decoding) - sample.time = tsc_to_perf_time(ptq->timestamp, &pt->tc); + sample.id = ptq->pt->instructions_id; + sample.stream_id = ptq->pt->instructions_id; + sample.period = ptq->state->tot_insn_cnt - ptq->last_insn_cnt; - sample.cpumode = PERF_RECORD_MISC_USER; - sample.ip = ptq->state->from_ip; - sample.pid = ptq->pid; - sample.tid = ptq->tid; - sample.addr = ptq->state->to_ip; - sample.id = ptq->pt->transactions_id; - sample.stream_id = ptq->pt->transactions_id; - sample.period = 1; - sample.cpu = ptq->cpu; - sample.flags = ptq->flags; - sample.insn_len = ptq->insn_len; - memcpy(sample.insn, ptq->insn, INTEL_PT_INSN_BUF_SZ); + ptq->last_insn_cnt = ptq->state->tot_insn_cnt; - if (pt->synth_opts.callchain) { - thread_stack__sample(ptq->thread, ptq->chain, - pt->synth_opts.callchain_sz, sample.ip); - sample.callchain = ptq->chain; - } + return intel_pt_deliver_synth_event(pt, ptq, event, &sample, + pt->instructions_sample_type); +} - if (pt->synth_opts.last_branch) { - intel_pt_copy_last_branch_rb(ptq); - sample.branch_stack = ptq->last_branch; - } +static int intel_pt_synth_transaction_sample(struct intel_pt_queue *ptq) +{ + struct intel_pt *pt = ptq->pt; + union perf_event *event = ptq->event_buf; + struct perf_sample sample = { .ip = 0, }; - if (pt->synth_opts.inject) { - ret = intel_pt_inject_event(event, &sample, - pt->transactions_sample_type, - pt->synth_needs_swap); - if (ret) - return ret; - } + if (intel_pt_skip_event(pt)) + return 0; - ret = perf_session__deliver_synth_event(pt->session, event, &sample); - if (ret) - pr_err("Intel Processor Trace: failed to deliver transaction event, error %d\n", - ret); + intel_pt_prep_sample(pt, ptq, event, &sample); - if (pt->synth_opts.last_branch) - intel_pt_reset_last_branch_rb(ptq); + sample.id = ptq->pt->transactions_id; + sample.stream_id = ptq->pt->transactions_id; - return ret; + return intel_pt_deliver_synth_event(pt, ptq, event, &sample, + pt->transactions_sample_type); } static int intel_pt_synth_error(struct intel_pt *pt, int code, int cpu, -- cgit v1.2.3 From f90d07a9f6d76e46ed99b4103747031394b16dd7 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Fri, 26 May 2017 11:17:28 +0300 Subject: perf intel-pt: Remove unused instructions_sample_period Remove unused struct intel_pt member instructions_sample_period. Signed-off-by: Adrian Hunter Cc: Andi Kleen Link: http://lkml.kernel.org/r/1495786658-18063-28-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/intel-pt.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/tools/perf/util/intel-pt.c b/tools/perf/util/intel-pt.c index dbff5dca09f0..f8237a0e2946 100644 --- a/tools/perf/util/intel-pt.c +++ b/tools/perf/util/intel-pt.c @@ -81,7 +81,6 @@ struct intel_pt { bool sample_instructions; u64 instructions_sample_type; - u64 instructions_sample_period; u64 instructions_id; bool sample_branches; @@ -1978,7 +1977,6 @@ static int intel_pt_synth_events(struct intel_pt *pt, intel_pt_ns_to_ticks(pt, pt->synth_opts.period); else attr.sample_period = pt->synth_opts.period; - pt->instructions_sample_period = attr.sample_period; if (pt->synth_opts.callchain) attr.sample_type |= PERF_SAMPLE_CALLCHAIN; if (pt->synth_opts.last_branch) -- cgit v1.2.3 From 406a180501f6d0d4e43d5acc5f580abfc95c742d Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Fri, 26 May 2017 11:17:29 +0300 Subject: perf intel-pt: Join needlessly wrapped lines Join needlessly wrapped lines. Signed-off-by: Adrian Hunter Cc: Andi Kleen Link: http://lkml.kernel.org/r/1495786658-18063-29-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/intel-pt.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/tools/perf/util/intel-pt.c b/tools/perf/util/intel-pt.c index f8237a0e2946..b670502b0264 100644 --- a/tools/perf/util/intel-pt.c +++ b/tools/perf/util/intel-pt.c @@ -1298,15 +1298,13 @@ static int intel_pt_sample(struct intel_pt_queue *ptq) ptq->have_sample = false; - if (pt->sample_instructions && - (state->type & INTEL_PT_INSTRUCTION)) { + if (pt->sample_instructions && (state->type & INTEL_PT_INSTRUCTION)) { err = intel_pt_synth_instruction_sample(ptq); if (err) return err; } - if (pt->sample_transactions && - (state->type & INTEL_PT_TRANSACTION)) { + if (pt->sample_transactions && (state->type & INTEL_PT_TRANSACTION)) { err = intel_pt_synth_transaction_sample(ptq); if (err) return err; -- cgit v1.2.3 From 85a564d26dfb45bbf0c0095e0fcee3bdc4a49a85 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Fri, 26 May 2017 11:17:30 +0300 Subject: perf intel-pt: Tidy Intel PT evsel lookup into separate function Tidy the lookup of the Intel PT selected event (perf_evsel) into a separate function. Signed-off-by: Adrian Hunter Cc: Andi Kleen Link: http://lkml.kernel.org/r/1495786658-18063-30-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/intel-pt.c | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/tools/perf/util/intel-pt.c b/tools/perf/util/intel-pt.c index b670502b0264..a9486b57584f 100644 --- a/tools/perf/util/intel-pt.c +++ b/tools/perf/util/intel-pt.c @@ -1922,24 +1922,29 @@ static int intel_pt_synth_event(struct perf_session *session, &id, intel_pt_event_synth); } +static struct perf_evsel *intel_pt_evsel(struct intel_pt *pt, + struct perf_evlist *evlist) +{ + struct perf_evsel *evsel; + + evlist__for_each_entry(evlist, evsel) { + if (evsel->attr.type == pt->pmu_type && evsel->ids) + return evsel; + } + + return NULL; +} + static int intel_pt_synth_events(struct intel_pt *pt, struct perf_session *session) { struct perf_evlist *evlist = session->evlist; - struct perf_evsel *evsel; + struct perf_evsel *evsel = intel_pt_evsel(pt, evlist); struct perf_event_attr attr; - bool found = false; u64 id; int err; - evlist__for_each_entry(evlist, evsel) { - if (evsel->attr.type == pt->pmu_type && evsel->ids) { - found = true; - break; - } - } - - if (!found) { + if (!evsel) { pr_debug("There are no selected events with Intel Processor Trace data\n"); return 0; } -- cgit v1.2.3 From 63a22cd9f8400fe914ddc3d597d925594f212519 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Fri, 26 May 2017 11:17:31 +0300 Subject: perf intel-pt: Tidy messages into called function intel_pt_synth_event() Tidy print messages into called function intel_pt_synth_event(). Signed-off-by: Adrian Hunter Cc: Andi Kleen Link: http://lkml.kernel.org/r/1495786658-18063-31-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/intel-pt.c | 42 ++++++++++++++++++------------------------ 1 file changed, 18 insertions(+), 24 deletions(-) diff --git a/tools/perf/util/intel-pt.c b/tools/perf/util/intel-pt.c index a9486b57584f..81907f60e7da 100644 --- a/tools/perf/util/intel-pt.c +++ b/tools/perf/util/intel-pt.c @@ -1910,16 +1910,25 @@ static int intel_pt_event_synth(struct perf_tool *tool, NULL); } -static int intel_pt_synth_event(struct perf_session *session, +static int intel_pt_synth_event(struct perf_session *session, const char *name, struct perf_event_attr *attr, u64 id) { struct intel_pt_synth intel_pt_synth; + int err; + + pr_debug("Synthesizing '%s' event with id %" PRIu64 " sample type %#" PRIx64 "\n", + name, id, (u64)attr->sample_type); memset(&intel_pt_synth, 0, sizeof(struct intel_pt_synth)); intel_pt_synth.session = session; - return perf_event__synthesize_attr(&intel_pt_synth.dummy_tool, attr, 1, - &id, intel_pt_event_synth); + err = perf_event__synthesize_attr(&intel_pt_synth.dummy_tool, attr, 1, + &id, intel_pt_event_synth); + if (err) + pr_err("%s: failed to synthesize '%s' event type\n", + __func__, name); + + return err; } static struct perf_evsel *intel_pt_evsel(struct intel_pt *pt, @@ -1984,14 +1993,9 @@ static int intel_pt_synth_events(struct intel_pt *pt, attr.sample_type |= PERF_SAMPLE_CALLCHAIN; if (pt->synth_opts.last_branch) attr.sample_type |= PERF_SAMPLE_BRANCH_STACK; - pr_debug("Synthesizing 'instructions' event with id %" PRIu64 " sample type %#" PRIx64 "\n", - id, (u64)attr.sample_type); - err = intel_pt_synth_event(session, &attr, id); - if (err) { - pr_err("%s: failed to synthesize 'instructions' event type\n", - __func__); + err = intel_pt_synth_event(session, "instructions", &attr, id); + if (err) return err; - } pt->sample_instructions = true; pt->instructions_sample_type = attr.sample_type; pt->instructions_id = id; @@ -2005,14 +2009,9 @@ static int intel_pt_synth_events(struct intel_pt *pt, attr.sample_type |= PERF_SAMPLE_CALLCHAIN; if (pt->synth_opts.last_branch) attr.sample_type |= PERF_SAMPLE_BRANCH_STACK; - pr_debug("Synthesizing 'transactions' event with id %" PRIu64 " sample type %#" PRIx64 "\n", - id, (u64)attr.sample_type); - err = intel_pt_synth_event(session, &attr, id); - if (err) { - pr_err("%s: failed to synthesize 'transactions' event type\n", - __func__); + err = intel_pt_synth_event(session, "transactions", &attr, id); + if (err) return err; - } pt->sample_transactions = true; pt->transactions_sample_type = attr.sample_type; pt->transactions_id = id; @@ -2033,14 +2032,9 @@ static int intel_pt_synth_events(struct intel_pt *pt, attr.sample_type |= PERF_SAMPLE_ADDR; attr.sample_type &= ~(u64)PERF_SAMPLE_CALLCHAIN; attr.sample_type &= ~(u64)PERF_SAMPLE_BRANCH_STACK; - pr_debug("Synthesizing 'branches' event with id %" PRIu64 " sample type %#" PRIx64 "\n", - id, (u64)attr.sample_type); - err = intel_pt_synth_event(session, &attr, id); - if (err) { - pr_err("%s: failed to synthesize 'branches' event type\n", - __func__); + err = intel_pt_synth_event(session, "branches", &attr, id); + if (err) return err; - } pt->sample_branches = true; pt->branches_sample_type = attr.sample_type; pt->branches_id = id; -- cgit v1.2.3 From bbac88ed64436201d6b6f2b00177d58081d56707 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Fri, 26 May 2017 11:17:32 +0300 Subject: perf intel-pt: Factor out intel_pt_set_event_name() Factor out intel_pt_set_event_name() so it can be reused. Signed-off-by: Adrian Hunter Cc: Andi Kleen Link: http://lkml.kernel.org/r/1495786658-18063-32-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/intel-pt.c | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/tools/perf/util/intel-pt.c b/tools/perf/util/intel-pt.c index 81907f60e7da..a20712e1ed28 100644 --- a/tools/perf/util/intel-pt.c +++ b/tools/perf/util/intel-pt.c @@ -1931,6 +1931,21 @@ static int intel_pt_synth_event(struct perf_session *session, const char *name, return err; } +static void intel_pt_set_event_name(struct perf_evlist *evlist, u64 id, + const char *name) +{ + struct perf_evsel *evsel; + + evlist__for_each_entry(evlist, evsel) { + if (evsel->id && evsel->id[0] == id) { + if (evsel->name) + zfree(&evsel->name); + evsel->name = strdup(name); + break; + } + } +} + static struct perf_evsel *intel_pt_evsel(struct intel_pt *pt, struct perf_evlist *evlist) { @@ -2015,15 +2030,8 @@ static int intel_pt_synth_events(struct intel_pt *pt, pt->sample_transactions = true; pt->transactions_sample_type = attr.sample_type; pt->transactions_id = id; + intel_pt_set_event_name(evlist, id, "transactions"); id += 1; - evlist__for_each_entry(evlist, evsel) { - if (evsel->id && evsel->id[0] == pt->transactions_id) { - if (evsel->name) - zfree(&evsel->name); - evsel->name = strdup("transactions"); - break; - } - } } if (pt->synth_opts.branches) { -- cgit v1.2.3 From 4a9fd4e0effc94b9ec79250946a0054d4dd1a963 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Fri, 26 May 2017 11:17:33 +0300 Subject: perf intel-pt: Move code in intel_pt_synth_events() to simplify attr setting intel_pt_synth_events() uses the same attr structure to create each event. Move the code around a bit to simplify that. Signed-off-by: Adrian Hunter Cc: Andi Kleen Link: http://lkml.kernel.org/r/1495786658-18063-33-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/intel-pt.c | 45 ++++++++++++++++++++++----------------------- 1 file changed, 22 insertions(+), 23 deletions(-) diff --git a/tools/perf/util/intel-pt.c b/tools/perf/util/intel-pt.c index a20712e1ed28..ace79a405f98 100644 --- a/tools/perf/util/intel-pt.c +++ b/tools/perf/util/intel-pt.c @@ -1997,6 +1997,25 @@ static int intel_pt_synth_events(struct intel_pt *pt, if (!id) id = 1; + if (pt->synth_opts.branches) { + attr.config = PERF_COUNT_HW_BRANCH_INSTRUCTIONS; + attr.sample_period = 1; + attr.sample_type |= PERF_SAMPLE_ADDR; + err = intel_pt_synth_event(session, "branches", &attr, id); + if (err) + return err; + pt->sample_branches = true; + pt->branches_sample_type = attr.sample_type; + pt->branches_id = id; + id += 1; + attr.sample_type &= ~(u64)PERF_SAMPLE_ADDR; + } + + if (pt->synth_opts.callchain) + attr.sample_type |= PERF_SAMPLE_CALLCHAIN; + if (pt->synth_opts.last_branch) + attr.sample_type |= PERF_SAMPLE_BRANCH_STACK; + if (pt->synth_opts.instructions) { attr.config = PERF_COUNT_HW_INSTRUCTIONS; if (pt->synth_opts.period_type == PERF_ITRACE_PERIOD_NANOSECS) @@ -2004,10 +2023,6 @@ static int intel_pt_synth_events(struct intel_pt *pt, intel_pt_ns_to_ticks(pt, pt->synth_opts.period); else attr.sample_period = pt->synth_opts.period; - if (pt->synth_opts.callchain) - attr.sample_type |= PERF_SAMPLE_CALLCHAIN; - if (pt->synth_opts.last_branch) - attr.sample_type |= PERF_SAMPLE_BRANCH_STACK; err = intel_pt_synth_event(session, "instructions", &attr, id); if (err) return err; @@ -2017,13 +2032,11 @@ static int intel_pt_synth_events(struct intel_pt *pt, id += 1; } + attr.sample_type &= ~(u64)PERF_SAMPLE_PERIOD; + attr.sample_period = 1; + if (pt->synth_opts.transactions) { attr.config = PERF_COUNT_HW_INSTRUCTIONS; - attr.sample_period = 1; - if (pt->synth_opts.callchain) - attr.sample_type |= PERF_SAMPLE_CALLCHAIN; - if (pt->synth_opts.last_branch) - attr.sample_type |= PERF_SAMPLE_BRANCH_STACK; err = intel_pt_synth_event(session, "transactions", &attr, id); if (err) return err; @@ -2034,20 +2047,6 @@ static int intel_pt_synth_events(struct intel_pt *pt, id += 1; } - if (pt->synth_opts.branches) { - attr.config = PERF_COUNT_HW_BRANCH_INSTRUCTIONS; - attr.sample_period = 1; - attr.sample_type |= PERF_SAMPLE_ADDR; - attr.sample_type &= ~(u64)PERF_SAMPLE_CALLCHAIN; - attr.sample_type &= ~(u64)PERF_SAMPLE_BRANCH_STACK; - err = intel_pt_synth_event(session, "branches", &attr, id); - if (err) - return err; - pt->sample_branches = true; - pt->branches_sample_type = attr.sample_type; - pt->branches_id = id; - } - pt->synth_needs_swap = evsel->needs_swap; return 0; -- cgit v1.2.3 From 3797307576191d7fb4c974cd461188162ac36f33 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Fri, 30 Jun 2017 11:36:45 +0300 Subject: perf intel-pt: Synthesize new power and "ptwrite" events Synthesize new power and ptwrite events. Power events report changes to C-state but I have also added support for the existing CBR (core-to-bus ratio) packet and included that when outputting power events. The PTWRITE packet is associated with the new "ptwrite" instruction, which is essentially just a way to stuff a 32 or 64 bit value into the PT trace. More details can be found in the patches that add documentation and in the Intel SDM. Signed-off-by: Adrian Hunter Cc: Andi Kleen Link: http://lkml.kernel.org/r/1498811805-2335-1-git-send-email-adrian.hunter@intel.com [ Copy the description of such packet from the patchkit cover message ] Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/intel-pt.c | 283 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 283 insertions(+) diff --git a/tools/perf/util/intel-pt.c b/tools/perf/util/intel-pt.c index ace79a405f98..b58f9fd1e2ee 100644 --- a/tools/perf/util/intel-pt.c +++ b/tools/perf/util/intel-pt.c @@ -92,6 +92,18 @@ struct intel_pt { u64 transactions_sample_type; u64 transactions_id; + bool sample_ptwrites; + u64 ptwrites_sample_type; + u64 ptwrites_id; + + bool sample_pwr_events; + u64 pwr_events_sample_type; + u64 mwait_id; + u64 pwre_id; + u64 exstop_id; + u64 pwrx_id; + u64 cbr_id; + bool synth_needs_swap; u64 tsc_bit; @@ -102,6 +114,7 @@ struct intel_pt { u64 cyc_bit; u64 noretcomp_bit; unsigned max_non_turbo_ratio; + unsigned cbr2khz; unsigned long num_events; @@ -1236,6 +1249,175 @@ static int intel_pt_synth_transaction_sample(struct intel_pt_queue *ptq) pt->transactions_sample_type); } +static void intel_pt_prep_p_sample(struct intel_pt *pt, + struct intel_pt_queue *ptq, + union perf_event *event, + struct perf_sample *sample) +{ + intel_pt_prep_sample(pt, ptq, event, sample); + + /* + * Zero IP is used to mean "trace start" but that is not the case for + * power or PTWRITE events with no IP, so clear the flags. + */ + if (!sample->ip) + sample->flags = 0; +} + +static int intel_pt_synth_ptwrite_sample(struct intel_pt_queue *ptq) +{ + struct intel_pt *pt = ptq->pt; + union perf_event *event = ptq->event_buf; + struct perf_sample sample = { .ip = 0, }; + struct perf_synth_intel_ptwrite raw; + + if (intel_pt_skip_event(pt)) + return 0; + + intel_pt_prep_p_sample(pt, ptq, event, &sample); + + sample.id = ptq->pt->ptwrites_id; + sample.stream_id = ptq->pt->ptwrites_id; + + raw.flags = 0; + raw.ip = !!(ptq->state->flags & INTEL_PT_FUP_IP); + raw.payload = cpu_to_le64(ptq->state->ptw_payload); + + sample.raw_size = perf_synth__raw_size(raw); + sample.raw_data = perf_synth__raw_data(&raw); + + return intel_pt_deliver_synth_event(pt, ptq, event, &sample, + pt->ptwrites_sample_type); +} + +static int intel_pt_synth_cbr_sample(struct intel_pt_queue *ptq) +{ + struct intel_pt *pt = ptq->pt; + union perf_event *event = ptq->event_buf; + struct perf_sample sample = { .ip = 0, }; + struct perf_synth_intel_cbr raw; + u32 flags; + + if (intel_pt_skip_event(pt)) + return 0; + + intel_pt_prep_p_sample(pt, ptq, event, &sample); + + sample.id = ptq->pt->cbr_id; + sample.stream_id = ptq->pt->cbr_id; + + flags = (u16)ptq->state->cbr_payload | (pt->max_non_turbo_ratio << 16); + raw.flags = cpu_to_le32(flags); + raw.freq = cpu_to_le32(raw.cbr * pt->cbr2khz); + raw.reserved3 = 0; + + sample.raw_size = perf_synth__raw_size(raw); + sample.raw_data = perf_synth__raw_data(&raw); + + return intel_pt_deliver_synth_event(pt, ptq, event, &sample, + pt->pwr_events_sample_type); +} + +static int intel_pt_synth_mwait_sample(struct intel_pt_queue *ptq) +{ + struct intel_pt *pt = ptq->pt; + union perf_event *event = ptq->event_buf; + struct perf_sample sample = { .ip = 0, }; + struct perf_synth_intel_mwait raw; + + if (intel_pt_skip_event(pt)) + return 0; + + intel_pt_prep_p_sample(pt, ptq, event, &sample); + + sample.id = ptq->pt->mwait_id; + sample.stream_id = ptq->pt->mwait_id; + + raw.reserved = 0; + raw.payload = cpu_to_le64(ptq->state->mwait_payload); + + sample.raw_size = perf_synth__raw_size(raw); + sample.raw_data = perf_synth__raw_data(&raw); + + return intel_pt_deliver_synth_event(pt, ptq, event, &sample, + pt->pwr_events_sample_type); +} + +static int intel_pt_synth_pwre_sample(struct intel_pt_queue *ptq) +{ + struct intel_pt *pt = ptq->pt; + union perf_event *event = ptq->event_buf; + struct perf_sample sample = { .ip = 0, }; + struct perf_synth_intel_pwre raw; + + if (intel_pt_skip_event(pt)) + return 0; + + intel_pt_prep_p_sample(pt, ptq, event, &sample); + + sample.id = ptq->pt->pwre_id; + sample.stream_id = ptq->pt->pwre_id; + + raw.reserved = 0; + raw.payload = cpu_to_le64(ptq->state->pwre_payload); + + sample.raw_size = perf_synth__raw_size(raw); + sample.raw_data = perf_synth__raw_data(&raw); + + return intel_pt_deliver_synth_event(pt, ptq, event, &sample, + pt->pwr_events_sample_type); +} + +static int intel_pt_synth_exstop_sample(struct intel_pt_queue *ptq) +{ + struct intel_pt *pt = ptq->pt; + union perf_event *event = ptq->event_buf; + struct perf_sample sample = { .ip = 0, }; + struct perf_synth_intel_exstop raw; + + if (intel_pt_skip_event(pt)) + return 0; + + intel_pt_prep_p_sample(pt, ptq, event, &sample); + + sample.id = ptq->pt->exstop_id; + sample.stream_id = ptq->pt->exstop_id; + + raw.flags = 0; + raw.ip = !!(ptq->state->flags & INTEL_PT_FUP_IP); + + sample.raw_size = perf_synth__raw_size(raw); + sample.raw_data = perf_synth__raw_data(&raw); + + return intel_pt_deliver_synth_event(pt, ptq, event, &sample, + pt->pwr_events_sample_type); +} + +static int intel_pt_synth_pwrx_sample(struct intel_pt_queue *ptq) +{ + struct intel_pt *pt = ptq->pt; + union perf_event *event = ptq->event_buf; + struct perf_sample sample = { .ip = 0, }; + struct perf_synth_intel_pwrx raw; + + if (intel_pt_skip_event(pt)) + return 0; + + intel_pt_prep_p_sample(pt, ptq, event, &sample); + + sample.id = ptq->pt->pwrx_id; + sample.stream_id = ptq->pt->pwrx_id; + + raw.reserved = 0; + raw.payload = cpu_to_le64(ptq->state->pwrx_payload); + + sample.raw_size = perf_synth__raw_size(raw); + sample.raw_data = perf_synth__raw_data(&raw); + + return intel_pt_deliver_synth_event(pt, ptq, event, &sample, + pt->pwr_events_sample_type); +} + static int intel_pt_synth_error(struct intel_pt *pt, int code, int cpu, pid_t pid, pid_t tid, u64 ip) { @@ -1287,6 +1469,10 @@ static inline bool intel_pt_is_switch_ip(struct intel_pt_queue *ptq, u64 ip) PERF_IP_FLAG_INTERRUPT | PERF_IP_FLAG_TX_ABORT)); } +#define INTEL_PT_PWR_EVT (INTEL_PT_MWAIT_OP | INTEL_PT_PWR_ENTRY | \ + INTEL_PT_EX_STOP | INTEL_PT_PWR_EXIT | \ + INTEL_PT_CBR_CHG) + static int intel_pt_sample(struct intel_pt_queue *ptq) { const struct intel_pt_state *state = ptq->state; @@ -1298,6 +1484,34 @@ static int intel_pt_sample(struct intel_pt_queue *ptq) ptq->have_sample = false; + if (pt->sample_pwr_events && (state->type & INTEL_PT_PWR_EVT)) { + if (state->type & INTEL_PT_CBR_CHG) { + err = intel_pt_synth_cbr_sample(ptq); + if (err) + return err; + } + if (state->type & INTEL_PT_MWAIT_OP) { + err = intel_pt_synth_mwait_sample(ptq); + if (err) + return err; + } + if (state->type & INTEL_PT_PWR_ENTRY) { + err = intel_pt_synth_pwre_sample(ptq); + if (err) + return err; + } + if (state->type & INTEL_PT_EX_STOP) { + err = intel_pt_synth_exstop_sample(ptq); + if (err) + return err; + } + if (state->type & INTEL_PT_PWR_EXIT) { + err = intel_pt_synth_pwrx_sample(ptq); + if (err) + return err; + } + } + if (pt->sample_instructions && (state->type & INTEL_PT_INSTRUCTION)) { err = intel_pt_synth_instruction_sample(ptq); if (err) @@ -1310,6 +1524,12 @@ static int intel_pt_sample(struct intel_pt_queue *ptq) return err; } + if (pt->sample_ptwrites && (state->type & INTEL_PT_PTW)) { + err = intel_pt_synth_ptwrite_sample(ptq); + if (err) + return err; + } + if (!(state->type & INTEL_PT_BRANCH)) return 0; @@ -2047,6 +2267,68 @@ static int intel_pt_synth_events(struct intel_pt *pt, id += 1; } + attr.type = PERF_TYPE_SYNTH; + attr.sample_type |= PERF_SAMPLE_RAW; + + if (pt->synth_opts.ptwrites) { + attr.config = PERF_SYNTH_INTEL_PTWRITE; + err = intel_pt_synth_event(session, "ptwrite", &attr, id); + if (err) + return err; + pt->sample_ptwrites = true; + pt->ptwrites_sample_type = attr.sample_type; + pt->ptwrites_id = id; + intel_pt_set_event_name(evlist, id, "ptwrite"); + id += 1; + } + + if (pt->synth_opts.pwr_events) { + pt->sample_pwr_events = true; + pt->pwr_events_sample_type = attr.sample_type; + + attr.config = PERF_SYNTH_INTEL_CBR; + err = intel_pt_synth_event(session, "cbr", &attr, id); + if (err) + return err; + pt->cbr_id = id; + intel_pt_set_event_name(evlist, id, "cbr"); + id += 1; + } + + if (pt->synth_opts.pwr_events && (evsel->attr.config & 0x10)) { + attr.config = PERF_SYNTH_INTEL_MWAIT; + err = intel_pt_synth_event(session, "mwait", &attr, id); + if (err) + return err; + pt->mwait_id = id; + intel_pt_set_event_name(evlist, id, "mwait"); + id += 1; + + attr.config = PERF_SYNTH_INTEL_PWRE; + err = intel_pt_synth_event(session, "pwre", &attr, id); + if (err) + return err; + pt->pwre_id = id; + intel_pt_set_event_name(evlist, id, "pwre"); + id += 1; + + attr.config = PERF_SYNTH_INTEL_EXSTOP; + err = intel_pt_synth_event(session, "exstop", &attr, id); + if (err) + return err; + pt->exstop_id = id; + intel_pt_set_event_name(evlist, id, "exstop"); + id += 1; + + attr.config = PERF_SYNTH_INTEL_PWRX; + err = intel_pt_synth_event(session, "pwrx", &attr, id); + if (err) + return err; + pt->pwrx_id = id; + intel_pt_set_event_name(evlist, id, "pwrx"); + id += 1; + } + pt->synth_needs_swap = evsel->needs_swap; return 0; @@ -2313,6 +2595,7 @@ int intel_pt_process_auxtrace_info(union perf_event *event, intel_pt_log("TSC frequency %"PRIu64"\n", tsc_freq); intel_pt_log("Maximum non-turbo ratio %u\n", pt->max_non_turbo_ratio); + pt->cbr2khz = tsc_freq / pt->max_non_turbo_ratio / 1000; } if (pt->synth_opts.calls) -- cgit v1.2.3 From cc892720d85a31cc04f4c01c03d88a0eb3c437fa Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Fri, 26 May 2017 11:17:35 +0300 Subject: perf intel-pt: Add example script for power events and PTWRITE Add script intel-pt-events.py that provides an example of how to unpack the raw data for power events and PTWRITE. Signed-off-by: Adrian Hunter Cc: Andi Kleen Link: http://lkml.kernel.org/r/1495786658-18063-35-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- .../perf/scripts/python/bin/intel-pt-events-record | 13 +++ .../perf/scripts/python/bin/intel-pt-events-report | 3 + tools/perf/scripts/python/intel-pt-events.py | 128 +++++++++++++++++++++ 3 files changed, 144 insertions(+) create mode 100644 tools/perf/scripts/python/bin/intel-pt-events-record create mode 100644 tools/perf/scripts/python/bin/intel-pt-events-report create mode 100644 tools/perf/scripts/python/intel-pt-events.py diff --git a/tools/perf/scripts/python/bin/intel-pt-events-record b/tools/perf/scripts/python/bin/intel-pt-events-record new file mode 100644 index 000000000000..10fe2b6977d4 --- /dev/null +++ b/tools/perf/scripts/python/bin/intel-pt-events-record @@ -0,0 +1,13 @@ +#!/bin/bash + +# +# print Intel PT Power Events and PTWRITE. The intel_pt PMU event needs +# to be specified with appropriate config terms. +# +if ! echo "$@" | grep -q intel_pt ; then + echo "Options must include the Intel PT event e.g. -e intel_pt/pwr_evt,ptw/" + echo "and for power events it probably needs to be system wide i.e. -a option" + echo "For example: -a -e intel_pt/pwr_evt,branch=0/ sleep 1" + exit 1 +fi +perf record $@ diff --git a/tools/perf/scripts/python/bin/intel-pt-events-report b/tools/perf/scripts/python/bin/intel-pt-events-report new file mode 100644 index 000000000000..9a9c92fcd026 --- /dev/null +++ b/tools/perf/scripts/python/bin/intel-pt-events-report @@ -0,0 +1,3 @@ +#!/bin/bash +# description: print Intel PT Power Events and PTWRITE +perf script $@ -s "$PERF_EXEC_PATH"/scripts/python/intel-pt-events.py \ No newline at end of file diff --git a/tools/perf/scripts/python/intel-pt-events.py b/tools/perf/scripts/python/intel-pt-events.py new file mode 100644 index 000000000000..b19172d673af --- /dev/null +++ b/tools/perf/scripts/python/intel-pt-events.py @@ -0,0 +1,128 @@ +# intel-pt-events.py: Print Intel PT Power Events and PTWRITE +# Copyright (c) 2017, Intel Corporation. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms and conditions of the GNU General Public License, +# version 2, as published by the Free Software Foundation. +# +# This program is distributed in the hope it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +# more details. + +import os +import sys +import struct + +sys.path.append(os.environ['PERF_EXEC_PATH'] + \ + '/scripts/python/Perf-Trace-Util/lib/Perf/Trace') + +# These perf imports are not used at present +#from perf_trace_context import * +#from Core import * + +def trace_begin(): + print "Intel PT Power Events and PTWRITE" + +def trace_end(): + print "End" + +def trace_unhandled(event_name, context, event_fields_dict): + print ' '.join(['%s=%s'%(k,str(v))for k,v in sorted(event_fields_dict.items())]) + +def print_ptwrite(raw_buf): + data = struct.unpack_from("> 32) & 0x3 + print "hints: %#x extensions: %#x" % (hints, extensions), + +def print_pwre(raw_buf): + data = struct.unpack_from("> 7) & 1 + cstate = (payload >> 12) & 0xf + subcstate = (payload >> 8) & 0xf + print "hw: %u cstate: %u sub-cstate: %u" % (hw, cstate, subcstate), + +def print_exstop(raw_buf): + data = struct.unpack_from("> 4) & 0xf + wake_reason = (payload >> 8) & 0xf + print "deepest cstate: %u last cstate: %u wake reason: %#x" % (deepest_cstate, last_cstate, wake_reason), + +def print_common_start(comm, sample, name): + ts = sample["time"] + cpu = sample["cpu"] + pid = sample["pid"] + tid = sample["tid"] + print "%16s %5u/%-5u [%03u] %9u.%09u %7s:" % (comm, pid, tid, cpu, ts / 1000000000, ts %1000000000, name), + +def print_common_ip(sample, symbol, dso): + ip = sample["ip"] + print "%16x %s (%s)" % (ip, symbol, dso) + +def process_event(param_dict): + event_attr = param_dict["attr"] + sample = param_dict["sample"] + raw_buf = param_dict["raw_buf"] + comm = param_dict["comm"] + name = param_dict["ev_name"] + + # Symbol and dso info are not always resolved + if (param_dict.has_key("dso")): + dso = param_dict["dso"] + else: + dso = "[unknown]" + + if (param_dict.has_key("symbol")): + symbol = param_dict["symbol"] + else: + symbol = "[unknown]" + + if name == "ptwrite": + print_common_start(comm, sample, name) + print_ptwrite(raw_buf) + print_common_ip(sample, symbol, dso) + elif name == "cbr": + print_common_start(comm, sample, name) + print_cbr(raw_buf) + print_common_ip(sample, symbol, dso) + elif name == "mwait": + print_common_start(comm, sample, name) + print_mwait(raw_buf) + print_common_ip(sample, symbol, dso) + elif name == "pwre": + print_common_start(comm, sample, name) + print_pwre(raw_buf) + print_common_ip(sample, symbol, dso) + elif name == "exstop": + print_common_start(comm, sample, name) + print_exstop(raw_buf) + print_common_ip(sample, symbol, dso) + elif name == "pwrx": + print_common_start(comm, sample, name) + print_pwrx(raw_buf) + print_common_ip(sample, symbol, dso) -- cgit v1.2.3 From ead2bfdb85ab311bc3e1c2e55bff207aafaab096 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Fri, 26 May 2017 11:17:36 +0300 Subject: perf intel-pt: Update documentation to include new ptwrite and power events Update documentation to include new ptwrite and power events. Signed-off-by: Adrian Hunter Cc: Andi Kleen Link: http://lkml.kernel.org/r/1495786658-18063-36-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Documentation/intel-pt.txt | 42 +++++++++++++++++++++++++++++++++-- 1 file changed, 40 insertions(+), 2 deletions(-) diff --git a/tools/perf/Documentation/intel-pt.txt b/tools/perf/Documentation/intel-pt.txt index d157dee7a4ec..4b6cdbf8f935 100644 --- a/tools/perf/Documentation/intel-pt.txt +++ b/tools/perf/Documentation/intel-pt.txt @@ -108,6 +108,9 @@ approach is available to export the data to a postgresql database. Refer to script export-to-postgresql.py for more details, and to script call-graph-from-postgresql.py for an example of using the database. +There is also script intel-pt-events.py which provides an example of how to +unpack the raw data for power events and PTWRITE. + As mentioned above, it is easy to capture too much data. One way to limit the data captured is to use 'snapshot' mode which is explained further below. Refer to 'new snapshot option' and 'Intel PT modes of operation' further below. @@ -710,13 +713,15 @@ Having no option is the same as which, in turn, is the same as - --itrace=ibxe + --itrace=ibxwpe The letters are: i synthesize "instructions" events b synthesize "branches" events x synthesize "transactions" events + w synthesize "ptwrite" events + p synthesize "power" events c synthesize branches events (calls only) r synthesize branches events (returns only) e synthesize tracing error events @@ -735,7 +740,40 @@ and "r" can be combined to get calls and returns. 'flags' field can be used in perf script to determine whether the event is a tranasaction start, commit or abort. -Error events are new. They show where the decoder lost the trace. Error events +Note that "instructions", "branches" and "transactions" events depend on code +flow packets which can be disabled by using the config term "branch=0". Refer +to the config terms section above. + +"ptwrite" events record the payload of the ptwrite instruction and whether +"fup_on_ptw" was used. "ptwrite" events depend on PTWRITE packets which are +recorded only if the "ptw" config term was used. Refer to the config terms +section above. perf script "synth" field displays "ptwrite" information like +this: "ip: 0 payload: 0x123456789abcdef0" where "ip" is 1 if "fup_on_ptw" was +used. + +"Power" events correspond to power event packets and CBR (core-to-bus ratio) +packets. While CBR packets are always recorded when tracing is enabled, power +event packets are recorded only if the "pwr_evt" config term was used. Refer to +the config terms section above. The power events record information about +C-state changes, whereas CBR is indicative of CPU frequency. perf script +"event,synth" fields display information like this: + cbr: cbr: 22 freq: 2189 MHz (200%) + mwait: hints: 0x60 extensions: 0x1 + pwre: hw: 0 cstate: 2 sub-cstate: 0 + exstop: ip: 1 + pwrx: deepest cstate: 2 last cstate: 2 wake reason: 0x4 +Where: + "cbr" includes the frequency and the percentage of maximum non-turbo + "mwait" shows mwait hints and extensions + "pwre" shows C-state transitions (to a C-state deeper than C0) and + whether initiated by hardware + "exstop" indicates execution stopped and whether the IP was recorded + exactly, + "pwrx" indicates return to C0 +For more details refer to the Intel 64 and IA-32 Architectures Software +Developer Manuals. + +Error events show where the decoder lost the trace. Error events are quite important. Users must know if what they are seeing is a complete picture or not. -- cgit v1.2.3 From 38b65b0891dc129dc0a5ce148a21c481e667b395 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Fri, 26 May 2017 11:17:37 +0300 Subject: perf intel-pt: Do not use TSC packets for calculating CPU cycles to TSC CBR (core-to-bus ratio) packets provide an indication of CPU frequency. A more accurate measure can be made by counting the cycles (given by CYC packets) in between other timing packets (either MTC or TSC). Using TSC packets has at least 2 issues: 1) timing might have stopped (e.g. mwait) or 2) TSC packets within PSB+ might slip past CYC packets. For now, simply do not use TSC packets for calculating CPU cycles to TSC. That leaves the case where 2 MTC packets are used, otherwise falling back to the CBR value. Signed-off-by: Adrian Hunter Cc: Andi Kleen Link: http://lkml.kernel.org/r/1495786658-18063-37-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/intel-pt-decoder/intel-pt-decoder.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c index 5dea06289db5..aa1593ce551d 100644 --- a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c +++ b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c @@ -711,6 +711,12 @@ static int intel_pt_calc_cyc_cb(struct intel_pt_pkt_info *pkt_info) break; case INTEL_PT_TSC: + /* + * For now, do not support using TSC packets - refer + * intel_pt_calc_cyc_to_tsc(). + */ + if (data->from_mtc) + return 1; timestamp = pkt_info->packet.payload | (data->timestamp & (0xffULL << 56)); if (data->from_mtc && timestamp < data->timestamp && @@ -828,6 +834,14 @@ static void intel_pt_calc_cyc_to_tsc(struct intel_pt_decoder *decoder, .cbr_cyc_to_tsc = 0, }; + /* + * For now, do not support using TSC packets for at least the reasons: + * 1) timing might have stopped + * 2) TSC packets within PSB+ can slip against CYC packets + */ + if (!from_mtc) + return; + intel_pt_pkt_lookahead(decoder, intel_pt_calc_cyc_cb, &data); } -- cgit v1.2.3 From 644e0840ad4615e032d67adec6ee60f821b669fe Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Fri, 26 May 2017 11:17:38 +0300 Subject: perf auxtrace: Add CPU filter support Decoding auxtrace data can take a long time. To avoid decoding unnecessarily, filter auxtrace data that is collected per-cpu before it is decoded. Signed-off-by: Adrian Hunter Cc: Andi Kleen Link: http://lkml.kernel.org/r/1495786658-18063-38-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-report.c | 1 + tools/perf/builtin-script.c | 1 + tools/perf/util/auxtrace.c | 10 ++++++++++ tools/perf/util/auxtrace.h | 2 ++ 4 files changed, 14 insertions(+) diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 1174a426d090..79a33eb1a10d 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -557,6 +557,7 @@ static int __cmd_report(struct report *rep) ui__error("failed to set cpu bitmap\n"); return ret; } + session->itrace_synth_opts->cpu_bitmap = rep->cpu_bitmap; } if (rep->show_threads) { diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index b458a0cc3544..83cdc0a61fd6 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c @@ -2992,6 +2992,7 @@ int cmd_script(int argc, const char **argv) err = perf_session__cpu_bitmap(session, cpu_list, cpu_bitmap); if (err < 0) goto out_delete; + itrace_synth_opts.cpu_bitmap = cpu_bitmap; } if (!no_callchain) diff --git a/tools/perf/util/auxtrace.c b/tools/perf/util/auxtrace.c index 651c01dfa5d3..5547457566a7 100644 --- a/tools/perf/util/auxtrace.c +++ b/tools/perf/util/auxtrace.c @@ -322,6 +322,13 @@ static int auxtrace_queues__add_event_buffer(struct auxtrace_queues *queues, return auxtrace_queues__add_buffer(queues, idx, buffer); } +static bool filter_cpu(struct perf_session *session, int cpu) +{ + unsigned long *cpu_bitmap = session->itrace_synth_opts->cpu_bitmap; + + return cpu_bitmap && cpu != -1 && !test_bit(cpu, cpu_bitmap); +} + int auxtrace_queues__add_event(struct auxtrace_queues *queues, struct perf_session *session, union perf_event *event, off_t data_offset, @@ -331,6 +338,9 @@ int auxtrace_queues__add_event(struct auxtrace_queues *queues, unsigned int idx; int err; + if (filter_cpu(session, event->auxtrace.cpu)) + return 0; + buffer = zalloc(sizeof(struct auxtrace_buffer)); if (!buffer) return -ENOMEM; diff --git a/tools/perf/util/auxtrace.h b/tools/perf/util/auxtrace.h index 68e0aa40b24a..33b5e6cdf38c 100644 --- a/tools/perf/util/auxtrace.h +++ b/tools/perf/util/auxtrace.h @@ -74,6 +74,7 @@ enum itrace_period_type { * @period: 'instructions' events period * @period_type: 'instructions' events period type * @initial_skip: skip N events at the beginning. + * @cpu_bitmap: CPUs for which to synthesize events, or NULL for all */ struct itrace_synth_opts { bool set; @@ -96,6 +97,7 @@ struct itrace_synth_opts { unsigned long long period; enum itrace_period_type period_type; unsigned long initial_skip; + unsigned long *cpu_bitmap; }; /** -- cgit v1.2.3