Skip to contentSkip to conversation

perf stat: Introduce --per-task option

PATCH Superseded Jiri Olsa 5 participants 54 messages Jun 10, 2015 – Jun 13, 2015 perf events

v1 of 5 Superseded Latest is v5 →

lore
Share & tools
lore

Jiri Olsa

author reviewer
#0 lore raw

cover perf stat: Introduce --per-task option

hi,
adding the possibility to display stat data per thread. Allowing following commands and output:

  $ perf stat -e cycles,instructions --per-task -p 12451,16173
  ^C
   Performance counter stats for process id '12451,16173':
  TASK-12451                77,784      cycles
  TASK-16173                64,809      cycles
  TASK-12451                14,432      instructions
  TASK-16173                14,452      instructions
         3.854957122 seconds time elapsed

Also woks under interval mode:

  $ ./perf stat -e cycles,instructions --per-task -p 16431,16173 -I 1000
  #           time task                      counts unit events
       1.000085816 TASK-16173                     0      cycles
       1.000085816 TASK-16431         3,358,360,926      cycles
       1.000085816 TASK-16173                     0      instructions
       1.000085816 TASK-16431         9,062,422,086      instructions
       2.000212262 TASK-16173                65,386      cycles
       2.000212262 TASK-16431         3,349,355,309      cycles
       2.000212262 TASK-16173                12,151      instructions
       2.000212262 TASK-16431         9,039,401,422      instructions
       3.000333402 TASK-16173                62,797      cycles
       3.000333402 TASK-16431         3,357,140,183      cycles
       3.000333402 TASK-16173                12,208      instructions
       3.000333402 TASK-16431         9,058,080,762      instructions
  ^C     3.375949851 TASK-16173                     0      cycles
       3.375949851 TASK-16431         1,264,764,804      cycles
       3.375949851 TASK-16173                     0      instructions
       3.375949851 TASK-16431         3,414,532,317      instructions

thanks for comments,
jirka

---
Jiri Olsa (25):
perf tools: Fix python code with missing stat dependency
perf tools: Introduce xyarray__zero function
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 stat: Introduce perf_counts__(alloc|free|reset) functions 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 evsel object perf stat: Move perf_evsel__(alloc|free)_prev_raw_counts into evsel 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: Introduce print_counters function
perf stat: Introduce --per-task option

 tools/perf/builtin-stat.c                  | 388 +++++++++++++++++++++++++++++--------------------------------
 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.c          |   6 +-
 tools/perf/tests/switch-tracking.c         |   4 +-
 tools/perf/util/cpumap.c                   |  24 +++-
 tools/perf/util/cpumap.h                   |   5 +-
 tools/perf/util/evlist.c                   |  61 +++++++++-
 tools/perf/util/evlist.h                   |   2 +
 tools/perf/util/evsel.c                    | 128 ++++++++++++++++----
 tools/perf/util/evsel.h                    |  48 ++++++--
 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.h                     |   1 +
 tools/perf/util/svghelper.c                |   2 +-
 tools/perf/util/thread_map.c               |  28 ++++-
 tools/perf/util/thread_map.h               |   6 +-
 tools/perf/util/xyarray.c                  |   8 ++
 tools/perf/util/xyarray.h                  |   2 +
 25 files changed, 484 insertions(+), 267 deletions(-)
author reviewer
#1 lore raw

PATCH 1/25 perf tools: Fix python code with missing stat dependency

The evsel object now depends on stat object and breaks python code because of missing stat object dependency. Putting stat.c object into python object list.

---
 tools/perf/util/python-ext-sources | 1 +
 1 file changed, 1 insertion(+)
tools/perf/util/python-ext-sources +1 -0
index 4d28624a1eca..04fb68fc6def 100644
@@ -18,4 +18,5 @@ util/cgroup.c
 util/rblist.c
 util/strlist.c
 util/trace-event.c
+util/stat.c
 ../../lib/rbtree.c
Signature · 1 line
1.9.3
#2 lore raw

Re: [PATCH 01/25] perf tools: Fix python code with missing stat dependency

Em Wed, Jun 10, 2015 at 08:10:34PM +0200, Jiri Olsa escreveu:

Quoted 3 lines

The evsel object now depends on stat object and breaks python code because of missing stat object dependency. Putting stat.c object into python object list.

Applied, but 'perf test python' was Okaying me before and after this change, strange :-\

- Arnaldo

Quoted 18 lines
---
 tools/perf/util/python-ext-sources | 1 +
 1 file changed, 1 insertion(+)
tools/perf/util/python-ext-sources +1 -0
index 4d28624a1eca..04fb68fc6def 100644
@@ -18,4 +18,5 @@ util/cgroup.c
 util/rblist.c
 util/strlist.c
 util/trace-event.c
+util/stat.c
 ../../lib/rbtree.c
Signature · 1 line
1.9.3
#3 lore raw

Re: [PATCH 01/25] perf tools: Fix python code with missing stat dependency

Quoted 7 lines · Arnaldo Carvalho de Melo

Em Wed, Jun 10, 2015 at 08:10:34PM +0200, Jiri Olsa escreveu:

Quoted 3 lines

The evsel object now depends on stat object and breaks python code because of missing stat object dependency. Putting stat.c object into python object list.

Applied, but 'perf test python' was Okaying me before and after this change, strange :-\

did you do 'make clean' ? there's not perfect dependency checking for python binding building ;-)

jirka

#4 lore raw

Re: [PATCH 01/25] perf tools: Fix python code with missing stat dependency

Em Wed, Jun 10, 2015 at 10:23:48PM +0200, Jiri Olsa escreveu:

Quoted 11 lines · Arnaldo Carvalho de Melo
Quoted 7 lines

Em Wed, Jun 10, 2015 at 08:10:34PM +0200, Jiri Olsa escreveu:

Quoted 3 lines

The evsel object now depends on stat object and breaks python code because of missing stat object dependency. Putting stat.c object into python object list.

Applied, but 'perf test python' was Okaying me before and after this change, strange :-\

did you do 'make clean' ? there's not perfect dependency checking for python binding building ;-)

I guess I did that, yes ;-)

But to make sure:

[acme@zoo linux]$ type perf
perf is /home/acme/bin/perf
[acme@zoo linux]$ rm -f ~/bin/perf
[acme@zoo linux]$ type perf
bash: type: perf: not found
[acme@zoo linux]$ rm -rf /tmp/build/perf
[acme@zoo linux]$ perf
bash: perf: command not found...
Install package 'perf' to provide command 'perf'? [N/y] n [acme@zoo linux]$ mkdir -p /tmp/build/perf
[acme@zoo linux]$ alias m
alias m='time make O=/tmp/build/perf -C tools/perf install-bin' [acme@zoo linux]$ m
make: Entering directory '/home/git/linux/tools/perf'
BUILD: Doing 'make -j4' parallel build

Auto-detecting system features:

...                         dwarf: [ on  ]
...                         glibc: [ on  ]
...                          gtk2: [ on  ]
...                      libaudit: [ on  ]
...                        libbfd: [ on  ]
...                        libelf: [ on  ]
...                       libnuma: [ on  ]
...                       libperl: [ on  ]
...                     libpython: [ on  ]
...                      libslang: [ on  ]
...                     libunwind: [ on  ]
...            libdw-dwarf-unwind: [ on  ]
...                          zlib: [ on  ]
...                          lzma: [ on  ]
  MKDIR    /tmp/build/perf/util/
  CC       /tmp/build/perf/util/abspath.o
  MKDIR    /tmp/build/perf/fd/
  CC       /tmp/build/perf/fd/array.o
  CC       /tmp/build/perf/event-parse.o
<SNIP>
  INSTALL  perl-scripts
  INSTALL  python-scripts
  INSTALL  perf_completion-script

make: Leaving directory '/home/git/linux/tools/perf'

real 0m9.785s
user 0m15.868s
sys 0m5.756s
[acme@zoo linux]$

[acme@zoo linux]$ perf test python
17: Try 'import perf' in python, checking link problems : Ok
[acme@zoo linux]$ su -
Password:
[root@zoo ~]# perf test python
17: Try 'import perf' in python, checking link problems : Ok
[root@zoo ~]# type perf
perf is hashed (/root/bin/perf)
[root@zoo ~]# ls -la ~/bin/perf
lrwxrwxrwx. 1 root root 19 Apr 29 15:58 /root/bin/perf -> /home/acme/bin/perf [root@zoo ~]#

So, it still works well, without your patch.

- Arnaldo

#5 lore raw

Re: [PATCH 01/25] perf tools: Fix python code with missing stat dependency

Quoted 7 lines · Arnaldo Carvalho de Melo

Em Wed, Jun 10, 2015 at 10:23:48PM +0200, Jiri Olsa escreveu:

Quoted 6 lines · Arnaldo Carvalho de Melo
Quoted 5 lines

Em Wed, Jun 10, 2015 at 08:10:34PM +0200, Jiri Olsa escreveu:

Quoted 3 lines

The evsel object now depends on stat object and breaks python code because of missing stat object dependency. Putting stat.c object into python object list.

Quoted 7 lines
Quoted 5 lines
Quoted 2 lines

Applied, but 'perf test python' was Okaying me before and after this change, strange :-\

did you do 'make clean' ? there's not perfect dependency checking for python binding building ;-)

I guess I did that, yes ;-)

ugh, the new version is all stat specific.. so no evsel dependency sry for the noise ;-)

jirka

author reviewer
#6 lore raw

PATCH 2/25 perf tools: Introduce xyarray__zero function

In reply to Jiri Olsa

To zero all the xyarray contents. It will be used
in following patches.

---
 tools/perf/util/xyarray.c | 8 ++++++++
 tools/perf/util/xyarray.h | 2 ++
 2 files changed, 10 insertions(+)
tools/perf/util/xyarray.c +8 -0
index 22afbf6c536a..d0ca9ed5e7f2 100644
@@ -9,11 +9,19 @@ struct xyarray *xyarray__new(int xlen, int ylen, size_t entry_size)
 	if (xy != NULL) {
 		xy->entry_size = entry_size;
 		xy->row_size   = row_size;
+		xy->entries    = xlen * ylen;
 	}
 
 	return xy;
 }
 
+void xyarray__zero(struct xyarray *xy)
+{
+	size_t n = xy->entries * xy->entry_size;
+
+	memset(xy->contents, 0, n);
+}
+
 void xyarray__delete(struct xyarray *xy)
 {
 	free(xy);
tools/perf/util/xyarray.h +2 -0
index c488a07275dd..60cd80acdaa9 100644
@@ -6,11 +6,13 @@
 struct xyarray {
 	size_t row_size;
 	size_t entry_size;
+	size_t entries;
 	char contents[];
 };
 
 struct xyarray *xyarray__new(int xlen, int ylen, size_t entry_size);
 void xyarray__delete(struct xyarray *xy);
+void xyarray__zero(struct xyarray *xy);
 
 static inline void *xyarray__entry(struct xyarray *xy, int x, int y)
 {
Signature · 1 line
1.9.3
#7 lore raw

Re: [PATCH 02/25] perf tools: Introduce xyarray__zero function

Em Wed, Jun 10, 2015 at 08:10:35PM +0200, Jiri Olsa escreveu:

Quoted 2 lines

To zero all the xyarray contents. It will be used
in following patches.

I guess I would prefer xyarray__memset(), similar semantics as 'memset()', but I did a quick look and this is used in the kernel in things like bitmap_zero() and wrappers to it have that semantic...

Interesting that we don't have anymore a bzero() like function, but then, looking at 'man bzero':

----------------------------
CONFORMING TO

4.3BSD. This function is deprecated (marked as LEGACY in
POSIX.1-2001): use memset(3) in new programs. POSIX.1-2008 removes the specification of bzero().

-----------------------------

Guess we should use 'xyarray__memset()', ok?

- Arnaldo

Quoted 51 lines
---
 tools/perf/util/xyarray.c | 8 ++++++++
 tools/perf/util/xyarray.h | 2 ++
 2 files changed, 10 insertions(+)
tools/perf/util/xyarray.c +8 -0
index 22afbf6c536a..d0ca9ed5e7f2 100644
@@ -9,11 +9,19 @@ struct xyarray *xyarray__new(int xlen, int ylen, size_t entry_size)
 	if (xy != NULL) {
 		xy->entry_size = entry_size;
 		xy->row_size   = row_size;
+		xy->entries    = xlen * ylen;
 	}
 
 	return xy;
 }
 
+void xyarray__zero(struct xyarray *xy)
+{
+	size_t n = xy->entries * xy->entry_size;
+
+	memset(xy->contents, 0, n);
+}
+
 void xyarray__delete(struct xyarray *xy)
 {
 	free(xy);
tools/perf/util/xyarray.h +2 -0
index c488a07275dd..60cd80acdaa9 100644
@@ -6,11 +6,13 @@
 struct xyarray {
 	size_t row_size;
 	size_t entry_size;
+	size_t entries;
 	char contents[];
 };
 
 struct xyarray *xyarray__new(int xlen, int ylen, size_t entry_size);
 void xyarray__delete(struct xyarray *xy);
+void xyarray__zero(struct xyarray *xy);
 
 static inline void *xyarray__entry(struct xyarray *xy, int x, int y)
 {
Signature · 1 line
1.9.3
#8 lore raw

Re: [PATCH 02/25] perf tools: Introduce xyarray__zero function

Quoted 14 lines · Arnaldo Carvalho de Melo

Em Wed, Jun 10, 2015 at 08:10:35PM +0200, Jiri Olsa escreveu:

Quoted 2 lines

To zero all the xyarray contents. It will be used
in following patches.

I guess I would prefer xyarray__memset(), similar semantics as 'memset()', but I did a quick look and this is used in the kernel in things like bitmap_zero() and wrappers to it have that semantic...

Interesting that we don't have anymore a bzero() like function, but then, looking at 'man bzero':

----------------------------
CONFORMING TO

Quoted 7 lines

4.3BSD. This function is deprecated (marked as LEGACY in
POSIX.1-2001): use memset(3) in new programs. POSIX.1-2008 removes the specification of bzero().

-----------------------------

Guess we should use 'xyarray__memset()', ok?

hum, how about xyarray__reset ?

jirka

#9 lore raw

Re: [PATCH 02/25] perf tools: Introduce xyarray__zero function

Em Wed, Jun 10, 2015 at 10:01:38PM +0200, Jiri Olsa escreveu:

Quoted 8 lines · Arnaldo Carvalho de Melo
Quoted 5 lines

Em Wed, Jun 10, 2015 at 08:10:35PM +0200, Jiri Olsa escreveu:

Quoted 2 lines

To zero all the xyarray contents. It will be used
in following patches.

Guess we should use 'xyarray__memset()', ok?

hum, how about xyarray__reset?

I am ok with it, its already used in many places:

[acme@zoo linux]$ find tools -name "*.[ch]" | xargs grep __reset | wc -l 60
[acme@zoo linux]$

- Arnaldo

author reviewer
#10 lore raw

PATCH 3/25 perf tools: Add reference counting for cpu_map object

In reply to Jiri Olsa

Adding 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           | 24 ++++++++++++++++++++++--
 tools/perf/util/cpumap.h           |  5 ++++-
 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, 42 insertions(+), 15 deletions(-)
tools/perf/tests/code-reading.c +1 -1
index e2a432b67d52..86d17d2e9e50 100644
@@ -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
index 5b171d1e338b..a330235cefc0 100644
@@ -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
index 5855cf471210..5a9ef5833452 100644
@@ -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
index 0d31403ea593..1b06122beb76 100644
@@ -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 +22 -2
index c4e55b71010c..60f4297ed233 100644
@@ -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;
+		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);
+		cpus->refcnt = 1;
 	}
 
 	return cpus;
@@ -194,14 +197,30 @@ struct cpu_map *cpu_map__dummy_new(void)
 	if (cpus != NULL) {
 		cpus->nr = 1;
 		cpus->map[0] = -1;
+		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(map->refcnt != 0, "cpu map refcnt disbalanced\n");
+		free(map);
+	}
+}
+
+struct cpu_map *cpu_map__get(struct cpu_map *map)
+{
+	map->refcnt++;
+	return map;
+}
+
+void cpu_map__put(struct cpu_map *map)
+{
+	if (map && --map->refcnt == 0)
+		cpu_map__delete(map);
 }
 
 int cpu_map__get_socket(struct cpu_map *map, int idx)
@@ -263,6 +282,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);
 
+	c->refcnt = 1;
 	*res = c;
 	return 0;
 }
tools/perf/util/cpumap.h +4 -1
index 61a654849002..19fe50b29375 100644
@@ -8,13 +8,13 @@
 #include "util/debug.h"
 
 struct cpu_map {
+	int 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 +22,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
index dc1dc2c181ef..6b895de1144d 100644
@@ -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;
@@ -1337,7 +1337,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
index a3e36fc634dc..3bd5769dd7b9 100644
@@ -902,6 +902,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
index 2a4d1ec02846..09f8d2357108 100644
@@ -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
index d906d0ad5d40..b106d56df240 100644
@@ -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
index d457c523a33d..1f7becbe5e18 100644
@@ -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
index 88d87bf3049f..c09f178cea63 100644
@@ -1838,7 +1838,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
index 283d3e73e2f2..eec6c1149f44 100644
@@ -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
#11 lore raw

Re: [PATCH 03/25] perf tools: Add reference counting for cpu_map object

Em Wed, Jun 10, 2015 at 08:10:36PM +0200, Jiri Olsa escreveu:

Quoted 5 lines

Adding 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.

Please use atomic.h, as was done recently for the 'map', 'dso' and 'thread' structs, but other than that, its fine.

- Arnaldo

Quoted 288 lines
---
 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           | 24 ++++++++++++++++++++++--
 tools/perf/util/cpumap.h           |  5 ++++-
 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, 42 insertions(+), 15 deletions(-)
tools/perf/tests/code-reading.c +1 -1
index e2a432b67d52..86d17d2e9e50 100644
@@ -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
index 5b171d1e338b..a330235cefc0 100644
@@ -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
index 5855cf471210..5a9ef5833452 100644
@@ -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
index 0d31403ea593..1b06122beb76 100644
@@ -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 +22 -2
index c4e55b71010c..60f4297ed233 100644
@@ -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;
+		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);
+		cpus->refcnt = 1;
 	}
 
 	return cpus;
@@ -194,14 +197,30 @@ struct cpu_map *cpu_map__dummy_new(void)
 	if (cpus != NULL) {
 		cpus->nr = 1;
 		cpus->map[0] = -1;
+		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(map->refcnt != 0, "cpu map refcnt disbalanced\n");
+		free(map);
+	}
+}
+
+struct cpu_map *cpu_map__get(struct cpu_map *map)
+{
+	map->refcnt++;
+	return map;
+}
+
+void cpu_map__put(struct cpu_map *map)
+{
+	if (map && --map->refcnt == 0)
+		cpu_map__delete(map);
 }
 
 int cpu_map__get_socket(struct cpu_map *map, int idx)
@@ -263,6 +282,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);
 
+	c->refcnt = 1;
 	*res = c;
 	return 0;
 }
