tools/perf: Add support for record transaction flags

Add support for recording and displaying the transaction flags.
They are essentially a new sort key. Also display them
in a nice way to the user.

Signed-off-by: Andi Kleen <ak@linux.intel.com>
Acked-by: Jiri Olsa <jolsa@redhat.com>
Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/1379688044-14173-6-git-send-email-andi@firstfloor.org
Signed-off-by: Ingo Molnar <mingo@kernel.org>
This commit is contained in:
Andi Kleen 2013-09-20 07:40:43 -07:00 committed by Ingo Molnar
parent 0126d493b6
commit 475eeab9f3
17 changed files with 122 additions and 15 deletions

View File

@ -179,12 +179,14 @@ is enabled for all the sampling events. The sampled branch type is the same for
The various filters must be specified as a comma separated list: --branch-filter any_ret,u,k The various filters must be specified as a comma separated list: --branch-filter any_ret,u,k
Note that this feature may not be available on all processors. Note that this feature may not be available on all processors.
-W::
--weight:: --weight::
Enable weightened sampling. An additional weight is recorded per sample and can be Enable weightened sampling. An additional weight is recorded per sample and can be
displayed with the weight and local_weight sort keys. This currently works for TSX displayed with the weight and local_weight sort keys. This currently works for TSX
abort events and some memory events in precise mode on modern Intel CPUs. abort events and some memory events in precise mode on modern Intel CPUs.
--transaction::
Record transaction flags for transaction related events.
SEE ALSO SEE ALSO
-------- --------
linkperf:perf-stat[1], linkperf:perf-list[1] linkperf:perf-stat[1], linkperf:perf-list[1]

View File

@ -72,6 +72,10 @@ OPTIONS
- cpu: cpu number the task ran at the time of sample - cpu: cpu number the task ran at the time of sample
- srcline: filename and line number executed at the time of sample. The - srcline: filename and line number executed at the time of sample. The
DWARF debugging info must be provided. DWARF debugging info must be provided.
- weight: Event specific weight, e.g. memory latency or transaction
abort cost. This is the global weight.
- local_weight: Local weight version of the weight above.
- transaction: Transaction abort flags.
By default, comm, dso and symbol keys are used. By default, comm, dso and symbol keys are used.
(i.e. --sort comm,dso,symbol) (i.e. --sort comm,dso,symbol)

View File

@ -113,7 +113,7 @@ Default is to monitor all CPUS.
-s:: -s::
--sort:: --sort::
Sort by key(s): pid, comm, dso, symbol, parent, srcline, weight, Sort by key(s): pid, comm, dso, symbol, parent, srcline, weight,
local_weight, abort, in_tx local_weight, abort, in_tx, transaction
-n:: -n::
--show-nr-samples:: --show-nr-samples::

View File

@ -63,7 +63,7 @@ static int perf_evsel__add_sample(struct perf_evsel *evsel,
return 0; return 0;
} }
he = __hists__add_entry(&evsel->hists, al, NULL, 1, 1); he = __hists__add_entry(&evsel->hists, al, NULL, 1, 1, 0);
if (he == NULL) if (he == NULL)
return -ENOMEM; return -ENOMEM;

View File

@ -304,9 +304,10 @@ static int formula_fprintf(struct hist_entry *he, struct hist_entry *pair,
static int hists__add_entry(struct hists *self, static int hists__add_entry(struct hists *self,
struct addr_location *al, u64 period, struct addr_location *al, u64 period,
u64 weight) u64 weight, u64 transaction)
{ {
if (__hists__add_entry(self, al, NULL, period, weight) != NULL) if (__hists__add_entry(self, al, NULL, period, weight, transaction)
!= NULL)
return 0; return 0;
return -ENOMEM; return -ENOMEM;
} }
@ -328,7 +329,8 @@ static int diff__process_sample_event(struct perf_tool *tool __maybe_unused,
if (al.filtered) if (al.filtered)
return 0; return 0;
if (hists__add_entry(&evsel->hists, &al, sample->period, sample->weight)) { if (hists__add_entry(&evsel->hists, &al, sample->period,
sample->weight, sample->transaction)) {
pr_warning("problem incrementing symbol period, skipping event\n"); pr_warning("problem incrementing symbol period, skipping event\n");
return -1; return -1;
} }

View File

@ -894,6 +894,8 @@ const struct option record_options[] = {
parse_branch_stack), parse_branch_stack),
OPT_BOOLEAN('W', "weight", &record.opts.sample_weight, OPT_BOOLEAN('W', "weight", &record.opts.sample_weight,
"sample by weight (on special events only)"), "sample by weight (on special events only)"),
OPT_BOOLEAN(0, "transaction", &record.opts.sample_transaction,
"sample transaction flags (special events only)"),
OPT_END() OPT_END()
}; };

