提交 afb71193 编写于 作者: I 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

perf/core improvements and fixes:

 * Reset SIGTERM handler in workload child process, fix from David Ahern.

 * Handle death by SIGTERM in 'perf record', fix from David Ahern.

 * Fix printing of perf_event_paranoid message, from David Ahern.

 * Handle realloc failures in 'perf kvm', from David Ahern.

 * Fix divide by 0 in variance, from David Ahern.

 * Save parent pid in thread struct, from David Ahern.

 * Handle JITed code in shared memory, from Andi Kleen.

 * Makefile reorganization, prep work for Kconfig patches, from Jiri Olsa.

 * Fixes for 'perf diff', from Jiri Olsa.

 * Add automated make test suite, from Jiri Olsa.

 * 'perf tests' fixes from Jiri Olsa.

 * Remove some unused struct members, from Jiri Olsa.

 * Add missing liblk.a dependency for python/perf.so, fix from Jiri Olsa.

 * Respect CROSS_COMPILE in liblk.a, from Rabin Vincent.

 * Expand definition of sysfs format attribute, from Michael Ellerman.

 * No need to do locking when adding hists in perf report, only 'top'
   needs that, from Namhyung Kim.

 * Sorting improvements, from Namhyung Kim.

 * Fix alignment of symbol column in in the hists browser (top, report)
   when -v is given, from NAmhyung Kim.

 * Add --percent-limit option to 'top' and 'report', from Namhyung Kim.

 * Fix 'perf top' -E option behavior, from Namhyung Kim.

 * Fix bug in isupper() and islower(), from Sukadev Bhattiprolu.

 * Fix compile errors in bp_signal 'perf test', from Sukadev Bhattiprolu.

 * Make Power7 CPI stack events available in sysfs, from Sukadev Bhattiprolu.
