[RFC PATCH] Add "-f" and "-F" flags to watch a "/sys? style file (single number)

From: Luck, Tony
Date: Tue Jul 25 2017 - 18:43:24 EST


From: Tony Luck <tony.luck@xxxxxxxxx>

-f shows absolute value from the file each time. -F shows the delta
---

This is a proof-of-concept patch to show how "perf" might be extended to
use the new RDT file system monitoring files. "-f" is useful for the llc_occupancy
"-F" for the MBM files.

tools/perf/builtin-c2c.c | 2 ++
tools/perf/builtin-mem.c | 2 ++
tools/perf/builtin-record.c | 4 ++++
tools/perf/builtin-stat.c | 4 ++++
tools/perf/builtin-top.c | 4 ++++
tools/perf/builtin-trace.c | 4 ++++
tools/perf/util/evsel.c | 22 ++++++++++++++++++++++
tools/perf/util/evsel.h | 1 +
tools/perf/util/parse-events.c | 17 +++++++++++++++++
tools/perf/util/parse-events.h | 1 +
10 files changed, 61 insertions(+)

diff --git a/tools/perf/builtin-c2c.c b/tools/perf/builtin-c2c.c
index 475999e48f66..094b84d34f7b 100644
--- a/tools/perf/builtin-c2c.c
+++ b/tools/perf/builtin-c2c.c
@@ -2692,6 +2692,8 @@ static int perf_c2c__record(int argc, const char **argv)
OPT_CALLBACK('e', "event", &event_set, "event",
"event selector. Use 'perf mem record -e list' to list available events",
parse_record_events),
+ OPT_CALLBACK('f', "file", &event_set, "file", "file selector", parse_files_option),
+ OPT_CALLBACK('F', "file", &event_set, "file", "delta file selector", parse_files_option),
OPT_BOOLEAN('u', "all-user", &all_user, "collect only user level data"),
OPT_BOOLEAN('k', "all-kernel", &all_kernel, "collect only kernel level data"),
OPT_UINTEGER('l', "ldlat", &perf_mem_events__loads_ldlat, "setup mem-loads latency"),
diff --git a/tools/perf/builtin-mem.c b/tools/perf/builtin-mem.c
index e001c0290793..86a332dd30cc 100644
--- a/tools/perf/builtin-mem.c
+++ b/tools/perf/builtin-mem.c
@@ -72,6 +72,8 @@ static int __cmd_record(int argc, const char **argv, struct perf_mem *mem)
OPT_CALLBACK('e', "event", &mem, "event",
"event selector. use 'perf mem record -e list' to list available events",
parse_record_events),
+ OPT_CALLBACK('f', "file", &mem, "file", "file selector", parse_files_option),
+ OPT_CALLBACK('F', "file", &mem, "file", "delta file selector", parse_files_option),
OPT_UINTEGER(0, "ldlat", &perf_mem_events__loads_ldlat, "mem-loads latency"),
OPT_INCR('v', "verbose", &verbose,
"be more verbose (show counter open errors, etc)"),
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index 17a14bcce34a..096a7b22f897 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -1551,6 +1551,10 @@ static struct option __record_options[] = {
OPT_CALLBACK('e', "event", &record.evlist, "event",
"event selector. use 'perf list' to list available events",
parse_events_option),
+ OPT_CALLBACK('f', "file", &record.evlist, "file",
+ "file selector", parse_files_option),
+ OPT_CALLBACK('F', "file", &record.evlist, "file",
+ "delta file selector", parse_files_option),
OPT_CALLBACK(0, "filter", &record.evlist, "filter",
"event filter", parse_filter),
OPT_CALLBACK_NOOPT(0, "exclude-perf", &record.evlist,
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index 48ac53b199fc..c5da65d0acce 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -1736,6 +1736,10 @@ static const struct option stat_options[] = {
OPT_CALLBACK('e', "event", &evsel_list, "event",
"event selector. use 'perf list' to list available events",
parse_events_option),
+ OPT_CALLBACK('f', "file", &evsel_list, "file",
+ "file selector", parse_files_option),
+ OPT_CALLBACK('F', "file", &evsel_list, "file",
+ "delta file selector", parse_files_option),
OPT_CALLBACK(0, "filter", &evsel_list, "filter",
"event filter", parse_filter),
OPT_BOOLEAN('i', "no-inherit", &no_inherit,
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index 6052376634c0..ded5a9e35c6b 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -1104,6 +1104,10 @@ int cmd_top(int argc, const char **argv)
OPT_CALLBACK('e', "event", &top.evlist, "event",
"event selector. use 'perf list' to list available events",
parse_events_option),
+ OPT_CALLBACK('f', "file", &top.evlist, "file",
+ "file selector", parse_files_option),
+ OPT_CALLBACK('F', "file", &top.evlist, "file",
+ "delta file selector", parse_files_option),
OPT_U64('c', "count", &opts->user_interval, "event period to sample"),
OPT_STRING('p', "pid", &target->pid, "pid",
"profile events on existing process id"),
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
index 4b2a5d298197..b404ebc829bc 100644
--- a/tools/perf/builtin-trace.c
+++ b/tools/perf/builtin-trace.c
@@ -2862,6 +2862,10 @@ int cmd_trace(int argc, const char **argv)
OPT_CALLBACK('e', "event", &trace, "event",
"event/syscall selector. use 'perf list' to list available events",
trace__parse_events_option),
+ OPT_CALLBACK('f', "file", &evsel_list, "file",
+ "file selector", parse_files_option),
+ OPT_CALLBACK('F', "file", &evsel_list, "file",
+ "delta file selector", parse_files_option),
OPT_BOOLEAN(0, "comm", &trace.show_comm,
"show the thread COMM next to its id"),
OPT_BOOLEAN(0, "tool_stats", &trace.show_tool_stats, "show tool stats"),
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index 413f74df08de..3353571a5c7e 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -1256,6 +1256,21 @@ void perf_counts_values__scale(struct perf_counts_values *count,
*pscaled = scaled;
}

+static int read_sys_file(int fd, struct perf_counts_values *count)
+{
+ char buf[100];
+ int n;
+ static u64 fake;
+
+ n = pread(fd, buf, sizeof buf, 0);
+ if (n >= 0) {
+ count->val = n ? strtol(buf, NULL, 0) : 0;
+ count->ena = count->run = ++fake;
+ return 0;
+ } else
+ return -errno;
+}
+
int perf_evsel__read(struct perf_evsel *evsel, int cpu, int thread,
struct perf_counts_values *count)
{
@@ -1264,6 +1279,8 @@ int perf_evsel__read(struct perf_evsel *evsel, int cpu, int thread,
if (FD(evsel, cpu, thread) < 0)
return -EINVAL;

+ if (evsel->sysfile)
+ return read_sys_file(FD(evsel, cpu, thread), count);
if (readn(FD(evsel, cpu, thread), count, sizeof(*count)) <= 0)
return -errno;

@@ -1556,6 +1573,11 @@ int perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
fprintf(stderr, "%.60s\n", graph_dotted_line);
}

+ if (evsel->sysfile) {
+ FD(evsel, 0, 0) = open(evsel->name, O_RDONLY, 0);
+ return 0;
+ }
+
for (cpu = 0; cpu < cpus->nr; cpu++) {

for (thread = 0; thread < nthreads; thread++) {
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
index d101695c482c..ede30e111947 100644
--- a/tools/perf/util/evsel.h
+++ b/tools/perf/util/evsel.h
@@ -121,6 +121,7 @@ struct perf_evsel {
bool per_pkg;
bool precise_max;
bool ignore_missing_thread;
+ bool sysfile;
/* parse modifier helper */
int exclude_GH;
int nr_members;
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 01e779b91c8e..0d725eda476d 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -1793,6 +1793,23 @@ int parse_events_option(const struct option *opt, const char *str,
return ret;
}

+int parse_files_option(const struct option *opt, const char *str,
+ int unset __maybe_unused)
+{
+ struct perf_evlist *evlist = *(struct perf_evlist **)opt->value;
+ struct perf_evsel *evsel = calloc(1, sizeof (*evsel));
+
+ evsel->name = strdup(str);
+ evsel->unit = "";
+ evsel->sysfile = true;
+ evsel->snapshot = (opt->short_name == 'f');
+ evsel->scale = 1.0;
+ INIT_LIST_HEAD(&evsel->config_terms);
+ evsel->bpf_fd = -1;
+ perf_evlist__add(evlist, evsel);
+ return 0;
+}
+
static int
foreach_evsel_in_last_glob(struct perf_evlist *evlist,
int (*func)(struct perf_evsel *evsel,
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
index a235f4d6d5e5..7e14a4c66fad 100644
--- a/tools/perf/util/parse-events.h
+++ b/tools/perf/util/parse-events.h
@@ -30,6 +30,7 @@ bool have_tracepoints(struct list_head *evlist);
const char *event_type(int type);

int parse_events_option(const struct option *opt, const char *str, int unset);
+int parse_files_option(const struct option *opt, const char *str, int unset);
int parse_events(struct perf_evlist *evlist, const char *str,
struct parse_events_error *error);
int parse_events_terms(struct list_head *terms, const char *str);
--
2.11.0