View File

@ -259,7 +259,7 @@ static int perf_evsel__add_hist_entry(struct perf_evsel *evsel,
} }
he = __hists__add_entry(&evsel->hists, al, parent, sample->period, he = __hists__add_entry(&evsel->hists, al, parent, sample->period,
sample->weight); sample->weight, sample->transaction);
if (he == NULL) if (he == NULL)
return -ENOMEM; return -ENOMEM;
@ -787,7 +787,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
"sort by key(s): pid, comm, dso, symbol, parent, cpu, srcline," "sort by key(s): pid, comm, dso, symbol, parent, cpu, srcline,"
" dso_to, dso_from, symbol_to, symbol_from, mispredict," " dso_to, dso_from, symbol_to, symbol_from, mispredict,"
" weight, local_weight, mem, symbol_daddr, dso_daddr, tlb, " " weight, local_weight, mem, symbol_daddr, dso_daddr, tlb, "
"snoop, locked, abort, in_tx"), "snoop, locked, abort, in_tx, transaction"),
OPT_BOOLEAN(0, "showcpuutilization", &symbol_conf.show_cpu_utilization, OPT_BOOLEAN(0, "showcpuutilization", &symbol_conf.show_cpu_utilization,
"Show sample percentage for different cpu modes"), "Show sample percentage for different cpu modes"),
OPT_STRING('p', "parent", &parent_pattern, "regex", OPT_STRING('p', "parent", &parent_pattern, "regex",

View File

@ -247,9 +247,8 @@ static struct hist_entry *perf_evsel__add_hist_entry(struct perf_evsel *evsel,
pthread_mutex_lock(&evsel->hists.lock); pthread_mutex_lock(&evsel->hists.lock);
he = __hists__add_entry(&evsel->hists, al, NULL, sample->period, he = __hists__add_entry(&evsel->hists, al, NULL, sample->period,
sample->weight); sample->weight, sample->transaction);
pthread_mutex_unlock(&evsel->hists.lock); pthread_mutex_unlock(&evsel->hists.lock);
if (he == NULL) if (he == NULL)
return NULL; return NULL;
@ -1104,7 +1103,7 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
"be more verbose (show counter open errors, etc)"), "be more verbose (show counter open errors, etc)"),
OPT_STRING('s', "sort", &sort_order, "key[,key2...]", OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
"sort by key(s): pid, comm, dso, symbol, parent, weight, local_weight," "sort by key(s): pid, comm, dso, symbol, parent, weight, local_weight,"
" abort, in_tx"), " abort, in_tx, transaction"),
OPT_BOOLEAN('n', "show-nr-samples", &symbol_conf.show_nr_samples, OPT_BOOLEAN('n', "show-nr-samples", &symbol_conf.show_nr_samples,
"Show a column with the number of samples"), "Show a column with the number of samples"),
OPT_CALLBACK_DEFAULT('G', "call-graph", &top.record_opts, OPT_CALLBACK_DEFAULT('G', "call-graph", &top.record_opts,

View File

@ -233,6 +233,7 @@ struct perf_record_opts {
u64 default_interval; u64 default_interval;
u64 user_interval; u64 user_interval;
u16 stack_dump_size; u16 stack_dump_size;
bool sample_transaction;
}; };
#endif #endif

View File

@ -222,7 +222,8 @@ static int add_hist_entries(struct perf_evlist *evlist, struct machine *machine)
&sample) < 0) &sample) < 0)
goto out; goto out;
he = __hists__add_entry(&evsel->hists, &al, NULL, 1, 1); he = __hists__add_entry(&evsel->hists, &al, NULL,
1, 1, 0);
if (he == NULL) if (he == NULL)
goto out; goto out;
@ -244,7 +245,8 @@ static int add_hist_entries(struct perf_evlist *evlist, struct machine *machine)
&sample) < 0) &sample) < 0)
goto out; goto out;
he = __hists__add_entry(&evsel->hists, &al, NULL, 1, 1); he = __hists__add_entry(&evsel->hists, &al, NULL, 1, 1,
0);
if (he == NULL) if (he == NULL)
goto out; goto out;

View File