tools/perf/util/cpumap.h +4 -1
index 61a654849002..19fe50b29375 100644
@@ -8,13 +8,13 @@
 #include "util/debug.h"
 
 struct cpu_map {
+	int 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 +22,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
index dc1dc2c181ef..6b895de1144d 100644
@@ -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;
@@ -1337,7 +1337,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
index a3e36fc634dc..3bd5769dd7b9 100644
@@ -902,6 +902,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
index 2a4d1ec02846..09f8d2357108 100644
@@ -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
index d906d0ad5d40..b106d56df240 100644
@@ -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
index d457c523a33d..1f7becbe5e18 100644
@@ -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
index 88d87bf3049f..c09f178cea63 100644
@@ -1838,7 +1838,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
index 283d3e73e2f2..eec6c1149f44 100644
@@ -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
#12 lore raw

Re: [PATCH 03/25] perf tools: Add reference counting for cpu_map object

Quoted 9 lines · Arnaldo Carvalho de Melo

Em Wed, Jun 10, 2015 at 08:10:36PM +0200, Jiri Olsa escreveu:

Quoted 5 lines

Adding 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.

Please use atomic.h, as was done recently for the 'map', 'dso' and 'thread' structs, but other than that, its fine.

ook,

jirka

author reviewer
#13 lore raw

PATCH 4/25 perf tools: Add reference counting for thread_map object

In reply to Jiri Olsa

Adding 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               | 28 ++++++++++++++++++++++++++--
 tools/perf/util/thread_map.h               |  6 ++++--
 11 files changed, 40 insertions(+), 14 deletions(-)
tools/perf/tests/code-reading.c +1 -1
index 86d17d2e9e50..7dcd2c3d865f 100644
@@ -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
index a330235cefc0..4d4b9837b630 100644
@@ -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
index 5a9ef5833452..666b67a4df9d 100644
@@ -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
index 264e215c0d36..412a41eb3f81 100644
@@ -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
index e34dfdf96b5a..8801983a38f0 100644
@@ -110,6 +110,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
index 9f9491bb8e48..bdfa1f446681 100644
@@ -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
index 1b06122beb76..e698742d4fec 100644
@@ -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
index 6b895de1144d..493675cfa90c 100644
@@ -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);
@@ -1104,7 +1104,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
index b106d56df240..626422eda727 100644
@@ -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 +26 -2
index f93b9734735b..04bc15e339dd 100644
@@ -8,6 +8,7 @@
 #include <unistd.h>
 #include "strlist.h"
 #include <string.h>
+#include "asm/bug.h"
 #include "thread_map.h"
 #include "util.h"
 
@@ -38,6 +39,7 @@ struct thread_map *thread_map__new_by_pid(pid_t pid)
 		for (i = 0; i < items; i++)
 			threads->map[i] = atoi(namelist[i]->d_name);
 		threads->nr = items;
+		threads->refcnt = 1;
 	}
 
 	for (i=0; i<items; i++)
@@ -54,6 +56,7 @@ struct thread_map *thread_map__new_by_tid(pid_t tid)
 	if (threads != NULL) {
 		threads->map[0] = tid;
 		threads->nr	= 1;
+		threads->refcnt = 1;
 	}
 
 	return threads;
@@ -75,6 +78,7 @@ struct thread_map *thread_map__new_by_uid(uid_t uid)
 		goto out_free_threads;
 
 	threads->nr = 0;
+	threads->refcnt = 1;
 
 	while (!readdir_r(proc, &dirent, &next) && next) {
 		char *end;
@@ -202,6 +206,8 @@ static struct thread_map *thread_map__new_by_pid_str(const char *pid_str)
 
 out:
 	strlist__delete(slist);
+	if (threads)
+		threads->refcnt = 1;
 	return threads;
 
 out_free_namelist:
@@ -221,6 +227,7 @@ struct thread_map *thread_map__new_dummy(void)
 	if (threads != NULL) {
 		threads->map[0]	= -1;
 		threads->nr	= 1;
+		threads->refcnt = 1;
 	}
 	return threads;
 }
@@ -263,6 +270,8 @@ static struct thread_map *thread_map__new_by_tid_str(const char *tid_str)
 		threads->nr		 = ntasks;
 	}
 out:
+	if (threads)
+		threads->refcnt = 1;
 	return threads;
 
 out_free_threads:
@@ -282,9 +291,24 @@ 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)
 {
-	free(threads);
+	if (threads) {
+		WARN_ONCE(threads->refcnt != 0, "thread map refcnt disbalanced\n");
+		free(threads);
+	}
+}
+
+struct thread_map *thread_map__get(struct thread_map *map)
+{
+	map->refcnt++;
+	return map;
+}
+
+void thread_map__put(struct thread_map *map)
+{
+	if (map && --map->refcnt == 0)
+		thread_map__delete(map);
 }
 
 size_t thread_map__fprintf(struct thread_map *threads, FILE *fp)
tools/perf/util/thread_map.h +4 -2
index 95313f43cc0f..dc02c259da36 100644
@@ -5,6 +5,7 @@
 #include <stdio.h>
 
 struct thread_map {
+	int refcnt;
 	int nr;
 	pid_t map[];
 };
@@ -15,11 +16,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
#14 lore raw

Re: [PATCH 04/25] perf tools: Add reference counting for thread_map object

Em Wed, Jun 10, 2015 at 08:10:37PM +0200, Jiri Olsa escreveu:

Quoted 5 lines

Adding 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.

Please use atomic.h, as was done recently for the 'map', 'dso' and 'thread' structs, but other than that, its fine.

Quoted 257 lines
---
 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               | 28 ++++++++++++++++++++++++++--
 tools/perf/util/thread_map.h               |  6 ++++--
 11 files changed, 40 insertions(+), 14 deletions(-)
tools/perf/tests/code-reading.c +1 -1
index 86d17d2e9e50..7dcd2c3d865f 100644
@@ -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
index a330235cefc0..4d4b9837b630 100644
@@ -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
index 5a9ef5833452..666b67a4df9d 100644
@@ -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
index 264e215c0d36..412a41eb3f81 100644
@@ -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
index e34dfdf96b5a..8801983a38f0 100644
@@ -110,6 +110,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
index 9f9491bb8e48..bdfa1f446681 100644
@@ -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
index 1b06122beb76..e698742d4fec 100644
@@ -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
index 6b895de1144d..493675cfa90c 100644
@@ -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);
@@ -1104,7 +1104,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
index b106d56df240..626422eda727 100644
@@ -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 +26 -2
index f93b9734735b..04bc15e339dd 100644
@@ -8,6 +8,7 @@
 #include <unistd.h>
 #include "strlist.h"
 #include <string.h>
+#include "asm/bug.h"
 #include "thread_map.h"
 #include "util.h"
 
@@ -38,6 +39,7 @@ struct thread_map *thread_map__new_by_pid(pid_t pid)
 		for (i = 0; i < items; i++)
 			threads->map[i] = atoi(namelist[i]->d_name);
 		threads->nr = items;
+		threads->refcnt = 1;
 	}
 
 	for (i=0; i<items; i++)
@@ -54,6 +56,7 @@ struct thread_map *thread_map__new_by_tid(pid_t tid)
 	if (threads != NULL) {
 		threads->map[0] = tid;
 		threads->nr	= 1;
+		threads->refcnt = 1;
 	}
 
 	return threads;
@@ -75,6 +78,7 @@ struct thread_map *thread_map__new_by_uid(uid_t uid)
 		goto out_free_threads;
 
 	threads->nr = 0;
+	threads->refcnt = 1;
 
 	while (!readdir_r(proc, &dirent, &next) && next) {
 		char *end;
@@ -202,6 +206,8 @@ static struct thread_map *thread_map__new_by_pid_str(const char *pid_str)
 
 out:
 	strlist__delete(slist);
+	if (threads)
+		threads->refcnt = 1;
 	return threads;
 
 out_free_namelist:
@@ -221,6 +227,7 @@ struct thread_map *thread_map__new_dummy(void)
 	if (threads != NULL) {
 		threads->map[0]	= -1;
 		threads->nr	= 1;
+		threads->refcnt = 1;
 	}
 	return threads;
 }
@@ -263,6 +270,8 @@ static struct thread_map *thread_map__new_by_tid_str(const char *tid_str)
 		threads->nr		 = ntasks;
 	}
 out:
+	if (threads)
+		threads->refcnt = 1;
 	return threads;
 
 out_free_threads:
@@ -282,9 +291,24 @@ 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)
 {
-	free(threads);
+	if (threads) {
+		WARN_ONCE(threads->refcnt != 0, "thread map refcnt disbalanced\n");
+		free(threads);
+	}
+}
+
+struct thread_map *thread_map__get(struct thread_map *map)
+{
+	map->refcnt++;
+	return map;
+}
+
+void thread_map__put(struct thread_map *map)
+{
+	if (map && --map->refcnt == 0)
+		thread_map__delete(map);
 }
 
 size_t thread_map__fprintf(struct thread_map *threads, FILE *fp)
tools/perf/util/thread_map.h +4 -2
index 95313f43cc0f..dc02c259da36 100644
@@ -5,6 +5,7 @@
 #include <stdio.h>
 
 struct thread_map {
+	int refcnt;
 	int nr;
 	pid_t map[];
 };
@@ -15,11 +16,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
#15 lore raw

Re: [PATCH 04/25] perf tools: Add reference counting for thread_map object

Quoted 9 lines · Arnaldo Carvalho de Melo

Em Wed, Jun 10, 2015 at 08:10:37PM +0200, Jiri Olsa escreveu:

Quoted 5 lines

Adding 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.

Please use atomic.h, as was done recently for the 'map', 'dso' and 'thread' structs, but other than that, its fine.

ook

jirka

author reviewer
#16 lore raw

PATCH 5/25 perf tools: Propagate cpu maps through the evlist

In reply to Jiri Olsa

Propagate 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 | 24 +++++++++++++++++++++++-
 1 file changed, 23 insertions(+), 1 deletion(-)
tools/perf/util/evlist.c +23 -1
index 493675cfa90c..7cb579ca5629 100644
@@ -1085,6 +1085,28 @@ int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages,
 	return perf_evlist__mmap_ex(evlist, pages, overwrite, 0, false);
 }
 
+static int 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,
@@ -1101,7 +1123,7 @@ int perf_evlist__create_maps(struct perf_evlist *evlist, struct target *target)
 	if (evlist->cpus == NULL)
 		goto out_delete_threads;
 
