Commit 475eeab9 authored by Andi Kleen's avatar Andi Kleen Committed by Ingo Molnar

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: default avatarAndi Kleen <ak@linux.intel.com>
Acked-by: default avatarJiri Olsa <jolsa@redhat.com>
Signed-off-by: default avatarPeter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/1379688044-14173-6-git-send-email-andi@firstfloor.orgSigned-off-by: default avatarIngo Molnar <mingo@kernel.org>
parent 0126d493
...@@ -179,12 +179,14 @@ is enabled for all the sampling events. The sampled branch type is the same for ...@@ -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]
...@@ -72,6 +72,10 @@ OPTIONS ...@@ -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)
......
...@@ -113,7 +113,7 @@ Default is to monitor all CPUS. ...@@ -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::
......
...@@ -63,7 +63,7 @@ static int perf_evsel__add_sample(struct perf_evsel *evsel, ...@@ -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;
......
...@@ -304,9 +304,10 @@ static int formula_fprintf(struct hist_entry *he, struct hist_entry *pair, ...@@ -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, ...@@ -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;
} }
......
...@@ -894,6 +894,8 @@ const struct option record_options[] = { ...@@ -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()
}; };
......
...@@ -259,7 +259,7 @@ static int perf_evsel__add_hist_entry(struct perf_evsel *evsel, ...@@ -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) ...@@ -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",
......
...@@ -247,9 +247,8 @@ static struct hist_entry *perf_evsel__add_hist_entry(struct perf_evsel *evsel, ...@@ -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) ...@@ -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,
......
...@@ -233,6 +233,7 @@ struct perf_record_opts { ...@@ -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
...@@ -222,7 +222,8 @@ static int add_hist_entries(struct perf_evlist *evlist, struct machine *machine) ...@@ -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) ...@@ -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;
......
...@@ -111,6 +111,7 @@ struct perf_sample { ...@@ -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;
......
...@@ -681,6 +681,9 @@ void perf_evsel__config(struct perf_evsel *evsel, ...@@ -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, ...@@ -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;
} }
......
...@@ -160,6 +160,10 @@ void hists__calc_col_len(struct hists *hists, struct hist_entry *h) ...@@ -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, ...@@ -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, ...@@ -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);
......
...@@ -59,6 +59,7 @@ enum hist_column { ...@@ -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 { ...@@ -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 *);
......
...@@ -858,6 +858,9 @@ static void dump_sample(struct perf_evsel *evsel, union perf_event *event, ...@@ -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);
} }
......
...@@ -907,6 +907,78 @@ struct sort_entry sort_in_tx = { ...@@ -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[] = { ...@@ -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
......
...@@ -85,6 +85,7 @@ struct hist_entry { ...@@ -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 { ...@@ -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,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment