2019-05-29 07:18:02 -07:00
|
|
|
// SPDX-License-Identifier: GPL-2.0-only
|
2015-07-17 19:33:41 +03:00
|
|
|
/*
|
|
|
|
* intel_pt.c: Intel Processor Trace support
|
|
|
|
* Copyright (c) 2013-2015, Intel Corporation.
|
|
|
|
*/
|
|
|
|
|
2017-04-18 10:46:11 -03:00
|
|
|
#include <errno.h>
|
2015-07-17 19:33:41 +03:00
|
|
|
#include <stdbool.h>
|
|
|
|
#include <linux/kernel.h>
|
|
|
|
#include <linux/types.h>
|
|
|
|
#include <linux/bitops.h>
|
|
|
|
#include <linux/log2.h>
|
2019-07-04 11:32:27 -03:00
|
|
|
#include <linux/zalloc.h>
|
2015-07-17 19:33:54 +03:00
|
|
|
#include <cpuid.h>
|
2015-07-17 19:33:41 +03:00
|
|
|
|
2020-03-05 23:11:08 -08:00
|
|
|
#include "../../../util/session.h"
|
|
|
|
#include "../../../util/event.h"
|
|
|
|
#include "../../../util/evlist.h"
|
|
|
|
#include "../../../util/evsel.h"
|
|
|
|
#include "../../../util/evsel_config.h"
|
|
|
|
#include "../../../util/cpumap.h"
|
|
|
|
#include "../../../util/mmap.h"
|
2015-12-15 09:39:39 -06:00
|
|
|
#include <subcmd/parse-options.h>
|
2020-03-05 23:11:08 -08:00
|
|
|
#include "../../../util/parse-events.h"
|
|
|
|
#include "../../../util/pmu.h"
|
|
|
|
#include "../../../util/debug.h"
|
|
|
|
#include "../../../util/auxtrace.h"
|
2020-05-05 11:49:08 -03:00
|
|
|
#include "../../../util/perf_api_probe.h"
|
2020-03-05 23:11:08 -08:00
|
|
|
#include "../../../util/record.h"
|
|
|
|
#include "../../../util/target.h"
|
|
|
|
#include "../../../util/tsc.h"
|
2019-08-06 15:25:25 +02:00
|
|
|
#include <internal/lib.h> // page_size
|
2020-03-05 23:11:08 -08:00
|
|
|
#include "../../../util/intel-pt.h"
|
2015-07-17 19:33:41 +03:00
|
|
|
|
|
|
|
#define KiB(x) ((x) * 1024)
|
|
|
|
#define MiB(x) ((x) * 1024 * 1024)
|
|
|
|
#define KiB_MASK(x) (KiB(x) - 1)
|
|
|
|
#define MiB_MASK(x) (MiB(x) - 1)
|
|
|
|
|
|
|
|
#define INTEL_PT_PSB_PERIOD_NEAR 256
|
|
|
|
|
|
|
|
struct intel_pt_snapshot_ref {
|
|
|
|
void *ref_buf;
|
|
|
|
size_t ref_offset;
|
|
|
|
bool wrapped;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct intel_pt_recording {
|
|
|
|
struct auxtrace_record itr;
|
|
|
|
struct perf_pmu *intel_pt_pmu;
|
|
|
|
int have_sched_switch;
|
2019-07-21 13:23:52 +02:00
|
|
|
struct evlist *evlist;
|
2015-07-17 19:33:41 +03:00
|
|
|
bool snapshot_mode;
|
|
|
|
bool snapshot_init_done;
|
|
|
|
size_t snapshot_size;
|
|
|
|
size_t snapshot_ref_buf_size;
|
|
|
|
int snapshot_ref_cnt;
|
|
|
|
struct intel_pt_snapshot_ref *snapshot_refs;
|
2016-09-23 17:38:45 +03:00
|
|
|
size_t priv_size;
|
2015-07-17 19:33:41 +03:00
|
|
|
};
|
|
|
|
|
perf parse-events: Make add PMU verbose output clearer
On a CPU like skylakex an uncore_iio_0 PMU may alias with
uncore_iio_free_running_0. The latter PMU doesn't support fc_mask as a
parameter and so pmu_config_term fails. Typically parse_events_add_pmu
is called in a loop where if one alias succeeds errors are ignored,
however, if multiple errors occur parse_events__handle_error will
currently give a WARN_ONCE.
This change removes the WARN_ONCE in parse_events__handle_error and
makes it a pr_debug. It adds verbose messages to parse_events_add_pmu
warning that non-fatal errors may occur, while giving details on the pmu
and config terms for useful context. pmu_config_term is altered so the
failing term and pmu are present in the case of the 'unknown term' error
which makes spotting the free_running case more straightforward.
Before:
$ perf --debug verbose=3 stat -M llc_misses.pcie_read sleep 1
Using CPUID GenuineIntel-6-55-4
metric expr unc_iio_data_req_of_cpu.mem_read.part0 + unc_iio_data_req_of_cpu.mem_read.part1 + unc_iio_data_req_of_cpu.mem_read.part2 + unc_iio_data_req_of_cpu.mem_read.part3 for LLC_MISSES.PCIE_READ
found event unc_iio_data_req_of_cpu.mem_read.part0
found event unc_iio_data_req_of_cpu.mem_read.part1
found event unc_iio_data_req_of_cpu.mem_read.part2
found event unc_iio_data_req_of_cpu.mem_read.part3
metric expr unc_iio_data_req_of_cpu.mem_read.part0 + unc_iio_data_req_of_cpu.mem_read.part1 + unc_iio_data_req_of_cpu.mem_read.part2 + unc_iio_data_req_of_cpu.mem_read.part3 for LLC_MISSES.PCIE_READ
found event unc_iio_data_req_of_cpu.mem_read.part0
found event unc_iio_data_req_of_cpu.mem_read.part1
found event unc_iio_data_req_of_cpu.mem_read.part2
found event unc_iio_data_req_of_cpu.mem_read.part3
adding {unc_iio_data_req_of_cpu.mem_read.part0,unc_iio_data_req_of_cpu.mem_read.part1,unc_iio_data_req_of_cpu.mem_read.part2,unc_iio_data_req_of_cpu.mem_read.part3}:W,{unc_iio_data_req_of_cpu.mem_read.part0,unc_iio_data_req_of_cpu.mem_read.part1,unc_iio_data_req_of_cpu.mem_read.part2,unc_iio_data_req_of_cpu.mem_read.part3}:W
intel_pt default config: tsc,mtc,mtc_period=3,psb_period=3,pt,branch
WARNING: multiple event parsing errors
...
Invalid event/parameter 'fc_mask'
...
After:
$ perf --debug verbose=3 stat -M llc_misses.pcie_read sleep 1
Using CPUID GenuineIntel-6-55-4
metric expr unc_iio_data_req_of_cpu.mem_read.part0 + unc_iio_data_req_of_cpu.mem_read.part1 + unc_iio_data_req_of_cpu.mem_read.part2 + unc_iio_data_req_of_cpu.mem_read.part3 for LLC_MISSES.PCIE_READ
found event unc_iio_data_req_of_cpu.mem_read.part0
found event unc_iio_data_req_of_cpu.mem_read.part1
found event unc_iio_data_req_of_cpu.mem_read.part2
found event unc_iio_data_req_of_cpu.mem_read.part3
metric expr unc_iio_data_req_of_cpu.mem_read.part0 + unc_iio_data_req_of_cpu.mem_read.part1 + unc_iio_data_req_of_cpu.mem_read.part2 + unc_iio_data_req_of_cpu.mem_read.part3 for LLC_MISSES.PCIE_READ
found event unc_iio_data_req_of_cpu.mem_read.part0
found event unc_iio_data_req_of_cpu.mem_read.part1
found event unc_iio_data_req_of_cpu.mem_read.part2
found event unc_iio_data_req_of_cpu.mem_read.part3
adding {unc_iio_data_req_of_cpu.mem_read.part0,unc_iio_data_req_of_cpu.mem_read.part1,unc_iio_data_req_of_cpu.mem_read.part2,unc_iio_data_req_of_cpu.mem_read.part3}:W,{unc_iio_data_req_of_cpu.mem_read.part0,unc_iio_data_req_of_cpu.mem_read.part1,unc_iio_data_req_of_cpu.mem_read.part2,unc_iio_data_req_of_cpu.mem_read.part3}:W
intel_pt default config: tsc,mtc,mtc_period=3,psb_period=3,pt,branch
Attempting to add event pmu 'uncore_iio_free_running_5' with 'unc_iio_data_req_of_cpu.mem_read.part0,' that may result in non-fatal errors
After aliases, add event pmu 'uncore_iio_free_running_5' with 'fc_mask,ch_mask,umask,event,' that may result in non-fatal errors
Attempting to add event pmu 'uncore_iio_free_running_3' with 'unc_iio_data_req_of_cpu.mem_read.part0,' that may result in non-fatal errors
After aliases, add event pmu 'uncore_iio_free_running_3' with 'fc_mask,ch_mask,umask,event,' that may result in non-fatal errors
Attempting to add event pmu 'uncore_iio_free_running_1' with 'unc_iio_data_req_of_cpu.mem_read.part0,' that may result in non-fatal errors
After aliases, add event pmu 'uncore_iio_free_running_1' with 'fc_mask,ch_mask,umask,event,' that may result in non-fatal errors
Multiple errors dropping message: unknown term 'fc_mask' for pmu 'uncore_iio_free_running_3' (valid terms: event,umask,config,config1,config2,name,period,percore)
...
So before you see a 'WARNING: multiple event parsing errors' and
'Invalid event/parameter'. After you see 'Attempting... that may result
in non-fatal errors' then 'Multiple errors...' with details that
'fc_mask' wasn't known to a free running counter. While not completely
clean, this makes it clearer that an error hasn't really occurred.
v2. addresses review feedback from Jiri Olsa <jolsa@redhat.com>.
Signed-off-by: Ian Rogers <irogers@google.com>
Reviewed-by: Andi Kleen <ak@linux.intel.com>
Acked-by: Jiri Olsa <jolsa@redhat.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Jin Yao <yao.jin@linux.intel.com>
Cc: John Garry <john.garry@huawei.com>
Cc: Kan Liang <kan.liang@linux.intel.com>
Cc: Leo Yan <leo.yan@linaro.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Mathieu Poirier <mathieu.poirier@linaro.org>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stephane Eranian <eranian@google.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Link: http://lore.kernel.org/lkml/20200513220635.54700-1-irogers@google.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2020-05-13 15:06:35 -07:00
|
|
|
static int intel_pt_parse_terms_with_default(const char *pmu_name,
|
|
|
|
struct list_head *formats,
|
2015-07-17 19:33:41 +03:00
|
|
|
const char *str,
|
|
|
|
u64 *config)
|
|
|
|
{
|
|
|
|
struct list_head *terms;
|
|
|
|
struct perf_event_attr attr = { .size = 0, };
|
|
|
|
int err;
|
|
|
|
|
|
|
|
terms = malloc(sizeof(struct list_head));
|
|
|
|
if (!terms)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
INIT_LIST_HEAD(terms);
|
|
|
|
|
|
|
|
err = parse_events_terms(terms, str);
|
|
|
|
if (err)
|
|
|
|
goto out_free;
|
|
|
|
|
|
|
|
attr.config = *config;
|
perf parse-events: Make add PMU verbose output clearer
On a CPU like skylakex an uncore_iio_0 PMU may alias with
uncore_iio_free_running_0. The latter PMU doesn't support fc_mask as a
parameter and so pmu_config_term fails. Typically parse_events_add_pmu
is called in a loop where if one alias succeeds errors are ignored,
however, if multiple errors occur parse_events__handle_error will
currently give a WARN_ONCE.
This change removes the WARN_ONCE in parse_events__handle_error and
makes it a pr_debug. It adds verbose messages to parse_events_add_pmu
warning that non-fatal errors may occur, while giving details on the pmu
and config terms for useful context. pmu_config_term is altered so the
failing term and pmu are present in the case of the 'unknown term' error
which makes spotting the free_running case more straightforward.
Before:
$ perf --debug verbose=3 stat -M llc_misses.pcie_read sleep 1
Using CPUID GenuineIntel-6-55-4
metric expr unc_iio_data_req_of_cpu.mem_read.part0 + unc_iio_data_req_of_cpu.mem_read.part1 + unc_iio_data_req_of_cpu.mem_read.part2 + unc_iio_data_req_of_cpu.mem_read.part3 for LLC_MISSES.PCIE_READ
found event unc_iio_data_req_of_cpu.mem_read.part0
found event unc_iio_data_req_of_cpu.mem_read.part1
found event unc_iio_data_req_of_cpu.mem_read.part2
found event unc_iio_data_req_of_cpu.mem_read.part3
metric expr unc_iio_data_req_of_cpu.mem_read.part0 + unc_iio_data_req_of_cpu.mem_read.part1 + unc_iio_data_req_of_cpu.mem_read.part2 + unc_iio_data_req_of_cpu.mem_read.part3 for LLC_MISSES.PCIE_READ
found event unc_iio_data_req_of_cpu.mem_read.part0
found event unc_iio_data_req_of_cpu.mem_read.part1
found event unc_iio_data_req_of_cpu.mem_read.part2
found event unc_iio_data_req_of_cpu.mem_read.part3
adding {unc_iio_data_req_of_cpu.mem_read.part0,unc_iio_data_req_of_cpu.mem_read.part1,unc_iio_data_req_of_cpu.mem_read.part2,unc_iio_data_req_of_cpu.mem_read.part3}:W,{unc_iio_data_req_of_cpu.mem_read.part0,unc_iio_data_req_of_cpu.mem_read.part1,unc_iio_data_req_of_cpu.mem_read.part2,unc_iio_data_req_of_cpu.mem_read.part3}:W
intel_pt default config: tsc,mtc,mtc_period=3,psb_period=3,pt,branch
WARNING: multiple event parsing errors
...
Invalid event/parameter 'fc_mask'
...
After:
$ perf --debug verbose=3 stat -M llc_misses.pcie_read sleep 1
Using CPUID GenuineIntel-6-55-4
metric expr unc_iio_data_req_of_cpu.mem_read.part0 + unc_iio_data_req_of_cpu.mem_read.part1 + unc_iio_data_req_of_cpu.mem_read.part2 + unc_iio_data_req_of_cpu.mem_read.part3 for LLC_MISSES.PCIE_READ
found event unc_iio_data_req_of_cpu.mem_read.part0
found event unc_iio_data_req_of_cpu.mem_read.part1
found event unc_iio_data_req_of_cpu.mem_read.part2
found event unc_iio_data_req_of_cpu.mem_read.part3
metric expr unc_iio_data_req_of_cpu.mem_read.part0 + unc_iio_data_req_of_cpu.mem_read.part1 + unc_iio_data_req_of_cpu.mem_read.part2 + unc_iio_data_req_of_cpu.mem_read.part3 for LLC_MISSES.PCIE_READ
found event unc_iio_data_req_of_cpu.mem_read.part0
found event unc_iio_data_req_of_cpu.mem_read.part1
found event unc_iio_data_req_of_cpu.mem_read.part2
found event unc_iio_data_req_of_cpu.mem_read.part3
adding {unc_iio_data_req_of_cpu.mem_read.part0,unc_iio_data_req_of_cpu.mem_read.part1,unc_iio_data_req_of_cpu.mem_read.part2,unc_iio_data_req_of_cpu.mem_read.part3}:W,{unc_iio_data_req_of_cpu.mem_read.part0,unc_iio_data_req_of_cpu.mem_read.part1,unc_iio_data_req_of_cpu.mem_read.part2,unc_iio_data_req_of_cpu.mem_read.part3}:W
intel_pt default config: tsc,mtc,mtc_period=3,psb_period=3,pt,branch
Attempting to add event pmu 'uncore_iio_free_running_5' with 'unc_iio_data_req_of_cpu.mem_read.part0,' that may result in non-fatal errors
After aliases, add event pmu 'uncore_iio_free_running_5' with 'fc_mask,ch_mask,umask,event,' that may result in non-fatal errors
Attempting to add event pmu 'uncore_iio_free_running_3' with 'unc_iio_data_req_of_cpu.mem_read.part0,' that may result in non-fatal errors
After aliases, add event pmu 'uncore_iio_free_running_3' with 'fc_mask,ch_mask,umask,event,' that may result in non-fatal errors
Attempting to add event pmu 'uncore_iio_free_running_1' with 'unc_iio_data_req_of_cpu.mem_read.part0,' that may result in non-fatal errors
After aliases, add event pmu 'uncore_iio_free_running_1' with 'fc_mask,ch_mask,umask,event,' that may result in non-fatal errors
Multiple errors dropping message: unknown term 'fc_mask' for pmu 'uncore_iio_free_running_3' (valid terms: event,umask,config,config1,config2,name,period,percore)
...
So before you see a 'WARNING: multiple event parsing errors' and
'Invalid event/parameter'. After you see 'Attempting... that may result
in non-fatal errors' then 'Multiple errors...' with details that
'fc_mask' wasn't known to a free running counter. While not completely
clean, this makes it clearer that an error hasn't really occurred.
v2. addresses review feedback from Jiri Olsa <jolsa@redhat.com>.
Signed-off-by: Ian Rogers <irogers@google.com>
Reviewed-by: Andi Kleen <ak@linux.intel.com>
Acked-by: Jiri Olsa <jolsa@redhat.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Jin Yao <yao.jin@linux.intel.com>
Cc: John Garry <john.garry@huawei.com>
Cc: Kan Liang <kan.liang@linux.intel.com>
Cc: Leo Yan <leo.yan@linaro.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Mathieu Poirier <mathieu.poirier@linaro.org>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stephane Eranian <eranian@google.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Link: http://lore.kernel.org/lkml/20200513220635.54700-1-irogers@google.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2020-05-13 15:06:35 -07:00
|
|
|
err = perf_pmu__config_terms(pmu_name, formats, &attr, terms, true,
|
|
|
|
NULL);
|
2015-07-17 19:33:41 +03:00
|
|
|
if (err)
|
|
|
|
goto out_free;
|
|
|
|
|
|
|
|
*config = attr.config;
|
|
|
|
out_free:
|
2016-02-12 17:09:17 -03:00
|
|
|
parse_events_terms__delete(terms);
|
2015-07-17 19:33:41 +03:00
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
perf parse-events: Make add PMU verbose output clearer
On a CPU like skylakex an uncore_iio_0 PMU may alias with
uncore_iio_free_running_0. The latter PMU doesn't support fc_mask as a
parameter and so pmu_config_term fails. Typically parse_events_add_pmu
is called in a loop where if one alias succeeds errors are ignored,
however, if multiple errors occur parse_events__handle_error will
currently give a WARN_ONCE.
This change removes the WARN_ONCE in parse_events__handle_error and
makes it a pr_debug. It adds verbose messages to parse_events_add_pmu
warning that non-fatal errors may occur, while giving details on the pmu
and config terms for useful context. pmu_config_term is altered so the
failing term and pmu are present in the case of the 'unknown term' error
which makes spotting the free_running case more straightforward.
Before:
$ perf --debug verbose=3 stat -M llc_misses.pcie_read sleep 1
Using CPUID GenuineIntel-6-55-4
metric expr unc_iio_data_req_of_cpu.mem_read.part0 + unc_iio_data_req_of_cpu.mem_read.part1 + unc_iio_data_req_of_cpu.mem_read.part2 + unc_iio_data_req_of_cpu.mem_read.part3 for LLC_MISSES.PCIE_READ
found event unc_iio_data_req_of_cpu.mem_read.part0
found event unc_iio_data_req_of_cpu.mem_read.part1
found event unc_iio_data_req_of_cpu.mem_read.part2
found event unc_iio_data_req_of_cpu.mem_read.part3
metric expr unc_iio_data_req_of_cpu.mem_read.part0 + unc_iio_data_req_of_cpu.mem_read.part1 + unc_iio_data_req_of_cpu.mem_read.part2 + unc_iio_data_req_of_cpu.mem_read.part3 for LLC_MISSES.PCIE_READ
found event unc_iio_data_req_of_cpu.mem_read.part0
found event unc_iio_data_req_of_cpu.mem_read.part1
found event unc_iio_data_req_of_cpu.mem_read.part2
found event unc_iio_data_req_of_cpu.mem_read.part3
adding {unc_iio_data_req_of_cpu.mem_read.part0,unc_iio_data_req_of_cpu.mem_read.part1,unc_iio_data_req_of_cpu.mem_read.part2,unc_iio_data_req_of_cpu.mem_read.part3}:W,{unc_iio_data_req_of_cpu.mem_read.part0,unc_iio_data_req_of_cpu.mem_read.part1,unc_iio_data_req_of_cpu.mem_read.part2,unc_iio_data_req_of_cpu.mem_read.part3}:W
intel_pt default config: tsc,mtc,mtc_period=3,psb_period=3,pt,branch
WARNING: multiple event parsing errors
...
Invalid event/parameter 'fc_mask'
...
After:
$ perf --debug verbose=3 stat -M llc_misses.pcie_read sleep 1
Using CPUID GenuineIntel-6-55-4
metric expr unc_iio_data_req_of_cpu.mem_read.part0 + unc_iio_data_req_of_cpu.mem_read.part1 + unc_iio_data_req_of_cpu.mem_read.part2 + unc_iio_data_req_of_cpu.mem_read.part3 for LLC_MISSES.PCIE_READ
found event unc_iio_data_req_of_cpu.mem_read.part0
found event unc_iio_data_req_of_cpu.mem_read.part1
found event unc_iio_data_req_of_cpu.mem_read.part2
found event unc_iio_data_req_of_cpu.mem_read.part3
metric expr unc_iio_data_req_of_cpu.mem_read.part0 + unc_iio_data_req_of_cpu.mem_read.part1 + unc_iio_data_req_of_cpu.mem_read.part2 + unc_iio_data_req_of_cpu.mem_read.part3 for LLC_MISSES.PCIE_READ
found event unc_iio_data_req_of_cpu.mem_read.part0
found event unc_iio_data_req_of_cpu.mem_read.part1
found event unc_iio_data_req_of_cpu.mem_read.part2
found event unc_iio_data_req_of_cpu.mem_read.part3
adding {unc_iio_data_req_of_cpu.mem_read.part0,unc_iio_data_req_of_cpu.mem_read.part1,unc_iio_data_req_of_cpu.mem_read.part2,unc_iio_data_req_of_cpu.mem_read.part3}:W,{unc_iio_data_req_of_cpu.mem_read.part0,unc_iio_data_req_of_cpu.mem_read.part1,unc_iio_data_req_of_cpu.mem_read.part2,unc_iio_data_req_of_cpu.mem_read.part3}:W
intel_pt default config: tsc,mtc,mtc_period=3,psb_period=3,pt,branch
Attempting to add event pmu 'uncore_iio_free_running_5' with 'unc_iio_data_req_of_cpu.mem_read.part0,' that may result in non-fatal errors
After aliases, add event pmu 'uncore_iio_free_running_5' with 'fc_mask,ch_mask,umask,event,' that may result in non-fatal errors
Attempting to add event pmu 'uncore_iio_free_running_3' with 'unc_iio_data_req_of_cpu.mem_read.part0,' that may result in non-fatal errors
After aliases, add event pmu 'uncore_iio_free_running_3' with 'fc_mask,ch_mask,umask,event,' that may result in non-fatal errors
Attempting to add event pmu 'uncore_iio_free_running_1' with 'unc_iio_data_req_of_cpu.mem_read.part0,' that may result in non-fatal errors
After aliases, add event pmu 'uncore_iio_free_running_1' with 'fc_mask,ch_mask,umask,event,' that may result in non-fatal errors
Multiple errors dropping message: unknown term 'fc_mask' for pmu 'uncore_iio_free_running_3' (valid terms: event,umask,config,config1,config2,name,period,percore)
...
So before you see a 'WARNING: multiple event parsing errors' and
'Invalid event/parameter'. After you see 'Attempting... that may result
in non-fatal errors' then 'Multiple errors...' with details that
'fc_mask' wasn't known to a free running counter. While not completely
clean, this makes it clearer that an error hasn't really occurred.
v2. addresses review feedback from Jiri Olsa <jolsa@redhat.com>.
Signed-off-by: Ian Rogers <irogers@google.com>
Reviewed-by: Andi Kleen <ak@linux.intel.com>
Acked-by: Jiri Olsa <jolsa@redhat.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Jin Yao <yao.jin@linux.intel.com>
Cc: John Garry <john.garry@huawei.com>
Cc: Kan Liang <kan.liang@linux.intel.com>
Cc: Leo Yan <leo.yan@linaro.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Mathieu Poirier <mathieu.poirier@linaro.org>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stephane Eranian <eranian@google.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Link: http://lore.kernel.org/lkml/20200513220635.54700-1-irogers@google.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2020-05-13 15:06:35 -07:00
|
|
|
static int intel_pt_parse_terms(const char *pmu_name, struct list_head *formats,
|
|
|
|
const char *str, u64 *config)
|
2015-07-17 19:33:41 +03:00
|
|
|
{
|
|
|
|
*config = 0;
|
perf parse-events: Make add PMU verbose output clearer
On a CPU like skylakex an uncore_iio_0 PMU may alias with
uncore_iio_free_running_0. The latter PMU doesn't support fc_mask as a
parameter and so pmu_config_term fails. Typically parse_events_add_pmu
is called in a loop where if one alias succeeds errors are ignored,
however, if multiple errors occur parse_events__handle_error will
currently give a WARN_ONCE.
This change removes the WARN_ONCE in parse_events__handle_error and
makes it a pr_debug. It adds verbose messages to parse_events_add_pmu
warning that non-fatal errors may occur, while giving details on the pmu
and config terms for useful context. pmu_config_term is altered so the
failing term and pmu are present in the case of the 'unknown term' error
which makes spotting the free_running case more straightforward.
Before:
$ perf --debug verbose=3 stat -M llc_misses.pcie_read sleep 1
Using CPUID GenuineIntel-6-55-4
metric expr unc_iio_data_req_of_cpu.mem_read.part0 + unc_iio_data_req_of_cpu.mem_read.part1 + unc_iio_data_req_of_cpu.mem_read.part2 + unc_iio_data_req_of_cpu.mem_read.part3 for LLC_MISSES.PCIE_READ
found event unc_iio_data_req_of_cpu.mem_read.part0
found event unc_iio_data_req_of_cpu.mem_read.part1
found event unc_iio_data_req_of_cpu.mem_read.part2
found event unc_iio_data_req_of_cpu.mem_read.part3
metric expr unc_iio_data_req_of_cpu.mem_read.part0 + unc_iio_data_req_of_cpu.mem_read.part1 + unc_iio_data_req_of_cpu.mem_read.part2 + unc_iio_data_req_of_cpu.mem_read.part3 for LLC_MISSES.PCIE_READ
found event unc_iio_data_req_of_cpu.mem_read.part0
found event unc_iio_data_req_of_cpu.mem_read.part1
found event unc_iio_data_req_of_cpu.mem_read.part2
found event unc_iio_data_req_of_cpu.mem_read.part3
adding {unc_iio_data_req_of_cpu.mem_read.part0,unc_iio_data_req_of_cpu.mem_read.part1,unc_iio_data_req_of_cpu.mem_read.part2,unc_iio_data_req_of_cpu.mem_read.part3}:W,{unc_iio_data_req_of_cpu.mem_read.part0,unc_iio_data_req_of_cpu.mem_read.part1,unc_iio_data_req_of_cpu.mem_read.part2,unc_iio_data_req_of_cpu.mem_read.part3}:W
intel_pt default config: tsc,mtc,mtc_period=3,psb_period=3,pt,branch
WARNING: multiple event parsing errors
...
Invalid event/parameter 'fc_mask'
...
After:
$ perf --debug verbose=3 stat -M llc_misses.pcie_read sleep 1
Using CPUID GenuineIntel-6-55-4
metric expr unc_iio_data_req_of_cpu.mem_read.part0 + unc_iio_data_req_of_cpu.mem_read.part1 + unc_iio_data_req_of_cpu.mem_read.part2 + unc_iio_data_req_of_cpu.mem_read.part3 for LLC_MISSES.PCIE_READ
found event unc_iio_data_req_of_cpu.mem_read.part0
found event unc_iio_data_req_of_cpu.mem_read.part1
found event unc_iio_data_req_of_cpu.mem_read.part2
found event unc_iio_data_req_of_cpu.mem_read.part3
metric expr unc_iio_data_req_of_cpu.mem_read.part0 + unc_iio_data_req_of_cpu.mem_read.part1 + unc_iio_data_req_of_cpu.mem_read.part2 + unc_iio_data_req_of_cpu.mem_read.part3 for LLC_MISSES.PCIE_READ
found event unc_iio_data_req_of_cpu.mem_read.part0
found event unc_iio_data_req_of_cpu.mem_read.part1
found event unc_iio_data_req_of_cpu.mem_read.part2
found event unc_iio_data_req_of_cpu.mem_read.part3
adding {unc_iio_data_req_of_cpu.mem_read.part0,unc_iio_data_req_of_cpu.mem_read.part1,unc_iio_data_req_of_cpu.mem_read.part2,unc_iio_data_req_of_cpu.mem_read.part3}:W,{unc_iio_data_req_of_cpu.mem_read.part0,unc_iio_data_req_of_cpu.mem_read.part1,unc_iio_data_req_of_cpu.mem_read.part2,unc_iio_data_req_of_cpu.mem_read.part3}:W
intel_pt default config: tsc,mtc,mtc_period=3,psb_period=3,pt,branch
Attempting to add event pmu 'uncore_iio_free_running_5' with 'unc_iio_data_req_of_cpu.mem_read.part0,' that may result in non-fatal errors
After aliases, add event pmu 'uncore_iio_free_running_5' with 'fc_mask,ch_mask,umask,event,' that may result in non-fatal errors
Attempting to add event pmu 'uncore_iio_free_running_3' with 'unc_iio_data_req_of_cpu.mem_read.part0,' that may result in non-fatal errors
After aliases, add event pmu 'uncore_iio_free_running_3' with 'fc_mask,ch_mask,umask,event,' that may result in non-fatal errors
Attempting to add event pmu 'uncore_iio_free_running_1' with 'unc_iio_data_req_of_cpu.mem_read.part0,' that may result in non-fatal errors
After aliases, add event pmu 'uncore_iio_free_running_1' with 'fc_mask,ch_mask,umask,event,' that may result in non-fatal errors
Multiple errors dropping message: unknown term 'fc_mask' for pmu 'uncore_iio_free_running_3' (valid terms: event,umask,config,config1,config2,name,period,percore)
...
So before you see a 'WARNING: multiple event parsing errors' and
'Invalid event/parameter'. After you see 'Attempting... that may result
in non-fatal errors' then 'Multiple errors...' with details that
'fc_mask' wasn't known to a free running counter. While not completely
clean, this makes it clearer that an error hasn't really occurred.
v2. addresses review feedback from Jiri Olsa <jolsa@redhat.com>.
Signed-off-by: Ian Rogers <irogers@google.com>
Reviewed-by: Andi Kleen <ak@linux.intel.com>
Acked-by: Jiri Olsa <jolsa@redhat.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Jin Yao <yao.jin@linux.intel.com>
Cc: John Garry <john.garry@huawei.com>
Cc: Kan Liang <kan.liang@linux.intel.com>
Cc: Leo Yan <leo.yan@linaro.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Mathieu Poirier <mathieu.poirier@linaro.org>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stephane Eranian <eranian@google.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Link: http://lore.kernel.org/lkml/20200513220635.54700-1-irogers@google.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2020-05-13 15:06:35 -07:00
|
|
|
return intel_pt_parse_terms_with_default(pmu_name, formats, str,
|
|
|
|
config);
|
2015-07-17 19:33:41 +03:00
|
|
|
}
|
|
|
|
|
2015-07-17 19:33:52 +03:00
|
|
|
static u64 intel_pt_masked_bits(u64 mask, u64 bits)
|
2015-07-17 19:33:41 +03:00
|
|
|
{
|
2015-07-17 19:33:52 +03:00
|
|
|
const u64 top_bit = 1ULL << 63;
|
|
|
|
u64 res = 0;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < 64; i++) {
|
|
|
|
if (mask & top_bit) {
|
|
|
|
res <<= 1;
|
|
|
|
if (bits & top_bit)
|
|
|
|
res |= 1;
|
|
|
|
}
|
|
|
|
mask <<= 1;
|
|
|
|
bits <<= 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int intel_pt_read_config(struct perf_pmu *intel_pt_pmu, const char *str,
|
2019-07-21 13:23:52 +02:00
|
|
|
struct evlist *evlist, u64 *res)
|
2015-07-17 19:33:52 +03:00
|
|
|
{
|
2019-07-21 13:23:51 +02:00
|
|
|
struct evsel *evsel;
|
2015-07-17 19:33:52 +03:00
|
|
|
u64 mask;
|
|
|
|
|
|
|
|
*res = 0;
|
|
|
|
|
|
|
|
mask = perf_pmu__format_bits(&intel_pt_pmu->format, str);
|
|
|
|
if (!mask)
|
|
|
|
return -EINVAL;
|
|
|
|
|
2016-06-23 11:26:15 -03:00
|
|
|
evlist__for_each_entry(evlist, evsel) {
|
2019-07-21 13:24:29 +02:00
|
|
|
if (evsel->core.attr.type == intel_pt_pmu->type) {
|
|
|
|
*res = intel_pt_masked_bits(mask, evsel->core.attr.config);
|
2015-07-17 19:33:52 +03:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static size_t intel_pt_psb_period(struct perf_pmu *intel_pt_pmu,
|
2019-07-21 13:23:52 +02:00
|
|
|
struct evlist *evlist)
|
2015-07-17 19:33:52 +03:00
|
|
|
{
|
|
|
|
u64 val;
|
|
|
|
int err, topa_multiple_entries;
|
|
|
|
size_t psb_period;
|
|
|
|
|
|
|
|
if (perf_pmu__scan_file(intel_pt_pmu, "caps/topa_multiple_entries",
|
|
|
|
"%d", &topa_multiple_entries) != 1)
|
|
|
|
topa_multiple_entries = 0;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Use caps/topa_multiple_entries to indicate early hardware that had
|
|
|
|
* extra frequent PSBs.
|
|
|
|
*/
|
|
|
|
if (!topa_multiple_entries) {
|
|
|
|
psb_period = 256;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
err = intel_pt_read_config(intel_pt_pmu, "psb_period", evlist, &val);
|
|
|
|
if (err)
|
|
|
|
val = 0;
|
|
|
|
|
|
|
|
psb_period = 1 << (val + 11);
|
|
|
|
out:
|
|
|
|
pr_debug2("%s psb_period %zu\n", intel_pt_pmu->name, psb_period);
|
|
|
|
return psb_period;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int intel_pt_pick_bit(int bits, int target)
|
|
|
|
{
|
|
|
|
int pos, pick = -1;
|
|
|
|
|
|
|
|
for (pos = 0; bits; bits >>= 1, pos++) {
|
|
|
|
if (bits & 1) {
|
|
|
|
if (pos <= target || pick < 0)
|
|
|
|
pick = pos;
|
|
|
|
if (pos >= target)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return pick;
|
2015-07-17 19:33:41 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
static u64 intel_pt_default_config(struct perf_pmu *intel_pt_pmu)
|
|
|
|
{
|
2015-07-17 19:33:52 +03:00
|
|
|
char buf[256];
|
2015-07-17 19:33:56 +03:00
|
|
|
int mtc, mtc_periods = 0, mtc_period;
|
2015-07-17 19:33:52 +03:00
|
|
|
int psb_cyc, psb_periods, psb_period;
|
|
|
|
int pos = 0;
|
2015-07-17 19:33:41 +03:00
|
|
|
u64 config;
|
2017-05-26 11:17:12 +03:00
|
|
|
char c;
|
2015-07-17 19:33:41 +03:00
|
|
|
|
2015-07-17 19:33:52 +03:00
|
|
|
pos += scnprintf(buf + pos, sizeof(buf) - pos, "tsc");
|
|
|
|
|
2015-07-17 19:33:56 +03:00
|
|
|
if (perf_pmu__scan_file(intel_pt_pmu, "caps/mtc", "%d",
|
|
|
|
&mtc) != 1)
|
|
|
|
mtc = 1;
|
|
|
|
|
|
|
|
if (mtc) {
|
|
|
|
if (perf_pmu__scan_file(intel_pt_pmu, "caps/mtc_periods", "%x",
|
|
|
|
&mtc_periods) != 1)
|
|
|
|
mtc_periods = 0;
|
|
|
|
if (mtc_periods) {
|
|
|
|
mtc_period = intel_pt_pick_bit(mtc_periods, 3);
|
|
|
|
pos += scnprintf(buf + pos, sizeof(buf) - pos,
|
|
|
|
",mtc,mtc_period=%d", mtc_period);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-07-17 19:33:52 +03:00
|
|
|
if (perf_pmu__scan_file(intel_pt_pmu, "caps/psb_cyc", "%d",
|
|
|
|
&psb_cyc) != 1)
|
|
|
|
psb_cyc = 1;
|
|
|
|
|
2015-07-17 19:33:56 +03:00
|
|
|
if (psb_cyc && mtc_periods) {
|
2015-07-17 19:33:52 +03:00
|
|
|
if (perf_pmu__scan_file(intel_pt_pmu, "caps/psb_periods", "%x",
|
|
|
|
&psb_periods) != 1)
|
|
|
|
psb_periods = 0;
|
|
|
|
if (psb_periods) {
|
|
|
|
psb_period = intel_pt_pick_bit(psb_periods, 3);
|
|
|
|
pos += scnprintf(buf + pos, sizeof(buf) - pos,
|
|
|
|
",psb_period=%d", psb_period);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-05-26 11:17:12 +03:00
|
|
|
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");
|
|
|
|
|
2015-07-17 19:33:52 +03:00
|
|
|
pr_debug2("%s default config: %s\n", intel_pt_pmu->name, buf);
|
|
|
|
|
perf parse-events: Make add PMU verbose output clearer
On a CPU like skylakex an uncore_iio_0 PMU may alias with
uncore_iio_free_running_0. The latter PMU doesn't support fc_mask as a
parameter and so pmu_config_term fails. Typically parse_events_add_pmu
is called in a loop where if one alias succeeds errors are ignored,
however, if multiple errors occur parse_events__handle_error will
currently give a WARN_ONCE.
This change removes the WARN_ONCE in parse_events__handle_error and
makes it a pr_debug. It adds verbose messages to parse_events_add_pmu
warning that non-fatal errors may occur, while giving details on the pmu
and config terms for useful context. pmu_config_term is altered so the
failing term and pmu are present in the case of the 'unknown term' error
which makes spotting the free_running case more straightforward.
Before:
$ perf --debug verbose=3 stat -M llc_misses.pcie_read sleep 1
Using CPUID GenuineIntel-6-55-4
metric expr unc_iio_data_req_of_cpu.mem_read.part0 + unc_iio_data_req_of_cpu.mem_read.part1 + unc_iio_data_req_of_cpu.mem_read.part2 + unc_iio_data_req_of_cpu.mem_read.part3 for LLC_MISSES.PCIE_READ
found event unc_iio_data_req_of_cpu.mem_read.part0
found event unc_iio_data_req_of_cpu.mem_read.part1
found event unc_iio_data_req_of_cpu.mem_read.part2
found event unc_iio_data_req_of_cpu.mem_read.part3
metric expr unc_iio_data_req_of_cpu.mem_read.part0 + unc_iio_data_req_of_cpu.mem_read.part1 + unc_iio_data_req_of_cpu.mem_read.part2 + unc_iio_data_req_of_cpu.mem_read.part3 for LLC_MISSES.PCIE_READ
found event unc_iio_data_req_of_cpu.mem_read.part0
found event unc_iio_data_req_of_cpu.mem_read.part1
found event unc_iio_data_req_of_cpu.mem_read.part2
found event unc_iio_data_req_of_cpu.mem_read.part3
adding {unc_iio_data_req_of_cpu.mem_read.part0,unc_iio_data_req_of_cpu.mem_read.part1,unc_iio_data_req_of_cpu.mem_read.part2,unc_iio_data_req_of_cpu.mem_read.part3}:W,{unc_iio_data_req_of_cpu.mem_read.part0,unc_iio_data_req_of_cpu.mem_read.part1,unc_iio_data_req_of_cpu.mem_read.part2,unc_iio_data_req_of_cpu.mem_read.part3}:W
intel_pt default config: tsc,mtc,mtc_period=3,psb_period=3,pt,branch
WARNING: multiple event parsing errors
...
Invalid event/parameter 'fc_mask'
...
After:
$ perf --debug verbose=3 stat -M llc_misses.pcie_read sleep 1
Using CPUID GenuineIntel-6-55-4
metric expr unc_iio_data_req_of_cpu.mem_read.part0 + unc_iio_data_req_of_cpu.mem_read.part1 + unc_iio_data_req_of_cpu.mem_read.part2 + unc_iio_data_req_of_cpu.mem_read.part3 for LLC_MISSES.PCIE_READ
found event unc_iio_data_req_of_cpu.mem_read.part0
found event unc_iio_data_req_of_cpu.mem_read.part1
found event unc_iio_data_req_of_cpu.mem_read.part2
found event unc_iio_data_req_of_cpu.mem_read.part3
metric expr unc_iio_data_req_of_cpu.mem_read.part0 + unc_iio_data_req_of_cpu.mem_read.part1 + unc_iio_data_req_of_cpu.mem_read.part2 + unc_iio_data_req_of_cpu.mem_read.part3 for LLC_MISSES.PCIE_READ
found event unc_iio_data_req_of_cpu.mem_read.part0
found event unc_iio_data_req_of_cpu.mem_read.part1
found event unc_iio_data_req_of_cpu.mem_read.part2
found event unc_iio_data_req_of_cpu.mem_read.part3
adding {unc_iio_data_req_of_cpu.mem_read.part0,unc_iio_data_req_of_cpu.mem_read.part1,unc_iio_data_req_of_cpu.mem_read.part2,unc_iio_data_req_of_cpu.mem_read.part3}:W,{unc_iio_data_req_of_cpu.mem_read.part0,unc_iio_data_req_of_cpu.mem_read.part1,unc_iio_data_req_of_cpu.mem_read.part2,unc_iio_data_req_of_cpu.mem_read.part3}:W
intel_pt default config: tsc,mtc,mtc_period=3,psb_period=3,pt,branch
Attempting to add event pmu 'uncore_iio_free_running_5' with 'unc_iio_data_req_of_cpu.mem_read.part0,' that may result in non-fatal errors
After aliases, add event pmu 'uncore_iio_free_running_5' with 'fc_mask,ch_mask,umask,event,' that may result in non-fatal errors
Attempting to add event pmu 'uncore_iio_free_running_3' with 'unc_iio_data_req_of_cpu.mem_read.part0,' that may result in non-fatal errors
After aliases, add event pmu 'uncore_iio_free_running_3' with 'fc_mask,ch_mask,umask,event,' that may result in non-fatal errors
Attempting to add event pmu 'uncore_iio_free_running_1' with 'unc_iio_data_req_of_cpu.mem_read.part0,' that may result in non-fatal errors
After aliases, add event pmu 'uncore_iio_free_running_1' with 'fc_mask,ch_mask,umask,event,' that may result in non-fatal errors
Multiple errors dropping message: unknown term 'fc_mask' for pmu 'uncore_iio_free_running_3' (valid terms: event,umask,config,config1,config2,name,period,percore)
...
So before you see a 'WARNING: multiple event parsing errors' and
'Invalid event/parameter'. After you see 'Attempting... that may result
in non-fatal errors' then 'Multiple errors...' with details that
'fc_mask' wasn't known to a free running counter. While not completely
clean, this makes it clearer that an error hasn't really occurred.
v2. addresses review feedback from Jiri Olsa <jolsa@redhat.com>.
Signed-off-by: Ian Rogers <irogers@google.com>
Reviewed-by: Andi Kleen <ak@linux.intel.com>
Acked-by: Jiri Olsa <jolsa@redhat.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Jin Yao <yao.jin@linux.intel.com>
Cc: John Garry <john.garry@huawei.com>
Cc: Kan Liang <kan.liang@linux.intel.com>
Cc: Leo Yan <leo.yan@linaro.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Mathieu Poirier <mathieu.poirier@linaro.org>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stephane Eranian <eranian@google.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Link: http://lore.kernel.org/lkml/20200513220635.54700-1-irogers@google.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2020-05-13 15:06:35 -07:00
|
|
|
intel_pt_parse_terms(intel_pt_pmu->name, &intel_pt_pmu->format, buf,
|
|
|
|
&config);
|
2015-07-17 19:33:52 +03:00
|
|
|
|
2015-07-17 19:33:41 +03:00
|
|
|
return config;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int intel_pt_parse_snapshot_options(struct auxtrace_record *itr,
|
|
|
|
struct record_opts *opts,
|
|
|
|
const char *str)
|
|
|
|
{
|
|
|
|
struct intel_pt_recording *ptr =
|
|
|
|
container_of(itr, struct intel_pt_recording, itr);
|
|
|
|
unsigned long long snapshot_size = 0;
|
|
|
|
char *endptr;
|
|
|
|
|
|
|
|
if (str) {
|
|
|
|
snapshot_size = strtoull(str, &endptr, 0);
|
|
|
|
if (*endptr || snapshot_size > SIZE_MAX)
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
opts->auxtrace_snapshot_mode = true;
|
|
|
|
opts->auxtrace_snapshot_size = snapshot_size;
|
|
|
|
|
|
|
|
ptr->snapshot_size = snapshot_size;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct perf_event_attr *
|
|
|
|
intel_pt_pmu_default_config(struct perf_pmu *intel_pt_pmu)
|
|
|
|
{
|
|
|
|
struct perf_event_attr *attr;
|
|
|
|
|
|
|
|
attr = zalloc(sizeof(struct perf_event_attr));
|
|
|
|
if (!attr)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
attr->config = intel_pt_default_config(intel_pt_pmu);
|
|
|
|
|
|
|
|
intel_pt_pmu->selectable = true;
|
|
|
|
|
|
|
|
return attr;
|
|
|
|
}
|
|
|
|
|
2019-07-21 13:23:52 +02:00
|
|
|
static const char *intel_pt_find_filter(struct evlist *evlist,
|
2016-09-23 17:38:45 +03:00
|
|
|
struct perf_pmu *intel_pt_pmu)
|
|
|
|
{
|
2019-07-21 13:23:51 +02:00
|
|
|
struct evsel *evsel;
|
2016-09-23 17:38:45 +03:00
|
|
|
|
|
|
|
evlist__for_each_entry(evlist, evsel) {
|
2019-07-21 13:24:29 +02:00
|
|
|
if (evsel->core.attr.type == intel_pt_pmu->type)
|
2016-09-23 17:38:45 +03:00
|
|
|
return evsel->filter;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static size_t intel_pt_filter_bytes(const char *filter)
|
|
|
|
{
|
|
|
|
size_t len = filter ? strlen(filter) : 0;
|
|
|
|
|
|
|
|
return len ? roundup(len + 1, 8) : 0;
|
|
|
|
}
|
|
|
|
|
2016-01-14 14:46:15 -07:00
|
|
|
static size_t
|
2019-07-21 13:23:52 +02:00
|
|
|
intel_pt_info_priv_size(struct auxtrace_record *itr, struct evlist *evlist)
|
2015-07-17 19:33:41 +03:00
|
|
|
{
|
2016-09-23 17:38:45 +03:00
|
|
|
struct intel_pt_recording *ptr =
|
|
|
|
container_of(itr, struct intel_pt_recording, itr);
|
|
|
|
const char *filter = intel_pt_find_filter(evlist, ptr->intel_pt_pmu);
|
|
|
|
|
|
|
|
ptr->priv_size = (INTEL_PT_AUXTRACE_PRIV_MAX * sizeof(u64)) +
|
|
|
|
intel_pt_filter_bytes(filter);
|
|
|
|
|
|
|
|
return ptr->priv_size;
|
2015-07-17 19:33:41 +03:00
|
|
|
}
|
|
|
|
|
2015-07-17 19:33:54 +03:00
|
|
|
static void intel_pt_tsc_ctc_ratio(u32 *n, u32 *d)
|
|
|
|
{
|
|
|
|
unsigned int eax = 0, ebx = 0, ecx = 0, edx = 0;
|
|
|
|
|
|
|
|
__get_cpuid(0x15, &eax, &ebx, &ecx, &edx);
|
|
|
|
*n = ebx;
|
|
|
|
*d = eax;
|
|
|
|
}
|
|
|
|
|
2015-07-17 19:33:41 +03:00
|
|
|
static int intel_pt_info_fill(struct auxtrace_record *itr,
|
|
|
|
struct perf_session *session,
|
2019-08-28 15:57:16 +02:00
|
|
|
struct perf_record_auxtrace_info *auxtrace_info,
|
2015-07-17 19:33:41 +03:00
|
|
|
size_t priv_size)
|
|
|
|
{
|
|
|
|
struct intel_pt_recording *ptr =
|
|
|
|
container_of(itr, struct intel_pt_recording, itr);
|
|
|
|
struct perf_pmu *intel_pt_pmu = ptr->intel_pt_pmu;
|
|
|
|
struct perf_event_mmap_page *pc;
|
|
|
|
struct perf_tsc_conversion tc = { .time_mult = 0, };
|
|
|
|
bool cap_user_time_zero = false, per_cpu_mmaps;
|
2015-07-17 19:33:54 +03:00
|
|
|
u64 tsc_bit, mtc_bit, mtc_freq_bits, cyc_bit, noretcomp_bit;
|
|
|
|
u32 tsc_ctc_ratio_n, tsc_ctc_ratio_d;
|
2016-09-23 17:38:42 +03:00
|
|
|
unsigned long max_non_turbo_ratio;
|
2016-09-23 17:38:45 +03:00
|
|
|
size_t filter_str_len;
|
|
|
|
const char *filter;
|
2019-08-28 15:57:02 +02:00
|
|
|
__u64 *info;
|
2015-07-17 19:33:41 +03:00
|
|
|
int err;
|
|
|
|
|
2016-09-23 17:38:45 +03:00
|
|
|
if (priv_size != ptr->priv_size)
|
2015-07-17 19:33:41 +03:00
|
|
|
return -EINVAL;
|
|
|
|
|
perf parse-events: Make add PMU verbose output clearer
On a CPU like skylakex an uncore_iio_0 PMU may alias with
uncore_iio_free_running_0. The latter PMU doesn't support fc_mask as a
parameter and so pmu_config_term fails. Typically parse_events_add_pmu
is called in a loop where if one alias succeeds errors are ignored,
however, if multiple errors occur parse_events__handle_error will
currently give a WARN_ONCE.
This change removes the WARN_ONCE in parse_events__handle_error and
makes it a pr_debug. It adds verbose messages to parse_events_add_pmu
warning that non-fatal errors may occur, while giving details on the pmu
and config terms for useful context. pmu_config_term is altered so the
failing term and pmu are present in the case of the 'unknown term' error
which makes spotting the free_running case more straightforward.
Before:
$ perf --debug verbose=3 stat -M llc_misses.pcie_read sleep 1
Using CPUID GenuineIntel-6-55-4
metric expr unc_iio_data_req_of_cpu.mem_read.part0 + unc_iio_data_req_of_cpu.mem_read.part1 + unc_iio_data_req_of_cpu.mem_read.part2 + unc_iio_data_req_of_cpu.mem_read.part3 for LLC_MISSES.PCIE_READ
found event unc_iio_data_req_of_cpu.mem_read.part0
found event unc_iio_data_req_of_cpu.mem_read.part1
found event unc_iio_data_req_of_cpu.mem_read.part2
found event unc_iio_data_req_of_cpu.mem_read.part3
metric expr unc_iio_data_req_of_cpu.mem_read.part0 + unc_iio_data_req_of_cpu.mem_read.part1 + unc_iio_data_req_of_cpu.mem_read.part2 + unc_iio_data_req_of_cpu.mem_read.part3 for LLC_MISSES.PCIE_READ
found event unc_iio_data_req_of_cpu.mem_read.part0
found event unc_iio_data_req_of_cpu.mem_read.part1
found event unc_iio_data_req_of_cpu.mem_read.part2
found event unc_iio_data_req_of_cpu.mem_read.part3
adding {unc_iio_data_req_of_cpu.mem_read.part0,unc_iio_data_req_of_cpu.mem_read.part1,unc_iio_data_req_of_cpu.mem_read.part2,unc_iio_data_req_of_cpu.mem_read.part3}:W,{unc_iio_data_req_of_cpu.mem_read.part0,unc_iio_data_req_of_cpu.mem_read.part1,unc_iio_data_req_of_cpu.mem_read.part2,unc_iio_data_req_of_cpu.mem_read.part3}:W
intel_pt default config: tsc,mtc,mtc_period=3,psb_period=3,pt,branch
WARNING: multiple event parsing errors
...
Invalid event/parameter 'fc_mask'
...
After:
$ perf --debug verbose=3 stat -M llc_misses.pcie_read sleep 1
Using CPUID GenuineIntel-6-55-4
metric expr unc_iio_data_req_of_cpu.mem_read.part0 + unc_iio_data_req_of_cpu.mem_read.part1 + unc_iio_data_req_of_cpu.mem_read.part2 + unc_iio_data_req_of_cpu.mem_read.part3 for LLC_MISSES.PCIE_READ
found event unc_iio_data_req_of_cpu.mem_read.part0
found event unc_iio_data_req_of_cpu.mem_read.part1
found event unc_iio_data_req_of_cpu.mem_read.part2
found event unc_iio_data_req_of_cpu.mem_read.part3
metric expr unc_iio_data_req_of_cpu.mem_read.part0 + unc_iio_data_req_of_cpu.mem_read.part1 + unc_iio_data_req_of_cpu.mem_read.part2 + unc_iio_data_req_of_cpu.mem_read.part3 for LLC_MISSES.PCIE_READ
found event unc_iio_data_req_of_cpu.mem_read.part0
found event unc_iio_data_req_of_cpu.mem_read.part1
found event unc_iio_data_req_of_cpu.mem_read.part2
found event unc_iio_data_req_of_cpu.mem_read.part3
adding {unc_iio_data_req_of_cpu.mem_read.part0,unc_iio_data_req_of_cpu.mem_read.part1,unc_iio_data_req_of_cpu.mem_read.part2,unc_iio_data_req_of_cpu.mem_read.part3}:W,{unc_iio_data_req_of_cpu.mem_read.part0,unc_iio_data_req_of_cpu.mem_read.part1,unc_iio_data_req_of_cpu.mem_read.part2,unc_iio_data_req_of_cpu.mem_read.part3}:W
intel_pt default config: tsc,mtc,mtc_period=3,psb_period=3,pt,branch
Attempting to add event pmu 'uncore_iio_free_running_5' with 'unc_iio_data_req_of_cpu.mem_read.part0,' that may result in non-fatal errors
After aliases, add event pmu 'uncore_iio_free_running_5' with 'fc_mask,ch_mask,umask,event,' that may result in non-fatal errors
Attempting to add event pmu 'uncore_iio_free_running_3' with 'unc_iio_data_req_of_cpu.mem_read.part0,' that may result in non-fatal errors
After aliases, add event pmu 'uncore_iio_free_running_3' with 'fc_mask,ch_mask,umask,event,' that may result in non-fatal errors
Attempting to add event pmu 'uncore_iio_free_running_1' with 'unc_iio_data_req_of_cpu.mem_read.part0,' that may result in non-fatal errors
After aliases, add event pmu 'uncore_iio_free_running_1' with 'fc_mask,ch_mask,umask,event,' that may result in non-fatal errors
Multiple errors dropping message: unknown term 'fc_mask' for pmu 'uncore_iio_free_running_3' (valid terms: event,umask,config,config1,config2,name,period,percore)
...
So before you see a 'WARNING: multiple event parsing errors' and
'Invalid event/parameter'. After you see 'Attempting... that may result
in non-fatal errors' then 'Multiple errors...' with details that
'fc_mask' wasn't known to a free running counter. While not completely
clean, this makes it clearer that an error hasn't really occurred.
v2. addresses review feedback from Jiri Olsa <jolsa@redhat.com>.
Signed-off-by: Ian Rogers <irogers@google.com>
Reviewed-by: Andi Kleen <ak@linux.intel.com>
Acked-by: Jiri Olsa <jolsa@redhat.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Jin Yao <yao.jin@linux.intel.com>
Cc: John Garry <john.garry@huawei.com>
Cc: Kan Liang <kan.liang@linux.intel.com>
Cc: Leo Yan <leo.yan@linaro.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Mathieu Poirier <mathieu.poirier@linaro.org>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stephane Eranian <eranian@google.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Link: http://lore.kernel.org/lkml/20200513220635.54700-1-irogers@google.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2020-05-13 15:06:35 -07:00
|
|
|
intel_pt_parse_terms(intel_pt_pmu->name, &intel_pt_pmu->format,
|
|
|
|
"tsc", &tsc_bit);
|
|
|
|
intel_pt_parse_terms(intel_pt_pmu->name, &intel_pt_pmu->format,
|
|
|
|
"noretcomp", &noretcomp_bit);
|
|
|
|
intel_pt_parse_terms(intel_pt_pmu->name, &intel_pt_pmu->format,
|
|
|
|
"mtc", &mtc_bit);
|
2015-07-17 19:33:54 +03:00
|
|
|
mtc_freq_bits = perf_pmu__format_bits(&intel_pt_pmu->format,
|
|
|
|
"mtc_period");
|
perf parse-events: Make add PMU verbose output clearer
On a CPU like skylakex an uncore_iio_0 PMU may alias with
uncore_iio_free_running_0. The latter PMU doesn't support fc_mask as a
parameter and so pmu_config_term fails. Typically parse_events_add_pmu
is called in a loop where if one alias succeeds errors are ignored,
however, if multiple errors occur parse_events__handle_error will
currently give a WARN_ONCE.
This change removes the WARN_ONCE in parse_events__handle_error and
makes it a pr_debug. It adds verbose messages to parse_events_add_pmu
warning that non-fatal errors may occur, while giving details on the pmu
and config terms for useful context. pmu_config_term is altered so the
failing term and pmu are present in the case of the 'unknown term' error
which makes spotting the free_running case more straightforward.
Before:
$ perf --debug verbose=3 stat -M llc_misses.pcie_read sleep 1
Using CPUID GenuineIntel-6-55-4
metric expr unc_iio_data_req_of_cpu.mem_read.part0 + unc_iio_data_req_of_cpu.mem_read.part1 + unc_iio_data_req_of_cpu.mem_read.part2 + unc_iio_data_req_of_cpu.mem_read.part3 for LLC_MISSES.PCIE_READ
found event unc_iio_data_req_of_cpu.mem_read.part0
found event unc_iio_data_req_of_cpu.mem_read.part1
found event unc_iio_data_req_of_cpu.mem_read.part2
found event unc_iio_data_req_of_cpu.mem_read.part3
metric expr unc_iio_data_req_of_cpu.mem_read.part0 + unc_iio_data_req_of_cpu.mem_read.part1 + unc_iio_data_req_of_cpu.mem_read.part2 + unc_iio_data_req_of_cpu.mem_read.part3 for LLC_MISSES.PCIE_READ
found event unc_iio_data_req_of_cpu.mem_read.part0
found event unc_iio_data_req_of_cpu.mem_read.part1
found event unc_iio_data_req_of_cpu.mem_read.part2
found event unc_iio_data_req_of_cpu.mem_read.part3
adding {unc_iio_data_req_of_cpu.mem_read.part0,unc_iio_data_req_of_cpu.mem_read.part1,unc_iio_data_req_of_cpu.mem_read.part2,unc_iio_data_req_of_cpu.mem_read.part3}:W,{unc_iio_data_req_of_cpu.mem_read.part0,unc_iio_data_req_of_cpu.mem_read.part1,unc_iio_data_req_of_cpu.mem_read.part2,unc_iio_data_req_of_cpu.mem_read.part3}:W
intel_pt default config: tsc,mtc,mtc_period=3,psb_period=3,pt,branch
WARNING: multiple event parsing errors
...
Invalid event/parameter 'fc_mask'
...
After:
$ perf --debug verbose=3 stat -M llc_misses.pcie_read sleep 1
Using CPUID GenuineIntel-6-55-4
metric expr unc_iio_data_req_of_cpu.mem_read.part0 + unc_iio_data_req_of_cpu.mem_read.part1 + unc_iio_data_req_of_cpu.mem_read.part2 + unc_iio_data_req_of_cpu.mem_read.part3 for LLC_MISSES.PCIE_READ
found event unc_iio_data_req_of_cpu.mem_read.part0
found event unc_iio_data_req_of_cpu.mem_read.part1
found event unc_iio_data_req_of_cpu.mem_read.part2
found event unc_iio_data_req_of_cpu.mem_read.part3
metric expr unc_iio_data_req_of_cpu.mem_read.part0 + unc_iio_data_req_of_cpu.mem_read.part1 + unc_iio_data_req_of_cpu.mem_read.part2 + unc_iio_data_req_of_cpu.mem_read.part3 for LLC_MISSES.PCIE_READ
found event unc_iio_data_req_of_cpu.mem_read.part0
found event unc_iio_data_req_of_cpu.mem_read.part1
found event unc_iio_data_req_of_cpu.mem_read.part2
found event unc_iio_data_req_of_cpu.mem_read.part3
adding {unc_iio_data_req_of_cpu.mem_read.part0,unc_iio_data_req_of_cpu.mem_read.part1,unc_iio_data_req_of_cpu.mem_read.part2,unc_iio_data_req_of_cpu.mem_read.part3}:W,{unc_iio_data_req_of_cpu.mem_read.part0,unc_iio_data_req_of_cpu.mem_read.part1,unc_iio_data_req_of_cpu.mem_read.part2,unc_iio_data_req_of_cpu.mem_read.part3}:W
intel_pt default config: tsc,mtc,mtc_period=3,psb_period=3,pt,branch
Attempting to add event pmu 'uncore_iio_free_running_5' with 'unc_iio_data_req_of_cpu.mem_read.part0,' that may result in non-fatal errors
After aliases, add event pmu 'uncore_iio_free_running_5' with 'fc_mask,ch_mask,umask,event,' that may result in non-fatal errors
Attempting to add event pmu 'uncore_iio_free_running_3' with 'unc_iio_data_req_of_cpu.mem_read.part0,' that may result in non-fatal errors
After aliases, add event pmu 'uncore_iio_free_running_3' with 'fc_mask,ch_mask,umask,event,' that may result in non-fatal errors
Attempting to add event pmu 'uncore_iio_free_running_1' with 'unc_iio_data_req_of_cpu.mem_read.part0,' that may result in non-fatal errors
After aliases, add event pmu 'uncore_iio_free_running_1' with 'fc_mask,ch_mask,umask,event,' that may result in non-fatal errors
Multiple errors dropping message: unknown term 'fc_mask' for pmu 'uncore_iio_free_running_3' (valid terms: event,umask,config,config1,config2,name,period,percore)
...
So before you see a 'WARNING: multiple event parsing errors' and
'Invalid event/parameter'. After you see 'Attempting... that may result
in non-fatal errors' then 'Multiple errors...' with details that
'fc_mask' wasn't known to a free running counter. While not completely
clean, this makes it clearer that an error hasn't really occurred.
v2. addresses review feedback from Jiri Olsa <jolsa@redhat.com>.
Signed-off-by: Ian Rogers <irogers@google.com>
Reviewed-by: Andi Kleen <ak@linux.intel.com>
Acked-by: Jiri Olsa <jolsa@redhat.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Jin Yao <yao.jin@linux.intel.com>
Cc: John Garry <john.garry@huawei.com>
Cc: Kan Liang <kan.liang@linux.intel.com>
Cc: Leo Yan <leo.yan@linaro.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Mathieu Poirier <mathieu.poirier@linaro.org>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stephane Eranian <eranian@google.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Link: http://lore.kernel.org/lkml/20200513220635.54700-1-irogers@google.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2020-05-13 15:06:35 -07:00
|
|
|
intel_pt_parse_terms(intel_pt_pmu->name, &intel_pt_pmu->format,
|
|
|
|
"cyc", &cyc_bit);
|
2015-07-17 19:33:54 +03:00
|
|
|
|
|
|
|
intel_pt_tsc_ctc_ratio(&tsc_ctc_ratio_n, &tsc_ctc_ratio_d);
|
2015-07-17 19:33:41 +03:00
|
|
|
|
2016-09-23 17:38:42 +03:00
|
|
|
if (perf_pmu__scan_file(intel_pt_pmu, "max_nonturbo_ratio",
|
|
|
|
"%lu", &max_non_turbo_ratio) != 1)
|
|
|
|
max_non_turbo_ratio = 0;
|
|
|
|
|
2016-09-23 17:38:45 +03:00
|
|
|
filter = intel_pt_find_filter(session->evlist, ptr->intel_pt_pmu);
|
|
|
|
filter_str_len = filter ? strlen(filter) : 0;
|
|
|
|
|
2019-07-30 13:04:59 +02:00
|
|
|
if (!session->evlist->core.nr_mmaps)
|
2015-07-17 19:33:41 +03:00
|
|
|
return -EINVAL;
|
|
|
|
|
2019-07-27 22:07:44 +02:00
|
|
|
pc = session->evlist->mmap[0].core.base;
|
2015-07-17 19:33:41 +03:00
|
|
|
if (pc) {
|
|
|
|
err = perf_read_tsc_conversion(pc, &tc);
|
|
|
|
if (err) {
|
|
|
|
if (err != -EOPNOTSUPP)
|
|
|
|
return err;
|
|
|
|
} else {
|
|
|
|
cap_user_time_zero = tc.time_mult != 0;
|
|
|
|
}
|
|
|
|
if (!cap_user_time_zero)
|
|
|
|
ui__warning("Intel Processor Trace: TSC not available\n");
|
|
|
|
}
|
|
|
|
|
2019-08-22 13:11:39 +02:00
|
|
|
per_cpu_mmaps = !perf_cpu_map__empty(session->evlist->core.cpus);
|
2015-07-17 19:33:41 +03:00
|
|
|
|
|
|
|
auxtrace_info->type = PERF_AUXTRACE_INTEL_PT;
|
|
|
|
auxtrace_info->priv[INTEL_PT_PMU_TYPE] = intel_pt_pmu->type;
|
|
|
|
auxtrace_info->priv[INTEL_PT_TIME_SHIFT] = tc.time_shift;
|
|
|
|
auxtrace_info->priv[INTEL_PT_TIME_MULT] = tc.time_mult;
|
|
|
|
auxtrace_info->priv[INTEL_PT_TIME_ZERO] = tc.time_zero;
|
|
|
|
auxtrace_info->priv[INTEL_PT_CAP_USER_TIME_ZERO] = cap_user_time_zero;
|
|
|
|
auxtrace_info->priv[INTEL_PT_TSC_BIT] = tsc_bit;
|
|
|
|
auxtrace_info->priv[INTEL_PT_NORETCOMP_BIT] = noretcomp_bit;
|
|
|
|
auxtrace_info->priv[INTEL_PT_HAVE_SCHED_SWITCH] = ptr->have_sched_switch;
|
|
|
|
auxtrace_info->priv[INTEL_PT_SNAPSHOT_MODE] = ptr->snapshot_mode;
|
|
|
|
auxtrace_info->priv[INTEL_PT_PER_CPU_MMAPS] = per_cpu_mmaps;
|
2015-07-17 19:33:54 +03:00
|
|
|
auxtrace_info->priv[INTEL_PT_MTC_BIT] = mtc_bit;
|
|
|
|
auxtrace_info->priv[INTEL_PT_MTC_FREQ_BITS] = mtc_freq_bits;
|
|
|
|
auxtrace_info->priv[INTEL_PT_TSC_CTC_N] = tsc_ctc_ratio_n;
|
|
|
|
auxtrace_info->priv[INTEL_PT_TSC_CTC_D] = tsc_ctc_ratio_d;
|
|
|
|
auxtrace_info->priv[INTEL_PT_CYC_BIT] = cyc_bit;
|
2016-09-23 17:38:42 +03:00
|
|
|
auxtrace_info->priv[INTEL_PT_MAX_NONTURBO_RATIO] = max_non_turbo_ratio;
|
2016-09-23 17:38:45 +03:00
|
|
|
auxtrace_info->priv[INTEL_PT_FILTER_STR_LEN] = filter_str_len;
|
|
|
|
|
|
|
|
info = &auxtrace_info->priv[INTEL_PT_FILTER_STR_LEN] + 1;
|
|
|
|
|
|
|
|
if (filter_str_len) {
|
|
|
|
size_t len = intel_pt_filter_bytes(filter);
|
|
|
|
|
|
|
|
strncpy((char *)info, filter, len);
|
|
|
|
info += len >> 3;
|
|
|
|
}
|
2015-07-17 19:33:41 +03:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-07-21 13:23:52 +02:00
|
|
|
static int intel_pt_track_switches(struct evlist *evlist)
|
2015-07-17 19:33:41 +03:00
|
|
|
{
|
|
|
|
const char *sched_switch = "sched:sched_switch";
|
2019-07-21 13:23:51 +02:00
|
|
|
struct evsel *evsel;
|
2015-07-17 19:33:41 +03:00
|
|
|
int err;
|
|
|
|
|
|
|
|
if (!perf_evlist__can_select_event(evlist, sched_switch))
|
|
|
|
return -EPERM;
|
|
|
|
|
|
|
|
err = parse_events(evlist, sched_switch, NULL);
|
|
|
|
if (err) {
|
|
|
|
pr_debug2("%s: failed to parse %s, error %d\n",
|
|
|
|
__func__, sched_switch, err);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2019-09-03 10:39:52 +02:00
|
|
|
evsel = evlist__last(evlist);
|
2015-07-17 19:33:41 +03:00
|
|
|
|
2020-04-29 16:12:15 -03:00
|
|
|
evsel__set_sample_bit(evsel, CPU);
|
|
|
|
evsel__set_sample_bit(evsel, TIME);
|
2015-07-17 19:33:41 +03:00
|
|
|
|
2019-08-06 11:35:19 +02:00
|
|
|
evsel->core.system_wide = true;
|
2015-07-17 19:33:41 +03:00
|
|
|
evsel->no_aux_samples = true;
|
|
|
|
evsel->immediate = true;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-07-17 19:33:52 +03:00
|
|
|
static void intel_pt_valid_str(char *str, size_t len, u64 valid)
|
|
|
|
{
|
|
|
|
unsigned int val, last = 0, state = 1;
|
|
|
|
int p = 0;
|
|
|
|
|
|
|
|
str[0] = '\0';
|
|
|
|
|
|
|
|
for (val = 0; val <= 64; val++, valid >>= 1) {
|
|
|
|
if (valid & 1) {
|
|
|
|
last = val;
|
|
|
|
switch (state) {
|
|
|
|
case 0:
|
|
|
|
p += scnprintf(str + p, len - p, ",");
|
|
|
|
/* Fall through */
|
|
|
|
case 1:
|
|
|
|
p += scnprintf(str + p, len - p, "%u", val);
|
|
|
|
state = 2;
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
state = 3;
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
state = 4;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
switch (state) {
|
|
|
|
case 3:
|
|
|
|
p += scnprintf(str + p, len - p, ",%u", last);
|
|
|
|
state = 0;
|
|
|
|
break;
|
|
|
|
case 4:
|
|
|
|
p += scnprintf(str + p, len - p, "-%u", last);
|
|
|
|
state = 0;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (state != 1)
|
|
|
|
state = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static int intel_pt_val_config_term(struct perf_pmu *intel_pt_pmu,
|
|
|
|
const char *caps, const char *name,
|
|
|
|
const char *supported, u64 config)
|
|
|
|
{
|
|
|
|
char valid_str[256];
|
|
|
|
unsigned int shift;
|
|
|
|
unsigned long long valid;
|
|
|
|
u64 bits;
|
|
|
|
int ok;
|
|
|
|
|
|
|
|
if (perf_pmu__scan_file(intel_pt_pmu, caps, "%llx", &valid) != 1)
|
|
|
|
valid = 0;
|
|
|
|
|
|
|
|
if (supported &&
|
|
|
|
perf_pmu__scan_file(intel_pt_pmu, supported, "%d", &ok) == 1 && !ok)
|
|
|
|
valid = 0;
|
|
|
|
|
|
|
|
valid |= 1;
|
|
|
|
|
|
|
|
bits = perf_pmu__format_bits(&intel_pt_pmu->format, name);
|
|
|
|
|
|
|
|
config &= bits;
|
|
|
|
|
|
|
|
for (shift = 0; bits && !(bits & 1); shift++)
|
|
|
|
bits >>= 1;
|
|
|
|
|
|
|
|
config >>= shift;
|
|
|
|
|
|
|
|
if (config > 63)
|
|
|
|
goto out_err;
|
|
|
|
|
|
|
|
if (valid & (1 << config))
|
|
|
|
return 0;
|
|
|
|
out_err:
|
|
|
|
intel_pt_valid_str(valid_str, sizeof(valid_str), valid);
|
|
|
|
pr_err("Invalid %s for %s. Valid values are: %s\n",
|
|
|
|
name, INTEL_PT_PMU_NAME, valid_str);
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int intel_pt_validate_config(struct perf_pmu *intel_pt_pmu,
|
2019-07-21 13:23:51 +02:00
|
|
|
struct evsel *evsel)
|
2015-07-17 19:33:52 +03:00
|
|
|
{
|
2015-07-17 19:33:56 +03:00
|
|
|
int err;
|
2018-11-26 14:12:52 +02:00
|
|
|
char c;
|
2015-07-17 19:33:56 +03:00
|
|
|
|
2015-07-17 19:33:52 +03:00
|
|
|
if (!evsel)
|
|
|
|
return 0;
|
|
|
|
|
2018-11-26 14:12:52 +02:00
|
|
|
/*
|
|
|
|
* If supported, force pass-through config term (pt=1) even if user
|
|
|
|
* sets pt=0, which avoids senseless kernel errors.
|
|
|
|
*/
|
|
|
|
if (perf_pmu__scan_file(intel_pt_pmu, "format/pt", "%c", &c) == 1 &&
|
2019-07-21 13:24:29 +02:00
|
|
|
!(evsel->core.attr.config & 1)) {
|
2018-11-26 14:12:52 +02:00
|
|
|
pr_warning("pt=0 doesn't make sense, forcing pt=1\n");
|
2019-07-21 13:24:29 +02:00
|
|
|
evsel->core.attr.config |= 1;
|
2018-11-26 14:12:52 +02:00
|
|
|
}
|
|
|
|
|
2015-07-17 19:33:58 +03:00
|
|
|
err = intel_pt_val_config_term(intel_pt_pmu, "caps/cycle_thresholds",
|
|
|
|
"cyc_thresh", "caps/psb_cyc",
|
2019-07-21 13:24:29 +02:00
|
|
|
evsel->core.attr.config);
|
2015-07-17 19:33:58 +03:00
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
2015-07-17 19:33:56 +03:00
|
|
|
err = intel_pt_val_config_term(intel_pt_pmu, "caps/mtc_periods",
|
|
|
|
"mtc_period", "caps/mtc",
|
2019-07-21 13:24:29 +02:00
|
|
|
evsel->core.attr.config);
|
2015-07-17 19:33:56 +03:00
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
2015-07-17 19:33:52 +03:00
|
|
|
return intel_pt_val_config_term(intel_pt_pmu, "caps/psb_periods",
|
|
|
|
"psb_period", "caps/psb_cyc",
|
2019-07-21 13:24:29 +02:00
|
|
|
evsel->core.attr.config);
|
2015-07-17 19:33:52 +03:00
|
|
|
}
|
|
|
|
|
2019-11-15 14:42:23 +02:00
|
|
|
static void intel_pt_config_sample_mode(struct perf_pmu *intel_pt_pmu,
|
|
|
|
struct evsel *evsel)
|
|
|
|
{
|
|
|
|
u64 user_bits = 0, bits;
|
2020-05-06 13:05:08 -03:00
|
|
|
struct evsel_config_term *term = evsel__get_config_term(evsel, CFG_CHG);
|
2019-11-15 14:42:23 +02:00
|
|
|
|
|
|
|
if (term)
|
|
|
|
user_bits = term->val.cfg_chg;
|
|
|
|
|
|
|
|
bits = perf_pmu__format_bits(&intel_pt_pmu->format, "psb_period");
|
|
|
|
|
|
|
|
/* Did user change psb_period */
|
|
|
|
if (bits & user_bits)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* Set psb_period to 0 */
|
|
|
|
evsel->core.attr.config &= ~bits;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void intel_pt_min_max_sample_sz(struct evlist *evlist,
|
|
|
|
size_t *min_sz, size_t *max_sz)
|
|
|
|
{
|
|
|
|
struct evsel *evsel;
|
|
|
|
|
|
|
|
evlist__for_each_entry(evlist, evsel) {
|
|
|
|
size_t sz = evsel->core.attr.aux_sample_size;
|
|
|
|
|
|
|
|
if (!sz)
|
|
|
|
continue;
|
|
|
|
if (min_sz && (sz < *min_sz || !*min_sz))
|
|
|
|
*min_sz = sz;
|
|
|
|
if (max_sz && sz > *max_sz)
|
|
|
|
*max_sz = sz;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-08-06 11:46:04 +03:00
|
|
|
/*
|
|
|
|
* Currently, there is not enough information to disambiguate different PEBS
|
|
|
|
* events, so only allow one.
|
|
|
|
*/
|
|
|
|
static bool intel_pt_too_many_aux_output(struct evlist *evlist)
|
|
|
|
{
|
|
|
|
struct evsel *evsel;
|
|
|
|
int aux_output_cnt = 0;
|
|
|
|
|
|
|
|
evlist__for_each_entry(evlist, evsel)
|
|
|
|
aux_output_cnt += !!evsel->core.attr.aux_output;
|
|
|
|
|
|
|
|
if (aux_output_cnt > 1) {
|
|
|
|
pr_err(INTEL_PT_PMU_NAME " supports at most one event with aux-output\n");
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-07-17 19:33:41 +03:00
|
|
|
static int intel_pt_recording_options(struct auxtrace_record *itr,
|
2019-07-21 13:23:52 +02:00
|
|
|
struct evlist *evlist,
|
2015-07-17 19:33:41 +03:00
|
|
|
struct record_opts *opts)
|
|
|
|
{
|
|
|
|
struct intel_pt_recording *ptr =
|
|
|
|
container_of(itr, struct intel_pt_recording, itr);
|
|
|
|
struct perf_pmu *intel_pt_pmu = ptr->intel_pt_pmu;
|
2016-08-15 10:23:04 +03:00
|
|
|
bool have_timing_info, need_immediate = false;
|
2019-07-21 13:23:51 +02:00
|
|
|
struct evsel *evsel, *intel_pt_evsel = NULL;
|
2019-07-21 13:24:41 +02:00
|
|
|
const struct perf_cpu_map *cpus = evlist->core.cpus;
|
2019-08-26 21:39:13 -04:00
|
|
|
bool privileged = perf_event_paranoid_check(-1);
|
2015-07-17 19:33:41 +03:00
|
|
|
u64 tsc_bit;
|
2015-07-17 19:33:52 +03:00
|
|
|
int err;
|
2015-07-17 19:33:41 +03:00
|
|
|
|
|
|
|
ptr->evlist = evlist;
|
|
|
|
ptr->snapshot_mode = opts->auxtrace_snapshot_mode;
|
|
|
|
|
2016-06-23 11:26:15 -03:00
|
|
|
evlist__for_each_entry(evlist, evsel) {
|
2019-07-21 13:24:29 +02:00
|
|
|
if (evsel->core.attr.type == intel_pt_pmu->type) {
|
2015-07-17 19:33:41 +03:00
|
|
|
if (intel_pt_evsel) {
|
|
|
|
pr_err("There may be only one " INTEL_PT_PMU_NAME " event\n");
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
2019-07-21 13:24:29 +02:00
|
|
|
evsel->core.attr.freq = 0;
|
|
|
|
evsel->core.attr.sample_period = 1;
|
2020-06-30 16:39:33 +03:00
|
|
|
evsel->no_aux_samples = true;
|
2015-07-17 19:33:41 +03:00
|
|
|
intel_pt_evsel = evsel;
|
|
|
|
opts->full_auxtrace = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (opts->auxtrace_snapshot_mode && !opts->full_auxtrace) {
|
|
|
|
pr_err("Snapshot mode (-S option) requires " INTEL_PT_PMU_NAME " PMU event (-e " INTEL_PT_PMU_NAME ")\n");
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2019-11-15 14:42:23 +02:00
|
|
|
if (opts->auxtrace_snapshot_mode && opts->auxtrace_sample_mode) {
|
|
|
|
pr_err("Snapshot mode (" INTEL_PT_PMU_NAME " PMU) and sample trace cannot be used together\n");
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2015-07-17 19:33:41 +03:00
|
|
|
if (opts->use_clockid) {
|
|
|
|
pr_err("Cannot use clockid (-k option) with " INTEL_PT_PMU_NAME "\n");
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2019-08-06 11:46:04 +03:00
|
|
|
if (intel_pt_too_many_aux_output(evlist))
|
|
|
|
return -EINVAL;
|
|
|
|
|
2015-07-17 19:33:41 +03:00
|
|
|
if (!opts->full_auxtrace)
|
|
|
|
return 0;
|
|
|
|
|
2019-11-15 14:42:23 +02:00
|
|
|
if (opts->auxtrace_sample_mode)
|
|
|
|
intel_pt_config_sample_mode(intel_pt_pmu, intel_pt_evsel);
|
|
|
|
|
2015-07-17 19:33:52 +03:00
|
|
|
err = intel_pt_validate_config(intel_pt_pmu, intel_pt_evsel);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
2015-07-17 19:33:41 +03:00
|
|
|
/* Set default sizes for snapshot mode */
|
|
|
|
if (opts->auxtrace_snapshot_mode) {
|
|
|
|
size_t psb_period = intel_pt_psb_period(intel_pt_pmu, evlist);
|
|
|
|
|
|
|
|
if (!opts->auxtrace_snapshot_size && !opts->auxtrace_mmap_pages) {
|
|
|
|
if (privileged) {
|
|
|
|
opts->auxtrace_mmap_pages = MiB(4) / page_size;
|
|
|
|
} else {
|
|
|
|
opts->auxtrace_mmap_pages = KiB(128) / page_size;
|
|
|
|
if (opts->mmap_pages == UINT_MAX)
|
|
|
|
opts->mmap_pages = KiB(256) / page_size;
|
|
|
|
}
|
|
|
|
} else if (!opts->auxtrace_mmap_pages && !privileged &&
|
|
|
|
opts->mmap_pages == UINT_MAX) {
|
|
|
|
opts->mmap_pages = KiB(256) / page_size;
|
|
|
|
}
|
|
|
|
if (!opts->auxtrace_snapshot_size)
|
|
|
|
opts->auxtrace_snapshot_size =
|
|
|
|
opts->auxtrace_mmap_pages * (size_t)page_size;
|
|
|
|
if (!opts->auxtrace_mmap_pages) {
|
|
|
|
size_t sz = opts->auxtrace_snapshot_size;
|
|
|
|
|
|
|
|
sz = round_up(sz, page_size) / page_size;
|
|
|
|
opts->auxtrace_mmap_pages = roundup_pow_of_two(sz);
|
|
|
|
}
|
|
|
|
if (opts->auxtrace_snapshot_size >
|
|
|
|
opts->auxtrace_mmap_pages * (size_t)page_size) {
|
|
|
|
pr_err("Snapshot size %zu must not be greater than AUX area tracing mmap size %zu\n",
|
|
|
|
opts->auxtrace_snapshot_size,
|
|
|
|
opts->auxtrace_mmap_pages * (size_t)page_size);
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
if (!opts->auxtrace_snapshot_size || !opts->auxtrace_mmap_pages) {
|
|
|
|
pr_err("Failed to calculate default snapshot size and/or AUX area tracing mmap pages\n");
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
pr_debug2("Intel PT snapshot size: %zu\n",
|
|
|
|
opts->auxtrace_snapshot_size);
|
|
|
|
if (psb_period &&
|
|
|
|
opts->auxtrace_snapshot_size <= psb_period +
|
|
|
|
INTEL_PT_PSB_PERIOD_NEAR)
|
|
|
|
ui__warning("Intel PT snapshot size (%zu) may be too small for PSB period (%zu)\n",
|
|
|
|
opts->auxtrace_snapshot_size, psb_period);
|
|
|
|
}
|
|
|
|
|
2019-11-15 14:42:23 +02:00
|
|
|
/* Set default sizes for sample mode */
|
|
|
|
if (opts->auxtrace_sample_mode) {
|
|
|
|
size_t psb_period = intel_pt_psb_period(intel_pt_pmu, evlist);
|
|
|
|
size_t min_sz = 0, max_sz = 0;
|
|
|
|
|
|
|
|
intel_pt_min_max_sample_sz(evlist, &min_sz, &max_sz);
|
|
|
|
if (!opts->auxtrace_mmap_pages && !privileged &&
|
|
|
|
opts->mmap_pages == UINT_MAX)
|
|
|
|
opts->mmap_pages = KiB(256) / page_size;
|
|
|
|
if (!opts->auxtrace_mmap_pages) {
|
|
|
|
size_t sz = round_up(max_sz, page_size) / page_size;
|
|
|
|
|
|
|
|
opts->auxtrace_mmap_pages = roundup_pow_of_two(sz);
|
|
|
|
}
|
|
|
|
if (max_sz > opts->auxtrace_mmap_pages * (size_t)page_size) {
|
|
|
|
pr_err("Sample size %zu must not be greater than AUX area tracing mmap size %zu\n",
|
|
|
|
max_sz,
|
|
|
|
opts->auxtrace_mmap_pages * (size_t)page_size);
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
pr_debug2("Intel PT min. sample size: %zu max. sample size: %zu\n",
|
|
|
|
min_sz, max_sz);
|
|
|
|
if (psb_period &&
|
|
|
|
min_sz <= psb_period + INTEL_PT_PSB_PERIOD_NEAR)
|
|
|
|
ui__warning("Intel PT sample size (%zu) may be too small for PSB period (%zu)\n",
|
|
|
|
min_sz, psb_period);
|
|
|
|
}
|
|
|
|
|
2015-07-17 19:33:41 +03:00
|
|
|
/* Set default sizes for full trace mode */
|
|
|
|
if (opts->full_auxtrace && !opts->auxtrace_mmap_pages) {
|
|
|
|
if (privileged) {
|
|
|
|
opts->auxtrace_mmap_pages = MiB(4) / page_size;
|
|
|
|
} else {
|
|
|
|
opts->auxtrace_mmap_pages = KiB(128) / page_size;
|
|
|
|
if (opts->mmap_pages == UINT_MAX)
|
|
|
|
opts->mmap_pages = KiB(256) / page_size;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Validate auxtrace_mmap_pages */
|
|
|
|
if (opts->auxtrace_mmap_pages) {
|
|
|
|
size_t sz = opts->auxtrace_mmap_pages * (size_t)page_size;
|
|
|
|
size_t min_sz;
|
|
|
|
|
2019-11-15 14:42:23 +02:00
|
|
|
if (opts->auxtrace_snapshot_mode || opts->auxtrace_sample_mode)
|
2015-07-17 19:33:41 +03:00
|
|
|
min_sz = KiB(4);
|
|
|
|
else
|
|
|
|
min_sz = KiB(8);
|
|
|
|
|
|
|
|
if (sz < min_sz || !is_power_of_2(sz)) {
|
|
|
|
pr_err("Invalid mmap size for Intel Processor Trace: must be at least %zuKiB and a power of 2\n",
|
|
|
|
min_sz / 1024);
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
perf parse-events: Make add PMU verbose output clearer
On a CPU like skylakex an uncore_iio_0 PMU may alias with
uncore_iio_free_running_0. The latter PMU doesn't support fc_mask as a
parameter and so pmu_config_term fails. Typically parse_events_add_pmu
is called in a loop where if one alias succeeds errors are ignored,
however, if multiple errors occur parse_events__handle_error will
currently give a WARN_ONCE.
This change removes the WARN_ONCE in parse_events__handle_error and
makes it a pr_debug. It adds verbose messages to parse_events_add_pmu
warning that non-fatal errors may occur, while giving details on the pmu
and config terms for useful context. pmu_config_term is altered so the
failing term and pmu are present in the case of the 'unknown term' error
which makes spotting the free_running case more straightforward.
Before:
$ perf --debug verbose=3 stat -M llc_misses.pcie_read sleep 1
Using CPUID GenuineIntel-6-55-4
metric expr unc_iio_data_req_of_cpu.mem_read.part0 + unc_iio_data_req_of_cpu.mem_read.part1 + unc_iio_data_req_of_cpu.mem_read.part2 + unc_iio_data_req_of_cpu.mem_read.part3 for LLC_MISSES.PCIE_READ
found event unc_iio_data_req_of_cpu.mem_read.part0
found event unc_iio_data_req_of_cpu.mem_read.part1
found event unc_iio_data_req_of_cpu.mem_read.part2
found event unc_iio_data_req_of_cpu.mem_read.part3
metric expr unc_iio_data_req_of_cpu.mem_read.part0 + unc_iio_data_req_of_cpu.mem_read.part1 + unc_iio_data_req_of_cpu.mem_read.part2 + unc_iio_data_req_of_cpu.mem_read.part3 for LLC_MISSES.PCIE_READ
found event unc_iio_data_req_of_cpu.mem_read.part0
found event unc_iio_data_req_of_cpu.mem_read.part1
found event unc_iio_data_req_of_cpu.mem_read.part2
found event unc_iio_data_req_of_cpu.mem_read.part3
adding {unc_iio_data_req_of_cpu.mem_read.part0,unc_iio_data_req_of_cpu.mem_read.part1,unc_iio_data_req_of_cpu.mem_read.part2,unc_iio_data_req_of_cpu.mem_read.part3}:W,{unc_iio_data_req_of_cpu.mem_read.part0,unc_iio_data_req_of_cpu.mem_read.part1,unc_iio_data_req_of_cpu.mem_read.part2,unc_iio_data_req_of_cpu.mem_read.part3}:W
intel_pt default config: tsc,mtc,mtc_period=3,psb_period=3,pt,branch
WARNING: multiple event parsing errors
...
Invalid event/parameter 'fc_mask'
...
After:
$ perf --debug verbose=3 stat -M llc_misses.pcie_read sleep 1
Using CPUID GenuineIntel-6-55-4
metric expr unc_iio_data_req_of_cpu.mem_read.part0 + unc_iio_data_req_of_cpu.mem_read.part1 + unc_iio_data_req_of_cpu.mem_read.part2 + unc_iio_data_req_of_cpu.mem_read.part3 for LLC_MISSES.PCIE_READ
found event unc_iio_data_req_of_cpu.mem_read.part0
found event unc_iio_data_req_of_cpu.mem_read.part1
found event unc_iio_data_req_of_cpu.mem_read.part2
found event unc_iio_data_req_of_cpu.mem_read.part3
metric expr unc_iio_data_req_of_cpu.mem_read.part0 + unc_iio_data_req_of_cpu.mem_read.part1 + unc_iio_data_req_of_cpu.mem_read.part2 + unc_iio_data_req_of_cpu.mem_read.part3 for LLC_MISSES.PCIE_READ
found event unc_iio_data_req_of_cpu.mem_read.part0
found event unc_iio_data_req_of_cpu.mem_read.part1
found event unc_iio_data_req_of_cpu.mem_read.part2
found event unc_iio_data_req_of_cpu.mem_read.part3
adding {unc_iio_data_req_of_cpu.mem_read.part0,unc_iio_data_req_of_cpu.mem_read.part1,unc_iio_data_req_of_cpu.mem_read.part2,unc_iio_data_req_of_cpu.mem_read.part3}:W,{unc_iio_data_req_of_cpu.mem_read.part0,unc_iio_data_req_of_cpu.mem_read.part1,unc_iio_data_req_of_cpu.mem_read.part2,unc_iio_data_req_of_cpu.mem_read.part3}:W
intel_pt default config: tsc,mtc,mtc_period=3,psb_period=3,pt,branch
Attempting to add event pmu 'uncore_iio_free_running_5' with 'unc_iio_data_req_of_cpu.mem_read.part0,' that may result in non-fatal errors
After aliases, add event pmu 'uncore_iio_free_running_5' with 'fc_mask,ch_mask,umask,event,' that may result in non-fatal errors
Attempting to add event pmu 'uncore_iio_free_running_3' with 'unc_iio_data_req_of_cpu.mem_read.part0,' that may result in non-fatal errors
After aliases, add event pmu 'uncore_iio_free_running_3' with 'fc_mask,ch_mask,umask,event,' that may result in non-fatal errors
Attempting to add event pmu 'uncore_iio_free_running_1' with 'unc_iio_data_req_of_cpu.mem_read.part0,' that may result in non-fatal errors
After aliases, add event pmu 'uncore_iio_free_running_1' with 'fc_mask,ch_mask,umask,event,' that may result in non-fatal errors
Multiple errors dropping message: unknown term 'fc_mask' for pmu 'uncore_iio_free_running_3' (valid terms: event,umask,config,config1,config2,name,period,percore)
...
So before you see a 'WARNING: multiple event parsing errors' and
'Invalid event/parameter'. After you see 'Attempting... that may result
in non-fatal errors' then 'Multiple errors...' with details that
'fc_mask' wasn't known to a free running counter. While not completely
clean, this makes it clearer that an error hasn't really occurred.
v2. addresses review feedback from Jiri Olsa <jolsa@redhat.com>.
Signed-off-by: Ian Rogers <irogers@google.com>
Reviewed-by: Andi Kleen <ak@linux.intel.com>
Acked-by: Jiri Olsa <jolsa@redhat.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Jin Yao <yao.jin@linux.intel.com>
Cc: John Garry <john.garry@huawei.com>
Cc: Kan Liang <kan.liang@linux.intel.com>
Cc: Leo Yan <leo.yan@linaro.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Mathieu Poirier <mathieu.poirier@linaro.org>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stephane Eranian <eranian@google.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Link: http://lore.kernel.org/lkml/20200513220635.54700-1-irogers@google.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2020-05-13 15:06:35 -07:00
|
|
|
intel_pt_parse_terms(intel_pt_pmu->name, &intel_pt_pmu->format,
|
|
|
|
"tsc", &tsc_bit);
|
2015-07-17 19:33:41 +03:00
|
|
|
|
2019-07-21 13:24:29 +02:00
|
|
|
if (opts->full_auxtrace && (intel_pt_evsel->core.attr.config & tsc_bit))
|
2015-07-17 19:33:41 +03:00
|
|
|
have_timing_info = true;
|
|
|
|
else
|
|
|
|
have_timing_info = false;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Per-cpu recording needs sched_switch events to distinguish different
|
|
|
|
* threads.
|
|
|
|
*/
|
2020-05-28 15:08:58 +03:00
|
|
|
if (have_timing_info && !perf_cpu_map__empty(cpus) &&
|
|
|
|
!record_opts__no_switch_events(opts)) {
|
2015-08-13 12:40:57 +03:00
|
|
|
if (perf_can_record_switch_events()) {
|
|
|
|
bool cpu_wide = !target__none(&opts->target) &&
|
|
|
|
!target__has_task(&opts->target);
|
|
|
|
|
|
|
|
if (!cpu_wide && perf_can_record_cpu_wide()) {
|
2019-07-21 13:23:51 +02:00
|
|
|
struct evsel *switch_evsel;
|
2015-08-13 12:40:57 +03:00
|
|
|
|
|
|
|
err = parse_events(evlist, "dummy:u", NULL);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
2019-09-03 10:39:52 +02:00
|
|
|
switch_evsel = evlist__last(evlist);
|
2015-08-13 12:40:57 +03:00
|
|
|
|
2019-07-21 13:24:29 +02:00
|
|
|
switch_evsel->core.attr.freq = 0;
|
|
|
|
switch_evsel->core.attr.sample_period = 1;
|
|
|
|
switch_evsel->core.attr.context_switch = 1;
|
2015-08-13 12:40:57 +03:00
|
|
|
|
2019-08-06 11:35:19 +02:00
|
|
|
switch_evsel->core.system_wide = true;
|
2015-08-13 12:40:57 +03:00
|
|
|
switch_evsel->no_aux_samples = true;
|
|
|
|
switch_evsel->immediate = true;
|
|
|
|
|
2020-04-29 16:12:15 -03:00
|
|
|
evsel__set_sample_bit(switch_evsel, TID);
|
|
|
|
evsel__set_sample_bit(switch_evsel, TIME);
|
|
|
|
evsel__set_sample_bit(switch_evsel, CPU);
|
|
|
|
evsel__reset_sample_bit(switch_evsel, BRANCH_STACK);
|
2015-08-13 12:40:57 +03:00
|
|
|
|
|
|
|
opts->record_switch_events = false;
|
|
|
|
ptr->have_sched_switch = 3;
|
|
|
|
} else {
|
|
|
|
opts->record_switch_events = true;
|
2016-08-15 10:23:04 +03:00
|
|
|
need_immediate = true;
|
2015-08-13 12:40:57 +03:00
|
|
|
if (cpu_wide)
|
|
|
|
ptr->have_sched_switch = 3;
|
|
|
|
else
|
|
|
|
ptr->have_sched_switch = 2;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
err = intel_pt_track_switches(evlist);
|
|
|
|
if (err == -EPERM)
|
|
|
|
pr_debug2("Unable to select sched:sched_switch\n");
|
|
|
|
else if (err)
|
|
|
|
return err;
|
|
|
|
else
|
|
|
|
ptr->have_sched_switch = 1;
|
|
|
|
}
|
2015-07-17 19:33:41 +03:00
|
|
|
}
|
|
|
|
|
perf intel-pt: Add support for text poke events
Select text poke events when available and the kernel is being traced.
Process text poke events to invalidate entries in Intel PT's instruction
cache.
Example:
The example requires kernel config:
CONFIG_PROC_SYSCTL=y
CONFIG_SCHED_DEBUG=y
CONFIG_SCHEDSTATS=y
Before:
# perf record -o perf.data.before --kcore -a -e intel_pt//k -m,64M &
# cat /proc/sys/kernel/sched_schedstats
0
# echo 1 > /proc/sys/kernel/sched_schedstats
# cat /proc/sys/kernel/sched_schedstats
1
# echo 0 > /proc/sys/kernel/sched_schedstats
# cat /proc/sys/kernel/sched_schedstats
0
# kill %1
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 3.341 MB perf.data.before ]
[1]+ Terminated perf record -o perf.data.before --kcore -a -e intel_pt//k -m,64M
# perf script -i perf.data.before --itrace=e >/dev/null
Warning:
474 instruction trace errors
After:
# perf record -o perf.data.after --kcore -a -e intel_pt//k -m,64M &
# cat /proc/sys/kernel/sched_schedstats
0
# echo 1 > /proc/sys/kernel/sched_schedstats
# cat /proc/sys/kernel/sched_schedstats
1
# echo 0 > /proc/sys/kernel/sched_schedstats
# cat /proc/sys/kernel/sched_schedstats
0
# kill %1
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 2.646 MB perf.data.after ]
[1]+ Terminated perf record -o perf.data.after --kcore -a -e intel_pt//k -m,64M
# perf script -i perf.data.after --itrace=e >/dev/null
Example:
The example requires kernel config:
# CONFIG_FUNCTION_TRACER is not set
Before:
# perf record --kcore -m,64M -o t1 -a -e intel_pt//k &
# perf probe __schedule
Added new event:
probe:__schedule (on __schedule)
You can now use it in all perf tools, such as:
perf record -e probe:__schedule -aR sleep 1
# perf record -e probe:__schedule -aR sleep 1
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.026 MB perf.data (68 samples) ]
# perf probe -d probe:__schedule
Removed event: probe:__schedule
# kill %1
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 41.268 MB t1 ]
[1]+ Terminated perf record --kcore -m,64M -o t1 -a -e intel_pt//k
# perf script -i t1 --itrace=e >/dev/null
Warning:
207 instruction trace errors
After:
# perf record --kcore -m,64M -o t1 -a -e intel_pt//k &
# perf probe __schedule
Added new event:
probe:__schedule (on __schedule)
You can now use it in all perf tools, such as:
perf record -e probe:__schedule -aR sleep 1
# perf record -e probe:__schedule -aR sleep 1
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.028 MB perf.data (107 samples) ]
# perf probe -d probe:__schedule
Removed event: probe:__schedule
# kill %1
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 39.978 MB t1 ]
[1]+ Terminated perf record --kcore -m,64M -o t1 -a -e intel_pt//k
# perf script -i t1 --itrace=e >/dev/null
# perf script -i t1 --no-itrace -D | grep 'POKE\|KSYMBOL'
6 565303693547 0x291f18 [0x50]: PERF_RECORD_KSYMBOL addr ffffffffc027a000 len 4096 type 2 flags 0x0 name kprobe_insn_page
6 565303697010 0x291f68 [0x40]: PERF_RECORD_TEXT_POKE addr 0xffffffffc027a000 old len 0 new len 6
6 565303838278 0x291fa8 [0x50]: PERF_RECORD_KSYMBOL addr ffffffffc027c000 len 4096 type 2 flags 0x0 name kprobe_optinsn_page
6 565303848286 0x291ff8 [0xa0]: PERF_RECORD_TEXT_POKE addr 0xffffffffc027c000 old len 0 new len 106
6 565369336743 0x292af8 [0x40]: PERF_RECORD_TEXT_POKE addr 0xffffffff88ab8890 old len 5 new len 5
7 566434327704 0x217c208 [0x40]: PERF_RECORD_TEXT_POKE addr 0xffffffff88ab8890 old len 5 new len 5
6 566456313475 0x293198 [0xa0]: PERF_RECORD_TEXT_POKE addr 0xffffffffc027c000 old len 106 new len 0
6 566456314935 0x293238 [0x40]: PERF_RECORD_TEXT_POKE addr 0xffffffffc027a000 old len 6 new len 0
Example:
The example requires kernel config:
CONFIG_FUNCTION_TRACER=y
Before:
# perf record --kcore -m,64M -o t1 -a -e intel_pt//k &
# perf probe __kmalloc
Added new event:
probe:__kmalloc (on __kmalloc)
You can now use it in all perf tools, such as:
perf record -e probe:__kmalloc -aR sleep 1
# perf record -e probe:__kmalloc -aR sleep 1
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.022 MB perf.data (6 samples) ]
# perf probe -d probe:__kmalloc
Removed event: probe:__kmalloc
# kill %1
[ perf record: Woken up 2 times to write data ]
[ perf record: Captured and wrote 43.850 MB t1 ]
[1]+ Terminated perf record --kcore -m,64M -o t1 -a -e intel_pt//k
# perf script -i t1 --itrace=e >/dev/null
Warning:
8 instruction trace errors
After:
# perf record --kcore -m,64M -o t1 -a -e intel_pt//k &
# perf probe __kmalloc
Added new event:
probe:__kmalloc (on __kmalloc)
You can now use it in all perf tools, such as:
perf record -e probe:__kmalloc -aR sleep 1
# perf record -e probe:__kmalloc -aR sleep 1
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.037 MB perf.data (206 samples) ]
# perf probe -d probe:__kmalloc
Removed event: probe:__kmalloc
# kill %1
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 41.442 MB t1 ]
[1]+ Terminated perf record --kcore -m,64M -o t1 -a -e intel_pt//k
# perf script -i t1 --itrace=e >/dev/null
# perf script -i t1 --no-itrace -D | grep 'POKE\|KSYMBOL'
5 312216133258 0x8bafe0 [0x50]: PERF_RECORD_KSYMBOL addr ffffffffc0360000 len 415 type 2 flags 0x0 name ftrace_trampoline
5 312216133494 0x8bb030 [0x1d8]: PERF_RECORD_TEXT_POKE addr 0xffffffffc0360000 old len 0 new len 415
5 312216229563 0x8bb208 [0x40]: PERF_RECORD_TEXT_POKE addr 0xffffffffac6016f5 old len 5 new len 5
5 312216239063 0x8bb248 [0x40]: PERF_RECORD_TEXT_POKE addr 0xffffffffac601803 old len 5 new len 5
5 312216727230 0x8bb288 [0x40]: PERF_RECORD_TEXT_POKE addr 0xffffffffabbea190 old len 5 new len 5
5 312216739322 0x8bb2c8 [0x40]: PERF_RECORD_TEXT_POKE addr 0xffffffffac6016f5 old len 5 new len 5
5 312216748321 0x8bb308 [0x40]: PERF_RECORD_TEXT_POKE addr 0xffffffffac601803 old len 5 new len 5
7 313287163462 0x2817430 [0x40]: PERF_RECORD_TEXT_POKE addr 0xffffffffac6016f5 old len 5 new len 5
7 313287174890 0x2817470 [0x40]: PERF_RECORD_TEXT_POKE addr 0xffffffffac601803 old len 5 new len 5
7 313287818979 0x28174b0 [0x40]: PERF_RECORD_TEXT_POKE addr 0xffffffffabbea190 old len 5 new len 5
7 313287829357 0x28174f0 [0x40]: PERF_RECORD_TEXT_POKE addr 0xffffffffac6016f5 old len 5 new len 5
7 313287841246 0x2817530 [0x40]: PERF_RECORD_TEXT_POKE addr 0xffffffffac601803 old len 5 new len 5
Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Borislav Petkov <bp@alien8.de>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Leo Yan <leo.yan@linaro.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Masami Hiramatsu <mhiramat@kernel.org>
Cc: Mathieu Poirier <mathieu.poirier@linaro.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Steven Rostedt (VMware) <rostedt@goodmis.org>
Cc: x86@kernel.org
Link: http://lore.kernel.org/lkml/20200512121922.8997-14-adrian.hunter@intel.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2020-05-12 15:19:20 +03:00
|
|
|
if (have_timing_info && !intel_pt_evsel->core.attr.exclude_kernel &&
|
|
|
|
perf_can_record_text_poke_events() && perf_can_record_cpu_wide())
|
|
|
|
opts->text_poke = true;
|
|
|
|
|
2015-07-17 19:33:41 +03:00
|
|
|
if (intel_pt_evsel) {
|
|
|
|
/*
|
|
|
|
* To obtain the auxtrace buffer file descriptor, the auxtrace
|
|
|
|
* event must come first.
|
|
|
|
*/
|
|
|
|
perf_evlist__to_front(evlist, intel_pt_evsel);
|
|
|
|
/*
|
|
|
|
* In the case of per-cpu mmaps, we need the CPU on the
|
|
|
|
* AUX event.
|
|
|
|
*/
|
2019-08-22 13:11:39 +02:00
|
|
|
if (!perf_cpu_map__empty(cpus))
|
2020-04-29 16:12:15 -03:00
|
|
|
evsel__set_sample_bit(intel_pt_evsel, CPU);
|
2015-07-17 19:33:41 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Add dummy event to keep tracking */
|
|
|
|
if (opts->full_auxtrace) {
|
2019-07-21 13:23:51 +02:00
|
|
|
struct evsel *tracking_evsel;
|
2015-07-17 19:33:41 +03:00
|
|
|
|
|
|
|
err = parse_events(evlist, "dummy:u", NULL);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
2019-09-03 10:39:52 +02:00
|
|
|
tracking_evsel = evlist__last(evlist);
|
2015-07-17 19:33:41 +03:00
|
|
|
|
|
|
|
perf_evlist__set_tracking_event(evlist, tracking_evsel);
|
|
|
|
|
2019-07-21 13:24:29 +02:00
|
|
|
tracking_evsel->core.attr.freq = 0;
|
|
|
|
tracking_evsel->core.attr.sample_period = 1;
|
2015-07-17 19:33:41 +03:00
|
|
|
|
2017-06-30 10:16:55 -04:00
|
|
|
tracking_evsel->no_aux_samples = true;
|
2016-08-15 10:23:04 +03:00
|
|
|
if (need_immediate)
|
|
|
|
tracking_evsel->immediate = true;
|
|
|
|
|
2015-07-17 19:33:41 +03:00
|
|
|
/* In per-cpu case, always need the time of mmap events etc */
|
2019-08-22 13:11:39 +02:00
|
|
|
if (!perf_cpu_map__empty(cpus)) {
|
2020-04-29 16:12:15 -03:00
|
|
|
evsel__set_sample_bit(tracking_evsel, TIME);
|
2015-08-13 12:40:57 +03:00
|
|
|
/* And the CPU for switch events */
|
2020-04-29 16:12:15 -03:00
|
|
|
evsel__set_sample_bit(tracking_evsel, CPU);
|
2015-08-13 12:40:57 +03:00
|
|
|
}
|
2020-04-29 16:12:15 -03:00
|
|
|
evsel__reset_sample_bit(tracking_evsel, BRANCH_STACK);
|
2015-07-17 19:33:41 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Warn the user when we do not have enough information to decode i.e.
|
|
|
|
* per-cpu with no sched_switch (except workload-only).
|
|
|
|
*/
|
2019-08-22 13:11:39 +02:00
|
|
|
if (!ptr->have_sched_switch && !perf_cpu_map__empty(cpus) &&
|
2020-05-28 15:08:59 +03:00
|
|
|
!target__none(&opts->target) &&
|
|
|
|
!intel_pt_evsel->core.attr.exclude_user)
|
2015-07-17 19:33:41 +03:00
|
|
|
ui__warning("Intel Processor Trace decoding will not be possible except for kernel tracing!\n");
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int intel_pt_snapshot_start(struct auxtrace_record *itr)
|
|
|
|
{
|
|
|
|
struct intel_pt_recording *ptr =
|
|
|
|
container_of(itr, struct intel_pt_recording, itr);
|
2019-07-21 13:23:51 +02:00
|
|
|
struct evsel *evsel;
|
2015-07-17 19:33:41 +03:00
|
|
|
|
2016-06-23 11:26:15 -03:00
|
|
|
evlist__for_each_entry(ptr->evlist, evsel) {
|
2019-07-21 13:24:29 +02:00
|
|
|
if (evsel->core.attr.type == ptr->intel_pt_pmu->type)
|
2019-07-21 13:24:03 +02:00
|
|
|
return evsel__disable(evsel);
|
2015-07-17 19:33:41 +03:00
|
|
|
}
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int intel_pt_snapshot_finish(struct auxtrace_record *itr)
|
|
|
|
{
|
|
|
|
struct intel_pt_recording *ptr =
|
|
|
|
container_of(itr, struct intel_pt_recording, itr);
|
2019-07-21 13:23:51 +02:00
|
|
|
struct evsel *evsel;
|
2015-07-17 19:33:41 +03:00
|
|
|
|
2016-06-23 11:26:15 -03:00
|
|
|
evlist__for_each_entry(ptr->evlist, evsel) {
|
2019-07-21 13:24:29 +02:00
|
|
|
if (evsel->core.attr.type == ptr->intel_pt_pmu->type)
|
2019-07-21 13:24:02 +02:00
|
|
|
return evsel__enable(evsel);
|
2015-07-17 19:33:41 +03:00
|
|
|
}
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int intel_pt_alloc_snapshot_refs(struct intel_pt_recording *ptr, int idx)
|
|
|
|
{
|
|
|
|
const size_t sz = sizeof(struct intel_pt_snapshot_ref);
|
|
|
|
int cnt = ptr->snapshot_ref_cnt, new_cnt = cnt * 2;
|
|
|
|
struct intel_pt_snapshot_ref *refs;
|
|
|
|
|
|
|
|
if (!new_cnt)
|
|
|
|
new_cnt = 16;
|
|
|
|
|
|
|
|
while (new_cnt <= idx)
|
|
|
|
new_cnt *= 2;
|
|
|
|
|
|
|
|
refs = calloc(new_cnt, sz);
|
|
|
|
if (!refs)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
memcpy(refs, ptr->snapshot_refs, cnt * sz);
|
|
|
|
|
|
|
|
ptr->snapshot_refs = refs;
|
|
|
|
ptr->snapshot_ref_cnt = new_cnt;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void intel_pt_free_snapshot_refs(struct intel_pt_recording *ptr)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < ptr->snapshot_ref_cnt; i++)
|
|
|
|
zfree(&ptr->snapshot_refs[i].ref_buf);
|
|
|
|
zfree(&ptr->snapshot_refs);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void intel_pt_recording_free(struct auxtrace_record *itr)
|
|
|
|
{
|
|
|
|
struct intel_pt_recording *ptr =
|
|
|
|
container_of(itr, struct intel_pt_recording, itr);
|
|
|
|
|
|
|
|
intel_pt_free_snapshot_refs(ptr);
|
|
|
|
free(ptr);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int intel_pt_alloc_snapshot_ref(struct intel_pt_recording *ptr, int idx,
|
|
|
|
size_t snapshot_buf_size)
|
|
|
|
{
|
|
|
|
size_t ref_buf_size = ptr->snapshot_ref_buf_size;
|
|
|
|
void *ref_buf;
|
|
|
|
|
|
|
|
ref_buf = zalloc(ref_buf_size);
|
|
|
|
if (!ref_buf)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
ptr->snapshot_refs[idx].ref_buf = ref_buf;
|
|
|
|
ptr->snapshot_refs[idx].ref_offset = snapshot_buf_size - ref_buf_size;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static size_t intel_pt_snapshot_ref_buf_size(struct intel_pt_recording *ptr,
|
|
|
|
size_t snapshot_buf_size)
|
|
|
|
{
|
|
|
|
const size_t max_size = 256 * 1024;
|
|
|
|
size_t buf_size = 0, psb_period;
|
|
|
|
|
|
|
|
if (ptr->snapshot_size <= 64 * 1024)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
psb_period = intel_pt_psb_period(ptr->intel_pt_pmu, ptr->evlist);
|
|
|
|
if (psb_period)
|
|
|
|
buf_size = psb_period * 2;
|
|
|
|
|
|
|
|
if (!buf_size || buf_size > max_size)
|
|
|
|
buf_size = max_size;
|
|
|
|
|
|
|
|
if (buf_size >= snapshot_buf_size)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (buf_size >= ptr->snapshot_size / 2)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
return buf_size;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int intel_pt_snapshot_init(struct intel_pt_recording *ptr,
|
|
|
|
size_t snapshot_buf_size)
|
|
|
|
{
|
|
|
|
if (ptr->snapshot_init_done)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
ptr->snapshot_init_done = true;
|
|
|
|
|
|
|
|
ptr->snapshot_ref_buf_size = intel_pt_snapshot_ref_buf_size(ptr,
|
|
|
|
snapshot_buf_size);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* intel_pt_compare_buffers - compare bytes in a buffer to a circular buffer.
|
|
|
|
* @buf1: first buffer
|
|
|
|
* @compare_size: number of bytes to compare
|
|
|
|
* @buf2: second buffer (a circular buffer)
|
|
|
|
* @offs2: offset in second buffer
|
|
|
|
* @buf2_size: size of second buffer
|
|
|
|
*
|
|
|
|
* The comparison allows for the possibility that the bytes to compare in the
|
|
|
|
* circular buffer are not contiguous. It is assumed that @compare_size <=
|
|
|
|
* @buf2_size. This function returns %false if the bytes are identical, %true
|
|
|
|
* otherwise.
|
|
|
|
*/
|
|
|
|
static bool intel_pt_compare_buffers(void *buf1, size_t compare_size,
|
|
|
|
void *buf2, size_t offs2, size_t buf2_size)
|
|
|
|
{
|
|
|
|
size_t end2 = offs2 + compare_size, part_size;
|
|
|
|
|
|
|
|
if (end2 <= buf2_size)
|
|
|
|
return memcmp(buf1, buf2 + offs2, compare_size);
|
|
|
|
|
|
|
|
part_size = end2 - buf2_size;
|
|
|
|
if (memcmp(buf1, buf2 + offs2, part_size))
|
|
|
|
return true;
|
|
|
|
|
|
|
|
compare_size -= part_size;
|
|
|
|
|
|
|
|
return memcmp(buf1 + part_size, buf2, compare_size);
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool intel_pt_compare_ref(void *ref_buf, size_t ref_offset,
|
|
|
|
size_t ref_size, size_t buf_size,
|
|
|
|
void *data, size_t head)
|
|
|
|
{
|
|
|
|
size_t ref_end = ref_offset + ref_size;
|
|
|
|
|
|
|
|
if (ref_end > buf_size) {
|
|
|
|
if (head > ref_offset || head < ref_end - buf_size)
|
|
|
|
return true;
|
|
|
|
} else if (head > ref_offset && head < ref_end) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return intel_pt_compare_buffers(ref_buf, ref_size, data, ref_offset,
|
|
|
|
buf_size);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void intel_pt_copy_ref(void *ref_buf, size_t ref_size, size_t buf_size,
|
|
|
|
void *data, size_t head)
|
|
|
|
{
|
|
|
|
if (head >= ref_size) {
|
|
|
|
memcpy(ref_buf, data + head - ref_size, ref_size);
|
|
|
|
} else {
|
|
|
|
memcpy(ref_buf, data, head);
|
|
|
|
ref_size -= head;
|
|
|
|
memcpy(ref_buf + head, data + buf_size - ref_size, ref_size);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool intel_pt_wrapped(struct intel_pt_recording *ptr, int idx,
|
|
|
|
struct auxtrace_mmap *mm, unsigned char *data,
|
|
|
|
u64 head)
|
|
|
|
{
|
|
|
|
struct intel_pt_snapshot_ref *ref = &ptr->snapshot_refs[idx];
|
|
|
|
bool wrapped;
|
|
|
|
|
|
|
|
wrapped = intel_pt_compare_ref(ref->ref_buf, ref->ref_offset,
|
|
|
|
ptr->snapshot_ref_buf_size, mm->len,
|
|
|
|
data, head);
|
|
|
|
|
|
|
|
intel_pt_copy_ref(ref->ref_buf, ptr->snapshot_ref_buf_size, mm->len,
|
|
|
|
data, head);
|
|
|
|
|
|
|
|
return wrapped;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool intel_pt_first_wrap(u64 *data, size_t buf_size)
|
|
|
|
{
|
|
|
|
int i, a, b;
|
|
|
|
|
|
|
|
b = buf_size >> 3;
|
|
|
|
a = b - 512;
|
|
|
|
if (a < 0)
|
|
|
|
a = 0;
|
|
|
|
|
|
|
|
for (i = a; i < b; i++) {
|
|
|
|
if (data[i])
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int intel_pt_find_snapshot(struct auxtrace_record *itr, int idx,
|
|
|
|
struct auxtrace_mmap *mm, unsigned char *data,
|
|
|
|
u64 *head, u64 *old)
|
|
|
|
{
|
|
|
|
struct intel_pt_recording *ptr =
|
|
|
|
container_of(itr, struct intel_pt_recording, itr);
|
|
|
|
bool wrapped;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
pr_debug3("%s: mmap index %d old head %zu new head %zu\n",
|
|
|
|
__func__, idx, (size_t)*old, (size_t)*head);
|
|
|
|
|
|
|
|
err = intel_pt_snapshot_init(ptr, mm->len);
|
|
|
|
if (err)
|
|
|
|
goto out_err;
|
|
|
|
|
|
|
|
if (idx >= ptr->snapshot_ref_cnt) {
|
|
|
|
err = intel_pt_alloc_snapshot_refs(ptr, idx);
|
|
|
|
if (err)
|
|
|
|
goto out_err;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ptr->snapshot_ref_buf_size) {
|
|
|
|
if (!ptr->snapshot_refs[idx].ref_buf) {
|
|
|
|
err = intel_pt_alloc_snapshot_ref(ptr, idx, mm->len);
|
|
|
|
if (err)
|
|
|
|
goto out_err;
|
|
|
|
}
|
|
|
|
wrapped = intel_pt_wrapped(ptr, idx, mm, data, *head);
|
|
|
|
} else {
|
|
|
|
wrapped = ptr->snapshot_refs[idx].wrapped;
|
|
|
|
if (!wrapped && intel_pt_first_wrap((u64 *)data, mm->len)) {
|
|
|
|
ptr->snapshot_refs[idx].wrapped = true;
|
|
|
|
wrapped = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* In full trace mode 'head' continually increases. However in snapshot
|
|
|
|
* mode 'head' is an offset within the buffer. Here 'old' and 'head'
|
|
|
|
* are adjusted to match the full trace case which expects that 'old' is
|
|
|
|
* always less than 'head'.
|
|
|
|
*/
|
|
|
|
if (wrapped) {
|
|
|
|
*old = *head;
|
|
|
|
*head += mm->len;
|
|
|
|
} else {
|
|
|
|
if (mm->mask)
|
|
|
|
*old &= mm->mask;
|
|
|
|
else
|
|
|
|
*old %= mm->len;
|
|
|
|
if (*old > *head)
|
|
|
|
*head += mm->len;
|
|
|
|
}
|
|
|
|
|
|
|
|
pr_debug3("%s: wrap-around %sdetected, adjusted old head %zu adjusted new head %zu\n",
|
|
|
|
__func__, wrapped ? "" : "not ", (size_t)*old, (size_t)*head);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
out_err:
|
|
|
|
pr_err("%s: failed, error %d\n", __func__, err);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
static u64 intel_pt_reference(struct auxtrace_record *itr __maybe_unused)
|
|
|
|
{
|
|
|
|
return rdtsc();
|
|
|
|
}
|
|
|
|
|
|
|
|
struct auxtrace_record *intel_pt_recording_init(int *err)
|
|
|
|
{
|
|
|
|
struct perf_pmu *intel_pt_pmu = perf_pmu__find(INTEL_PT_PMU_NAME);
|
|
|
|
struct intel_pt_recording *ptr;
|
|
|
|
|
|
|
|
if (!intel_pt_pmu)
|
|
|
|
return NULL;
|
|
|
|
|
2016-03-08 10:38:53 +02:00
|
|
|
if (setenv("JITDUMP_USE_ARCH_TIMESTAMP", "1", 1)) {
|
|
|
|
*err = -errno;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2015-07-17 19:33:41 +03:00
|
|
|
ptr = zalloc(sizeof(struct intel_pt_recording));
|
|
|
|
if (!ptr) {
|
|
|
|
*err = -ENOMEM;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
ptr->intel_pt_pmu = intel_pt_pmu;
|
2020-02-17 10:23:00 +02:00
|
|
|
ptr->itr.pmu = intel_pt_pmu;
|
2015-07-17 19:33:41 +03:00
|
|
|
ptr->itr.recording_options = intel_pt_recording_options;
|
|
|
|
ptr->itr.info_priv_size = intel_pt_info_priv_size;
|
|
|
|
ptr->itr.info_fill = intel_pt_info_fill;
|
|
|
|
ptr->itr.free = intel_pt_recording_free;
|
|
|
|
ptr->itr.snapshot_start = intel_pt_snapshot_start;
|
|
|
|
ptr->itr.snapshot_finish = intel_pt_snapshot_finish;
|
|
|
|
ptr->itr.find_snapshot = intel_pt_find_snapshot;
|
|
|
|
ptr->itr.parse_snapshot_options = intel_pt_parse_snapshot_options;
|
|
|
|
ptr->itr.reference = intel_pt_reference;
|
2020-02-17 10:23:00 +02:00
|
|
|
ptr->itr.read_finish = auxtrace_record__read_finish;
|
2019-11-15 14:42:23 +02:00
|
|
|
/*
|
|
|
|
* Decoding starts at a PSB packet. Minimum PSB period is 2K so 4K
|
|
|
|
* should give at least 1 PSB per sample.
|
|
|
|
*/
|
|
|
|
ptr->itr.default_aux_sample_size = 4096;
|
2015-07-17 19:33:41 +03:00
|
|
|
return &ptr->itr;
|
|
|
|
}
|