-	return 0;
+	return propagate_maps(evlist, target);
 
 out_delete_threads:
 	thread_map__put(evlist->threads);
Signature · 1 line
1.9.3
#17 lore raw

Re: [PATCH 05/25] perf tools: Propagate cpu maps through the evlist

Em Wed, Jun 10, 2015 at 08:10:38PM +0200, Jiri Olsa escreveu:

Quoted 19 lines

Propagate 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 | 24 +++++++++++++++++++++++-
 1 file changed, 23 insertions(+), 1 deletion(-)
tools/perf/util/evlist.c +0 -0
index 493675cfa90c..7cb579ca5629 100644
@@ -1085,6 +1085,28 @@ int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages,
 	return perf_evlist__mmap_ex(evlist, pages, overwrite, 0, false);
 }

tools/perf/util/evlist.c int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages, · line 1096

Quoted 10 lines
tools/perf/util/evlist.c +9 -0
 
+static int 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.
+		 */

There was some discussion about this with Stephane, lost track, will try to dig it... :-\

- Arnaldo

Quoted 27 lines
tools/perf/util/evlist.c +14 -1
+		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,
@@ -1101,7 +1123,7 @@ int perf_evlist__create_maps(struct perf_evlist *evlist, struct target *target)
 	if (evlist->cpus == NULL)
 		goto out_delete_threads;
 
-	return 0;
+	return propagate_maps(evlist, target);
 
 out_delete_threads:
 	thread_map__put(evlist->threads);
Signature · 1 line
1.9.3
author reviewer
#18 lore raw

PATCH 6/25 perf tools: Propagate thread maps through the evlist

In reply to Jiri Olsa

Propagate evlist's thread_map object through all the evsel objects.

It'll be handy to access evsel's threads directly
in following patches.

---
 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
index 7cb579ca5629..f438881040f2 100644
@@ -1100,7 +1100,9 @@ static int propagate_maps(struct perf_evlist *evlist, struct target *target)
 		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
index 3bd5769dd7b9..bd1c3b71e455 100644
@@ -903,6 +903,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
index 21ec08247d47..d18572223b08 100644
@@ -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
#19 lore raw

Re: [PATCH 06/25] perf tools: Propagate thread maps through the evlist

Em Wed, Jun 10, 2015 at 08:10:39PM +0200, Jiri Olsa escreveu:

Quoted 5 lines

Propagate evlist's thread_map object through all the evsel objects.

It'll be handy to access evsel's threads directly
in following patches.

Handy in what way? I.e. I should know one example without having to look at future patches ;-)

- Arnaldo

Quoted 49 lines
---
 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
index 7cb579ca5629..f438881040f2 100644
@@ -1100,7 +1100,9 @@ static int propagate_maps(struct perf_evlist *evlist, struct target *target)
 		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
index 3bd5769dd7b9..bd1c3b71e455 100644
@@ -903,6 +903,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
index 21ec08247d47..d18572223b08 100644
@@ -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
#20 lore raw

Re: [PATCH 06/25] perf tools: Propagate thread maps through the evlist

Quoted 9 lines · Arnaldo Carvalho de Melo

Em Wed, Jun 10, 2015 at 08:10:39PM +0200, Jiri Olsa escreveu:

Quoted 5 lines

Propagate evlist's thread_map object through all the evsel objects.

It'll be handy to access evsel's threads directly
in following patches.

Handy in what way? I.e. I should know one example without having to look at future patches ;-)

there's no link to evlist which hold threads map now, and it's not always available.. I'll update the changelog in v2

jirka

maintainer
#21 lore raw

Re: [PATCH 06/25] perf tools: Propagate thread maps through the evlist

Hi Jiri,

Quoted 8 lines · Jiri Olsa
Quoted 7 lines · Arnaldo Carvalho de Melo

Em Wed, Jun 10, 2015 at 08:10:39PM +0200, Jiri Olsa escreveu:

Quoted 5 lines

Propagate evlist's thread_map object through all the evsel objects.

It'll be handy to access evsel's threads directly
in following patches.

Quoted 6 lines
Quoted 2 lines

Handy in what way? I.e. I should know one example without having to look at future patches ;-)

there's no link to evlist which hold threads map now, and it's not always available.. I'll update the changelog in v2

What about adding a link to evlist in evsel then?

Thanks,
Namhyung

#22 lore raw

Re: [PATCH 06/25] perf tools: Propagate thread maps through the evlist

Quoted 11 lines · Namhyung Kim

Hi Jiri,

Quoted 8 lines · Jiri Olsa
Quoted 7 lines · Arnaldo Carvalho de Melo

Em Wed, Jun 10, 2015 at 08:10:39PM +0200, Jiri Olsa escreveu:

Quoted 5 lines

Propagate evlist's thread_map object through all the evsel objects.

It'll be handy to access evsel's threads directly
in following patches.

Quoted 8 lines
Quoted 6 lines
Quoted 2 lines

Handy in what way? I.e. I should know one example without having to look at future patches ;-)

there's no link to evlist which hold threads map now, and it's not always available.. I'll update the changelog in v2

What about adding a link to evlist in evsel then?

I guess thats possiuble, but we already have it for cpu map in evsel, so I wanted to stay consistent with thread map.. and it's just pointer with extra refcnt increased

jirka

author reviewer
#23 lore raw

PATCH 7/25 perf tools: Make perf_evsel__(nr_)cpus generic

In reply to Jiri Olsa

Because 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
index ff3d25803400..79a596fcfd6c 100644
@@ -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
index d18572223b08..54afdc80a651 100644
@@ -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
author reviewer
#24 lore raw

PATCH 8/25 perf stat: Introduce perf_counts__(alloc|free|reset) functions

In reply to Jiri Olsa

Move 'struct perf_counts' allocation|free|reset code into separate functions.

---
 tools/perf/builtin-stat.c | 19 +++++++------------
 tools/perf/util/evsel.c   | 28 +++++++++++++++++++++++-----
 tools/perf/util/evsel.h   |  3 +++
 3 files changed, 33 insertions(+), 17 deletions(-)
tools/perf/builtin-stat.c +7 -12
index 79a596fcfd6c..90766538fd8f 100644
@@ -168,24 +168,19 @@ static void perf_evsel__free_stat_priv(struct perf_evsel *evsel)
 
 static int perf_evsel__alloc_prev_raw_counts(struct perf_evsel *evsel)
 {
-	void *addr;
-	size_t sz;
+	struct perf_counts *counts;
 
-	sz = sizeof(*evsel->counts) +
-	     (perf_evsel__nr_cpus(evsel) * sizeof(struct perf_counts_values));
+	counts = perf_counts__alloc(perf_evsel__nr_cpus(evsel));
+	if (counts)
+		evsel->prev_raw_counts = counts;
 
-	addr = zalloc(sz);
-	if (!addr)
-		return -ENOMEM;
-
-	evsel->prev_raw_counts =  addr;
-
-	return 0;
+	return counts ? 0 : -ENOMEM;
 }
 
 static void perf_evsel__free_prev_raw_counts(struct perf_evsel *evsel)
 {
-	zfree(&evsel->prev_raw_counts);
+	perf_counts__free(evsel->prev_raw_counts);
+	evsel->prev_raw_counts = NULL;
 }
 
 static void perf_evlist__free_stats(struct perf_evlist *evlist)
tools/perf/util/evsel.c +23 -5
index bd1c3b71e455..fde2416921cc 100644
@@ -851,16 +851,33 @@ int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads)
 	return 0;
 }
 
+struct perf_counts *perf_counts__alloc(int ncpus)
+{
+	int size = sizeof(struct perf_counts) +
+		   ncpus * sizeof(struct perf_counts_values);
+
+	return zalloc(size);
+}
+
+void perf_counts__free(struct perf_counts *counts)
+{
+	free(counts);
+}
+
+static void perf_counts__reset(struct perf_counts *counts, int ncpus)
+{
+	memset(counts, 0, (sizeof(*counts) +
+	       (ncpus * sizeof(struct perf_counts_values))));
+}
+
 void perf_evsel__reset_counts(struct perf_evsel *evsel, int ncpus)
 {
-	memset(evsel->counts, 0, (sizeof(*evsel->counts) +
-				 (ncpus * sizeof(struct perf_counts_values))));
+	perf_counts__reset(evsel->counts, ncpus);
 }
 
 int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus)
 {
-	evsel->counts = zalloc((sizeof(*evsel->counts) +
-				(ncpus * sizeof(struct perf_counts_values))));
+	evsel->counts = perf_counts__alloc(ncpus);
 	return evsel->counts != NULL ? 0 : -ENOMEM;
 }
 
@@ -893,7 +910,8 @@ void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads)
 
 void perf_evsel__free_counts(struct perf_evsel *evsel)
 {
-	zfree(&evsel->counts);
+	perf_counts__free(evsel->counts);
+	evsel->counts = NULL;
 }
 
 void perf_evsel__exit(struct perf_evsel *evsel)
