From 0b157b1000195bc96c3180e8a1d45e1c6c0f2fa1 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 4 Sep 2020 14:11:18 -0300 Subject: perf annotate: Add 'ret' (intel disasm style) as an alias for 'retq' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When we use the 'intel' disassembler style we get 'ret' instead of 'retq', so add that as an alias. # perf annotate --disassembler-style=intel --stdio2 acpi_processor_ffh_cstate_enter > before Apply this patch and then: # perf annotate --disassembler-style=intel --stdio2 acpi_processor_ffh_cstate_enter > after # diff -u before after --- before 2020-09-04 14:10:47.768414634 -0300 +++ after 2020-09-04 14:10:59.116681039 -0300 @@ -33,7 +33,7 @@ test al,0x8 ↓ je 97 and DWORD PTR gs:[rip+0x7e548509],0x7fffffff - 97: ret + 97: ← ret mov rax,QWORD PTR gs:0x17bc0 lock or BYTE PTR [rax+0x2],0x20 mov rax,QWORD PTR [rax] # Cc: Adrian Hunter Cc: Andi Kleen Cc: David Ahern Cc: Ian Rogers Cc: Jin Yao Cc: Jiri Olsa Cc: Martin Liška Cc: Matt P. Dziubinski Cc: Namhyung Kim Cc: Ravi Bangoria Cc: Thomas Richter Cc: Wang Nan Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/arch/x86/annotate/instructions.c | 1 + 1 file changed, 1 insertion(+) (limited to 'tools/perf/arch') diff --git a/tools/perf/arch/x86/annotate/instructions.c b/tools/perf/arch/x86/annotate/instructions.c index 7eb5621c021d..24ea12ec7e02 100644 --- a/tools/perf/arch/x86/annotate/instructions.c +++ b/tools/perf/arch/x86/annotate/instructions.c @@ -110,6 +110,7 @@ static struct ins x86__instructions[] = { { .name = "por", .ops = &mov_ops, }, { .name = "rclb", .ops = &mov_ops, }, { .name = "rcll", .ops = &mov_ops, }, + { .name = "ret", .ops = &ret_ops, }, { .name = "retq", .ops = &ret_ops, }, { .name = "sbb", .ops = &mov_ops, }, { .name = "sbbl", .ops = &mov_ops, }, -- cgit v1.2.3 From f5a489dc8189bd6a6a418e408bada1ed5b9d02b1 Mon Sep 17 00:00:00 2001 From: Kajol Jain Date: Mon, 7 Sep 2020 12:11:32 +0530 Subject: perf metricgroup: Pass pmu_event structure as a parameter for arch_get_runtimeparam() This patch adds passing of pmu_event as a parameter in function 'arch_get_runtimeparam' which can be used to get details like if the event is percore/perchip. Signed-off-by: Kajol Jain Acked-by: Ian Rogers Acked-by: Jiri Olsa Cc: Alexander Shishkin Cc: Andi Kleen Cc: Jin Yao Cc: John Garry Cc: Madhavan Srinivasan Cc: Mark Rutland Cc: Namhyung Kim Cc: Paul Clarke Cc: Peter Zijlstra Cc: Ravi Bangoria Link: http://lore.kernel.org/lkml/20200907064133.75090-5-kjain@linux.ibm.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/arch/powerpc/util/header.c | 7 +++++-- tools/perf/util/metricgroup.c | 5 ++--- tools/perf/util/metricgroup.h | 3 ++- 3 files changed, 9 insertions(+), 6 deletions(-) (limited to 'tools/perf/arch') diff --git a/tools/perf/arch/powerpc/util/header.c b/tools/perf/arch/powerpc/util/header.c index 1a950171a66f..58b2d610aadb 100644 --- a/tools/perf/arch/powerpc/util/header.c +++ b/tools/perf/arch/powerpc/util/header.c @@ -40,8 +40,11 @@ get_cpuid_str(struct perf_pmu *pmu __maybe_unused) return bufp; } -int arch_get_runtimeparam(void) +int arch_get_runtimeparam(struct pmu_event *pe) { int count; - return sysfs__read_int("/devices/hv_24x7/interface/sockets", &count) < 0 ? 1 : count; + char path[PATH_MAX] = "/devices/hv_24x7/interface/"; + + atoi(pe->aggr_mode) == PerChip ? strcat(path, "sockets") : strcat(path, "coresperchip"); + return sysfs__read_int(path, &count) < 0 ? 1 : count; } diff --git a/tools/perf/util/metricgroup.c b/tools/perf/util/metricgroup.c index 5476e0767e8c..d03bac65a3c2 100644 --- a/tools/perf/util/metricgroup.c +++ b/tools/perf/util/metricgroup.c @@ -15,7 +15,6 @@ #include "rblist.h" #include #include -#include "pmu-events/pmu-events.h" #include "strlist.h" #include #include @@ -636,7 +635,7 @@ static bool metricgroup__has_constraint(struct pmu_event *pe) return false; } -int __weak arch_get_runtimeparam(void) +int __weak arch_get_runtimeparam(struct pmu_event *pe __maybe_unused) { return 1; } @@ -904,7 +903,7 @@ static int add_metric(struct list_head *metric_list, } else { int j, count; - count = arch_get_runtimeparam(); + count = arch_get_runtimeparam(pe); /* This loop is added to create multiple * events depend on count value and add diff --git a/tools/perf/util/metricgroup.h b/tools/perf/util/metricgroup.h index 62623a39cbec..491a5d78252d 100644 --- a/tools/perf/util/metricgroup.h +++ b/tools/perf/util/metricgroup.h @@ -5,6 +5,7 @@ #include #include #include +#include "pmu-events/pmu-events.h" struct evsel; struct evlist; @@ -52,6 +53,6 @@ int metricgroup__parse_groups_test(struct evlist *evlist, void metricgroup__print(bool metrics, bool groups, char *filter, bool raw, bool details); bool metricgroup__has_metric(const char *metric); -int arch_get_runtimeparam(void); +int arch_get_runtimeparam(struct pmu_event *pe __maybe_unused); void metricgroup__rblist_exit(struct rblist *metric_events); #endif -- cgit v1.2.3 From 687986bbeb668068d39a47658edf4d7a6414eefb Mon Sep 17 00:00:00 2001 From: Kan Liang Date: Fri, 11 Sep 2020 07:48:05 -0700 Subject: perf tools: Rename group to topdown The group.h/c only include TopDown group related functions. The name "group" is too generic and inaccurate. Use the name "topdown" to replace it. Move topdown related functions to a dedicated file, topdown.c. Signed-off-by: Kan Liang Acked-by: Jiri Olsa Acked-by: Namhyung Kim Cc: Andi Kleen Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lore.kernel.org/lkml/20200911144808.27603-2-kan.liang@linux.intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/arch/x86/util/Build | 2 +- tools/perf/arch/x86/util/group.c | 28 -------------------- tools/perf/arch/x86/util/topdown.c | 28 ++++++++++++++++++++ tools/perf/builtin-stat.c | 51 +----------------------------------- tools/perf/util/Build | 1 + tools/perf/util/group.h | 8 ------ tools/perf/util/topdown.c | 53 ++++++++++++++++++++++++++++++++++++++ tools/perf/util/topdown.h | 10 +++++++ 8 files changed, 94 insertions(+), 87 deletions(-) delete mode 100644 tools/perf/arch/x86/util/group.c create mode 100644 tools/perf/arch/x86/util/topdown.c delete mode 100644 tools/perf/util/group.h create mode 100644 tools/perf/util/topdown.c create mode 100644 tools/perf/util/topdown.h (limited to 'tools/perf/arch') diff --git a/tools/perf/arch/x86/util/Build b/tools/perf/arch/x86/util/Build index 47f9c56e744f..347c39b960eb 100644 --- a/tools/perf/arch/x86/util/Build +++ b/tools/perf/arch/x86/util/Build @@ -3,7 +3,7 @@ perf-y += tsc.o perf-y += pmu.o perf-y += kvm-stat.o perf-y += perf_regs.o -perf-y += group.o +perf-y += topdown.o perf-y += machine.o perf-y += event.o diff --git a/tools/perf/arch/x86/util/group.c b/tools/perf/arch/x86/util/group.c deleted file mode 100644 index e2f8034b8973..000000000000 --- a/tools/perf/arch/x86/util/group.c +++ /dev/null @@ -1,28 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#include -#include "api/fs/fs.h" -#include "util/group.h" - -/* - * Check whether we can use a group for top down. - * Without a group may get bad results due to multiplexing. - */ -bool arch_topdown_check_group(bool *warn) -{ - int n; - - if (sysctl__read_int("kernel/nmi_watchdog", &n) < 0) - return false; - if (n > 0) { - *warn = true; - return false; - } - return true; -} - -void arch_topdown_group_warn(void) -{ - fprintf(stderr, - "nmi_watchdog enabled with topdown. May give wrong results.\n" - "Disable with echo 0 > /proc/sys/kernel/nmi_watchdog\n"); -} diff --git a/tools/perf/arch/x86/util/topdown.c b/tools/perf/arch/x86/util/topdown.c new file mode 100644 index 000000000000..597e963fb3e7 --- /dev/null +++ b/tools/perf/arch/x86/util/topdown.c @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: GPL-2.0 +#include +#include "api/fs/fs.h" +#include "util/topdown.h" + +/* + * Check whether we can use a group for top down. + * Without a group may get bad results due to multiplexing. + */ +bool arch_topdown_check_group(bool *warn) +{ + int n; + + if (sysctl__read_int("kernel/nmi_watchdog", &n) < 0) + return false; + if (n > 0) { + *warn = true; + return false; + } + return true; +} + +void arch_topdown_group_warn(void) +{ + fprintf(stderr, + "nmi_watchdog enabled with topdown. May give wrong results.\n" + "Disable with echo 0 > /proc/sys/kernel/nmi_watchdog\n"); +} diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index 7f8d756d9408..a39bb28b44f9 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -56,7 +56,7 @@ #include "util/cpumap.h" #include "util/thread_map.h" #include "util/counts.h" -#include "util/group.h" +#include "util/topdown.h" #include "util/session.h" #include "util/tool.h" #include "util/string2.h" @@ -1481,55 +1481,6 @@ static int perf_stat_init_aggr_mode_file(struct perf_stat *st) return 0; } -static int topdown_filter_events(const char **attr, char **str, bool use_group) -{ - int off = 0; - int i; - int len = 0; - char *s; - - for (i = 0; attr[i]; i++) { - if (pmu_have_event("cpu", attr[i])) { - len += strlen(attr[i]) + 1; - attr[i - off] = attr[i]; - } else - off++; - } - attr[i - off] = NULL; - - *str = malloc(len + 1 + 2); - if (!*str) - return -1; - s = *str; - if (i - off == 0) { - *s = 0; - return 0; - } - if (use_group) - *s++ = '{'; - for (i = 0; attr[i]; i++) { - strcpy(s, attr[i]); - s += strlen(s); - *s++ = ','; - } - if (use_group) { - s[-1] = '}'; - *s = 0; - } else - s[-1] = 0; - return 0; -} - -__weak bool arch_topdown_check_group(bool *warn) -{ - *warn = false; - return false; -} - -__weak void arch_topdown_group_warn(void) -{ -} - /* * Add default attributes, if there were no attributes specified or * if -d/--detailed, -d -d or -d -d -d is used: diff --git a/tools/perf/util/Build b/tools/perf/util/Build index cd5e41960e64..eebbd5223cae 100644 --- a/tools/perf/util/Build +++ b/tools/perf/util/Build @@ -101,6 +101,7 @@ perf-y += call-path.o perf-y += rwsem.o perf-y += thread-stack.o perf-y += spark.o +perf-y += topdown.o perf-$(CONFIG_AUXTRACE) += auxtrace.o perf-$(CONFIG_AUXTRACE) += intel-pt-decoder/ perf-$(CONFIG_AUXTRACE) += intel-pt.o diff --git a/tools/perf/util/group.h b/tools/perf/util/group.h deleted file mode 100644 index f36c7e31780a..000000000000 --- a/tools/perf/util/group.h +++ /dev/null @@ -1,8 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef GROUP_H -#define GROUP_H 1 - -bool arch_topdown_check_group(bool *warn); -void arch_topdown_group_warn(void); - -#endif diff --git a/tools/perf/util/topdown.c b/tools/perf/util/topdown.c new file mode 100644 index 000000000000..a085b3c77c27 --- /dev/null +++ b/tools/perf/util/topdown.c @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: GPL-2.0 +#include +#include "pmu.h" +#include "topdown.h" + +int topdown_filter_events(const char **attr, char **str, bool use_group) +{ + int off = 0; + int i; + int len = 0; + char *s; + + for (i = 0; attr[i]; i++) { + if (pmu_have_event("cpu", attr[i])) { + len += strlen(attr[i]) + 1; + attr[i - off] = attr[i]; + } else + off++; + } + attr[i - off] = NULL; + + *str = malloc(len + 1 + 2); + if (!*str) + return -1; + s = *str; + if (i - off == 0) { + *s = 0; + return 0; + } + if (use_group) + *s++ = '{'; + for (i = 0; attr[i]; i++) { + strcpy(s, attr[i]); + s += strlen(s); + *s++ = ','; + } + if (use_group) { + s[-1] = '}'; + *s = 0; + } else + s[-1] = 0; + return 0; +} + +__weak bool arch_topdown_check_group(bool *warn) +{ + *warn = false; + return false; +} + +__weak void arch_topdown_group_warn(void) +{ +} diff --git a/tools/perf/util/topdown.h b/tools/perf/util/topdown.h new file mode 100644 index 000000000000..e3d70e95f4f1 --- /dev/null +++ b/tools/perf/util/topdown.h @@ -0,0 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef TOPDOWN_H +#define TOPDOWN_H 1 + +bool arch_topdown_check_group(bool *warn); +void arch_topdown_group_warn(void); + +int topdown_filter_events(const char **attr, char **str, bool use_group); + +#endif -- cgit v1.2.3 From acb65150a47c2baea5ea02fd7cb66460f7733fcd Mon Sep 17 00:00:00 2001 From: Kan Liang Date: Fri, 11 Sep 2020 07:48:06 -0700 Subject: perf record: Support sample-read topdown metric group With the hardware TopDown metrics feature, sample-read feature should be supported for a topdown group, e.g., sample a non-topdown event and read a topdown metric group. But the current perf record code errors out. For a topdown metric group, the slots event must be the leader of the group, but the leader slots event doesn't support sampling. To support sample-read the topdown metric group, use the 2nd event of the group as the "leader" for the purposes of sampling. Only the platform with Topdown metic feature supports sample-read the topdown group. Add arch_topdown_sample_read() to indicate whether the topdown group supports sample-read. Signed-off-by: Kan Liang Acked-by: Jiri Olsa Acked-by: Namhyung Kim Cc: Andi Kleen Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lore.kernel.org/lkml/20200911144808.27603-3-kan.liang@linux.intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/arch/x86/util/topdown.c | 35 +++++++++++++++++++++++++++++++++++ tools/perf/util/record.c | 3 ++- tools/perf/util/topdown.c | 5 +++++ tools/perf/util/topdown.h | 2 ++ 4 files changed, 44 insertions(+), 1 deletion(-) (limited to 'tools/perf/arch') diff --git a/tools/perf/arch/x86/util/topdown.c b/tools/perf/arch/x86/util/topdown.c index 597e963fb3e7..2f3d96aa92a5 100644 --- a/tools/perf/arch/x86/util/topdown.c +++ b/tools/perf/arch/x86/util/topdown.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 #include #include "api/fs/fs.h" +#include "util/pmu.h" #include "util/topdown.h" /* @@ -26,3 +27,37 @@ void arch_topdown_group_warn(void) "nmi_watchdog enabled with topdown. May give wrong results.\n" "Disable with echo 0 > /proc/sys/kernel/nmi_watchdog\n"); } + +#define TOPDOWN_SLOTS 0x0400 + +static bool is_topdown_slots_event(struct evsel *counter) +{ + if (!counter->pmu_name) + return false; + + if (strcmp(counter->pmu_name, "cpu")) + return false; + + if (counter->core.attr.config == TOPDOWN_SLOTS) + return true; + + return false; +} + +/* + * Check whether a topdown group supports sample-read. + * + * Only Topdown metic supports sample-read. The slots + * event must be the leader of the topdown group. + */ + +bool arch_topdown_sample_read(struct evsel *leader) +{ + if (!pmu_have_event("cpu", "slots")) + return false; + + if (is_topdown_slots_event(leader)) + return true; + + return false; +} diff --git a/tools/perf/util/record.c b/tools/perf/util/record.c index ea9aa1d7cf50..07e4b96a6625 100644 --- a/tools/perf/util/record.c +++ b/tools/perf/util/record.c @@ -14,6 +14,7 @@ #include "util/perf_api_probe.h" #include "record.h" #include "../perf-sys.h" +#include "topdown.h" /* * evsel__config_leader_sampling() uses special rules for leader sampling. @@ -24,7 +25,7 @@ static struct evsel *evsel__read_sampler(struct evsel *evsel, struct evlist *evl { struct evsel *leader = evsel->leader; - if (evsel__is_aux_event(leader)) { + if (evsel__is_aux_event(leader) || arch_topdown_sample_read(leader)) { evlist__for_each_entry(evlist, evsel) { if (evsel->leader == leader && evsel != evsel->leader) return evsel; diff --git a/tools/perf/util/topdown.c b/tools/perf/util/topdown.c index a085b3c77c27..1081b20f9891 100644 --- a/tools/perf/util/topdown.c +++ b/tools/perf/util/topdown.c @@ -51,3 +51,8 @@ __weak bool arch_topdown_check_group(bool *warn) __weak void arch_topdown_group_warn(void) { } + +__weak bool arch_topdown_sample_read(struct evsel *leader __maybe_unused) +{ + return false; +} diff --git a/tools/perf/util/topdown.h b/tools/perf/util/topdown.h index e3d70e95f4f1..2f0d0b887639 100644 --- a/tools/perf/util/topdown.h +++ b/tools/perf/util/topdown.h @@ -1,9 +1,11 @@ /* SPDX-License-Identifier: GPL-2.0 */ #ifndef TOPDOWN_H #define TOPDOWN_H 1 +#include "evsel.h" bool arch_topdown_check_group(bool *warn); void arch_topdown_group_warn(void); +bool arch_topdown_sample_read(struct evsel *leader); int topdown_filter_events(const char **attr, char **str, bool use_group); -- cgit v1.2.3 From 03fca3af51703bd77ed14c88c3d5733840a69f3f Mon Sep 17 00:00:00 2001 From: Leo Yan Date: Mon, 14 Sep 2020 19:53:06 +0800 Subject: perf tsc: Move out common functions from x86 Functions perf_read_tsc_conversion() and perf_event__synth_time_conv() should work as common functions rather than x86 specific, so move these two functions out from arch/x86 folder and place them into util/tsc.c. Since the function perf_event__synth_time_conv() will be linked in util/tsc.c, remove its weak version. Committer testing: Before/after: # perf test tsc 70: Convert perf time to TSC : Ok # # perf test -v tsc 70: Convert perf time to TSC : --- start --- test child forked, pid 8520 mmap size 528384B 1st event perf time 592110439891 tsc 2317172044331 rdtsc time 592110441915 tsc 2317172052010 2nd event perf time 592110442336 tsc 2317172053605 test child finished with 0 ---- end ---- Convert perf time to TSC: Ok # Signed-off-by: Leo Yan Tested-by: Arnaldo Carvalho de Melo Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Andi Kleen Cc: Gustavo A. R. Silva Cc: Ian Rogers Cc: Jiri Olsa Cc: John Garry Cc: Kemeng Shi Cc: linux-arm-kernel@lists.infradead.org Cc: Mark Rutland Cc: Mathieu Poirier Cc: Namhyung Kim Cc: Nick Gasson Cc: Peter Zijlstra Cc: Remi Bernon Cc: Stephane Eranian Cc: Steve Maclean Cc: Will Deacon Cc: Zou Wei Link: http://lore.kernel.org/lkml/20200914115311.2201-2-leo.yan@linaro.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/arch/x86/util/tsc.c | 73 +------------------------------------- tools/perf/util/synthetic-events.c | 8 ----- tools/perf/util/tsc.c | 71 ++++++++++++++++++++++++++++++++++++ 3 files changed, 72 insertions(+), 80 deletions(-) (limited to 'tools/perf/arch') diff --git a/tools/perf/arch/x86/util/tsc.c b/tools/perf/arch/x86/util/tsc.c index 2f55afb14e1f..559365f8fe52 100644 --- a/tools/perf/arch/x86/util/tsc.c +++ b/tools/perf/arch/x86/util/tsc.c @@ -1,45 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 -#include -#include - -#include -#include - #include -#include -#include "../../../util/debug.h" -#include "../../../util/event.h" -#include "../../../util/synthetic-events.h" -#include "../../../util/tsc.h" - -int perf_read_tsc_conversion(const struct perf_event_mmap_page *pc, - struct perf_tsc_conversion *tc) -{ - bool cap_user_time_zero; - u32 seq; - int i = 0; - - while (1) { - seq = pc->lock; - rmb(); - tc->time_mult = pc->time_mult; - tc->time_shift = pc->time_shift; - tc->time_zero = pc->time_zero; - cap_user_time_zero = pc->cap_user_time_zero; - rmb(); - if (pc->lock == seq && !(seq & 1)) - break; - if (++i > 10000) { - pr_debug("failed to get perf_event_mmap_page lock\n"); - return -EINVAL; - } - } - if (!cap_user_time_zero) - return -EOPNOTSUPP; - - return 0; -} +#include "../../../util/tsc.h" u64 rdtsc(void) { @@ -49,36 +11,3 @@ u64 rdtsc(void) return low | ((u64)high) << 32; } - -int perf_event__synth_time_conv(const struct perf_event_mmap_page *pc, - struct perf_tool *tool, - perf_event__handler_t process, - struct machine *machine) -{ - union perf_event event = { - .time_conv = { - .header = { - .type = PERF_RECORD_TIME_CONV, - .size = sizeof(struct perf_record_time_conv), - }, - }, - }; - struct perf_tsc_conversion tc; - int err; - - if (!pc) - return 0; - err = perf_read_tsc_conversion(pc, &tc); - if (err == -EOPNOTSUPP) - return 0; - if (err) - return err; - - pr_debug2("Synthesizing TSC conversion information\n"); - - event.time_conv.time_mult = tc.time_mult; - event.time_conv.time_shift = tc.time_shift; - event.time_conv.time_zero = tc.time_zero; - - return process(tool, &event, NULL, machine); -} diff --git a/tools/perf/util/synthetic-events.c b/tools/perf/util/synthetic-events.c index 89b390623b63..3ca5d9399680 100644 --- a/tools/perf/util/synthetic-events.c +++ b/tools/perf/util/synthetic-events.c @@ -2006,14 +2006,6 @@ int perf_event__synthesize_stat_events(struct perf_stat_config *config, struct p return 0; } -int __weak perf_event__synth_time_conv(const struct perf_event_mmap_page *pc __maybe_unused, - struct perf_tool *tool __maybe_unused, - perf_event__handler_t process __maybe_unused, - struct machine *machine __maybe_unused) -{ - return 0; -} - extern const struct perf_header_feature_ops feat_ops[HEADER_LAST_FEATURE]; int perf_event__synthesize_features(struct perf_tool *tool, struct perf_session *session, diff --git a/tools/perf/util/tsc.c b/tools/perf/util/tsc.c index bfa782421cbd..9e3f04ddddf8 100644 --- a/tools/perf/util/tsc.c +++ b/tools/perf/util/tsc.c @@ -1,7 +1,16 @@ // SPDX-License-Identifier: GPL-2.0 +#include + #include +#include +#include #include +#include + +#include "event.h" +#include "synthetic-events.h" +#include "debug.h" #include "tsc.h" u64 perf_time_to_tsc(u64 ns, struct perf_tsc_conversion *tc) @@ -25,6 +34,68 @@ u64 tsc_to_perf_time(u64 cyc, struct perf_tsc_conversion *tc) ((rem * tc->time_mult) >> tc->time_shift); } +int perf_read_tsc_conversion(const struct perf_event_mmap_page *pc, + struct perf_tsc_conversion *tc) +{ + bool cap_user_time_zero; + u32 seq; + int i = 0; + + while (1) { + seq = pc->lock; + rmb(); + tc->time_mult = pc->time_mult; + tc->time_shift = pc->time_shift; + tc->time_zero = pc->time_zero; + cap_user_time_zero = pc->cap_user_time_zero; + rmb(); + if (pc->lock == seq && !(seq & 1)) + break; + if (++i > 10000) { + pr_debug("failed to get perf_event_mmap_page lock\n"); + return -EINVAL; + } + } + + if (!cap_user_time_zero) + return -EOPNOTSUPP; + + return 0; +} + +int perf_event__synth_time_conv(const struct perf_event_mmap_page *pc, + struct perf_tool *tool, + perf_event__handler_t process, + struct machine *machine) +{ + union perf_event event = { + .time_conv = { + .header = { + .type = PERF_RECORD_TIME_CONV, + .size = sizeof(struct perf_record_time_conv), + }, + }, + }; + struct perf_tsc_conversion tc; + int err; + + if (!pc) + return 0; + err = perf_read_tsc_conversion(pc, &tc); + if (err == -EOPNOTSUPP) + return 0; + if (err) + return err; + + pr_debug2("Synthesizing TSC conversion information\n"); + + event.time_conv.time_mult = tc.time_mult; + event.time_conv.time_shift = tc.time_shift; + event.time_conv.time_zero = tc.time_zero; + + return process(tool, &event, NULL, machine); +} + u64 __weak rdtsc(void) { return 0; -- cgit v1.2.3 From 4979e861415d59a479c7376e16d90df83da94bb1 Mon Sep 17 00:00:00 2001 From: Leo Yan Date: Mon, 14 Sep 2020 19:53:07 +0800 Subject: perf tsc: Add rdtsc() for Arm64 The system register CNTVCT_EL0 can be used to retrieve the counter from user space. Add rdtsc() for Arm64. Signed-off-by: Leo Yan Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Andi Kleen Cc: Gustavo A. R. Silva Cc: Ian Rogers Cc: Jiri Olsa Cc: John Garry Cc: Kemeng Shi Cc: Mark Rutland Cc: Mathieu Poirier Cc: Namhyung Kim Cc: Nick Gasson Cc: Peter Zijlstra Cc: Remi Bernon Cc: Stephane Eranian Cc: Steve Maclean Cc: Will Deacon Cc: Zou Wei Cc: linux-arm-kernel@lists.infradead.org Link: http://lore.kernel.org/lkml/20200914115311.2201-3-leo.yan@linaro.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/arch/arm64/util/Build | 1 + tools/perf/arch/arm64/util/tsc.c | 21 +++++++++++++++++++++ 2 files changed, 22 insertions(+) create mode 100644 tools/perf/arch/arm64/util/tsc.c (limited to 'tools/perf/arch') diff --git a/tools/perf/arch/arm64/util/Build b/tools/perf/arch/arm64/util/Build index 5c13438c7bd4..b53294d74b01 100644 --- a/tools/perf/arch/arm64/util/Build +++ b/tools/perf/arch/arm64/util/Build @@ -1,6 +1,7 @@ perf-y += header.o perf-y += machine.o perf-y += perf_regs.o +perf-y += tsc.o perf-$(CONFIG_DWARF) += dwarf-regs.o perf-$(CONFIG_LOCAL_LIBUNWIND) += unwind-libunwind.o perf-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o diff --git a/tools/perf/arch/arm64/util/tsc.c b/tools/perf/arch/arm64/util/tsc.c new file mode 100644 index 000000000000..cc85bd9e73f1 --- /dev/null +++ b/tools/perf/arch/arm64/util/tsc.c @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include + +#include "../../../util/tsc.h" + +u64 rdtsc(void) +{ + u64 val; + + /* + * According to ARM DDI 0487F.c, from Armv8.0 to Armv8.5 inclusive, the + * system counter is at least 56 bits wide; from Armv8.6, the counter + * must be 64 bits wide. So the system counter could be less than 64 + * bits wide and it is attributed with the flag 'cap_user_time_short' + * is true. + */ + asm volatile("mrs %0, cntvct_el0" : "=r" (val)); + + return val; +} -- cgit v1.2.3