-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
perf report: Fix and improve the displaying of per-thread event counters
Improve and fix the handling of per-thread counter stats recorded via perf record -s. Previously we only displayed it in debug printouts (-D) and even that output was hard to disambiguate. I moved everything to utils/values.[ch] so that we may reuse it in perf stat. We get something like this now: # PID TID cache-misses cache-references 4658 4659 495581 3238779 4658 4662 498246 3236823 4658 4663 499531 3243162 Then it'll be easy to add --pretty=raw to display a single line per thread/event. By the way, -S was also used for --symbol... So I used -T/--thread here. perf report: Add -T/--threads to display per-thread counter values We get something like this now: # PID TID cache-misses cache-references 4658 4659 495581 3238779 4658 4662 498246 3236823 4658 4663 499531 3243162 Per-thread arrays of counter values are managed in utils/values.[ch] Signed-off-by: Brice Goglin <Brice.Goglin@inria.fr> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Cc: paulus@samba.org Signed-off-by: Ingo Molnar <mingo@elte.hu>
- Loading branch information
Brice Goglin
authored and
Ingo Molnar
committed
Aug 9, 2009
1 parent
30dd568
commit 8d51327
Showing
5 changed files
with
227 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,171 @@ | ||
#include <stdlib.h> | ||
|
||
#include "util.h" | ||
#include "values.h" | ||
|
||
void perf_read_values_init(struct perf_read_values *values) | ||
{ | ||
values->threads_max = 16; | ||
values->pid = malloc(values->threads_max * sizeof(*values->pid)); | ||
values->tid = malloc(values->threads_max * sizeof(*values->tid)); | ||
values->value = malloc(values->threads_max * sizeof(*values->value)); | ||
if (!values->pid || !values->tid || !values->value) | ||
die("failed to allocate read_values threads arrays"); | ||
values->threads = 0; | ||
|
||
values->counters_max = 16; | ||
values->counterrawid = malloc(values->counters_max | ||
* sizeof(*values->counterrawid)); | ||
values->countername = malloc(values->counters_max | ||
* sizeof(*values->countername)); | ||
if (!values->counterrawid || !values->countername) | ||
die("failed to allocate read_values counters arrays"); | ||
values->counters = 0; | ||
} | ||
|
||
void perf_read_values_destroy(struct perf_read_values *values) | ||
{ | ||
int i; | ||
|
||
if (!values->threads_max || !values->counters_max) | ||
return; | ||
|
||
for (i = 0; i < values->threads; i++) | ||
free(values->value[i]); | ||
free(values->pid); | ||
free(values->tid); | ||
free(values->counterrawid); | ||
for (i = 0; i < values->counters; i++) | ||
free(values->countername[i]); | ||
free(values->countername); | ||
} | ||
|
||
static void perf_read_values__enlarge_threads(struct perf_read_values *values) | ||
{ | ||
values->threads_max *= 2; | ||
values->pid = realloc(values->pid, | ||
values->threads_max * sizeof(*values->pid)); | ||
values->tid = realloc(values->tid, | ||
values->threads_max * sizeof(*values->tid)); | ||
values->value = realloc(values->value, | ||
values->threads_max * sizeof(*values->value)); | ||
if (!values->pid || !values->tid || !values->value) | ||
die("failed to enlarge read_values threads arrays"); | ||
} | ||
|
||
static int perf_read_values__findnew_thread(struct perf_read_values *values, | ||
u32 pid, u32 tid) | ||
{ | ||
int i; | ||
|
||
for (i = 0; i < values->threads; i++) | ||
if (values->pid[i] == pid && values->tid[i] == tid) | ||
return i; | ||
|
||
if (values->threads == values->threads_max) | ||
perf_read_values__enlarge_threads(values); | ||
|
||
i = values->threads++; | ||
values->pid[i] = pid; | ||
values->tid[i] = tid; | ||
values->value[i] = malloc(values->counters_max * sizeof(**values->value)); | ||
if (!values->value[i]) | ||
die("failed to allocate read_values counters array"); | ||
|
||
return i; | ||
} | ||
|
||
static void perf_read_values__enlarge_counters(struct perf_read_values *values) | ||
{ | ||
int i; | ||
|
||
values->counters_max *= 2; | ||
values->counterrawid = realloc(values->counterrawid, | ||
values->counters_max * sizeof(*values->counterrawid)); | ||
values->countername = realloc(values->countername, | ||
values->counters_max * sizeof(*values->countername)); | ||
if (!values->counterrawid || !values->countername) | ||
die("failed to enlarge read_values counters arrays"); | ||
|
||
for (i = 0; i < values->threads; i++) { | ||
values->value[i] = realloc(values->value[i], | ||
values->counters_max * sizeof(**values->value)); | ||
if (!values->value[i]) | ||
die("failed to enlarge read_values counters arrays"); | ||
} | ||
} | ||
|
||
static int perf_read_values__findnew_counter(struct perf_read_values *values, | ||
u64 rawid, char *name) | ||
{ | ||
int i; | ||
|
||
for (i = 0; i < values->counters; i++) | ||
if (values->counterrawid[i] == rawid) | ||
return i; | ||
|
||
if (values->counters == values->counters_max) | ||
perf_read_values__enlarge_counters(values); | ||
|
||
i = values->counters++; | ||
values->counterrawid[i] = rawid; | ||
values->countername[i] = strdup(name); | ||
|
||
return i; | ||
} | ||
|
||
void perf_read_values_add_value(struct perf_read_values *values, | ||
u32 pid, u32 tid, | ||
u64 rawid, char *name, u64 value) | ||
{ | ||
int tindex, cindex; | ||
|
||
tindex = perf_read_values__findnew_thread(values, pid, tid); | ||
cindex = perf_read_values__findnew_counter(values, rawid, name); | ||
|
||
values->value[tindex][cindex] = value; | ||
} | ||
|
||
void perf_read_values_display(FILE *fp, struct perf_read_values *values) | ||
{ | ||
int i, j; | ||
int pidwidth, tidwidth; | ||
int *counterwidth; | ||
|
||
counterwidth = malloc(values->counters * sizeof(*counterwidth)); | ||
if (!counterwidth) | ||
die("failed to allocate counterwidth array"); | ||
tidwidth = 3; | ||
pidwidth = 3; | ||
for (j = 0; j < values->counters; j++) | ||
counterwidth[j] = strlen(values->countername[j]); | ||
for (i = 0; i < values->threads; i++) { | ||
int width; | ||
|
||
width = snprintf(NULL, 0, "%d", values->pid[i]); | ||
if (width > pidwidth) | ||
pidwidth = width; | ||
width = snprintf(NULL, 0, "%d", values->tid[i]); | ||
if (width > tidwidth) | ||
tidwidth = width; | ||
for (j = 0; j < values->counters; j++) { | ||
width = snprintf(NULL, 0, "%Lu", values->value[i][j]); | ||
if (width > counterwidth[j]) | ||
counterwidth[j] = width; | ||
} | ||
} | ||
|
||
fprintf(fp, "# %*s %*s", pidwidth, "PID", tidwidth, "TID"); | ||
for (j = 0; j < values->counters; j++) | ||
fprintf(fp, " %*s", counterwidth[j], values->countername[j]); | ||
fprintf(fp, "\n"); | ||
|
||
for (i = 0; i < values->threads; i++) { | ||
fprintf(fp, " %*d %*d", pidwidth, values->pid[i], | ||
tidwidth, values->tid[i]); | ||
for (j = 0; j < values->counters; j++) | ||
fprintf(fp, " %*Lu", | ||
counterwidth[j], values->value[i][j]); | ||
fprintf(fp, "\n"); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
#ifndef _PERF_VALUES_H | ||
#define _PERF_VALUES_H | ||
|
||
#include "types.h" | ||
|
||
struct perf_read_values { | ||
int threads; | ||
int threads_max; | ||
u32 *pid, *tid; | ||
int counters; | ||
int counters_max; | ||
u64 *counterrawid; | ||
char **countername; | ||
u64 **value; | ||
}; | ||
|
||
void perf_read_values_init(struct perf_read_values *values); | ||
void perf_read_values_destroy(struct perf_read_values *values); | ||
|
||
void perf_read_values_add_value(struct perf_read_values *values, | ||
u32 pid, u32 tid, | ||
u64 rawid, char *name, u64 value); | ||
|
||
void perf_read_values_display(FILE *fp, struct perf_read_values *values); | ||
|
||
#endif /* _PERF_VALUES_H */ |