tools/perf/util/evsel.h +3 -0
index 54afdc80a651..ef619645a08f 100644
@@ -131,6 +131,9 @@ void perf_counts_values__scale(struct perf_counts_values *count,
 void perf_evsel__compute_deltas(struct perf_evsel *evsel, int cpu,
 				struct perf_counts_values *count);
 
+struct perf_counts *perf_counts__alloc(int ncpus);
+void perf_counts__free(struct perf_counts *counts);
+
 int perf_evsel__object_config(size_t object_size,
 			      int (*init)(struct perf_evsel *evsel),
 			      void (*fini)(struct perf_evsel *evsel));
Signature · 1 line
1.9.3
#25 lore raw

Re: [PATCH 08/25] perf stat: Introduce perf_counts__(alloc|free|reset) functions

Em Wed, Jun 10, 2015 at 08:10:41PM +0200, Jiri Olsa escreveu:

Quoted 10 lines

Move 'struct perf_counts' allocation|free|reset code into separate functions.

---
 tools/perf/builtin-stat.c | 19 +++++++------------
 tools/perf/util/evsel.c   | 28 +++++++++++++++++++++++-----
 tools/perf/util/evsel.h   |  3 +++
 3 files changed, 33 insertions(+), 17 deletions(-)

But please do not move it to 'evsel.[ch]', i.e. you're introducing a new class, i.e. "perf_counts", you might as well put them in a separate file, i.e. tools/perf/util/counts.[ch].

And please rename perf_counts__alloc() to perf_counds__new(), ditto for __free() -> __delete(),

Quoted 104 lines
tools/perf/builtin-stat.c +7 -12
index 79a596fcfd6c..90766538fd8f 100644
@@ -168,24 +168,19 @@ static void perf_evsel__free_stat_priv(struct perf_evsel *evsel)
 
 static int perf_evsel__alloc_prev_raw_counts(struct perf_evsel *evsel)
 {
-	void *addr;
-	size_t sz;
+	struct perf_counts *counts;
 
-	sz = sizeof(*evsel->counts) +
-	     (perf_evsel__nr_cpus(evsel) * sizeof(struct perf_counts_values));
+	counts = perf_counts__alloc(perf_evsel__nr_cpus(evsel));
+	if (counts)
+		evsel->prev_raw_counts = counts;
 
-	addr = zalloc(sz);
-	if (!addr)
-		return -ENOMEM;
-
-	evsel->prev_raw_counts =  addr;
-
-	return 0;
+	return counts ? 0 : -ENOMEM;
 }
 
 static void perf_evsel__free_prev_raw_counts(struct perf_evsel *evsel)
 {
-	zfree(&evsel->prev_raw_counts);
+	perf_counts__free(evsel->prev_raw_counts);
+	evsel->prev_raw_counts = NULL;
 }
 
 static void perf_evlist__free_stats(struct perf_evlist *evlist)
tools/perf/util/evsel.c +23 -5
index bd1c3b71e455..fde2416921cc 100644
@@ -851,16 +851,33 @@ int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads)
 	return 0;
 }
 
+struct perf_counts *perf_counts__alloc(int ncpus)
+{
+	int size = sizeof(struct perf_counts) +
+		   ncpus * sizeof(struct perf_counts_values);
+
+	return zalloc(size);
+}
+
+void perf_counts__free(struct perf_counts *counts)
+{
+	free(counts);
+}
+
+static void perf_counts__reset(struct perf_counts *counts, int ncpus)
+{
+	memset(counts, 0, (sizeof(*counts) +
+	       (ncpus * sizeof(struct perf_counts_values))));
+}
+
 void perf_evsel__reset_counts(struct perf_evsel *evsel, int ncpus)
 {
-	memset(evsel->counts, 0, (sizeof(*evsel->counts) +
-				 (ncpus * sizeof(struct perf_counts_values))));
+	perf_counts__reset(evsel->counts, ncpus);
 }
 
 int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus)
 {
-	evsel->counts = zalloc((sizeof(*evsel->counts) +
-				(ncpus * sizeof(struct perf_counts_values))));
+	evsel->counts = perf_counts__alloc(ncpus);
 	return evsel->counts != NULL ? 0 : -ENOMEM;
 }
 
@@ -893,7 +910,8 @@ void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads)
 
 void perf_evsel__free_counts(struct perf_evsel *evsel)
 {
-	zfree(&evsel->counts);
+	perf_counts__free(evsel->counts);
+	evsel->counts = NULL;
 }
 
 void perf_evsel__exit(struct perf_evsel *evsel)
tools/perf/util/evsel.h +3 -0
index 54afdc80a651..ef619645a08f 100644
@@ -131,6 +131,9 @@ void perf_counts_values__scale(struct perf_counts_values *count,
 void perf_evsel__compute_deltas(struct perf_evsel *evsel, int cpu,
 				struct perf_counts_values *count);
 
+struct perf_counts *perf_counts__alloc(int ncpus);
+void perf_counts__free(struct perf_counts *counts);
+
 int perf_evsel__object_config(size_t object_size,
 			      int (*init)(struct perf_evsel *evsel),
 			      void (*fini)(struct perf_evsel *evsel));
Signature · 1 line
1.9.3
#26 lore raw

Re: [PATCH 08/25] perf stat: Introduce perf_counts__(alloc|free|reset) functions

Quoted 12 lines · Arnaldo Carvalho de Melo

Em Wed, Jun 10, 2015 at 08:10:41PM +0200, Jiri Olsa escreveu:

Quoted 10 lines

Move 'struct perf_counts' allocation|free|reset code into separate functions.

---
 tools/perf/builtin-stat.c | 19 +++++++------------
 tools/perf/util/evsel.c   | 28 +++++++++++++++++++++++-----
 tools/perf/util/evsel.h   |  3 +++
 3 files changed, 33 insertions(+), 17 deletions(-)
Quoted 6 lines

But please do not move it to 'evsel.[ch]', i.e. you're introducing a new class, i.e. "perf_counts", you might as well put them in a separate file, i.e. tools/perf/util/counts.[ch].

And please rename perf_counts__alloc() to perf_counds__new(), ditto for __free() -> __delete(),

ok

jirka

author reviewer
#27 lore raw

PATCH 9/25 perf stat: Introduce perf_counts function

In reply to Jiri Olsa

Introducing perf_counts function, that returns 'struct perf_counts_values' pointer for given cpu.

---
 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                    |  6 ++++++
 5 files changed, 19 insertions(+), 13 deletions(-)
tools/perf/builtin-stat.c +7 -7
index 90766538fd8f..7d1aebd5e1e4 100644
@@ -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;
@@ -802,9 +802,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)
@@ -912,9 +912,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
index 8801983a38f0..a89a39f282ea 100644
@@ -97,9 +97,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
index bdfa1f446681..e86fc477a74f 100644
@@ -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
index fde2416921cc..1a6bdd16ec37 100644
@@ -945,8 +945,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;
@@ -1007,7 +1007,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 +6 -0
index ef619645a08f..3037c24e1fea 100644
@@ -134,6 +134,12 @@ void perf_evsel__compute_deltas(struct perf_evsel *evsel, int cpu,
 struct perf_counts *perf_counts__alloc(int ncpus);
 void perf_counts__free(struct perf_counts *counts);
 
+static inline struct perf_counts_values*
+perf_counts(struct perf_counts *counts, int cpu)
+{
+	return &counts->cpu[cpu];
+}
+
 int perf_evsel__object_config(size_t object_size,
 			      int (*init)(struct perf_evsel *evsel),
 			      void (*fini)(struct perf_evsel *evsel));
Signature · 1 line
1.9.3
author reviewer
#28 lore raw

PATCH 10/25 perf stat: Use xyarray for cpu evsel counts

In reply to Jiri Olsa

Switching 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/evsel.c           | 31 ++++++++++++++++++++++---------
 tools/perf/util/evsel.h           |  6 +++---
 4 files changed, 27 insertions(+), 14 deletions(-)
tools/perf/builtin-stat.c +1 -1
index 7d1aebd5e1e4..2221a75e11e5 100644
@@ -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
index e86fc477a74f..bd882f09ebbc 100644
@@ -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/evsel.c +22 -9
index 1a6bdd16ec37..e69a7ee4cc0b 100644
@@ -853,26 +853,39 @@ int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads)
 
 struct perf_counts *perf_counts__alloc(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__free(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__zero(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/evsel.h +3 -3
index 3037c24e1fea..12e87f917d44 100644
@@ -24,7 +24,7 @@ struct perf_counts_values {
 struct perf_counts {
 	s8		   	  scaled;
 	struct perf_counts_values aggr;
-	struct perf_counts_values cpu[];
+	struct xyarray		  *cpu;
 };
 
 struct perf_evsel;
@@ -137,7 +137,7 @@ void perf_counts__free(struct perf_counts *counts);
 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);
 }
 
 int perf_evsel__object_config(size_t object_size,
@@ -192,7 +192,7 @@ int perf_evsel__group_desc(struct perf_evsel *evsel, char *buf, size_t size);
 
 int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads);
 int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus);
-void perf_evsel__reset_counts(struct perf_evsel *evsel, int ncpus);
+void perf_evsel__reset_counts(struct perf_evsel *evsel);
 void perf_evsel__free_counts(struct perf_evsel *evsel);
 void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads);
 
Signature · 1 line
1.9.3
author reviewer
#29 lore raw

PATCH 11/25 perf stat: Make stats work over the thread dimension

In reply to Jiri Olsa

Now 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                    | 20 +++++++++----------
 tools/perf/util/evsel.h                    | 10 +++++-----
 5 files changed, 38 insertions(+), 34 deletions(-)
tools/perf/builtin-stat.c +18 -14
index 2221a75e11e5..8359f6dad441 100644
@@ -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__alloc(perf_evsel__nr_cpus(evsel));
+	counts = perf_counts__alloc(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++)
@@ -802,9 +806,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)
@@ -912,9 +916,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
index a89a39f282ea..d943c8b18fe1 100644
@@ -77,7 +77,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;
 	}
@@ -97,9 +97,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
index bd882f09ebbc..c9a37bc6b33a 100644
@@ -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 +10 -10
index e69a7ee4cc0b..b9f798732866 100644
@@ -851,14 +851,14 @@ int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads)
 	return 0;
 }
 
-struct perf_counts *perf_counts__alloc(int ncpus)
+struct perf_counts *perf_counts__alloc(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;
@@ -888,9 +888,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__alloc(ncpus);
+	evsel->counts = perf_counts__alloc(ncpus, nthreads);
 	return evsel->counts != NULL ? 0 : -ENOMEM;
 }
 
@@ -946,7 +946,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;
@@ -958,8 +958,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;
@@ -1012,15 +1012,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 +5 -5
index 12e87f917d44..5e3a9d875137 100644
@@ -128,16 +128,16 @@ 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);
 
-struct perf_counts *perf_counts__alloc(int ncpus);
+struct perf_counts *perf_counts__alloc(int ncpus, int nthreads);
 void perf_counts__free(struct perf_counts *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);
 }
 
 int perf_evsel__object_config(size_t object_size,
@@ -191,7 +191,7 @@ const char *perf_evsel__group_name(struct perf_evsel *evsel);
 int perf_evsel__group_desc(struct perf_evsel *evsel, char *buf, size_t size);
 
 int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads);
-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__reset_counts(struct perf_evsel *evsel);
 void perf_evsel__free_counts(struct perf_evsel *evsel);
 void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads);
Signature · 1 line
1.9.3
author reviewer
#30 lore raw

PATCH 12/25 perf stat: Rename struct perf_counts::cpu member to values

In reply to Jiri Olsa

Renaming 'struct xyarray *cpu' pointer to more fitting/generic values, because now we store both cpu and thread values.

---
 tools/perf/util/evsel.c | 12 ++++++------
 tools/perf/util/evsel.h |  4 ++--
 2 files changed, 8 insertions(+), 8 deletions(-)
tools/perf/util/evsel.c +6 -6
index b9f798732866..a5409d39392e 100644
@@ -856,15 +856,15 @@ struct perf_counts *perf_counts__alloc(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;
@@ -873,14 +873,14 @@ struct perf_counts *perf_counts__alloc(int ncpus, int nthreads)
 void perf_counts__free(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__zero(counts->cpu);
+	xyarray__zero(counts->values);
 }
 
 void perf_evsel__reset_counts(struct perf_evsel *evsel)
tools/perf/util/evsel.h +2 -2
index 5e3a9d875137..0d495bd161c3 100644
@@ -24,7 +24,7 @@ struct perf_counts_values {
 struct perf_counts {
 	s8		   	  scaled;
 	struct perf_counts_values aggr;
-	struct xyarray		  *cpu;
+	struct xyarray		  *values;
 };
 
 struct perf_evsel;
@@ -137,7 +137,7 @@ void perf_counts__free(struct perf_counts *counts);
 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);
 }
 
 int perf_evsel__object_config(size_t object_size,
Signature · 1 line
1.9.3
author reviewer
#31 lore raw

PATCH 13/25 perf stat: Move perf_evsel__(alloc|free|reset)_stat_priv into evsel object

In reply to Jiri Olsa

Moving perf_evsel__(alloc|free|reset)_stat_priv into evsel object, so it could be used outside stat object in following patches.

---
 tools/perf/builtin-stat.c | 25 -------------------------
 tools/perf/util/evsel.c   | 26 ++++++++++++++++++++++++++
 tools/perf/util/evsel.h   |  5 +++++
 3 files changed, 31 insertions(+), 25 deletions(-)
tools/perf/builtin-stat.c +0 -25
index 8359f6dad441..d6f23c3436ae 100644
@@ -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/evsel.c +26 -0
index a5409d39392e..7375dcc634da 100644
@@ -26,6 +26,7 @@
 #include "perf_regs.h"
 #include "debug.h"
 #include "trace-event.h"
+#include "stat.h"
 
 static struct {
 	bool sample_id_all;
@@ -851,6 +852,31 @@ int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads)
 	return 0;
 }
 
+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);
+}
+
 struct perf_counts *perf_counts__alloc(int ncpus, int nthreads)
 {
 	struct perf_counts *counts = zalloc(sizeof(*counts));
tools/perf/util/evsel.h +5 -0
index 0d495bd161c3..051175098f0b 100644
@@ -192,6 +192,11 @@ int perf_evsel__group_desc(struct perf_evsel *evsel, char *buf, size_t size);
 
 int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads);
 int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus, int nthreads);
+
+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);
+
 void perf_evsel__reset_counts(struct perf_evsel *evsel);
 void perf_evsel__free_counts(struct perf_evsel *evsel);
 void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads);
Signature · 1 line
1.9.3
#32 lore raw

Re: [PATCH 13/25] perf stat: Move perf_evsel__(alloc|free|reset)_stat_priv into evsel object

Em Wed, Jun 10, 2015 at 08:10:46PM +0200, Jiri Olsa escreveu:

Quoted 5 lines

Moving perf_evsel__(alloc|free|reset)_stat_priv into evsel object, so it could be used outside stat object in following patches.

+++ b/tools/perf/util/evsel.c

tools/perf/util/evsel.c int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads) · line 864

Quoted 10 lines
tools/perf/util/evsel.c +10 -0
+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);
+}

Please move this to some 'stat' specific place, so that evsel.c has nothing that is tool specific, like references to 'struct perf_stat'.

- Arnaldo

Quoted 35 lines
tools/perf/util/evsel.c +14 -0
+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);
+}
+
 struct perf_counts *perf_counts__alloc(int ncpus, int nthreads)
 {
 	struct perf_counts *counts = zalloc(sizeof(*counts));
tools/perf/util/evsel.h +5 -0
index 0d495bd161c3..051175098f0b 100644
@@ -192,6 +192,11 @@ int perf_evsel__group_desc(struct perf_evsel *evsel, char *buf, size_t size);
 
 int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads);
 int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus, int nthreads);
+
+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);
+
 void perf_evsel__reset_counts(struct perf_evsel *evsel);
 void perf_evsel__free_counts(struct perf_evsel *evsel);
 void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads);
Signature · 1 line
1.9.3
#33 lore raw

Re: [PATCH 13/25] perf stat: Move perf_evsel__(alloc|free|reset)_stat_priv into evsel object

Quoted 6 lines · Arnaldo Carvalho de Melo

Em Wed, Jun 10, 2015 at 08:10:46PM +0200, Jiri Olsa escreveu:

Quoted 4 lines

Moving perf_evsel__(alloc|free|reset)_stat_priv into evsel object, so it could be used outside stat object in following patches.

+++ b/tools/perf/util/evsel.c

Quoted 13 lines

tools/perf/util/evsel.c int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads) · line 864

Quoted 10 lines
tools/perf/util/evsel.c +10 -0
+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);
+}

Please move this to some 'stat' specific place, so that evsel.c has nothing that is tool specific, like references to 'struct perf_stat'.

ok, util/stat.c then

jirka

author reviewer
#34 lore raw

PATCH 14/25 perf stat: Move perf_evsel__(alloc|free)_prev_raw_counts into evsel object

In reply to Jiri Olsa

Moving perf_evsel__(alloc|free)_prev_raw_counts into evsel object, so it could be used in following patches.

---
 tools/perf/builtin-stat.c | 18 ------------------
 tools/perf/util/evsel.c   | 18 ++++++++++++++++++
 tools/perf/util/evsel.h   |  4 ++++
 3 files changed, 22 insertions(+), 18 deletions(-)
tools/perf/builtin-stat.c +0 -18
index d6f23c3436ae..b15fc47aa673 100644
@@ -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__alloc(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__free(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/evsel.c +18 -0
index 7375dcc634da..d5680f210fc4 100644
@@ -852,6 +852,24 @@ int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads)
 	return 0;
 }
 
+int perf_evsel__alloc_prev_raw_counts(struct perf_evsel *evsel,
+				      int ncpus, int nthreads)
+{
+	struct perf_counts *counts;
+
+	counts = perf_counts__alloc(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__free(evsel->prev_raw_counts);
+	evsel->prev_raw_counts = NULL;
+}
+
 void perf_evsel__reset_stat_priv(struct perf_evsel *evsel)
 {
 	int i;
tools/perf/util/evsel.h +4 -0
index 051175098f0b..d16ed197c00a 100644
@@ -193,6 +193,10 @@ int perf_evsel__group_desc(struct perf_evsel *evsel, char *buf, size_t size);
 int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads);
 int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus, int nthreads);
 
+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);
+
 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);
Signature · 1 line
1.9.3
author reviewer
#35 lore raw

PATCH 15/25 perf stat: Move perf_evlist__(alloc|free)_stats into evlist object

In reply to Jiri Olsa

Moving 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.c  | 32 ++++++++++++++++++++++++++++++++
 tools/perf/util/evlist.h  |  2 ++
 3 files changed, 34 insertions(+), 32 deletions(-)
tools/perf/builtin-stat.c +0 -32
index b15fc47aa673..5072ca809c23 100644
@@ -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.c +32 -0
index f438881040f2..44d52a07223c 100644
@@ -1651,3 +1651,35 @@ void perf_evlist__set_tracking_event(struct perf_evlist *evlist,
 
 	tracking_evsel->tracking = true;
 }
