perf stat: Introduce --per-thread option
Jiri Olsa
reviewerv3 cover perf stat: Introduce --per-thread option
hi,
adding the possibility to display stat data per thread.
Allowing following commands and output:
$ perf stat -e cycles,instructions --per-thread -p 30190,30242 ^C Performance counter stats for process id '30190,30242':
cat-30190 0 cycles
yes-30242 3,842,525,421 cycles
cat-30190 0 instructions
yes-30242 10,370,817,010 instructions1.143155657 seconds time elapsed
Also works under interval mode:
$ perf stat -e cycles,instructions --per-thread -p 30190,30242 -I 1000
# time comm-pid counts unit events
1.000073435 cat-30190 89,058 cycles
1.000073435 yes-30242 3,360,786,902 cycles (100.00%)
1.000073435 cat-30190 14,066 instructions
1.000073435 yes-30242 9,069,937,462 instructions
2.000204830 cat-30190 0 cycles
2.000204830 yes-30242 3,351,667,626 cycles
2.000204830 cat-30190 0 instructions
2.000204830 yes-30242 9,045,796,885 instructions
^C 2.771286639 cat-30190 0 cycles
2.771286639 yes-30242 2,593,884,166 cycles
2.771286639 cat-30190 0 instructions
2.771286639 yes-30242 7,001,171,191 instructionsAvailable in here:
git://git.kernel.org/pub/scm/linux/kernel/git/jolsa/perf.git
perf/per_thread
v3 changes:
- some patches already pulled in, rebased on latest acme's perf/core
- fixed cpu_map__get/thread_map__get to accept NULL map
- renamed propagate_maps to perf_evlist__propagate_maps
- renamed --per-task option to --per-thread
- changed 'task-pid' header output to 'comm-pid'
v2 changes:
- renamed xyarray__zero to xyarray__reset
- using atomic_t for cpu_map/thread_map refcnt
- moving all stat functions into stat object
- using init_stats to initialize 'struct stats*'
- change TASK-$pid output into $comm-$pid
- updated doc with --per-task option
thanks,
jirka
---
Jiri Olsa (26):
perf tools: Change thread_map::map into struct
perf tools: Add comm string into struct thread_map
perf tools: Add reference counting for cpu_map object
perf tools: Add reference counting for thread_map object perf tools: Propagate cpu maps through the evlist
perf tools: Propagate thread maps through the evlist
perf tools: Make perf_evsel__(nr_)cpus generic
perf tests: Add thread_map object tests
perf stat: Introduce perf_counts function
perf stat: Use xyarray for cpu evsel counts
perf stat: Make stats work over the thread dimension
perf stat: Rename struct perf_counts::cpu member to values perf stat: Move perf_evsel__(alloc|free|reset)_stat_priv into stat object perf stat: Move perf_evsel__(alloc|free)_prev_raw_counts into stat object perf stat: Move perf_evlist__(alloc|free)_stats into evlist object perf stat: Introduce perf_evsel__alloc_stats function
perf stat: Introduce perf_evsel__read function
perf stat: Introduce read_counters function
perf stat: Separate counters reading and processing
perf stat: Move zero_per_pkg into counter process code
perf stat: Move perf_stat initialization counter process code perf stat: Remove perf_evsel__read_cb function
perf stat: Rename print_interval to process_interval
perf stat: Using init_stats instead of memset
perf stat: Introduce print_counters function
perf stat: Introduce --per-thread option
tools/perf/Documentation/perf-stat.txt | 4 + tools/perf/builtin-stat.c | 394 ++++++++++++++-------------- tools/perf/builtin-trace.c | 4 +- tools/perf/tests/Build | 1 + tools/perf/tests/builtin-test.c | 4 + tools/perf/tests/code-reading.c | 4 +- tools/perf/tests/keep-tracking.c | 4 +- tools/perf/tests/mmap-basic.c | 4 +- tools/perf/tests/mmap-thread-lookup.c | 2 +- tools/perf/tests/openat-syscall-all-cpus.c | 8 +- tools/perf/tests/openat-syscall-tp-fields.c | 2 +- tools/perf/tests/openat-syscall.c | 6 +- tools/perf/tests/switch-tracking.c | 4 +- tools/perf/tests/tests.h | 1 + tools/perf/tests/thread-map.c | 28 ++ tools/perf/util/auxtrace.c | 4 +- tools/perf/util/cpumap.c | 26 +- tools/perf/util/cpumap.h | 6 +- tools/perf/util/event.c | 6 +- tools/perf/util/evlist.c | 39 ++- tools/perf/util/evlist.h | 1 - tools/perf/util/evsel.c | 28 +- tools/perf/util/evsel.h | 40 ++- tools/perf/util/parse-events.c | 5 +- tools/perf/util/python-ext-sources | 1 + tools/perf/util/python.c | 4 +- tools/perf/util/record.c | 4 +- tools/perf/util/session.c | 2 +- tools/perf/util/stat.c | 122 ++++++++- tools/perf/util/stat.h | 46 +++- tools/perf/util/svghelper.c | 2 +- tools/perf/util/thread_map.c | 110 ++++++-- tools/perf/util/thread_map.h | 17 +- 33 files changed, 622 insertions(+), 311 deletions(-) create mode 100644 tools/perf/tests/thread-map.c
Jiri Olsa
reviewerPATCH v3 1/26 perf tools: Change thread_map::map into struct
We need to store command names with the pid. Changing map to be struct holding pid. Process name is coming in shortly.
--- tools/perf/builtin-trace.c | 4 ++-- tools/perf/tests/openat-syscall-tp-fields.c | 2 +- tools/perf/util/auxtrace.c | 4 ++-- tools/perf/util/event.c | 6 +++--- tools/perf/util/evlist.c | 4 ++-- tools/perf/util/evsel.c | 2 +- tools/perf/util/thread_map.c | 22 +++++++++++----------- tools/perf/util/thread_map.h | 8 +++++++- 8 files changed, 29 insertions(+), 23 deletions(-)
tools/perf/builtin-trace.c +2 -2
@@ -2324,7 +2324,7 @@ static int trace__run(struct trace *trace, int argc, const char **argv)*/ if (trace->filter_pids.nr >0 ) err =perf_evlist__set_filter_pids (evlist, trace->filter_pids.nr, trace->filter_pids.entries); -else if (evlist->threads->map[0 ] ==-1 ) +else if (thread_map__pid (evlist->threads,0 ) ==-1 ) err =perf_evlist__set_filter_pid (evlist,getpid ());if (err <0 ) {
@@ -2342,7 +2342,7 @@ static int trace__run(struct trace *trace, int argc, const char **argv)if (forks)perf_evlist__start_workload (evlist); - trace->multiple_threads = evlist->threads->map[0 ] ==-1 || + trace->multiple_threads =thread_map__pid (evlist->threads,0 ) ==-1 || evlist->threads->nr >1 ||perf_evlist__first (evlist)->attr.inherit; again:
tools/perf/tests/openat-syscall-tp-fields.c +1 -1
@@ -45,7 +45,7 @@ int test__syscall_openat_tp_fields(void)perf_evsel__config (evsel, &opts); - evlist->threads->map[0 ] =getpid (); +thread_map__pid (evlist->threads,0 ) =getpid (); err =perf_evlist__open (evlist);if (err <0 ) {
tools/perf/util/auxtrace.c +2 -2
@@ -119,12 +119,12 @@ void auxtrace_mmap_params__set_idx(struct auxtrace_mmap_params *mp,if (per_cpu) { mp->cpu = evlist->cpus->map[idx];if (evlist->threads) - mp->tid = evlist->threads->map[0 ]; + mp->tid =thread_map__pid (evlist->threads,0 );else mp->tid =-1 ; }else { mp->cpu =-1 ; - mp->tid = evlist->threads->map[idx]; + mp->tid =thread_map__pid (evlist->threads, idx); } }
tools/perf/util/event.c +3 -3
@@ -479,7 +479,7 @@ int perf_event__synthesize_thread_map(struct perf_tool *tool,for (thread =0 ; thread < threads->nr; ++thread) {if (__event__synthesize_thread (comm_event, mmap_event, fork_event, - threads->map[thread],0 , +thread_map__pid (threads, thread),0 , process, tool, machine, mmap_data)) { err =-1 ;
@@ -490,12 +490,12 @@ int perf_event__synthesize_thread_map(struct perf_tool *tool,* comm.pid is set to thread group id by * perf_event__synthesize_comm */ -if ((int ) comm_event->comm.pid != threads->map[thread]) { +if ((int ) comm_event->comm.pid !=thread_map__pid (threads, thread)) {bool need_leader = true;/* is thread group leader in thread_map? */ for (j =0 ; j < threads->nr; ++j) { -if ((int ) comm_event->comm.pid == threads->map[j]) { +if ((int ) comm_event->comm.pid ==thread_map__pid (threads, j)) { need_leader = false;break ; }
tools/perf/util/evlist.c +2 -2
@@ -548,7 +548,7 @@ static void perf_evlist__set_sid_idx(struct perf_evlist *evlist,else sid->cpu =-1 ;if (!evsel->system_wide && evlist->threads && thread >=0 ) - sid->tid = evlist->threads->map[thread]; + sid->tid =thread_map__pid (evlist->threads, thread);else sid->tid =-1 ; }
@@ -1475,7 +1475,7 @@ int perf_evlist__prepare_workload(struct perf_evlist *evlist, struct target *tar __func__, __LINE__); goto out_close_pipes; } - evlist->threads->map[0 ] = evlist->workload.pid; +thread_map__pid (evlist->threads,0 ) = evlist->workload.pid; }close (child_ready_pipe[1 ]);
tools/perf/util/evsel.c +1 -1
@@ -1167,7 +1167,7 @@ retry_sample_id:int group_fd;if (!evsel->cgrp && !evsel->system_wide) - pid = threads->map[thread]; + pid =thread_map__pid (threads, thread); group_fd =get_group_fd (evsel, cpu, thread); retry_open:
tools/perf/util/thread_map.c +11 -11
@@ -22,7 +22,7 @@ static int filter(const struct dirent *dir)static struct thread_map *thread_map__realloc (struct thread_map *map,int nr) { -size_t size =sizeof (*map) +sizeof (pid_t) * nr; +size_t size =sizeof (*map) +sizeof (struct thread_map_data ) * nr;return realloc (map, size); }
@@ -45,7 +45,7 @@ struct thread_map *thread_map__new_by_pid(pid_t pid) threads =thread_map__alloc (items);if (threads !=NULL ) {for (i =0 ; i < items; i++) - threads->map[i] =atoi (namelist[i]->d_name); +thread_map__pid (threads, i) =atoi (namelist[i]->d_name); threads->nr = items; }
@@ -61,8 +61,8 @@ struct thread_map *thread_map__new_by_tid(pid_t tid)struct thread_map *threads =thread_map__alloc (1 );if (threads !=NULL ) { - threads->map[0 ] = tid; - threads->nr =1 ; +thread_map__pid (threads,0 ) = tid; + threads->nr =1 ; }return threads;
@@ -124,7 +124,7 @@ struct thread_map *thread_map__new_by_uid(uid_t uid) }for (i =0 ; i < items; i++) - threads->map[threads->nr + i] =atoi (namelist[i]->d_name); +thread_map__pid (threads, threads->nr + i) =atoi (namelist[i]->d_name);for (i =0 ; i < items; i++)zfree (&namelist[i]);
@@ -201,7 +201,7 @@ static struct thread_map *thread_map__new_by_pid_str(const char *pid_str) threads = nt;for (i =0 ; i < items; i++) { - threads->map[j++] =atoi (namelist[i]->d_name); +thread_map__pid (threads, j++) =atoi (namelist[i]->d_name);zfree (&namelist[i]); } threads->nr = total_tasks;
@@ -227,8 +227,8 @@ struct thread_map *thread_map__new_dummy(void)struct thread_map *threads =thread_map__alloc (1 );if (threads !=NULL ) { - threads->map[0 ] =-1 ; - threads->nr =1 ; +thread_map__pid (threads,0 ) =-1 ; + threads->nr =1 ; }return threads; }
@@ -267,8 +267,8 @@ static struct thread_map *thread_map__new_by_tid_str(const char *tid_str) goto out_free_threads; threads = nt; - threads->map[ntasks -1 ] = tid; - threads->nr = ntasks; +thread_map__pid (threads, ntasks -1 ) = tid; + threads->nr = ntasks; } out:return threads;
@@ -301,7 +301,7 @@ size_t thread_map__fprintf(struct thread_map *threads, FILE *fp)size_t printed =fprintf (fp,"%d thread%s: " , threads->nr, threads->nr >1 ?"s" :"" );for (i =0 ; i < threads->nr; ++i) - printed +=fprintf (fp,"%s%d" , i ?", " :"" , threads->map[i]); + printed +=fprintf (fp,"%s%d" , i ?", " :"" ,thread_map__pid (threads, i));return printed +fprintf (fp,"\n" ); }
tools/perf/util/thread_map.h +7 -1
@@ -4,11 +4,17 @@#include <sys/types.h> #include <stdio.h> +struct thread_map_data { +pid_t pid; +}; +struct thread_map {int nr; -pid_t map[]; +struct thread_map_data map[]; }; +#define thread_map__pid (__m, __t) __m->map[__t].pid +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);
Signature · 1 line
1.9.3
Arnaldo Carvalho de Melo
maintainerRe: [PATCH 01/26] perf tools: Change thread_map::map into struct
Em Thu, Jun 18, 2015 at 11:48:40PM +0200, Jiri Olsa escreveu:
Quoted 44 lines
We need to store command names with the pid. Changing map to be struct holding pid. Process name is coming in shortly.
Signed-off-by Jiri Olsa <[email protected]>--- tools/perf/builtin-trace.c | 4 ++-- tools/perf/tests/openat-syscall-tp-fields.c | 2 +- tools/perf/util/auxtrace.c | 4 ++-- tools/perf/util/event.c | 6 +++--- tools/perf/util/evlist.c | 4 ++-- tools/perf/util/evsel.c | 2 +- tools/perf/util/thread_map.c | 22 +++++++++++----------- tools/perf/util/thread_map.h | 8 +++++++- 8 files changed, 29 insertions(+), 23 deletions(-)tools/perf/builtin-trace.c +2
-2@@ -2324,7 +2324,7 @@ static int trace__run(struct trace *trace, int argc, const char **argv)*/ if (trace->filter_pids.nr >0 ) err =perf_evlist__set_filter_pids (evlist, trace->filter_pids.nr, trace->filter_pids.entries); -else if (evlist->threads->map[0 ] ==-1 ) +else if (thread_map__pid (evlist->threads,0 ) ==-1 ) err =perf_evlist__set_filter_pid (evlist,getpid ());if (err <0 ) {@@ -2342,7 +2342,7 @@ static int trace__run(struct trace *trace, int argc, const char **argv)if (forks)perf_evlist__start_workload (evlist); - trace->multiple_threads = evlist->threads->map[0 ] ==-1 || + trace->multiple_threads =thread_map__pid (evlist->threads,0 ) ==-1 || evlist->threads->nr >1 ||perf_evlist__first (evlist)->attr.inherit; again:tools/perf/tests/openat-syscall-tp-fields.c +0
-0
tools/perf/tests/openat-syscall-tp-fields.c int test__syscall_openat_tp_fields(void) · line 48
Quoted 5 lines
tools/perf/tests/openat-syscall-tp-fields.c +1
-1@@ -45,7 +45,7 @@ int test__syscall_openat_tp_fields(void)perf_evsel__config (evsel, &opts); - evlist->threads->map[0 ] =getpid (); +thread_map__pid (evlist->threads,0 ) =getpid ();
So this 'function(parms) = something' idiom looks ugly/unfamiliar, can't we keep using:
evlist->thread->map[0].pid = getpid();
I.e. just add the .pid to the existing usage.
- Arnaldo
Quoted 192 lines
tools/perf/tests/openat-syscall-tp-fields.c +0
-0err =perf_evlist__open (evlist);if (err <0 ) {tools/perf/util/auxtrace.c +2
-2@@ -119,12 +119,12 @@ void auxtrace_mmap_params__set_idx(struct auxtrace_mmap_params *mp,if (per_cpu) { mp->cpu = evlist->cpus->map[idx];if (evlist->threads) - mp->tid = evlist->threads->map[0 ]; + mp->tid =thread_map__pid (evlist->threads,0 );else mp->tid =-1 ; }else { mp->cpu =-1 ; - mp->tid = evlist->threads->map[idx]; + mp->tid =thread_map__pid (evlist->threads, idx); } }tools/perf/util/event.c +3
-3@@ -479,7 +479,7 @@ int perf_event__synthesize_thread_map(struct perf_tool *tool,for (thread =0 ; thread < threads->nr; ++thread) {if (__event__synthesize_thread (comm_event, mmap_event, fork_event, - threads->map[thread],0 , +thread_map__pid (threads, thread),0 , process, tool, machine, mmap_data)) { err =-1 ;@@ -490,12 +490,12 @@ int perf_event__synthesize_thread_map(struct perf_tool *tool,* comm.pid is set to thread group id by * perf_event__synthesize_comm */ -if ((int ) comm_event->comm.pid != threads->map[thread]) { +if ((int ) comm_event->comm.pid !=thread_map__pid (threads, thread)) {bool need_leader = true;/* is thread group leader in thread_map? */ for (j =0 ; j < threads->nr; ++j) { -if ((int ) comm_event->comm.pid == threads->map[j]) { +if ((int ) comm_event->comm.pid ==thread_map__pid (threads, j)) { need_leader = false;break ; }tools/perf/util/evlist.c +2
-2@@ -548,7 +548,7 @@ static void perf_evlist__set_sid_idx(struct perf_evlist *evlist,else sid->cpu =-1 ;if (!evsel->system_wide && evlist->threads && thread >=0 ) - sid->tid = evlist->threads->map[thread]; + sid->tid =thread_map__pid (evlist->threads, thread);else sid->tid =-1 ; }@@ -1475,7 +1475,7 @@ int perf_evlist__prepare_workload(struct perf_evlist *evlist, struct target *tar __func__, __LINE__); goto out_close_pipes; } - evlist->threads->map[0 ] = evlist->workload.pid; +thread_map__pid (evlist->threads,0 ) = evlist->workload.pid; }close (child_ready_pipe[1 ]);tools/perf/util/evsel.c +1
-1@@ -1167,7 +1167,7 @@ retry_sample_id:int group_fd;if (!evsel->cgrp && !evsel->system_wide) - pid = threads->map[thread]; + pid =thread_map__pid (threads, thread); group_fd =get_group_fd (evsel, cpu, thread); retry_open:tools/perf/util/thread_map.c +11
-11@@ -22,7 +22,7 @@ static int filter(const struct dirent *dir)static struct thread_map *thread_map__realloc (struct thread_map *map,int nr) { -size_t size =sizeof (*map) +sizeof (pid_t) * nr; +size_t size =sizeof (*map) +sizeof (struct thread_map_data ) * nr;return realloc (map, size); }@@ -45,7 +45,7 @@ struct thread_map *thread_map__new_by_pid(pid_t pid) threads =thread_map__alloc (items);if (threads !=NULL ) {for (i =0 ; i < items; i++) - threads->map[i] =atoi (namelist[i]->d_name); +thread_map__pid (threads, i) =atoi (namelist[i]->d_name); threads->nr = items; }@@ -61,8 +61,8 @@ struct thread_map *thread_map__new_by_tid(pid_t tid)struct thread_map *threads =thread_map__alloc (1 );if (threads !=NULL ) { - threads->map[0 ] = tid; - threads->nr =1 ; +thread_map__pid (threads,0 ) = tid; + threads->nr =1 ; }return threads;@@ -124,7 +124,7 @@ struct thread_map *thread_map__new_by_uid(uid_t uid) }for (i =0 ; i < items; i++) - threads->map[threads->nr + i] =atoi (namelist[i]->d_name); +thread_map__pid (threads, threads->nr + i) =atoi (namelist[i]->d_name);for (i =0 ; i < items; i++)zfree (&namelist[i]);@@ -201,7 +201,7 @@ static struct thread_map *thread_map__new_by_pid_str(const char *pid_str) threads = nt;for (i =0 ; i < items; i++) { - threads->map[j++] =atoi (namelist[i]->d_name); +thread_map__pid (threads, j++) =atoi (namelist[i]->d_name);zfree (&namelist[i]); } threads->nr = total_tasks;@@ -227,8 +227,8 @@ struct thread_map *thread_map__new_dummy(void)struct thread_map *threads =thread_map__alloc (1 );if (threads !=NULL ) { - threads->map[0 ] =-1 ; - threads->nr =1 ; +thread_map__pid (threads,0 ) =-1 ; + threads->nr =1 ; }return threads; }@@ -267,8 +267,8 @@ static struct thread_map *thread_map__new_by_tid_str(const char *tid_str) goto out_free_threads; threads = nt; - threads->map[ntasks -1 ] = tid; - threads->nr = ntasks; +thread_map__pid (threads, ntasks -1 ) = tid; + threads->nr = ntasks; } out:return threads;@@ -301,7 +301,7 @@ size_t thread_map__fprintf(struct thread_map *threads, FILE *fp)size_t printed =fprintf (fp,"%d thread%s: " , threads->nr, threads->nr >1 ?"s" :"" );for (i =0 ; i < threads->nr; ++i) - printed +=fprintf (fp,"%s%d" , i ?", " :"" , threads->map[i]); + printed +=fprintf (fp,"%s%d" , i ?", " :"" ,thread_map__pid (threads, i));return printed +fprintf (fp,"\n" ); }tools/perf/util/thread_map.h +7
-1@@ -4,11 +4,17 @@#include <sys/types.h> #include <stdio.h> +struct thread_map_data { +pid_t pid; +}; +struct thread_map {int nr; -pid_t map[]; +struct thread_map_data map[]; }; +#define thread_map__pid (__m, __t) __m->map[__t].pid +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);Signature · 1 line
1.9.3
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH 01/26] perf tools: Change thread_map::map into struct
Quoted 48 lines · Arnaldo Carvalho de Melo
Em Thu, Jun 18, 2015 at 11:48:40PM +0200, Jiri Olsa escreveu:
Quoted 47 lines
We need to store command names with the pid. Changing map to be struct holding pid. Process name is coming in shortly.
Signed-off-by Jiri Olsa <[email protected]>--- tools/perf/builtin-trace.c | 4 ++-- tools/perf/tests/openat-syscall-tp-fields.c | 2 +- tools/perf/util/auxtrace.c | 4 ++-- tools/perf/util/event.c | 6 +++--- tools/perf/util/evlist.c | 4 ++-- tools/perf/util/evsel.c | 2 +- tools/perf/util/thread_map.c | 22 +++++++++++----------- tools/perf/util/thread_map.h | 8 +++++++- 8 files changed, 29 insertions(+), 23 deletions(-)tools/perf/builtin-trace.c +2
-2@@ -2324,7 +2324,7 @@ static int trace__run(struct trace *trace, int argc, const char **argv)*/ if (trace->filter_pids.nr >0 ) err =perf_evlist__set_filter_pids (evlist, trace->filter_pids.nr, trace->filter_pids.entries); -else if (evlist->threads->map[0 ] ==-1 ) +else if (thread_map__pid (evlist->threads,0 ) ==-1 ) err =perf_evlist__set_filter_pid (evlist,getpid ());if (err <0 ) {@@ -2342,7 +2342,7 @@ static int trace__run(struct trace *trace, int argc, const char **argv)if (forks)perf_evlist__start_workload (evlist); - trace->multiple_threads = evlist->threads->map[0 ] ==-1 || + trace->multiple_threads =thread_map__pid (evlist->threads,0 ) ==-1 || evlist->threads->nr >1 ||perf_evlist__first (evlist)->attr.inherit; again:tools/perf/tests/openat-syscall-tp-fields.c +0
-0@@ -45,7 +45,7 @@ int test__syscall_openat_tp_fields(void)perf_evsel__config (evsel, &opts);
Quoted 7 lines
tools/perf/tests/openat-syscall-tp-fields.c int test__syscall_openat_tp_fields(void) · line 48
Quoted 2 lines
tools/perf/tests/openat-syscall-tp-fields.c +1
-1- evlist->threads->map[0 ] =getpid (); +thread_map__pid (evlist->threads,0 ) =getpid ();So this 'function(parms) = something' idiom looks ugly/unfamiliar, can't we keep using:
evlist->thread->map[0].pid = getpid();
hum, I like it more than above line.. what's ugly about that assignment?
I'm adding thread_map__comm to access new 'comm' member, so I wanted to introduce easy accessors for both members
get/set functions seem like overkill.. we could use upper case to state that it's a macro:
THREAD_MAP__PID(evlist->threads, 0) = getpid();
anyway I can keep the original way if you insist ;-)
jirka
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in Please read the FAQ at http://www.tux.org/lkml/
Arnaldo Carvalho de Melo
maintainerRe: [PATCH 01/26] perf tools: Change thread_map::map into struct
Em Sat, Jun 20, 2015 at 12:05:31AM +0200, Jiri Olsa escreveu:
Quoted 62 lines · Arnaldo Carvalho de Melo
Quoted 48 lines
Em Thu, Jun 18, 2015 at 11:48:40PM +0200, Jiri Olsa escreveu:
Quoted 47 lines
We need to store command names with the pid. Changing map to be struct holding pid. Process name is coming in shortly.
Signed-off-by Jiri Olsa <[email protected]>--- tools/perf/builtin-trace.c | 4 ++-- tools/perf/tests/openat-syscall-tp-fields.c | 2 +- tools/perf/util/auxtrace.c | 4 ++-- tools/perf/util/event.c | 6 +++--- tools/perf/util/evlist.c | 4 ++-- tools/perf/util/evsel.c | 2 +- tools/perf/util/thread_map.c | 22 +++++++++++----------- tools/perf/util/thread_map.h | 8 +++++++- 8 files changed, 29 insertions(+), 23 deletions(-)tools/perf/builtin-trace.c +2
-2@@ -2324,7 +2324,7 @@ static int trace__run(struct trace *trace, int argc, const char **argv)*/ if (trace->filter_pids.nr >0 ) err =perf_evlist__set_filter_pids (evlist, trace->filter_pids.nr, trace->filter_pids.entries); -else if (evlist->threads->map[0 ] ==-1 ) +else if (thread_map__pid (evlist->threads,0 ) ==-1 ) err =perf_evlist__set_filter_pid (evlist,getpid ());if (err <0 ) {@@ -2342,7 +2342,7 @@ static int trace__run(struct trace *trace, int argc, const char **argv)if (forks)perf_evlist__start_workload (evlist); - trace->multiple_threads = evlist->threads->map[0 ] ==-1 || + trace->multiple_threads =thread_map__pid (evlist->threads,0 ) ==-1 || evlist->threads->nr >1 ||perf_evlist__first (evlist)->attr.inherit; again:tools/perf/tests/openat-syscall-tp-fields.c +0
-0@@ -45,7 +45,7 @@ int test__syscall_openat_tp_fields(void)perf_evsel__config (evsel, &opts);Quoted 7 lines
tools/perf/tests/openat-syscall-tp-fields.c int test__syscall_openat_tp_fields(void) · line 48
Quoted 2 lines
tools/perf/tests/openat-syscall-tp-fields.c +1
-1- evlist->threads->map[0 ] =getpid (); +thread_map__pid (evlist->threads,0 ) =getpid ();So this 'function(parms) = something' idiom looks ugly/unfamiliar, can't we keep using:
evlist->thread->map[0].pid = getpid();hum, I like it more than above line.. what's ugly about that assignment?
I'm adding
thread_map__commto access new 'comm' member, so I wanted to introduce easy accessors for both members
Quoted 6 lines
get/set functions seem like overkill.. we could use upper case to state that it's a macro:
THREAD_MAP__PID(evlist->threads, 0) = getpid();anyway I can keep the original way if you insist ;-)
I really think that
foo(a, b, c) = bla;
is ugly :-\
*foo(a, b, c) = bla;
Is uglier tho, bored right now to go beyond aesthetics tho :-\
- Arnaldo
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH 01/26] perf tools: Change thread_map::map into struct
On Mon, Jun 22, 2015 at 11:40:16AM -0300, Arnaldo Carvalho de Melo wrote:
SNIP
Quoted 27 lines
Quoted 18 lines
Quoted 5 lines
Quoted 5 lines
+++
b/tools/perf/tests/openat-syscall-tp-fields.ctools/perf/tests/openat-syscall-tp-fields.c +0
-0@@ -45,7 +45,7 @@ int test__syscall_openat_tp_fields(void)perf_evsel__config (evsel, &opts);Quoted 7 lines
tools/perf/tests/openat-syscall-tp-fields.c int test__syscall_openat_tp_fields(void) · line 48
Quoted 2 lines
tools/perf/tests/openat-syscall-tp-fields.c +1
-1- evlist->threads->map[0 ] =getpid (); +thread_map__pid (evlist->threads,0 ) =getpid ();So this 'function(parms) = something' idiom looks ugly/unfamiliar, can't we keep using:
evlist->thread->map[0].pid = getpid();hum, I like it more than above line.. what's ugly about that assignment?
I'm adding
thread_map__commto access new 'comm' member, so I wanted to introduce easy accessors for both membersQuoted 6 lines
get/set functions seem like overkill.. we could use upper case to state that it's a macro:
THREAD_MAP__PID(evlist->threads, 0) = getpid();anyway I can keep the original way if you insist ;-)
I really think that
Quoted 7 lines
foo(a, b, c) = bla;is ugly :-\
*foo(a, b, c) = bla;Is uglier tho, bored right now to go beyond aesthetics tho :-\
discussed on irc and decided to go with:
thread_map__pid(threads, i) // to get pid
thread_map__set_pid(threads, i, pid) // to set pid
thread_map__comm(threads, i) // to get comm
thread_map__set_comm(threads, i, comm) // to set comm
jirka
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in Please read the FAQ at http://www.tux.org/lkml/
Arnaldo Carvalho de Melo
maintainerRe: [PATCH 01/26] perf tools: Change thread_map::map into struct
Em Mon, Jun 22, 2015 at 07:37:45PM +0200, Jiri Olsa escreveu:
Quoted 18 lines · Arnaldo Carvalho de Melo
Quoted 9 lines
Quoted 6 lines
get/set functions seem like overkill.. we could use upper case to state that it's a macro:
THREAD_MAP__PID(evlist->threads, 0) = getpid();anyway I can keep the original way if you insist ;-)
I really think that
Quoted 7 lines
foo(a, b, c) = bla;is ugly :-\
*foo(a, b, c) = bla;Is uglier tho, bored right now to go beyond aesthetics tho :-\
Quoted 7 lines
discussed on irc and decided to go with:
thread_map__pid(threads, i)// to get pid
thread_map__set_pid(threads, i, pid)// to set pid
thread_map__comm(threads, i)// to get comm
thread_map__set_comm(threads, i, comm)// to set comm
Ack.
- Arnaldo
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in Please read the FAQ at http://www.tux.org/lkml/
Jiri Olsa
reviewerPATCH v3 2/26 perf tools: Add comm string into struct thread_map
In reply to Jiri OlsaAdding support to hold comm name together with pids in 'struct thread_map'. It will be useful for --per-task option to display task pid together with task name.
Getting the task name from /proc/$pid/comm.
--- tools/perf/util/python-ext-sources | 1 + tools/perf/util/thread_map.c | 63 +++++++++++++++++++++++++++++++++++--- tools/perf/util/thread_map.h | 2 ++ 3 files changed, 62 insertions(+), 4 deletions(-)
tools/perf/util/python-ext-sources +1 -0
@@ -20,3 +20,4 @@ util/stat.c util/strlist.c util/trace-event.c ../../lib/rbtree.c +util/string.c
tools/perf/util/thread_map.c +59 -4
121 lines not on this page · raw message
tools/perf/util/thread_map.h +2 -0
@@ -6,6 +6,7 @@struct thread_map_data {pid_t pid; +char *comm; };struct thread_map {
@@ -14,6 +15,7 @@ struct thread_map { };#define thread_map__pid (__m, __t) __m->map[__t].pid +#define thread_map__comm (__m, __t) __m->map[__t].commstruct thread_map *thread_map__new_dummy (void );struct thread_map *thread_map__new_by_pid (pid_t pid);
Signature · 1 line
1.9.3
Jiri Olsa
reviewerPATCH v3 3/26 perf tools: Add reference counting for cpu_map object
In reply to Jiri OlsaAdding refference counting for cpu_map object, so
it could be easily shared among other objects.
Using cpu_map__put instead cpu_map__delete and making cpu_map__delete static.
--- tools/perf/tests/code-reading.c | 2 +- tools/perf/tests/keep-tracking.c | 2 +- tools/perf/tests/mmap-basic.c | 2 +- tools/perf/tests/switch-tracking.c | 2 +- tools/perf/util/cpumap.c | 26 ++++++++++++++++++++++++-- tools/perf/util/cpumap.h | 6 +++++- tools/perf/util/evlist.c | 4 ++-- tools/perf/util/evsel.c | 1 + tools/perf/util/parse-events.c | 5 ++++- tools/perf/util/python.c | 2 +- tools/perf/util/record.c | 4 ++-- tools/perf/util/session.c | 2 +- tools/perf/util/svghelper.c | 2 +- 13 files changed, 45 insertions(+), 15 deletions(-)
tools/perf/tests/code-reading.c +1 -1
@@ -545,7 +545,7 @@ out_err:if (evlist) {perf_evlist__delete (evlist); }else { -cpu_map__delete (cpus); +cpu_map__put (cpus);thread_map__delete (threads); }machines__destroy_kernel_maps (&machines);
tools/perf/tests/keep-tracking.c +1 -1
@@ -144,7 +144,7 @@ out_err:perf_evlist__disable (evlist);perf_evlist__delete (evlist); }else { -cpu_map__delete (cpus); +cpu_map__put (cpus);thread_map__delete (threads); }
tools/perf/tests/mmap-basic.c +1 -1
@@ -140,7 +140,7 @@ out_delete_evlist: cpus =NULL ; threads =NULL ; out_free_cpus: -cpu_map__delete (cpus); +cpu_map__put (cpus); out_free_threads:thread_map__delete (threads);return err;
tools/perf/tests/switch-tracking.c +1 -1
@@ -560,7 +560,7 @@ out:perf_evlist__disable (evlist);perf_evlist__delete (evlist); }else { -cpu_map__delete (cpus); +cpu_map__put (cpus);thread_map__delete (threads); }
tools/perf/util/cpumap.c +24 -2
@@ -5,6 +5,7 @@#include <assert.h> #include <stdio.h> #include <stdlib.h> +#include "asm/bug.h" static struct cpu_map *cpu_map__default_new (void ) {
@@ -22,6 +23,7 @@ static struct cpu_map *cpu_map__default_new(void) cpus->map[i] = i; cpus->nr = nr_cpus; +atomic_set (&cpus->refcnt,1 ); }return cpus;
@@ -35,6 +37,7 @@ static struct cpu_map *cpu_map__trim_new(int nr_cpus, int *tmp_cpus)if (cpus !=NULL ) { cpus->nr = nr_cpus;memcpy (cpus->map, tmp_cpus, payload_size); +atomic_set (&cpus->refcnt,1 ); }return cpus;
@@ -194,14 +197,32 @@ struct cpu_map *cpu_map__dummy_new(void)if (cpus !=NULL ) { cpus->nr =1 ; cpus->map[0 ] =-1 ; +atomic_set (&cpus->refcnt,1 ); }return cpus; } -void cpu_map__delete (struct cpu_map *map) +static void cpu_map__delete (struct cpu_map *map) { -free (map); +if (map) { +WARN_ONCE (atomic_read (&map->refcnt) !=0 , +"cpu map refcnt disbalanced\n" ); +free (map); + } +} + +struct cpu_map *cpu_map__get (struct cpu_map *map) +{ +if (map) +atomic_inc (&map->refcnt); +return map; +} + +void cpu_map__put (struct cpu_map *map) +{ +if (map &&atomic_dec_and_test (&map->refcnt)) +cpu_map__delete (map); }int cpu_map__get_socket (struct cpu_map *map,int idx)
@@ -263,6 +284,7 @@ static int cpu_map__build_map(struct cpu_map *cpus, struct cpu_map **res,/* ensure we process id in increasing order */ qsort (c->map, c->nr,sizeof (int ), cmp_ids); +atomic_set (&cpus->refcnt,1 ); *res = c;return 0 ; }
tools/perf/util/cpumap.h +5 -1
@@ -3,18 +3,19 @@#include <stdio.h> #include <stdbool.h> +#include <linux/atomic.h> #include "perf.h" #include "util/debug.h" struct cpu_map { +atomic_t refcnt;int nr;int map[]; };struct cpu_map *cpu_map__new (const char *cpu_list);struct cpu_map *cpu_map__dummy_new (void ); -void cpu_map__delete (struct cpu_map *map);struct cpu_map *cpu_map__read (FILE *file);size_t cpu_map__fprintf (struct cpu_map *map,FILE *fp);int cpu_map__get_socket (struct cpu_map *map,int idx);
@@ -22,6 +23,9 @@ int cpu_map__get_core(struct cpu_map *map, int idx);int cpu_map__build_socket_map (struct cpu_map *cpus,struct cpu_map **sockp);int cpu_map__build_core_map (struct cpu_map *cpus,struct cpu_map **corep); +struct cpu_map *cpu_map__get (struct cpu_map *map); +void cpu_map__put (struct cpu_map *map); +static inline int cpu_map__socket (struct cpu_map *sock,int s) {if (!sock || s > sock->nr || s <0 )
tools/perf/util/evlist.c +2 -2
@@ -114,7 +114,7 @@ void perf_evlist__delete(struct perf_evlist *evlist) {perf_evlist__munmap (evlist);perf_evlist__close (evlist); -cpu_map__delete (evlist->cpus); +cpu_map__put (evlist->cpus);thread_map__delete (evlist->threads); evlist->cpus =NULL ; evlist->threads =NULL ;
@@ -1353,7 +1353,7 @@ static int perf_evlist__create_syswide_maps(struct perf_evlist *evlist) out:return err; out_free_cpus: -cpu_map__delete (evlist->cpus); +cpu_map__put (evlist->cpus); evlist->cpus =NULL ; goto out; }
tools/perf/util/evsel.c +1 -0
@@ -885,6 +885,7 @@ void perf_evsel__exit(struct perf_evsel *evsel)perf_evsel__free_fd (evsel);perf_evsel__free_id (evsel);close_cgroup (evsel->cgrp); +cpu_map__put (evsel->cpus);zfree (&evsel->group_name);zfree (&evsel->name); perf_evsel__object.fini (evsel);
tools/perf/util/parse-events.c +4 -1
@@ -17,6 +17,7 @@#include "parse-events-flex.h" #include "pmu.h" #include "thread_map.h" +#include "cpumap.h" #include "asm/bug.h" #define MAX_NAME_LEN 100
@@ -285,7 +286,9 @@ __add_event(struct list_head *list, int *idx,if (!evsel)return NULL ; - evsel->cpus = cpus; +if (cpus) + evsel->cpus =cpu_map__get (cpus); +if (name) evsel->name =strdup (name);list_add_tail (&evsel->node, list);
tools/perf/util/python.c +1 -1
@@ -384,7 +384,7 @@ static int pyrf_cpu_map__init(struct pyrf_cpu_map *pcpus,static void pyrf_cpu_map__delete (struct pyrf_cpu_map *pcpus) { -cpu_map__delete (pcpus->cpus); +cpu_map__put (pcpus->cpus); pcpus->ob_type->tp_free ((PyObject *)pcpus); }
tools/perf/util/record.c +2 -2
@@ -64,7 +64,7 @@ static bool perf_probe_api(setup_probe_fn_t fn)if (!cpus)return false; cpu = cpus->map[0 ]; -cpu_map__delete (cpus); +cpu_map__put (cpus); do { ret = perf_do_probe_api(fn, cpu, try[i++]);
@@ -226,7 +226,7 @@ bool perf_evlist__can_select_event(struct perf_evlist *evlist, const char *str)struct cpu_map *cpus =cpu_map__new (NULL ); cpu = cpus ? cpus->map[0 ] :0 ; -cpu_map__delete (cpus); +cpu_map__put (cpus); }else { cpu = evlist->cpus->map[0 ]; }
tools/perf/util/session.c +1 -1
@@ -1860,7 +1860,7 @@ int perf_session__cpu_bitmap(struct perf_session *session, err =0 ; out_delete_map: -cpu_map__delete (map); +cpu_map__put (map);return err; }
tools/perf/util/svghelper.c +1 -1
@@ -748,7 +748,7 @@ static int str_to_bitmap(char *s, cpumask_t *b)set_bit (c,cpumask_bits (b)); } -cpu_map__delete (m); +cpu_map__put (m);return ret; }
Signature · 1 line
1.9.3
Jiri Olsa
reviewerPATCH v3 4/26 perf tools: Add reference counting for thread_map object
In reply to Jiri OlsaAdding refference counting for thread_map object, so it could be easily shared among other objects.
Using thread_map__put instead thread_map__delete and making thread_map__delete static.
--- tools/perf/tests/code-reading.c | 2 +- tools/perf/tests/keep-tracking.c | 2 +- tools/perf/tests/mmap-basic.c | 2 +- tools/perf/tests/mmap-thread-lookup.c | 2 +- tools/perf/tests/openat-syscall-all-cpus.c | 2 +- tools/perf/tests/openat-syscall.c | 2 +- tools/perf/tests/switch-tracking.c | 2 +- tools/perf/util/evlist.c | 4 ++-- tools/perf/util/python.c | 2 +- tools/perf/util/thread_map.c | 31 ++++++++++++++++++++++++++---- tools/perf/util/thread_map.h | 7 +++++-- 11 files changed, 42 insertions(+), 16 deletions(-)
tools/perf/tests/code-reading.c +1 -1
@@ -546,7 +546,7 @@ out_err:perf_evlist__delete (evlist); }else {cpu_map__put (cpus); -thread_map__delete (threads); +thread_map__put (threads); }machines__destroy_kernel_maps (&machines);machine__delete_threads (machine);
tools/perf/tests/keep-tracking.c +1 -1
@@ -145,7 +145,7 @@ out_err:perf_evlist__delete (evlist); }else {cpu_map__put (cpus); -thread_map__delete (threads); +thread_map__put (threads); }return err;
tools/perf/tests/mmap-basic.c +1 -1
@@ -142,6 +142,6 @@ out_delete_evlist: out_free_cpus:cpu_map__put (cpus); out_free_threads: -thread_map__delete (threads); +thread_map__put (threads);return err; }
tools/perf/tests/mmap-thread-lookup.c +1 -1
@@ -143,7 +143,7 @@ static int synth_process(struct machine *machine) perf_event__process, machine, 0); -thread_map__delete (map); +thread_map__put (map);return err; }
tools/perf/tests/openat-syscall-all-cpus.c +1 -1
@@ -111,6 +111,6 @@ out_close_fd: out_evsel_delete:perf_evsel__delete (evsel); out_thread_map_delete: -thread_map__delete (threads); +thread_map__put (threads);return err; }
tools/perf/tests/openat-syscall.c +1 -1
@@ -56,6 +56,6 @@ out_close_fd: out_evsel_delete:perf_evsel__delete (evsel); out_thread_map_delete: -thread_map__delete (threads); +thread_map__put (threads);return err; }
tools/perf/tests/switch-tracking.c +1 -1
@@ -561,7 +561,7 @@ out:perf_evlist__delete (evlist); }else {cpu_map__put (cpus); -thread_map__delete (threads); +thread_map__put (threads); }return err;
tools/perf/util/evlist.c +2 -2
@@ -115,7 +115,7 @@ void perf_evlist__delete(struct perf_evlist *evlist)perf_evlist__munmap (evlist);perf_evlist__close (evlist);cpu_map__put (evlist->cpus); -thread_map__delete (evlist->threads); +thread_map__put (evlist->threads); evlist->cpus =NULL ; evlist->threads =NULL ;perf_evlist__purge (evlist);
@@ -1120,7 +1120,7 @@ int perf_evlist__create_maps(struct perf_evlist *evlist, struct target *target)return 0 ; out_delete_threads: -thread_map__delete (evlist->threads); +thread_map__put (evlist->threads); evlist->threads =NULL ;return -1 ; }
tools/perf/util/python.c +1 -1
@@ -453,7 +453,7 @@ static int pyrf_thread_map__init(struct pyrf_thread_map *pthreads,static void pyrf_thread_map__delete (struct pyrf_thread_map *pthreads) { -thread_map__delete (pthreads->threads); +thread_map__put (pthreads->threads); pthreads->ob_type->tp_free ((PyObject *)pthreads); }
tools/perf/util/thread_map.c +27 -4
@@ -9,6 +9,7 @@#include "strlist.h" #include <string.h> #include <api/fs/fs.h> +#include "asm/bug.h" #include "thread_map.h" #include "util.h" #include "debug.h"
@@ -89,6 +90,7 @@ struct thread_map *thread_map__new_by_pid(pid_t pid)comm_init (threads, i); } threads->nr = items; +atomic_set (&threads->refcnt,1 ); }for (i=0 ; i<items; i++)
@@ -106,6 +108,7 @@ struct thread_map *thread_map__new_by_tid(pid_t tid)thread_map__pid (threads,0 ) = tid; threads->nr =1 ;comm_init (threads,0 ); +atomic_set (&threads->refcnt,1 ); }return threads;
@@ -127,6 +130,7 @@ struct thread_map *thread_map__new_by_uid(uid_t uid) goto out_free_threads; threads->nr =0 ; +atomic_set (&threads->refcnt,1 );while (!readdir_r (proc, &dirent, &next) && next) {char *end;
@@ -256,6 +260,8 @@ static struct thread_map *thread_map__new_by_pid_str(const char *pid_str) out:strlist__delete (slist); +if (threads) +atomic_set (&threads->refcnt,1 );return threads; out_free_namelist:
@@ -276,6 +282,7 @@ struct thread_map *thread_map__new_dummy(void)thread_map__pid (threads,0 ) =-1 ; threads->nr =1 ;comm_init (threads,0 ); +atomic_set (&threads->refcnt,1 ); }return threads; }
@@ -319,6 +326,8 @@ static struct thread_map *thread_map__new_by_tid_str(const char *tid_str)comm_init (threads, ntasks -1 ); } out: +if (threads) +atomic_set (&threads->refcnt,1 );return threads; out_free_threads:
@@ -338,16 +347,30 @@ struct thread_map *thread_map__new_str(const char *pid, const char *tid,return thread_map__new_by_tid_str (tid); } -void thread_map__delete (struct thread_map *threads) +static void thread_map__delete (struct thread_map *threads) { -int i; -if (threads) { +int i; + +WARN_ONCE (atomic_read (&threads->refcnt) !=0 , +"thread map refcnt disbalanced\n" );for (i =0 ; i < threads->nr; i++)free (thread_map__comm (threads, i)); +free (threads); } +} -free (threads); +struct thread_map *thread_map__get (struct thread_map *map) +{ +if (map) +atomic_inc (&map->refcnt); +return map; +} + +void thread_map__put (struct thread_map *map) +{ +if (map &&atomic_dec_and_test (&map->refcnt)) +thread_map__delete (map); }size_t thread_map__fprintf (struct thread_map *threads,FILE *fp)
tools/perf/util/thread_map.h +5 -2
@@ -3,6 +3,7 @@#include <sys/types.h> #include <stdio.h> +#include <linux/atomic.h> struct thread_map_data {pid_t pid;
@@ -10,6 +11,7 @@ struct thread_map_data { };struct thread_map { +atomic_t refcnt;int nr;struct thread_map_data map[]; };
@@ -23,11 +25,12 @@ 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__get (struct thread_map *map); +void thread_map__put (struct thread_map *map); +struct thread_map *thread_map__new_str (const char *pid,const char *tid,uid_t uid); -void thread_map__delete (struct thread_map *threads); -size_t thread_map__fprintf (struct thread_map *threads,FILE *fp);static inline int thread_map__nr (struct thread_map *threads)
Signature · 1 line
1.9.3
Jiri Olsa
reviewerPATCH v3 5/26 perf tools: Propagate cpu maps through the evlist
In reply to Jiri OlsaPropagate evlist's cpu_map object through all the evsel objects, while keeping already configured evsel->cpus.
It'll be handy to access evsel's cpus directly
in following patches.
--- tools/perf/util/evlist.c | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-)
tools/perf/util/evlist.c +24 -1
@@ -1101,6 +1101,29 @@ int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages,return perf_evlist__mmap_ex (evlist, pages, overwrite,0 , false); } +static int perf_evlist__propagate_maps (struct perf_evlist *evlist, +struct target *target) +{ +struct perf_evsel *evsel; + +evlist__for_each (evlist, evsel) { +/* +* We already have cpus for evsel (via PMU sysfs) so +* keep it, if there's no target cpu list defined. +*/ +if (evsel->cpus && target->cpu_list) +cpu_map__put (evsel->cpus); + +if (!evsel->cpus || target->cpu_list) + evsel->cpus =cpu_map__get (evlist->cpus); + +if (!evsel->cpus) +return -ENOMEM ; + } + +return 0 ; +} +int perf_evlist__create_maps (struct perf_evlist *evlist,struct target *target) { evlist->threads = thread_map__new_str(target->pid, target->tid,
@@ -1117,7 +1140,7 @@ int perf_evlist__create_maps(struct perf_evlist *evlist, struct target *target)if (evlist->cpus ==NULL ) goto out_delete_threads; -return 0 ; +return perf_evlist__propagate_maps (evlist, target); out_delete_threads:thread_map__put (evlist->threads);
Signature · 1 line
1.9.3
Jiri Olsa
reviewerPATCH v3 6/26 perf tools: Propagate thread maps through the evlist
In reply to Jiri OlsaPropagate evlist's thread_map object through all the evsel objects.
It'll be handy to access evsel's threads directly in following patches. The reason is there's no link from evsel to evlist which hold threads map now and evlist is not always available.
--- tools/perf/util/evlist.c | 4 +++- tools/perf/util/evsel.c | 1 + tools/perf/util/evsel.h | 1 + 3 files changed, 5 insertions(+), 1 deletion(-)
tools/perf/util/evlist.c +3 -1
@@ -1117,7 +1117,9 @@ static int perf_evlist__propagate_maps(struct perf_evlist *evlist,if (!evsel->cpus || target->cpu_list) evsel->cpus =cpu_map__get (evlist->cpus); -if (!evsel->cpus) + evsel->threads =thread_map__get (evlist->threads); + +if (!evsel->cpus || !evsel->threads)return -ENOMEM ; }
tools/perf/util/evsel.c +1 -0
@@ -886,6 +886,7 @@ void perf_evsel__exit(struct perf_evsel *evsel)perf_evsel__free_id (evsel);close_cgroup (evsel->cgrp);cpu_map__put (evsel->cpus); +thread_map__put (evsel->threads);zfree (&evsel->group_name);zfree (&evsel->name); perf_evsel__object.fini (evsel);
tools/perf/util/evsel.h +1 -0
@@ -82,6 +82,7 @@ struct perf_evsel {struct cgroup_sel *cgrp;void *handler;struct cpu_map *cpus; +struct thread_map *threads;unsigned int sample_size;int id_pos;int is_pos;
Signature · 1 line
1.9.3
Jiri Olsa
reviewerPATCH v3 7/26 perf tools: Make perf_evsel__(nr_)cpus generic
In reply to Jiri OlsaBecause we now propagate all evlist's cpu_maps and thread_map objects through all evsels, the perf_evsel__(nr_)cpus no longer need to be specific to stat object and check evlist and target objects.
--- tools/perf/builtin-stat.c | 10 ---------- tools/perf/util/evsel.h | 11 +++++++++++ 2 files changed, 11 insertions(+), 10 deletions(-)
tools/perf/builtin-stat.c +0 -10
@@ -141,16 +141,6 @@ static inline void diff_timespec(struct timespec *r, struct timespec *a, } } -static inline struct cpu_map *perf_evsel__cpus (struct perf_evsel *evsel) -{ -return (evsel->cpus && !target.cpu_list) ? evsel->cpus : evsel_list->cpus; -} - -static inline int perf_evsel__nr_cpus (struct perf_evsel *evsel) -{ -return perf_evsel__cpus (evsel)->nr; -} -static void perf_evsel__reset_stat_priv (struct perf_evsel *evsel) {int i;
tools/perf/util/evsel.h +11 -0
@@ -8,6 +8,7 @@#include <linux/types.h> #include "xyarray.h" #include "symbol.h" +#include "cpumap.h" struct perf_counts_values { union {
@@ -114,6 +115,16 @@ struct thread_map;struct perf_evlist ;struct record_opts ; +static inline struct cpu_map *perf_evsel__cpus (struct perf_evsel *evsel) +{ +return evsel->cpus; +} + +static inline int perf_evsel__nr_cpus (struct perf_evsel *evsel) +{ +return perf_evsel__cpus (evsel)->nr; +} +void perf_counts_values__scale (struct perf_counts_values *count,bool scale,s8 *pscaled);
Signature · 1 line
1.9.3
Jiri Olsa
reviewerPATCH v3 8/26 perf tests: Add thread_map object tests
In reply to Jiri OlsaAdding thread_map object tests for comm name values.
--- tools/perf/tests/Build | 1 + tools/perf/tests/builtin-test.c | 4 ++++ tools/perf/tests/tests.h | 1 + tools/perf/tests/thread-map.c | 28 ++++++++++++++++++++++++++++ 4 files changed, 34 insertions(+) create mode 100644 tools/perf/tests/thread-map.c
tools/perf/tests/Build +1 -0
@@ -31,6 +31,7 @@ perf-y += code-reading.o perf-y += sample-parsing.o perf-y += parse-no-sample-id-all.o perf-y += kmod-path.o +perf-y += thread-map.o perf-$(CONFIG_X86) += perf-time-to-tsc.o
tools/perf/tests/builtin-test.c +4 -0
@@ -171,6 +171,10 @@ static struct test { .func = test__kmod_path__parse, }, { + .desc = "Test thread map", + .func = test__thread_map, + }, + { .func = NULL, }, };
tools/perf/tests/tests.h +1 -0
@@ -61,6 +61,7 @@ int test__switch_tracking(void);int test__fdarray__filter (void );int test__fdarray__add (void );int test__kmod_path__parse (void ); +int test__thread_map (void );#if defined(__x86_64__) || defined(__i386__) || defined(__arm__) || defined(__aarch64__)#ifdef HAVE_DWARF_UNWIND_SUPPORT
tools/perf/tests/thread-map.c new file +28 -0
@@ -0,0 +1,28 @@ +#include <sys/types.h> +#include <unistd.h> +#include "tests.h" +#include "thread_map.h" +#include "debug.h" + +int test__thread_map (void ) +{ +struct thread_map *map; + +/* test map on current pid */ + map =thread_map__new_by_pid (getpid ()); +TEST_ASSERT_VAL ("wrong nr" , map->nr ==1 ); +TEST_ASSERT_VAL ("wrong pid" , +thread_map__pid (map,0 ) ==getpid ()); +TEST_ASSERT_VAL ("wrong pid" , + !strcmp (thread_map__comm (map,0 ),"perf" )); +thread_map__put (map); + +/* test dummy pid */ + map =thread_map__new_dummy (); +TEST_ASSERT_VAL ("wrong nr" , map->nr ==1 ); +TEST_ASSERT_VAL ("wrong pid" ,thread_map__pid (map,0 ) ==-1 ); +TEST_ASSERT_VAL ("wrong pid" , + !strcmp (thread_map__comm (map,0 ),"dummy" )); +thread_map__put (map); +return 0 ; +}
Signature · 1 line
1.9.3
Jiri Olsa
reviewerPATCH v3 9/26 perf stat: Introduce perf_counts function
In reply to Jiri OlsaIntroducing perf_counts function, that returns 'struct perf_counts_values' pointer for given cpu.
Also moving perf_counts* structures into stat.h.
--- tools/perf/builtin-stat.c | 14 +++++++------- tools/perf/tests/openat-syscall-all-cpus.c | 4 ++-- tools/perf/tests/openat-syscall.c | 2 +- tools/perf/util/evsel.c | 6 +++--- tools/perf/util/evsel.h | 18 +----------------- tools/perf/util/stat.h | 23 +++++++++++++++++++++++ 6 files changed, 37 insertions(+), 30 deletions(-)
tools/perf/builtin-stat.c +7 -7
@@ -316,7 +316,7 @@ static int read_cb(struct perf_evsel *evsel, int cpu, int thread __maybe_unused,if (!evsel->snapshot)perf_evsel__compute_deltas (evsel, cpu, count);perf_counts_values__scale (count, scale,NULL ); - evsel->counts->cpu[cpu] = *count; + *perf_counts (evsel->counts, cpu) = *count;if (aggr_mode ==AGGR_NONE )perf_stat__update_shadow_stats (evsel, count->values, cpu);break ;
@@ -805,9 +805,9 @@ static void print_aggr(char *prefix) s2 =aggr_get_id (evsel_list->cpus, cpu2);if (s2 != id)continue ; - val += counter->counts->cpu[cpu].val; - ena += counter->counts->cpu[cpu].ena; - run += counter->counts->cpu[cpu].run; + val +=perf_counts (counter->counts, cpu)->val; + ena +=perf_counts (counter->counts, cpu)->ena; + run +=perf_counts (counter->counts, cpu)->run; nr++; }if (prefix)
@@ -915,9 +915,9 @@ static void print_counter(struct perf_evsel *counter, char *prefix)int cpu;for (cpu =0 ; cpu <perf_evsel__nr_cpus (counter); cpu++) { - val = counter->counts->cpu[cpu].val; - ena = counter->counts->cpu[cpu].ena; - run = counter->counts->cpu[cpu].run; + val =perf_counts (counter->counts, cpu)->val; + ena =perf_counts (counter->counts, cpu)->ena; + run =perf_counts (counter->counts, cpu)->run;if (prefix)fprintf (output,"%s" , prefix);
tools/perf/tests/openat-syscall-all-cpus.c +2 -2
@@ -98,9 +98,9 @@ int test__openat_syscall_event_on_all_cpus(void) } expected = nr_openat_calls + cpu; -if (evsel->counts->cpu[cpu].val != expected) { +if (perf_counts (evsel->counts, cpu)->val != expected) {pr_debug ("perf_evsel__read_on_cpu: expected to intercept %d calls on cpu %d, got %" PRIu64"\n" , - expected, cpus->map[cpu], evsel->counts->cpu[cpu].val); + expected, cpus->map[cpu],perf_counts (evsel->counts, cpu)->val); err =-1 ; } }
tools/perf/tests/openat-syscall.c +1 -1
@@ -44,7 +44,7 @@ int test__openat_syscall_event(void) goto out_close_fd; } -if (evsel->counts->cpu[0 ].val != nr_openat_calls) { +if (perf_counts (evsel->counts,0 )->val != nr_openat_calls) {pr_debug ("perf_evsel__read_on_cpu: expected to intercept %d calls, got %" PRIu64"\n" , nr_openat_calls, evsel->counts->cpu[0 ].val); goto out_close_fd;
tools/perf/util/evsel.c +3 -3
@@ -910,8 +910,8 @@ void perf_evsel__compute_deltas(struct perf_evsel *evsel, int cpu, tmp = evsel->prev_raw_counts->aggr; evsel->prev_raw_counts->aggr = *count; }else { - tmp = evsel->prev_raw_counts->cpu[cpu]; - evsel->prev_raw_counts->cpu[cpu] = *count; + tmp = *perf_counts (evsel->prev_raw_counts, cpu); + *perf_counts (evsel->prev_raw_counts, cpu) = *count; } count->val = count->val - tmp.val;
@@ -972,7 +972,7 @@ int __perf_evsel__read_on_cpu(struct perf_evsel *evsel,perf_evsel__compute_deltas (evsel, cpu, &count);perf_counts_values__scale (&count, scale,NULL ); - evsel->counts->cpu[cpu] = count; + *perf_counts (evsel->counts, cpu) = count;return 0 ; }
tools/perf/util/evsel.h +1 -17
@@ -9,23 +9,7 @@#include "xyarray.h" #include "symbol.h" #include "cpumap.h" - -struct perf_counts_values { -union { -struct { -u64 val; -u64 ena; -u64 run; - }; -u64 values[3 ]; - }; -}; - -struct perf_counts { -s8 scaled; -struct perf_counts_values aggr; -struct perf_counts_values cpu[]; -}; +#include "stat.h" struct perf_evsel ;
tools/perf/util/stat.h +23 -0
@@ -31,6 +31,29 @@ enum aggr_mode { AGGR_CORE, }; +struct perf_counts_values { +union { +struct { +u64 val; +u64 ena; +u64 run; + }; +u64 values[3 ]; + }; +}; + +struct perf_counts { +s8 scaled; +struct perf_counts_values aggr; +struct perf_counts_values cpu[]; +}; + +static inline struct perf_counts_values * +perf_counts (struct perf_counts *counts,int cpu) +{ +return &counts->cpu[cpu]; +} +void update_stats (struct stats *stats,u64 val);double avg_stats (struct stats *stats);double stddev_stats (struct stats *stats);
Signature · 1 line
1.9.3
Jiri Olsa
reviewerPATCH v3 10/26 perf stat: Use xyarray for cpu evsel counts
In reply to Jiri OlsaSwitching single dimensional array of 'struct perf_counts_values' with xyarray object, so we could store thread dimension counts.
--- tools/perf/builtin-stat.c | 2 +- tools/perf/tests/openat-syscall.c | 2 +- tools/perf/util/stat.c | 31 ++++++++++++++++++++++--------- tools/perf/util/stat.h | 7 ++++--- 4 files changed, 28 insertions(+), 14 deletions(-)
tools/perf/builtin-stat.c +1 -1
@@ -218,7 +218,7 @@ static void perf_stat__reset_stats(struct perf_evlist *evlist)evlist__for_each (evlist, evsel) {perf_evsel__reset_stat_priv (evsel); -perf_evsel__reset_counts (evsel,perf_evsel__nr_cpus (evsel)); +perf_evsel__reset_counts (evsel); }perf_stat__reset_shadow_stats ();
tools/perf/tests/openat-syscall.c +1 -1
@@ -46,7 +46,7 @@ int test__openat_syscall_event(void)if (perf_counts (evsel->counts,0 )->val != nr_openat_calls) {pr_debug ("perf_evsel__read_on_cpu: expected to intercept %d calls, got %" PRIu64"\n" , - nr_openat_calls, evsel->counts->cpu[0 ].val); + nr_openat_calls,perf_counts (evsel->counts,0 )->val); goto out_close_fd; }
tools/perf/util/stat.c +22 -9
@@ -97,26 +97,39 @@ void perf_stat_evsel_id_init(struct perf_evsel *evsel)struct perf_counts *perf_counts__new (int ncpus) { -int size =sizeof (struct perf_counts ) + - ncpus *sizeof (struct perf_counts_values ); +struct perf_counts *counts =zalloc (sizeof (*counts)); -return zalloc (size); +if (counts) { +struct xyarray *cpu; + + cpu =xyarray__new (ncpus,1 ,sizeof (struct perf_counts_values )); +if (!cpu) { +free (counts); +return NULL ; + } + + counts->cpu = cpu; + } + +return counts; }void perf_counts__delete (struct perf_counts *counts) { -free (counts); +if (counts) { +xyarray__delete (counts->cpu); +free (counts); + } } -static void perf_counts__reset (struct perf_counts *counts,int ncpus) +static void perf_counts__reset (struct perf_counts *counts) { -memset (counts,0 , (sizeof (*counts) + - (ncpus *sizeof (struct perf_counts_values )))); +xyarray__reset (counts->cpu); } -void perf_evsel__reset_counts (struct perf_evsel *evsel,int ncpus) +void perf_evsel__reset_counts (struct perf_evsel *evsel) { -perf_counts__reset (evsel->counts, ncpus); +perf_counts__reset (evsel->counts); }int perf_evsel__alloc_counts (struct perf_evsel *evsel,int ncpus)
tools/perf/util/stat.h +4 -3
@@ -3,6 +3,7 @@#include <linux/types.h> #include <stdio.h> +#include "xyarray.h" struct stats {
@@ -45,13 +46,13 @@ struct perf_counts_values {struct perf_counts {s8 scaled;struct perf_counts_values aggr; -struct perf_counts_values cpu[]; +struct xyarray *cpu; };static inline struct perf_counts_values *perf_counts (struct perf_counts *counts,int cpu) { -return &counts->cpu[cpu]; +return xyarray__entry (counts->cpu, cpu,0 ); }void update_stats (struct stats *stats,u64 val);
@@ -88,7 +89,7 @@ void perf_stat__print_shadow_stats(FILE *out, struct perf_evsel *evsel,struct perf_counts *perf_counts__new (int ncpus);void perf_counts__delete (struct perf_counts *counts); -void perf_evsel__reset_counts (struct perf_evsel *evsel,int ncpus); +void perf_evsel__reset_counts (struct perf_evsel *evsel);int perf_evsel__alloc_counts (struct perf_evsel *evsel,int ncpus);void perf_evsel__free_counts (struct perf_evsel *evsel);#endif
Signature · 1 line
1.9.3
Jiri Olsa
reviewerPATCH v3 11/26 perf stat: Make stats work over the thread dimension
In reply to Jiri OlsaNow that we have space for thread dimension counts, let's store it.
--- tools/perf/builtin-stat.c | 32 +++++++++++++++++------------- tools/perf/tests/openat-syscall-all-cpus.c | 6 +++--- tools/perf/tests/openat-syscall.c | 4 ++-- tools/perf/util/evsel.c | 12 +++++------ tools/perf/util/evsel.h | 2 +- tools/perf/util/stat.c | 8 ++++---- tools/perf/util/stat.h | 8 ++++---- 7 files changed, 38 insertions(+), 34 deletions(-)
tools/perf/builtin-stat.c +18 -14
@@ -166,11 +166,12 @@ static void perf_evsel__free_stat_priv(struct perf_evsel *evsel)zfree (&evsel->priv); } -static int perf_evsel__alloc_prev_raw_counts (struct perf_evsel *evsel) +static int perf_evsel__alloc_prev_raw_counts (struct perf_evsel *evsel, +int ncpus,int nthreads) {struct perf_counts *counts; - counts =perf_counts__new (perf_evsel__nr_cpus (evsel)); + counts =perf_counts__new (ncpus, nthreads);if (counts) evsel->prev_raw_counts = counts;
@@ -197,11 +198,14 @@ static void perf_evlist__free_stats(struct perf_evlist *evlist)static int perf_evlist__alloc_stats (struct perf_evlist *evlist,bool alloc_raw) {struct perf_evsel *evsel; +int nthreads =thread_map__nr (evsel_list->threads);evlist__for_each (evlist, evsel) { +int ncpus =perf_evsel__nr_cpus (evsel); +if (perf_evsel__alloc_stat_priv (evsel) <0 || -perf_evsel__alloc_counts (evsel,perf_evsel__nr_cpus (evsel)) <0 || - (alloc_raw &&perf_evsel__alloc_prev_raw_counts (evsel) <0 )) +perf_evsel__alloc_counts (evsel, ncpus, nthreads) <0 || + (alloc_raw &&perf_evsel__alloc_prev_raw_counts (evsel, ncpus, nthreads) <0 )) goto out_free; }
@@ -294,7 +298,7 @@ static int check_per_pkg(struct perf_evsel *counter, int cpu, bool *skip)return 0 ; } -static int read_cb (struct perf_evsel *evsel,int cpu,int thread__maybe_unused , +static int read_cb (struct perf_evsel *evsel,int cpu,int thread,struct perf_counts_values *count) {struct perf_counts_values *aggr = &evsel->counts->aggr;
@@ -314,9 +318,9 @@ static int read_cb(struct perf_evsel *evsel, int cpu, int thread __maybe_unused,case AGGR_SOCKET :case AGGR_NONE :if (!evsel->snapshot) -perf_evsel__compute_deltas (evsel, cpu, count); +perf_evsel__compute_deltas (evsel, cpu, thread, count);perf_counts_values__scale (count, scale,NULL ); - *perf_counts (evsel->counts, cpu) = *count; + *perf_counts (evsel->counts, cpu, thread) = *count;if (aggr_mode ==AGGR_NONE )perf_stat__update_shadow_stats (evsel, count->values, cpu);break ;
@@ -352,7 +356,7 @@ static int read_counter_aggr(struct perf_evsel *counter)return -1 ;if (!counter->snapshot) -perf_evsel__compute_deltas (counter,-1 , aggr); +perf_evsel__compute_deltas (counter,-1 ,-1 , aggr);perf_counts_values__scale (aggr, scale, &counter->counts->scaled);for (i =0 ; i <3 ; i++)
@@ -805,9 +809,9 @@ static void print_aggr(char *prefix) s2 =aggr_get_id (evsel_list->cpus, cpu2);if (s2 != id)continue ; - val +=perf_counts (counter->counts, cpu)->val; - ena +=perf_counts (counter->counts, cpu)->ena; - run +=perf_counts (counter->counts, cpu)->run; + val +=perf_counts (counter->counts, cpu,0 )->val; + ena +=perf_counts (counter->counts, cpu,0 )->ena; + run +=perf_counts (counter->counts, cpu,0 )->run; nr++; }if (prefix)
@@ -915,9 +919,9 @@ static void print_counter(struct perf_evsel *counter, char *prefix)int cpu;for (cpu =0 ; cpu <perf_evsel__nr_cpus (counter); cpu++) { - val =perf_counts (counter->counts, cpu)->val; - ena =perf_counts (counter->counts, cpu)->ena; - run =perf_counts (counter->counts, cpu)->run; + val =perf_counts (counter->counts, cpu,0 )->val; + ena =perf_counts (counter->counts, cpu,0 )->ena; + run =perf_counts (counter->counts, cpu,0 )->run;if (prefix)fprintf (output,"%s" , prefix);
tools/perf/tests/openat-syscall-all-cpus.c +3 -3
@@ -78,7 +78,7 @@ int test__openat_syscall_event_on_all_cpus(void)* we use the auto allocation it will allocate just for 1 cpu, * as we start by cpu 0. */ -if (perf_evsel__alloc_counts (evsel, cpus->nr) <0 ) { +if (perf_evsel__alloc_counts (evsel, cpus->nr,1 ) <0 ) {pr_debug ("perf_evsel__alloc_counts(ncpus=%d)\n" , cpus->nr); goto out_close_fd; }
@@ -98,9 +98,9 @@ int test__openat_syscall_event_on_all_cpus(void) } expected = nr_openat_calls + cpu; -if (perf_counts (evsel->counts, cpu)->val != expected) { +if (perf_counts (evsel->counts, cpu,0 )->val != expected) {pr_debug ("perf_evsel__read_on_cpu: expected to intercept %d calls on cpu %d, got %" PRIu64"\n" , - expected, cpus->map[cpu],perf_counts (evsel->counts, cpu)->val); + expected, cpus->map[cpu],perf_counts (evsel->counts, cpu,0 )->val); err =-1 ; } }
tools/perf/tests/openat-syscall.c +2 -2
@@ -44,9 +44,9 @@ int test__openat_syscall_event(void) goto out_close_fd; } -if (perf_counts (evsel->counts,0 )->val != nr_openat_calls) { +if (perf_counts (evsel->counts,0 ,0 )->val != nr_openat_calls) {pr_debug ("perf_evsel__read_on_cpu: expected to intercept %d calls, got %" PRIu64"\n" , - nr_openat_calls,perf_counts (evsel->counts,0 )->val); + nr_openat_calls,perf_counts (evsel->counts,0 ,0 )->val); goto out_close_fd; }
tools/perf/util/evsel.c +6 -6
@@ -898,7 +898,7 @@ void perf_evsel__delete(struct perf_evsel *evsel)free (evsel); } -void perf_evsel__compute_deltas (struct perf_evsel *evsel,int cpu, +void perf_evsel__compute_deltas (struct perf_evsel *evsel,int cpu,int thread,struct perf_counts_values *count) {struct perf_counts_values tmp;
@@ -910,8 +910,8 @@ void perf_evsel__compute_deltas(struct perf_evsel *evsel, int cpu, tmp = evsel->prev_raw_counts->aggr; evsel->prev_raw_counts->aggr = *count; }else { - tmp = *perf_counts (evsel->prev_raw_counts, cpu); - *perf_counts (evsel->prev_raw_counts, cpu) = *count; + tmp = *perf_counts (evsel->prev_raw_counts, cpu, thread); + *perf_counts (evsel->prev_raw_counts, cpu, thread) = *count; } count->val = count->val - tmp.val;
@@ -964,15 +964,15 @@ int __perf_evsel__read_on_cpu(struct perf_evsel *evsel,if (FD (evsel, cpu, thread) <0 )return -EINVAL ; -if (evsel->counts ==NULL &&perf_evsel__alloc_counts (evsel, cpu +1 ) <0 ) +if (evsel->counts ==NULL &&perf_evsel__alloc_counts (evsel, cpu +1 , thread +1 ) <0 )return -ENOMEM ;if (readn (FD (evsel, cpu, thread), &count, nv *sizeof (u64)) <0 )return -errno; -perf_evsel__compute_deltas (evsel, cpu, &count); +perf_evsel__compute_deltas (evsel, cpu, thread, &count);perf_counts_values__scale (&count, scale,NULL ); - *perf_counts (evsel->counts, cpu) = count; + *perf_counts (evsel->counts, cpu, thread) = count;return 0 ; }
tools/perf/util/evsel.h +1 -1
@@ -112,7 +112,7 @@ static inline int perf_evsel__nr_cpus(struct perf_evsel *evsel)void perf_counts_values__scale (struct perf_counts_values *count,bool scale,s8 *pscaled); -void perf_evsel__compute_deltas (struct perf_evsel *evsel,int cpu, +void perf_evsel__compute_deltas (struct perf_evsel *evsel,int cpu,int thread,struct perf_counts_values *count); int perf_evsel__object_config(size_t object_size,
tools/perf/util/stat.c +4 -4
@@ -95,14 +95,14 @@ void perf_stat_evsel_id_init(struct perf_evsel *evsel) } } -struct perf_counts *perf_counts__new (int ncpus) +struct perf_counts *perf_counts__new (int ncpus,int nthreads) {struct perf_counts *counts =zalloc (sizeof (*counts));if (counts) {struct xyarray *cpu; - cpu =xyarray__new (ncpus,1 ,sizeof (struct perf_counts_values )); + cpu =xyarray__new (ncpus, nthreads,sizeof (struct perf_counts_values ));if (!cpu) {free (counts);return NULL ;
@@ -132,9 +132,9 @@ void perf_evsel__reset_counts(struct perf_evsel *evsel)perf_counts__reset (evsel->counts); } -int perf_evsel__alloc_counts (struct perf_evsel *evsel,int ncpus) +int perf_evsel__alloc_counts (struct perf_evsel *evsel,int ncpus,int nthreads) { - evsel->counts =perf_counts__new (ncpus); + evsel->counts =perf_counts__new (ncpus, nthreads);return evsel->counts !=NULL ?0 : -ENOMEM ; }
tools/perf/util/stat.h +4 -4
@@ -50,9 +50,9 @@ struct perf_counts { };static inline struct perf_counts_values * -perf_counts (struct perf_counts *counts,int cpu) +perf_counts (struct perf_counts *counts,int cpu,int thread) { -return xyarray__entry (counts->cpu, cpu,0 ); +return xyarray__entry (counts->cpu, cpu, thread); }void update_stats (struct stats *stats,u64 val);
@@ -86,10 +86,10 @@ void perf_stat__update_shadow_stats(struct perf_evsel *counter, u64 *count,void perf_stat__print_shadow_stats (FILE *out,struct perf_evsel *evsel,double avg,int cpu,enum aggr_mode aggr); -struct perf_counts *perf_counts__new (int ncpus); +struct perf_counts *perf_counts__new (int ncpus,int nthreads);void perf_counts__delete (struct perf_counts *counts);void perf_evsel__reset_counts (struct perf_evsel *evsel); -int perf_evsel__alloc_counts (struct perf_evsel *evsel,int ncpus); +int perf_evsel__alloc_counts (struct perf_evsel *evsel,int ncpus,int nthreads);void perf_evsel__free_counts (struct perf_evsel *evsel);#endif
Signature · 1 line
1.9.3
Jiri Olsa
reviewerPATCH v3 12/26 perf stat: Rename struct perf_counts::cpu member to values
In reply to Jiri OlsaRenaming 'struct xyarray *cpu' pointer to more fitting/generic values, because now we store both cpu and thread values.
--- tools/perf/util/stat.c | 12 ++++++------ tools/perf/util/stat.h | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-)
tools/perf/util/stat.c +6 -6
@@ -100,15 +100,15 @@ struct perf_counts *perf_counts__new(int ncpus, int nthreads)struct perf_counts *counts =zalloc (sizeof (*counts));if (counts) { -struct xyarray *cpu; +struct xyarray *values; - cpu =xyarray__new (ncpus, nthreads,sizeof (struct perf_counts_values )); -if (!cpu) { + values =xyarray__new (ncpus, nthreads,sizeof (struct perf_counts_values )); +if (!values) {free (counts);return NULL ; } - counts->cpu = cpu; + counts->values = values; }return counts;
@@ -117,14 +117,14 @@ struct perf_counts *perf_counts__new(int ncpus, int nthreads)void perf_counts__delete (struct perf_counts *counts) {if (counts) { -xyarray__delete (counts->cpu); +xyarray__delete (counts->values);free (counts); } }static void perf_counts__reset (struct perf_counts *counts) { -xyarray__reset (counts->cpu); +xyarray__reset (counts->values); }void perf_evsel__reset_counts (struct perf_evsel *evsel)
tools/perf/util/stat.h +2 -2
@@ -46,13 +46,13 @@ struct perf_counts_values {struct perf_counts {s8 scaled;struct perf_counts_values aggr; -struct xyarray *cpu; +struct xyarray *values; };static inline struct perf_counts_values *perf_counts (struct perf_counts *counts,int cpu,int thread) { -return xyarray__entry (counts->cpu, cpu, thread); +return xyarray__entry (counts->values, cpu, thread); }void update_stats (struct stats *stats,u64 val);
Signature · 1 line
1.9.3
Jiri Olsa
reviewerPATCH v3 13/26 perf stat: Move perf_evsel__(alloc|free|reset)_stat_priv into stat object
In reply to Jiri OlsaMoving perf_evsel__(alloc|free|reset)_stat_priv into stat object, so it could be used outside stat command in following patches.
--- tools/perf/builtin-stat.c | 25 ------------------------- tools/perf/util/stat.c | 25 +++++++++++++++++++++++++ tools/perf/util/stat.h | 4 ++++ 3 files changed, 29 insertions(+), 25 deletions(-)
tools/perf/builtin-stat.c +0 -25
@@ -141,31 +141,6 @@ static inline void diff_timespec(struct timespec *r, struct timespec *a, } } -static void perf_evsel__reset_stat_priv (struct perf_evsel *evsel) -{ -int i; -struct perf_stat *ps = evsel->priv; - -for (i =0 ; i <3 ; i++) -init_stats (&ps->res_stats[i]); - -perf_stat_evsel_id_init (evsel); -} - -static int perf_evsel__alloc_stat_priv (struct perf_evsel *evsel) -{ - evsel->priv =zalloc (sizeof (struct perf_stat )); -if (evsel->priv ==NULL ) -return -ENOMEM ; -perf_evsel__reset_stat_priv (evsel); -return 0 ; -} - -static void perf_evsel__free_stat_priv (struct perf_evsel *evsel) -{ -zfree (&evsel->priv); -} -static int perf_evsel__alloc_prev_raw_counts (struct perf_evsel *evsel,int ncpus,int nthreads) {
tools/perf/util/stat.c +25 -0
@@ -143,3 +143,28 @@ void perf_evsel__free_counts(struct perf_evsel *evsel)perf_counts__delete (evsel->counts); evsel->counts =NULL ; } + +void perf_evsel__reset_stat_priv (struct perf_evsel *evsel) +{ +int i; +struct perf_stat *ps = evsel->priv; + +for (i =0 ; i <3 ; i++) +init_stats (&ps->res_stats[i]); + +perf_stat_evsel_id_init (evsel); +} + +int perf_evsel__alloc_stat_priv (struct perf_evsel *evsel) +{ + evsel->priv =zalloc (sizeof (struct perf_stat )); +if (evsel->priv ==NULL ) +return -ENOMEM ; +perf_evsel__reset_stat_priv (evsel); +return 0 ; +} + +void perf_evsel__free_stat_priv (struct perf_evsel *evsel) +{ +zfree (&evsel->priv); +}
tools/perf/util/stat.h +4 -0
@@ -92,4 +92,8 @@ void perf_counts__delete(struct perf_counts *counts);void perf_evsel__reset_counts (struct perf_evsel *evsel);int perf_evsel__alloc_counts (struct perf_evsel *evsel,int ncpus,int nthreads);void perf_evsel__free_counts (struct perf_evsel *evsel); + +void perf_evsel__reset_stat_priv (struct perf_evsel *evsel); +int perf_evsel__alloc_stat_priv (struct perf_evsel *evsel); +void perf_evsel__free_stat_priv (struct perf_evsel *evsel);#endif
Signature · 1 line
1.9.3
Jiri Olsa
reviewerPATCH v3 14/26 perf stat: Move perf_evsel__(alloc|free)_prev_raw_counts into stat object
In reply to Jiri OlsaMoving perf_evsel__(alloc|free)_prev_raw_counts into stat object, so it could be used in following patches.
--- tools/perf/builtin-stat.c | 18 ------------------ tools/perf/util/stat.c | 18 ++++++++++++++++++ tools/perf/util/stat.h | 4 ++++ 3 files changed, 22 insertions(+), 18 deletions(-)
tools/perf/builtin-stat.c +0 -18
@@ -141,24 +141,6 @@ static inline void diff_timespec(struct timespec *r, struct timespec *a, } } -static int perf_evsel__alloc_prev_raw_counts (struct perf_evsel *evsel, -int ncpus,int nthreads) -{ -struct perf_counts *counts; - - counts =perf_counts__new (ncpus, nthreads); -if (counts) - evsel->prev_raw_counts = counts; - -return counts ?0 : -ENOMEM ; -} - -static void perf_evsel__free_prev_raw_counts (struct perf_evsel *evsel) -{ -perf_counts__delete (evsel->prev_raw_counts); - evsel->prev_raw_counts =NULL ; -} -static void perf_evlist__free_stats (struct perf_evlist *evlist) {struct perf_evsel *evsel;
tools/perf/util/stat.c +18 -0
@@ -168,3 +168,21 @@ void perf_evsel__free_stat_priv(struct perf_evsel *evsel) {zfree (&evsel->priv); } + +int perf_evsel__alloc_prev_raw_counts (struct perf_evsel *evsel, +int ncpus,int nthreads) +{ +struct perf_counts *counts; + + counts =perf_counts__new (ncpus, nthreads); +if (counts) + evsel->prev_raw_counts = counts; + +return counts ?0 : -ENOMEM ; +} + +void perf_evsel__free_prev_raw_counts (struct perf_evsel *evsel) +{ +perf_counts__delete (evsel->prev_raw_counts); + evsel->prev_raw_counts =NULL ; +}
tools/perf/util/stat.h +4 -0
@@ -96,4 +96,8 @@ void perf_evsel__free_counts(struct perf_evsel *evsel);void perf_evsel__reset_stat_priv (struct perf_evsel *evsel);int perf_evsel__alloc_stat_priv (struct perf_evsel *evsel);void perf_evsel__free_stat_priv (struct perf_evsel *evsel); + +int perf_evsel__alloc_prev_raw_counts (struct perf_evsel *evsel, +int ncpus,int nthreads); +void perf_evsel__free_prev_raw_counts (struct perf_evsel *evsel);#endif
Signature · 1 line
1.9.3
Jiri Olsa
reviewerPATCH v3 15/26 perf stat: Move perf_evlist__(alloc|free)_stats into evlist object
In reply to Jiri OlsaMoving perf_evlist__(alloc|free)_stats into evsel object, so it could be used in following patches.
--- tools/perf/builtin-stat.c | 32 -------------------------------- tools/perf/util/evlist.h | 1 - tools/perf/util/stat.c | 34 ++++++++++++++++++++++++++++++++++ tools/perf/util/stat.h | 5 +++++ 4 files changed, 39 insertions(+), 33 deletions(-)
tools/perf/builtin-stat.c +0 -32
@@ -141,38 +141,6 @@ static inline void diff_timespec(struct timespec *r, struct timespec *a, } } -static void perf_evlist__free_stats (struct perf_evlist *evlist) -{ -struct perf_evsel *evsel; - -evlist__for_each (evlist, evsel) { -perf_evsel__free_stat_priv (evsel); -perf_evsel__free_counts (evsel); -perf_evsel__free_prev_raw_counts (evsel); - } -} - -static int perf_evlist__alloc_stats (struct perf_evlist *evlist,bool alloc_raw) -{ -struct perf_evsel *evsel; -int nthreads =thread_map__nr (evsel_list->threads); - -evlist__for_each (evlist, evsel) { -int ncpus =perf_evsel__nr_cpus (evsel); - -if (perf_evsel__alloc_stat_priv (evsel) <0 || -perf_evsel__alloc_counts (evsel, ncpus, nthreads) <0 || - (alloc_raw &&perf_evsel__alloc_prev_raw_counts (evsel, ncpus, nthreads) <0 )) - goto out_free; - } - -return 0 ; - -out_free: -perf_evlist__free_stats (evlist); -return -1 ; -} -static void perf_stat__reset_stats (struct perf_evlist *evlist) {struct perf_evsel *evsel;
tools/perf/util/evlist.h +0 -1
@@ -289,5 +289,4 @@ void perf_evlist__to_front(struct perf_evlist *evlist,void perf_evlist__set_tracking_event (struct perf_evlist *evlist,struct perf_evsel *tracking_evsel); -#endif /* __PERF_EVLIST_H */
tools/perf/util/stat.c +34 -0
@@ -1,6 +1,8 @@#include <math.h> #include "stat.h" +#include "evlist.h" #include "evsel.h" +#include "thread_map.h" void update_stats (struct stats *stats,u64 val) {
@@ -186,3 +188,35 @@ void perf_evsel__free_prev_raw_counts(struct perf_evsel *evsel)perf_counts__delete (evsel->prev_raw_counts); evsel->prev_raw_counts =NULL ; } + +int perf_evlist__alloc_stats (struct perf_evlist *evlist,bool alloc_raw) +{ +struct perf_evsel *evsel; +int nthreads =thread_map__nr (evlist->threads); + +evlist__for_each (evlist, evsel) { +int ncpus =perf_evsel__nr_cpus (evsel); + +if (perf_evsel__alloc_stat_priv (evsel) <0 || +perf_evsel__alloc_counts (evsel, ncpus, nthreads) <0 || + (alloc_raw &&perf_evsel__alloc_prev_raw_counts (evsel, ncpus, nthreads) <0 )) + goto out_free; + } + +return 0 ; + +out_free: +perf_evlist__free_stats (evlist); +return -1 ; +} + +void perf_evlist__free_stats (struct perf_evlist *evlist) +{ +struct perf_evsel *evsel; + +evlist__for_each (evlist, evsel) { +perf_evsel__free_stat_priv (evsel); +perf_evsel__free_counts (evsel); +perf_evsel__free_prev_raw_counts (evsel); + } +}
tools/perf/util/stat.h +5 -0
@@ -70,6 +70,8 @@ static inline void init_stats(struct stats *stats) }struct perf_evsel ; +struct perf_evlist ; +bool __perf_evsel_stat__is (struct perf_evsel *evsel,enum perf_stat_evsel_id id);
@@ -100,4 +102,7 @@ void perf_evsel__free_stat_priv(struct perf_evsel *evsel);int perf_evsel__alloc_prev_raw_counts (struct perf_evsel *evsel,int ncpus,int nthreads);void perf_evsel__free_prev_raw_counts (struct perf_evsel *evsel); + +int perf_evlist__alloc_stats (struct perf_evlist *evlist,bool alloc_raw); +void perf_evlist__free_stats (struct perf_evlist *evlist);#endif
Signature · 1 line
1.9.3
Jiri Olsa
reviewerPATCH v3 16/26 perf stat: Introduce perf_evsel__alloc_stats function
In reply to Jiri OlsaMove all stat allocation logic related to stat
object under single function. This way we can
use it separately for stat object out of evlist
object.
--- tools/perf/util/stat.c | 20 ++++++++++++++------ tools/perf/util/stat.h | 2 ++ 2 files changed, 16 insertions(+), 6 deletions(-)
tools/perf/util/stat.c +14 -6
@@ -189,17 +189,25 @@ void perf_evsel__free_prev_raw_counts(struct perf_evsel *evsel) evsel->prev_raw_counts =NULL ; } +int perf_evsel__alloc_stats (struct perf_evsel *evsel,bool alloc_raw) +{ +int ncpus =perf_evsel__nr_cpus (evsel); +int nthreads =thread_map__nr (evsel->threads); + +if (perf_evsel__alloc_stat_priv (evsel) <0 || +perf_evsel__alloc_counts (evsel, ncpus, nthreads) <0 || + (alloc_raw &&perf_evsel__alloc_prev_raw_counts (evsel, ncpus, nthreads) <0 )) +return -ENOMEM ; + +return 0 ; +} +int perf_evlist__alloc_stats (struct perf_evlist *evlist,bool alloc_raw) {struct perf_evsel *evsel; -int nthreads =thread_map__nr (evlist->threads);evlist__for_each (evlist, evsel) { -int ncpus =perf_evsel__nr_cpus (evsel); - -if (perf_evsel__alloc_stat_priv (evsel) <0 || -perf_evsel__alloc_counts (evsel, ncpus, nthreads) <0 || - (alloc_raw &&perf_evsel__alloc_prev_raw_counts (evsel, ncpus, nthreads) <0 )) +if (perf_evsel__alloc_stats (evsel, alloc_raw)) goto out_free; }
tools/perf/util/stat.h +2 -0
@@ -103,6 +103,8 @@ int perf_evsel__alloc_prev_raw_counts(struct perf_evsel *evsel, int ncpus, int nthreads);void perf_evsel__free_prev_raw_counts (struct perf_evsel *evsel); +int perf_evsel__alloc_stats (struct perf_evsel *evsel,bool alloc_raw); +int perf_evlist__alloc_stats (struct perf_evlist *evlist,bool alloc_raw);void perf_evlist__free_stats (struct perf_evlist *evlist);#endif
Signature · 1 line
1.9.3
Jiri Olsa
reviewerPATCH v3 17/26 perf stat: Introduce perf_evsel__read function
In reply to Jiri OlsaAdding simple read function that reads/store data into given struct perf_counts_values *count object.
--- tools/perf/util/evsel.c | 14 ++++++++++++++ tools/perf/util/evsel.h | 3 +++ 2 files changed, 17 insertions(+)
tools/perf/util/evsel.c +14 -0
@@ -955,6 +955,20 @@ int perf_evsel__read_cb(struct perf_evsel *evsel, int cpu, int thread,return cb (evsel, cpu, thread, &count); } +int perf_evsel__read (struct perf_evsel *evsel,int cpu,int thread, +struct perf_counts_values *count) +{ +memset (count,0 ,sizeof (*count)); + +if (FD (evsel, cpu, thread) <0 ) +return -EINVAL ; + +if (readn (FD (evsel, cpu, thread), count,sizeof (*count)) <0 ) +return -errno; + +return 0 ; +} +int __perf_evsel__read_on_cpu (struct perf_evsel *evsel,int cpu,int thread,bool scale) {
tools/perf/util/evsel.h +3 -0
@@ -236,6 +236,9 @@ typedef int (perf_evsel__read_cb_t)(struct perf_evsel *evsel,int perf_evsel__read_cb (struct perf_evsel *evsel,int cpu,int thread,perf_evsel__read_cb_t cb); +int perf_evsel__read (struct perf_evsel *evsel,int cpu,int thread, +struct perf_counts_values *count); +int __perf_evsel__read_on_cpu (struct perf_evsel *evsel,int cpu,int thread,bool scale);
Signature · 1 line
1.9.3
Jiri Olsa
reviewerPATCH v3 18/26 perf stat: Introduce read_counters function
In reply to Jiri OlsaMoving read counters logic into single read_counters function, which will be called for both interval and overall processing legs.
The reason is to split reading and processing (following patches) counters code, so we could read counters from other sources (like perf.data) and process them in the same way as 'perf stat' command does.
--- tools/perf/builtin-stat.c | 47 ++++++++++++++++++++++------------------------- 1 file changed, 22 insertions(+), 25 deletions(-)
tools/perf/builtin-stat.c +22 -25
@@ -329,27 +329,35 @@ static int read_counter(struct perf_evsel *counter)return 0 ; } -static void print_interval (void ) +static void read_counters (bool close) { -static int num_print_interval;struct perf_evsel *counter;struct perf_stat *ps; -struct timespec ts, rs; -char prefix[64 ]; -if (aggr_mode ==AGGR_GLOBAL ) { -evlist__for_each (evsel_list, counter) { - ps = counter->priv; -memset (ps->res_stats,0 ,sizeof (ps->res_stats)); +evlist__for_each (evsel_list, counter) { + ps = counter->priv; +memset (ps->res_stats,0 ,sizeof (ps->res_stats)); + +if (aggr_mode ==AGGR_GLOBAL )read_counter_aggr (counter); - } - }else { -evlist__for_each (evsel_list, counter) { - ps = counter->priv; -memset (ps->res_stats,0 ,sizeof (ps->res_stats)); +else read_counter (counter); + +if (close) { +perf_evsel__close_fd (counter,perf_evsel__nr_cpus (counter), +thread_map__nr (evsel_list->threads)); } } +} + +static void print_interval (void ) +{ +static int num_print_interval; +struct perf_evsel *counter; +struct timespec ts, rs; +char prefix[64 ]; + +read_counters (false);clock_gettime (CLOCK_MONOTONIC , &ts);diff_timespec (&rs, &ts, &ref_time);
@@ -531,18 +539,7 @@ static int __run_perf_stat(int argc, const char **argv)update_stats (&walltime_nsecs_stats, t1 - t0); -if (aggr_mode ==AGGR_GLOBAL ) { -evlist__for_each (evsel_list, counter) { -read_counter_aggr (counter); -perf_evsel__close_fd (counter,perf_evsel__nr_cpus (counter), -thread_map__nr (evsel_list->threads)); - } - }else { -evlist__for_each (evsel_list, counter) { -read_counter (counter); -perf_evsel__close_fd (counter,perf_evsel__nr_cpus (counter),1 ); - } - } +read_counters (true);return WEXITSTATUS (status); }
Signature · 1 line
1.9.3
Jiri Olsa
reviewerPATCH v3 19/26 perf stat: Separate counters reading and processing
In reply to Jiri OlsaSeparating counters reading and processing so we could use the processing part in following patches.
Using simple reading via perf_evsel__read function to read counters now, because part of the processing was in the read_cb callback.
--- tools/perf/builtin-stat.c | 56 +++++++++++++++++++++++++++++++++-------------- 1 file changed, 39 insertions(+), 17 deletions(-)
tools/perf/builtin-stat.c +39 -17
@@ -223,8 +223,9 @@ static int check_per_pkg(struct perf_evsel *counter, int cpu, bool *skip)return 0 ; } -static int read_cb (struct perf_evsel *evsel,int cpu,int thread, -struct perf_counts_values *count) +static int +process_counter_values (struct perf_evsel *evsel,int cpu,int thread, +struct perf_counts_values *count) {struct perf_counts_values *aggr = &evsel->counts->aggr;static struct perf_counts_values zero;
@@ -245,7 +246,6 @@ static int read_cb(struct perf_evsel *evsel, int cpu, int thread,if (!evsel->snapshot)perf_evsel__compute_deltas (evsel, cpu, thread, count);perf_counts_values__scale (count, scale,NULL ); - *perf_counts (evsel->counts, cpu, thread) = *count;if (aggr_mode ==AGGR_NONE )perf_stat__update_shadow_stats (evsel, count->values, cpu);break ;
@@ -262,23 +262,41 @@ static int read_cb(struct perf_evsel *evsel, int cpu, int thread,return 0 ; } -static int read_counter (struct perf_evsel *counter); +static int process_counter_maps (struct perf_evsel *counter) +{ +int nthreads =thread_map__nr (counter->threads); +int ncpus =perf_evsel__nr_cpus (counter); +int cpu, thread; -/* -* Read out the results of a single counter: -* aggregate counts across CPUs in system-wide mode -*/ -static int read_counter_aggr (struct perf_evsel *counter) +if (counter->system_wide) + nthreads =1 ; + +for (thread =0 ; thread < nthreads; thread++) { +for (cpu =0 ; cpu < ncpus; cpu++) { +if (process_counter_values (counter, cpu, thread, +perf_counts (counter->counts, cpu, thread))) +return -1 ; + } + } + +return 0 ; +} + +static int process_counter (struct perf_evsel *counter) {struct perf_counts_values *aggr = &counter->counts->aggr;struct perf_stat *ps = counter->priv;u64 *count = counter->counts->aggr.values; -int i; +int i, ret; aggr->val = aggr->ena = aggr->run =0 ; -if (read_counter (counter)) -return -1 ; + ret =process_counter_maps (counter); +if (ret) +return ret; + +if (aggr_mode !=AGGR_GLOBAL ) +return 0 ;if (!counter->snapshot)perf_evsel__compute_deltas (counter,-1 ,-1 , aggr);
@@ -321,7 +339,10 @@ static int read_counter(struct perf_evsel *counter)for (thread =0 ; thread < nthreads; thread++) {for (cpu =0 ; cpu < ncpus; cpu++) { -if (perf_evsel__read_cb (counter, cpu, thread, read_cb)) +struct perf_counts_values *count; + + count =perf_counts (counter->counts, cpu, thread); +if (perf_evsel__read (counter, cpu, thread, count))return -1 ; } }
@@ -338,10 +359,11 @@ static void read_counters(bool close) ps = counter->priv;memset (ps->res_stats,0 ,sizeof (ps->res_stats)); -if (aggr_mode ==AGGR_GLOBAL ) -read_counter_aggr (counter); -else -read_counter (counter); +if (read_counter (counter)) +pr_warning ("failed to read counter %s\n" , counter->name); + +if (process_counter (counter)) +pr_warning ("failed to process counter %s\n" , counter->name);if (close) { perf_evsel__close_fd(counter, perf_evsel__nr_cpus(counter),
Signature · 1 line
1.9.3
Jiri Olsa
reviewerPATCH v3 20/26 perf stat: Move zero_per_pkg into counter process code
In reply to Jiri OlsaMoving zero_per_pkg into counter process code, to make the reading path free of processing logic.
--- tools/perf/builtin-stat.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
tools/perf/builtin-stat.c +3 -3
@@ -291,6 +291,9 @@ static int process_counter(struct perf_evsel *counter) aggr->val = aggr->ena = aggr->run =0 ; +if (counter->per_pkg) +zero_per_pkg (counter); + ret =process_counter_maps (counter);if (ret)return ret;
@@ -334,9 +337,6 @@ static int read_counter(struct perf_evsel *counter)if (counter->system_wide) nthreads =1 ; -if (counter->per_pkg) -zero_per_pkg (counter); -for (thread =0 ; thread < nthreads; thread++) {for (cpu =0 ; cpu < ncpus; cpu++) {struct perf_counts_values *count;
Signature · 1 line
1.9.3
Jiri Olsa
reviewerPATCH v3 21/26 perf stat: Move perf_stat initialization counter process code
In reply to Jiri OlsaMoving perf_stat initialization counter process code, to make the reading path free of processing logic.
--- tools/perf/builtin-stat.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-)
tools/perf/builtin-stat.c +1 -4
@@ -290,6 +290,7 @@ static int process_counter(struct perf_evsel *counter)int i, ret; aggr->val = aggr->ena = aggr->run =0 ; +memset (ps->res_stats,0 ,sizeof (ps->res_stats));if (counter->per_pkg)zero_per_pkg (counter);
@@ -353,12 +354,8 @@ static int read_counter(struct perf_evsel *counter)static void read_counters (bool close) {struct perf_evsel *counter; -struct perf_stat *ps;evlist__for_each (evsel_list, counter) { - ps = counter->priv; -memset (ps->res_stats,0 ,sizeof (ps->res_stats)); -if (read_counter (counter))pr_warning ("failed to read counter %s\n" , counter->name);
Signature · 1 line
1.9.3
Jiri Olsa
reviewerPATCH v3 22/26 perf stat: Remove perf_evsel__read_cb function
In reply to Jiri OlsaIt's no longer used, the stat command uses perf_evsel__read now.
--- tools/perf/util/evsel.c | 16 ---------------- tools/perf/util/evsel.h | 7 ------- 2 files changed, 23 deletions(-)
tools/perf/util/evsel.c +0 -16
@@ -939,22 +939,6 @@ void perf_counts_values__scale(struct perf_counts_values *count, *pscaled = scaled; } -int perf_evsel__read_cb (struct perf_evsel *evsel,int cpu,int thread, -perf_evsel__read_cb_t cb) -{ -struct perf_counts_values count; - -memset (&count,0 ,sizeof (count)); - -if (FD (evsel, cpu, thread) <0 ) -return -EINVAL ; - -if (readn (FD (evsel, cpu, thread), &count,sizeof (count)) <0 ) -return -errno; - -return cb (evsel, cpu, thread, &count); -} -int perf_evsel__read (struct perf_evsel *evsel,int cpu,int thread,struct perf_counts_values *count) {
tools/perf/util/evsel.h +0 -7
@@ -229,13 +229,6 @@ static inline bool perf_evsel__match2(struct perf_evsel *e1, (a)->attr.type == (b)->attr.type && \ (a)->attr.config == (b)->attr.config) -typedef int (perf_evsel__read_cb_t )(struct perf_evsel *evsel, -int cpu,int thread, -struct perf_counts_values *count); - -int perf_evsel__read_cb (struct perf_evsel *evsel,int cpu,int thread, -perf_evsel__read_cb_t cb); -int perf_evsel__read (struct perf_evsel *evsel,int cpu,int thread,struct perf_counts_values *count);
Signature · 1 line
1.9.3
Jiri Olsa
reviewerPATCH v3 23/26 perf stat: Rename print_interval to process_interval
In reply to Jiri OlsaIt suits better, because the function also reads counter's data.
Also the 'print_interval' name will be used in following generalization of counters display.
--- tools/perf/builtin-stat.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
tools/perf/builtin-stat.c +3 -3
@@ -369,7 +369,7 @@ static void read_counters(bool close) } } -static void print_interval (void ) +static void process_interval (void ) {static int num_print_interval;struct perf_evsel *counter;
@@ -532,7 +532,7 @@ static int __run_perf_stat(int argc, const char **argv)if (interval) {while (!waitpid (child_pid, &status,WNOHANG )) {nanosleep (&ts,NULL ); -print_interval (); +process_interval (); } }wait (&status);
@@ -550,7 +550,7 @@ static int __run_perf_stat(int argc, const char **argv)while (!done) {nanosleep (&ts,NULL );if (interval) -print_interval (); +process_interval (); } }
Signature · 1 line
1.9.3
Jiri Olsa
reviewerPATCH v3 24/26 perf stat: Using init_stats instead of memset
In reply to Jiri OlsaThe init_stats function is meant to init 'struct stats'.
--- tools/perf/builtin-stat.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
tools/perf/builtin-stat.c +1 -1
@@ -290,7 +290,7 @@ static int process_counter(struct perf_evsel *counter)int i, ret; aggr->val = aggr->ena = aggr->run =0 ; -memset (ps->res_stats,0 ,sizeof (ps->res_stats)); +init_stats (ps->res_stats);if (counter->per_pkg)zero_per_pkg (counter);
Signature · 1 line
1.9.3
Jiri Olsa
reviewerPATCH v3 25/26 perf stat: Introduce print_counters function
In reply to Jiri OlsaCentralize counters print code into singleprint_counters function.
--- tools/perf/builtin-stat.c | 127 +++++++++++++++++++++++----------------------- 1 file changed, 64 insertions(+), 63 deletions(-)
tools/perf/builtin-stat.c +64 -63
@@ -67,10 +67,7 @@#define CNTR_NOT_SUPPORTED "<not supported>"#define CNTR_NOT_COUNTED "<not counted>" -static void print_stat (int argc,const char **argv); -static void print_counter_aggr (struct perf_evsel *counter,char *prefix); -static void print_counter (struct perf_evsel *counter,char *prefix); -static void print_aggr (char *prefix); +static void print_counters (struct timespec *ts,int argc,const char **argv);/* Default events used for perf stat -T */ static const char *transaction_attrs = {
@@ -371,53 +368,14 @@ static void read_counters(bool close)static void process_interval (void ) { -static int num_print_interval; -struct perf_evsel *counter;struct timespec ts, rs; -char prefix[64 ];read_counters (false);clock_gettime (CLOCK_MONOTONIC , &ts);diff_timespec (&rs, &ts, &ref_time); -sprintf (prefix,"%6lu.%09lu%s" , rs.tv_sec, rs.tv_nsec, csv_sep); - -if (num_print_interval ==0 && !csv_output) { -switch (aggr_mode) { -case AGGR_SOCKET : -fprintf (output,"# time socket cpus counts %*s events\n" , unit_width,"unit" ); -break ; -case AGGR_CORE : -fprintf (output,"# time core cpus counts %*s events\n" , unit_width,"unit" ); -break ; -case AGGR_NONE : -fprintf (output,"# time CPU counts %*s events\n" , unit_width,"unit" ); -break ; -case AGGR_GLOBAL : -default : -fprintf (output,"# time counts %*s events\n" , unit_width,"unit" ); - } - } - -if (++num_print_interval ==25 ) - num_print_interval =0 ; -switch (aggr_mode) { -case AGGR_CORE : -case AGGR_SOCKET : -print_aggr (prefix); -break ; -case AGGR_NONE : -evlist__for_each (evsel_list, counter) -print_counter (counter, prefix); -break ; -case AGGR_GLOBAL : -default : -evlist__for_each (evsel_list, counter) -print_counter_aggr (counter, prefix); - } - -fflush (output); +print_counters (&rs,0 ,NULL ); }static void handle_initial_delay (void )
@@ -907,9 +865,35 @@ static void print_counter(struct perf_evsel *counter, char *prefix) } } -static void print_stat (int argc,const char **argv) +static void print_interval (char *prefix,struct timespec *ts) +{ +static int num_print_interval; + +sprintf (prefix,"%6lu.%09lu%s" , ts->tv_sec, ts->tv_nsec, csv_sep); + +if (num_print_interval ==0 && !csv_output) { +switch (aggr_mode) { +case AGGR_SOCKET : +fprintf (output,"# time socket cpus counts %*s events\n" , unit_width,"unit" ); +break ; +case AGGR_CORE : +fprintf (output,"# time core cpus counts %*s events\n" , unit_width,"unit" ); +break ; +case AGGR_NONE : +fprintf (output,"# time CPU counts %*s events\n" , unit_width,"unit" ); +break ; +case AGGR_GLOBAL : +default : +fprintf (output,"# time counts %*s events\n" , unit_width,"unit" ); + } + } + +if (++num_print_interval ==25 ) + num_print_interval =0 ; +} + +static void print_header (int argc,const char **argv) { -struct perf_evsel *counter;int i;fflush (stdout);
@@ -935,36 +919,53 @@ static void print_stat(int argc, const char **argv)fprintf (output," (%d runs)" , run_count);fprintf (output,":\n\n" ); } +} + +static void print_footer (void ) +{ +if (!null_run) +fprintf (output,"\n" ); +fprintf (output," %17.9f seconds time elapsed" , +avg_stats (&walltime_nsecs_stats)/1e9 ); +if (run_count >1 ) { +fprintf (output," " ); +print_noise_pct (stddev_stats (&walltime_nsecs_stats), +avg_stats (&walltime_nsecs_stats)); + } +fprintf (output,"\n\n" ); +} + +static void print_counters (struct timespec *ts,int argc,const char **argv) +{ +struct perf_evsel *counter; +char buf[64 ], *prefix =NULL ; + +if (interval) +print_interval (prefix = buf, ts); +else +print_header (argc, argv);switch (aggr_mode) {case AGGR_CORE :case AGGR_SOCKET : -print_aggr (NULL ); +print_aggr (prefix);break ;case AGGR_GLOBAL :evlist__for_each (evsel_list, counter) -print_counter_aggr (counter,NULL ); +print_counter_aggr (counter, prefix);break ;case AGGR_NONE :evlist__for_each (evsel_list, counter) -print_counter (counter,NULL ); +print_counter (counter, prefix);break ;default :break ; } -if (!csv_output) { -if (!null_run) -fprintf (output,"\n" ); -fprintf (output," %17.9f seconds time elapsed" , -avg_stats (&walltime_nsecs_stats)/1e9 ); -if (run_count >1 ) { -fprintf (output," " ); -print_noise_pct (stddev_stats (&walltime_nsecs_stats), -avg_stats (&walltime_nsecs_stats)); - } -fprintf (output,"\n\n" ); - } +if (!interval && !csv_output) +print_footer (); + +fflush (output); }static volatile int signr =-1 ;
@@ -1413,13 +1414,13 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused) status =run_perf_stat (argc, argv);if (forever && status !=-1 ) { -print_stat (argc, argv); +print_counters (NULL , argc, argv);perf_stat__reset_stats (evsel_list); } }if (!forever && status !=-1 && !interval) -print_stat (argc, argv); +print_counters (NULL , argc, argv);perf_evlist__free_stats (evsel_list); out:
Signature · 1 line
1.9.3
Jiri Olsa
reviewerPATCH v3 26/26 perf stat: Introduce --per-thread option
In reply to Jiri OlsaCurrently all the -p option PID arguments tasks values get aggregated and printed as single values.
Adding --per-tasks option to print values per task.
$ perf stat -e cycles,instructions --per-thread -p 30190,30242 ^C Performance counter stats for process id '30190,30242':
cat-30190 0 cycles
yes-30242 3,842,525,421 cycles
cat-30190 0 instructions
yes-30242 10,370,817,010 instructions1.143155657 seconds time elapsed
Also works under interval mode:
$ perf stat -e cycles,instructions --per-thread -p 30190,30242 -I 1000
# time comm-pid counts unit events
1.000073435 cat-30190 89,058 cycles
1.000073435 yes-30242 3,360,786,902 cycles (100.00%)
1.000073435 cat-30190 14,066 instructions
1.000073435 yes-30242 9,069,937,462 instructions
2.000204830 cat-30190 0 cycles
2.000204830 yes-30242 3,351,667,626 cycles
2.000204830 cat-30190 0 instructions
2.000204830 yes-30242 9,045,796,885 instructions
^C 2.771286639 cat-30190 0 cycles
2.771286639 yes-30242 2,593,884,166 cycles
2.771286639 cat-30190 0 instructions
2.771286639 yes-30242 7,001,171,191 instructionsIt works only with -t and -p options, otherwise following error is printed:
$ perf stat -e cycles --per-thread -I 1000 ls
The --per-thread option is only available when monitoring via -p -t options.
-p, --pid <pid> stat events on existing process id
-t, --tid <tid> stat events on existing thread id--- tools/perf/Documentation/perf-stat.txt | 4 ++ tools/perf/builtin-stat.c | 68 +++++++++++++++++++++++++++++++++- tools/perf/util/stat.h | 1 + 3 files changed, 71 insertions(+), 2 deletions(-)
tools/perf/Documentation/perf-stat.txt +4 -0
@@ -144,6 +144,10 @@ is a useful mode to detect imbalance between physical cores. To enable this mod use --per-core in addition to -a. (system-wide). The output includes the core number and the number of online logical processors on that physical processor. +--per-thread:: +Aggregate counts per monitored threads, when monitoring threads (-t option) +or processes (-p option). + -D msecs:: --delay msecs:: After starting the program, wait msecs before measuring. This is useful to
tools/perf/builtin-stat.c +66 -2
116 lines not on this page · raw message
tools/perf/util/stat.h +1 -0
@@ -30,6 +30,7 @@ enum aggr_mode {AGGR_GLOBAL ,AGGR_SOCKET ,AGGR_CORE , + AGGR_THREAD, }; struct perf_counts_values {
Signature · 1 line
1.9.3