Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1250192 > unrolled thread
| Started by | Mathieu Poirier <mathieu.poirier@linaro.org> |
|---|---|
| First post | 2015-10-18 20:30 +0200 |
| Last post | 2015-10-18 20:40 +0200 |
| Articles | 20 on this page of 30 — 3 participants |
Back to article view | Back to linux.kernel
[PATCH V2 00/30] Coresight integration with perf Mathieu Poirier <mathieu.poirier@linaro.org> - 2015-10-18 20:30 +0200
[PATCH V2 18/30] coresight: etb10: moving to local atomic operations Mathieu Poirier <mathieu.poirier@linaro.org> - 2015-10-18 20:30 +0200
[PATCH V2 30/30] perf tools: adding coresight etm PMU record capabilities Mathieu Poirier <mathieu.poirier@linaro.org> - 2015-10-18 20:30 +0200
[PATCH V2 19/30] coresight: etb10: implementing the setup_aux() API Mathieu Poirier <mathieu.poirier@linaro.org> - 2015-10-18 20:30 +0200
Re: [PATCH V2 19/30] coresight: etb10: implementing the setup_aux() API Alexander Shishkin <alexander.shishkin@linux.intel.com> - 2015-10-19 15:50 +0200
Re: [PATCH V2 19/30] coresight: etb10: implementing the setup_aux() API Mathieu Poirier <mathieu.poirier@linaro.org> - 2015-10-20 18:50 +0200
Re: [PATCH V2 19/30] coresight: etb10: implementing the setup_aux() API Alexander Shishkin <alexander.shishkin@linux.intel.com> - 2015-10-20 13:50 +0200
[PATCH V2 07/30] coresight: etm3x: moving etm_drvdata::enable to atomic field Mathieu Poirier <mathieu.poirier@linaro.org> - 2015-10-18 20:30 +0200
[PATCH V2 05/30] coresight: etm3x: set progbit to stop trace collection Mathieu Poirier <mathieu.poirier@linaro.org> - 2015-10-18 20:30 +0200
[PATCH V2 22/30] coresight: etm-perf: new PMU driver for ETM tracers Mathieu Poirier <mathieu.poirier@linaro.org> - 2015-10-18 20:30 +0200
Re: [PATCH V2 22/30] coresight: etm-perf: new PMU driver for ETM tracers Alexander Shishkin <alexander.shishkin@linux.intel.com> - 2015-10-19 17:50 +0200
Re: [PATCH V2 22/30] coresight: etm-perf: new PMU driver for ETM tracers Mathieu Poirier <mathieu.poirier@linaro.org> - 2015-10-20 18:50 +0200
Re: [PATCH V2 22/30] coresight: etm-perf: new PMU driver for ETM tracers Alexander Shishkin <alexander.shishkin@linux.intel.com> - 2015-10-20 11:40 +0200
Re: [PATCH V2 22/30] coresight: etm-perf: new PMU driver for ETM tracers Mathieu Poirier <mathieu.poirier@linaro.org> - 2015-10-20 21:20 +0200
[PATCH V2 25/30] perf tools: adding perf_session to *info_prive_size() Mathieu Poirier <mathieu.poirier@linaro.org> - 2015-10-18 20:30 +0200
[PATCH V2 10/30] coresight: etm3x: consolidating initial config Mathieu Poirier <mathieu.poirier@linaro.org> - 2015-10-18 20:30 +0200
[PATCH V2 26/30] perf tools: making source devices path broadly accessible Mathieu Poirier <mathieu.poirier@linaro.org> - 2015-10-18 20:30 +0200
[PATCH V2 21/30] coresight: etb10: implementing buffer update API Mathieu Poirier <mathieu.poirier@linaro.org> - 2015-10-18 20:30 +0200
[PATCH V2 15/30] coresight: making coresight_build_paths() public Mathieu Poirier <mathieu.poirier@linaro.org> - 2015-10-18 20:40 +0200
[PATCH V2 08/30] coresight: etm3x: implementing 'cpu_id()' API Mathieu Poirier <mathieu.poirier@linaro.org> - 2015-10-18 20:40 +0200
[PATCH V2 17/30] perf: changing pmu::setup_aux() parameter to include event Mathieu Poirier <mathieu.poirier@linaro.org> - 2015-10-18 20:40 +0200
Re: [PATCH V2 17/30] perf: changing pmu::setup_aux() parameter to include event Alexander Shishkin <alexander.shishkin@linux.intel.com> - 2015-10-19 15:40 +0200
[PATCH V2 06/30] coresight: clearly labeling source operarions Mathieu Poirier <mathieu.poirier@linaro.org> - 2015-10-18 20:40 +0200
[PATCH V2 12/30] coresight: etm3x: adding perf_get/set_config() API Mathieu Poirier <mathieu.poirier@linaro.org> - 2015-10-18 20:40 +0200
[PATCH V2 03/30] coresight: etm3x: unlocking tracers in default arch init Mathieu Poirier <mathieu.poirier@linaro.org> - 2015-10-18 20:40 +0200
[PATCH V2 11/30] coresight: etm3x: implementing user/kernel mode tracing Mathieu Poirier <mathieu.poirier@linaro.org> - 2015-10-18 20:40 +0200
[PATCH V2 09/30] coresight: etm3x: changing default trace configuration Mathieu Poirier <mathieu.poirier@linaro.org> - 2015-10-18 20:40 +0200
[PATCH V2 01/30] coresight: etm3x: moving etm_readl/writel to header file Mathieu Poirier <mathieu.poirier@linaro.org> - 2015-10-18 20:40 +0200
Re: [PATCH V2 01/30] coresight: etm3x: moving etm_readl/writel to header file Greg KH <gregkh@linuxfoundation.org> - 2015-10-19 20:40 +0200
[PATCH V2 13/30] coresight: etm3x: implementing perf_enable/disable() API Mathieu Poirier <mathieu.poirier@linaro.org> - 2015-10-18 20:40 +0200
Page 1 of 2 [1] 2 Next page →
| From | Mathieu Poirier <mathieu.poirier@linaro.org> |
|---|---|
| Date | 2015-10-18 20:30 +0200 |
| Subject | [PATCH V2 00/30] Coresight integration with perf |
| Message-ID | <ql0St-4NE-3@gated-at.bofh.it> |
This patchset aims to integrate configuration and control of the Coresight tracers with the perf sub-system. The goal is to use PMUs to represent tracers and the auxiliary buffer enhancement to collect processor traces. As such a lot of work is done to move the current Coresight sysFS oriented configuration and control commands to perf's AUX API. For the time being the work concentrates on ETMv3 and ETB1.0 sink buffers. Work on ETMv4 and other type of sink buffers will follow once a foundation has been established. Best regards, Mathieu Changes since V1: * Fixed typos in typographical error in documentation. * Moved to a multi session support scheme. * Split static and dynamic tracer configuration. * Fixed configuration for user and kernel space tracing. * Using WARN_ON_ONCE() rather than WARN_ON(). * Implemented strategy to prevent tracers from being used simultaneously. * Changed sink_ops::unset_buffer() to sink_ops::reset_buffer(). * Moves ETM's sysFS interface from driver core to dedicated file. * Removed spinlock in "etm_cpu_id()". * Aggregated PMU driver pieces in a single patch. * Added user space changes and rebased everything to v4.3-rc5. Mathieu Poirier (30): coresight: etm3x: moving etm_readl/writel to header file coresight: etm3x: moving sysFS entries to dedicated file coresight: etm3x: unlocking tracers in default arch init coresight: etm3x: splitting struct etm_drvdata coresight: etm3x: set progbit to stop trace collection coresight: clearly labeling source operarions coresight: etm3x: moving etm_drvdata::enable to atomic field coresight: etm3x: implementing 'cpu_id()' API coresight: etm3x: changing default trace configuration coresight: etm3x: consolidating initial config coresight: etm3x: implementing user/kernel mode tracing coresight: etm3x: adding perf_get/set_config() API coresight: etm3x: implementing perf_enable/disable() API coresight: etm3x: implementing perf_start/stop() API coresight: making coresight_build_paths() public coresight: keeping track of enabled sink buffers perf: changing pmu::setup_aux() parameter to include event coresight: etb10: moving to local atomic operations coresight: etb10: implementing the setup_aux() API coresight: etb10: implementing buffer set/reset() API coresight: etb10: implementing buffer update API coresight: etm-perf: new PMU driver for ETM tracers coresight: updating documentation to reflect integration with perf perf tools: making function set_max_cpu_num() non static perf tools: adding perf_session to *info_prive_size() perf tools: making source devices path broadly accessible perf build: adding X86 auxiliary specific flags perf tools: making coresight PMU listable perf tools: adding coresight define for auxtrace perf tools: adding coresight etm PMU record capabilities Documentation/trace/coresight.txt | 138 +- arch/x86/kernel/cpu/perf_event_intel_bts.c | 4 +- arch/x86/kernel/cpu/perf_event_intel_pt.c | 5 +- drivers/hwtracing/coresight/Makefile | 4 +- drivers/hwtracing/coresight/coresight-etb10.c | 247 ++- drivers/hwtracing/coresight/coresight-etm-perf.c | 533 ++++++ drivers/hwtracing/coresight/coresight-etm-perf.h | 27 + drivers/hwtracing/coresight/coresight-etm.h | 151 +- .../hwtracing/coresight/coresight-etm3x-sysfs.c | 1442 ++++++++++++++++ drivers/hwtracing/coresight/coresight-etm3x.c | 1724 ++++---------------- drivers/hwtracing/coresight/coresight-etm4x.c | 8 +- drivers/hwtracing/coresight/coresight-priv.h | 4 + drivers/hwtracing/coresight/coresight.c | 27 +- include/linux/coresight.h | 51 +- include/linux/perf_event.h | 2 +- kernel/events/ring_buffer.c | 2 +- tools/perf/arch/arm/util/Build | 2 + tools/perf/arch/arm/util/auxtrace.c | 48 + tools/perf/arch/arm/util/cs_etm.c | 444 +++++ tools/perf/arch/arm/util/cs_etm.h | 37 + tools/perf/arch/arm/util/pmu.c | 18 + tools/perf/arch/x86/util/Build | 6 +- tools/perf/arch/x86/util/intel-bts.c | 4 +- tools/perf/arch/x86/util/intel-pt.c | 4 +- tools/perf/arch/x86/util/pmu.c | 2 +- tools/perf/builtin-inject.c | 2 +- tools/perf/builtin-record.c | 2 +- tools/perf/config/Makefile | 19 +- tools/perf/util/Build | 6 +- tools/perf/util/auxtrace.c | 8 +- tools/perf/util/auxtrace.h | 9 +- tools/perf/util/cpumap.c | 2 +- tools/perf/util/cpumap.h | 1 + tools/perf/util/intel-bts.h | 11 + tools/perf/util/intel-pt-decoder/Build | 2 +- tools/perf/util/intel-pt.h | 15 + tools/perf/util/pmu.c | 2 - tools/perf/util/pmu.h | 1 + 38 files changed, 3531 insertions(+), 1483 deletions(-) create mode 100644 drivers/hwtracing/coresight/coresight-etm-perf.c create mode 100644 drivers/hwtracing/coresight/coresight-etm-perf.h create mode 100644 drivers/hwtracing/coresight/coresight-etm3x-sysfs.c create mode 100644 tools/perf/arch/arm/util/auxtrace.c create mode 100644 tools/perf/arch/arm/util/cs_etm.c create mode 100644 tools/perf/arch/arm/util/cs_etm.h create mode 100644 tools/perf/arch/arm/util/pmu.c -- 1.9.1 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[toc] | [next] | [standalone]
| From | Mathieu Poirier <mathieu.poirier@linaro.org> |
|---|---|
| Date | 2015-10-18 20:30 +0200 |
| Subject | [PATCH V2 18/30] coresight: etb10: moving to local atomic operations |
| Message-ID | <ql0Sv-4NE-47@gated-at.bofh.it> |
| In reply to | #1250192 |
Moving to use local atomic operations to take advantage of the
lockless implementation, something that will come handy when
the ETB is accessed from the Perf subsystem.
Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
---
drivers/hwtracing/coresight/coresight-etb10.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-etb10.c b/drivers/hwtracing/coresight/coresight-etb10.c
index 77d0f9c1118d..ecdbe0dd4d08 100644
--- a/drivers/hwtracing/coresight/coresight-etb10.c
+++ b/drivers/hwtracing/coresight/coresight-etb10.c
@@ -84,7 +84,7 @@ struct etb_drvdata {
struct coresight_device *csdev;
struct miscdevice miscdev;
spinlock_t spinlock;
- atomic_t in_use;
+ local_t in_use;
u8 *buf;
u32 buffer_depth;
bool enable;
@@ -281,7 +281,7 @@ static int etb_open(struct inode *inode, struct file *file)
struct etb_drvdata *drvdata = container_of(file->private_data,
struct etb_drvdata, miscdev);
- if (atomic_cmpxchg(&drvdata->in_use, 0, 1))
+ if (local_cmpxchg(&drvdata->in_use, 0, 1))
return -EBUSY;
dev_dbg(drvdata->dev, "%s: successfully opened\n", __func__);
@@ -317,7 +317,7 @@ static int etb_release(struct inode *inode, struct file *file)
{
struct etb_drvdata *drvdata = container_of(file->private_data,
struct etb_drvdata, miscdev);
- atomic_set(&drvdata->in_use, 0);
+ local_set(&drvdata->in_use, 0);
dev_dbg(drvdata->dev, "%s: released\n", __func__);
return 0;
--
1.9.1
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Mathieu Poirier <mathieu.poirier@linaro.org> |
|---|---|
| Date | 2015-10-18 20:30 +0200 |
| Subject | [PATCH V2 30/30] perf tools: adding coresight etm PMU record capabilities |
| Message-ID | <ql0Su-4NE-31@gated-at.bofh.it> |
| In reply to | #1250192 |
Coresight ETMs are IP blocks allowing to perform HW assisted tracing
on a CPU core. This patch introduce the required auxiliary API
functions allowing the perf core to interact with a tracer.
Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
---
tools/perf/arch/arm/util/Build | 2 +-
tools/perf/arch/arm/util/auxtrace.c | 48 ++++
tools/perf/arch/arm/util/cs_etm.c | 444 ++++++++++++++++++++++++++++++++++++
tools/perf/arch/arm/util/cs_etm.h | 37 +++
4 files changed, 530 insertions(+), 1 deletion(-)
create mode 100644 tools/perf/arch/arm/util/auxtrace.c
create mode 100644 tools/perf/arch/arm/util/cs_etm.c
create mode 100644 tools/perf/arch/arm/util/cs_etm.h
diff --git a/tools/perf/arch/arm/util/Build b/tools/perf/arch/arm/util/Build
index 371a3bf12297..87545604b029 100644
--- a/tools/perf/arch/arm/util/Build
+++ b/tools/perf/arch/arm/util/Build
@@ -3,4 +3,4 @@ libperf-$(CONFIG_DWARF) += dwarf-regs.o
libperf-$(CONFIG_LIBUNWIND) += unwind-libunwind.o
libperf-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o
-libperf-$(CONFIG_AUXTRACE_ARM) += pmu.o
+libperf-$(CONFIG_AUXTRACE_ARM) += pmu.o auxtrace.o cs_etm.o
diff --git a/tools/perf/arch/arm/util/auxtrace.c b/tools/perf/arch/arm/util/auxtrace.c
new file mode 100644
index 000000000000..4988fdf7cb8a
--- /dev/null
+++ b/tools/perf/arch/arm/util/auxtrace.c
@@ -0,0 +1,48 @@
+/*
+ * Copyright(C) 2015 Linaro Limited. All rights reserved.
+ * Author: Mathieu Poirier <mathieu.poirier@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdbool.h>
+#include <linux/coresight-pmu.h>
+
+#include "../../util/auxtrace.h"
+#include "../../util/evlist.h"
+#include "../../util/pmu.h"
+#include "cs_etm.h"
+
+struct auxtrace_record
+*auxtrace_record__init(struct perf_evlist *evlist, int *err)
+{
+ struct perf_pmu *cs_etm_pmu;
+ struct perf_evsel *evsel;
+ bool found_etm = false;
+
+ cs_etm_pmu = perf_pmu__find(CORESIGHT_ETM_PMU_NAME);
+
+ if (evlist) {
+ evlist__for_each(evlist, evsel) {
+ if (cs_etm_pmu &&
+ evsel->attr.type == cs_etm_pmu->type)
+ found_etm = true;
+ }
+ }
+
+ if (found_etm)
+ return cs_etm_record_init(err);
+
+ *err = -EINVAL;
+ return NULL;
+}
diff --git a/tools/perf/arch/arm/util/cs_etm.c b/tools/perf/arch/arm/util/cs_etm.c
new file mode 100644
index 000000000000..2e89b44dd4da
--- /dev/null
+++ b/tools/perf/arch/arm/util/cs_etm.c
@@ -0,0 +1,444 @@
+/*
+ * Copyright(C) 2015 Linaro Limited. All rights reserved.
+ * Author: Mathieu Poirier <mathieu.poirier@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <api/fs/fs.h>
+#include <linux/bitops.h>
+#include <linux/coresight-pmu.h>
+#include <linux/kernel.h>
+#include <linux/log2.h>
+#include <linux/types.h>
+
+#include "../../perf.h"
+#include "../../util/auxtrace.h"
+#include "../../util/cpumap.h"
+#include "../../util/evlist.h"
+#include "../../util/pmu.h"
+#include "../../util/thread_map.h"
+#include "cs_etm.h"
+
+#include <stdlib.h>
+
+/* Also used by Intel - should go to a common header */
+#define KiB(x) ((x) * 1024)
+#define MiB(x) ((x) * 1024 * 1024)
+
+struct cs_etm_recording {
+ struct auxtrace_record itr;
+ struct perf_pmu *cs_etm_pmu;
+ struct perf_evlist *evlist;
+ bool snapshot_mode;
+ size_t snapshot_size;
+};
+
+static int cs_etm_parse_snapshot_options(struct auxtrace_record *itr,
+ struct record_opts *opts,
+ const char *str)
+{
+ struct cs_etm_recording *ptr =
+ container_of(itr, struct cs_etm_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;
+}
+
+static int cs_etm_recording_options(struct auxtrace_record *itr,
+ struct perf_evlist *evlist,
+ struct record_opts *opts)
+{
+ struct cs_etm_recording *ptr =
+ container_of(itr, struct cs_etm_recording, itr);
+ struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu;
+ struct perf_evsel *evsel, *cs_etm_evsel = NULL;
+ const struct cpu_map *cpus = evlist->cpus;
+ bool privileged = (geteuid() == 0 || perf_event_paranoid() < 0);
+
+ ptr->evlist = evlist;
+ ptr->snapshot_mode = opts->auxtrace_snapshot_mode;
+
+ evlist__for_each(evlist, evsel) {
+ if (evsel->attr.type == cs_etm_pmu->type) {
+ if (cs_etm_evsel) {
+ pr_err("There may be only one %s event\n",
+ CORESIGHT_ETM_PMU_NAME);
+ return -EINVAL;
+ }
+ evsel->attr.freq = 0;
+ evsel->attr.sample_period = 1;
+ cs_etm_evsel = evsel;
+ opts->full_auxtrace = true;
+ }
+ }
+
+ /* no need to continue if at least one event of interest was found */
+ if (!cs_etm_evsel)
+ return 0;
+
+ if (opts->use_clockid) {
+ pr_err("Cannot use clockid (-k option) with %s\n",
+ CORESIGHT_ETM_PMU_NAME);
+ return -EINVAL;
+ }
+
+ /* we are in snapshot mode */
+ if (opts->auxtrace_snapshot_mode) {
+ /*
+ * No size were given to '-S' or '-m,', so go with
+ * the default
+ */
+ 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;
+ }
+
+ /*
+ * '-m,xyz' was specified but no snapshot size, so make the
+ * snapshot size as big as the auxtrace mmap area.
+ */
+ if (!opts->auxtrace_snapshot_size) {
+ opts->auxtrace_snapshot_size =
+ opts->auxtrace_mmap_pages * (size_t)page_size;
+ }
+
+ /*
+ * -Sxyz was specified but no auxtrace mmap area, so make the
+ * auxtrace mmap area big enough to fit the requested snapshot
+ * 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);
+ }
+
+ /* Snapshost size can't be bigger than the auxtrace area */
+ 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;
+ }
+
+ /* Something went wrong somewhere - this shouldn't happen */
+ 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;
+ }
+ }
+
+ /* We are in full trace mode but '-m,xyz' wasn't specified */
+ 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 provided by user */
+ if (opts->auxtrace_mmap_pages) {
+ unsigned int max_page = (KiB(128) / page_size);
+ size_t sz = opts->auxtrace_mmap_pages * (size_t)page_size;
+
+ if (!privileged &&
+ opts->auxtrace_mmap_pages > max_page) {
+ opts->auxtrace_mmap_pages = max_page;
+ pr_err("auxtrace too big, truncating to %d\n",
+ max_page);
+ }
+
+ if (!is_power_of_2(sz)) {
+ pr_err("Invalid mmap size for %s: must be a power of 2\n",
+ CORESIGHT_ETM_PMU_NAME);
+ return -EINVAL;
+ }
+ }
+
+ if (opts->auxtrace_snapshot_mode)
+ pr_debug2("%s snapshot size: %zu\n", CORESIGHT_ETM_PMU_NAME,
+ opts->auxtrace_snapshot_size);
+
+ if (cs_etm_evsel) {
+ /*
+ * To obtain the auxtrace buffer file descriptor, the auxtrace
+ * event must come first.
+ */
+ perf_evlist__to_front(evlist, cs_etm_evsel);
+ /*
+ * In the case of per-cpu mmaps, we need the CPU on the
+ * AUX event.
+ */
+ if (!cpu_map__empty(cpus))
+ perf_evsel__set_sample_bit(cs_etm_evsel, CPU);
+ }
+
+ /* Add dummy event to keep tracking */
+ if (opts->full_auxtrace) {
+ struct perf_evsel *tracking_evsel;
+ int err;
+
+ err = parse_events(evlist, "dummy:u", NULL);
+ if (err)
+ return err;
+
+ tracking_evsel = perf_evlist__last(evlist);
+ perf_evlist__set_tracking_event(evlist, tracking_evsel);
+
+ tracking_evsel->attr.freq = 0;
+ tracking_evsel->attr.sample_period = 1;
+
+ /* In per-cpu case, always need the time of mmap events etc */
+ if (!cpu_map__empty(cpus))
+ perf_evsel__set_sample_bit(tracking_evsel, TIME);
+ }
+
+ return 0;
+}
+
+static size_t
+cs_etm_info_priv_size(struct auxtrace_record *itr __maybe_unused,
+ struct perf_session *session __maybe_unused)
+{
+ int records;
+ const struct cpu_map *cpus = session->evlist->cpus;
+
+ if (!cpu_map__empty(cpus)) {
+ records = cpu_map__nr(cpus);
+ goto out;
+ }
+
+ set_max_cpu_num();
+ records = cpu__max_cpu();
+out:
+ return records * CS_ETM_PRIV_SIZE;
+}
+
+static const char *metadata[CS_ETM_PRIV_MAX] = {
+ [CS_ETM_ETMCR] = "etmcr",
+ [CS_ETM_ETMCCER] = "etmccer",
+ [CS_ETM_ETMIDR] = "etmidr",
+ [CS_ETM_ETMTRACEIDR] = "etmtraceidr",
+};
+
+static int cs_etm_get_metadata(int cpu, int offset,
+ struct cs_etm_recording *ptr,
+ struct auxtrace_info_event *info)
+{
+ int i, ret = 0;
+ const char *sysfs = sysfs__mountpoint();
+
+ if (!sysfs)
+ return -EINVAL;
+
+ info->priv[offset + CS_ETM_MAGIC] = __perf_cs_etm_magic;
+ info->priv[offset + CS_ETM_CPU] = cpu;
+ info->priv[offset + CS_ETM_SNAPSHOT] = ptr->snapshot_mode;
+
+ /* get metadata from sysfs */
+ for (i = CS_ETM_ETMCR; i < CS_ETM_PRIV_MAX && !ret; i++) {
+ FILE *file;
+ char path[PATH_MAX], value[128];
+
+ snprintf(path, PATH_MAX,
+ "%s" EVENT_SOURCE_DEVICE_PATH "%s/cpu%d/mgmt/%s",
+ sysfs, CORESIGHT_ETM_PMU_NAME, cpu, metadata[i]);
+
+ file = fopen(path, "r");
+ if (!file)
+ return -EINVAL;
+
+ if (fscanf(file, "%s", value) != 1)
+ ret = -EINVAL;
+
+ fclose(file);
+
+ info->priv[offset + i] = strtol(value, NULL, 16);
+ }
+
+ return 0;
+}
+
+static int cs_etm_info_fill(struct auxtrace_record *itr,
+ struct perf_session *session,
+ struct auxtrace_info_event *auxtrace_info,
+ size_t priv_size)
+{
+ int i, nr_cpu, ret = 0;
+ const struct cpu_map *cpus = session->evlist->cpus;
+ struct cs_etm_recording *ptr =
+ container_of(itr, struct cs_etm_recording, itr);
+
+ if (priv_size != cs_etm_info_priv_size(itr, session))
+ return -EINVAL;
+
+ if (!session->evlist->nr_mmaps)
+ return -EINVAL;
+
+ auxtrace_info->type = PERF_AUXTRACE_CS_ETM;
+
+ /* cpu map is not empty, we have specific CPUs to work with */
+ if (!cpu_map__empty(cpus)) {
+ for (i = 0; i < cpu_map__nr(cpus); i++)
+ ret = cs_etm_get_metadata(cpus->map[i],
+ i * CS_ETM_PRIV_MAX,
+ ptr, auxtrace_info);
+ if (ret)
+ goto out;
+ }
+
+ /* get configuration for all CPUs in the system */
+ nr_cpu = cpu__max_cpu();
+ for (i = 0; i < nr_cpu; i++) {
+ ret = cs_etm_get_metadata(i, i * CS_ETM_PRIV_MAX,
+ ptr, auxtrace_info);
+ if (ret)
+ goto out;
+ }
+
+out:
+ return ret;
+}
+
+static int cs_etm_find_snapshot(struct auxtrace_record *itr __maybe_unused,
+ int idx, struct auxtrace_mmap *mm,
+ unsigned char *data __maybe_unused,
+ u64 *head, u64 *old)
+{
+ pr_debug3("%s: mmap index %d old head %zu new head %zu size %zu\n",
+ __func__, idx, (size_t)*old, (size_t)*head, mm->len);
+
+ *old = *head;
+ *head += mm->len;
+
+ return 0;
+}
+
+static int cs_etm_snapshot_start(struct auxtrace_record *itr)
+{
+ struct cs_etm_recording *ptr =
+ container_of(itr, struct cs_etm_recording, itr);
+ struct perf_evsel *evsel;
+
+ evlist__for_each(ptr->evlist, evsel) {
+ if (evsel->attr.type == ptr->cs_etm_pmu->type)
+ return perf_evlist__disable_event(ptr->evlist, evsel);
+ }
+ return -EINVAL;
+}
+
+static int cs_etm_snapshot_finish(struct auxtrace_record *itr)
+{
+ struct cs_etm_recording *ptr =
+ container_of(itr, struct cs_etm_recording, itr);
+ struct perf_evsel *evsel;
+
+ evlist__for_each(ptr->evlist, evsel) {
+ if (evsel->attr.type == ptr->cs_etm_pmu->type)
+ return perf_evlist__enable_event(ptr->evlist, evsel);
+ }
+ return -EINVAL;
+}
+
+static u64 cs_etm_reference(struct auxtrace_record *itr __maybe_unused)
+{
+ return (((u64) rand() << 0) & 0x00000000FFFFFFFFull) |
+ (((u64) rand() << 32) & 0xFFFFFFFF00000000ull);
+}
+
+static void cs_etm_recording_free(struct auxtrace_record *itr)
+{
+ struct cs_etm_recording *ptr =
+ container_of(itr, struct cs_etm_recording, itr);
+ free(ptr);
+}
+
+static int cs_etm_read_finish(struct auxtrace_record *itr, int idx)
+{
+ struct cs_etm_recording *ptr =
+ container_of(itr, struct cs_etm_recording, itr);
+ struct perf_evsel *evsel;
+
+ evlist__for_each(ptr->evlist, evsel) {
+ if (evsel->attr.type == ptr->cs_etm_pmu->type)
+ return perf_evlist__enable_event_idx(ptr->evlist,
+ evsel, idx);
+ }
+
+ return -EINVAL;
+}
+
+struct auxtrace_record *cs_etm_record_init(int *err)
+{
+ struct perf_pmu *cs_etm_pmu;
+ struct cs_etm_recording *ptr;
+
+ cs_etm_pmu = perf_pmu__find(CORESIGHT_ETM_PMU_NAME);
+
+ if (!cs_etm_pmu) {
+ *err = -EINVAL;
+ goto out;
+ }
+
+ ptr = zalloc(sizeof(struct cs_etm_recording));
+ if (!ptr) {
+ *err = -ENOMEM;
+ goto out;
+ }
+
+ ptr->cs_etm_pmu = cs_etm_pmu;
+ ptr->itr.parse_snapshot_options = cs_etm_parse_snapshot_options;
+ ptr->itr.recording_options = cs_etm_recording_options;
+ ptr->itr.info_priv_size = cs_etm_info_priv_size;
+ ptr->itr.info_fill = cs_etm_info_fill;
+ ptr->itr.find_snapshot = cs_etm_find_snapshot;
+ ptr->itr.snapshot_start = cs_etm_snapshot_start;
+ ptr->itr.snapshot_finish = cs_etm_snapshot_finish;
+ ptr->itr.reference = cs_etm_reference;
+ ptr->itr.free = cs_etm_recording_free;
+ ptr->itr.read_finish = cs_etm_read_finish;
+
+ *err = 0;
+ return &ptr->itr;
+out:
+ return NULL;
+}
diff --git a/tools/perf/arch/arm/util/cs_etm.h b/tools/perf/arch/arm/util/cs_etm.h
new file mode 100644
index 000000000000..b3b3f16d80e3
--- /dev/null
+++ b/tools/perf/arch/arm/util/cs_etm.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright(C) 2015 Linaro Limited. All rights reserved.
+ * Author: Mathieu Poirier <mathieu.poirier@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef INCLUDE__PERF_CS_ETM_H__
+#define INCLUDE__PERF_CS_ETM_H__
+
+enum {
+ CS_ETM_MAGIC,
+ CS_ETM_CPU,
+ CS_ETM_SNAPSHOT,
+ CS_ETM_ETMCR,
+ CS_ETM_ETMCCER,
+ CS_ETM_ETMIDR,
+ CS_ETM_ETMTRACEIDR,
+ CS_ETM_PRIV_MAX,
+};
+
+static const u64 __perf_cs_etm_magic = 0x3030303030303030ULL;
+#define CS_ETM_PRIV_SIZE (CS_ETM_PRIV_MAX * sizeof(u64))
+
+struct auxtrace_record *cs_etm_record_init(int *err);
+
+#endif
--
1.9.1
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Mathieu Poirier <mathieu.poirier@linaro.org> |
|---|---|
| Date | 2015-10-18 20:30 +0200 |
| Subject | [PATCH V2 19/30] coresight: etb10: implementing the setup_aux() API |
| Message-ID | <ql0Sv-4NE-39@gated-at.bofh.it> |
| In reply to | #1250192 |
Adding an ETB10 specific auxiliary area setup operation to be
used by the perf framework when events are initialised.
Part of this operation involves modeling the mmap'ed area based
on the specific ways a sink buffer gathers information.
Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
---
drivers/hwtracing/coresight/coresight-etb10.c | 55 +++++++++++++++++++++++++++
include/linux/coresight.h | 3 ++
2 files changed, 58 insertions(+)
diff --git a/drivers/hwtracing/coresight/coresight-etb10.c b/drivers/hwtracing/coresight/coresight-etb10.c
index ecdbe0dd4d08..7f34e7af465e 100644
--- a/drivers/hwtracing/coresight/coresight-etb10.c
+++ b/drivers/hwtracing/coresight/coresight-etb10.c
@@ -27,6 +27,9 @@
#include <linux/coresight.h>
#include <linux/amba/bus.h>
#include <linux/clk.h>
+#include <linux/mm.h>
+
+#include <asm/local.h>
#include "coresight-priv.h"
@@ -64,6 +67,32 @@
#define ETB_FRAME_SIZE_WORDS 4
/**
+ * struct cs_buffer - keep track of a recording session' specifics
+ * @cur: index of the current buffer
+ * @nr_pages: max number of pages granted to us
+ * @nr_bufs: number of clustered pages
+ * @offset: offset within the current buffer
+ * @size: how much space we have for this run
+ * @data_size: how much we collected in this run
+ * @head: head of the ring buffer
+ * @lost: other than zero if we had a HW buffer wrap around
+ * @snapshot: is this run in snapshot mode
+ * @addr: virtual address this buffer starts at
+ */
+struct cs_buffers {
+ unsigned int cur;
+ unsigned int nr_pages;
+ unsigned int nr_bufs;
+ unsigned long offset;
+ unsigned long size;
+ local_t data_size;
+ local_t head;
+ local_t lost;
+ bool snapshot;
+ void *addr[0];
+};
+
+/**
* struct etb_drvdata - specifics associated to an ETB component
* @base: memory mapped base address for this component.
* @dev: the device entity associated to this component.
@@ -252,9 +281,35 @@ static void etb_disable(struct coresight_device *csdev)
dev_info(drvdata->dev, "ETB disabled\n");
}
+static void *etb_setup_aux(struct coresight_device *csdev, int cpu,
+ void **pages, int nr_pages, bool overwrite)
+{
+ int node, pg;
+ struct cs_buffers *buf;
+
+ if (cpu == -1)
+ cpu = smp_processor_id();
+ node = cpu_to_node(cpu);
+
+ buf = kzalloc_node(offsetof(struct cs_buffers, addr[nr_pages]),
+ GFP_KERNEL, node);
+ if (!buf)
+ return NULL;
+
+ buf->snapshot = overwrite;
+ buf->nr_pages = nr_pages;
+
+ /* Record information about buffers */
+ for (pg = 0; pg < buf->nr_pages; pg++)
+ buf->addr[pg] = pages[pg];
+
+ return buf;
+}
+
static const struct coresight_ops_sink etb_sink_ops = {
.enable = etb_enable,
.disable = etb_disable,
+ .setup_aux = etb_setup_aux,
};
static const struct coresight_ops etb_cs_ops = {
diff --git a/include/linux/coresight.h b/include/linux/coresight.h
index dd530a6d3e21..b1c25eba83b4 100644
--- a/include/linux/coresight.h
+++ b/include/linux/coresight.h
@@ -187,10 +187,13 @@ struct coresight_device {
* Operations available for sinks
* @enable: enables the sink.
* @disable: disables the sink.
+ * @setup_aux: initialises perf's ring buffer for trace collection.
*/
struct coresight_ops_sink {
int (*enable)(struct coresight_device *csdev);
void (*disable)(struct coresight_device *csdev);
+ void *(*setup_aux)(struct coresight_device *csdev, int cpu,
+ void **pages, int nr_pages, bool overwrite);
};
/**
--
1.9.1
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Alexander Shishkin <alexander.shishkin@linux.intel.com> |
|---|---|
| Date | 2015-10-19 15:50 +0200 |
| Subject | Re: [PATCH V2 19/30] coresight: etb10: implementing the setup_aux() API |
| Message-ID | <qliZ4-613-9@gated-at.bofh.it> |
| In reply to | #1250195 |
Mathieu Poirier <mathieu.poirier@linaro.org> writes:
> Adding an ETB10 specific auxiliary area setup operation to be
> used by the perf framework when events are initialised.
>
> Part of this operation involves modeling the mmap'ed area based
> on the specific ways a sink buffer gathers information.
It really doesn't seem to be ETB10 specific at all. When you add more
sinks, you'll probably end up copying this code every time.
Furthermore,
> +static void *etb_setup_aux(struct coresight_device *csdev, int cpu,
> + void **pages, int nr_pages, bool overwrite)
> +{
> + int node, pg;
> + struct cs_buffers *buf;
> +
> + if (cpu == -1)
> + cpu = smp_processor_id();
> + node = cpu_to_node(cpu);
> +
> + buf = kzalloc_node(offsetof(struct cs_buffers, addr[nr_pages]),
> + GFP_KERNEL, node);
> + if (!buf)
> + return NULL;
> +
> + buf->snapshot = overwrite;
> + buf->nr_pages = nr_pages;
> +
> + /* Record information about buffers */
> + for (pg = 0; pg < buf->nr_pages; pg++)
> + buf->addr[pg] = pages[pg];
> +
> + return buf;
> +}
> +
this one is so generic that I'm tempted to move this into perf's
ring_buffer code, because by the looks of it we'll need it pretty much
in every setup_aux().
Regards,
--
Alex
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Mathieu Poirier <mathieu.poirier@linaro.org> |
|---|---|
| Date | 2015-10-20 18:50 +0200 |
| Subject | Re: [PATCH V2 19/30] coresight: etb10: implementing the setup_aux() API |
| Message-ID | <qlIgN-YP-1@gated-at.bofh.it> |
| In reply to | #1250727 |
On 19 October 2015 at 07:44, Alexander Shishkin
<alexander.shishkin@linux.intel.com> wrote:
> Mathieu Poirier <mathieu.poirier@linaro.org> writes:
>
>> Adding an ETB10 specific auxiliary area setup operation to be
>> used by the perf framework when events are initialised.
>>
>> Part of this operation involves modeling the mmap'ed area based
>> on the specific ways a sink buffer gathers information.
>
> It really doesn't seem to be ETB10 specific at all. When you add more
> sinks, you'll probably end up copying this code every time.
That will depend on how that specific sinks work, but indeed, it is
pretty generic.
>
> Furthermore,
>
>> +static void *etb_setup_aux(struct coresight_device *csdev, int cpu,
>> + void **pages, int nr_pages, bool overwrite)
>> +{
>> + int node, pg;
>> + struct cs_buffers *buf;
>> +
>> + if (cpu == -1)
>> + cpu = smp_processor_id();
>> + node = cpu_to_node(cpu);
>> +
>> + buf = kzalloc_node(offsetof(struct cs_buffers, addr[nr_pages]),
>> + GFP_KERNEL, node);
>> + if (!buf)
>> + return NULL;
>> +
>> + buf->snapshot = overwrite;
>> + buf->nr_pages = nr_pages;
>> +
>> + /* Record information about buffers */
>> + for (pg = 0; pg < buf->nr_pages; pg++)
>> + buf->addr[pg] = pages[pg];
>> +
>> + return buf;
>> +}
>> +
>
> this one is so generic that I'm tempted to move this into perf's
> ring_buffer code, because by the looks of it we'll need it pretty much
> in every setup_aux().
It is tempting but I suggest we wait to see what kind of trend we get
before moving ahead with this. There is always opportunity for
further consolidation should the need arise.
>
> Regards,
> --
> Alex
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Alexander Shishkin <alexander.shishkin@linux.intel.com> |
|---|---|
| Date | 2015-10-20 13:50 +0200 |
| Subject | Re: [PATCH V2 19/30] coresight: etb10: implementing the setup_aux() API |
| Message-ID | <qlDAu-2Db-17@gated-at.bofh.it> |
| In reply to | #1250195 |
Mathieu Poirier <mathieu.poirier@linaro.org> writes:
> /**
> + * struct cs_buffer - keep track of a recording session' specifics
> + * @cur: index of the current buffer
> + * @nr_pages: max number of pages granted to us
> + * @nr_bufs: number of clustered pages
> + * @offset: offset within the current buffer
> + * @size: how much space we have for this run
> + * @data_size: how much we collected in this run
> + * @head: head of the ring buffer
> + * @lost: other than zero if we had a HW buffer wrap around
> + * @snapshot: is this run in snapshot mode
> + * @addr: virtual address this buffer starts at
> + */
> +struct cs_buffers {
> + unsigned int cur;
> + unsigned int nr_pages;
> + unsigned int nr_bufs;
This one is not really used.
> + unsigned long offset;
> + unsigned long size;
And this one seems to be only set in one place.
> + local_t data_size;
> + local_t head;
And so is this one.
> + local_t lost;
> + bool snapshot;
> + void *addr[0];
And this one seems to be a copy of what perf's ring buffer gives us.
> +static void *etb_setup_aux(struct coresight_device *csdev, int cpu,
> + void **pages, int nr_pages, bool overwrite)
> +{
> + int node, pg;
> + struct cs_buffers *buf;
> +
> + if (cpu == -1)
> + cpu = smp_processor_id();
> + node = cpu_to_node(cpu);
> +
> + buf = kzalloc_node(offsetof(struct cs_buffers, addr[nr_pages]),
> + GFP_KERNEL, node);
> + if (!buf)
> + return NULL;
> +
> + buf->snapshot = overwrite;
> + buf->nr_pages = nr_pages;
> +
> + /* Record information about buffers */
> + for (pg = 0; pg < buf->nr_pages; pg++)
> + buf->addr[pg] = pages[pg];
Yes, buf::addr is a copy of @pages. You could save some space by just
saving @pages, it's going to be around until pmu::free_aux().
Regards,
--
Alex
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Mathieu Poirier <mathieu.poirier@linaro.org> |
|---|---|
| Date | 2015-10-18 20:30 +0200 |
| Subject | [PATCH V2 07/30] coresight: etm3x: moving etm_drvdata::enable to atomic field |
| Message-ID | <ql0Sv-4NE-41@gated-at.bofh.it> |
| In reply to | #1250192 |
Moving etm_drvdata::enable to an atomic type that gives the
'state' of the tracer, i.e disabled, handled via sysFS or Perf.
That way a tracer can't be used if it is already marshaled by
another subsystem.
Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
---
drivers/hwtracing/coresight/coresight-etm.h | 11 +++++++++--
drivers/hwtracing/coresight/coresight-etm3x-sysfs.c | 4 ++--
drivers/hwtracing/coresight/coresight-etm3x.c | 21 +++++++++++++++------
3 files changed, 26 insertions(+), 10 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-etm.h b/drivers/hwtracing/coresight/coresight-etm.h
index 9317510d555f..0996537ff142 100644
--- a/drivers/hwtracing/coresight/coresight-etm.h
+++ b/drivers/hwtracing/coresight/coresight-etm.h
@@ -13,6 +13,7 @@
#ifndef _CORESIGHT_CORESIGHT_ETM_H
#define _CORESIGHT_CORESIGHT_ETM_H
+#include <asm/local.h>
#include <linux/spinlock.h>
#include "coresight-priv.h"
@@ -214,7 +215,7 @@ struct etm_config {
* @port_size: port size as reported by ETMCR bit 4-6 and 21.
* @arch: ETM/PTM version number.
* @use_cpu14: true if management registers need to be accessed via CP14.
- * @enable: is this ETM/PTM currently tracing.
+ * @state: this tracer's state, i.e sysFS, Perf or disabled.
* @sticky_enable: true if ETM base configuration has been done.
* @boot_enable:true if we should start tracing at boot time.
* @os_unlock: true if access to management registers is allowed.
@@ -238,7 +239,7 @@ struct etm_drvdata {
int port_size;
u8 arch;
bool use_cp14;
- bool enable;
+ local_t state;
bool sticky_enable;
bool boot_enable;
bool os_unlock;
@@ -253,6 +254,12 @@ struct etm_drvdata {
struct etm_config *config;
};
+enum etm_state {
+ ETM_STATE_DISABLED,
+ ETM_STATE_SYSFS,
+ ETM_STATE_PERF,
+};
+
enum etm_addr_type {
ETM_ADDR_TYPE_NONE,
ETM_ADDR_TYPE_SINGLE,
diff --git a/drivers/hwtracing/coresight/coresight-etm3x-sysfs.c b/drivers/hwtracing/coresight/coresight-etm3x-sysfs.c
index 410d29e2b90c..bc8f04214567 100644
--- a/drivers/hwtracing/coresight/coresight-etm3x-sysfs.c
+++ b/drivers/hwtracing/coresight/coresight-etm3x-sysfs.c
@@ -811,7 +811,7 @@ static ssize_t cntr_val_show(struct device *dev,
if (WARN_ON_ONCE(!config))
return -EINVAL;
- if (!drvdata->enable) {
+ if (!local_read(&drvdata->state)) {
spin_lock(&drvdata->spinlock);
for (i = 0; i < drvdata->nr_cntr; i++)
ret += sprintf(buf, "counter %d: %x\n",
@@ -1072,7 +1072,7 @@ static ssize_t seq_curr_state_show(struct device *dev,
if (WARN_ON_ONCE(!config))
return -EINVAL;
- if (!drvdata->enable) {
+ if (!local_read(&drvdata->state)) {
val = config->seq_curr_state;
goto out;
}
diff --git a/drivers/hwtracing/coresight/coresight-etm3x.c b/drivers/hwtracing/coresight/coresight-etm3x.c
index 3d7fa0b2acf9..3fe6433764d4 100644
--- a/drivers/hwtracing/coresight/coresight-etm3x.c
+++ b/drivers/hwtracing/coresight/coresight-etm3x.c
@@ -320,7 +320,7 @@ int etm_get_trace_id(struct etm_drvdata *drvdata)
if (!drvdata)
goto out;
- if (!drvdata->enable)
+ if (!local_read(&drvdata->state))
return drvdata->traceid;
pm_runtime_get_sync(drvdata->dev);
@@ -354,6 +354,12 @@ static int sysfs_etm_enable(struct coresight_device *csdev)
pm_runtime_get_sync(csdev->dev.parent);
spin_lock(&drvdata->spinlock);
+ if (local_cmpxchg(&drvdata->state,
+ ETM_STATE_DISABLED, ETM_STATE_SYSFS)) {
+ ret = -EBUSY;
+ goto out;
+ }
+
/*
* Configure the ETM only if the CPU is online. If it isn't online
* hw configuration will take place when 'CPU_STARTING' is received
@@ -366,17 +372,20 @@ static int sysfs_etm_enable(struct coresight_device *csdev)
goto err;
}
- drvdata->enable = true;
drvdata->sticky_enable = true;
spin_unlock(&drvdata->spinlock);
dev_info(drvdata->dev, "ETM tracing enabled\n");
return 0;
-err:
+out:
spin_unlock(&drvdata->spinlock);
pm_runtime_put(csdev->dev.parent);
return ret;
+
+err:
+ local_set(&drvdata->state, ETM_STATE_DISABLED);
+ goto out;
}
static void etm_disable_hw(void *info)
@@ -425,7 +434,7 @@ static void sysfs_etm_disable(struct coresight_device *csdev)
* ensures that register writes occur when cpu is powered.
*/
smp_call_function_single(drvdata->cpu, etm_disable_hw, drvdata, 1);
- drvdata->enable = false;
+ local_set(&drvdata->state, ETM_STATE_DISABLED);
spin_unlock(&drvdata->spinlock);
put_online_cpus();
@@ -460,7 +469,7 @@ static int etm_cpu_callback(struct notifier_block *nfb, unsigned long action,
etmdrvdata[cpu]->os_unlock = true;
}
- if (etmdrvdata[cpu]->enable)
+ if (local_read(&etmdrvdata[cpu]->state))
etm_enable_hw(etmdrvdata[cpu]);
spin_unlock(&etmdrvdata[cpu]->spinlock);
break;
@@ -473,7 +482,7 @@ static int etm_cpu_callback(struct notifier_block *nfb, unsigned long action,
case CPU_DYING:
spin_lock(&etmdrvdata[cpu]->spinlock);
- if (etmdrvdata[cpu]->enable)
+ if (local_read(&etmdrvdata[cpu]->state))
etm_disable_hw(etmdrvdata[cpu]);
spin_unlock(&etmdrvdata[cpu]->spinlock);
break;
--
1.9.1
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Mathieu Poirier <mathieu.poirier@linaro.org> |
|---|---|
| Date | 2015-10-18 20:30 +0200 |
| Subject | [PATCH V2 05/30] coresight: etm3x: set progbit to stop trace collection |
| Message-ID | <ql0Sv-4NE-55@gated-at.bofh.it> |
| In reply to | #1250192 |
There is no need to use the event enable's "always false" event to stop trace collection. For that purpose setting the programming bit (ETMCR:10) is enough. Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org> --- drivers/hwtracing/coresight/coresight-etm3x.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-etm3x.c b/drivers/hwtracing/coresight/coresight-etm3x.c index 966955f5b0f9..713ffe1b761f 100644 --- a/drivers/hwtracing/coresight/coresight-etm3x.c +++ b/drivers/hwtracing/coresight/coresight-etm3x.c @@ -391,9 +391,6 @@ static void etm_disable_hw(void *info) CS_UNLOCK(drvdata->base); etm_set_prog(drvdata); - /* Program trace enable to low by using always false event */ - etm_writel(drvdata, ETM_HARD_WIRE_RES_A | ETM_EVENT_NOT_A, ETMTEEVR); - /* Read back sequencer and counters for post trace analysis */ config->seq_curr_state = (etm_readl(drvdata, ETMSQR) & ETM_SQR_MASK); -- 1.9.1 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Mathieu Poirier <mathieu.poirier@linaro.org> |
|---|---|
| Date | 2015-10-18 20:30 +0200 |
| Subject | [PATCH V2 22/30] coresight: etm-perf: new PMU driver for ETM tracers |
| Message-ID | <ql0Sv-4NE-45@gated-at.bofh.it> |
| In reply to | #1250192 |
Perf is a well known and used tool for performance monitoring
and much more. A such it is an ideal condaditate for integration
with coresight based HW tracing.
This patch introduces a PMU that represent a coresight tracer to
the Perf core.
Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
---
drivers/hwtracing/coresight/Makefile | 3 +-
drivers/hwtracing/coresight/coresight-etm-perf.c | 533 +++++++++++++++++++++++
drivers/hwtracing/coresight/coresight-etm-perf.h | 27 ++
drivers/hwtracing/coresight/coresight-etm3x.c | 7 +
4 files changed, 569 insertions(+), 1 deletion(-)
create mode 100644 drivers/hwtracing/coresight/coresight-etm-perf.c
create mode 100644 drivers/hwtracing/coresight/coresight-etm-perf.h
diff --git a/drivers/hwtracing/coresight/Makefile b/drivers/hwtracing/coresight/Makefile
index 233d66cf22d3..cf8c6d689747 100644
--- a/drivers/hwtracing/coresight/Makefile
+++ b/drivers/hwtracing/coresight/Makefile
@@ -9,6 +9,7 @@ obj-$(CONFIG_CORESIGHT_SINK_ETBV10) += coresight-etb10.o
obj-$(CONFIG_CORESIGHT_LINKS_AND_SINKS) += coresight-funnel.o \
coresight-replicator.o
obj-$(CONFIG_CORESIGHT_SOURCE_ETM3X) += coresight-etm3x.o coresight-etm-cp14.o \
- coresight-etm3x-sysfs.o
+ coresight-etm3x-sysfs.o \
+ coresight-etm-perf.o
obj-$(CONFIG_CORESIGHT_SOURCE_ETM4X) += coresight-etm4x.o
obj-$(CONFIG_CORESIGHT_QCOM_REPLICATOR) += coresight-replicator-qcom.o
diff --git a/drivers/hwtracing/coresight/coresight-etm-perf.c b/drivers/hwtracing/coresight/coresight-etm-perf.c
new file mode 100644
index 000000000000..dbd02277fcda
--- /dev/null
+++ b/drivers/hwtracing/coresight/coresight-etm-perf.c
@@ -0,0 +1,533 @@
+/*
+ * Copyright(C) 2015 Linaro Limited. All rights reserved.
+ * Author: Mathieu Poirier <mathieu.poirier@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/coresight.h>
+#include <linux/cpumask.h>
+#include <linux/device.h>
+#include <linux/list.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/perf_event.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+
+#include "coresight-priv.h"
+
+#define CORESIGHT_ETM_PMU_NAME "cs_etm"
+
+static struct pmu etm_pmu;
+static bool etm_perf_up;
+
+/**
+ * struct etm_event_data - Coresight specifics associated to an event
+ * @mask: hold the CPU(s) this event was set for.
+ * @source_config: per CPU tracer configuration associated to a
+ * trace session.
+ * @sink_config: per CPU AUX configuration associated to a
+ * trace session.
+ * @sink: sink associated to a CPU.
+ */
+struct etm_event_data {
+ cpumask_t mask;
+ void **source_config;
+ void **sink_config;
+ void **sink;
+};
+
+static DEFINE_PER_CPU(struct perf_output_handle, ctx_handle);
+static DEFINE_PER_CPU(struct coresight_device *, csdev_src);
+
+/* ETMCR is 'config' */
+PMU_FORMAT_ATTR(cycacc, "config:12");
+PMU_FORMAT_ATTR(timestamp, "config:28");
+
+static struct attribute *etm_config_formats_attr[] = {
+ &format_attr_cycacc.attr,
+ &format_attr_timestamp.attr,
+ NULL,
+};
+
+static struct attribute_group etm_pmu_format_group = {
+ .name = "format",
+ .attrs = etm_config_formats_attr,
+};
+
+static const struct attribute_group *etm_pmu_attr_groups[] = {
+ &etm_pmu_format_group,
+ NULL,
+};
+
+static void etm_event_read(struct perf_event *event) {}
+
+/**
+ * etm_event_build_path() - setup a path between source and sink
+ * @cpu: The CPU the tracer is associated to.
+ * @build: Whether the path should be setup or thorned down.
+ *
+ * Return: The _first_ sink buffer discovered during the walkthrough.
+ */
+static struct coresight_device *etm_event_build_path(int cpu, bool build)
+{
+ int ret = 0;
+ LIST_HEAD(path);
+ LIST_HEAD(sinks);
+ struct coresight_device *csdev_source;
+ struct coresight_device *csdev_sink = NULL;
+
+ csdev_source = per_cpu(csdev_src, cpu);
+
+ if (!csdev_source)
+ return ERR_PTR(-EINVAL);
+
+ if (csdev_source->type != CORESIGHT_DEV_TYPE_SOURCE)
+ return ERR_PTR(-EINVAL);
+
+ if (build) {
+ ret = coresight_build_paths(csdev_source, &path, &sinks, build);
+ if (ret) {
+ dev_dbg(&csdev_source->dev,
+ "creating path(s) failed\n");
+ goto out;
+ }
+
+ /* Everything is good, record first enabled sink buffer */
+ csdev_sink = list_first_entry(&sinks,
+ struct coresight_device, sinks);
+ } else {
+ ret = coresight_build_paths(csdev_source, &path, NULL, build);
+ if (ret)
+ dev_dbg(&csdev_source->dev,
+ "releasing path(s) failed\n");
+ }
+
+out:
+ return csdev_sink;
+}
+
+static int etm_event_pmu_start(struct perf_event *event)
+{
+ int cpu, ret;
+ cpumask_t mask;
+ struct coresight_device *csdev;
+
+ cpumask_clear(&mask);
+ if (event->cpu != -1)
+ cpumask_set_cpu(event->cpu, &mask);
+ else
+ cpumask_copy(&mask, cpu_online_mask);
+
+ for_each_cpu(cpu, &mask) {
+ csdev = per_cpu(csdev_src, cpu);
+
+ if (!source_ops(csdev)->perf_start)
+ continue;
+
+ ret = source_ops(csdev)->perf_start(csdev);
+ if (ret)
+ goto err;
+ }
+
+out:
+ return ret;
+err:
+ for_each_cpu(cpu, &mask) {
+ csdev = per_cpu(csdev_src, cpu);
+
+ if (!source_ops(csdev)->perf_stop)
+ continue;
+ source_ops(csdev)->perf_stop(csdev);
+ }
+
+ goto out;
+}
+
+static void etm_event_destroy(struct perf_event *event)
+{
+ int cpu;
+ cpumask_t mask;
+ struct coresight_device *csdev;
+
+ cpumask_clear(&mask);
+ if (event->cpu != -1)
+ cpumask_set_cpu(event->cpu, &mask);
+ else
+ cpumask_copy(&mask, cpu_online_mask);
+
+ for_each_cpu(cpu, &mask) {
+ csdev = per_cpu(csdev_src, cpu);
+ etm_event_build_path(cpu, false);
+
+ if (!source_ops(csdev)->perf_stop)
+ continue;
+ source_ops(csdev)->perf_stop(csdev);
+ }
+}
+
+static int etm_event_init(struct perf_event *event)
+{
+ int ret;
+
+ if (event->attr.type != etm_pmu.type)
+ return -ENOENT;
+
+ if (event->cpu >= nr_cpu_ids)
+ return -EINVAL;
+
+ ret = etm_event_pmu_start(event);
+ if (ret)
+ return ret;
+
+ event->destroy = etm_event_destroy;
+
+ return 0;
+}
+
+static void *alloc_event_data(int cpu)
+{
+ int size;
+ struct etm_event_data *event_data;
+ void *source_config, *sink_config, *sink;
+
+ event_data = kzalloc(sizeof(struct etm_event_data), GFP_KERNEL);
+ if (!event_data)
+ return NULL;
+
+ if (cpu != -1)
+ size = 1;
+ else
+ size = num_online_cpus();
+
+ source_config = kcalloc(size, sizeof(void *), GFP_KERNEL);
+ if (!source_config)
+ goto source_config_err;
+
+ sink_config = kcalloc(size, sizeof(void *), GFP_KERNEL);
+ if (!sink_config)
+ goto sink_config_err;
+
+ sink = kcalloc(size, sizeof(void *), GFP_KERNEL);
+ if (!sink)
+ goto sink_err;
+
+ cpumask_clear(&event_data->mask);
+ event_data->source_config = source_config;
+ event_data->sink_config = sink_config;
+ event_data->sink = sink;
+
+out:
+ return event_data;
+
+sink_err:
+ kfree(sink_config);
+sink_config_err:
+ kfree(source_config);
+source_config_err:
+ kfree(event_data);
+ event_data = NULL;
+ goto out;
+}
+
+static void free_event_data(struct etm_event_data *event_data)
+{
+ int cpu;
+ cpumask_t *mask = &event_data->mask;
+
+ for_each_cpu(cpu, mask) {
+ kfree(event_data->source_config[cpu]);
+ kfree(event_data->sink_config[cpu]);
+ kfree(event_data->sink[cpu]);
+ }
+
+ kfree(event_data->source_config);
+ kfree(event_data->sink_config);
+ kfree(event_data->sink);
+ kfree(event_data);
+}
+
+static void *etm_setup_aux(struct perf_event *event, void **pages,
+ int nr_pages, bool overwrite)
+{
+ int cpu;
+ cpumask_t *mask;
+ struct etm_event_data *event_data = NULL;
+ struct coresight_device *csdev;
+
+ event_data = alloc_event_data(event->cpu);
+ if (!event_data)
+ return NULL;
+
+ mask = &event_data->mask;
+
+ if (event->cpu != -1)
+ cpumask_set_cpu(event->cpu, mask);
+ else
+ cpumask_copy(mask, cpu_online_mask);
+
+ for_each_cpu(cpu, mask) {
+ struct coresight_device *sink;
+
+ csdev = per_cpu(csdev_src, cpu);
+ if (!csdev)
+ goto err;
+
+ /* Get the tracer's config from perf */
+ if (!source_ops(csdev)->perf_get_config)
+ goto err;
+
+ event_data->source_config[cpu] =
+ source_ops(csdev)->perf_get_config(csdev, event);
+
+ if (!event_data->source_config[cpu])
+ goto err;
+
+ /*
+ * Get a handle on the sink buffer associated
+ * with this tracer.
+ */
+ event_data->sink[cpu] = (void *)etm_event_build_path(cpu, true);
+
+ if (!event_data->sink[cpu])
+ goto err;
+
+ sink = event_data->sink[cpu];
+
+ if (!sink_ops(sink)->setup_aux)
+ goto err;
+
+ /* Finally get the AUX specific data from the sink buffer */
+ event_data->sink_config[cpu] =
+ sink_ops(sink)->setup_aux(sink, cpu, pages,
+ nr_pages, overwrite);
+ if (!event_data->sink_config[cpu])
+ goto err;
+ }
+
+out:
+ return event_data;
+
+err:
+ for_each_cpu(cpu, mask) {
+ etm_event_build_path(cpu, false);
+ }
+
+ free_event_data(event_data);
+ event_data = NULL;
+ goto out;
+}
+
+static void etm_free_aux(void *data)
+{
+ free_event_data(data);
+}
+
+static void etm_event_stop(struct perf_event *event, int mode)
+{
+ int cpu = smp_processor_id();
+ struct coresight_device *csdev = per_cpu(csdev_src, cpu);
+
+ if (event->hw.state == PERF_HES_STOPPED)
+ return;
+
+ if (!csdev)
+ return;
+
+ /* stop tracer */
+ if (!source_ops(csdev)->perf_disable)
+ return;
+
+ if (source_ops(csdev)->perf_disable(csdev))
+ return;
+
+ /* tell the core */
+ event->hw.state = PERF_HES_STOPPED;
+
+
+ if (mode & PERF_EF_UPDATE) {
+ struct coresight_device *sink;
+ struct perf_output_handle *handle = this_cpu_ptr(&ctx_handle);
+ struct etm_event_data *event_data = perf_get_aux(handle);
+
+ if (WARN_ON_ONCE(handle->event != event))
+ return;
+
+ if (WARN_ON_ONCE(!event_data))
+ return;
+
+ sink = event_data->sink[cpu];
+ if (WARN_ON_ONCE(!sink))
+ return;
+
+ /* update trace information */
+ if (!sink_ops(sink)->update_buffer)
+ return;
+
+ sink_ops(sink)->update_buffer(sink, handle,
+ event_data->sink_config[cpu]);
+ }
+}
+
+static void etm_event_start(struct perf_event *event, int flags)
+{
+ int cpu = smp_processor_id();
+ struct coresight_device *csdev = per_cpu(csdev_src, cpu);
+
+ if (!csdev)
+ goto fail;
+
+ /* tell the perf core the event is alive */
+ event->hw.state = 0;
+
+ if (!source_ops(csdev)->perf_enable)
+ goto fail;
+
+ if (source_ops(csdev)->perf_enable(csdev))
+ goto fail;
+
+ return;
+
+fail:
+ event->hw.state = PERF_HES_STOPPED;
+}
+
+static void etm_event_del(struct perf_event *event, int mode)
+{
+ int cpu = smp_processor_id();
+ struct coresight_device *sink;
+ struct perf_output_handle *handle = this_cpu_ptr(&ctx_handle);
+ struct etm_event_data *event_data = perf_get_aux(handle);
+
+ if (WARN_ON_ONCE(!event_data))
+ return;
+
+ sink = event_data->sink[cpu];
+ if (!sink)
+ return;
+
+ etm_event_stop(event, PERF_EF_UPDATE);
+
+ if (!sink_ops(sink)->reset_buffer)
+ return;
+
+ sink_ops(sink)->reset_buffer(sink, handle,
+ event_data->sink_config[cpu]);
+}
+
+static int etm_event_add(struct perf_event *event, int mode)
+{
+
+ int ret = -EBUSY, cpu = smp_processor_id();
+ struct etm_event_data *event_data;
+ struct perf_output_handle *handle = this_cpu_ptr(&ctx_handle);
+ struct hw_perf_event *hwc = &event->hw;
+ struct coresight_device *csdev = per_cpu(csdev_src, cpu);
+ struct coresight_device *sink;
+
+ if (handle->event)
+ goto out;
+
+ event_data = perf_aux_output_begin(handle, event);
+ ret = -EINVAL;
+ if (WARN_ON_ONCE(!event_data))
+ goto fail_stop;
+
+ sink = event_data->sink[cpu];
+ if (!sink)
+ goto fail_end_stop;
+
+ if (!sink_ops(sink)->set_buffer)
+ goto fail_end_stop;
+
+ ret = sink_ops(sink)->set_buffer(sink, handle,
+ event_data->sink_config[cpu]);
+ if (ret)
+ goto fail_end_stop;
+
+ if (!source_ops(csdev)->perf_set_config) {
+ ret = -EINVAL;
+ goto fail_end_stop;
+ }
+
+ source_ops(csdev)->perf_set_config(csdev,
+ event_data->source_config[cpu]);
+
+ if (mode & PERF_EF_START) {
+ etm_event_start(event, 0);
+ if (hwc->state & PERF_HES_STOPPED) {
+ etm_event_del(event, 0);
+ return -EBUSY;
+ }
+ }
+
+out:
+ return ret;
+
+fail_end_stop:
+ perf_aux_output_end(handle, 0, true);
+fail_stop:
+ hwc->state = PERF_HES_STOPPED;
+ goto out;
+}
+
+int etm_perf_symlink(struct coresight_device *csdev, bool link)
+{
+ char entry[sizeof("cpu9999999")];
+ int ret = 0, cpu = source_ops(csdev)->cpu_id(csdev);
+ struct device *pmu_dev = etm_pmu.dev;
+ struct device *cs_dev = &csdev->dev;
+
+ sprintf(entry, "cpu%d", cpu);
+
+ if (!etm_perf_up)
+ return -EPROBE_DEFER;
+
+ if (link) {
+ ret = sysfs_create_link(&pmu_dev->kobj, &cs_dev->kobj, entry);
+ if (ret)
+ return ret;
+ per_cpu(csdev_src, cpu) = csdev;
+ } else {
+ sysfs_remove_link(&pmu_dev->kobj, entry);
+ per_cpu(csdev_src, cpu) = NULL;
+ }
+
+ return 0;
+}
+
+static int __init etm_perf_init(void)
+{
+ int ret;
+
+ etm_pmu.capabilities = PERF_PMU_CAP_EXCLUSIVE;
+
+ etm_pmu.attr_groups = etm_pmu_attr_groups;
+ etm_pmu.task_ctx_nr = perf_sw_context;
+ etm_pmu.read = etm_event_read;
+ etm_pmu.event_init = etm_event_init;
+ etm_pmu.setup_aux = etm_setup_aux;
+ etm_pmu.free_aux = etm_free_aux;
+ etm_pmu.stop = etm_event_stop;
+ etm_pmu.start = etm_event_start;
+ etm_pmu.del = etm_event_del;
+ etm_pmu.add = etm_event_add;
+
+ ret = perf_pmu_register(&etm_pmu, CORESIGHT_ETM_PMU_NAME, -1);
+ if (ret == 0)
+ etm_perf_up = true;
+
+ return ret;
+}
+module_init(etm_perf_init);
diff --git a/drivers/hwtracing/coresight/coresight-etm-perf.h b/drivers/hwtracing/coresight/coresight-etm-perf.h
new file mode 100644
index 000000000000..4dd900f2362a
--- /dev/null
+++ b/drivers/hwtracing/coresight/coresight-etm-perf.h
@@ -0,0 +1,27 @@
+/* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _CORESIGHT_ETM_PERF_H
+#define _CORESIGHT_ETM_PERF_H
+
+struct coresight_device;
+
+#ifdef CONFIG_CORESIGHT
+int etm_perf_symlink(struct coresight_device *csdev, bool link);
+
+#else
+static inline int etm_perf_symlink(struct coresight_device *csdev, bool link)
+{ return -EINVAL; }
+
+#endif /* CONFIG_CORESIGHT */
+
+#endif
diff --git a/drivers/hwtracing/coresight/coresight-etm3x.c b/drivers/hwtracing/coresight/coresight-etm3x.c
index 9b4c0359ca29..7407c7ecf668 100644
--- a/drivers/hwtracing/coresight/coresight-etm3x.c
+++ b/drivers/hwtracing/coresight/coresight-etm3x.c
@@ -35,6 +35,7 @@
#include <asm/sections.h>
#include "coresight-etm.h"
+#include "coresight-etm-perf.h"
static int boot_enable;
module_param_named(boot_enable, boot_enable, int, S_IRUGO);
@@ -850,6 +851,12 @@ static int etm_probe(struct amba_device *adev, const struct amba_id *id)
goto err_arch_supported;
}
+ ret = etm_perf_symlink(drvdata->csdev, true);
+ if (ret) {
+ coresight_unregister(drvdata->csdev);
+ goto err_arch_supported;
+ }
+
pm_runtime_put(&adev->dev);
dev_info(dev, "%s initialized\n", (char *)id->data);
--
1.9.1
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Alexander Shishkin <alexander.shishkin@linux.intel.com> |
|---|---|
| Date | 2015-10-19 17:50 +0200 |
| Subject | Re: [PATCH V2 22/30] coresight: etm-perf: new PMU driver for ETM tracers |
| Message-ID | <qlkRd-ll-39@gated-at.bofh.it> |
| In reply to | #1250198 |
Mathieu Poirier <mathieu.poirier@linaro.org> writes:
> +static int etm_event_pmu_start(struct perf_event *event)
> +{
> + int cpu, ret;
> + cpumask_t mask;
> + struct coresight_device *csdev;
> +
> + cpumask_clear(&mask);
> + if (event->cpu != -1)
> + cpumask_set_cpu(event->cpu, &mask);
> + else
> + cpumask_copy(&mask, cpu_online_mask);
> +
> + for_each_cpu(cpu, &mask) {
> + csdev = per_cpu(csdev_src, cpu);
> +
> + if (!source_ops(csdev)->perf_start)
> + continue;
> +
> + ret = source_ops(csdev)->perf_start(csdev);
> + if (ret)
> + goto err;
So long as "perf_start" and "perf_stop" here mean
"pm_runtime_get()/put()", this can work, but in that case maybe a better
name should be used, because no real starting or stopping of anything
takes place here. Since pmu::event_init and event::destroy happen in
allocation/deallocation paths and at event scheduling, it's not a good
idea to actually start anything here.
Regards,
--
Alex
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Mathieu Poirier <mathieu.poirier@linaro.org> |
|---|---|
| Date | 2015-10-20 18:50 +0200 |
| Subject | Re: [PATCH V2 22/30] coresight: etm-perf: new PMU driver for ETM tracers |
| Message-ID | <qlIgO-YP-33@gated-at.bofh.it> |
| In reply to | #1250861 |
On 19 October 2015 at 09:37, Alexander Shishkin
<alexander.shishkin@linux.intel.com> wrote:
> Mathieu Poirier <mathieu.poirier@linaro.org> writes:
>
>> +static int etm_event_pmu_start(struct perf_event *event)
>> +{
>> + int cpu, ret;
>> + cpumask_t mask;
>> + struct coresight_device *csdev;
>> +
>> + cpumask_clear(&mask);
>> + if (event->cpu != -1)
>> + cpumask_set_cpu(event->cpu, &mask);
>> + else
>> + cpumask_copy(&mask, cpu_online_mask);
>> +
>> + for_each_cpu(cpu, &mask) {
>> + csdev = per_cpu(csdev_src, cpu);
>> +
>> + if (!source_ops(csdev)->perf_start)
>> + continue;
>> +
>> + ret = source_ops(csdev)->perf_start(csdev);
>> + if (ret)
>> + goto err;
>
> So long as "perf_start" and "perf_stop" here mean
> "pm_runtime_get()/put()", this can work, but in that case maybe a better
> name should be used, because no real starting or stopping of anything
> takes place here.
You're correct, nothing else than pm_runtime operations should be
happening in there. I will revise the naming convention.
> Since pmu::event_init and event::destroy happen in
> allocation/deallocation paths and at event scheduling, it's not a good
> idea to actually start anything here.
>
> Regards,
> --
> Alex
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Alexander Shishkin <alexander.shishkin@linux.intel.com> |
|---|---|
| Date | 2015-10-20 11:40 +0200 |
| Subject | Re: [PATCH V2 22/30] coresight: etm-perf: new PMU driver for ETM tracers |
| Message-ID | <qlByH-87B-29@gated-at.bofh.it> |
| In reply to | #1250198 |
Mathieu Poirier <mathieu.poirier@linaro.org> writes:
> +static void *etm_setup_aux(struct perf_event *event, void **pages,
> + int nr_pages, bool overwrite)
> +{
> + int cpu;
> + cpumask_t *mask;
> + struct etm_event_data *event_data = NULL;
> + struct coresight_device *csdev;
> +
> + event_data = alloc_event_data(event->cpu);
> + if (!event_data)
> + return NULL;
> +
> + mask = &event_data->mask;
> +
> + if (event->cpu != -1)
> + cpumask_set_cpu(event->cpu, mask);
> + else
> + cpumask_copy(mask, cpu_online_mask);
> +
> + for_each_cpu(cpu, mask) {
> + struct coresight_device *sink;
> +
> + csdev = per_cpu(csdev_src, cpu);
> + if (!csdev)
> + goto err;
> +
> + /* Get the tracer's config from perf */
> + if (!source_ops(csdev)->perf_get_config)
> + goto err;
> +
> + event_data->source_config[cpu] =
> + source_ops(csdev)->perf_get_config(csdev, event);
> +
> + if (!event_data->source_config[cpu])
> + goto err;
> +
> + /*
> + * Get a handle on the sink buffer associated
> + * with this tracer.
> + */
> + event_data->sink[cpu] = (void *)etm_event_build_path(cpu, true);
There are several problems here. What is created/allocated during
setup_aux(), has to be undone in free_aux(), however, the effect of
build_path() will only be undone in the event::destroy() path. So if the
user unmaps the aux buffer and then maps it again, we'll go ahead and
try to build the path again. (Btw, coresight_build_paths() and other
non-static functions and especially exported ones are really lacking
documentation at the moment).
It really looks like this has to be done in pmu::add(), so that the
source<=>sink connection exists only while the event is scheduled and
otherwise other events are free to connect their sources to these
sinks. And at pmu::del() the connection has to be torn down. This way we
can have a sensible multisession support. That is, provided my
understanding of the coresight driver architecture is correct.
Also, you won't have to configure things on multiple cpus for cpu==-1 if
you keep the source<=>sink connection only between pmu::add() and
pmu::del(), as an event can only be scheduled on one cpu at a time,
which should make things simpler.
> +
> + if (!event_data->sink[cpu])
> + goto err;
> +
> + sink = event_data->sink[cpu];
> +
> + if (!sink_ops(sink)->setup_aux)
> + goto err;
> +
> + /* Finally get the AUX specific data from the sink buffer */
> + event_data->sink_config[cpu] =
> + sink_ops(sink)->setup_aux(sink, cpu, pages,
> + nr_pages, overwrite);
Now this is a sensible thing to do. I understand that you'll have to
know which sink you're using so that you can pick the right sink_ops and
build an appropriate configuration, but perhaps it also makes sense to
release it once you got the sink_config.
> +static void etm_event_stop(struct perf_event *event, int mode)
> +{
> + int cpu = smp_processor_id();
> + struct coresight_device *csdev = per_cpu(csdev_src, cpu);
> +
> + if (event->hw.state == PERF_HES_STOPPED)
> + return;
> +
> + if (!csdev)
> + return;
> +
> + /* stop tracer */
> + if (!source_ops(csdev)->perf_disable)
> + return;
This really shouldn't happen. It makes sense to make sure that we have
all the callbacks that we rely on in pmu::event_init() or pmu::add() and
refuse to start if we don't, but at this point we really shouldn't end
up in a situation where we suddenly don't have one of the callbacks.
> + if (source_ops(csdev)->perf_disable(csdev))
> + return;
This has a similar problem. I'd say that this callback should not be
able to fail and return anything other than success.
> + /* tell the core */
> + event->hw.state = PERF_HES_STOPPED;
> +
> +
> + if (mode & PERF_EF_UPDATE) {
> + struct coresight_device *sink;
> + struct perf_output_handle *handle = this_cpu_ptr(&ctx_handle);
> + struct etm_event_data *event_data = perf_get_aux(handle);
> +
> + if (WARN_ON_ONCE(handle->event != event))
> + return;
> +
> + if (WARN_ON_ONCE(!event_data))
> + return;
> +
> + sink = event_data->sink[cpu];
> + if (WARN_ON_ONCE(!sink))
> + return;
> +
> + /* update trace information */
> + if (!sink_ops(sink)->update_buffer)
> + return;
> +
> + sink_ops(sink)->update_buffer(sink, handle,
> + event_data->sink_config[cpu]);
> + }
> +}
> +
> +static void etm_event_start(struct perf_event *event, int flags)
> +{
> + int cpu = smp_processor_id();
> + struct coresight_device *csdev = per_cpu(csdev_src, cpu);
> +
> + if (!csdev)
> + goto fail;
> +
> + /* tell the perf core the event is alive */
> + event->hw.state = 0;
> +
> + if (!source_ops(csdev)->perf_enable)
> + goto fail;
Same here.
> +
> + if (source_ops(csdev)->perf_enable(csdev))
> + goto fail;
This may fail, I suppose.
> +
> + return;
> +
> +fail:
> + event->hw.state = PERF_HES_STOPPED;
> +}
> +
> +static void etm_event_del(struct perf_event *event, int mode)
> +{
> + int cpu = smp_processor_id();
> + struct coresight_device *sink;
> + struct perf_output_handle *handle = this_cpu_ptr(&ctx_handle);
> + struct etm_event_data *event_data = perf_get_aux(handle);
> +
> + if (WARN_ON_ONCE(!event_data))
> + return;
> +
> + sink = event_data->sink[cpu];
> + if (!sink)
> + return;
This also shouldn't be able to prevent us from stopping the event.
> +
> + etm_event_stop(event, PERF_EF_UPDATE);
> +
> + if (!sink_ops(sink)->reset_buffer)
> + return;
> +
> + sink_ops(sink)->reset_buffer(sink, handle,
> + event_data->sink_config[cpu]);
> +}
> +
> +static int etm_event_add(struct perf_event *event, int mode)
> +{
> +
> + int ret = -EBUSY, cpu = smp_processor_id();
> + struct etm_event_data *event_data;
> + struct perf_output_handle *handle = this_cpu_ptr(&ctx_handle);
> + struct hw_perf_event *hwc = &event->hw;
> + struct coresight_device *csdev = per_cpu(csdev_src, cpu);
> + struct coresight_device *sink;
> +
> + if (handle->event)
> + goto out;
> +
> + event_data = perf_aux_output_begin(handle, event);
> + ret = -EINVAL;
> + if (WARN_ON_ONCE(!event_data))
> + goto fail_stop;
> +
> + sink = event_data->sink[cpu];
So if you're able to fetch the sink right here and release it in
_del(). Of course, this being a hot path and an atomic context needs to
be taken into account.
Regards,
--
Alex
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Mathieu Poirier <mathieu.poirier@linaro.org> |
|---|---|
| Date | 2015-10-20 21:20 +0200 |
| Subject | Re: [PATCH V2 22/30] coresight: etm-perf: new PMU driver for ETM tracers |
| Message-ID | <qlKBX-4yw-5@gated-at.bofh.it> |
| In reply to | #1251528 |
On 20 October 2015 at 03:34, Alexander Shishkin
<alexander.shishkin@linux.intel.com> wrote:
> Mathieu Poirier <mathieu.poirier@linaro.org> writes:
>
>> +static void *etm_setup_aux(struct perf_event *event, void **pages,
>> + int nr_pages, bool overwrite)
>> +{
>> + int cpu;
>> + cpumask_t *mask;
>> + struct etm_event_data *event_data = NULL;
>> + struct coresight_device *csdev;
>> +
>> + event_data = alloc_event_data(event->cpu);
>> + if (!event_data)
>> + return NULL;
>> +
>> + mask = &event_data->mask;
>> +
>> + if (event->cpu != -1)
>> + cpumask_set_cpu(event->cpu, mask);
>> + else
>> + cpumask_copy(mask, cpu_online_mask);
>> +
>> + for_each_cpu(cpu, mask) {
>> + struct coresight_device *sink;
>> +
>> + csdev = per_cpu(csdev_src, cpu);
>> + if (!csdev)
>> + goto err;
>> +
>> + /* Get the tracer's config from perf */
>> + if (!source_ops(csdev)->perf_get_config)
>> + goto err;
>> +
>> + event_data->source_config[cpu] =
>> + source_ops(csdev)->perf_get_config(csdev, event);
>> +
>> + if (!event_data->source_config[cpu])
>> + goto err;
>> +
>> + /*
>> + * Get a handle on the sink buffer associated
>> + * with this tracer.
>> + */
>> + event_data->sink[cpu] = (void *)etm_event_build_path(cpu, true);
>
> There are several problems here. What is created/allocated during
> setup_aux(), has to be undone in free_aux(), however, the effect of
> build_path() will only be undone in the event::destroy() path. So if the
> user unmaps the aux buffer and then maps it again, we'll go ahead and
> try to build the path again. (Btw, coresight_build_paths() and other
> non-static functions and especially exported ones are really lacking
> documentation at the moment).
>
> It really looks like this has to be done in pmu::add(), so that the
> source<=>sink connection exists only while the event is scheduled and
> otherwise other events are free to connect their sources to these
> sinks. And at pmu::del() the connection has to be torn down. This way we
> can have a sensible multisession support. That is, provided my
> understanding of the coresight driver architecture is correct.
>
> Also, you won't have to configure things on multiple cpus for cpu==-1 if
> you keep the source<=>sink connection only between pmu::add() and
> pmu::del(), as an event can only be scheduled on one cpu at a time,
> which should make things simpler.
I am well aware of all this... Currently the process of building a
path is too heavy to be done at context switch time. To be efficient
the components of a path would have to be kept in a linked list that
is then enabled/disabled when the time comes. I've been meaning to do
something better for a while now. This might be the perfect time to
address the problem.
Thanks for reviewing the patch set,
Mathieu
>
>> +
>> + if (!event_data->sink[cpu])
>> + goto err;
>> +
>> + sink = event_data->sink[cpu];
>> +
>> + if (!sink_ops(sink)->setup_aux)
>> + goto err;
>> +
>> + /* Finally get the AUX specific data from the sink buffer */
>> + event_data->sink_config[cpu] =
>> + sink_ops(sink)->setup_aux(sink, cpu, pages,
>> + nr_pages, overwrite);
>
> Now this is a sensible thing to do. I understand that you'll have to
> know which sink you're using so that you can pick the right sink_ops and
> build an appropriate configuration, but perhaps it also makes sense to
> release it once you got the sink_config.
>
>> +static void etm_event_stop(struct perf_event *event, int mode)
>> +{
>> + int cpu = smp_processor_id();
>> + struct coresight_device *csdev = per_cpu(csdev_src, cpu);
>> +
>> + if (event->hw.state == PERF_HES_STOPPED)
>> + return;
>> +
>> + if (!csdev)
>> + return;
>> +
>> + /* stop tracer */
>> + if (!source_ops(csdev)->perf_disable)
>> + return;
>
> This really shouldn't happen. It makes sense to make sure that we have
> all the callbacks that we rely on in pmu::event_init() or pmu::add() and
> refuse to start if we don't, but at this point we really shouldn't end
> up in a situation where we suddenly don't have one of the callbacks.
>
>> + if (source_ops(csdev)->perf_disable(csdev))
>> + return;
>
> This has a similar problem. I'd say that this callback should not be
> able to fail and return anything other than success.
>
>> + /* tell the core */
>> + event->hw.state = PERF_HES_STOPPED;
>> +
>> +
>> + if (mode & PERF_EF_UPDATE) {
>> + struct coresight_device *sink;
>> + struct perf_output_handle *handle = this_cpu_ptr(&ctx_handle);
>> + struct etm_event_data *event_data = perf_get_aux(handle);
>> +
>> + if (WARN_ON_ONCE(handle->event != event))
>> + return;
>> +
>> + if (WARN_ON_ONCE(!event_data))
>> + return;
>> +
>> + sink = event_data->sink[cpu];
>> + if (WARN_ON_ONCE(!sink))
>> + return;
>> +
>> + /* update trace information */
>> + if (!sink_ops(sink)->update_buffer)
>> + return;
>> +
>> + sink_ops(sink)->update_buffer(sink, handle,
>> + event_data->sink_config[cpu]);
>> + }
>> +}
>> +
>> +static void etm_event_start(struct perf_event *event, int flags)
>> +{
>> + int cpu = smp_processor_id();
>> + struct coresight_device *csdev = per_cpu(csdev_src, cpu);
>> +
>> + if (!csdev)
>> + goto fail;
>> +
>> + /* tell the perf core the event is alive */
>> + event->hw.state = 0;
>> +
>> + if (!source_ops(csdev)->perf_enable)
>> + goto fail;
>
> Same here.
>
>> +
>> + if (source_ops(csdev)->perf_enable(csdev))
>> + goto fail;
>
> This may fail, I suppose.
>
>> +
>> + return;
>> +
>> +fail:
>> + event->hw.state = PERF_HES_STOPPED;
>> +}
>> +
>> +static void etm_event_del(struct perf_event *event, int mode)
>> +{
>> + int cpu = smp_processor_id();
>> + struct coresight_device *sink;
>> + struct perf_output_handle *handle = this_cpu_ptr(&ctx_handle);
>> + struct etm_event_data *event_data = perf_get_aux(handle);
>> +
>> + if (WARN_ON_ONCE(!event_data))
>> + return;
>> +
>> + sink = event_data->sink[cpu];
>> + if (!sink)
>> + return;
>
> This also shouldn't be able to prevent us from stopping the event.
>
>> +
>> + etm_event_stop(event, PERF_EF_UPDATE);
>> +
>> + if (!sink_ops(sink)->reset_buffer)
>> + return;
>> +
>> + sink_ops(sink)->reset_buffer(sink, handle,
>> + event_data->sink_config[cpu]);
>> +}
>> +
>> +static int etm_event_add(struct perf_event *event, int mode)
>> +{
>> +
>> + int ret = -EBUSY, cpu = smp_processor_id();
>> + struct etm_event_data *event_data;
>> + struct perf_output_handle *handle = this_cpu_ptr(&ctx_handle);
>> + struct hw_perf_event *hwc = &event->hw;
>> + struct coresight_device *csdev = per_cpu(csdev_src, cpu);
>> + struct coresight_device *sink;
>> +
>> + if (handle->event)
>> + goto out;
>> +
>> + event_data = perf_aux_output_begin(handle, event);
>> + ret = -EINVAL;
>> + if (WARN_ON_ONCE(!event_data))
>> + goto fail_stop;
>> +
>> + sink = event_data->sink[cpu];
>
> So if you're able to fetch the sink right here and release it in
> _del(). Of course, this being a hot path and an atomic context needs to
> be taken into account.
>
> Regards,
> --
> Alex
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Mathieu Poirier <mathieu.poirier@linaro.org> |
|---|---|
| Date | 2015-10-18 20:30 +0200 |
| Subject | [PATCH V2 25/30] perf tools: adding perf_session to *info_prive_size() |
| Message-ID | <ql0Sv-4NE-49@gated-at.bofh.it> |
| In reply to | #1250192 |
On some architecture the size of the private header may
be dependent on the number of tracers used in the session. As
such adding a "struct perf_session" parameter, which should
contain all the required information.
Also adjusting the existing client of the interface to take
the new parameter into account.
Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
---
tools/perf/arch/x86/util/intel-bts.c | 4 +++-
tools/perf/arch/x86/util/intel-pt.c | 4 +++-
tools/perf/util/auxtrace.c | 7 ++++---
tools/perf/util/auxtrace.h | 6 ++++--
4 files changed, 14 insertions(+), 7 deletions(-)
diff --git a/tools/perf/arch/x86/util/intel-bts.c b/tools/perf/arch/x86/util/intel-bts.c
index 9b94ce520917..6efdc5e86d97 100644
--- a/tools/perf/arch/x86/util/intel-bts.c
+++ b/tools/perf/arch/x86/util/intel-bts.c
@@ -60,7 +60,9 @@ struct branch {
u64 misc;
};
-static size_t intel_bts_info_priv_size(struct auxtrace_record *itr __maybe_unused)
+static size_t
+intel_bts_info_priv_size(struct auxtrace_record *itr __maybe_unused,
+ struct perf_session *session __maybe_unused)
{
return INTEL_BTS_AUXTRACE_PRIV_SIZE;
}
diff --git a/tools/perf/arch/x86/util/intel-pt.c b/tools/perf/arch/x86/util/intel-pt.c
index 2ca10d796c0b..1fd9a16f668c 100644
--- a/tools/perf/arch/x86/util/intel-pt.c
+++ b/tools/perf/arch/x86/util/intel-pt.c
@@ -273,7 +273,9 @@ intel_pt_pmu_default_config(struct perf_pmu *intel_pt_pmu)
return attr;
}
-static size_t intel_pt_info_priv_size(struct auxtrace_record *itr __maybe_unused)
+static size_t
+intel_pt_info_priv_size(struct auxtrace_record *itr __maybe_unused,
+ struct perf_session *session __maybe_unused)
{
return INTEL_PT_AUXTRACE_PRIV_SIZE;
}
diff --git a/tools/perf/util/auxtrace.c b/tools/perf/util/auxtrace.c
index a980e7c50ee0..430df9575dbe 100644
--- a/tools/perf/util/auxtrace.c
+++ b/tools/perf/util/auxtrace.c
@@ -478,10 +478,11 @@ void auxtrace_heap__pop(struct auxtrace_heap *heap)
heap_array[last].ordinal);
}
-size_t auxtrace_record__info_priv_size(struct auxtrace_record *itr)
+size_t auxtrace_record__info_priv_size(struct auxtrace_record *itr,
+ struct perf_session *session)
{
if (itr)
- return itr->info_priv_size(itr);
+ return itr->info_priv_size(itr, session);
return 0;
}
@@ -852,7 +853,7 @@ int perf_event__synthesize_auxtrace_info(struct auxtrace_record *itr,
int err;
pr_debug2("Synthesizing auxtrace information\n");
- priv_size = auxtrace_record__info_priv_size(itr);
+ priv_size = auxtrace_record__info_priv_size(itr, session);
ev = zalloc(sizeof(struct auxtrace_info_event) + priv_size);
if (!ev)
return -ENOMEM;
diff --git a/tools/perf/util/auxtrace.h b/tools/perf/util/auxtrace.h
index bf72b77a588a..d76177169484 100644
--- a/tools/perf/util/auxtrace.h
+++ b/tools/perf/util/auxtrace.h
@@ -289,7 +289,8 @@ struct auxtrace_record {
int (*recording_options)(struct auxtrace_record *itr,
struct perf_evlist *evlist,
struct record_opts *opts);
- size_t (*info_priv_size)(struct auxtrace_record *itr);
+ size_t (*info_priv_size)(struct auxtrace_record *itr,
+ struct perf_session *session);
int (*info_fill)(struct auxtrace_record *itr,
struct perf_session *session,
struct auxtrace_info_event *auxtrace_info,
@@ -425,7 +426,8 @@ int auxtrace_parse_snapshot_options(struct auxtrace_record *itr,
int auxtrace_record__options(struct auxtrace_record *itr,
struct perf_evlist *evlist,
struct record_opts *opts);
-size_t auxtrace_record__info_priv_size(struct auxtrace_record *itr);
+size_t auxtrace_record__info_priv_size(struct auxtrace_record *itr,
+ struct perf_session *session);
int auxtrace_record__info_fill(struct auxtrace_record *itr,
struct perf_session *session,
struct auxtrace_info_event *auxtrace_info,
--
1.9.1
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Mathieu Poirier <mathieu.poirier@linaro.org> |
|---|---|
| Date | 2015-10-18 20:30 +0200 |
| Subject | [PATCH V2 10/30] coresight: etm3x: consolidating initial config |
| Message-ID | <ql0Sv-4NE-53@gated-at.bofh.it> |
| In reply to | #1250192 |
There is really no point having two functions to take care
of doing the initials tracer configuration. As such moving
everything to 'etm_set_default()'.
Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
---
drivers/hwtracing/coresight/coresight-etm3x.c | 37 ++++++++++-----------------
1 file changed, 14 insertions(+), 23 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-etm3x.c b/drivers/hwtracing/coresight/coresight-etm3x.c
index 8bd161584f85..cc0b08437419 100644
--- a/drivers/hwtracing/coresight/coresight-etm3x.c
+++ b/drivers/hwtracing/coresight/coresight-etm3x.c
@@ -41,7 +41,6 @@ module_param_named(boot_enable, boot_enable, int, S_IRUGO);
/* The number of ETM/PTM currently registered */
static int etm_count;
static struct etm_drvdata *etmdrvdata[NR_CPUS];
-static void etm_init_default_data(struct etm_config *config);
/*
* Memory mapped writes to clear os lock are not supported on some processors
@@ -199,7 +198,7 @@ struct etm_config *get_etm_config(struct etm_drvdata *drvdata)
return NULL;
/* Set default config */
- etm_init_default_data(config);
+ etm_set_default(config);
drvdata->config = config;
out:
return drvdata->config;
@@ -212,6 +211,19 @@ void etm_set_default(struct etm_config *config)
if (WARN_ON_ONCE(!config))
return;
+ /*
+ * Taken verbatim from the TRM:
+ *
+ * To trace all memory:
+ * set bit [24] in register 0x009, the ETMTECR1, to 1
+ * set all other bits in register 0x009, the ETMTECR1, to 0
+ * set all bits in register 0x007, the ETMTECR2, to 0
+ * set register 0x008, the ETMTEEVR, to 0x6F (TRUE).
+ */
+ config->enable_ctrl1 = BIT(24);
+ config->enable_ctrl2 = 0x0;
+ config->enable_event = ETM_HARD_WIRE_RES_A;
+
config->trigger_event = ETM_DEFAULT_EVENT_VAL;
config->enable_event = ETM_HARD_WIRE_RES_A;
@@ -565,27 +577,6 @@ static void etm_init_arch_data(void *info)
CS_LOCK(drvdata->base);
}
-static void etm_init_default_data(struct etm_config *config)
-{
- if (WARN_ON_ONCE(!config))
- return;
-
- etm_set_default(config);
-
- /*
- * Taken verbatim from the TRM:
- *
- * To trace all memory:
- * set bit [24] in register 0x009, the ETMTECR1, to 1
- * set all other bits in register 0x009, the ETMTECR1, to 0
- * set all bits in register 0x007, the ETMTECR2, to 0
- * set register 0x008, the ETMTEEVR, to 0x6F (TRUE).
- */
- config->enable_ctrl1 = BIT(24);
- config->enable_ctrl2 = 0x0;
- config->enable_event = ETM_HARD_WIRE_RES_A;
-}
-
static void etm_init_trace_id(struct etm_drvdata *drvdata)
{
/*
--
1.9.1
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Mathieu Poirier <mathieu.poirier@linaro.org> |
|---|---|
| Date | 2015-10-18 20:30 +0200 |
| Subject | [PATCH V2 26/30] perf tools: making source devices path broadly accessible |
| Message-ID | <ql0Sv-4NE-57@gated-at.bofh.it> |
| In reply to | #1250192 |
Other perf tools may want access to the event source device
directory. As such moving the path definition to pmu.h for
easy inclusion by other clients.
Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
---
tools/perf/util/pmu.c | 2 --
tools/perf/util/pmu.h | 1 +
2 files changed, 1 insertion(+), 2 deletions(-)
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index 89c91a1a67e7..e1f2dc23a253 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -20,8 +20,6 @@ struct perf_pmu_format {
struct list_head list;
};
-#define EVENT_SOURCE_DEVICE_PATH "/bus/event_source/devices/"
-
int perf_pmu_parse(struct list_head *list, char *name);
extern FILE *perf_pmu_in;
diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h
index 5d7e84466bee..3fbb791a955a 100644
--- a/tools/perf/util/pmu.h
+++ b/tools/perf/util/pmu.h
@@ -35,6 +35,7 @@ struct perf_pmu_info {
};
#define UNIT_MAX_LEN 31 /* max length for event unit name */
+#define EVENT_SOURCE_DEVICE_PATH "/bus/event_source/devices/"
struct perf_pmu_alias {
char *name;
--
1.9.1
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Mathieu Poirier <mathieu.poirier@linaro.org> |
|---|---|
| Date | 2015-10-18 20:30 +0200 |
| Subject | [PATCH V2 21/30] coresight: etb10: implementing buffer update API |
| Message-ID | <ql0Sv-4NE-59@gated-at.bofh.it> |
| In reply to | #1250192 |
Implementing buffer API to update the location of the ETB
internal ring buffer once a trace session has ended.
Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
---
drivers/hwtracing/coresight/coresight-etb10.c | 128 ++++++++++++++++++++++++++
include/linux/coresight.h | 14 ++-
2 files changed, 137 insertions(+), 5 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-etb10.c b/drivers/hwtracing/coresight/coresight-etb10.c
index ca2c4b42464d..8e469d097955 100644
--- a/drivers/hwtracing/coresight/coresight-etb10.c
+++ b/drivers/hwtracing/coresight/coresight-etb10.c
@@ -28,6 +28,7 @@
#include <linux/amba/bus.h>
#include <linux/clk.h>
#include <linux/mm.h>
+#include <linux/circ_buf.h>
#include <linux/perf_event.h>
#include <asm/local.h>
@@ -362,12 +363,139 @@ static void etb_reset_buffer(struct coresight_device *csdev,
local_set(&drvdata->in_use, 0);
}
+static void etb_update_buffer(struct coresight_device *csdev,
+ struct perf_output_handle *handle,
+ void *sink_config)
+{
+ int i, cur;
+ u8 *buf_ptr;
+ u32 read_ptr, write_ptr, start;
+ u32 status, read_data, words;
+ unsigned long flags, offset;
+ struct cs_buffers *buf = sink_config;
+ struct etb_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+
+ if (!buf)
+ return;
+
+ spin_lock_irqsave(&drvdata->spinlock, flags);
+ if (!drvdata->enable)
+ goto out;
+
+ etb_disable_hw(drvdata);
+ CS_UNLOCK(drvdata->base);
+
+ /* unit is in words, not bytes */
+ read_ptr = readl_relaxed(drvdata->base + ETB_RAM_READ_POINTER);
+ write_ptr = readl_relaxed(drvdata->base + ETB_RAM_WRITE_POINTER);
+
+ /*
+ * Entries should be aligned to the frame size. If they are not
+ * go back to the last alignement point to give decoding tools a
+ * chance to fix things.
+ */
+ if (write_ptr % ETB_FRAME_SIZE_WORDS) {
+ dev_err(drvdata->dev,
+ "write_ptr: %lu not aligned to formatter frame size\n",
+ (unsigned long)write_ptr);
+
+ write_ptr &= ~ETB_FRAME_SIZE_WORDS;
+ local_inc(&buf->lost);
+ }
+
+ /*
+ * Get a hold of the status register and see if a wrap around
+ * has occurred. If so adjust things accordingly. Otherwise
+ * start at the beginning and go until the write pointer has
+ * been reached.
+ */
+ status = readl_relaxed(drvdata->base + ETB_STATUS_REG);
+ if (status & ETB_STATUS_RAM_FULL) {
+ local_inc(&buf->lost);
+ words = drvdata->buffer_depth;
+ start = write_ptr;
+ } else {
+ words = CIRC_CNT(write_ptr, read_ptr, drvdata->buffer_depth);
+ start = read_ptr;
+ }
+
+ /*
+ * Make sure we don't overwrite data that hasn't been consumed yet.
+ * It is entirely possible that the HW buffer has more data than the
+ * ring buffer can currently handle. If so adjust the start address
+ * to take only the last traces.
+ *
+ * In snapshot mode we are looking to get the latest traces only and as
+ * such, we don't care about not overwriting data that hasn't been
+ * processed by user space.
+ *
+ * Since metrics related to ETBs is in words, multiply by the
+ * amount of byte per word to have the right units.
+ */
+ if (!buf->snapshot && words * ETB_FRAME_SIZE_WORDS > handle->size) {
+ unsigned int capacity = drvdata->buffer_depth;
+
+ /* make sure new sizes are still multiples the frame size */
+ words = handle->size / ETB_FRAME_SIZE_WORDS;
+ /* advance the start pointer to get the latest trace data */
+ start += capacity - words;
+ /* wrap around if we've reach the end of the HW buffer */
+ start &= capacity - 1;
+ /* let the decoder know we've skipped ahead */
+ local_inc(&buf->lost);
+ }
+
+ /* finally tell HW where we want to start reading from */
+ writel_relaxed(start, drvdata->base + ETB_RAM_READ_POINTER);
+
+ cur = buf->cur;
+ offset = buf->offset;
+ for (i = 0; i < words; i++) {
+ buf_ptr = buf->addr[cur] + offset;
+ read_data = readl_relaxed(drvdata->base +
+ ETB_RAM_READ_DATA_REG);
+ *buf_ptr++ = read_data >> 0;
+ *buf_ptr++ = read_data >> 8;
+ *buf_ptr++ = read_data >> 16;
+ *buf_ptr++ = read_data >> 24;
+
+ offset += 4;
+ if (offset >= PAGE_SIZE) {
+ offset = 0;
+ cur++;
+ /* wrap around at the end of the buffer */
+ cur &= buf->nr_pages - 1;
+ }
+ }
+
+ /* reset ETB buffer for next run */
+ writel_relaxed(0x0, drvdata->base + ETB_RAM_READ_POINTER);
+ writel_relaxed(0x0, drvdata->base + ETB_RAM_WRITE_POINTER);
+
+ /*
+ * In snapshot mode all we have to do is communicate to
+ * perf_aux_output_end() the address of the current head. In full
+ * trace mode the same function expects a size to move rb->aux_head
+ * forward.
+ */
+ if (buf->snapshot)
+ local_set(&buf->data_size, (cur * PAGE_SIZE) + offset);
+ else
+ local_add(words * ETB_FRAME_SIZE_WORDS, &buf->data_size);
+
+ CS_LOCK(drvdata->base);
+ etb_enable_hw(drvdata);
+out:
+ spin_unlock_irqrestore(&drvdata->spinlock, flags);
+}
+
static const struct coresight_ops_sink etb_sink_ops = {
.enable = etb_enable,
.disable = etb_disable,
.setup_aux = etb_setup_aux,
.set_buffer = etb_set_buffer,
.reset_buffer = etb_reset_buffer,
+ .update_buffer = etb_update_buffer,
};
static const struct coresight_ops etb_cs_ops = {
diff --git a/include/linux/coresight.h b/include/linux/coresight.h
index 78202d5ea58a..cdf401d51998 100644
--- a/include/linux/coresight.h
+++ b/include/linux/coresight.h
@@ -186,11 +186,12 @@ struct coresight_device {
/**
* struct coresight_ops_sink - basic operations for a sink
* Operations available for sinks
- * @enable: enables the sink.
- * @disable: disables the sink.
- * @setup_aux: initialises perf's ring buffer for trace collection.
- * @set_buffer: initialises buffer mechanic before a trace session.
- * @reset_buffer: finalises buffer mechanic after a trace session.
+ * @enable: enables the sink.
+ * @disable: disables the sink.
+ * @setup_aux: initialises perf's ring buffer for trace collection.
+ * @set_buffer: initialises buffer mechanic before a trace session.
+ * @reset_buffer: finalises buffer mechanic after a trace session.
+ * @update_buffer: update buffer pointers after a trace session.
*/
struct coresight_ops_sink {
int (*enable)(struct coresight_device *csdev);
@@ -203,6 +204,9 @@ struct coresight_ops_sink {
void (*reset_buffer)(struct coresight_device *csdev,
struct perf_output_handle *handle,
void *sink_config);
+ void (*update_buffer)(struct coresight_device *csdev,
+ struct perf_output_handle *handle,
+ void *sink_config);
};
/**
--
1.9.1
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Mathieu Poirier <mathieu.poirier@linaro.org> |
|---|---|
| Date | 2015-10-18 20:40 +0200 |
| Subject | [PATCH V2 15/30] coresight: making coresight_build_paths() public |
| Message-ID | <ql129-500-1@gated-at.bofh.it> |
| In reply to | #1250192 |
That way a path can be built outside of the core framework,
something useful when a PMU is initialised from the perf
subsystem.
Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
---
drivers/hwtracing/coresight/coresight-priv.h | 3 +++
drivers/hwtracing/coresight/coresight.c | 5 ++---
2 files changed, 5 insertions(+), 3 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-priv.h b/drivers/hwtracing/coresight/coresight-priv.h
index 62fcd98cc7cf..8a52fdcb4bd6 100644
--- a/drivers/hwtracing/coresight/coresight-priv.h
+++ b/drivers/hwtracing/coresight/coresight-priv.h
@@ -52,6 +52,9 @@ static inline void CS_UNLOCK(void __iomem *addr)
} while (0);
}
+int coresight_build_paths(struct coresight_device *csdev,
+ struct list_head *path, bool enable);
+
#ifdef CONFIG_CORESIGHT_SOURCE_ETM3X
extern int etm_readl_cp14(u32 off, unsigned int *val);
extern int etm_writel_cp14(u32 off, u32 val);
diff --git a/drivers/hwtracing/coresight/coresight.c b/drivers/hwtracing/coresight/coresight.c
index d318a338a517..083080d435af 100644
--- a/drivers/hwtracing/coresight/coresight.c
+++ b/drivers/hwtracing/coresight/coresight.c
@@ -301,9 +301,8 @@ static int coresight_disable_path(struct list_head *path)
return 0;
}
-static int coresight_build_paths(struct coresight_device *csdev,
- struct list_head *path,
- bool enable)
+int coresight_build_paths(struct coresight_device *csdev,
+ struct list_head *path, bool enable)
{
int i, ret = -EINVAL;
struct coresight_connection *conn;
--
1.9.1
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Mathieu Poirier <mathieu.poirier@linaro.org> |
|---|---|
| Date | 2015-10-18 20:40 +0200 |
| Subject | [PATCH V2 08/30] coresight: etm3x: implementing 'cpu_id()' API |
| Message-ID | <ql129-500-5@gated-at.bofh.it> |
| In reply to | #1250192 |
Adding an interface to lookup the CPU a tracer has been affined
to along with a source operation allowing external customers to
access it.
Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
---
drivers/hwtracing/coresight/coresight-etm3x.c | 8 ++++++++
include/linux/coresight.h | 3 +++
2 files changed, 11 insertions(+)
diff --git a/drivers/hwtracing/coresight/coresight-etm3x.c b/drivers/hwtracing/coresight/coresight-etm3x.c
index 3fe6433764d4..e199746bba05 100644
--- a/drivers/hwtracing/coresight/coresight-etm3x.c
+++ b/drivers/hwtracing/coresight/coresight-etm3x.c
@@ -312,6 +312,13 @@ static void etm_enable_hw(void *info)
dev_dbg(drvdata->dev, "cpu: %d enable smp call done\n", drvdata->cpu);
}
+static int etm_cpu_id(struct coresight_device *csdev)
+{
+ struct etm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+
+ return drvdata->cpu;
+}
+
int etm_get_trace_id(struct etm_drvdata *drvdata)
{
unsigned long flags;
@@ -444,6 +451,7 @@ static void sysfs_etm_disable(struct coresight_device *csdev)
}
static const struct coresight_ops_source etm_source_ops = {
+ .cpu_id = etm_cpu_id,
.trace_id = etm_trace_id,
.sysfs_enable = sysfs_etm_enable,
.sysfs_disable = sysfs_etm_disable,
diff --git a/include/linux/coresight.h b/include/linux/coresight.h
index 97155527dbdd..f9210df15f03 100644
--- a/include/linux/coresight.h
+++ b/include/linux/coresight.h
@@ -205,12 +205,15 @@ struct coresight_ops_link {
/**
* struct coresight_ops_source - basic operations for a source
* Operations available for sources.
+ * @cpu_id: returns the value of the CPU number this component
+ * is associated to.
* @trace_id: returns the value of the component's trace ID as known
to the HW.
* @sysfs_enable: enables tracing for a source, from sysFS.
* @sysfs_disable: disables tracing for a source, from sysFS.
*/
struct coresight_ops_source {
+ int (*cpu_id)(struct coresight_device *csdev);
int (*trace_id)(struct coresight_device *csdev);
int (*sysfs_enable)(struct coresight_device *csdev);
void (*sysfs_disable)(struct coresight_device *csdev);
--
1.9.1
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
Page 1 of 2 [1] 2 Next page →
Back to top | Article view | linux.kernel
csiph-web