+
+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/evlist.h +2 -0
index 955bf31b7dd3..557083673bab 100644
@@ -288,4 +288,6 @@ void perf_evlist__to_front(struct perf_evlist *evlist,
 void perf_evlist__set_tracking_event(struct perf_evlist *evlist,
 				     struct perf_evsel *tracking_evsel);
 
+int perf_evlist__alloc_stats(struct perf_evlist *evlist, bool alloc_raw);
+void perf_evlist__free_stats(struct perf_evlist *evlist);
 #endif /* __PERF_EVLIST_H */
Signature · 1 line
1.9.3
#36 lore raw

Re: [PATCH 15/25] perf stat: Move perf_evlist__(alloc|free)_stats into evlist object

Em Wed, Jun 10, 2015 at 08:10:48PM +0200, Jiri Olsa escreveu:

Quoted 2 lines

Moving perf_evlist__(alloc|free)_stats into evsel object, so it could be used in following patches.

Can this go into the new counts.[ch] file too? As it is specific to counting tools?

- Arnaldo

Quoted 104 lines
---
 tools/perf/builtin-stat.c | 32 --------------------------------
 tools/perf/util/evlist.c  | 32 ++++++++++++++++++++++++++++++++
 tools/perf/util/evlist.h  |  2 ++
 3 files changed, 34 insertions(+), 32 deletions(-)
tools/perf/builtin-stat.c +0 -32
index b15fc47aa673..5072ca809c23 100644
@@ -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.c +32 -0
index f438881040f2..44d52a07223c 100644
@@ -1651,3 +1651,35 @@ void perf_evlist__set_tracking_event(struct perf_evlist *evlist,
 
 	tracking_evsel->tracking = true;
 }
+
+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/evlist.h +2 -0
index 955bf31b7dd3..557083673bab 100644
@@ -288,4 +288,6 @@ void perf_evlist__to_front(struct perf_evlist *evlist,
 void perf_evlist__set_tracking_event(struct perf_evlist *evlist,
 				     struct perf_evsel *tracking_evsel);
 
+int perf_evlist__alloc_stats(struct perf_evlist *evlist, bool alloc_raw);
+void perf_evlist__free_stats(struct perf_evlist *evlist);
 #endif /* __PERF_EVLIST_H */
Signature · 1 line
1.9.3
#37 lore raw

Re: [PATCH 15/25] perf stat: Move perf_evlist__(alloc|free)_stats into evlist object

Quoted 6 lines · Arnaldo Carvalho de Melo

Em Wed, Jun 10, 2015 at 08:10:48PM +0200, Jiri Olsa escreveu:

Quoted 2 lines

Moving perf_evlist__(alloc|free)_stats into evsel object, so it could be used in following patches.

Can this go into the new counts.[ch] file too? As it is specific to counting tools?

ook

jirka

author reviewer
#38 lore raw

PATCH 16/25 perf stat: Introduce perf_evsel__alloc_stats function

In reply to Jiri Olsa

Move all stat allocation logic related to evsel
object under single function. This way we can
use it separately for evsel object out of evlist
object.

---
 tools/perf/util/evlist.c |  7 +------
 tools/perf/util/evsel.c  | 13 +++++++++++++
 tools/perf/util/evsel.h  |  2 ++
 3 files changed, 16 insertions(+), 6 deletions(-)
tools/perf/util/evlist.c +1 -6
index 44d52a07223c..73db625ed1ce 100644
@@ -1655,14 +1655,9 @@ void perf_evlist__set_tracking_event(struct perf_evlist *evlist,
 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/evsel.c +13 -0
index d5680f210fc4..1608e29ab83d 100644
@@ -938,6 +938,19 @@ int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus, int nthreads)
 	return evsel->counts != NULL ? 0 : -ENOMEM;
 }
 
+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;
+}
+
 static void perf_evsel__free_fd(struct perf_evsel *evsel)
 {
 	xyarray__delete(evsel->fd);
tools/perf/util/evsel.h +2 -0
index d16ed197c00a..80929965f0f5 100644
@@ -201,6 +201,8 @@ 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_stats(struct perf_evsel *evsel, bool alloc_raw);
+
 void perf_evsel__reset_counts(struct perf_evsel *evsel);
 void perf_evsel__free_counts(struct perf_evsel *evsel);
 void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads);
Signature · 1 line
1.9.3
author reviewer
#39 lore raw

PATCH 17/25 perf stat: Introduce perf_evsel__read function

In reply to Jiri Olsa

Adding 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
index 1608e29ab83d..c1d210f8e799 100644
@@ -1060,6 +1060,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
index 80929965f0f5..9609df91abc1 100644
@@ -275,6 +275,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
author reviewer
#40 lore raw

PATCH 18/25 perf stat: Introduce read_counters function

In reply to Jiri Olsa

Moving 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
index 5072ca809c23..8fc40a3f3098 100644
@@ -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);
@@ -528,18 +536,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
author reviewer
#41 lore raw

PATCH 19/25 perf stat: Separate counters reading and processing

In reply to Jiri Olsa

Separating 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
index 8fc40a3f3098..59e1815e4def 100644
@@ -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
author reviewer
#42 lore raw

PATCH 20/25 perf stat: Move zero_per_pkg into counter process code

In reply to Jiri Olsa

Moving zero_per_pkg into counter process code.

---
 tools/perf/builtin-stat.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)
tools/perf/builtin-stat.c +3 -3
index 59e1815e4def..efc4d420f12e 100644
@@ -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
author reviewer
#43 lore raw

PATCH 21/25 perf stat: Move perf_stat initialization counter process code

In reply to Jiri Olsa

Moving perf_stat initialization counter process code.

---
 tools/perf/builtin-stat.c | 5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)
tools/perf/builtin-stat.c +1 -4
index efc4d420f12e..3ababdb83aad 100644
@@ -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
#44 lore raw

Re: [PATCH 21/25] perf stat: Move perf_stat initialization counter process code

tools/perf/builtin-stat.c static int process_counter(struct perf_evsel *counter) · line 294

Quoted 10 lines · Jiri Olsa
tools/perf/builtin-stat.c +1 -0
index efc4d420f12e..3ababdb83aad 100644
@@ -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));
 

init_stats()?

#45 lore raw

Re: [PATCH 21/25] perf stat: Move perf_stat initialization counter process code

Quoted 8 lines · David Ahern
Quoted 7 lines · Jiri Olsa
tools/perf/builtin-stat.c +0 -0
index efc4d420f12e..3ababdb83aad 100644
@@ -290,6 +290,7 @@ static int process_counter(struct perf_evsel *counter)
 	int i, ret;
 
Quoted 6 lines

tools/perf/builtin-stat.c static int process_counter(struct perf_evsel *counter) · line 294

Quoted 3 lines
tools/perf/builtin-stat.c +1 -0
 	aggr->val = aggr->ena = aggr->run = 0;
+	memset(ps->res_stats, 0, sizeof(ps->res_stats));
 

init_stats()?

right, thanks

jirka

#46 lore raw
In reply to Jiri Olsa
Quoted 3 lines · Jiri Olsa

hi,
adding the possibility to display stat data per thread. Allowing following commands and output:

available in here:
git://git.kernel.org/pub/scm/linux/kernel/git/jolsa/perf.git
perf/per_task

jirka

Quoted 91 lines
  $ perf stat -e cycles,instructions --per-task -p 12451,16173
  ^C
   Performance counter stats for process id '12451,16173':
  TASK-12451                77,784      cycles
  TASK-16173                64,809      cycles
  TASK-12451                14,432      instructions
  TASK-16173                14,452      instructions
         3.854957122 seconds time elapsed

Also woks under interval mode:

  $ ./perf stat -e cycles,instructions --per-task -p 16431,16173 -I 1000
  #           time task                      counts unit events
       1.000085816 TASK-16173                     0      cycles
       1.000085816 TASK-16431         3,358,360,926      cycles
       1.000085816 TASK-16173                     0      instructions
       1.000085816 TASK-16431         9,062,422,086      instructions
       2.000212262 TASK-16173                65,386      cycles
       2.000212262 TASK-16431         3,349,355,309      cycles
       2.000212262 TASK-16173                12,151      instructions
       2.000212262 TASK-16431         9,039,401,422      instructions
       3.000333402 TASK-16173                62,797      cycles
       3.000333402 TASK-16431         3,357,140,183      cycles
       3.000333402 TASK-16173                12,208      instructions
       3.000333402 TASK-16431         9,058,080,762      instructions
  ^C     3.375949851 TASK-16173                     0      cycles
       3.375949851 TASK-16431         1,264,764,804      cycles
       3.375949851 TASK-16173                     0      instructions
       3.375949851 TASK-16431         3,414,532,317      instructions

thanks for comments,
jirka

---
Jiri Olsa (25):
perf tools: Fix python code with missing stat dependency
perf tools: Introduce xyarray__zero function
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 stat: Introduce perf_counts__(alloc|free|reset) functions 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 evsel object perf stat: Move perf_evsel__(alloc|free)_prev_raw_counts into evsel 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: Introduce print_counters function
perf stat: Introduce --per-task option

 tools/perf/builtin-stat.c                  | 388 +++++++++++++++++++++++++++++--------------------------------
 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.c          |   6 +-
 tools/perf/tests/switch-tracking.c         |   4 +-
 tools/perf/util/cpumap.c                   |  24 +++-
 tools/perf/util/cpumap.h                   |   5 +-
 tools/perf/util/evlist.c                   |  61 +++++++++-
 tools/perf/util/evlist.h                   |   2 +
 tools/perf/util/evsel.c                    | 128 ++++++++++++++++----
 tools/perf/util/evsel.h                    |  48 ++++++--
 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.h                     |   1 +
 tools/perf/util/svghelper.c                |   2 +-
 tools/perf/util/thread_map.c               |  28 ++++-
 tools/perf/util/thread_map.h               |   6 +-
 tools/perf/util/xyarray.c                  |   8 ++
 tools/perf/util/xyarray.h                  |   2 +
 25 files changed, 484 insertions(+), 267 deletions(-)
author reviewer
#47 lore raw

PATCH 22/25 perf stat: Remove perf_evsel__read_cb function

In reply to Jiri Olsa

It'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
index c1d210f8e799..ea76f821a251 100644
@@ -1044,22 +1044,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
index 9609df91abc1..d1f894ea6520 100644
@@ -268,13 +268,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
author reviewer
#48 lore raw

PATCH 23/25 perf stat: Rename print_interval to process_interval

In reply to Jiri Olsa

It 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
index 3ababdb83aad..d73ae0f134d1 100644
@@ -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;
@@ -529,7 +529,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);
@@ -547,7 +547,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
author reviewer
#49 lore raw

PATCH 24/25 perf stat: Introduce print_counters function

In reply to Jiri Olsa

Centralize counters print code into single
print_counters function.

---
 tools/perf/builtin-stat.c | 127 +++++++++++++++++++++++-----------------------
 1 file changed, 64 insertions(+), 63 deletions(-)