Signed-off-by: NArnaldo Carvalho de Melo <acme@redhat.com>
......@@ -27,14 +27,36 @@ Description: Generic performance monitoring events
"basename".
What: /sys/devices/cpu/events/PM_LD_MISS_L1
/sys/devices/cpu/events/PM_LD_REF_L1
/sys/devices/cpu/events/PM_CYC
What: /sys/devices/cpu/events/PM_1PLUS_PPC_CMPL
/sys/devices/cpu/events/PM_BRU_FIN
/sys/devices/cpu/events/PM_GCT_NOSLOT_CYC
/sys/devices/cpu/events/PM_BRU_MPRED
/sys/devices/cpu/events/PM_INST_CMPL
/sys/devices/cpu/events/PM_CMPLU_STALL
/sys/devices/cpu/events/PM_CMPLU_STALL_BRU
/sys/devices/cpu/events/PM_CMPLU_STALL_DCACHE_MISS
/sys/devices/cpu/events/PM_CMPLU_STALL_DFU
/sys/devices/cpu/events/PM_CMPLU_STALL_DIV
/sys/devices/cpu/events/PM_CMPLU_STALL_ERAT_MISS
/sys/devices/cpu/events/PM_CMPLU_STALL_FXU
/sys/devices/cpu/events/PM_CMPLU_STALL_IFU
/sys/devices/cpu/events/PM_CMPLU_STALL_LSU
/sys/devices/cpu/events/PM_CMPLU_STALL_REJECT
/sys/devices/cpu/events/PM_CMPLU_STALL_SCALAR
/sys/devices/cpu/events/PM_CMPLU_STALL_SCALAR_LONG
/sys/devices/cpu/events/PM_CMPLU_STALL_STORE
/sys/devices/cpu/events/PM_CMPLU_STALL_THRD
/sys/devices/cpu/events/PM_CMPLU_STALL_VECTOR
/sys/devices/cpu/events/PM_CMPLU_STALL_VECTOR_LONG
/sys/devices/cpu/events/PM_CYC
/sys/devices/cpu/events/PM_GCT_NOSLOT_BR_MPRED
/sys/devices/cpu/events/PM_GCT_NOSLOT_BR_MPRED_IC_MISS
/sys/devices/cpu/events/PM_GCT_NOSLOT_CYC
/sys/devices/cpu/events/PM_GCT_NOSLOT_IC_MISS
/sys/devices/cpu/events/PM_GRP_CMPL
/sys/devices/cpu/events/PM_INST_CMPL
/sys/devices/cpu/events/PM_LD_MISS_L1
/sys/devices/cpu/events/PM_LD_REF_L1
/sys/devices/cpu/events/PM_RUN_CYC
/sys/devices/cpu/events/PM_RUN_INST_CMPL
Date: 2013/01/08
......
......@@ -9,6 +9,12 @@ Description:
we want to export, so that userspace can deal with sane
name/value pairs.
Userspace must be prepared for the possibility that attributes
define overlapping bit ranges. For example:
attr1 = 'config:0-23'
attr2 = 'config:0-7'
attr3 = 'config:12-35'
Example: 'config1:1,6-10,44'
Defines contents of attribute that occupies bits 1,6-10,44 of
perf_event_attr::config1.
......@@ -62,6 +62,29 @@
#define PME_PM_BRU_FIN 0x10068
#define PME_PM_BRU_MPRED 0x400f6
#define PME_PM_CMPLU_STALL_FXU 0x20014
#define PME_PM_CMPLU_STALL_DIV 0x40014
#define PME_PM_CMPLU_STALL_SCALAR 0x40012
#define PME_PM_CMPLU_STALL_SCALAR_LONG 0x20018
#define PME_PM_CMPLU_STALL_VECTOR 0x2001c
#define PME_PM_CMPLU_STALL_VECTOR_LONG 0x4004a
#define PME_PM_CMPLU_STALL_LSU 0x20012
#define PME_PM_CMPLU_STALL_REJECT 0x40016
#define PME_PM_CMPLU_STALL_ERAT_MISS 0x40018
#define PME_PM_CMPLU_STALL_DCACHE_MISS 0x20016
#define PME_PM_CMPLU_STALL_STORE 0x2004a
#define PME_PM_CMPLU_STALL_THRD 0x1001c
#define PME_PM_CMPLU_STALL_IFU 0x4004c
#define PME_PM_CMPLU_STALL_BRU 0x4004e
#define PME_PM_GCT_NOSLOT_IC_MISS 0x2001a
#define PME_PM_GCT_NOSLOT_BR_MPRED 0x4001a
#define PME_PM_GCT_NOSLOT_BR_MPRED_IC_MISS 0x4001c
#define PME_PM_GRP_CMPL 0x30004
#define PME_PM_1PLUS_PPC_CMPL 0x100f2
#define PME_PM_CMPLU_STALL_DFU 0x2003c
#define PME_PM_RUN_CYC 0x200f4
#define PME_PM_RUN_INST_CMPL 0x400fa
/*
* Layout of constraint bits:
* 6666555555555544444444443333333333222222222211111111110000000000
......@@ -393,6 +416,31 @@ POWER_EVENT_ATTR(LD_MISS_L1, LD_MISS_L1);
POWER_EVENT_ATTR(BRU_FIN, BRU_FIN)
POWER_EVENT_ATTR(BRU_MPRED, BRU_MPRED);
POWER_EVENT_ATTR(CMPLU_STALL_FXU, CMPLU_STALL_FXU);
POWER_EVENT_ATTR(CMPLU_STALL_DIV, CMPLU_STALL_DIV);
POWER_EVENT_ATTR(CMPLU_STALL_SCALAR, CMPLU_STALL_SCALAR);
POWER_EVENT_ATTR(CMPLU_STALL_SCALAR_LONG, CMPLU_STALL_SCALAR_LONG);
POWER_EVENT_ATTR(CMPLU_STALL_VECTOR, CMPLU_STALL_VECTOR);
POWER_EVENT_ATTR(CMPLU_STALL_VECTOR_LONG, CMPLU_STALL_VECTOR_LONG);
POWER_EVENT_ATTR(CMPLU_STALL_LSU, CMPLU_STALL_LSU);
POWER_EVENT_ATTR(CMPLU_STALL_REJECT, CMPLU_STALL_REJECT);
POWER_EVENT_ATTR(CMPLU_STALL_ERAT_MISS, CMPLU_STALL_ERAT_MISS);
POWER_EVENT_ATTR(CMPLU_STALL_DCACHE_MISS, CMPLU_STALL_DCACHE_MISS);
POWER_EVENT_ATTR(CMPLU_STALL_STORE, CMPLU_STALL_STORE);
POWER_EVENT_ATTR(CMPLU_STALL_THRD, CMPLU_STALL_THRD);
POWER_EVENT_ATTR(CMPLU_STALL_IFU, CMPLU_STALL_IFU);
POWER_EVENT_ATTR(CMPLU_STALL_BRU, CMPLU_STALL_BRU);
POWER_EVENT_ATTR(GCT_NOSLOT_IC_MISS, GCT_NOSLOT_IC_MISS);
POWER_EVENT_ATTR(GCT_NOSLOT_BR_MPRED, GCT_NOSLOT_BR_MPRED);
POWER_EVENT_ATTR(GCT_NOSLOT_BR_MPRED_IC_MISS, GCT_NOSLOT_BR_MPRED_IC_MISS);
POWER_EVENT_ATTR(GRP_CMPL, GRP_CMPL);
POWER_EVENT_ATTR(1PLUS_PPC_CMPL, 1PLUS_PPC_CMPL);
POWER_EVENT_ATTR(CMPLU_STALL_DFU, CMPLU_STALL_DFU);
POWER_EVENT_ATTR(RUN_CYC, RUN_CYC);
POWER_EVENT_ATTR(RUN_INST_CMPL, RUN_INST_CMPL);
static struct attribute *power7_events_attr[] = {
GENERIC_EVENT_PTR(CYC),
GENERIC_EVENT_PTR(GCT_NOSLOT_CYC),
......@@ -411,6 +459,31 @@ static struct attribute *power7_events_attr[] = {
POWER_EVENT_PTR(LD_MISS_L1),
POWER_EVENT_PTR(BRU_FIN),
POWER_EVENT_PTR(BRU_MPRED),
POWER_EVENT_PTR(CMPLU_STALL_FXU),
POWER_EVENT_PTR(CMPLU_STALL_DIV),
POWER_EVENT_PTR(CMPLU_STALL_SCALAR),
POWER_EVENT_PTR(CMPLU_STALL_SCALAR_LONG),
POWER_EVENT_PTR(CMPLU_STALL_VECTOR),
POWER_EVENT_PTR(CMPLU_STALL_VECTOR_LONG),
POWER_EVENT_PTR(CMPLU_STALL_LSU),
POWER_EVENT_PTR(CMPLU_STALL_REJECT),
POWER_EVENT_PTR(CMPLU_STALL_ERAT_MISS),
POWER_EVENT_PTR(CMPLU_STALL_DCACHE_MISS),
POWER_EVENT_PTR(CMPLU_STALL_STORE),
POWER_EVENT_PTR(CMPLU_STALL_THRD),
POWER_EVENT_PTR(CMPLU_STALL_IFU),
POWER_EVENT_PTR(CMPLU_STALL_BRU),
POWER_EVENT_PTR(GCT_NOSLOT_IC_MISS),
POWER_EVENT_PTR(GCT_NOSLOT_BR_MPRED),
POWER_EVENT_PTR(GCT_NOSLOT_BR_MPRED_IC_MISS),
POWER_EVENT_PTR(GRP_CMPL),
POWER_EVENT_PTR(1PLUS_PPC_CMPL),
POWER_EVENT_PTR(CMPLU_STALL_DFU),
POWER_EVENT_PTR(RUN_CYC),
POWER_EVENT_PTR(RUN_INST_CMPL),
NULL
};
......
include ../../scripts/Makefile.include
CC = $(CROSS_COMPILE)gcc
AR = $(CROSS_COMPILE)ar
# guard against environment variables
LIB_H=
LIB_OBJS=
......
......@@ -13,7 +13,7 @@ SYNOPSIS
DESCRIPTION
-----------
This command runs runs perf-buildid-list --with-hits, and collects the files
with the buildids found so that analisys of perf.data contents can be possible
with the buildids found so that analysis of perf.data contents can be possible
on another machine.
......
......@@ -210,6 +210,10 @@ OPTIONS
Demangle symbol names to human readable form. It's enabled by default,
disable with --no-demangle.
--percent-limit::
Do not show entries which have an overhead under that percent.
(Default: 0).
SEE ALSO
--------
linkperf:perf-stat[1], linkperf:perf-annotate[1]
......@@ -155,6 +155,10 @@ Default is to monitor all CPUS.
Default: fractal,0.5,callee.
--percent-limit::
Do not show entries which have an overhead under that percent.
(Default: 0).
INTERACTIVE PROMPTING KEYS
--------------------------
......
此差异已折叠。
......@@ -323,13 +323,20 @@ static void hists__baseline_only(struct hists *hists)
static void hists__precompute(struct hists *hists)
{
struct rb_node *next = rb_first(&hists->entries);
struct rb_root *root;
struct rb_node *next;
if (sort__need_collapse)
root = &hists->entries_collapsed;
else
root = hists->entries_in;
next = rb_first(root);
while (next != NULL) {
struct hist_entry *he = rb_entry(next, struct hist_entry, rb_node);
struct hist_entry *he = rb_entry(next, struct hist_entry, rb_node_in);
struct hist_entry *pair = hist_entry__next_pair(he);
next = rb_next(&he->rb_node);
next = rb_next(&he->rb_node_in);
if (!pair)
continue;
......@@ -457,7 +464,7 @@ static void hists__process(struct hists *old, struct hists *new)
hists__output_resort(new);
}
hists__fprintf(new, true, 0, 0, stdout);
hists__fprintf(new, true, 0, 0, 0, stdout);
}
static int __cmd_diff(void)
......@@ -611,9 +618,7 @@ int cmd_diff(int argc, const char **argv, const char *prefix __maybe_unused)
setup_pager();
sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, "dso", NULL);
sort_entry__setup_elide(&sort_comm, symbol_conf.comm_list, "comm", NULL);
sort_entry__setup_elide(&sort_sym, symbol_conf.sym_list, "symbol", NULL);
sort__setup_elide(NULL);
return __cmd_diff();
}
......@@ -328,6 +328,7 @@ static int kvm_events_hash_fn(u64 key)
static bool kvm_event_expand(struct kvm_event *event, int vcpu_id)
{
int old_max_vcpu = event->max_vcpu;
void *prev;
if (vcpu_id < event->max_vcpu)
return true;
......@@ -335,9 +336,11 @@ static bool kvm_event_expand(struct kvm_event *event, int vcpu_id)
while (event->max_vcpu <= vcpu_id)
event->max_vcpu += DEFAULT_VCPU_NUM;
prev = event->vcpu;
event->vcpu = realloc(event->vcpu,
event->max_vcpu * sizeof(*event->vcpu));
if (!event->vcpu) {
free(prev);
pr_err("Not enough memory\n");
return false;
}
......
......@@ -198,7 +198,6 @@ static void perf_record__sig_exit(int exit_status __maybe_unused, void *arg)
return;
signal(signr, SIG_DFL);
kill(getpid(), signr);
}
static bool perf_evlist__equal(struct perf_evlist *evlist,
......@@ -404,6 +403,7 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
signal(SIGCHLD, sig_handler);
signal(SIGINT, sig_handler);
signal(SIGUSR1, sig_handler);
signal(SIGTERM, sig_handler);
if (!output_name) {
if (!fstat(STDOUT_FILENO, &st) && S_ISFIFO(st.st_mode))
......
......@@ -52,6 +52,7 @@ struct perf_report {
symbol_filter_t annotate_init;
const char *cpu_list;
const char *symbol_filter_str;
float min_percent;
DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS);
};
......@@ -61,6 +62,11 @@ static int perf_report_config(const char *var, const char *value, void *cb)
symbol_conf.event_group = perf_config_bool(var, value);
return 0;
}
if (!strcmp(var, "report.percent-limit")) {
struct perf_report *rep = cb;
rep->min_percent = strtof(value, NULL);
return 0;
}
return perf_default_config(var, value, cb);
}
......@@ -187,6 +193,9 @@ static int perf_report__add_branch_hist_entry(struct perf_tool *tool,
for (i = 0; i < sample->branch_stack->nr; i++) {
if (rep->hide_unresolved && !(bi[i].from.sym && bi[i].to.sym))
continue;
err = -ENOMEM;
/*
* The report shows the percentage of total branches captured
* and not events sampled. Thus we use a pseudo period of 1.
......@@ -195,7 +204,6 @@ static int perf_report__add_branch_hist_entry(struct perf_tool *tool,
&bi[i], 1, 1);
if (he) {
struct annotation *notes;
err = -ENOMEM;
bx = he->branch_info;
if (bx->from.sym && use_browser == 1 && sort__has_sym) {
notes = symbol__annotation(bx->from.sym);
......@@ -226,11 +234,12 @@ static int perf_report__add_branch_hist_entry(struct perf_tool *tool,
}
evsel->hists.stats.total_period += 1;
hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE);
err = 0;
} else
return -ENOMEM;
goto out;
}
err = 0;
out:
free(bi);
return err;
}
......@@ -294,6 +303,7 @@ static int process_sample_event(struct perf_tool *tool,
{
struct perf_report *rep = container_of(tool, struct perf_report, tool);
struct addr_location al;
int ret;
if (perf_event__preprocess_sample(event, machine, &al, sample,
rep->annotate_init) < 0) {
......@@ -308,28 +318,25 @@ static int process_sample_event(struct perf_tool *tool,
if (rep->cpu_list && !test_bit(sample->cpu, rep->cpu_bitmap))
return 0;
if (sort__branch_mode == 1) {
if (perf_report__add_branch_hist_entry(tool, &al, sample,
evsel, machine)) {
if (sort__mode == SORT_MODE__BRANCH) {
ret = perf_report__add_branch_hist_entry(tool, &al, sample,
evsel, machine);
if (ret < 0)
pr_debug("problem adding lbr entry, skipping event\n");
return -1;
}
} else if (rep->mem_mode == 1) {
if (perf_report__add_mem_hist_entry(tool, &al, sample,
evsel, machine, event)) {
ret = perf_report__add_mem_hist_entry(tool, &al, sample,
evsel, machine, event);
if (ret < 0)
pr_debug("problem adding mem entry, skipping event\n");
return -1;
}
} else {
if (al.map != NULL)
al.map->dso->hit = 1;
if (perf_evsel__add_hist_entry(evsel, &al, sample, machine)) {
ret = perf_evsel__add_hist_entry(evsel, &al, sample, machine);
if (ret < 0)
pr_debug("problem incrementing symbol period, skipping event\n");
return -1;
}
}
return 0;
return ret;
}
static int process_read_event(struct perf_tool *tool,
......@@ -384,7 +391,7 @@ static int perf_report__setup_sample_type(struct perf_report *rep)
}
}
if (sort__branch_mode == 1) {
if (sort__mode == SORT_MODE__BRANCH) {
if (!self->fd_pipe &&
!(sample_type & PERF_SAMPLE_BRANCH_STACK)) {
ui__error("Selected -b but no branch data. "
......@@ -455,7 +462,7 @@ static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist,
continue;
hists__fprintf_nr_sample_events(rep, hists, evname, stdout);
hists__fprintf(hists, true, 0, 0, stdout);
hists__fprintf(hists, true, 0, 0, rep->min_percent, stdout);
fprintf(stdout, "\n\n");
}
......@@ -574,8 +581,8 @@ static int __cmd_report(struct perf_report *rep)
if (use_browser > 0) {
if (use_browser == 1) {
ret = perf_evlist__tui_browse_hists(session->evlist,
help,
NULL,
help, NULL,
rep->min_percent,
&session->header.env);
/*
* Usually "ret" is the last pressed key, and we only
......@@ -586,7 +593,7 @@ static int __cmd_report(struct perf_report *rep)
} else if (use_browser == 2) {
perf_evlist__gtk_browse_hists(session->evlist, help,
NULL);
NULL, rep->min_percent);
}
} else
perf_evlist__tty_browse_hists(session->evlist, rep, help);
......@@ -691,7 +698,19 @@ static int
parse_branch_mode(const struct option *opt __maybe_unused,
const char *str __maybe_unused, int unset)
{
sort__branch_mode = !unset;
int *branch_mode = opt->value;
*branch_mode = !unset;
return 0;
}
static int
parse_percent_limit(const struct option *opt, const char *str,
int unset __maybe_unused)
{
struct perf_report *rep = opt->value;
rep->min_percent = strtof(str, NULL);
return 0;
}
......@@ -700,6 +719,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
struct perf_session *session;
struct stat st;
bool has_br_stack = false;
int branch_mode = -1;
int ret = -1;
char callchain_default_opt[] = "fractal,0.5,callee";
const char * const report_usage[] = {
......@@ -796,17 +816,19 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
"Show a column with the sum of periods"),
OPT_BOOLEAN(0, "group", &symbol_conf.event_group,
"Show event group information together"),
OPT_CALLBACK_NOOPT('b', "branch-stack", &sort__branch_mode, "",
OPT_CALLBACK_NOOPT('b', "branch-stack", &branch_mode, "",
"use branch records for histogram filling", parse_branch_mode),
OPT_STRING(0, "objdump", &objdump_path, "path",
"objdump binary to use for disassembly and annotations"),
OPT_BOOLEAN(0, "demangle", &symbol_conf.demangle,
"Disable symbol demangling"),
OPT_BOOLEAN(0, "mem-mode", &report.mem_mode, "mem access profile"),
OPT_CALLBACK(0, "percent-limit", &report, "percent",
"Don't show entries under that percent", parse_percent_limit),
OPT_END()
};
perf_config(perf_report_config, NULL);
perf_config(perf_report_config, &report);
argc = parse_options(argc, argv, options, report_usage, 0);
......@@ -846,11 +868,11 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
has_br_stack = perf_header__has_feat(&session->header,
HEADER_BRANCH_STACK);
if (sort__branch_mode == -1 && has_br_stack)
sort__branch_mode = 1;
if (branch_mode == -1 && has_br_stack)
sort__mode = SORT_MODE__BRANCH;
/* sort__branch_mode could be 0 if --no-branch-stack */
if (sort__branch_mode == 1) {
/* sort__mode could be NORMAL if --no-branch-stack */
if (sort__mode == SORT_MODE__BRANCH) {
/*
* if no sort_order is provided, then specify
* branch-mode specific order
......@@ -861,10 +883,12 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
}
if (report.mem_mode) {
if (sort__branch_mode == 1) {
if (sort__mode == SORT_MODE__BRANCH) {
fprintf(stderr, "branch and mem mode incompatible\n");
goto error;
}
sort__mode = SORT_MODE__MEMORY;
/*
* if no sort_order is provided, then specify
* branch-mode specific order
......@@ -929,25 +953,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
report.symbol_filter_str = argv[0];
}
sort_entry__setup_elide(&sort_comm, symbol_conf.comm_list, "comm", stdout);
if (sort__branch_mode == 1) {
sort_entry__setup_elide(&sort_dso_from, symbol_conf.dso_from_list, "dso_from", stdout);
sort_entry__setup_elide(&sort_dso_to, symbol_conf.dso_to_list, "dso_to", stdout);
sort_entry__setup_elide(&sort_sym_from, symbol_conf.sym_from_list, "sym_from", stdout);
sort_entry__setup_elide(&sort_sym_to, symbol_conf.sym_to_list, "sym_to", stdout);
} else {
if (report.mem_mode) {
sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, "symbol_daddr", stdout);
sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, "dso_daddr", stdout);
sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, "mem", stdout);
sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, "local_weight", stdout);
sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, "tlb", stdout);
sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, "snoop", stdout);
}
sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, "dso", stdout);
sort_entry__setup_elide(&sort_sym, symbol_conf.sym_list, "symbol", stdout);
}
sort__setup_elide(stdout);
ret = __cmd_report(&report);
if (ret == K_SWITCH_INPUT_DATA) {
......
......@@ -70,10 +70,11 @@
static volatile int done;
#define HEADER_LINE_NR 5
static void perf_top__update_print_entries(struct perf_top *top)
{
if (top->print_entries > 9)
top->print_entries -= 9;
top->print_entries = top->winsize.ws_row - HEADER_LINE_NR;
}
static void perf_top__sig_winch(int sig __maybe_unused,
......@@ -82,13 +83,6 @@ static void perf_top__sig_winch(int sig __maybe_unused,
struct perf_top *top = arg;
get_term_dimensions(&top->winsize);
if (!top->print_entries
|| (top->print_entries+4) > top->winsize.ws_row) {
top->print_entries = top->winsize.ws_row;
} else {
top->print_entries += 4;
top->winsize.ws_row = top->print_entries;
}
perf_top__update_print_entries(top);
}
......@@ -251,8 +245,11 @@ static struct hist_entry *perf_evsel__add_hist_entry(struct perf_evsel *evsel,
{
struct hist_entry *he;
pthread_mutex_lock(&evsel->hists.lock);
he = __hists__add_entry(&evsel->hists, al, NULL, sample->period,
sample->weight);
pthread_mutex_unlock(&evsel->hists.lock);
if (he == NULL)
return NULL;
......@@ -290,16 +287,17 @@ static void perf_top__print_sym_table(struct perf_top *top)
return;
}
hists__collapse_resort_threaded(&top->sym_evsel->hists);
hists__output_resort_threaded(&top->sym_evsel->hists);
hists__decay_entries_threaded(&top->sym_evsel->hists,
top->hide_user_symbols,
top->hide_kernel_symbols);
hists__collapse_resort(&top->sym_evsel->hists);
hists__output_resort(&top->sym_evsel->hists);
hists__decay_entries(&top->sym_evsel->hists,
top->hide_user_symbols,
top->hide_kernel_symbols);
hists__output_recalc_col_len(&top->sym_evsel->hists,
top->winsize.ws_row - 3);
top->print_entries - printed);
putchar('\n');
hists__fprintf(&top->sym_evsel->hists, false,
top->winsize.ws_row - 4 - printed, win_width, stdout);
top->print_entries - printed, win_width,
top->min_percent, stdout);
}
static void prompt_integer(int *target, const char *msg)
......@@ -477,7 +475,6 @@ static bool perf_top__handle_keypress(struct perf_top *top, int c)
perf_top__sig_winch(SIGWINCH, NULL, top);
sigaction(SIGWINCH, &act, NULL);
} else {
perf_top__sig_winch(SIGWINCH, NULL, top);
signal(SIGWINCH, SIG_DFL);
}
break;
......@@ -556,11 +553,11 @@ static void perf_top__sort_new_samples(void *arg)
if (t->evlist->selected != NULL)
t->sym_evsel = t->evlist->selected;
hists__collapse_resort_threaded(&t->sym_evsel->hists);
hists__output_resort_threaded(&t->sym_evsel->hists);
hists__decay_entries_threaded(&t->sym_evsel->hists,
t->hide_user_symbols,
t->hide_kernel_symbols);
hists__collapse_resort(&t->sym_evsel->hists);
hists__output_resort(&t->sym_evsel->hists);
hists__decay_entries(&t->sym_evsel->hists,
t->hide_user_symbols,
t->hide_kernel_symbols);
}
static void *display_thread_tui(void *arg)
......@@ -584,7 +581,7 @@ static void *display_thread_tui(void *arg)
list_for_each_entry(pos, &top->evlist->entries, node)
pos->hists.uid_filter_str = top->record_opts.target.uid_str;
perf_evlist__tui_browse_hists(top->evlist, help, &hbt,
perf_evlist__tui_browse_hists(top->evlist, help, &hbt, top->min_percent,
&top->session->header.env);
done = 1;
......@@ -794,7 +791,7 @@ static void perf_event__process_sample(struct perf_tool *tool,
return;
}
if (top->sort_has_symbols)
if (sort__has_sym)
perf_top__record_precise_ip(top, he, evsel->idx, ip);
}
......@@ -912,9 +909,9 @@ static int perf_top__start_counters(struct perf_top *top)
return -1;
}
static int perf_top__setup_sample_type(struct perf_top *top)
static int perf_top__setup_sample_type(struct perf_top *top __maybe_unused)
{
if (!top->sort_has_symbols) {
if (!sort__has_sym) {
if (symbol_conf.use_callchain) {
ui__error("Selected -g but \"sym\" not present in --sort/-s.");
return -EINVAL;
......@@ -1025,6 +1022,16 @@ parse_callchain_opt(const struct option *opt, const char *arg, int unset)
return record_parse_callchain_opt(opt, arg, unset);
}
static int
parse_percent_limit(const struct option *opt, const char *arg,
int unset __maybe_unused)
{
struct perf_top *top = opt->value;
top->min_percent = strtof(arg, NULL);
return 0;
}
int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
{
int status;
......@@ -1110,6 +1117,8 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style",
"Specify disassembler style (e.g. -M intel for intel syntax)"),
OPT_STRING('u', "uid", &target->uid_str, "user", "user to profile"),
OPT_CALLBACK(0, "percent-limit", &top, "percent",
"Don't show entries under that percent", parse_percent_limit),
OPT_END()
};
const char * const top_usage[] = {
......@@ -1133,6 +1142,9 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
if (setup_sorting() < 0)
usage_with_options(top_usage, options);
/* display thread wants entries to be collapsed in a different tree */
sort__need_collapse = 1;
if (top.use_stdio)
use_browser = 0;
else if (top.use_tui)
......@@ -1200,15 +1212,7 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
if (symbol__init() < 0)
return -1;
sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, "dso", stdout);
sort_entry__setup_elide(&sort_comm, symbol_conf.comm_list, "comm", stdout);
sort_entry__setup_elide(&sort_sym, symbol_conf.sym_list, "symbol", stdout);
/*
* Avoid annotation data structures overhead when symbols aren't on the
* sort list.
*/
top.sort_has_symbols = sort_sym.list.next != NULL;
sort__setup_elide(stdout);
get_term_dimensions(&top.winsize);
if (top.print_entries == 0) {
......
uname_M := $(shell uname -m 2>/dev/null || echo not)
ARCH ?= $(shell echo $(uname_M) | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ \
-e s/arm.*/arm/ -e s/sa110/arm/ \
-e s/s390x/s390/ -e s/parisc64/parisc/ \
-e s/ppc.*/powerpc/ -e s/mips.*/mips/ \
-e s/sh[234].*/sh/ -e s/aarch64.*/arm64/ )
NO_PERF_REGS := 1
CFLAGS := $(EXTRA_CFLAGS) $(EXTRA_WARNINGS)
# Additional ARCH settings for x86
ifeq ($(ARCH),i386)
override ARCH := x86
NO_PERF_REGS := 0
LIBUNWIND_LIBS = -lunwind -lunwind-x86
endif
ifeq ($(ARCH),x86_64)
override ARCH := x86
IS_X86_64 := 0
ifeq (, $(findstring m32,$(CFLAGS)))
IS_X86_64 := $(shell echo __x86_64__ | ${CC} -E -x c - | tail -n 1)
endif
ifeq (${IS_X86_64}, 1)
RAW_ARCH := x86_64
CFLAGS += -DARCH_X86_64
ARCH_INCLUDE = ../../arch/x86/lib/memcpy_64.S ../../arch/x86/lib/memset_64.S
endif
NO_PERF_REGS := 0
LIBUNWIND_LIBS = -lunwind -lunwind-x86_64
endif
ifeq ($(NO_PERF_REGS),0)
CFLAGS += -DHAVE_PERF_REGS
endif
ifeq ($(src-perf),)
src-perf := $(srctree)/tools/perf
endif
ifeq ($(obj-perf),)
obj-perf := $(objtree)
endif
ifneq ($(obj-perf),)
obj-perf := $(abspath $(obj-perf))/
endif
# include ARCH specific config
-include $(src-perf)/arch/$(ARCH)/Makefile
include $(src-perf)/config/feature-tests.mak
include $(src-perf)/config/utilities.mak
ifeq ($(call get-executable,$(FLEX)),)
dummy := $(error Error: $(FLEX) is missing on this system, please install it)
endif
ifeq ($(call get-executable,$(BISON)),)
dummy := $(error Error: $(BISON) is missing on this system, please install it)
endif
# Treat warnings as errors unless directed not to
ifneq ($(WERROR),0)
CFLAGS += -Werror
endif
ifeq ("$(origin DEBUG)", "command line")
PERF_DEBUG = $(DEBUG)
endif
ifndef PERF_DEBUG
CFLAGS += -O6
endif
ifdef PARSER_DEBUG
PARSER_DEBUG_BISON := -t
PARSER_DEBUG_FLEX := -d
CFLAGS += -DPARSER_DEBUG
endif
CFLAGS += -fno-omit-frame-pointer
CFLAGS += -ggdb3
CFLAGS += -funwind-tables
CFLAGS += -Wall
CFLAGS += -Wextra
CFLAGS += -std=gnu99
EXTLIBS = -lpthread -lrt -lelf -lm
ifeq ($(call try-cc,$(SOURCE_HELLO),$(CFLAGS) -Werror -fstack-protector-all,-fstack-protector-all),y)
CFLAGS += -fstack-protector-all
endif
ifeq ($(call try-cc,$(SOURCE_HELLO),$(CFLAGS) -Werror -Wstack-protector,-Wstack-protector),y)
CFLAGS += -Wstack-protector
endif
ifeq ($(call try-cc,$(SOURCE_HELLO),$(CFLAGS) -Werror -Wvolatile-register-var,-Wvolatile-register-var),y)
CFLAGS += -Wvolatile-register-var
endif
ifndef PERF_DEBUG
ifeq ($(call try-cc,$(SOURCE_HELLO),$(CFLAGS) -D_FORTIFY_SOURCE=2,-D_FORTIFY_SOURCE=2),y)
CFLAGS += -D_FORTIFY_SOURCE=2
endif
endif
CFLAGS += -I$(src-perf)/util/include
CFLAGS += -I$(src-perf)/arch/$(ARCH)/include
CFLAGS += -I$(srctree)/arch/$(ARCH)/include/uapi
CFLAGS += -I$(srctree)/arch/$(ARCH)/include
CFLAGS += -I$(srctree)/include/uapi
CFLAGS += -I$(srctree)/include
# $(obj-perf) for generated common-cmds.h
# $(obj-perf)/util for generated bison/flex headers
ifneq ($(OUTPUT),)
CFLAGS += -I$(obj-perf)/util
CFLAGS += -I$(obj-perf)
endif
CFLAGS += -I$(src-perf)/util
CFLAGS += -I$(src-perf)
CFLAGS += -I$(TRACE_EVENT_DIR)
CFLAGS += -I$(srctree)/tools/lib/
CFLAGS += -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE
ifndef NO_BIONIC
ifeq ($(call try-cc,$(SOURCE_BIONIC),$(CFLAGS),bionic),y)
BIONIC := 1
EXTLIBS := $(filter-out -lrt,$(EXTLIBS))
EXTLIBS := $(filter-out -lpthread,$(EXTLIBS))
endif
endif # NO_BIONIC
ifdef NO_LIBELF
NO_DWARF := 1
NO_DEMANGLE := 1
NO_LIBUNWIND := 1
else
FLAGS_LIBELF=$(CFLAGS) $(LDFLAGS) $(EXTLIBS)
ifneq ($(call try-cc,$(SOURCE_LIBELF),$(FLAGS_LIBELF),libelf),y)
FLAGS_GLIBC=$(CFLAGS) $(LDFLAGS)
ifeq ($(call try-cc,$(SOURCE_GLIBC),$(FLAGS_GLIBC),glibc),y)
LIBC_SUPPORT := 1
endif
ifeq ($(BIONIC),1)
LIBC_SUPPORT := 1
endif
ifeq ($(LIBC_SUPPORT),1)
msg := $(warning No libelf found, disables 'probe' tool, please install elfutils-libelf-devel/libelf-dev);
NO_LIBELF := 1
NO_DWARF := 1
NO_DEMANGLE := 1
else
msg := $(error No gnu/libc-version.h found, please install glibc-dev[el]/glibc-static);
endif
else
# for linking with debug library, run like:
# make DEBUG=1 LIBDW_DIR=/opt/libdw/
ifdef LIBDW_DIR
LIBDW_CFLAGS := -I$(LIBDW_DIR)/include
LIBDW_LDFLAGS := -L$(LIBDW_DIR)/lib
endif
FLAGS_DWARF=$(CFLAGS) $(LIBDW_CFLAGS) -ldw -lelf $(LIBDW_LDFLAGS) $(LDFLAGS) $(EXTLIBS)
ifneq ($(call try-cc,$(SOURCE_DWARF),$(FLAGS_DWARF),libdw),y)
msg := $(warning No libdw.h found or old libdw.h found or elfutils is older than 0.138, disables dwarf support. Please install new elfutils-devel/libdw-dev);
NO_DWARF := 1
endif # Dwarf support
endif # SOURCE_LIBELF
endif # NO_LIBELF
ifndef NO_LIBELF
CFLAGS += -DLIBELF_SUPPORT
FLAGS_LIBELF=$(CFLAGS) $(LDFLAGS) $(EXTLIBS)
ifeq ($(call try-cc,$(SOURCE_ELF_MMAP),$(FLAGS_LIBELF),-DLIBELF_MMAP),y)
CFLAGS += -DLIBELF_MMAP
endif
# include ARCH specific config
-include $(src-perf)/arch/$(ARCH)/Makefile
ifndef NO_DWARF
ifeq ($(origin PERF_HAVE_DWARF_REGS), undefined)
msg := $(warning DWARF register mappings have not been defined for architecture $(ARCH), DWARF support disabled);
NO_DWARF := 1
else
CFLAGS += -DDWARF_SUPPORT $(LIBDW_CFLAGS)
LDFLAGS += $(LIBDW_LDFLAGS)
EXTLIBS += -lelf -ldw
endif # PERF_HAVE_DWARF_REGS
endif # NO_DWARF
endif # NO_LIBELF
ifndef NO_LIBELF
CFLAGS += -DLIBELF_SUPPORT
FLAGS_LIBELF=$(CFLAGS) $(LDFLAGS) $(EXTLIBS)
ifeq ($(call try-cc,$(SOURCE_ELF_MMAP),$(FLAGS_LIBELF),-DLIBELF_MMAP),y)
CFLAGS += -DLIBELF_MMAP
endif # try-cc
endif # NO_LIBELF
# There's only x86 (both 32 and 64) support for CFI unwind so far
ifneq ($(ARCH),x86)
NO_LIBUNWIND := 1
endif
ifndef NO_LIBUNWIND
# for linking with debug library, run like:
# make DEBUG=1 LIBUNWIND_DIR=/opt/libunwind/
ifdef LIBUNWIND_DIR
LIBUNWIND_CFLAGS := -I$(LIBUNWIND_DIR)/include
LIBUNWIND_LDFLAGS := -L$(LIBUNWIND_DIR)/lib
endif
FLAGS_UNWIND=$(LIBUNWIND_CFLAGS) $(CFLAGS) $(LIBUNWIND_LDFLAGS) $(LDFLAGS) $(EXTLIBS) $(LIBUNWIND_LIBS)
ifneq ($(call try-cc,$(SOURCE_LIBUNWIND),$(FLAGS_UNWIND),libunwind),y)
msg := $(warning No libunwind found, disabling post unwind support. Please install libunwind-dev[el] >= 0.99);
NO_LIBUNWIND := 1
endif # Libunwind support
endif # NO_LIBUNWIND
ifndef NO_LIBUNWIND
CFLAGS += -DLIBUNWIND_SUPPORT
EXTLIBS += $(LIBUNWIND_LIBS)
CFLAGS += $(LIBUNWIND_CFLAGS)
LDFLAGS += $(LIBUNWIND_LDFLAGS)
endif # NO_LIBUNWIND
ifndef NO_LIBAUDIT
FLAGS_LIBAUDIT = $(CFLAGS) $(LDFLAGS) -laudit
ifneq ($(call try-cc,$(SOURCE_LIBAUDIT),$(FLAGS_LIBAUDIT),libaudit),y)
msg := $(warning No libaudit.h found, disables 'trace' tool, please install audit-libs-devel or libaudit-dev);
NO_LIBAUDIT := 1
else
CFLAGS += -DLIBAUDIT_SUPPORT
EXTLIBS += -laudit
endif
endif
ifdef NO_NEWT
NO_SLANG=1
endif
ifndef NO_SLANG
FLAGS_SLANG=$(CFLAGS) $(LDFLAGS) $(EXTLIBS) -I/usr/include/slang -lslang
ifneq ($(call try-cc,$(SOURCE_SLANG),$(FLAGS_SLANG),libslang),y)
msg := $(warning slang not found, disables TUI support. Please install slang-devel or libslang-dev);
NO_SLANG := 1
else
# Fedora has /usr/include/slang/slang.h, but ubuntu /usr/include/slang.h
CFLAGS += -I/usr/include/slang
CFLAGS += -DSLANG_SUPPORT
EXTLIBS += -lslang
endif
endif
ifndef NO_GTK2
FLAGS_GTK2=$(CFLAGS) $(LDFLAGS) $(EXTLIBS) $(shell pkg-config --libs --cflags gtk+-2.0 2>/dev/null)
ifneq ($(call try-cc,$(SOURCE_GTK2),$(FLAGS_GTK2),gtk2),y)
msg := $(warning GTK2 not found, disables GTK2 support. Please install gtk2-devel or libgtk2.0-dev);
NO_GTK2 := 1
else
ifeq ($(call try-cc,$(SOURCE_GTK2_INFOBAR),$(FLAGS_GTK2),-DHAVE_GTK_INFO_BAR),y)
CFLAGS += -DHAVE_GTK_INFO_BAR
endif
CFLAGS += -DGTK2_SUPPORT
CFLAGS += $(shell pkg-config --cflags gtk+-2.0 2>/dev/null)
EXTLIBS += $(shell pkg-config --libs gtk+-2.0 2>/dev/null)
endif
endif
grep-libs = $(filter -l%,$(1))
strip-libs = $(filter-out -l%,$(1))
ifdef NO_LIBPERL
CFLAGS += -DNO_LIBPERL
else
PERL_EMBED_LDOPTS = $(shell perl -MExtUtils::Embed -e ldopts 2>/dev/null)
PERL_EMBED_LDFLAGS = $(call strip-libs,$(PERL_EMBED_LDOPTS))
PERL_EMBED_LIBADD = $(call grep-libs,$(PERL_EMBED_LDOPTS))
PERL_EMBED_CCOPTS = `perl -MExtUtils::Embed -e ccopts 2>/dev/null`
FLAGS_PERL_EMBED=$(PERL_EMBED_CCOPTS) $(PERL_EMBED_LDOPTS)
ifneq ($(call try-cc,$(SOURCE_PERL_EMBED),$(FLAGS_PERL_EMBED),perl),y)
CFLAGS += -DNO_LIBPERL
NO_LIBPERL := 1
else
LDFLAGS += $(PERL_EMBED_LDFLAGS)
EXTLIBS += $(PERL_EMBED_LIBADD)
endif
endif
disable-python = $(eval $(disable-python_code))
define disable-python_code
CFLAGS += -DNO_LIBPYTHON
$(if $(1),$(warning No $(1) was found))
$(warning Python support will not be built)
NO_LIBPYTHON := 1
endef
override PYTHON := \
$(call get-executable-or-default,PYTHON,python)
ifndef PYTHON
$(call disable-python,python interpreter)
else
PYTHON_WORD := $(call shell-wordify,$(PYTHON))
ifdef NO_LIBPYTHON
$(call disable-python)
else
override PYTHON_CONFIG := \
$(call get-executable-or-default,PYTHON_CONFIG,$(PYTHON)-config)
ifndef PYTHON_CONFIG
$(call disable-python,python-config tool)
else
PYTHON_CONFIG_SQ := $(call shell-sq,$(PYTHON_CONFIG))
PYTHON_EMBED_LDOPTS := $(shell $(PYTHON_CONFIG_SQ) --ldflags 2>/dev/null)
PYTHON_EMBED_LDFLAGS := $(call strip-libs,$(PYTHON_EMBED_LDOPTS))
PYTHON_EMBED_LIBADD := $(call grep-libs,$(PYTHON_EMBED_LDOPTS))
PYTHON_EMBED_CCOPTS := $(shell $(PYTHON_CONFIG_SQ) --cflags 2>/dev/null)
FLAGS_PYTHON_EMBED := $(PYTHON_EMBED_CCOPTS) $(PYTHON_EMBED_LDOPTS)
ifneq ($(call try-cc,$(SOURCE_PYTHON_EMBED),$(FLAGS_PYTHON_EMBED),python),y)
$(call disable-python,Python.h (for Python 2.x))
else
ifneq ($(call try-cc,$(SOURCE_PYTHON_VERSION),$(FLAGS_PYTHON_EMBED),python version),y)
$(warning Python 3 is not yet supported; please set)
$(warning PYTHON and/or PYTHON_CONFIG appropriately.)
$(warning If you also have Python 2 installed, then)
$(warning try something like:)
$(warning $(and ,))
$(warning $(and ,) make PYTHON=python2)
$(warning $(and ,))
$(warning Otherwise, disable Python support entirely:)
$(warning $(and ,))
$(warning $(and ,) make NO_LIBPYTHON=1)
$(warning $(and ,))
$(error $(and ,))
else
LDFLAGS += $(PYTHON_EMBED_LDFLAGS)
EXTLIBS += $(PYTHON_EMBED_LIBADD)
LANG_BINDINGS += $(obj-perf)python/perf.so
endif
endif
endif
endif
endif
ifdef NO_DEMANGLE
CFLAGS += -DNO_DEMANGLE
else
ifdef HAVE_CPLUS_DEMANGLE
EXTLIBS += -liberty
CFLAGS += -DHAVE_CPLUS_DEMANGLE
else
FLAGS_BFD=$(CFLAGS) $(LDFLAGS) $(EXTLIBS) -DPACKAGE='perf' -lbfd
has_bfd := $(call try-cc,$(SOURCE_BFD),$(FLAGS_BFD),libbfd)
ifeq ($(has_bfd),y)
EXTLIBS += -lbfd
else
FLAGS_BFD_IBERTY=$(FLAGS_BFD) -liberty
has_bfd_iberty := $(call try-cc,$(SOURCE_BFD),$(FLAGS_BFD_IBERTY),liberty)
ifeq ($(has_bfd_iberty),y)
EXTLIBS += -lbfd -liberty
else
FLAGS_BFD_IBERTY_Z=$(FLAGS_BFD_IBERTY) -lz
has_bfd_iberty_z := $(call try-cc,$(SOURCE_BFD),$(FLAGS_BFD_IBERTY_Z),libz)
ifeq ($(has_bfd_iberty_z),y)
EXTLIBS += -lbfd -liberty -lz
else
FLAGS_CPLUS_DEMANGLE=$(CFLAGS) $(LDFLAGS) $(EXTLIBS) -liberty
has_cplus_demangle := $(call try-cc,$(SOURCE_CPLUS_DEMANGLE),$(FLAGS_CPLUS_DEMANGLE),demangle)
ifeq ($(has_cplus_demangle),y)
EXTLIBS += -liberty
CFLAGS += -DHAVE_CPLUS_DEMANGLE
else
msg := $(warning No bfd.h/libbfd found, install binutils-dev[el]/zlib-static to gain symbol demangling)
CFLAGS += -DNO_DEMANGLE
endif
endif
endif
endif
endif
endif
ifndef NO_STRLCPY
ifeq ($(call try-cc,$(SOURCE_STRLCPY),,-DHAVE_STRLCPY),y)
CFLAGS += -DHAVE_STRLCPY
endif
endif
ifndef NO_ON_EXIT
ifeq ($(call try-cc,$(SOURCE_ON_EXIT),,-DHAVE_ON_EXIT),y)
CFLAGS += -DHAVE_ON_EXIT
endif
endif
ifndef NO_BACKTRACE
ifeq ($(call try-cc,$(SOURCE_BACKTRACE),,-DBACKTRACE_SUPPORT),y)
CFLAGS += -DBACKTRACE_SUPPORT
endif
endif
ifndef NO_LIBNUMA
FLAGS_LIBNUMA = $(CFLAGS) $(LDFLAGS) -lnuma
ifneq ($(call try-cc,$(SOURCE_LIBNUMA),$(FLAGS_LIBNUMA),libnuma),y)
msg := $(warning No numa.h found, disables 'perf bench numa mem' benchmark, please install numa-libs-devel or libnuma-dev);
NO_LIBNUMA := 1
else
CFLAGS += -DLIBNUMA_SUPPORT
EXTLIBS += -lnuma
endif
endif
# Among the variables below, these:
# perfexecdir
# template_dir
# mandir
# infodir
# htmldir
# ETC_PERFCONFIG (but not sysconfdir)
# can be specified as a relative path some/where/else;
# this is interpreted as relative to $(prefix) and "perf" at
# runtime figures out where they are based on the path to the executable.
# This can help installing the suite in a relocatable way.
# Make the path relative to DESTDIR, not to prefix
ifndef DESTDIR
prefix = $(HOME)
endif
bindir_relative = bin
bindir = $(prefix)/$(bindir_relative)
mandir = share/man
infodir = share/info
perfexecdir = libexec/perf-core
sharedir = $(prefix)/share
template_dir = share/perf-core/templates
htmldir = share/doc/perf-doc
ifeq ($(prefix),/usr)
sysconfdir = /etc
ETC_PERFCONFIG = $(sysconfdir)/perfconfig
else
sysconfdir = $(prefix)/etc
ETC_PERFCONFIG = etc/perfconfig
endif
lib = lib
# Shell quote (do not use $(call) to accommodate ancient setups);
ETC_PERFCONFIG_SQ = $(subst ','\'',$(ETC_PERFCONFIG))
DESTDIR_SQ = $(subst ','\'',$(DESTDIR))
bindir_SQ = $(subst ','\'',$(bindir))
mandir_SQ = $(subst ','\'',$(mandir))
infodir_SQ = $(subst ','\'',$(infodir))
perfexecdir_SQ = $(subst ','\'',$(perfexecdir))
template_dir_SQ = $(subst ','\'',$(template_dir))
htmldir_SQ = $(subst ','\'',$(htmldir))
prefix_SQ = $(subst ','\'',$(prefix))
sysconfdir_SQ = $(subst ','\'',$(sysconfdir))
ifneq ($(filter /%,$(firstword $(perfexecdir))),)
perfexec_instdir = $(perfexecdir)
else
perfexec_instdir = $(prefix)/$(perfexecdir)
endif
perfexec_instdir_SQ = $(subst ','\'',$(perfexec_instdir))
......@@ -27,8 +27,8 @@ watermark=0
precise_ip=0
mmap_data=0
sample_id_all=1
exclude_host=0
exclude_guest=1
exclude_host=0|1
exclude_guest=0|1
exclude_callchain_kernel=0
exclude_callchain_user=0
wakeup_events=0
......
......@@ -27,8 +27,8 @@ watermark=0
precise_ip=0
mmap_data=0
sample_id_all=0
exclude_host=0
exclude_guest=1
exclude_host=0|1
exclude_guest=0|1
exclude_callchain_kernel=0
exclude_callchain_user=0
wakeup_events=0
......
......@@ -4,5 +4,8 @@ args = -d kill >/dev/null 2>&1
[event:base-record]
sample_period=4000
sample_type=271
# sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID | PERF_SAMPLE_TIME |
# PERF_SAMPLE_ADDR | PERF_SAMPLE_PERIOD | PERF_SAMPLE_DATA_SRC
sample_type=33039
mmap_data=1
......@@ -4,6 +4,12 @@
* (git://github.com/deater/perf_event_tests)
*/
/*
* Powerpc needs __SANE_USERSPACE_TYPES__ before <linux/types.h> to select
* 'int-ll64.h' and avoid compile warnings when printing __u64 with %llu.
*/
#define __SANE_USERSPACE_TYPES__
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
......
......@@ -3,6 +3,12 @@
* perf_event_tests (git://github.com/deater/perf_event_tests)
*/
/*
* Powerpc needs __SANE_USERSPACE_TYPES__ before <linux/types.h> to select
* 'int-ll64.h' and avoid compile warnings when printing __u64 with %llu.
*/
#define __SANE_USERSPACE_TYPES__
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
......
......@@ -70,7 +70,7 @@ static struct test {
.func = test__attr,
},
{
.desc = "Test matching and linking mutliple hists",
.desc = "Test matching and linking multiple hists",
.func = test__hists_link,
},
{
......
PERF := .
MK := Makefile
# standard single make variable specified
make_clean_all := clean all
make_python_perf_so := python/perf.so
make_debug := DEBUG=1
make_no_libperl := NO_LIBPERL=1
make_no_libpython := NO_LIBPYTHON=1
make_no_scripts := NO_LIBPYTHON=1 NO_LIBPERL=1
make_no_newt := NO_NEWT=1
make_no_slang := NO_SLANG=1
make_no_gtk2 := NO_GTK2=1
make_no_ui := NO_NEWT=1 NO_SLANG=1 NO_GTK2=1
make_no_demangle := NO_DEMANGLE=1
make_no_libelf := NO_LIBELF=1
make_no_libunwind := NO_LIBUNWIND=1
make_no_backtrace := NO_BACKTRACE=1
make_no_libnuma := NO_LIBNUMA=1
make_no_libaudit := NO_LIBAUDIT=1
make_no_libbionic := NO_LIBBIONIC=1
make_tags := tags
make_cscope := cscope
make_help := help
make_doc := doc
make_perf_o := perf.o
make_util_map_o := util/map.o
# all the NO_* variable combined
make_minimal := NO_LIBPERL=1 NO_LIBPYTHON=1 NO_NEWT=1 NO_GTK2=1
make_minimal += NO_DEMANGLE=1 NO_LIBELF=1 NO_LIBUNWIND=1 NO_BACKTRACE=1
make_minimal += NO_LIBNUMA=1 NO_LIBAUDIT=1 NO_LIBBIONIC=1
# $(run) contains all available tests
run := make_pure
run += make_clean_all
run += make_python_perf_so
run += make_debug
run += make_no_libperl
run += make_no_libpython
run += make_no_scripts
run += make_no_newt
run += make_no_slang
run += make_no_gtk2
run += make_no_ui
run += make_no_demangle
run += make_no_libelf
run += make_no_libunwind
run += make_no_backtrace
run += make_no_libnuma
run += make_no_libaudit
run += make_no_libbionic
run += make_tags
run += make_cscope
run += make_help
run += make_doc
run += make_perf_o
run += make_util_map_o
run += make_minimal
# $(run_O) contains same portion of $(run) tests with '_O' attached
# to distinguish O=... tests
run_O := $(addsuffix _O,$(run))
# disable some tests for O=...
run_O := $(filter-out make_python_perf_so_O,$(run_O))
# define test for each compile as 'test_NAME' variable
# with the test itself as a value
test_make_tags = test -f tags
test_make_cscope = test -f cscope.out
test_make_tags_O := $(test_make_tags)
test_make_cscope_O := $(test_make_cscope)
test_ok := true
test_make_help := $(test_ok)
test_make_doc := $(test_ok)
test_make_help_O := $(test_ok)
test_make_doc_O := $(test_ok)
test_make_python_perf_so := test -f $(PERF)/python/perf.so
test_make_perf_o := test -f $(PERF)/perf.o
test_make_util_map_o := test -f $(PERF)/util/map.o
# Kbuild tests only
#test_make_python_perf_so_O := test -f $$TMP/tools/perf/python/perf.so
#test_make_perf_o_O := test -f $$TMP/tools/perf/perf.o
#test_make_util_map_o_O := test -f $$TMP/tools/perf/util/map.o
test_make_perf_o_O := true
test_make_util_map_o_O := true
test_default = test -x $(PERF)/perf
test = $(if $(test_$1),$(test_$1),$(test_default))
test_default_O = test -x $$TMP/perf
test_O = $(if $(test_$1),$(test_$1),$(test_default_O))
all:
ifdef DEBUG
d := $(info run $(run))
d := $(info run_O $(run_O))
endif
MAKEFLAGS := --no-print-directory
clean := @(cd $(PERF); make -s -f $(MK) clean >/dev/null)
$(run):
$(call clean)
@cmd="cd $(PERF) && make -f $(MK) $($@)"; \
echo "- $@: $$cmd" && echo $$cmd > $@ && \
( eval $$cmd ) >> $@ 2>&1; \
echo " test: $(call test,$@)"; \
$(call test,$@) && \
rm -f $@
$(run_O):
$(call clean)
@TMP=$$(mktemp -d); \
cmd="cd $(PERF) && make -f $(MK) $($(patsubst %_O,%,$@)) O=$$TMP"; \
echo "- $@: $$cmd" && echo $$cmd > $@ && \
( eval $$cmd ) >> $@ 2>&1 && \
echo " test: $(call test_O,$@)"; \
$(call test_O,$@) && \
rm -f $@ && \
rm -rf $$TMP
all: $(run) $(run_O)
@echo OK
out: $(run_O)
@echo OK
.PHONY: all $(run) $(run_O) clean
......@@ -25,7 +25,8 @@ struct hist_browser {
struct map_symbol *selection;
int print_seq;
bool show_dso;
bool has_symbols;
float min_pcnt;
u64 nr_pcnt_entries;
};
extern void hist_browser__init_hpp(void);
......@@ -309,6 +310,8 @@ static void ui_browser__warn_lost_events(struct ui_browser *browser)
"Or reduce the sampling frequency.");
}
static void hist_browser__update_pcnt_entries(struct hist_browser *hb);
static int hist_browser__run(struct hist_browser *browser, const char *ev_name,
struct hist_browser_timer *hbt)
{
......@@ -318,6 +321,8 @@ static int hist_browser__run(struct hist_browser *browser, const char *ev_name,
browser->b.entries = &browser->hists->entries;
browser->b.nr_entries = browser->hists->nr_entries;
if (browser->min_pcnt)
browser->b.nr_entries = browser->nr_pcnt_entries;
hist_browser__refresh_dimensions(browser);
hists__browser_title(browser->hists, title, sizeof(title), ev_name);
......@@ -330,9 +335,18 @@ static int hist_browser__run(struct hist_browser *browser, const char *ev_name,
key = ui_browser__run(&browser->b, delay_secs);
switch (key) {
case K_TIMER:
case K_TIMER: {
u64 nr_entries;
hbt->timer(hbt->arg);
ui_browser__update_nr_entries(&browser->b, browser->hists->nr_entries);
if (browser->min_pcnt) {
hist_browser__update_pcnt_entries(browser);
nr_entries = browser->nr_pcnt_entries;
} else {
nr_entries = browser->hists->nr_entries;
}
ui_browser__update_nr_entries(&browser->b, nr_entries);
if (browser->hists->stats.nr_lost_warned !=
browser->hists->stats.nr_events[PERF_RECORD_LOST]) {
......@@ -344,6 +358,7 @@ static int hist_browser__run(struct hist_browser *browser, const char *ev_name,
hists__browser_title(browser->hists, title, sizeof(title), ev_name);
ui_browser__show_title(&browser->b, title);
continue;
}
case 'D': { /* Debug */
static int seq;
struct hist_entry *h = rb_entry(browser->b.top,
......@@ -796,10 +811,15 @@ static unsigned int hist_browser__refresh(struct ui_browser *browser)
for (nd = browser->top; nd; nd = rb_next(nd)) {
struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
float percent = h->stat.period * 100.0 /
hb->hists->stats.total_period;
if (h->filtered)
continue;
if (percent < hb->min_pcnt)
continue;
row += hist_browser__show_entry(hb, h, row);
if (row == browser->height)
break;
......@@ -808,10 +828,18 @@ static unsigned int hist_browser__refresh(struct ui_browser *browser)
return row;
}
static struct rb_node *hists__filter_entries(struct rb_node *nd)
static struct rb_node *hists__filter_entries(struct rb_node *nd,
struct hists *hists,
float min_pcnt)
{
while (nd != NULL) {
struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
float percent = h->stat.period * 100.0 /
hists->stats.total_period;
if (percent < min_pcnt)
return NULL;
if (!h->filtered)
return nd;
......@@ -821,11 +849,16 @@ static struct rb_node *hists__filter_entries(struct rb_node *nd)
return NULL;
}
static struct rb_node *hists__filter_prev_entries(struct rb_node *nd)
static struct rb_node *hists__filter_prev_entries(struct rb_node *nd,
struct hists *hists,
float min_pcnt)
{
while (nd != NULL) {
struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
if (!h->filtered)
float percent = h->stat.period * 100.0 /
hists->stats.total_period;
if (!h->filtered && percent >= min_pcnt)
return nd;
nd = rb_prev(nd);
......@@ -840,6 +873,9 @@ static void ui_browser__hists_seek(struct ui_browser *browser,
struct hist_entry *h;
struct rb_node *nd;
bool first = true;
struct hist_browser *hb;
hb = container_of(browser, struct hist_browser, b);
if (browser->nr_entries == 0)
return;
......@@ -848,13 +884,15 @@ static void ui_browser__hists_seek(struct ui_browser *browser,
switch (whence) {
case SEEK_SET:
nd = hists__filter_entries(rb_first(browser->entries));
nd = hists__filter_entries(rb_first(browser->entries),
hb->hists, hb->min_pcnt);
break;
case SEEK_CUR:
nd = browser->top;
goto do_offset;
case SEEK_END:
nd = hists__filter_prev_entries(rb_last(browser->entries));
nd = hists__filter_prev_entries(rb_last(browser->entries),
hb->hists, hb->min_pcnt);
first = false;
break;
default:
......@@ -897,7 +935,8 @@ static void ui_browser__hists_seek(struct ui_browser *browser,
break;
}
}
nd = hists__filter_entries(rb_next(nd));
nd = hists__filter_entries(rb_next(nd), hb->hists,
hb->min_pcnt);
if (nd == NULL)
break;
--offset;
......@@ -930,7 +969,8 @@ static void ui_browser__hists_seek(struct ui_browser *browser,
}
}
nd = hists__filter_prev_entries(rb_prev(nd));
nd = hists__filter_prev_entries(rb_prev(nd), hb->hists,
hb->min_pcnt);
if (nd == NULL)
break;
++offset;
......@@ -1099,14 +1139,17 @@ static int hist_browser__fprintf_entry(struct hist_browser *browser,
static int hist_browser__fprintf(struct hist_browser *browser, FILE *fp)
{
struct rb_node *nd = hists__filter_entries(rb_first(browser->b.entries));
struct rb_node *nd = hists__filter_entries(rb_first(browser->b.entries),
browser->hists,
browser->min_pcnt);
int printed = 0;
while (nd) {
struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
printed += hist_browser__fprintf_entry(browser, h, fp);
nd = hists__filter_entries(rb_next(nd));
nd = hists__filter_entries(rb_next(nd), browser->hists,
browser->min_pcnt);
}
return printed;
......@@ -1155,10 +1198,6 @@ static struct hist_browser *hist_browser__new(struct hists *hists)
browser->b.refresh = hist_browser__refresh;
browser->b.seek = ui_browser__hists_seek;
browser->b.use_navkeypressed = true;
if (sort__branch_mode == 1)
browser->has_symbols = sort_sym_from.list.next != NULL;
else
browser->has_symbols = sort_sym.list.next != NULL;
}
return browser;
......@@ -1329,11 +1368,25 @@ static int switch_data_file(void)
return ret;
}
static void hist_browser__update_pcnt_entries(struct hist_browser *hb)
{
u64 nr_entries = 0;
struct rb_node *nd = rb_first(&hb->hists->entries);
while (nd) {
nr_entries++;
nd = hists__filter_entries(rb_next(nd), hb->hists,
hb->min_pcnt);
}
hb->nr_pcnt_entries = nr_entries;
}
static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
const char *helpline, const char *ev_name,
bool left_exits,
struct hist_browser_timer *hbt,
float min_pcnt,
struct perf_session_env *env)
{
struct hists *hists = &evsel->hists;
......@@ -1350,6 +1403,11 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
if (browser == NULL)
return -1;
if (min_pcnt) {
browser->min_pcnt = min_pcnt;
hist_browser__update_pcnt_entries(browser);
}
fstack = pstack__new(2);
if (fstack == NULL)
goto out;
......@@ -1386,7 +1444,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
*/
goto out_free_stack;
case 'a':
if (!browser->has_symbols) {
if (!sort__has_sym) {
ui_browser__warning(&browser->b, delay_secs * 2,
"Annotation is only available for symbolic views, "
"include \"sym*\" in --sort to use it.");
......@@ -1485,10 +1543,10 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
continue;
}
if (!browser->has_symbols)
if (!sort__has_sym)
goto add_exit_option;
if (sort__branch_mode == 1) {
if (sort__mode == SORT_MODE__BRANCH) {
bi = browser->he_selection->branch_info;
if (browser->selection != NULL &&
bi &&
......@@ -1689,6 +1747,7 @@ struct perf_evsel_menu {
struct ui_browser b;
struct perf_evsel *selection;
bool lost_events, lost_events_warned;
float min_pcnt;
struct perf_session_env *env;
};
......@@ -1782,6 +1841,7 @@ static int perf_evsel_menu__run(struct perf_evsel_menu *menu,
ev_name = perf_evsel__name(pos);
key = perf_evsel__hists_browse(pos, nr_events, help,
ev_name, true, hbt,
menu->min_pcnt,
menu->env);
ui_browser__show_title(&menu->b, title);
switch (key) {
......@@ -1843,6 +1903,7 @@ static bool filter_group_entries(struct ui_browser *self __maybe_unused,
static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
int nr_entries, const char *help,
struct hist_browser_timer *hbt,
float min_pcnt,
struct perf_session_env *env)
{
struct perf_evsel *pos;
......@@ -1856,6 +1917,7 @@ static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
.nr_entries = nr_entries,
.priv = evlist,
},
.min_pcnt = min_pcnt,
.env = env,
};
......@@ -1874,6 +1936,7 @@ static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help,
struct hist_browser_timer *hbt,
float min_pcnt,
struct perf_session_env *env)
{
int nr_entries = evlist->nr_entries;
......@@ -1885,7 +1948,8 @@ int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help,
const char *ev_name = perf_evsel__name(first);
return perf_evsel__hists_browse(first, nr_entries, help,
ev_name, false, hbt, env);
ev_name, false, hbt, min_pcnt,
env);
}
if (symbol_conf.event_group) {
......@@ -1901,5 +1965,5 @@ int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help,
}
return __perf_evlist__tui_browse_hists(evlist, nr_entries, help,
hbt, env);
hbt, min_pcnt, env);
}
......@@ -124,7 +124,8 @@ void perf_gtk__init_hpp(void)
perf_gtk__hpp_color_overhead_guest_us;
}
static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists)
static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,
float min_pcnt)
{
struct perf_hpp_fmt *fmt;
GType col_types[MAX_COLUMNS];
......@@ -189,10 +190,15 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists)
for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
GtkTreeIter iter;
float percent = h->stat.period * 100.0 /
hists->stats.total_period;
if (h->filtered)
continue;
if (percent < min_pcnt)
continue;
gtk_list_store_append(store, &iter);
col_idx = 0;
......@@ -222,7 +228,8 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists)
int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist,
const char *help,
struct hist_browser_timer *hbt __maybe_unused)
struct hist_browser_timer *hbt __maybe_unused,
float min_pcnt)
{
struct perf_evsel *pos;
GtkWidget *vbox;
......@@ -286,7 +293,7 @@ int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist,
GTK_POLICY_AUTOMATIC,
GTK_POLICY_AUTOMATIC);
perf_gtk__show_hists(scrolled_window, hists);
perf_gtk__show_hists(scrolled_window, hists, min_pcnt);
tab_label = gtk_label_new(evname);
......
......@@ -334,7 +334,7 @@ static int hist_entry__fprintf(struct hist_entry *he, size_t size,
}
size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,
int max_cols, FILE *fp)
int max_cols, float min_pcnt, FILE *fp)
{
struct perf_hpp_fmt *fmt;
struct sort_entry *se;
......@@ -440,10 +440,15 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,
print_entries:
for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
float percent = h->stat.period * 100.0 /
hists->stats.total_period;
if (h->filtered)
continue;
if (percent < min_pcnt)
continue;
ret += hist_entry__fprintf(h, max_cols, hists, fp);
if (max_rows && ++nr_rows >= max_rows)
......
......@@ -776,6 +776,8 @@ int perf_evlist__prepare_workload(struct perf_evlist *evlist,
if (pipe_output)
dup2(2, 1);
signal(SIGTERM, SIG_DFL);
close(child_ready_pipe[0]);
close(go_pipe[1]);
fcntl(go_pipe[0], F_SETFD, FD_CLOEXEC);
......
......@@ -1514,7 +1514,7 @@ int perf_evsel__open_strerror(struct perf_evsel *evsel,
switch (err) {
case EPERM:
case EACCES:
return scnprintf(msg, size, "%s",
return scnprintf(msg, size,
"You may not have permission to collect %sstats.\n"
"Consider tweaking /proc/sys/kernel/perf_event_paranoid:\n"
" -1 - Not paranoid at all\n"
......
......@@ -2391,7 +2391,6 @@ int perf_session__write_header(struct perf_session *session,
}
lseek(fd, header->data_offset + header->data_size, SEEK_SET);
header->frozen = 1;
return 0;
}
......@@ -2871,7 +2870,6 @@ int perf_session__read_header(struct perf_session *session, int fd)
session->pevent))
goto out_delete_evlist;
header->frozen = 1;
return 0;
out_errno:
return -errno;
......
......@@ -84,7 +84,6 @@ struct perf_session_env {
};
struct perf_header {
int frozen;
bool needs_swap;
s64 attr_offset;
u64 data_offset;
......
......@@ -70,9 +70,17 @@ void hists__calc_col_len(struct hists *hists, struct hist_entry *h)
int symlen;
u16 len;
if (h->ms.sym)
hists__new_col_len(hists, HISTC_SYMBOL, h->ms.sym->namelen + 4);
else {
/*
* +4 accounts for '[x] ' priv level info
* +2 accounts for 0x prefix on raw addresses
* +3 accounts for ' y ' symtab origin info
*/
if (h->ms.sym) {
symlen = h->ms.sym->namelen + 4;
if (verbose)
symlen += BITS_PER_LONG / 4 + 2 + 3;
hists__new_col_len(hists, HISTC_SYMBOL, symlen);
} else {
symlen = unresolved_col_width + 4 + 2;
hists__new_col_len(hists, HISTC_SYMBOL, symlen);
hists__set_unres_dso_col_len(hists, HISTC_DSO);
......@@ -91,12 +99,10 @@ void hists__calc_col_len(struct hists *hists, struct hist_entry *h)
hists__new_col_len(hists, HISTC_PARENT, h->parent->namelen);
if (h->branch_info) {
/*
* +4 accounts for '[x] ' priv level info
* +2 account of 0x prefix on raw addresses
*/
if (h->branch_info->from.sym) {
symlen = (int)h->branch_info->from.sym->namelen + 4;
if (verbose)
symlen += BITS_PER_LONG / 4 + 2 + 3;
hists__new_col_len(hists, HISTC_SYMBOL_FROM, symlen);
symlen = dso__name_len(h->branch_info->from.map->dso);
......@@ -109,6 +115,8 @@ void hists__calc_col_len(struct hists *hists, struct hist_entry *h)
if (h->branch_info->to.sym) {
symlen = (int)h->branch_info->to.sym->namelen + 4;
if (verbose)
symlen += BITS_PER_LONG / 4 + 2 + 3;
hists__new_col_len(hists, HISTC_SYMBOL_TO, symlen);
symlen = dso__name_len(h->branch_info->to.map->dso);
......@@ -121,10 +129,6 @@ void hists__calc_col_len(struct hists *hists, struct hist_entry *h)
}
if (h->mem_info) {
/*
* +4 accounts for '[x] ' priv level info
* +2 account of 0x prefix on raw addresses
*/
if (h->mem_info->daddr.sym) {
symlen = (int)h->mem_info->daddr.sym->namelen + 4
+ unresolved_col_width + 2;
......@@ -236,8 +240,7 @@ static bool hists__decay_entry(struct hists *hists, struct hist_entry *he)
return he->stat.period == 0;
}
static void __hists__decay_entries(struct hists *hists, bool zap_user,
bool zap_kernel, bool threaded)
void hists__decay_entries(struct hists *hists, bool zap_user, bool zap_kernel)
{
struct rb_node *next = rb_first(&hists->entries);
struct hist_entry *n;
......@@ -256,7 +259,7 @@ static void __hists__decay_entries(struct hists *hists, bool zap_user,
!n->used) {
rb_erase(&n->rb_node, &hists->entries);
if (sort__need_collapse || threaded)
if (sort__need_collapse)
rb_erase(&n->rb_node_in, &hists->entries_collapsed);
hist_entry__free(n);
......@@ -265,17 +268,6 @@ static void __hists__decay_entries(struct hists *hists, bool zap_user,
}
}
void hists__decay_entries(struct hists *hists, bool zap_user, bool zap_kernel)
{
return __hists__decay_entries(hists, zap_user, zap_kernel, false);
}
void hists__decay_entries_threaded(struct hists *hists,
bool zap_user, bool zap_kernel)
{
return __hists__decay_entries(hists, zap_user, zap_kernel, true);
}
/*
* histogram, sorted on item, collects periods
*/
......@@ -292,6 +284,20 @@ static struct hist_entry *hist_entry__new(struct hist_entry *template)
he->ms.map->referenced = true;
if (he->branch_info) {
/*
* This branch info is (a part of) allocated from
* machine__resolve_bstack() and will be freed after
* adding new entries. So we need to save a copy.
*/
he->branch_info = malloc(sizeof(*he->branch_info));
if (he->branch_info == NULL) {
free(he);
return NULL;
}
memcpy(he->branch_info, template->branch_info,
sizeof(*he->branch_info));
if (he->branch_info->from.map)
he->branch_info->from.map->referenced = true;
if (he->branch_info->to.map)
......@@ -341,8 +347,6 @@ static struct hist_entry *add_hist_entry(struct hists *hists,
struct hist_entry *he;
int cmp;
pthread_mutex_lock(&hists->lock);
p = &hists->entries_in->rb_node;
while (*p != NULL) {
......@@ -360,6 +364,12 @@ static struct hist_entry *add_hist_entry(struct hists *hists,
if (!cmp) {
he_stat__add_period(&he->stat, period, weight);
/*
* This mem info was allocated from machine__resolve_mem
* and will not be used anymore.
*/
free(entry->mem_info);
/* If the map of an existing hist_entry has
* become out-of-date due to an exec() or
* similar, update it. Otherwise we will
......@@ -382,14 +392,12 @@ static struct hist_entry *add_hist_entry(struct hists *hists,
he = hist_entry__new(entry);
if (!he)
goto out_unlock;
return NULL;
rb_link_node(&he->rb_node_in, parent, p);
rb_insert_color(&he->rb_node_in, hists->entries_in);
out:
hist_entry__add_cpumode_period(he, al->cpumode, period);
out_unlock:
pthread_mutex_unlock(&hists->lock);
return he;
}
......@@ -589,13 +597,13 @@ static void hists__apply_filters(struct hists *hists, struct hist_entry *he)
hists__filter_entry_by_symbol(hists, he);
}
static void __hists__collapse_resort(struct hists *hists, bool threaded)
void hists__collapse_resort(struct hists *hists)
{
struct rb_root *root;
struct rb_node *next;
struct hist_entry *n;
if (!sort__need_collapse && !threaded)
if (!sort__need_collapse)
return;
root = hists__get_rotate_entries_in(hists);
......@@ -617,16 +625,6 @@ static void __hists__collapse_resort(struct hists *hists, bool threaded)
}
}
void hists__collapse_resort(struct hists *hists)
{
return __hists__collapse_resort(hists, false);
}
void hists__collapse_resort_threaded(struct hists *hists)
{
return __hists__collapse_resort(hists, true);
}
/*
* reverse the map, sort on period.
*/
......@@ -713,7 +711,7 @@ static void __hists__insert_output_entry(struct rb_root *entries,
rb_insert_color(&he->rb_node, entries);
}
static void __hists__output_resort(struct hists *hists, bool threaded)
void hists__output_resort(struct hists *hists)
{
struct rb_root *root;
struct rb_node *next;
......@@ -722,7 +720,7 @@ static void __hists__output_resort(struct hists *hists, bool threaded)
min_callchain_hits = hists->stats.total_period * (callchain_param.min_percent / 100);
if (sort__need_collapse || threaded)
if (sort__need_collapse)
root = &hists->entries_collapsed;
else
root = hists->entries_in;
......@@ -743,16 +741,6 @@ static void __hists__output_resort(struct hists *hists, bool threaded)
}
}
void hists__output_resort(struct hists *hists)
{
return __hists__output_resort(hists, false);
}
void hists__output_resort_threaded(struct hists *hists)
{
return __hists__output_resort(hists, true);
}
static void hists__remove_entry_filter(struct hists *hists, struct hist_entry *h,
enum hist_filter filter)
{
......
......@@ -43,12 +43,12 @@ enum hist_column {
HISTC_COMM,
HISTC_PARENT,
HISTC_CPU,
HISTC_SRCLINE,
HISTC_MISPREDICT,
HISTC_SYMBOL_FROM,
HISTC_SYMBOL_TO,
HISTC_DSO_FROM,
HISTC_DSO_TO,
HISTC_SRCLINE,
HISTC_LOCAL_WEIGHT,
HISTC_GLOBAL_WEIGHT,
HISTC_MEM_DADDR_SYMBOL,
......@@ -104,13 +104,9 @@ struct hist_entry *__hists__add_mem_entry(struct hists *self,
u64 weight);
void hists__output_resort(struct hists *self);
void hists__output_resort_threaded(struct hists *hists);
void hists__collapse_resort(struct hists *self);
void hists__collapse_resort_threaded(struct hists *hists);
void hists__decay_entries(struct hists *hists, bool zap_user, bool zap_kernel);
void hists__decay_entries_threaded(struct hists *hists, bool zap_user,
bool zap_kernel);
void hists__output_recalc_col_len(struct hists *hists, int max_rows);
void hists__inc_nr_entries(struct hists *hists, struct hist_entry *h);
......@@ -119,7 +115,7 @@ void events_stats__inc(struct events_stats *stats, u32 type);
size_t events_stats__fprintf(struct events_stats *stats, FILE *fp);
size_t hists__fprintf(struct hists *self, bool show_header, int max_rows,
int max_cols, FILE *fp);
int max_cols, float min_pcnt, FILE *fp);
int hist_entry__inc_addr_samples(struct hist_entry *self, int evidx, u64 addr);
int hist_entry__annotate(struct hist_entry *self, size_t privsize);
......@@ -199,6 +195,7 @@ int hist_entry__tui_annotate(struct hist_entry *he, struct perf_evsel *evsel,
int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help,
struct hist_browser_timer *hbt,
float min_pcnt,
struct perf_session_env *env);
int script_browse(const char *script_opt);
#else
......@@ -206,6 +203,7 @@ static inline
int perf_evlist__tui_browse_hists(struct perf_evlist *evlist __maybe_unused,
const char *help __maybe_unused,
struct hist_browser_timer *hbt __maybe_unused,
float min_pcnt __maybe_unused,
struct perf_session_env *env __maybe_unused)
{
return 0;
......@@ -233,12 +231,14 @@ static inline int script_browse(const char *script_opt __maybe_unused)
#ifdef GTK2_SUPPORT
int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist, const char *help,
struct hist_browser_timer *hbt __maybe_unused);
struct hist_browser_timer *hbt __maybe_unused,
float min_pcnt);
#else
static inline
int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist __maybe_unused,
const char *help __maybe_unused,
struct hist_browser_timer *hbt __maybe_unused)
struct hist_browser_timer *hbt __maybe_unused,
float min_pcnt __maybe_unused)
{
return 0;
}
......
......@@ -21,6 +21,7 @@ const char *map_type__name[MAP__NR_TYPES] = {
static inline int is_anon_memory(const char *filename)
{
return !strcmp(filename, "//anon") ||
!strcmp(filename, "/dev/zero (deleted)") ||
!strcmp(filename, "/anon_hugepage (deleted)");
}
......
......@@ -37,7 +37,6 @@ struct perf_session {
int fd;
bool fd_pipe;
bool repipe;
int cwdlen;
char *cwd;
struct ordered_samples ordered_samples;
char filename[1];
......
......@@ -18,8 +18,9 @@ class install_lib(_install_lib):
self.build_dir = build_lib
cflags = ['-fno-strict-aliasing', '-Wno-write-strings']
cflags += getenv('CFLAGS', '').split()
cflags = getenv('CFLAGS', '').split()
# switch off several checks (need to be at the end of cflags list)
cflags += ['-fno-strict-aliasing', '-Wno-write-strings', '-Wno-unused-parameter' ]
build_lib = getenv('PYTHON_EXTBUILD_LIB')
build_tmp = getenv('PYTHON_EXTBUILD_TMP')
......
#include "sort.h"
#include "hist.h"
#include "symbol.h"
regex_t parent_regex;
const char default_parent_pattern[] = "^sys_|^do_page_fault";
......@@ -9,7 +10,7 @@ const char *sort_order = default_sort_order;
int sort__need_collapse = 0;
int sort__has_parent = 0;
int sort__has_sym = 0;
int sort__branch_mode = -1; /* -1 = means not set */
enum sort_mode sort__mode = SORT_MODE__NORMAL;
enum sort_type sort__first_dimension;
......@@ -194,7 +195,7 @@ static int _hist_entry__sym_snprintf(struct map *map, struct symbol *sym,
if (verbose) {
char o = map ? dso__symtab_origin(map->dso) : '!';
ret += repsep_snprintf(bf, size, "%-#*llx %c ",
BITS_PER_LONG / 4, ip, o);
BITS_PER_LONG / 4 + 2, ip, o);
}
ret += repsep_snprintf(bf + ret, size - ret, "[%c] ", level);
......@@ -871,14 +872,6 @@ static struct sort_dimension common_sort_dimensions[] = {
DIM(SORT_PARENT, "parent", sort_parent),
DIM(SORT_CPU, "cpu", sort_cpu),
DIM(SORT_SRCLINE, "srcline", sort_srcline),
DIM(SORT_LOCAL_WEIGHT, "local_weight", sort_local_weight),
DIM(SORT_GLOBAL_WEIGHT, "weight", sort_global_weight),
DIM(SORT_MEM_DADDR_SYMBOL, "symbol_daddr", sort_mem_daddr_sym),
DIM(SORT_MEM_DADDR_DSO, "dso_daddr", sort_mem_daddr_dso),
DIM(SORT_MEM_LOCKED, "locked", sort_mem_locked),
DIM(SORT_MEM_TLB, "tlb", sort_mem_tlb),
DIM(SORT_MEM_LVL, "mem", sort_mem_lvl),
DIM(SORT_MEM_SNOOP, "snoop", sort_mem_snoop),
};
#undef DIM
......@@ -895,6 +888,36 @@ static struct sort_dimension bstack_sort_dimensions[] = {
#undef DIM
#define DIM(d, n, func) [d - __SORT_MEMORY_MODE] = { .name = n, .entry = &(func) }
static struct sort_dimension memory_sort_dimensions[] = {
DIM(SORT_LOCAL_WEIGHT, "local_weight", sort_local_weight),
DIM(SORT_GLOBAL_WEIGHT, "weight", sort_global_weight),
DIM(SORT_MEM_DADDR_SYMBOL, "symbol_daddr", sort_mem_daddr_sym),
DIM(SORT_MEM_DADDR_DSO, "dso_daddr", sort_mem_daddr_dso),
DIM(SORT_MEM_LOCKED, "locked", sort_mem_locked),
DIM(SORT_MEM_TLB, "tlb", sort_mem_tlb),
DIM(SORT_MEM_LVL, "mem", sort_mem_lvl),
DIM(SORT_MEM_SNOOP, "snoop", sort_mem_snoop),
};
#undef DIM
static void __sort_dimension__add(struct sort_dimension *sd, enum sort_type idx)
{
if (sd->taken)
return;
if (sd->entry->se_collapse)
sort__need_collapse = 1;
if (list_empty(&hist_entry__sort_list))
sort__first_dimension = idx;
list_add_tail(&sd->entry->list, &hist_entry__sort_list);
sd->taken = 1;
}
int sort_dimension__add(const char *tok)
{
unsigned int i;
......@@ -915,25 +938,11 @@ int sort_dimension__add(const char *tok)
return -EINVAL;
}
sort__has_parent = 1;
} else if (sd->entry == &sort_sym ||
sd->entry == &sort_sym_from ||
sd->entry == &sort_sym_to ||
sd->entry == &sort_mem_daddr_sym) {
} else if (sd->entry == &sort_sym) {
sort__has_sym = 1;
}
if (sd->taken)
return 0;
if (sd->entry->se_collapse)
sort__need_collapse = 1;
if (list_empty(&hist_entry__sort_list))
sort__first_dimension = i;
list_add_tail(&sd->entry->list, &hist_entry__sort_list);
sd->taken = 1;
__sort_dimension__add(sd, i);
return 0;
}
......@@ -943,24 +952,29 @@ int sort_dimension__add(const char *tok)
if (strncasecmp(tok, sd->name, strlen(tok)))
continue;
if (sort__branch_mode != 1)
if (sort__mode != SORT_MODE__BRANCH)
return -EINVAL;
if (sd->entry == &sort_sym_from || sd->entry == &sort_sym_to)
sort__has_sym = 1;
if (sd->taken)
return 0;
__sort_dimension__add(sd, i + __SORT_BRANCH_STACK);
return 0;
}
if (sd->entry->se_collapse)
sort__need_collapse = 1;
for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++) {
struct sort_dimension *sd = &memory_sort_dimensions[i];
if (list_empty(&hist_entry__sort_list))
sort__first_dimension = i + __SORT_BRANCH_STACK;
if (strncasecmp(tok, sd->name, strlen(tok)))
continue;
list_add_tail(&sd->entry->list, &hist_entry__sort_list);
sd->taken = 1;
if (sort__mode != SORT_MODE__MEMORY)
return -EINVAL;
if (sd->entry == &sort_mem_daddr_sym)
sort__has_sym = 1;
__sort_dimension__add(sd, i + __SORT_MEMORY_MODE);
return 0;
}
......@@ -993,8 +1007,9 @@ int setup_sorting(void)
return ret;
}
void sort_entry__setup_elide(struct sort_entry *self, struct strlist *list,
const char *list_name, FILE *fp)
static void sort_entry__setup_elide(struct sort_entry *self,
struct strlist *list,
const char *list_name, FILE *fp)
{
if (list && strlist__nr_entries(list) == 1) {
if (fp != NULL)
......@@ -1003,3 +1018,42 @@ void sort_entry__setup_elide(struct sort_entry *self, struct strlist *list,
self->elide = true;
}
}
void sort__setup_elide(FILE *output)
{
sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
"dso", output);
sort_entry__setup_elide(&sort_comm, symbol_conf.comm_list,
"comm", output);
sort_entry__setup_elide(&sort_sym, symbol_conf.sym_list,
"symbol", output);
if (sort__mode == SORT_MODE__BRANCH) {
sort_entry__setup_elide(&sort_dso_from,
symbol_conf.dso_from_list,
"dso_from", output);
sort_entry__setup_elide(&sort_dso_to,
symbol_conf.dso_to_list,
"dso_to", output);
sort_entry__setup_elide(&sort_sym_from,
symbol_conf.sym_from_list,
"sym_from", output);
sort_entry__setup_elide(&sort_sym_to,
symbol_conf.sym_to_list,
"sym_to", output);
} else if (sort__mode == SORT_MODE__MEMORY) {
sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
"symbol_daddr", output);
sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
"dso_daddr", output);
sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
"mem", output);
sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
"local_weight", output);
sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
"tlb", output);
sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
"snoop", output);
}
}
......@@ -32,7 +32,7 @@ extern const char default_sort_order[];
extern int sort__need_collapse;
extern int sort__has_parent;
extern int sort__has_sym;
extern int sort__branch_mode;
extern enum sort_mode sort__mode;
extern struct sort_entry sort_comm;
extern struct sort_entry sort_dso;
extern struct sort_entry sort_sym;
......@@ -117,12 +117,18 @@ static inline struct hist_entry *hist_entry__next_pair(struct hist_entry *he)
return NULL;
}
static inline void hist_entry__add_pair(struct hist_entry *he,
struct hist_entry *pair)
static inline void hist_entry__add_pair(struct hist_entry *pair,
struct hist_entry *he)
{
list_add_tail(&he->pairs.head, &pair->pairs.node);
list_add_tail(&pair->pairs.node, &he->pairs.head);
}
enum sort_mode {
SORT_MODE__NORMAL,
SORT_MODE__BRANCH,
SORT_MODE__MEMORY,
};
enum sort_type {
/* common sort keys */
SORT_PID,
......@@ -132,14 +138,6 @@ enum sort_type {
SORT_PARENT,
SORT_CPU,
SORT_SRCLINE,
SORT_LOCAL_WEIGHT,
SORT_GLOBAL_WEIGHT,
SORT_MEM_DADDR_SYMBOL,
SORT_MEM_DADDR_DSO,
SORT_MEM_LOCKED,
SORT_MEM_TLB,
SORT_MEM_LVL,
SORT_MEM_SNOOP,
/* branch stack specific sort keys */
__SORT_BRANCH_STACK,
......@@ -148,6 +146,17 @@ enum sort_type {
SORT_SYM_FROM,
SORT_SYM_TO,
SORT_MISPREDICT,
/* memory mode specific sort keys */
__SORT_MEMORY_MODE,
SORT_LOCAL_WEIGHT = __SORT_MEMORY_MODE,
SORT_GLOBAL_WEIGHT,
SORT_MEM_DADDR_SYMBOL,
SORT_MEM_DADDR_DSO,
SORT_MEM_LOCKED,
SORT_MEM_TLB,
SORT_MEM_LVL,
SORT_MEM_SNOOP,
};
/*
......@@ -172,7 +181,6 @@ extern struct list_head hist_entry__sort_list;
int setup_sorting(void);
extern int sort_dimension__add(const char *);
void sort_entry__setup_elide(struct sort_entry *self, struct strlist *list,
const char *list_name, FILE *fp);
void sort__setup_elide(FILE *fp);
#endif /* __PERF_SORT_H */
......@@ -37,7 +37,7 @@ double stddev_stats(struct stats *stats)
{
double variance, variance_mean;
if (!stats->n)
if (stats->n < 2)
return 0.0;
variance = stats->M2 / (stats->n - 1);
......
......@@ -14,6 +14,7 @@ struct thread *thread__new(pid_t pid)
if (self != NULL) {
map_groups__init(&self->mg);
self->pid = pid;
self->ppid = -1;
self->comm = malloc(32);
if (self->comm)
snprintf(self->comm, 32, ":%d", self->pid);
......@@ -82,5 +83,8 @@ int thread__fork(struct thread *self, struct thread *parent)
for (i = 0; i < MAP__NR_TYPES; ++i)
if (map_groups__clone(&self->mg, &parent->mg, i) < 0)
return -ENOMEM;
self->ppid = parent->pid;
return 0;
}
......@@ -13,6 +13,7 @@ struct thread {
};
struct map_groups mg;
pid_t pid;
pid_t ppid;
char shortname[3];
bool comm_set;
char *comm;
......
......@@ -23,20 +23,31 @@
size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size)
{
float samples_per_sec = top->samples / top->delay_secs;
float ksamples_per_sec = top->kernel_samples / top->delay_secs;
float esamples_percent = (100.0 * top->exact_samples) / top->samples;
float samples_per_sec;
float ksamples_per_sec;
float esamples_percent;
struct perf_record_opts *opts = &top->record_opts;
struct perf_target *target = &opts->target;
size_t ret = 0;
if (top->samples) {
samples_per_sec = top->samples / top->delay_secs;
ksamples_per_sec = top->kernel_samples / top->delay_secs;
esamples_percent = (100.0 * top->exact_samples) / top->samples;
} else {
samples_per_sec = ksamples_per_sec = esamples_percent = 0.0;
}
if (!perf_guest) {
float ksamples_percent = 0.0;
if (samples_per_sec)
ksamples_percent = (100.0 * ksamples_per_sec) /
samples_per_sec;
ret = SNPRINTF(bf, size,
" PerfTop:%8.0f irqs/sec kernel:%4.1f%%"
" exact: %4.1f%% [", samples_per_sec,
100.0 - (100.0 * ((samples_per_sec - ksamples_per_sec) /
samples_per_sec)),
esamples_percent);
ksamples_percent, esamples_percent);
} else {
float us_samples_per_sec = top->us_samples / top->delay_secs;
float guest_kernel_samples_per_sec = top->guest_kernel_samples / top->delay_secs;
......
......@@ -26,7 +26,6 @@ struct perf_top {
int print_entries, count_filter, delay_secs;
bool hide_kernel_symbols, hide_user_symbols, zero;
bool use_tui, use_stdio;
bool sort_has_symbols;
bool kptr_restrict_warned;
bool vmlinux_warned;
bool dump_symtab;
......@@ -37,6 +36,7 @@ struct perf_top {
int realtime_prio;
int sym_pcnt_filter;
const char *sym_filter;
float min_percent;
};
size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size);
......
......@@ -221,8 +221,8 @@ extern unsigned char sane_ctype[256];
#define isalpha(x) sane_istest(x,GIT_ALPHA)
#define isalnum(x) sane_istest(x,GIT_ALPHA | GIT_DIGIT)
#define isprint(x) sane_istest(x,GIT_PRINT)
#define islower(x) (sane_istest(x,GIT_ALPHA) && sane_istest(x,0x20))
#define isupper(x) (sane_istest(x,GIT_ALPHA) && !sane_istest(x,0x20))
#define islower(x) (sane_istest(x,GIT_ALPHA) && (x & 0x20))
#define isupper(x) (sane_istest(x,GIT_ALPHA) && !(x & 0x20))
#define tolower(x) sane_case((unsigned char)(x), 0x20)
#define toupper(x) sane_case((unsigned char)(x), 0)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册