2015-07-21 12:32:13

by Jiri Olsa

[permalink] [raw]
Subject: [RFC 00/47] perf stat: Add scripting support

hi,
sending RFC on another attempt for stat scripting.

The initial attempt defined its own formula lang and allowed
triggering user's script on the end of the stat command:
http://marc.info/?l=linux-kernel&m=136742146322273&w=2

This patchset abandons the idea of new formula language
and rather adds support to:
- store stat data into perf.data file
- add python support to process stat events

Basically it allows to store stat data into perf.data and
post process it with python scripts in a similar way we
do for sampling data.

Examples:

To record data for command stat workload:
$ perf stat record kill
...

Performance counter stats for 'kill':

0.372007 task-clock (msec) # 0.613 CPUs utilized
3 context-switches # 0.008 M/sec
0 cpu-migrations # 0.000 K/sec
62 page-faults # 0.167 M/sec
1,129,973 cycles # 3.038 GHz
<not supported> stalled-cycles-frontend
<not supported> stalled-cycles-backend
813,313 instructions # 0.72 insns per cycle
166,161 branches # 446.661 M/sec
8,747 branch-misses # 5.26% of all branches

0.000607287 seconds time elapsed

To report perf stat data:
$ perf stat report

Performance counter stats for '/home/jolsa/bin/perf stat record kill':

0.372007 task-clock (msec) # inf CPUs utilized
3 context-switches # 0.008 M/sec
0 cpu-migrations # 0.000 K/sec
62 page-faults # 0.167 M/sec
1,129,973 cycles # 3.038 GHz
<not supported> stalled-cycles-frontend
<not supported> stalled-cycles-backend
813,313 instructions # 0.72 insns per cycle
166,161 branches # 446.661 M/sec
8,747 branch-misses # 5.26% of all branches

0.000000000 seconds time elapsed

To store system-wide period stat data:
$ perf stat -e cycles:u,instructions:u -a -I 1000 record
# time counts unit events
1.000265471 462,311,482 cycles:u (100.00%)
1.000265471 590,037,440 instructions:u
2.000483453 722,532,336 cycles:u (100.00%)
2.000483453 848,678,197 instructions:u
3.000759876 75,990,880 cycles:u (100.00%)
3.000759876 86,187,813 instructions:u
^C 3.213960893 85,329,533 cycles:u (100.00%)
3.213960893 135,954,296 instructions:u

To report perf stat data:
$ perf stat report
# time counts unit events
1.000265471 462,311,482 cycles:u (100.00%)
1.000265471 590,037,440 instructions:u
2.000483453 722,532,336 cycles:u (100.00%)
2.000483453 848,678,197 instructions:u
3.000759876 75,990,880 cycles:u (100.00%)
3.000759876 86,187,813 instructions:u
3.213960893 85,329,533 cycles:u (100.00%)
3.213960893 135,954,296 instructions:u

To run stat-cpi.py script over perf.data:
$ perf script -s scripts/python/stat-cpi.py
1.000265: cpu -1, thread -1 -> cpi 0.783529 (462311482/590037440)
2.000483: cpu -1, thread -1 -> cpi 0.851362 (722532336/848678197)
3.000760: cpu -1, thread -1 -> cpi 0.881689 (75990880/86187813)
3.213961: cpu -1, thread -1 -> cpi 0.627634 (85329533/135954296)

To pipe data from stat to stat-cpi script:
$ perf stat -e cycles:u,instructions:u -A -C 0 -I 1000 record | perf script -s scripts/python/stat-cpi.py
1.000192: cpu 0, thread -1 -> cpi 0.739535 (23921908/32347236)
2.000376: cpu 0, thread -1 -> cpi 1.663482 (2519340/1514498)
3.000621: cpu 0, thread -1 -> cpi 1.396308 (16162767/11575362)
4.000700: cpu 0, thread -1 -> cpi 1.092246 (20077258/18381624)
5.000867: cpu 0, thread -1 -> cpi 0.473816 (45157586/95306156)
6.001034: cpu 0, thread -1 -> cpi 0.532792 (43701668/82023818)
7.001195: cpu 0, thread -1 -> cpi 1.122059 (29890042/26638561)

Raw script stat data output:
$ perf stat -e cycles:u,instructions:u -A -C 0 -I 1000 record | perf --no-pager script
CPU THREAD VAL ENA RUN TIME EVENT
0 -1 12302059 1000811347 1000810712 1000198821 cycles:u
0 -1 2565362 1000823218 1000823218 1000198821 instructions:u
0 -1 14453353 1000812704 1000812704 2000382283 cycles:u
0 -1 4600932 1000799342 1000799342 2000382283 instructions:u
0 -1 15245106 1000774425 1000774425 3000538255 cycles:u
0 -1 2624324 1000769310 1000769310 3000538255 instructions:u


The stat data are stored in new stat, stat-round, stat-config user events.
stat - stored for each read syscall of the counter
stat round - stored for each interval or end of the command invocation
stat config - stores all the config information needed to process data
so report tool could restore the same output as record

The python script can now define 'stat__<eventname>_<modifier>' functions
to get stat events data and 'stat__interval' to get stat-round data. See
CPI script example in scripts/python/stat-cpi.py.

Also available in:
git://git.kernel.org/pub/scm/linux/kernel/git/jolsa/perf.git
perf/stat_script


This patchset still has MANY rough edges and loose ends,
but I think it's better approach than to define our own
formula scripting language.

The patchset is growing and there's still a long way to go,
so I'd like to hear some opinions before I go further ;-)


thanks for comments,
jirka


Cc: Andi Kleen <[email protected]>
Cc: Ulrich Drepper <[email protected]>
Cc: Will Deacon <[email protected]>
Cc: Stephane Eranian <[email protected]>
---
Jiri Olsa (47):
perf test: Check for refcnt in thread_map test
perf stat: Introduce struct perf_stat_config
perf stat: Move scale into struct perf_stat_config
perf stat: Move output into struct perf_stat_config
perf stat: Move interval into struct perf_stat_config
perf stat: Pass struct perf_stat_config into process_counter
perf stat: Move counter processing code into stat object
perf tools: Use bool instead of target argument in perf_evlist__propagate_maps
perf tools: Tolerate NULL maps in perf_evlist__propagate_maps
perf tools: Force perf_evlist__set_maps to propagate maps through events
perf tools: Use argv style storage for cmdline feature data
perf tools: Add thread_map event
perf tools: Add thread_map event sythesize function
perf tools: Add thread_map__new_event function
perf tools: Add cpu_map event
perf tools: Add cpu_map event synthesize function
perf tools: Add cpu_map__new_event function
perf tools: Add stat config event
perf tools: Add stat config event synthesize function
perf tools: Add stat config event read function
perf tools: Add stat event
perf tools: Add stat event synthesize function
perf tools: Add stat event read function
perf tools: Add stat round event
perf tools: Add stat round event synthesize function
perf tools: Introduce stat feature
perf tools: Move id_offset out of struct perf_evsel union
perf stat record: Add record command
perf stat record: Initialize record features
perf stat record: Synthesize stat record data
perf stat record: Store events IDs in perf data file
perf stat record: Add pipe support for record command
perf stat record: Write stat events on record
perf stat record: Write stat round events on record
perf stat report: Add report command
perf stat report: Process cpu/threads maps
perf stat report: Process stat config event
perf stat report: Process stat and stat round events
perf stat report: Move csv_sep initialization before report command
perf script: Check output fields only for samples
perf script: Process cpu/threads maps
perf script: Process stat config event
perf script: Add process_stat/process_stat_interval scripting interface
perf script: Add stat default handlers
perf script: Display stat events by default
perf script: Add python support for stat events
perf script: Add stat-cpi.py script

tools/perf/Documentation/perf-stat.txt | 24 +
tools/perf/builtin-record.c | 2 +
tools/perf/builtin-script.c | 143 ++++-
tools/perf/builtin-stat.c | 579 +++++++++++++++------
tools/perf/scripts/python/stat-cpi.py | 74 +++
tools/perf/tests/Build | 2 +
tools/perf/tests/builtin-test.c | 20 +
tools/perf/tests/cpumap.c | 39 ++
tools/perf/tests/stat.c | 108 ++++
tools/perf/tests/tests.h | 6 +
tools/perf/tests/thread-map.c | 47 ++
tools/perf/util/cpumap.c | 27 +
tools/perf/util/cpumap.h | 3 +
tools/perf/util/event.c | 170 ++++++
tools/perf/util/event.h | 94 +++-
tools/perf/util/evlist.c | 34 +-
tools/perf/util/evlist.h | 14 +-
tools/perf/util/evsel.h | 2 +-
tools/perf/util/header.c | 49 +-
tools/perf/util/header.h | 2 +
.../util/scripting-engines/trace-event-python.c | 113 +++-
tools/perf/util/session.c | 123 +++++
tools/perf/util/stat.c | 162 ++++++
tools/perf/util/stat.h | 16 +
tools/perf/util/thread_map.c | 27 +
tools/perf/util/thread_map.h | 3 +
tools/perf/util/tool.h | 7 +-
tools/perf/util/trace-event.h | 4 +
28 files changed, 1686 insertions(+), 208 deletions(-)
create mode 100644 tools/perf/scripts/python/stat-cpi.py
create mode 100644 tools/perf/tests/cpumap.c
create mode 100644 tools/perf/tests/stat.c


2015-07-21 12:32:15

by Jiri Olsa

[permalink] [raw]
Subject: [PATCH 01/47] perf test: Check for refcnt in thread_map test

Checking also for refcnt in thread_map test.

Link: http://lkml.kernel.org/n/[email protected]
Signed-off-by: Jiri Olsa <[email protected]>
---
tools/perf/tests/thread-map.c | 4 ++++
1 file changed, 4 insertions(+)

diff --git a/tools/perf/tests/thread-map.c b/tools/perf/tests/thread-map.c
index 5acf000939ea..138a0e3431fa 100644
--- a/tools/perf/tests/thread-map.c
+++ b/tools/perf/tests/thread-map.c
@@ -20,6 +20,8 @@ int test__thread_map(void)
TEST_ASSERT_VAL("wrong comm",
thread_map__comm(map, 0) &&
!strcmp(thread_map__comm(map, 0), "perf"));
+ TEST_ASSERT_VAL("wrong refcnt",
+ atomic_read(&map->refcnt) == 1);
thread_map__put(map);

/* test dummy pid */
@@ -33,6 +35,8 @@ int test__thread_map(void)
TEST_ASSERT_VAL("wrong comm",
thread_map__comm(map, 0) &&
!strcmp(thread_map__comm(map, 0), "dummy"));
+ TEST_ASSERT_VAL("wrong refcnt",
+ atomic_read(&map->refcnt) == 1);
thread_map__put(map);
return 0;
}
--
2.4.3

2015-07-21 12:32:18

by Jiri Olsa

[permalink] [raw]
Subject: [PATCH 02/47] perf stat: Introduce struct perf_stat_config

Moving aggr_mode into new struct. The point is to centralize
the base stat config so it could be used localy together with
other stat routines in other parts of perf code.

Link: http://lkml.kernel.org/n/[email protected]
Signed-off-by: Jiri Olsa <[email protected]>
---
tools/perf/builtin-stat.c | 39 ++++++++++++++++++++++-----------------
tools/perf/util/stat.h | 4 ++++
2 files changed, 26 insertions(+), 17 deletions(-)

diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index d99d850e1444..bafb830b1bd9 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -102,7 +102,6 @@ static struct target target = {
static int run_count = 1;
static bool no_inherit = false;
static bool scale = true;
-static enum aggr_mode aggr_mode = AGGR_GLOBAL;
static volatile pid_t child_pid = -1;
static bool null_run = false;
static int detailed_run = 0;
@@ -126,6 +125,10 @@ static int (*aggr_get_id)(struct cpu_map *m, int cpu);

static volatile int done = 0;

+static struct perf_stat_config stat_config = {
+ .aggr_mode = AGGR_GLOBAL,
+};
+
static inline void diff_timespec(struct timespec *r, struct timespec *a,
struct timespec *b)
{
@@ -230,7 +233,7 @@ process_counter_values(struct perf_evsel *evsel, int cpu, int thread,
if (skip)
count = &zero;

- switch (aggr_mode) {
+ switch (stat_config.aggr_mode) {
case AGGR_THREAD:
case AGGR_CORE:
case AGGR_SOCKET:
@@ -238,7 +241,7 @@ process_counter_values(struct perf_evsel *evsel, int cpu, int thread,
if (!evsel->snapshot)
perf_evsel__compute_deltas(evsel, cpu, thread, count);
perf_counts_values__scale(count, scale, NULL);
- if (aggr_mode == AGGR_NONE)
+ if (stat_config.aggr_mode == AGGR_NONE)
perf_stat__update_shadow_stats(evsel, count->values, cpu);
break;
case AGGR_GLOBAL:
@@ -291,7 +294,7 @@ static int process_counter(struct perf_evsel *counter)
if (ret)
return ret;

- if (aggr_mode != AGGR_GLOBAL)
+ if (stat_config.aggr_mode != AGGR_GLOBAL)
return 0;

if (!counter->snapshot)
@@ -578,7 +581,7 @@ static void print_noise(struct perf_evsel *evsel, double avg)

static void aggr_printout(struct perf_evsel *evsel, int id, int nr)
{
- switch (aggr_mode) {
+ switch (stat_config.aggr_mode) {
case AGGR_CORE:
fprintf(output, "S%d-C%*d%s%*d%s",
cpu_map__id_to_socket(id),
@@ -670,7 +673,7 @@ static void abs_printout(int id, int nr, struct perf_evsel *evsel, double avg)

aggr_printout(evsel, id, nr);

- if (aggr_mode == AGGR_GLOBAL)
+ if (stat_config.aggr_mode == AGGR_GLOBAL)
cpu = 0;

fprintf(output, fmt, avg, csv_sep);
@@ -688,7 +691,8 @@ static void abs_printout(int id, int nr, struct perf_evsel *evsel, double avg)
if (csv_output || interval)
return;

- perf_stat__print_shadow_stats(output, evsel, avg, cpu, aggr_mode);
+ perf_stat__print_shadow_stats(output, evsel, avg, cpu,
+ stat_config.aggr_mode);
}

static void print_aggr(char *prefix)
@@ -909,7 +913,7 @@ static void print_interval(char *prefix, struct timespec *ts)
sprintf(prefix, "%6lu.%09lu%s", ts->tv_sec, ts->tv_nsec, csv_sep);

if (num_print_interval == 0 && !csv_output) {
- switch (aggr_mode) {
+ switch (stat_config.aggr_mode) {
case AGGR_SOCKET:
fprintf(output, "# time socket cpus counts %*s events\n", unit_width, "unit");
break;
@@ -985,7 +989,7 @@ static void print_counters(struct timespec *ts, int argc, const char **argv)
else
print_header(argc, argv);

- switch (aggr_mode) {
+ switch (stat_config.aggr_mode) {
case AGGR_CORE:
case AGGR_SOCKET:
print_aggr(prefix);
@@ -1064,7 +1068,7 @@ static int stat__set_big_num(const struct option *opt __maybe_unused,

static int perf_stat_init_aggr_mode(void)
{
- switch (aggr_mode) {
+ switch (stat_config.aggr_mode) {
case AGGR_SOCKET:
if (cpu_map__build_socket_map(evsel_list->cpus, &aggr_map)) {
perror("cannot build socket map");
@@ -1286,7 +1290,7 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
stat__set_big_num),
OPT_STRING('C', "cpu", &target.cpu_list, "cpu",
"list of cpus to monitor in system-wide"),
- OPT_SET_UINT('A', "no-aggr", &aggr_mode,
+ OPT_SET_UINT('A', "no-aggr", &stat_config.aggr_mode,
"disable CPU count aggregation", AGGR_NONE),
OPT_STRING('x', "field-separator", &csv_sep, "separator",
"print counts with custom separator"),
@@ -1302,11 +1306,11 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
"command to run after to the measured command"),
OPT_UINTEGER('I', "interval-print", &interval,
"print counts at regular interval in ms (>= 100)"),
- OPT_SET_UINT(0, "per-socket", &aggr_mode,
+ OPT_SET_UINT(0, "per-socket", &stat_config.aggr_mode,
"aggregate counts per processor socket", AGGR_SOCKET),
- OPT_SET_UINT(0, "per-core", &aggr_mode,
+ OPT_SET_UINT(0, "per-core", &stat_config.aggr_mode,
"aggregate counts per physical processor core", AGGR_CORE),
- OPT_SET_UINT(0, "per-thread", &aggr_mode,
+ OPT_SET_UINT(0, "per-thread", &stat_config.aggr_mode,
"aggregate counts per thread", AGGR_THREAD),
OPT_UINTEGER('D', "delay", &initial_delay,
"ms to wait before starting measurement after program start"),
@@ -1399,7 +1403,7 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
run_count = 1;
}

- if ((aggr_mode == AGGR_THREAD) && !target__has_task(&target)) {
+ if ((stat_config.aggr_mode == AGGR_THREAD) && !target__has_task(&target)) {
fprintf(stderr, "The --per-thread option is only available "
"when monitoring via -p -t options.\n");
parse_options_usage(NULL, options, "p", 1);
@@ -1411,7 +1415,8 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
* no_aggr, cgroup are for system-wide only
* --per-thread is aggregated per thread, we dont mix it with cpu mode
*/
- if (((aggr_mode != AGGR_GLOBAL && aggr_mode != AGGR_THREAD) || nr_cgroups) &&
+ if (((stat_config.aggr_mode != AGGR_GLOBAL &&
+ stat_config.aggr_mode != AGGR_THREAD) || nr_cgroups) &&
!target__has_cpu(&target)) {
fprintf(stderr, "both cgroup and no-aggregation "
"modes only available in system-wide mode\n");
@@ -1444,7 +1449,7 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
* Initialize thread_map with comm names,
* so we could print it out on output.
*/
- if (aggr_mode == AGGR_THREAD)
+ if (stat_config.aggr_mode == AGGR_THREAD)
thread_map__read_comms(evsel_list->threads);

if (interval && interval < 100) {
diff --git a/tools/perf/util/stat.h b/tools/perf/util/stat.h
index 1cfbe0a980ac..078bee49ccad 100644
--- a/tools/perf/util/stat.h
+++ b/tools/perf/util/stat.h
@@ -50,6 +50,10 @@ struct perf_counts {
struct xyarray *values;
};

+struct perf_stat_config {
+ enum aggr_mode aggr_mode;
+};
+
static inline struct perf_counts_values*
perf_counts(struct perf_counts *counts, int cpu, int thread)
{
--
2.4.3

2015-07-21 12:44:48

by Jiri Olsa

[permalink] [raw]
Subject: [PATCH 03/47] perf stat: Move scale into struct perf_stat_config

Moving scale into struct perf_stat_config. The point is to centralize
the base stat config so it could be used localy together with
other stat routines in other parts of perf code.

Link: http://lkml.kernel.org/n/[email protected]
Signed-off-by: Jiri Olsa <[email protected]>
---
tools/perf/builtin-stat.c | 12 ++++++------
tools/perf/util/stat.h | 1 +
2 files changed, 7 insertions(+), 6 deletions(-)

diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index bafb830b1bd9..3fb2865e519a 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -101,7 +101,6 @@ static struct target target = {

static int run_count = 1;
static bool no_inherit = false;
-static bool scale = true;
static volatile pid_t child_pid = -1;
static bool null_run = false;
static int detailed_run = 0;
@@ -127,6 +126,7 @@ static volatile int done = 0;

static struct perf_stat_config stat_config = {
.aggr_mode = AGGR_GLOBAL,
+ .scale = true,
};

static inline void diff_timespec(struct timespec *r, struct timespec *a,
@@ -151,7 +151,7 @@ static int create_perf_stat_counter(struct perf_evsel *evsel)
{
struct perf_event_attr *attr = &evsel->attr;

- if (scale)
+ if (stat_config.scale)
attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED |
PERF_FORMAT_TOTAL_TIME_RUNNING;

@@ -240,13 +240,13 @@ process_counter_values(struct perf_evsel *evsel, int cpu, int thread,
case AGGR_NONE:
if (!evsel->snapshot)
perf_evsel__compute_deltas(evsel, cpu, thread, count);
- perf_counts_values__scale(count, scale, NULL);
+ perf_counts_values__scale(count, stat_config.scale, NULL);
if (stat_config.aggr_mode == AGGR_NONE)
perf_stat__update_shadow_stats(evsel, count->values, cpu);
break;
case AGGR_GLOBAL:
aggr->val += count->val;
- if (scale) {
+ if (stat_config.scale) {
aggr->ena += count->ena;
aggr->run += count->run;
}
@@ -299,7 +299,7 @@ static int process_counter(struct perf_evsel *counter)

if (!counter->snapshot)
perf_evsel__compute_deltas(counter, -1, -1, aggr);
- perf_counts_values__scale(aggr, scale, &counter->counts->scaled);
+ perf_counts_values__scale(aggr, stat_config.scale, &counter->counts->scaled);

for (i = 0; i < 3; i++)
update_stats(&ps->res_stats[i], count[i]);
@@ -1274,7 +1274,7 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
"system-wide collection from all CPUs"),
OPT_BOOLEAN('g', "group", &group,
"put the counters into a counter group"),
- OPT_BOOLEAN('c', "scale", &scale, "scale/normalize counters"),
+ OPT_BOOLEAN('c', "scale", &stat_config.scale, "scale/normalize counters"),
OPT_INCR('v', "verbose", &verbose,
"be more verbose (show counter open errors, etc)"),
OPT_INTEGER('r', "repeat", &run_count,
diff --git a/tools/perf/util/stat.h b/tools/perf/util/stat.h
index 078bee49ccad..0a1d83faa7b9 100644
--- a/tools/perf/util/stat.h
+++ b/tools/perf/util/stat.h
@@ -52,6 +52,7 @@ struct perf_counts {

struct perf_stat_config {
enum aggr_mode aggr_mode;
+ bool scale;
};

static inline struct perf_counts_values*
--
2.4.3

2015-07-21 12:32:21

by Jiri Olsa

[permalink] [raw]
Subject: [PATCH 04/47] perf stat: Move output into struct perf_stat_config

Moving output into struct perf_stat_config. The point is to centralize
the base stat config so it could be used localy together with
other stat routines in other parts of perf code.

Link: http://lkml.kernel.org/n/[email protected]
Signed-off-by: Jiri Olsa <[email protected]>
---
tools/perf/builtin-stat.c | 35 +++++++++++++++++++++++------------
tools/perf/util/stat.h | 1 +
2 files changed, 24 insertions(+), 12 deletions(-)

diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index 3fb2865e519a..e3ea8b67703d 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -110,7 +110,6 @@ static int big_num_opt = -1;
static const char *csv_sep = NULL;
static bool csv_output = false;
static bool group = false;
-static FILE *output = NULL;
static const char *pre_cmd = NULL;
static const char *post_cmd = NULL;
static bool sync_run = false;
@@ -305,7 +304,7 @@ static int process_counter(struct perf_evsel *counter)
update_stats(&ps->res_stats[i], count[i]);

if (verbose) {
- fprintf(output, "%s: %" PRIu64 " %" PRIu64 " %" PRIu64 "\n",
+ fprintf(stat_config.output, "%s: %" PRIu64 " %" PRIu64 " %" PRIu64 "\n",
perf_evsel__name(counter), count[0], count[1], count[2]);
}

@@ -548,13 +547,13 @@ static int run_perf_stat(int argc, const char **argv)
static void print_running(u64 run, u64 ena)
{
if (csv_output) {
- fprintf(output, "%s%" PRIu64 "%s%.2f",
+ fprintf(stat_config.output, "%s%" PRIu64 "%s%.2f",
csv_sep,
run,
csv_sep,
ena ? 100.0 * run / ena : 100.0);
} else if (run != ena) {
- fprintf(output, " (%.2f%%)", 100.0 * run / ena);
+ fprintf(stat_config.output, " (%.2f%%)", 100.0 * run / ena);
}
}

@@ -563,9 +562,9 @@ static void print_noise_pct(double total, double avg)
double pct = rel_stddev_stats(total, avg);

if (csv_output)
- fprintf(output, "%s%.2f%%", csv_sep, pct);
+ fprintf(stat_config.output, "%s%.2f%%", csv_sep, pct);
else if (pct)
- fprintf(output, " ( +-%6.2f%% )", pct);
+ fprintf(stat_config.output, " ( +-%6.2f%% )", pct);
}

static void print_noise(struct perf_evsel *evsel, double avg)
@@ -583,7 +582,7 @@ static void aggr_printout(struct perf_evsel *evsel, int id, int nr)
{
switch (stat_config.aggr_mode) {
case AGGR_CORE:
- fprintf(output, "S%d-C%*d%s%*d%s",
+ fprintf(stat_config.output, "S%d-C%*d%s%*d%s",
cpu_map__id_to_socket(id),
csv_output ? 0 : -8,
cpu_map__id_to_cpu(id),
@@ -593,7 +592,7 @@ static void aggr_printout(struct perf_evsel *evsel, int id, int nr)
csv_sep);
break;
case AGGR_SOCKET:
- fprintf(output, "S%*d%s%*d%s",
+ fprintf(stat_config.output, "S%*d%s%*d%s",
csv_output ? 0 : -5,
id,
csv_sep,
@@ -602,12 +601,12 @@ static void aggr_printout(struct perf_evsel *evsel, int id, int nr)
csv_sep);
break;
case AGGR_NONE:
- fprintf(output, "CPU%*d%s",
+ fprintf(stat_config.output, "CPU%*d%s",
csv_output ? 0 : -4,
perf_evsel__cpus(evsel)->map[id], csv_sep);
break;
case AGGR_THREAD:
- fprintf(output, "%*s-%*d%s",
+ fprintf(stat_config.output, "%*s-%*d%s",
csv_output ? 0 : 16,
thread_map__comm(evsel->threads, id),
csv_output ? 0 : -8,
@@ -622,6 +621,7 @@ static void aggr_printout(struct perf_evsel *evsel, int id, int nr)

static void nsec_printout(int id, int nr, struct perf_evsel *evsel, double avg)
{
+ FILE *output = stat_config.output;
double msecs = avg / 1e6;
const char *fmt_v, *fmt_n;
char name[25];
@@ -658,6 +658,7 @@ static void nsec_printout(int id, int nr, struct perf_evsel *evsel, double avg)

static void abs_printout(int id, int nr, struct perf_evsel *evsel, double avg)
{
+ FILE *output = stat_config.output;
double sc = evsel->scale;
const char *fmt;
int cpu = cpu_map__id_to_cpu(id);
@@ -697,6 +698,7 @@ static void abs_printout(int id, int nr, struct perf_evsel *evsel, double avg)

static void print_aggr(char *prefix)
{
+ FILE *output = stat_config.output;
struct perf_evsel *counter;
int cpu, cpu2, s, s2, id, nr;
double uval;
@@ -765,6 +767,7 @@ static void print_aggr(char *prefix)

static void print_aggr_thread(struct perf_evsel *counter, char *prefix)
{
+ FILE *output = stat_config.output;
int nthreads = thread_map__nr(counter->threads);
int ncpus = cpu_map__nr(counter->cpus);
int cpu, thread;
@@ -803,6 +806,7 @@ static void print_aggr_thread(struct perf_evsel *counter, char *prefix)
*/
static void print_counter_aggr(struct perf_evsel *counter, char *prefix)
{
+ FILE *output = stat_config.output;
struct perf_stat *ps = counter->priv;
double avg = avg_stats(&ps->res_stats[0]);
int scaled = counter->counts->scaled;
@@ -854,6 +858,7 @@ static void print_counter_aggr(struct perf_evsel *counter, char *prefix)
*/
static void print_counter(struct perf_evsel *counter, char *prefix)
{
+ FILE *output = stat_config.output;
u64 ena, run, val;
double uval;
int cpu;
@@ -908,6 +913,7 @@ static void print_counter(struct perf_evsel *counter, char *prefix)

static void print_interval(char *prefix, struct timespec *ts)
{
+ FILE *output = stat_config.output;
static int num_print_interval;

sprintf(prefix, "%6lu.%09lu%s", ts->tv_sec, ts->tv_nsec, csv_sep);
@@ -938,6 +944,7 @@ static void print_interval(char *prefix, struct timespec *ts)

static void print_header(int argc, const char **argv)
{
+ FILE *output = stat_config.output;
int i;

fflush(stdout);
@@ -967,6 +974,8 @@ static void print_header(int argc, const char **argv)

static void print_footer(void)
{
+ FILE *output = stat_config.output;
+
if (!null_run)
fprintf(output, "\n");
fprintf(output, " %17.9f seconds time elapsed",
@@ -1013,7 +1022,7 @@ static void print_counters(struct timespec *ts, int argc, const char **argv)
if (!interval && !csv_output)
print_footer();

- fflush(output);
+ fflush(stat_config.output);
}

static volatile int signr = -1;
@@ -1322,6 +1331,7 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
};
int status = -EINVAL, run_idx;
const char *mode;
+ FILE *output = stderr;

setlocale(LC_ALL, "");

@@ -1332,7 +1342,6 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
argc = parse_options(argc, argv, options, stat_usage,
PARSE_OPT_STOP_AT_NON_OPTION);

- output = stderr;
if (output_name && strcmp(output_name, "-"))
output = NULL;

@@ -1369,6 +1378,8 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
}
}

+ stat_config.output = output;
+
if (csv_sep) {
csv_output = true;
if (!strcmp(csv_sep, "\\t"))
diff --git a/tools/perf/util/stat.h b/tools/perf/util/stat.h
index 0a1d83faa7b9..ed0e05829cb0 100644
--- a/tools/perf/util/stat.h
+++ b/tools/perf/util/stat.h
@@ -53,6 +53,7 @@ struct perf_counts {
struct perf_stat_config {
enum aggr_mode aggr_mode;
bool scale;
+ FILE *output;
};

static inline struct perf_counts_values*
--
2.4.3

2015-07-21 12:44:21

by Jiri Olsa

[permalink] [raw]
Subject: [PATCH 05/47] perf stat: Move interval into struct perf_stat_config

Moving interval into struct perf_stat_config. The point is to centralize
the base stat config so it could be used localy together with
other stat routines in other parts of perf code.

Link: http://lkml.kernel.org/n/[email protected]
Signed-off-by: Jiri Olsa <[email protected]>
---
tools/perf/builtin-stat.c | 14 +++++++++-----
tools/perf/util/stat.h | 1 +
2 files changed, 10 insertions(+), 5 deletions(-)

diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index e3ea8b67703d..1bdfec8f5fe6 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -113,7 +113,6 @@ static bool group = false;
static const char *pre_cmd = NULL;
static const char *post_cmd = NULL;
static bool sync_run = false;
-static unsigned int interval = 0;
static unsigned int initial_delay = 0;
static unsigned int unit_width = 4; /* strlen("unit") */
static bool forever = false;
@@ -404,6 +403,7 @@ static void workload_exec_failed_signal(int signo __maybe_unused, siginfo_t *inf

static int __run_perf_stat(int argc, const char **argv)
{
+ int interval = stat_config.interval;
char msg[512];
unsigned long long t0, t1;
struct perf_evsel *counter;
@@ -646,7 +646,7 @@ static void nsec_printout(int id, int nr, struct perf_evsel *evsel, double avg)
if (evsel->cgrp)
fprintf(output, "%s%s", csv_sep, evsel->cgrp->name);

- if (csv_output || interval)
+ if (csv_output || stat_config.interval)
return;

if (perf_evsel__match(evsel, SOFTWARE, SW_TASK_CLOCK))
@@ -689,7 +689,7 @@ static void abs_printout(int id, int nr, struct perf_evsel *evsel, double avg)
if (evsel->cgrp)
fprintf(output, "%s%s", csv_sep, evsel->cgrp->name);

- if (csv_output || interval)
+ if (csv_output || stat_config.interval)
return;

perf_stat__print_shadow_stats(output, evsel, avg, cpu,
@@ -990,6 +990,7 @@ static void print_footer(void)

static void print_counters(struct timespec *ts, int argc, const char **argv)
{
+ int interval = stat_config.interval;
struct perf_evsel *counter;
char buf[64], *prefix = NULL;

@@ -1029,7 +1030,7 @@ static volatile int signr = -1;

static void skip_signal(int signo)
{
- if ((child_pid == -1) || interval)
+ if ((child_pid == -1) || stat_config.interval)
done = 1;

signr = signo;
@@ -1313,7 +1314,7 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
"command to run prior to the measured command"),
OPT_STRING(0, "post", &post_cmd, "command",
"command to run after to the measured command"),
- OPT_UINTEGER('I', "interval-print", &interval,
+ OPT_UINTEGER('I', "interval-print", &stat_config.interval,
"print counts at regular interval in ms (>= 100)"),
OPT_SET_UINT(0, "per-socket", &stat_config.aggr_mode,
"aggregate counts per processor socket", AGGR_SOCKET),
@@ -1332,6 +1333,7 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
int status = -EINVAL, run_idx;
const char *mode;
FILE *output = stderr;
+ unsigned int interval;

setlocale(LC_ALL, "");

@@ -1342,6 +1344,8 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
argc = parse_options(argc, argv, options, stat_usage,
PARSE_OPT_STOP_AT_NON_OPTION);

+ interval = stat_config.interval;
+
if (output_name && strcmp(output_name, "-"))
output = NULL;

diff --git a/tools/perf/util/stat.h b/tools/perf/util/stat.h
index ed0e05829cb0..1da706d848fb 100644
--- a/tools/perf/util/stat.h
+++ b/tools/perf/util/stat.h
@@ -54,6 +54,7 @@ struct perf_stat_config {
enum aggr_mode aggr_mode;
bool scale;
FILE *output;
+ unsigned int interval;
};

static inline struct perf_counts_values*
--
2.4.3

2015-07-21 12:32:25

by Jiri Olsa

[permalink] [raw]
Subject: [PATCH 06/47] perf stat: Pass struct perf_stat_config into process_counter

Passing struct perf_stat_config into process_counter, so we could
make process_counter global and use it from other places.

Link: http://lkml.kernel.org/n/[email protected]
Signed-off-by: Jiri Olsa <[email protected]>
---
tools/perf/builtin-stat.c | 29 ++++++++++++++++-------------
1 file changed, 16 insertions(+), 13 deletions(-)

diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index 1bdfec8f5fe6..5a781718c09f 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -216,7 +216,8 @@ static int check_per_pkg(struct perf_evsel *counter, int cpu, bool *skip)
}

static int
-process_counter_values(struct perf_evsel *evsel, int cpu, int thread,
+process_counter_values(struct perf_stat_config *config, struct perf_evsel *evsel,
+ int cpu, int thread,
struct perf_counts_values *count)
{
struct perf_counts_values *aggr = &evsel->counts->aggr;
@@ -231,20 +232,20 @@ process_counter_values(struct perf_evsel *evsel, int cpu, int thread,
if (skip)
count = &zero;

- switch (stat_config.aggr_mode) {
+ switch (config->aggr_mode) {
case AGGR_THREAD:
case AGGR_CORE:
case AGGR_SOCKET:
case AGGR_NONE:
if (!evsel->snapshot)
perf_evsel__compute_deltas(evsel, cpu, thread, count);
- perf_counts_values__scale(count, stat_config.scale, NULL);
- if (stat_config.aggr_mode == AGGR_NONE)
+ perf_counts_values__scale(count, config->scale, NULL);
+ if (config->aggr_mode == AGGR_NONE)
perf_stat__update_shadow_stats(evsel, count->values, cpu);
break;
case AGGR_GLOBAL:
aggr->val += count->val;
- if (stat_config.scale) {
+ if (config->scale) {
aggr->ena += count->ena;
aggr->run += count->run;
}
@@ -255,7 +256,8 @@ process_counter_values(struct perf_evsel *evsel, int cpu, int thread,
return 0;
}

-static int process_counter_maps(struct perf_evsel *counter)
+static int process_counter_maps(struct perf_stat_config *config,
+ struct perf_evsel *counter)
{
int nthreads = thread_map__nr(counter->threads);
int ncpus = perf_evsel__nr_cpus(counter);
@@ -266,7 +268,7 @@ static int process_counter_maps(struct perf_evsel *counter)

for (thread = 0; thread < nthreads; thread++) {
for (cpu = 0; cpu < ncpus; cpu++) {
- if (process_counter_values(counter, cpu, thread,
+ if (process_counter_values(config, counter, cpu, thread,
perf_counts(counter->counts, cpu, thread)))
return -1;
}
@@ -275,7 +277,8 @@ static int process_counter_maps(struct perf_evsel *counter)
return 0;
}

-static int process_counter(struct perf_evsel *counter)
+static int process_counter(struct perf_stat_config *config,
+ struct perf_evsel *counter)
{
struct perf_counts_values *aggr = &counter->counts->aggr;
struct perf_stat *ps = counter->priv;
@@ -288,22 +291,22 @@ static int process_counter(struct perf_evsel *counter)
if (counter->per_pkg)
zero_per_pkg(counter);

- ret = process_counter_maps(counter);
+ ret = process_counter_maps(&stat_config, counter);
if (ret)
return ret;

- if (stat_config.aggr_mode != AGGR_GLOBAL)
+ if (config->aggr_mode != AGGR_GLOBAL)
return 0;

if (!counter->snapshot)
perf_evsel__compute_deltas(counter, -1, -1, aggr);
- perf_counts_values__scale(aggr, stat_config.scale, &counter->counts->scaled);
+ perf_counts_values__scale(aggr, config->scale, &counter->counts->scaled);

for (i = 0; i < 3; i++)
update_stats(&ps->res_stats[i], count[i]);

if (verbose) {
- fprintf(stat_config.output, "%s: %" PRIu64 " %" PRIu64 " %" PRIu64 "\n",
+ fprintf(config->output, "%s: %" PRIu64 " %" PRIu64 " %" PRIu64 "\n",
perf_evsel__name(counter), count[0], count[1], count[2]);
}

@@ -352,7 +355,7 @@ static void read_counters(bool close_counters)
if (read_counter(counter))
pr_warning("failed to read counter %s\n", counter->name);

- if (process_counter(counter))
+ if (process_counter(&stat_config, counter))
pr_warning("failed to process counter %s\n", counter->name);

if (close_counters) {
--
2.4.3

2015-07-21 12:32:27

by Jiri Olsa

[permalink] [raw]
Subject: [PATCH 07/47] perf stat: Move counter processing code into stat object

Moving counter processing code into stat object
as perf_stat__process_counter.

Link: http://lkml.kernel.org/n/[email protected]
Signed-off-by: Jiri Olsa <[email protected]>
---
tools/perf/builtin-stat.c | 141 +---------------------------------------------
tools/perf/util/stat.c | 139 +++++++++++++++++++++++++++++++++++++++++++++
tools/perf/util/stat.h | 3 +
3 files changed, 143 insertions(+), 140 deletions(-)

diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index 5a781718c09f..a054ddc0b2a0 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -179,145 +179,6 @@ static inline int nsec_counter(struct perf_evsel *evsel)
return 0;
}

-static void zero_per_pkg(struct perf_evsel *counter)
-{
- if (counter->per_pkg_mask)
- memset(counter->per_pkg_mask, 0, MAX_NR_CPUS);
-}
-
-static int check_per_pkg(struct perf_evsel *counter, int cpu, bool *skip)
-{
- unsigned long *mask = counter->per_pkg_mask;
- struct cpu_map *cpus = perf_evsel__cpus(counter);
- int s;
-
- *skip = false;
-
- if (!counter->per_pkg)
- return 0;
-
- if (cpu_map__empty(cpus))
- return 0;
-
- if (!mask) {
- mask = zalloc(MAX_NR_CPUS);
- if (!mask)
- return -ENOMEM;
-
- counter->per_pkg_mask = mask;
- }
-
- s = cpu_map__get_socket(cpus, cpu);
- if (s < 0)
- return -1;
-
- *skip = test_and_set_bit(s, mask) == 1;
- return 0;
-}
-
-static int
-process_counter_values(struct perf_stat_config *config, struct perf_evsel *evsel,
- int cpu, int thread,
- struct perf_counts_values *count)
-{
- struct perf_counts_values *aggr = &evsel->counts->aggr;
- static struct perf_counts_values zero;
- bool skip = false;
-
- if (check_per_pkg(evsel, cpu, &skip)) {
- pr_err("failed to read per-pkg counter\n");
- return -1;
- }
-
- if (skip)
- count = &zero;
-
- switch (config->aggr_mode) {
- case AGGR_THREAD:
- case AGGR_CORE:
- case AGGR_SOCKET:
- case AGGR_NONE:
- if (!evsel->snapshot)
- perf_evsel__compute_deltas(evsel, cpu, thread, count);
- perf_counts_values__scale(count, config->scale, NULL);
- if (config->aggr_mode == AGGR_NONE)
- perf_stat__update_shadow_stats(evsel, count->values, cpu);
- break;
- case AGGR_GLOBAL:
- aggr->val += count->val;
- if (config->scale) {
- aggr->ena += count->ena;
- aggr->run += count->run;
- }
- default:
- break;
- }
-
- return 0;
-}
-
-static int process_counter_maps(struct perf_stat_config *config,
- struct perf_evsel *counter)
-{
- int nthreads = thread_map__nr(counter->threads);
- int ncpus = perf_evsel__nr_cpus(counter);
- int cpu, thread;
-
- if (counter->system_wide)
- nthreads = 1;
-
- for (thread = 0; thread < nthreads; thread++) {
- for (cpu = 0; cpu < ncpus; cpu++) {
- if (process_counter_values(config, counter, cpu, thread,
- perf_counts(counter->counts, cpu, thread)))
- return -1;
- }
- }
-
- return 0;
-}
-
-static int process_counter(struct perf_stat_config *config,
- struct perf_evsel *counter)
-{
- struct perf_counts_values *aggr = &counter->counts->aggr;
- struct perf_stat *ps = counter->priv;
- u64 *count = counter->counts->aggr.values;
- int i, ret;
-
- aggr->val = aggr->ena = aggr->run = 0;
- init_stats(ps->res_stats);
-
- if (counter->per_pkg)
- zero_per_pkg(counter);
-
- ret = process_counter_maps(&stat_config, counter);
- if (ret)
- return ret;
-
- if (config->aggr_mode != AGGR_GLOBAL)
- return 0;
-
- if (!counter->snapshot)
- perf_evsel__compute_deltas(counter, -1, -1, aggr);
- perf_counts_values__scale(aggr, config->scale, &counter->counts->scaled);
-
- for (i = 0; i < 3; i++)
- update_stats(&ps->res_stats[i], count[i]);
-
- if (verbose) {
- fprintf(config->output, "%s: %" PRIu64 " %" PRIu64 " %" PRIu64 "\n",
- perf_evsel__name(counter), count[0], count[1], count[2]);
- }
-
- /*
- * Save the full runtime - to allow normalization during printout:
- */
- perf_stat__update_shadow_stats(counter, count, 0);
-
- return 0;
-}
-
/*
* Read out the results of a single counter:
* do not aggregate counts across CPUs in system-wide mode
@@ -355,7 +216,7 @@ static void read_counters(bool close_counters)
if (read_counter(counter))
pr_warning("failed to read counter %s\n", counter->name);

- if (process_counter(&stat_config, counter))
+ if (perf_stat_process_counter(&stat_config, counter))
pr_warning("failed to process counter %s\n", counter->name);

if (close_counters) {
diff --git a/tools/perf/util/stat.c b/tools/perf/util/stat.c
index f2a0d1521e26..c5c709cdc3ce 100644
--- a/tools/perf/util/stat.c
+++ b/tools/perf/util/stat.c
@@ -238,3 +238,142 @@ void perf_evlist__reset_stats(struct perf_evlist *evlist)
perf_evsel__reset_counts(evsel);
}
}
+
+static void zero_per_pkg(struct perf_evsel *counter)
+{
+ if (counter->per_pkg_mask)
+ memset(counter->per_pkg_mask, 0, MAX_NR_CPUS);
+}
+
+static int check_per_pkg(struct perf_evsel *counter, int cpu, bool *skip)
+{
+ unsigned long *mask = counter->per_pkg_mask;
+ struct cpu_map *cpus = perf_evsel__cpus(counter);
+ int s;
+
+ *skip = false;
+
+ if (!counter->per_pkg)
+ return 0;
+
+ if (cpu_map__empty(cpus))
+ return 0;
+
+ if (!mask) {
+ mask = zalloc(MAX_NR_CPUS);
+ if (!mask)
+ return -ENOMEM;
+
+ counter->per_pkg_mask = mask;
+ }
+
+ s = cpu_map__get_socket(cpus, cpu);
+ if (s < 0)
+ return -1;
+
+ *skip = test_and_set_bit(s, mask) == 1;
+ return 0;
+}
+
+static int
+process_counter_values(struct perf_stat_config *config, struct perf_evsel *evsel,
+ int cpu, int thread,
+ struct perf_counts_values *count)
+{
+ struct perf_counts_values *aggr = &evsel->counts->aggr;
+ static struct perf_counts_values zero;
+ bool skip = false;
+
+ if (check_per_pkg(evsel, cpu, &skip)) {
+ pr_err("failed to read per-pkg counter\n");
+ return -1;
+ }
+
+ if (skip)
+ count = &zero;
+
+ switch (config->aggr_mode) {
+ case AGGR_THREAD:
+ case AGGR_CORE:
+ case AGGR_SOCKET:
+ case AGGR_NONE:
+ if (!evsel->snapshot)
+ perf_evsel__compute_deltas(evsel, cpu, thread, count);
+ perf_counts_values__scale(count, config->scale, NULL);
+ if (config->aggr_mode == AGGR_NONE)
+ perf_stat__update_shadow_stats(evsel, count->values, cpu);
+ break;
+ case AGGR_GLOBAL:
+ aggr->val += count->val;
+ if (config->scale) {
+ aggr->ena += count->ena;
+ aggr->run += count->run;
+ }
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int process_counter_maps(struct perf_stat_config *config,
+ struct perf_evsel *counter)
+{
+ int nthreads = thread_map__nr(counter->threads);
+ int ncpus = perf_evsel__nr_cpus(counter);
+ int cpu, thread;
+
+ if (counter->system_wide)
+ nthreads = 1;
+
+ for (thread = 0; thread < nthreads; thread++) {
+ for (cpu = 0; cpu < ncpus; cpu++) {
+ if (process_counter_values(config, counter, cpu, thread,
+ perf_counts(counter->counts, cpu, thread)))
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+int perf_stat_process_counter(struct perf_stat_config *config,
+ struct perf_evsel *counter)
+{
+ struct perf_counts_values *aggr = &counter->counts->aggr;
+ struct perf_stat *ps = counter->priv;
+ u64 *count = counter->counts->aggr.values;
+ int i, ret;
+
+ aggr->val = aggr->ena = aggr->run = 0;
+ init_stats(ps->res_stats);
+
+ if (counter->per_pkg)
+ zero_per_pkg(counter);
+
+ ret = process_counter_maps(config, counter);
+ if (ret)
+ return ret;
+
+ if (config->aggr_mode != AGGR_GLOBAL)
+ return 0;
+
+ if (!counter->snapshot)
+ perf_evsel__compute_deltas(counter, -1, -1, aggr);
+ perf_counts_values__scale(aggr, config->scale, &counter->counts->scaled);
+
+ for (i = 0; i < 3; i++)
+ update_stats(&ps->res_stats[i], count[i]);
+
+ if (verbose) {
+ fprintf(config->output, "%s: %" PRIu64 " %" PRIu64 " %" PRIu64 "\n",
+ perf_evsel__name(counter), count[0], count[1], count[2]);
+ }
+
+ /*
+ * Save the full runtime - to allow normalization during printout:
+ */
+ perf_stat__update_shadow_stats(counter, count, 0);
+
+ return 0;
+}
diff --git a/tools/perf/util/stat.h b/tools/perf/util/stat.h
index 1da706d848fb..0b897b083682 100644
--- a/tools/perf/util/stat.h
+++ b/tools/perf/util/stat.h
@@ -116,4 +116,7 @@ int perf_evsel__alloc_stats(struct perf_evsel *evsel, bool alloc_raw);
int perf_evlist__alloc_stats(struct perf_evlist *evlist, bool alloc_raw);
void perf_evlist__free_stats(struct perf_evlist *evlist);
void perf_evlist__reset_stats(struct perf_evlist *evlist);
+
+int perf_stat_process_counter(struct perf_stat_config *config,
+ struct perf_evsel *counter);
#endif
--
2.4.3

2015-07-21 12:43:40

by Jiri Olsa

[permalink] [raw]
Subject: [PATCH 08/47] perf tools: Use bool instead of target argument in perf_evlist__propagate_maps

We need only bool info wether user defined her own set of cpus.
Switching target argument to bool so it could be used from
places without target object defined in following patches.

Link: http://lkml.kernel.org/n/[email protected]
Signed-off-by: Jiri Olsa <[email protected]>
---
tools/perf/util/evlist.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index f7d9c77ee31b..63bc24dbf03b 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -1102,7 +1102,7 @@ int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages,
}

static int perf_evlist__propagate_maps(struct perf_evlist *evlist,
- struct target *target)
+ bool has_user_cpus)
{
struct perf_evsel *evsel;

@@ -1111,10 +1111,10 @@ static int perf_evlist__propagate_maps(struct perf_evlist *evlist,
* We already have cpus for evsel (via PMU sysfs) so
* keep it, if there's no target cpu list defined.
*/
- if (evsel->cpus && target->cpu_list)
+ if (evsel->cpus && has_user_cpus)
cpu_map__put(evsel->cpus);

- if (!evsel->cpus || target->cpu_list)
+ if (!evsel->cpus || has_user_cpus)
evsel->cpus = cpu_map__get(evlist->cpus);

evsel->threads = thread_map__get(evlist->threads);
@@ -1142,7 +1142,7 @@ int perf_evlist__create_maps(struct perf_evlist *evlist, struct target *target)
if (evlist->cpus == NULL)
goto out_delete_threads;

- return perf_evlist__propagate_maps(evlist, target);
+ return perf_evlist__propagate_maps(evlist, !!target->cpu_list);

out_delete_threads:
thread_map__put(evlist->threads);
--
2.4.3

2015-07-21 12:32:30

by Jiri Olsa

[permalink] [raw]
Subject: [PATCH 09/47] perf tools: Tolerate NULL maps in perf_evlist__propagate_maps

Tolerating NULL maps in perf_evlist__propagate_maps,
so we dont need to pass evlist with both cpus and threads
maps defined.

Link: http://lkml.kernel.org/n/[email protected]
Signed-off-by: Jiri Olsa <[email protected]>
---
tools/perf/util/evlist.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index 63bc24dbf03b..f1714bedd5de 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -1119,7 +1119,8 @@ static int perf_evlist__propagate_maps(struct perf_evlist *evlist,

evsel->threads = thread_map__get(evlist->threads);

- if (!evsel->cpus || !evsel->threads)
+ if ((evlist->cpus && !evsel->cpus) ||
+ (evlist->threads && !evsel->threads))
return -ENOMEM;
}

--
2.4.3

2015-07-21 12:32:32

by Jiri Olsa

[permalink] [raw]
Subject: [PATCH 10/47] perf tools: Force perf_evlist__set_maps to propagate maps through events

Forcing perf_evlist__set_maps to propagate maps through events,
so cpu/thread maps get set within evlist.

Link: http://lkml.kernel.org/n/[email protected]
Signed-off-by: Jiri Olsa <[email protected]>
---
tools/perf/util/evlist.c | 17 +++++++++++++++++
tools/perf/util/evlist.h | 11 +++--------
2 files changed, 20 insertions(+), 8 deletions(-)

diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index f1714bedd5de..3b9f411a6b46 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -1151,6 +1151,23 @@ out_delete_threads:
return -1;
}

+int perf_evlist__set_maps(struct perf_evlist *evlist,
+ struct cpu_map *cpus,
+ struct thread_map *threads)
+{
+ if (evlist->cpus)
+ cpu_map__put(evlist->cpus);
+
+ evlist->cpus = cpus;
+
+ if (evlist->threads)
+ thread_map__put(evlist->threads);
+
+ evlist->threads = threads;
+
+ return perf_evlist__propagate_maps(evlist, false);
+}
+
int perf_evlist__apply_filters(struct perf_evlist *evlist, struct perf_evsel **err_evsel)
{
struct perf_evsel *evsel;
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h
index 037633c1da9d..406a8216a51e 100644
--- a/tools/perf/util/evlist.h
+++ b/tools/perf/util/evlist.h
@@ -152,14 +152,9 @@ int perf_evlist__enable_event_idx(struct perf_evlist *evlist,
void perf_evlist__set_selected(struct perf_evlist *evlist,
struct perf_evsel *evsel);

-static inline void perf_evlist__set_maps(struct perf_evlist *evlist,
- struct cpu_map *cpus,
- struct thread_map *threads)
-{
- evlist->cpus = cpus;
- evlist->threads = threads;
-}
-
+int perf_evlist__set_maps(struct perf_evlist *evlist,
+ struct cpu_map *cpus,
+ struct thread_map *threads);
int perf_evlist__create_maps(struct perf_evlist *evlist, struct target *target);
int perf_evlist__apply_filters(struct perf_evlist *evlist, struct perf_evsel **err_evsel);

--
2.4.3

2015-07-21 12:43:07

by Jiri Olsa

[permalink] [raw]
Subject: [PATCH 11/47] perf tools: Use argv style storage for cmdline feature data

We will reuse argv style data in following change to display
counters header showing monitored command line.

Link: http://lkml.kernel.org/n/[email protected]
Signed-off-by: Jiri Olsa <[email protected]>
---
tools/perf/util/header.c | 35 ++++++++++++++++++++---------------
tools/perf/util/header.h | 1 +
tools/perf/util/session.c | 1 +
3 files changed, 22 insertions(+), 15 deletions(-)

diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index 03ace57a800c..179b2bdd157d 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -923,17 +923,13 @@ static void print_cmdline(struct perf_header *ph, int fd __maybe_unused,
FILE *fp)
{
int nr, i;
- char *str;

nr = ph->env.nr_cmdline;
- str = ph->env.cmdline;

fprintf(fp, "# cmdline : ");

- for (i = 0; i < nr; i++) {
- fprintf(fp, "%s ", str);
- str += strlen(str) + 1;
- }
+ for (i = 0; i < nr; i++)
+ fprintf(fp, "%s ", ph->env.cmdline_argv[i]);
fputc('\n', fp);
}

@@ -1541,14 +1537,13 @@ process_event_desc(struct perf_file_section *section __maybe_unused,
return 0;
}

-static int process_cmdline(struct perf_file_section *section __maybe_unused,
+static int process_cmdline(struct perf_file_section *section,
struct perf_header *ph, int fd,
void *data __maybe_unused)
{
ssize_t ret;
- char *str;
- u32 nr, i;
- struct strbuf sb;
+ char *str, *cmdline = NULL, **argv = NULL;
+ u32 nr, i, len = 0;

ret = readn(fd, &nr, sizeof(nr));
if (ret != sizeof(nr))
@@ -1558,22 +1553,32 @@ static int process_cmdline(struct perf_file_section *section __maybe_unused,
nr = bswap_32(nr);

ph->env.nr_cmdline = nr;
- strbuf_init(&sb, 128);
+
+ cmdline = zalloc(section->size + nr + 1);
+ if (!cmdline)
+ return -1;
+
+ argv = zalloc(sizeof(char *) * (nr + 1));
+ if (!argv)
+ goto error;

for (i = 0; i < nr; i++) {
str = do_read_string(fd, ph);
if (!str)
goto error;

- /* include a NULL character at the end */
- strbuf_add(&sb, str, strlen(str) + 1);
+ argv[i] = cmdline + len;
+ memcpy(argv[i], str, strlen(str) + 1);
+ len += strlen(str) + 1;
free(str);
}
- ph->env.cmdline = strbuf_detach(&sb, NULL);
+ ph->env.cmdline = cmdline;
+ ph->env.cmdline_argv = (const char **) argv;
return 0;

error:
- strbuf_release(&sb);
+ free(argv);
+ free(cmdline);
return -1;
}

diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
index d4d57962c591..9b53b6525ce8 100644
--- a/tools/perf/util/header.h
+++ b/tools/perf/util/header.h
@@ -84,6 +84,7 @@ struct perf_session_env {
int nr_pmu_mappings;
int nr_groups;
char *cmdline;
+ const char **cmdline_argv;
char *sibling_cores;
char *sibling_threads;
char *numa_nodes;
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index ed9dc2555ec7..fb1d525ca3d0 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -180,6 +180,7 @@ static void perf_session_env__delete(struct perf_session_env *env)
zfree(&env->cpuid);

zfree(&env->cmdline);
+ zfree(&env->cmdline_argv);
zfree(&env->sibling_cores);
zfree(&env->sibling_threads);
zfree(&env->numa_nodes);
--
2.4.3

2015-07-21 12:32:36

by Jiri Olsa

[permalink] [raw]
Subject: [PATCH 12/47] perf tools: Add thread_map event

Adding thread_map event to pass/store thread maps.

Link: http://lkml.kernel.org/n/[email protected]
Signed-off-by: Jiri Olsa <[email protected]>
---
tools/perf/util/event.c | 1 +
tools/perf/util/event.h | 13 +++++++++++++
tools/perf/util/session.c | 26 ++++++++++++++++++++++++++
tools/perf/util/tool.h | 3 ++-
4 files changed, 42 insertions(+), 1 deletion(-)

diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index 67a977e5d0ab..1ff4a0bb0feb 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -35,6 +35,7 @@ static const char *perf_event__names[] = {
[PERF_RECORD_AUXTRACE_INFO] = "AUXTRACE_INFO",
[PERF_RECORD_AUXTRACE] = "AUXTRACE",
[PERF_RECORD_AUXTRACE_ERROR] = "AUXTRACE_ERROR",
+ [PERF_RECORD_THREAD_MAP] = "THREAD_MAP",
};

const char *perf_event__name(unsigned int id)
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index c53f36384b64..64dc752f3589 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -225,6 +225,7 @@ enum perf_user_event_type { /* above any possible kernel type */
PERF_RECORD_AUXTRACE_INFO = 70,
PERF_RECORD_AUXTRACE = 71,
PERF_RECORD_AUXTRACE_ERROR = 72,
+ PERF_RECORD_THREAD_MAP = 73,
PERF_RECORD_HEADER_MAX
};

@@ -348,6 +349,17 @@ struct itrace_start_event {
u32 pid, tid;
};

+struct thread_map_data_event {
+ u64 pid;
+ char comm[16];
+};
+
+struct thread_map_event {
+ struct perf_event_header header;
+ u64 nr;
+ struct thread_map_data_event data[];
+};
+
union perf_event {
struct perf_event_header header;
struct mmap_event mmap;
@@ -369,6 +381,7 @@ union perf_event {
struct auxtrace_error_event auxtrace_error;
struct aux_event aux;
struct itrace_start_event itrace_start;
+ struct thread_map_event thread_map;
};

void perf_event__print_totals(void);
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index fb1d525ca3d0..e20cd50a9a8f 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -311,6 +311,16 @@ int process_event_auxtrace_error_stub(struct perf_tool *tool __maybe_unused,
return 0;
}

+
+static
+int process_event_thread_map_stub(struct perf_tool *tool __maybe_unused,
+ union perf_event *event __maybe_unused,
+ struct perf_session *session __maybe_unused)
+{
+ dump_printf(": unhandled!\n");
+ return 0;
+}
+
void perf_tool__fill_defaults(struct perf_tool *tool)
{
if (tool->sample == NULL)
@@ -359,6 +369,8 @@ void perf_tool__fill_defaults(struct perf_tool *tool)
tool->auxtrace = process_event_auxtrace_stub;
if (tool->auxtrace_error == NULL)
tool->auxtrace_error = process_event_auxtrace_error_stub;
+ if (tool->thread_map == NULL)
+ tool->thread_map = process_event_thread_map_stub;
}

static void swap_sample_id_all(union perf_event *event, void *data)
@@ -616,6 +628,17 @@ static void perf_event__auxtrace_error_swap(union perf_event *event,
event->auxtrace_error.ip = bswap_64(event->auxtrace_error.ip);
}

+static void perf_event__thread_map_swap(union perf_event *event,
+ bool sample_id_all __maybe_unused)
+{
+ unsigned i;
+
+ event->thread_map.nr = bswap_64(event->thread_map.nr);
+
+ for (i = 0; i < event->thread_map.nr; i++)
+ event->thread_map.data[i].pid = bswap_64(event->thread_map.data[i].pid);
+}
+
typedef void (*perf_event__swap_op)(union perf_event *event,
bool sample_id_all);

@@ -641,6 +664,7 @@ static perf_event__swap_op perf_event__swap_ops[] = {
[PERF_RECORD_AUXTRACE_INFO] = perf_event__auxtrace_info_swap,
[PERF_RECORD_AUXTRACE] = perf_event__auxtrace_swap,
[PERF_RECORD_AUXTRACE_ERROR] = perf_event__auxtrace_error_swap,
+ [PERF_RECORD_THREAD_MAP] = perf_event__thread_map_swap,
[PERF_RECORD_HEADER_MAX] = NULL,
};

@@ -1163,6 +1187,8 @@ static s64 perf_session__process_user_event(struct perf_session *session,
case PERF_RECORD_AUXTRACE_ERROR:
perf_session__auxtrace_error_inc(session, event);
return tool->auxtrace_error(tool, event, session);
+ case PERF_RECORD_THREAD_MAP:
+ return tool->thread_map(tool, event, session);
default:
return -EINVAL;
}
diff --git a/tools/perf/util/tool.h b/tools/perf/util/tool.h
index c307dd438286..cbaffbeb5b18 100644
--- a/tools/perf/util/tool.h
+++ b/tools/perf/util/tool.h
@@ -54,7 +54,8 @@ struct perf_tool {
event_op2 build_id,
id_index,
auxtrace_info,
- auxtrace_error;
+ auxtrace_error,
+ thread_map;
event_op3 auxtrace;
bool ordered_events;
bool ordering_requires_timestamps;
--
2.4.3

2015-07-21 12:42:42

by Jiri Olsa

[permalink] [raw]
Subject: [PATCH 13/47] perf tools: Add thread_map event sythesize function

Introduce perf_event__synthesize_thread_map2 function to
sythesize struct thread_map.

Link: http://lkml.kernel.org/n/[email protected]
Signed-off-by: Jiri Olsa <[email protected]>
---
tools/perf/tests/builtin-test.c | 4 ++++
tools/perf/tests/tests.h | 1 +
tools/perf/tests/thread-map.c | 29 +++++++++++++++++++++++++++++
tools/perf/util/event.c | 36 ++++++++++++++++++++++++++++++++++++
tools/perf/util/event.h | 4 ++++
5 files changed, 74 insertions(+)

diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c
index c1dde733c3a6..7b289d20bd8b 100644
--- a/tools/perf/tests/builtin-test.c
+++ b/tools/perf/tests/builtin-test.c
@@ -175,6 +175,10 @@ static struct test {
.func = test__thread_map,
},
{
+ .desc = "Test thread map synthesize",
+ .func = test__thread_map_synthesize,
+ },
+ {
.func = NULL,
},
};
diff --git a/tools/perf/tests/tests.h b/tools/perf/tests/tests.h
index ebb47d96bc0b..14e2d821d0fd 100644
--- a/tools/perf/tests/tests.h
+++ b/tools/perf/tests/tests.h
@@ -62,6 +62,7 @@ int test__fdarray__filter(void);
int test__fdarray__add(void);
int test__kmod_path__parse(void);
int test__thread_map(void);
+int test__thread_map_synthesize(void);

#if defined(__x86_64__) || defined(__i386__) || defined(__arm__) || defined(__aarch64__)
#ifdef HAVE_DWARF_UNWIND_SUPPORT
diff --git a/tools/perf/tests/thread-map.c b/tools/perf/tests/thread-map.c
index 138a0e3431fa..0facd9fa3458 100644
--- a/tools/perf/tests/thread-map.c
+++ b/tools/perf/tests/thread-map.c
@@ -40,3 +40,32 @@ int test__thread_map(void)
thread_map__put(map);
return 0;
}
+
+static int process_event(struct perf_tool *tool __maybe_unused,
+ union perf_event *event,
+ struct perf_sample *sample __maybe_unused,
+ struct machine *machine __maybe_unused)
+{
+ struct thread_map_event *map = &event->thread_map;
+
+ TEST_ASSERT_VAL("wrong nr", map->nr == 1);
+ TEST_ASSERT_VAL("wrong pid", map->data[0].pid == (u64) getpid());
+ TEST_ASSERT_VAL("wrong comm", !strcmp(map->data[0].comm, "perf"));
+ return 0;
+}
+
+int test__thread_map_synthesize(void)
+{
+ struct thread_map *threads;
+
+ /* test map on current pid */
+ threads = thread_map__new_by_pid(getpid());
+ TEST_ASSERT_VAL("failed to alloc map", threads);
+
+ thread_map__read_comms(threads);
+
+ TEST_ASSERT_VAL("failed to synthesize map",
+ !perf_event__synthesize_thread_map2(NULL, threads, process_event, NULL));
+
+ return 0;
+}
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index 1ff4a0bb0feb..15fb35c6baed 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -698,6 +698,42 @@ int perf_event__synthesize_kernel_mmap(struct perf_tool *tool,
return err;
}

+int perf_event__synthesize_thread_map2(struct perf_tool *tool,
+ struct thread_map *threads,
+ perf_event__handler_t process,
+ struct machine *machine)
+{
+ union perf_event *event;
+ int i, err, size;
+
+ size = sizeof(event->thread_map);
+ size += threads->nr * sizeof(event->thread_map.data[0]);
+
+ event = zalloc(size);
+ if (!event)
+ return -ENOMEM;
+
+ event->header.type = PERF_RECORD_THREAD_MAP;
+ event->header.size = size;
+ event->thread_map.nr = threads->nr;
+
+ for (i = 0; i < threads->nr; i++) {
+ struct thread_map_data_event *data = &event->thread_map.data[i];
+ char *comm = thread_map__comm(threads, i);
+
+ if (!comm)
+ comm = (char *) "";
+
+ data->pid = thread_map__pid(threads, i);
+ strncpy((char *) &data->comm, comm, sizeof(data->comm));
+ }
+
+ err = process(tool, event, NULL, machine);
+
+ free(event);
+ return err;
+}
+
size_t perf_event__fprintf_comm(union perf_event *event, FILE *fp)
{
const char *s;
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index 64dc752f3589..c204dbf7e386 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -399,6 +399,10 @@ int perf_event__synthesize_thread_map(struct perf_tool *tool,
perf_event__handler_t process,
struct machine *machine, bool mmap_data,
unsigned int proc_map_timeout);
+int perf_event__synthesize_thread_map2(struct perf_tool *tool,
+ struct thread_map *threads,
+ perf_event__handler_t process,
+ struct machine *machine);
int perf_event__synthesize_threads(struct perf_tool *tool,
perf_event__handler_t process,
struct machine *machine, bool mmap_data,
--
2.4.3

2015-07-21 12:32:39

by Jiri Olsa

[permalink] [raw]
Subject: [PATCH 14/47] perf tools: Add thread_map__new_event function

Introducing thread_map__new_event function to create
struct thread_map object from thread_map event.

Link: http://lkml.kernel.org/n/[email protected]
Signed-off-by: Jiri Olsa <[email protected]>
---
tools/perf/tests/thread-map.c | 14 ++++++++++++++
tools/perf/util/thread_map.c | 27 +++++++++++++++++++++++++++
tools/perf/util/thread_map.h | 3 +++
3 files changed, 44 insertions(+)

diff --git a/tools/perf/tests/thread-map.c b/tools/perf/tests/thread-map.c
index 0facd9fa3458..da7b047d3ada 100644
--- a/tools/perf/tests/thread-map.c
+++ b/tools/perf/tests/thread-map.c
@@ -47,10 +47,24 @@ static int process_event(struct perf_tool *tool __maybe_unused,
struct machine *machine __maybe_unused)
{
struct thread_map_event *map = &event->thread_map;
+ struct thread_map *threads;

TEST_ASSERT_VAL("wrong nr", map->nr == 1);
TEST_ASSERT_VAL("wrong pid", map->data[0].pid == (u64) getpid());
TEST_ASSERT_VAL("wrong comm", !strcmp(map->data[0].comm, "perf"));
+
+ threads = thread_map__new_event(&event->thread_map);
+ TEST_ASSERT_VAL("failed to alloc map", threads);
+
+ TEST_ASSERT_VAL("wrong nr", threads->nr == 1);
+ TEST_ASSERT_VAL("wrong pid",
+ thread_map__pid(threads, 0) == getpid());
+ TEST_ASSERT_VAL("wrong comm",
+ thread_map__comm(threads, 0) &&
+ !strcmp(thread_map__comm(threads, 0), "perf"));
+ TEST_ASSERT_VAL("wrong refcnt",
+ atomic_read(&threads->refcnt) == 1);
+ thread_map__put(threads);
return 0;
}

diff --git a/tools/perf/util/thread_map.c b/tools/perf/util/thread_map.c
index da7646d767fe..34d44df2fb1e 100644
--- a/tools/perf/util/thread_map.c
+++ b/tools/perf/util/thread_map.c
@@ -13,6 +13,7 @@
#include "thread_map.h"
#include "util.h"
#include "debug.h"
+#include "event.h"

/* Skip "." and ".." directories */
static int filter(const struct dirent *dir)
@@ -407,3 +408,29 @@ void thread_map__read_comms(struct thread_map *threads)
for (i = 0; i < threads->nr; ++i)
comm_init(threads, i);
}
+
+static void thread_map__copy_event(struct thread_map *threads,
+ struct thread_map_event *event)
+{
+ unsigned i;
+
+ threads->nr = (int) event->nr;
+
+ for (i = 0; i < event->nr; i++) {
+ thread_map__set_pid(threads, i, (pid_t) event->data[i].pid);
+ threads->map[i].comm = strndup(event->data[i].comm, 16);
+ }
+
+ atomic_set(&threads->refcnt, 1);
+}
+
+struct thread_map *thread_map__new_event(struct thread_map_event *event)
+{
+ struct thread_map *threads;
+
+ threads = thread_map__alloc(event->nr);
+ if (threads)
+ thread_map__copy_event(threads, event);
+
+ return threads;
+}
diff --git a/tools/perf/util/thread_map.h b/tools/perf/util/thread_map.h
index af679d8a50f8..85e4c7c4fbde 100644
--- a/tools/perf/util/thread_map.h
+++ b/tools/perf/util/thread_map.h
@@ -16,11 +16,14 @@ struct thread_map {
struct thread_map_data map[];
};

+struct thread_map_event;
+
struct thread_map *thread_map__new_dummy(void);
struct thread_map *thread_map__new_by_pid(pid_t pid);
struct thread_map *thread_map__new_by_tid(pid_t tid);
struct thread_map *thread_map__new_by_uid(uid_t uid);
struct thread_map *thread_map__new(pid_t pid, pid_t tid, uid_t uid);
+struct thread_map *thread_map__new_event(struct thread_map_event *event);

struct thread_map *thread_map__get(struct thread_map *map);
void thread_map__put(struct thread_map *map);
--
2.4.3

2015-07-21 12:32:49

by Jiri Olsa

[permalink] [raw]
Subject: [PATCH 15/47] perf tools: Add cpu_map event

Adding cpu_map event to pass/store cpu maps.

Link: http://lkml.kernel.org/n/[email protected]
Signed-off-by: Jiri Olsa <[email protected]>
---
tools/perf/util/event.c | 1 +
tools/perf/util/event.h | 8 ++++++++
tools/perf/util/session.c | 25 +++++++++++++++++++++++++
tools/perf/util/tool.h | 3 ++-
4 files changed, 36 insertions(+), 1 deletion(-)

diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index 15fb35c6baed..9f8ffbfc5cd4 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -36,6 +36,7 @@ static const char *perf_event__names[] = {
[PERF_RECORD_AUXTRACE] = "AUXTRACE",
[PERF_RECORD_AUXTRACE_ERROR] = "AUXTRACE_ERROR",
[PERF_RECORD_THREAD_MAP] = "THREAD_MAP",
+ [PERF_RECORD_CPU_MAP] = "CPU_MAP",
};

const char *perf_event__name(unsigned int id)
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index c204dbf7e386..f05c4d868162 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -226,6 +226,7 @@ enum perf_user_event_type { /* above any possible kernel type */
PERF_RECORD_AUXTRACE = 71,
PERF_RECORD_AUXTRACE_ERROR = 72,
PERF_RECORD_THREAD_MAP = 73,
+ PERF_RECORD_CPU_MAP = 74,
PERF_RECORD_HEADER_MAX
};

@@ -360,6 +361,12 @@ struct thread_map_event {
struct thread_map_data_event data[];
};

+struct cpu_map_event {
+ struct perf_event_header header;
+ u64 nr;
+ u64 cpu[];
+};
+
union perf_event {
struct perf_event_header header;
struct mmap_event mmap;
@@ -382,6 +389,7 @@ union perf_event {
struct aux_event aux;
struct itrace_start_event itrace_start;
struct thread_map_event thread_map;
+ struct cpu_map_event cpu_map;
};

void perf_event__print_totals(void);
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index e20cd50a9a8f..9db7cb19e4b4 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -321,6 +321,15 @@ int process_event_thread_map_stub(struct perf_tool *tool __maybe_unused,
return 0;
}

+static
+int process_event_cpu_map_stub(struct perf_tool *tool __maybe_unused,
+ union perf_event *event __maybe_unused,
+ struct perf_session *session __maybe_unused)
+{
+ dump_printf(": unhandled!\n");
+ return 0;
+}
+
void perf_tool__fill_defaults(struct perf_tool *tool)
{
if (tool->sample == NULL)
@@ -371,6 +380,8 @@ void perf_tool__fill_defaults(struct perf_tool *tool)
tool->auxtrace_error = process_event_auxtrace_error_stub;
if (tool->thread_map == NULL)
tool->thread_map = process_event_thread_map_stub;
+ if (tool->cpu_map == NULL)
+ tool->cpu_map = process_event_cpu_map_stub;
}

static void swap_sample_id_all(union perf_event *event, void *data)
@@ -639,6 +650,17 @@ static void perf_event__thread_map_swap(union perf_event *event,
event->thread_map.data[i].pid = bswap_64(event->thread_map.data[i].pid);
}

+static void perf_event__cpu_map_swap(union perf_event *event,
+ bool sample_id_all __maybe_unused)
+{
+ unsigned i;
+
+ event->cpu_map.nr = bswap_64(event->cpu_map.nr);
+
+ for (i = 0; i < event->cpu_map.nr; i++)
+ event->cpu_map.cpu[i] = bswap_64(event->cpu_map.cpu[i]);
+}
+
typedef void (*perf_event__swap_op)(union perf_event *event,
bool sample_id_all);

@@ -665,6 +687,7 @@ static perf_event__swap_op perf_event__swap_ops[] = {
[PERF_RECORD_AUXTRACE] = perf_event__auxtrace_swap,
[PERF_RECORD_AUXTRACE_ERROR] = perf_event__auxtrace_error_swap,
[PERF_RECORD_THREAD_MAP] = perf_event__thread_map_swap,
+ [PERF_RECORD_CPU_MAP] = perf_event__cpu_map_swap,
[PERF_RECORD_HEADER_MAX] = NULL,
};

@@ -1189,6 +1212,8 @@ static s64 perf_session__process_user_event(struct perf_session *session,
return tool->auxtrace_error(tool, event, session);
case PERF_RECORD_THREAD_MAP:
return tool->thread_map(tool, event, session);
+ case PERF_RECORD_CPU_MAP:
+ return tool->cpu_map(tool, event, session);
default:
return -EINVAL;
}
diff --git a/tools/perf/util/tool.h b/tools/perf/util/tool.h
index cbaffbeb5b18..ddb88a6e18ee 100644
--- a/tools/perf/util/tool.h
+++ b/tools/perf/util/tool.h
@@ -55,7 +55,8 @@ struct perf_tool {
id_index,
auxtrace_info,
auxtrace_error,
- thread_map;
+ thread_map,
+ cpu_map;
event_op3 auxtrace;
bool ordered_events;
bool ordering_requires_timestamps;
--
2.4.3

2015-07-21 12:32:47

by Jiri Olsa

[permalink] [raw]
Subject: [PATCH 16/47] perf tools: Add cpu_map event synthesize function

Introduce perf_event__synthesize_cpu_map function to
sythesize struct cpu_map.

Link: http://lkml.kernel.org/n/[email protected]
Signed-off-by: Jiri Olsa <[email protected]>
---
tools/perf/tests/Build | 1 +
tools/perf/tests/builtin-test.c | 4 ++++
tools/perf/tests/cpumap.c | 29 +++++++++++++++++++++++++++++
tools/perf/tests/tests.h | 1 +
tools/perf/util/event.c | 28 ++++++++++++++++++++++++++++
tools/perf/util/event.h | 5 +++++
6 files changed, 68 insertions(+)
create mode 100644 tools/perf/tests/cpumap.c

diff --git a/tools/perf/tests/Build b/tools/perf/tests/Build
index d20d6e6ab65b..05faf02ed1ee 100644
--- a/tools/perf/tests/Build
+++ b/tools/perf/tests/Build
@@ -32,6 +32,7 @@ perf-y += sample-parsing.o
perf-y += parse-no-sample-id-all.o
perf-y += kmod-path.o
perf-y += thread-map.o
+perf-y += cpumap.o

perf-$(CONFIG_X86) += perf-time-to-tsc.o

diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c
index 7b289d20bd8b..d4cfc0592f6b 100644
--- a/tools/perf/tests/builtin-test.c
+++ b/tools/perf/tests/builtin-test.c
@@ -179,6 +179,10 @@ static struct test {
.func = test__thread_map_synthesize,
},
{
+ .desc = "Test cpu map synthesize",
+ .func = test__cpu_map_synthesize,
+ },
+ {
.func = NULL,
},
};
diff --git a/tools/perf/tests/cpumap.c b/tools/perf/tests/cpumap.c
new file mode 100644
index 000000000000..475c040f8a8d
--- /dev/null
+++ b/tools/perf/tests/cpumap.c
@@ -0,0 +1,29 @@
+#include "tests.h"
+#include "cpumap.h"
+
+static int process_event(struct perf_tool *tool __maybe_unused,
+ union perf_event *event,
+ struct perf_sample *sample __maybe_unused,
+ struct machine *machine __maybe_unused)
+{
+ struct cpu_map_event *map = &event->cpu_map;
+
+ TEST_ASSERT_VAL("wrong nr", map->nr == 3);
+ TEST_ASSERT_VAL("wrong cpu", map->cpu[0] == 1);
+ TEST_ASSERT_VAL("wrong cpu", map->cpu[1] == 2);
+ TEST_ASSERT_VAL("wrong cpu", map->cpu[2] == 4);
+ return 0;
+}
+
+int test__cpu_map_synthesize(void)
+{
+ struct cpu_map *cpus;
+
+ cpus = cpu_map__new("1,2,4");
+
+
+ TEST_ASSERT_VAL("failed to synthesize map",
+ !perf_event__synthesize_cpu_map(NULL, cpus, process_event, NULL));
+
+ return 0;
+}
diff --git a/tools/perf/tests/tests.h b/tools/perf/tests/tests.h
index 14e2d821d0fd..c251d5a21e0c 100644
--- a/tools/perf/tests/tests.h
+++ b/tools/perf/tests/tests.h
@@ -63,6 +63,7 @@ int test__fdarray__add(void);
int test__kmod_path__parse(void);
int test__thread_map(void);
int test__thread_map_synthesize(void);
+int test__cpu_map_synthesize(void);

#if defined(__x86_64__) || defined(__i386__) || defined(__arm__) || defined(__aarch64__)
#ifdef HAVE_DWARF_UNWIND_SUPPORT
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index 9f8ffbfc5cd4..7bbe64c51d85 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -735,6 +735,34 @@ int perf_event__synthesize_thread_map2(struct perf_tool *tool,
return err;
}

+int perf_event__synthesize_cpu_map(struct perf_tool *tool,
+ struct cpu_map *cpus,
+ perf_event__handler_t process,
+ struct machine *machine)
+{
+ union perf_event *event;
+ int i, err, size;
+
+ size = sizeof(event->cpu_map);
+ size += cpus->nr * sizeof(event->cpu_map.cpu[0]);
+
+ event = zalloc(size);
+ if (!event)
+ return -ENOMEM;
+
+ event->header.type = PERF_RECORD_CPU_MAP;
+ event->header.size = size;
+ event->cpu_map.nr = cpus->nr;
+
+ for (i = 0; i < cpus->nr; i++)
+ event->cpu_map.cpu[i] = cpus->map[i];
+
+ err = process(tool, event, NULL, machine);
+
+ free(event);
+ return err;
+}
+
size_t perf_event__fprintf_comm(union perf_event *event, FILE *fp)
{
const char *s;
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index f05c4d868162..6600da608782 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -396,6 +396,7 @@ void perf_event__print_totals(void);

struct perf_tool;
struct thread_map;
+struct cpu_map;

typedef int (*perf_event__handler_t)(struct perf_tool *tool,
union perf_event *event,
@@ -411,6 +412,10 @@ int perf_event__synthesize_thread_map2(struct perf_tool *tool,
struct thread_map *threads,
perf_event__handler_t process,
struct machine *machine);
+int perf_event__synthesize_cpu_map(struct perf_tool *tool,
+ struct cpu_map *cpus,
+ perf_event__handler_t process,
+ struct machine *machine);
int perf_event__synthesize_threads(struct perf_tool *tool,
perf_event__handler_t process,
struct machine *machine, bool mmap_data,
--
2.4.3

2015-07-21 12:32:45

by Jiri Olsa

[permalink] [raw]
Subject: [PATCH 17/47] perf tools: Add cpu_map__new_event function

Introducing cpu_map__new_event function to create
struct cpu_map object from cpu_map event.

Link: http://lkml.kernel.org/n/[email protected]
Signed-off-by: Jiri Olsa <[email protected]>
---
tools/perf/tests/cpumap.c | 10 ++++++++++
tools/perf/util/cpumap.c | 27 +++++++++++++++++++++++++++
tools/perf/util/cpumap.h | 3 +++
3 files changed, 40 insertions(+)

diff --git a/tools/perf/tests/cpumap.c b/tools/perf/tests/cpumap.c
index 475c040f8a8d..af8a3f520a2a 100644
--- a/tools/perf/tests/cpumap.c
+++ b/tools/perf/tests/cpumap.c
@@ -7,11 +7,21 @@ static int process_event(struct perf_tool *tool __maybe_unused,
struct machine *machine __maybe_unused)
{
struct cpu_map_event *map = &event->cpu_map;
+ struct cpu_map *cpus;

TEST_ASSERT_VAL("wrong nr", map->nr == 3);
TEST_ASSERT_VAL("wrong cpu", map->cpu[0] == 1);
TEST_ASSERT_VAL("wrong cpu", map->cpu[1] == 2);
TEST_ASSERT_VAL("wrong cpu", map->cpu[2] == 4);
+
+ cpus = cpu_map__new_event(&event->cpu_map);
+ TEST_ASSERT_VAL("wrong nr", cpus->nr == 3);
+ TEST_ASSERT_VAL("wrong cpu", cpus->map[0] == 1);
+ TEST_ASSERT_VAL("wrong cpu", cpus->map[1] == 2);
+ TEST_ASSERT_VAL("wrong cpu", cpus->map[2] == 4);
+ TEST_ASSERT_VAL("wrong refcnt",
+ atomic_read(&cpus->refcnt) == 1);
+ cpu_map__put(cpus);
return 0;
}

diff --git a/tools/perf/util/cpumap.c b/tools/perf/util/cpumap.c
index 3667e2123e5b..81e82cadda50 100644
--- a/tools/perf/util/cpumap.c
+++ b/tools/perf/util/cpumap.c
@@ -179,6 +179,33 @@ out:
return cpus;
}

+static void cpu_map__copy_event(struct cpu_map *cpus,
+ struct cpu_map_event *event)
+{
+ unsigned i;
+
+ cpus->nr = event->nr;
+
+ for (i = 0; i < event->nr; i++)
+ cpus->map[i] = (int) event->cpu[i];
+
+ atomic_set(&cpus->refcnt, 1);
+}
+
+struct cpu_map *cpu_map__new_event(struct cpu_map_event *event)
+{
+ struct cpu_map *cpus;
+ int size;
+
+ size = sizeof(cpus) + (event->nr * sizeof(cpus->map[0]));
+
+ cpus = zalloc(size);
+ if (cpus)
+ cpu_map__copy_event(cpus, event);
+
+ return cpus;
+}
+
size_t cpu_map__fprintf(struct cpu_map *map, FILE *fp)
{
int i;
diff --git a/tools/perf/util/cpumap.h b/tools/perf/util/cpumap.h
index 0af9cecb4c51..44a68b63bf48 100644
--- a/tools/perf/util/cpumap.h
+++ b/tools/perf/util/cpumap.h
@@ -14,8 +14,11 @@ struct cpu_map {
int map[];
};

+struct cpu_map_event;
+
struct cpu_map *cpu_map__new(const char *cpu_list);
struct cpu_map *cpu_map__dummy_new(void);
+struct cpu_map *cpu_map__new_event(struct cpu_map_event *event);
struct cpu_map *cpu_map__read(FILE *file);
size_t cpu_map__fprintf(struct cpu_map *map, FILE *fp);
int cpu_map__get_socket(struct cpu_map *map, int idx);
--
2.4.3

2015-07-21 12:42:08

by Jiri Olsa

[permalink] [raw]
Subject: [PATCH 18/47] perf tools: Add stat config event

Adding stat config event to pass/store stat config data,
so report tools (report/script) know how to interpret
stat data.

Link: http://lkml.kernel.org/n/[email protected]
Signed-off-by: Jiri Olsa <[email protected]>
---
tools/perf/util/event.c | 1 +
tools/perf/util/event.h | 20 ++++++++++++++++++++
tools/perf/util/session.c | 24 ++++++++++++++++++++++++
tools/perf/util/tool.h | 3 ++-
4 files changed, 47 insertions(+), 1 deletion(-)

diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index 7bbe64c51d85..e2c6c2df57fb 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -37,6 +37,7 @@ static const char *perf_event__names[] = {
[PERF_RECORD_AUXTRACE_ERROR] = "AUXTRACE_ERROR",
[PERF_RECORD_THREAD_MAP] = "THREAD_MAP",
[PERF_RECORD_CPU_MAP] = "CPU_MAP",
+ [PERF_RECORD_STAT_CONFIG] = "STAT_CONFIG",
};

const char *perf_event__name(unsigned int id)
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index 6600da608782..a67f4e8e0633 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -227,6 +227,7 @@ enum perf_user_event_type { /* above any possible kernel type */
PERF_RECORD_AUXTRACE_ERROR = 72,
PERF_RECORD_THREAD_MAP = 73,
PERF_RECORD_CPU_MAP = 74,
+ PERF_RECORD_STAT_CONFIG = 75,
PERF_RECORD_HEADER_MAX
};

@@ -367,6 +368,24 @@ struct cpu_map_event {
u64 cpu[];
};

+enum {
+ PERF_STAT_CONFIG_TERM__AGGR_MODE = 0,
+ PERF_STAT_CONFIG_TERM__INTERVAL = 1,
+ PERF_STAT_CONFIG_TERM__SCALE = 2,
+ PERF_STAT_CONFIG_TERM__MAX = 3,
+};
+
+struct stat_config_term_event {
+ u64 tag;
+ u64 val;
+};
+
+struct stat_config_event {
+ struct perf_event_header header;
+ u64 nr;
+ struct stat_config_term_event data[];
+};
+
union perf_event {
struct perf_event_header header;
struct mmap_event mmap;
@@ -390,6 +409,7 @@ union perf_event {
struct itrace_start_event itrace_start;
struct thread_map_event thread_map;
struct cpu_map_event cpu_map;
+ struct stat_config_event stat_config;
};

void perf_event__print_totals(void);
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index 9db7cb19e4b4..d9027593e4a2 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -330,6 +330,15 @@ int process_event_cpu_map_stub(struct perf_tool *tool __maybe_unused,
return 0;
}

+static
+int process_event_stat_config_stub(struct perf_tool *tool __maybe_unused,
+ union perf_event *event __maybe_unused,
+ struct perf_session *session __maybe_unused)
+{
+ dump_printf(": unhandled!\n");
+ return 0;
+}
+
void perf_tool__fill_defaults(struct perf_tool *tool)
{
if (tool->sample == NULL)
@@ -382,6 +391,8 @@ void perf_tool__fill_defaults(struct perf_tool *tool)
tool->thread_map = process_event_thread_map_stub;
if (tool->cpu_map == NULL)
tool->cpu_map = process_event_cpu_map_stub;
+ if (tool->stat_config == NULL)
+ tool->stat_config = process_event_stat_config_stub;
}

static void swap_sample_id_all(union perf_event *event, void *data)
@@ -661,6 +672,16 @@ static void perf_event__cpu_map_swap(union perf_event *event,
event->cpu_map.cpu[i] = bswap_64(event->cpu_map.cpu[i]);
}

+static void perf_event__stat_config_swap(union perf_event *event,
+ bool sample_id_all __maybe_unused)
+{
+ u64 size;
+
+ size = event->stat_config.nr * sizeof(event->stat_config.data[0]);
+ size += 1; /* nr item itself */
+ mem_bswap_64(&event->stat_config.nr, size);
+}
+
typedef void (*perf_event__swap_op)(union perf_event *event,
bool sample_id_all);

@@ -688,6 +709,7 @@ static perf_event__swap_op perf_event__swap_ops[] = {
[PERF_RECORD_AUXTRACE_ERROR] = perf_event__auxtrace_error_swap,
[PERF_RECORD_THREAD_MAP] = perf_event__thread_map_swap,
[PERF_RECORD_CPU_MAP] = perf_event__cpu_map_swap,
+ [PERF_RECORD_STAT_CONFIG] = perf_event__stat_config_swap,
[PERF_RECORD_HEADER_MAX] = NULL,
};

@@ -1214,6 +1236,8 @@ static s64 perf_session__process_user_event(struct perf_session *session,
return tool->thread_map(tool, event, session);
case PERF_RECORD_CPU_MAP:
return tool->cpu_map(tool, event, session);
+ case PERF_RECORD_STAT_CONFIG:
+ return tool->stat_config(tool, event, session);
default:
return -EINVAL;
}
diff --git a/tools/perf/util/tool.h b/tools/perf/util/tool.h
index ddb88a6e18ee..5c209743ad97 100644
--- a/tools/perf/util/tool.h
+++ b/tools/perf/util/tool.h
@@ -56,7 +56,8 @@ struct perf_tool {
auxtrace_info,
auxtrace_error,
thread_map,
- cpu_map;
+ cpu_map,
+ stat_config;
event_op3 auxtrace;
bool ordered_events;
bool ordering_requires_timestamps;
--
2.4.3

2015-07-21 12:41:46

by Jiri Olsa

[permalink] [raw]
Subject: [PATCH 19/47] perf tools: Add stat config event synthesize function

Introduce perf_event__synthesize_stat_config function to
sythesize 'struct perf_stat_config'.

Storing stat config in form of tag-value pairs in a believe
it'll sort out future version issues.

Link: http://lkml.kernel.org/n/[email protected]
Signed-off-by: Jiri Olsa <[email protected]>
---
tools/perf/tests/Build | 1 +
tools/perf/tests/builtin-test.c | 4 ++++
tools/perf/tests/stat.c | 53 +++++++++++++++++++++++++++++++++++++++++
tools/perf/tests/tests.h | 1 +
tools/perf/util/event.c | 39 ++++++++++++++++++++++++++++++
tools/perf/util/event.h | 5 ++++
6 files changed, 103 insertions(+)
create mode 100644 tools/perf/tests/stat.c

diff --git a/tools/perf/tests/Build b/tools/perf/tests/Build
index 05faf02ed1ee..5c3b9da9c1c3 100644
--- a/tools/perf/tests/Build
+++ b/tools/perf/tests/Build
@@ -33,6 +33,7 @@ perf-y += parse-no-sample-id-all.o
perf-y += kmod-path.o
perf-y += thread-map.o
perf-y += cpumap.o
+perf-y += stat.o

perf-$(CONFIG_X86) += perf-time-to-tsc.o

diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c
index d4cfc0592f6b..203164ad9c82 100644
--- a/tools/perf/tests/builtin-test.c
+++ b/tools/perf/tests/builtin-test.c
@@ -183,6 +183,10 @@ static struct test {
.func = test__cpu_map_synthesize,
},
{
+ .desc = "Test stat config synthesize",
+ .func = test__synthesize_stat_config,
+ },
+ {
.func = NULL,
},
};
diff --git a/tools/perf/tests/stat.c b/tools/perf/tests/stat.c
new file mode 100644
index 000000000000..5e6a2441998c
--- /dev/null
+++ b/tools/perf/tests/stat.c
@@ -0,0 +1,53 @@
+#include <linux/compiler.h>
+#include "event.h"
+#include "tests.h"
+#include "stat.h"
+#include "debug.h"
+
+static bool has_term(struct stat_config_event *config,
+ u64 tag, u64 val)
+{
+ unsigned i;
+
+ for (i = 0; i < config->nr; i++) {
+ if ((config->data[i].tag == tag) &&
+ (config->data[i].val == val))
+ return true;
+ }
+
+ return false;
+}
+
+static int process_event(struct perf_tool *tool __maybe_unused,
+ union perf_event *event,
+ struct perf_sample *sample __maybe_unused,
+ struct machine *machine __maybe_unused)
+{
+ struct stat_config_event *config = &event->stat_config;
+
+#define HAS(term, val) \
+ has_term(config, PERF_STAT_CONFIG_TERM__##term, val)
+
+ TEST_ASSERT_VAL("wrong nr", config->nr == PERF_STAT_CONFIG_TERM__MAX);
+ TEST_ASSERT_VAL("wrong aggr_mode", HAS(AGGR_MODE, AGGR_CORE));
+ TEST_ASSERT_VAL("wrong scale", HAS(SCALE, 1));
+ TEST_ASSERT_VAL("wrong interval", HAS(INTERVAL, 1));
+
+#undef HAS
+
+ return 0;
+}
+
+int test__synthesize_stat_config(void)
+{
+ struct perf_stat_config stat_config = {
+ .aggr_mode = AGGR_CORE,
+ .scale = 1,
+ .interval = 1,
+ };
+
+ TEST_ASSERT_VAL("failed to synthesize stat_config",
+ !perf_event__synthesize_stat_config(NULL, &stat_config, process_event, NULL));
+
+ return 0;
+}
diff --git a/tools/perf/tests/tests.h b/tools/perf/tests/tests.h
index c251d5a21e0c..dfb6db7d8a4d 100644
--- a/tools/perf/tests/tests.h
+++ b/tools/perf/tests/tests.h
@@ -64,6 +64,7 @@ int test__kmod_path__parse(void);
int test__thread_map(void);
int test__thread_map_synthesize(void);
int test__cpu_map_synthesize(void);
+int test__synthesize_stat_config(void);

#if defined(__x86_64__) || defined(__i386__) || defined(__arm__) || defined(__aarch64__)
#ifdef HAVE_DWARF_UNWIND_SUPPORT
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index e2c6c2df57fb..aa166ebf9fc0 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -10,6 +10,7 @@
#include "thread.h"
#include "thread_map.h"
#include "symbol/kallsyms.h"
+#include "asm/bug.h"

static const char *perf_event__names[] = {
[0] = "TOTAL",
@@ -764,6 +765,44 @@ int perf_event__synthesize_cpu_map(struct perf_tool *tool,
return err;
}

+int perf_event__synthesize_stat_config(struct perf_tool *tool,
+ struct perf_stat_config *config,
+ perf_event__handler_t process,
+ struct machine *machine)
+{
+ struct stat_config_event *event;
+ int size, i = 0, err;
+
+ size = sizeof(*event);
+ size += (PERF_STAT_CONFIG_TERM__MAX * sizeof(event->data[0]));
+
+ event = zalloc(size);
+ if (!event)
+ return -ENOMEM;
+
+ event->header.type = PERF_RECORD_STAT_CONFIG;
+ event->header.size = size;
+ event->nr = PERF_STAT_CONFIG_TERM__MAX;
+
+#define ADD(__term, __val) \
+ event->data[i].tag = PERF_STAT_CONFIG_TERM__##__term; \
+ event->data[i].val = __val; \
+ i++;
+
+ ADD(AGGR_MODE, config->aggr_mode);
+ ADD(INTERVAL, config->interval);
+ ADD(SCALE, config->scale);
+
+ WARN_ONCE(i != PERF_STAT_CONFIG_TERM__MAX,
+ "stat config terms unbalanced\n");
+#undef ADD
+
+ err = process(tool, (union perf_event *) event, NULL, machine);
+
+ free(event);
+ return err;
+}
+
size_t perf_event__fprintf_comm(union perf_event *event, FILE *fp)
{
const char *s;
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index a67f4e8e0633..23dba7bb8973 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -417,6 +417,7 @@ void perf_event__print_totals(void);
struct perf_tool;
struct thread_map;
struct cpu_map;
+struct perf_stat_config;

typedef int (*perf_event__handler_t)(struct perf_tool *tool,
union perf_event *event,
@@ -443,6 +444,10 @@ int perf_event__synthesize_threads(struct perf_tool *tool,
int perf_event__synthesize_kernel_mmap(struct perf_tool *tool,
perf_event__handler_t process,
struct machine *machine);
+int perf_event__synthesize_stat_config(struct perf_tool *tool,
+ struct perf_stat_config *config,
+ perf_event__handler_t process,
+ struct machine *machine);

int perf_event__synthesize_modules(struct perf_tool *tool,
perf_event__handler_t process,
--
2.4.3

2015-07-21 12:41:27

by Jiri Olsa

[permalink] [raw]
Subject: [PATCH 20/47] perf tools: Add stat config event read function

Introducing perf_event__read_stat_config function to read
struct perf_stat_config object data from stat config event.

Link: http://lkml.kernel.org/n/[email protected]
Signed-off-by: Jiri Olsa <[email protected]>
---
tools/perf/tests/stat.c | 6 ++++++
tools/perf/util/event.c | 24 ++++++++++++++++++++++++
tools/perf/util/event.h | 2 ++
3 files changed, 32 insertions(+)

diff --git a/tools/perf/tests/stat.c b/tools/perf/tests/stat.c
index 5e6a2441998c..2049c5a3e4a2 100644
--- a/tools/perf/tests/stat.c
+++ b/tools/perf/tests/stat.c
@@ -24,6 +24,7 @@ static int process_event(struct perf_tool *tool __maybe_unused,
struct machine *machine __maybe_unused)
{
struct stat_config_event *config = &event->stat_config;
+ struct perf_stat_config stat_config;

#define HAS(term, val) \
has_term(config, PERF_STAT_CONFIG_TERM__##term, val)
@@ -35,6 +36,11 @@ static int process_event(struct perf_tool *tool __maybe_unused,

#undef HAS

+ perf_event__read_stat_config(&stat_config, config);
+
+ TEST_ASSERT_VAL("wrong aggr_mode", stat_config.aggr_mode == AGGR_CORE);
+ TEST_ASSERT_VAL("wrong scale", stat_config.scale == 1);
+ TEST_ASSERT_VAL("wrong interval", stat_config.interval == 1);
return 0;
}

diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index aa166ebf9fc0..887731b52c40 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -803,6 +803,30 @@ int perf_event__synthesize_stat_config(struct perf_tool *tool,
return err;
}

+void perf_event__read_stat_config(struct perf_stat_config *config,
+ struct stat_config_event *event)
+{
+ unsigned i;
+
+ for (i = 0; i < event->nr; i++) {
+
+ switch (event->data[i].tag) {
+#define CASE(__term, __val) \
+ case PERF_STAT_CONFIG_TERM__##__term: \
+ config->__val = event->data[i].val; \
+ break;
+
+ CASE(AGGR_MODE, aggr_mode);
+ CASE(SCALE, scale);
+ CASE(INTERVAL, interval);
+#undef CASE
+ default:
+ pr_warning("unknown stat config term %" PRIu64 "\n",
+ event->data[i].tag);
+ }
+ }
+}
+
size_t perf_event__fprintf_comm(union perf_event *event, FILE *fp)
{
const char *s;
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index 23dba7bb8973..72da01b30cf9 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -448,6 +448,8 @@ int perf_event__synthesize_stat_config(struct perf_tool *tool,
struct perf_stat_config *config,
perf_event__handler_t process,
struct machine *machine);
+void perf_event__read_stat_config(struct perf_stat_config *config,
+ struct stat_config_event *event);

int perf_event__synthesize_modules(struct perf_tool *tool,
perf_event__handler_t process,
--
2.4.3

2015-07-21 12:32:52

by Jiri Olsa

[permalink] [raw]
Subject: [PATCH 21/47] perf tools: Add stat event

Adding stat event to store 'struct perf_counter_values' for
given event/cpu/thread.

Link: http://lkml.kernel.org/n/[email protected]
Signed-off-by: Jiri Olsa <[email protected]>
---
tools/perf/util/event.c | 1 +
tools/perf/util/event.h | 19 +++++++++++++++++++
tools/perf/util/session.c | 26 +++++++++++++++++++++++++-
tools/perf/util/tool.h | 3 ++-
4 files changed, 47 insertions(+), 2 deletions(-)

diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index 887731b52c40..6779ab62ff6a 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -39,6 +39,7 @@ static const char *perf_event__names[] = {
[PERF_RECORD_THREAD_MAP] = "THREAD_MAP",
[PERF_RECORD_CPU_MAP] = "CPU_MAP",
[PERF_RECORD_STAT_CONFIG] = "STAT_CONFIG",
+ [PERF_RECORD_STAT] = "STAT",
};

const char *perf_event__name(unsigned int id)
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index 72da01b30cf9..ab98be7a9612 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -228,6 +228,7 @@ enum perf_user_event_type { /* above any possible kernel type */
PERF_RECORD_THREAD_MAP = 73,
PERF_RECORD_CPU_MAP = 74,
PERF_RECORD_STAT_CONFIG = 75,
+ PERF_RECORD_STAT = 76,
PERF_RECORD_HEADER_MAX
};

@@ -386,6 +387,23 @@ struct stat_config_event {
struct stat_config_term_event data[];
};

+struct stat_event {
+ struct perf_event_header header;
+
+ u64 id;
+ u32 cpu;
+ u32 thread;
+
+ union {
+ struct {
+ u64 val;
+ u64 ena;
+ u64 run;
+ };
+ u64 values[3];
+ };
+};
+
union perf_event {
struct perf_event_header header;
struct mmap_event mmap;
@@ -410,6 +428,7 @@ union perf_event {
struct thread_map_event thread_map;
struct cpu_map_event cpu_map;
struct stat_config_event stat_config;
+ struct stat_event stat;
};

void perf_event__print_totals(void);
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index d9027593e4a2..e0ad3e691e6a 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -311,7 +311,6 @@ int process_event_auxtrace_error_stub(struct perf_tool *tool __maybe_unused,
return 0;
}

-
static
int process_event_thread_map_stub(struct perf_tool *tool __maybe_unused,
union perf_event *event __maybe_unused,
@@ -339,6 +338,15 @@ int process_event_stat_config_stub(struct perf_tool *tool __maybe_unused,
return 0;
}

+static int process_stat_stub(struct perf_tool *tool __maybe_unused,
+ union perf_event *event __maybe_unused,
+ struct perf_session *perf_session
+ __maybe_unused)
+{
+ dump_printf(": unhandled!\n");
+ return 0;
+}
+
void perf_tool__fill_defaults(struct perf_tool *tool)
{
if (tool->sample == NULL)
@@ -393,6 +401,8 @@ void perf_tool__fill_defaults(struct perf_tool *tool)
tool->cpu_map = process_event_cpu_map_stub;
if (tool->stat_config == NULL)
tool->stat_config = process_event_stat_config_stub;
+ if (tool->stat == NULL)
+ tool->stat = process_stat_stub;
}

static void swap_sample_id_all(union perf_event *event, void *data)
@@ -682,6 +692,17 @@ static void perf_event__stat_config_swap(union perf_event *event,
mem_bswap_64(&event->stat_config.nr, size);
}

+static void perf_event__stat_swap(union perf_event *event,
+ bool sample_id_all __maybe_unused)
+{
+ event->stat.id = bswap_64(event->stat.id);
+ event->stat.thread = bswap_32(event->stat.thread);
+ event->stat.cpu = bswap_32(event->stat.cpu);
+ event->stat.val = bswap_64(event->stat.val);
+ event->stat.ena = bswap_64(event->stat.ena);
+ event->stat.run = bswap_64(event->stat.run);
+}
+
typedef void (*perf_event__swap_op)(union perf_event *event,
bool sample_id_all);

@@ -710,6 +731,7 @@ static perf_event__swap_op perf_event__swap_ops[] = {
[PERF_RECORD_THREAD_MAP] = perf_event__thread_map_swap,
[PERF_RECORD_CPU_MAP] = perf_event__cpu_map_swap,
[PERF_RECORD_STAT_CONFIG] = perf_event__stat_config_swap,
+ [PERF_RECORD_STAT] = perf_event__stat_swap,
[PERF_RECORD_HEADER_MAX] = NULL,
};

@@ -1238,6 +1260,8 @@ static s64 perf_session__process_user_event(struct perf_session *session,
return tool->cpu_map(tool, event, session);
case PERF_RECORD_STAT_CONFIG:
return tool->stat_config(tool, event, session);
+ case PERF_RECORD_STAT:
+ return tool->stat(tool, event, session);
default:
return -EINVAL;
}
diff --git a/tools/perf/util/tool.h b/tools/perf/util/tool.h
index 5c209743ad97..49224232995b 100644
--- a/tools/perf/util/tool.h
+++ b/tools/perf/util/tool.h
@@ -57,7 +57,8 @@ struct perf_tool {
auxtrace_error,
thread_map,
cpu_map,
- stat_config;
+ stat_config,
+ stat;
event_op3 auxtrace;
bool ordered_events;
bool ordering_requires_timestamps;
--
2.4.3

2015-07-21 12:40:54

by Jiri Olsa

[permalink] [raw]
Subject: [PATCH 22/47] perf tools: Add stat event synthesize function

Introduce perf_event__synthesize_stat function to
synthesize 'struct stat_event'.

Link: http://lkml.kernel.org/n/[email protected]
Signed-off-by: Jiri Olsa <[email protected]>
---
tools/perf/tests/builtin-test.c | 4 ++++
tools/perf/tests/stat.c | 40 +++++++++++++++++++++++++++++++++++-----
tools/perf/tests/tests.h | 1 +
tools/perf/util/event.c | 22 ++++++++++++++++++++++
tools/perf/util/event.h | 7 ++++++-
5 files changed, 68 insertions(+), 6 deletions(-)

diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c
index 203164ad9c82..7d8772c0ea82 100644
--- a/tools/perf/tests/builtin-test.c
+++ b/tools/perf/tests/builtin-test.c
@@ -187,6 +187,10 @@ static struct test {
.func = test__synthesize_stat_config,
},
{
+ .desc = "Test stat synthesize",
+ .func = test__synthesize_stat,
+ },
+ {
.func = NULL,
},
};
diff --git a/tools/perf/tests/stat.c b/tools/perf/tests/stat.c
index 2049c5a3e4a2..31b242159e79 100644
--- a/tools/perf/tests/stat.c
+++ b/tools/perf/tests/stat.c
@@ -18,10 +18,10 @@ static bool has_term(struct stat_config_event *config,
return false;
}

-static int process_event(struct perf_tool *tool __maybe_unused,
- union perf_event *event,
- struct perf_sample *sample __maybe_unused,
- struct machine *machine __maybe_unused)
+static int process_stat_config_event(struct perf_tool *tool __maybe_unused,
+ union perf_event *event,
+ struct perf_sample *sample __maybe_unused,
+ struct machine *machine __maybe_unused)
{
struct stat_config_event *config = &event->stat_config;
struct perf_stat_config stat_config;
@@ -53,7 +53,37 @@ int test__synthesize_stat_config(void)
};

TEST_ASSERT_VAL("failed to synthesize stat_config",
- !perf_event__synthesize_stat_config(NULL, &stat_config, process_event, NULL));
+ !perf_event__synthesize_stat_config(NULL, &stat_config, process_stat_config_event, NULL));
+
+ return 0;
+}
+
+static int process_stat_event(struct perf_tool *tool __maybe_unused,
+ union perf_event *event,
+ struct perf_sample *sample __maybe_unused,
+ struct machine *machine __maybe_unused)
+{
+ struct stat_event *stat = &event->stat;
+
+ TEST_ASSERT_VAL("wrong cpu", stat->cpu == 1);
+ TEST_ASSERT_VAL("wrong thread", stat->thread == 2);
+ TEST_ASSERT_VAL("wrong id", stat->id == 3);
+ TEST_ASSERT_VAL("wrong val", stat->val == 100);
+ TEST_ASSERT_VAL("wrong run", stat->ena == 200);
+ TEST_ASSERT_VAL("wrong ena", stat->run == 300);
+ return 0;
+}
+
+int test__synthesize_stat(void)
+{
+ struct perf_counts_values count = {
+ .val = 100,
+ .ena = 200,
+ .run = 300,
+ };
+
+ TEST_ASSERT_VAL("failed to synthesize stat_config",
+ !perf_event__synthesize_stat(NULL, 1, 2, 3, &count, process_stat_event, NULL));

return 0;
}
diff --git a/tools/perf/tests/tests.h b/tools/perf/tests/tests.h
index dfb6db7d8a4d..98beb2be1e26 100644
--- a/tools/perf/tests/tests.h
+++ b/tools/perf/tests/tests.h
@@ -65,6 +65,7 @@ int test__thread_map(void);
int test__thread_map_synthesize(void);
int test__cpu_map_synthesize(void);
int test__synthesize_stat_config(void);
+int test__synthesize_stat(void);

#if defined(__x86_64__) || defined(__i386__) || defined(__arm__) || defined(__aarch64__)
#ifdef HAVE_DWARF_UNWIND_SUPPORT
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index 6779ab62ff6a..02954385ccdc 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -804,6 +804,28 @@ int perf_event__synthesize_stat_config(struct perf_tool *tool,
return err;
}

+int perf_event__synthesize_stat(struct perf_tool *tool,
+ u32 cpu, u32 thread, u64 id,
+ struct perf_counts_values *count,
+ perf_event__handler_t process,
+ struct machine *machine)
+{
+ struct stat_event event;
+
+ event.header.type = PERF_RECORD_STAT;
+ event.header.size = sizeof(event);
+ event.header.misc = 0;
+
+ event.id = id;
+ event.cpu = cpu;
+ event.thread = thread;
+ event.val = count->val;
+ event.ena = count->ena;
+ event.run = count->run;
+
+ return process(tool, (union perf_event *) &event, NULL, machine);
+}
+
void perf_event__read_stat_config(struct perf_stat_config *config,
struct stat_config_event *event)
{
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index ab98be7a9612..375b1de34cc6 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -437,6 +437,7 @@ struct perf_tool;
struct thread_map;
struct cpu_map;
struct perf_stat_config;
+struct perf_counts_values;

typedef int (*perf_event__handler_t)(struct perf_tool *tool,
union perf_event *event,
@@ -469,7 +470,11 @@ int perf_event__synthesize_stat_config(struct perf_tool *tool,
struct machine *machine);
void perf_event__read_stat_config(struct perf_stat_config *config,
struct stat_config_event *event);
-
+int perf_event__synthesize_stat(struct perf_tool *tool,
+ u32 cpu, u32 thread, u64 id,
+ struct perf_counts_values *count,
+ perf_event__handler_t process,
+ struct machine *machine);
int perf_event__synthesize_modules(struct perf_tool *tool,
perf_event__handler_t process,
struct machine *machine);
--
2.4.3

2015-07-21 12:32:56

by Jiri Olsa

[permalink] [raw]
Subject: [PATCH 23/47] perf tools: Add stat event read function

Introducing perf_event__process_stat_event function to process
'struct perf_stat' data from stat event.

Link: http://lkml.kernel.org/n/[email protected]
Signed-off-by: Jiri Olsa <[email protected]>
---
tools/perf/util/stat.c | 23 +++++++++++++++++++++++
tools/perf/util/stat.h | 6 ++++++
2 files changed, 29 insertions(+)

diff --git a/tools/perf/util/stat.c b/tools/perf/util/stat.c
index c5c709cdc3ce..c5d4b15c6c7a 100644
--- a/tools/perf/util/stat.c
+++ b/tools/perf/util/stat.c
@@ -377,3 +377,26 @@ int perf_stat_process_counter(struct perf_stat_config *config,

return 0;
}
+
+int perf_event__process_stat_event(struct perf_tool *tool __maybe_unused,
+ union perf_event *event,
+ struct perf_session *session)
+{
+ struct perf_counts_values count;
+ struct stat_event *stat = &event->stat;
+ struct perf_evsel *counter;
+
+ count.val = stat->val;
+ count.ena = stat->ena;
+ count.run = stat->run;
+
+ counter = perf_evlist__id2evsel(session->evlist, stat->id);
+ if (!counter) {
+ pr_err("Failed to resolve counter for stat event.\n");
+ return -EINVAL;
+ }
+
+ *perf_counts(counter->counts, stat->cpu, stat->thread) = count;
+ counter->supported = true;
+ return 0;
+}
diff --git a/tools/perf/util/stat.h b/tools/perf/util/stat.h
index 0b897b083682..b69246759cfc 100644
--- a/tools/perf/util/stat.h
+++ b/tools/perf/util/stat.h
@@ -119,4 +119,10 @@ void perf_evlist__reset_stats(struct perf_evlist *evlist);

int perf_stat_process_counter(struct perf_stat_config *config,
struct perf_evsel *counter);
+struct perf_tool;
+union perf_event;
+struct perf_session;
+int perf_event__process_stat_event(struct perf_tool *tool,
+ union perf_event *event,
+ struct perf_session *session);
#endif
--
2.4.3

2015-07-21 12:39:49

by Jiri Olsa

[permalink] [raw]
Subject: [PATCH 24/47] perf tools: Add stat round event

Adding stat round event to be stored afer each stat interval round,
so report tools (report/script) get notified and process interval
data.

Link: http://lkml.kernel.org/n/[email protected]
Signed-off-by: Jiri Olsa <[email protected]>
---
tools/perf/util/event.c | 1 +
tools/perf/util/event.h | 7 +++++++
tools/perf/util/session.c | 20 ++++++++++++++++++++
tools/perf/util/tool.h | 3 ++-
4 files changed, 30 insertions(+), 1 deletion(-)

diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index 02954385ccdc..658cb81eb27f 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -40,6 +40,7 @@ static const char *perf_event__names[] = {
[PERF_RECORD_CPU_MAP] = "CPU_MAP",
[PERF_RECORD_STAT_CONFIG] = "STAT_CONFIG",
[PERF_RECORD_STAT] = "STAT",
+ [PERF_RECORD_STAT_ROUND] = "STAT_ROUND",
};

const char *perf_event__name(unsigned int id)
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index 375b1de34cc6..a4d3b3098613 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -229,6 +229,7 @@ enum perf_user_event_type { /* above any possible kernel type */
PERF_RECORD_CPU_MAP = 74,
PERF_RECORD_STAT_CONFIG = 75,
PERF_RECORD_STAT = 76,
+ PERF_RECORD_STAT_ROUND = 77,
PERF_RECORD_HEADER_MAX
};

@@ -404,6 +405,11 @@ struct stat_event {
};
};

+struct stat_round_event {
+ struct perf_event_header header;
+ u64 time;
+};
+
union perf_event {
struct perf_event_header header;
struct mmap_event mmap;
@@ -429,6 +435,7 @@ union perf_event {
struct cpu_map_event cpu_map;
struct stat_config_event stat_config;
struct stat_event stat;
+ struct stat_round_event stat_round;
};

void perf_event__print_totals(void);
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index e0ad3e691e6a..4b957c02fffb 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -347,6 +347,15 @@ static int process_stat_stub(struct perf_tool *tool __maybe_unused,
return 0;
}

+static int process_stat_round_stub(struct perf_tool *tool __maybe_unused,
+ union perf_event *event __maybe_unused,
+ struct perf_session *perf_session
+ __maybe_unused)
+{
+ dump_printf(": unhandled!\n");
+ return 0;
+}
+
void perf_tool__fill_defaults(struct perf_tool *tool)
{
if (tool->sample == NULL)
@@ -403,6 +412,8 @@ void perf_tool__fill_defaults(struct perf_tool *tool)
tool->stat_config = process_event_stat_config_stub;
if (tool->stat == NULL)
tool->stat = process_stat_stub;
+ if (tool->stat_round == NULL)
+ tool->stat_round = process_stat_round_stub;
}

static void swap_sample_id_all(union perf_event *event, void *data)
@@ -703,6 +714,12 @@ static void perf_event__stat_swap(union perf_event *event,
event->stat.run = bswap_64(event->stat.run);
}

+static void perf_event__stat_round_swap(union perf_event *event,
+ bool sample_id_all __maybe_unused)
+{
+ event->stat_round.time = bswap_64(event->stat_round.time);
+}
+
typedef void (*perf_event__swap_op)(union perf_event *event,
bool sample_id_all);

@@ -732,6 +749,7 @@ static perf_event__swap_op perf_event__swap_ops[] = {
[PERF_RECORD_CPU_MAP] = perf_event__cpu_map_swap,
[PERF_RECORD_STAT_CONFIG] = perf_event__stat_config_swap,
[PERF_RECORD_STAT] = perf_event__stat_swap,
+ [PERF_RECORD_STAT_ROUND] = perf_event__stat_round_swap,
[PERF_RECORD_HEADER_MAX] = NULL,
};

@@ -1262,6 +1280,8 @@ static s64 perf_session__process_user_event(struct perf_session *session,
return tool->stat_config(tool, event, session);
case PERF_RECORD_STAT:
return tool->stat(tool, event, session);
+ case PERF_RECORD_STAT_ROUND:
+ return tool->stat_round(tool, event, session);
default:
return -EINVAL;
}
diff --git a/tools/perf/util/tool.h b/tools/perf/util/tool.h
index 49224232995b..fca37b3460cb 100644
--- a/tools/perf/util/tool.h
+++ b/tools/perf/util/tool.h
@@ -58,7 +58,8 @@ struct perf_tool {
thread_map,
cpu_map,
stat_config,
- stat;
+ stat,
+ stat_round;
event_op3 auxtrace;
bool ordered_events;
bool ordering_requires_timestamps;
--
2.4.3

2015-07-21 12:33:02

by Jiri Olsa

[permalink] [raw]
Subject: [PATCH 25/47] perf tools: Add stat round event synthesize function

Introduce perf_event__synthesize_stat_round function to
synthesize 'struct stat_round_event'.

Link: http://lkml.kernel.org/n/[email protected]
Signed-off-by: Jiri Olsa <[email protected]>
---
tools/perf/tests/builtin-test.c | 4 ++++
tools/perf/tests/stat.c | 19 +++++++++++++++++++
tools/perf/tests/tests.h | 2 ++
tools/perf/util/event.c | 16 ++++++++++++++++
tools/perf/util/event.h | 4 ++++
5 files changed, 45 insertions(+)

diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c
index 7d8772c0ea82..4dd6483a6c1c 100644
--- a/tools/perf/tests/builtin-test.c
+++ b/tools/perf/tests/builtin-test.c
@@ -191,6 +191,10 @@ static struct test {
.func = test__synthesize_stat,
},
{
+ .desc = "Test stat round synthesize",
+ .func = test__synthesize_stat_round,
+ },
+ {
.func = NULL,
},
};
diff --git a/tools/perf/tests/stat.c b/tools/perf/tests/stat.c
index 31b242159e79..862062256cca 100644
--- a/tools/perf/tests/stat.c
+++ b/tools/perf/tests/stat.c
@@ -87,3 +87,22 @@ int test__synthesize_stat(void)

return 0;
}
+
+static int process_stat_round_event(struct perf_tool *tool __maybe_unused,
+ union perf_event *event,
+ struct perf_sample *sample __maybe_unused,
+ struct machine *machine __maybe_unused)
+{
+ struct stat_round_event *stat_round = &event->stat_round;
+
+ TEST_ASSERT_VAL("wrong time", stat_round->time == 0xdeadbeef);
+ return 0;
+}
+
+int test__synthesize_stat_round(void)
+{
+ TEST_ASSERT_VAL("failed to synthesize stat_config",
+ !perf_event__synthesize_stat_round(NULL, 0xdeadbeef, process_stat_round_event, NULL));
+
+ return 0;
+}
diff --git a/tools/perf/tests/tests.h b/tools/perf/tests/tests.h
index 98beb2be1e26..ae28421a4834 100644
--- a/tools/perf/tests/tests.h
+++ b/tools/perf/tests/tests.h
@@ -66,6 +66,8 @@ int test__thread_map_synthesize(void);
int test__cpu_map_synthesize(void);
int test__synthesize_stat_config(void);
int test__synthesize_stat(void);
+int test__synthesize_stat_round(void);
+

#if defined(__x86_64__) || defined(__i386__) || defined(__arm__) || defined(__aarch64__)
#ifdef HAVE_DWARF_UNWIND_SUPPORT
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index 658cb81eb27f..905c6dc21ac8 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -827,6 +827,22 @@ int perf_event__synthesize_stat(struct perf_tool *tool,
return process(tool, (union perf_event *) &event, NULL, machine);
}

+int perf_event__synthesize_stat_round(struct perf_tool *tool,
+ u64 time,
+ perf_event__handler_t process,
+ struct machine *machine)
+{
+ struct stat_round_event event;
+
+ event.header.type = PERF_RECORD_STAT_ROUND;
+ event.header.size = sizeof(event);
+ event.header.misc = 0;
+
+ event.time = time;
+
+ return process(tool, (union perf_event *) &event, NULL, machine);
+}
+
void perf_event__read_stat_config(struct perf_stat_config *config,
struct stat_config_event *event)
{
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index a4d3b3098613..d5a248b7643a 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -482,6 +482,10 @@ int perf_event__synthesize_stat(struct perf_tool *tool,
struct perf_counts_values *count,
perf_event__handler_t process,
struct machine *machine);
+int perf_event__synthesize_stat_round(struct perf_tool *tool,
+ u64 time,
+ perf_event__handler_t process,
+ struct machine *machine);
int perf_event__synthesize_modules(struct perf_tool *tool,
perf_event__handler_t process,
struct machine *machine);
--
2.4.3

2015-07-21 12:39:31

by Jiri Olsa

[permalink] [raw]
Subject: [PATCH 26/47] perf tools: Introduce stat feature

Introducing stat feature to mark perf.data as created by
perf stat record command. It contains no data.

It's needed for report tools (report/script) to differentiate
sampling data from stat data, because they need to be treated
in a different way.

Link: http://lkml.kernel.org/n/[email protected]
Signed-off-by: Jiri Olsa <[email protected]>
---
tools/perf/builtin-record.c | 2 ++
tools/perf/util/header.c | 14 ++++++++++++++
tools/perf/util/header.h | 1 +
3 files changed, 17 insertions(+)

diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index 283fe96bdfc1..68dda0cffc4e 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -449,6 +449,8 @@ static void record__init_features(struct record *rec)

if (!rec->opts.full_auxtrace)
perf_header__clear_feat(&session->header, HEADER_AUXTRACE);
+
+ perf_header__clear_feat(&session->header, HEADER_STAT);
}

static volatile int workload_exec_errno;
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index 179b2bdd157d..1eb17453d78b 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -883,6 +883,13 @@ static int write_auxtrace(int fd, struct perf_header *h,
return err;
}

+static int write_stat(int fd __maybe_unused,
+ struct perf_header *h __maybe_unused,
+ struct perf_evlist *evlist __maybe_unused)
+{
+ return 0;
+}
+
static void print_hostname(struct perf_header *ph, int fd __maybe_unused,
FILE *fp)
{
@@ -1166,6 +1173,12 @@ static void print_auxtrace(struct perf_header *ph __maybe_unused,
fprintf(fp, "# contains AUX area data (e.g. instruction trace)\n");
}

+static void print_stat(struct perf_header *ph __maybe_unused,
+ int fd __maybe_unused, FILE *fp)
+{
+ fprintf(fp, "# contains stat data\n");
+}
+
static void print_pmu_mappings(struct perf_header *ph, int fd __maybe_unused,
FILE *fp)
{
@@ -1899,6 +1912,7 @@ static const struct feature_ops feat_ops[HEADER_LAST_FEATURE] = {
FEAT_OPP(HEADER_PMU_MAPPINGS, pmu_mappings),
FEAT_OPP(HEADER_GROUP_DESC, group_desc),
FEAT_OPP(HEADER_AUXTRACE, auxtrace),
+ FEAT_OPA(HEADER_STAT, stat),
};

struct header_print_data {
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
index 9b53b6525ce8..5ef500777428 100644
--- a/tools/perf/util/header.h
+++ b/tools/perf/util/header.h
@@ -31,6 +31,7 @@ enum {
HEADER_PMU_MAPPINGS,
HEADER_GROUP_DESC,
HEADER_AUXTRACE,
+ HEADER_STAT,
HEADER_LAST_FEATURE,
HEADER_FEAT_BITS = 256,
};
--
2.4.3

2015-07-21 12:39:09

by Jiri Olsa

[permalink] [raw]
Subject: [PATCH 27/47] perf tools: Move id_offset out of struct perf_evsel union

Because following stat patches use id_offset together
with priv pointer.

Link: http://lkml.kernel.org/n/[email protected]
Signed-off-by: Jiri Olsa <[email protected]>
---
tools/perf/util/evsel.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
index fe9f3279632b..6e0bcf74b33b 100644
--- a/tools/perf/util/evsel.h
+++ b/tools/perf/util/evsel.h
@@ -59,9 +59,9 @@ struct perf_evsel {
double scale;
const char *unit;
struct event_format *tp_format;
+ off_t id_offset;
union {
void *priv;
- off_t id_offset;
u64 db_id;
};
struct cgroup_sel *cgrp;
--
2.4.3

2015-07-21 12:33:11

by Jiri Olsa

[permalink] [raw]
Subject: [PATCH 28/47] perf stat record: Add record command

Add 'perf stat record' command support. It creates simple
(header only) perf.data file ATM.

Link: http://lkml.kernel.org/n/[email protected]
Signed-off-by: Jiri Olsa <[email protected]>
---
tools/perf/Documentation/perf-stat.txt | 12 ++++++
tools/perf/builtin-stat.c | 74 +++++++++++++++++++++++++++++++++-
2 files changed, 84 insertions(+), 2 deletions(-)

diff --git a/tools/perf/Documentation/perf-stat.txt b/tools/perf/Documentation/perf-stat.txt
index 47469abdcc1c..0ccce466ad53 100644
--- a/tools/perf/Documentation/perf-stat.txt
+++ b/tools/perf/Documentation/perf-stat.txt
@@ -10,6 +10,7 @@ SYNOPSIS
[verse]
'perf stat' [-e <EVENT> | --event=EVENT] [-a] <command>
'perf stat' [-e <EVENT> | --event=EVENT] [-a] -- <command> [<options>]
+'perf stat' [-e <EVENT> | --event=EVENT] [-a] record [-o file] -- <command> [<options>]

DESCRIPTION
-----------
@@ -22,6 +23,8 @@ OPTIONS
<command>...::
Any command you can specify in a shell.

+record::
+ See STAT RECORD.

-e::
--event=::
@@ -158,6 +161,15 @@ filter out the startup phase of the program, which is often very different.

Print statistics of transactional execution if supported.

+STAT RECORD
+-----------
+Stores stat data into perf data file.
+
+-o file::
+--output file::
+Output file name.
+
+
EXAMPLES
--------

diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index a054ddc0b2a0..f78bd3e22d40 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -58,6 +58,7 @@
#include "util/cpumap.h"
#include "util/thread.h"
#include "util/thread_map.h"
+#include "util/session.h"

#include <stdlib.h>
#include <sys/prctl.h>
@@ -120,6 +121,16 @@ static struct timespec ref_time;
static struct cpu_map *aggr_map;
static int (*aggr_get_id)(struct cpu_map *m, int cpu);

+struct perf_stat_record {
+ bool enabled;
+ struct perf_data_file file;
+ struct perf_session *session;
+ u64 bytes_written;
+};
+
+static struct perf_stat_record stat_record;
+#define STAT_RECORD stat_record.enabled
+
static volatile int done = 0;

static struct perf_stat_config stat_config = {
@@ -338,6 +349,15 @@ static int __run_perf_stat(int argc, const char **argv)
return -1;
}

+ if (STAT_RECORD) {
+ int err, fd = perf_data_file__fd(&stat_record.file);
+
+ err = perf_session__write_header(stat_record.session, evsel_list,
+ fd, false);
+ if (err < 0)
+ return err;
+ }
+
/*
* Enable counters and exec the command:
*/
@@ -1125,6 +1145,39 @@ static int add_default_attributes(void)
return perf_evlist__add_default_attrs(evsel_list, very_very_detailed_attrs);
}

+static const char * const recort_usage[] = {
+ "perf stat record [<options>]",
+ NULL,
+};
+
+static int __cmd_record(int argc, const char **argv)
+{
+ struct perf_session *session;
+ struct perf_data_file *file = &stat_record.file;
+ const struct option options[] = {
+ OPT_STRING('o', "output", &stat_record.file.path, "file", "output file name"),
+ OPT_END()
+ };
+
+ argc = parse_options(argc, argv, options, record_usage,
+ PARSE_OPT_STOP_AT_NON_OPTION);
+
+ session = perf_session__new(file, false, NULL);
+ if (session == NULL) {
+ pr_err("Perf session creation failed.\n");
+ return -1;
+ }
+
+ /* No pipe support ATM */
+ if (stat_record.file.is_pipe)
+ return -EINVAL;
+
+ session->evlist = evsel_list;
+ stat_record.session = session;
+ stat_record.enabled = true;
+ return argc;
+}
+
int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
{
bool append_file = false;
@@ -1198,6 +1251,7 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
const char *mode;
FILE *output = stderr;
unsigned int interval;
+ const char * const stat_subcommands[] = { "record" };

setlocale(LC_ALL, "");

@@ -1205,8 +1259,15 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
if (evsel_list == NULL)
return -ENOMEM;

- argc = parse_options(argc, argv, options, stat_usage,
- PARSE_OPT_STOP_AT_NON_OPTION);
+ argc = parse_options_subcommand(argc, argv, options, stat_subcommands,
+ (const char **) stat_usage,
+ PARSE_OPT_STOP_AT_NON_OPTION);
+
+ if (argc && !strncmp(argv[0], "rec", 3)) {
+ argc = __cmd_record(argc, argv);
+ if (argc < 0)
+ return -1;
+ }

interval = stat_config.interval;

@@ -1372,6 +1433,15 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
if (!forever && status != -1 && !interval)
print_counters(NULL, argc, argv);

+ if (STAT_RECORD) {
+ int fd = perf_data_file__fd(&stat_record.file);
+
+ stat_record.session->header.data_size += stat_record.bytes_written;
+ perf_session__write_header(stat_record.session, evsel_list, fd, true);
+
+ perf_session__delete(stat_record.session);
+ }
+
perf_evlist__free_stats(evsel_list);
out:
perf_evlist__delete(evsel_list);
--
2.4.3

2015-07-21 12:33:07

by Jiri Olsa

[permalink] [raw]
Subject: [PATCH 29/47] perf stat record: Initialize record features

Disabling all non stat related features.

Link: http://lkml.kernel.org/n/[email protected]
Signed-off-by: Jiri Olsa <[email protected]>
---
tools/perf/builtin-stat.c | 15 +++++++++++++++
1 file changed, 15 insertions(+)

diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index f78bd3e22d40..95030e686bc4 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -1150,6 +1150,19 @@ static const char * const recort_usage[] = {
NULL,
};

+static void init_features(struct perf_session *session)
+{
+ int feat;
+
+ for (feat = HEADER_FIRST_FEATURE; feat < HEADER_LAST_FEATURE; feat++)
+ perf_header__set_feat(&session->header, feat);
+
+ perf_header__clear_feat(&session->header, HEADER_BUILD_ID);
+ perf_header__clear_feat(&session->header, HEADER_TRACING_DATA);
+ perf_header__clear_feat(&session->header, HEADER_BRANCH_STACK);
+ perf_header__clear_feat(&session->header, HEADER_AUXTRACE);
+}
+
static int __cmd_record(int argc, const char **argv)
{
struct perf_session *session;
@@ -1172,6 +1185,8 @@ static int __cmd_record(int argc, const char **argv)
if (stat_record.file.is_pipe)
return -EINVAL;

+ init_features(session);
+
session->evlist = evsel_list;
stat_record.session = session;
stat_record.enabled = true;
--
2.4.3

2015-07-21 12:38:33

by Jiri Olsa

[permalink] [raw]
Subject: [PATCH 30/47] perf stat record: Synthesize stat record data

Synthesizing needed stat record data for report/script:
- cpu/thread maps
- stat config

Link: http://lkml.kernel.org/n/[email protected]
Signed-off-by: Jiri Olsa <[email protected]>
---
tools/perf/builtin-stat.c | 48 +++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 48 insertions(+)

diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index 95030e686bc4..50d7c8ba0e00 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -190,6 +190,20 @@ static inline int nsec_counter(struct perf_evsel *evsel)
return 0;
}

+static int process_synthesized_event(struct perf_tool *tool __maybe_unused,
+ union perf_event *event,
+ struct perf_sample *sample __maybe_unused,
+ struct machine *machine __maybe_unused)
+{
+ if (perf_data_file__write(&stat_record.file, event, event->header.size) < 0) {
+ pr_err("failed to write perf data, error: %m\n");
+ return -1;
+ }
+
+ stat_record.bytes_written += event->header.size;
+ return 0;
+}
+
/*
* Read out the results of a single counter:
* do not aggregate counts across CPUs in system-wide mode
@@ -276,6 +290,36 @@ static void workload_exec_failed_signal(int signo __maybe_unused, siginfo_t *inf
workload_exec_errno = info->si_value.sival_int;
}

+static int perf_stat_synthesize_config(void)
+{
+ int err;
+
+ err = perf_event__synthesize_stat_config(NULL, &stat_config,
+ process_synthesized_event, NULL);
+ if (err < 0) {
+ pr_err("Couldn't synthesize config.\n");
+ return err;
+ }
+
+ err = perf_event__synthesize_thread_map2(NULL, evsel_list->threads,
+ process_synthesized_event,
+ NULL);
+ if (err < 0) {
+ pr_err("Couldn't synthesize thread map.\n");
+ return err;
+ }
+
+ err = perf_event__synthesize_cpu_map(NULL, evsel_list->cpus,
+ process_synthesized_event,
+ NULL);
+ if (err < 0) {
+ pr_err("Couldn't synthesize thread map.\n");
+ return err;
+ }
+
+ return 0;
+}
+
static int __run_perf_stat(int argc, const char **argv)
{
int interval = stat_config.interval;
@@ -356,6 +400,10 @@ static int __run_perf_stat(int argc, const char **argv)
fd, false);
if (err < 0)
return err;
+
+ err = perf_stat_synthesize_config();
+ if (err < 0)
+ return err;
}

/*
--
2.4.3

2015-07-21 12:38:04

by Jiri Olsa

[permalink] [raw]
Subject: [PATCH 31/47] perf stat record: Store events IDs in perf data file

Store event IDs in evlist object so it get stored
into perf.data file.

Link: http://lkml.kernel.org/n/[email protected]
Signed-off-by: Jiri Olsa <[email protected]>
---
tools/perf/builtin-stat.c | 35 +++++++++++++++++++++++++++++++++++
tools/perf/util/evlist.c | 6 +++---
tools/perf/util/evlist.h | 3 +++
3 files changed, 41 insertions(+), 3 deletions(-)

diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index 50d7c8ba0e00..eba46eeacd91 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -320,6 +320,38 @@ static int perf_stat_synthesize_config(void)
return 0;
}

+#define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y))
+
+static int __store_counter_ids(struct perf_evsel *counter,
+ struct cpu_map *cpus,
+ struct thread_map *threads)
+{
+ int cpu, thread;
+
+ for (cpu = 0; cpu < cpus->nr; cpu++) {
+ for (thread = 0; thread < threads->nr; thread++) {
+ int fd = FD(counter, cpu, thread);
+
+ if (perf_evlist__id_add_fd(evsel_list, counter,
+ cpu, thread, fd) < 0)
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+static int store_counter_ids(struct perf_evsel *counter)
+{
+ struct cpu_map *cpus = counter->cpus;
+ struct thread_map *threads = counter->threads;
+
+ if (perf_evsel__alloc_id(counter, cpus->nr, threads->nr))
+ return -ENOMEM;
+
+ return __store_counter_ids(counter, cpus, threads);
+}
+
static int __run_perf_stat(int argc, const char **argv)
{
int interval = stat_config.interval;
@@ -384,6 +416,9 @@ static int __run_perf_stat(int argc, const char **argv)
l = strlen(counter->unit);
if (l > unit_width)
unit_width = l;
+
+ if (STAT_RECORD && store_counter_ids(counter))
+ return -1;
}

if (perf_evlist__apply_filters(evsel_list, &counter)) {
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index 3b9f411a6b46..28c2e9b1eab9 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -496,9 +496,9 @@ void perf_evlist__id_add(struct perf_evlist *evlist, struct perf_evsel *evsel,
evsel->id[evsel->ids++] = id;
}

-static int perf_evlist__id_add_fd(struct perf_evlist *evlist,
- struct perf_evsel *evsel,
- int cpu, int thread, int fd)
+int perf_evlist__id_add_fd(struct perf_evlist *evlist,
+ struct perf_evsel *evsel,
+ int cpu, int thread, int fd)
{
u64 read_data[4] = { 0, };
int id_idx = 1; /* The first entry is the counter value */
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h
index 406a8216a51e..c02d7bc64a65 100644
--- a/tools/perf/util/evlist.h
+++ b/tools/perf/util/evlist.h
@@ -94,6 +94,9 @@ perf_evlist__find_tracepoint_by_name(struct perf_evlist *evlist,

void perf_evlist__id_add(struct perf_evlist *evlist, struct perf_evsel *evsel,
int cpu, int thread, u64 id);
+int perf_evlist__id_add_fd(struct perf_evlist *evlist,
+ struct perf_evsel *evsel,
+ int cpu, int thread, int fd);

int perf_evlist__add_pollfd(struct perf_evlist *evlist, int fd);
int perf_evlist__alloc_pollfd(struct perf_evlist *evlist);
--
2.4.3

2015-07-21 12:37:47

by Jiri Olsa

[permalink] [raw]
Subject: [PATCH 32/47] perf stat record: Add pipe support for record command

Allowing storing stat record data into pipe, so report
tools (report/script) could read data directly from
record.

Link: http://lkml.kernel.org/n/[email protected]
Signed-off-by: Jiri Olsa <[email protected]>
---
tools/perf/builtin-stat.c | 39 ++++++++++++++++++++++++++++-----------
1 file changed, 28 insertions(+), 11 deletions(-)

diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index eba46eeacd91..d6ba710e7358 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -290,7 +290,7 @@ static void workload_exec_failed_signal(int signo __maybe_unused, siginfo_t *inf
workload_exec_errno = info->si_value.sival_int;
}

-static int perf_stat_synthesize_config(void)
+static int perf_stat_synthesize_config(bool is_pipe)
{
int err;

@@ -301,6 +301,15 @@ static int perf_stat_synthesize_config(void)
return err;
}

+ if (is_pipe) {
+ err = perf_event__synthesize_attrs(NULL, stat_record.session,
+ process_synthesized_event);
+ if (err < 0) {
+ pr_err("Couldn't synthesize attrs.\n");
+ return err;
+ }
+ }
+
err = perf_event__synthesize_thread_map2(NULL, evsel_list->threads,
process_synthesized_event,
NULL);
@@ -362,6 +371,7 @@ static int __run_perf_stat(int argc, const char **argv)
size_t l;
int status = 0;
const bool forks = (argc > 0);
+ bool is_pipe = STAT_RECORD ? stat_record.file.is_pipe : false;

if (interval) {
ts.tv_sec = interval / 1000;
@@ -372,7 +382,7 @@ static int __run_perf_stat(int argc, const char **argv)
}

if (forks) {
- if (perf_evlist__prepare_workload(evsel_list, &target, argv, false,
+ if (perf_evlist__prepare_workload(evsel_list, &target, argv, is_pipe,
workload_exec_failed_signal) < 0) {
perror("failed to prepare workload");
return -1;
@@ -431,12 +441,17 @@ static int __run_perf_stat(int argc, const char **argv)
if (STAT_RECORD) {
int err, fd = perf_data_file__fd(&stat_record.file);

- err = perf_session__write_header(stat_record.session, evsel_list,
- fd, false);
+ if (is_pipe) {
+ err = perf_header__write_pipe(perf_data_file__fd(&stat_record.file));
+ } else {
+ err = perf_session__write_header(stat_record.session, evsel_list,
+ fd, false);
+ }
+
if (err < 0)
return err;

- err = perf_stat_synthesize_config();
+ err = perf_stat_synthesize_config(is_pipe);
if (err < 0)
return err;
}
@@ -961,6 +976,10 @@ static void print_counters(struct timespec *ts, int argc, const char **argv)
struct perf_evsel *counter;
char buf[64], *prefix = NULL;

+ /* Do not print anything if we record to the pipe. */
+ if (STAT_RECORD && stat_record.file.is_pipe)
+ return;
+
if (interval)
print_interval(prefix = buf, ts);
else
@@ -1264,10 +1283,6 @@ static int __cmd_record(int argc, const char **argv)
return -1;
}

- /* No pipe support ATM */
- if (stat_record.file.is_pipe)
- return -EINVAL;
-
init_features(session);

session->evlist = evsel_list;
@@ -1534,8 +1549,10 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
if (STAT_RECORD) {
int fd = perf_data_file__fd(&stat_record.file);

- stat_record.session->header.data_size += stat_record.bytes_written;
- perf_session__write_header(stat_record.session, evsel_list, fd, true);
+ if (!stat_record.file.is_pipe) {
+ stat_record.session->header.data_size += stat_record.bytes_written;
+ perf_session__write_header(stat_record.session, evsel_list, fd, true);
+ }

perf_session__delete(stat_record.session);
}
--
2.4.3

2015-07-21 12:37:21

by Jiri Olsa

[permalink] [raw]
Subject: [PATCH 33/47] perf stat record: Write stat events on record

Writing stat events on 'perf stat record' at the time
we read counter values from kernel.

Link: http://lkml.kernel.org/n/[email protected]
Signed-off-by: Jiri Olsa <[email protected]>
---
tools/perf/builtin-stat.c | 19 +++++++++++++++++++
1 file changed, 19 insertions(+)

diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index d6ba710e7358..49948be5680f 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -204,6 +204,18 @@ static int process_synthesized_event(struct perf_tool *tool __maybe_unused,
return 0;
}

+#define SID(e, x, y) xyarray__entry(e->sample_id, x, y)
+
+static int
+perf_evsel__write_stat_event(struct perf_evsel *counter, u32 cpu, u32 thread,
+ struct perf_counts_values *count)
+{
+ struct perf_sample_id *sid = SID(counter, cpu, thread);
+
+ return perf_event__synthesize_stat(NULL, cpu, thread, sid->id, count,
+ process_synthesized_event, NULL);
+}
+
/*
* Read out the results of a single counter:
* do not aggregate counts across CPUs in system-wide mode
@@ -227,6 +239,13 @@ static int read_counter(struct perf_evsel *counter)
count = perf_counts(counter->counts, cpu, thread);
if (perf_evsel__read(counter, cpu, thread, count))
return -1;
+
+ if (STAT_RECORD) {
+ if (perf_evsel__write_stat_event(counter, cpu, thread, count)) {
+ pr_err("failed to write stat event\n");
+ return -1;
+ }
+ }
}
}

--
2.4.3

2015-07-21 12:33:16

by Jiri Olsa

[permalink] [raw]
Subject: [PATCH 34/47] perf stat record: Write stat round events on record

Writing stat round events on 'perf stat record' for
each interval round. In non interval mode we store
round event after the last stat event.

Link: http://lkml.kernel.org/n/[email protected]
Signed-off-by: Jiri Olsa <[email protected]>
---
tools/perf/builtin-stat.c | 17 +++++++++++++++++
1 file changed, 17 insertions(+)

diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index 49948be5680f..8ad497522a0e 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -204,6 +204,13 @@ static int process_synthesized_event(struct perf_tool *tool __maybe_unused,
return 0;
}

+static int write_stat_round_event(u64 time)
+{
+ return perf_event__synthesize_stat_round(NULL, time,
+ process_synthesized_event,
+ NULL);
+}
+
#define SID(e, x, y) xyarray__entry(e->sample_id, x, y)

static int
@@ -279,6 +286,11 @@ static void process_interval(void)
clock_gettime(CLOCK_MONOTONIC, &ts);
diff_timespec(&rs, &ts, &ref_time);

+ if (STAT_RECORD) {
+ if (write_stat_round_event(rs.tv_sec * NSECS_PER_SEC + rs.tv_nsec))
+ pr_err("failed to write stat round event\n");
+ }
+
print_counters(&rs, 0, NULL);
}

@@ -1568,6 +1580,11 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
if (STAT_RECORD) {
int fd = perf_data_file__fd(&stat_record.file);

+ if (!interval) {
+ if (write_stat_round_event(0))
+ pr_err("failed to write stat round event\n");
+ }
+
if (!stat_record.file.is_pipe) {
stat_record.session->header.data_size += stat_record.bytes_written;
perf_session__write_header(stat_record.session, evsel_list, fd, true);
--
2.4.3

2015-07-21 12:36:56

by Jiri Olsa

[permalink] [raw]
Subject: [PATCH 35/47] perf stat report: Add report command

Adding 'perf stat report' command support. ATM it only
processes attr events and display nothing.

Link: http://lkml.kernel.org/n/[email protected]
Signed-off-by: Jiri Olsa <[email protected]>
---
tools/perf/Documentation/perf-stat.txt | 12 ++++++++
tools/perf/builtin-stat.c | 54 +++++++++++++++++++++++++++++++---
tools/perf/util/session.c | 3 ++
3 files changed, 65 insertions(+), 4 deletions(-)

diff --git a/tools/perf/Documentation/perf-stat.txt b/tools/perf/Documentation/perf-stat.txt
index 0ccce466ad53..f7234c6263c0 100644
--- a/tools/perf/Documentation/perf-stat.txt
+++ b/tools/perf/Documentation/perf-stat.txt
@@ -11,6 +11,7 @@ SYNOPSIS
'perf stat' [-e <EVENT> | --event=EVENT] [-a] <command>
'perf stat' [-e <EVENT> | --event=EVENT] [-a] -- <command> [<options>]
'perf stat' [-e <EVENT> | --event=EVENT] [-a] record [-o file] -- <command> [<options>]
+'perf stat' report [-i file]

DESCRIPTION
-----------
@@ -26,6 +27,9 @@ OPTIONS
record::
See STAT RECORD.

+report::
+ See STAT REPORT.
+
-e::
--event=::
Select the PMU event. Selection can be:
@@ -169,6 +173,14 @@ Stores stat data into perf data file.
--output file::
Output file name.

+STAT RECORD
+-----------
+Reads and reports stat data from perf data file.
+
+-i file::
+--input file::
+Input file name.
+

EXAMPLES
--------
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index 8ad497522a0e..aa2352f92878 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -59,6 +59,8 @@
#include "util/thread.h"
#include "util/thread_map.h"
#include "util/session.h"
+#include "util/tool.h"
+#include "asm/bug.h"

#include <stdlib.h>
#include <sys/prctl.h>
@@ -138,6 +140,10 @@ static struct perf_stat_config stat_config = {
.scale = true,
};

+struct perf_stat_cmd {
+ struct perf_tool tool;
+};
+
static inline void diff_timespec(struct timespec *r, struct timespec *a,
struct timespec *b)
{
@@ -970,8 +976,8 @@ static void print_header(int argc, const char **argv)
else if (target.cpu_list)
fprintf(output, "\'CPU(s) %s", target.cpu_list);
else if (!target__has_task(&target)) {
- fprintf(output, "\'%s", argv[0]);
- for (i = 1; i < argc; i++)
+ fprintf(output, "\'%s", argv ? argv[0] : "pipe");
+ for (i = 1; argv && (i < argc); i++)
fprintf(output, " %s", argv[i]);
} else if (target.pid)
fprintf(output, "process id \'%s", target.pid);
@@ -1322,6 +1328,45 @@ static int __cmd_record(int argc, const char **argv)
return argc;
}

+static const char * const report_usage[] = {
+ "perf stat report [<options>]",
+ NULL,
+};
+
+static int __cmd_report(int argc, const char **argv)
+{
+ struct perf_session *session;
+ const struct option options[] = {
+ OPT_STRING('i', "input", &input_name, "file", "input file name"),
+ OPT_END()
+ };
+ struct perf_data_file file = {
+ .mode = PERF_DATA_MODE_READ,
+ };
+ struct perf_stat_cmd stat = {
+ .tool = {
+ .attr = perf_event__process_attr,
+ },
+ };
+ int ret;
+
+ argc = parse_options(argc, argv, options, report_usage, 0);
+
+ session = perf_session__new(&file, false, &stat.tool);
+ if (session == NULL)
+ return -1;
+
+ stat_config.output = stderr;
+ evsel_list = session->evlist;
+
+ ret = perf_session__process_events(session);
+ if (ret)
+ return ret;
+
+ perf_session__delete(session);
+ return 0;
+}
+
int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
{
bool append_file = false;
@@ -1395,7 +1440,7 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
const char *mode;
FILE *output = stderr;
unsigned int interval;
- const char * const stat_subcommands[] = { "record" };
+ const char * const stat_subcommands[] = { "record", "report" };

setlocale(LC_ALL, "");

@@ -1411,7 +1456,8 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
argc = __cmd_record(argc, argv);
if (argc < 0)
return -1;
- }
+ } else if (argc && !strncmp(argv[0], "rep", 3))
+ return __cmd_report(argc, argv);

interval = stat_config.interval;

diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index 4b957c02fffb..4fdd0458a166 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -36,6 +36,9 @@ static int perf_session__open(struct perf_session *session)
if (perf_data_file__is_pipe(file))
return 0;

+ if (perf_header__has_feat(&session->header, HEADER_STAT))
+ return 0;
+
if (!perf_evlist__valid_sample_type(session->evlist)) {
pr_err("non matching sample_type");
return -1;
--
2.4.3

2015-07-21 12:33:28

by Jiri Olsa

[permalink] [raw]
Subject: [PATCH 36/47] perf stat report: Process cpu/threads maps

Adding processing of cpu/threads maps. Configuring session's
evlist with these maps.

Link: http://lkml.kernel.org/n/[email protected]
Signed-off-by: Jiri Olsa <[email protected]>
---
tools/perf/builtin-stat.c | 59 +++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 59 insertions(+)

diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index aa2352f92878..a1a5e5b2b69c 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -142,6 +142,9 @@ static struct perf_stat_config stat_config = {

struct perf_stat_cmd {
struct perf_tool tool;
+ bool allocated;
+ struct cpu_map *cpus;
+ struct thread_map *threads;
};

static inline void diff_timespec(struct timespec *r, struct timespec *a,
@@ -1328,6 +1331,60 @@ static int __cmd_record(int argc, const char **argv)
return argc;
}

+static int set_maps(struct perf_stat_cmd *stat)
+{
+ if (!stat->cpus || !stat->threads)
+ return 0;
+
+ if (WARN_ONCE(stat->allocated, "stats double allocation\n"))
+ return -EINVAL;
+
+ if (perf_evlist__set_maps(evsel_list, stat->cpus, stat->threads) ||
+ perf_evlist__alloc_stats(evsel_list, true))
+ return -ENOMEM;
+
+ stat->allocated = true;
+ return 0;
+}
+
+static
+int process_thread_map_event(struct perf_tool *tool __maybe_unused,
+ union perf_event *event,
+ struct perf_session *session __maybe_unused)
+{
+ struct perf_stat_cmd *stat = container_of(tool, struct perf_stat_cmd, tool);
+
+ if (stat->threads) {
+ pr_warning("Extra thread map event, ignoring.\n");
+ return 0;
+ }
+
+ stat->threads = thread_map__new_event(&event->thread_map);
+ if (!stat->threads)
+ return -ENOMEM;
+
+ return set_maps(stat);
+}
+
+static
+int process_cpu_map_event(struct perf_tool *tool __maybe_unused,
+ union perf_event *event,
+ struct perf_session *session __maybe_unused)
+{
+ struct perf_stat_cmd *stat = container_of(tool, struct perf_stat_cmd, tool);
+
+ if (stat->cpus) {
+ pr_warning("Extra cpu map event, ignoring.\n");
+ return 0;
+ }
+
+ stat->cpus = cpu_map__new_event(&event->cpu_map);
+ if (!stat->cpus)
+ return -ENOMEM;
+
+ return set_maps(stat);
+}
+
static const char * const report_usage[] = {
"perf stat report [<options>]",
NULL,
@@ -1346,6 +1403,8 @@ static int __cmd_report(int argc, const char **argv)
struct perf_stat_cmd stat = {
.tool = {
.attr = perf_event__process_attr,
+ .thread_map = process_thread_map_event,
+ .cpu_map = process_cpu_map_event,
},
};
int ret;
--
2.4.3

2015-07-21 12:54:21

by Jiri Olsa

[permalink] [raw]
Subject: [PATCH 37/47] perf stat report: Process stat config event

Adding processing of stat config event and initialize
stat_config object.

Link: http://lkml.kernel.org/n/[email protected]
Signed-off-by: Jiri Olsa <[email protected]>
---
tools/perf/builtin-stat.c | 10 ++++++++++
1 file changed, 10 insertions(+)

diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index a1a5e5b2b69c..6db3c435539e 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -1331,6 +1331,15 @@ static int __cmd_record(int argc, const char **argv)
return argc;
}

+static
+int process_stat_config_event(struct perf_tool *tool __maybe_unused,
+ union perf_event *event,
+ struct perf_session *session __maybe_unused)
+{
+ perf_event__read_stat_config(&stat_config, &event->stat_config);
+ return 0;
+}
+
static int set_maps(struct perf_stat_cmd *stat)
{
if (!stat->cpus || !stat->threads)
@@ -1403,6 +1412,7 @@ static int __cmd_report(int argc, const char **argv)
struct perf_stat_cmd stat = {
.tool = {
.attr = perf_event__process_attr,
+ .stat_config = process_stat_config_event,
.thread_map = process_thread_map_event,
.cpu_map = process_cpu_map_event,
},
--
2.4.3

2015-07-21 12:33:25

by Jiri Olsa

[permalink] [raw]
Subject: [PATCH 38/47] perf stat report: Process stat and stat round events

Adding processing of stat and stat round events.

Link: http://lkml.kernel.org/n/[email protected]
Signed-off-by: Jiri Olsa <[email protected]>
---
tools/perf/builtin-stat.c | 25 +++++++++++++++++++++++++
1 file changed, 25 insertions(+)

diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index 6db3c435539e..6602323ecd43 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -1331,6 +1331,29 @@ static int __cmd_record(int argc, const char **argv)
return argc;
}

+static int process_stat_round_event(struct perf_tool *tool __maybe_unused,
+ union perf_event *event,
+ struct perf_session *session)
+{
+ struct stat_round_event *round = &event->stat_round;
+ struct perf_evsel *counter;
+ struct timespec tsh, *ts = NULL;
+ const char **argv = session->header.env.cmdline_argv;
+ int argc = session->header.env.nr_cmdline;
+
+ evlist__for_each(evsel_list, counter)
+ perf_stat_process_counter(&stat_config, counter);
+
+ if (stat_config.interval && round->time) {
+ tsh.tv_sec = round->time / NSECS_PER_SEC;
+ tsh.tv_nsec = round->time % NSECS_PER_SEC;
+ ts = &tsh;
+ }
+
+ print_counters(ts, argc, argv);
+ return 0;
+}
+
static
int process_stat_config_event(struct perf_tool *tool __maybe_unused,
union perf_event *event,
@@ -1412,6 +1435,8 @@ static int __cmd_report(int argc, const char **argv)
struct perf_stat_cmd stat = {
.tool = {
.attr = perf_event__process_attr,
+ .stat = perf_event__process_stat_event,
+ .stat_round = process_stat_round_event,
.stat_config = process_stat_config_event,
.thread_map = process_thread_map_event,
.cpu_map = process_cpu_map_event,
--
2.4.3

2015-07-21 12:36:35

by Jiri Olsa

[permalink] [raw]
Subject: [PATCH 39/47] perf stat report: Move csv_sep initialization before report command

So we have csv_sep properly initialized before
report command leg.

Link: http://lkml.kernel.org/n/[email protected]
Signed-off-by: Jiri Olsa <[email protected]>
---
tools/perf/builtin-stat.c | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index 6602323ecd43..a5c831a242a7 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -1546,6 +1546,13 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
(const char **) stat_usage,
PARSE_OPT_STOP_AT_NON_OPTION);

+ if (csv_sep) {
+ csv_output = true;
+ if (!strcmp(csv_sep, "\\t"))
+ csv_sep = "\t";
+ } else
+ csv_sep = DEFAULT_SEPARATOR;
+
if (argc && !strncmp(argv[0], "rec", 3)) {
argc = __cmd_record(argc, argv);
if (argc < 0)
@@ -1593,13 +1600,6 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)

stat_config.output = output;

- if (csv_sep) {
- csv_output = true;
- if (!strcmp(csv_sep, "\\t"))
- csv_sep = "\t";
- } else
- csv_sep = DEFAULT_SEPARATOR;
-
/*
* let the spreadsheet do the pretty-printing
*/
--
2.4.3

2015-07-21 12:36:15

by Jiri Olsa

[permalink] [raw]
Subject: [PATCH 40/47] perf script: Check output fields only for samples

There's no need to check sampling output fields
for events without perf_event_attr::sample_type
field set.

Link: http://lkml.kernel.org/n/[email protected]
Signed-off-by: Jiri Olsa <[email protected]>
---
tools/perf/builtin-script.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
index 24809787369f..308c022ae918 100644
--- a/tools/perf/builtin-script.c
+++ b/tools/perf/builtin-script.c
@@ -650,7 +650,10 @@ static int process_attr(struct perf_tool *tool, union perf_event *event,

set_print_ip_opts(&evsel->attr);

- return perf_evsel__check_attr(evsel, scr->session);
+ if (evsel->attr.sample_type)
+ err = perf_evsel__check_attr(evsel, scr->session);
+
+ return err;
}

static int process_comm_event(struct perf_tool *tool,
--
2.4.3

2015-07-21 12:35:34

by Jiri Olsa

[permalink] [raw]
Subject: [PATCH 41/47] perf script: Process cpu/threads maps

Adding processing of cpu/threads maps. Configuring session's
evlist with these maps.

Link: http://lkml.kernel.org/n/[email protected]
Signed-off-by: Jiri Olsa <[email protected]>
---
tools/perf/builtin-script.c | 65 +++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 65 insertions(+)

diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
index 308c022ae918..051177d5daed 100644
--- a/tools/perf/builtin-script.c
+++ b/tools/perf/builtin-script.c
@@ -17,7 +17,10 @@
#include "util/sort.h"
#include "util/data.h"
#include "util/auxtrace.h"
+#include "util/cpumap.h"
+#include "util/thread_map.h"
#include <linux/bitmap.h>
+#include "asm/bug.h"

static char const *script_name;
static char const *generate_script_lang;
@@ -623,6 +626,9 @@ struct perf_script {
struct perf_session *session;
bool show_task_events;
bool show_mmap_events;
+ bool allocated;
+ struct cpu_map *cpus;
+ struct thread_map *threads;
};

static int process_attr(struct perf_tool *tool, union perf_event *event,
@@ -1535,6 +1541,62 @@ static int have_cmd(int argc, const char **argv)
return 0;
}

+static int set_maps(struct perf_script *script)
+{
+ struct perf_evlist *evlist = script->session->evlist;
+
+ if (!script->cpus || !script->threads)
+ return 0;
+
+ if (WARN_ONCE(script->allocated, "stats double allocation\n"))
+ return -EINVAL;
+
+ if (perf_evlist__set_maps(evlist, script->cpus, script->threads) ||
+ perf_evlist__alloc_stats(evlist, true))
+ return -ENOMEM;
+
+ script->allocated = true;
+ return 0;
+}
+
+static
+int process_thread_map_event(struct perf_tool *tool,
+ union perf_event *event,
+ struct perf_session *session __maybe_unused)
+{
+ struct perf_script *script = container_of(tool, struct perf_script, tool);
+
+ if (script->threads) {
+ pr_warning("Extra thread map event, ignoring.\n");
+ return 0;
+ }
+
+ script->threads = thread_map__new_event(&event->thread_map);
+ if (!script->threads)
+ return -ENOMEM;
+
+ return set_maps(script);
+}
+
+static
+int process_cpu_map_event(struct perf_tool *tool __maybe_unused,
+ union perf_event *event,
+ struct perf_session *session __maybe_unused)
+{
+ struct perf_script *script = container_of(tool, struct perf_script, tool);
+
+ if (script->cpus) {
+ pr_warning("Extra cpu map event, ignoring.\n");
+ return 0;
+ }
+
+ script->cpus = cpu_map__new_event(&event->cpu_map);
+ if (!script->cpus)
+ return -ENOMEM;
+
+ return set_maps(script);
+}
+
int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
{
bool show_full_info = false;
@@ -1563,6 +1625,8 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
.auxtrace_info = perf_event__process_auxtrace_info,
.auxtrace = perf_event__process_auxtrace,
.auxtrace_error = perf_event__process_auxtrace_error,
+ .thread_map = process_thread_map_event,
+ .cpu_map = process_cpu_map_event,
.ordered_events = true,
.ordering_requires_timestamps = true,
},
@@ -1892,6 +1956,7 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
flush_scripting();

out_delete:
+ perf_evlist__free_stats(session->evlist);
perf_session__delete(session);

if (script_started)
--
2.4.3

2015-07-21 12:35:07

by Jiri Olsa

[permalink] [raw]
Subject: [PATCH 42/47] perf script: Process stat config event

Adding processing of stat config event and initialize
stat_config object.

Link: http://lkml.kernel.org/n/[email protected]
Signed-off-by: Jiri Olsa <[email protected]>
---
tools/perf/builtin-script.c | 11 +++++++++++
1 file changed, 11 insertions(+)

diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
index 051177d5daed..b64e4cdc29e2 100644
--- a/tools/perf/builtin-script.c
+++ b/tools/perf/builtin-script.c
@@ -19,6 +19,7 @@
#include "util/auxtrace.h"
#include "util/cpumap.h"
#include "util/thread_map.h"
+#include "util/stat.h"
#include <linux/bitmap.h>
#include "asm/bug.h"

@@ -33,6 +34,7 @@ static bool system_wide;
static bool print_flags;
static const char *cpu_list;
static DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS);
+static struct perf_stat_config stat_config;

enum perf_output_field {
PERF_OUTPUT_COMM = 1U << 0,
@@ -1541,6 +1543,14 @@ static int have_cmd(int argc, const char **argv)
return 0;
}

+static int process_stat_config_event(struct perf_tool *tool __maybe_unused,
+ union perf_event *event,
+ struct perf_session *session __maybe_unused)
+{
+ perf_event__read_stat_config(&stat_config, &event->stat_config);
+ return 0;
+}
+
static int set_maps(struct perf_script *script)
{
struct perf_evlist *evlist = script->session->evlist;
@@ -1625,6 +1635,7 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
.auxtrace_info = perf_event__process_auxtrace_info,
.auxtrace = perf_event__process_auxtrace,
.auxtrace_error = perf_event__process_auxtrace_error,
+ .stat_config = process_stat_config_event,
.thread_map = process_thread_map_event,
.cpu_map = process_cpu_map_event,
.ordered_events = true,
--
2.4.3

2015-07-21 12:33:33

by Jiri Olsa

[permalink] [raw]
Subject: [PATCH 43/47] perf script: Add process_stat/process_stat_interval scripting interface

Python and perl scripting code will define those
callbacks and get stat data.

Link: http://lkml.kernel.org/n/[email protected]
Signed-off-by: Jiri Olsa <[email protected]>
---
tools/perf/util/trace-event.h | 4 ++++
1 file changed, 4 insertions(+)

diff --git a/tools/perf/util/trace-event.h b/tools/perf/util/trace-event.h
index d5168f0be4ec..d84147deae58 100644
--- a/tools/perf/util/trace-event.h
+++ b/tools/perf/util/trace-event.h
@@ -63,6 +63,7 @@ int tracing_data_put(struct tracing_data *tdata);
struct addr_location;

struct perf_session;
+struct perf_stat_config;

struct scripting_ops {
const char *name;
@@ -73,6 +74,9 @@ struct scripting_ops {
struct perf_sample *sample,
struct perf_evsel *evsel,
struct addr_location *al);
+ void (*process_stat) (struct perf_stat_config *config,
+ struct perf_evsel *evsel, u64 time);
+ void (*process_stat_interval) (u64 time);
int (*generate_script) (struct pevent *pevent, const char *outfile);
};

--
2.4.3

2015-07-21 12:33:35

by Jiri Olsa

[permalink] [raw]
Subject: [PATCH 44/47] perf script: Add stat default handlers

Implement struct scripting_ops::(process_stat|process_stat_interval)
handlers - calling scripting handlers from stat events handlers.

Link: http://lkml.kernel.org/n/[email protected]
Signed-off-by: Jiri Olsa <[email protected]>
---
tools/perf/builtin-script.c | 31 +++++++++++++++++++++++++++++++
1 file changed, 31 insertions(+)

diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
index b64e4cdc29e2..9171c53f504f 100644
--- a/tools/perf/builtin-script.c
+++ b/tools/perf/builtin-script.c
@@ -199,6 +199,9 @@ static int perf_evsel__check_attr(struct perf_evsel *evsel,
struct perf_event_attr *attr = &evsel->attr;
bool allow_user_set;

+ if (perf_header__has_feat(&session->header, HEADER_STAT))
+ return 0;
+
allow_user_set = perf_header__has_feat(&session->header,
HEADER_AUXTRACE);

@@ -533,6 +536,14 @@ static void process_event(union perf_event *event, struct perf_sample *sample,
printf("\n");
}

+static void process_stat(struct perf_stat_config *config __maybe_unused,
+ struct perf_evsel *evsel __maybe_unused,
+ u64 time __maybe_unused)
+{
+}
+
+static void process_stat_interval(u64 time __maybe_unused) { }
+
static int default_start_script(const char *script __maybe_unused,
int argc __maybe_unused,
const char **argv __maybe_unused)
@@ -561,6 +572,8 @@ static struct scripting_ops default_scripting_ops = {
.flush_script = default_flush_script,
.stop_script = default_stop_script,
.process_event = process_event,
+ .process_stat = process_stat,
+ .process_stat_interval = process_stat_interval,
.generate_script = default_generate_script,
};

@@ -1543,6 +1556,22 @@ static int have_cmd(int argc, const char **argv)
return 0;
}

+static int process_stat_round_event(struct perf_tool *tool __maybe_unused,
+ union perf_event *event,
+ struct perf_session *session)
+{
+ struct stat_round_event *round = &event->stat_round;
+ struct perf_evsel *counter;
+
+ evlist__for_each(session->evlist, counter) {
+ perf_stat_process_counter(&stat_config, counter);
+ scripting_ops->process_stat(&stat_config, counter, round->time);
+ }
+
+ scripting_ops->process_stat_interval(round->time);
+ return 0;
+}
+
static int process_stat_config_event(struct perf_tool *tool __maybe_unused,
union perf_event *event,
struct perf_session *session __maybe_unused)
@@ -1635,6 +1664,8 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
.auxtrace_info = perf_event__process_auxtrace_info,
.auxtrace = perf_event__process_auxtrace,
.auxtrace_error = perf_event__process_auxtrace_error,
+ .stat = perf_event__process_stat_event,
+ .stat_round = process_stat_round_event,
.stat_config = process_stat_config_event,
.thread_map = process_thread_map_event,
.cpu_map = process_cpu_map_event,
--
2.4.3

2015-07-21 12:34:34

by Jiri Olsa

[permalink] [raw]
Subject: [PATCH 45/47] perf script: Display stat events by default

If no script is specified for stat data, display
stat events in raw form.

Link: http://lkml.kernel.org/n/[email protected]
Signed-off-by: Jiri Olsa <[email protected]>
---
tools/perf/builtin-script.c | 35 +++++++++++++++++++++++++++++++++--
1 file changed, 33 insertions(+), 2 deletions(-)

diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
index 9171c53f504f..e3f781a400b9 100644
--- a/tools/perf/builtin-script.c
+++ b/tools/perf/builtin-script.c
@@ -537,9 +537,40 @@ static void process_event(union perf_event *event, struct perf_sample *sample,
}

static void process_stat(struct perf_stat_config *config __maybe_unused,
- struct perf_evsel *evsel __maybe_unused,
- u64 time __maybe_unused)
+ struct perf_evsel *counter, u64 time)
{
+ int nthreads = thread_map__nr(counter->threads);
+ int ncpus = perf_evsel__nr_cpus(counter);
+ int cpu, thread;
+ static int header_printed;
+
+ if (counter->system_wide)
+ nthreads = 1;
+
+ if (!header_printed) {
+ printf("%3s %8s %15s %15s %15s %15s %s\n",
+ "CPU", "THREAD", "VAL", "ENA", "RUN", "TIME", "EVENT");
+ header_printed = 1;
+ }
+
+ for (thread = 0; thread < nthreads; thread++) {
+ for (cpu = 0; cpu < ncpus; cpu++) {
+ struct perf_counts_values *counts;
+
+ counts = perf_counts(counter->counts, cpu, thread);
+
+ printf("%3d %8d %15" PRIu64 " %15" PRIu64 " %15" PRIu64 " %15" PRIu64 " %s\n",
+ counter->cpus->map[cpu],
+ thread_map__pid(counter->threads, thread),
+ counts->val,
+ counts->ena,
+ counts->run,
+ time,
+ perf_evsel__name(counter));
+ }
+ }
+
+ return;
}

static void process_stat_interval(u64 time __maybe_unused) { }
--
2.4.3

2015-07-21 12:33:56

by Jiri Olsa

[permalink] [raw]
Subject: [PATCH 46/47] perf script: Add python support for stat events

Add support to get stat events data in perf python scripts.

Link: http://lkml.kernel.org/n/[email protected]
Signed-off-by: Jiri Olsa <[email protected]>
---
.../util/scripting-engines/trace-event-python.c | 113 +++++++++++++++++++--
1 file changed, 107 insertions(+), 6 deletions(-)

diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c
index ace2484985cb..2e771ede9428 100644
--- a/tools/perf/util/scripting-engines/trace-event-python.c
+++ b/tools/perf/util/scripting-engines/trace-event-python.c
@@ -41,6 +41,8 @@
#include "../thread-stack.h"
#include "../trace-event.h"
#include "../machine.h"
+#include "thread_map.h"
+#include "cpumap.h"

PyMODINIT_FUNC initperf_trace_context(void);

@@ -858,6 +860,103 @@ static void python_process_event(union perf_event *event,
}
}

+static void get_handler_name(char *str, size_t size,
+ struct perf_evsel *evsel)
+{
+ char *p = str;
+
+ scnprintf(str, size, "stat__%s", perf_evsel__name(evsel));
+
+ while ((p = strchr(p, ':'))) {
+ *p = '_';
+ p++;
+ }
+}
+
+static void
+process_stat(struct perf_evsel *counter, int cpu, int thread, u64 time,
+ struct perf_counts_values *count)
+{
+ PyObject *handler, *t;
+ static char handler_name[256];
+ int n = 0;
+
+ t = PyTuple_New(MAX_FIELDS);
+ if (!t)
+ Py_FatalError("couldn't create Python tuple");
+
+ get_handler_name(handler_name, sizeof(handler_name),
+ counter);
+
+ handler = get_handler(handler_name);
+ if (!handler) {
+ pr_debug("can't find python handler %s\n", handler_name);
+ return;
+ }
+
+ PyTuple_SetItem(t, n++, PyInt_FromLong(cpu));
+ PyTuple_SetItem(t, n++, PyInt_FromLong(thread));
+ PyTuple_SetItem(t, n++, PyLong_FromLong(time));
+ PyTuple_SetItem(t, n++, PyLong_FromLong(count->val));
+ PyTuple_SetItem(t, n++, PyLong_FromLong(count->ena));
+ PyTuple_SetItem(t, n++, PyLong_FromLong(count->run));
+
+ if (_PyTuple_Resize(&t, n) == -1)
+ Py_FatalError("error resizing Python tuple");
+
+ call_object(handler, t, handler_name);
+
+ Py_DECREF(t);
+}
+
+static void python_process_stat(struct perf_stat_config *config,
+ struct perf_evsel *counter, u64 time)
+{
+ struct thread_map *threads = counter->threads;
+ struct cpu_map *cpus = counter->cpus;
+ int cpu, thread;
+
+ if (config->aggr_mode == AGGR_GLOBAL) {
+ process_stat(counter, -1, -1, time,
+ &counter->counts->aggr);
+ return;
+ }
+
+ for (thread = 0; thread < threads->nr; thread++) {
+ for (cpu = 0; cpu < cpus->nr; cpu++) {
+ process_stat(counter, cpus->map[cpu],
+ thread_map__pid(threads, thread), time,
+ perf_counts(counter->counts, cpu, thread));
+ }
+ }
+}
+
+static void python_process_stat_interval(u64 time)
+{
+ PyObject *handler, *t;
+ static const char handler_name[] = "stat__interval";
+ int n = 0;
+
+ t = PyTuple_New(MAX_FIELDS);
+ if (!t)
+ Py_FatalError("couldn't create Python tuple");
+
+ handler = get_handler(handler_name);
+ if (!handler) {
+ pr_debug("can't find python handler %s\n", handler_name);
+ return;
+ }
+
+ PyTuple_SetItem(t, n++, PyLong_FromLong(time));
+
+ if (_PyTuple_Resize(&t, n) == -1)
+ Py_FatalError("error resizing Python tuple");
+
+ call_object(handler, t, handler_name);
+
+ Py_DECREF(t);
+}
+
static int run_start_sub(void)
{
main_module = PyImport_AddModule("__main__");
@@ -1200,10 +1299,12 @@ static int python_generate_script(struct pevent *pevent, const char *outfile)
}

struct scripting_ops python_scripting_ops = {
- .name = "Python",
- .start_script = python_start_script,
- .flush_script = python_flush_script,
- .stop_script = python_stop_script,
- .process_event = python_process_event,
- .generate_script = python_generate_script,
+ .name = "Python",
+ .start_script = python_start_script,
+ .flush_script = python_flush_script,
+ .stop_script = python_stop_script,
+ .process_event = python_process_event,
+ .process_stat = python_process_stat,
+ .process_stat_interval = python_process_stat_interval,
+ .generate_script = python_generate_script,
};
--
2.4.3

2015-07-21 12:33:38

by Jiri Olsa

[permalink] [raw]
Subject: [PATCH 47/47] perf script: Add stat-cpi.py script

Link: http://lkml.kernel.org/n/[email protected]
Signed-off-by: Jiri Olsa <[email protected]>
---
tools/perf/scripts/python/stat-cpi.py | 74 +++++++++++++++++++++++++++++++++++
1 file changed, 74 insertions(+)
create mode 100644 tools/perf/scripts/python/stat-cpi.py

diff --git a/tools/perf/scripts/python/stat-cpi.py b/tools/perf/scripts/python/stat-cpi.py
new file mode 100644
index 000000000000..eb3936e99862
--- /dev/null
+++ b/tools/perf/scripts/python/stat-cpi.py
@@ -0,0 +1,74 @@
+#!/bin/python
+
+data = {}
+times = []
+threads = []
+cpus = []
+
+def get_key(time, event, cpu, thread):
+ return "%d-%s-%d-%d" % (time, event, cpu, thread)
+
+def store_key(time, cpu, thread):
+ if (time not in times):
+ times.append(time)
+
+ if (cpu not in cpus):
+ cpus.append(cpu)
+
+ if (thread not in threads):
+ threads.append(thread)
+
+def store(time, event, cpu, thread, val, ena, run):
+ #print "event %s cpu %d, thread %d, time %d, val %d, ena %d, run %d" % \
+ # (event, cpu, thread, time, val, ena, run)
+
+ store_key(time, cpu, thread)
+ key = get_key(time, event, cpu, thread)
+ data[key] = [ val, ena, run]
+
+def get(time, event, cpu, thread):
+ key = get_key(time, event, cpu, thread)
+ return data[key][0]
+
+def stat__cycles_k(cpu, thread, time, val, ena, run):
+ store(time, "cycles", cpu, thread, val, ena, run);
+
+def stat__instructions_k(cpu, thread, time, val, ena, run):
+ store(time, "instructions", cpu, thread, val, ena, run);
+
+def stat__cycles_u(cpu, thread, time, val, ena, run):
+ store(time, "cycles", cpu, thread, val, ena, run);
+
+def stat__instructions_u(cpu, thread, time, val, ena, run):
+ store(time, "instructions", cpu, thread, val, ena, run);
+
+def stat__cycles(cpu, thread, time, val, ena, run):
+ store(time, "cycles", cpu, thread, val, ena, run);
+
+def stat__instructions(cpu, thread, time, val, ena, run):
+ store(time, "instructions", cpu, thread, val, ena, run);
+
+def stat__interval(time):
+ for cpu in cpus:
+ for thread in threads:
+ cyc = get(time, "cycles", cpu, thread)
+ ins = get(time, "instructions", cpu, thread)
+ cpi = 0
+
+ if ins != 0:
+ cpi = cyc/float(ins)
+
+ print "%15f: cpu %d, thread %d -> cpi %f (%d/%d)" % (time/(float(1000000000)), cpu, thread, cpi, cyc, ins)
+
+def trace_end():
+ pass
+# for time in times:
+# for cpu in cpus:
+# for thread in threads:
+# cyc = get(time, "cycles", cpu, thread)
+# ins = get(time, "instructions", cpu, thread)
+#
+# if ins != 0:
+# cpi = cyc/float(ins)
+#
+# print "time %.9f, cpu %d, thread %d -> cpi %f" % (time/(float(1000000000)), cpu, thread, cpi)
--
2.4.3

2015-07-21 14:43:18

by Andi Kleen

[permalink] [raw]
Subject: Re: [RFC 00/47] perf stat: Add scripting support

On Tue, Jul 21, 2015 at 02:31:20PM +0200, Jiri Olsa wrote:
> hi,
> sending RFC on another attempt for stat scripting.
>
> The initial attempt defined its own formula lang and allowed
> triggering user's script on the end of the stat command:
> http://marc.info/?l=linux-kernel&m=136742146322273&w=2
>
> This patchset abandons the idea of new formula language
> and rather adds support to:
> - store stat data into perf.data file
> - add python support to process stat events
>
> Basically it allows to store stat data into perf.data and
> post process it with python scripts in a similar way we
> do for sampling data.

I suspect there is some overlap with Kan's patchkit to put
uncore data into perf.data too.

The basic direction seems good just from reading the intro
(haven't read the code so far). I've been thinking about
doing something similar to do native topdown support in perf.
This would require evaluating formulas which are depending
on the CPU.

-Andi

2015-07-21 17:24:28

by Arnaldo Carvalho de Melo

[permalink] [raw]
Subject: Re: [PATCH 02/47] perf stat: Introduce struct perf_stat_config

Em Tue, Jul 21, 2015 at 02:31:22PM +0200, Jiri Olsa escreveu:
> Moving aggr_mode into new struct. The point is to centralize
> the base stat config so it could be used localy together with
> other stat routines in other parts of perf code.

Why not use 'struct perf_stat' for that? It is already there and is
supposed to hold the stat tool internal state. Yeah, lots of those
globals should go there as well, just like we have the 'perf_sched',
'perf_top', 'perf_script', etc structs.

- Arnaldo


> Link: http://lkml.kernel.org/n/[email protected]
> Signed-off-by: Jiri Olsa <[email protected]>
> ---
> tools/perf/builtin-stat.c | 39 ++++++++++++++++++++++-----------------
> tools/perf/util/stat.h | 4 ++++
> 2 files changed, 26 insertions(+), 17 deletions(-)
>
> diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
> index d99d850e1444..bafb830b1bd9 100644
> --- a/tools/perf/builtin-stat.c
> +++ b/tools/perf/builtin-stat.c
> @@ -102,7 +102,6 @@ static struct target target = {
> static int run_count = 1;
> static bool no_inherit = false;
> static bool scale = true;
> -static enum aggr_mode aggr_mode = AGGR_GLOBAL;
> static volatile pid_t child_pid = -1;
> static bool null_run = false;
> static int detailed_run = 0;
> @@ -126,6 +125,10 @@ static int (*aggr_get_id)(struct cpu_map *m, int cpu);
>
> static volatile int done = 0;
>
> +static struct perf_stat_config stat_config = {
> + .aggr_mode = AGGR_GLOBAL,
> +};
> +
> static inline void diff_timespec(struct timespec *r, struct timespec *a,
> struct timespec *b)
> {
> @@ -230,7 +233,7 @@ process_counter_values(struct perf_evsel *evsel, int cpu, int thread,
> if (skip)
> count = &zero;
>
> - switch (aggr_mode) {
> + switch (stat_config.aggr_mode) {
> case AGGR_THREAD:
> case AGGR_CORE:
> case AGGR_SOCKET:
> @@ -238,7 +241,7 @@ process_counter_values(struct perf_evsel *evsel, int cpu, int thread,
> if (!evsel->snapshot)
> perf_evsel__compute_deltas(evsel, cpu, thread, count);
> perf_counts_values__scale(count, scale, NULL);
> - if (aggr_mode == AGGR_NONE)
> + if (stat_config.aggr_mode == AGGR_NONE)
> perf_stat__update_shadow_stats(evsel, count->values, cpu);
> break;
> case AGGR_GLOBAL:
> @@ -291,7 +294,7 @@ static int process_counter(struct perf_evsel *counter)
> if (ret)
> return ret;
>
> - if (aggr_mode != AGGR_GLOBAL)
> + if (stat_config.aggr_mode != AGGR_GLOBAL)
> return 0;
>
> if (!counter->snapshot)
> @@ -578,7 +581,7 @@ static void print_noise(struct perf_evsel *evsel, double avg)
>
> static void aggr_printout(struct perf_evsel *evsel, int id, int nr)
> {
> - switch (aggr_mode) {
> + switch (stat_config.aggr_mode) {
> case AGGR_CORE:
> fprintf(output, "S%d-C%*d%s%*d%s",
> cpu_map__id_to_socket(id),
> @@ -670,7 +673,7 @@ static void abs_printout(int id, int nr, struct perf_evsel *evsel, double avg)
>
> aggr_printout(evsel, id, nr);
>
> - if (aggr_mode == AGGR_GLOBAL)
> + if (stat_config.aggr_mode == AGGR_GLOBAL)
> cpu = 0;
>
> fprintf(output, fmt, avg, csv_sep);
> @@ -688,7 +691,8 @@ static void abs_printout(int id, int nr, struct perf_evsel *evsel, double avg)
> if (csv_output || interval)
> return;
>
> - perf_stat__print_shadow_stats(output, evsel, avg, cpu, aggr_mode);
> + perf_stat__print_shadow_stats(output, evsel, avg, cpu,
> + stat_config.aggr_mode);
> }
>
> static void print_aggr(char *prefix)
> @@ -909,7 +913,7 @@ static void print_interval(char *prefix, struct timespec *ts)
> sprintf(prefix, "%6lu.%09lu%s", ts->tv_sec, ts->tv_nsec, csv_sep);
>
> if (num_print_interval == 0 && !csv_output) {
> - switch (aggr_mode) {
> + switch (stat_config.aggr_mode) {
> case AGGR_SOCKET:
> fprintf(output, "# time socket cpus counts %*s events\n", unit_width, "unit");
> break;
> @@ -985,7 +989,7 @@ static void print_counters(struct timespec *ts, int argc, const char **argv)
> else
> print_header(argc, argv);
>
> - switch (aggr_mode) {
> + switch (stat_config.aggr_mode) {
> case AGGR_CORE:
> case AGGR_SOCKET:
> print_aggr(prefix);
> @@ -1064,7 +1068,7 @@ static int stat__set_big_num(const struct option *opt __maybe_unused,
>
> static int perf_stat_init_aggr_mode(void)
> {
> - switch (aggr_mode) {
> + switch (stat_config.aggr_mode) {
> case AGGR_SOCKET:
> if (cpu_map__build_socket_map(evsel_list->cpus, &aggr_map)) {
> perror("cannot build socket map");
> @@ -1286,7 +1290,7 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
> stat__set_big_num),
> OPT_STRING('C', "cpu", &target.cpu_list, "cpu",
> "list of cpus to monitor in system-wide"),
> - OPT_SET_UINT('A', "no-aggr", &aggr_mode,
> + OPT_SET_UINT('A', "no-aggr", &stat_config.aggr_mode,
> "disable CPU count aggregation", AGGR_NONE),
> OPT_STRING('x', "field-separator", &csv_sep, "separator",
> "print counts with custom separator"),
> @@ -1302,11 +1306,11 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
> "command to run after to the measured command"),
> OPT_UINTEGER('I', "interval-print", &interval,
> "print counts at regular interval in ms (>= 100)"),
> - OPT_SET_UINT(0, "per-socket", &aggr_mode,
> + OPT_SET_UINT(0, "per-socket", &stat_config.aggr_mode,
> "aggregate counts per processor socket", AGGR_SOCKET),
> - OPT_SET_UINT(0, "per-core", &aggr_mode,
> + OPT_SET_UINT(0, "per-core", &stat_config.aggr_mode,
> "aggregate counts per physical processor core", AGGR_CORE),
> - OPT_SET_UINT(0, "per-thread", &aggr_mode,
> + OPT_SET_UINT(0, "per-thread", &stat_config.aggr_mode,
> "aggregate counts per thread", AGGR_THREAD),
> OPT_UINTEGER('D', "delay", &initial_delay,
> "ms to wait before starting measurement after program start"),
> @@ -1399,7 +1403,7 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
> run_count = 1;
> }
>
> - if ((aggr_mode == AGGR_THREAD) && !target__has_task(&target)) {
> + if ((stat_config.aggr_mode == AGGR_THREAD) && !target__has_task(&target)) {
> fprintf(stderr, "The --per-thread option is only available "
> "when monitoring via -p -t options.\n");
> parse_options_usage(NULL, options, "p", 1);
> @@ -1411,7 +1415,8 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
> * no_aggr, cgroup are for system-wide only
> * --per-thread is aggregated per thread, we dont mix it with cpu mode
> */
> - if (((aggr_mode != AGGR_GLOBAL && aggr_mode != AGGR_THREAD) || nr_cgroups) &&
> + if (((stat_config.aggr_mode != AGGR_GLOBAL &&
> + stat_config.aggr_mode != AGGR_THREAD) || nr_cgroups) &&
> !target__has_cpu(&target)) {
> fprintf(stderr, "both cgroup and no-aggregation "
> "modes only available in system-wide mode\n");
> @@ -1444,7 +1449,7 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
> * Initialize thread_map with comm names,
> * so we could print it out on output.
> */
> - if (aggr_mode == AGGR_THREAD)
> + if (stat_config.aggr_mode == AGGR_THREAD)
> thread_map__read_comms(evsel_list->threads);
>
> if (interval && interval < 100) {
> diff --git a/tools/perf/util/stat.h b/tools/perf/util/stat.h
> index 1cfbe0a980ac..078bee49ccad 100644
> --- a/tools/perf/util/stat.h
> +++ b/tools/perf/util/stat.h
> @@ -50,6 +50,10 @@ struct perf_counts {
> struct xyarray *values;
> };
>
> +struct perf_stat_config {
> + enum aggr_mode aggr_mode;
> +};
> +
> static inline struct perf_counts_values*
> perf_counts(struct perf_counts *counts, int cpu, int thread)
> {
> --
> 2.4.3

2015-07-21 17:25:47

by Arnaldo Carvalho de Melo

[permalink] [raw]
Subject: Re: [PATCH 10/47] perf tools: Force perf_evlist__set_maps to propagate maps through events

Em Tue, Jul 21, 2015 at 02:31:30PM +0200, Jiri Olsa escreveu:
> Forcing perf_evlist__set_maps to propagate maps through events,
> so cpu/thread maps get set within evlist.

Applied

> Link: http://lkml.kernel.org/n/[email protected]
> Signed-off-by: Jiri Olsa <[email protected]>
> ---
> tools/perf/util/evlist.c | 17 +++++++++++++++++
> tools/perf/util/evlist.h | 11 +++--------
> 2 files changed, 20 insertions(+), 8 deletions(-)
>
> diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
> index f1714bedd5de..3b9f411a6b46 100644
> --- a/tools/perf/util/evlist.c
> +++ b/tools/perf/util/evlist.c
> @@ -1151,6 +1151,23 @@ out_delete_threads:
> return -1;
> }
>
> +int perf_evlist__set_maps(struct perf_evlist *evlist,
> + struct cpu_map *cpus,
> + struct thread_map *threads)
> +{
> + if (evlist->cpus)
> + cpu_map__put(evlist->cpus);
> +
> + evlist->cpus = cpus;
> +
> + if (evlist->threads)
> + thread_map__put(evlist->threads);
> +
> + evlist->threads = threads;
> +
> + return perf_evlist__propagate_maps(evlist, false);
> +}
> +
> int perf_evlist__apply_filters(struct perf_evlist *evlist, struct perf_evsel **err_evsel)
> {
> struct perf_evsel *evsel;
> diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h
> index 037633c1da9d..406a8216a51e 100644
> --- a/tools/perf/util/evlist.h
> +++ b/tools/perf/util/evlist.h
> @@ -152,14 +152,9 @@ int perf_evlist__enable_event_idx(struct perf_evlist *evlist,
> void perf_evlist__set_selected(struct perf_evlist *evlist,
> struct perf_evsel *evsel);
>
> -static inline void perf_evlist__set_maps(struct perf_evlist *evlist,
> - struct cpu_map *cpus,
> - struct thread_map *threads)
> -{
> - evlist->cpus = cpus;
> - evlist->threads = threads;
> -}
> -
> +int perf_evlist__set_maps(struct perf_evlist *evlist,
> + struct cpu_map *cpus,
> + struct thread_map *threads);
> int perf_evlist__create_maps(struct perf_evlist *evlist, struct target *target);
> int perf_evlist__apply_filters(struct perf_evlist *evlist, struct perf_evsel **err_evsel);
>
> --
> 2.4.3

2015-07-21 17:26:22

by Arnaldo Carvalho de Melo

[permalink] [raw]
Subject: Re: [PATCH 01/47] perf test: Check for refcnt in thread_map test

Em Tue, Jul 21, 2015 at 02:31:21PM +0200, Jiri Olsa escreveu:
> Checking also for refcnt in thread_map test.

Applied.

> Link: http://lkml.kernel.org/n/[email protected]
> Signed-off-by: Jiri Olsa <[email protected]>
> ---
> tools/perf/tests/thread-map.c | 4 ++++
> 1 file changed, 4 insertions(+)
>
> diff --git a/tools/perf/tests/thread-map.c b/tools/perf/tests/thread-map.c
> index 5acf000939ea..138a0e3431fa 100644
> --- a/tools/perf/tests/thread-map.c
> +++ b/tools/perf/tests/thread-map.c
> @@ -20,6 +20,8 @@ int test__thread_map(void)
> TEST_ASSERT_VAL("wrong comm",
> thread_map__comm(map, 0) &&
> !strcmp(thread_map__comm(map, 0), "perf"));
> + TEST_ASSERT_VAL("wrong refcnt",
> + atomic_read(&map->refcnt) == 1);
> thread_map__put(map);
>
> /* test dummy pid */
> @@ -33,6 +35,8 @@ int test__thread_map(void)
> TEST_ASSERT_VAL("wrong comm",
> thread_map__comm(map, 0) &&
> !strcmp(thread_map__comm(map, 0), "dummy"));
> + TEST_ASSERT_VAL("wrong refcnt",
> + atomic_read(&map->refcnt) == 1);
> thread_map__put(map);
> return 0;
> }
> --
> 2.4.3

2015-07-21 17:29:29

by Arnaldo Carvalho de Melo

[permalink] [raw]
Subject: Re: [PATCH 11/47] perf tools: Use argv style storage for cmdline feature data

Em Tue, Jul 21, 2015 at 02:31:31PM +0200, Jiri Olsa escreveu:
> We will reuse argv style data in following change to display
> counters header showing monitored command line.

Applied

> Link: http://lkml.kernel.org/n/[email protected]
> Signed-off-by: Jiri Olsa <[email protected]>
> ---
> tools/perf/util/header.c | 35 ++++++++++++++++++++---------------
> tools/perf/util/header.h | 1 +
> tools/perf/util/session.c | 1 +
> 3 files changed, 22 insertions(+), 15 deletions(-)
>
> diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
> index 03ace57a800c..179b2bdd157d 100644
> --- a/tools/perf/util/header.c
> +++ b/tools/perf/util/header.c
> @@ -923,17 +923,13 @@ static void print_cmdline(struct perf_header *ph, int fd __maybe_unused,
> FILE *fp)
> {
> int nr, i;
> - char *str;
>
> nr = ph->env.nr_cmdline;
> - str = ph->env.cmdline;
>
> fprintf(fp, "# cmdline : ");
>
> - for (i = 0; i < nr; i++) {
> - fprintf(fp, "%s ", str);
> - str += strlen(str) + 1;
> - }
> + for (i = 0; i < nr; i++)
> + fprintf(fp, "%s ", ph->env.cmdline_argv[i]);
> fputc('\n', fp);
> }
>
> @@ -1541,14 +1537,13 @@ process_event_desc(struct perf_file_section *section __maybe_unused,
> return 0;
> }
>
> -static int process_cmdline(struct perf_file_section *section __maybe_unused,
> +static int process_cmdline(struct perf_file_section *section,
> struct perf_header *ph, int fd,
> void *data __maybe_unused)
> {
> ssize_t ret;
> - char *str;
> - u32 nr, i;
> - struct strbuf sb;
> + char *str, *cmdline = NULL, **argv = NULL;
> + u32 nr, i, len = 0;
>
> ret = readn(fd, &nr, sizeof(nr));
> if (ret != sizeof(nr))
> @@ -1558,22 +1553,32 @@ static int process_cmdline(struct perf_file_section *section __maybe_unused,
> nr = bswap_32(nr);
>
> ph->env.nr_cmdline = nr;
> - strbuf_init(&sb, 128);
> +
> + cmdline = zalloc(section->size + nr + 1);
> + if (!cmdline)
> + return -1;
> +
> + argv = zalloc(sizeof(char *) * (nr + 1));
> + if (!argv)
> + goto error;
>
> for (i = 0; i < nr; i++) {
> str = do_read_string(fd, ph);
> if (!str)
> goto error;
>
> - /* include a NULL character at the end */
> - strbuf_add(&sb, str, strlen(str) + 1);
> + argv[i] = cmdline + len;
> + memcpy(argv[i], str, strlen(str) + 1);
> + len += strlen(str) + 1;
> free(str);
> }
> - ph->env.cmdline = strbuf_detach(&sb, NULL);
> + ph->env.cmdline = cmdline;
> + ph->env.cmdline_argv = (const char **) argv;
> return 0;
>
> error:
> - strbuf_release(&sb);
> + free(argv);
> + free(cmdline);
> return -1;
> }
>
> diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
> index d4d57962c591..9b53b6525ce8 100644
> --- a/tools/perf/util/header.h
> +++ b/tools/perf/util/header.h
> @@ -84,6 +84,7 @@ struct perf_session_env {
> int nr_pmu_mappings;
> int nr_groups;
> char *cmdline;
> + const char **cmdline_argv;
> char *sibling_cores;
> char *sibling_threads;
> char *numa_nodes;
> diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
> index ed9dc2555ec7..fb1d525ca3d0 100644
> --- a/tools/perf/util/session.c
> +++ b/tools/perf/util/session.c
> @@ -180,6 +180,7 @@ static void perf_session_env__delete(struct perf_session_env *env)
> zfree(&env->cpuid);
>
> zfree(&env->cmdline);
> + zfree(&env->cmdline_argv);
> zfree(&env->sibling_cores);
> zfree(&env->sibling_threads);
> zfree(&env->numa_nodes);
> --
> 2.4.3

2015-07-21 17:31:30

by Arnaldo Carvalho de Melo

[permalink] [raw]
Subject: Re: [PATCH 09/47] perf tools: Tolerate NULL maps in perf_evlist__propagate_maps

Em Tue, Jul 21, 2015 at 02:31:29PM +0200, Jiri Olsa escreveu:
> Tolerating NULL maps in perf_evlist__propagate_maps,
> so we dont need to pass evlist with both cpus and threads
> maps defined.

Applied

> Link: http://lkml.kernel.org/n/[email protected]
> Signed-off-by: Jiri Olsa <[email protected]>
> ---
> tools/perf/util/evlist.c | 3 ++-
> 1 file changed, 2 insertions(+), 1 deletion(-)
>
> diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
> index 63bc24dbf03b..f1714bedd5de 100644
> --- a/tools/perf/util/evlist.c
> +++ b/tools/perf/util/evlist.c
> @@ -1119,7 +1119,8 @@ static int perf_evlist__propagate_maps(struct perf_evlist *evlist,
>
> evsel->threads = thread_map__get(evlist->threads);
>
> - if (!evsel->cpus || !evsel->threads)
> + if ((evlist->cpus && !evsel->cpus) ||
> + (evlist->threads && !evsel->threads))
> return -ENOMEM;
> }
>
> --
> 2.4.3

2015-07-21 17:37:34

by Arnaldo Carvalho de Melo

[permalink] [raw]
Subject: Re: [PATCH 02/47] perf stat: Introduce struct perf_stat_config

Em Tue, Jul 21, 2015 at 02:24:19PM -0300, Arnaldo Carvalho de Melo escreveu:
> Em Tue, Jul 21, 2015 at 02:31:22PM +0200, Jiri Olsa escreveu:
> > Moving aggr_mode into new struct. The point is to centralize
> > the base stat config so it could be used localy together with
> > other stat routines in other parts of perf code.
>
> Why not use 'struct perf_stat' for that? It is already there and is
> supposed to hold the stat tool internal state. Yeah, lots of those
> globals should go there as well, just like we have the 'perf_sched',
> 'perf_top', 'perf_script',y etc structs.

Erm, saw some more patches, this stuff gets marshalled into perf.data,
continuing to read... Probably you made this somehow extensible...

- Arnaldo

2015-07-22 08:39:40

by Jiri Olsa

[permalink] [raw]
Subject: Re: [PATCH 02/47] perf stat: Introduce struct perf_stat_config

On Tue, Jul 21, 2015 at 02:37:26PM -0300, Arnaldo Carvalho de Melo wrote:
> Em Tue, Jul 21, 2015 at 02:24:19PM -0300, Arnaldo Carvalho de Melo escreveu:
> > Em Tue, Jul 21, 2015 at 02:31:22PM +0200, Jiri Olsa escreveu:
> > > Moving aggr_mode into new struct. The point is to centralize
> > > the base stat config so it could be used localy together with
> > > other stat routines in other parts of perf code.
> >
> > Why not use 'struct perf_stat' for that? It is already there and is
> > supposed to hold the stat tool internal state. Yeah, lots of those
> > globals should go there as well, just like we have the 'perf_sched',
> > 'perf_top', 'perf_script',y etc structs.

hm, but it's used as perf_evsel priv data..

the 'struct perf_stat_config' is coupled with the same event,
we could switch the name for:

'struct perf_stat' -> 'struct perf_evsel_stat'
'struct perf_stat_cmd' -> 'struct perf_stat'

and move 'struct perf_stat_record' under 'struct perf_stat' ;-)

>
> Erm, saw some more patches, this stuff gets marshalled into perf.data,
> continuing to read... Probably you made this somehow extensible...

yep, I'm storing it in 'tag-value' way, it's mentioned in the changelog

jirka

2015-07-26 13:51:16

by Jiri Olsa

[permalink] [raw]
Subject: Re: [RFC 00/47] perf stat: Add scripting support

On Tue, Jul 21, 2015 at 04:43:08PM +0200, Andi Kleen wrote:
> On Tue, Jul 21, 2015 at 02:31:20PM +0200, Jiri Olsa wrote:
> > hi,
> > sending RFC on another attempt for stat scripting.
> >
> > The initial attempt defined its own formula lang and allowed
> > triggering user's script on the end of the stat command:
> > http://marc.info/?l=linux-kernel&m=136742146322273&w=2
> >
> > This patchset abandons the idea of new formula language
> > and rather adds support to:
> > - store stat data into perf.data file
> > - add python support to process stat events
> >
> > Basically it allows to store stat data into perf.data and
> > post process it with python scripts in a similar way we
> > do for sampling data.
>
> I suspect there is some overlap with Kan's patchkit to put
> uncore data into perf.data too.

hum, haven't seen this, was it posted already?

jirka

2015-07-27 12:46:51

by Liang, Kan

[permalink] [raw]
Subject: RE: [RFC 00/47] perf stat: Add scripting support

>
> On Tue, Jul 21, 2015 at 04:43:08PM +0200, Andi Kleen wrote:
> > On Tue, Jul 21, 2015 at 02:31:20PM +0200, Jiri Olsa wrote:
> > > hi,
> > > sending RFC on another attempt for stat scripting.
> > >
> > > The initial attempt defined its own formula lang and allowed
> > > triggering user's script on the end of the stat command:
> > > http://marc.info/?l=linux-kernel&m=136742146322273&w=2
> > >
> > > This patchset abandons the idea of new formula language and rather
> > > adds support to:
> > > - store stat data into perf.data file
> > > - add python support to process stat events
> > >
> > > Basically it allows to store stat data into perf.data and post
> > > process it with python scripts in a similar way we do for sampling
> > > data.
> >
> > I suspect there is some overlap with Kan's patchkit to put uncore data
> > into perf.data too.
>
> hum, haven't seen this, was it posted already?
>
Not yet.
But I think the proposal is different as yours.
It intends to regularly read (10-20ms interval) counter during perf sampling.
So I modified the perf record, added a timer to read counter regularly, and
wrote the delta results into perf.data.
We want to do that is because we can read memory bandwidth from uncore
event during cpu PMU event is sampling. The sophisticated bandwidth
analysis requires fine granularity.
We cannot use sample read, because we need stable interval.
We tried to run perf record and perf stat together by script. But the script
way have various issue and complex to parses the output.
So I propose to change the perf record and regularly write the counter
value into perf.data
I will send them to review soon.

Thanks,
Kan

Subject: [tip:perf/core] perf test: Check for refcnt in thread_map test

Commit-ID: 35318d204db83f5c1f24c281839763b271b9b323
Gitweb: http://git.kernel.org/tip/35318d204db83f5c1f24c281839763b271b9b323
Author: Jiri Olsa <[email protected]>
AuthorDate: Tue, 21 Jul 2015 14:31:21 +0200
Committer: Arnaldo Carvalho de Melo <[email protected]>
CommitDate: Tue, 21 Jul 2015 14:20:32 -0300

perf test: Check for refcnt in thread_map test

Checking also for refcnt in thread_map test.

Signed-off-by: Jiri Olsa <[email protected]>
Cc: David Ahern <[email protected]>
Cc: Namhyung Kim <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Link: http://lkml.kernel.org/r/[email protected]
Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
---
tools/perf/tests/thread-map.c | 4 ++++
1 file changed, 4 insertions(+)

diff --git a/tools/perf/tests/thread-map.c b/tools/perf/tests/thread-map.c
index 5acf000..138a0e3 100644
--- a/tools/perf/tests/thread-map.c
+++ b/tools/perf/tests/thread-map.c
@@ -20,6 +20,8 @@ int test__thread_map(void)
TEST_ASSERT_VAL("wrong comm",
thread_map__comm(map, 0) &&
!strcmp(thread_map__comm(map, 0), "perf"));
+ TEST_ASSERT_VAL("wrong refcnt",
+ atomic_read(&map->refcnt) == 1);
thread_map__put(map);

/* test dummy pid */
@@ -33,6 +35,8 @@ int test__thread_map(void)
TEST_ASSERT_VAL("wrong comm",
thread_map__comm(map, 0) &&
!strcmp(thread_map__comm(map, 0), "dummy"));
+ TEST_ASSERT_VAL("wrong refcnt",
+ atomic_read(&map->refcnt) == 1);
thread_map__put(map);
return 0;
}

Subject: [tip:perf/core] perf evlist: Force perf_evlist__set_maps to propagate maps through events

Commit-ID: 3de5cfb04435b82aa427d0285df996ba73d2f426
Gitweb: http://git.kernel.org/tip/3de5cfb04435b82aa427d0285df996ba73d2f426
Author: Jiri Olsa <[email protected]>
AuthorDate: Tue, 21 Jul 2015 14:31:30 +0200
Committer: Arnaldo Carvalho de Melo <[email protected]>
CommitDate: Tue, 21 Jul 2015 14:25:12 -0300

perf evlist: Force perf_evlist__set_maps to propagate maps through events

Forcing perf_evlist__set_maps to propagate maps through events, so
cpu/thread maps get set within evlist.

Signed-off-by: Jiri Olsa <[email protected]>
Cc: David Ahern <[email protected]>
Cc: Namhyung Kim <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Link: http://lkml.kernel.org/r/[email protected]
Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
---
tools/perf/util/evlist.c | 17 +++++++++++++++++
tools/perf/util/evlist.h | 11 +++--------
2 files changed, 20 insertions(+), 8 deletions(-)

diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index f7d9c77..6bfcab9b 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -1150,6 +1150,23 @@ out_delete_threads:
return -1;
}

+int perf_evlist__set_maps(struct perf_evlist *evlist,
+ struct cpu_map *cpus,
+ struct thread_map *threads)
+{
+ if (evlist->cpus)
+ cpu_map__put(evlist->cpus);
+
+ evlist->cpus = cpus;
+
+ if (evlist->threads)
+ thread_map__put(evlist->threads);
+
+ evlist->threads = threads;
+
+ return perf_evlist__propagate_maps(evlist, false);
+}
+
int perf_evlist__apply_filters(struct perf_evlist *evlist, struct perf_evsel **err_evsel)
{
struct perf_evsel *evsel;
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h
index 037633c..406a821 100644
--- a/tools/perf/util/evlist.h
+++ b/tools/perf/util/evlist.h
@@ -152,14 +152,9 @@ int perf_evlist__enable_event_idx(struct perf_evlist *evlist,
void perf_evlist__set_selected(struct perf_evlist *evlist,
struct perf_evsel *evsel);

-static inline void perf_evlist__set_maps(struct perf_evlist *evlist,
- struct cpu_map *cpus,
- struct thread_map *threads)
-{
- evlist->cpus = cpus;
- evlist->threads = threads;
-}
-
+int perf_evlist__set_maps(struct perf_evlist *evlist,
+ struct cpu_map *cpus,
+ struct thread_map *threads);
int perf_evlist__create_maps(struct perf_evlist *evlist, struct target *target);
int perf_evlist__apply_filters(struct perf_evlist *evlist, struct perf_evsel **err_evsel);

Subject: [tip:perf/core] perf evlist: Use bool instead of target argument in propagate_maps()

Commit-ID: 52361ff093c807464f5a32a587a370b360bd399a
Gitweb: http://git.kernel.org/tip/52361ff093c807464f5a32a587a370b360bd399a
Author: Jiri Olsa <[email protected]>
AuthorDate: Tue, 21 Jul 2015 14:31:28 +0200
Committer: Arnaldo Carvalho de Melo <[email protected]>
CommitDate: Tue, 21 Jul 2015 14:34:07 -0300

perf evlist: Use bool instead of target argument in propagate_maps()

We need only bool info wether user defined her own set of cpus.

Switching target argument to bool so it could be used from places
without target object defined in following patches.

Signed-off-by: Jiri Olsa <[email protected]>
Cc: David Ahern <[email protected]>
Cc: Namhyung Kim <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Link: http://lkml.kernel.org/r/[email protected]
Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
---
tools/perf/util/evlist.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index 6bfcab9b..80ab942 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -1102,7 +1102,7 @@ int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages,
}

static int perf_evlist__propagate_maps(struct perf_evlist *evlist,
- struct target *target)
+ bool has_user_cpus)
{
struct perf_evsel *evsel;

@@ -1111,10 +1111,10 @@ static int perf_evlist__propagate_maps(struct perf_evlist *evlist,
* We already have cpus for evsel (via PMU sysfs) so
* keep it, if there's no target cpu list defined.
*/
- if (evsel->cpus && target->cpu_list)
+ if (evsel->cpus && has_user_cpus)
cpu_map__put(evsel->cpus);

- if (!evsel->cpus || target->cpu_list)
+ if (!evsel->cpus || has_user_cpus)
evsel->cpus = cpu_map__get(evlist->cpus);

evsel->threads = thread_map__get(evlist->threads);
@@ -1142,7 +1142,7 @@ int perf_evlist__create_maps(struct perf_evlist *evlist, struct target *target)
if (evlist->cpus == NULL)
goto out_delete_threads;

- return perf_evlist__propagate_maps(evlist, target);
+ return perf_evlist__propagate_maps(evlist, !!target->cpu_list);

out_delete_threads:
thread_map__put(evlist->threads);

Subject: [tip:perf/core] perf evlist: Tolerate NULL maps in propagate_maps

Commit-ID: 0e5ffb317d7f861c309b0ab679ed2f59e9f72adf
Gitweb: http://git.kernel.org/tip/0e5ffb317d7f861c309b0ab679ed2f59e9f72adf
Author: Jiri Olsa <[email protected]>
AuthorDate: Tue, 21 Jul 2015 14:31:29 +0200
Committer: Arnaldo Carvalho de Melo <[email protected]>
CommitDate: Tue, 21 Jul 2015 14:34:07 -0300

perf evlist: Tolerate NULL maps in propagate_maps

Tolerating NULL maps in perf_evlist__propagate_maps, so we dont need to
pass evlist with both cpus and threads maps defined.

Signed-off-by: Jiri Olsa <[email protected]>
Cc: David Ahern <[email protected]>
Cc: Namhyung Kim <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Link: http://lkml.kernel.org/r/[email protected]
Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
---
tools/perf/util/evlist.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index 80ab942..3b9f411 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -1119,7 +1119,8 @@ static int perf_evlist__propagate_maps(struct perf_evlist *evlist,

evsel->threads = thread_map__get(evlist->threads);

- if (!evsel->cpus || !evsel->threads)
+ if ((evlist->cpus && !evsel->cpus) ||
+ (evlist->threads && !evsel->threads))
return -ENOMEM;
}

Subject: [tip:perf/core] perf header: Use argv style storage for cmdline feature data

Commit-ID: 768dd3f3a6af25730ed1eec458e47a3c481bc3e5
Gitweb: http://git.kernel.org/tip/768dd3f3a6af25730ed1eec458e47a3c481bc3e5
Author: Jiri Olsa <[email protected]>
AuthorDate: Tue, 21 Jul 2015 14:31:31 +0200
Committer: Arnaldo Carvalho de Melo <[email protected]>
CommitDate: Tue, 21 Jul 2015 14:34:08 -0300

perf header: Use argv style storage for cmdline feature data

We will reuse argv style data in following change to display counters
header showing monitored command line.

Signed-off-by: Jiri Olsa <[email protected]>
Cc: David Ahern <[email protected]>
Cc: Namhyung Kim <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Link: http://lkml.kernel.org/r/[email protected]
Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
---
tools/perf/util/header.c | 35 ++++++++++++++++++++---------------
tools/perf/util/header.h | 1 +
tools/perf/util/session.c | 1 +
3 files changed, 22 insertions(+), 15 deletions(-)

diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index 03ace57..179b2bd 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -923,17 +923,13 @@ static void print_cmdline(struct perf_header *ph, int fd __maybe_unused,
FILE *fp)
{
int nr, i;
- char *str;

nr = ph->env.nr_cmdline;
- str = ph->env.cmdline;

fprintf(fp, "# cmdline : ");

- for (i = 0; i < nr; i++) {
- fprintf(fp, "%s ", str);
- str += strlen(str) + 1;
- }
+ for (i = 0; i < nr; i++)
+ fprintf(fp, "%s ", ph->env.cmdline_argv[i]);
fputc('\n', fp);
}

@@ -1541,14 +1537,13 @@ process_event_desc(struct perf_file_section *section __maybe_unused,
return 0;
}

-static int process_cmdline(struct perf_file_section *section __maybe_unused,
+static int process_cmdline(struct perf_file_section *section,
struct perf_header *ph, int fd,
void *data __maybe_unused)
{
ssize_t ret;
- char *str;
- u32 nr, i;
- struct strbuf sb;
+ char *str, *cmdline = NULL, **argv = NULL;
+ u32 nr, i, len = 0;

ret = readn(fd, &nr, sizeof(nr));
if (ret != sizeof(nr))
@@ -1558,22 +1553,32 @@ static int process_cmdline(struct perf_file_section *section __maybe_unused,
nr = bswap_32(nr);

ph->env.nr_cmdline = nr;
- strbuf_init(&sb, 128);
+
+ cmdline = zalloc(section->size + nr + 1);
+ if (!cmdline)
+ return -1;
+
+ argv = zalloc(sizeof(char *) * (nr + 1));
+ if (!argv)
+ goto error;

for (i = 0; i < nr; i++) {
str = do_read_string(fd, ph);
if (!str)
goto error;

- /* include a NULL character at the end */
- strbuf_add(&sb, str, strlen(str) + 1);
+ argv[i] = cmdline + len;
+ memcpy(argv[i], str, strlen(str) + 1);
+ len += strlen(str) + 1;
free(str);
}
- ph->env.cmdline = strbuf_detach(&sb, NULL);
+ ph->env.cmdline = cmdline;
+ ph->env.cmdline_argv = (const char **) argv;
return 0;

error:
- strbuf_release(&sb);
+ free(argv);
+ free(cmdline);
return -1;
}

diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
index d4d5796..9b53b65 100644
--- a/tools/perf/util/header.h
+++ b/tools/perf/util/header.h
@@ -84,6 +84,7 @@ struct perf_session_env {
int nr_pmu_mappings;
int nr_groups;
char *cmdline;
+ const char **cmdline_argv;
char *sibling_cores;
char *sibling_threads;
char *numa_nodes;
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index ed9dc25..fb1d525 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -180,6 +180,7 @@ static void perf_session_env__delete(struct perf_session_env *env)
zfree(&env->cpuid);

zfree(&env->cmdline);
+ zfree(&env->cmdline_argv);
zfree(&env->sibling_cores);
zfree(&env->sibling_threads);
zfree(&env->numa_nodes);

2015-08-07 02:08:55

by Arnaldo Carvalho de Melo

[permalink] [raw]
Subject: Re: [RFC 00/47] perf stat: Add scripting support

Em Tue, Jul 21, 2015 at 02:31:20PM +0200, Jiri Olsa escreveu:
> hi,
> sending RFC on another attempt for stat scripting.
>
> The initial attempt defined its own formula lang and allowed
> triggering user's script on the end of the stat command:
> http://marc.info/?l=linux-kernel&m=136742146322273&w=2
>
> This patchset abandons the idea of new formula language
> and rather adds support to:
> - store stat data into perf.data file
> - add python support to process stat events

Applied the first 11, some in a previous pull req, the ones moving stuff
to perf_stat_config now, but the 12nd fails, please check when I get
these merged by Ingo.

Also do you intend to do some rework on this due to the conversation
with Kan? The ones I merged are good anyway, merged.

Thanks,

- Arnaldo

Subject: [tip:perf/core] perf stat: Introduce struct perf_stat_config

Commit-ID: 421a50f3fafaf271bb3293378eaafca71337dfec
Gitweb: http://git.kernel.org/tip/421a50f3fafaf271bb3293378eaafca71337dfec
Author: Jiri Olsa <[email protected]>
AuthorDate: Tue, 21 Jul 2015 14:31:22 +0200
Committer: Arnaldo Carvalho de Melo <[email protected]>
CommitDate: Thu, 6 Aug 2015 16:02:29 -0300

perf stat: Introduce struct perf_stat_config

Moving 'aggr_mode' into new struct. The point is to centralize the base
stat config so it could be used localy together with other stat routines
in other parts of perf code.

Signed-off-by: Jiri Olsa <[email protected]>
Cc: David Ahern <[email protected]>
Cc: Namhyung Kim <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Link: http://lkml.kernel.org/r/[email protected]
Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
---
tools/perf/builtin-stat.c | 39 ++++++++++++++++++++++-----------------
tools/perf/util/stat.h | 4 ++++
2 files changed, 26 insertions(+), 17 deletions(-)

diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index d99d850..bafb830 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -102,7 +102,6 @@ static struct target target = {
static int run_count = 1;
static bool no_inherit = false;
static bool scale = true;
-static enum aggr_mode aggr_mode = AGGR_GLOBAL;
static volatile pid_t child_pid = -1;
static bool null_run = false;
static int detailed_run = 0;
@@ -126,6 +125,10 @@ static int (*aggr_get_id)(struct cpu_map *m, int cpu);

static volatile int done = 0;

+static struct perf_stat_config stat_config = {
+ .aggr_mode = AGGR_GLOBAL,
+};
+
static inline void diff_timespec(struct timespec *r, struct timespec *a,
struct timespec *b)
{
@@ -230,7 +233,7 @@ process_counter_values(struct perf_evsel *evsel, int cpu, int thread,
if (skip)
count = &zero;

- switch (aggr_mode) {
+ switch (stat_config.aggr_mode) {
case AGGR_THREAD:
case AGGR_CORE:
case AGGR_SOCKET:
@@ -238,7 +241,7 @@ process_counter_values(struct perf_evsel *evsel, int cpu, int thread,
if (!evsel->snapshot)
perf_evsel__compute_deltas(evsel, cpu, thread, count);
perf_counts_values__scale(count, scale, NULL);
- if (aggr_mode == AGGR_NONE)
+ if (stat_config.aggr_mode == AGGR_NONE)
perf_stat__update_shadow_stats(evsel, count->values, cpu);
break;
case AGGR_GLOBAL:
@@ -291,7 +294,7 @@ static int process_counter(struct perf_evsel *counter)
if (ret)
return ret;

- if (aggr_mode != AGGR_GLOBAL)
+ if (stat_config.aggr_mode != AGGR_GLOBAL)
return 0;

if (!counter->snapshot)
@@ -578,7 +581,7 @@ static void print_noise(struct perf_evsel *evsel, double avg)

static void aggr_printout(struct perf_evsel *evsel, int id, int nr)
{
- switch (aggr_mode) {
+ switch (stat_config.aggr_mode) {
case AGGR_CORE:
fprintf(output, "S%d-C%*d%s%*d%s",
cpu_map__id_to_socket(id),
@@ -670,7 +673,7 @@ static void abs_printout(int id, int nr, struct perf_evsel *evsel, double avg)

aggr_printout(evsel, id, nr);

- if (aggr_mode == AGGR_GLOBAL)
+ if (stat_config.aggr_mode == AGGR_GLOBAL)
cpu = 0;

fprintf(output, fmt, avg, csv_sep);
@@ -688,7 +691,8 @@ static void abs_printout(int id, int nr, struct perf_evsel *evsel, double avg)
if (csv_output || interval)
return;

- perf_stat__print_shadow_stats(output, evsel, avg, cpu, aggr_mode);
+ perf_stat__print_shadow_stats(output, evsel, avg, cpu,
+ stat_config.aggr_mode);
}

static void print_aggr(char *prefix)
@@ -909,7 +913,7 @@ static void print_interval(char *prefix, struct timespec *ts)
sprintf(prefix, "%6lu.%09lu%s", ts->tv_sec, ts->tv_nsec, csv_sep);

if (num_print_interval == 0 && !csv_output) {
- switch (aggr_mode) {
+ switch (stat_config.aggr_mode) {
case AGGR_SOCKET:
fprintf(output, "# time socket cpus counts %*s events\n", unit_width, "unit");
break;
@@ -985,7 +989,7 @@ static void print_counters(struct timespec *ts, int argc, const char **argv)
else
print_header(argc, argv);

- switch (aggr_mode) {
+ switch (stat_config.aggr_mode) {
case AGGR_CORE:
case AGGR_SOCKET:
print_aggr(prefix);
@@ -1064,7 +1068,7 @@ static int stat__set_big_num(const struct option *opt __maybe_unused,

static int perf_stat_init_aggr_mode(void)
{
- switch (aggr_mode) {
+ switch (stat_config.aggr_mode) {
case AGGR_SOCKET:
if (cpu_map__build_socket_map(evsel_list->cpus, &aggr_map)) {
perror("cannot build socket map");
@@ -1286,7 +1290,7 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
stat__set_big_num),
OPT_STRING('C', "cpu", &target.cpu_list, "cpu",
"list of cpus to monitor in system-wide"),
- OPT_SET_UINT('A', "no-aggr", &aggr_mode,
+ OPT_SET_UINT('A', "no-aggr", &stat_config.aggr_mode,
"disable CPU count aggregation", AGGR_NONE),
OPT_STRING('x', "field-separator", &csv_sep, "separator",
"print counts with custom separator"),
@@ -1302,11 +1306,11 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
"command to run after to the measured command"),
OPT_UINTEGER('I', "interval-print", &interval,
"print counts at regular interval in ms (>= 100)"),
- OPT_SET_UINT(0, "per-socket", &aggr_mode,
+ OPT_SET_UINT(0, "per-socket", &stat_config.aggr_mode,
"aggregate counts per processor socket", AGGR_SOCKET),
- OPT_SET_UINT(0, "per-core", &aggr_mode,
+ OPT_SET_UINT(0, "per-core", &stat_config.aggr_mode,
"aggregate counts per physical processor core", AGGR_CORE),
- OPT_SET_UINT(0, "per-thread", &aggr_mode,
+ OPT_SET_UINT(0, "per-thread", &stat_config.aggr_mode,
"aggregate counts per thread", AGGR_THREAD),
OPT_UINTEGER('D', "delay", &initial_delay,
"ms to wait before starting measurement after program start"),
@@ -1399,7 +1403,7 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
run_count = 1;
}

- if ((aggr_mode == AGGR_THREAD) && !target__has_task(&target)) {
+ if ((stat_config.aggr_mode == AGGR_THREAD) && !target__has_task(&target)) {
fprintf(stderr, "The --per-thread option is only available "
"when monitoring via -p -t options.\n");
parse_options_usage(NULL, options, "p", 1);
@@ -1411,7 +1415,8 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
* no_aggr, cgroup are for system-wide only
* --per-thread is aggregated per thread, we dont mix it with cpu mode
*/
- if (((aggr_mode != AGGR_GLOBAL && aggr_mode != AGGR_THREAD) || nr_cgroups) &&
+ if (((stat_config.aggr_mode != AGGR_GLOBAL &&
+ stat_config.aggr_mode != AGGR_THREAD) || nr_cgroups) &&
!target__has_cpu(&target)) {
fprintf(stderr, "both cgroup and no-aggregation "
"modes only available in system-wide mode\n");
@@ -1444,7 +1449,7 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
* Initialize thread_map with comm names,
* so we could print it out on output.
*/
- if (aggr_mode == AGGR_THREAD)
+ if (stat_config.aggr_mode == AGGR_THREAD)
thread_map__read_comms(evsel_list->threads);

if (interval && interval < 100) {
diff --git a/tools/perf/util/stat.h b/tools/perf/util/stat.h
index 1cfbe0a..078bee4 100644
--- a/tools/perf/util/stat.h
+++ b/tools/perf/util/stat.h
@@ -50,6 +50,10 @@ struct perf_counts {
struct xyarray *values;
};

+struct perf_stat_config {
+ enum aggr_mode aggr_mode;
+};
+
static inline struct perf_counts_values*
perf_counts(struct perf_counts *counts, int cpu, int thread)
{

Subject: [tip:perf/core] perf stat: Move 'scale' into struct perf_stat_config

Commit-ID: 711a572ea8ae7e9ab6575403c6d632d058d5cb3d
Gitweb: http://git.kernel.org/tip/711a572ea8ae7e9ab6575403c6d632d058d5cb3d
Author: Jiri Olsa <[email protected]>
AuthorDate: Tue, 21 Jul 2015 14:31:23 +0200
Committer: Arnaldo Carvalho de Melo <[email protected]>
CommitDate: Thu, 6 Aug 2015 16:02:39 -0300

perf stat: Move 'scale' into struct perf_stat_config

Moving 'scale' into struct perf_stat_config. The point is to centralize
the base stat config so it could be used localy together with other stat
routines in other parts of perf code.

Signed-off-by: Jiri Olsa <[email protected]>
Cc: David Ahern <[email protected]>
Cc: Namhyung Kim <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Link: http://lkml.kernel.org/r/[email protected]
Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
---
tools/perf/builtin-stat.c | 12 ++++++------
tools/perf/util/stat.h | 1 +
2 files changed, 7 insertions(+), 6 deletions(-)

diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index bafb830..3fb2865 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -101,7 +101,6 @@ static struct target target = {

static int run_count = 1;
static bool no_inherit = false;
-static bool scale = true;
static volatile pid_t child_pid = -1;
static bool null_run = false;
static int detailed_run = 0;
@@ -127,6 +126,7 @@ static volatile int done = 0;

static struct perf_stat_config stat_config = {
.aggr_mode = AGGR_GLOBAL,
+ .scale = true,
};

static inline void diff_timespec(struct timespec *r, struct timespec *a,
@@ -151,7 +151,7 @@ static int create_perf_stat_counter(struct perf_evsel *evsel)
{
struct perf_event_attr *attr = &evsel->attr;

- if (scale)
+ if (stat_config.scale)
attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED |
PERF_FORMAT_TOTAL_TIME_RUNNING;

@@ -240,13 +240,13 @@ process_counter_values(struct perf_evsel *evsel, int cpu, int thread,
case AGGR_NONE:
if (!evsel->snapshot)
perf_evsel__compute_deltas(evsel, cpu, thread, count);
- perf_counts_values__scale(count, scale, NULL);
+ perf_counts_values__scale(count, stat_config.scale, NULL);
if (stat_config.aggr_mode == AGGR_NONE)
perf_stat__update_shadow_stats(evsel, count->values, cpu);
break;
case AGGR_GLOBAL:
aggr->val += count->val;
- if (scale) {
+ if (stat_config.scale) {
aggr->ena += count->ena;
aggr->run += count->run;
}
@@ -299,7 +299,7 @@ static int process_counter(struct perf_evsel *counter)

if (!counter->snapshot)
perf_evsel__compute_deltas(counter, -1, -1, aggr);
- perf_counts_values__scale(aggr, scale, &counter->counts->scaled);
+ perf_counts_values__scale(aggr, stat_config.scale, &counter->counts->scaled);

for (i = 0; i < 3; i++)
update_stats(&ps->res_stats[i], count[i]);
@@ -1274,7 +1274,7 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
"system-wide collection from all CPUs"),
OPT_BOOLEAN('g', "group", &group,
"put the counters into a counter group"),
- OPT_BOOLEAN('c', "scale", &scale, "scale/normalize counters"),
+ OPT_BOOLEAN('c', "scale", &stat_config.scale, "scale/normalize counters"),
OPT_INCR('v', "verbose", &verbose,
"be more verbose (show counter open errors, etc)"),
OPT_INTEGER('r', "repeat", &run_count,
diff --git a/tools/perf/util/stat.h b/tools/perf/util/stat.h
index 078bee4..0a1d83f 100644
--- a/tools/perf/util/stat.h
+++ b/tools/perf/util/stat.h
@@ -52,6 +52,7 @@ struct perf_counts {

struct perf_stat_config {
enum aggr_mode aggr_mode;
+ bool scale;
};

static inline struct perf_counts_values*

Subject: [tip:perf/core] perf stat: Move 'output' into struct perf_stat_config

Commit-ID: 5821522e9484a8b503f89aa546085900b99589e9
Gitweb: http://git.kernel.org/tip/5821522e9484a8b503f89aa546085900b99589e9
Author: Jiri Olsa <[email protected]>
AuthorDate: Tue, 21 Jul 2015 14:31:24 +0200
Committer: Arnaldo Carvalho de Melo <[email protected]>
CommitDate: Thu, 6 Aug 2015 16:02:51 -0300

perf stat: Move 'output' into struct perf_stat_config

Moving 'output' into struct perf_stat_config. The point is to centralize
the base stat config so it could be used localy together with other stat
routines in other parts of perf code.

Signed-off-by: Jiri Olsa <[email protected]>
Cc: David Ahern <[email protected]>
Cc: Namhyung Kim <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Link: http://lkml.kernel.org/r/[email protected]
Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
---
tools/perf/builtin-stat.c | 35 +++++++++++++++++++++++------------
tools/perf/util/stat.h | 1 +
2 files changed, 24 insertions(+), 12 deletions(-)

diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index 3fb2865..e3ea8b6 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -110,7 +110,6 @@ static int big_num_opt = -1;
static const char *csv_sep = NULL;
static bool csv_output = false;
static bool group = false;
-static FILE *output = NULL;
static const char *pre_cmd = NULL;
static const char *post_cmd = NULL;
static bool sync_run = false;
@@ -305,7 +304,7 @@ static int process_counter(struct perf_evsel *counter)
update_stats(&ps->res_stats[i], count[i]);

if (verbose) {
- fprintf(output, "%s: %" PRIu64 " %" PRIu64 " %" PRIu64 "\n",
+ fprintf(stat_config.output, "%s: %" PRIu64 " %" PRIu64 " %" PRIu64 "\n",
perf_evsel__name(counter), count[0], count[1], count[2]);
}

@@ -548,13 +547,13 @@ static int run_perf_stat(int argc, const char **argv)
static void print_running(u64 run, u64 ena)
{
if (csv_output) {
- fprintf(output, "%s%" PRIu64 "%s%.2f",
+ fprintf(stat_config.output, "%s%" PRIu64 "%s%.2f",
csv_sep,
run,
csv_sep,
ena ? 100.0 * run / ena : 100.0);
} else if (run != ena) {
- fprintf(output, " (%.2f%%)", 100.0 * run / ena);
+ fprintf(stat_config.output, " (%.2f%%)", 100.0 * run / ena);
}
}

@@ -563,9 +562,9 @@ static void print_noise_pct(double total, double avg)
double pct = rel_stddev_stats(total, avg);

if (csv_output)
- fprintf(output, "%s%.2f%%", csv_sep, pct);
+ fprintf(stat_config.output, "%s%.2f%%", csv_sep, pct);
else if (pct)
- fprintf(output, " ( +-%6.2f%% )", pct);
+ fprintf(stat_config.output, " ( +-%6.2f%% )", pct);
}

static void print_noise(struct perf_evsel *evsel, double avg)
@@ -583,7 +582,7 @@ static void aggr_printout(struct perf_evsel *evsel, int id, int nr)
{
switch (stat_config.aggr_mode) {
case AGGR_CORE:
- fprintf(output, "S%d-C%*d%s%*d%s",
+ fprintf(stat_config.output, "S%d-C%*d%s%*d%s",
cpu_map__id_to_socket(id),
csv_output ? 0 : -8,
cpu_map__id_to_cpu(id),
@@ -593,7 +592,7 @@ static void aggr_printout(struct perf_evsel *evsel, int id, int nr)
csv_sep);
break;
case AGGR_SOCKET:
- fprintf(output, "S%*d%s%*d%s",
+ fprintf(stat_config.output, "S%*d%s%*d%s",
csv_output ? 0 : -5,
id,
csv_sep,
@@ -602,12 +601,12 @@ static void aggr_printout(struct perf_evsel *evsel, int id, int nr)
csv_sep);
break;
case AGGR_NONE:
- fprintf(output, "CPU%*d%s",
+ fprintf(stat_config.output, "CPU%*d%s",
csv_output ? 0 : -4,
perf_evsel__cpus(evsel)->map[id], csv_sep);
break;
case AGGR_THREAD:
- fprintf(output, "%*s-%*d%s",
+ fprintf(stat_config.output, "%*s-%*d%s",
csv_output ? 0 : 16,
thread_map__comm(evsel->threads, id),
csv_output ? 0 : -8,
@@ -622,6 +621,7 @@ static void aggr_printout(struct perf_evsel *evsel, int id, int nr)

static void nsec_printout(int id, int nr, struct perf_evsel *evsel, double avg)
{
+ FILE *output = stat_config.output;
double msecs = avg / 1e6;
const char *fmt_v, *fmt_n;
char name[25];
@@ -658,6 +658,7 @@ static void nsec_printout(int id, int nr, struct perf_evsel *evsel, double avg)

static void abs_printout(int id, int nr, struct perf_evsel *evsel, double avg)
{
+ FILE *output = stat_config.output;
double sc = evsel->scale;
const char *fmt;
int cpu = cpu_map__id_to_cpu(id);
@@ -697,6 +698,7 @@ static void abs_printout(int id, int nr, struct perf_evsel *evsel, double avg)

static void print_aggr(char *prefix)
{
+ FILE *output = stat_config.output;
struct perf_evsel *counter;
int cpu, cpu2, s, s2, id, nr;
double uval;
@@ -765,6 +767,7 @@ static void print_aggr(char *prefix)

static void print_aggr_thread(struct perf_evsel *counter, char *prefix)
{
+ FILE *output = stat_config.output;
int nthreads = thread_map__nr(counter->threads);
int ncpus = cpu_map__nr(counter->cpus);
int cpu, thread;
@@ -803,6 +806,7 @@ static void print_aggr_thread(struct perf_evsel *counter, char *prefix)
*/
static void print_counter_aggr(struct perf_evsel *counter, char *prefix)
{
+ FILE *output = stat_config.output;
struct perf_stat *ps = counter->priv;
double avg = avg_stats(&ps->res_stats[0]);
int scaled = counter->counts->scaled;
@@ -854,6 +858,7 @@ static void print_counter_aggr(struct perf_evsel *counter, char *prefix)
*/
static void print_counter(struct perf_evsel *counter, char *prefix)
{
+ FILE *output = stat_config.output;
u64 ena, run, val;
double uval;
int cpu;
@@ -908,6 +913,7 @@ static void print_counter(struct perf_evsel *counter, char *prefix)

static void print_interval(char *prefix, struct timespec *ts)
{
+ FILE *output = stat_config.output;
static int num_print_interval;

sprintf(prefix, "%6lu.%09lu%s", ts->tv_sec, ts->tv_nsec, csv_sep);
@@ -938,6 +944,7 @@ static void print_interval(char *prefix, struct timespec *ts)

static void print_header(int argc, const char **argv)
{
+ FILE *output = stat_config.output;
int i;

fflush(stdout);
@@ -967,6 +974,8 @@ static void print_header(int argc, const char **argv)

static void print_footer(void)
{
+ FILE *output = stat_config.output;
+
if (!null_run)
fprintf(output, "\n");
fprintf(output, " %17.9f seconds time elapsed",
@@ -1013,7 +1022,7 @@ static void print_counters(struct timespec *ts, int argc, const char **argv)
if (!interval && !csv_output)
print_footer();

- fflush(output);
+ fflush(stat_config.output);
}

static volatile int signr = -1;
@@ -1322,6 +1331,7 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
};
int status = -EINVAL, run_idx;
const char *mode;
+ FILE *output = stderr;

setlocale(LC_ALL, "");

@@ -1332,7 +1342,6 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
argc = parse_options(argc, argv, options, stat_usage,
PARSE_OPT_STOP_AT_NON_OPTION);

- output = stderr;
if (output_name && strcmp(output_name, "-"))
output = NULL;

@@ -1369,6 +1378,8 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
}
}

+ stat_config.output = output;
+
if (csv_sep) {
csv_output = true;
if (!strcmp(csv_sep, "\\t"))
diff --git a/tools/perf/util/stat.h b/tools/perf/util/stat.h
index 0a1d83f..ed0e058 100644
--- a/tools/perf/util/stat.h
+++ b/tools/perf/util/stat.h
@@ -53,6 +53,7 @@ struct perf_counts {
struct perf_stat_config {
enum aggr_mode aggr_mode;
bool scale;
+ FILE *output;
};

static inline struct perf_counts_values*

Subject: [tip:perf/core] perf stat: Move 'interval' into struct perf_stat_config

Commit-ID: ec0d3d1fd292adb80372193c03d859e9cbefd367
Gitweb: http://git.kernel.org/tip/ec0d3d1fd292adb80372193c03d859e9cbefd367
Author: Jiri Olsa <[email protected]>
AuthorDate: Tue, 21 Jul 2015 14:31:25 +0200
Committer: Arnaldo Carvalho de Melo <[email protected]>
CommitDate: Thu, 6 Aug 2015 16:03:04 -0300

perf stat: Move 'interval' into struct perf_stat_config

Moving 'interval' into struct perf_stat_config. The point is to
centralize the base stat config so it could be used localy together with
other stat routines in other parts of perf code.

Signed-off-by: Jiri Olsa <[email protected]>
Cc: David Ahern <[email protected]>
Cc: Namhyung Kim <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Link: http://lkml.kernel.org/r/[email protected]
Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
---
tools/perf/builtin-stat.c | 14 +++++++++-----
tools/perf/util/stat.h | 1 +
2 files changed, 10 insertions(+), 5 deletions(-)

diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index e3ea8b6..1bdfec8 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -113,7 +113,6 @@ static bool group = false;
static const char *pre_cmd = NULL;
static const char *post_cmd = NULL;
static bool sync_run = false;
-static unsigned int interval = 0;
static unsigned int initial_delay = 0;
static unsigned int unit_width = 4; /* strlen("unit") */
static bool forever = false;
@@ -404,6 +403,7 @@ static void workload_exec_failed_signal(int signo __maybe_unused, siginfo_t *inf

static int __run_perf_stat(int argc, const char **argv)
{
+ int interval = stat_config.interval;
char msg[512];
unsigned long long t0, t1;
struct perf_evsel *counter;
@@ -646,7 +646,7 @@ static void nsec_printout(int id, int nr, struct perf_evsel *evsel, double avg)
if (evsel->cgrp)
fprintf(output, "%s%s", csv_sep, evsel->cgrp->name);

- if (csv_output || interval)
+ if (csv_output || stat_config.interval)
return;

if (perf_evsel__match(evsel, SOFTWARE, SW_TASK_CLOCK))
@@ -689,7 +689,7 @@ static void abs_printout(int id, int nr, struct perf_evsel *evsel, double avg)
if (evsel->cgrp)
fprintf(output, "%s%s", csv_sep, evsel->cgrp->name);

- if (csv_output || interval)
+ if (csv_output || stat_config.interval)
return;

perf_stat__print_shadow_stats(output, evsel, avg, cpu,
@@ -990,6 +990,7 @@ static void print_footer(void)

static void print_counters(struct timespec *ts, int argc, const char **argv)
{
+ int interval = stat_config.interval;
struct perf_evsel *counter;
char buf[64], *prefix = NULL;

@@ -1029,7 +1030,7 @@ static volatile int signr = -1;

static void skip_signal(int signo)
{
- if ((child_pid == -1) || interval)
+ if ((child_pid == -1) || stat_config.interval)
done = 1;

signr = signo;
@@ -1313,7 +1314,7 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
"command to run prior to the measured command"),
OPT_STRING(0, "post", &post_cmd, "command",
"command to run after to the measured command"),
- OPT_UINTEGER('I', "interval-print", &interval,
+ OPT_UINTEGER('I', "interval-print", &stat_config.interval,
"print counts at regular interval in ms (>= 100)"),
OPT_SET_UINT(0, "per-socket", &stat_config.aggr_mode,
"aggregate counts per processor socket", AGGR_SOCKET),
@@ -1332,6 +1333,7 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
int status = -EINVAL, run_idx;
const char *mode;
FILE *output = stderr;
+ unsigned int interval;

setlocale(LC_ALL, "");

@@ -1342,6 +1344,8 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
argc = parse_options(argc, argv, options, stat_usage,
PARSE_OPT_STOP_AT_NON_OPTION);

+ interval = stat_config.interval;
+
if (output_name && strcmp(output_name, "-"))
output = NULL;

diff --git a/tools/perf/util/stat.h b/tools/perf/util/stat.h
index ed0e058..1da706d 100644
--- a/tools/perf/util/stat.h
+++ b/tools/perf/util/stat.h
@@ -54,6 +54,7 @@ struct perf_stat_config {
enum aggr_mode aggr_mode;
bool scale;
FILE *output;
+ unsigned int interval;
};

static inline struct perf_counts_values*

Subject: [tip:perf/core] perf stat: Pass 'struct perf_stat_config' into process_counter()

Commit-ID: 5e5fe748bec771a810b1f44ec9c19e4b92685246
Gitweb: http://git.kernel.org/tip/5e5fe748bec771a810b1f44ec9c19e4b92685246
Author: Jiri Olsa <[email protected]>
AuthorDate: Tue, 21 Jul 2015 14:31:26 +0200
Committer: Arnaldo Carvalho de Melo <[email protected]>
CommitDate: Thu, 6 Aug 2015 16:07:36 -0300

perf stat: Pass 'struct perf_stat_config' into process_counter()

Passing 'struct perf_stat_config' into process_counter(), so that we can
make process_counter() non static and use it from other places.

Signed-off-by: Jiri Olsa <[email protected]>
Cc: David Ahern <[email protected]>
Cc: Namhyung Kim <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Link: http://lkml.kernel.org/r/[email protected]
Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
---
tools/perf/builtin-stat.c | 29 ++++++++++++++++-------------
1 file changed, 16 insertions(+), 13 deletions(-)

diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index 1bdfec8..5a78171 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -216,7 +216,8 @@ static int check_per_pkg(struct perf_evsel *counter, int cpu, bool *skip)
}

static int
-process_counter_values(struct perf_evsel *evsel, int cpu, int thread,
+process_counter_values(struct perf_stat_config *config, struct perf_evsel *evsel,
+ int cpu, int thread,
struct perf_counts_values *count)
{
struct perf_counts_values *aggr = &evsel->counts->aggr;
@@ -231,20 +232,20 @@ process_counter_values(struct perf_evsel *evsel, int cpu, int thread,
if (skip)
count = &zero;

- switch (stat_config.aggr_mode) {
+ switch (config->aggr_mode) {
case AGGR_THREAD:
case AGGR_CORE:
case AGGR_SOCKET:
case AGGR_NONE:
if (!evsel->snapshot)
perf_evsel__compute_deltas(evsel, cpu, thread, count);
- perf_counts_values__scale(count, stat_config.scale, NULL);
- if (stat_config.aggr_mode == AGGR_NONE)
+ perf_counts_values__scale(count, config->scale, NULL);
+ if (config->aggr_mode == AGGR_NONE)
perf_stat__update_shadow_stats(evsel, count->values, cpu);
break;
case AGGR_GLOBAL:
aggr->val += count->val;
- if (stat_config.scale) {
+ if (config->scale) {
aggr->ena += count->ena;
aggr->run += count->run;
}
@@ -255,7 +256,8 @@ process_counter_values(struct perf_evsel *evsel, int cpu, int thread,
return 0;
}

-static int process_counter_maps(struct perf_evsel *counter)
+static int process_counter_maps(struct perf_stat_config *config,
+ struct perf_evsel *counter)
{
int nthreads = thread_map__nr(counter->threads);
int ncpus = perf_evsel__nr_cpus(counter);
@@ -266,7 +268,7 @@ static int process_counter_maps(struct perf_evsel *counter)

for (thread = 0; thread < nthreads; thread++) {
for (cpu = 0; cpu < ncpus; cpu++) {
- if (process_counter_values(counter, cpu, thread,
+ if (process_counter_values(config, counter, cpu, thread,
perf_counts(counter->counts, cpu, thread)))
return -1;
}
@@ -275,7 +277,8 @@ static int process_counter_maps(struct perf_evsel *counter)
return 0;
}

-static int process_counter(struct perf_evsel *counter)
+static int process_counter(struct perf_stat_config *config,
+ struct perf_evsel *counter)
{
struct perf_counts_values *aggr = &counter->counts->aggr;
struct perf_stat *ps = counter->priv;
@@ -288,22 +291,22 @@ static int process_counter(struct perf_evsel *counter)
if (counter->per_pkg)
zero_per_pkg(counter);

- ret = process_counter_maps(counter);
+ ret = process_counter_maps(&stat_config, counter);
if (ret)
return ret;

- if (stat_config.aggr_mode != AGGR_GLOBAL)
+ if (config->aggr_mode != AGGR_GLOBAL)
return 0;

if (!counter->snapshot)
perf_evsel__compute_deltas(counter, -1, -1, aggr);
- perf_counts_values__scale(aggr, stat_config.scale, &counter->counts->scaled);
+ perf_counts_values__scale(aggr, config->scale, &counter->counts->scaled);

for (i = 0; i < 3; i++)
update_stats(&ps->res_stats[i], count[i]);

if (verbose) {
- fprintf(stat_config.output, "%s: %" PRIu64 " %" PRIu64 " %" PRIu64 "\n",
+ fprintf(config->output, "%s: %" PRIu64 " %" PRIu64 " %" PRIu64 "\n",
perf_evsel__name(counter), count[0], count[1], count[2]);
}

@@ -352,7 +355,7 @@ static void read_counters(bool close_counters)
if (read_counter(counter))
pr_warning("failed to read counter %s\n", counter->name);

- if (process_counter(counter))
+ if (process_counter(&stat_config, counter))
pr_warning("failed to process counter %s\n", counter->name);

if (close_counters) {

Subject: [tip:perf/core] perf stat: Move counter processing code into stat object

Commit-ID: f80010eb230b94e8d9cf5bf83373a097fb5b2dcc
Gitweb: http://git.kernel.org/tip/f80010eb230b94e8d9cf5bf83373a097fb5b2dcc
Author: Jiri Olsa <[email protected]>
AuthorDate: Tue, 21 Jul 2015 14:31:27 +0200
Committer: Arnaldo Carvalho de Melo <[email protected]>
CommitDate: Thu, 6 Aug 2015 16:08:16 -0300

perf stat: Move counter processing code into stat object

Moving counter processing code into stat object as
perf_stat__process_counter.

Signed-off-by: Jiri Olsa <[email protected]>
Cc: David Ahern <[email protected]>
Cc: Namhyung Kim <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Link: http://lkml.kernel.org/r/[email protected]
Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
---
tools/perf/builtin-stat.c | 141 +---------------------------------------------
tools/perf/util/stat.c | 139 +++++++++++++++++++++++++++++++++++++++++++++
tools/perf/util/stat.h | 3 +
3 files changed, 143 insertions(+), 140 deletions(-)

diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index 5a78171..a054ddc 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -179,145 +179,6 @@ static inline int nsec_counter(struct perf_evsel *evsel)
return 0;
}

-static void zero_per_pkg(struct perf_evsel *counter)
-{
- if (counter->per_pkg_mask)
- memset(counter->per_pkg_mask, 0, MAX_NR_CPUS);
-}
-
-static int check_per_pkg(struct perf_evsel *counter, int cpu, bool *skip)
-{
- unsigned long *mask = counter->per_pkg_mask;
- struct cpu_map *cpus = perf_evsel__cpus(counter);
- int s;
-
- *skip = false;
-
- if (!counter->per_pkg)
- return 0;
-
- if (cpu_map__empty(cpus))
- return 0;
-
- if (!mask) {
- mask = zalloc(MAX_NR_CPUS);
- if (!mask)
- return -ENOMEM;
-
- counter->per_pkg_mask = mask;
- }
-
- s = cpu_map__get_socket(cpus, cpu);
- if (s < 0)
- return -1;
-
- *skip = test_and_set_bit(s, mask) == 1;
- return 0;
-}
-
-static int
-process_counter_values(struct perf_stat_config *config, struct perf_evsel *evsel,
- int cpu, int thread,
- struct perf_counts_values *count)
-{
- struct perf_counts_values *aggr = &evsel->counts->aggr;
- static struct perf_counts_values zero;
- bool skip = false;
-
- if (check_per_pkg(evsel, cpu, &skip)) {
- pr_err("failed to read per-pkg counter\n");
- return -1;
- }
-
- if (skip)
- count = &zero;
-
- switch (config->aggr_mode) {
- case AGGR_THREAD:
- case AGGR_CORE:
- case AGGR_SOCKET:
- case AGGR_NONE:
- if (!evsel->snapshot)
- perf_evsel__compute_deltas(evsel, cpu, thread, count);
- perf_counts_values__scale(count, config->scale, NULL);
- if (config->aggr_mode == AGGR_NONE)
- perf_stat__update_shadow_stats(evsel, count->values, cpu);
- break;
- case AGGR_GLOBAL:
- aggr->val += count->val;
- if (config->scale) {
- aggr->ena += count->ena;
- aggr->run += count->run;
- }
- default:
- break;
- }
-
- return 0;
-}
-
-static int process_counter_maps(struct perf_stat_config *config,
- struct perf_evsel *counter)
-{
- int nthreads = thread_map__nr(counter->threads);
- int ncpus = perf_evsel__nr_cpus(counter);
- int cpu, thread;
-
- if (counter->system_wide)
- nthreads = 1;
-
- for (thread = 0; thread < nthreads; thread++) {
- for (cpu = 0; cpu < ncpus; cpu++) {
- if (process_counter_values(config, counter, cpu, thread,
- perf_counts(counter->counts, cpu, thread)))
- return -1;
- }
- }
-
- return 0;
-}
-
-static int process_counter(struct perf_stat_config *config,
- struct perf_evsel *counter)
-{
- struct perf_counts_values *aggr = &counter->counts->aggr;
- struct perf_stat *ps = counter->priv;
- u64 *count = counter->counts->aggr.values;
- int i, ret;
-
- aggr->val = aggr->ena = aggr->run = 0;
- init_stats(ps->res_stats);
-
- if (counter->per_pkg)
- zero_per_pkg(counter);
-
- ret = process_counter_maps(&stat_config, counter);
- if (ret)
- return ret;
-
- if (config->aggr_mode != AGGR_GLOBAL)
- return 0;
-
- if (!counter->snapshot)
- perf_evsel__compute_deltas(counter, -1, -1, aggr);
- perf_counts_values__scale(aggr, config->scale, &counter->counts->scaled);
-
- for (i = 0; i < 3; i++)
- update_stats(&ps->res_stats[i], count[i]);
-
- if (verbose) {
- fprintf(config->output, "%s: %" PRIu64 " %" PRIu64 " %" PRIu64 "\n",
- perf_evsel__name(counter), count[0], count[1], count[2]);
- }
-
- /*
- * Save the full runtime - to allow normalization during printout:
- */
- perf_stat__update_shadow_stats(counter, count, 0);
-
- return 0;
-}
-
/*
* Read out the results of a single counter:
* do not aggregate counts across CPUs in system-wide mode
@@ -355,7 +216,7 @@ static void read_counters(bool close_counters)
if (read_counter(counter))
pr_warning("failed to read counter %s\n", counter->name);

- if (process_counter(&stat_config, counter))
+ if (perf_stat_process_counter(&stat_config, counter))
pr_warning("failed to process counter %s\n", counter->name);

if (close_counters) {
diff --git a/tools/perf/util/stat.c b/tools/perf/util/stat.c
index f2a0d15..c5c709c 100644
--- a/tools/perf/util/stat.c
+++ b/tools/perf/util/stat.c
@@ -238,3 +238,142 @@ void perf_evlist__reset_stats(struct perf_evlist *evlist)
perf_evsel__reset_counts(evsel);
}
}
+
+static void zero_per_pkg(struct perf_evsel *counter)
+{
+ if (counter->per_pkg_mask)
+ memset(counter->per_pkg_mask, 0, MAX_NR_CPUS);
+}
+
+static int check_per_pkg(struct perf_evsel *counter, int cpu, bool *skip)
+{
+ unsigned long *mask = counter->per_pkg_mask;
+ struct cpu_map *cpus = perf_evsel__cpus(counter);
+ int s;
+
+ *skip = false;
+
+ if (!counter->per_pkg)
+ return 0;
+
+ if (cpu_map__empty(cpus))
+ return 0;
+
+ if (!mask) {
+ mask = zalloc(MAX_NR_CPUS);
+ if (!mask)
+ return -ENOMEM;
+
+ counter->per_pkg_mask = mask;
+ }
+
+ s = cpu_map__get_socket(cpus, cpu);
+ if (s < 0)
+ return -1;
+
+ *skip = test_and_set_bit(s, mask) == 1;
+ return 0;
+}
+
+static int
+process_counter_values(struct perf_stat_config *config, struct perf_evsel *evsel,
+ int cpu, int thread,
+ struct perf_counts_values *count)
+{
+ struct perf_counts_values *aggr = &evsel->counts->aggr;
+ static struct perf_counts_values zero;
+ bool skip = false;
+
+ if (check_per_pkg(evsel, cpu, &skip)) {
+ pr_err("failed to read per-pkg counter\n");
+ return -1;
+ }
+
+ if (skip)
+ count = &zero;
+
+ switch (config->aggr_mode) {
+ case AGGR_THREAD:
+ case AGGR_CORE:
+ case AGGR_SOCKET:
+ case AGGR_NONE:
+ if (!evsel->snapshot)
+ perf_evsel__compute_deltas(evsel, cpu, thread, count);
+ perf_counts_values__scale(count, config->scale, NULL);
+ if (config->aggr_mode == AGGR_NONE)
+ perf_stat__update_shadow_stats(evsel, count->values, cpu);
+ break;
+ case AGGR_GLOBAL:
+ aggr->val += count->val;
+ if (config->scale) {
+ aggr->ena += count->ena;
+ aggr->run += count->run;
+ }
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int process_counter_maps(struct perf_stat_config *config,
+ struct perf_evsel *counter)
+{
+ int nthreads = thread_map__nr(counter->threads);
+ int ncpus = perf_evsel__nr_cpus(counter);
+ int cpu, thread;
+
+ if (counter->system_wide)
+ nthreads = 1;
+
+ for (thread = 0; thread < nthreads; thread++) {
+ for (cpu = 0; cpu < ncpus; cpu++) {
+ if (process_counter_values(config, counter, cpu, thread,
+ perf_counts(counter->counts, cpu, thread)))
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+int perf_stat_process_counter(struct perf_stat_config *config,
+ struct perf_evsel *counter)
+{
+ struct perf_counts_values *aggr = &counter->counts->aggr;
+ struct perf_stat *ps = counter->priv;
+ u64 *count = counter->counts->aggr.values;
+ int i, ret;
+
+ aggr->val = aggr->ena = aggr->run = 0;
+ init_stats(ps->res_stats);
+
+ if (counter->per_pkg)
+ zero_per_pkg(counter);
+
+ ret = process_counter_maps(config, counter);
+ if (ret)
+ return ret;
+
+ if (config->aggr_mode != AGGR_GLOBAL)
+ return 0;
+
+ if (!counter->snapshot)
+ perf_evsel__compute_deltas(counter, -1, -1, aggr);
+ perf_counts_values__scale(aggr, config->scale, &counter->counts->scaled);
+
+ for (i = 0; i < 3; i++)
+ update_stats(&ps->res_stats[i], count[i]);
+
+ if (verbose) {
+ fprintf(config->output, "%s: %" PRIu64 " %" PRIu64 " %" PRIu64 "\n",
+ perf_evsel__name(counter), count[0], count[1], count[2]);
+ }
+
+ /*
+ * Save the full runtime - to allow normalization during printout:
+ */
+ perf_stat__update_shadow_stats(counter, count, 0);
+
+ return 0;
+}
diff --git a/tools/perf/util/stat.h b/tools/perf/util/stat.h
index 1da706d..0b897b0 100644
--- a/tools/perf/util/stat.h
+++ b/tools/perf/util/stat.h
@@ -116,4 +116,7 @@ int perf_evsel__alloc_stats(struct perf_evsel *evsel, bool alloc_raw);
int perf_evlist__alloc_stats(struct perf_evlist *evlist, bool alloc_raw);
void perf_evlist__free_stats(struct perf_evlist *evlist);
void perf_evlist__reset_stats(struct perf_evlist *evlist);
+
+int perf_stat_process_counter(struct perf_stat_config *config,
+ struct perf_evsel *counter);
#endif

2015-08-07 07:46:03

by Jiri Olsa

[permalink] [raw]
Subject: Re: [RFC 00/47] perf stat: Add scripting support

On Thu, Aug 06, 2015 at 04:27:56PM -0300, Arnaldo Carvalho de Melo wrote:
> Em Tue, Jul 21, 2015 at 02:31:20PM +0200, Jiri Olsa escreveu:
> > hi,
> > sending RFC on another attempt for stat scripting.
> >
> > The initial attempt defined its own formula lang and allowed
> > triggering user's script on the end of the stat command:
> > http://marc.info/?l=linux-kernel&m=136742146322273&w=2
> >
> > This patchset abandons the idea of new formula language
> > and rather adds support to:
> > - store stat data into perf.data file
> > - add python support to process stat events
>
> Applied the first 11, some in a previous pull req, the ones moving stuff
> to perf_stat_config now, but the 12nd fails, please check when I get
> these merged by Ingo.

thanks

>
> Also do you intend to do some rework on this due to the conversation
> with Kan? The ones I merged are good anyway, merged.

Kan still did not send his code.. I'll send new version
with review comments and with some enhancements soon

jirka

2015-08-07 13:10:20

by Arnaldo Carvalho de Melo

[permalink] [raw]
Subject: Re: [RFC 00/47] perf stat: Add scripting support

Em Fri, Aug 07, 2015 at 09:45:56AM +0200, Jiri Olsa escreveu:
> On Thu, Aug 06, 2015 at 04:27:56PM -0300, Arnaldo Carvalho de Melo wrote:
> > Applied the first 11, some in a previous pull req, the ones moving stuff
> > to perf_stat_config now, but the 12nd fails, please check when I get
> > these merged by Ingo.

> thanks

> > Also do you intend to do some rework on this due to the conversation
> > with Kan? The ones I merged are good anyway, merged.

> Kan still did not send his code.. I'll send new version
> with review comments and with some enhancements soon

Ok, this is all in tip.git now, BTW.

- Arnaldo