tools/perf/builtin-stat.c +64 -63
index d73ae0f134d1..4a7cad8debac 100644
@@ -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)
@@ -904,9 +862,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);
@@ -932,36 +916,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;
@@ -1410,13 +1411,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
author reviewer
#50 lore raw

PATCH 25/25 perf stat: Introduce --per-task option

In reply to Jiri Olsa

Currently 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-task -p 12451,16173
  ^C
   Performance counter stats for process id '12451,16173':
  TASK-12451                77,784      cycles
  TASK-16173                64,809      cycles
  TASK-12451                14,432      instructions
  TASK-16173                14,452      instructions
         3.854957122 seconds time elapsed

Also woks under interval mode:

  $ ./perf stat -e cycles,instructions --per-task -p 16431,16173 -I 1000
  #           time task                      counts unit events
       1.000085816 TASK-16173                     0      cycles
       1.000085816 TASK-16431         3,358,360,926      cycles
       1.000085816 TASK-16173                     0      instructions
       1.000085816 TASK-16431         9,062,422,086      instructions
       2.000212262 TASK-16173                65,386      cycles
       2.000212262 TASK-16431         3,349,355,309      cycles
       2.000212262 TASK-16173                12,151      instructions
       2.000212262 TASK-16431         9,039,401,422      instructions
       3.000333402 TASK-16173                62,797      cycles
       3.000333402 TASK-16431         3,357,140,183      cycles
       3.000333402 TASK-16173                12,208      instructions
       3.000333402 TASK-16431         9,058,080,762      instructions
  ^C     3.375949851 TASK-16173                     0      cycles
       3.375949851 TASK-16431         1,264,764,804      cycles
       3.375949851 TASK-16173                     0      instructions
       3.375949851 TASK-16431         3,414,532,317      instructions
---
 tools/perf/builtin-stat.c | 57 +++++++++++++++++++++++++++++++++++++++++++++--
 tools/perf/util/stat.h    |  1 +
 2 files changed, 56 insertions(+), 2 deletions(-)
tools/perf/builtin-stat.c +55 -2
index 4a7cad8debac..293d1029e2ba 100644
@@ -237,6 +237,7 @@ process_counter_values(struct perf_evsel *evsel, int cpu, int thread,
 		count = &zero;
 
 	switch (aggr_mode) {
+	case AGGR_TASK:
 	case AGGR_CORE:
 	case AGGR_SOCKET:
 	case AGGR_NONE:
@@ -605,6 +606,11 @@ static void aggr_printout(struct perf_evsel *evsel, int id, int nr)
 			csv_output ? 0 : -4,
 			perf_evsel__cpus(evsel)->map[id], csv_sep);
 		break;
+	case AGGR_TASK:
+		fprintf(output, "TASK-%*d%s",
+			csv_output ? 0 : -8,
+			evsel->threads->map[id], csv_sep);
+		break;
 	case AGGR_GLOBAL:
 	default:
 		break;
@@ -753,6 +759,40 @@ static void print_aggr(char *prefix)
 	}
 }
 
+static void print_aggr_task(struct perf_evsel *counter, char *prefix)
+{
+	int nthreads = thread_map__nr(counter->threads);
+	int ncpus = cpu_map__nr(counter->cpus);
+	int cpu, thread;
+	double uval;
+
+	for (thread = 0; thread < nthreads; thread++) {
+		u64 ena = 0, run = 0, val = 0;
+
+		for (cpu = 0; cpu < ncpus; cpu++) {
+			val += perf_counts(counter->counts, cpu, thread)->val;
+			ena += perf_counts(counter->counts, cpu, thread)->ena;
+			run += perf_counts(counter->counts, cpu, thread)->run;
+		}
+
+		if (prefix)
+			fprintf(output, "%s", prefix);
+
+		uval = val * counter->scale;
+
+		if (nsec_counter(counter))
+			nsec_printout(thread, 0, counter, uval);
+		else
+			abs_printout(thread, 0, counter, uval);
+
+		if (!csv_output)
+			print_noise(counter, 1.0);
+
+		print_running(run, ena);
+		fputc('\n', output);
+	}
+}
+
 /*
  * Print out the results of a single counter:
  * aggregated counts in system-wide mode
@@ -879,6 +919,9 @@ static void print_interval(char *prefix, struct timespec *ts)
 		case AGGR_NONE:
 			fprintf(output, "#           time CPU                counts %*s events\n", unit_width, "unit");
 			break;
+		case AGGR_TASK:
+			fprintf(output, "#           time task                      counts %*s events\n", unit_width, "unit");
+			break;
 		case AGGR_GLOBAL:
 		default:
 			fprintf(output, "#           time             counts %*s events\n", unit_width, "unit");
@@ -947,6 +990,10 @@ static void print_counters(struct timespec *ts, int argc, const char **argv)
 	case AGGR_SOCKET:
 		print_aggr(prefix);
 		break;
+	case AGGR_TASK:
+		evlist__for_each(evsel_list, counter)
+			print_aggr_task(counter, prefix);
+		break;
 	case AGGR_GLOBAL:
 		evlist__for_each(evsel_list, counter)
 			print_counter_aggr(counter, prefix);
@@ -1034,6 +1081,7 @@ static int perf_stat_init_aggr_mode(void)
 		break;
 	case AGGR_NONE:
 	case AGGR_GLOBAL:
+	case AGGR_TASK:
 	default:
 		break;
 	}
@@ -1258,6 +1306,8 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
 		     "aggregate counts per processor socket", AGGR_SOCKET),
 	OPT_SET_UINT(0, "per-core", &aggr_mode,
 		     "aggregate counts per physical processor core", AGGR_CORE),
+	OPT_SET_UINT(0, "per-task", &aggr_mode,
+		     "aggregate counts per task", AGGR_TASK),
 	OPT_UINTEGER('D', "delay", &initial_delay,
 		     "ms to wait before starting measurement after program start"),
 	OPT_END()
@@ -1349,8 +1399,11 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
 		run_count = 1;
 	}
 
-	/* no_aggr, cgroup are for system-wide only */
-	if ((aggr_mode != AGGR_GLOBAL || nr_cgroups) &&
+	/*
+	 * no_aggr, cgroup are for system-wide only
+	 * --per-task is aggregated per task, we dont mix it with cpu mode
+	 */
+	if (((aggr_mode != AGGR_GLOBAL && aggr_mode != AGGR_TASK) || nr_cgroups) &&
 	    !target__has_cpu(&target)) {
 		fprintf(stderr, "both cgroup and no-aggregation "
 			"modes only available in system-wide mode\n");
tools/perf/util/stat.h +1 -0
index 615c779eb42a..e4c616af057d 100644
@@ -29,6 +29,7 @@ enum aggr_mode {
 	AGGR_GLOBAL,
 	AGGR_SOCKET,
 	AGGR_CORE,
+	AGGR_TASK,
 };
 
 void update_stats(struct stats *stats, u64 val);
Signature · 1 line
1.9.3
#51 lore raw
Quoted 28 lines · Jiri Olsa

Currently 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-task -p 12451,16173
   ^C
    Performance counter stats for process id '12451,16173':
   TASK-12451                77,784      cycles
   TASK-16173                64,809      cycles
   TASK-12451                14,432      instructions
   TASK-16173                14,452      instructions
          3.854957122 seconds time elapsed

Also woks under interval mode:

   $ ./perf stat -e cycles,instructions --per-task -p 16431,16173 -I 1000
   #           time task                      counts unit events
        1.000085816 TASK-16173                     0      cycles
        1.000085816 TASK-16431         3,358,360,926      cycles
        1.000085816 TASK-16173                     0      instructions
        1.000085816 TASK-16431         9,062,422,086      instructions
        2.000212262 TASK-16173                65,386      cycles
        2.000212262 TASK-16431         3,349,355,309      cycles
        2.000212262 TASK-16173                12,151      instructions
        2.000212262 TASK-16431         9,039,401,422      instructions
Quoted 9 lines
        3.000333402 TASK-16173                62,797      cycles
        3.000333402 TASK-16431         3,357,140,183      cycles
        3.000333402 TASK-16173                12,208      instructions
        3.000333402 TASK-16431         9,058,080,762      instructions
   ^C     3.375949851 TASK-16173                     0      cycles
        3.375949851 TASK-16431         1,264,764,804      cycles
        3.375949851 TASK-16173                     0      instructions
        3.375949851 TASK-16431         3,414,532,317      instructions

Why not print $comm-$pid versus TASK-$pid?

#52 lore raw

On Wed, Jun 10, 2015 at 12:44:34PM -0600, David Ahern wrote:

SNIP

Quoted 11 lines
Quoted 10 lines
       2.000212262 TASK-16431         9,039,401,422      instructions
       3.000333402 TASK-16173                62,797      cycles
       3.000333402 TASK-16431         3,357,140,183      cycles
       3.000333402 TASK-16173                12,208      instructions
       3.000333402 TASK-16431         9,058,080,762      instructions
  ^C     3.375949851 TASK-16173                     0      cycles
       3.375949851 TASK-16431         1,264,764,804      cycles
       3.375949851 TASK-16173                     0      instructions
       3.375949851 TASK-16431         3,414,532,317      instructions
Quoted 2 lines

Why not print $comm-$pid versus TASK-$pid?

yep, good idea

jirka

#53 lore raw
In reply to David Ahern

Em Wed, Jun 10, 2015 at 12:44:34PM -0600, David Ahern escreveu:

Quoted 11 lines · Jiri Olsa
Quoted 9 lines

Also woks under interval mode:

  $ ./perf stat -e cycles,instructions --per-task -p 16431,16173 -I 1000
  #           time task                      counts unit events
       1.000085816 TASK-16173                     0      cycles
       1.000085816 TASK-16431         3,358,360,926      cycles
       3.375949851 TASK-16173                     0      instructions
       3.375949851 TASK-16431         3,414,532,317      instructions
Quoted 1 line

Why not print $comm-$pid versus TASK-$pid?

Agreed.

- Arnaldo