hi, sending another version of stat scripting. v5 changes: - several patches from v4 already taken - using u16 for cpu number in cpu_map_event - renamed PERF_RECORD_HEADER_ATTR_UPDATE to PERF_RECORD_EVENT_UPDATE - moved low hanging fuits patches to the start of the patchset - patchset tested by Kan Liang, thanks! v4 changes: - added attr update event for event's cpumask - forbig aggregation on task workloads - some minor reorders and changelog fixes v3 changes: - added attr update event to handle unit,scale,name for event it fixed the uncore_imc_1/cas_count_read/ record/report - perf report -D now displays stat related events - some minor and changelog fixes v2 changes: - rebased to latest Arnaldo's perf/core - patches 1 to 11 already merged in - added --per-core/--per-socket/-A options for perf stat report command to allow custom aggregation in stat report, please check new examples below - couple changelogs changes 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. 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 thanks, jirka 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 - To display different aggregation in report: $ perf stat -e cycles -a -I 1000 record sleep 3 # time counts unit events 1.000223609 703,427,617 cycles 2.000443651 609,975,307 cycles 3.000569616 668,479,597 cycles 3.000735323 1,155,816 cycles $ perf stat report # time counts unit events 1.000223609 703,427,617 cycles 2.000443651 609,975,307 cycles 3.000569616 668,479,597 cycles 3.000735323 1,155,816 cycles $ perf stat report --per-core # time core cpus counts unit events 1.000223609 S0-C0 2 327,612,412 cycles 1.000223609 S0-C1 2 375,815,205 cycles 2.000443651 S0-C0 2 287,462,177 cycles 2.000443651 S0-C1 2 322,513,130 cycles 3.000569616 S0-C0 2 271,571,908 cycles 3.000569616 S0-C1 2 396,907,689 cycles 3.000735323 S0-C0 2 694,977 cycles 3.000735323 S0-C1 2 460,839 cycles $ perf stat report --per-socket # time socket cpus counts unit events 1.000223609 S0 4 703,427,617 cycles 2.000443651 S0 4 609,975,307 cycles 3.000569616 S0 4 668,479,597 cycles 3.000735323 S0 4 1,155,816 cycles $ perf stat report -A # time CPU counts unit events 1.000223609 CPU0 205,431,505 cycles 1.000223609 CPU1 122,180,907 cycles 1.000223609 CPU2 176,649,682 cycles 1.000223609 CPU3 199,165,523 cycles 2.000443651 CPU0 148,447,922 cycles 2.000443651 CPU1 139,014,255 cycles 2.000443651 CPU2 204,436,559 cycles 2.000443651 CPU3 118,076,571 cycles 3.000569616 CPU0 149,788,954 cycles 3.000569616 CPU1 121,782,954 cycles 3.000569616 CPU2 247,277,700 cycles 3.000569616 CPU3 149,629,989 cycles 3.000735323 CPU0 269,675 cycles 3.000735323 CPU1 425,302 cycles 3.000735323 CPU2 364,169 cycles 3.000735323 CPU3 96,670 cycles Cc: Andi Kleen <andi@firstfloor.org> Cc: Ulrich Drepper <drepper@gmail.com> Cc: Will Deacon <will.deacon@arm.com> Cc: Stephane Eranian <eranian@google.com> Cc: Don Zickus <dzickus@redhat.com> Tested-by: Kan Liang <kan.liang@intel.com> --- Jiri Olsa (52): perf cpu_map: Add cpu_map__empty_new function perf stat: Cache aggregated map entries in extra cpumap 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 perf_event__fprintf_thread_map 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 perf_event__fprintf_cpu_map 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: Add stat events fprintf functions perf tools: Add event_update event perf tools: Add event_update event unit type perf tools: Add event_update event scale type perf tools: Add event_update event name type perf tools: Add event_update event cpus type perf tools: Add perf_event__fprintf_event_update function perf report: Display newly added events in raw dump 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 record: Do not allow record with multiple runs mode perf stat record: Synthesize event update events perf stat report: Add report command perf stat report: Process cpu/threads maps perf stat report: Process stat config event perf stat report: Add support to initialize aggr_map from file perf stat report: Process stat and stat round events perf stat report: Process event update events perf stat report: Move csv_sep initialization before report command perf stat report: Allow to override aggr_mode 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 | 34 ++ tools/perf/builtin-record.c | 2 + tools/perf/builtin-script.c | 139 +++++ tools/perf/builtin-stat.c | 643 ++++++++++++++++++++- tools/perf/scripts/python/stat-cpi.py | 74 +++ tools/perf/tests/Build | 3 + tools/perf/tests/builtin-test.c | 24 + tools/perf/tests/cpumap.c | 88 +++ tools/perf/tests/event_update.c | 117 ++++ tools/perf/tests/stat.c | 111 ++++ tools/perf/tests/tests.h | 7 + tools/perf/tests/thread-map.c | 43 ++ tools/perf/util/cpumap.c | 59 ++ tools/perf/util/cpumap.h | 2 + tools/perf/util/event.c | 308 ++++++++++ tools/perf/util/event.h | 150 ++++- tools/perf/util/evlist.c | 6 +- tools/perf/util/evlist.h | 3 + tools/perf/util/evsel.h | 2 +- tools/perf/util/header.c | 205 +++++++ tools/perf/util/header.h | 17 + .../util/scripting-engines/trace-event-python.c | 114 +++- tools/perf/util/session.c | 189 ++++++ tools/perf/util/stat.c | 62 ++ tools/perf/util/stat.h | 10 + tools/perf/util/thread_map.c | 27 + tools/perf/util/thread_map.h | 3 + tools/perf/util/tool.h | 8 +- tools/perf/util/trace-event.h | 4 + 29 files changed, 2427 insertions(+), 27 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/event_update.c create mode 100644 tools/perf/tests/stat.c
Adding cpu_map__empty_new interface to create empty cpumap with given size. The cpumap entries are initialized with -1. It'll be used for caching cpu_map in following patches. Link: http://lkml.kernel.org/n/tip-2q9tmp3shdscmtiv6h8afhvd@git.kernel.org Signed-off-by: Jiri Olsa <jolsa@kernel.org> --- tools/perf/util/cpumap.c | 17 +++++++++++++++++ tools/perf/util/cpumap.h | 1 + 2 files changed, 18 insertions(+) diff --git a/tools/perf/util/cpumap.c b/tools/perf/util/cpumap.c index aa6b490aa471..10af1e7524fb 100644 --- a/tools/perf/util/cpumap.c +++ b/tools/perf/util/cpumap.c @@ -203,6 +203,23 @@ struct cpu_map *cpu_map__dummy_new(void) return cpus; } +struct cpu_map *cpu_map__empty_new(int nr) +{ + struct cpu_map *cpus = malloc(sizeof(*cpus) + sizeof(int) * nr); + + if (cpus != NULL) { + int i; + + cpus->nr = nr; + for (i = 0; i < nr; i++) + cpus->map[i] = -1; + + atomic_set(&cpus->refcnt, 1); + } + + return cpus; +} + static void cpu_map__delete(struct cpu_map *map) { if (map) { diff --git a/tools/perf/util/cpumap.h b/tools/perf/util/cpumap.h index f1bcd2cfa164..85f7772457fa 100644 --- a/tools/perf/util/cpumap.h +++ b/tools/perf/util/cpumap.h @@ -15,6 +15,7 @@ struct cpu_map { }; struct cpu_map *cpu_map__new(const char *cpu_list); +struct cpu_map *cpu_map__empty_new(int nr); struct cpu_map *cpu_map__dummy_new(void); struct cpu_map *cpu_map__read(FILE *file); size_t cpu_map__fprintf(struct cpu_map *map, FILE *fp); -- 2.4.3
Currently any time we need to access socket or core id for given cpu, we access the sysfs topology file. Adding cpus_aggr_map cpu_map to cache those entries. Link: http://lkml.kernel.org/n/tip-2cw82b5piydhao8sft09am3r@git.kernel.org Signed-off-by: Jiri Olsa <jolsa@kernel.org> --- tools/perf/builtin-stat.c | 60 +++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 56 insertions(+), 4 deletions(-) diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index 91e793a76929..a3880aa65b04 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -100,6 +100,8 @@ static struct target target = { .uid = UINT_MAX, }; +typedef int (*aggr_get_id_t)(struct cpu_map *m, int cpu); + static int run_count = 1; static bool no_inherit = false; static volatile pid_t child_pid = -1; @@ -119,7 +121,7 @@ static unsigned int unit_width = 4; /* strlen("unit") */ static bool forever = false; static struct timespec ref_time; static struct cpu_map *aggr_map; -static int (*aggr_get_id)(struct cpu_map *m, int cpu); +static aggr_get_id_t aggr_get_id; static volatile int done = 0; @@ -944,6 +946,7 @@ static int stat__set_big_num(const struct option *opt __maybe_unused, return 0; } + static int perf_stat__get_socket(struct cpu_map *map, int cpu) { return cpu_map__get_socket(map, cpu, NULL); @@ -954,22 +957,63 @@ static int perf_stat__get_core(struct cpu_map *map, int cpu) return cpu_map__get_core(map, cpu, NULL); } +static int cpu_map__get_max(struct cpu_map *map) +{ + int i, max = -1; + + for (i = 0; i < map->nr; i++) { + if (map->map[i] > max) + max = map->map[i]; + } + + return max; +} + +static struct cpu_map *cpus_aggr_map; + +static int perf_stat__get_aggr(aggr_get_id_t get_id, struct cpu_map *map, int idx) +{ + int cpu; + + if (idx >= map->nr) + return -1; + + cpu = map->map[idx]; + + if (cpus_aggr_map->map[cpu] == -1) + cpus_aggr_map->map[cpu] = get_id(map, idx); + + return cpus_aggr_map->map[cpu]; +} + +static int perf_stat__get_socket_cached(struct cpu_map *map, int idx) +{ + return perf_stat__get_aggr(perf_stat__get_socket, map, idx); +} + +static int perf_stat__get_core_cached(struct cpu_map *map, int idx) +{ + return perf_stat__get_aggr(perf_stat__get_core, map, idx); +} + static int perf_stat_init_aggr_mode(void) { + int nr; + switch (stat_config.aggr_mode) { case AGGR_SOCKET: if (cpu_map__build_socket_map(evsel_list->cpus, &aggr_map)) { perror("cannot build socket map"); return -1; } - aggr_get_id = perf_stat__get_socket; + aggr_get_id = perf_stat__get_socket_cached; break; case AGGR_CORE: if (cpu_map__build_core_map(evsel_list->cpus, &aggr_map)) { perror("cannot build core map"); return -1; } - aggr_get_id = perf_stat__get_core; + aggr_get_id = perf_stat__get_core_cached; break; case AGGR_NONE: case AGGR_GLOBAL: @@ -978,7 +1022,15 @@ static int perf_stat_init_aggr_mode(void) default: break; } - return 0; + + /* + * The evsel_list->cpus is the base we operate on, + * taking the highest cpu number to be the size of + * the aggregation translate cpumap. + */ + nr = cpu_map__get_max(evsel_list->cpus); + cpus_aggr_map = cpu_map__empty_new(nr + 1); + return cpus_aggr_map ? 0 : -ENOMEM; } /* -- 2.4.3
Adding thread_map event to pass/store thread maps as data in pipe/perf.data. Storing thread ID along with the standard comm[16] thread name string. Link: http://lkml.kernel.org/n/tip-2l07qyf3buhnt83q4ezqz5sj@git.kernel.org Signed-off-by: Jiri Olsa <jolsa@kernel.org> --- 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 8b10621b415c..771545a27b9b 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_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 a0dbcbd4f6d8..f075f9ed0051 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_INFO = 70, PERF_RECORD_AUXTRACE = 71, PERF_RECORD_AUXTRACE_ERROR = 72, + PERF_RECORD_THREAD_MAP = 73, PERF_RECORD_HEADER_MAX }; @@ -356,6 +357,17 @@ struct context_switch_event { u32 next_prev_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; @@ -378,6 +390,7 @@ union perf_event { struct aux_event aux; struct itrace_start_event itrace_start; struct context_switch_event context_switch; + 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 428149bc64d2..ec1ecd31003b 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -296,6 +296,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) @@ -346,6 +356,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); @@ -643,6 +666,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, }; @@ -1179,6 +1203,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 cab8cc24831b..1af4774960c3 100644 --- a/tools/perf/util/tool.h +++ b/tools/perf/util/tool.h @@ -55,7 +55,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
Introduce perf_event__synthesize_thread_map2 function to synthesize struct thread_map. The perf_event__synthesize_thread_map name is already taken for synthesizing complete threads data (comm/mmap/fork). Link: http://lkml.kernel.org/n/tip-cykuf1v8qb6li8q6w6tbm05w@git.kernel.org Signed-off-by: Jiri Olsa <jolsa@kernel.org> --- 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 66f72d3d6677..a59fd320da64 100644 --- a/tools/perf/tests/builtin-test.c +++ b/tools/perf/tests/builtin-test.c @@ -166,6 +166,10 @@ static struct test generic_tests[] = { .func = test_session_topology, }, { + .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 c80486969f83..2e280a5cd579 100644 --- a/tools/perf/tests/tests.h +++ b/tools/perf/tests/tests.h @@ -67,6 +67,7 @@ int test__kmod_path__parse(void); int test__thread_map(void); int test__llvm(void); int test_session_topology(void); +int test__thread_map_synthesize(void); #if 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 771545a27b9b..10e852201955 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c @@ -700,6 +700,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 f075f9ed0051..3ef69fef4497 100644 --- a/tools/perf/util/event.h +++ b/tools/perf/util/event.h @@ -408,6 +408,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
Introducing thread_map__new_event function to create struct thread_map object from thread_map event. Link: http://lkml.kernel.org/n/tip-0gu5uv3g51p4mzul93bhh2yh@git.kernel.org Signed-off-by: Jiri Olsa <jolsa@kernel.org> --- 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 6ec3c5ca438f..04b8dc368cbb 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) @@ -408,3 +409,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
To display thread_map event for raw dump. Link: http://lkml.kernel.org/n/tip-q60h5rhe4mmyvzkjst64ewhk@git.kernel.org Signed-off-by: Jiri Olsa <jolsa@kernel.org> --- tools/perf/util/event.c | 16 ++++++++++++++++ tools/perf/util/event.h | 1 + 2 files changed, 17 insertions(+) diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index 10e852201955..ec2965b139a4 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c @@ -820,6 +820,22 @@ size_t perf_event__fprintf_mmap2(union perf_event *event, FILE *fp) event->mmap2.filename); } +size_t perf_event__fprintf_thread_map(union perf_event *event, FILE *fp) +{ + struct thread_map *threads = thread_map__new_event(&event->thread_map); + size_t ret; + + ret = fprintf(fp, " nr: "); + + if (threads) + ret += thread_map__fprintf(threads, fp); + else + ret += fprintf(fp, "failed to get threads from event\n"); + + thread_map__put(threads); + return ret; +} + int perf_event__process_mmap(struct perf_tool *tool __maybe_unused, union perf_event *event, struct perf_sample *sample, diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h index 3ef69fef4497..75157f3b16fb 100644 --- a/tools/perf/util/event.h +++ b/tools/perf/util/event.h @@ -516,6 +516,7 @@ size_t perf_event__fprintf_task(union perf_event *event, FILE *fp); size_t perf_event__fprintf_aux(union perf_event *event, FILE *fp); size_t perf_event__fprintf_itrace_start(union perf_event *event, FILE *fp); size_t perf_event__fprintf_switch(union perf_event *event, FILE *fp); +size_t perf_event__fprintf_thread_map(union perf_event *event, FILE *fp); size_t perf_event__fprintf(union perf_event *event, FILE *fp); u64 kallsyms__get_function_start(const char *kallsyms_filename, -- 2.4.3
Adding cpu_map event to pass/store cpu maps as data in pipe/perf.data. We store maps in 2 formats: - list of cpus - mask of cpus The format that takes less space is selected transparently in following patch. The interface is made generic, so we could add cpumap event data into another event in following patches. Link: http://lkml.kernel.org/n/tip-tomgwwohnuxvvalwu4znaa2o@git.kernel.org Signed-off-by: Jiri Olsa <jolsa@kernel.org> --- tools/perf/util/event.c | 1 + tools/perf/util/event.h | 28 ++++++++++++++++++++++++++ tools/perf/util/session.c | 50 +++++++++++++++++++++++++++++++++++++++++++++++ tools/perf/util/tool.h | 3 ++- 4 files changed, 81 insertions(+), 1 deletion(-) diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index ec2965b139a4..c05f4b036069 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c @@ -38,6 +38,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 75157f3b16fb..4df6f9c60406 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 = 71, PERF_RECORD_AUXTRACE_ERROR = 72, PERF_RECORD_THREAD_MAP = 73, + PERF_RECORD_CPU_MAP = 74, PERF_RECORD_HEADER_MAX }; @@ -271,6 +272,32 @@ struct events_stats { u32 nr_proc_map_timeout; }; +enum { + PERF_CPU_MAP__CPUS = 0, + PERF_CPU_MAP__MASK = 1, +}; + +struct cpu_map_data_cpus { + u16 nr; + u16 cpu[]; +}; + +struct cpu_map_data_mask { + u16 nr; + u16 long_size; + unsigned long mask[]; +}; + +struct cpu_map_data { + u16 type; + char data[]; +}; + +struct cpu_map_event { + struct perf_event_header header; + struct cpu_map_data data; +}; + struct attr_event { struct perf_event_header header; struct perf_event_attr attr; @@ -391,6 +418,7 @@ union perf_event { struct itrace_start_event itrace_start; struct context_switch_event context_switch; 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 ec1ecd31003b..5126b18c671c 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -306,6 +306,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) @@ -358,6 +367,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,42 @@ 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) +{ + struct cpu_map_data *data = &event->cpu_map.data; + struct cpu_map_data_cpus *cpus; + struct cpu_map_data_mask *mask; + unsigned i; + + data->type = bswap_64(data->type); + + switch (data->type) { + case PERF_CPU_MAP__CPUS: + cpus = (struct cpu_map_data_cpus *) data->data; + + cpus->nr = bswap_16(cpus->nr); + + for (i = 0; i < cpus->nr; i++) + cpus->cpu[i] = bswap_16(cpus->cpu[i]); + break; + case PERF_CPU_MAP__MASK: + mask = (struct cpu_map_data_mask *) data->data; + + mask->nr = bswap_16(mask->nr); + mask->long_size = bswap_16(mask->long_size); + + switch (mask->long_size) { + case 4: mem_bswap_32(&mask->mask, mask->nr); break; + case 8: mem_bswap_64(&mask->mask, mask->nr); break; + default: + pr_err("cpu_map swap: unsupported long size\n"); + } + default: + break; + } +} + typedef void (*perf_event__swap_op)(union perf_event *event, bool sample_id_all); @@ -667,6 +714,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, }; @@ -1205,6 +1253,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 1af4774960c3..9e5925c78519 100644 --- a/tools/perf/util/tool.h +++ b/tools/perf/util/tool.h @@ -56,7 +56,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
Introduce perf_event__synthesize_cpu_map function to synthesize struct cpu_map. Added generic interface: cpu_map_data__alloc cpu_map_data__synthesize to make the cpu_map synthesizing usable for other events. Link: http://lkml.kernel.org/n/tip-miidn8vqsx3udu4ct8103v5f@git.kernel.org Signed-off-by: Jiri Olsa <jolsa@kernel.org> --- tools/perf/tests/Build | 1 + tools/perf/tests/builtin-test.c | 4 ++ tools/perf/tests/cpumap.c | 71 ++++++++++++++++++++++ tools/perf/tests/tests.h | 1 + tools/perf/util/event.c | 131 ++++++++++++++++++++++++++++++++++++++++ tools/perf/util/event.h | 8 +++ 6 files changed, 216 insertions(+) create mode 100644 tools/perf/tests/cpumap.c diff --git a/tools/perf/tests/Build b/tools/perf/tests/Build index 50de2253cff6..1c0296fc95ea 100644 --- a/tools/perf/tests/Build +++ b/tools/perf/tests/Build @@ -33,6 +33,7 @@ perf-y += kmod-path.o perf-y += thread-map.o perf-y += llvm.o perf-y += topology.o +perf-y += cpumap.o ifeq ($(ARCH),$(filter $(ARCH),x86 arm arm64)) perf-$(CONFIG_DWARF_UNWIND) += dwarf-unwind.o diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c index a59fd320da64..bdccd27868ba 100644 --- a/tools/perf/tests/builtin-test.c +++ b/tools/perf/tests/builtin-test.c @@ -170,6 +170,10 @@ static struct test generic_tests[] = { .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..dc923ec7688f --- /dev/null +++ b/tools/perf/tests/cpumap.c @@ -0,0 +1,71 @@ +#include "tests.h" +#include "cpumap.h" + +static int process_event_mask(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; + struct cpu_map_data_mask *mask; + struct cpu_map_data *data; + int i; + + data = &map->data; + + TEST_ASSERT_VAL("wrong type", data->type == PERF_CPU_MAP__MASK); + + mask = (struct cpu_map_data_mask *) data->data; + + TEST_ASSERT_VAL("wrong nr", mask->nr == 1); + + for (i = 0; i < 20; i++) { + TEST_ASSERT_VAL("wrong cpu", test_bit(i, mask->mask)); + } + + return 0; +} + +static int process_event_cpus(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; + struct cpu_map_data_cpus *cpus; + struct cpu_map_data *data; + + data = &map->data; + + TEST_ASSERT_VAL("wrong type", data->type == PERF_CPU_MAP__CPUS); + + cpus = (struct cpu_map_data_cpus *) data->data; + + TEST_ASSERT_VAL("wrong nr", cpus->nr == 2); + TEST_ASSERT_VAL("wrong cpu", cpus->cpu[0] == 1); + TEST_ASSERT_VAL("wrong cpu", cpus->cpu[1] == 256); + return 0; +} + + +int test__cpu_map_synthesize(void) +{ + struct cpu_map *cpus; + + /* This one is better stores in mask. */ + cpus = cpu_map__new("0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19"); + + TEST_ASSERT_VAL("failed to synthesize map", + !perf_event__synthesize_cpu_map(NULL, cpus, process_event_mask, NULL)); + + cpu_map__put(cpus); + + /* This one is better stores in cpu values. */ + cpus = cpu_map__new("1,256"); + + TEST_ASSERT_VAL("failed to synthesize map", + !perf_event__synthesize_cpu_map(NULL, cpus, process_event_cpus, NULL)); + + cpu_map__put(cpus); + return 0; +} diff --git a/tools/perf/tests/tests.h b/tools/perf/tests/tests.h index 2e280a5cd579..c7f3c3211bcf 100644 --- a/tools/perf/tests/tests.h +++ b/tools/perf/tests/tests.h @@ -68,6 +68,7 @@ int test__thread_map(void); int test__llvm(void); int test_session_topology(void); int test__thread_map_synthesize(void); +int test__cpu_map_synthesize(void); #if defined(__arm__) || defined(__aarch64__) #ifdef HAVE_DWARF_UNWIND_SUPPORT diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index c05f4b036069..a04bdabb7ae9 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c @@ -737,6 +737,137 @@ int perf_event__synthesize_thread_map2(struct perf_tool *tool, return err; } +static void synthesize_cpus(struct cpu_map_data_cpus *cpus, + struct cpu_map *map) +{ + int i; + + cpus->nr = map->nr; + + for (i = 0; i < map->nr; i++) + cpus->cpu[i] = map->map[i]; +} + +static void synthesize_mask(struct cpu_map_data_mask *mask, + struct cpu_map *map, int max) +{ + int i; + + mask->nr = BITS_TO_LONGS(max); + mask->long_size = sizeof(long); + + for (i = 0; i < map->nr; i++) + set_bit(map->map[i], mask->mask); +} + +static size_t cpus_size(struct cpu_map *map) +{ + return sizeof(struct cpu_map_data_cpus) + map->nr * sizeof(u16); +} + +static size_t mask_size(struct cpu_map *map, int *max) +{ + int i; + + *max = 0; + + for (i = 0; i < map->nr; i++) { + /* bit possition of the cpu is + 1 */ + int bit = map->map[i] + 1; + + if (bit > *max) + *max = bit; + } + + return sizeof(struct cpu_map_data_mask) + BITS_TO_LONGS(*max) * sizeof(long); +} + +void *cpu_map_data__alloc(struct cpu_map *map, size_t *size, u16 *type, int *max) +{ + size_t size_cpus, size_mask; + bool is_dummy = cpu_map__empty(map); + + /* + * Both array and mask data have variable size based + * on the number of cpus and their actual values. + * The size of the 'struct cpu_map_data' is: + * + * array = size of 'struct cpu_map_data_cpus' + + * number of cpus * sizeof(u64) + * + * mask = size of 'struct cpu_map_data_mask' + + * maximum cpu bit converted to size of longs + * + * and finaly + the size of 'struct cpu_map_data'. + */ + size_cpus = cpus_size(map); + size_mask = mask_size(map, max); + + if (is_dummy || (size_cpus < size_mask)) { + *size += size_cpus; + *type = PERF_CPU_MAP__CPUS; + } else { + *size += size_mask; + *type = PERF_CPU_MAP__MASK; + } + + *size += sizeof(struct cpu_map_data); + return zalloc(*size); +} + +void cpu_map_data__synthesize(struct cpu_map_data *data, struct cpu_map *map, + u16 type, int max) +{ + data->type = type; + + switch (type) { + case PERF_CPU_MAP__CPUS: + synthesize_cpus((struct cpu_map_data_cpus *) data->data, map); + break; + case PERF_CPU_MAP__MASK: + synthesize_mask((struct cpu_map_data_mask *) data->data, map, max); + default: + break; + }; +} + +static struct cpu_map_event* cpu_map_event__new(struct cpu_map *map) +{ + size_t size = sizeof(struct cpu_map_event); + struct cpu_map_event *event; + int max; + u16 type; + + event = cpu_map_data__alloc(map, &size, &type, &max); + if (!event) + return NULL; + + event->header.type = PERF_RECORD_CPU_MAP; + event->header.size = size; + event->data.type = type; + + cpu_map_data__synthesize(&event->data, map, type, max); + return event; +} + +int perf_event__synthesize_cpu_map(struct perf_tool *tool, + struct cpu_map *map, + perf_event__handler_t process, + struct machine *machine) +{ + struct cpu_map_event *event; + int err; + + event = cpu_map_event__new(map); + if (!event) + return -ENOMEM; + + 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 4df6f9c60406..5f5560d039d7 100644 --- a/tools/perf/util/event.h +++ b/tools/perf/util/event.h @@ -425,6 +425,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, @@ -440,6 +441,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, @@ -550,4 +555,7 @@ size_t perf_event__fprintf(union perf_event *event, FILE *fp); u64 kallsyms__get_function_start(const char *kallsyms_filename, const char *symbol_name); +void *cpu_map_data__alloc(struct cpu_map *map, size_t *size, u16 *type, int *max); +void cpu_map_data__synthesize(struct cpu_map_data *data, struct cpu_map *map, + u16 type, int max); #endif /* __PERF_RECORD_H */ -- 2.4.3
Introducing cpu_map__new_event function to create struct cpu_map object from cpu_map event. Link: http://lkml.kernel.org/n/tip-tepv49tbjsqeprmf8k05lc6r@git.kernel.org Signed-off-by: Jiri Olsa <jolsa@kernel.org> --- tools/perf/tests/cpumap.c | 25 +++++++++++++++++++++---- tools/perf/util/cpumap.c | 42 ++++++++++++++++++++++++++++++++++++++++++ tools/perf/util/cpumap.h | 1 + 3 files changed, 64 insertions(+), 4 deletions(-) diff --git a/tools/perf/tests/cpumap.c b/tools/perf/tests/cpumap.c index dc923ec7688f..cf67c7b07be2 100644 --- a/tools/perf/tests/cpumap.c +++ b/tools/perf/tests/cpumap.c @@ -6,12 +6,13 @@ static int process_event_mask(struct perf_tool *tool __maybe_unused, struct perf_sample *sample __maybe_unused, struct machine *machine __maybe_unused) { - struct cpu_map_event *map = &event->cpu_map; + struct cpu_map_event *map_event = &event->cpu_map; struct cpu_map_data_mask *mask; struct cpu_map_data *data; + struct cpu_map *map; int i; - data = &map->data; + data = &map_event->data; TEST_ASSERT_VAL("wrong type", data->type == PERF_CPU_MAP__MASK); @@ -23,6 +24,14 @@ static int process_event_mask(struct perf_tool *tool __maybe_unused, TEST_ASSERT_VAL("wrong cpu", test_bit(i, mask->mask)); } + map = cpu_map__new_data(data); + TEST_ASSERT_VAL("wrong nr", map->nr == 20); + + for (i = 0; i < 20; i++) { + TEST_ASSERT_VAL("wrong cpu", map->map[i] == i); + } + + cpu_map__put(map); return 0; } @@ -31,11 +40,12 @@ static int process_event_cpus(struct perf_tool *tool __maybe_unused, struct perf_sample *sample __maybe_unused, struct machine *machine __maybe_unused) { - struct cpu_map_event *map = &event->cpu_map; + struct cpu_map_event *map_event = &event->cpu_map; struct cpu_map_data_cpus *cpus; struct cpu_map_data *data; + struct cpu_map *map; - data = &map->data; + data = &map_event->data; TEST_ASSERT_VAL("wrong type", data->type == PERF_CPU_MAP__CPUS); @@ -44,6 +54,13 @@ static int process_event_cpus(struct perf_tool *tool __maybe_unused, TEST_ASSERT_VAL("wrong nr", cpus->nr == 2); TEST_ASSERT_VAL("wrong cpu", cpus->cpu[0] == 1); TEST_ASSERT_VAL("wrong cpu", cpus->cpu[1] == 256); + + map = cpu_map__new_data(data); + TEST_ASSERT_VAL("wrong nr", map->nr == 2); + TEST_ASSERT_VAL("wrong cpu", map->map[0] == 1); + TEST_ASSERT_VAL("wrong cpu", map->map[1] == 256); + TEST_ASSERT_VAL("wrong refcnt", atomic_read(&map->refcnt) == 1); + cpu_map__put(map); return 0; } diff --git a/tools/perf/util/cpumap.c b/tools/perf/util/cpumap.c index 10af1e7524fb..00eb4e0c438b 100644 --- a/tools/perf/util/cpumap.c +++ b/tools/perf/util/cpumap.c @@ -5,6 +5,7 @@ #include <assert.h> #include <stdio.h> #include <stdlib.h> +#include <linux/bitmap.h> #include "asm/bug.h" static struct cpu_map *cpu_map__default_new(void) @@ -179,6 +180,47 @@ out: return cpus; } +static struct cpu_map *cpu_map__from_cpus(struct cpu_map_data_cpus *cpus) +{ + struct cpu_map *map; + + map = cpu_map__empty_new(cpus->nr); + if (map) { + unsigned i; + + for (i = 0; i < cpus->nr; i++) + map->map[i] = (int) cpus->cpu[i]; + } + + return map; +} + +static struct cpu_map *cpu_map__from_mask(struct cpu_map_data_mask *mask) +{ + struct cpu_map *map; + int nr, nbits = mask->nr * mask->long_size * BITS_PER_BYTE; + + nr = bitmap_weight(mask->mask, nbits); + + map = cpu_map__empty_new(nr); + if (map) { + int cpu, i = 0; + + for_each_set_bit(cpu, mask->mask, nbits) + map->map[i++] = cpu; + } + return map; + +} + +struct cpu_map *cpu_map__new_data(struct cpu_map_data *data) +{ + if (data->type == PERF_CPU_MAP__CPUS) + return cpu_map__from_cpus((struct cpu_map_data_cpus *) data->data); + else + return cpu_map__from_mask((struct cpu_map_data_mask *) data->data); +} + 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 85f7772457fa..71c41b9efabb 100644 --- a/tools/perf/util/cpumap.h +++ b/tools/perf/util/cpumap.h @@ -17,6 +17,7 @@ struct cpu_map { struct cpu_map *cpu_map__new(const char *cpu_list); struct cpu_map *cpu_map__empty_new(int nr); struct cpu_map *cpu_map__dummy_new(void); +struct cpu_map *cpu_map__new_data(struct cpu_map_data *data); struct cpu_map *cpu_map__read(FILE *file); size_t cpu_map__fprintf(struct cpu_map *map, FILE *fp); int cpu_map__get_socket_id(int cpu); -- 2.4.3
To display cpu_map event for raw dump. Link: http://lkml.kernel.org/n/tip-3uv795xlylejtbkf76om5rb5@git.kernel.org Signed-off-by: Jiri Olsa <jolsa@kernel.org> --- tools/perf/util/event.c | 16 ++++++++++++++++ tools/perf/util/event.h | 1 + 2 files changed, 17 insertions(+) diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index a04bdabb7ae9..36dc992b072f 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c @@ -968,6 +968,22 @@ size_t perf_event__fprintf_thread_map(union perf_event *event, FILE *fp) return ret; } +size_t perf_event__fprintf_cpu_map(union perf_event *event, FILE *fp) +{ + struct cpu_map *cpus = cpu_map__new_data(&event->cpu_map.data); + size_t ret; + + ret = fprintf(fp, " nr: "); + + if (cpus) + ret += cpu_map__fprintf(cpus, fp); + else + ret += fprintf(fp, "failed to get cpumap from event\n"); + + cpu_map__put(cpus); + return ret; +} + int perf_event__process_mmap(struct perf_tool *tool __maybe_unused, union perf_event *event, struct perf_sample *sample, diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h index 5f5560d039d7..e46f95285350 100644 --- a/tools/perf/util/event.h +++ b/tools/perf/util/event.h @@ -550,6 +550,7 @@ size_t perf_event__fprintf_aux(union perf_event *event, FILE *fp); size_t perf_event__fprintf_itrace_start(union perf_event *event, FILE *fp); size_t perf_event__fprintf_switch(union perf_event *event, FILE *fp); size_t perf_event__fprintf_thread_map(union perf_event *event, FILE *fp); +size_t perf_event__fprintf_cpu_map(union perf_event *event, FILE *fp); size_t perf_event__fprintf(union perf_event *event, FILE *fp); u64 kallsyms__get_function_start(const char *kallsyms_filename, -- 2.4.3
Adding stat config event to pass/store stat config data, so report tools (report/script) know how to interpret stat data. The config data are stored in 'tag|value' way to allow easy extension and backward compatibility. Link: http://lkml.kernel.org/n/tip-1npdsfez8635vogthpqwtkd0@git.kernel.org Signed-off-by: Jiri Olsa <jolsa@kernel.org> --- 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 36dc992b072f..1165cb1d891f 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_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 e46f95285350..0bc3393dd28c 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_AUXTRACE_ERROR = 72, PERF_RECORD_THREAD_MAP = 73, PERF_RECORD_CPU_MAP = 74, + PERF_RECORD_STAT_CONFIG = 75, PERF_RECORD_HEADER_MAX }; @@ -395,6 +396,24 @@ struct thread_map_event { struct thread_map_data_event data[]; }; +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; @@ -419,6 +438,7 @@ union perf_event { struct context_switch_event context_switch; 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 5126b18c671c..a550464925ea 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -315,6 +315,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) @@ -369,6 +378,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) @@ -686,6 +697,16 @@ static void perf_event__cpu_map_swap(union perf_event *event, } } +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); @@ -715,6 +736,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, }; @@ -1255,6 +1277,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 9e5925c78519..aa7ae73d76b4 100644 --- a/tools/perf/util/tool.h +++ b/tools/perf/util/tool.h @@ -57,7 +57,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
Introduce perf_event__synthesize_stat_config function to synthesize '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/tip-zof1adf5flwp38xdzxzn4p2z@git.kernel.org Signed-off-by: Jiri Olsa <jolsa@kernel.org> --- 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 | 40 +++++++++++++++++++++++++++++++ tools/perf/util/event.h | 5 ++++ 6 files changed, 104 insertions(+) create mode 100644 tools/perf/tests/stat.c diff --git a/tools/perf/tests/Build b/tools/perf/tests/Build index 1c0296fc95ea..ea4ef8fdd463 100644 --- a/tools/perf/tests/Build +++ b/tools/perf/tests/Build @@ -34,6 +34,7 @@ perf-y += thread-map.o perf-y += llvm.o perf-y += topology.o perf-y += cpumap.o +perf-y += stat.o ifeq ($(ARCH),$(filter $(ARCH),x86 arm arm64)) perf-$(CONFIG_DWARF_UNWIND) += dwarf-unwind.o diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c index bdccd27868ba..1a9064f54da5 100644 --- a/tools/perf/tests/builtin-test.c +++ b/tools/perf/tests/builtin-test.c @@ -174,6 +174,10 @@ static struct test generic_tests[] = { .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 c7f3c3211bcf..227ad216197e 100644 --- a/tools/perf/tests/tests.h +++ b/tools/perf/tests/tests.h @@ -69,6 +69,7 @@ int test__llvm(void); int test_session_topology(void); int test__thread_map_synthesize(void); int test__cpu_map_synthesize(void); +int test__synthesize_stat_config(void); #if defined(__arm__) || defined(__aarch64__) #ifdef HAVE_DWARF_UNWIND_SUPPORT diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index 1165cb1d891f..a9f596cf6ad9 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c @@ -10,6 +10,8 @@ #include "thread.h" #include "thread_map.h" #include "symbol/kallsyms.h" +#include "asm/bug.h" +#include "stat.h" static const char *perf_event__names[] = { [0] = "TOTAL", @@ -869,6 +871,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 0bc3393dd28c..5f246a7cf5ab 100644 --- a/tools/perf/util/event.h +++ b/tools/perf/util/event.h @@ -446,6 +446,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, @@ -472,6 +473,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
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/tip-62ae08zz97jp2qkhygp8uet5@git.kernel.org Signed-off-by: Jiri Olsa <jolsa@kernel.org> --- 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 a9f596cf6ad9..381e0b0bcc8d 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c @@ -909,6 +909,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 5f246a7cf5ab..a9debe60c42b 100644 --- a/tools/perf/util/event.h +++ b/tools/perf/util/event.h @@ -477,6 +477,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
Adding stat event to store 'struct perf_counter_values' for given event/cpu/thread. Link: http://lkml.kernel.org/n/tip-56xpt7m6au4d8u39nffoqgx1@git.kernel.org Signed-off-by: Jiri Olsa <jolsa@kernel.org> --- tools/perf/util/event.c | 1 + tools/perf/util/event.h | 19 +++++++++++++++++++ tools/perf/util/session.c | 25 +++++++++++++++++++++++++ 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 381e0b0bcc8d..dfff3db6077f 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c @@ -42,6 +42,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 a9debe60c42b..91a05c8328d7 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_THREAD_MAP = 73, PERF_RECORD_CPU_MAP = 74, PERF_RECORD_STAT_CONFIG = 75, + PERF_RECORD_STAT = 76, PERF_RECORD_HEADER_MAX }; @@ -414,6 +415,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; @@ -439,6 +457,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 a550464925ea..d165674500e2 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -324,6 +324,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) @@ -380,6 +389,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) @@ -707,6 +718,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); @@ -737,6 +759,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, }; @@ -1279,6 +1302,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 aa7ae73d76b4..f0b9da0c166a 100644 --- a/tools/perf/util/tool.h +++ b/tools/perf/util/tool.h @@ -58,7 +58,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
Introduce perf_event__synthesize_stat function to synthesize 'struct stat_event'. Link: http://lkml.kernel.org/n/tip-0jr9x4vwk0nxbs2ueclj7jfy@git.kernel.org Signed-off-by: Jiri Olsa <jolsa@kernel.org> --- tools/perf/tests/builtin-test.c | 4 ++++ tools/perf/tests/stat.c | 41 ++++++++++++++++++++++++++++++++++++----- tools/perf/tests/tests.h | 1 + tools/perf/util/event.c | 22 ++++++++++++++++++++++ tools/perf/util/event.h | 7 ++++++- 5 files changed, 69 insertions(+), 6 deletions(-) diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c index 1a9064f54da5..87d6244f15f9 100644 --- a/tools/perf/tests/builtin-test.c +++ b/tools/perf/tests/builtin-test.c @@ -178,6 +178,10 @@ static struct test generic_tests[] = { .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..805ff30bb1d5 100644 --- a/tools/perf/tests/stat.c +++ b/tools/perf/tests/stat.c @@ -2,6 +2,7 @@ #include "event.h" #include "tests.h" #include "stat.h" +#include "counts.h" #include "debug.h" static bool has_term(struct stat_config_event *config, @@ -18,10 +19,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 +54,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; + + count.val = 100; + count.ena = 200; + count.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 227ad216197e..edf460e5cd64 100644 --- a/tools/perf/tests/tests.h +++ b/tools/perf/tests/tests.h @@ -70,6 +70,7 @@ int test_session_topology(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(__arm__) || defined(__aarch64__) #ifdef HAVE_DWARF_UNWIND_SUPPORT diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index dfff3db6077f..ebbfdc1c1d3b 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c @@ -910,6 +910,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 91a05c8328d7..1799b06e3fac 100644 --- a/tools/perf/util/event.h +++ b/tools/perf/util/event.h @@ -466,6 +466,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, @@ -498,7 +499,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
Introducing perf_event__process_stat_event function to process 'struct perf_stat' data from stat event. Link: http://lkml.kernel.org/n/tip-2bvpxxp60e0qqcsecohgeju3@git.kernel.org Signed-off-by: Jiri Olsa <jolsa@kernel.org> --- 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 2d9d8306dbd3..40fa99b640f8 100644 --- a/tools/perf/util/stat.c +++ b/tools/perf/util/stat.c @@ -341,3 +341,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 da1d11c4f8c1..afe6844e5219 100644 --- a/tools/perf/util/stat.h +++ b/tools/perf/util/stat.h @@ -90,4 +90,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
Adding stat round event to be stored after each stat interval round, so report tools (report/script) get notified and process interval data. Link: http://lkml.kernel.org/n/tip-nqhzuxrv12ulccx11k7x86mr@git.kernel.org Signed-off-by: Jiri Olsa <jolsa@kernel.org> --- tools/perf/util/event.c | 1 + tools/perf/util/event.h | 13 +++++++++++++ tools/perf/util/session.c | 21 +++++++++++++++++++++ tools/perf/util/tool.h | 3 ++- 4 files changed, 37 insertions(+), 1 deletion(-) diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index ebbfdc1c1d3b..164d13c88c0e 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c @@ -43,6 +43,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 1799b06e3fac..7e8427dfb59e 100644 --- a/tools/perf/util/event.h +++ b/tools/perf/util/event.h @@ -230,6 +230,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 }; @@ -432,6 +433,17 @@ struct stat_event { }; }; +enum { + PERF_STAT_ROUND_TYPE__INTERVAL = 0, + PERF_STAT_ROUND_TYPE__FINAL = 1, +}; + +struct stat_round_event { + struct perf_event_header header; + u64 type; + u64 time; +}; + union perf_event { struct perf_event_header header; struct mmap_event mmap; @@ -458,6 +470,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 d165674500e2..c6c28194d65b 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -333,6 +333,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) @@ -391,6 +400,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) @@ -729,6 +740,13 @@ 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.type = bswap_64(event->stat_round.type); + event->stat_round.time = bswap_64(event->stat_round.time); +} + typedef void (*perf_event__swap_op)(union perf_event *event, bool sample_id_all); @@ -760,6 +778,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, }; @@ -1304,6 +1323,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 f0b9da0c166a..d04d9e5f444a 100644 --- a/tools/perf/util/tool.h +++ b/tools/perf/util/tool.h @@ -59,7 +59,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
Introduce perf_event__synthesize_stat_round function to synthesize 'struct stat_round_event'. Link: http://lkml.kernel.org/n/tip-gl8rk2il9grrnqalrqlo7iym@git.kernel.org Signed-off-by: Jiri Olsa <jolsa@kernel.org> --- tools/perf/tests/builtin-test.c | 4 ++++ tools/perf/tests/stat.c | 21 +++++++++++++++++++++ tools/perf/tests/tests.h | 2 ++ tools/perf/util/event.c | 17 +++++++++++++++++ tools/perf/util/event.h | 4 ++++ 5 files changed, 48 insertions(+) diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c index 87d6244f15f9..e18f5b818a02 100644 --- a/tools/perf/tests/builtin-test.c +++ b/tools/perf/tests/builtin-test.c @@ -182,6 +182,10 @@ static struct test generic_tests[] = { .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 805ff30bb1d5..3fae829c59fc 100644 --- a/tools/perf/tests/stat.c +++ b/tools/perf/tests/stat.c @@ -88,3 +88,24 @@ 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); + TEST_ASSERT_VAL("wrong type", stat_round->type == PERF_STAT_ROUND_TYPE__INTERVAL); + return 0; +} + +int test__synthesize_stat_round(void) +{ + TEST_ASSERT_VAL("failed to synthesize stat_config", + !perf_event__synthesize_stat_round(NULL, 0xdeadbeef, PERF_STAT_ROUND_TYPE__INTERVAL, + process_stat_round_event, NULL)); + + return 0; +} diff --git a/tools/perf/tests/tests.h b/tools/perf/tests/tests.h index edf460e5cd64..261716924ad9 100644 --- a/tools/perf/tests/tests.h +++ b/tools/perf/tests/tests.h @@ -71,6 +71,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(__arm__) || defined(__aarch64__) #ifdef HAVE_DWARF_UNWIND_SUPPORT diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index 164d13c88c0e..bec18c57e032 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c @@ -933,6 +933,23 @@ 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, u64 type, + 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; + event.type = type; + + 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 7e8427dfb59e..45a82cbc6643 100644 --- a/tools/perf/util/event.h +++ b/tools/perf/util/event.h @@ -517,6 +517,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, u64 type, + 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
Introducing following functions to display stat events for raw dump. perf_event__fprintf_stat perf_event__fprintf_stat_round perf_event__fprintf_stat_config Link: http://lkml.kernel.org/n/tip-hw2aywbi4w9jsq7cw8cene3u@git.kernel.org Signed-off-by: Jiri Olsa <jolsa@kernel.org> --- tools/perf/util/stat.c | 39 +++++++++++++++++++++++++++++++++++++++ tools/perf/util/stat.h | 4 ++++ 2 files changed, 43 insertions(+) diff --git a/tools/perf/util/stat.c b/tools/perf/util/stat.c index 40fa99b640f8..0480f39c8c4a 100644 --- a/tools/perf/util/stat.c +++ b/tools/perf/util/stat.c @@ -364,3 +364,42 @@ int perf_event__process_stat_event(struct perf_tool *tool __maybe_unused, counter->supported = true; return 0; } + +size_t perf_event__fprintf_stat(union perf_event *event, FILE *fp) +{ + struct stat_event *stat = (struct stat_event*) event; + size_t ret; + + ret = fprintf(fp, "\n... id %" PRIu64 ", cpu %d, thread %d\n", + stat->id, stat->cpu, stat->thread); + ret += fprintf(fp, "... value %" PRIu64 ", enabled %" PRIu64 ", running %" PRIu64 "\n", + stat->val, stat->ena, stat->run); + + return ret; +} + +size_t perf_event__fprintf_stat_round(union perf_event *event, FILE *fp) +{ + struct stat_round_event *round = (struct stat_round_event*) event; + size_t ret; + + ret = fprintf(fp, "\n... time %" PRIu64 ", type %s\n", round->time, + round->type == PERF_STAT_ROUND_TYPE__FINAL ? "FINAL" : "INTERVAL"); + + return ret; +} + +size_t perf_event__fprintf_stat_config(union perf_event *event, FILE *fp) +{ + struct perf_stat_config sc; + size_t ret; + + perf_event__read_stat_config(&sc, &event->stat_config); + + ret = fprintf(fp, "\n"); + ret += fprintf(fp, "... aggr_mode %d\n", sc.aggr_mode); + ret += fprintf(fp, "... scale %d\n", sc.scale); + ret += fprintf(fp, "... interval %u\n", sc.interval); + + return ret; +} diff --git a/tools/perf/util/stat.h b/tools/perf/util/stat.h index afe6844e5219..086f4e128d63 100644 --- a/tools/perf/util/stat.h +++ b/tools/perf/util/stat.h @@ -96,4 +96,8 @@ struct perf_session; int perf_event__process_stat_event(struct perf_tool *tool, union perf_event *event, struct perf_session *session); + +size_t perf_event__fprintf_stat(union perf_event *event, FILE *fp); +size_t perf_event__fprintf_stat_round(union perf_event *event, FILE *fp); +size_t perf_event__fprintf_stat_config(union perf_event *event, FILE *fp); #endif -- 2.4.3
It'll server as base event for additional event attributes details, that are not part of the attr event. At the moment this event is just dummy one without specific functionality. The type value will distinguish the update event details. It comes in following patches. The idea for this event is to be extensible for any update that event might need in the future. Link: http://lkml.kernel.org/n/tip-uik5iyftzgk488ttrgpjvtf6@git.kernel.org Signed-off-by: Jiri Olsa <jolsa@kernel.org> --- tools/perf/util/event.c | 1 + tools/perf/util/event.h | 10 ++++++++++ tools/perf/util/header.c | 20 ++++++++++++++++++++ tools/perf/util/header.h | 3 +++ tools/perf/util/session.c | 21 +++++++++++++++++++++ tools/perf/util/tool.h | 1 + 6 files changed, 56 insertions(+) diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index bec18c57e032..d25aa5097822 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c @@ -44,6 +44,7 @@ static const char *perf_event__names[] = { [PERF_RECORD_STAT_CONFIG] = "STAT_CONFIG", [PERF_RECORD_STAT] = "STAT", [PERF_RECORD_STAT_ROUND] = "STAT_ROUND", + [PERF_RECORD_EVENT_UPDATE] = "EVENT_UPDATE", }; const char *perf_event__name(unsigned int id) diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h index 45a82cbc6643..45819fc960ab 100644 --- a/tools/perf/util/event.h +++ b/tools/perf/util/event.h @@ -231,6 +231,7 @@ enum perf_user_event_type { /* above any possible kernel type */ PERF_RECORD_STAT_CONFIG = 75, PERF_RECORD_STAT = 76, PERF_RECORD_STAT_ROUND = 77, + PERF_RECORD_EVENT_UPDATE = 78, PERF_RECORD_HEADER_MAX }; @@ -307,6 +308,14 @@ struct attr_event { u64 id[]; }; +struct event_update_event { + struct perf_event_header header; + u64 type; + u64 id; + + char data[]; +}; + #define MAX_EVENT_NAME 64 struct perf_trace_event_type { @@ -456,6 +465,7 @@ union perf_event { struct throttle_event throttle; struct sample_event sample; struct attr_event attr; + struct event_update_event event_update; struct event_type_event event_type; struct tracing_data_event tracing_data; struct build_id_event build_id; diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 43838003c1a1..532184570e97 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -2745,6 +2745,26 @@ int perf_event__process_attr(struct perf_tool *tool __maybe_unused, return 0; } +int perf_event__process_event_update(struct perf_tool *tool __maybe_unused, + union perf_event *event, + struct perf_evlist **pevlist) +{ + struct event_update_event *ev = &event->event_update; + struct perf_evlist *evlist; + struct perf_evsel *evsel; + + if (!pevlist || *pevlist == NULL) + return -EINVAL; + + evlist = *pevlist; + + evsel = perf_evlist__id2evsel(evlist, ev->id); + if (evsel == NULL) + return -EINVAL; + + return 0; +} + int perf_event__synthesize_tracing_data(struct perf_tool *tool, int fd, struct perf_evlist *evlist, perf_event__handler_t process) diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h index 05f27cb6b7e3..1e843c67a4ff 100644 --- a/tools/perf/util/header.h +++ b/tools/perf/util/header.h @@ -107,6 +107,9 @@ int perf_event__synthesize_attrs(struct perf_tool *tool, perf_event__handler_t process); int perf_event__process_attr(struct perf_tool *tool, union perf_event *event, struct perf_evlist **pevlist); +int perf_event__process_event_update(struct perf_tool *tool __maybe_unused, + union perf_event *event, + struct perf_evlist **pevlist); int perf_event__synthesize_tracing_data(struct perf_tool *tool, int fd, struct perf_evlist *evlist, diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index c6c28194d65b..4a5acea07d50 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -205,6 +205,15 @@ static int process_event_synth_attr_stub(struct perf_tool *tool __maybe_unused, return 0; } +static int process_event_synth_event_update_stub(struct perf_tool *tool __maybe_unused, + union perf_event *event __maybe_unused, + struct perf_evlist **pevlist + __maybe_unused) +{ + dump_printf(": unhandled!\n"); + return 0; +} + static int process_event_sample_stub(struct perf_tool *tool __maybe_unused, union perf_event *event __maybe_unused, struct perf_sample *sample __maybe_unused, @@ -374,6 +383,8 @@ void perf_tool__fill_defaults(struct perf_tool *tool) tool->unthrottle = process_event_stub; if (tool->attr == NULL) tool->attr = process_event_synth_attr_stub; + if (tool->event_update == NULL) + tool->event_update = process_event_synth_event_update_stub; if (tool->tracing_data == NULL) tool->tracing_data = process_event_synth_tracing_data_stub; if (tool->build_id == NULL) @@ -625,6 +636,13 @@ static void perf_event__hdr_attr_swap(union perf_event *event, mem_bswap_64(event->attr.id, size); } +static void perf_event__event_update_swap(union perf_event *event, + bool sample_id_all __maybe_unused) +{ + event->event_update.type = bswap_64(event->event_update.type); + event->event_update.id = bswap_64(event->event_update.id); +} + static void perf_event__event_type_swap(union perf_event *event, bool sample_id_all __maybe_unused) { @@ -779,6 +797,7 @@ static perf_event__swap_op perf_event__swap_ops[] = { [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_EVENT_UPDATE] = perf_event__event_update_swap, [PERF_RECORD_HEADER_MAX] = NULL, }; @@ -1290,6 +1309,8 @@ static s64 perf_session__process_user_event(struct perf_session *session, perf_session__set_comm_exec(session); } return err; + case PERF_RECORD_EVENT_UPDATE: + return tool->event_update(tool, event, &session->evlist); case PERF_RECORD_HEADER_EVENT_TYPE: /* * Depreceated, but we need to handle it for sake diff --git a/tools/perf/util/tool.h b/tools/perf/util/tool.h index d04d9e5f444a..55de4cffcd4e 100644 --- a/tools/perf/util/tool.h +++ b/tools/perf/util/tool.h @@ -50,6 +50,7 @@ struct perf_tool { throttle, unthrottle; event_attr_op attr; + event_attr_op event_update; event_op2 tracing_data; event_oe finished_round; event_op2 build_id, -- 2.4.3
Adding unit type 'event update' event, that stores/transfer events unit name. The unit name is part of the perf stat output data. Link: http://lkml.kernel.org/n/tip-5s6ape0vz2sfxgzu16eu8y7r@git.kernel.org Signed-off-by: Jiri Olsa <jolsa@kernel.org> --- tools/perf/tests/Build | 1 + tools/perf/tests/builtin-test.c | 4 ++++ tools/perf/tests/event_update.c | 42 +++++++++++++++++++++++++++++++++++++++ tools/perf/tests/tests.h | 1 + tools/perf/util/event.h | 4 ++++ tools/perf/util/header.c | 44 +++++++++++++++++++++++++++++++++++++++++ tools/perf/util/header.h | 3 +++ 7 files changed, 99 insertions(+) create mode 100644 tools/perf/tests/event_update.c diff --git a/tools/perf/tests/Build b/tools/perf/tests/Build index ea4ef8fdd463..522dc2fa6dae 100644 --- a/tools/perf/tests/Build +++ b/tools/perf/tests/Build @@ -35,6 +35,7 @@ perf-y += llvm.o perf-y += topology.o perf-y += cpumap.o perf-y += stat.o +perf-y += event_update.o ifeq ($(ARCH),$(filter $(ARCH),x86 arm arm64)) perf-$(CONFIG_DWARF_UNWIND) += dwarf-unwind.o diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c index e18f5b818a02..dca022d1f342 100644 --- a/tools/perf/tests/builtin-test.c +++ b/tools/perf/tests/builtin-test.c @@ -186,6 +186,10 @@ static struct test generic_tests[] = { .func = test__synthesize_stat_round, }, { + .desc = "Test attr update synthesize", + .func = test__event_update, + }, + { .func = NULL, }, }; diff --git a/tools/perf/tests/event_update.c b/tools/perf/tests/event_update.c new file mode 100644 index 000000000000..4ed9e35c4459 --- /dev/null +++ b/tools/perf/tests/event_update.c @@ -0,0 +1,42 @@ +#include <linux/compiler.h> +#include "evlist.h" +#include "evsel.h" +#include "machine.h" +#include "tests.h" +#include "debug.h" + +static int process_event_unit(struct perf_tool *tool __maybe_unused, + union perf_event *event, + struct perf_sample *sample __maybe_unused, + struct machine *machine __maybe_unused) +{ + struct event_update_event *ev = (struct event_update_event*) event; + + TEST_ASSERT_VAL("wrong id", ev->id == 123); + TEST_ASSERT_VAL("wrong id", ev->type == PERF_EVENT_UPDATE__UNIT); + TEST_ASSERT_VAL("wrong unit", !strcmp(ev->data, "KRAVA")); + return 0; +} + +int test__event_update(void) +{ + struct perf_evlist *evlist; + struct perf_evsel *evsel; + + evlist = perf_evlist__new_default(); + TEST_ASSERT_VAL("failed to get evlist", evlist); + + evsel = perf_evlist__first(evlist); + + TEST_ASSERT_VAL("failed to allos ids", + !perf_evsel__alloc_id(evsel, 1, 1)); + + perf_evlist__id_add(evlist, evsel, 0, 0, 123); + + evsel->unit = strdup("KRAVA"); + + TEST_ASSERT_VAL("failed to synthesize attr update unit", + !perf_event__synthesize_event_update_unit(NULL, evsel, process_event_unit)); + + return 0; +} diff --git a/tools/perf/tests/tests.h b/tools/perf/tests/tests.h index 261716924ad9..4e1ec66caec0 100644 --- a/tools/perf/tests/tests.h +++ b/tools/perf/tests/tests.h @@ -72,6 +72,7 @@ int test__cpu_map_synthesize(void); int test__synthesize_stat_config(void); int test__synthesize_stat(void); int test__synthesize_stat_round(void); +int test__event_update(void); #if defined(__arm__) || defined(__aarch64__) diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h index 45819fc960ab..ee932d9329f9 100644 --- a/tools/perf/util/event.h +++ b/tools/perf/util/event.h @@ -308,6 +308,10 @@ struct attr_event { u64 id[]; }; +enum { + PERF_EVENT_UPDATE__UNIT = 0, +}; + struct event_update_event { struct perf_event_header header; u64 type; diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 532184570e97..6b96e7320794 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -2686,6 +2686,43 @@ int perf_event__synthesize_attr(struct perf_tool *tool, return err; } +static struct event_update_event* +event_update_event__alloc(size_t size, u64 type, u64 id) +{ + struct event_update_event *ev; + + size += sizeof(*ev); + size = PERF_ALIGN(size, sizeof(u64)); + + ev = zalloc(size); + if (ev) { + ev->header.type = PERF_RECORD_EVENT_UPDATE; + ev->header.size = (u16)size; + ev->type = type; + ev->id = id; + } + return ev; +} + +int +perf_event__synthesize_event_update_unit(struct perf_tool *tool, + struct perf_evsel *evsel, + perf_event__handler_t process) +{ + struct event_update_event *ev; + size_t size = strlen(evsel->unit); + int err; + + ev = event_update_event__alloc(size + 1, PERF_EVENT_UPDATE__UNIT, evsel->id[0]); + if (ev == NULL) + return -ENOMEM; + + strncpy(ev->data, evsel->unit, size); + err = process(tool, (union perf_event*) ev, NULL, NULL); + free(ev); + return err; +} + int perf_event__synthesize_attrs(struct perf_tool *tool, struct perf_session *session, perf_event__handler_t process) @@ -2762,6 +2799,13 @@ int perf_event__process_event_update(struct perf_tool *tool __maybe_unused, if (evsel == NULL) return -EINVAL; + switch (ev->type) { + case PERF_EVENT_UPDATE__UNIT: + evsel->unit = strdup(ev->data); + default: + break; + } + return 0; } diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h index 1e843c67a4ff..6aa2b9242fc1 100644 --- a/tools/perf/util/header.h +++ b/tools/perf/util/header.h @@ -105,6 +105,9 @@ int perf_event__synthesize_attr(struct perf_tool *tool, int perf_event__synthesize_attrs(struct perf_tool *tool, struct perf_session *session, perf_event__handler_t process); +int perf_event__synthesize_event_update_unit(struct perf_tool *tool, + struct perf_evsel *evsel, + perf_event__handler_t process); int perf_event__process_attr(struct perf_tool *tool, union perf_event *event, struct perf_evlist **pevlist); int perf_event__process_event_update(struct perf_tool *tool __maybe_unused, -- 2.4.3
Adding scale type 'event update' event, that stores/transfer events scale value. The PMU events can define the scale value which is used to multiply events data. Link: http://lkml.kernel.org/n/tip-by8wb1atqzhtpx86ybjhwge2@git.kernel.org Signed-off-by: Jiri Olsa <jolsa@kernel.org> --- tools/perf/tests/event_update.c | 21 +++++++++++++++++++++ tools/perf/util/event.h | 5 +++++ tools/perf/util/header.c | 26 ++++++++++++++++++++++++++ tools/perf/util/header.h | 3 +++ 4 files changed, 55 insertions(+) diff --git a/tools/perf/tests/event_update.c b/tools/perf/tests/event_update.c index 4ed9e35c4459..a2f9f0ac7eef 100644 --- a/tools/perf/tests/event_update.c +++ b/tools/perf/tests/event_update.c @@ -18,6 +18,22 @@ static int process_event_unit(struct perf_tool *tool __maybe_unused, return 0; } +static int process_event_scale(struct perf_tool *tool __maybe_unused, + union perf_event *event, + struct perf_sample *sample __maybe_unused, + struct machine *machine __maybe_unused) +{ + struct event_update_event *ev = (struct event_update_event *) event; + struct event_update_event_scale *ev_data; + + ev_data = (struct event_update_event_scale *) ev->data; + + TEST_ASSERT_VAL("wrong id", ev->id == 123); + TEST_ASSERT_VAL("wrong id", ev->type == PERF_EVENT_UPDATE__SCALE); + TEST_ASSERT_VAL("wrong scale", ev_data->scale = 0.123); + return 0; +} + int test__event_update(void) { struct perf_evlist *evlist; @@ -38,5 +54,10 @@ int test__event_update(void) TEST_ASSERT_VAL("failed to synthesize attr update unit", !perf_event__synthesize_event_update_unit(NULL, evsel, process_event_unit)); + evsel->scale = 0.123; + + TEST_ASSERT_VAL("failed to synthesize attr update scale", + !perf_event__synthesize_event_update_scale(NULL, evsel, process_event_scale)); + return 0; } diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h index ee932d9329f9..9a065665e3bb 100644 --- a/tools/perf/util/event.h +++ b/tools/perf/util/event.h @@ -310,6 +310,11 @@ struct attr_event { enum { PERF_EVENT_UPDATE__UNIT = 0, + PERF_EVENT_UPDATE__SCALE = 1, +}; + +struct event_update_event_scale { + double scale; }; struct event_update_event { diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 6b96e7320794..4d36c960804b 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -2723,6 +2723,27 @@ perf_event__synthesize_event_update_unit(struct perf_tool *tool, return err; } +int +perf_event__synthesize_event_update_scale(struct perf_tool *tool, + struct perf_evsel *evsel, + perf_event__handler_t process) +{ + struct event_update_event *ev; + struct event_update_event_scale *ev_data; + int err; + + ev = event_update_event__alloc(sizeof(*ev_data), PERF_EVENT_UPDATE__SCALE, evsel->id[0]); + if (ev == NULL) + return -ENOMEM; + + ev_data = (struct event_update_event_scale *) ev->data; + ev_data->scale = evsel->scale; + err = process(tool, (union perf_event*) ev, NULL, NULL); + free(ev); + return err; +} + + int perf_event__synthesize_attrs(struct perf_tool *tool, struct perf_session *session, perf_event__handler_t process) @@ -2787,6 +2808,7 @@ int perf_event__process_event_update(struct perf_tool *tool __maybe_unused, struct perf_evlist **pevlist) { struct event_update_event *ev = &event->event_update; + struct event_update_event_scale *ev_scale; struct perf_evlist *evlist; struct perf_evsel *evsel; @@ -2802,6 +2824,10 @@ int perf_event__process_event_update(struct perf_tool *tool __maybe_unused, switch (ev->type) { case PERF_EVENT_UPDATE__UNIT: evsel->unit = strdup(ev->data); + break; + case PERF_EVENT_UPDATE__SCALE: + ev_scale = (struct event_update_event_scale *) ev->data; + evsel->scale = ev_scale->scale; default: break; } diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h index 6aa2b9242fc1..fad04cbab666 100644 --- a/tools/perf/util/header.h +++ b/tools/perf/util/header.h @@ -108,6 +108,9 @@ int perf_event__synthesize_attrs(struct perf_tool *tool, int perf_event__synthesize_event_update_unit(struct perf_tool *tool, struct perf_evsel *evsel, perf_event__handler_t process); +int perf_event__synthesize_event_update_scale(struct perf_tool *tool, + struct perf_evsel *evsel, + perf_event__handler_t process); int perf_event__process_attr(struct perf_tool *tool, union perf_event *event, struct perf_evlist **pevlist); int perf_event__process_event_update(struct perf_tool *tool __maybe_unused, -- 2.4.3
Adding name type 'event update' event, that stores/transfer events name. Event's name is stored within perf.data's EVENT_DESC feature, but we don't have if we get report data from pipe. Link: http://lkml.kernel.org/n/tip-j8b9c0ev11zisop3qup1hdy8@git.kernel.org Signed-off-by: Jiri Olsa <jolsa@kernel.org> --- tools/perf/tests/event_update.c | 25 +++++++++++++++++++++++++ tools/perf/util/event.h | 1 + tools/perf/util/header.c | 21 +++++++++++++++++++++ tools/perf/util/header.h | 3 +++ 4 files changed, 50 insertions(+) diff --git a/tools/perf/tests/event_update.c b/tools/perf/tests/event_update.c index a2f9f0ac7eef..7b7515dde130 100644 --- a/tools/perf/tests/event_update.c +++ b/tools/perf/tests/event_update.c @@ -34,10 +34,30 @@ static int process_event_scale(struct perf_tool *tool __maybe_unused, return 0; } +struct event_name { + struct perf_tool tool; + const char *name; +}; + +static int process_event_name(struct perf_tool *tool, + union perf_event *event, + struct perf_sample *sample __maybe_unused, + struct machine *machine __maybe_unused) +{ + struct event_name *tmp = container_of(tool, struct event_name, tool); + struct event_update_event *ev = (struct event_update_event*) event; + + TEST_ASSERT_VAL("wrong id", ev->id == 123); + TEST_ASSERT_VAL("wrong id", ev->type == PERF_EVENT_UPDATE__NAME); + TEST_ASSERT_VAL("wrong name", !strcmp(ev->data, tmp->name)); + return 0; +} + int test__event_update(void) { struct perf_evlist *evlist; struct perf_evsel *evsel; + struct event_name tmp; evlist = perf_evlist__new_default(); TEST_ASSERT_VAL("failed to get evlist", evlist); @@ -59,5 +79,10 @@ int test__event_update(void) TEST_ASSERT_VAL("failed to synthesize attr update scale", !perf_event__synthesize_event_update_scale(NULL, evsel, process_event_scale)); + tmp.name = perf_evsel__name(evsel); + + TEST_ASSERT_VAL("failed to synthesize attr update name", + !perf_event__synthesize_event_update_name(&tmp.tool, evsel, process_event_name)); + return 0; } diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h index 9a065665e3bb..fe8781de2528 100644 --- a/tools/perf/util/event.h +++ b/tools/perf/util/event.h @@ -311,6 +311,7 @@ struct attr_event { enum { PERF_EVENT_UPDATE__UNIT = 0, PERF_EVENT_UPDATE__SCALE = 1, + PERF_EVENT_UPDATE__NAME = 2, }; struct event_update_event_scale { diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 4d36c960804b..1e7fe3546c33 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -2743,6 +2743,24 @@ perf_event__synthesize_event_update_scale(struct perf_tool *tool, return err; } +int +perf_event__synthesize_event_update_name(struct perf_tool *tool, + struct perf_evsel *evsel, + perf_event__handler_t process) +{ + struct event_update_event *ev; + size_t len = strlen(evsel->name); + int err; + + ev = event_update_event__alloc(len + 1, PERF_EVENT_UPDATE__NAME, evsel->id[0]); + if (ev == NULL) + return -ENOMEM; + + strncpy(ev->data, evsel->name, len); + err = process(tool, (union perf_event*) ev, NULL, NULL); + free(ev); + return err; +} int perf_event__synthesize_attrs(struct perf_tool *tool, struct perf_session *session, @@ -2825,6 +2843,9 @@ int perf_event__process_event_update(struct perf_tool *tool __maybe_unused, case PERF_EVENT_UPDATE__UNIT: evsel->unit = strdup(ev->data); break; + case PERF_EVENT_UPDATE__NAME: + evsel->name = strdup(ev->data); + break; case PERF_EVENT_UPDATE__SCALE: ev_scale = (struct event_update_event_scale *) ev->data; evsel->scale = ev_scale->scale; diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h index fad04cbab666..51cf566a0835 100644 --- a/tools/perf/util/header.h +++ b/tools/perf/util/header.h @@ -111,6 +111,9 @@ int perf_event__synthesize_event_update_unit(struct perf_tool *tool, int perf_event__synthesize_event_update_scale(struct perf_tool *tool, struct perf_evsel *evsel, perf_event__handler_t process); +int perf_event__synthesize_event_update_name(struct perf_tool *tool, + struct perf_evsel *evsel, + perf_event__handler_t process); int perf_event__process_attr(struct perf_tool *tool, union perf_event *event, struct perf_evlist **pevlist); int perf_event__process_event_update(struct perf_tool *tool __maybe_unused, -- 2.4.3
Adding cpumask 'event update' event, that stores/transfer cpumask for event. Link: http://lkml.kernel.org/n/tip-wm844j3ht4isjn2elinc09rk@git.kernel.org Signed-off-by: Jiri Olsa <jolsa@kernel.org> --- tools/perf/tests/event_update.c | 29 ++++++++++++++++++++++++++++ tools/perf/util/event.h | 5 +++++ tools/perf/util/header.c | 42 +++++++++++++++++++++++++++++++++++++++++ tools/perf/util/header.h | 3 +++ 4 files changed, 79 insertions(+) diff --git a/tools/perf/tests/event_update.c b/tools/perf/tests/event_update.c index 7b7515dde130..f05314abdab5 100644 --- a/tools/perf/tests/event_update.c +++ b/tools/perf/tests/event_update.c @@ -53,6 +53,29 @@ static int process_event_name(struct perf_tool *tool, return 0; } +static int process_event_cpus(struct perf_tool *tool __maybe_unused, + union perf_event *event, + struct perf_sample *sample __maybe_unused, + struct machine *machine __maybe_unused) +{ + struct event_update_event *ev = (struct event_update_event*) event; + struct event_update_event_cpus *ev_data; + struct cpu_map *map; + + ev_data = (struct event_update_event_cpus*) ev->data; + + map = cpu_map__new_data(&ev_data->cpus); + + TEST_ASSERT_VAL("wrong id", ev->id == 123); + TEST_ASSERT_VAL("wrong type", ev->type == PERF_EVENT_UPDATE__CPUS); + TEST_ASSERT_VAL("wrong cpus", map->nr == 3); + TEST_ASSERT_VAL("wrong cpus", map->map[0] == 1); + TEST_ASSERT_VAL("wrong cpus", map->map[1] == 2); + TEST_ASSERT_VAL("wrong cpus", map->map[2] == 3); + cpu_map__put(map); + return 0; +} + int test__event_update(void) { struct perf_evlist *evlist; @@ -84,5 +107,11 @@ int test__event_update(void) TEST_ASSERT_VAL("failed to synthesize attr update name", !perf_event__synthesize_event_update_name(&tmp.tool, evsel, process_event_name)); + evsel->own_cpus = cpu_map__new("1,2,3"); + + TEST_ASSERT_VAL("failed to synthesize attr update cpus", + !perf_event__synthesize_event_update_cpus(&tmp.tool, evsel, process_event_cpus)); + + cpu_map__put(evsel->own_cpus); return 0; } diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h index fe8781de2528..063230fc91d8 100644 --- a/tools/perf/util/event.h +++ b/tools/perf/util/event.h @@ -312,6 +312,11 @@ enum { PERF_EVENT_UPDATE__UNIT = 0, PERF_EVENT_UPDATE__SCALE = 1, PERF_EVENT_UPDATE__NAME = 2, + PERF_EVENT_UPDATE__CPUS = 3, +}; + +struct event_update_event_cpus { + struct cpu_map_data cpus; }; struct event_update_event_scale { diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 1e7fe3546c33..e4cb510aa246 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -2762,6 +2762,38 @@ perf_event__synthesize_event_update_name(struct perf_tool *tool, return err; } +int +perf_event__synthesize_event_update_cpus(struct perf_tool *tool, + struct perf_evsel *evsel, + perf_event__handler_t process) +{ + size_t size = sizeof(struct event_update_event); + struct event_update_event *ev; + int max, err; + u16 type; + + if (!evsel->own_cpus) + return 0; + + ev = cpu_map_data__alloc(evsel->own_cpus, &size, &type, &max); + if (!ev) + return -ENOMEM; + + ev->header.type = PERF_RECORD_EVENT_UPDATE; + ev->header.size = (u16)size; + ev->type = PERF_EVENT_UPDATE__CPUS; + ev->id = evsel->id[0]; + + cpu_map_data__synthesize((struct cpu_map_data *) ev->data, + evsel->own_cpus, + type, max); + + err = process(tool, (union perf_event*) ev, NULL, NULL); + free(ev); + return err; +} + + int perf_event__synthesize_attrs(struct perf_tool *tool, struct perf_session *session, perf_event__handler_t process) @@ -2827,8 +2859,10 @@ int perf_event__process_event_update(struct perf_tool *tool __maybe_unused, { struct event_update_event *ev = &event->event_update; struct event_update_event_scale *ev_scale; + struct event_update_event_cpus *ev_cpus; struct perf_evlist *evlist; struct perf_evsel *evsel; + struct cpu_map *map; if (!pevlist || *pevlist == NULL) return -EINVAL; @@ -2849,6 +2883,14 @@ int perf_event__process_event_update(struct perf_tool *tool __maybe_unused, case PERF_EVENT_UPDATE__SCALE: ev_scale = (struct event_update_event_scale *) ev->data; evsel->scale = ev_scale->scale; + case PERF_EVENT_UPDATE__CPUS: + ev_cpus = (struct event_update_event_cpus *) ev->data; + + map = cpu_map__new_data(&ev_cpus->cpus); + if (map) + evsel->own_cpus = map; + else + pr_err("failed to get event_update cpus\n"); default: break; } diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h index 51cf566a0835..a1bc0c5706a3 100644 --- a/tools/perf/util/header.h +++ b/tools/perf/util/header.h @@ -114,6 +114,9 @@ int perf_event__synthesize_event_update_scale(struct perf_tool *tool, int perf_event__synthesize_event_update_name(struct perf_tool *tool, struct perf_evsel *evsel, perf_event__handler_t process); +int perf_event__synthesize_event_update_cpus(struct perf_tool *tool, + struct perf_evsel *evsel, + perf_event__handler_t process); int perf_event__process_attr(struct perf_tool *tool, union perf_event *event, struct perf_evlist **pevlist); int perf_event__process_event_update(struct perf_tool *tool __maybe_unused, -- 2.4.3
To display 'event update' event for raw dump. Link: http://lkml.kernel.org/n/tip-ch2nor544486ppvwscqg55ik@git.kernel.org Signed-off-by: Jiri Olsa <jolsa@kernel.org> --- tools/perf/util/header.c | 38 ++++++++++++++++++++++++++++++++++++++ tools/perf/util/header.h | 1 + 2 files changed, 39 insertions(+) diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index e4cb510aa246..00582be5f717 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -2793,6 +2793,44 @@ perf_event__synthesize_event_update_cpus(struct perf_tool *tool, return err; } +size_t perf_event__fprintf_event_update(union perf_event *event, FILE *fp) +{ + struct event_update_event *ev = &event->event_update; + struct event_update_event_scale *ev_scale; + struct event_update_event_cpus *ev_cpus; + struct cpu_map *map; + size_t ret; + + ret = fprintf(fp, "\n... id: %" PRIu64 "\n", ev->id); + + switch (ev->type) { + case PERF_EVENT_UPDATE__SCALE: + ev_scale = (struct event_update_event_scale *) ev->data; + ret += fprintf(fp, "... scale: %f\n", ev_scale->scale); + break; + case PERF_EVENT_UPDATE__UNIT: + ret += fprintf(fp, "... unit: %s\n", ev->data); + break; + case PERF_EVENT_UPDATE__NAME: + ret += fprintf(fp, "... name: %s\n", ev->data); + break; + case PERF_EVENT_UPDATE__CPUS: + ev_cpus = (struct event_update_event_cpus *) ev->data; + ret += fprintf(fp, "... "); + + map = cpu_map__new_data(&ev_cpus->cpus); + if (map) + ret += cpu_map__fprintf(map, fp); + else + ret += fprintf(fp, "failed to get cpus\n"); + break; + default: + ret += fprintf(fp, "... unknown type\n"); + break; + } + + return ret; +} int perf_event__synthesize_attrs(struct perf_tool *tool, struct perf_session *session, diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h index a1bc0c5706a3..710deecf8f80 100644 --- a/tools/perf/util/header.h +++ b/tools/perf/util/header.h @@ -122,6 +122,7 @@ int perf_event__process_attr(struct perf_tool *tool, union perf_event *event, int perf_event__process_event_update(struct perf_tool *tool __maybe_unused, union perf_event *event, struct perf_evlist **pevlist); +size_t perf_event__fprintf_event_update(union perf_event *event, FILE *fp); int perf_event__synthesize_tracing_data(struct perf_tool *tool, int fd, struct perf_evlist *evlist, -- 2.4.3
The 'perf report -D' command will now display dump and detailed output for newly added events: event_update thread_map cpu_map stat stat_config stat_round Link: http://lkml.kernel.org/n/tip-8dgrmsf866ltq2s86d1zezvm@git.kernel.org Signed-off-by: Jiri Olsa <jolsa@kernel.org> --- tools/perf/util/session.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 4a5acea07d50..dafdbda37411 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -17,6 +17,7 @@ #include "asm/bug.h" #include "auxtrace.h" #include "thread-stack.h" +#include "stat.h" static int perf_session__deliver_event(struct perf_session *session, union perf_event *event, @@ -210,6 +211,9 @@ static int process_event_synth_event_update_stub(struct perf_tool *tool __maybe_ struct perf_evlist **pevlist __maybe_unused) { + if (dump_trace) + perf_event__fprintf_event_update(event, stdout); + dump_printf(": unhandled!\n"); return 0; } @@ -311,6 +315,9 @@ int process_event_thread_map_stub(struct perf_tool *tool __maybe_unused, union perf_event *event __maybe_unused, struct perf_session *session __maybe_unused) { + if (dump_trace) + perf_event__fprintf_thread_map(event, stdout); + dump_printf(": unhandled!\n"); return 0; } @@ -320,6 +327,9 @@ int process_event_cpu_map_stub(struct perf_tool *tool __maybe_unused, union perf_event *event __maybe_unused, struct perf_session *session __maybe_unused) { + if (dump_trace) + perf_event__fprintf_cpu_map(event, stdout); + dump_printf(": unhandled!\n"); return 0; } @@ -329,6 +339,9 @@ int process_event_stat_config_stub(struct perf_tool *tool __maybe_unused, union perf_event *event __maybe_unused, struct perf_session *session __maybe_unused) { + if (dump_trace) + perf_event__fprintf_stat_config(event, stdout); + dump_printf(": unhandled!\n"); return 0; } @@ -338,6 +351,9 @@ static int process_stat_stub(struct perf_tool *tool __maybe_unused, struct perf_session *perf_session __maybe_unused) { + if (dump_trace) + perf_event__fprintf_stat(event, stdout); + dump_printf(": unhandled!\n"); return 0; } @@ -347,6 +363,9 @@ static int process_stat_round_stub(struct perf_tool *tool __maybe_unused, struct perf_session *perf_session __maybe_unused) { + if (dump_trace) + perf_event__fprintf_stat_round(event, stdout); + dump_printf(": unhandled!\n"); return 0; } -- 2.4.3
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. In future it might be used to store version of the stat storage system we used. Link: http://lkml.kernel.org/n/tip-56xpt7m6au4d8u39nffoqgx1@git.kernel.org Signed-off-by: Jiri Olsa <jolsa@kernel.org> --- 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 2740d7a82ae8..6f0421b3acaf 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -451,6 +451,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 00582be5f717..b2c4fe34d19f 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -868,6 +868,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) { @@ -1159,6 +1166,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) { @@ -1948,6 +1961,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 710deecf8f80..cff9892452ee 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
Because following stat patches use id_offset together with priv pointer. Link: http://lkml.kernel.org/n/tip-ts3nkj35lx54whb649by02py@git.kernel.org Signed-off-by: Jiri Olsa <jolsa@kernel.org> --- 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 02a5fed8d924..0e22c0b7dab5 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h @@ -90,9 +90,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
Add 'perf stat record' command support. It creates simple (header only) perf.data file ATM. Link: http://lkml.kernel.org/n/tip-0av5yfkwyywwgoiali88w4hi@git.kernel.org Signed-off-by: Jiri Olsa <jolsa@kernel.org> --- 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 4e074a660826..70eee1c2c444 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=:: @@ -159,6 +162,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 a3880aa65b04..b65cc6a46226 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -59,6 +59,7 @@ #include "util/thread.h" #include "util/thread_map.h" #include "util/counts.h" +#include "util/session.h" #include <stdlib.h> #include <sys/prctl.h> @@ -123,6 +124,16 @@ static struct timespec ref_time; static struct cpu_map *aggr_map; static aggr_get_id_t aggr_get_id; +struct perf_stat { + bool record; + struct perf_data_file file; + struct perf_session *session; + u64 bytes_written; +}; + +static struct perf_stat perf_stat; +#define STAT_RECORD perf_stat.record + static volatile int done = 0; static struct perf_stat_config stat_config = { @@ -341,6 +352,15 @@ static int __run_perf_stat(int argc, const char **argv) return -1; } + if (STAT_RECORD) { + int err, fd = perf_data_file__fd(&perf_stat.file); + + err = perf_session__write_header(perf_stat.session, evsel_list, + fd, false); + if (err < 0) + return err; + } + /* * Enable counters and exec the command: */ @@ -1192,6 +1212,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 = &perf_stat.file; + const struct option options[] = { + OPT_STRING('o', "output", &perf_stat.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 (perf_stat.file.is_pipe) + return -EINVAL; + + session->evlist = evsel_list; + perf_stat.session = session; + perf_stat.record = true; + return argc; +} + int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused) { bool append_file = false; @@ -1265,6 +1318,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, ""); @@ -1272,8 +1326,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; @@ -1444,6 +1505,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(&perf_stat.file); + + perf_stat.session->header.data_size += perf_stat.bytes_written; + perf_session__write_header(perf_stat.session, evsel_list, fd, true); + + perf_session__delete(perf_stat.session); + } + perf_evlist__free_stats(evsel_list); out: perf_evlist__delete(evsel_list); -- 2.4.3
Disabling all non stat related features. Link: http://lkml.kernel.org/n/tip-0av5yfkwyywwgoiali88w4hi@git.kernel.org Signed-off-by: Jiri Olsa <jolsa@kernel.org> --- 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 b65cc6a46226..3f470345e4fa 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -1217,6 +1217,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; @@ -1239,6 +1252,8 @@ static int __cmd_record(int argc, const char **argv) if (perf_stat.file.is_pipe) return -EINVAL; + init_features(session); + session->evlist = evsel_list; perf_stat.session = session; perf_stat.record = true; -- 2.4.3
Synthesizing needed stat record data for report/script: - cpu/thread maps - stat config Link: http://lkml.kernel.org/n/tip-wni1s2i2sq17g4vomjyda2yf@git.kernel.org Signed-off-by: Jiri Olsa <jolsa@kernel.org> --- tools/perf/builtin-stat.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index 3f470345e4fa..ac4e1f47bd3c 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -193,6 +193,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(&perf_stat.file, event, event->header.size) < 0) { + pr_err("failed to write perf data, error: %m\n"); + return -1; + } + + perf_stat.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 @@ -279,6 +293,35 @@ 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_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; + } + + 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; + } + + return 0; +} + static int __run_perf_stat(int argc, const char **argv) { int interval = stat_config.interval; @@ -359,6 +402,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
Store event IDs in evlist object so it get stored into perf.data file. Also making perf_evlist__id_add_fd global. Link: http://lkml.kernel.org/n/tip-v2xwpeots3tz08e44lej5y9e@git.kernel.org Signed-off-by: Jiri Olsa <jolsa@kernel.org> --- 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 ac4e1f47bd3c..3a0f53fdfacb 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -322,6 +322,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; @@ -386,6 +418,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 d1392194a9a9..8069a6a588df 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c @@ -550,9 +550,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 a459fe71b452..139a50038097 100644 --- a/tools/perf/util/evlist.h +++ b/tools/perf/util/evlist.h @@ -97,6 +97,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
Allowing storing stat record data into pipe, so report tools (report/script) could read data directly from record. Link: http://lkml.kernel.org/n/tip-m8fj758gty57hgvss5efy6na@git.kernel.org Signed-off-by: Jiri Olsa <jolsa@kernel.org> --- 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 3a0f53fdfacb..9b680c608ff5 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -293,10 +293,19 @@ 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; + if (is_pipe) { + err = perf_event__synthesize_attrs(NULL, perf_stat.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); @@ -364,6 +373,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 ? perf_stat.file.is_pipe : false; if (interval) { ts.tv_sec = interval / 1000; @@ -374,7 +384,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; @@ -433,12 +443,17 @@ static int __run_perf_stat(int argc, const char **argv) if (STAT_RECORD) { int err, fd = perf_data_file__fd(&perf_stat.file); - err = perf_session__write_header(perf_stat.session, evsel_list, - fd, false); + if (is_pipe) { + err = perf_header__write_pipe(perf_data_file__fd(&perf_stat.file)); + } else { + err = perf_session__write_header(perf_stat.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; } @@ -965,6 +980,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 && perf_stat.file.is_pipe) + return; + if (interval) print_interval(prefix = buf, ts); else @@ -1330,10 +1349,6 @@ static int __cmd_record(int argc, const char **argv) return -1; } - /* No pipe support ATM */ - if (perf_stat.file.is_pipe) - return -EINVAL; - init_features(session); session->evlist = evsel_list; @@ -1605,8 +1620,10 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused) if (STAT_RECORD) { int fd = perf_data_file__fd(&perf_stat.file); - perf_stat.session->header.data_size += perf_stat.bytes_written; - perf_session__write_header(perf_stat.session, evsel_list, fd, true); + if (!perf_stat.file.is_pipe) { + perf_stat.session->header.data_size += perf_stat.bytes_written; + perf_session__write_header(perf_stat.session, evsel_list, fd, true); + } perf_session__delete(perf_stat.session); } -- 2.4.3
Writing stat events on 'perf stat record' at the time we read counter values from kernel. Link: http://lkml.kernel.org/n/tip-ojc826gy0x9jj74elbjfccej@git.kernel.org Signed-off-by: Jiri Olsa <jolsa@kernel.org> --- 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 9b680c608ff5..6b8b7c27ce4a 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -207,6 +207,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 @@ -230,6 +242,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
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/tip-a43rs4c6szofeuo2gjlcpm0h@git.kernel.org Signed-off-by: Jiri Olsa <jolsa@kernel.org> --- tools/perf/builtin-stat.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index 6b8b7c27ce4a..9ab268086ae7 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -207,6 +207,16 @@ static int process_synthesized_event(struct perf_tool *tool __maybe_unused, return 0; } +static int write_stat_round_event(u64 time, u64 type) +{ + return perf_event__synthesize_stat_round(NULL, time, type, + process_synthesized_event, + NULL); +} + +#define WRITE_STAT_ROUND_EVENT(time, interval) \ + write_stat_round_event(time, PERF_STAT_ROUND_TYPE__ ## interval) + #define SID(e, x, y) xyarray__entry(e->sample_id, x, y) static int @@ -282,6 +292,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, INTERVAL)) + pr_err("failed to write stat round event\n"); + } + print_counters(&rs, 0, NULL); } @@ -1639,6 +1654,11 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused) if (STAT_RECORD) { int fd = perf_data_file__fd(&perf_stat.file); + if (!interval) { + if (WRITE_STAT_ROUND_EVENT(walltime_nsecs_stats.max, FINAL)) + pr_err("failed to write stat round event\n"); + } + if (!perf_stat.file.is_pipe) { perf_stat.session->header.data_size += perf_stat.bytes_written; perf_session__write_header(perf_stat.session, evsel_list, fd, true); -- 2.4.3
We currently don't support storing multiple session in perf.data, so we can't allow -r option in stat record. $ perf stat -e cycles -r 2 record ls Cannot use -r option with perf stat record. Link: http://lkml.kernel.org/n/tip-wulio303py16c5hbbo8zrib6@git.kernel.org Signed-off-by: Jiri Olsa <jolsa@kernel.org> --- tools/perf/builtin-stat.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index 9ab268086ae7..719d2c5ade5b 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -1377,6 +1377,11 @@ static int __cmd_record(int argc, const char **argv) argc = parse_options(argc, argv, options, record_usage, PARSE_OPT_STOP_AT_NON_OPTION); + if (run_count != 1 || forever) { + pr_err("Cannot use -r option with perf stat record.\n"); + return -1; + } + session = perf_session__new(file, false, NULL); if (session == NULL) { pr_err("Perf session creation failed.\n"); -- 2.4.3
Synthesize other events stuff not carried within attr event - unit, scale, name. Link: http://lkml.kernel.org/n/tip-dzt1cls17hvc9nowg778z7vm@git.kernel.org Signed-off-by: Jiri Olsa <jolsa@kernel.org> --- 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 719d2c5ade5b..54050095ee43 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -327,8 +327,19 @@ static void workload_exec_failed_signal(int signo __maybe_unused, siginfo_t *inf workload_exec_errno = info->si_value.sival_int; } +static bool has_unit(struct perf_evsel *counter) +{ + return counter->unit && *counter->unit; +} + +static bool has_scale(struct perf_evsel *counter) +{ + return counter->scale != 1; +} + static int perf_stat_synthesize_config(bool is_pipe) { + struct perf_evsel *counter; int err; if (is_pipe) { @@ -340,6 +351,54 @@ static int perf_stat_synthesize_config(bool is_pipe) } } + /* + * Synthesize other events stuff not carried within + * attr event - unit, scale, name + */ + evlist__for_each(evsel_list, counter) { + if (!counter->supported) + continue; + + /* + * Synthesize unit and scale only if it's defined. + */ + if (has_unit(counter)) { + err = perf_event__synthesize_event_update_unit(NULL, counter, process_synthesized_event); + if (err < 0) { + pr_err("Couldn't synthesize evsel unit.\n"); + return err; + } + } + + if (has_scale(counter)) { + err = perf_event__synthesize_event_update_scale(NULL, counter, process_synthesized_event); + if (err < 0) { + pr_err("Couldn't synthesize evsel scale.\n"); + return err; + } + } + + if (counter->own_cpus) { + err = perf_event__synthesize_event_update_cpus(NULL, counter, process_synthesized_event); + if (err < 0) { + pr_err("Couldn't synthesize evsel scale.\n"); + return err; + } + } + + /* + * Name is needed only for pipe output, + * perf.data carries event names. + */ + if (is_pipe) { + err = perf_event__synthesize_event_update_name(NULL, counter, process_synthesized_event); + if (err < 0) { + pr_err("Couldn't synthesize evsel name.\n"); + return err; + } + } + } + err = perf_event__synthesize_thread_map2(NULL, evsel_list->threads, process_synthesized_event, NULL); -- 2.4.3
Adding 'perf stat report' command support. ATM it only processes attr events and display nothing. Link: http://lkml.kernel.org/n/tip-a43rs4c6szofeuo2gjlcpm0h@git.kernel.org Signed-off-by: Jiri Olsa <jolsa@kernel.org> --- tools/perf/Documentation/perf-stat.txt | 12 +++++++ tools/perf/builtin-stat.c | 61 +++++++++++++++++++++++++++++++--- tools/perf/util/session.c | 3 ++ 3 files changed, 72 insertions(+), 4 deletions(-) diff --git a/tools/perf/Documentation/perf-stat.txt b/tools/perf/Documentation/perf-stat.txt index 70eee1c2c444..95f492828657 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: @@ -170,6 +174,14 @@ Stores stat data into perf data file. --output file:: Output file name. +STAT REPORT +----------- +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 54050095ee43..1491cce68da3 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -60,6 +60,8 @@ #include "util/thread_map.h" #include "util/counts.h" #include "util/session.h" +#include "util/tool.h" +#include "asm/bug.h" #include <stdlib.h> #include <sys/prctl.h> @@ -129,6 +131,7 @@ struct perf_stat { struct perf_data_file file; struct perf_session *session; u64 bytes_written; + struct perf_tool tool; }; static struct perf_stat perf_stat; @@ -1036,8 +1039,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); @@ -1455,6 +1458,55 @@ static int __cmd_record(int argc, const char **argv) return argc; } +static const char * const report_usage[] = { + "perf stat report [<options>]", + NULL, +}; + +static struct perf_stat perf_stat = { + .tool = { + .attr = perf_event__process_attr, + }, +}; + +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 stat st; + int ret; + + argc = parse_options(argc, argv, options, report_usage, 0); + + if (!input_name || !strlen(input_name)) { + if (!fstat(STDIN_FILENO, &st) && S_ISFIFO(st.st_mode)) + input_name = "-"; + else + input_name = "perf.data"; + } + + perf_stat.file.path = input_name; + perf_stat.file.mode = PERF_DATA_MODE_READ; + + session = perf_session__new(&perf_stat.file, false, &perf_stat.tool); + if (session == NULL) + return -1; + + perf_stat.session = session; + 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; @@ -1528,7 +1580,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, ""); @@ -1544,7 +1596,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 dafdbda37411..647be278a48f 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -37,6 +37,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
Adding processing of cpu/threads maps. Configuring session's evlist with these maps. Link: http://lkml.kernel.org/n/tip-f2bo5wm0cw76zc5qsjm4pztx@git.kernel.org Signed-off-by: Jiri Olsa <jolsa@kernel.org> --- tools/perf/builtin-stat.c | 62 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index 1491cce68da3..b765e0c0ab0a 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -132,6 +132,9 @@ struct perf_stat { struct perf_session *session; u64 bytes_written; struct perf_tool tool; + bool maps_allocated; + struct cpu_map *cpus; + struct thread_map *threads; }; static struct perf_stat perf_stat; @@ -1458,6 +1461,63 @@ static int __cmd_record(int argc, const char **argv) return argc; } +static int set_maps(struct perf_stat *stat) +{ + if (!stat->cpus || !stat->threads) + return 0; + + if (WARN_ONCE(stat->maps_allocated, "stats double allocation\n")) + return -EINVAL; + + perf_evlist__set_maps(evsel_list, stat->cpus, stat->threads); + + if (perf_evlist__alloc_stats(evsel_list, true)) + return -ENOMEM; + + stat->maps_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 *stat = container_of(tool, struct perf_stat, 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 *stat = container_of(tool, struct perf_stat, tool); + struct cpu_map *cpus; + + if (stat->cpus) { + pr_warning("Extra cpu map event, ignoring.\n"); + return 0; + } + + cpus = cpu_map__new_data(&event->cpu_map.data); + if (!cpus) + return -ENOMEM; + + stat->cpus = cpus; + return set_maps(stat); +} + static const char * const report_usage[] = { "perf stat report [<options>]", NULL, @@ -1466,6 +1526,8 @@ static const char * const report_usage[] = { static struct perf_stat perf_stat = { .tool = { .attr = perf_event__process_attr, + .thread_map = process_thread_map_event, + .cpu_map = process_cpu_map_event, }, }; -- 2.4.3
Adding processing of stat config event and initialize stat_config object. Link: http://lkml.kernel.org/n/tip-f2bo5wm0cw76zc5qsjm4pztx@git.kernel.org Signed-off-by: Jiri Olsa <jolsa@kernel.org> --- 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 b765e0c0ab0a..22475d03f754 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -1461,6 +1461,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 *stat) { if (!stat->cpus || !stat->threads) @@ -1528,6 +1537,7 @@ static struct perf_stat perf_stat = { .attr = perf_event__process_attr, .thread_map = process_thread_map_event, .cpu_map = process_cpu_map_event, + .stat_config = process_stat_config_event, }, }; -- 2.4.3
Using perf.data's perf_env data to initialize aggregate config. Link: http://lkml.kernel.org/n/tip-p15mtcu2jon85trs37bwoh5f@git.kernel.org Signed-off-by: Jiri Olsa <jolsa@kernel.org> --- tools/perf/builtin-stat.c | 103 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 103 insertions(+) diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index 22475d03f754..a1617e1e5f24 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -1253,6 +1253,101 @@ static int perf_stat_init_aggr_mode(void) return cpus_aggr_map ? 0 : -ENOMEM; } +static inline int perf_env__get_cpu(struct perf_env *env, struct cpu_map *map, int idx) +{ + int cpu; + + if (idx > map->nr) + return -1; + + cpu = map->map[idx]; + + if (cpu >= env->nr_cpus_online) + return -1; + + return cpu; +} + +static int perf_env__get_socket(struct cpu_map *map, int idx, void *data) +{ + struct perf_env *env = data; + int cpu = perf_env__get_cpu(env, map, idx); + + return cpu == -1 ? -1 : env->cpu[cpu].socket_id; +} + +static int perf_env__get_core(struct cpu_map *map, int idx, void *data) +{ + struct perf_env *env = data; + int core = -1, cpu = perf_env__get_cpu(env, map, idx); + + if (cpu != -1) { + int socket = env->cpu[cpu].socket_id; + + /* + * Encode socket in upper 16 bits + * core_id is relative to socket, and + * we need a global id. So we combine + * socket + core id. + */ + core = (socket << 16) | (env->cpu[cpu].core_id & 0xffff); + } + + return core; +} + +static int perf_env__build_socket_map(struct perf_env *env, struct cpu_map *cpus, + struct cpu_map **sockp) +{ + return cpu_map__build_map(cpus, sockp, perf_env__get_socket, env); +} + +static int perf_env__build_core_map(struct perf_env *env, struct cpu_map *cpus, + struct cpu_map **corep) +{ + return cpu_map__build_map(cpus, corep, perf_env__get_core, env); +} + +static int perf_stat__get_socket_file(struct cpu_map *map, int idx) +{ + return perf_env__get_socket(map, idx, &perf_stat.session->header.env); +} + +static int perf_stat__get_core_file(struct cpu_map *map, int idx) +{ + return perf_env__get_core(map, idx, &perf_stat.session->header.env); +} + +static int perf_stat_init_aggr_mode_file(struct perf_stat *stat) +{ + struct perf_env *env = &stat->session->header.env; + + switch (stat_config.aggr_mode) { + case AGGR_SOCKET: + if (perf_env__build_socket_map(env, evsel_list->cpus, &aggr_map)) { + perror("cannot build socket map"); + return -1; + } + aggr_get_id = perf_stat__get_socket_file; + break; + case AGGR_CORE: + if (perf_env__build_core_map(env, evsel_list->cpus, &aggr_map)) { + perror("cannot build core map"); + return -1; + } + aggr_get_id = perf_stat__get_core_file; + break; + case AGGR_NONE: + case AGGR_GLOBAL: + case AGGR_THREAD: + case AGGR_UNSET: + default: + break; + } + + return 0; +} + /* * Add default attributes, if there were no attributes specified or * if -d/--detailed, -d -d or -d -d -d is used: @@ -1466,7 +1561,15 @@ int process_stat_config_event(struct perf_tool *tool __maybe_unused, union perf_event *event, struct perf_session *session __maybe_unused) { + struct perf_stat *stat = container_of(tool, struct perf_stat, tool); + perf_event__read_stat_config(&stat_config, &event->stat_config); + + if (perf_stat.file.is_pipe) + perf_stat_init_aggr_mode(); + else + perf_stat_init_aggr_mode_file(stat); + return 0; } -- 2.4.3
Adding processing of stat and stat round events. The stat data com in stat events, using generic function process_stat_round_event to store data under perf_evsel object. The stat-round events comes each interval or as last event in non interval mode. The function process_stat_round_event process stored data for each perf_evsel object and print it out. Link: http://lkml.kernel.org/n/tip-qc3ihpf6j8hlfdts64uj4nmc@git.kernel.org Signed-off-by: Jiri Olsa <jolsa@kernel.org> --- tools/perf/builtin-stat.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index a1617e1e5f24..cb05a9e1f6ea 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -1556,6 +1556,32 @@ 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 (round->type == PERF_STAT_ROUND_TYPE__FINAL) + update_stats(&walltime_nsecs_stats, round->time); + + 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, @@ -1641,6 +1667,8 @@ static struct perf_stat perf_stat = { .thread_map = process_thread_map_event, .cpu_map = process_cpu_map_event, .stat_config = process_stat_config_event, + .stat = perf_event__process_stat_event, + .stat_round = process_stat_round_event, }, }; -- 2.4.3
Adding processing of event update events, so perf stat report can store additional info for events - unit,scale,name. Link: http://lkml.kernel.org/n/tip-3afz05w7naoeu8slxi9hc0d5@git.kernel.org Signed-off-by: Jiri Olsa <jolsa@kernel.org> --- tools/perf/builtin-stat.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index cb05a9e1f6ea..6caefdc40617 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -1664,6 +1664,7 @@ static const char * const report_usage[] = { static struct perf_stat perf_stat = { .tool = { .attr = perf_event__process_attr, + .event_update = perf_event__process_event_update, .thread_map = process_thread_map_event, .cpu_map = process_cpu_map_event, .stat_config = process_stat_config_event, -- 2.4.3
So we have csv_sep properly initialized before report command leg. Link: http://lkml.kernel.org/n/tip-i5mmbomj7lt4eg04awzocdd4@git.kernel.org Signed-off-by: Jiri Olsa <jolsa@kernel.org> --- 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 6caefdc40617..4d79a11107a7 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -1796,6 +1796,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) @@ -1843,13 +1850,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
Allowing to override record aggr_mode. It's possible to use perf stat like: $ perf stat report -A $ perf stat report --per-core $ perf stat report --per-socket To customize the recorded aggregate mode regardless what was used during the stat record command. Link: http://lkml.kernel.org/n/tip-5ckzk91fsn6cvv7a740nfh8s@git.kernel.org Signed-off-by: Jiri Olsa <jolsa@kernel.org> --- tools/perf/Documentation/perf-stat.txt | 10 ++++++++++ tools/perf/builtin-stat.c | 17 +++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/tools/perf/Documentation/perf-stat.txt b/tools/perf/Documentation/perf-stat.txt index 95f492828657..52ef7a9d50aa 100644 --- a/tools/perf/Documentation/perf-stat.txt +++ b/tools/perf/Documentation/perf-stat.txt @@ -182,6 +182,16 @@ Reads and reports stat data from perf data file. --input file:: Input file name. +--per-socket:: +Aggregate counts per processor socket for system-wide mode measurements. + +--per-core:: +Aggregate counts per physical processor for system-wide mode measurements. + +-A:: +--no-aggr:: +Do not aggregate counts across all monitored CPUs. + EXAMPLES -------- diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index 4d79a11107a7..a8da4a2b0255 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -135,6 +135,7 @@ struct perf_stat { bool maps_allocated; struct cpu_map *cpus; struct thread_map *threads; + enum aggr_mode aggr_mode; }; static struct perf_stat perf_stat; @@ -1591,6 +1592,15 @@ int process_stat_config_event(struct perf_tool *tool __maybe_unused, perf_event__read_stat_config(&stat_config, &event->stat_config); + if (cpu_map__empty(stat->cpus)) { + if (stat->aggr_mode != AGGR_UNSET) + pr_warning("warning: processing task data, aggregation mode not set\n"); + return 0; + } + + if (stat->aggr_mode != AGGR_UNSET) + stat_config.aggr_mode = stat->aggr_mode; + if (perf_stat.file.is_pipe) perf_stat_init_aggr_mode(); else @@ -1671,6 +1681,7 @@ static struct perf_stat perf_stat = { .stat = perf_event__process_stat_event, .stat_round = process_stat_round_event, }, + .aggr_mode = AGGR_UNSET, }; static int __cmd_report(int argc, const char **argv) @@ -1678,6 +1689,12 @@ 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_SET_UINT(0, "per-socket", &perf_stat.aggr_mode, + "aggregate counts per processor socket", AGGR_SOCKET), + OPT_SET_UINT(0, "per-core", &perf_stat.aggr_mode, + "aggregate counts per physical processor core", AGGR_CORE), + OPT_SET_UINT('A', "no-aggr", &perf_stat.aggr_mode, + "disable CPU count aggregation", AGGR_NONE), OPT_END() }; struct stat st; -- 2.4.3
Adding processing of cpu/threads maps. Configuring session's evlist with these maps. Link: http://lkml.kernel.org/n/tip-s3txa1u2qv3bi8uspp4hi7al@git.kernel.org Signed-off-by: Jiri Olsa <jolsa@kernel.org> --- tools/perf/builtin-script.c | 67 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index 2653c0273b89..651ac9edf870 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c @@ -18,7 +18,11 @@ #include "util/sort.h" #include "util/data.h" #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" static char const *script_name; static char const *generate_script_lang; @@ -659,6 +663,9 @@ struct perf_script { bool show_task_events; bool show_mmap_events; bool show_switch_events; + bool allocated; + struct cpu_map *cpus; + struct thread_map *threads; }; static int process_attr(struct perf_tool *tool, union perf_event *event, @@ -1615,6 +1622,63 @@ static void script__setup_sample_type(struct perf_script *script) } } +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; + + perf_evlist__set_maps(evlist, script->cpus, script->threads); + + if (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_data(&event->cpu_map.data); + 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; @@ -1643,6 +1707,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, }, @@ -1996,6 +2062,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
Adding processing of stat config event and initialize stat_config object. Link: http://lkml.kernel.org/n/tip-1m1s8mahzq38foo32qb7p2a5@git.kernel.org Signed-off-by: Jiri Olsa <jolsa@kernel.org> --- tools/perf/builtin-script.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index 651ac9edf870..9ccb82deba21 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c @@ -36,6 +36,7 @@ static bool print_flags; static bool nanosecs; static const char *cpu_list; static DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS); +static struct perf_stat_config stat_config; unsigned int scripting_max_stack = PERF_MAX_STACK_DEPTH; @@ -1622,6 +1623,14 @@ static void script__setup_sample_type(struct perf_script *script) } } +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; @@ -1707,6 +1716,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
Python and perl scripting code will define those callbacks and get stat data. Link: http://lkml.kernel.org/n/tip-6802z3siu5f59wdsmhaym3wm@git.kernel.org Signed-off-by: Jiri Olsa <jolsa@kernel.org> --- 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 b85ee55cca0c..0ebc9dab2c7c 100644 --- a/tools/perf/util/trace-event.h +++ b/tools/perf/util/trace-event.h @@ -65,6 +65,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; @@ -75,6 +76,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
Implement struct scripting_ops::(process_stat|process_stat_interval) handlers - calling scripting handlers from stat events handlers. Link: http://lkml.kernel.org/n/tip-3iu6vmvuur1bntbnh43v3bib@git.kernel.org Signed-off-by: Jiri Olsa <jolsa@kernel.org> --- 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 9ccb82deba21..c8750815c6d3 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c @@ -205,6 +205,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); @@ -568,6 +571,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) @@ -596,6 +607,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, }; @@ -1623,6 +1636,22 @@ static void script__setup_sample_type(struct perf_script *script) } } +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) @@ -1716,6 +1745,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
If no script is specified for stat data, display stat events in raw form. $ perf stat record ls SNIP Performance counter stats for 'ls': 0.851585 task-clock (msec) # 0.717 CPUs utilized 0 context-switches # 0.000 K/sec 0 cpu-migrations # 0.000 K/sec 114 page-faults # 0.134 M/sec 2,620,918 cycles # 3.078 GHz <not supported> stalled-cycles-frontend <not supported> stalled-cycles-backend 2,714,111 instructions # 1.04 insns per cycle 542,434 branches # 636.970 M/sec 15,946 branch-misses # 2.94% of all branches 0.001186954 seconds time elapsed $ perf script CPU THREAD VAL ENA RUN TIME EVENT -1 26185 851585 851585 851585 1186954 task-clock -1 26185 0 851585 851585 1186954 context-switches -1 26185 0 851585 851585 1186954 cpu-migrations -1 26185 114 851585 851585 1186954 page-faults -1 26185 2620918 853340 853340 1186954 cycles -1 26185 0 0 0 1186954 stalled-cycles-frontend -1 26185 0 0 0 1186954 stalled-cycles-backend -1 26185 2714111 853340 853340 1186954 instructions -1 26185 542434 853340 853340 1186954 branches -1 26185 15946 853340 853340 1186954 branch-misses Link: http://lkml.kernel.org/n/tip-ph7bpnetmskvmietfwllf6i6@git.kernel.org Signed-off-by: Jiri Olsa <jolsa@kernel.org> --- 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 c8750815c6d3..8197e6a2d7cb 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c @@ -572,9 +572,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
Add support to get stat events data in perf python scripts. The python script shall implement following new interface to process stat data: def stat__<event_name>_[<modifier>](cpu, thread, time, val, ena, run): - is called for every stat event for given counter, if user monitors 'cycles,instructions:u" following callbacks should be defined: def stat__cycles(cpu, thread, time, val, ena, run): def stat__instructions_u(cpu, thread, time, val, ena, run): def stat__interval(time): - is called for every interval with its time, in non interval mode it's called after last stat event with total meassured time in ns The rest of the current interface stays untouched.. Please check example CPI metrics script in following patch with command line examples in changelogs. Link: http://lkml.kernel.org/n/tip-jojiaelyckrw6040wqc06q1j@git.kernel.org Signed-off-by: Jiri Olsa <jolsa@kernel.org> --- .../util/scripting-engines/trace-event-python.c | 114 +++++++++++++++++++-- 1 file changed, 108 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 a8e825fca42a..8436eb23eb16 100644 --- a/tools/perf/util/scripting-engines/trace-event-python.c +++ b/tools/perf/util/scripting-engines/trace-event-python.c @@ -41,6 +41,9 @@ #include "../thread-stack.h" #include "../trace-event.h" #include "../machine.h" +#include "thread_map.h" +#include "cpumap.h" +#include "stat.h" PyMODINIT_FUNC initperf_trace_context(void); @@ -859,6 +862,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__"); @@ -1201,10 +1301,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
Adding stat-cpi.py as an example of how to do stat scripting. It computes the CPI metrics from cycles and instructions events. Following stat record/report/script combinations could be used: - get CPI for given workload $ perf stat -e cycles,instructions record ls SNIP Performance counter stats for 'ls': 2,904,431 cycles 3,346,878 instructions # 1.15 insns per cycle 0.001782686 seconds time elapsed $ perf script -s ./scripts/python/stat-cpi.py 0.001783: cpu -1, thread -1 -> cpi 0.867803 (2904431/3346878) $ perf stat -e cycles,instructions record ls | perf script -s ./scripts/python/stat-cpi.py SNIP 0.001730: cpu -1, thread -1 -> cpi 0.869026 (2928292/3369627) - get CPI systemwide: $ perf stat -e cycles,instructions -a -I 1000 record sleep 3 # time counts unit events 1.000158618 594,274,711 cycles (100.00%) 1.000158618 441,898,250 instructions 2.000350973 567,649,705 cycles (100.00%) 2.000350973 432,669,206 instructions 3.000559210 561,940,430 cycles (100.00%) 3.000559210 420,403,465 instructions 3.000670798 780,105 cycles (100.00%) 3.000670798 326,516 instructions $ perf script -s ./scripts/python/stat-cpi.py 1.000159: cpu -1, thread -1 -> cpi 1.344823 (594274711/441898250) 2.000351: cpu -1, thread -1 -> cpi 1.311972 (567649705/432669206) 3.000559: cpu -1, thread -1 -> cpi 1.336669 (561940430/420403465) 3.000671: cpu -1, thread -1 -> cpi 2.389178 (780105/326516) $ perf stat -e cycles,instructions -a -I 1000 record sleep 3 | perf script -s ./scripts/python/stat-cpi.py 1.000202: cpu -1, thread -1 -> cpi 1.035091 (940778881/908885530) 2.000392: cpu -1, thread -1 -> cpi 1.442600 (627493992/434974455) 3.000545: cpu -1, thread -1 -> cpi 1.353612 (741463930/547766890) 3.000622: cpu -1, thread -1 -> cpi 2.642110 (784083/296764) Link: http://lkml.kernel.org/n/tip-15vwwb4yea15wzz6bqbxdpc0@git.kernel.org Signed-off-by: Jiri Olsa <jolsa@kernel.org> --- 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
Em Sun, Oct 25, 2015 at 03:51:16PM +0100, Jiri Olsa escreveu: > hi, > sending another version of stat scripting. > > v5 changes: > - several patches from v4 already taken > - using u16 for cpu number in cpu_map_event > - renamed PERF_RECORD_HEADER_ATTR_UPDATE to PERF_RECORD_EVENT_UPDATE > - moved low hanging fuits patches to the start of the patchset > - patchset tested by Kan Liang, thanks! So, next time please add the Tested-by: tag for the patches you haven't changed since Kan (or any other tester, I guess) said he tested. I'm not adding it now, since I'm not checking one by one the patches to see the ones that changed, only re-reviewing them on their own. If Kan could provide retest, I can go on and add the Tested-by tags, Thanks, - Arnaldo > v4 changes: > - added attr update event for event's cpumask > - forbig aggregation on task workloads > - some minor reorders and changelog fixes > > v3 changes: > - added attr update event to handle unit,scale,name for event > it fixed the uncore_imc_1/cas_count_read/ record/report > - perf report -D now displays stat related events > - some minor and changelog fixes > > v2 changes: > - rebased to latest Arnaldo's perf/core > - patches 1 to 11 already merged in > - added --per-core/--per-socket/-A options for perf stat report > command to allow custom aggregation in stat report, please > check new examples below > - couple changelogs changes > > 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. > > 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 > > thanks, > jirka > > 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 > > - To display different aggregation in report: > > $ perf stat -e cycles -a -I 1000 record sleep 3 > # time counts unit events > 1.000223609 703,427,617 cycles > 2.000443651 609,975,307 cycles > 3.000569616 668,479,597 cycles > 3.000735323 1,155,816 cycles > > $ perf stat report > # time counts unit events > 1.000223609 703,427,617 cycles > 2.000443651 609,975,307 cycles > 3.000569616 668,479,597 cycles > 3.000735323 1,155,816 cycles > > $ perf stat report --per-core > # time core cpus counts unit events > 1.000223609 S0-C0 2 327,612,412 cycles > 1.000223609 S0-C1 2 375,815,205 cycles > 2.000443651 S0-C0 2 287,462,177 cycles > 2.000443651 S0-C1 2 322,513,130 cycles > 3.000569616 S0-C0 2 271,571,908 cycles > 3.000569616 S0-C1 2 396,907,689 cycles > 3.000735323 S0-C0 2 694,977 cycles > 3.000735323 S0-C1 2 460,839 cycles > > $ perf stat report --per-socket > # time socket cpus counts unit events > 1.000223609 S0 4 703,427,617 cycles > 2.000443651 S0 4 609,975,307 cycles > 3.000569616 S0 4 668,479,597 cycles > 3.000735323 S0 4 1,155,816 cycles > > $ perf stat report -A > # time CPU counts unit events > 1.000223609 CPU0 205,431,505 cycles > 1.000223609 CPU1 122,180,907 cycles > 1.000223609 CPU2 176,649,682 cycles > 1.000223609 CPU3 199,165,523 cycles > 2.000443651 CPU0 148,447,922 cycles > 2.000443651 CPU1 139,014,255 cycles > 2.000443651 CPU2 204,436,559 cycles > 2.000443651 CPU3 118,076,571 cycles > 3.000569616 CPU0 149,788,954 cycles > 3.000569616 CPU1 121,782,954 cycles > 3.000569616 CPU2 247,277,700 cycles > 3.000569616 CPU3 149,629,989 cycles > 3.000735323 CPU0 269,675 cycles > 3.000735323 CPU1 425,302 cycles > 3.000735323 CPU2 364,169 cycles > 3.000735323 CPU3 96,670 cycles > > > Cc: Andi Kleen <andi@firstfloor.org> > Cc: Ulrich Drepper <drepper@gmail.com> > Cc: Will Deacon <will.deacon@arm.com> > Cc: Stephane Eranian <eranian@google.com> > Cc: Don Zickus <dzickus@redhat.com> > Tested-by: Kan Liang <kan.liang@intel.com> > --- > Jiri Olsa (52): > perf cpu_map: Add cpu_map__empty_new function > perf stat: Cache aggregated map entries in extra cpumap > 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 perf_event__fprintf_thread_map 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 perf_event__fprintf_cpu_map 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: Add stat events fprintf functions > perf tools: Add event_update event > perf tools: Add event_update event unit type > perf tools: Add event_update event scale type > perf tools: Add event_update event name type > perf tools: Add event_update event cpus type > perf tools: Add perf_event__fprintf_event_update function > perf report: Display newly added events in raw dump > 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 record: Do not allow record with multiple runs mode > perf stat record: Synthesize event update events > perf stat report: Add report command > perf stat report: Process cpu/threads maps > perf stat report: Process stat config event > perf stat report: Add support to initialize aggr_map from file > perf stat report: Process stat and stat round events > perf stat report: Process event update events > perf stat report: Move csv_sep initialization before report command > perf stat report: Allow to override aggr_mode > 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 | 34 ++ > tools/perf/builtin-record.c | 2 + > tools/perf/builtin-script.c | 139 +++++ > tools/perf/builtin-stat.c | 643 ++++++++++++++++++++- > tools/perf/scripts/python/stat-cpi.py | 74 +++ > tools/perf/tests/Build | 3 + > tools/perf/tests/builtin-test.c | 24 + > tools/perf/tests/cpumap.c | 88 +++ > tools/perf/tests/event_update.c | 117 ++++ > tools/perf/tests/stat.c | 111 ++++ > tools/perf/tests/tests.h | 7 + > tools/perf/tests/thread-map.c | 43 ++ > tools/perf/util/cpumap.c | 59 ++ > tools/perf/util/cpumap.h | 2 + > tools/perf/util/event.c | 308 ++++++++++ > tools/perf/util/event.h | 150 ++++- > tools/perf/util/evlist.c | 6 +- > tools/perf/util/evlist.h | 3 + > tools/perf/util/evsel.h | 2 +- > tools/perf/util/header.c | 205 +++++++ > tools/perf/util/header.h | 17 + > .../util/scripting-engines/trace-event-python.c | 114 +++- > tools/perf/util/session.c | 189 ++++++ > tools/perf/util/stat.c | 62 ++ > tools/perf/util/stat.h | 10 + > tools/perf/util/thread_map.c | 27 + > tools/perf/util/thread_map.h | 3 + > tools/perf/util/tool.h | 8 +- > tools/perf/util/trace-event.h | 4 + > 29 files changed, 2427 insertions(+), 27 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/event_update.c > create mode 100644 tools/perf/tests/stat.c
Em Sun, Oct 25, 2015 at 03:51:19PM +0100, Jiri Olsa escreveu: > Adding thread_map event to pass/store thread maps > as data in pipe/perf.data. > > Storing thread ID along with the standard comm[16] > thread name string. > > Link: http://lkml.kernel.org/n/tip-2l07qyf3buhnt83q4ezqz5sj@git.kernel.org > Signed-off-by: Jiri Olsa <jolsa@kernel.org> > --- > 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 8b10621b415c..771545a27b9b 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_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 a0dbcbd4f6d8..f075f9ed0051 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_INFO = 70, > PERF_RECORD_AUXTRACE = 71, > PERF_RECORD_AUXTRACE_ERROR = 72, > + PERF_RECORD_THREAD_MAP = 73, > PERF_RECORD_HEADER_MAX > }; > > @@ -356,6 +357,17 @@ struct context_switch_event { > u32 next_prev_tid; > }; > > +struct thread_map_data_event { Humm, I think "data" here is way too vague here, how about "thread_map_event_entry"? Moving of "entry" to the end also helps in understanding that this is not an "event" per se, it doesn't have the perv_event_header, etc, its just an entry in a 'struct thread_map_event'. I'm tentatively doing this change in my local branch, please let me know if you have any reason to object to such a change, - Arnaldo > + 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; > @@ -378,6 +390,7 @@ union perf_event { > struct aux_event aux; > struct itrace_start_event itrace_start; > struct context_switch_event context_switch; > + 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 428149bc64d2..ec1ecd31003b 100644 > --- a/tools/perf/util/session.c > +++ b/tools/perf/util/session.c > @@ -296,6 +296,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) > @@ -346,6 +356,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); > > @@ -643,6 +666,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, > }; > > @@ -1179,6 +1203,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 cab8cc24831b..1af4774960c3 100644 > --- a/tools/perf/util/tool.h > +++ b/tools/perf/util/tool.h > @@ -55,7 +55,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
On Mon, Oct 26, 2015 at 02:42:06PM -0300, Arnaldo Carvalho de Melo wrote:
SNIP
> > PERF_RECORD_AUXTRACE_ERROR = 72,
> > + PERF_RECORD_THREAD_MAP = 73,
> > PERF_RECORD_HEADER_MAX
> > };
> >
> > @@ -356,6 +357,17 @@ struct context_switch_event {
> > u32 next_prev_tid;
> > };
> >
> > +struct thread_map_data_event {
>
> Humm, I think "data" here is way too vague here, how about
> "thread_map_event_entry"?
>
> Moving of "entry" to the end also helps in understanding that this is
> not an "event" per se, it doesn't have the perv_event_header, etc, its
> just an entry in a 'struct thread_map_event'.
>
> I'm tentatively doing this change in my local branch, please let me know
> if you have any reason to object to such a change,
np, hope there's not much dependency on this later
in patchset ;-) probably not..
thanks,
jirka
Em Mon, Oct 26, 2015 at 02:42:06PM -0300, Arnaldo Carvalho de Melo escreveu: > Em Sun, Oct 25, 2015 at 03:51:19PM +0100, Jiri Olsa escreveu: > > Adding thread_map event to pass/store thread maps > > as data in pipe/perf.data. > > > > Storing thread ID along with the standard comm[16] > > thread name string. > > > > Link: http://lkml.kernel.org/n/tip-2l07qyf3buhnt83q4ezqz5sj@git.kernel.org > > Signed-off-by: Jiri Olsa <jolsa@kernel.org> > > --- > > 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 8b10621b415c..771545a27b9b 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_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 a0dbcbd4f6d8..f075f9ed0051 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_INFO = 70, > > PERF_RECORD_AUXTRACE = 71, > > PERF_RECORD_AUXTRACE_ERROR = 72, > > + PERF_RECORD_THREAD_MAP = 73, > > PERF_RECORD_HEADER_MAX > > }; > > > > @@ -356,6 +357,17 @@ struct context_switch_event { > > u32 next_prev_tid; > > }; > > > > +struct thread_map_data_event { > > Humm, I think "data" here is way too vague here, how about > "thread_map_event_entry"? > > Moving of "entry" to the end also helps in understanding that this is > not an "event" per se, it doesn't have the perv_event_header, etc, its > just an entry in a 'struct thread_map_event'. > > I'm tentatively doing this change in my local branch, please let me know > if you have any reason to object to such a change, The resulting patch, that I'm merging with this one: diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h index f075f9ed0051..66f303e69c4d 100644 --- a/tools/perf/util/event.h +++ b/tools/perf/util/event.h @@ -357,7 +357,7 @@ struct context_switch_event { u32 next_prev_tid; }; -struct thread_map_data_event { +struct thread_map_event_entry { u64 pid; char comm[16]; }; @@ -365,7 +365,7 @@ struct thread_map_data_event { struct thread_map_event { struct perf_event_header header; u64 nr; - struct thread_map_data_event data[]; + struct thread_map_event_entry entries[]; }; union perf_event { diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index ec1ecd31003b..0aedce61f930 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -636,7 +636,7 @@ static void perf_event__thread_map_swap(union perf_event *event, 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); + event->thread_map.entries[i].pid = bswap_64(event->thread_map.entries[i].pid); } typedef void (*perf_event__swap_op)(union perf_event *event,
On Mon, Oct 26, 2015 at 02:48:25PM -0300, Arnaldo Carvalho de Melo wrote:
SNIP
> > > u32 next_prev_tid;
> > > };
> > >
> > > +struct thread_map_data_event {
> >
> > Humm, I think "data" here is way too vague here, how about
> > "thread_map_event_entry"?
> >
> > Moving of "entry" to the end also helps in understanding that this is
> > not an "event" per se, it doesn't have the perv_event_header, etc, its
> > just an entry in a 'struct thread_map_event'.
> >
> > I'm tentatively doing this change in my local branch, please let me know
> > if you have any reason to object to such a change,
>
> The resulting patch, that I'm merging with this one:
seems ok, thanks
jirka
Em Mon, Oct 26, 2015 at 06:55:45PM +0100, Jiri Olsa escreveu:
> On Mon, Oct 26, 2015 at 02:48:25PM -0300, Arnaldo Carvalho de Melo wrote:
>
> SNIP
>
> > > > u32 next_prev_tid;
> > > > };
> > > >
> > > > +struct thread_map_data_event {
> > >
> > > Humm, I think "data" here is way too vague here, how about
> > > "thread_map_event_entry"?
> > >
> > > Moving of "entry" to the end also helps in understanding that this is
> > > not an "event" per se, it doesn't have the perv_event_header, etc, its
> > > just an entry in a 'struct thread_map_event'.
> > >
> > > I'm tentatively doing this change in my local branch, please let me know
> > > if you have any reason to object to such a change,
> >
> > The resulting patch, that I'm merging with this one:
>
>
> seems ok, thanks
Thanks for checking, hopefully I can push this today.
- Arnaldo
Em Sun, Oct 25, 2015 at 03:51:27PM +0100, Jiri Olsa escreveu: > Adding stat config event to pass/store stat config data, > so report tools (report/script) know how to interpret > stat data. > > The config data are stored in 'tag|value' way to allow > easy extension and backward compatibility. I wonder if this couldn't be renamed 'PERF_RECORD_CONFIG' and just go on using one of those 2^64-1 tags for the 'stat config' needs, but then this is just a matter of changing the name of this event, which won't break anything when done. Other stuff we may want to have stored like this include sysctl, sysfs values, kernel command line options used, etc. - Arnaldo > Link: http://lkml.kernel.org/n/tip-1npdsfez8635vogthpqwtkd0@git.kernel.org > Signed-off-by: Jiri Olsa <jolsa@kernel.org> > --- > 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 36dc992b072f..1165cb1d891f 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_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 e46f95285350..0bc3393dd28c 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_AUXTRACE_ERROR = 72, > PERF_RECORD_THREAD_MAP = 73, > PERF_RECORD_CPU_MAP = 74, > + PERF_RECORD_STAT_CONFIG = 75, > PERF_RECORD_HEADER_MAX > }; > > @@ -395,6 +396,24 @@ struct thread_map_event { > struct thread_map_data_event data[]; > }; > > +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; > @@ -419,6 +438,7 @@ union perf_event { > struct context_switch_event context_switch; > 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 5126b18c671c..a550464925ea 100644 > --- a/tools/perf/util/session.c > +++ b/tools/perf/util/session.c > @@ -315,6 +315,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) > @@ -369,6 +378,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) > @@ -686,6 +697,16 @@ static void perf_event__cpu_map_swap(union perf_event *event, > } > } > > +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); > > @@ -715,6 +736,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, > }; > > @@ -1255,6 +1277,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 9e5925c78519..aa7ae73d76b4 100644 > --- a/tools/perf/util/tool.h > +++ b/tools/perf/util/tool.h > @@ -57,7 +57,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
On Tue, Oct 27, 2015 at 10:16:05AM -0300, Arnaldo Carvalho de Melo wrote: > Em Sun, Oct 25, 2015 at 03:51:27PM +0100, Jiri Olsa escreveu: > > Adding stat config event to pass/store stat config data, > > so report tools (report/script) know how to interpret > > stat data. > > > > The config data are stored in 'tag|value' way to allow > > easy extension and backward compatibility. > > I wonder if this couldn't be renamed 'PERF_RECORD_CONFIG' and just go > on using one of those 2^64-1 tags for the 'stat config' needs, but then > this is just a matter of changing the name of this event, which won't > break anything when done. we use this event to update 'struct perf_stat_config', so it's kind of stat specific > > Other stuff we may want to have stored like this include sysctl, sysfs > values, kernel command line options used, etc. I think we could easily add record specific event for this once it's needed.. there's plenty of free numbers in user events area ;-) jirka
Em Tue, Oct 27, 2015 at 02:30:43PM +0100, Jiri Olsa escreveu: > On Tue, Oct 27, 2015 at 10:16:05AM -0300, Arnaldo Carvalho de Melo wrote: > > Em Sun, Oct 25, 2015 at 03:51:27PM +0100, Jiri Olsa escreveu: > > > Adding stat config event to pass/store stat config data, > > > so report tools (report/script) know how to interpret > > > stat data. > > > > > > The config data are stored in 'tag|value' way to allow > > > easy extension and backward compatibility. > > > > I wonder if this couldn't be renamed 'PERF_RECORD_CONFIG' and just go > > on using one of those 2^64-1 tags for the 'stat config' needs, but then > > this is just a matter of changing the name of this event, which won't > > break anything when done. > > we use this event to update 'struct perf_stat_config', > so it's kind of stat specific What makes it specific? Isn't this just tag/value? If it was generic all it would take would be for us to register a range of values (or several) to be handled by the stat config reading routine. > > Other stuff we may want to have stored like this include sysctl, sysfs > > values, kernel command line options used, etc. > > I think we could easily add record specific event for this > once it's needed.. there's plenty of free numbers in user > events area ;-) Shhh, don't ask PeterZ about it ;-) But seriously, what makes this specific? Do you envision the stat code needing 2^64-1 tags? Anyway, we can revisit this when code needing to store tag/value appears. - Arnaldo
On Tue, Oct 27, 2015 at 10:44:40AM -0300, Arnaldo Carvalho de Melo wrote:
> Em Tue, Oct 27, 2015 at 02:30:43PM +0100, Jiri Olsa escreveu:
> > On Tue, Oct 27, 2015 at 10:16:05AM -0300, Arnaldo Carvalho de Melo wrote:
> > > Em Sun, Oct 25, 2015 at 03:51:27PM +0100, Jiri Olsa escreveu:
> > > > Adding stat config event to pass/store stat config data,
> > > > so report tools (report/script) know how to interpret
> > > > stat data.
> > > >
> > > > The config data are stored in 'tag|value' way to allow
> > > > easy extension and backward compatibility.
> > >
> > > I wonder if this couldn't be renamed 'PERF_RECORD_CONFIG' and just go
> > > on using one of those 2^64-1 tags for the 'stat config' needs, but then
> > > this is just a matter of changing the name of this event, which won't
> > > break anything when done.
> >
> > we use this event to update 'struct perf_stat_config',
> > so it's kind of stat specific
>
> What makes it specific? Isn't this just tag/value? If it was generic all
> it would take would be for us to register a range of values (or several)
> to be handled by the stat config reading routine.
>
> > > Other stuff we may want to have stored like this include sysctl, sysfs
> > > values, kernel command line options used, etc.
> >
> > I think we could easily add record specific event for this
> > once it's needed.. there's plenty of free numbers in user
> > events area ;-)
>
> Shhh, don't ask PeterZ about it ;-)
>
> But seriously, what makes this specific? Do you envision the stat code
> needing 2^64-1 tags?
nope ;-)
it's just the read function perf_event__read_stat_config takes the
'struct perf_stat_config *' and updates it based on the event data.
we would need to change the code to be more generic.. but as you said,
it's future ;-)
jirka
Em Tue, Oct 27, 2015 at 02:51:54PM +0100, Jiri Olsa escreveu: > On Tue, Oct 27, 2015 at 10:44:40AM -0300, Arnaldo Carvalho de Melo wrote: > > > I think we could easily add record specific event for this > > > once it's needed.. there's plenty of free numbers in user > > > events area ;-) > > Shhh, don't ask PeterZ about it ;-) > > But seriously, what makes this specific? Do you envision the stat code > > needing 2^64-1 tags? > nope ;-) > it's just the read function perf_event__read_stat_config takes the > 'struct perf_stat_config *' and updates it based on the event data. > we would need to change the code to be more generic.. but as you said, > it's future ;-) Right, I applied the patch, I was just curious if I was missing some detail that would prevent us from using this as a generic tag/value perf.data storing facility. - Arnaldo
> > Em Sun, Oct 25, 2015 at 03:51:16PM +0100, Jiri Olsa escreveu: > > hi, > > sending another version of stat scripting. > > > > v5 changes: > > - several patches from v4 already taken > > - using u16 for cpu number in cpu_map_event > > - renamed PERF_RECORD_HEADER_ATTR_UPDATE to > PERF_RECORD_EVENT_UPDATE > > - moved low hanging fuits patches to the start of the patchset > > - patchset tested by Kan Liang, thanks! > > So, next time please add the Tested-by: tag for the patches you haven't > changed since Kan (or any other tester, I guess) said he tested. > > I'm not adding it now, since I'm not checking one by one the patches to see > the ones that changed, only re-reviewing them on their own. > > If Kan could provide retest, I can go on and add the Tested-by tags, > Redo the test for V5. It looks good to me. Tested-by: Kan Liang <kan.liang@intel.com> Thanks, Kan > Thanks, > > - Arnaldo > > > v4 changes: > > - added attr update event for event's cpumask > > - forbig aggregation on task workloads > > - some minor reorders and changelog fixes > > > > v3 changes: > > - added attr update event to handle unit,scale,name for event > > it fixed the uncore_imc_1/cas_count_read/ record/report > > - perf report -D now displays stat related events > > - some minor and changelog fixes > > > > v2 changes: > > - rebased to latest Arnaldo's perf/core > > - patches 1 to 11 already merged in > > - added --per-core/--per-socket/-A options for perf stat report > > command to allow custom aggregation in stat report, please > > check new examples below > > - couple changelogs changes > > > > 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. > > > > 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 > > > > thanks, > > jirka > > > > 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 > > > > - To display different aggregation in report: > > > > $ perf stat -e cycles -a -I 1000 record sleep 3 > > # time counts unit events > > 1.000223609 703,427,617 cycles > > 2.000443651 609,975,307 cycles > > 3.000569616 668,479,597 cycles > > 3.000735323 1,155,816 cycles > > > > $ perf stat report > > # time counts unit events > > 1.000223609 703,427,617 cycles > > 2.000443651 609,975,307 cycles > > 3.000569616 668,479,597 cycles > > 3.000735323 1,155,816 cycles > > > > $ perf stat report --per-core > > # time core cpus counts unit events > > 1.000223609 S0-C0 2 327,612,412 cycles > > 1.000223609 S0-C1 2 375,815,205 cycles > > 2.000443651 S0-C0 2 287,462,177 cycles > > 2.000443651 S0-C1 2 322,513,130 cycles > > 3.000569616 S0-C0 2 271,571,908 cycles > > 3.000569616 S0-C1 2 396,907,689 cycles > > 3.000735323 S0-C0 2 694,977 cycles > > 3.000735323 S0-C1 2 460,839 cycles > > > > $ perf stat report --per-socket > > # time socket cpus counts unit events > > 1.000223609 S0 4 703,427,617 cycles > > 2.000443651 S0 4 609,975,307 cycles > > 3.000569616 S0 4 668,479,597 cycles > > 3.000735323 S0 4 1,155,816 cycles > > > > $ perf stat report -A > > # time CPU counts unit events > > 1.000223609 CPU0 205,431,505 cycles > > 1.000223609 CPU1 122,180,907 cycles > > 1.000223609 CPU2 176,649,682 cycles > > 1.000223609 CPU3 199,165,523 cycles > > 2.000443651 CPU0 148,447,922 cycles > > 2.000443651 CPU1 139,014,255 cycles > > 2.000443651 CPU2 204,436,559 cycles > > 2.000443651 CPU3 118,076,571 cycles > > 3.000569616 CPU0 149,788,954 cycles > > 3.000569616 CPU1 121,782,954 cycles > > 3.000569616 CPU2 247,277,700 cycles > > 3.000569616 CPU3 149,629,989 cycles > > 3.000735323 CPU0 269,675 cycles > > 3.000735323 CPU1 425,302 cycles > > 3.000735323 CPU2 364,169 cycles > > 3.000735323 CPU3 96,670 cycles > > > > > > Cc: Andi Kleen <andi@firstfloor.org> > > Cc: Ulrich Drepper <drepper@gmail.com> > > Cc: Will Deacon <will.deacon@arm.com> > > Cc: Stephane Eranian <eranian@google.com> > > Cc: Don Zickus <dzickus@redhat.com> > > Tested-by: Kan Liang <kan.liang@intel.com> > > --- > > Jiri Olsa (52): > > perf cpu_map: Add cpu_map__empty_new function > > perf stat: Cache aggregated map entries in extra cpumap > > 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 perf_event__fprintf_thread_map 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 perf_event__fprintf_cpu_map 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: Add stat events fprintf functions > > perf tools: Add event_update event > > perf tools: Add event_update event unit type > > perf tools: Add event_update event scale type > > perf tools: Add event_update event name type > > perf tools: Add event_update event cpus type > > perf tools: Add perf_event__fprintf_event_update function > > perf report: Display newly added events in raw dump > > 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 record: Do not allow record with multiple runs mode > > perf stat record: Synthesize event update events > > perf stat report: Add report command > > perf stat report: Process cpu/threads maps > > perf stat report: Process stat config event > > perf stat report: Add support to initialize aggr_map from file > > perf stat report: Process stat and stat round events > > perf stat report: Process event update events > > perf stat report: Move csv_sep initialization before report command > > perf stat report: Allow to override aggr_mode > > 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 | 34 ++ > > tools/perf/builtin-record.c | 2 + > > tools/perf/builtin-script.c | 139 +++++ > > tools/perf/builtin-stat.c | 643 ++++++++++++++++++++- > > tools/perf/scripts/python/stat-cpi.py | 74 +++ > > tools/perf/tests/Build | 3 + > > tools/perf/tests/builtin-test.c | 24 + > > tools/perf/tests/cpumap.c | 88 +++ > > tools/perf/tests/event_update.c | 117 ++++ > > tools/perf/tests/stat.c | 111 ++++ > > tools/perf/tests/tests.h | 7 + > > tools/perf/tests/thread-map.c | 43 ++ > > tools/perf/util/cpumap.c | 59 ++ > > tools/perf/util/cpumap.h | 2 + > > tools/perf/util/event.c | 308 ++++++++++ > > tools/perf/util/event.h | 150 ++++- > > tools/perf/util/evlist.c | 6 +- > > tools/perf/util/evlist.h | 3 + > > tools/perf/util/evsel.h | 2 +- > > tools/perf/util/header.c | 205 +++++++ > > tools/perf/util/header.h | 17 + > > .../util/scripting-engines/trace-event-python.c | 114 +++- > > tools/perf/util/session.c | 189 ++++++ > > tools/perf/util/stat.c | 62 ++ > > tools/perf/util/stat.h | 10 + > > tools/perf/util/thread_map.c | 27 + > > tools/perf/util/thread_map.h | 3 + > > tools/perf/util/tool.h | 8 +- > > tools/perf/util/trace-event.h | 4 + > > 29 files changed, 2427 insertions(+), 27 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/event_update.c create mode 100644 > > tools/perf/tests/stat.c
Em Sun, Oct 25, 2015 at 03:51:45PM +0100, Jiri Olsa escreveu: > Add 'perf stat record' command support. It creates simple > (header only) perf.data file ATM. Huh? Couldn't we have the tools providing a sensible message at this point? [root@zoo linux]# rm -f perf.data [root@zoo linux]# perf stat record usleep 1 Performance counter stats for 'usleep 1': 0.575678 task-clock (msec) # 0.508 CPUs utilized 1 context-switches # 0.002 M/sec 0 cpu-migrations # 0.000 K/sec 52 page-faults # 0.090 M/sec 905601 cycles # 1.573 GHz 608259 stalled-cycles-frontend # 67.17% frontend cycles idle <not supported> stalled-cycles-backend 616889 instructions # 0.68 insns per cycle # 0.99 stalled cycles per insn 125710 branches # 218.369 M/sec 7589 branch-misses # 6.04% of all branches 0.001134076 seconds time elapsed [root@zoo linux]# perf evlist WARNING: The perf.data file's data size field is 0 which is unexpected. Was the 'perf record' command properly terminated? non matching sample_type[root@zoo linux]# [root@zoo linux]# perf report --stdio WARNING: The perf.data file's data size field is 0 which is unexpected. Was the 'perf record' command properly terminated? non matching sample_type[root@zoo linux]# --------------------------------------------------------------------------------------- Can't we make it so that older tools will juts state that there are no samples, i.e.: [root@zoo linux]# perf record -e alignment-faults usleep 1 [ perf record: Woken up 1 times to write data ] [ perf record: Captured and wrote 0.018 MB perf.data ] [root@zoo linux]# perf evlist alignment-faults [root@zoo linux]# perf report --stdio Error: The perf.data file has no samples! # To display the perf.data header info, please use --header/--header-only options. # [root@zoo linux]# -------------------------------------------------------------------------------- This looks a friendlier message, as the 'perf stat record' file really has no samples, by definition :-) This is not a show stopper tho, to make progress, I'll continue processing the patches here, but please consider changing this patch to improve the output produced by older tools. - Arnaldo > Link: http://lkml.kernel.org/n/tip-0av5yfkwyywwgoiali88w4hi@git.kernel.org > Signed-off-by: Jiri Olsa <jolsa@kernel.org> > --- > 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 4e074a660826..70eee1c2c444 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=:: > @@ -159,6 +162,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 a3880aa65b04..b65cc6a46226 100644 > --- a/tools/perf/builtin-stat.c > +++ b/tools/perf/builtin-stat.c > @@ -59,6 +59,7 @@ > #include "util/thread.h" > #include "util/thread_map.h" > #include "util/counts.h" > +#include "util/session.h" > > #include <stdlib.h> > #include <sys/prctl.h> > @@ -123,6 +124,16 @@ static struct timespec ref_time; > static struct cpu_map *aggr_map; > static aggr_get_id_t aggr_get_id; > > +struct perf_stat { > + bool record; > + struct perf_data_file file; > + struct perf_session *session; > + u64 bytes_written; > +}; > + > +static struct perf_stat perf_stat; > +#define STAT_RECORD perf_stat.record > + > static volatile int done = 0; > > static struct perf_stat_config stat_config = { > @@ -341,6 +352,15 @@ static int __run_perf_stat(int argc, const char **argv) > return -1; > } > > + if (STAT_RECORD) { > + int err, fd = perf_data_file__fd(&perf_stat.file); > + > + err = perf_session__write_header(perf_stat.session, evsel_list, > + fd, false); > + if (err < 0) > + return err; > + } > + > /* > * Enable counters and exec the command: > */ > @@ -1192,6 +1212,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 = &perf_stat.file; > + const struct option options[] = { > + OPT_STRING('o', "output", &perf_stat.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 (perf_stat.file.is_pipe) > + return -EINVAL; > + > + session->evlist = evsel_list; > + perf_stat.session = session; > + perf_stat.record = true; > + return argc; > +} > + > int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused) > { > bool append_file = false; > @@ -1265,6 +1318,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, ""); > > @@ -1272,8 +1326,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; > > @@ -1444,6 +1505,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(&perf_stat.file); > + > + perf_stat.session->header.data_size += perf_stat.bytes_written; > + perf_session__write_header(perf_stat.session, evsel_list, fd, true); > + > + perf_session__delete(perf_stat.session); > + } > + > perf_evlist__free_stats(evsel_list); > out: > perf_evlist__delete(evsel_list); > -- > 2.4.3
Em Sun, Oct 25, 2015 at 03:51:47PM +0100, Jiri Olsa escreveu:
> Synthesizing needed stat record data for report/script:
> - cpu/thread maps
> - stat config
After this it gets a bit better, but then I expected that to specify an
event I would be able to use:
[root@zoo linux]# perf stat record -e cycles usleep 1
Error: unknown switch `e'
Usage: perf record [<options>] [<command>]
or: perf record [<options>] -- <command> [<options>]
-o, --output <file> output file name
But I need to do it as:
[root@zoo linux]# perf stat -e cycles record usleep 1
Performance counter stats for 'usleep 1':
948417 cycles
0.000749965 seconds time elapsed
[root@zoo linux]#
--------------------------------------------------
This is confusing...
Anyway, now the perf.data file doesn't produce that many confusing
messages, just one, and the error reporting continues needing a
newline, oops just noticed another problem:
[root@zoo linux]# perf stat record usleep 1
Performance counter stats for 'usleep 1':
0.520959 task-clock (msec) # 0.504 CPUs utilized
1 context-switches # 0.002 M/sec
0 cpu-migrations # 0.000 K/sec
51 page-faults # 0.098 M/sec
929738 cycles # 1.785 GHz
625885 stalled-cycles-frontend # 67.32% frontend cycles idle
<not supported> stalled-cycles-backend
634514 instructions # 0.68 insns per cycle
# 0.99 stalled cycles per insn
128859 branches # 247.350 M/sec
7602 branch-misses # 5.90% of all branches
0.001034675 seconds time elapsed
[root@zoo linux]# perf evlist
non matching sample_type[root@zoo linux]#
But, if I specify an event:
[root@zoo linux]# perf stat -e cycles record usleep 1
Performance counter stats for 'usleep 1':
876987 cycles
0.001285050 seconds time elapsed
[root@zoo linux]# perf evlist
cycles
[root@zoo linux]# perf evlist -v
cycles: size: 112, read_format: TOTAL_TIME_ENABLED|TOTAL_TIME_RUNNING, disabled: 1, inherit: 1, enable_on_exec: 1, exclude_guest: 1
[root@zoo linux]#
-------------------------
It then works as expected, lists the event collected, no confusing message
about 'sample_type' stuff is emitted.
Ditto for 'perf report'
[root@zoo linux]# perf report --stdio
Warning:
Kernel address maps (/proc/{kallsyms,modules}) were restricted.
Check /proc/sys/kernel/kptr_restrict before running 'perf record'.
As no suitable kallsyms nor vmlinux was found, kernel samples
can't be resolved.
Samples in kernel modules can't be resolved as well.
Error:
The perf.data file has no samples!
# To display the perf.data header info, please use --header/--header-only options.
#
[root@zoo linux]#
------------------------------------------------
I.e. when I explicitely state what events should be collected, it behaves
nicely, modulo this message about kernel address maps being restricted in
'report', so it looks like just some fix is needed to make it work like that
when no events are specified.
So, I'm creating a perf/stat branch and putting what I processed so far, with
the changelog edits and changes in some function/struct names I
partially mentioned, please try to continue from there, ok?
- Arnaldo
Em Tue, Oct 27, 2015 at 02:24:03PM +0000, Liang, Kan escreveu:
>
>
> >
> > Em Sun, Oct 25, 2015 at 03:51:16PM +0100, Jiri Olsa escreveu:
> > > hi,
> > > sending another version of stat scripting.
> > >
> > > v5 changes:
> > > - several patches from v4 already taken
> > > - using u16 for cpu number in cpu_map_event
> > > - renamed PERF_RECORD_HEADER_ATTR_UPDATE to
> > PERF_RECORD_EVENT_UPDATE
> > > - moved low hanging fuits patches to the start of the patchset
> > > - patchset tested by Kan Liang, thanks!
> >
> > So, next time please add the Tested-by: tag for the patches you haven't
> > changed since Kan (or any other tester, I guess) said he tested.
> >
> > I'm not adding it now, since I'm not checking one by one the patches to see
> > the ones that changed, only re-reviewing them on their own.
> >
> > If Kan could provide retest, I can go on and add the Tested-by tags,
> >
>
> Redo the test for V5. It looks good to me.
>
> Tested-by: Kan Liang <kan.liang@intel.com>
Thanks, adding this tag to the patches I processed so far, then
repushing to the perf/stat branch.
- Arnaldo
On Tue, Oct 27, 2015 at 11:42:44AM -0300, Arnaldo Carvalho de Melo wrote:
SNIP
>
> So, I'm creating a perf/stat branch and putting what I processed so far, with
> the changelog edits and changes in some function/struct names I
> partially mentioned, please try to continue from there, ok?
ok, I'll rebase the rest on yours perf/stat
thanks,
jirka
On Tue, Oct 27, 2015 at 11:42:44AM -0300, Arnaldo Carvalho de Melo wrote:
> Em Sun, Oct 25, 2015 at 03:51:47PM +0100, Jiri Olsa escreveu:
> > Synthesizing needed stat record data for report/script:
> > - cpu/thread maps
> > - stat config
>
> After this it gets a bit better, but then I expected that to specify an
> event I would be able to use:
>
> [root@zoo linux]# perf stat record -e cycles usleep 1
> Error: unknown switch `e'
>
> Usage: perf record [<options>] [<command>]
> or: perf record [<options>] -- <command> [<options>]
>
> -o, --output <file> output file name
>
>
> But I need to do it as:
>
> [root@zoo linux]# perf stat -e cycles record usleep 1
>
> Performance counter stats for 'usleep 1':
>
> 948417 cycles
>
> 0.000749965 seconds time elapsed
>
> [root@zoo linux]#
>
> --------------------------------------------------
>
> This is confusing...
yep, the thing is that we need to have all the options supported
by perf stat to work under perf stat record.
you basically let user use perf stat with 'record' that just says
'store the data I'm monitoring'
I'll try to find some way to move the options under perf stat record
without too many changes.. but not sure
jirka
On Tue, Oct 27, 2015 at 11:42:44AM -0300, Arnaldo Carvalho de Melo wrote:
SNIP
> This is confusing...
>
> Anyway, now the perf.data file doesn't produce that many confusing
> messages, just one, and the error reporting continues needing a
> newline, oops just noticed another problem:
>
> [root@zoo linux]# perf stat record usleep 1
>
> Performance counter stats for 'usleep 1':
>
> 0.520959 task-clock (msec) # 0.504 CPUs utilized
> 1 context-switches # 0.002 M/sec
> 0 cpu-migrations # 0.000 K/sec
> 51 page-faults # 0.098 M/sec
> 929738 cycles # 1.785 GHz
> 625885 stalled-cycles-frontend # 67.32% frontend cycles idle
> <not supported> stalled-cycles-backend
> 634514 instructions # 0.68 insns per cycle
> # 0.99 stalled cycles per insn
> 128859 branches # 247.350 M/sec
> 7602 branch-misses # 5.90% of all branches
>
> 0.001034675 seconds time elapsed
>
> [root@zoo linux]# perf evlist
> non matching sample_type[root@zoo linux]#
will check, thanks,
jirka
Commit-ID: af3399817428d8adc2c87c91df23fde77dbcdb35 Gitweb: http://git.kernel.org/tip/af3399817428d8adc2c87c91df23fde77dbcdb35 Author: Jiri Olsa <jolsa@kernel.org> AuthorDate: Sun, 25 Oct 2015 15:51:44 +0100 Committer: Arnaldo Carvalho de Melo <acme@redhat.com> CommitDate: Tue, 27 Oct 2015 15:04:29 -0300 perf evsel: Move id_offset out of struct perf_evsel union member Because the 'perf stat record' patches will use the id_offset member together with the priv pointer. Signed-off-by: Jiri Olsa <jolsa@kernel.org> Tested-by: Kan Liang <kan.liang@intel.com> Cc: David Ahern <dsahern@gmail.com> Cc: Namhyung Kim <namhyung@kernel.org> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Link: http://lkml.kernel.org/r/1445784728-21732-29-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> --- 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 02a5fed..0e22c0b 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h @@ -90,9 +90,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;
Commit-ID: 2322f573f8131da9c6d1fab01fe0a0c2c23aa549 Gitweb: http://git.kernel.org/tip/2322f573f8131da9c6d1fab01fe0a0c2c23aa549 Author: Jiri Olsa <jolsa@kernel.org> AuthorDate: Sun, 25 Oct 2015 15:51:17 +0100 Committer: Arnaldo Carvalho de Melo <acme@redhat.com> CommitDate: Tue, 27 Oct 2015 15:05:36 -0300 perf cpu_map: Add cpu_map__empty_new function Adding cpu_map__empty_new interface to create empty cpumap with given size. The cpumap entries are initialized with -1. It'll be used for caching cpu_map in following patches. Signed-off-by: Jiri Olsa <jolsa@kernel.org> Tested-by: Kan Liang <kan.liang@intel.com> Cc: Namhyung Kim <namhyung@kernel.org> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Link: http://lkml.kernel.org/r/1445784728-21732-2-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> --- tools/perf/util/cpumap.c | 17 +++++++++++++++++ tools/perf/util/cpumap.h | 1 + 2 files changed, 18 insertions(+) diff --git a/tools/perf/util/cpumap.c b/tools/perf/util/cpumap.c index aa6b490..10af1e7 100644 --- a/tools/perf/util/cpumap.c +++ b/tools/perf/util/cpumap.c @@ -203,6 +203,23 @@ struct cpu_map *cpu_map__dummy_new(void) return cpus; } +struct cpu_map *cpu_map__empty_new(int nr) +{ + struct cpu_map *cpus = malloc(sizeof(*cpus) + sizeof(int) * nr); + + if (cpus != NULL) { + int i; + + cpus->nr = nr; + for (i = 0; i < nr; i++) + cpus->map[i] = -1; + + atomic_set(&cpus->refcnt, 1); + } + + return cpus; +} + static void cpu_map__delete(struct cpu_map *map) { if (map) { diff --git a/tools/perf/util/cpumap.h b/tools/perf/util/cpumap.h index f1bcd2c..85f7772 100644 --- a/tools/perf/util/cpumap.h +++ b/tools/perf/util/cpumap.h @@ -15,6 +15,7 @@ struct cpu_map { }; struct cpu_map *cpu_map__new(const char *cpu_list); +struct cpu_map *cpu_map__empty_new(int nr); struct cpu_map *cpu_map__dummy_new(void); struct cpu_map *cpu_map__read(FILE *file); size_t cpu_map__fprintf(struct cpu_map *map, FILE *fp);
Commit-ID: 1e5a29318ba8506f52a8d727b5c6a53143f9882a Gitweb: http://git.kernel.org/tip/1e5a29318ba8506f52a8d727b5c6a53143f9882a Author: Jiri Olsa <jolsa@kernel.org> AuthorDate: Sun, 25 Oct 2015 15:51:18 +0100 Committer: Arnaldo Carvalho de Melo <acme@redhat.com> CommitDate: Tue, 27 Oct 2015 15:08:07 -0300 perf stat: Cache aggregated map entries in extra cpumap Currently any time we need to access socket or core id for given cpu, we access the sysfs topology file. Adding a cpus_aggr_map cpu_map to cache those entries. Signed-off-by: Jiri Olsa <jolsa@kernel.org> Tested-by: Kan Liang <kan.liang@intel.com> Cc: David Ahern <dsahern@gmail.com> Cc: Namhyung Kim <namhyung@kernel.org> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Link: http://lkml.kernel.org/r/1445784728-21732-3-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> --- tools/perf/builtin-stat.c | 59 +++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 55 insertions(+), 4 deletions(-) diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index 91e793a..2f438f7 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -100,6 +100,8 @@ static struct target target = { .uid = UINT_MAX, }; +typedef int (*aggr_get_id_t)(struct cpu_map *m, int cpu); + static int run_count = 1; static bool no_inherit = false; static volatile pid_t child_pid = -1; @@ -119,7 +121,7 @@ static unsigned int unit_width = 4; /* strlen("unit") */ static bool forever = false; static struct timespec ref_time; static struct cpu_map *aggr_map; -static int (*aggr_get_id)(struct cpu_map *m, int cpu); +static aggr_get_id_t aggr_get_id; static volatile int done = 0; @@ -954,22 +956,63 @@ static int perf_stat__get_core(struct cpu_map *map, int cpu) return cpu_map__get_core(map, cpu, NULL); } +static int cpu_map__get_max(struct cpu_map *map) +{ + int i, max = -1; + + for (i = 0; i < map->nr; i++) { + if (map->map[i] > max) + max = map->map[i]; + } + + return max; +} + +static struct cpu_map *cpus_aggr_map; + +static int perf_stat__get_aggr(aggr_get_id_t get_id, struct cpu_map *map, int idx) +{ + int cpu; + + if (idx >= map->nr) + return -1; + + cpu = map->map[idx]; + + if (cpus_aggr_map->map[cpu] == -1) + cpus_aggr_map->map[cpu] = get_id(map, idx); + + return cpus_aggr_map->map[cpu]; +} + +static int perf_stat__get_socket_cached(struct cpu_map *map, int idx) +{ + return perf_stat__get_aggr(perf_stat__get_socket, map, idx); +} + +static int perf_stat__get_core_cached(struct cpu_map *map, int idx) +{ + return perf_stat__get_aggr(perf_stat__get_core, map, idx); +} + static int perf_stat_init_aggr_mode(void) { + int nr; + switch (stat_config.aggr_mode) { case AGGR_SOCKET: if (cpu_map__build_socket_map(evsel_list->cpus, &aggr_map)) { perror("cannot build socket map"); return -1; } - aggr_get_id = perf_stat__get_socket; + aggr_get_id = perf_stat__get_socket_cached; break; case AGGR_CORE: if (cpu_map__build_core_map(evsel_list->cpus, &aggr_map)) { perror("cannot build core map"); return -1; } - aggr_get_id = perf_stat__get_core; + aggr_get_id = perf_stat__get_core_cached; break; case AGGR_NONE: case AGGR_GLOBAL: @@ -978,7 +1021,15 @@ static int perf_stat_init_aggr_mode(void) default: break; } - return 0; + + /* + * The evsel_list->cpus is the base we operate on, + * taking the highest cpu number to be the size of + * the aggregation translate cpumap. + */ + nr = cpu_map__get_max(evsel_list->cpus); + cpus_aggr_map = cpu_map__empty_new(nr + 1); + return cpus_aggr_map ? 0 : -ENOMEM; } /*
Commit-ID: 5f3339d2e83ca587c2e13c3e37e1b5fb7c68ebe5 Gitweb: http://git.kernel.org/tip/5f3339d2e83ca587c2e13c3e37e1b5fb7c68ebe5 Author: Jiri Olsa <jolsa@kernel.org> AuthorDate: Sun, 25 Oct 2015 15:51:19 +0100 Committer: Arnaldo Carvalho de Melo <acme@redhat.com> CommitDate: Thu, 17 Dec 2015 14:38:16 -0300 perf thread_map: Add thread_map user level event Adding the thread_map event to pass/store thread maps as data in the pipe/perf.data. Storing the thread ID along with the standard comm[16] thread name string. Signed-off-by: Jiri Olsa <jolsa@kernel.org> Tested-by: Kan Liang <kan.liang@intel.com> Cc: David Ahern <dsahern@gmail.com> Cc: Namhyung Kim <namhyung@kernel.org> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Link: http://lkml.kernel.org/r/1445784728-21732-4-git-send-email-jolsa@kernel.org [ Renamed thread_map_data_event to thread_map_event_entry ] Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> --- 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 8b10621..771545a 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_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 a0dbcbd..66f303e 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_INFO = 70, PERF_RECORD_AUXTRACE = 71, PERF_RECORD_AUXTRACE_ERROR = 72, + PERF_RECORD_THREAD_MAP = 73, PERF_RECORD_HEADER_MAX }; @@ -356,6 +357,17 @@ struct context_switch_event { u32 next_prev_tid; }; +struct thread_map_event_entry { + u64 pid; + char comm[16]; +}; + +struct thread_map_event { + struct perf_event_header header; + u64 nr; + struct thread_map_event_entry entries[]; +}; + union perf_event { struct perf_event_header header; struct mmap_event mmap; @@ -378,6 +390,7 @@ union perf_event { struct aux_event aux; struct itrace_start_event itrace_start; struct context_switch_event context_switch; + 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 9774686..36b07b2 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -296,6 +296,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) @@ -346,6 +356,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.entries[i].pid = bswap_64(event->thread_map.entries[i].pid); +} + typedef void (*perf_event__swap_op)(union perf_event *event, bool sample_id_all); @@ -643,6 +666,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, }; @@ -1179,6 +1203,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 cab8cc2..1af4774 100644 --- a/tools/perf/util/tool.h +++ b/tools/perf/util/tool.h @@ -55,7 +55,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;
Commit-ID: 99471c967a00c875bb5d61f377d4267904545499 Gitweb: http://git.kernel.org/tip/99471c967a00c875bb5d61f377d4267904545499 Author: Jiri Olsa <jolsa@kernel.org> AuthorDate: Sun, 25 Oct 2015 15:51:20 +0100 Committer: Arnaldo Carvalho de Melo <acme@redhat.com> CommitDate: Thu, 17 Dec 2015 14:38:16 -0300 perf thread_map: Add thread_map event sythesize function Introduce the perf_event__synthesize_thread_map2 function to synthesize struct thread_map. The perf_event__synthesize_thread_map name is already taken for synthesizing the complete threads data (comm/mmap/fork). Signed-off-by: Jiri Olsa <jolsa@kernel.org> Tested-by: Kan Liang <kan.liang@intel.com> Cc: David Ahern <dsahern@gmail.com> Cc: Namhyung Kim <namhyung@kernel.org> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Link: http://lkml.kernel.org/r/1445784728-21732-5-git-send-email-jolsa@kernel.org [ Rename thread_map_data_event to thread_map_event_entry ] Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> --- 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 0372d59..745bdb0 100644 --- a/tools/perf/tests/builtin-test.c +++ b/tools/perf/tests/builtin-test.c @@ -180,6 +180,10 @@ static struct test generic_tests[] = { }, }, { + .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 a0733aa..3fe52cc 100644 --- a/tools/perf/tests/tests.h +++ b/tools/perf/tests/tests.h @@ -79,6 +79,7 @@ int test__bpf(int subtest); const char *test__bpf_subtest_get_desc(int subtest); int test__bpf_subtest_get_nr(void); int test_session_topology(int subtest); +int test__thread_map_synthesize(int subtest); #if 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 2be02d3..ac5be25 100644 --- a/tools/perf/tests/thread-map.c +++ b/tools/perf/tests/thread-map.c @@ -40,3 +40,32 @@ int test__thread_map(int subtest __maybe_unused) 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->entries[0].pid == (u64) getpid()); + TEST_ASSERT_VAL("wrong comm", !strcmp(map->entries[0].comm, "perf")); + return 0; +} + +int test__thread_map_synthesize(int subtest __maybe_unused) +{ + 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 771545a..b13373a 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c @@ -700,6 +700,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.entries[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_event_entry *entry = &event->thread_map.entries[i]; + char *comm = thread_map__comm(threads, i); + + if (!comm) + comm = (char *) ""; + + entry->pid = thread_map__pid(threads, i); + strncpy((char *) &entry->comm, comm, sizeof(entry->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 66f303e..952dd4d 100644 --- a/tools/perf/util/event.h +++ b/tools/perf/util/event.h @@ -408,6 +408,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,
Commit-ID: 59660942397b57b37eccba014544623cf4beb12b Gitweb: http://git.kernel.org/tip/59660942397b57b37eccba014544623cf4beb12b Author: Jiri Olsa <jolsa@kernel.org> AuthorDate: Sun, 25 Oct 2015 15:51:21 +0100 Committer: Arnaldo Carvalho de Melo <acme@redhat.com> CommitDate: Thu, 17 Dec 2015 14:38:16 -0300 perf thread_map: Add thread_map__new_event function Introducing the thread_map__new_event function to create a struct thread_map object from a thread_map event. Signed-off-by: Jiri Olsa <jolsa@kernel.org> Tested-by: Kan Liang <kan.liang@intel.com> Cc: David Ahern <dsahern@gmail.com> Cc: Namhyung Kim <namhyung@kernel.org> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Link: http://lkml.kernel.org/r/1445784728-21732-6-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> --- 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 ac5be25..fccde84 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->entries[0].pid == (u64) getpid()); TEST_ASSERT_VAL("wrong comm", !strcmp(map->entries[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 371fb28..08afc69 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) @@ -409,3 +410,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->entries[i].pid); + threads->map[i].comm = strndup(event->entries[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 af679d8..85e4c7c 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);
Commit-ID: ec7fa596f514b76a5f1003ffe9e6dfb50cb9e811 Gitweb: http://git.kernel.org/tip/ec7fa596f514b76a5f1003ffe9e6dfb50cb9e811 Author: Jiri Olsa <jolsa@kernel.org> AuthorDate: Sun, 25 Oct 2015 15:51:22 +0100 Committer: Arnaldo Carvalho de Melo <acme@redhat.com> CommitDate: Thu, 17 Dec 2015 14:38:17 -0300 perf thread_map: Add perf_event__fprintf_thread_map function To display a thread_map event for a raw dump. Signed-off-by: Jiri Olsa <jolsa@kernel.org> Tested-by: Kan Liang <kan.liang@intel.com> Cc: David Ahern <dsahern@gmail.com> Cc: Namhyung Kim <namhyung@kernel.org> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Link: http://lkml.kernel.org/r/1445784728-21732-7-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> --- tools/perf/util/event.c | 16 ++++++++++++++++ tools/perf/util/event.h | 1 + 2 files changed, 17 insertions(+) diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index b13373a..938f006 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c @@ -820,6 +820,22 @@ size_t perf_event__fprintf_mmap2(union perf_event *event, FILE *fp) event->mmap2.filename); } +size_t perf_event__fprintf_thread_map(union perf_event *event, FILE *fp) +{ + struct thread_map *threads = thread_map__new_event(&event->thread_map); + size_t ret; + + ret = fprintf(fp, " nr: "); + + if (threads) + ret += thread_map__fprintf(threads, fp); + else + ret += fprintf(fp, "failed to get threads from event\n"); + + thread_map__put(threads); + return ret; +} + int perf_event__process_mmap(struct perf_tool *tool __maybe_unused, union perf_event *event, struct perf_sample *sample, diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h index 952dd4d..b7ad896 100644 --- a/tools/perf/util/event.h +++ b/tools/perf/util/event.h @@ -516,6 +516,7 @@ size_t perf_event__fprintf_task(union perf_event *event, FILE *fp); size_t perf_event__fprintf_aux(union perf_event *event, FILE *fp); size_t perf_event__fprintf_itrace_start(union perf_event *event, FILE *fp); size_t perf_event__fprintf_switch(union perf_event *event, FILE *fp); +size_t perf_event__fprintf_thread_map(union perf_event *event, FILE *fp); size_t perf_event__fprintf(union perf_event *event, FILE *fp); u64 kallsyms__get_function_start(const char *kallsyms_filename,
Commit-ID: 6640b6c227fc85fd8bdcc4a31239a04450487f6a Gitweb: http://git.kernel.org/tip/6640b6c227fc85fd8bdcc4a31239a04450487f6a Author: Jiri Olsa <jolsa@kernel.org> AuthorDate: Sun, 25 Oct 2015 15:51:23 +0100 Committer: Arnaldo Carvalho de Melo <acme@redhat.com> CommitDate: Thu, 17 Dec 2015 14:38:17 -0300 perf cpu_map: Add cpu_map user level event Adding the cpu_map event to pass/store cpu maps as data in a pipe/perf.data. We store maps in 2 formats: - list of cpus - mask of cpus The format that takes less space is selected transparently in the following patch. The interface is made generic, so we could add the cpumap event data into another event in the following patches. Signed-off-by: Jiri Olsa <jolsa@kernel.org> Tested-by: Kan Liang <kan.liang@intel.com> Cc: David Ahern <dsahern@gmail.com> Cc: Namhyung Kim <namhyung@kernel.org> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Link: http://lkml.kernel.org/r/1445784728-21732-8-git-send-email-jolsa@kernel.org [ cpu_map_data_cpus -> cpu_map_entries, cpu_map_data_mask -> cpu_map_mask ] Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> --- tools/perf/util/event.c | 1 + tools/perf/util/event.h | 28 ++++++++++++++++++++++++++ tools/perf/util/session.c | 50 +++++++++++++++++++++++++++++++++++++++++++++++ tools/perf/util/tool.h | 3 ++- 4 files changed, 81 insertions(+), 1 deletion(-) diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index 938f006..719c078 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c @@ -38,6 +38,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 b7ad896..1c82a0e 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 = 71, PERF_RECORD_AUXTRACE_ERROR = 72, PERF_RECORD_THREAD_MAP = 73, + PERF_RECORD_CPU_MAP = 74, PERF_RECORD_HEADER_MAX }; @@ -271,6 +272,32 @@ struct events_stats { u32 nr_proc_map_timeout; }; +enum { + PERF_CPU_MAP__CPUS = 0, + PERF_CPU_MAP__MASK = 1, +}; + +struct cpu_map_entries { + u16 nr; + u16 cpu[]; +}; + +struct cpu_map_mask { + u16 nr; + u16 long_size; + unsigned long mask[]; +}; + +struct cpu_map_data { + u16 type; + char data[]; +}; + +struct cpu_map_event { + struct perf_event_header header; + struct cpu_map_data data; +}; + struct attr_event { struct perf_event_header header; struct perf_event_attr attr; @@ -391,6 +418,7 @@ union perf_event { struct itrace_start_event itrace_start; struct context_switch_event context_switch; 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 36b07b2..4350f5e 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -306,6 +306,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) @@ -358,6 +367,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,42 @@ static void perf_event__thread_map_swap(union perf_event *event, event->thread_map.entries[i].pid = bswap_64(event->thread_map.entries[i].pid); } +static void perf_event__cpu_map_swap(union perf_event *event, + bool sample_id_all __maybe_unused) +{ + struct cpu_map_data *data = &event->cpu_map.data; + struct cpu_map_entries *cpus; + struct cpu_map_mask *mask; + unsigned i; + + data->type = bswap_64(data->type); + + switch (data->type) { + case PERF_CPU_MAP__CPUS: + cpus = (struct cpu_map_entries *)data->data; + + cpus->nr = bswap_16(cpus->nr); + + for (i = 0; i < cpus->nr; i++) + cpus->cpu[i] = bswap_16(cpus->cpu[i]); + break; + case PERF_CPU_MAP__MASK: + mask = (struct cpu_map_mask *) data->data; + + mask->nr = bswap_16(mask->nr); + mask->long_size = bswap_16(mask->long_size); + + switch (mask->long_size) { + case 4: mem_bswap_32(&mask->mask, mask->nr); break; + case 8: mem_bswap_64(&mask->mask, mask->nr); break; + default: + pr_err("cpu_map swap: unsupported long size\n"); + } + default: + break; + } +} + typedef void (*perf_event__swap_op)(union perf_event *event, bool sample_id_all); @@ -667,6 +714,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, }; @@ -1205,6 +1253,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 1af4774..9e5925c 100644 --- a/tools/perf/util/tool.h +++ b/tools/perf/util/tool.h @@ -56,7 +56,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;
Commit-ID: 6c872901af07c41745f1abf5ceac9b3b4d9cdbb6 Gitweb: http://git.kernel.org/tip/6c872901af07c41745f1abf5ceac9b3b4d9cdbb6 Author: Jiri Olsa <jolsa@kernel.org> AuthorDate: Sun, 25 Oct 2015 15:51:24 +0100 Committer: Arnaldo Carvalho de Melo <acme@redhat.com> CommitDate: Thu, 17 Dec 2015 14:38:18 -0300 perf cpu_map: Add cpu_map event synthesize function Introduce the perf_event__synthesize_cpu_map function to synthesize a struct cpu_map. Added generic interface: cpu_map_data__alloc cpu_map_data__synthesize to make the cpu_map synthesizing usable for other events. Signed-off-by: Jiri Olsa <jolsa@kernel.org> Tested-by: Kan Liang <kan.liang@intel.com> Cc: David Ahern <dsahern@gmail.com> Cc: Namhyung Kim <namhyung@kernel.org> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Link: http://lkml.kernel.org/r/1445784728-21732-9-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> --- tools/perf/tests/Build | 1 + tools/perf/tests/builtin-test.c | 4 ++ tools/perf/tests/cpumap.c | 71 ++++++++++++++++++++++ tools/perf/tests/tests.h | 1 + tools/perf/util/event.c | 131 ++++++++++++++++++++++++++++++++++++++++ tools/perf/util/event.h | 8 +++ 6 files changed, 216 insertions(+) diff --git a/tools/perf/tests/Build b/tools/perf/tests/Build index f23fb7e..7abad28 100644 --- a/tools/perf/tests/Build +++ b/tools/perf/tests/Build @@ -34,6 +34,7 @@ perf-y += thread-map.o perf-y += llvm.o llvm-src-base.o llvm-src-kbuild.o llvm-src-prologue.o perf-y += bpf.o perf-y += topology.o +perf-y += cpumap.o $(OUTPUT)tests/llvm-src-base.c: tests/bpf-script-example.c tests/Build $(call rule_mkdir) diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c index 745bdb0..0c3fe28 100644 --- a/tools/perf/tests/builtin-test.c +++ b/tools/perf/tests/builtin-test.c @@ -184,6 +184,10 @@ static struct test generic_tests[] = { .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 0000000..7154805 --- /dev/null +++ b/tools/perf/tests/cpumap.c @@ -0,0 +1,71 @@ +#include "tests.h" +#include "cpumap.h" + +static int process_event_mask(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; + struct cpu_map_mask *mask; + struct cpu_map_data *data; + int i; + + data = &map->data; + + TEST_ASSERT_VAL("wrong type", data->type == PERF_CPU_MAP__MASK); + + mask = (struct cpu_map_mask *)data->data; + + TEST_ASSERT_VAL("wrong nr", mask->nr == 1); + + for (i = 0; i < 20; i++) { + TEST_ASSERT_VAL("wrong cpu", test_bit(i, mask->mask)); + } + + return 0; +} + +static int process_event_cpus(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; + struct cpu_map_entries *cpus; + struct cpu_map_data *data; + + data = &map->data; + + TEST_ASSERT_VAL("wrong type", data->type == PERF_CPU_MAP__CPUS); + + cpus = (struct cpu_map_entries *)data->data; + + TEST_ASSERT_VAL("wrong nr", cpus->nr == 2); + TEST_ASSERT_VAL("wrong cpu", cpus->cpu[0] == 1); + TEST_ASSERT_VAL("wrong cpu", cpus->cpu[1] == 256); + return 0; +} + + +int test__cpu_map_synthesize(int subtest __maybe_unused) +{ + struct cpu_map *cpus; + + /* This one is better stores in mask. */ + cpus = cpu_map__new("0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19"); + + TEST_ASSERT_VAL("failed to synthesize map", + !perf_event__synthesize_cpu_map(NULL, cpus, process_event_mask, NULL)); + + cpu_map__put(cpus); + + /* This one is better stores in cpu values. */ + cpus = cpu_map__new("1,256"); + + TEST_ASSERT_VAL("failed to synthesize map", + !perf_event__synthesize_cpu_map(NULL, cpus, process_event_cpus, NULL)); + + cpu_map__put(cpus); + return 0; +} diff --git a/tools/perf/tests/tests.h b/tools/perf/tests/tests.h index 3fe52cc..f85160f 100644 --- a/tools/perf/tests/tests.h +++ b/tools/perf/tests/tests.h @@ -80,6 +80,7 @@ const char *test__bpf_subtest_get_desc(int subtest); int test__bpf_subtest_get_nr(void); int test_session_topology(int subtest); int test__thread_map_synthesize(int subtest); +int test__cpu_map_synthesize(int subtest); #if defined(__arm__) || defined(__aarch64__) #ifdef HAVE_DWARF_UNWIND_SUPPORT diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index 719c078..15d6466 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c @@ -737,6 +737,137 @@ int perf_event__synthesize_thread_map2(struct perf_tool *tool, return err; } +static void synthesize_cpus(struct cpu_map_entries *cpus, + struct cpu_map *map) +{ + int i; + + cpus->nr = map->nr; + + for (i = 0; i < map->nr; i++) + cpus->cpu[i] = map->map[i]; +} + +static void synthesize_mask(struct cpu_map_mask *mask, + struct cpu_map *map, int max) +{ + int i; + + mask->nr = BITS_TO_LONGS(max); + mask->long_size = sizeof(long); + + for (i = 0; i < map->nr; i++) + set_bit(map->map[i], mask->mask); +} + +static size_t cpus_size(struct cpu_map *map) +{ + return sizeof(struct cpu_map_entries) + map->nr * sizeof(u16); +} + +static size_t mask_size(struct cpu_map *map, int *max) +{ + int i; + + *max = 0; + + for (i = 0; i < map->nr; i++) { + /* bit possition of the cpu is + 1 */ + int bit = map->map[i] + 1; + + if (bit > *max) + *max = bit; + } + + return sizeof(struct cpu_map_mask) + BITS_TO_LONGS(*max) * sizeof(long); +} + +void *cpu_map_data__alloc(struct cpu_map *map, size_t *size, u16 *type, int *max) +{ + size_t size_cpus, size_mask; + bool is_dummy = cpu_map__empty(map); + + /* + * Both array and mask data have variable size based + * on the number of cpus and their actual values. + * The size of the 'struct cpu_map_data' is: + * + * array = size of 'struct cpu_map_entries' + + * number of cpus * sizeof(u64) + * + * mask = size of 'struct cpu_map_mask' + + * maximum cpu bit converted to size of longs + * + * and finaly + the size of 'struct cpu_map_data'. + */ + size_cpus = cpus_size(map); + size_mask = mask_size(map, max); + + if (is_dummy || (size_cpus < size_mask)) { + *size += size_cpus; + *type = PERF_CPU_MAP__CPUS; + } else { + *size += size_mask; + *type = PERF_CPU_MAP__MASK; + } + + *size += sizeof(struct cpu_map_data); + return zalloc(*size); +} + +void cpu_map_data__synthesize(struct cpu_map_data *data, struct cpu_map *map, + u16 type, int max) +{ + data->type = type; + + switch (type) { + case PERF_CPU_MAP__CPUS: + synthesize_cpus((struct cpu_map_entries *) data->data, map); + break; + case PERF_CPU_MAP__MASK: + synthesize_mask((struct cpu_map_mask *) data->data, map, max); + default: + break; + }; +} + +static struct cpu_map_event* cpu_map_event__new(struct cpu_map *map) +{ + size_t size = sizeof(struct cpu_map_event); + struct cpu_map_event *event; + int max; + u16 type; + + event = cpu_map_data__alloc(map, &size, &type, &max); + if (!event) + return NULL; + + event->header.type = PERF_RECORD_CPU_MAP; + event->header.size = size; + event->data.type = type; + + cpu_map_data__synthesize(&event->data, map, type, max); + return event; +} + +int perf_event__synthesize_cpu_map(struct perf_tool *tool, + struct cpu_map *map, + perf_event__handler_t process, + struct machine *machine) +{ + struct cpu_map_event *event; + int err; + + event = cpu_map_event__new(map); + if (!event) + return -ENOMEM; + + 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 1c82a0e..de18ee0 100644 --- a/tools/perf/util/event.h +++ b/tools/perf/util/event.h @@ -425,6 +425,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, @@ -440,6 +441,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, @@ -550,4 +555,7 @@ size_t perf_event__fprintf(union perf_event *event, FILE *fp); u64 kallsyms__get_function_start(const char *kallsyms_filename, const char *symbol_name); +void *cpu_map_data__alloc(struct cpu_map *map, size_t *size, u16 *type, int *max); +void cpu_map_data__synthesize(struct cpu_map_data *data, struct cpu_map *map, + u16 type, int max); #endif /* __PERF_RECORD_H */
Commit-ID: f77b57ad4fc42a074eae564bbb6660f0a3ff5503 Gitweb: http://git.kernel.org/tip/f77b57ad4fc42a074eae564bbb6660f0a3ff5503 Author: Jiri Olsa <jolsa@kernel.org> AuthorDate: Sun, 25 Oct 2015 15:51:25 +0100 Committer: Arnaldo Carvalho de Melo <acme@redhat.com> CommitDate: Thu, 17 Dec 2015 14:38:18 -0300 perf cpu_map: Add cpu_map__new_event function Introducing the cpu_map__new_event function to create a struct cpu_map object from a cpu_map event. Signed-off-by: Jiri Olsa <jolsa@kernel.org> Tested-by: Kan Liang <kan.liang@intel.com> Cc: David Ahern <dsahern@gmail.com> Cc: Namhyung Kim <namhyung@kernel.org> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Link: http://lkml.kernel.org/r/1445784728-21732-10-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> --- tools/perf/tests/cpumap.c | 25 +++++++++++++++++++++---- tools/perf/util/cpumap.c | 42 ++++++++++++++++++++++++++++++++++++++++++ tools/perf/util/cpumap.h | 1 + 3 files changed, 64 insertions(+), 4 deletions(-) diff --git a/tools/perf/tests/cpumap.c b/tools/perf/tests/cpumap.c index 7154805..4cb6418 100644 --- a/tools/perf/tests/cpumap.c +++ b/tools/perf/tests/cpumap.c @@ -6,12 +6,13 @@ static int process_event_mask(struct perf_tool *tool __maybe_unused, struct perf_sample *sample __maybe_unused, struct machine *machine __maybe_unused) { - struct cpu_map_event *map = &event->cpu_map; + struct cpu_map_event *map_event = &event->cpu_map; struct cpu_map_mask *mask; struct cpu_map_data *data; + struct cpu_map *map; int i; - data = &map->data; + data = &map_event->data; TEST_ASSERT_VAL("wrong type", data->type == PERF_CPU_MAP__MASK); @@ -23,6 +24,14 @@ static int process_event_mask(struct perf_tool *tool __maybe_unused, TEST_ASSERT_VAL("wrong cpu", test_bit(i, mask->mask)); } + map = cpu_map__new_data(data); + TEST_ASSERT_VAL("wrong nr", map->nr == 20); + + for (i = 0; i < 20; i++) { + TEST_ASSERT_VAL("wrong cpu", map->map[i] == i); + } + + cpu_map__put(map); return 0; } @@ -31,11 +40,12 @@ static int process_event_cpus(struct perf_tool *tool __maybe_unused, struct perf_sample *sample __maybe_unused, struct machine *machine __maybe_unused) { - struct cpu_map_event *map = &event->cpu_map; + struct cpu_map_event *map_event = &event->cpu_map; struct cpu_map_entries *cpus; struct cpu_map_data *data; + struct cpu_map *map; - data = &map->data; + data = &map_event->data; TEST_ASSERT_VAL("wrong type", data->type == PERF_CPU_MAP__CPUS); @@ -44,6 +54,13 @@ static int process_event_cpus(struct perf_tool *tool __maybe_unused, TEST_ASSERT_VAL("wrong nr", cpus->nr == 2); TEST_ASSERT_VAL("wrong cpu", cpus->cpu[0] == 1); TEST_ASSERT_VAL("wrong cpu", cpus->cpu[1] == 256); + + map = cpu_map__new_data(data); + TEST_ASSERT_VAL("wrong nr", map->nr == 2); + TEST_ASSERT_VAL("wrong cpu", map->map[0] == 1); + TEST_ASSERT_VAL("wrong cpu", map->map[1] == 256); + TEST_ASSERT_VAL("wrong refcnt", atomic_read(&map->refcnt) == 1); + cpu_map__put(map); return 0; } diff --git a/tools/perf/util/cpumap.c b/tools/perf/util/cpumap.c index 10af1e7..a0717b9 100644 --- a/tools/perf/util/cpumap.c +++ b/tools/perf/util/cpumap.c @@ -5,6 +5,7 @@ #include <assert.h> #include <stdio.h> #include <stdlib.h> +#include <linux/bitmap.h> #include "asm/bug.h" static struct cpu_map *cpu_map__default_new(void) @@ -179,6 +180,47 @@ out: return cpus; } +static struct cpu_map *cpu_map__from_entries(struct cpu_map_entries *cpus) +{ + struct cpu_map *map; + + map = cpu_map__empty_new(cpus->nr); + if (map) { + unsigned i; + + for (i = 0; i < cpus->nr; i++) + map->map[i] = (int)cpus->cpu[i]; + } + + return map; +} + +static struct cpu_map *cpu_map__from_mask(struct cpu_map_mask *mask) +{ + struct cpu_map *map; + int nr, nbits = mask->nr * mask->long_size * BITS_PER_BYTE; + + nr = bitmap_weight(mask->mask, nbits); + + map = cpu_map__empty_new(nr); + if (map) { + int cpu, i = 0; + + for_each_set_bit(cpu, mask->mask, nbits) + map->map[i++] = cpu; + } + return map; + +} + +struct cpu_map *cpu_map__new_data(struct cpu_map_data *data) +{ + if (data->type == PERF_CPU_MAP__CPUS) + return cpu_map__from_entries((struct cpu_map_entries *)data->data); + else + return cpu_map__from_mask((struct cpu_map_mask *)data->data); +} + 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 85f7772..71c41b9 100644 --- a/tools/perf/util/cpumap.h +++ b/tools/perf/util/cpumap.h @@ -17,6 +17,7 @@ struct cpu_map { struct cpu_map *cpu_map__new(const char *cpu_list); struct cpu_map *cpu_map__empty_new(int nr); struct cpu_map *cpu_map__dummy_new(void); +struct cpu_map *cpu_map__new_data(struct cpu_map_data *data); struct cpu_map *cpu_map__read(FILE *file); size_t cpu_map__fprintf(struct cpu_map *map, FILE *fp); int cpu_map__get_socket_id(int cpu);
Commit-ID: eb12a1afdc02e59fc09934743490549c77327b1a Gitweb: http://git.kernel.org/tip/eb12a1afdc02e59fc09934743490549c77327b1a Author: Jiri Olsa <jolsa@kernel.org> AuthorDate: Sun, 25 Oct 2015 15:51:26 +0100 Committer: Arnaldo Carvalho de Melo <acme@redhat.com> CommitDate: Thu, 17 Dec 2015 14:38:18 -0300 perf cpu_map: Add perf_event__fprintf_cpu_map function To display a cpu_map event for raw dump. Signed-off-by: Jiri Olsa <jolsa@kernel.org> Tested-by: Kan Liang <kan.liang@intel.com> Cc: David Ahern <dsahern@gmail.com> Cc: Namhyung Kim <namhyung@kernel.org> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Link: http://lkml.kernel.org/r/1445784728-21732-11-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> --- tools/perf/util/event.c | 16 ++++++++++++++++ tools/perf/util/event.h | 1 + 2 files changed, 17 insertions(+) diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index 15d6466..f31ab3b 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c @@ -968,6 +968,22 @@ size_t perf_event__fprintf_thread_map(union perf_event *event, FILE *fp) return ret; } +size_t perf_event__fprintf_cpu_map(union perf_event *event, FILE *fp) +{ + struct cpu_map *cpus = cpu_map__new_data(&event->cpu_map.data); + size_t ret; + + ret = fprintf(fp, " nr: "); + + if (cpus) + ret += cpu_map__fprintf(cpus, fp); + else + ret += fprintf(fp, "failed to get cpumap from event\n"); + + cpu_map__put(cpus); + return ret; +} + int perf_event__process_mmap(struct perf_tool *tool __maybe_unused, union perf_event *event, struct perf_sample *sample, diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h index de18ee0..74a4341 100644 --- a/tools/perf/util/event.h +++ b/tools/perf/util/event.h @@ -550,6 +550,7 @@ size_t perf_event__fprintf_aux(union perf_event *event, FILE *fp); size_t perf_event__fprintf_itrace_start(union perf_event *event, FILE *fp); size_t perf_event__fprintf_switch(union perf_event *event, FILE *fp); size_t perf_event__fprintf_thread_map(union perf_event *event, FILE *fp); +size_t perf_event__fprintf_cpu_map(union perf_event *event, FILE *fp); size_t perf_event__fprintf(union perf_event *event, FILE *fp); u64 kallsyms__get_function_start(const char *kallsyms_filename,
Commit-ID: 374fb9e362f64e730388abc1de9bb93829670a54 Gitweb: http://git.kernel.org/tip/374fb9e362f64e730388abc1de9bb93829670a54 Author: Jiri Olsa <jolsa@kernel.org> AuthorDate: Sun, 25 Oct 2015 15:51:27 +0100 Committer: Arnaldo Carvalho de Melo <acme@redhat.com> CommitDate: Thu, 17 Dec 2015 14:38:18 -0300 perf tools: Add stat config user level event Adding the stat config event to pass/store stat config data, so report tools (report/script) know how to interpret stat data. The config data is stored in a 'tag|value' way to allow for easy extension and backwards compatibility. Signed-off-by: Jiri Olsa <jolsa@kernel.org> Tested-by: Kan Liang <kan.liang@intel.com> Cc: David Ahern <dsahern@gmail.com> Cc: Namhyung Kim <namhyung@kernel.org> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Link: http://lkml.kernel.org/r/1445784728-21732-12-git-send-email-jolsa@kernel.org [ stat_config_term_event -> stat_config_event_entry ] Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> --- 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 f31ab3b..43e2dfc 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_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 74a4341..16cee44 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_AUXTRACE_ERROR = 72, PERF_RECORD_THREAD_MAP = 73, PERF_RECORD_CPU_MAP = 74, + PERF_RECORD_STAT_CONFIG = 75, PERF_RECORD_HEADER_MAX }; @@ -395,6 +396,24 @@ struct thread_map_event { struct thread_map_event_entry entries[]; }; +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_event_entry { + u64 tag; + u64 val; +}; + +struct stat_config_event { + struct perf_event_header header; + u64 nr; + struct stat_config_event_entry data[]; +}; + union perf_event { struct perf_event_header header; struct mmap_event mmap; @@ -419,6 +438,7 @@ union perf_event { struct context_switch_event context_switch; 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 4350f5e..fbc52ab 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -315,6 +315,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) @@ -369,6 +378,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) @@ -686,6 +697,16 @@ static void perf_event__cpu_map_swap(union perf_event *event, } } +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); @@ -715,6 +736,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, }; @@ -1255,6 +1277,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 9e5925c..aa7ae73 100644 --- a/tools/perf/util/tool.h +++ b/tools/perf/util/tool.h @@ -57,7 +57,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;
Commit-ID: 6742434261158ad9678bf15b165304e0200cc324 Gitweb: http://git.kernel.org/tip/6742434261158ad9678bf15b165304e0200cc324 Author: Jiri Olsa <jolsa@kernel.org> AuthorDate: Sun, 25 Oct 2015 15:51:28 +0100 Committer: Arnaldo Carvalho de Melo <acme@redhat.com> CommitDate: Thu, 17 Dec 2015 14:38:19 -0300 perf tools: Add stat config event synthesize function Introduce the perf_event__synthesize_stat_config to synthesize a 'struct perf_stat_config'. Storing the stat config in the form of tag-value pairs will, I believe, sort out future version extensibility issues. Signed-off-by: Jiri Olsa <jolsa@kernel.org> Tested-by: Kan Liang <kan.liang@intel.com> Cc: David Ahern <dsahern@gmail.com> Cc: Namhyung Kim <namhyung@kernel.org> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Link: http://lkml.kernel.org/r/1445784728-21732-13-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> --- 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 | 40 +++++++++++++++++++++++++++++++ tools/perf/util/event.h | 5 ++++ 6 files changed, 104 insertions(+) diff --git a/tools/perf/tests/Build b/tools/perf/tests/Build index 7abad28..fc02931 100644 --- a/tools/perf/tests/Build +++ b/tools/perf/tests/Build @@ -35,6 +35,7 @@ perf-y += llvm.o llvm-src-base.o llvm-src-kbuild.o llvm-src-prologue.o perf-y += bpf.o perf-y += topology.o perf-y += cpumap.o +perf-y += stat.o $(OUTPUT)tests/llvm-src-base.c: tests/bpf-script-example.c tests/Build $(call rule_mkdir) diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c index 0c3fe28..ed8402f 100644 --- a/tools/perf/tests/builtin-test.c +++ b/tools/perf/tests/builtin-test.c @@ -188,6 +188,10 @@ static struct test generic_tests[] = { .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 0000000..c7a2bdb --- /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(int subtest __maybe_unused) +{ + 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 f85160f..319757a 100644 --- a/tools/perf/tests/tests.h +++ b/tools/perf/tests/tests.h @@ -81,6 +81,7 @@ int test__bpf_subtest_get_nr(void); int test_session_topology(int subtest); int test__thread_map_synthesize(int subtest); int test__cpu_map_synthesize(int subtest); +int test__synthesize_stat_config(int subtest); #if defined(__arm__) || defined(__aarch64__) #ifdef HAVE_DWARF_UNWIND_SUPPORT diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index 43e2dfc..1ea693c 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c @@ -10,6 +10,8 @@ #include "thread.h" #include "thread_map.h" #include "symbol/kallsyms.h" +#include "asm/bug.h" +#include "stat.h" static const char *perf_event__names[] = { [0] = "TOTAL", @@ -869,6 +871,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 16cee44..39014c7 100644 --- a/tools/perf/util/event.h +++ b/tools/perf/util/event.h @@ -446,6 +446,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, @@ -472,6 +473,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,
Commit-ID: 8e381596b67af53564a69f16440d3e5d5a73d034 Gitweb: http://git.kernel.org/tip/8e381596b67af53564a69f16440d3e5d5a73d034 Author: Jiri Olsa <jolsa@kernel.org> AuthorDate: Sun, 25 Oct 2015 15:51:29 +0100 Committer: Arnaldo Carvalho de Melo <acme@redhat.com> CommitDate: Thu, 17 Dec 2015 14:38:19 -0300 perf tools: Add stat config event read function Introducing the perf_event__read_stat_config function to read a struct perf_stat_config object data from a stat config event. Signed-off-by: Jiri Olsa <jolsa@kernel.org> Tested-by: Kan Liang <kan.liang@intel.com> Cc: David Ahern <dsahern@gmail.com> Cc: Namhyung Kim <namhyung@kernel.org> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Link: http://lkml.kernel.org/r/1445784728-21732-14-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> --- 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 c7a2bdb..aa35d28 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 1ea693c..223deaf 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c @@ -909,6 +909,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 39014c7..4e87be2 100644 --- a/tools/perf/util/event.h +++ b/tools/perf/util/event.h @@ -477,6 +477,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,
Commit-ID: d80518c90bb2b4af9755d79af5dfe9d44e04cdb9 Gitweb: http://git.kernel.org/tip/d80518c90bb2b4af9755d79af5dfe9d44e04cdb9 Author: Jiri Olsa <jolsa@kernel.org> AuthorDate: Sun, 25 Oct 2015 15:51:30 +0100 Committer: Arnaldo Carvalho de Melo <acme@redhat.com> CommitDate: Thu, 17 Dec 2015 14:38:20 -0300 perf tools: Add stat user level event Adding a stat event to store a 'struct perf_counter_values' for a given event/cpu/thread. Signed-off-by: Jiri Olsa <jolsa@kernel.org> Tested-by: Kan Liang <kan.liang@intel.com> Cc: David Ahern <dsahern@gmail.com> Cc: Namhyung Kim <namhyung@kernel.org> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Link: http://lkml.kernel.org/r/1445784728-21732-15-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> --- tools/perf/util/event.c | 1 + tools/perf/util/event.h | 19 +++++++++++++++++++ tools/perf/util/session.c | 25 +++++++++++++++++++++++++ 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 223deaf..670123f 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c @@ -42,6 +42,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 4e87be2..f23f464 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_THREAD_MAP = 73, PERF_RECORD_CPU_MAP = 74, PERF_RECORD_STAT_CONFIG = 75, + PERF_RECORD_STAT = 76, PERF_RECORD_HEADER_MAX }; @@ -414,6 +415,23 @@ struct stat_config_event { struct stat_config_event_entry 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; @@ -439,6 +457,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 fbc52ab..663a2fd 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -324,6 +324,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) @@ -380,6 +389,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) @@ -707,6 +718,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); @@ -737,6 +759,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, }; @@ -1279,6 +1302,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 aa7ae73..f0b9da0 100644 --- a/tools/perf/util/tool.h +++ b/tools/perf/util/tool.h @@ -58,7 +58,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;
Commit-ID: 5796f8f073fe50171376f058376dde93ec5f3785 Gitweb: http://git.kernel.org/tip/5796f8f073fe50171376f058376dde93ec5f3785 Author: Jiri Olsa <jolsa@kernel.org> AuthorDate: Sun, 25 Oct 2015 15:51:31 +0100 Committer: Arnaldo Carvalho de Melo <acme@redhat.com> CommitDate: Thu, 17 Dec 2015 14:55:31 -0300 perf tools: Add stat event synthesize function Introduce the perf_event__synthesize_stat function to synthesize a 'struct stat_event'. Signed-off-by: Jiri Olsa <jolsa@kernel.org> Tested-by: Kan Liang <kan.liang@intel.com> Cc: David Ahern <dsahern@gmail.com> Cc: Namhyung Kim <namhyung@kernel.org> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Link: http://lkml.kernel.org/r/1445784728-21732-16-git-send-email-jolsa@kernel.org [ Renamed 'stat' parameter to 'st' to fix 'already defined' build error with older distros (e.g. RHEL6.7) ] Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> --- tools/perf/tests/builtin-test.c | 4 ++++ tools/perf/tests/stat.c | 41 ++++++++++++++++++++++++++++++++++++----- tools/perf/tests/tests.h | 1 + tools/perf/util/event.c | 22 ++++++++++++++++++++++ tools/perf/util/event.h | 7 ++++++- 5 files changed, 69 insertions(+), 6 deletions(-) diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c index ed8402f..4a7d998 100644 --- a/tools/perf/tests/builtin-test.c +++ b/tools/perf/tests/builtin-test.c @@ -192,6 +192,10 @@ static struct test generic_tests[] = { .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 aa35d28..d319875 100644 --- a/tools/perf/tests/stat.c +++ b/tools/perf/tests/stat.c @@ -2,6 +2,7 @@ #include "event.h" #include "tests.h" #include "stat.h" +#include "counts.h" #include "debug.h" static bool has_term(struct stat_config_event *config, @@ -18,10 +19,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 +54,37 @@ int test__synthesize_stat_config(int subtest __maybe_unused) }; 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 *st = &event->stat; + + TEST_ASSERT_VAL("wrong cpu", st->cpu == 1); + TEST_ASSERT_VAL("wrong thread", st->thread == 2); + TEST_ASSERT_VAL("wrong id", st->id == 3); + TEST_ASSERT_VAL("wrong val", st->val == 100); + TEST_ASSERT_VAL("wrong run", st->ena == 200); + TEST_ASSERT_VAL("wrong ena", st->run == 300); + return 0; +} + +int test__synthesize_stat(int subtest __maybe_unused) +{ + struct perf_counts_values count; + + count.val = 100; + count.ena = 200; + count.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 319757a..d36eda1 100644 --- a/tools/perf/tests/tests.h +++ b/tools/perf/tests/tests.h @@ -82,6 +82,7 @@ int test_session_topology(int subtest); int test__thread_map_synthesize(int subtest); int test__cpu_map_synthesize(int subtest); int test__synthesize_stat_config(int subtest); +int test__synthesize_stat(int subtest); #if defined(__arm__) || defined(__aarch64__) #ifdef HAVE_DWARF_UNWIND_SUPPORT diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index 670123f..eb8243a 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c @@ -910,6 +910,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 f23f464..336eb44 100644 --- a/tools/perf/util/event.h +++ b/tools/perf/util/event.h @@ -466,6 +466,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, @@ -498,7 +499,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);
Commit-ID: 0ea0e3558607626196eb09ace796aac585e61f5c Gitweb: http://git.kernel.org/tip/0ea0e3558607626196eb09ace796aac585e61f5c Author: Jiri Olsa <jolsa@kernel.org> AuthorDate: Sun, 25 Oct 2015 15:51:32 +0100 Committer: Arnaldo Carvalho de Melo <acme@redhat.com> CommitDate: Thu, 17 Dec 2015 14:55:43 -0300 perf tools: Add stat event read function Introducing the perf_event__process_stat_event function to process a 'struct perf_stat' data from a stat event. Signed-off-by: Jiri Olsa <jolsa@kernel.org> Tested-by: Kan Liang <kan.liang@intel.com> Cc: David Ahern <dsahern@gmail.com> Cc: Namhyung Kim <namhyung@kernel.org> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Link: http://lkml.kernel.org/r/1445784728-21732-17-git-send-email-jolsa@kernel.org [ Renamed 'stat' parameter to 'st' to fix 'already defined' build error with older distros (e.g. RHEL6.7) ] Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> --- 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 2d9d830..0ad59ce 100644 --- a/tools/perf/util/stat.c +++ b/tools/perf/util/stat.c @@ -341,3 +341,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 *st = &event->stat; + struct perf_evsel *counter; + + count.val = st->val; + count.ena = st->ena; + count.run = st->run; + + counter = perf_evlist__id2evsel(session->evlist, st->id); + if (!counter) { + pr_err("Failed to resolve counter for stat event.\n"); + return -EINVAL; + } + + *perf_counts(counter->counts, st->cpu, st->thread) = count; + counter->supported = true; + return 0; +} diff --git a/tools/perf/util/stat.h b/tools/perf/util/stat.h index da1d11c..afe6844 100644 --- a/tools/perf/util/stat.h +++ b/tools/perf/util/stat.h @@ -90,4 +90,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
Commit-ID: 2d8f0f18a5c37cf0322cb385b99adb1167b7cf78 Gitweb: http://git.kernel.org/tip/2d8f0f18a5c37cf0322cb385b99adb1167b7cf78 Author: Jiri Olsa <jolsa@kernel.org> AuthorDate: Sun, 25 Oct 2015 15:51:33 +0100 Committer: Arnaldo Carvalho de Melo <acme@redhat.com> CommitDate: Thu, 17 Dec 2015 14:55:43 -0300 perf tools: Add stat round user level event Adding the stat round event to be stored after each stat interval round, so that report tools (report/script) gets notified and process interval data. Signed-off-by: Jiri Olsa <jolsa@kernel.org> Tested-by: Kan Liang <kan.liang@intel.com> Cc: David Ahern <dsahern@gmail.com> Cc: Namhyung Kim <namhyung@kernel.org> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Link: http://lkml.kernel.org/r/1445784728-21732-18-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> --- tools/perf/util/event.c | 1 + tools/perf/util/event.h | 13 +++++++++++++ tools/perf/util/session.c | 21 +++++++++++++++++++++ tools/perf/util/tool.h | 3 ++- 4 files changed, 37 insertions(+), 1 deletion(-) diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index eb8243a..725db54 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c @@ -43,6 +43,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 336eb44..5eb4f55 100644 --- a/tools/perf/util/event.h +++ b/tools/perf/util/event.h @@ -230,6 +230,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 }; @@ -432,6 +433,17 @@ struct stat_event { }; }; +enum { + PERF_STAT_ROUND_TYPE__INTERVAL = 0, + PERF_STAT_ROUND_TYPE__FINAL = 1, +}; + +struct stat_round_event { + struct perf_event_header header; + u64 type; + u64 time; +}; + union perf_event { struct perf_event_header header; struct mmap_event mmap; @@ -458,6 +470,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 663a2fd..5b3a81a 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -333,6 +333,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) @@ -391,6 +400,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) @@ -729,6 +740,13 @@ 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.type = bswap_64(event->stat_round.type); + event->stat_round.time = bswap_64(event->stat_round.time); +} + typedef void (*perf_event__swap_op)(union perf_event *event, bool sample_id_all); @@ -760,6 +778,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, }; @@ -1304,6 +1323,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 f0b9da0..d04d9e5 100644 --- a/tools/perf/util/tool.h +++ b/tools/perf/util/tool.h @@ -59,7 +59,8 @@ struct perf_tool { thread_map, cpu_map, stat_config, - stat; + stat, + stat_round; event_op3 auxtrace; bool ordered_events; bool ordering_requires_timestamps;
Commit-ID: d4c2259195f538505d2570e78555532372fb4ad2 Gitweb: http://git.kernel.org/tip/d4c2259195f538505d2570e78555532372fb4ad2 Author: Jiri Olsa <jolsa@kernel.org> AuthorDate: Sun, 25 Oct 2015 15:51:34 +0100 Committer: Arnaldo Carvalho de Melo <acme@redhat.com> CommitDate: Thu, 17 Dec 2015 14:55:44 -0300 perf tools: Add stat round event synthesize function Introduce the perf_event__synthesize_stat_round function to synthesize a 'struct stat_round_event'. Signed-off-by: Jiri Olsa <jolsa@kernel.org> Tested-by: Kan Liang <kan.liang@intel.com> Cc: David Ahern <dsahern@gmail.com> Cc: Namhyung Kim <namhyung@kernel.org> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Link: http://lkml.kernel.org/r/1445784728-21732-19-git-send-email-jolsa@kernel.org [ Renamed 'time' parameter to 'evtime' to fix build on older systems ] Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> --- tools/perf/tests/builtin-test.c | 4 ++++ tools/perf/tests/stat.c | 21 +++++++++++++++++++++ tools/perf/tests/tests.h | 1 + tools/perf/util/event.c | 17 +++++++++++++++++ tools/perf/util/event.h | 4 ++++ 5 files changed, 47 insertions(+) diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c index 4a7d998..6a35198 100644 --- a/tools/perf/tests/builtin-test.c +++ b/tools/perf/tests/builtin-test.c @@ -196,6 +196,10 @@ static struct test generic_tests[] = { .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 d319875..6a20ff2 100644 --- a/tools/perf/tests/stat.c +++ b/tools/perf/tests/stat.c @@ -88,3 +88,24 @@ int test__synthesize_stat(int subtest __maybe_unused) 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); + TEST_ASSERT_VAL("wrong type", stat_round->type == PERF_STAT_ROUND_TYPE__INTERVAL); + return 0; +} + +int test__synthesize_stat_round(int subtest __maybe_unused) +{ + TEST_ASSERT_VAL("failed to synthesize stat_config", + !perf_event__synthesize_stat_round(NULL, 0xdeadbeef, PERF_STAT_ROUND_TYPE__INTERVAL, + process_stat_round_event, NULL)); + + return 0; +} diff --git a/tools/perf/tests/tests.h b/tools/perf/tests/tests.h index d36eda1..a82ab9c 100644 --- a/tools/perf/tests/tests.h +++ b/tools/perf/tests/tests.h @@ -83,6 +83,7 @@ int test__thread_map_synthesize(int subtest); int test__cpu_map_synthesize(int subtest); int test__synthesize_stat_config(int subtest); int test__synthesize_stat(int subtest); +int test__synthesize_stat_round(int subtest); #if defined(__arm__) || defined(__aarch64__) #ifdef HAVE_DWARF_UNWIND_SUPPORT diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index 725db54..e4c68ba 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c @@ -933,6 +933,23 @@ 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 evtime, u64 type, + 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 = evtime; + event.type = type; + + 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 5eb4f55..1afaa21 100644 --- a/tools/perf/util/event.h +++ b/tools/perf/util/event.h @@ -517,6 +517,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, u64 type, + 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);
Commit-ID: e08a4564e23f8f89a055d717887674f54a9da515 Gitweb: http://git.kernel.org/tip/e08a4564e23f8f89a055d717887674f54a9da515 Author: Jiri Olsa <jolsa@kernel.org> AuthorDate: Sun, 25 Oct 2015 15:51:35 +0100 Committer: Arnaldo Carvalho de Melo <acme@redhat.com> CommitDate: Thu, 17 Dec 2015 15:09:38 -0300 perf tools: Add stat events fprintf functions Introducing the following functions to display the stat events for raw dump. perf_event__fprintf_stat perf_event__fprintf_stat_round perf_event__fprintf_stat_config Signed-off-by: Jiri Olsa <jolsa@kernel.org> Tested-by: Kan Liang <kan.liang@intel.com> Cc: David Ahern <dsahern@gmail.com> Cc: Namhyung Kim <namhyung@kernel.org> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Link: http://lkml.kernel.org/r/1445784728-21732-20-git-send-email-jolsa@kernel.org [ s/stat/st/g and s/round/rd/g parameters to fix 'already defined' build error with older distros (e.g. RHEL6.7) ] Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> --- tools/perf/util/stat.c | 39 +++++++++++++++++++++++++++++++++++++++ tools/perf/util/stat.h | 4 ++++ 2 files changed, 43 insertions(+) diff --git a/tools/perf/util/stat.c b/tools/perf/util/stat.c index 0ad59ce..2f901d1 100644 --- a/tools/perf/util/stat.c +++ b/tools/perf/util/stat.c @@ -364,3 +364,42 @@ int perf_event__process_stat_event(struct perf_tool *tool __maybe_unused, counter->supported = true; return 0; } + +size_t perf_event__fprintf_stat(union perf_event *event, FILE *fp) +{ + struct stat_event *st = (struct stat_event *) event; + size_t ret; + + ret = fprintf(fp, "\n... id %" PRIu64 ", cpu %d, thread %d\n", + st->id, st->cpu, st->thread); + ret += fprintf(fp, "... value %" PRIu64 ", enabled %" PRIu64 ", running %" PRIu64 "\n", + st->val, st->ena, st->run); + + return ret; +} + +size_t perf_event__fprintf_stat_round(union perf_event *event, FILE *fp) +{ + struct stat_round_event *rd = (struct stat_round_event *)event; + size_t ret; + + ret = fprintf(fp, "\n... time %" PRIu64 ", type %s\n", rd->time, + rd->type == PERF_STAT_ROUND_TYPE__FINAL ? "FINAL" : "INTERVAL"); + + return ret; +} + +size_t perf_event__fprintf_stat_config(union perf_event *event, FILE *fp) +{ + struct perf_stat_config sc; + size_t ret; + + perf_event__read_stat_config(&sc, &event->stat_config); + + ret = fprintf(fp, "\n"); + ret += fprintf(fp, "... aggr_mode %d\n", sc.aggr_mode); + ret += fprintf(fp, "... scale %d\n", sc.scale); + ret += fprintf(fp, "... interval %u\n", sc.interval); + + return ret; +} diff --git a/tools/perf/util/stat.h b/tools/perf/util/stat.h index afe6844..086f4e1 100644 --- a/tools/perf/util/stat.h +++ b/tools/perf/util/stat.h @@ -96,4 +96,8 @@ struct perf_session; int perf_event__process_stat_event(struct perf_tool *tool, union perf_event *event, struct perf_session *session); + +size_t perf_event__fprintf_stat(union perf_event *event, FILE *fp); +size_t perf_event__fprintf_stat_round(union perf_event *event, FILE *fp); +size_t perf_event__fprintf_stat_config(union perf_event *event, FILE *fp); #endif
Commit-ID: ffe777254cce24fb5fde3f0aa91fc755cfb1b812 Gitweb: http://git.kernel.org/tip/ffe777254cce24fb5fde3f0aa91fc755cfb1b812 Author: Jiri Olsa <jolsa@kernel.org> AuthorDate: Sun, 25 Oct 2015 15:51:36 +0100 Committer: Arnaldo Carvalho de Melo <acme@redhat.com> CommitDate: Thu, 17 Dec 2015 15:10:16 -0300 perf tools: Add event_update user level event It'll serve as a base event for additional event attributes details, that are not part of the attr event. At the moment this event is just a dummy one without any specific functionality. The type value will distinguish the update event details. It'll come in the following patches. The idea for this event is to be extensible for any update that the event might need in the future. Signed-off-by: Jiri Olsa <jolsa@kernel.org> Tested-by: Kan Liang <kan.liang@intel.com> Cc: David Ahern <dsahern@gmail.com> Cc: Namhyung Kim <namhyung@kernel.org> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Link: http://lkml.kernel.org/r/1445784728-21732-21-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> --- tools/perf/util/event.c | 1 + tools/perf/util/event.h | 10 ++++++++++ tools/perf/util/header.c | 20 ++++++++++++++++++++ tools/perf/util/header.h | 3 +++ tools/perf/util/session.c | 21 +++++++++++++++++++++ tools/perf/util/tool.h | 1 + 6 files changed, 56 insertions(+) diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index e4c68ba..cd61bb1 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c @@ -44,6 +44,7 @@ static const char *perf_event__names[] = { [PERF_RECORD_STAT_CONFIG] = "STAT_CONFIG", [PERF_RECORD_STAT] = "STAT", [PERF_RECORD_STAT_ROUND] = "STAT_ROUND", + [PERF_RECORD_EVENT_UPDATE] = "EVENT_UPDATE", }; const char *perf_event__name(unsigned int id) diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h index 1afaa21..6966a4b 100644 --- a/tools/perf/util/event.h +++ b/tools/perf/util/event.h @@ -231,6 +231,7 @@ enum perf_user_event_type { /* above any possible kernel type */ PERF_RECORD_STAT_CONFIG = 75, PERF_RECORD_STAT = 76, PERF_RECORD_STAT_ROUND = 77, + PERF_RECORD_EVENT_UPDATE = 78, PERF_RECORD_HEADER_MAX }; @@ -307,6 +308,14 @@ struct attr_event { u64 id[]; }; +struct event_update_event { + struct perf_event_header header; + u64 type; + u64 id; + + char data[]; +}; + #define MAX_EVENT_NAME 64 struct perf_trace_event_type { @@ -456,6 +465,7 @@ union perf_event { struct throttle_event throttle; struct sample_event sample; struct attr_event attr; + struct event_update_event event_update; struct event_type_event event_type; struct tracing_data_event tracing_data; struct build_id_event build_id; diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 5ac7bdb..6b4e002 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -2745,6 +2745,26 @@ int perf_event__process_attr(struct perf_tool *tool __maybe_unused, return 0; } +int perf_event__process_event_update(struct perf_tool *tool __maybe_unused, + union perf_event *event, + struct perf_evlist **pevlist) +{ + struct event_update_event *ev = &event->event_update; + struct perf_evlist *evlist; + struct perf_evsel *evsel; + + if (!pevlist || *pevlist == NULL) + return -EINVAL; + + evlist = *pevlist; + + evsel = perf_evlist__id2evsel(evlist, ev->id); + if (evsel == NULL) + return -EINVAL; + + return 0; +} + int perf_event__synthesize_tracing_data(struct perf_tool *tool, int fd, struct perf_evlist *evlist, perf_event__handler_t process) diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h index 05f27cb..1e843c6 100644 --- a/tools/perf/util/header.h +++ b/tools/perf/util/header.h @@ -107,6 +107,9 @@ int perf_event__synthesize_attrs(struct perf_tool *tool, perf_event__handler_t process); int perf_event__process_attr(struct perf_tool *tool, union perf_event *event, struct perf_evlist **pevlist); +int perf_event__process_event_update(struct perf_tool *tool __maybe_unused, + union perf_event *event, + struct perf_evlist **pevlist); int perf_event__synthesize_tracing_data(struct perf_tool *tool, int fd, struct perf_evlist *evlist, diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 5b3a81a..49e5cdc 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -205,6 +205,15 @@ static int process_event_synth_attr_stub(struct perf_tool *tool __maybe_unused, return 0; } +static int process_event_synth_event_update_stub(struct perf_tool *tool __maybe_unused, + union perf_event *event __maybe_unused, + struct perf_evlist **pevlist + __maybe_unused) +{ + dump_printf(": unhandled!\n"); + return 0; +} + static int process_event_sample_stub(struct perf_tool *tool __maybe_unused, union perf_event *event __maybe_unused, struct perf_sample *sample __maybe_unused, @@ -374,6 +383,8 @@ void perf_tool__fill_defaults(struct perf_tool *tool) tool->unthrottle = process_event_stub; if (tool->attr == NULL) tool->attr = process_event_synth_attr_stub; + if (tool->event_update == NULL) + tool->event_update = process_event_synth_event_update_stub; if (tool->tracing_data == NULL) tool->tracing_data = process_event_synth_tracing_data_stub; if (tool->build_id == NULL) @@ -625,6 +636,13 @@ static void perf_event__hdr_attr_swap(union perf_event *event, mem_bswap_64(event->attr.id, size); } +static void perf_event__event_update_swap(union perf_event *event, + bool sample_id_all __maybe_unused) +{ + event->event_update.type = bswap_64(event->event_update.type); + event->event_update.id = bswap_64(event->event_update.id); +} + static void perf_event__event_type_swap(union perf_event *event, bool sample_id_all __maybe_unused) { @@ -779,6 +797,7 @@ static perf_event__swap_op perf_event__swap_ops[] = { [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_EVENT_UPDATE] = perf_event__event_update_swap, [PERF_RECORD_HEADER_MAX] = NULL, }; @@ -1290,6 +1309,8 @@ static s64 perf_session__process_user_event(struct perf_session *session, perf_session__set_comm_exec(session); } return err; + case PERF_RECORD_EVENT_UPDATE: + return tool->event_update(tool, event, &session->evlist); case PERF_RECORD_HEADER_EVENT_TYPE: /* * Depreceated, but we need to handle it for sake diff --git a/tools/perf/util/tool.h b/tools/perf/util/tool.h index d04d9e5..55de4cf 100644 --- a/tools/perf/util/tool.h +++ b/tools/perf/util/tool.h @@ -50,6 +50,7 @@ struct perf_tool { throttle, unthrottle; event_attr_op attr; + event_attr_op event_update; event_op2 tracing_data; event_oe finished_round; event_op2 build_id,
Commit-ID: a6e5281780d1da65c15ce529707f43eb4a6df856 Gitweb: http://git.kernel.org/tip/a6e5281780d1da65c15ce529707f43eb4a6df856 Author: Jiri Olsa <jolsa@kernel.org> AuthorDate: Sun, 25 Oct 2015 15:51:37 +0100 Committer: Arnaldo Carvalho de Melo <acme@redhat.com> CommitDate: Thu, 17 Dec 2015 15:11:10 -0300 perf tools: Add event_update event unit type Adding unit type 'event update' event, that stores/transfer events unit name. The unit name is part of the perf stat output data. Signed-off-by: Jiri Olsa <jolsa@kernel.org> Tested-by: Kan Liang <kan.liang@intel.com> Cc: David Ahern <dsahern@gmail.com> Cc: Namhyung Kim <namhyung@kernel.org> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Link: http://lkml.kernel.org/r/1445784728-21732-22-git-send-email-jolsa@kernel.org [ Rename __alloc() to __new() for consistency ] Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> --- tools/perf/tests/Build | 1 + tools/perf/tests/builtin-test.c | 4 ++++ tools/perf/tests/event_update.c | 42 +++++++++++++++++++++++++++++++++++++++ tools/perf/tests/tests.h | 1 + tools/perf/util/event.h | 4 ++++ tools/perf/util/header.c | 44 +++++++++++++++++++++++++++++++++++++++++ tools/perf/util/header.h | 3 +++ 7 files changed, 99 insertions(+) diff --git a/tools/perf/tests/Build b/tools/perf/tests/Build index fc02931..614899b 100644 --- a/tools/perf/tests/Build +++ b/tools/perf/tests/Build @@ -36,6 +36,7 @@ perf-y += bpf.o perf-y += topology.o perf-y += cpumap.o perf-y += stat.o +perf-y += event_update.o $(OUTPUT)tests/llvm-src-base.c: tests/bpf-script-example.c tests/Build $(call rule_mkdir) diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c index 6a35198..f2b1dca 100644 --- a/tools/perf/tests/builtin-test.c +++ b/tools/perf/tests/builtin-test.c @@ -200,6 +200,10 @@ static struct test generic_tests[] = { .func = test__synthesize_stat_round, }, { + .desc = "Test attr update synthesize", + .func = test__event_update, + }, + { .func = NULL, }, }; diff --git a/tools/perf/tests/event_update.c b/tools/perf/tests/event_update.c new file mode 100644 index 0000000..9cdf4c9 --- /dev/null +++ b/tools/perf/tests/event_update.c @@ -0,0 +1,42 @@ +#include <linux/compiler.h> +#include "evlist.h" +#include "evsel.h" +#include "machine.h" +#include "tests.h" +#include "debug.h" + +static int process_event_unit(struct perf_tool *tool __maybe_unused, + union perf_event *event, + struct perf_sample *sample __maybe_unused, + struct machine *machine __maybe_unused) +{ + struct event_update_event *ev = (struct event_update_event *) event; + + TEST_ASSERT_VAL("wrong id", ev->id == 123); + TEST_ASSERT_VAL("wrong id", ev->type == PERF_EVENT_UPDATE__UNIT); + TEST_ASSERT_VAL("wrong unit", !strcmp(ev->data, "KRAVA")); + return 0; +} + +int test__event_update(int subtest __maybe_unused) +{ + struct perf_evlist *evlist; + struct perf_evsel *evsel; + + evlist = perf_evlist__new_default(); + TEST_ASSERT_VAL("failed to get evlist", evlist); + + evsel = perf_evlist__first(evlist); + + TEST_ASSERT_VAL("failed to allos ids", + !perf_evsel__alloc_id(evsel, 1, 1)); + + perf_evlist__id_add(evlist, evsel, 0, 0, 123); + + evsel->unit = strdup("KRAVA"); + + TEST_ASSERT_VAL("failed to synthesize attr update unit", + !perf_event__synthesize_event_update_unit(NULL, evsel, process_event_unit)); + + return 0; +} diff --git a/tools/perf/tests/tests.h b/tools/perf/tests/tests.h index a82ab9c..82b2b5e 100644 --- a/tools/perf/tests/tests.h +++ b/tools/perf/tests/tests.h @@ -84,6 +84,7 @@ int test__cpu_map_synthesize(int subtest); int test__synthesize_stat_config(int subtest); int test__synthesize_stat(int subtest); int test__synthesize_stat_round(int subtest); +int test__event_update(int subtest); #if defined(__arm__) || defined(__aarch64__) #ifdef HAVE_DWARF_UNWIND_SUPPORT diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h index 6966a4b..64c4cdf 100644 --- a/tools/perf/util/event.h +++ b/tools/perf/util/event.h @@ -308,6 +308,10 @@ struct attr_event { u64 id[]; }; +enum { + PERF_EVENT_UPDATE__UNIT = 0, +}; + struct event_update_event { struct perf_event_header header; u64 type; diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 6b4e002..5759ebf 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -2686,6 +2686,43 @@ int perf_event__synthesize_attr(struct perf_tool *tool, return err; } +static struct event_update_event * +event_update_event__new(size_t size, u64 type, u64 id) +{ + struct event_update_event *ev; + + size += sizeof(*ev); + size = PERF_ALIGN(size, sizeof(u64)); + + ev = zalloc(size); + if (ev) { + ev->header.type = PERF_RECORD_EVENT_UPDATE; + ev->header.size = (u16)size; + ev->type = type; + ev->id = id; + } + return ev; +} + +int +perf_event__synthesize_event_update_unit(struct perf_tool *tool, + struct perf_evsel *evsel, + perf_event__handler_t process) +{ + struct event_update_event *ev; + size_t size = strlen(evsel->unit); + int err; + + ev = event_update_event__new(size + 1, PERF_EVENT_UPDATE__UNIT, evsel->id[0]); + if (ev == NULL) + return -ENOMEM; + + strncpy(ev->data, evsel->unit, size); + err = process(tool, (union perf_event *)ev, NULL, NULL); + free(ev); + return err; +} + int perf_event__synthesize_attrs(struct perf_tool *tool, struct perf_session *session, perf_event__handler_t process) @@ -2762,6 +2799,13 @@ int perf_event__process_event_update(struct perf_tool *tool __maybe_unused, if (evsel == NULL) return -EINVAL; + switch (ev->type) { + case PERF_EVENT_UPDATE__UNIT: + evsel->unit = strdup(ev->data); + default: + break; + } + return 0; } diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h index 1e843c6..6aa2b92 100644 --- a/tools/perf/util/header.h +++ b/tools/perf/util/header.h @@ -105,6 +105,9 @@ int perf_event__synthesize_attr(struct perf_tool *tool, int perf_event__synthesize_attrs(struct perf_tool *tool, struct perf_session *session, perf_event__handler_t process); +int perf_event__synthesize_event_update_unit(struct perf_tool *tool, + struct perf_evsel *evsel, + perf_event__handler_t process); int perf_event__process_attr(struct perf_tool *tool, union perf_event *event, struct perf_evlist **pevlist); int perf_event__process_event_update(struct perf_tool *tool __maybe_unused,
Commit-ID: daeecbc0c431f15f492fb8d704080a02de6e2918 Gitweb: http://git.kernel.org/tip/daeecbc0c431f15f492fb8d704080a02de6e2918 Author: Jiri Olsa <jolsa@kernel.org> AuthorDate: Sun, 25 Oct 2015 15:51:38 +0100 Committer: Arnaldo Carvalho de Melo <acme@redhat.com> CommitDate: Thu, 17 Dec 2015 15:11:59 -0300 perf tools: Add event_update event scale type A__allocdding scale type 'event update' event, that stores/transfer events scale value. The PMU events can define the scale value which is used to multiply events data. Signed-off-by: Jiri Olsa <jolsa@kernel.org> Tested-by: Kan Liang <kan.liang@intel.com> Cc: David Ahern <dsahern@gmail.com> Cc: Namhyung Kim <namhyung@kernel.org> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Link: http://lkml.kernel.org/r/1445784728-21732-23-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> --- tools/perf/tests/event_update.c | 21 +++++++++++++++++++++ tools/perf/util/event.h | 5 +++++ tools/perf/util/header.c | 26 ++++++++++++++++++++++++++ tools/perf/util/header.h | 3 +++ 4 files changed, 55 insertions(+) diff --git a/tools/perf/tests/event_update.c b/tools/perf/tests/event_update.c index 9cdf4c9..a91fcef 100644 --- a/tools/perf/tests/event_update.c +++ b/tools/perf/tests/event_update.c @@ -18,6 +18,22 @@ static int process_event_unit(struct perf_tool *tool __maybe_unused, return 0; } +static int process_event_scale(struct perf_tool *tool __maybe_unused, + union perf_event *event, + struct perf_sample *sample __maybe_unused, + struct machine *machine __maybe_unused) +{ + struct event_update_event *ev = (struct event_update_event *) event; + struct event_update_event_scale *ev_data; + + ev_data = (struct event_update_event_scale *) ev->data; + + TEST_ASSERT_VAL("wrong id", ev->id == 123); + TEST_ASSERT_VAL("wrong id", ev->type == PERF_EVENT_UPDATE__SCALE); + TEST_ASSERT_VAL("wrong scale", ev_data->scale = 0.123); + return 0; +} + int test__event_update(int subtest __maybe_unused) { struct perf_evlist *evlist; @@ -38,5 +54,10 @@ int test__event_update(int subtest __maybe_unused) TEST_ASSERT_VAL("failed to synthesize attr update unit", !perf_event__synthesize_event_update_unit(NULL, evsel, process_event_unit)); + evsel->scale = 0.123; + + TEST_ASSERT_VAL("failed to synthesize attr update scale", + !perf_event__synthesize_event_update_scale(NULL, evsel, process_event_scale)); + return 0; } diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h index 64c4cdf..44198e8 100644 --- a/tools/perf/util/event.h +++ b/tools/perf/util/event.h @@ -310,6 +310,11 @@ struct attr_event { enum { PERF_EVENT_UPDATE__UNIT = 0, + PERF_EVENT_UPDATE__SCALE = 1, +}; + +struct event_update_event_scale { + double scale; }; struct event_update_event { diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 5759ebf..30edb4b 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -2723,6 +2723,27 @@ perf_event__synthesize_event_update_unit(struct perf_tool *tool, return err; } +int +perf_event__synthesize_event_update_scale(struct perf_tool *tool, + struct perf_evsel *evsel, + perf_event__handler_t process) +{ + struct event_update_event *ev; + struct event_update_event_scale *ev_data; + int err; + + ev = event_update_event__new(sizeof(*ev_data), PERF_EVENT_UPDATE__SCALE, evsel->id[0]); + if (ev == NULL) + return -ENOMEM; + + ev_data = (struct event_update_event_scale *) ev->data; + ev_data->scale = evsel->scale; + err = process(tool, (union perf_event*) ev, NULL, NULL); + free(ev); + return err; +} + + int perf_event__synthesize_attrs(struct perf_tool *tool, struct perf_session *session, perf_event__handler_t process) @@ -2787,6 +2808,7 @@ int perf_event__process_event_update(struct perf_tool *tool __maybe_unused, struct perf_evlist **pevlist) { struct event_update_event *ev = &event->event_update; + struct event_update_event_scale *ev_scale; struct perf_evlist *evlist; struct perf_evsel *evsel; @@ -2802,6 +2824,10 @@ int perf_event__process_event_update(struct perf_tool *tool __maybe_unused, switch (ev->type) { case PERF_EVENT_UPDATE__UNIT: evsel->unit = strdup(ev->data); + break; + case PERF_EVENT_UPDATE__SCALE: + ev_scale = (struct event_update_event_scale *) ev->data; + evsel->scale = ev_scale->scale; default: break; } diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h index 6aa2b92..fad04cb 100644 --- a/tools/perf/util/header.h +++ b/tools/perf/util/header.h @@ -108,6 +108,9 @@ int perf_event__synthesize_attrs(struct perf_tool *tool, int perf_event__synthesize_event_update_unit(struct perf_tool *tool, struct perf_evsel *evsel, perf_event__handler_t process); +int perf_event__synthesize_event_update_scale(struct perf_tool *tool, + struct perf_evsel *evsel, + perf_event__handler_t process); int perf_event__process_attr(struct perf_tool *tool, union perf_event *event, struct perf_evlist **pevlist); int perf_event__process_event_update(struct perf_tool *tool __maybe_unused,
Commit-ID: 802c9048b824eaa3c75d875e2d107460ad586439 Gitweb: http://git.kernel.org/tip/802c9048b824eaa3c75d875e2d107460ad586439 Author: Jiri Olsa <jolsa@kernel.org> AuthorDate: Sun, 25 Oct 2015 15:51:39 +0100 Committer: Arnaldo Carvalho de Melo <acme@redhat.com> CommitDate: Thu, 17 Dec 2015 15:12:46 -0300 perf tools: Add event_update event name type Adding name type 'event update' event, that stores/transfer events name. Event's name is stored within perf.data's EVENT_DESC feature, but we don't have it if we get the report data from pipe. Signed-off-by: Jiri Olsa <jolsa@kernel.org> Tested-by: Kan Liang <kan.liang@intel.com> Cc: David Ahern <dsahern@gmail.com> Cc: Namhyung Kim <namhyung@kernel.org> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Link: http://lkml.kernel.org/r/1445784728-21732-24-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> --- tools/perf/tests/event_update.c | 25 +++++++++++++++++++++++++ tools/perf/util/event.h | 1 + tools/perf/util/header.c | 21 +++++++++++++++++++++ tools/perf/util/header.h | 3 +++ 4 files changed, 50 insertions(+) diff --git a/tools/perf/tests/event_update.c b/tools/perf/tests/event_update.c index a91fcef..482b896 100644 --- a/tools/perf/tests/event_update.c +++ b/tools/perf/tests/event_update.c @@ -34,10 +34,30 @@ static int process_event_scale(struct perf_tool *tool __maybe_unused, return 0; } +struct event_name { + struct perf_tool tool; + const char *name; +}; + +static int process_event_name(struct perf_tool *tool, + union perf_event *event, + struct perf_sample *sample __maybe_unused, + struct machine *machine __maybe_unused) +{ + struct event_name *tmp = container_of(tool, struct event_name, tool); + struct event_update_event *ev = (struct event_update_event*) event; + + TEST_ASSERT_VAL("wrong id", ev->id == 123); + TEST_ASSERT_VAL("wrong id", ev->type == PERF_EVENT_UPDATE__NAME); + TEST_ASSERT_VAL("wrong name", !strcmp(ev->data, tmp->name)); + return 0; +} + int test__event_update(int subtest __maybe_unused) { struct perf_evlist *evlist; struct perf_evsel *evsel; + struct event_name tmp; evlist = perf_evlist__new_default(); TEST_ASSERT_VAL("failed to get evlist", evlist); @@ -59,5 +79,10 @@ int test__event_update(int subtest __maybe_unused) TEST_ASSERT_VAL("failed to synthesize attr update scale", !perf_event__synthesize_event_update_scale(NULL, evsel, process_event_scale)); + tmp.name = perf_evsel__name(evsel); + + TEST_ASSERT_VAL("failed to synthesize attr update name", + !perf_event__synthesize_event_update_name(&tmp.tool, evsel, process_event_name)); + return 0; } diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h index 44198e8..235196b 100644 --- a/tools/perf/util/event.h +++ b/tools/perf/util/event.h @@ -311,6 +311,7 @@ struct attr_event { enum { PERF_EVENT_UPDATE__UNIT = 0, PERF_EVENT_UPDATE__SCALE = 1, + PERF_EVENT_UPDATE__NAME = 2, }; struct event_update_event_scale { diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 30edb4b..cd3d005 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -2743,6 +2743,24 @@ perf_event__synthesize_event_update_scale(struct perf_tool *tool, return err; } +int +perf_event__synthesize_event_update_name(struct perf_tool *tool, + struct perf_evsel *evsel, + perf_event__handler_t process) +{ + struct event_update_event *ev; + size_t len = strlen(evsel->name); + int err; + + ev = event_update_event__new(len + 1, PERF_EVENT_UPDATE__NAME, evsel->id[0]); + if (ev == NULL) + return -ENOMEM; + + strncpy(ev->data, evsel->name, len); + err = process(tool, (union perf_event*) ev, NULL, NULL); + free(ev); + return err; +} int perf_event__synthesize_attrs(struct perf_tool *tool, struct perf_session *session, @@ -2825,6 +2843,9 @@ int perf_event__process_event_update(struct perf_tool *tool __maybe_unused, case PERF_EVENT_UPDATE__UNIT: evsel->unit = strdup(ev->data); break; + case PERF_EVENT_UPDATE__NAME: + evsel->name = strdup(ev->data); + break; case PERF_EVENT_UPDATE__SCALE: ev_scale = (struct event_update_event_scale *) ev->data; evsel->scale = ev_scale->scale; diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h index fad04cb..51cf566 100644 --- a/tools/perf/util/header.h +++ b/tools/perf/util/header.h @@ -111,6 +111,9 @@ int perf_event__synthesize_event_update_unit(struct perf_tool *tool, int perf_event__synthesize_event_update_scale(struct perf_tool *tool, struct perf_evsel *evsel, perf_event__handler_t process); +int perf_event__synthesize_event_update_name(struct perf_tool *tool, + struct perf_evsel *evsel, + perf_event__handler_t process); int perf_event__process_attr(struct perf_tool *tool, union perf_event *event, struct perf_evlist **pevlist); int perf_event__process_event_update(struct perf_tool *tool __maybe_unused,
Commit-ID: 86ebb09f96fe6886e1e5d53b648df5537ba859ca Gitweb: http://git.kernel.org/tip/86ebb09f96fe6886e1e5d53b648df5537ba859ca Author: Jiri Olsa <jolsa@kernel.org> AuthorDate: Sun, 25 Oct 2015 15:51:40 +0100 Committer: Arnaldo Carvalho de Melo <acme@redhat.com> CommitDate: Thu, 17 Dec 2015 15:13:38 -0300 perf tools: Add event_update event cpus type Adding the cpumask 'event update' event, that stores/transfer the cpumask for a event. Signed-off-by: Jiri Olsa <jolsa@kernel.org> Tested-by: Kan Liang <kan.liang@intel.com> Cc: David Ahern <dsahern@gmail.com> Cc: Namhyung Kim <namhyung@kernel.org> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Link: http://lkml.kernel.org/r/1445784728-21732-25-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> --- tools/perf/tests/event_update.c | 29 ++++++++++++++++++++++++++++ tools/perf/util/event.h | 5 +++++ tools/perf/util/header.c | 42 +++++++++++++++++++++++++++++++++++++++++ tools/perf/util/header.h | 3 +++ 4 files changed, 79 insertions(+) diff --git a/tools/perf/tests/event_update.c b/tools/perf/tests/event_update.c index 482b896..012eab5 100644 --- a/tools/perf/tests/event_update.c +++ b/tools/perf/tests/event_update.c @@ -53,6 +53,29 @@ static int process_event_name(struct perf_tool *tool, return 0; } +static int process_event_cpus(struct perf_tool *tool __maybe_unused, + union perf_event *event, + struct perf_sample *sample __maybe_unused, + struct machine *machine __maybe_unused) +{ + struct event_update_event *ev = (struct event_update_event*) event; + struct event_update_event_cpus *ev_data; + struct cpu_map *map; + + ev_data = (struct event_update_event_cpus*) ev->data; + + map = cpu_map__new_data(&ev_data->cpus); + + TEST_ASSERT_VAL("wrong id", ev->id == 123); + TEST_ASSERT_VAL("wrong type", ev->type == PERF_EVENT_UPDATE__CPUS); + TEST_ASSERT_VAL("wrong cpus", map->nr == 3); + TEST_ASSERT_VAL("wrong cpus", map->map[0] == 1); + TEST_ASSERT_VAL("wrong cpus", map->map[1] == 2); + TEST_ASSERT_VAL("wrong cpus", map->map[2] == 3); + cpu_map__put(map); + return 0; +} + int test__event_update(int subtest __maybe_unused) { struct perf_evlist *evlist; @@ -84,5 +107,11 @@ int test__event_update(int subtest __maybe_unused) TEST_ASSERT_VAL("failed to synthesize attr update name", !perf_event__synthesize_event_update_name(&tmp.tool, evsel, process_event_name)); + evsel->own_cpus = cpu_map__new("1,2,3"); + + TEST_ASSERT_VAL("failed to synthesize attr update cpus", + !perf_event__synthesize_event_update_cpus(&tmp.tool, evsel, process_event_cpus)); + + cpu_map__put(evsel->own_cpus); return 0; } diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h index 235196b..b7ffb7e 100644 --- a/tools/perf/util/event.h +++ b/tools/perf/util/event.h @@ -312,6 +312,11 @@ enum { PERF_EVENT_UPDATE__UNIT = 0, PERF_EVENT_UPDATE__SCALE = 1, PERF_EVENT_UPDATE__NAME = 2, + PERF_EVENT_UPDATE__CPUS = 3, +}; + +struct event_update_event_cpus { + struct cpu_map_data cpus; }; struct event_update_event_scale { diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index cd3d005..79d3eb9 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -2762,6 +2762,38 @@ perf_event__synthesize_event_update_name(struct perf_tool *tool, return err; } +int +perf_event__synthesize_event_update_cpus(struct perf_tool *tool, + struct perf_evsel *evsel, + perf_event__handler_t process) +{ + size_t size = sizeof(struct event_update_event); + struct event_update_event *ev; + int max, err; + u16 type; + + if (!evsel->own_cpus) + return 0; + + ev = cpu_map_data__alloc(evsel->own_cpus, &size, &type, &max); + if (!ev) + return -ENOMEM; + + ev->header.type = PERF_RECORD_EVENT_UPDATE; + ev->header.size = (u16)size; + ev->type = PERF_EVENT_UPDATE__CPUS; + ev->id = evsel->id[0]; + + cpu_map_data__synthesize((struct cpu_map_data *) ev->data, + evsel->own_cpus, + type, max); + + err = process(tool, (union perf_event*) ev, NULL, NULL); + free(ev); + return err; +} + + int perf_event__synthesize_attrs(struct perf_tool *tool, struct perf_session *session, perf_event__handler_t process) @@ -2827,8 +2859,10 @@ int perf_event__process_event_update(struct perf_tool *tool __maybe_unused, { struct event_update_event *ev = &event->event_update; struct event_update_event_scale *ev_scale; + struct event_update_event_cpus *ev_cpus; struct perf_evlist *evlist; struct perf_evsel *evsel; + struct cpu_map *map; if (!pevlist || *pevlist == NULL) return -EINVAL; @@ -2849,6 +2883,14 @@ int perf_event__process_event_update(struct perf_tool *tool __maybe_unused, case PERF_EVENT_UPDATE__SCALE: ev_scale = (struct event_update_event_scale *) ev->data; evsel->scale = ev_scale->scale; + case PERF_EVENT_UPDATE__CPUS: + ev_cpus = (struct event_update_event_cpus *) ev->data; + + map = cpu_map__new_data(&ev_cpus->cpus); + if (map) + evsel->own_cpus = map; + else + pr_err("failed to get event_update cpus\n"); default: break; } diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h index 51cf566..a1bc0c57 100644 --- a/tools/perf/util/header.h +++ b/tools/perf/util/header.h @@ -114,6 +114,9 @@ int perf_event__synthesize_event_update_scale(struct perf_tool *tool, int perf_event__synthesize_event_update_name(struct perf_tool *tool, struct perf_evsel *evsel, perf_event__handler_t process); +int perf_event__synthesize_event_update_cpus(struct perf_tool *tool, + struct perf_evsel *evsel, + perf_event__handler_t process); int perf_event__process_attr(struct perf_tool *tool, union perf_event *event, struct perf_evlist **pevlist); int perf_event__process_event_update(struct perf_tool *tool __maybe_unused,
Commit-ID: c853f9394b7bc189632673cac802bdbf6537463b Gitweb: http://git.kernel.org/tip/c853f9394b7bc189632673cac802bdbf6537463b Author: Jiri Olsa <jolsa@kernel.org> AuthorDate: Sun, 25 Oct 2015 15:51:41 +0100 Committer: Arnaldo Carvalho de Melo <acme@redhat.com> CommitDate: Thu, 17 Dec 2015 15:14:36 -0300 perf tools: Add perf_event__fprintf_event_update function To display a 'event update' event for raw dump. Signed-off-by: Jiri Olsa <jolsa@kernel.org> Tested-by: Kan Liang <kan.liang@intel.com> Cc: David Ahern <dsahern@gmail.com> Cc: Namhyung Kim <namhyung@kernel.org> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Link: http://lkml.kernel.org/r/1445784728-21732-26-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> --- tools/perf/util/header.c | 38 ++++++++++++++++++++++++++++++++++++++ tools/perf/util/header.h | 1 + 2 files changed, 39 insertions(+) diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 79d3eb9..49676c1 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -2793,6 +2793,44 @@ perf_event__synthesize_event_update_cpus(struct perf_tool *tool, return err; } +size_t perf_event__fprintf_event_update(union perf_event *event, FILE *fp) +{ + struct event_update_event *ev = &event->event_update; + struct event_update_event_scale *ev_scale; + struct event_update_event_cpus *ev_cpus; + struct cpu_map *map; + size_t ret; + + ret = fprintf(fp, "\n... id: %" PRIu64 "\n", ev->id); + + switch (ev->type) { + case PERF_EVENT_UPDATE__SCALE: + ev_scale = (struct event_update_event_scale *) ev->data; + ret += fprintf(fp, "... scale: %f\n", ev_scale->scale); + break; + case PERF_EVENT_UPDATE__UNIT: + ret += fprintf(fp, "... unit: %s\n", ev->data); + break; + case PERF_EVENT_UPDATE__NAME: + ret += fprintf(fp, "... name: %s\n", ev->data); + break; + case PERF_EVENT_UPDATE__CPUS: + ev_cpus = (struct event_update_event_cpus *) ev->data; + ret += fprintf(fp, "... "); + + map = cpu_map__new_data(&ev_cpus->cpus); + if (map) + ret += cpu_map__fprintf(map, fp); + else + ret += fprintf(fp, "failed to get cpus\n"); + break; + default: + ret += fprintf(fp, "... unknown type\n"); + break; + } + + return ret; +} int perf_event__synthesize_attrs(struct perf_tool *tool, struct perf_session *session, diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h index a1bc0c57..710deec 100644 --- a/tools/perf/util/header.h +++ b/tools/perf/util/header.h @@ -122,6 +122,7 @@ int perf_event__process_attr(struct perf_tool *tool, union perf_event *event, int perf_event__process_event_update(struct perf_tool *tool __maybe_unused, union perf_event *event, struct perf_evlist **pevlist); +size_t perf_event__fprintf_event_update(union perf_event *event, FILE *fp); int perf_event__synthesize_tracing_data(struct perf_tool *tool, int fd, struct perf_evlist *evlist,
Commit-ID: 2d2aea6ae736503d3896c4997b494760ed8febc1 Gitweb: http://git.kernel.org/tip/2d2aea6ae736503d3896c4997b494760ed8febc1 Author: Jiri Olsa <jolsa@kernel.org> AuthorDate: Sun, 25 Oct 2015 15:51:42 +0100 Committer: Arnaldo Carvalho de Melo <acme@redhat.com> CommitDate: Thu, 17 Dec 2015 15:15:13 -0300 perf report: Display newly added events in raw dump The 'perf report -D' command will now display detailed output for these newly added events: event_update thread_map cpu_map stat stat_config stat_round Signed-off-by: Jiri Olsa <jolsa@kernel.org> Tested-by: Kan Liang <kan.liang@intel.com> Cc: David Ahern <dsahern@gmail.com> Cc: Namhyung Kim <namhyung@kernel.org> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Link: http://lkml.kernel.org/r/1445784728-21732-27-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> --- tools/perf/util/session.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 49e5cdc..a90c74b 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -17,6 +17,7 @@ #include "asm/bug.h" #include "auxtrace.h" #include "thread-stack.h" +#include "stat.h" static int perf_session__deliver_event(struct perf_session *session, union perf_event *event, @@ -210,6 +211,9 @@ static int process_event_synth_event_update_stub(struct perf_tool *tool __maybe_ struct perf_evlist **pevlist __maybe_unused) { + if (dump_trace) + perf_event__fprintf_event_update(event, stdout); + dump_printf(": unhandled!\n"); return 0; } @@ -311,6 +315,9 @@ int process_event_thread_map_stub(struct perf_tool *tool __maybe_unused, union perf_event *event __maybe_unused, struct perf_session *session __maybe_unused) { + if (dump_trace) + perf_event__fprintf_thread_map(event, stdout); + dump_printf(": unhandled!\n"); return 0; } @@ -320,6 +327,9 @@ int process_event_cpu_map_stub(struct perf_tool *tool __maybe_unused, union perf_event *event __maybe_unused, struct perf_session *session __maybe_unused) { + if (dump_trace) + perf_event__fprintf_cpu_map(event, stdout); + dump_printf(": unhandled!\n"); return 0; } @@ -329,6 +339,9 @@ int process_event_stat_config_stub(struct perf_tool *tool __maybe_unused, union perf_event *event __maybe_unused, struct perf_session *session __maybe_unused) { + if (dump_trace) + perf_event__fprintf_stat_config(event, stdout); + dump_printf(": unhandled!\n"); return 0; } @@ -338,6 +351,9 @@ static int process_stat_stub(struct perf_tool *tool __maybe_unused, struct perf_session *perf_session __maybe_unused) { + if (dump_trace) + perf_event__fprintf_stat(event, stdout); + dump_printf(": unhandled!\n"); return 0; } @@ -347,6 +363,9 @@ static int process_stat_round_stub(struct perf_tool *tool __maybe_unused, struct perf_session *perf_session __maybe_unused) { + if (dump_trace) + perf_event__fprintf_stat_round(event, stdout); + dump_printf(": unhandled!\n"); return 0; }
Commit-ID: ffa517adf625fa6a6c168285534e1ff7344fa2f1 Gitweb: http://git.kernel.org/tip/ffa517adf625fa6a6c168285534e1ff7344fa2f1 Author: Jiri Olsa <jolsa@kernel.org> AuthorDate: Sun, 25 Oct 2015 15:51:43 +0100 Committer: Arnaldo Carvalho de Melo <acme@redhat.com> CommitDate: Thu, 17 Dec 2015 15:15:14 -0300 perf tools: Introduce stat perf.data header feature Introducing the 'stat' feature to mark a perf.data as created by the 'perf stat record' command. It contains no data. It's needed so that the report tools (report/script) can differentiate sampling data from counting data, because they need to be treated in a different way. In the future it might be used to store the version of the stat storage system used. Signed-off-by: Jiri Olsa <jolsa@kernel.org> Tested-by: Kan Liang <kan.liang@intel.com> Cc: David Ahern <dsahern@gmail.com> Cc: Namhyung Kim <namhyung@kernel.org> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Link: http://lkml.kernel.org/r/1445784728-21732-28-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> --- 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 1435ef6..9c5cdc2c4 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -452,6 +452,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 49676c1..f50b723 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -868,6 +868,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) { @@ -1159,6 +1166,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) { @@ -1948,6 +1961,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 710deec..cff9892 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, };