Commit 5f1230c9 authored by Ingo Molnar's avatar Ingo Molnar

Merge tag 'perf-core-for-mingo' of...

Merge tag 'perf-core-for-mingo' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/core

Pull perf/core improvements and fixes from Arnaldo Carvalho de Melo:

User visible changes:

  - Introduce 'srcfile' sort key: (Andi Kleen)

    # perf record -F 10000 usleep 1
    # perf report --stdio --dsos '[kernel.vmlinux]' -s srcfile
    <SNIP>
    # Overhead  Source File
        26.49%  copy_page_64.S
         5.49%  signal.c
         0.51%  msr.h
    #

    It can be combined with other fields, for instance, experiment with
    '-s srcfile,symbol'.

    There are some oddities in some distros and with some specific DSOs, being
    investigated, so your mileage may vary.

  - Update the column width for the "srcline" sort key (Arnaldo Carvalho de Melo)

  - Support per-event 'freq' term: (Namhyung Kim)

    $ perf record -e 'cpu/instructions,freq=1234/',cycles -c 1000 sleep 1
    $ perf evlist -F
    cpu/instructions,freq=1234/: sample_freq=1234
    cycles: sample_period=1000
    $

Infrastructure changes:

  - Move perf_counts struct and functions into separate object (Jiri Olsa)

  - Unset perf_event_attr::freq when period term is set (Jiri Olsa)

  - Move callchain option parsing code to util.c (Kan Liang)
Signed-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: default avatarIngo Molnar <mingo@kernel.org>
parents 709bc871 4605bb55
...@@ -49,6 +49,7 @@ OPTIONS ...@@ -49,6 +49,7 @@ OPTIONS
These params can be used to overload default config values per event. These params can be used to overload default config values per event.
Here is a list of the params. Here is a list of the params.
- 'period': Set event sampling period - 'period': Set event sampling period
- 'freq': Set event sampling frequency
- 'time': Disable/enable time stamping. Acceptable values are 1 for - 'time': Disable/enable time stamping. Acceptable values are 1 for
enabling time stamping. 0 for disabling time stamping. enabling time stamping. 0 for disabling time stamping.
The default is 1. The default is 1.
......
...@@ -81,6 +81,8 @@ OPTIONS ...@@ -81,6 +81,8 @@ 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.
- srcfile: file name of the source file of the same. Requires dwarf
information.
- weight: Event specific weight, e.g. memory latency or transaction - weight: Event specific weight, e.g. memory latency or transaction
abort cost. This is the global weight. abort cost. This is the global weight.
- local_weight: Local weight version of the weight above. - local_weight: Local weight version of the weight above.
...@@ -354,6 +356,8 @@ OPTIONS ...@@ -354,6 +356,8 @@ OPTIONS
To disable decoding entirely, use --no-itrace. To disable decoding entirely, use --no-itrace.
--full-source-path::
Show the full path for source files for srcline output.
include::callchain-overhead-calculation.txt[] include::callchain-overhead-calculation.txt[]
......
...@@ -260,6 +260,9 @@ OPTIONS ...@@ -260,6 +260,9 @@ OPTIONS
To disable decoding entirely, use --no-itrace. To disable decoding entirely, use --no-itrace.
--full-source-path::
Show the full path for source files for srcline output.
SEE ALSO SEE ALSO
-------- --------
linkperf:perf-record[1], linkperf:perf-script-perl[1], linkperf:perf-record[1], linkperf:perf-script-perl[1],
......
...@@ -738,6 +738,8 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused) ...@@ -738,6 +738,8 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
OPT_CALLBACK_OPTARG(0, "itrace", &itrace_synth_opts, NULL, "opts", OPT_CALLBACK_OPTARG(0, "itrace", &itrace_synth_opts, NULL, "opts",
"Instruction Tracing options", "Instruction Tracing options",
itrace_parse_synth_opts), itrace_parse_synth_opts),
OPT_BOOLEAN(0, "full-source-path", &srcline_full_filename,
"Show full source file name path for source lines"),
OPT_END() OPT_END()
}; };
struct perf_data_file file = { struct perf_data_file file = {
......
...@@ -1653,6 +1653,8 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused) ...@@ -1653,6 +1653,8 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
OPT_CALLBACK_OPTARG(0, "itrace", &itrace_synth_opts, NULL, "opts", OPT_CALLBACK_OPTARG(0, "itrace", &itrace_synth_opts, NULL, "opts",
"Instruction Tracing options", "Instruction Tracing options",
itrace_parse_synth_opts), itrace_parse_synth_opts),
OPT_BOOLEAN(0, "full-source-path", &srcline_full_filename,
"Show full source file name path for source lines"),
OPT_END() OPT_END()
}; };
const char * const script_subcommands[] = { "record", "report", NULL }; const char * const script_subcommands[] = { "record", "report", NULL };
......
...@@ -58,6 +58,7 @@ ...@@ -58,6 +58,7 @@
#include "util/cpumap.h" #include "util/cpumap.h"
#include "util/thread.h" #include "util/thread.h"
#include "util/thread_map.h" #include "util/thread_map.h"
#include "util/counts.h"
#include <stdlib.h> #include <stdlib.h>
#include <sys/prctl.h> #include <sys/prctl.h>
......
...@@ -68,6 +68,7 @@ libperf-y += target.o ...@@ -68,6 +68,7 @@ libperf-y += target.o
libperf-y += rblist.o libperf-y += rblist.o
libperf-y += intlist.o libperf-y += intlist.o
libperf-y += vdso.o libperf-y += vdso.o
libperf-y += counts.o
libperf-y += stat.o libperf-y += stat.o
libperf-y += stat-shadow.o libperf-y += stat-shadow.o
libperf-y += record.o libperf-y += record.o
......
...@@ -25,96 +25,9 @@ ...@@ -25,96 +25,9 @@
__thread struct callchain_cursor callchain_cursor; __thread struct callchain_cursor callchain_cursor;
#ifdef HAVE_DWARF_UNWIND_SUPPORT
static int get_stack_size(const char *str, unsigned long *_size)
{
char *endptr;
unsigned long size;
unsigned long max_size = round_down(USHRT_MAX, sizeof(u64));
size = strtoul(str, &endptr, 0);
do {
if (*endptr)
break;
size = round_up(size, sizeof(u64));
if (!size || size > max_size)
break;
*_size = size;
return 0;
} while (0);
pr_err("callchain: Incorrect stack dump size (max %ld): %s\n",
max_size, str);
return -1;
}
#endif /* HAVE_DWARF_UNWIND_SUPPORT */
int parse_callchain_record_opt(const char *arg, struct callchain_param *param) int parse_callchain_record_opt(const char *arg, struct callchain_param *param)
{ {
char *tok, *name, *saveptr = NULL; return parse_callchain_record(arg, param);
char *buf;
int ret = -1;
/* We need buffer that we know we can write to. */
buf = malloc(strlen(arg) + 1);
if (!buf)
return -ENOMEM;
strcpy(buf, arg);
tok = strtok_r((char *)buf, ",", &saveptr);
name = tok ? : (char *)buf;
do {
/* Framepointer style */
if (!strncmp(name, "fp", sizeof("fp"))) {
if (!strtok_r(NULL, ",", &saveptr)) {
param->record_mode = CALLCHAIN_FP;
ret = 0;
} else
pr_err("callchain: No more arguments "
"needed for --call-graph fp\n");
break;
#ifdef HAVE_DWARF_UNWIND_SUPPORT
/* Dwarf style */
} else if (!strncmp(name, "dwarf", sizeof("dwarf"))) {
const unsigned long default_stack_dump_size = 8192;
ret = 0;
param->record_mode = CALLCHAIN_DWARF;
param->dump_size = default_stack_dump_size;
tok = strtok_r(NULL, ",", &saveptr);
if (tok) {
unsigned long size = 0;
ret = get_stack_size(tok, &size);
param->dump_size = size;
}
#endif /* HAVE_DWARF_UNWIND_SUPPORT */
} else if (!strncmp(name, "lbr", sizeof("lbr"))) {
if (!strtok_r(NULL, ",", &saveptr)) {
param->record_mode = CALLCHAIN_LBR;
ret = 0;
} else
pr_err("callchain: No more arguments "
"needed for --call-graph lbr\n");
break;
} else {
pr_err("callchain: Unknown --call-graph option "
"value: %s\n", arg);
break;
}
} while (0);
free(buf);
return ret;
} }
static int parse_callchain_mode(const char *value) static int parse_callchain_mode(const char *value)
......
...@@ -177,6 +177,7 @@ int fill_callchain_info(struct addr_location *al, struct callchain_cursor_node * ...@@ -177,6 +177,7 @@ int fill_callchain_info(struct addr_location *al, struct callchain_cursor_node *
bool hide_unresolved); bool hide_unresolved);
extern const char record_callchain_help[]; extern const char record_callchain_help[];
extern int parse_callchain_record(const char *arg, struct callchain_param *param);
int parse_callchain_record_opt(const char *arg, struct callchain_param *param); int parse_callchain_record_opt(const char *arg, struct callchain_param *param);
int parse_callchain_report_opt(const char *arg); int parse_callchain_report_opt(const char *arg);
int perf_callchain_config(const char *var, const char *value); int perf_callchain_config(const char *var, const char *value);
......
#include <stdlib.h>
#include "evsel.h"
#include "counts.h"
struct perf_counts *perf_counts__new(int ncpus, int nthreads)
{
struct perf_counts *counts = zalloc(sizeof(*counts));
if (counts) {
struct xyarray *values;
values = xyarray__new(ncpus, nthreads, sizeof(struct perf_counts_values));
if (!values) {
free(counts);
return NULL;
}
counts->values = values;
}
return counts;
}
void perf_counts__delete(struct perf_counts *counts)
{
if (counts) {
xyarray__delete(counts->values);
free(counts);
}
}
static void perf_counts__reset(struct perf_counts *counts)
{
xyarray__reset(counts->values);
}
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 nthreads)
{
evsel->counts = perf_counts__new(ncpus, nthreads);
return evsel->counts != NULL ? 0 : -ENOMEM;
}
void perf_evsel__free_counts(struct perf_evsel *evsel)
{
perf_counts__delete(evsel->counts);
evsel->counts = NULL;
}
#ifndef __PERF_COUNTS_H
#define __PERF_COUNTS_H
#include "xyarray.h"
struct perf_counts_values {
union {
struct {
u64 val;
u64 ena;
u64 run;
};
u64 values[3];
};
};
struct perf_counts {
s8 scaled;
struct perf_counts_values aggr;
struct xyarray *values;
};
static inline struct perf_counts_values*
perf_counts(struct perf_counts *counts, int cpu, int thread)
{
return xyarray__entry(counts->values, cpu, thread);
}
struct perf_counts *perf_counts__new(int ncpus, int nthreads);
void perf_counts__delete(struct perf_counts *counts);
void perf_evsel__reset_counts(struct perf_evsel *evsel);
int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus, int nthreads);
void perf_evsel__free_counts(struct perf_evsel *evsel);
#endif /* __PERF_COUNTS_H */
...@@ -598,6 +598,11 @@ static void apply_config_terms(struct perf_evsel *evsel) ...@@ -598,6 +598,11 @@ static void apply_config_terms(struct perf_evsel *evsel)
switch (term->type) { switch (term->type) {
case PERF_EVSEL__CONFIG_TERM_PERIOD: case PERF_EVSEL__CONFIG_TERM_PERIOD:
attr->sample_period = term->val.period; attr->sample_period = term->val.period;
attr->freq = 0;
break;
case PERF_EVSEL__CONFIG_TERM_FREQ:
attr->sample_freq = term->val.freq;
attr->freq = 1;
break; break;
case PERF_EVSEL__CONFIG_TERM_TIME: case PERF_EVSEL__CONFIG_TERM_TIME:
if (term->val.time) if (term->val.time)
...@@ -2153,8 +2158,13 @@ int perf_evsel__fprintf(struct perf_evsel *evsel, ...@@ -2153,8 +2158,13 @@ int perf_evsel__fprintf(struct perf_evsel *evsel,
printed += perf_event_attr__fprintf(fp, &evsel->attr, printed += perf_event_attr__fprintf(fp, &evsel->attr,
__print_attr__fprintf, &first); __print_attr__fprintf, &first);
} else if (details->freq) { } else if (details->freq) {
printed += comma_fprintf(fp, &first, " sample_freq=%" PRIu64, const char *term = "sample_freq";
(u64)evsel->attr.sample_freq);
if (!evsel->attr.freq)
term = "sample_period";
printed += comma_fprintf(fp, &first, " %s=%" PRIu64,
term, (u64)evsel->attr.sample_freq);
} }
out: out:
fputc('\n', fp); fputc('\n', fp);
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
#include "xyarray.h" #include "xyarray.h"
#include "symbol.h" #include "symbol.h"
#include "cpumap.h" #include "cpumap.h"
#include "stat.h" #include "counts.h"
struct perf_evsel; struct perf_evsel;
...@@ -39,6 +39,7 @@ struct cgroup_sel; ...@@ -39,6 +39,7 @@ struct cgroup_sel;
*/ */
enum { enum {
PERF_EVSEL__CONFIG_TERM_PERIOD, PERF_EVSEL__CONFIG_TERM_PERIOD,
PERF_EVSEL__CONFIG_TERM_FREQ,
PERF_EVSEL__CONFIG_TERM_TIME, PERF_EVSEL__CONFIG_TERM_TIME,
PERF_EVSEL__CONFIG_TERM_MAX, PERF_EVSEL__CONFIG_TERM_MAX,
}; };
...@@ -48,6 +49,7 @@ struct perf_evsel_config_term { ...@@ -48,6 +49,7 @@ struct perf_evsel_config_term {
int type; int type;
union { union {
u64 period; u64 period;
u64 freq;
bool time; bool time;
} val; } val;
}; };
......
...@@ -151,6 +151,12 @@ void hists__calc_col_len(struct hists *hists, struct hist_entry *h) ...@@ -151,6 +151,12 @@ void hists__calc_col_len(struct hists *hists, struct hist_entry *h)
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->srcline)
hists__new_col_len(hists, HISTC_SRCLINE, strlen(h->srcline));
if (h->srcfile)
hists__new_col_len(hists, HISTC_SRCFILE, strlen(h->srcfile));
if (h->transaction) if (h->transaction)
hists__new_col_len(hists, HISTC_TRANSACTION, hists__new_col_len(hists, HISTC_TRANSACTION,
hist_entry__transaction_len()); hist_entry__transaction_len());
...@@ -761,6 +767,7 @@ iter_add_next_cumulative_entry(struct hist_entry_iter *iter, ...@@ -761,6 +767,7 @@ iter_add_next_cumulative_entry(struct hist_entry_iter *iter,
struct hist_entry **he_cache = iter->priv; struct hist_entry **he_cache = iter->priv;
struct hist_entry *he; struct hist_entry *he;
struct hist_entry he_tmp = { struct hist_entry he_tmp = {
.hists = evsel__hists(evsel),
.cpu = al->cpu, .cpu = al->cpu,
.thread = al->thread, .thread = al->thread,
.comm = thread__comm(al->thread), .comm = thread__comm(al->thread),
...@@ -945,6 +952,8 @@ void hist_entry__delete(struct hist_entry *he) ...@@ -945,6 +952,8 @@ void hist_entry__delete(struct hist_entry *he)
zfree(&he->stat_acc); zfree(&he->stat_acc);
free_srcline(he->srcline); free_srcline(he->srcline);
if (he->srcfile && he->srcfile[0])
free(he->srcfile);
free_callchain(he->callchain); free_callchain(he->callchain);
free(he); free(he);
} }
......
...@@ -30,6 +30,7 @@ enum hist_column { ...@@ -30,6 +30,7 @@ enum hist_column {
HISTC_PARENT, HISTC_PARENT,
HISTC_CPU, HISTC_CPU,
HISTC_SRCLINE, HISTC_SRCLINE,
HISTC_SRCFILE,
HISTC_MISPREDICT, HISTC_MISPREDICT,
HISTC_IN_TX, HISTC_IN_TX,
HISTC_ABORT, HISTC_ABORT,
......
...@@ -597,6 +597,9 @@ do { \ ...@@ -597,6 +597,9 @@ do { \
case PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD: case PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD:
CHECK_TYPE_VAL(NUM); CHECK_TYPE_VAL(NUM);
break; break;
case PARSE_EVENTS__TERM_TYPE_SAMPLE_FREQ:
CHECK_TYPE_VAL(NUM);
break;
case PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE: case PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE:
/* /*
* TODO uncomment when the field is available * TODO uncomment when the field is available
...@@ -659,6 +662,9 @@ do { \ ...@@ -659,6 +662,9 @@ do { \
case PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD: case PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD:
ADD_CONFIG_TERM(PERIOD, period, term->val.num); ADD_CONFIG_TERM(PERIOD, period, term->val.num);
break; break;
case PARSE_EVENTS__TERM_TYPE_SAMPLE_FREQ:
ADD_CONFIG_TERM(FREQ, freq, term->val.num);
break;
case PARSE_EVENTS__TERM_TYPE_TIME: case PARSE_EVENTS__TERM_TYPE_TIME:
ADD_CONFIG_TERM(TIME, time, term->val.num); ADD_CONFIG_TERM(TIME, time, term->val.num);
break; break;
......
...@@ -62,6 +62,7 @@ enum { ...@@ -62,6 +62,7 @@ enum {
PARSE_EVENTS__TERM_TYPE_CONFIG2, PARSE_EVENTS__TERM_TYPE_CONFIG2,
PARSE_EVENTS__TERM_TYPE_NAME, PARSE_EVENTS__TERM_TYPE_NAME,
PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD, PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD,
PARSE_EVENTS__TERM_TYPE_SAMPLE_FREQ,
PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE, PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE,
PARSE_EVENTS__TERM_TYPE_TIME, PARSE_EVENTS__TERM_TYPE_TIME,
}; };
......
...@@ -182,6 +182,7 @@ config1 { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_CONFIG1); } ...@@ -182,6 +182,7 @@ config1 { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_CONFIG1); }
config2 { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_CONFIG2); } config2 { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_CONFIG2); }
name { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_NAME); } name { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_NAME); }
period { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD); } period { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD); }
freq { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_SAMPLE_FREQ); }
branch_type { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE); } branch_type { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE); }
time { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_TIME); } time { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_TIME); }
, { return ','; } , { return ','; }
......
...@@ -634,7 +634,7 @@ static char *formats_error_string(struct list_head *formats) ...@@ -634,7 +634,7 @@ static char *formats_error_string(struct list_head *formats)
{ {
struct perf_pmu_format *format; struct perf_pmu_format *format;
char *err, *str; char *err, *str;
static const char *static_terms = "config,config1,config2,name,period,branch_type,time\n"; static const char *static_terms = "config,config1,config2,name,period,freq,branch_type,time\n";
unsigned i = 0; unsigned i = 0;
if (!asprintf(&str, "valid terms:")) if (!asprintf(&str, "valid terms:"))
......
...@@ -16,7 +16,7 @@ util/util.c ...@@ -16,7 +16,7 @@ util/util.c
util/xyarray.c util/xyarray.c
util/cgroup.c util/cgroup.c
util/rblist.c util/rblist.c
util/stat.c util/counts.c
util/strlist.c util/strlist.c
util/trace-event.c util/trace-event.c
../lib/rbtree.c ../lib/rbtree.c
......
...@@ -319,6 +319,57 @@ struct sort_entry sort_srcline = { ...@@ -319,6 +319,57 @@ struct sort_entry sort_srcline = {
.se_width_idx = HISTC_SRCLINE, .se_width_idx = HISTC_SRCLINE,
}; };
/* --sort srcfile */
static char no_srcfile[1];
static char *get_srcfile(struct hist_entry *e)
{
char *sf, *p;
struct map *map = e->ms.map;
sf = get_srcline(map->dso, map__rip_2objdump(map, e->ip),
e->ms.sym, true);
p = strchr(sf, ':');
if (p && *sf) {
*p = 0;
return sf;
}
free(sf);
return no_srcfile;
}
static int64_t
sort__srcfile_cmp(struct hist_entry *left, struct hist_entry *right)
{
if (!left->srcfile) {
if (!left->ms.map)
left->srcfile = no_srcfile;
else
left->srcfile = get_srcfile(left);
}
if (!right->srcfile) {
if (!right->ms.map)
right->srcfile = no_srcfile;
else
right->srcfile = get_srcfile(right);
}
return strcmp(right->srcfile, left->srcfile);
}
static int hist_entry__srcfile_snprintf(struct hist_entry *he, char *bf,
size_t size, unsigned int width)
{
return repsep_snprintf(bf, size, "%-*.*s", width, width, he->srcfile);
}
struct sort_entry sort_srcfile = {
.se_header = "Source File",
.se_cmp = sort__srcfile_cmp,
.se_snprintf = hist_entry__srcfile_snprintf,
.se_width_idx = HISTC_SRCFILE,
};
/* --sort parent */ /* --sort parent */
static int64_t static int64_t
...@@ -1196,6 +1247,7 @@ static struct sort_dimension common_sort_dimensions[] = { ...@@ -1196,6 +1247,7 @@ static struct sort_dimension common_sort_dimensions[] = {
DIM(SORT_PARENT, "parent", sort_parent), DIM(SORT_PARENT, "parent", sort_parent),
DIM(SORT_CPU, "cpu", sort_cpu), DIM(SORT_CPU, "cpu", sort_cpu),
DIM(SORT_SRCLINE, "srcline", sort_srcline), DIM(SORT_SRCLINE, "srcline", sort_srcline),
DIM(SORT_SRCFILE, "srcfile", sort_srcfile),
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), DIM(SORT_TRANSACTION, "transaction", sort_transaction),
......
...@@ -114,6 +114,7 @@ struct hist_entry { ...@@ -114,6 +114,7 @@ struct hist_entry {
}; };
}; };
char *srcline; char *srcline;
char *srcfile;
struct symbol *parent; struct symbol *parent;
struct rb_root sorted_chain; struct rb_root sorted_chain;
struct branch_info *branch_info; struct branch_info *branch_info;
...@@ -172,6 +173,7 @@ enum sort_type { ...@@ -172,6 +173,7 @@ enum sort_type {
SORT_PARENT, SORT_PARENT,
SORT_CPU, SORT_CPU,
SORT_SRCLINE, SORT_SRCLINE,
SORT_SRCFILE,
SORT_LOCAL_WEIGHT, SORT_LOCAL_WEIGHT,
SORT_GLOBAL_WEIGHT, SORT_GLOBAL_WEIGHT,
SORT_TRANSACTION, SORT_TRANSACTION,
......
...@@ -10,6 +10,8 @@ ...@@ -10,6 +10,8 @@
#include "symbol.h" #include "symbol.h"
bool srcline_full_filename;
#ifdef HAVE_LIBBFD_SUPPORT #ifdef HAVE_LIBBFD_SUPPORT
/* /*
...@@ -277,7 +279,9 @@ char *get_srcline(struct dso *dso, u64 addr, struct symbol *sym, ...@@ -277,7 +279,9 @@ char *get_srcline(struct dso *dso, u64 addr, struct symbol *sym,
if (!addr2line(dso_name, addr, &file, &line, dso)) if (!addr2line(dso_name, addr, &file, &line, dso))
goto out; goto out;
if (asprintf(&srcline, "%s:%u", basename(file), line) < 0) { if (asprintf(&srcline, "%s:%u",
srcline_full_filename ? file : basename(file),
line) < 0) {
free(file); free(file);
goto out; goto out;
} }
......
...@@ -97,55 +97,6 @@ void perf_stat_evsel_id_init(struct perf_evsel *evsel) ...@@ -97,55 +97,6 @@ void perf_stat_evsel_id_init(struct perf_evsel *evsel)
} }
} }
struct perf_counts *perf_counts__new(int ncpus, int nthreads)
{
struct perf_counts *counts = zalloc(sizeof(*counts));
if (counts) {
struct xyarray *values;
values = xyarray__new(ncpus, nthreads, sizeof(struct perf_counts_values));
if (!values) {
free(counts);
return NULL;
}
counts->values = values;
}
return counts;
}
void perf_counts__delete(struct perf_counts *counts)
{
if (counts) {
xyarray__delete(counts->values);
free(counts);
}
}
static void perf_counts__reset(struct perf_counts *counts)
{
xyarray__reset(counts->values);
}
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 nthreads)
{
evsel->counts = perf_counts__new(ncpus, nthreads);
return evsel->counts != NULL ? 0 : -ENOMEM;
}
void perf_evsel__free_counts(struct perf_evsel *evsel)
{
perf_counts__delete(evsel->counts);
evsel->counts = NULL;
}
void perf_evsel__reset_stat_priv(struct perf_evsel *evsel) void perf_evsel__reset_stat_priv(struct perf_evsel *evsel)
{ {
int i; int i;
......
...@@ -33,23 +33,6 @@ enum aggr_mode { ...@@ -33,23 +33,6 @@ enum aggr_mode {
AGGR_THREAD, AGGR_THREAD,
}; };
struct perf_counts_values {
union {
struct {
u64 val;
u64 ena;
u64 run;
};
u64 values[3];
};
};
struct perf_counts {
s8 scaled;
struct perf_counts_values aggr;
struct xyarray *values;
};
struct perf_stat_config { struct perf_stat_config {
enum aggr_mode aggr_mode; enum aggr_mode aggr_mode;
bool scale; bool scale;
...@@ -57,12 +40,6 @@ struct perf_stat_config { ...@@ -57,12 +40,6 @@ struct perf_stat_config {
unsigned int interval; unsigned int interval;
}; };
static inline struct perf_counts_values*
perf_counts(struct perf_counts *counts, int cpu, int thread)
{
return xyarray__entry(counts->values, cpu, thread);
}
void update_stats(struct stats *stats, u64 val); void update_stats(struct stats *stats, u64 val);
double avg_stats(struct stats *stats); double avg_stats(struct stats *stats);
double stddev_stats(struct stats *stats); double stddev_stats(struct stats *stats);
...@@ -96,13 +73,6 @@ void perf_stat__update_shadow_stats(struct perf_evsel *counter, u64 *count, ...@@ -96,13 +73,6 @@ void perf_stat__update_shadow_stats(struct perf_evsel *counter, u64 *count,
void perf_stat__print_shadow_stats(FILE *out, struct perf_evsel *evsel, void perf_stat__print_shadow_stats(FILE *out, struct perf_evsel *evsel,
double avg, int cpu, enum aggr_mode aggr); double avg, int cpu, enum aggr_mode aggr);
struct perf_counts *perf_counts__new(int ncpus, int nthreads);
void perf_counts__delete(struct perf_counts *counts);
void perf_evsel__reset_counts(struct perf_evsel *evsel);
int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus, int nthreads);
void perf_evsel__free_counts(struct perf_evsel *evsel);
void perf_evsel__reset_stat_priv(struct perf_evsel *evsel); void perf_evsel__reset_stat_priv(struct perf_evsel *evsel);
int perf_evsel__alloc_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__free_stat_priv(struct perf_evsel *evsel);
......
...@@ -566,6 +566,96 @@ unsigned long parse_tag_value(const char *str, struct parse_tag *tags) ...@@ -566,6 +566,96 @@ unsigned long parse_tag_value(const char *str, struct parse_tag *tags)
return (unsigned long) -1; return (unsigned long) -1;
} }
int get_stack_size(const char *str, unsigned long *_size)
{
char *endptr;
unsigned long size;
unsigned long max_size = round_down(USHRT_MAX, sizeof(u64));
size = strtoul(str, &endptr, 0);
do {
if (*endptr)
break;
size = round_up(size, sizeof(u64));
if (!size || size > max_size)
break;
*_size = size;
return 0;
} while (0);
pr_err("callchain: Incorrect stack dump size (max %ld): %s\n",
max_size, str);
return -1;
}
int parse_callchain_record(const char *arg, struct callchain_param *param)
{
char *tok, *name, *saveptr = NULL;
char *buf;
int ret = -1;
/* We need buffer that we know we can write to. */
buf = malloc(strlen(arg) + 1);
if (!buf)
return -ENOMEM;
strcpy(buf, arg);
tok = strtok_r((char *)buf, ",", &saveptr);
name = tok ? : (char *)buf;
do {
/* Framepointer style */
if (!strncmp(name, "fp", sizeof("fp"))) {
if (!strtok_r(NULL, ",", &saveptr)) {
param->record_mode = CALLCHAIN_FP;
ret = 0;
} else
pr_err("callchain: No more arguments "
"needed for --call-graph fp\n");
break;
#ifdef HAVE_DWARF_UNWIND_SUPPORT
/* Dwarf style */
} else if (!strncmp(name, "dwarf", sizeof("dwarf"))) {
const unsigned long default_stack_dump_size = 8192;
ret = 0;
param->record_mode = CALLCHAIN_DWARF;
param->dump_size = default_stack_dump_size;
tok = strtok_r(NULL, ",", &saveptr);
if (tok) {
unsigned long size = 0;
ret = get_stack_size(tok, &size);
param->dump_size = size;
}
#endif /* HAVE_DWARF_UNWIND_SUPPORT */
} else if (!strncmp(name, "lbr", sizeof("lbr"))) {
if (!strtok_r(NULL, ",", &saveptr)) {
param->record_mode = CALLCHAIN_LBR;
ret = 0;
} else
pr_err("callchain: No more arguments "
"needed for --call-graph lbr\n");
break;
} else {
pr_err("callchain: Unknown --call-graph option "
"value: %s\n", arg);
break;
}
} while (0);
free(buf);
return ret;
}
int filename__read_str(const char *filename, char **buf, size_t *sizep) int filename__read_str(const char *filename, char **buf, size_t *sizep)
{ {
size_t size = 0, alloc_size = 0; size_t size = 0, alloc_size = 0;
......
...@@ -318,6 +318,7 @@ static inline int path__join3(char *bf, size_t size, ...@@ -318,6 +318,7 @@ static inline int path__join3(char *bf, size_t size,
struct dso; struct dso;
struct symbol; struct symbol;
extern bool srcline_full_filename;
char *get_srcline(struct dso *dso, u64 addr, struct symbol *sym, char *get_srcline(struct dso *dso, u64 addr, struct symbol *sym,
bool show_sym); bool show_sym);
void free_srcline(char *srcline); void free_srcline(char *srcline);
...@@ -351,4 +352,6 @@ static inline char *asprintf_expr_not_in_ints(const char *var, size_t nints, int ...@@ -351,4 +352,6 @@ static inline char *asprintf_expr_not_in_ints(const char *var, size_t nints, int
return asprintf_expr_inout_ints(var, false, nints, ints); return asprintf_expr_inout_ints(var, false, nints, ints);
} }
int get_stack_size(const char *str, unsigned long *_size);
#endif /* GIT_COMPAT_UTIL_H */ #endif /* GIT_COMPAT_UTIL_H */
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