[PATCH v4 6/6] perf tools: Use ioctl function to send sink configuration to kernel

Mathieu Poirier
2018-11-28T22:01:34Z

The communication of sink information for a trace session doesn't work when
more than one CPU is involved in the scenario due to the static nature of
sysFS. As such communicate the sink information to each event by using the
driver's sink configuration information and an ioctl command.

Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
---
tools/perf/arch/arm/util/cs-etm.c | 49 +++++++++++++++++++++++++++++++++++++--
tools/perf/util/evsel.c | 7 ++++++
tools/perf/util/evsel.h | 1 +
3 files changed, 55 insertions(+), 2 deletions(-)

diff --git a/tools/perf/arch/arm/util/cs-etm.c b/tools/perf/arch/arm/util/cs-etm.c
index d8081c2e6d44..4f0563b99a07 100644
--- a/tools/perf/arch/arm/util/cs-etm.c
+++ b/tools/perf/arch/arm/util/cs-etm.c
@@ -619,6 +619,26 @@ static FILE *cs_device__open_file(const char *name)

}

+static int cs_etm_check_drv_config_term(const char *name)
+{
+ struct stat st;
+ char path[PATH_MAX];
+ const char *sysfs;
+
+ /* CS devices are all found under sysFS */
+ sysfs = sysfs__mountpoint();
+ if (!sysfs)
+ return -EINVAL;
+
+ snprintf(path, PATH_MAX,
+ "%s" CS_BUS_DEVICE_PATH "%s", sysfs, name);
+
+ if (stat(path, &st) < 0)
+ return -EINVAL;
+
+ return 0;
+}
+
static int __printf(2, 3) cs_device__print_file(const char *name, const char *fmt, ...)
{
va_list args;
@@ -635,7 +655,7 @@ static int __printf(2, 3) cs_device__print_file(const char *name, const char *fm
return ret;
}

-static int cs_etm_set_drv_config_term(struct perf_evsel_config_term *term)
+static int cs_etm_set_drv_config_term_sysfs(struct perf_evsel_config_term *term)
{
int ret;
char enable_sink[ENABLE_SINK_MAX];
@@ -650,6 +670,21 @@ static int cs_etm_set_drv_config_term(struct perf_evsel_config_term *term)
return 0;
}

+static int cs_etm_set_drv_config_term_ioctl(struct perf_evsel *evsel,
+ struct perf_evsel_config_term *term)
+{
+ int ret;
+ const char *drv_cfg = term->val.drv_cfg;
+
+ /* First check the input */
+ ret = cs_etm_check_drv_config_term(drv_cfg);
+ if (ret)
+ return ret;
+
+ /* All good, apply configuration */
+ return perf_evsel__apply_drv_config(evsel, drv_cfg);
+}
+
int cs_etm_set_drv_config(struct perf_evsel *evsel,
struct perf_evsel_config_term **err_term)
{
@@ -660,7 +695,17 @@ int cs_etm_set_drv_config(struct perf_evsel *evsel,
if (term->type != PERF_EVSEL__CONFIG_TERM_DRV_CFG)
continue;

- err = cs_etm_set_drv_config_term(term);
+ /* First try the new interface, i.e ioctl() */
+ err = cs_etm_set_drv_config_term_ioctl(evsel, term);
+ if (!err)
+ continue;
+
+ /*
+ * Something went wrong, we are probably working with an older
+ * kernel. As such use the sysFS interface, which will only
+ * work for per-thread scenarios.
+ */
+ err = cs_etm_set_drv_config_term_sysfs(term);
if (err) {
*err_term = term;
break;
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index 6d187059a373..a0374dab843f 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -1195,6 +1195,13 @@ static int perf_evsel__append_filter(struct perf_evsel *evsel,
return -1;
}

+int perf_evsel__apply_drv_config(struct perf_evsel *evsel, const char *config)
+{
+ return perf_evsel__run_ioctl(evsel,
+ PERF_EVENT_IOC_SET_DRV_CONFIG,
+ (void *)config);
+}
+
int perf_evsel__append_tp_filter(struct perf_evsel *evsel, const char *filter)
{
return perf_evsel__append_filter(evsel, "(%s) && (%s)", filter);
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
index 3147ca76c6fc..30083b0ae62c 100644
--- a/tools/perf/util/evsel.h
+++ b/tools/perf/util/evsel.h
@@ -276,6 +276,7 @@ int perf_evsel__append_tp_filter(struct perf_evsel *evsel, const char *filter);
int perf_evsel__append_addr_filter(struct perf_evsel *evsel,
const char *filter);
int perf_evsel__apply_filter(struct perf_evsel *evsel, const char *filter);
+int perf_evsel__apply_drv_config(struct perf_evsel *evsel, const char *config);
int perf_evsel__enable(struct perf_evsel *evsel);
int perf_evsel__disable(struct perf_evsel *evsel);

--
2.7.4