@ -111,6 +111,7 @@ struct perf_sample {
u64 stream_id; u64 stream_id;
u64 period; u64 period;
u64 weight; u64 weight;
u64 transaction;
u32 cpu; u32 cpu;
u32 raw_size; u32 raw_size;
u64 data_src; u64 data_src;

View File

@ -681,6 +681,9 @@ void perf_evsel__config(struct perf_evsel *evsel,
attr->mmap2 = track && !perf_missing_features.mmap2; attr->mmap2 = track && !perf_missing_features.mmap2;
attr->comm = track; attr->comm = track;
if (opts->sample_transaction)
attr->sample_type |= PERF_SAMPLE_TRANSACTION;
/* /*
* XXX see the function comment above * XXX see the function comment above
* *
@ -1470,6 +1473,12 @@ int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event,
array++; array++;
} }
data->transaction = 0;
if (type & PERF_SAMPLE_TRANSACTION) {
data->transaction = *array;
array++;
}
return 0; return 0;
} }

View File

@ -160,6 +160,10 @@ void hists__calc_col_len(struct hists *hists, struct hist_entry *h)
hists__new_col_len(hists, HISTC_MEM_LVL, 21 + 3); hists__new_col_len(hists, HISTC_MEM_LVL, 21 + 3);
hists__new_col_len(hists, HISTC_LOCAL_WEIGHT, 12); hists__new_col_len(hists, HISTC_LOCAL_WEIGHT, 12);
hists__new_col_len(hists, HISTC_GLOBAL_WEIGHT, 12); hists__new_col_len(hists, HISTC_GLOBAL_WEIGHT, 12);
if (h->transaction)
hists__new_col_len(hists, HISTC_TRANSACTION,
hist_entry__transaction_len());
} }
void hists__output_recalc_col_len(struct hists *hists, int max_rows) void hists__output_recalc_col_len(struct hists *hists, int max_rows)
@ -466,7 +470,7 @@ struct hist_entry *__hists__add_branch_entry(struct hists *self,
struct hist_entry *__hists__add_entry(struct hists *self, struct hist_entry *__hists__add_entry(struct hists *self,
struct addr_location *al, struct addr_location *al,
struct symbol *sym_parent, u64 period, struct symbol *sym_parent, u64 period,
u64 weight) u64 weight, u64 transaction)
{ {
struct hist_entry entry = { struct hist_entry entry = {
.thread = al->thread, .thread = al->thread,
@ -487,6 +491,7 @@ struct hist_entry *__hists__add_entry(struct hists *self,
.hists = self, .hists = self,
.branch_info = NULL, .branch_info = NULL,
.mem_info = NULL, .mem_info = NULL,
.transaction = transaction,
}; };
return add_hist_entry(self, &entry, al, period, weight); return add_hist_entry(self, &entry, al, period, weight);

View File

@ -59,6 +59,7 @@ enum hist_column {
HISTC_MEM_TLB, HISTC_MEM_TLB,
HISTC_MEM_LVL, HISTC_MEM_LVL,
HISTC_MEM_SNOOP, HISTC_MEM_SNOOP,
HISTC_TRANSACTION,
HISTC_NR_COLS, /* Last entry */ HISTC_NR_COLS, /* Last entry */
}; };
@ -84,9 +85,10 @@ struct hists {
struct hist_entry *__hists__add_entry(struct hists *self, struct hist_entry *__hists__add_entry(struct hists *self,
struct addr_location *al, struct addr_location *al,
struct symbol *parent, u64 period, struct symbol *parent, u64 period,
u64 weight); u64 weight, u64 transaction);
int64_t hist_entry__cmp(struct hist_entry *left, struct hist_entry *right); int64_t hist_entry__cmp(struct hist_entry *left, struct hist_entry *right);
int64_t hist_entry__collapse(struct hist_entry *left, struct hist_entry *right); int64_t hist_entry__collapse(struct hist_entry *left, struct hist_entry *right);
int hist_entry__transaction_len(void);
int hist_entry__sort_snprintf(struct hist_entry *self, char *bf, size_t size, int hist_entry__sort_snprintf(struct hist_entry *self, char *bf, size_t size,
struct hists *hists); struct hists *hists);
void hist_entry__free(struct hist_entry *); void hist_entry__free(struct hist_entry *);

View File

@ -858,6 +858,9 @@ static void dump_sample(struct perf_evsel *evsel, union perf_event *event,
if (sample_type & PERF_SAMPLE_DATA_SRC) if (sample_type & PERF_SAMPLE_DATA_SRC)
printf(" . data_src: 0x%"PRIx64"\n", sample->data_src); printf(" . data_src: 0x%"PRIx64"\n", sample->data_src);
if (sample_type & PERF_SAMPLE_TRANSACTION)
printf("... transaction: %" PRIx64 "\n", sample->transaction);
if (sample_type & PERF_SAMPLE_READ) if (sample_type & PERF_SAMPLE_READ)
sample_read__printf(sample, evsel->attr.read_format); sample_read__printf(sample, evsel->attr.read_format);
} }

View File

@ -907,6 +907,78 @@ struct sort_entry sort_in_tx = {
.se_width_idx = HISTC_IN_TX, .se_width_idx = HISTC_IN_TX,
}; };
static int64_t
sort__transaction_cmp(struct hist_entry *left, struct hist_entry *right)
{
return left->transaction - right->transaction;
}
static inline char *add_str(char *p, const char *str)
{
strcpy(p, str);
return p + strlen(str);
}
static struct txbit {
unsigned flag;
const char *name;
int skip_for_len;
} txbits[] = {
{ PERF_TXN_ELISION, "EL ", 0 },
{ PERF_TXN_TRANSACTION, "TX ", 1 },
{ PERF_TXN_SYNC, "SYNC ", 1 },
{ PERF_TXN_ASYNC, "ASYNC ", 0 },
{ PERF_TXN_RETRY, "RETRY ", 0 },
{ PERF_TXN_CONFLICT, "CON ", 0 },
{ PERF_TXN_CAPACITY_WRITE, "CAP-WRITE ", 1 },
{ PERF_TXN_CAPACITY_READ, "CAP-READ ", 0 },
{ 0, NULL, 0 }
};
int hist_entry__transaction_len(void)
{
int i;
int len = 0;
for (i = 0; txbits[i].name; i++) {
if (!txbits[i].skip_for_len)
len += strlen(txbits[i].name);
}
len += 4; /* :XX<space> */
return len;
}
static int hist_entry__transaction_snprintf(struct hist_entry *self, char *bf,
size_t size, unsigned int width)
{
u64 t = self->transaction;
char buf[128];
char *p = buf;
int i;
buf[0] = 0;
for (i = 0; txbits[i].name; i++)
if (txbits[i].flag & t)
p = add_str(p, txbits[i].name);
if (t && !(t & (PERF_TXN_SYNC|PERF_TXN_ASYNC)))
p = add_str(p, "NEITHER ");
if (t & PERF_TXN_ABORT_MASK) {
sprintf(p, ":%" PRIx64,
(t & PERF_TXN_ABORT_MASK) >>
PERF_TXN_ABORT_SHIFT);
p += strlen(p);
}
return repsep_snprintf(bf, size, "%-*s", width, buf);
}
struct sort_entry sort_transaction = {
.se_header = "Transaction ",
.se_cmp = sort__transaction_cmp,
.se_snprintf = hist_entry__transaction_snprintf,
.se_width_idx = HISTC_TRANSACTION,
};
struct sort_dimension { struct sort_dimension {
const char *name; const char *name;
struct sort_entry *entry; struct sort_entry *entry;
@ -925,6 +997,7 @@ static struct sort_dimension common_sort_dimensions[] = {
DIM(SORT_SRCLINE, "srcline", sort_srcline), DIM(SORT_SRCLINE, "srcline", sort_srcline),
DIM(SORT_LOCAL_WEIGHT, "local_weight", sort_local_weight), DIM(SORT_LOCAL_WEIGHT, "local_weight", sort_local_weight),
DIM(SORT_GLOBAL_WEIGHT, "weight", sort_global_weight), DIM(SORT_GLOBAL_WEIGHT, "weight", sort_global_weight),
DIM(SORT_TRANSACTION, "transaction", sort_transaction),
}; };
#undef DIM #undef DIM

View File

@ -85,6 +85,7 @@ struct hist_entry {
struct map_symbol ms; struct map_symbol ms;
struct thread *thread; struct thread *thread;
u64 ip; u64 ip;
u64 transaction;
s32 cpu; s32 cpu;
struct hist_entry_diff diff; struct hist_entry_diff diff;
@ -145,6 +146,7 @@ enum sort_type {
SORT_SRCLINE, SORT_SRCLINE,
SORT_LOCAL_WEIGHT, SORT_LOCAL_WEIGHT,
SORT_GLOBAL_WEIGHT, SORT_GLOBAL_WEIGHT,
SORT_TRANSACTION,
/* branch stack specific sort keys */ /* branch stack specific sort keys */
__SORT_BRANCH_STACK, __SORT_BRANCH_STACK,